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     public int msgType;
  69     private int pvno;
  70     public PAData[] pAData = null; //optional
  71     private boolean DEBUG = Krb5.DEBUG;
  72 
  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 
  96     public KDCRep() {
  97     }
  98 
  99     public KDCRep(byte[] data, int req_type) throws Asn1Exception,
 100             KrbApErrException, RealmException, IOException {
 101         init(new DerValue(data), req_type);
 102     }
 103 
 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      */
 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      */
 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 }