Authenticator.java revision 12318:bee34b1dcbf1
1/*
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 it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.  Oracle designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * 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 WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 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 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25/*
26 *  (C) Copyright IBM Corp. 1999 All Rights Reserved.
27 *  Copyright 1997 The Open Group Research Institute.  All rights reserved.
28 */
29
30package sun.security.krb5.internal;
31
32import sun.security.krb5.*;
33import sun.security.util.*;
34import java.util.Vector;
35import java.io.IOException;
36import java.math.BigInteger;
37
38/**
39 * Implements the ASN.1 Authenticator type.
40 *
41 * <xmp>
42 * Authenticator   ::= [APPLICATION 2] SEQUENCE  {
43 *         authenticator-vno       [0] INTEGER (5),
44 *         crealm                  [1] Realm,
45 *         cname                   [2] PrincipalName,
46 *         cksum                   [3] Checksum OPTIONAL,
47 *         cusec                   [4] Microseconds,
48 *         ctime                   [5] KerberosTime,
49 *         subkey                  [6] EncryptionKey OPTIONAL,
50 *         seq-number              [7] UInt32 OPTIONAL,
51 *         authorization-data      [8] AuthorizationData OPTIONAL
52 * }
53 * </xmp>
54 *
55 * <p>
56 * This definition reflects the Network Working Group RFC 4120
57 * specification available at
58 * <a href="http://www.ietf.org/rfc/rfc4120.txt">
59 * http://www.ietf.org/rfc/rfc4120.txt</a>.
60 */
61public class Authenticator {
62
63    public int authenticator_vno;
64    public PrincipalName cname;
65    Checksum cksum; //optional
66    public int cusec;
67    public KerberosTime ctime;
68    EncryptionKey subKey; //optional
69    Integer seqNumber; //optional
70    public AuthorizationData authorizationData; //optional
71
72    public Authenticator(
73            PrincipalName new_cname,
74            Checksum new_cksum,
75            int new_cusec,
76            KerberosTime new_ctime,
77            EncryptionKey new_subKey,
78            Integer new_seqNumber,
79            AuthorizationData new_authorizationData) {
80        authenticator_vno = Krb5.AUTHNETICATOR_VNO;
81        cname = new_cname;
82        cksum = new_cksum;
83        cusec = new_cusec;
84        ctime = new_ctime;
85        subKey = new_subKey;
86        seqNumber = new_seqNumber;
87        authorizationData = new_authorizationData;
88    }
89
90    public Authenticator(byte[] data)
91            throws Asn1Exception, IOException, KrbApErrException, RealmException {
92        init(new DerValue(data));
93    }
94
95    public Authenticator(DerValue encoding)
96            throws Asn1Exception, IOException, KrbApErrException, RealmException {
97        init(encoding);
98    }
99
100    /**
101     * Initializes an Authenticator object.
102     * @param encoding a single DER-encoded value.
103     * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
104     * @exception IOException if an I/O error occurs while reading encoded data.
105     * @exception KrbApErrException if the value read from the DER-encoded data
106     *  stream does not match the pre-defined value.
107     * @exception RealmException if an error occurs while parsing a Realm object.
108     */
109    private void init(DerValue encoding)
110            throws Asn1Exception, IOException, KrbApErrException, RealmException {
111        DerValue der, subDer;
112        //may not be the correct error code for a tag
113        //mismatch on an encrypted structure
114        if (((encoding.getTag() & (byte) 0x1F) != (byte) 0x02)
115                || (encoding.isApplication() != true)
116                || (encoding.isConstructed() != true)) {
117            throw new Asn1Exception(Krb5.ASN1_BAD_ID);
118        }
119        der = encoding.getData().getDerValue();
120        if (der.getTag() != DerValue.tag_Sequence) {
121            throw new Asn1Exception(Krb5.ASN1_BAD_ID);
122        }
123        subDer = der.getData().getDerValue();
124        if ((subDer.getTag() & (byte) 0x1F) != (byte) 0x00) {
125            throw new Asn1Exception(Krb5.ASN1_BAD_ID);
126        }
127        authenticator_vno = subDer.getData().getBigInteger().intValue();
128        if (authenticator_vno != 5) {
129            throw new KrbApErrException(Krb5.KRB_AP_ERR_BADVERSION);
130        }
131        Realm crealm = Realm.parse(der.getData(), (byte) 0x01, false);
132        cname = PrincipalName.parse(der.getData(), (byte) 0x02, false, crealm);
133        cksum = Checksum.parse(der.getData(), (byte) 0x03, true);
134        subDer = der.getData().getDerValue();
135        if ((subDer.getTag() & (byte) 0x1F) == 0x04) {
136            cusec = subDer.getData().getBigInteger().intValue();
137        } else {
138            throw new Asn1Exception(Krb5.ASN1_BAD_ID);
139        }
140        ctime = KerberosTime.parse(der.getData(), (byte) 0x05, false);
141        if (der.getData().available() > 0) {
142            subKey = EncryptionKey.parse(der.getData(), (byte) 0x06, true);
143        } else {
144            subKey = null;
145            seqNumber = null;
146            authorizationData = null;
147        }
148        if (der.getData().available() > 0) {
149            if ((der.getData().peekByte() & 0x1F) == 0x07) {
150                subDer = der.getData().getDerValue();
151                if ((subDer.getTag() & (byte) 0x1F) == (byte) 0x07) {
152                    seqNumber = subDer.getData().getBigInteger().intValue();
153                }
154            }
155        } else {
156            seqNumber = null;
157            authorizationData = null;
158        }
159        if (der.getData().available() > 0) {
160            authorizationData = AuthorizationData.parse(der.getData(), (byte) 0x08, true);
161        } else {
162            authorizationData = null;
163        }
164        if (der.getData().available() > 0) {
165            throw new Asn1Exception(Krb5.ASN1_BAD_ID);
166        }
167    }
168
169    /**
170     * Encodes an Authenticator object.
171     * @return byte array of encoded Authenticator object.
172     * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
173     * @exception IOException if an I/O error occurs while reading encoded data.
174     */
175    public byte[] asn1Encode() throws Asn1Exception, IOException {
176        Vector<DerValue> v = new Vector<>();
177        DerOutputStream temp = new DerOutputStream();
178        temp.putInteger(BigInteger.valueOf(authenticator_vno));
179        v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x00), temp.toByteArray()));
180        v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x01), cname.getRealm().asn1Encode()));
181        v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x02), cname.asn1Encode()));
182        if (cksum != null) {
183            v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x03), cksum.asn1Encode()));
184        }
185        temp = new DerOutputStream();
186        temp.putInteger(BigInteger.valueOf(cusec));
187        v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x04), temp.toByteArray()));
188        v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x05), ctime.asn1Encode()));
189        if (subKey != null) {
190            v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x06), subKey.asn1Encode()));
191        }
192        if (seqNumber != null) {
193            temp = new DerOutputStream();
194            // encode as an unsigned integer (UInt32)
195            temp.putInteger(BigInteger.valueOf(seqNumber.longValue()));
196            v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x07), temp.toByteArray()));
197        }
198        if (authorizationData != null) {
199            v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x08), authorizationData.asn1Encode()));
200        }
201        DerValue[] der = new DerValue[v.size()];
202        v.copyInto(der);
203        temp = new DerOutputStream();
204        temp.putSequence(der);
205        DerOutputStream out = new DerOutputStream();
206        out.write(DerValue.createTag(DerValue.TAG_APPLICATION, true, (byte) 0x02), temp);
207        return out.toByteArray();
208    }
209
210    public final Checksum getChecksum() {
211        return cksum;
212    }
213
214    public final Integer getSeqNumber() {
215        return seqNumber;
216    }
217
218    public final EncryptionKey getSubKey() {
219        return subKey;
220    }
221}
222