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  *
27  *  (C) Copyright IBM Corp. 1999 All Rights Reserved.
28  *  Copyright 1997 The Open Group Research Institute.  All rights reserved.
29  */
30 
31 package sun.security.krb5.internal;
32 
33 import sun.security.krb5.*;
34 import sun.security.util.*;
35 import java.io.IOException;
36 import java.math.BigInteger;
37 
38 /**
39  * Implements the ASN.1 KDC-REP type.
40  *
41  * <pre>{@code
42  * KDC-REP         ::= SEQUENCE {
43  *         pvno            [0] INTEGER (5),
44  *         msg-type        [1] INTEGER (11 -- AS -- | 13 -- TGS --),
45  *         padata          [2] SEQUENCE OF PA-DATA OPTIONAL
46  *                                   -- NOTE: not empty --,
47  *         crealm          [3] Realm,
48  *         cname           [4] PrincipalName,
49  *         ticket          [5] Ticket,
50  *         enc-part        [6] EncryptedData
51  *                                   -- EncASRepPart or EncTGSRepPart,
52  *                                   -- as appropriate
53  * }
54  * }</pre>
55  *
56  * <p>
57  * This definition reflects the Network Working Group RFC 4120
58  * specification available at
59  * <a href="http://www.ietf.org/rfc/rfc4120.txt">
60  * http://www.ietf.org/rfc/rfc4120.txt</a>.
61  */
62 public class KDCRep {
63 
64     public PrincipalName cname;
65     public Ticket ticket;
66     public EncryptedData encPart;
67     public EncKDCRepPart encKDCRepPart; //not part of ASN.1 encoding
68     private int pvno;
69     private int msgType;
70     public PAData[] pAData = null; //optional
71     private boolean DEBUG = Krb5.DEBUG;
72 
KDCRep( PAData[] new_pAData, PrincipalName new_cname, Ticket new_ticket, EncryptedData new_encPart, int req_type)73     public KDCRep(
74             PAData[] new_pAData,
75             PrincipalName new_cname,
76             Ticket new_ticket,
77             EncryptedData new_encPart,
78             int req_type) throws IOException {
79         pvno = Krb5.PVNO;
80         msgType = req_type;
81         if (new_pAData != null) {
82             pAData = new PAData[new_pAData.length];
83             for (int i = 0; i < new_pAData.length; i++) {
84                 if (new_pAData[i] == null) {
85                     throw new IOException("Cannot create a KDCRep");
86                 } else {
87                     pAData[i] = (PAData) new_pAData[i].clone();
88                 }
89             }
90         }
91         cname = new_cname;
92         ticket = new_ticket;
93         encPart = new_encPart;
94     }
95 
KDCRep()96     public KDCRep() {
97     }
98 
KDCRep(byte[] data, int req_type)99     public KDCRep(byte[] data, int req_type) throws Asn1Exception,
100             KrbApErrException, RealmException, IOException {
101         init(new DerValue(data), req_type);
102     }
103 
KDCRep(DerValue encoding, int req_type)104     public KDCRep(DerValue encoding, int req_type) throws Asn1Exception,
105             RealmException, KrbApErrException, IOException {
106         init(encoding, req_type);
107     }
108 
109     /*
110     // Not used? Don't know what keyusage to use here %%%
111     public void decrypt(EncryptionKey key) throws Asn1Exception,
112             IOException, KrbException, RealmException {
113         encKDCRepPart = new EncKDCRepPart(encPart.decrypt(key), msgType);
114     }
115      */
116     /**
117      * Initializes an KDCRep object.
118      *
119      * @param encoding a single DER-encoded value.
120      * @param req_type reply message type.
121      * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
122      * @exception IOException if an I/O error occurs while reading encoded data.
123      * @exception RealmException if an error occurs while constructing
124      * a Realm object from DER-encoded data.
125      * @exception KrbApErrException if the value read from the DER-encoded
126      * data stream does not match the pre-defined value.
127      *
128      */
init(DerValue encoding, int req_type)129     protected void init(DerValue encoding, int req_type)
130             throws Asn1Exception, RealmException, IOException,
131             KrbApErrException {
132         DerValue der, subDer;
133         if ((encoding.getTag() & 0x1F) != req_type) {
134             if (DEBUG) {
135                 System.out.println(">>> KDCRep: init() " +
136                         "encoding tag is " +
137                         encoding.getTag() +
138                         " req type is " + req_type);
139             }
140             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
141         }
142         der = encoding.getData().getDerValue();
143         if (der.getTag() != DerValue.tag_Sequence) {
144             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
145         }
146         subDer = der.getData().getDerValue();
147         if ((subDer.getTag() & 0x1F) == 0x00) {
148             pvno = subDer.getData().getBigInteger().intValue();
149             if (pvno != Krb5.PVNO) {
150                 throw new KrbApErrException(Krb5.KRB_AP_ERR_BADVERSION);
151             }
152         } else {
153             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
154         }
155         subDer = der.getData().getDerValue();
156         if ((subDer.getTag() & 0x1F) == 0x01) {
157             msgType = subDer.getData().getBigInteger().intValue();
158             if (msgType != req_type) {
159                 throw new KrbApErrException(Krb5.KRB_AP_ERR_MSG_TYPE);
160             }
161         } else {
162             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
163         }
164         if ((der.getData().peekByte() & 0x1F) == 0x02) {
165             subDer = der.getData().getDerValue();
166             DerValue[] padata = subDer.getData().getSequence(1);
167             pAData = new PAData[padata.length];
168             for (int i = 0; i < padata.length; i++) {
169                 pAData[i] = new PAData(padata[i]);
170             }
171         } else {
172             pAData = null;
173         }
174         Realm crealm = Realm.parse(der.getData(), (byte) 0x03, false);
175         cname = PrincipalName.parse(der.getData(), (byte) 0x04, false, crealm);
176         ticket = Ticket.parse(der.getData(), (byte) 0x05, false);
177         encPart = EncryptedData.parse(der.getData(), (byte) 0x06, false);
178         if (der.getData().available() > 0) {
179             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
180         }
181     }
182 
183     /**
184      * Encodes this object to a byte array.
185      * @return byte array of encoded APReq object.
186      * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
187      * @exception IOException if an I/O error occurs while reading encoded data.
188      *
189      */
asn1Encode()190     public byte[] asn1Encode() throws Asn1Exception, IOException {
191 
192         DerOutputStream bytes = new DerOutputStream();
193         DerOutputStream temp = new DerOutputStream();
194         temp.putInteger(BigInteger.valueOf(pvno));
195         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
196                 true, (byte) 0x00), temp);
197         temp = new DerOutputStream();
198         temp.putInteger(BigInteger.valueOf(msgType));
199         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
200                 true, (byte) 0x01), temp);
201         if (pAData != null && pAData.length > 0) {
202             DerOutputStream padata_stream = new DerOutputStream();
203             for (int i = 0; i < pAData.length; i++) {
204                 padata_stream.write(pAData[i].asn1Encode());
205             }
206             temp = new DerOutputStream();
207             temp.write(DerValue.tag_SequenceOf, padata_stream);
208             bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
209                     true, (byte) 0x02), temp);
210         }
211         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
212                 true, (byte) 0x03), cname.getRealm().asn1Encode());
213         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
214                 true, (byte) 0x04), cname.asn1Encode());
215         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
216                 true, (byte) 0x05), ticket.asn1Encode());
217         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
218                 true, (byte) 0x06), encPart.asn1Encode());
219         temp = new DerOutputStream();
220         temp.write(DerValue.tag_Sequence, bytes);
221         return temp.toByteArray();
222     }
223 }
224