1package org.bouncycastle.asn1.x509;
2
3import java.math.BigInteger;
4import java.util.Enumeration;
5
6import org.bouncycastle.asn1.ASN1EncodableVector;
7import org.bouncycastle.asn1.ASN1Integer;
8import org.bouncycastle.asn1.ASN1Object;
9import org.bouncycastle.asn1.ASN1OctetString;
10import org.bouncycastle.asn1.ASN1Primitive;
11import org.bouncycastle.asn1.ASN1Sequence;
12import org.bouncycastle.asn1.ASN1TaggedObject;
13import org.bouncycastle.asn1.DEROctetString;
14import org.bouncycastle.asn1.DERSequence;
15import org.bouncycastle.asn1.DERTaggedObject;
16import org.bouncycastle.crypto.Digest;
17// BEGIN android-changed
18import org.bouncycastle.crypto.digests.AndroidDigestFactory;
19// END android-changed
20
21/**
22 * The AuthorityKeyIdentifier object.
23 * <pre>
24 * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }
25 *
26 *   AuthorityKeyIdentifier ::= SEQUENCE {
27 *      keyIdentifier             [0] IMPLICIT KeyIdentifier           OPTIONAL,
28 *      authorityCertIssuer       [1] IMPLICIT GeneralNames            OPTIONAL,
29 *      authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL  }
30 *
31 *   KeyIdentifier ::= OCTET STRING
32 * </pre>
33 *
34 */
35public class AuthorityKeyIdentifier
36    extends ASN1Object
37{
38    ASN1OctetString keyidentifier=null;
39    GeneralNames certissuer=null;
40    ASN1Integer certserno=null;
41
42    public static AuthorityKeyIdentifier getInstance(
43        ASN1TaggedObject obj,
44        boolean          explicit)
45    {
46        return getInstance(ASN1Sequence.getInstance(obj, explicit));
47    }
48
49    public static AuthorityKeyIdentifier getInstance(
50        Object  obj)
51    {
52        if (obj instanceof AuthorityKeyIdentifier)
53        {
54            return (AuthorityKeyIdentifier)obj;
55        }
56        if (obj != null)
57        {
58            return new AuthorityKeyIdentifier(ASN1Sequence.getInstance(obj));
59        }
60
61        return null;
62    }
63
64    public static AuthorityKeyIdentifier fromExtensions(Extensions extensions)
65    {
66         return AuthorityKeyIdentifier.getInstance(extensions.getExtensionParsedValue(Extension.authorityKeyIdentifier));
67    }
68
69    protected AuthorityKeyIdentifier(
70        ASN1Sequence   seq)
71    {
72        Enumeration     e = seq.getObjects();
73
74        while (e.hasMoreElements())
75        {
76            ASN1TaggedObject o = DERTaggedObject.getInstance(e.nextElement());
77
78            switch (o.getTagNo())
79            {
80            case 0:
81                this.keyidentifier = ASN1OctetString.getInstance(o, false);
82                break;
83            case 1:
84                this.certissuer = GeneralNames.getInstance(o, false);
85                break;
86            case 2:
87                this.certserno = ASN1Integer.getInstance(o, false);
88                break;
89            default:
90                throw new IllegalArgumentException("illegal tag");
91            }
92        }
93    }
94
95    /**
96     *
97     * Calulates the keyidentifier using a SHA1 hash over the BIT STRING
98     * from SubjectPublicKeyInfo as defined in RFC2459.
99     *
100     * Example of making a AuthorityKeyIdentifier:
101     * <pre>
102     *   SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
103     *       publicKey.getEncoded()).readObject());
104     *   AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki);
105     * </pre>
106     * @deprecated create the extension using org.bouncycastle.cert.X509ExtensionUtils
107     **/
108    public AuthorityKeyIdentifier(
109        SubjectPublicKeyInfo    spki)
110    {
111        // BEGIN android-changed
112        Digest  digest = AndroidDigestFactory.getSHA1();
113        // END android-changed
114        byte[]  resBuf = new byte[digest.getDigestSize()];
115
116        byte[] bytes = spki.getPublicKeyData().getBytes();
117        digest.update(bytes, 0, bytes.length);
118        digest.doFinal(resBuf, 0);
119        this.keyidentifier = new DEROctetString(resBuf);
120    }
121
122    /**
123     * create an AuthorityKeyIdentifier with the GeneralNames tag and
124     * the serial number provided as well.
125     * @deprecated create the extension using org.bouncycastle.cert.X509ExtensionUtils
126     */
127    public AuthorityKeyIdentifier(
128        SubjectPublicKeyInfo    spki,
129        GeneralNames            name,
130        BigInteger              serialNumber)
131    {
132        // BEGIN android-changed
133        Digest  digest = AndroidDigestFactory.getSHA1();
134        // END android-changed
135        byte[]  resBuf = new byte[digest.getDigestSize()];
136
137        byte[] bytes = spki.getPublicKeyData().getBytes();
138        digest.update(bytes, 0, bytes.length);
139        digest.doFinal(resBuf, 0);
140
141        this.keyidentifier = new DEROctetString(resBuf);
142        this.certissuer = GeneralNames.getInstance(name.toASN1Primitive());
143        this.certserno = new ASN1Integer(serialNumber);
144    }
145
146    /**
147     * create an AuthorityKeyIdentifier with the GeneralNames tag and
148     * the serial number provided.
149     */
150    public AuthorityKeyIdentifier(
151        GeneralNames            name,
152        BigInteger              serialNumber)
153    {
154        this((byte[])null, name, serialNumber);
155    }
156
157    /**
158      * create an AuthorityKeyIdentifier with a precomputed key identifier
159      */
160     public AuthorityKeyIdentifier(
161         byte[]                  keyIdentifier)
162     {
163         this(keyIdentifier, null, null);
164     }
165
166    /**
167     * create an AuthorityKeyIdentifier with a precomputed key identifier
168     * and the GeneralNames tag and the serial number provided as well.
169     */
170    public AuthorityKeyIdentifier(
171        byte[]                  keyIdentifier,
172        GeneralNames            name,
173        BigInteger              serialNumber)
174    {
175        this.keyidentifier = (keyIdentifier != null) ? new DEROctetString(keyIdentifier) : null;
176        this.certissuer = name;
177        this.certserno = (serialNumber != null) ? new ASN1Integer(serialNumber) : null;
178    }
179
180    public byte[] getKeyIdentifier()
181    {
182        if (keyidentifier != null)
183        {
184            return keyidentifier.getOctets();
185        }
186
187        return null;
188    }
189
190    public GeneralNames getAuthorityCertIssuer()
191    {
192        return certissuer;
193    }
194
195    public BigInteger getAuthorityCertSerialNumber()
196    {
197        if (certserno != null)
198        {
199            return certserno.getValue();
200        }
201
202        return null;
203    }
204
205    /**
206     * Produce an object suitable for an ASN1OutputStream.
207     */
208    public ASN1Primitive toASN1Primitive()
209    {
210        ASN1EncodableVector  v = new ASN1EncodableVector();
211
212        if (keyidentifier != null)
213        {
214            v.add(new DERTaggedObject(false, 0, keyidentifier));
215        }
216
217        if (certissuer != null)
218        {
219            v.add(new DERTaggedObject(false, 1, certissuer));
220        }
221
222        if (certserno != null)
223        {
224            v.add(new DERTaggedObject(false, 2, certserno));
225        }
226
227
228        return new DERSequence(v);
229    }
230
231    public String toString()
232    {
233        return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.getOctets() + ")");
234    }
235}
236