// --- 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.x509; import java.io.IOException; import java.io.OutputStream; import java.io.Serializable; import java.util.Enumeration; import java.util.Vector; import netscape.security.util.DerEncoder; import netscape.security.util.DerOutputStream; import netscape.security.util.DerValue; import netscape.security.util.ObjectIdentifier; /** * An attribute, as identified by some attribute ID, has some particular values. * Values are as a rule ASN.1 printable strings. A conventional set of type IDs * is recognized when parsing. The following shows the syntax: * *
 *
 *    Attribute	::= SEQUENCE {
 * type		AttributeType,
 * 	value		SET OF AttributeValue
 *              	-- at least one value is required --}
 *
 *    AttributeType	::= OBJECT IDENTIFIER
 *
 *    AttributeValue	::= ANY
 *
 * 
* * Refer to draft-ietf-pkix-ipki-part1-11 for the support attributes listed on * page 96 of the internet draft. The are listed here for easy reference: name, * common name, surname, given name, initials, generation qualifier, dn qualifier, * country name, locality name, state or province name, organization name, organization * unit name, title, pkcs9 email. Not all the attributes are supported. Please check * the X500NameAttrMap for defined attributes. * * @author Christine Ho */ public final class Attribute implements Serializable, DerEncoder { /** * */ private static final long serialVersionUID = -931486084625476764L; //private variables ObjectIdentifier oid; Vector valueSet = new Vector(); transient protected X500NameAttrMap attrMap; //========== CONSTRUCTOR ================================== /** * Construct an attribute from attribute type and attribute value * * @param oid the object identifier of the attribute type * @param value the value string */ public Attribute(ObjectIdentifier oid, String value) throws IOException { //pre-condition verification if ((oid == null) || (value == null)) throw new IOException("Invalid Input - null passed"); attrMap = X500NameAttrMap.getDefault(); this.oid = oid; valueSet.addElement(value); } /** * Construct an attribute from attribute type and attribute values * * @param oid the object identifier of the attribute type * @param values String value vector */ public Attribute(ObjectIdentifier oid, Vector values) throws IOException { //pre-condition verification if ((oid == null) || (values == null)) throw new IOException("Invalid Input - null passed"); attrMap = X500NameAttrMap.getDefault(); this.oid = oid; //copy the value into the valueSet list Enumeration vals = values.elements(); while (vals.hasMoreElements()) { valueSet.addElement(vals.nextElement()); } } /** * Construct an attribute from attribute type and attribute values * * @param oid attribute type string CN,OU,O,C,L,TITLE,ST,STREET,UID,MAIL,E,DC * @param values String value vector */ public Attribute(String attr, Vector values) throws IOException { //pre-condition verification if ((attr == null) || (values == null)) throw new IOException("Invalid Input - null passed"); ObjectIdentifier identifier = null; try { identifier = new ObjectIdentifier(attr); } catch (Exception e) { } ObjectIdentifier id = identifier; if (identifier == null) { attrMap = X500NameAttrMap.getDefault(); id = attrMap.getOid(attr); if (id == null) throw new IOException("Attr is not supported - does not contain in attr map"); } this.oid = id; //copy the value into the valueSet list Enumeration vals = values.elements(); while (vals.hasMoreElements()) { valueSet.addElement(vals.nextElement()); } } /** * Construct an attribute from a der encoded object. This der * der encoded value should represent the attribute object. * * @param value the attribute object in der encode form. */ public Attribute(DerValue val) throws IOException { //pre-condition verification if (val == null) throw new IOException("Invalid Input - null passed"); attrMap = X500NameAttrMap.getDefault(); decodeThis(val); } //========== PUBLIC METHODS ================================== /** * Returns the OID in the Attribute. * * @return the ObjectIdentifier in this Attribute. */ public ObjectIdentifier getOid() { return oid; } /** * Returns enumeration of values in this attribute. * * @return Enumeration of values of this Attribute. */ public Enumeration getValues() { if (valueSet == null) return null; return valueSet.elements(); } /** * Encodes the Attribute to a Der output stream. * Attribute are encoded as a SEQUENCE of two elements. * * @param out The Der output stream. */ public void encode(DerOutputStream out) throws IOException { encodeThis(out); } /** * DER encode this object onto an output stream. * Implements the DerEncoder interface. * * @param out * the output stream on which to write the DER encoding. * * @exception IOException on encoding error. */ public void derEncode(OutputStream out) throws IOException { encodeThis(out); } /** * Prints a string version of this extension. */ public String toString() { String theoid = "Attribute: " + oid + "\n"; StringBuffer values = new StringBuffer("Values: "); Enumeration n = valueSet.elements(); if (n.hasMoreElements()) { values.append(n.nextElement()); while (n.hasMoreElements()) values.append("," + n.nextElement()); } return theoid + values.toString() + "\n"; } //========== PRIVATE METHODS ================================== //encode the attribute object private void encodeThis(OutputStream out) throws IOException { DerOutputStream tmp = new DerOutputStream(); DerOutputStream tmp2 = new DerOutputStream(); tmp.putOID(oid); encodeValueSet(tmp); tmp2.write(DerValue.tag_Sequence, tmp); out.write(tmp2.toByteArray()); } //encode the attribute object private void encodeValueSet(OutputStream out) throws IOException { DerOutputStream tmp = new DerOutputStream(); DerOutputStream tmp2 = new DerOutputStream(); //get the attribute converter AVAValueConverter converter = attrMap.getValueConverter(oid); if (converter == null) { converter = new GenericValueConverter(); //throw new IOException("Converter not found: unsupported attribute type"); } //loop through all the values and encode Enumeration vals = valueSet.elements(); while (vals.hasMoreElements()) { String val = vals.nextElement(); DerValue derobj = converter.getValue(val); derobj.encode(tmp); } tmp2.write(DerValue.tag_SetOf, tmp); out.write(tmp2.toByteArray()); } //decode the attribute object private void decodeThis(DerValue val) throws IOException { //pre-condition verification if (val == null) { throw new IOException("Invalid Input - null passed."); } if (val.tag != DerValue.tag_Sequence) { throw new IOException("Invalid encoding for Attribute."); } if (val.data.available() == 0) { throw new IOException("No data available in " + "passed DER encoded value."); } this.oid = val.data.getDerValue().getOID(); if (val.data.available() == 0) { throw new IOException("Invalid encoding for Attribute - value missing"); } decodeValueSet(val.data.getDerValue()); if (this.oid == null) throw new IOException("Invalid encoding for Attribute - OID missing"); } //decode the attribute value set private void decodeValueSet(DerValue val) throws IOException { //pre-condition verification if (val == null) { throw new IOException("Invalid Input - null passed."); } AVAValueConverter converter = attrMap.getValueConverter(this.oid); if (converter == null) { converter = new GenericValueConverter(); //throw new IOException("Attribute is not supported - not in attr map"); } if (val.tag != DerValue.tag_SetOf) { throw new IOException("Invalid encoding for Attribute Value Set."); } if (val.data.available() == 0) { throw new IOException("No data available in " + "passed DER encoded attribute value set."); } //get the value set while (val.data.available() != 0) { DerValue value = val.data.getDerValue(); valueSet.addElement(converter.getAsString(value)); } } }