diff options
author | PKI Team <PKI Team@c9f7a03b-bd48-0410-a16d-cbbf54688b0b> | 2008-03-18 22:36:57 +0000 |
---|---|---|
committer | PKI Team <PKI Team@c9f7a03b-bd48-0410-a16d-cbbf54688b0b> | 2008-03-18 22:36:57 +0000 |
commit | d0f2e4efbd3eb0f1d7f5a28e7f97c1fb4ec027bb (patch) | |
tree | 7e7473fae8af5ad7e6cda7eabbef787093fc59a7 /pki/base/util/src/netscape/security/pkcs/PKCS9Attribute.java | |
parent | 273f8d85df5c31293a908185622b378c8f3cf7e8 (diff) | |
download | pki-d0f2e4efbd3eb0f1d7f5a28e7f97c1fb4ec027bb.tar.gz pki-d0f2e4efbd3eb0f1d7f5a28e7f97c1fb4ec027bb.tar.xz pki-d0f2e4efbd3eb0f1d7f5a28e7f97c1fb4ec027bb.zip |
Initial open source version based upon proprietary Red Hat Certificate System (RHCS) 7.3.
git-svn-id: svn+ssh://svn.fedorahosted.org/svn/pki/trunk@2 c9f7a03b-bd48-0410-a16d-cbbf54688b0b
Diffstat (limited to 'pki/base/util/src/netscape/security/pkcs/PKCS9Attribute.java')
-rw-r--r-- | pki/base/util/src/netscape/security/pkcs/PKCS9Attribute.java | 1145 |
1 files changed, 1145 insertions, 0 deletions
diff --git a/pki/base/util/src/netscape/security/pkcs/PKCS9Attribute.java b/pki/base/util/src/netscape/security/pkcs/PKCS9Attribute.java new file mode 100644 index 000000000..17eee2010 --- /dev/null +++ b/pki/base/util/src/netscape/security/pkcs/PKCS9Attribute.java @@ -0,0 +1,1145 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package netscape.security.pkcs; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Date; +import java.util.Hashtable; +import netscape.security.util.DerEncoder; +import netscape.security.util.DerValue; +import netscape.security.util.DerInputStream; +import netscape.security.util.DerOutputStream; +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.CertificateExtensions; +import java.security.cert.CertificateException; + +/** + * Class supporting any PKCS9 attribute except + * ExtendedCertificateAttribute. Supports DER decoding and access to + * attribute values, but not DER encoding or setting of values. + * + * @version 1.2 97/12/10 + * @author Douglas Hoover + */ +public class PKCS9Attribute implements DerEncoder { + + /* + * OIDs of PKCS #9 attribute types. + */ + private static final String RSADSI_str = "1.2.840.113549"; + private static final String PKCS_str = RSADSI_str + ".1"; + private static final String PKCS9_str = PKCS_str + ".9"; + + /** + * Array of attribute OIDs defined in PKCS9, by number. + */ + static final ObjectIdentifier[] PKCS9_OIDS = + //new ObjectIdentifier[10]; + // There are some Obsolete(?) attribute identifiers. + // This is mainly for extensionRequest (14) in pkcs10. + // We just add the other 4 as by products. + new ObjectIdentifier[15]; + + static { // static initializer for PKCS9_OIDS + for (int i = 1; i < PKCS9_OIDS.length; i++) { + PKCS9_OIDS[i] = new ObjectIdentifier(PKCS9_str + "." + i); + } + } + + 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_AND_SERIALNUMBER_OID = PKCS9_OIDS[10]; + public static final ObjectIdentifier + PASSWORD_CHECK_OID = PKCS9_OIDS[11]; + public static final ObjectIdentifier + PUBLIC_KEY_OID = PKCS9_OIDS[12]; + public static final ObjectIdentifier + SIGNING_DESCRIPTION_OID = PKCS9_OIDS[13]; + public static final ObjectIdentifier + EXTENSION_REQUEST_OID = PKCS9_OIDS[14]; + + 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_AND_SERIALNUMBER_STR = "IssuerAndSerialNumber"; + public static final String + PASSWORD_CHECK_STR = "PasswordCheck"; + public static final String + PUBLIC_KEY_STR = "PublicKey"; + public static final String + SIGNING_DESCRIPTION_STR = "SigningDescription"; + public static final String + EXTENSION_REQUEST_STR = "ExtensionRequest"; + + /** + * 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 NAME_OID_TABLE = new Hashtable(28); + + 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("passwordcheck", PKCS9_OIDS[11]); + NAME_OID_TABLE.put("publickey", PKCS9_OIDS[12]); + NAME_OID_TABLE.put("signingdescription", PKCS9_OIDS[13]); + NAME_OID_TABLE.put("extensionrequest", PKCS9_OIDS[14]); + }; + + /** + * Hashtable mapping attribute OIDs defined in PKCS9 to the + * corresponding attribute value type. + */ + private static final Hashtable OID_NAME_TABLE = new Hashtable(14); + 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_AND_SERIALNUMBER_STR); + OID_NAME_TABLE.put(PKCS9_OIDS[11], PASSWORD_CHECK_STR); + OID_NAME_TABLE.put(PKCS9_OIDS[12], PUBLIC_KEY_STR); + OID_NAME_TABLE.put(PKCS9_OIDS[13], SIGNING_DESCRIPTION_STR); + OID_NAME_TABLE.put(PKCS9_OIDS[14], EXTENSION_REQUEST_STR); + } + + /** + * 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, + {Byte.valueOf(DerValue.tag_IA5String)}, // EMailAddress + {Byte.valueOf(DerValue.tag_IA5String)}, // UnstructuredName + {Byte.valueOf(DerValue.tag_ObjectId)}, // ContentType + {Byte.valueOf(DerValue.tag_OctetString)}, // MessageDigest + {Byte.valueOf(DerValue.tag_UtcTime)}, // SigningTime + {Byte.valueOf(DerValue.tag_Sequence)}, // Countersignature + {Byte.valueOf(DerValue.tag_PrintableString), + Byte.valueOf(DerValue.tag_T61String)}, // ChallengePassword + {Byte.valueOf(DerValue.tag_PrintableString), + Byte.valueOf(DerValue.tag_T61String)}, // UnstructuredAddress + {Byte.valueOf(DerValue.tag_SetOf)}, // ExtendedCertificateAttributes + + null, //IssuerAndSerialNumber + null, //PasswordCheck + null, //PublicKey + null, //SigningDescription + {Byte.valueOf(DerValue.tag_Sequence)} //ExtensionRequest + }; + + /** + * Class types required for values for a given PKCS9 + * attribute type. + * + * <P> The following table shows the correspondence between + * attribute types and value component classes. + * + * <P> + * <TABLE BORDER CELLPADDING=8 ALIGN=CENTER> + * + * <TR> + * <TH>OID</TH> + * <TH>Attribute Type Name</TH> + * <TH>Kind</TH> + * <TH>Value Class</TH> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.1</TD> + * <TD>EmailAddress</TD> + * <TD>Multiple-valued</TD> + * <TD><code>String[]</code></TD> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.2</TD> + * <TD>UnstructuredName</TD> + * <TD>Multiple-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>Multiple-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>Multiple-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</TD> + * <TD>PasswordCheck</TD> + * <TD>Single-valued</TD> + * <TD>(not supported)</TD> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.12</TD> + * <TD>PublicKey</TD> + * <TD>Single-valued</TD> + * <TD>(not supported)</TD> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.13</TD> + * <TD>SigningDescription</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><code>Sequence</code></TD> + * </TR> + * + * </TABLE> + */ + private static final Class[] VALUE_CLASSES = new Class[15]; + + 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("netscape.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("[Lnetscape.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; // PasswordCheck + VALUE_CLASSES[12] = null; // PublicKey + VALUE_CLASSES[13] = null; // SigningDescription + VALUE_CLASSES[14] = // ExtensionRequest + Class.forName("netscape.security.x509.CertificateExtensions"); //xxxx + } catch (ClassNotFoundException e) { + throw new ExceptionInInitializerError(e.toString()); + } + } + + /** + * 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 + true, // PasswordCheck + true, // PublicKey + true, // SigningDescription + true // ExtensionRequest + }; + + /** + * The OID of this attribute is <code>PKCS9_OIDS[index]</code>. + */ + private int 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 + * multiple-valued, provide an array containing all the values. + * Arrays of length zero are accepted, though probably useless. + * + * <P> The following table gives the class that <code>value</code> + * must have for a given attribute. + * + * <P> + * <TABLE BORDER CELLPADDING=8 ALIGN=CENTER> + * + * <TR> + * <TH>OID</TH> + * <TH>Attribute Type Name</TH> + * <TH>Kind</TH> + * <TH>Value Class</TH> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.1</TD> + * <TD>EmailAddress</TD> + * <TD>Multiple-valued</TD> + * <TD><code>String[]</code></TD> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.2</TD> + * <TD>UnstructuredName</TD> + * <TD>Multiple-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>Multiple-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>Multiple-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</TD> + * <TD>PasswordCheck</TD> + * <TD>Single-valued</TD> + * <TD>(not supported)</TD> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.12</TD> + * <TD>PublicKey</TD> + * <TD>Single-valued</TD> + * <TD>(not supported)</TD> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.13</TD> + * <TD>SigningDescription</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><code>Sequence</code></TD> + * </TR> + * + * </TABLE> + */ + 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 + * multiple-valued, provide an array containing all the values. + * Arrays of length zero are accepted, though probably useless. + * + * <P> The following table 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. + * + * <P> + * <TABLE BORDER CELLPADDING=8 ALIGN=CENTER> + * + * <TR> + * <TH>OID</TH> + * <TH>Attribute Type Name</TH> + * <TH>Kind</TH> + * <TH>Value Class</TH> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.1</TD> + * <TD>EmailAddress</TD> + * <TD>Multiple-valued</TD> + * <TD><code>String[]</code></TD> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.2</TD> + * <TD>UnstructuredName</TD> + * <TD>Multiple-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>Multiple-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>Multiple-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</TD> + * <TD>PasswordCheck</TD> + * <TD>Single-valued</TD> + * <TD>(not supported)</TD> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.12</TD> + * <TD>PublicKey</TD> + * <TD>Single-valued</TD> + * <TD>(not supported)</TD> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.13</TD> + * <TD>SigningDescription</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><code>Sequence</code></TD> + * </TR> + * + * </TABLE> + * + * @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. + * + * @exception IOException on parsing error. + */ + public PKCS9Attribute(DerValue derVal) throws IOException { + + decode(derVal); + } + + /** + * Decode a PKCS9 attribute. + * + * @param val + * the DerValue representing the DER encoding of the attribute. + */ + private void decode(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"); + + DerValue[] elems; + + // get the oid + ObjectIdentifier oid = val[0].getOID(); + + index = indexOf(oid,PKCS9_OIDS,1); + Byte tag; + + if (index == -1) + throw new IOException("Invalid OID for PKCS9 attribute: " + + oid); + + 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 + for (int i=0; i < elems.length; i++) { + tag = Byte.valueOf(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."); + + case 10: // IssuerAndSerialNumber attribute -- not + // supported + throw new IOException("PKCS9 IssuerAndSerialNumber " + + "attribute not supported."); + + case 11: // passwordCheck attribute -- not + // supported + throw new IOException("PKCS9 passwordCheck " + + "attribute not supported."); + case 12: // PublicKey attribute -- not + // supported + throw new IOException("PKCS9 PublicKey " + + "attribute not supported."); + case 13: // SigningDescription attribute -- not + // supported + throw new IOException("PKCS9 SigningDescription " + + "attribute not supported."); + case 14: // ExtensionRequest attribute + value = + new CertificateExtensions(elems[0].toDerInputStream()); + + // break unnecessary + + default: // can't happen + } + + } + + /** + * 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."); + + case 10: // IssuerAndSerialNumber attribute -- not + // supported + throw new IOException("PKCS9 IssuerAndSerialNumber " + + "attribute not supported."); + + case 11: // passwordCheck attribute -- not + // supported + throw new IOException("PKCS9 passwordCheck " + + "attribute not supported."); + case 12: // PublicKey attribute -- not + // supported + throw new IOException("PKCS9 PublicKey " + + "attribute not supported."); + case 13: // SigningDescription attribute -- not + // supported + throw new IOException("PKCS9 SigningDescription " + + "attribute not supported."); + case 14: // ExtensionRequest attribute + try { + DerOutputStream temp2 = new DerOutputStream(); + //temp2.putSequence((CertificateExtensions) value); + ((CertificateExtensions)value).encode(temp2); + temp.write(DerValue.tag_Sequence, temp2.toByteArray()); + } catch (CertificateException e) { + throw new IOException("PKCS9 extension attributes not encoded"); + } + + // break unnecessary + 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 + * multiple-valued, return an array containing all the values. + * It is possible for this array to be of length 0. + * + * <P> The following table gives the class of the value returned, + * depending on the type of this attribute. + + * <P> + * <TABLE BORDER CELLPADDING=8 ALIGN=CENTER> + * + * <TR> + * <TH>OID</TH> + * <TH>Attribute Type Name</TH> + * <TH>Kind</TH> + * <TH>Value Class</TH> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.1</TD> + * <TD>EmailAddress</TD> + * <TD>Multiple-valued</TD> + * <TD><code>String[]</code></TD> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.2</TD> + * <TD>UnstructuredName</TD> + * <TD>Multiple-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>Multiple-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>Multiple-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</TD> + * <TD>PasswordCheck</TD> + * <TD>Single-valued</TD> + * <TD>(not supported)</TD> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.12</TD> + * <TD>PublicKey</TD> + * <TD>Single-valued</TD> + * <TD>(not supported)</TD> + * </TR> + * + * <TR> + * <TD>1.2.840.113549.1.9.13</TD> + * <TD>SigningDescription</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><code>Sequence</code></TD> + * </TR> + * + * </TABLE> + * + */ + public Object getValue() { + return value; + } + + /** + * Show whether this attribute is single-valued. + */ + public boolean isSingleValued() { + return SINGLE_VALUED[index]; + } + + /** + * Return the OID of this attribute. + */ + public ObjectIdentifier getOID() { + return PKCS9_OIDS[index]; + } + + /** + * Return the name of this attribute. + */ + public String getName() { + return (String) OID_NAME_TABLE.get(PKCS9_OIDS[index]); + } + + /** + * Return the OID for a given attribute name or null if we don't recognize + * the name. + */ + public static ObjectIdentifier getOID(String name) { + return (ObjectIdentifier) NAME_OID_TABLE.get(name.toLowerCase()); + } + + /** + * Return the attribute name for a given OID or null if we don't recognize + * the oid. + */ + public static String getName(ObjectIdentifier oid) { + return (String) OID_NAME_TABLE.get(oid); + } + + /** + * 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 + netscape.security.util.PrettyPrintFormat pp = + new netscape.security.util.PrettyPrintFormat(" ", 20); + String valuebits = pp.toHexString(((byte[])value)); + buf.append(valuebits); + } else { + buf.append(value.toString()); + } + buf.append("]"); + return buf.toString(); + } else { // multiple-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 <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. + */ + 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. + */ + 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()); + } + +} |