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.util.Vector;
  36 import java.io.IOException;
  37 import java.math.BigInteger;
  38 
  39 /**
  40  * Implements the ASN.1 EncAPRepPart type.
  41  *
  42  * <xmp>
  43  * EncAPRepPart ::= [APPLICATION 27] SEQUENCE {
  44  *      ctime           [0] KerberosTime,
  45  *      cusec           [1] Microseconds,
  46  *      subkey          [2] EncryptionKey OPTIONAL,
  47  *      seq-number      [3] UInt32 OPTIONAL
  48  * }
  49  * </xmp>
  50  *
  51  * <p>
  52  * This definition reflects the Network Working Group RFC 4120
  53  * specification available at
  54  * <a href="http://www.ietf.org/rfc/rfc4120.txt">
  55  * http://www.ietf.org/rfc/rfc4120.txt</a>.
  56  */
  57 public class EncAPRepPart {
  58 
  59     public KerberosTime ctime;
  60     public int cusec;
  61     EncryptionKey subKey; //optional
  62     Integer seqNumber; //optional
  63 
  64     public EncAPRepPart(
  65             KerberosTime new_ctime,
  66             int new_cusec,
  67             EncryptionKey new_subKey,
  68             Integer new_seqNumber) {
  69         ctime = new_ctime;
  70         cusec = new_cusec;
  71         subKey = new_subKey;
  72         seqNumber = new_seqNumber;
  73     }
  74 
  75     public EncAPRepPart(byte[] data)
  76             throws Asn1Exception, IOException {
  77         init(new DerValue(data));
  78     }
  79 
  80     public EncAPRepPart(DerValue encoding)
  81             throws Asn1Exception, IOException {
  82         init(encoding);
  83     }
  84 
  85     /**
  86      * Initializes an EncaPRepPart object.
  87      * @param encoding a single DER-encoded value.
  88      * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
  89      * @exception IOException if an I/O error occurs while reading encoded data.
  90      */
  91     private void init(DerValue encoding) throws Asn1Exception, IOException {
  92         DerValue der, subDer;
  93         if (((encoding.getTag() & (byte) 0x1F) != (byte) 0x1B)
  94                 || (encoding.isApplication() != true)
  95                 || (encoding.isConstructed() != true)) {
  96             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
  97         }
  98         der = encoding.getData().getDerValue();
  99         if (der.getTag() != DerValue.tag_Sequence) {
 100             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
 101         }
 102         ctime = KerberosTime.parse(der.getData(), (byte) 0x00, true);
 103         subDer = der.getData().getDerValue();
 104         if ((subDer.getTag() & (byte) 0x1F) == (byte) 0x01) {
 105             cusec = subDer.getData().getBigInteger().intValue();
 106         } else {
 107             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
 108         }
 109         if (der.getData().available() > 0) {
 110             subKey = EncryptionKey.parse(der.getData(), (byte) 0x02, true);
 111         } else {
 112             subKey = null;
 113             seqNumber = null;
 114         }
 115         if (der.getData().available() > 0) {
 116             subDer = der.getData().getDerValue();
 117             if ((subDer.getTag() & 0x1F) != 0x03) {
 118                 throw new Asn1Exception(Krb5.ASN1_BAD_ID);
 119             }
 120             seqNumber = subDer.getData().getBigInteger().intValue();
 121         } else {
 122             seqNumber = null;
 123         }
 124         if (der.getData().available() > 0) {
 125             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
 126         }
 127     }
 128 
 129     /**
 130      * Encodes an EncAPRepPart object.
 131      * @return byte array of encoded EncAPRepPart object.
 132      * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
 133      * @exception IOException if an I/O error occurs while reading encoded data.
 134      */
 135     public byte[] asn1Encode() throws Asn1Exception, IOException {
 136         Vector<DerValue> v = new Vector<>();
 137         DerOutputStream temp = new DerOutputStream();
 138         v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,
 139                 true, (byte) 0x00), ctime.asn1Encode()));
 140         temp.putInteger(BigInteger.valueOf(cusec));
 141         v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,
 142                 true, (byte) 0x01), temp.toByteArray()));
 143         if (subKey != null) {
 144             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,
 145                     true, (byte) 0x02), subKey.asn1Encode()));
 146         }
 147         if (seqNumber != null) {
 148             temp = new DerOutputStream();
 149             // encode as an unsigned integer (UInt32)
 150             temp.putInteger(BigInteger.valueOf(seqNumber.longValue()));
 151             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,
 152                     true, (byte) 0x03), temp.toByteArray()));
 153         }
 154         DerValue[] der = new DerValue[v.size()];
 155         v.copyInto(der);
 156         temp = new DerOutputStream();
 157         temp.putSequence(der);
 158         DerOutputStream out = new DerOutputStream();
 159         out.write(DerValue.createTag(DerValue.TAG_APPLICATION,
 160                 true, (byte) 0x1B), temp);
 161         return out.toByteArray();
 162     }
 163 
 164     public final EncryptionKey getSubKey() {
 165         return subKey;
 166     }
 167 
 168     public final Integer getSeqNumber() {
 169         return seqNumber;
 170     }
 171 }