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