722 lines
26 KiB
Java
722 lines
26 KiB
Java
/*
|
|
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
package sun.security.jgss.krb5;
|
|
|
|
import org.ietf.jgss.*;
|
|
import sun.security.jgss.*;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.io.IOException;
|
|
import java.io.ByteArrayInputStream;
|
|
import java.security.MessageDigest;
|
|
|
|
/**
|
|
* This class is a base class for other token definitions that pertain to
|
|
* per-message GSS-API calls. Conceptually GSS-API has two types of
|
|
* per-message tokens: WrapToken and MicToken. They differ in the respect
|
|
* that a WrapToken carries additional plaintext or ciphertext application
|
|
* data besides just the sequence number and checksum. This class
|
|
* encapsulates the commonality in the structure of the WrapToken and the
|
|
* MicToken. This structure can be represented as:
|
|
* <p>
|
|
* <pre>
|
|
* 0..1 TOK_ID Identification field.
|
|
* 01 01 - Mic token
|
|
* 02 01 - Wrap token
|
|
* 2..3 SGN_ALG Checksum algorithm indicator.
|
|
* 00 00 - DES MAC MD5
|
|
* 01 00 - MD2.5
|
|
* 02 00 - DES MAC
|
|
* 04 00 - HMAC SHA1 DES3-KD
|
|
* 11 00 - RC4-HMAC
|
|
* 4..5 SEAL_ALG ff ff - none
|
|
* 00 00 - DES
|
|
* 02 00 - DES3-KD
|
|
* 10 00 - RC4-HMAC
|
|
* 6..7 Filler Contains ff ff
|
|
* 8..15 SND_SEQ Encrypted sequence number field.
|
|
* 16..s+15 SGN_CKSUM Checksum of plaintext padded data,
|
|
* calculated according to algorithm
|
|
* specified in SGN_ALG field.
|
|
* s+16..last Data encrypted or plaintext padded data
|
|
* </pre>
|
|
* Where "s" indicates the size of the checksum.
|
|
* <p>
|
|
* As always, this is preceeded by a GSSHeader.
|
|
*
|
|
* @author Mayank Upadhyay
|
|
* @author Ram Marti
|
|
* @see sun.security.jgss.GSSHeader
|
|
*/
|
|
|
|
abstract class MessageToken extends Krb5Token {
|
|
/* Fields in header minus checksum size */
|
|
private static final int TOKEN_NO_CKSUM_SIZE = 16;
|
|
|
|
/**
|
|
* Filler data as defined in the specification of the Kerberos v5 GSS-API
|
|
* Mechanism.
|
|
*/
|
|
private static final int FILLER = 0xffff;
|
|
|
|
// Signing algorithm values (for the SNG_ALG field)
|
|
|
|
// From RFC 1964
|
|
/* Use a DES MAC MD5 checksum */
|
|
static final int SGN_ALG_DES_MAC_MD5 = 0x0000;
|
|
|
|
/* Use DES MAC checksum. */
|
|
static final int SGN_ALG_DES_MAC = 0x0200;
|
|
|
|
// From draft-raeburn-cat-gssapi-krb5-3des-00
|
|
/* Use a HMAC SHA1 DES3 -KD checksum */
|
|
static final int SGN_ALG_HMAC_SHA1_DES3_KD = 0x0400;
|
|
|
|
// Sealing algorithm values (for the SEAL_ALG field)
|
|
|
|
// RFC 1964
|
|
/**
|
|
* A value for the SEAL_ALG field that indicates that no encryption was
|
|
* used.
|
|
*/
|
|
static final int SEAL_ALG_NONE = 0xffff;
|
|
/* Use DES CBC encryption algorithm. */
|
|
static final int SEAL_ALG_DES = 0x0000;
|
|
|
|
// From draft-raeburn-cat-gssapi-krb5-3des-00
|
|
/**
|
|
* Use DES3-KD sealing algorithm. (draft-raeburn-cat-gssapi-krb5-3des-00)
|
|
* This algorithm uses triple-DES with key derivation, with a usage
|
|
* value KG_USAGE_SEAL. Padding is still to 8-byte multiples, and the
|
|
* IV for encrypting application data is zero.
|
|
*/
|
|
static final int SEAL_ALG_DES3_KD = 0x0200;
|
|
|
|
// draft draft-brezak-win2k-krb-rc4-hmac-04.txt
|
|
static final int SEAL_ALG_ARCFOUR_HMAC = 0x1000;
|
|
static final int SGN_ALG_HMAC_MD5_ARCFOUR = 0x1100;
|
|
|
|
private static final int TOKEN_ID_POS = 0;
|
|
private static final int SIGN_ALG_POS = 2;
|
|
private static final int SEAL_ALG_POS = 4;
|
|
|
|
private int seqNumber;
|
|
|
|
private boolean confState = true;
|
|
private boolean initiator = true;
|
|
|
|
private int tokenId = 0;
|
|
private GSSHeader gssHeader = null;
|
|
private MessageTokenHeader tokenHeader = null;
|
|
private byte[] checksum = null;
|
|
private byte[] encSeqNumber = null;
|
|
private byte[] seqNumberData = null;
|
|
|
|
/* cipher instance used by the corresponding GSSContext */
|
|
CipherHelper cipherHelper = null;
|
|
|
|
|
|
/**
|
|
* Constructs a MessageToken from a byte array. If there are more bytes
|
|
* in the array than needed, the extra bytes are simply ignroed.
|
|
*
|
|
* @param tokenId the token id that should be contained in this token as
|
|
* it is read.
|
|
* @param context the Kerberos context associated with this token
|
|
* @param tokenBytes the byte array containing the token
|
|
* @param tokenOffset the offset where the token begins
|
|
* @param tokenLen the length of the token
|
|
* @param prop the MessageProp structure in which the properties of the
|
|
* token should be stored.
|
|
* @throws GSSException if there is a problem parsing the token
|
|
*/
|
|
MessageToken(int tokenId, Krb5Context context,
|
|
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
|
MessageProp prop) throws GSSException {
|
|
this(tokenId, context,
|
|
new ByteArrayInputStream(tokenBytes, tokenOffset, tokenLen),
|
|
prop);
|
|
}
|
|
|
|
/**
|
|
* Constructs a MessageToken from an InputStream. Bytes will be read on
|
|
* demand and the thread might block if there are not enough bytes to
|
|
* complete the token.
|
|
*
|
|
* @param tokenId the token id that should be contained in this token as
|
|
* it is read.
|
|
* @param context the Kerberos context associated with this token
|
|
* @param is the InputStream from which to read
|
|
* @param prop the MessageProp structure in which the properties of the
|
|
* token should be stored.
|
|
* @throws GSSException if there is a problem reading from the
|
|
* InputStream or parsing the token
|
|
*/
|
|
MessageToken(int tokenId, Krb5Context context, InputStream is,
|
|
MessageProp prop) throws GSSException {
|
|
init(tokenId, context);
|
|
|
|
try {
|
|
gssHeader = new GSSHeader(is);
|
|
|
|
if (!gssHeader.getOid().equals((Object)OID)) {
|
|
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
|
getTokenName(tokenId));
|
|
}
|
|
if (!confState) {
|
|
prop.setPrivacy(false);
|
|
}
|
|
|
|
tokenHeader = new MessageTokenHeader(is, prop);
|
|
|
|
encSeqNumber = new byte[8];
|
|
readFully(is, encSeqNumber);
|
|
|
|
// debug("\n\tRead EncSeq#=" +
|
|
// getHexBytes(encSeqNumber, encSeqNumber.length));
|
|
|
|
checksum = new byte[cipherHelper.getChecksumLength()];
|
|
readFully(is, checksum);
|
|
|
|
// debug("\n\tRead checksum=" +
|
|
// getHexBytes(checksum, checksum.length));
|
|
// debug("\nLeaving MessageToken.Cons\n");
|
|
|
|
} catch (IOException e) {
|
|
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
|
getTokenName(tokenId) + ":" + e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Used to obtain the GSSHeader that was at the start of this
|
|
* token.
|
|
*/
|
|
public final GSSHeader getGSSHeader() {
|
|
return gssHeader;
|
|
}
|
|
|
|
/**
|
|
* Used to obtain the token id that was contained in this token.
|
|
* @return the token id in the token
|
|
*/
|
|
public final int getTokenId() {
|
|
return tokenId;
|
|
}
|
|
|
|
/**
|
|
* Used to obtain the encrypted sequence number in this token.
|
|
* @return the encrypted sequence number in the token
|
|
*/
|
|
public final byte[] getEncSeqNumber() {
|
|
return encSeqNumber;
|
|
}
|
|
|
|
/**
|
|
* Used to obtain the checksum that was contained in this token.
|
|
* @return the checksum in the token
|
|
*/
|
|
public final byte[] getChecksum() {
|
|
return checksum;
|
|
}
|
|
|
|
/**
|
|
* Used to determine if this token contains any encrypted data.
|
|
* @return true if it contains any encrypted data, false if there is only
|
|
* plaintext data or if there is no data.
|
|
*/
|
|
public final boolean getConfState() {
|
|
return confState;
|
|
}
|
|
|
|
/**
|
|
* Generates the checksum field and the encrypted sequence number
|
|
* field. The encrypted sequence number uses the 8 bytes of the checksum
|
|
* as an initial vector in a fixed DesCbc algorithm.
|
|
*
|
|
* @param prop the MessageProp structure that determines what sort of
|
|
* checksum and sealing algorithm should be used. The lower byte
|
|
* of qop determines the checksum algorithm while the upper byte
|
|
* determines the signing algorithm.
|
|
* Checksum values are:
|
|
* 0 - default (DES_MAC)
|
|
* 1 - MD5
|
|
* 2 - DES_MD5
|
|
* 3 - DES_MAC
|
|
* 4 - HMAC_SHA1
|
|
* Sealing values are:
|
|
* 0 - default (DES)
|
|
* 1 - DES
|
|
* 2 - DES3-KD
|
|
*
|
|
* @param optionalHeader an optional header that will be processed first
|
|
* during checksum calculation
|
|
*
|
|
* @param data the application data to checksum
|
|
* @param offset the offset where the data starts
|
|
* @param len the length of the data
|
|
*
|
|
* @param optionalTrailer an optional trailer that will be processed
|
|
* last during checksum calculation. e.g., padding that should be
|
|
* appended to the application data
|
|
*
|
|
* @throws GSSException if an error occurs in the checksum calculation or
|
|
* encryption sequence number calculation.
|
|
*/
|
|
public void genSignAndSeqNumber(MessageProp prop,
|
|
byte[] optionalHeader,
|
|
byte[] data, int offset, int len,
|
|
byte[] optionalTrailer)
|
|
throws GSSException {
|
|
|
|
// debug("Inside MessageToken.genSignAndSeqNumber:\n");
|
|
|
|
int qop = prop.getQOP();
|
|
if (qop != 0) {
|
|
qop = 0;
|
|
prop.setQOP(qop);
|
|
}
|
|
|
|
if (!confState) {
|
|
prop.setPrivacy(false);
|
|
}
|
|
|
|
// Create a token header with the correct sign and seal algorithm
|
|
// values.
|
|
tokenHeader =
|
|
new MessageTokenHeader(tokenId, prop.getPrivacy(), qop);
|
|
|
|
// Calculate SGN_CKSUM
|
|
|
|
checksum =
|
|
getChecksum(optionalHeader, data, offset, len, optionalTrailer);
|
|
|
|
// debug("\n\tCalc checksum=" +
|
|
// getHexBytes(checksum, checksum.length));
|
|
|
|
// Calculate SND_SEQ
|
|
|
|
seqNumberData = new byte[8];
|
|
|
|
// When using this RC4 based encryption type, the sequence number is
|
|
// always sent in big-endian rather than little-endian order.
|
|
if (cipherHelper.isArcFour()) {
|
|
writeBigEndian(seqNumber, seqNumberData);
|
|
} else {
|
|
// for all other etypes
|
|
writeLittleEndian(seqNumber, seqNumberData);
|
|
}
|
|
if (!initiator) {
|
|
seqNumberData[4] = (byte)0xff;
|
|
seqNumberData[5] = (byte)0xff;
|
|
seqNumberData[6] = (byte)0xff;
|
|
seqNumberData[7] = (byte)0xff;
|
|
}
|
|
|
|
encSeqNumber = cipherHelper.encryptSeq(checksum, seqNumberData, 0, 8);
|
|
|
|
// debug("\n\tCalc seqNum=" +
|
|
// getHexBytes(seqNumberData, seqNumberData.length));
|
|
// debug("\n\tCalc encSeqNum=" +
|
|
// getHexBytes(encSeqNumber, encSeqNumber.length));
|
|
}
|
|
|
|
/**
|
|
* Verifies that the checksum field and sequence number direction bytes
|
|
* are valid and consistent with the application data.
|
|
*
|
|
* @param optionalHeader an optional header that will be processed first
|
|
* during checksum calculation.
|
|
*
|
|
* @param data the application data
|
|
* @param offset the offset where the data begins
|
|
* @param len the length of the application data
|
|
*
|
|
* @param optionalTrailer an optional trailer that will be processed last
|
|
* during checksum calculation. e.g., padding that should be appended to
|
|
* the application data
|
|
*
|
|
* @throws GSSException if an error occurs in the checksum calculation or
|
|
* encryption sequence number calculation.
|
|
*/
|
|
public final boolean verifySignAndSeqNumber(byte[] optionalHeader,
|
|
byte[] data, int offset, int len,
|
|
byte[] optionalTrailer)
|
|
throws GSSException {
|
|
// debug("\tIn verifySign:\n");
|
|
|
|
// debug("\t\tchecksum: [" + getHexBytes(checksum) + "]\n");
|
|
|
|
byte[] myChecksum =
|
|
getChecksum(optionalHeader, data, offset, len, optionalTrailer);
|
|
|
|
// debug("\t\tmychecksum: [" + getHexBytes(myChecksum) +"]\n");
|
|
// debug("\t\tchecksum: [" + getHexBytes(checksum) + "]\n");
|
|
|
|
if (MessageDigest.isEqual(checksum, myChecksum)) {
|
|
|
|
seqNumberData = cipherHelper.decryptSeq(
|
|
checksum, encSeqNumber, 0, 8);
|
|
|
|
// debug("\t\tencSeqNumber: [" + getHexBytes(encSeqNumber)
|
|
// + "]\n");
|
|
// debug("\t\tseqNumberData: [" + getHexBytes(seqNumberData)
|
|
// + "]\n");
|
|
|
|
/*
|
|
* The token from the initiator has direction bytes 0x00 and
|
|
* the token from the acceptor has direction bytes 0xff.
|
|
*/
|
|
byte directionByte = 0;
|
|
if (initiator)
|
|
directionByte = (byte) 0xff; // Received token from acceptor
|
|
|
|
if ((seqNumberData[4] == directionByte) &&
|
|
(seqNumberData[5] == directionByte) &&
|
|
(seqNumberData[6] == directionByte) &&
|
|
(seqNumberData[7] == directionByte))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
public final int getSequenceNumber() {
|
|
int sequenceNum = 0;
|
|
if (cipherHelper.isArcFour()) {
|
|
sequenceNum = readBigEndian(seqNumberData, 0, 4);
|
|
} else {
|
|
sequenceNum = readLittleEndian(seqNumberData, 0, 4);
|
|
}
|
|
return sequenceNum;
|
|
}
|
|
|
|
/**
|
|
* Computes the checksum based on the algorithm stored in the
|
|
* tokenHeader.
|
|
*
|
|
* @param optionalHeader an optional header that will be processed first
|
|
* during checksum calculation.
|
|
*
|
|
* @param data the application data
|
|
* @param offset the offset where the data begins
|
|
* @param len the length of the application data
|
|
*
|
|
* @param optionalTrailer an optional trailer that will be processed last
|
|
* during checksum calculation. e.g., padding that should be appended to
|
|
* the application data
|
|
*
|
|
* @throws GSSException if an error occurs in the checksum calculation.
|
|
*/
|
|
private byte[] getChecksum(byte[] optionalHeader,
|
|
byte[] data, int offset, int len,
|
|
byte[] optionalTrailer)
|
|
throws GSSException {
|
|
|
|
// debug("Will do getChecksum:\n");
|
|
|
|
/*
|
|
* For checksum calculation the token header bytes i.e., the first 8
|
|
* bytes following the GSSHeader, are logically prepended to the
|
|
* application data to bind the data to this particular token.
|
|
*
|
|
* Note: There is no such requirement wrt adding padding to the
|
|
* application data for checksumming, although the cryptographic
|
|
* algorithm used might itself apply some padding.
|
|
*/
|
|
|
|
byte[] tokenHeaderBytes = tokenHeader.getBytes();
|
|
byte[] existingHeader = optionalHeader;
|
|
byte[] checksumDataHeader = tokenHeaderBytes;
|
|
|
|
if (existingHeader != null) {
|
|
checksumDataHeader = new byte[tokenHeaderBytes.length +
|
|
existingHeader.length];
|
|
System.arraycopy(tokenHeaderBytes, 0,
|
|
checksumDataHeader, 0, tokenHeaderBytes.length);
|
|
System.arraycopy(existingHeader, 0,
|
|
checksumDataHeader, tokenHeaderBytes.length,
|
|
existingHeader.length);
|
|
}
|
|
|
|
return cipherHelper.calculateChecksum(tokenHeader.getSignAlg(),
|
|
checksumDataHeader, optionalTrailer, data, offset, len, tokenId);
|
|
}
|
|
|
|
|
|
/**
|
|
* Constructs an empty MessageToken for the local context to send to
|
|
* the peer. It also increments the local sequence number in the
|
|
* Krb5Context instance it uses after obtaining the object lock for
|
|
* it.
|
|
*
|
|
* @param tokenId the token id that should be contained in this token
|
|
* @param context the Kerberos context associated with this token
|
|
*/
|
|
MessageToken(int tokenId, Krb5Context context) throws GSSException {
|
|
/*
|
|
debug("\n============================");
|
|
debug("\nMySessionKey=" +
|
|
getHexBytes(context.getMySessionKey().getBytes()));
|
|
debug("\nPeerSessionKey=" +
|
|
getHexBytes(context.getPeerSessionKey().getBytes()));
|
|
debug("\n============================\n");
|
|
*/
|
|
init(tokenId, context);
|
|
this.seqNumber = context.incrementMySequenceNumber();
|
|
}
|
|
|
|
private void init(int tokenId, Krb5Context context) throws GSSException {
|
|
this.tokenId = tokenId;
|
|
// Just for consistency check in Wrap
|
|
this.confState = context.getConfState();
|
|
|
|
this.initiator = context.isInitiator();
|
|
|
|
this.cipherHelper = context.getCipherHelper(null);
|
|
// debug("In MessageToken.Cons");
|
|
}
|
|
|
|
/**
|
|
* Encodes a GSSHeader and this token onto an OutputStream.
|
|
*
|
|
* @param os the OutputStream to which this should be written
|
|
* @throws GSSException if an error occurs while writing to the OutputStream
|
|
*/
|
|
public void encode(OutputStream os) throws IOException, GSSException {
|
|
gssHeader = new GSSHeader(OID, getKrb5TokenSize());
|
|
gssHeader.encode(os);
|
|
tokenHeader.encode(os);
|
|
// debug("Writing seqNumber: " + getHexBytes(encSeqNumber));
|
|
os.write(encSeqNumber);
|
|
// debug("Writing checksum: " + getHexBytes(checksum));
|
|
os.write(checksum);
|
|
}
|
|
|
|
/**
|
|
* Obtains the size of this token. Note that this excludes the size of
|
|
* the GSSHeader.
|
|
* @return token size
|
|
*/
|
|
protected int getKrb5TokenSize() throws GSSException {
|
|
return getTokenSize();
|
|
}
|
|
|
|
protected final int getTokenSize() throws GSSException {
|
|
return TOKEN_NO_CKSUM_SIZE + cipherHelper.getChecksumLength();
|
|
}
|
|
|
|
protected static final int getTokenSize(CipherHelper ch)
|
|
throws GSSException {
|
|
return TOKEN_NO_CKSUM_SIZE + ch.getChecksumLength();
|
|
}
|
|
|
|
/**
|
|
* Obtains the conext key that is associated with this token.
|
|
* @return the context key
|
|
*/
|
|
/*
|
|
public final byte[] getContextKey() {
|
|
return contextKey;
|
|
}
|
|
*/
|
|
|
|
/**
|
|
* Obtains the encryption algorithm that should be used in this token
|
|
* given the state of confidentiality the application requested.
|
|
* Requested qop must be consistent with negotiated session key.
|
|
* @param confRequested true if the application desired confidentiality
|
|
* on this token, false otherwise
|
|
* @param qop the qop requested by the application
|
|
* @throws GSSException if qop is incompatible with the negotiated
|
|
* session key
|
|
*/
|
|
protected abstract int getSealAlg(boolean confRequested, int qop)
|
|
throws GSSException;
|
|
|
|
// ******************************************* //
|
|
// I N N E R C L A S S E S F O L L O W
|
|
// ******************************************* //
|
|
|
|
/**
|
|
* This inner class represents the initial portion of the message token
|
|
* and contains information about the checksum and encryption algorithms
|
|
* that are in use. It constitutes the first 8 bytes of the
|
|
* message token:
|
|
* <pre>
|
|
* 0..1 TOK_ID Identification field.
|
|
* 01 01 - Mic token
|
|
* 02 01 - Wrap token
|
|
* 2..3 SGN_ALG Checksum algorithm indicator.
|
|
* 00 00 - DES MAC MD5
|
|
* 01 00 - MD2.5
|
|
* 02 00 - DES MAC
|
|
* 04 00 - HMAC SHA1 DES3-KD
|
|
* 11 00 - RC4-HMAC
|
|
* 4..5 SEAL_ALG ff ff - none
|
|
* 00 00 - DES
|
|
* 02 00 - DES3-KD
|
|
* 10 00 - RC4-HMAC
|
|
* 6..7 Filler Contains ff ff
|
|
* </pre>
|
|
*/
|
|
class MessageTokenHeader {
|
|
|
|
private int tokenId;
|
|
private int signAlg;
|
|
private int sealAlg;
|
|
|
|
private byte[] bytes = new byte[8];
|
|
|
|
/**
|
|
* Constructs a MessageTokenHeader for the specified token type with
|
|
* appropriate checksum and encryption algorithms fields.
|
|
*
|
|
* @param tokenId the token id for this message token
|
|
* @param conf true if confidentiality will be resuested with this
|
|
* message token, false otherwise.
|
|
* @param qop the value of the quality of protection that will be
|
|
* desired.
|
|
*/
|
|
public MessageTokenHeader(int tokenId, boolean conf, int qop)
|
|
throws GSSException {
|
|
|
|
this.tokenId = tokenId;
|
|
|
|
signAlg = MessageToken.this.getSgnAlg(qop);
|
|
|
|
sealAlg = MessageToken.this.getSealAlg(conf, qop);
|
|
|
|
bytes[0] = (byte) (tokenId >>> 8);
|
|
bytes[1] = (byte) (tokenId);
|
|
|
|
bytes[2] = (byte) (signAlg >>> 8);
|
|
bytes[3] = (byte) (signAlg);
|
|
|
|
bytes[4] = (byte) (sealAlg >>> 8);
|
|
bytes[5] = (byte) (sealAlg);
|
|
|
|
bytes[6] = (byte) (MessageToken.FILLER >>> 8);
|
|
bytes[7] = (byte) (MessageToken.FILLER);
|
|
}
|
|
|
|
/**
|
|
* Constructs a MessageTokenHeader by reading it from an InputStream
|
|
* and sets the appropriate confidentiality and quality of protection
|
|
* values in a MessageProp structure.
|
|
*
|
|
* @param is the InputStream to read from
|
|
* @param prop the MessageProp to populate
|
|
* @throws IOException is an error occurs while reading from the
|
|
* InputStream
|
|
*/
|
|
public MessageTokenHeader(InputStream is, MessageProp prop)
|
|
throws IOException {
|
|
readFully(is, bytes);
|
|
tokenId = readInt(bytes, TOKEN_ID_POS);
|
|
signAlg = readInt(bytes, SIGN_ALG_POS);
|
|
sealAlg = readInt(bytes, SEAL_ALG_POS);
|
|
// debug("\nMessageTokenHeader read tokenId=" +
|
|
// getHexBytes(bytes) + "\n");
|
|
// XXX compare to FILLER
|
|
int temp = readInt(bytes, SEAL_ALG_POS + 2);
|
|
|
|
// debug("SIGN_ALG=" + signAlg);
|
|
|
|
switch (sealAlg) {
|
|
case SEAL_ALG_DES:
|
|
case SEAL_ALG_DES3_KD:
|
|
case SEAL_ALG_ARCFOUR_HMAC:
|
|
prop.setPrivacy(true);
|
|
break;
|
|
|
|
default:
|
|
prop.setPrivacy(false);
|
|
}
|
|
|
|
prop.setQOP(0); // default
|
|
}
|
|
|
|
/**
|
|
* Encodes this MessageTokenHeader onto an OutputStream
|
|
* @param os the OutputStream to write to
|
|
* @throws IOException is an error occurs while writing
|
|
*/
|
|
public final void encode(OutputStream os) throws IOException {
|
|
os.write(bytes);
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the token id for the message token.
|
|
* @return the token id
|
|
* @see sun.security.jgss.krb5.Krb5Token#MIC_ID
|
|
* @see sun.security.jgss.krb5.Krb5Token#WRAP_ID
|
|
*/
|
|
public final int getTokenId() {
|
|
return tokenId;
|
|
}
|
|
|
|
/**
|
|
* Returns the sign algorithm for the message token.
|
|
* @return the sign algorithm
|
|
* @see sun.security.jgss.krb5.MessageToken#SIGN_DES_MAC
|
|
* @see sun.security.jgss.krb5.MessageToken#SIGN_DES_MAC_MD5
|
|
*/
|
|
public final int getSignAlg() {
|
|
return signAlg;
|
|
}
|
|
|
|
/**
|
|
* Returns the seal algorithm for the message token.
|
|
* @return the seal algorithm
|
|
* @see sun.security.jgss.krb5.MessageToken#SEAL_ALG_DES
|
|
* @see sun.security.jgss.krb5.MessageToken#SEAL_ALG_NONE
|
|
*/
|
|
public final int getSealAlg() {
|
|
return sealAlg;
|
|
}
|
|
|
|
/**
|
|
* Returns the bytes of this header.
|
|
* @return 8 bytes that form this header
|
|
*/
|
|
public final byte[] getBytes() {
|
|
return bytes;
|
|
}
|
|
} // end of class MessageTokenHeader
|
|
|
|
|
|
/**
|
|
* Determine signing algorithm based on QOP.
|
|
*/
|
|
protected int getSgnAlg(int qop) throws GSSException {
|
|
// QOP ignored
|
|
return cipherHelper.getSgnAlg();
|
|
}
|
|
}
|