Home | History | Annotate | Download | only in pkcs
      1 /*
      2  * Copyright (c) 1997, 2010, 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 
     26 package sun.security.pkcs;
     27 
     28 import java.io.IOException;
     29 import java.io.OutputStream;
     30 import java.security.cert.CertificateException;
     31 import java.util.Locale;
     32 import java.util.Date;
     33 import java.util.Hashtable;
     34 import sun.security.x509.CertificateExtensions;
     35 import sun.security.util.Debug;
     36 import sun.security.util.DerEncoder;
     37 import sun.security.util.DerValue;
     38 import sun.security.util.DerInputStream;
     39 import sun.security.util.DerOutputStream;
     40 import sun.security.util.ObjectIdentifier;
     41 import sun.misc.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  * <P>
     55  * <TABLE BORDER CELLPADDING=8 ALIGN=CENTER>
     56  *
     57  * <TR>
     58  * <TH>Object Identifier</TH>
     59  * <TH>Attribute Name</TH>
     60  * <TH>Type</TH>
     61  * <TH>Value Class</TH>
     62  * </TR>
     63  *
     64  * <TR>
     65  * <TD>1.2.840.113549.1.9.1</TD>
     66  * <TD>EmailAddress</TD>
     67  * <TD>Multi-valued</TD>
     68  * <TD><code>String[]</code></TD>
     69  * </TR>
     70  *
     71  * <TR>
     72  * <TD>1.2.840.113549.1.9.2</TD>
     73  * <TD>UnstructuredName</TD>
     74  * <TD>Multi-valued</TD>
     75  * <TD><code>String[]</code></TD>
     76  * </TR>
     77  *
     78  * <TR>
     79  * <TD>1.2.840.113549.1.9.3</TD>
     80  * <TD>ContentType</TD>
     81  * <TD>Single-valued</TD>
     82  * <TD><code>ObjectIdentifier</code></TD>
     83  * </TR>
     84  *
     85  * <TR>
     86  * <TD>1.2.840.113549.1.9.4</TD>
     87  * <TD>MessageDigest</TD>
     88  * <TD>Single-valued</TD>
     89  * <TD><code>byte[]</code></TD>
     90  * </TR>
     91  *
     92  * <TR>
     93  * <TD>1.2.840.113549.1.9.5</TD>
     94  * <TD>SigningTime</TD>
     95  * <TD>Single-valued</TD>
     96  * <TD><code>Date</code></TD>
     97  * </TR>
     98  *
     99  * <TR>
    100  * <TD>1.2.840.113549.1.9.6</TD>
    101  * <TD>Countersignature</TD>
    102  * <TD>Multi-valued</TD>
    103  * <TD><code>SignerInfo[]</code></TD>
    104  * </TR>
    105  *
    106  * <TR>
    107  * <TD>1.2.840.113549.1.9.7</TD>
    108  * <TD>ChallengePassword</TD>
    109  * <TD>Single-valued</TD>
    110  * <TD><code>String</code></TD>
    111  * </TR>
    112  *
    113  * <TR>
    114  * <TD>1.2.840.113549.1.9.8</TD>
    115  * <TD>UnstructuredAddress</TD>
    116  * <TD>Single-valued</TD>
    117  * <TD><code>String</code></TD>
    118  * </TR>
    119  *
    120  * <TR>
    121  * <TD>1.2.840.113549.1.9.9</TD>
    122  * <TD>ExtendedCertificateAttributes</TD>
    123  * <TD>Multi-valued</TD>
    124  * <TD>(not supported)</TD>
    125  * </TR>
    126  *
    127  * <TR>
    128  * <TD>1.2.840.113549.1.9.10</TD>
    129  * <TD>IssuerAndSerialNumber</TD>
    130  * <TD>Single-valued</TD>
    131  * <TD>(not supported)</TD>
    132  * </TR>
    133  *
    134  * <TR>
    135  * <TD>1.2.840.113549.1.9.{11,12}</TD>
    136  * <TD>RSA DSI proprietary</TD>
    137  * <TD>Single-valued</TD>
    138  * <TD>(not supported)</TD>
    139  * </TR>
    140  *
    141  * <TR>
    142  * <TD>1.2.840.113549.1.9.13</TD>
    143  * <TD>S/MIME unused assignment</TD>
    144  * <TD>Single-valued</TD>
    145  * <TD>(not supported)</TD>
    146  * </TR>
    147  *
    148  * <TR>
    149  * <TD>1.2.840.113549.1.9.14</TD>
    150  * <TD>ExtensionRequest</TD>
    151  * <TD>Single-valued</TD>
    152  * <TD>CertificateExtensions</TD>
    153  * </TR>
    154  *
    155  * <TR>
    156  * <TD>1.2.840.113549.1.9.15</TD>
    157  * <TD>SMIMECapability</TD>
    158  * <TD>Single-valued</TD>
    159  * <TD>(not supported)</TD>
    160  * </TR>
    161  *
    162  * <TR>
    163  * <TD>1.2.840.113549.1.9.16.2.12</TD>
    164  * <TD>SigningCertificate</TD>
    165  * <TD>Single-valued</TD>
    166  * <TD>SigningCertificateInfo</TD>
    167  * </TR>
    168  *
    169  * <TR>
    170  * <TD>1.2.840.113549.1.9.16.2.14</TD>
    171  * <TD>SignatureTimestampToken</TD>
    172  * <TD>Single-valued</TD>
    173  * <TD>byte[]</TD>
    174  * </TR>
    175  *
    176  * </TABLE>
    177  *
    178  * @author Douglas Hoover
    179  */
    180 public class PKCS9Attribute implements DerEncoder {
    181 
    182     /* Are we debugging ? */
    183     private static final Debug debug = Debug.getInstance("jar");
    184 
    185     /**
    186      * Array of attribute OIDs defined in PKCS9, by number.
    187      */
    188     static final ObjectIdentifier[] PKCS9_OIDS = new ObjectIdentifier[18];
    189 
    190     private final static Class<?> BYTE_ARRAY_CLASS;
    191 
    192     static {   // static initializer for PKCS9_OIDS
    193         for (int i = 1; i < PKCS9_OIDS.length - 2; i++) {
    194             PKCS9_OIDS[i] =
    195                 ObjectIdentifier.newInternal(new int[]{1,2,840,113549,1,9,i});
    196         }
    197         // Initialize SigningCertificate and SignatureTimestampToken
    198         // separately (because their values are out of sequence)
    199         PKCS9_OIDS[PKCS9_OIDS.length - 2] =
    200             ObjectIdentifier.newInternal(new int[]{1,2,840,113549,1,9,16,2,12});
    201         PKCS9_OIDS[PKCS9_OIDS.length - 1] =
    202             ObjectIdentifier.newInternal(new int[]{1,2,840,113549,1,9,16,2,14});
    203 
    204         try {
    205             BYTE_ARRAY_CLASS = Class.forName("[B");
    206         } catch (ClassNotFoundException e) {
    207             throw new ExceptionInInitializerError(e.toString());
    208         }
    209     }
    210 
    211     // first element [0] not used
    212     public static final ObjectIdentifier EMAIL_ADDRESS_OID = PKCS9_OIDS[1];
    213     public static final ObjectIdentifier UNSTRUCTURED_NAME_OID = PKCS9_OIDS[2];
    214     public static final ObjectIdentifier CONTENT_TYPE_OID = PKCS9_OIDS[3];
    215     public static final ObjectIdentifier MESSAGE_DIGEST_OID = PKCS9_OIDS[4];
    216     public static final ObjectIdentifier SIGNING_TIME_OID = PKCS9_OIDS[5];
    217     public static final ObjectIdentifier COUNTERSIGNATURE_OID = PKCS9_OIDS[6];
    218     public static final ObjectIdentifier CHALLENGE_PASSWORD_OID = PKCS9_OIDS[7];
    219     public static final ObjectIdentifier UNSTRUCTURED_ADDRESS_OID = PKCS9_OIDS[8];
    220     public static final ObjectIdentifier EXTENDED_CERTIFICATE_ATTRIBUTES_OID
    221                                          = PKCS9_OIDS[9];
    222     public static final ObjectIdentifier ISSUER_SERIALNUMBER_OID = PKCS9_OIDS[10];
    223     // [11], [12] are RSA DSI proprietary
    224     // [13] ==> signingDescription, S/MIME, not used anymore
    225     public static final ObjectIdentifier EXTENSION_REQUEST_OID = PKCS9_OIDS[14];
    226     public static final ObjectIdentifier SMIME_CAPABILITY_OID = PKCS9_OIDS[15];
    227     public static final ObjectIdentifier SIGNING_CERTIFICATE_OID = PKCS9_OIDS[16];
    228     public static final ObjectIdentifier SIGNATURE_TIMESTAMP_TOKEN_OID =
    229                                 PKCS9_OIDS[17];
    230     public static final String EMAIL_ADDRESS_STR = "EmailAddress";
    231     public static final String UNSTRUCTURED_NAME_STR = "UnstructuredName";
    232     public static final String CONTENT_TYPE_STR = "ContentType";
    233     public static final String MESSAGE_DIGEST_STR = "MessageDigest";
    234     public static final String SIGNING_TIME_STR = "SigningTime";
    235     public static final String COUNTERSIGNATURE_STR = "Countersignature";
    236     public static final String CHALLENGE_PASSWORD_STR = "ChallengePassword";
    237     public static final String UNSTRUCTURED_ADDRESS_STR = "UnstructuredAddress";
    238     public static final String EXTENDED_CERTIFICATE_ATTRIBUTES_STR =
    239                                "ExtendedCertificateAttributes";
    240     public static final String ISSUER_SERIALNUMBER_STR = "IssuerAndSerialNumber";
    241     // [11], [12] are RSA DSI proprietary
    242     private static final String RSA_PROPRIETARY_STR = "RSAProprietary";
    243     // [13] ==> signingDescription, S/MIME, not used anymore
    244     private static final String SMIME_SIGNING_DESC_STR = "SMIMESigningDesc";
    245     public static final String EXTENSION_REQUEST_STR = "ExtensionRequest";
    246     public static final String SMIME_CAPABILITY_STR = "SMIMECapability";
    247     public static final String SIGNING_CERTIFICATE_STR = "SigningCertificate";
    248     public static final String SIGNATURE_TIMESTAMP_TOKEN_STR =
    249                                 "SignatureTimestampToken";
    250 
    251     /**
    252      * Hashtable mapping names and variant names of supported
    253      * attributes to their OIDs. This table contains all name forms
    254      * that occur in PKCS9, in lower case.
    255      */
    256     private static final Hashtable<String, ObjectIdentifier> NAME_OID_TABLE =
    257         new Hashtable<String, ObjectIdentifier>(18);
    258 
    259     static { // static initializer for PCKS9_NAMES
    260         NAME_OID_TABLE.put("emailaddress", PKCS9_OIDS[1]);
    261         NAME_OID_TABLE.put("unstructuredname", PKCS9_OIDS[2]);
    262         NAME_OID_TABLE.put("contenttype", PKCS9_OIDS[3]);
    263         NAME_OID_TABLE.put("messagedigest", PKCS9_OIDS[4]);
    264         NAME_OID_TABLE.put("signingtime", PKCS9_OIDS[5]);
    265         NAME_OID_TABLE.put("countersignature", PKCS9_OIDS[6]);
    266         NAME_OID_TABLE.put("challengepassword", PKCS9_OIDS[7]);
    267         NAME_OID_TABLE.put("unstructuredaddress", PKCS9_OIDS[8]);
    268         NAME_OID_TABLE.put("extendedcertificateattributes", PKCS9_OIDS[9]);
    269         NAME_OID_TABLE.put("issuerandserialnumber", PKCS9_OIDS[10]);
    270         NAME_OID_TABLE.put("rsaproprietary", PKCS9_OIDS[11]);
    271         NAME_OID_TABLE.put("rsaproprietary", PKCS9_OIDS[12]);
    272         NAME_OID_TABLE.put("signingdescription", PKCS9_OIDS[13]);
    273         NAME_OID_TABLE.put("extensionrequest", PKCS9_OIDS[14]);
    274         NAME_OID_TABLE.put("smimecapability", PKCS9_OIDS[15]);
    275         NAME_OID_TABLE.put("signingcertificate", PKCS9_OIDS[16]);
    276         NAME_OID_TABLE.put("signaturetimestamptoken", PKCS9_OIDS[17]);
    277     };
    278 
    279     /**
    280      * Hashtable mapping attribute OIDs defined in PKCS9 to the
    281      * corresponding attribute value type.
    282      */
    283     private static final Hashtable<ObjectIdentifier, String> OID_NAME_TABLE =
    284         new Hashtable<ObjectIdentifier, String>(16);
    285     static {
    286         OID_NAME_TABLE.put(PKCS9_OIDS[1], EMAIL_ADDRESS_STR);
    287         OID_NAME_TABLE.put(PKCS9_OIDS[2], UNSTRUCTURED_NAME_STR);
    288         OID_NAME_TABLE.put(PKCS9_OIDS[3], CONTENT_TYPE_STR);
    289         OID_NAME_TABLE.put(PKCS9_OIDS[4], MESSAGE_DIGEST_STR);
    290         OID_NAME_TABLE.put(PKCS9_OIDS[5], SIGNING_TIME_STR);
    291         OID_NAME_TABLE.put(PKCS9_OIDS[6], COUNTERSIGNATURE_STR);
    292         OID_NAME_TABLE.put(PKCS9_OIDS[7], CHALLENGE_PASSWORD_STR);
    293         OID_NAME_TABLE.put(PKCS9_OIDS[8], UNSTRUCTURED_ADDRESS_STR);
    294         OID_NAME_TABLE.put(PKCS9_OIDS[9], EXTENDED_CERTIFICATE_ATTRIBUTES_STR);
    295         OID_NAME_TABLE.put(PKCS9_OIDS[10], ISSUER_SERIALNUMBER_STR);
    296         OID_NAME_TABLE.put(PKCS9_OIDS[11], RSA_PROPRIETARY_STR);
    297         OID_NAME_TABLE.put(PKCS9_OIDS[12], RSA_PROPRIETARY_STR);
    298         OID_NAME_TABLE.put(PKCS9_OIDS[13], SMIME_SIGNING_DESC_STR);
    299         OID_NAME_TABLE.put(PKCS9_OIDS[14], EXTENSION_REQUEST_STR);
    300         OID_NAME_TABLE.put(PKCS9_OIDS[15], SMIME_CAPABILITY_STR);
    301         OID_NAME_TABLE.put(PKCS9_OIDS[16], SIGNING_CERTIFICATE_STR);
    302         OID_NAME_TABLE.put(PKCS9_OIDS[17], SIGNATURE_TIMESTAMP_TOKEN_STR);
    303     }
    304 
    305     /**
    306      * Acceptable ASN.1 tags for DER encodings of values of PKCS9
    307      * attributes, by index in <code>PKCS9_OIDS</code>.
    308      * Sets of acceptable tags are represented as arrays.
    309      */
    310     private static final Byte[][] PKCS9_VALUE_TAGS = {
    311         null,
    312         {new Byte(DerValue.tag_IA5String)},   // EMailAddress
    313         {new Byte(DerValue.tag_IA5String)},   // UnstructuredName
    314         {new Byte(DerValue.tag_ObjectId)},    // ContentType
    315         {new Byte(DerValue.tag_OctetString)}, // MessageDigest
    316         {new Byte(DerValue.tag_UtcTime)},     // SigningTime
    317         {new Byte(DerValue.tag_Sequence)},    // Countersignature
    318         {new Byte(DerValue.tag_PrintableString),
    319          new Byte(DerValue.tag_T61String)},   // ChallengePassword
    320         {new Byte(DerValue.tag_PrintableString),
    321          new Byte(DerValue.tag_T61String)},   // UnstructuredAddress
    322         {new Byte(DerValue.tag_SetOf)},       // ExtendedCertificateAttributes
    323         {new Byte(DerValue.tag_Sequence)},    // issuerAndSerialNumber
    324         null,
    325         null,
    326         null,
    327         {new Byte(DerValue.tag_Sequence)},    // extensionRequest
    328         {new Byte(DerValue.tag_Sequence)},    // SMIMECapability
    329         {new Byte(DerValue.tag_Sequence)},    // SigningCertificate
    330         {new Byte(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 val 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 = new Byte(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         StringBuffer buf = new StringBuffer(100);
    793 
    794         buf.append("[");
    795 
    796         if (index == -1) {
    797             buf.append(oid.toString());
    798         } else {
    799             buf.append(OID_NAME_TABLE.get(PKCS9_OIDS[index]));
    800         }
    801         buf.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                 buf.append(hexDump.encodeBuffer((byte[]) value));
    807             } else {
    808                 buf.append(value.toString());
    809             }
    810             buf.append("]");
    811             return buf.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                     buf.append(", ");
    821 
    822                 buf.append(values[j].toString());
    823             }
    824             return buf.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         StringBuffer msg = new StringBuffer(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