/* * Copyright (c) 2000, 2006, 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;import org.ietf.jgss.GSSException;import java.io.InputStream;import java.io.OutputStream;import java.io.IOException;import sun.security.util.*;/** * This class represents the mechanism independent part of a GSS-API * context establishment token. Some mechanisms may choose to encode * all subsequent tokens as well such that they start with an encoding * of an instance of this class. e.g., The Kerberos v5 GSS-API Mechanism * uses this header for all GSS-API tokens. * <p> * The format is specified in RFC 2743 section 3.1. * * @author Mayank Upadhyay *//* * The RFC states that implementations should explicitly follow the * encoding scheme descibed in this section rather than use ASN.1 * compilers. However, we should consider removing duplicate ASN.1 * like code from here and depend on sun.security.util if possible. */public class GSSHeader { private ObjectIdentifier mechOid = null; private byte[] mechOidBytes = null; private int mechTokenLength = 0; /** * The tag defined in the GSS-API mechanism independent token * format. */ public static final int TOKEN_ID=0x60; /** * Creates a GSSHeader instance whose encoding can be used as the * prefix for a particular mechanism token. * @param mechOid the Oid of the mechanism which generated the token * @param mechTokenLength the length of the subsequent portion that * the mechanism will be adding. */ public GSSHeader(ObjectIdentifier mechOid, int mechTokenLength) throws IOException { this.mechOid = mechOid; DerOutputStream temp = new DerOutputStream(); temp.putOID(mechOid); mechOidBytes = temp.toByteArray(); this.mechTokenLength = mechTokenLength; } /** * Reads in a GSSHeader from an InputStream. Typically this would be * used as part of reading the complete token from an InputStream * that is obtained from a socket. */ public GSSHeader(InputStream is) throws IOException, GSSException { // debug("Parsing GSS token: "); int tag = is.read(); // debug("tag=" + tag); if (tag != TOKEN_ID) throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "GSSHeader did not find the right tag"); int length = getLength(is); DerValue temp = new DerValue(is); mechOidBytes = temp.toByteArray(); mechOid = temp.getOID(); // debug (" oid=" + mechOid); // debug (" len starting with oid=" + length); mechTokenLength = length - mechOidBytes.length; // debug(" mechToken length=" + mechTokenLength); } /** * Used to obtain the Oid stored in this GSSHeader instance. * @return the Oid of the mechanism. */ public ObjectIdentifier getOid() { return mechOid; } /** * Used to obtain the length of the mechanism specific token that * will follow the encoding of this GSSHeader instance. * @return the length of the mechanism specific token portion that * will follow this GSSHeader. */ public int getMechTokenLength() { return mechTokenLength; } /** * Used to obtain the length of the encoding of this GSSHeader. * @return the lenght of the encoding of this GSSHeader instance. */ public int getLength() { int lenField = mechOidBytes.length + mechTokenLength; return (1 + getLenFieldSize(lenField) + mechOidBytes.length); } /** * Used to determine what the maximum possible mechanism token * size is if the complete GSSToken returned to the application * (including a GSSHeader) is not to exceed some pre-determined * value in size. * @param mechOid the Oid of the mechanism that will generate * this GSS-API token * @param maxTotalSize the pre-determined value that serves as a * maximum size for the complete GSS-API token (including a * GSSHeader) * @return the maximum size of mechanism token that can be used * so as to not exceed maxTotalSize with the GSS-API token */ public static int getMaxMechTokenSize(ObjectIdentifier mechOid, int maxTotalSize) { int mechOidBytesSize = 0; try { DerOutputStream temp = new DerOutputStream(); temp.putOID(mechOid); mechOidBytesSize = temp.toByteArray().length; } catch (IOException e) { } // Subtract bytes needed for 0x60 tag and mechOidBytes maxTotalSize -= (1 + mechOidBytesSize); // Subtract maximum len bytes maxTotalSize -= 5; return maxTotalSize; /* * Len field and mechanism token must fit in remaining * space. The range of the len field that we allow is * 1 through 5. * int mechTokenSize = 0; for (int lenFieldSize = 1; lenFieldSize <= 5; lenFieldSize++) { mechTokenSize = maxTotalSize - lenFieldSize; if (getLenFieldSize(mechTokenSize + mechOidBytesSize + lenFieldSize) <= lenFieldSize) break; } return mechTokenSize; */ } /** * Used to determine the number of bytes that will be need to encode * the length field of the GSSHeader. */ private int getLenFieldSize(int len) { int retVal = 1; if (len < 128) { retVal=1; } else if (len < (1 << 8)) { retVal=2; } else if (len < (1 << 16)) { retVal=3; } else if (len < (1 << 24)) { retVal=4; } else { retVal=5; // See getMaxMechTokenSize } return retVal; } /** * Encodes this GSSHeader instance onto the provided OutputStream. * @param os the OutputStream to which the token should be written. * @return the number of bytes that are output as a result of this * encoding */ public int encode(OutputStream os) throws IOException { int retVal = 1 + mechOidBytes.length; os.write(TOKEN_ID); int length = mechOidBytes.length + mechTokenLength; retVal += putLength(length, os); os.write(mechOidBytes); return retVal; } /** * Get a length from the input stream, allowing for at most 32 bits of * encoding to be used. (Not the same as getting a tagged integer!) * * @return the length or -1 if indefinite length found. * @exception IOException on parsing error or unsupported lengths. */ // shameless lifted from sun.security.util.DerInputStream. private int getLength(InputStream in) throws IOException { return getLength(in.read(), in); } /** * Get a length from the input stream, allowing for at most 32 bits of * encoding to be used. (Not the same as getting a tagged integer!) * * @return the length or -1 if indefinite length found. * @exception IOException on parsing error or unsupported lengths. */ // shameless lifted from sun.security.util.DerInputStream. private int getLength(int lenByte, InputStream in) throws IOException { int value, tmp; tmp = lenByte; if ((tmp & 0x080) == 0x00) { // short form, 1 byte datum value = tmp; } else { // long form or indefinite tmp &= 0x07f; /* * NOTE: tmp == 0 indicates indefinite length encoded data. * tmp > 4 indicates more than 4Gb of data. */ if (tmp == 0) return -1; if (tmp < 0 || tmp > 4) throw new IOException("DerInputStream.getLength(): lengthTag=" + tmp + ", " + ((tmp < 0) ? "incorrect DER encoding." : "too big.")); for (value = 0; tmp > 0; tmp --) { value <<= 8; value += 0x0ff & in.read(); } } return value; } /** * Put the encoding of the length in the specified stream. * * @params len the length of the attribute. * @param out the outputstream to write the length to * @return the number of bytes written * @exception IOException on writing errors. */ // Shameless lifted from sun.security.util.DerOutputStream. private int putLength(int len, OutputStream out) throws IOException { int retVal = 0; if (len < 128) { out.write((byte)len); retVal=1; } else if (len < (1 << 8)) { out.write((byte)0x081); out.write((byte)len); retVal=2; } else if (len < (1 << 16)) { out.write((byte)0x082); out.write((byte)(len >> 8)); out.write((byte)len); retVal=3; } else if (len < (1 << 24)) { out.write((byte)0x083); out.write((byte)(len >> 16)); out.write((byte)(len >> 8)); out.write((byte)len); retVal=4; } else { out.write((byte)0x084); out.write((byte)(len >> 24)); out.write((byte)(len >> 16)); out.write((byte)(len >> 8)); out.write((byte)len); retVal=5; } return retVal; } // XXX Call these two in some central class private void debug(String str) { System.err.print(str); } private String getHexBytes(byte[] bytes, int len) throws IOException { StringBuffer sb = new StringBuffer(); for (int i = 0; i < len; i++) { int b1 = (bytes[i]>>4) & 0x0f; int b2 = bytes[i] & 0x0f; sb.append(Integer.toHexString(b1)); sb.append(Integer.toHexString(b2)); sb.append(' '); } return sb.toString(); }}
/*
* Copyright (c) 2000, 2006, 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;
import org.ietf.jgss.GSSException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import sun.security.util.*;
/**
* This class represents the mechanism independent part of a GSS-API
* context establishment token. Some mechanisms may choose to encode
* all subsequent tokens as well such that they start with an encoding
* of an instance of this class. e.g., The Kerberos v5 GSS-API Mechanism
* uses this header for all GSS-API tokens.
* <p>
* The format is specified in RFC 2743 section 3.1.
*
* @author Mayank Upadhyay
*/
/*
* The RFC states that implementations should explicitly follow the
* encoding scheme descibed in this section rather than use ASN.1
* compilers. However, we should consider removing duplicate ASN.1
* like code from here and depend on sun.security.util if possible.
*/
public class GSSHeader {
private ObjectIdentifier mechOid = null;
private byte[] mechOidBytes = null;
private int mechTokenLength = 0;
/**
* The tag defined in the GSS-API mechanism independent token
* format.
*/
public static final int TOKEN_ID=0x60;
/**
* Creates a GSSHeader instance whose encoding can be used as the
* prefix for a particular mechanism token.
* @param mechOid the Oid of the mechanism which generated the token
* @param mechTokenLength the length of the subsequent portion that
* the mechanism will be adding.
*/
public GSSHeader(ObjectIdentifier mechOid, int mechTokenLength)
throws IOException {
this.mechOid = mechOid;
DerOutputStream temp = new DerOutputStream();
temp.putOID(mechOid);
mechOidBytes = temp.toByteArray();
this.mechTokenLength = mechTokenLength;
}
/**
* Reads in a GSSHeader from an InputStream. Typically this would be
* used as part of reading the complete token from an InputStream
* that is obtained from a socket.
*/
public GSSHeader(InputStream is)
throws IOException, GSSException {
// debug("Parsing GSS token: ");
int tag = is.read();
// debug("tag=" + tag);
if (tag != TOKEN_ID)
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
"GSSHeader did not find the right tag");
int length = getLength(is);
DerValue temp = new DerValue(is);
mechOidBytes = temp.toByteArray();
mechOid = temp.getOID();
// debug (" oid=" + mechOid);
// debug (" len starting with oid=" + length);
mechTokenLength = length - mechOidBytes.length;
// debug(" mechToken length=" + mechTokenLength);
}
/**
* Used to obtain the Oid stored in this GSSHeader instance.
* @return the Oid of the mechanism.
*/
public ObjectIdentifier getOid() {
return mechOid;
}
/**
* Used to obtain the length of the mechanism specific token that
* will follow the encoding of this GSSHeader instance.
* @return the length of the mechanism specific token portion that
* will follow this GSSHeader.
*/
public int getMechTokenLength() {
return mechTokenLength;
}
/**
* Used to obtain the length of the encoding of this GSSHeader.
* @return the lenght of the encoding of this GSSHeader instance.
*/
public int getLength() {
int lenField = mechOidBytes.length + mechTokenLength;
return (1 + getLenFieldSize(lenField) + mechOidBytes.length);
}
/**
* Used to determine what the maximum possible mechanism token
* size is if the complete GSSToken returned to the application
* (including a GSSHeader) is not to exceed some pre-determined
* value in size.
* @param mechOid the Oid of the mechanism that will generate
* this GSS-API token
* @param maxTotalSize the pre-determined value that serves as a
* maximum size for the complete GSS-API token (including a
* GSSHeader)
* @return the maximum size of mechanism token that can be used
* so as to not exceed maxTotalSize with the GSS-API token
*/
public static int getMaxMechTokenSize(ObjectIdentifier mechOid,
int maxTotalSize) {
int mechOidBytesSize = 0;
try {
DerOutputStream temp = new DerOutputStream();
temp.putOID(mechOid);
mechOidBytesSize = temp.toByteArray().length;
} catch (IOException e) {
}
// Subtract bytes needed for 0x60 tag and mechOidBytes
maxTotalSize -= (1 + mechOidBytesSize);
// Subtract maximum len bytes
maxTotalSize -= 5;
return maxTotalSize;
/*
* Len field and mechanism token must fit in remaining
* space. The range of the len field that we allow is
* 1 through 5.
*
int mechTokenSize = 0;
for (int lenFieldSize = 1; lenFieldSize <= 5;
lenFieldSize++) {
mechTokenSize = maxTotalSize - lenFieldSize;
if (getLenFieldSize(mechTokenSize + mechOidBytesSize +
lenFieldSize) <= lenFieldSize)
break;
}
return mechTokenSize;
*/
}
/**
* Used to determine the number of bytes that will be need to encode
* the length field of the GSSHeader.
*/
private int getLenFieldSize(int len) {
int retVal = 1;
if (len < 128) {
retVal=1;
} else if (len < (1 << 8)) {
retVal=2;
} else if (len < (1 << 16)) {
retVal=3;
} else if (len < (1 << 24)) {
retVal=4;
} else {
retVal=5; // See getMaxMechTokenSize
}
return retVal;
}
/**
* Encodes this GSSHeader instance onto the provided OutputStream.
* @param os the OutputStream to which the token should be written.
* @return the number of bytes that are output as a result of this
* encoding
*/
public int encode(OutputStream os) throws IOException {
int retVal = 1 + mechOidBytes.length;
os.write(TOKEN_ID);
int length = mechOidBytes.length + mechTokenLength;
retVal += putLength(length, os);
os.write(mechOidBytes);
return retVal;
}
/**
* Get a length from the input stream, allowing for at most 32 bits of
* encoding to be used. (Not the same as getting a tagged integer!)
*
* @return the length or -1 if indefinite length found.
* @exception IOException on parsing error or unsupported lengths.
*/
// shameless lifted from sun.security.util.DerInputStream.
private int getLength(InputStream in) throws IOException {
return getLength(in.read(), in);
}
/**
* Get a length from the input stream, allowing for at most 32 bits of
* encoding to be used. (Not the same as getting a tagged integer!)
*
* @return the length or -1 if indefinite length found.
* @exception IOException on parsing error or unsupported lengths.
*/
// shameless lifted from sun.security.util.DerInputStream.
private int getLength(int lenByte, InputStream in) throws IOException {
int value, tmp;
tmp = lenByte;
if ((tmp & 0x080) == 0x00) { // short form, 1 byte datum
value = tmp;
} else { // long form or indefinite
tmp &= 0x07f;
/*
* NOTE: tmp == 0 indicates indefinite length encoded data.
* tmp > 4 indicates more than 4Gb of data.
*/
if (tmp == 0)
return -1;
if (tmp < 0 || tmp > 4)
throw new IOException("DerInputStream.getLength(): lengthTag="
+ tmp + ", "
+ ((tmp < 0) ? "incorrect DER encoding." : "too big."));
for (value = 0; tmp > 0; tmp --) {
value <<= 8;
value += 0x0ff & in.read();
}
}
return value;
}
/**
* Put the encoding of the length in the specified stream.
*
* @params len the length of the attribute.
* @param out the outputstream to write the length to
* @return the number of bytes written
* @exception IOException on writing errors.
*/
// Shameless lifted from sun.security.util.DerOutputStream.
private int putLength(int len, OutputStream out) throws IOException {
int retVal = 0;
if (len < 128) {
out.write((byte)len);
retVal=1;
} else if (len < (1 << 8)) {
out.write((byte)0x081);
out.write((byte)len);
retVal=2;
} else if (len < (1 << 16)) {
out.write((byte)0x082);
out.write((byte)(len >> 8));
out.write((byte)len);
retVal=3;
} else if (len < (1 << 24)) {
out.write((byte)0x083);
out.write((byte)(len >> 16));
out.write((byte)(len >> 8));
out.write((byte)len);
retVal=4;
} else {
out.write((byte)0x084);
out.write((byte)(len >> 24));
out.write((byte)(len >> 16));
out.write((byte)(len >> 8));
out.write((byte)len);
retVal=5;
}
return retVal;
}
// XXX Call these two in some central class
private void debug(String str) {
System.err.print(str);
}
private String getHexBytes(byte[] bytes, int len)
throws IOException {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < len; i++) {
int b1 = (bytes[i]>>4) & 0x0f;
int b2 = bytes[i] & 0x0f;
sb.append(Integer.toHexString(b1));
sb.append(Integer.toHexString(b2));
sb.append(' ');
}
return sb.toString();
}
}