/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
/**
* This class is a base class for new GSS token definitions, as defined
* in RFC 4121, 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>
* Wrap Tokens
*
* Octet no Name Description
* ---------------------------------------------------------------
* 0..1 TOK_ID Identification field. Tokens emitted by
* GSS_Wrap() contain the hex value 05 04
* expressed in big-endian order in this field.
* 2 Flags Attributes field, as described in section
* 4.2.2.
* 3 Filler Contains the hex value FF.
* 4..5 EC Contains the "extra count" field, in big-
* endian order as described in section 4.2.3.
* 6..7 RRC Contains the "right rotation count" in big
* endian order, as described in section 4.2.5.
* 8..15 SND_SEQ Sequence number field in clear text,
* expressed in big-endian order.
* 16..last Data Encrypted data for Wrap tokens with
* confidentiality, or plaintext data followed
* by the checksum for Wrap tokens without
* confidentiality, as described in section
* 4.2.4.
* MIC Tokens
*
* Octet no Name Description
* -----------------------------------------------------------------
* 0..1 TOK_ID Identification field. Tokens emitted by
* GSS_GetMIC() contain the hex value 04 04
* expressed in big-endian order in this field.
* 2 Flags Attributes field, as described in section
* 4.2.2.
* 3..7 Filler Contains five octets of hex value FF.
* 8..15 SND_SEQ Sequence number field in clear text,
* expressed in big-endian order.
* 16..last SGN_CKSUM Checksum of the "to-be-signed" data and
* octet 0..15, as described in section 4.2.4.
*
* </pre>
* <p>
* This class is the super class of WrapToken_v2 and MicToken_v2. The token's
* header (bytes[0..15]) and data (byte[16..]) are saved in tokenHeader and
* tokenData fields. Since there is no easy way to find out the exact length
* of a WrapToken_v2 token from any header info, in the case of reading from
* stream, we read all available() bytes into the token.
* <p>
* All read actions are performed in this super class. On the write part, the
* super class only write the tokenHeader, and the content writing is inside
* child classes.
*
* @author Seema Malkani
*/
/**
* The size of the random confounder used in a WrapToken.
*/
// RFC 4121, key usage values
// RFC 4121, Flags Field
// Common field
private int seqNumber;
protected int tokenDataLen;
// Key usage number for crypto action
// EC and RRC fields, WrapToken only
// Checksum. Always in MicToken, might be in WrapToken
// Context properties
private boolean confState = true;
private boolean initiator = true;
private boolean have_acceptor_subkey = false;
/* cipher instance used by the corresponding GSSContext */
/**
* Constructs a MessageToken from a byte array.
*
* @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
*/
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. Please note there is no accurate way to find out
* the size of a token, but we try our best to make sure there is
* enough bytes to construct one.
*
* @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
*/
try {
if (!confState) {
prop.setPrivacy(false);
}
// set key_usage
}
} else {
}
// Read token data
// The only case we can precisely predict the token data length
} else {
tokenData = new byte[tokenDataLen];
} else {
// Hope while blocked in the read above, more data would
// come and is.available() below contains the whole token.
}
}
rotate();
}
// Read checksum
// validate EC for Wrap tokens without confidentiality
}
}
}
} catch (IOException e) {
}
}
/**
* 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 key_usage type for this token.
* @return the key_usage for the token
*/
public final int getKeyUsage() {
return key_usage;
}
/**
* 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 sequence number field.
*
* @param prop the MessageProp structure
* @param data the application data to checksum
* @param offset the offset where the data starts
* @param len the length of the data
*
* @throws GSSException if an error occurs in the checksum calculation or
* sequence number calculation.
*/
throws GSSException {
// debug("Inside MessageToken.genSignAndSeqNumber:\n");
if (qop != 0) {
qop = 0;
}
if (!confState) {
prop.setPrivacy(false);
}
// Create a new gss token header as defined in RFC 4121
// debug("\n\t Message Header = " +
// getHexBytes(tokenHeader.getBytes(), tokenHeader.getBytes().length));
// set key_usage
}
// Calculate SGN_CKSUM
// debug("\n\tCalc checksum=" +
// getHexBytes(checksum, checksum.length));
}
// In Wrap tokens without confidentiality, the EC field SHALL be used
// to encode the number of octets in the trailing checksum
}
}
/**
* Verifies the validity of checksum field
*
* @param data the application data
* @param offset the offset where the data begins
* @param len the length of the application data
*
* @throws GSSException if an error occurs in the checksum calculation
*/
throws GSSException {
// debug("\t====In verifySign:====\n");
// debug("\t\t checksum: [" + getHexBytes(checksum) + "]\n");
// debug("\t\t data = [" + getHexBytes(data) + "]\n");
// debug("\t\t mychecksum: [" + getHexBytes(myChecksum) +"]\n");
// debug("\t\t====Checksum PASS:====\n");
return true;
}
return false;
}
/**
* Rotate bytes as per the "RRC" (Right Rotation Count) received.
* Our implementation does not do any rotates when sending, only
* when receiving, we rotate left as per the RRC count, to revert it.
*/
private void rotate() {
byte[] newBytes = new byte[tokenDataLen];
}
}
public final int getSequenceNumber() {
return seqNumber;
}
/**
* Computes the checksum based on the algorithm stored in the
* tokenHeader.
*
* @param data the application data
* @param offset the offset where the data begins
* @param len the length of the application data
*
* @throws GSSException if an error occurs in the checksum calculation.
*/
throws GSSException {
// debug("Will do getChecksum:\n");
/*
* For checksum calculation the token header bytes i.e., the first 16
* 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.
*/
// check confidentiality
// clear EC and RRC in token header for checksum calculation
}
}
/**
* 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
*/
/*
debug("\n============================");
debug("\nMySessionKey=" +
getHexBytes(context.getMySessionKey().getBytes()));
debug("\nPeerSessionKey=" +
getHexBytes(context.getPeerSessionKey().getBytes()));
debug("\n============================\n");
*/
}
// Just for consistency check in Wrap
// debug("In MessageToken.Cons");
}
/**
* Encodes a MessageTokenHeader onto an OutputStream.
*
* @param os the OutputStream to which this should be written
* @throws IOException is an error occurs while writing to the OutputStream
*/
}
/**
* Encodes a MessageToken_v2 onto an OutputStream.
*
* @param os the OutputStream to which this should be written
* @throws IOException is an error occurs while encoding the token
*/
protected final byte[] getTokenHeader() {
return (tokenHeader.getBytes());
}
// ******************************************* //
// 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.
* It constitutes the first 16 bytes of the message token.
*/
class MessageTokenHeader {
private int tokenId;
// Writes a new token header
// Flags (Note: MIT impl requires subkey)
int flags = 0;
FLAG_WRAP_CONFIDENTIAL : 0) |
// filler
if (tokenId == WRAP_ID_v2) {
// EC field
// RRC field
// more filler for MicToken
for (int i = 4; i < 8; i++) {
}
}
// Calculate SND_SEQ, only write 4 bytes from the 12th position
}
/**
* Reads a MessageTokenHeader 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
*/
throws IOException, GSSException {
// validate Token ID
}
/*
* Validate new GSS TokenHeader
*/
// valid acceptor_flag
// If I am initiator, the received token should have ACCEPTOR on
if (flag != acceptor_flag) {
}
// check for confidentiality
if ((conf_flag == FLAG_WRAP_CONFIDENTIAL) &&
(tokenId == WRAP_ID_v2)) {
prop.setPrivacy(true);
} else {
prop.setPrivacy(false);
}
if (tokenId == WRAP_ID_v2) {
// validate filler
}
// read EC field
// read RRC field
for (int i = 3; i < 8; i++) {
"Defective Token Filler!");
}
}
}
// set default QOP
// sequence number
}
/**
* Encodes this MessageTokenHeader onto an OutputStream
* @param os the OutputStream to write to
* @throws IOException is an error occurs while writing
*/
}
/**
* Returns the token id for the message token.
* @return the token id
* @see sun.security.jgss.krb5.Krb5Token#MIC_ID_v2
* @see sun.security.jgss.krb5.Krb5Token#WRAP_ID_v2
*/
public final int getTokenId() {
return tokenId;
}
/**
* Returns the bytes of this header.
* @return 8 bytes that form this header
*/
public final byte[] getBytes() {
return bytes;
}
} // end of class MessageTokenHeader
}