/*
* Copyright (c) 1997, 2013, 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.security.util.HexDumpEncoder;
Class supporting any PKCS9 attributes.
Supports DER decoding/encoding and access to attribute values.
Type/Class Table
The following table shows the correspondence between
PKCS9 attribute types and value component classes.
For types not listed here, its name is the OID
in string form, its value is a (single-valued)
byte array that is the SET's encoding.
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/encoding and access to attribute values.
*
* <a name="classTable"><h3>Type/Class Table</h3></a>
* The following table shows the correspondence between
* PKCS9 attribute types and value component classes.
* For types not listed here, its name is the OID
* in string form, its value is a (single-valued)
* byte array that is the SET's encoding.
*
* <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];
private static final Class<?> BYTE_ARRAY_CLASS;
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});
try {
BYTE_ARRAY_CLASS = Class.forName("[B");
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError(e.toString());
}
}
// 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,
{DerValue.tag_IA5String}, // EMailAddress
{DerValue.tag_IA5String, // UnstructuredName
DerValue.tag_PrintableString},
{DerValue.tag_ObjectId}, // ContentType
{DerValue.tag_OctetString}, // MessageDigest
{DerValue.tag_UtcTime}, // SigningTime
{DerValue.tag_Sequence}, // Countersignature
{DerValue.tag_PrintableString,
DerValue.tag_T61String}, // ChallengePassword
{DerValue.tag_PrintableString,
DerValue.tag_T61String}, // UnstructuredAddress
{DerValue.tag_SetOf}, // ExtendedCertificateAttributes
{DerValue.tag_Sequence}, // issuerAndSerialNumber
null,
null,
null,
{DerValue.tag_Sequence}, // extensionRequest
{DerValue.tag_Sequence}, // SMIMECapability
{DerValue.tag_Sequence}, // SigningCertificate
{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] = BYTE_ARRAY_CLASS; // 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] = BYTE_ARRAY_CLASS; // 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.
/**
* The OID of this attribute.
*/
private ObjectIdentifier oid;
The index of the OID of this attribute in PKCS9_OIDS
,
or -1 if it's unknown.
/**
* The index of the OID of this attribute in <code>PKCS9_OIDS</code>,
* or -1 if it's unknown.
*/
private int index;
Value set of this attribute. Its class is given by
VALUE_CLASSES[index]
. The SET itself
as byte[] if unknown.
/**
* Value set of this attribute. Its class is given by
* <code>VALUE_CLASSES[index]</code>. The SET itself
* as byte[] if unknown.
*/
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.
Throws: - IllegalArgumentException –
if the
value
has the wrong type.
/**
* 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.
*
* @exception IllegalArgumentException
* if the <code>value</code> has the wrong type.
*/
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 or 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 or 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 {
this.oid = oid;
index = indexOf(oid, PKCS9_OIDS, 1);
Class<?> clazz = index == -1 ? BYTE_ARRAY_CLASS: VALUE_CLASSES[index];
if (!clazz.isInstance(value)) {
throw new IllegalArgumentException(
"Wrong value class " +
" for attribute " + oid +
" constructing PKCS9Attribute; was " +
value.getClass().toString() + ", should be " +
clazz.toString());
}
this.value = value;
}
Construct a PKCS9Attribute from its encoding on an input
stream.
Params: - derVal – the DerValue representing the DER encoding of the attribute.
Throws: - IOException – on parsing error.
/**
* Construct a PKCS9Attribute from its encoding on an input
* stream.
*
* @param derVal 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
oid = val[0].getOID();
byte[] content = val[1].toByteArray();
DerValue[] elems = new DerInputStream(content).getSet(1);
index = indexOf(oid, PKCS9_OIDS, 1);
if (index == -1) {
if (debug != null) {
debug.println("Unsupported signer attribute: " + oid);
}
value = content;
return;
}
// 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 = 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
PrintableString
s, without checking whether they
should be encoded as T61String
s.
/**
* 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(oid);
switch (index) {
case -1: // Unknown
temp.write((byte[])value);
break;
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());
}
Returns if the attribute is known. Unknown attributes can be created
from DER encoding with unknown OIDs.
/**
* Returns if the attribute is known. Unknown attributes can be created
* from DER encoding with unknown OIDs.
*/
public boolean isKnown() {
return index != -1;
}
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 index == -1 || SINGLE_VALUED[index];
}
Return the OID of this attribute.
/**
* Return the OID of this attribute.
*/
public ObjectIdentifier getOID() {
return oid;
}
Return the name of this attribute.
/**
* Return the name of this attribute.
*/
public String getName() {
return index == -1 ?
oid.toString() :
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() {
StringBuilder sb = new StringBuilder(100);
sb.append("[");
if (index == -1) {
sb.append(oid.toString());
} else {
sb.append(OID_NAME_TABLE.get(PKCS9_OIDS[index]));
}
sb.append(": ");
if (index == -1 || SINGLE_VALUED[index]) {
if (value instanceof byte[]) { // special case for octet string
HexDumpEncoder hexDump = new HexDumpEncoder();
sb.append(hexDump.encodeBuffer((byte[]) value));
} else {
sb.append(value.toString());
}
sb.append("]");
return sb.toString();
} else { // multi-valued
boolean first = true;
Object[] values = (Object[]) value;
for (int j=0; j < values.length; j++) {
if (first)
first = false;
else
sb.append(", ");
sb.append(values[j].toString());
}
return sb.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 " +
oid + " (" + getName() + ")" +
" has multiple values.");
}
Throw an exception when the tag on a value encoding is
wrong for the attribute whose value it is. This method
will only be called for known tags.
/**
* Throw an exception when the tag on a value encoding is
* wrong for the attribute whose value it is. This method
* will only be called for known tags.
*/
private void throwTagException(Byte tag)
throws IOException {
Byte[] expectedTags = PKCS9_VALUE_TAGS[index];
StringBuilder msg = new StringBuilder(100);
msg.append("Value of attribute ");
msg.append(oid.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());
}
}