1/*
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.security.pkcs;
27
28import java.io.IOException;
29import java.io.OutputStream;
30import java.security.cert.CertificateException;
31import java.util.Locale;
32import java.util.Date;
33import java.util.Hashtable;
34import sun.security.x509.CertificateExtensions;
35import sun.security.util.Debug;
36import sun.security.util.DerEncoder;
37import sun.security.util.DerValue;
38import sun.security.util.DerInputStream;
39import sun.security.util.DerOutputStream;
40import sun.security.util.ObjectIdentifier;
41import sun.security.util.HexDumpEncoder;
42
43/**
44 * Class supporting any PKCS9 attributes.
45 * Supports DER decoding/encoding and access to attribute values.
46 *
47 * <a name="classTable"><h3>Type/Class Table</h3></a>
48 * The following table shows the correspondence between
49 * PKCS9 attribute types and value component classes.
50 * For types not listed here, its name is the OID
51 * in string form, its value is a (single-valued)
52 * byte array that is the SET's encoding.
53 *
54 * <TABLE BORDER CELLPADDING=8 ALIGN=CENTER>
55 *
56 * <TR>
57 * <TH>Object Identifier</TH>
58 * <TH>Attribute Name</TH>
59 * <TH>Type</TH>
60 * <TH>Value Class</TH>
61 * </TR>
62 *
63 * <TR>
64 * <TD>1.2.840.113549.1.9.1</TD>
65 * <TD>EmailAddress</TD>
66 * <TD>Multi-valued</TD>
67 * <TD><code>String[]</code></TD>
68 * </TR>
69 *
70 * <TR>
71 * <TD>1.2.840.113549.1.9.2</TD>
72 * <TD>UnstructuredName</TD>
73 * <TD>Multi-valued</TD>
74 * <TD><code>String[]</code></TD>
75 * </TR>
76 *
77 * <TR>
78 * <TD>1.2.840.113549.1.9.3</TD>
79 * <TD>ContentType</TD>
80 * <TD>Single-valued</TD>
81 * <TD><code>ObjectIdentifier</code></TD>
82 * </TR>
83 *
84 * <TR>
85 * <TD>1.2.840.113549.1.9.4</TD>
86 * <TD>MessageDigest</TD>
87 * <TD>Single-valued</TD>
88 * <TD><code>byte[]</code></TD>
89 * </TR>
90 *
91 * <TR>
92 * <TD>1.2.840.113549.1.9.5</TD>
93 * <TD>SigningTime</TD>
94 * <TD>Single-valued</TD>
95 * <TD><code>Date</code></TD>
96 * </TR>
97 *
98 * <TR>
99 * <TD>1.2.840.113549.1.9.6</TD>
100 * <TD>Countersignature</TD>
101 * <TD>Multi-valued</TD>
102 * <TD><code>SignerInfo[]</code></TD>
103 * </TR>
104 *
105 * <TR>
106 * <TD>1.2.840.113549.1.9.7</TD>
107 * <TD>ChallengePassword</TD>
108 * <TD>Single-valued</TD>
109 * <TD><code>String</code></TD>
110 * </TR>
111 *
112 * <TR>
113 * <TD>1.2.840.113549.1.9.8</TD>
114 * <TD>UnstructuredAddress</TD>
115 * <TD>Single-valued</TD>
116 * <TD><code>String</code></TD>
117 * </TR>
118 *
119 * <TR>
120 * <TD>1.2.840.113549.1.9.9</TD>
121 * <TD>ExtendedCertificateAttributes</TD>
122 * <TD>Multi-valued</TD>
123 * <TD>(not supported)</TD>
124 * </TR>
125 *
126 * <TR>
127 * <TD>1.2.840.113549.1.9.10</TD>
128 * <TD>IssuerAndSerialNumber</TD>
129 * <TD>Single-valued</TD>
130 * <TD>(not supported)</TD>
131 * </TR>
132 *
133 * <TR>
134 * <TD>1.2.840.113549.1.9.{11,12}</TD>
135 * <TD>RSA DSI proprietary</TD>
136 * <TD>Single-valued</TD>
137 * <TD>(not supported)</TD>
138 * </TR>
139 *
140 * <TR>
141 * <TD>1.2.840.113549.1.9.13</TD>
142 * <TD>S/MIME unused assignment</TD>
143 * <TD>Single-valued</TD>
144 * <TD>(not supported)</TD>
145 * </TR>
146 *
147 * <TR>
148 * <TD>1.2.840.113549.1.9.14</TD>
149 * <TD>ExtensionRequest</TD>
150 * <TD>Single-valued</TD>
151 * <TD>CertificateExtensions</TD>
152 * </TR>
153 *
154 * <TR>
155 * <TD>1.2.840.113549.1.9.15</TD>
156 * <TD>SMIMECapability</TD>
157 * <TD>Single-valued</TD>
158 * <TD>(not supported)</TD>
159 * </TR>
160 *
161 * <TR>
162 * <TD>1.2.840.113549.1.9.16.2.12</TD>
163 * <TD>SigningCertificate</TD>
164 * <TD>Single-valued</TD>
165 * <TD>SigningCertificateInfo</TD>
166 * </TR>
167 *
168 * <TR>
169 * <TD>1.2.840.113549.1.9.16.2.14</TD>
170 * <TD>SignatureTimestampToken</TD>
171 * <TD>Single-valued</TD>
172 * <TD>byte[]</TD>
173 * </TR>
174 *
175 * </TABLE>
176 *
177 * @author Douglas Hoover
178 */
179public class PKCS9Attribute implements DerEncoder {
180
181    /* Are we debugging ? */
182    private static final Debug debug = Debug.getInstance("jar");
183
184    /**
185     * Array of attribute OIDs defined in PKCS9, by number.
186     */
187    static final ObjectIdentifier[] PKCS9_OIDS = new ObjectIdentifier[18];
188
189    private static final Class<?> BYTE_ARRAY_CLASS;
190
191    static {   // static initializer for PKCS9_OIDS
192        for (int i = 1; i < PKCS9_OIDS.length - 2; i++) {
193            PKCS9_OIDS[i] =
194                ObjectIdentifier.newInternal(new int[]{1,2,840,113549,1,9,i});
195        }
196        // Initialize SigningCertificate and SignatureTimestampToken
197        // separately (because their values are out of sequence)
198        PKCS9_OIDS[PKCS9_OIDS.length - 2] =
199            ObjectIdentifier.newInternal(new int[]{1,2,840,113549,1,9,16,2,12});
200        PKCS9_OIDS[PKCS9_OIDS.length - 1] =
201            ObjectIdentifier.newInternal(new int[]{1,2,840,113549,1,9,16,2,14});
202
203        try {
204            BYTE_ARRAY_CLASS = Class.forName("[B");
205        } catch (ClassNotFoundException e) {
206            throw new ExceptionInInitializerError(e.toString());
207        }
208    }
209
210    // first element [0] not used
211    public static final ObjectIdentifier EMAIL_ADDRESS_OID = PKCS9_OIDS[1];
212    public static final ObjectIdentifier UNSTRUCTURED_NAME_OID = PKCS9_OIDS[2];
213    public static final ObjectIdentifier CONTENT_TYPE_OID = PKCS9_OIDS[3];
214    public static final ObjectIdentifier MESSAGE_DIGEST_OID = PKCS9_OIDS[4];
215    public static final ObjectIdentifier SIGNING_TIME_OID = PKCS9_OIDS[5];
216    public static final ObjectIdentifier COUNTERSIGNATURE_OID = PKCS9_OIDS[6];
217    public static final ObjectIdentifier CHALLENGE_PASSWORD_OID = PKCS9_OIDS[7];
218    public static final ObjectIdentifier UNSTRUCTURED_ADDRESS_OID = PKCS9_OIDS[8];
219    public static final ObjectIdentifier EXTENDED_CERTIFICATE_ATTRIBUTES_OID
220                                         = PKCS9_OIDS[9];
221    public static final ObjectIdentifier ISSUER_SERIALNUMBER_OID = PKCS9_OIDS[10];
222    // [11], [12] are RSA DSI proprietary
223    // [13] ==> signingDescription, S/MIME, not used anymore
224    public static final ObjectIdentifier EXTENSION_REQUEST_OID = PKCS9_OIDS[14];
225    public static final ObjectIdentifier SMIME_CAPABILITY_OID = PKCS9_OIDS[15];
226    public static final ObjectIdentifier SIGNING_CERTIFICATE_OID = PKCS9_OIDS[16];
227    public static final ObjectIdentifier SIGNATURE_TIMESTAMP_TOKEN_OID =
228                                PKCS9_OIDS[17];
229    public static final String EMAIL_ADDRESS_STR = "EmailAddress";
230    public static final String UNSTRUCTURED_NAME_STR = "UnstructuredName";
231    public static final String CONTENT_TYPE_STR = "ContentType";
232    public static final String MESSAGE_DIGEST_STR = "MessageDigest";
233    public static final String SIGNING_TIME_STR = "SigningTime";
234    public static final String COUNTERSIGNATURE_STR = "Countersignature";
235    public static final String CHALLENGE_PASSWORD_STR = "ChallengePassword";
236    public static final String UNSTRUCTURED_ADDRESS_STR = "UnstructuredAddress";
237    public static final String EXTENDED_CERTIFICATE_ATTRIBUTES_STR =
238                               "ExtendedCertificateAttributes";
239    public static final String ISSUER_SERIALNUMBER_STR = "IssuerAndSerialNumber";
240    // [11], [12] are RSA DSI proprietary
241    private static final String RSA_PROPRIETARY_STR = "RSAProprietary";
242    // [13] ==> signingDescription, S/MIME, not used anymore
243    private static final String SMIME_SIGNING_DESC_STR = "SMIMESigningDesc";
244    public static final String EXTENSION_REQUEST_STR = "ExtensionRequest";
245    public static final String SMIME_CAPABILITY_STR = "SMIMECapability";
246    public static final String SIGNING_CERTIFICATE_STR = "SigningCertificate";
247    public static final String SIGNATURE_TIMESTAMP_TOKEN_STR =
248                                "SignatureTimestampToken";
249
250    /**
251     * Hashtable mapping names and variant names of supported
252     * attributes to their OIDs. This table contains all name forms
253     * that occur in PKCS9, in lower case.
254     */
255    private static final Hashtable<String, ObjectIdentifier> NAME_OID_TABLE =
256        new Hashtable<String, ObjectIdentifier>(18);
257
258    static { // static initializer for PCKS9_NAMES
259        NAME_OID_TABLE.put("emailaddress", PKCS9_OIDS[1]);
260        NAME_OID_TABLE.put("unstructuredname", PKCS9_OIDS[2]);
261        NAME_OID_TABLE.put("contenttype", PKCS9_OIDS[3]);
262        NAME_OID_TABLE.put("messagedigest", PKCS9_OIDS[4]);
263        NAME_OID_TABLE.put("signingtime", PKCS9_OIDS[5]);
264        NAME_OID_TABLE.put("countersignature", PKCS9_OIDS[6]);
265        NAME_OID_TABLE.put("challengepassword", PKCS9_OIDS[7]);
266        NAME_OID_TABLE.put("unstructuredaddress", PKCS9_OIDS[8]);
267        NAME_OID_TABLE.put("extendedcertificateattributes", PKCS9_OIDS[9]);
268        NAME_OID_TABLE.put("issuerandserialnumber", PKCS9_OIDS[10]);
269        NAME_OID_TABLE.put("rsaproprietary", PKCS9_OIDS[11]);
270        NAME_OID_TABLE.put("rsaproprietary", PKCS9_OIDS[12]);
271        NAME_OID_TABLE.put("signingdescription", PKCS9_OIDS[13]);
272        NAME_OID_TABLE.put("extensionrequest", PKCS9_OIDS[14]);
273        NAME_OID_TABLE.put("smimecapability", PKCS9_OIDS[15]);
274        NAME_OID_TABLE.put("signingcertificate", PKCS9_OIDS[16]);
275        NAME_OID_TABLE.put("signaturetimestamptoken", PKCS9_OIDS[17]);
276    };
277
278    /**
279     * Hashtable mapping attribute OIDs defined in PKCS9 to the
280     * corresponding attribute value type.
281     */
282    private static final Hashtable<ObjectIdentifier, String> OID_NAME_TABLE =
283        new Hashtable<ObjectIdentifier, String>(16);
284    static {
285        OID_NAME_TABLE.put(PKCS9_OIDS[1], EMAIL_ADDRESS_STR);
286        OID_NAME_TABLE.put(PKCS9_OIDS[2], UNSTRUCTURED_NAME_STR);
287        OID_NAME_TABLE.put(PKCS9_OIDS[3], CONTENT_TYPE_STR);
288        OID_NAME_TABLE.put(PKCS9_OIDS[4], MESSAGE_DIGEST_STR);
289        OID_NAME_TABLE.put(PKCS9_OIDS[5], SIGNING_TIME_STR);
290        OID_NAME_TABLE.put(PKCS9_OIDS[6], COUNTERSIGNATURE_STR);
291        OID_NAME_TABLE.put(PKCS9_OIDS[7], CHALLENGE_PASSWORD_STR);
292        OID_NAME_TABLE.put(PKCS9_OIDS[8], UNSTRUCTURED_ADDRESS_STR);
293        OID_NAME_TABLE.put(PKCS9_OIDS[9], EXTENDED_CERTIFICATE_ATTRIBUTES_STR);
294        OID_NAME_TABLE.put(PKCS9_OIDS[10], ISSUER_SERIALNUMBER_STR);
295        OID_NAME_TABLE.put(PKCS9_OIDS[11], RSA_PROPRIETARY_STR);
296        OID_NAME_TABLE.put(PKCS9_OIDS[12], RSA_PROPRIETARY_STR);
297        OID_NAME_TABLE.put(PKCS9_OIDS[13], SMIME_SIGNING_DESC_STR);
298        OID_NAME_TABLE.put(PKCS9_OIDS[14], EXTENSION_REQUEST_STR);
299        OID_NAME_TABLE.put(PKCS9_OIDS[15], SMIME_CAPABILITY_STR);
300        OID_NAME_TABLE.put(PKCS9_OIDS[16], SIGNING_CERTIFICATE_STR);
301        OID_NAME_TABLE.put(PKCS9_OIDS[17], SIGNATURE_TIMESTAMP_TOKEN_STR);
302    }
303
304    /**
305     * Acceptable ASN.1 tags for DER encodings of values of PKCS9
306     * attributes, by index in <code>PKCS9_OIDS</code>.
307     * Sets of acceptable tags are represented as arrays.
308     */
309    private static final Byte[][] PKCS9_VALUE_TAGS = {
310        null,
311        {DerValue.tag_IA5String},   // EMailAddress
312        {DerValue.tag_IA5String,   // UnstructuredName
313         DerValue.tag_PrintableString},
314        {DerValue.tag_ObjectId},    // ContentType
315        {DerValue.tag_OctetString}, // MessageDigest
316        {DerValue.tag_UtcTime},     // SigningTime
317        {DerValue.tag_Sequence},    // Countersignature
318        {DerValue.tag_PrintableString,
319         DerValue.tag_T61String},   // ChallengePassword
320        {DerValue.tag_PrintableString,
321         DerValue.tag_T61String},   // UnstructuredAddress
322        {DerValue.tag_SetOf},       // ExtendedCertificateAttributes
323        {DerValue.tag_Sequence},    // issuerAndSerialNumber
324        null,
325        null,
326        null,
327        {DerValue.tag_Sequence},    // extensionRequest
328        {DerValue.tag_Sequence},    // SMIMECapability
329        {DerValue.tag_Sequence},    // SigningCertificate
330        {DerValue.tag_Sequence}     // SignatureTimestampToken
331    };
332
333    private static final Class<?>[] VALUE_CLASSES = new Class<?>[18];
334
335    static {
336        try {
337            Class<?> str = Class.forName("[Ljava.lang.String;");
338
339            VALUE_CLASSES[0] = null;  // not used
340            VALUE_CLASSES[1] = str;   // EMailAddress
341            VALUE_CLASSES[2] = str;   // UnstructuredName
342            VALUE_CLASSES[3] =        // ContentType
343                Class.forName("sun.security.util.ObjectIdentifier");
344            VALUE_CLASSES[4] = BYTE_ARRAY_CLASS; // MessageDigest (byte[])
345            VALUE_CLASSES[5] = Class.forName("java.util.Date"); // SigningTime
346            VALUE_CLASSES[6] =        // Countersignature
347                Class.forName("[Lsun.security.pkcs.SignerInfo;");
348            VALUE_CLASSES[7] =        // ChallengePassword
349                Class.forName("java.lang.String");
350            VALUE_CLASSES[8] = str;   // UnstructuredAddress
351            VALUE_CLASSES[9] = null;  // ExtendedCertificateAttributes
352            VALUE_CLASSES[10] = null;  // IssuerAndSerialNumber
353            VALUE_CLASSES[11] = null;  // not used
354            VALUE_CLASSES[12] = null;  // not used
355            VALUE_CLASSES[13] = null;  // not used
356            VALUE_CLASSES[14] =        // ExtensionRequest
357                Class.forName("sun.security.x509.CertificateExtensions");
358            VALUE_CLASSES[15] = null;  // not supported yet
359            VALUE_CLASSES[16] = null;  // not supported yet
360            VALUE_CLASSES[17] = BYTE_ARRAY_CLASS;  // SignatureTimestampToken
361        } catch (ClassNotFoundException e) {
362            throw new ExceptionInInitializerError(e.toString());
363        }
364    }
365
366    /**
367     * Array indicating which PKCS9 attributes are single-valued,
368     * by index in <code>PKCS9_OIDS</code>.
369     */
370    private static final boolean[] SINGLE_VALUED = {
371      false,
372      false,   // EMailAddress
373      false,   // UnstructuredName
374      true,    // ContentType
375      true,    // MessageDigest
376      true,    // SigningTime
377      false,   // Countersignature
378      true,    // ChallengePassword
379      false,   // UnstructuredAddress
380      false,   // ExtendedCertificateAttributes
381      true,    // IssuerAndSerialNumber - not supported yet
382      false,   // not used
383      false,   // not used
384      false,   // not used
385      true,    // ExtensionRequest
386      true,    // SMIMECapability - not supported yet
387      true,    // SigningCertificate
388      true     // SignatureTimestampToken
389    };
390
391    /**
392     * The OID of this attribute.
393     */
394    private ObjectIdentifier oid;
395
396    /**
397     * The index of the OID of this attribute in <code>PKCS9_OIDS</code>,
398     * or -1 if it's unknown.
399     */
400    private int index;
401
402    /**
403     * Value set of this attribute.  Its class is given by
404     * <code>VALUE_CLASSES[index]</code>. The SET itself
405     * as byte[] if unknown.
406     */
407    private Object value;
408
409    /**
410     * Construct an attribute object from the attribute's OID and
411     * value.  If the attribute is single-valued, provide only one
412     * value.  If the attribute is multi-valued, provide an array
413     * containing all the values.
414     * Arrays of length zero are accepted, though probably useless.
415     *
416     * <P> The
417     * <a href=#classTable>table</a> gives the class that <code>value</code>
418     * must have for a given attribute.
419     *
420     * @exception IllegalArgumentException
421     * if the <code>value</code> has the wrong type.
422     */
423    public PKCS9Attribute(ObjectIdentifier oid, Object value)
424    throws IllegalArgumentException {
425        init(oid, value);
426    }
427
428    /**
429     * Construct an attribute object from the attribute's name and
430     * value.  If the attribute is single-valued, provide only one
431     * value.  If the attribute is multi-valued, provide an array
432     * containing all the values.
433     * Arrays of length zero are accepted, though probably useless.
434     *
435     * <P> The
436     * <a href=#classTable>table</a> gives the class that <code>value</code>
437     * must have for a given attribute. Reasonable variants of these
438     * attributes are accepted; in particular, case does not matter.
439     *
440     * @exception IllegalArgumentException
441     * if the <code>name</code> is not recognized or the
442     * <code>value</code> has the wrong type.
443     */
444    public PKCS9Attribute(String name, Object value)
445    throws IllegalArgumentException {
446        ObjectIdentifier oid = getOID(name);
447
448        if (oid == null)
449            throw new IllegalArgumentException(
450                       "Unrecognized attribute name " + name +
451                       " constructing PKCS9Attribute.");
452
453        init(oid, value);
454    }
455
456    private void init(ObjectIdentifier oid, Object value)
457        throws IllegalArgumentException {
458
459        this.oid = oid;
460        index = indexOf(oid, PKCS9_OIDS, 1);
461        Class<?> clazz = index == -1 ? BYTE_ARRAY_CLASS: VALUE_CLASSES[index];
462        if (!clazz.isInstance(value)) {
463                throw new IllegalArgumentException(
464                           "Wrong value class " +
465                           " for attribute " + oid +
466                           " constructing PKCS9Attribute; was " +
467                           value.getClass().toString() + ", should be " +
468                           clazz.toString());
469        }
470        this.value = value;
471    }
472
473
474    /**
475     * Construct a PKCS9Attribute from its encoding on an input
476     * stream.
477     *
478     * @param derVal the DerValue representing the DER encoding of the attribute.
479     * @exception IOException on parsing error.
480     */
481    public PKCS9Attribute(DerValue derVal) throws IOException {
482
483        DerInputStream derIn = new DerInputStream(derVal.toByteArray());
484        DerValue[] val =  derIn.getSequence(2);
485
486        if (derIn.available() != 0)
487            throw new IOException("Excess data parsing PKCS9Attribute");
488
489        if (val.length != 2)
490            throw new IOException("PKCS9Attribute doesn't have two components");
491
492        // get the oid
493        oid = val[0].getOID();
494        byte[] content = val[1].toByteArray();
495        DerValue[] elems = new DerInputStream(content).getSet(1);
496
497        index = indexOf(oid, PKCS9_OIDS, 1);
498        if (index == -1) {
499            if (debug != null) {
500                debug.println("Unsupported signer attribute: " + oid);
501            }
502            value = content;
503            return;
504        }
505
506        // check single valued have only one value
507        if (SINGLE_VALUED[index] && elems.length > 1)
508            throwSingleValuedException();
509
510        // check for illegal element tags
511        Byte tag;
512        for (int i=0; i < elems.length; i++) {
513            tag = elems[i].tag;
514
515            if (indexOf(tag, PKCS9_VALUE_TAGS[index], 0) == -1)
516                throwTagException(tag);
517        }
518
519        switch (index) {
520        case 1:     // email address
521        case 2:     // unstructured name
522        case 8:     // unstructured address
523            { // open scope
524                String[] values = new String[elems.length];
525
526                for (int i=0; i < elems.length; i++)
527                    values[i] = elems[i].getAsString();
528                value = values;
529            } // close scope
530            break;
531
532        case 3:     // content type
533            value = elems[0].getOID();
534            break;
535
536        case 4:     // message digest
537            value = elems[0].getOctetString();
538            break;
539
540        case 5:     // signing time
541            value = (new DerInputStream(elems[0].toByteArray())).getUTCTime();
542            break;
543
544        case 6:     // countersignature
545            { // open scope
546                SignerInfo[] values = new SignerInfo[elems.length];
547                for (int i=0; i < elems.length; i++)
548                    values[i] =
549                        new SignerInfo(elems[i].toDerInputStream());
550                value = values;
551            } // close scope
552            break;
553
554        case 7:     // challenge password
555            value = elems[0].getAsString();
556            break;
557
558        case 9:     // extended-certificate attribute -- not supported
559            throw new IOException("PKCS9 extended-certificate " +
560                                  "attribute not supported.");
561            // break unnecessary
562        case 10:    // issuerAndserialNumber attribute -- not supported
563            throw new IOException("PKCS9 IssuerAndSerialNumber" +
564                                  "attribute not supported.");
565            // break unnecessary
566        case 11:    // RSA DSI proprietary
567        case 12:    // RSA DSI proprietary
568            throw new IOException("PKCS9 RSA DSI attributes" +
569                                  "11 and 12, not supported.");
570            // break unnecessary
571        case 13:    // S/MIME unused attribute
572            throw new IOException("PKCS9 attribute #13 not supported.");
573            // break unnecessary
574
575        case 14:     // ExtensionRequest
576            value = new CertificateExtensions(
577                       new DerInputStream(elems[0].toByteArray()));
578            break;
579
580        case 15:     // SMIME-capability attribute -- not supported
581            throw new IOException("PKCS9 SMIMECapability " +
582                                  "attribute not supported.");
583            // break unnecessary
584        case 16:     // SigningCertificate attribute
585            value = new SigningCertificateInfo(elems[0].toByteArray());
586            break;
587
588        case 17:     // SignatureTimestampToken attribute
589            value = elems[0].toByteArray();
590            break;
591        default: // can't happen
592        }
593    }
594
595    /**
596     * Write the DER encoding of this attribute to an output stream.
597     *
598     * <P> N.B.: This method always encodes values of
599     * ChallengePassword and UnstructuredAddress attributes as ASN.1
600     * <code>PrintableString</code>s, without checking whether they
601     * should be encoded as <code>T61String</code>s.
602     */
603    public void derEncode(OutputStream out) throws IOException {
604        DerOutputStream temp = new DerOutputStream();
605        temp.putOID(oid);
606        switch (index) {
607        case -1:    // Unknown
608            temp.write((byte[])value);
609            break;
610        case 1:     // email address
611        case 2:     // unstructured name
612            { // open scope
613                String[] values = (String[]) value;
614                DerOutputStream[] temps = new
615                    DerOutputStream[values.length];
616
617                for (int i=0; i < values.length; i++) {
618                    temps[i] = new DerOutputStream();
619                    temps[i].putIA5String( values[i]);
620                }
621                temp.putOrderedSetOf(DerValue.tag_Set, temps);
622            } // close scope
623            break;
624
625        case 3:     // content type
626            {
627                DerOutputStream temp2 = new DerOutputStream();
628                temp2.putOID((ObjectIdentifier) value);
629                temp.write(DerValue.tag_Set, temp2.toByteArray());
630            }
631            break;
632
633        case 4:     // message digest
634            {
635                DerOutputStream temp2 = new DerOutputStream();
636                temp2.putOctetString((byte[]) value);
637                temp.write(DerValue.tag_Set, temp2.toByteArray());
638            }
639            break;
640
641        case 5:     // signing time
642            {
643                DerOutputStream temp2 = new DerOutputStream();
644                temp2.putUTCTime((Date) value);
645                temp.write(DerValue.tag_Set, temp2.toByteArray());
646            }
647            break;
648
649        case 6:     // countersignature
650            temp.putOrderedSetOf(DerValue.tag_Set, (DerEncoder[]) value);
651            break;
652
653        case 7:     // challenge password
654            {
655                DerOutputStream temp2 = new DerOutputStream();
656                temp2.putPrintableString((String) value);
657                temp.write(DerValue.tag_Set, temp2.toByteArray());
658            }
659            break;
660
661        case 8:     // unstructured address
662            { // open scope
663                String[] values = (String[]) value;
664                DerOutputStream[] temps = new
665                    DerOutputStream[values.length];
666
667                for (int i=0; i < values.length; i++) {
668                    temps[i] = new DerOutputStream();
669                    temps[i].putPrintableString(values[i]);
670                }
671                temp.putOrderedSetOf(DerValue.tag_Set, temps);
672            } // close scope
673            break;
674
675        case 9:     // extended-certificate attribute -- not supported
676            throw new IOException("PKCS9 extended-certificate " +
677                                  "attribute not supported.");
678            // break unnecessary
679        case 10:    // issuerAndserialNumber attribute -- not supported
680            throw new IOException("PKCS9 IssuerAndSerialNumber" +
681                                  "attribute not supported.");
682            // break unnecessary
683        case 11:    // RSA DSI proprietary
684        case 12:    // RSA DSI proprietary
685            throw new IOException("PKCS9 RSA DSI attributes" +
686                                  "11 and 12, not supported.");
687            // break unnecessary
688        case 13:    // S/MIME unused attribute
689            throw new IOException("PKCS9 attribute #13 not supported.");
690            // break unnecessary
691
692        case 14:     // ExtensionRequest
693            {
694                DerOutputStream temp2 = new DerOutputStream();
695                CertificateExtensions exts = (CertificateExtensions)value;
696                try {
697                    exts.encode(temp2, true);
698                } catch (CertificateException ex) {
699                    throw new IOException(ex.toString());
700                }
701                temp.write(DerValue.tag_Set, temp2.toByteArray());
702            }
703            break;
704        case 15:    // SMIMECapability
705            throw new IOException("PKCS9 attribute #15 not supported.");
706            // break unnecessary
707
708        case 16:    // SigningCertificate
709            throw new IOException(
710                "PKCS9 SigningCertificate attribute not supported.");
711            // break unnecessary
712
713        case 17:    // SignatureTimestampToken
714            temp.write(DerValue.tag_Set, (byte[])value);
715            break;
716
717        default: // can't happen
718        }
719
720        DerOutputStream derOut = new DerOutputStream();
721        derOut.write(DerValue.tag_Sequence, temp.toByteArray());
722
723        out.write(derOut.toByteArray());
724
725    }
726
727    /**
728     * Returns if the attribute is known. Unknown attributes can be created
729     * from DER encoding with unknown OIDs.
730     */
731    public boolean isKnown() {
732        return index != -1;
733    }
734
735    /**
736     * Get the value of this attribute.  If the attribute is
737     * single-valued, return just the one value.  If the attribute is
738     * multi-valued, return an array containing all the values.
739     * It is possible for this array to be of length 0.
740     *
741     * <P> The
742     * <a href=#classTable>table</a> gives the class of the value returned,
743     * depending on the type of this attribute.
744     */
745    public Object getValue() {
746        return value;
747    }
748
749    /**
750     * Show whether this attribute is single-valued.
751     */
752    public boolean isSingleValued() {
753        return index == -1 || SINGLE_VALUED[index];
754    }
755
756    /**
757     *  Return the OID of this attribute.
758     */
759    public ObjectIdentifier getOID() {
760        return oid;
761    }
762
763    /**
764     *  Return the name of this attribute.
765     */
766    public String getName() {
767        return index == -1 ?
768                oid.toString() :
769                OID_NAME_TABLE.get(PKCS9_OIDS[index]);
770    }
771
772    /**
773     * Return the OID for a given attribute name or null if we don't recognize
774     * the name.
775     */
776    public static ObjectIdentifier getOID(String name) {
777        return NAME_OID_TABLE.get(name.toLowerCase(Locale.ENGLISH));
778    }
779
780    /**
781     * Return the attribute name for a given OID or null if we don't recognize
782     * the oid.
783     */
784    public static String getName(ObjectIdentifier oid) {
785        return OID_NAME_TABLE.get(oid);
786    }
787
788    /**
789     * Returns a string representation of this attribute.
790     */
791    public String toString() {
792        StringBuilder sb = new StringBuilder(100);
793
794        sb.append("[");
795
796        if (index == -1) {
797            sb.append(oid.toString());
798        } else {
799            sb.append(OID_NAME_TABLE.get(PKCS9_OIDS[index]));
800        }
801        sb.append(": ");
802
803        if (index == -1 || SINGLE_VALUED[index]) {
804            if (value instanceof byte[]) { // special case for octet string
805                HexDumpEncoder hexDump = new HexDumpEncoder();
806                sb.append(hexDump.encodeBuffer((byte[]) value));
807            } else {
808                sb.append(value.toString());
809            }
810            sb.append("]");
811            return sb.toString();
812        } else { // multi-valued
813            boolean first = true;
814            Object[] values = (Object[]) value;
815
816            for (int j=0; j < values.length; j++) {
817                if (first)
818                    first = false;
819                else
820                    sb.append(", ");
821
822                sb.append(values[j].toString());
823            }
824            return sb.toString();
825        }
826    }
827
828    /**
829     * Beginning the search at <code>start</code>, find the first
830     * index <code>i</code> such that <code>a[i] = obj</code>.
831     *
832     * @return the index, if found, and -1 otherwise.
833     */
834    static int indexOf(Object obj, Object[] a, int start) {
835        for (int i=start; i < a.length; i++) {
836            if (obj.equals(a[i])) return i;
837        }
838        return -1;
839    }
840
841    /**
842     * Throw an exception when there are multiple values for
843     * a single-valued attribute.
844     */
845    private void throwSingleValuedException() throws IOException {
846        throw new IOException("Single-value attribute " +
847                              oid + " (" + getName() + ")" +
848                              " has multiple values.");
849    }
850
851    /**
852     * Throw an exception when the tag on a value encoding is
853     * wrong for the attribute whose value it is. This method
854     * will only be called for known tags.
855     */
856    private void throwTagException(Byte tag)
857    throws IOException {
858        Byte[] expectedTags = PKCS9_VALUE_TAGS[index];
859        StringBuilder msg = new StringBuilder(100);
860        msg.append("Value of attribute ");
861        msg.append(oid.toString());
862        msg.append(" (");
863        msg.append(getName());
864        msg.append(") has wrong tag: ");
865        msg.append(tag.toString());
866        msg.append(".  Expected tags: ");
867
868        msg.append(expectedTags[0].toString());
869
870        for (int i = 1; i < expectedTags.length; i++) {
871            msg.append(", ");
872            msg.append(expectedTags[i].toString());
873        }
874        msg.append(".");
875        throw new IOException(msg.toString());
876    }
877}
878