/*
 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.security.pkcs;

import java.io.IOException;
import java.io.OutputStream;
import java.security.cert.CertificateException;
import java.util.Locale;
import java.util.Date;
import java.util.Hashtable;
import sun.security.x509.CertificateExtensions;
import sun.security.util.Debug;
import sun.security.util.DerEncoder;
import sun.security.util.DerValue;
import sun.security.util.DerInputStream;
import sun.security.util.DerOutputStream;
import sun.security.util.ObjectIdentifier;
import sun.misc.HexDumpEncoder;

Class supporting any PKCS9 attributes. Supports DER decoding and access to attribute values, but not DER encoding or setting of values.

Type/Class Table

The following table shows the correspondence between PKCS9 attribute types and value component classes.

Object Identifier Attribute Name Type Value Class
1.2.840.113549.1.9.1 EmailAddress Multi-valued String[]
1.2.840.113549.1.9.2 UnstructuredName Multi-valued String[]
1.2.840.113549.1.9.3 ContentType Single-valued ObjectIdentifier
1.2.840.113549.1.9.4 MessageDigest Single-valued byte[]
1.2.840.113549.1.9.5 SigningTime Single-valued Date
1.2.840.113549.1.9.6 Countersignature Multi-valued SignerInfo[]
1.2.840.113549.1.9.7 ChallengePassword Single-valued String
1.2.840.113549.1.9.8 UnstructuredAddress Single-valued String
1.2.840.113549.1.9.9 ExtendedCertificateAttributes Multi-valued (not supported)
1.2.840.113549.1.9.10 IssuerAndSerialNumber Single-valued (not supported)
1.2.840.113549.1.9.{11,12} RSA DSI proprietary Single-valued (not supported)
1.2.840.113549.1.9.13 S/MIME unused assignment Single-valued (not supported)
1.2.840.113549.1.9.14 ExtensionRequest Single-valued CertificateExtensions
1.2.840.113549.1.9.15 SMIMECapability Single-valued (not supported)
1.2.840.113549.1.9.16.2.12 SigningCertificate Single-valued SigningCertificateInfo
1.2.840.113549.1.9.16.2.14 SignatureTimestampToken Single-valued byte[]
Author:Douglas Hoover
/** * Class supporting any PKCS9 attributes. * Supports DER decoding and access to attribute values, but not * DER encoding or setting of values. * * <a name="classTable"><h3>Type/Class Table</h3></a> * The following table shows the correspondence between * PKCS9 attribute types and value component classes. * * <P> * <TABLE BORDER CELLPADDING=8 ALIGN=CENTER> * * <TR> * <TH>Object Identifier</TH> * <TH>Attribute Name</TH> * <TH>Type</TH> * <TH>Value Class</TH> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.1</TD> * <TD>EmailAddress</TD> * <TD>Multi-valued</TD> * <TD><code>String[]</code></TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.2</TD> * <TD>UnstructuredName</TD> * <TD>Multi-valued</TD> * <TD><code>String[]</code></TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.3</TD> * <TD>ContentType</TD> * <TD>Single-valued</TD> * <TD><code>ObjectIdentifier</code></TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.4</TD> * <TD>MessageDigest</TD> * <TD>Single-valued</TD> * <TD><code>byte[]</code></TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.5</TD> * <TD>SigningTime</TD> * <TD>Single-valued</TD> * <TD><code>Date</code></TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.6</TD> * <TD>Countersignature</TD> * <TD>Multi-valued</TD> * <TD><code>SignerInfo[]</code></TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.7</TD> * <TD>ChallengePassword</TD> * <TD>Single-valued</TD> * <TD><code>String</code></TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.8</TD> * <TD>UnstructuredAddress</TD> * <TD>Single-valued</TD> * <TD><code>String</code></TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.9</TD> * <TD>ExtendedCertificateAttributes</TD> * <TD>Multi-valued</TD> * <TD>(not supported)</TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.10</TD> * <TD>IssuerAndSerialNumber</TD> * <TD>Single-valued</TD> * <TD>(not supported)</TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.{11,12}</TD> * <TD>RSA DSI proprietary</TD> * <TD>Single-valued</TD> * <TD>(not supported)</TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.13</TD> * <TD>S/MIME unused assignment</TD> * <TD>Single-valued</TD> * <TD>(not supported)</TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.14</TD> * <TD>ExtensionRequest</TD> * <TD>Single-valued</TD> * <TD>CertificateExtensions</TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.15</TD> * <TD>SMIMECapability</TD> * <TD>Single-valued</TD> * <TD>(not supported)</TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.16.2.12</TD> * <TD>SigningCertificate</TD> * <TD>Single-valued</TD> * <TD>SigningCertificateInfo</TD> * </TR> * * <TR> * <TD>1.2.840.113549.1.9.16.2.14</TD> * <TD>SignatureTimestampToken</TD> * <TD>Single-valued</TD> * <TD>byte[]</TD> * </TR> * * </TABLE> * * @author Douglas Hoover */
public class PKCS9Attribute implements DerEncoder { /* Are we debugging ? */ private static final Debug debug = Debug.getInstance("jar");
Array of attribute OIDs defined in PKCS9, by number.
/** * Array of attribute OIDs defined in PKCS9, by number. */
static final ObjectIdentifier[] PKCS9_OIDS = new ObjectIdentifier[18]; static { // static initializer for PKCS9_OIDS for (int i = 1; i < PKCS9_OIDS.length - 2; i++) { PKCS9_OIDS[i] = ObjectIdentifier.newInternal(new int[]{1,2,840,113549,1,9,i}); } // Initialize SigningCertificate and SignatureTimestampToken // separately (because their values are out of sequence) PKCS9_OIDS[PKCS9_OIDS.length - 2] = ObjectIdentifier.newInternal(new int[]{1,2,840,113549,1,9,16,2,12}); PKCS9_OIDS[PKCS9_OIDS.length - 1] = ObjectIdentifier.newInternal(new int[]{1,2,840,113549,1,9,16,2,14}); } // first element [0] not used public static final ObjectIdentifier EMAIL_ADDRESS_OID = PKCS9_OIDS[1]; public static final ObjectIdentifier UNSTRUCTURED_NAME_OID = PKCS9_OIDS[2]; public static final ObjectIdentifier CONTENT_TYPE_OID = PKCS9_OIDS[3]; public static final ObjectIdentifier MESSAGE_DIGEST_OID = PKCS9_OIDS[4]; public static final ObjectIdentifier SIGNING_TIME_OID = PKCS9_OIDS[5]; public static final ObjectIdentifier COUNTERSIGNATURE_OID = PKCS9_OIDS[6]; public static final ObjectIdentifier CHALLENGE_PASSWORD_OID = PKCS9_OIDS[7]; public static final ObjectIdentifier UNSTRUCTURED_ADDRESS_OID = PKCS9_OIDS[8]; public static final ObjectIdentifier EXTENDED_CERTIFICATE_ATTRIBUTES_OID = PKCS9_OIDS[9]; public static final ObjectIdentifier ISSUER_SERIALNUMBER_OID = PKCS9_OIDS[10]; // [11], [12] are RSA DSI proprietary // [13] ==> signingDescription, S/MIME, not used anymore public static final ObjectIdentifier EXTENSION_REQUEST_OID = PKCS9_OIDS[14]; public static final ObjectIdentifier SMIME_CAPABILITY_OID = PKCS9_OIDS[15]; public static final ObjectIdentifier SIGNING_CERTIFICATE_OID = PKCS9_OIDS[16]; public static final ObjectIdentifier SIGNATURE_TIMESTAMP_TOKEN_OID = PKCS9_OIDS[17]; public static final String EMAIL_ADDRESS_STR = "EmailAddress"; public static final String UNSTRUCTURED_NAME_STR = "UnstructuredName"; public static final String CONTENT_TYPE_STR = "ContentType"; public static final String MESSAGE_DIGEST_STR = "MessageDigest"; public static final String SIGNING_TIME_STR = "SigningTime"; public static final String COUNTERSIGNATURE_STR = "Countersignature"; public static final String CHALLENGE_PASSWORD_STR = "ChallengePassword"; public static final String UNSTRUCTURED_ADDRESS_STR = "UnstructuredAddress"; public static final String EXTENDED_CERTIFICATE_ATTRIBUTES_STR = "ExtendedCertificateAttributes"; public static final String ISSUER_SERIALNUMBER_STR = "IssuerAndSerialNumber"; // [11], [12] are RSA DSI proprietary private static final String RSA_PROPRIETARY_STR = "RSAProprietary"; // [13] ==> signingDescription, S/MIME, not used anymore private static final String SMIME_SIGNING_DESC_STR = "SMIMESigningDesc"; public static final String EXTENSION_REQUEST_STR = "ExtensionRequest"; public static final String SMIME_CAPABILITY_STR = "SMIMECapability"; public static final String SIGNING_CERTIFICATE_STR = "SigningCertificate"; public static final String SIGNATURE_TIMESTAMP_TOKEN_STR = "SignatureTimestampToken";
Hashtable mapping names and variant names of supported attributes to their OIDs. This table contains all name forms that occur in PKCS9, in lower case.
/** * Hashtable mapping names and variant names of supported * attributes to their OIDs. This table contains all name forms * that occur in PKCS9, in lower case. */
private static final Hashtable<String, ObjectIdentifier> NAME_OID_TABLE = new Hashtable<String, ObjectIdentifier>(18); static { // static initializer for PCKS9_NAMES NAME_OID_TABLE.put("emailaddress", PKCS9_OIDS[1]); NAME_OID_TABLE.put("unstructuredname", PKCS9_OIDS[2]); NAME_OID_TABLE.put("contenttype", PKCS9_OIDS[3]); NAME_OID_TABLE.put("messagedigest", PKCS9_OIDS[4]); NAME_OID_TABLE.put("signingtime", PKCS9_OIDS[5]); NAME_OID_TABLE.put("countersignature", PKCS9_OIDS[6]); NAME_OID_TABLE.put("challengepassword", PKCS9_OIDS[7]); NAME_OID_TABLE.put("unstructuredaddress", PKCS9_OIDS[8]); NAME_OID_TABLE.put("extendedcertificateattributes", PKCS9_OIDS[9]); NAME_OID_TABLE.put("issuerandserialnumber", PKCS9_OIDS[10]); NAME_OID_TABLE.put("rsaproprietary", PKCS9_OIDS[11]); NAME_OID_TABLE.put("rsaproprietary", PKCS9_OIDS[12]); NAME_OID_TABLE.put("signingdescription", PKCS9_OIDS[13]); NAME_OID_TABLE.put("extensionrequest", PKCS9_OIDS[14]); NAME_OID_TABLE.put("smimecapability", PKCS9_OIDS[15]); NAME_OID_TABLE.put("signingcertificate", PKCS9_OIDS[16]); NAME_OID_TABLE.put("signaturetimestamptoken", PKCS9_OIDS[17]); };
Hashtable mapping attribute OIDs defined in PKCS9 to the corresponding attribute value type.
/** * Hashtable mapping attribute OIDs defined in PKCS9 to the * corresponding attribute value type. */
private static final Hashtable<ObjectIdentifier, String> OID_NAME_TABLE = new Hashtable<ObjectIdentifier, String>(16); static { OID_NAME_TABLE.put(PKCS9_OIDS[1], EMAIL_ADDRESS_STR); OID_NAME_TABLE.put(PKCS9_OIDS[2], UNSTRUCTURED_NAME_STR); OID_NAME_TABLE.put(PKCS9_OIDS[3], CONTENT_TYPE_STR); OID_NAME_TABLE.put(PKCS9_OIDS[4], MESSAGE_DIGEST_STR); OID_NAME_TABLE.put(PKCS9_OIDS[5], SIGNING_TIME_STR); OID_NAME_TABLE.put(PKCS9_OIDS[6], COUNTERSIGNATURE_STR); OID_NAME_TABLE.put(PKCS9_OIDS[7], CHALLENGE_PASSWORD_STR); OID_NAME_TABLE.put(PKCS9_OIDS[8], UNSTRUCTURED_ADDRESS_STR); OID_NAME_TABLE.put(PKCS9_OIDS[9], EXTENDED_CERTIFICATE_ATTRIBUTES_STR); OID_NAME_TABLE.put(PKCS9_OIDS[10], ISSUER_SERIALNUMBER_STR); OID_NAME_TABLE.put(PKCS9_OIDS[11], RSA_PROPRIETARY_STR); OID_NAME_TABLE.put(PKCS9_OIDS[12], RSA_PROPRIETARY_STR); OID_NAME_TABLE.put(PKCS9_OIDS[13], SMIME_SIGNING_DESC_STR); OID_NAME_TABLE.put(PKCS9_OIDS[14], EXTENSION_REQUEST_STR); OID_NAME_TABLE.put(PKCS9_OIDS[15], SMIME_CAPABILITY_STR); OID_NAME_TABLE.put(PKCS9_OIDS[16], SIGNING_CERTIFICATE_STR); OID_NAME_TABLE.put(PKCS9_OIDS[17], SIGNATURE_TIMESTAMP_TOKEN_STR); }
Acceptable ASN.1 tags for DER encodings of values of PKCS9 attributes, by index in PKCS9_OIDS. Sets of acceptable tags are represented as arrays.
/** * Acceptable ASN.1 tags for DER encodings of values of PKCS9 * attributes, by index in <code>PKCS9_OIDS</code>. * Sets of acceptable tags are represented as arrays. */
private static final Byte[][] PKCS9_VALUE_TAGS = { null, {new Byte(DerValue.tag_IA5String)}, // EMailAddress {new Byte(DerValue.tag_IA5String)}, // UnstructuredName {new Byte(DerValue.tag_ObjectId)}, // ContentType {new Byte(DerValue.tag_OctetString)}, // MessageDigest {new Byte(DerValue.tag_UtcTime)}, // SigningTime {new Byte(DerValue.tag_Sequence)}, // Countersignature {new Byte(DerValue.tag_PrintableString), new Byte(DerValue.tag_T61String)}, // ChallengePassword {new Byte(DerValue.tag_PrintableString), new Byte(DerValue.tag_T61String)}, // UnstructuredAddress {new Byte(DerValue.tag_SetOf)}, // ExtendedCertificateAttributes {new Byte(DerValue.tag_Sequence)}, // issuerAndSerialNumber null, null, null, {new Byte(DerValue.tag_Sequence)}, // extensionRequest {new Byte(DerValue.tag_Sequence)}, // SMIMECapability {new Byte(DerValue.tag_Sequence)}, // SigningCertificate {new Byte(DerValue.tag_Sequence)} // SignatureTimestampToken }; private static final Class<?>[] VALUE_CLASSES = new Class<?>[18]; static { try { Class<?> str = Class.forName("[Ljava.lang.String;"); VALUE_CLASSES[0] = null; // not used VALUE_CLASSES[1] = str; // EMailAddress VALUE_CLASSES[2] = str; // UnstructuredName VALUE_CLASSES[3] = // ContentType Class.forName("sun.security.util.ObjectIdentifier"); VALUE_CLASSES[4] = Class.forName("[B"); // MessageDigest (byte[]) VALUE_CLASSES[5] = Class.forName("java.util.Date"); // SigningTime VALUE_CLASSES[6] = // Countersignature Class.forName("[Lsun.security.pkcs.SignerInfo;"); VALUE_CLASSES[7] = // ChallengePassword Class.forName("java.lang.String"); VALUE_CLASSES[8] = str; // UnstructuredAddress VALUE_CLASSES[9] = null; // ExtendedCertificateAttributes VALUE_CLASSES[10] = null; // IssuerAndSerialNumber VALUE_CLASSES[11] = null; // not used VALUE_CLASSES[12] = null; // not used VALUE_CLASSES[13] = null; // not used VALUE_CLASSES[14] = // ExtensionRequest Class.forName("sun.security.x509.CertificateExtensions"); VALUE_CLASSES[15] = null; // not supported yet VALUE_CLASSES[16] = null; // not supported yet VALUE_CLASSES[17] = Class.forName("[B"); // SignatureTimestampToken } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(e.toString()); } }
Array indicating which PKCS9 attributes are single-valued, by index in PKCS9_OIDS.
/** * Array indicating which PKCS9 attributes are single-valued, * by index in <code>PKCS9_OIDS</code>. */
private static final boolean[] SINGLE_VALUED = { false, false, // EMailAddress false, // UnstructuredName true, // ContentType true, // MessageDigest true, // SigningTime false, // Countersignature true, // ChallengePassword false, // UnstructuredAddress false, // ExtendedCertificateAttributes true, // IssuerAndSerialNumber - not supported yet false, // not used false, // not used false, // not used true, // ExtensionRequest true, // SMIMECapability - not supported yet true, // SigningCertificate true // SignatureTimestampToken };
The OID of this attribute is PKCS9_OIDS[index].
/** * The OID of this attribute is <code>PKCS9_OIDS[index]</code>. */
private int index;
Value set of this attribute. Its class is given by VALUE_CLASSES[index].
/** * Value set of this attribute. Its class is given by * <code>VALUE_CLASSES[index]</code>. */
private Object value;
Construct an attribute object from the attribute's OID and value. If the attribute is single-valued, provide only one value. If the attribute is multi-valued, provide an array containing all the values. Arrays of length zero are accepted, though probably useless.

The table gives the class that value must have for a given attribute.

/** * Construct an attribute object from the attribute's OID and * value. If the attribute is single-valued, provide only one * value. If the attribute is multi-valued, provide an array * containing all the values. * Arrays of length zero are accepted, though probably useless. * * <P> The * <a href=#classTable>table</a> gives the class that <code>value</code> * must have for a given attribute. * */
public PKCS9Attribute(ObjectIdentifier oid, Object value) throws IllegalArgumentException { init(oid, value); }
Construct an attribute object from the attribute's name and value. If the attribute is single-valued, provide only one value. If the attribute is multi-valued, provide an array containing all the values. Arrays of length zero are accepted, though probably useless.

The table gives the class that value must have for a given attribute. Reasonable variants of these attributes are accepted; in particular, case does not matter.

Throws:
  • IllegalArgumentException – if the name is not recognized of the value has the wrong type.
/** * Construct an attribute object from the attribute's name and * value. If the attribute is single-valued, provide only one * value. If the attribute is multi-valued, provide an array * containing all the values. * Arrays of length zero are accepted, though probably useless. * * <P> The * <a href=#classTable>table</a> gives the class that <code>value</code> * must have for a given attribute. Reasonable variants of these * attributes are accepted; in particular, case does not matter. * * @exception IllegalArgumentException * if the <code>name</code> is not recognized of the * <code>value</code> has the wrong type. */
public PKCS9Attribute(String name, Object value) throws IllegalArgumentException { ObjectIdentifier oid = getOID(name); if (oid == null) throw new IllegalArgumentException( "Unrecognized attribute name " + name + " constructing PKCS9Attribute."); init(oid, value); } private void init(ObjectIdentifier oid, Object value) throws IllegalArgumentException { index = indexOf(oid, PKCS9_OIDS, 1); if (index == -1) throw new IllegalArgumentException( "Unsupported OID " + oid + " constructing PKCS9Attribute."); if (!VALUE_CLASSES[index].isInstance(value)) throw new IllegalArgumentException( "Wrong value class " + " for attribute " + oid + " constructing PKCS9Attribute; was " + value.getClass().toString() + ", should be " + VALUE_CLASSES[index].toString()); this.value = value; }
Construct a PKCS9Attribute from its encoding on an input stream.
Params:
  • val – the DerValue representing the DER encoding of the attribute.
Throws:
/** * Construct a PKCS9Attribute from its encoding on an input * stream. * * @param val the DerValue representing the DER encoding of the attribute. * @exception IOException on parsing error. */
public PKCS9Attribute(DerValue derVal) throws IOException { DerInputStream derIn = new DerInputStream(derVal.toByteArray()); DerValue[] val = derIn.getSequence(2); if (derIn.available() != 0) throw new IOException("Excess data parsing PKCS9Attribute"); if (val.length != 2) throw new IOException("PKCS9Attribute doesn't have two components"); // get the oid ObjectIdentifier oid = val[0].getOID(); index = indexOf(oid, PKCS9_OIDS, 1); if (index == -1) { if (debug != null) { debug.println("ignoring unsupported signer attribute: " + oid); } throw new ParsingException("Unsupported PKCS9 attribute: " + oid); } DerValue[] elems = new DerInputStream(val[1].toByteArray()).getSet(1); // check single valued have only one value if (SINGLE_VALUED[index] && elems.length > 1) throwSingleValuedException(); // check for illegal element tags Byte tag; for (int i=0; i < elems.length; i++) { tag = new Byte(elems[i].tag); if (indexOf(tag, PKCS9_VALUE_TAGS[index], 0) == -1) throwTagException(tag); } switch (index) { case 1: // email address case 2: // unstructured name case 8: // unstructured address { // open scope String[] values = new String[elems.length]; for (int i=0; i < elems.length; i++) values[i] = elems[i].getAsString(); value = values; } // close scope break; case 3: // content type value = elems[0].getOID(); break; case 4: // message digest value = elems[0].getOctetString(); break; case 5: // signing time value = (new DerInputStream(elems[0].toByteArray())).getUTCTime(); break; case 6: // countersignature { // open scope SignerInfo[] values = new SignerInfo[elems.length]; for (int i=0; i < elems.length; i++) values[i] = new SignerInfo(elems[i].toDerInputStream()); value = values; } // close scope break; case 7: // challenge password value = elems[0].getAsString(); break; case 9: // extended-certificate attribute -- not supported throw new IOException("PKCS9 extended-certificate " + "attribute not supported."); // break unnecessary case 10: // issuerAndserialNumber attribute -- not supported throw new IOException("PKCS9 IssuerAndSerialNumber" + "attribute not supported."); // break unnecessary case 11: // RSA DSI proprietary case 12: // RSA DSI proprietary throw new IOException("PKCS9 RSA DSI attributes" + "11 and 12, not supported."); // break unnecessary case 13: // S/MIME unused attribute throw new IOException("PKCS9 attribute #13 not supported."); // break unnecessary case 14: // ExtensionRequest value = new CertificateExtensions( new DerInputStream(elems[0].toByteArray())); break; case 15: // SMIME-capability attribute -- not supported throw new IOException("PKCS9 SMIMECapability " + "attribute not supported."); // break unnecessary case 16: // SigningCertificate attribute value = new SigningCertificateInfo(elems[0].toByteArray()); break; case 17: // SignatureTimestampToken attribute value = elems[0].toByteArray(); break; default: // can't happen } }
Write the DER encoding of this attribute to an output stream.

N.B.: This method always encodes values of ChallengePassword and UnstructuredAddress attributes as ASN.1 PrintableStrings, without checking whether they should be encoded as T61Strings.

/** * Write the DER encoding of this attribute to an output stream. * * <P> N.B.: This method always encodes values of * ChallengePassword and UnstructuredAddress attributes as ASN.1 * <code>PrintableString</code>s, without checking whether they * should be encoded as <code>T61String</code>s. */
public void derEncode(OutputStream out) throws IOException { DerOutputStream temp = new DerOutputStream(); temp.putOID(getOID()); switch (index) { case 1: // email address case 2: // unstructured name { // open scope String[] values = (String[]) value; DerOutputStream[] temps = new DerOutputStream[values.length]; for (int i=0; i < values.length; i++) { temps[i] = new DerOutputStream(); temps[i].putIA5String( values[i]); } temp.putOrderedSetOf(DerValue.tag_Set, temps); } // close scope break; case 3: // content type { DerOutputStream temp2 = new DerOutputStream(); temp2.putOID((ObjectIdentifier) value); temp.write(DerValue.tag_Set, temp2.toByteArray()); } break; case 4: // message digest { DerOutputStream temp2 = new DerOutputStream(); temp2.putOctetString((byte[]) value); temp.write(DerValue.tag_Set, temp2.toByteArray()); } break; case 5: // signing time { DerOutputStream temp2 = new DerOutputStream(); temp2.putUTCTime((Date) value); temp.write(DerValue.tag_Set, temp2.toByteArray()); } break; case 6: // countersignature temp.putOrderedSetOf(DerValue.tag_Set, (DerEncoder[]) value); break; case 7: // challenge password { DerOutputStream temp2 = new DerOutputStream(); temp2.putPrintableString((String) value); temp.write(DerValue.tag_Set, temp2.toByteArray()); } break; case 8: // unstructured address { // open scope String[] values = (String[]) value; DerOutputStream[] temps = new DerOutputStream[values.length]; for (int i=0; i < values.length; i++) { temps[i] = new DerOutputStream(); temps[i].putPrintableString(values[i]); } temp.putOrderedSetOf(DerValue.tag_Set, temps); } // close scope break; case 9: // extended-certificate attribute -- not supported throw new IOException("PKCS9 extended-certificate " + "attribute not supported."); // break unnecessary case 10: // issuerAndserialNumber attribute -- not supported throw new IOException("PKCS9 IssuerAndSerialNumber" + "attribute not supported."); // break unnecessary case 11: // RSA DSI proprietary case 12: // RSA DSI proprietary throw new IOException("PKCS9 RSA DSI attributes" + "11 and 12, not supported."); // break unnecessary case 13: // S/MIME unused attribute throw new IOException("PKCS9 attribute #13 not supported."); // break unnecessary case 14: // ExtensionRequest { DerOutputStream temp2 = new DerOutputStream(); CertificateExtensions exts = (CertificateExtensions)value; try { exts.encode(temp2, true); } catch (CertificateException ex) { throw new IOException(ex.toString()); } temp.write(DerValue.tag_Set, temp2.toByteArray()); } break; case 15: // SMIMECapability throw new IOException("PKCS9 attribute #15 not supported."); // break unnecessary case 16: // SigningCertificate throw new IOException( "PKCS9 SigningCertificate attribute not supported."); // break unnecessary case 17: // SignatureTimestampToken temp.write(DerValue.tag_Set, (byte[])value); break; default: // can't happen } DerOutputStream derOut = new DerOutputStream(); derOut.write(DerValue.tag_Sequence, temp.toByteArray()); out.write(derOut.toByteArray()); }
Get the value of this attribute. If the attribute is single-valued, return just the one value. If the attribute is multi-valued, return an array containing all the values. It is possible for this array to be of length 0.

The table gives the class of the value returned, depending on the type of this attribute.

/** * Get the value of this attribute. If the attribute is * single-valued, return just the one value. If the attribute is * multi-valued, return an array containing all the values. * It is possible for this array to be of length 0. * * <P> The * <a href=#classTable>table</a> gives the class of the value returned, * depending on the type of this attribute. */
public Object getValue() { return value; }
Show whether this attribute is single-valued.
/** * Show whether this attribute is single-valued. */
public boolean isSingleValued() { return SINGLE_VALUED[index]; }
Return the OID of this attribute.
/** * Return the OID of this attribute. */
public ObjectIdentifier getOID() { return PKCS9_OIDS[index]; }
Return the name of this attribute.
/** * Return the name of this attribute. */
public String getName() { return OID_NAME_TABLE.get(PKCS9_OIDS[index]); }
Return the OID for a given attribute name or null if we don't recognize the name.
/** * Return the OID for a given attribute name or null if we don't recognize * the name. */
public static ObjectIdentifier getOID(String name) { return NAME_OID_TABLE.get(name.toLowerCase(Locale.ENGLISH)); }
Return the attribute name for a given OID or null if we don't recognize the oid.
/** * Return the attribute name for a given OID or null if we don't recognize * the oid. */
public static String getName(ObjectIdentifier oid) { return OID_NAME_TABLE.get(oid); }
Returns a string representation of this attribute.
/** * Returns a string representation of this attribute. */
public String toString() { StringBuffer buf = new StringBuffer(100); buf.append("["); buf.append(OID_NAME_TABLE.get(PKCS9_OIDS[index])); buf.append(": "); if (SINGLE_VALUED[index]) { if (value instanceof byte[]) { // special case for octet string HexDumpEncoder hexDump = new HexDumpEncoder(); buf.append(hexDump.encodeBuffer((byte[]) value)); } else { buf.append(value.toString()); } buf.append("]"); return buf.toString(); } else { // multi-valued boolean first = true; Object[] values = (Object[]) value; for (int j=0; j < values.length; j++) { if (first) first = false; else buf.append(", "); buf.append(values[j].toString()); } return buf.toString(); } }
Beginning the search at start, find the first index i such that a[i] = obj.
Returns:the index, if found, and -1 otherwise.
/** * Beginning the search at <code>start</code>, find the first * index <code>i</code> such that <code>a[i] = obj</code>. * * @return the index, if found, and -1 otherwise. */
static int indexOf(Object obj, Object[] a, int start) { for (int i=start; i < a.length; i++) { if (obj.equals(a[i])) return i; } return -1; }
Throw an exception when there are multiple values for a single-valued attribute.
/** * Throw an exception when there are multiple values for * a single-valued attribute. */
private void throwSingleValuedException() throws IOException { throw new IOException("Single-value attribute " + getOID() + " (" + getName() + ")" + " has multiple values."); }
Throw an exception when the tag on a value encoding is wrong for the attribute whose value it is.
/** * Throw an exception when the tag on a value encoding is * wrong for the attribute whose value it is. */
private void throwTagException(Byte tag) throws IOException { Byte[] expectedTags = PKCS9_VALUE_TAGS[index]; StringBuffer msg = new StringBuffer(100); msg.append("Value of attribute "); msg.append(getOID().toString()); msg.append(" ("); msg.append(getName()); msg.append(") has wrong tag: "); msg.append(tag.toString()); msg.append(". Expected tags: "); msg.append(expectedTags[0].toString()); for (int i = 1; i < expectedTags.length; i++) { msg.append(", "); msg.append(expectedTags[i].toString()); } msg.append("."); throw new IOException(msg.toString()); } }