Path: blob/master/src/java.security.jgss/share/classes/sun/security/jgss/GSSHeader.java
41159 views
/*1* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.jgss;2627import org.ietf.jgss.GSSException;28import java.io.InputStream;29import java.io.OutputStream;30import java.io.IOException;31import sun.security.util.*;3233/**34* This class represents the mechanism independent part of a GSS-API35* context establishment token. Some mechanisms may choose to encode36* all subsequent tokens as well such that they start with an encoding37* of an instance of this class. e.g., The Kerberos v5 GSS-API Mechanism38* uses this header for all GSS-API tokens.39* <p>40* The format is specified in RFC 2743 section 3.1.41*42* @author Mayank Upadhyay43*/4445/*46* The RFC states that implementations should explicitly follow the47* encoding scheme descibed in this section rather than use ASN.148* compilers. However, we should consider removing duplicate ASN.149* like code from here and depend on sun.security.util if possible.50*/5152public class GSSHeader {5354private ObjectIdentifier mechOid = null;55private byte[] mechOidBytes = null;56private int mechTokenLength = 0;5758/**59* The tag defined in the GSS-API mechanism independent token60* format.61*/62public static final int TOKEN_ID=0x60;6364/**65* Creates a GSSHeader instance whose encoding can be used as the66* prefix for a particular mechanism token.67* @param mechOid the Oid of the mechanism which generated the token68* @param mechTokenLength the length of the subsequent portion that69* the mechanism will be adding.70*/71public GSSHeader(ObjectIdentifier mechOid, int mechTokenLength)72throws IOException {7374this.mechOid = mechOid;75DerOutputStream temp = new DerOutputStream();76temp.putOID(mechOid);77mechOidBytes = temp.toByteArray();78this.mechTokenLength = mechTokenLength;79}8081/**82* Reads in a GSSHeader from an InputStream. Typically this would be83* used as part of reading the complete token from an InputStream84* that is obtained from a socket.85*/86public GSSHeader(InputStream is)87throws IOException, GSSException {8889// debug("Parsing GSS token: ");9091int tag = is.read();9293// debug("tag=" + tag);9495if (tag != TOKEN_ID)96throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,97"GSSHeader did not find the right tag");9899int length = getLength(is);100101DerValue temp = new DerValue(is);102mechOidBytes = temp.toByteArray();103mechOid = temp.getOID();104// debug (" oid=" + mechOid);105106// debug (" len starting with oid=" + length);107mechTokenLength = length - mechOidBytes.length;108109// debug(" mechToken length=" + mechTokenLength);110111}112113/**114* Used to obtain the Oid stored in this GSSHeader instance.115* @return the Oid of the mechanism.116*/117public ObjectIdentifier getOid() {118return mechOid;119}120121/**122* Used to obtain the length of the mechanism specific token that123* will follow the encoding of this GSSHeader instance.124* @return the length of the mechanism specific token portion that125* will follow this GSSHeader.126*/127public int getMechTokenLength() {128return mechTokenLength;129}130131/**132* Used to obtain the length of the encoding of this GSSHeader.133* @return the lenght of the encoding of this GSSHeader instance.134*/135public int getLength() {136int lenField = mechOidBytes.length + mechTokenLength;137return (1 + getLenFieldSize(lenField) + mechOidBytes.length);138}139140/**141* Used to determine what the maximum possible mechanism token142* size is if the complete GSSToken returned to the application143* (including a GSSHeader) is not to exceed some pre-determined144* value in size.145* @param mechOid the Oid of the mechanism that will generate146* this GSS-API token147* @param maxTotalSize the pre-determined value that serves as a148* maximum size for the complete GSS-API token (including a149* GSSHeader)150* @return the maximum size of mechanism token that can be used151* so as to not exceed maxTotalSize with the GSS-API token152*/153public static int getMaxMechTokenSize(ObjectIdentifier mechOid,154int maxTotalSize) {155156int mechOidBytesSize = 0;157try {158DerOutputStream temp = new DerOutputStream();159temp.putOID(mechOid);160mechOidBytesSize = temp.toByteArray().length;161} catch (IOException e) {162}163164// Subtract bytes needed for 0x60 tag and mechOidBytes165maxTotalSize -= (1 + mechOidBytesSize);166167// Subtract maximum len bytes168maxTotalSize -= 5;169170return maxTotalSize;171172/*173* Len field and mechanism token must fit in remaining174* space. The range of the len field that we allow is175* 1 through 5.176*177178int mechTokenSize = 0;179for (int lenFieldSize = 1; lenFieldSize <= 5;180lenFieldSize++) {181mechTokenSize = maxTotalSize - lenFieldSize;182if (getLenFieldSize(mechTokenSize + mechOidBytesSize +183lenFieldSize) <= lenFieldSize)184break;185}186187return mechTokenSize;188*/189190191}192193/**194* Used to determine the number of bytes that will be need to encode195* the length field of the GSSHeader.196*/197private int getLenFieldSize(int len) {198int retVal = 1;199if (len < 128) {200retVal=1;201} else if (len < (1 << 8)) {202retVal=2;203} else if (len < (1 << 16)) {204retVal=3;205} else if (len < (1 << 24)) {206retVal=4;207} else {208retVal=5; // See getMaxMechTokenSize209}210return retVal;211}212213/**214* Encodes this GSSHeader instance onto the provided OutputStream.215* @param os the OutputStream to which the token should be written.216* @return the number of bytes that are output as a result of this217* encoding218*/219public int encode(OutputStream os) throws IOException {220int retVal = 1 + mechOidBytes.length;221os.write(TOKEN_ID);222int length = mechOidBytes.length + mechTokenLength;223retVal += putLength(length, os);224os.write(mechOidBytes);225return retVal;226}227228/**229* Get a length from the input stream, allowing for at most 32 bits of230* encoding to be used. (Not the same as getting a tagged integer!)231*232* @return the length or -1 if indefinite length found.233* @exception IOException on parsing error or unsupported lengths.234*/235// shameless lifted from sun.security.util.DerInputStream.236private int getLength(InputStream in) throws IOException {237return getLength(in.read(), in);238}239240/**241* Get a length from the input stream, allowing for at most 32 bits of242* encoding to be used. (Not the same as getting a tagged integer!)243*244* @return the length or -1 if indefinite length found.245* @exception IOException on parsing error or unsupported lengths.246*/247// shameless lifted from sun.security.util.DerInputStream.248private int getLength(int lenByte, InputStream in) throws IOException {249int value, tmp;250251tmp = lenByte;252if ((tmp & 0x080) == 0x00) { // short form, 1 byte datum253value = tmp;254} else { // long form or indefinite255tmp &= 0x07f;256257/*258* NOTE: tmp == 0 indicates indefinite length encoded data.259* tmp > 4 indicates more than 4Gb of data.260*/261if (tmp == 0)262return -1;263if (tmp < 0 || tmp > 4)264throw new IOException("DerInputStream.getLength(): lengthTag="265+ tmp + ", "266+ ((tmp < 0) ? "incorrect DER encoding." : "too big."));267268for (value = 0; tmp > 0; tmp --) {269value <<= 8;270value += 0x0ff & in.read();271}272if (value < 0) {273throw new IOException("Invalid length bytes");274}275}276return value;277}278279/**280* Put the encoding of the length in the specified stream.281*282* @params len the length of the attribute.283* @param out the outputstream to write the length to284* @return the number of bytes written285* @exception IOException on writing errors.286*/287// Shameless lifted from sun.security.util.DerOutputStream.288private int putLength(int len, OutputStream out) throws IOException {289int retVal = 0;290if (len < 128) {291out.write((byte)len);292retVal=1;293294} else if (len < (1 << 8)) {295out.write((byte)0x081);296out.write((byte)len);297retVal=2;298299} else if (len < (1 << 16)) {300out.write((byte)0x082);301out.write((byte)(len >> 8));302out.write((byte)len);303retVal=3;304305} else if (len < (1 << 24)) {306out.write((byte)0x083);307out.write((byte)(len >> 16));308out.write((byte)(len >> 8));309out.write((byte)len);310retVal=4;311312} else {313out.write((byte)0x084);314out.write((byte)(len >> 24));315out.write((byte)(len >> 16));316out.write((byte)(len >> 8));317out.write((byte)len);318retVal=5;319}320321return retVal;322}323324// XXX Call these two in some central class325private void debug(String str) {326System.err.print(str);327}328329private String getHexBytes(byte[] bytes, int len)330throws IOException {331332StringBuilder sb = new StringBuilder();333for (int i = 0; i < len; i++) {334335int b1 = (bytes[i]>>4) & 0x0f;336int b2 = bytes[i] & 0x0f;337338sb.append(Integer.toHexString(b1));339sb.append(Integer.toHexString(b2));340sb.append(' ');341}342return sb.toString();343}344}345346347