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 java.util.Vector;
35 import sun.security.util.*;
36 import java.io.IOException;
37 import java.math.BigInteger;
38 
39 /**
40  * Implements the ASN.1 KRB_KDC_REQ type.
41  *
42  * <pre>{@code
43  * KDC-REQ              ::= SEQUENCE {
44  *      -- NOTE: first tag is [1], not [0]
45  *      pvno            [1] INTEGER (5) ,
46  *      msg-type        [2] INTEGER (10 -- AS -- | 12 -- TGS --),
47  *      padata          [3] SEQUENCE OF PA-DATA OPTIONAL
48  *                            -- NOTE: not empty --,
49  *      req-body        [4] KDC-REQ-BODY
50  * }
51  * }</pre>
52  *
53  * <p>
54  * This definition reflects the Network Working Group RFC 4120
55  * specification available at
56  * <a href="http://www.ietf.org/rfc/rfc4120.txt">
57  * http://www.ietf.org/rfc/rfc4120.txt</a>.
58  */
59 public class KDCReq {
60 
61     public KDCReqBody reqBody;
62     private int pvno;
63     private int msgType;
64     private PAData[] pAData = null; //optional
65 
KDCReq(PAData[] new_pAData, KDCReqBody new_reqBody, int req_type)66     public KDCReq(PAData[] new_pAData, KDCReqBody new_reqBody,
67             int req_type) throws IOException {
68         pvno = Krb5.PVNO;
69         msgType = req_type;
70         if (new_pAData != null) {
71             pAData = new PAData[new_pAData.length];
72             for (int i = 0; i < new_pAData.length; i++) {
73                 if (new_pAData[i] == null) {
74                     throw new IOException("Cannot create a KDCRep");
75                 } else {
76                     pAData[i] = (PAData) new_pAData[i].clone();
77                 }
78             }
79         }
80         reqBody = new_reqBody;
81     }
82 
KDCReq()83     public KDCReq() {
84     }
85 
KDCReq(byte[] data, int req_type)86     public KDCReq(byte[] data, int req_type) throws Asn1Exception,
87             IOException, KrbException {
88         init(new DerValue(data), req_type);
89     }
90 
91     /**
92      * Creates an KDCReq object from a DerValue object and asn1 type.
93      *
94      * @param der a DER value of an KDCReq object.
95      * @param req_type a encoded asn1 type value.
96      * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
97      * @exception IOException if an I/O error occurs while reading encoded data.
98      * @exception KrbErrException
99      */
KDCReq(DerValue der, int req_type)100     public KDCReq(DerValue der, int req_type) throws Asn1Exception,
101             IOException, KrbException {
102         init(der, req_type);
103     }
104 
105     /**
106      * Initializes a KDCReq object from a DerValue.  The DER encoding
107      * must be in the format specified by the KRB_KDC_REQ ASN.1 notation.
108      *
109      * @param encoding a DER-encoded KDCReq object.
110      * @param req_type an int indicating whether it's KRB_AS_REQ or KRB_TGS_REQ type
111      * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
112      * @exception IOException if an I/O error occurs while reading encoded data.
113      * @exception KrbException if an error occurs while constructing a Realm object,
114      * or a Krb object from DER-encoded data.
115      */
init(DerValue encoding, int req_type)116     protected void init(DerValue encoding, int req_type) throws Asn1Exception,
117             IOException, KrbException {
118         DerValue der, subDer;
119         BigInteger bint;
120         if ((encoding.getTag() & 0x1F) != req_type) {
121             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
122         }
123         der = encoding.getData().getDerValue();
124         if (der.getTag() != DerValue.tag_Sequence) {
125             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
126         }
127         subDer = der.getData().getDerValue();
128         if ((subDer.getTag() & 0x01F) == 0x01) {
129             bint = subDer.getData().getBigInteger();
130             this.pvno = bint.intValue();
131             if (this.pvno != Krb5.PVNO) {
132                 throw new KrbApErrException(Krb5.KRB_AP_ERR_BADVERSION);
133             }
134         } else {
135             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
136         }
137         subDer = der.getData().getDerValue();
138         if ((subDer.getTag() & 0x01F) == 0x02) {
139             bint = subDer.getData().getBigInteger();
140             this.msgType = bint.intValue();
141             if (this.msgType != req_type) {
142                 throw new KrbApErrException(Krb5.KRB_AP_ERR_MSG_TYPE);
143             }
144         } else {
145             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
146         }
147         if ((der.getData().peekByte() & 0x1F) == 0x03) {
148             subDer = der.getData().getDerValue();
149             DerValue subsubDer = subDer.getData().getDerValue();
150             if (subsubDer.getTag() != DerValue.tag_SequenceOf) {
151                 throw new Asn1Exception(Krb5.ASN1_BAD_ID);
152             }
153             Vector<PAData> v = new Vector<>();
154             while (subsubDer.getData().available() > 0) {
155                 v.addElement(new PAData(subsubDer.getData().getDerValue()));
156             }
157             if (v.size() > 0) {
158                 pAData = new PAData[v.size()];
159                 v.copyInto(pAData);
160             }
161         } else {
162             pAData = null;
163         }
164         subDer = der.getData().getDerValue();
165         if ((subDer.getTag() & 0x01F) == 0x04) {
166             DerValue subsubDer = subDer.getData().getDerValue();
167             reqBody = new KDCReqBody(subsubDer, msgType);
168         } else {
169             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
170         }
171     }
172 
173     /**
174      * Encodes this object to a byte array.
175      *
176      * @return an byte array of encoded data.
177      * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
178      * @exception IOException if an I/O error occurs while reading encoded data.
179      *
180      */
asn1Encode()181     public byte[] asn1Encode() throws Asn1Exception, IOException {
182         DerOutputStream temp, bytes, out;
183         temp = new DerOutputStream();
184         temp.putInteger(BigInteger.valueOf(pvno));
185         out = new DerOutputStream();
186         out.write(DerValue.createTag(DerValue.TAG_CONTEXT,
187                 true, (byte) 0x01), temp);
188         temp = new DerOutputStream();
189         temp.putInteger(BigInteger.valueOf(msgType));
190         out.write(DerValue.createTag(DerValue.TAG_CONTEXT,
191                 true, (byte) 0x02), temp);
192         if (pAData != null && pAData.length > 0) {
193             temp = new DerOutputStream();
194             for (int i = 0; i < pAData.length; i++) {
195                 temp.write(pAData[i].asn1Encode());
196             }
197             bytes = new DerOutputStream();
198             bytes.write(DerValue.tag_SequenceOf, temp);
199             out.write(DerValue.createTag(DerValue.TAG_CONTEXT,
200                     true, (byte) 0x03), bytes);
201         }
202         out.write(DerValue.createTag(DerValue.TAG_CONTEXT,
203                 true, (byte) 0x04), reqBody.asn1Encode(msgType));
204         bytes = new DerOutputStream();
205         bytes.write(DerValue.tag_Sequence, out);
206         out = new DerOutputStream();
207         out.write(DerValue.createTag(DerValue.TAG_APPLICATION,
208                 true, (byte) msgType), bytes);
209         return out.toByteArray();
210     }
211 
asn1EncodeReqBody()212     public byte[] asn1EncodeReqBody() throws Asn1Exception, IOException {
213         return reqBody.asn1Encode(msgType);
214     }
215 }
216