1/* 2 * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package sun.security.jgss.spnego; 27 28import java.io.*; 29import java.util.*; 30import org.ietf.jgss.*; 31import sun.security.jgss.*; 32import sun.security.util.*; 33 34/** 35 * Implements the SPNEGO NegTokenInit token 36 * as specified in RFC 2478 37 * 38 * NegTokenInit ::= SEQUENCE { 39 * mechTypes [0] MechTypeList OPTIONAL, 40 * reqFlags [1] ContextFlags OPTIONAL, 41 * mechToken [2] OCTET STRING OPTIONAL, 42 * mechListMIC [3] OCTET STRING OPTIONAL 43 * } 44 * 45 * MechTypeList ::= SEQUENCE OF MechType 46 * 47 * MechType::= OBJECT IDENTIFIER 48 * 49 * ContextFlags ::= BIT STRING { 50 * delegFlag (0), 51 * mutualFlag (1), 52 * replayFlag (2), 53 * sequenceFlag (3), 54 * anonFlag (4), 55 * confFlag (5), 56 * integFlag (6) 57 * } 58 * 59 * @author Seema Malkani 60 * @since 1.6 61 */ 62 63public class NegTokenInit extends SpNegoToken { 64 65 // DER-encoded mechTypes 66 private byte[] mechTypes = null; 67 private Oid[] mechTypeList = null; 68 69 private BitArray reqFlags = null; 70 private byte[] mechToken = null; 71 private byte[] mechListMIC = null; 72 73 NegTokenInit(byte[] mechTypes, BitArray flags, 74 byte[] token, byte[] mechListMIC) 75 { 76 super(NEG_TOKEN_INIT_ID); 77 this.mechTypes = mechTypes; 78 this.reqFlags = flags; 79 this.mechToken = token; 80 this.mechListMIC = mechListMIC; 81 } 82 83 // Used by sun.security.jgss.wrapper.NativeGSSContext 84 // to parse SPNEGO tokens 85 public NegTokenInit(byte[] in) throws GSSException { 86 super(NEG_TOKEN_INIT_ID); 87 parseToken(in); 88 } 89 90 final byte[] encode() throws GSSException { 91 try { 92 // create negInitToken 93 DerOutputStream initToken = new DerOutputStream(); 94 95 // DER-encoded mechTypes with CONTEXT 00 96 if (mechTypes != null) { 97 initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT, 98 true, (byte) 0x00), mechTypes); 99 } 100 101 // write context flags with CONTEXT 01 102 if (reqFlags != null) { 103 DerOutputStream flags = new DerOutputStream(); 104 flags.putUnalignedBitString(reqFlags); 105 initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT, 106 true, (byte) 0x01), flags); 107 } 108 109 // mechToken with CONTEXT 02 110 if (mechToken != null) { 111 DerOutputStream dataValue = new DerOutputStream(); 112 dataValue.putOctetString(mechToken); 113 initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT, 114 true, (byte) 0x02), dataValue); 115 } 116 117 // mechListMIC with CONTEXT 03 118 if (mechListMIC != null) { 119 if (DEBUG) { 120 System.out.println("SpNegoToken NegTokenInit: " + 121 "sending MechListMIC"); 122 } 123 DerOutputStream mic = new DerOutputStream(); 124 mic.putOctetString(mechListMIC); 125 initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT, 126 true, (byte) 0x03), mic); 127 } 128 129 // insert in a SEQUENCE 130 DerOutputStream out = new DerOutputStream(); 131 out.write(DerValue.tag_Sequence, initToken); 132 133 return out.toByteArray(); 134 135 } catch (IOException e) { 136 throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, 137 "Invalid SPNEGO NegTokenInit token : " + e.getMessage()); 138 } 139 } 140 141 private void parseToken(byte[] in) throws GSSException { 142 try { 143 DerValue der = new DerValue(in); 144 // verify NegotiationToken type token 145 if (!der.isContextSpecific((byte) NEG_TOKEN_INIT_ID)) { 146 throw new IOException("SPNEGO NegoTokenInit : " + 147 "did not have right token type"); 148 } 149 DerValue tmp1 = der.data.getDerValue(); 150 if (tmp1.tag != DerValue.tag_Sequence) { 151 throw new IOException("SPNEGO NegoTokenInit : " + 152 "did not have the Sequence tag"); 153 } 154 155 // parse various fields if present 156 int lastField = -1; 157 while (tmp1.data.available() > 0) { 158 DerValue tmp2 = tmp1.data.getDerValue(); 159 if (tmp2.isContextSpecific((byte)0x00)) { 160 // get the DER-encoded sequence of mechTypes 161 lastField = checkNextField(lastField, 0); 162 DerInputStream mValue = tmp2.data; 163 mechTypes = mValue.toByteArray(); 164 165 // read all the mechTypes 166 DerValue[] mList = mValue.getSequence(0); 167 mechTypeList = new Oid[mList.length]; 168 ObjectIdentifier mech = null; 169 for (int i = 0; i < mList.length; i++) { 170 mech = mList[i].getOID(); 171 if (DEBUG) { 172 System.out.println("SpNegoToken NegTokenInit: " + 173 "reading Mechanism Oid = " + mech); 174 } 175 mechTypeList[i] = new Oid(mech.toString()); 176 } 177 } else if (tmp2.isContextSpecific((byte)0x01)) { 178 lastField = checkNextField(lastField, 1); 179 // received reqFlags, skip it 180 } else if (tmp2.isContextSpecific((byte)0x02)) { 181 lastField = checkNextField(lastField, 2); 182 if (DEBUG) { 183 System.out.println("SpNegoToken NegTokenInit: " + 184 "reading Mech Token"); 185 } 186 mechToken = tmp2.data.getOctetString(); 187 } else if (tmp2.isContextSpecific((byte)0x03)) { 188 lastField = checkNextField(lastField, 3); 189 if (!GSSUtil.useMSInterop()) { 190 mechListMIC = tmp2.data.getOctetString(); 191 if (DEBUG) { 192 System.out.println("SpNegoToken NegTokenInit: " + 193 "MechListMIC Token = " + 194 getHexBytes(mechListMIC)); 195 } 196 } 197 } 198 } 199 } catch (IOException e) { 200 throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, 201 "Invalid SPNEGO NegTokenInit token : " + e.getMessage()); 202 } 203 } 204 205 byte[] getMechTypes() { 206 return mechTypes; 207 } 208 209 // Used by sun.security.jgss.wrapper.NativeGSSContext 210 // to find the mechs in SPNEGO tokens 211 public Oid[] getMechTypeList() { 212 return mechTypeList; 213 } 214 215 BitArray getReqFlags() { 216 return reqFlags; 217 } 218 219 // Used by sun.security.jgss.wrapper.NativeGSSContext 220 // to access the mech token portion of SPNEGO tokens 221 public byte[] getMechToken() { 222 return mechToken; 223 } 224 225 byte[] getMechListMIC() { 226 return mechListMIC; 227 } 228 229} 230