365 lines · 11.7 KB · Java
RawDownload
/* * Copyright (c) 1997, 2006, 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.util.Hashtable;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; /** * A set of attributes of class PKCS9Attribute. * * @author Douglas Hoover */public class PKCS9Attributes {    /**     * Attributes in this set indexed by OID.     */    private final Hashtable<ObjectIdentifier, PKCS9Attribute> attributes =        new Hashtable<ObjectIdentifier, PKCS9Attribute>(3);     /**     * The keys of this hashtable are the OIDs of permitted attributes.     */    private final Hashtable<ObjectIdentifier, ObjectIdentifier> permittedAttributes;     /**     * The DER encoding of this attribute set.  The tag byte must be     * DerValue.tag_SetOf.     */    private final byte[] derEncoding;     /*     * Contols how attributes, which are not recognized by the PKCS9Attribute     * class, are handled during parsing.     */    private boolean ignoreUnsupportedAttributes = false;     /**     * Construct a set of PKCS9 Attributes from its     * DER encoding on a DerInputStream, accepting only attributes     * with OIDs on the given     * list.  If the array is null, accept all attributes supported by     * class PKCS9Attribute.     *     * @param permittedAttributes     * Array of attribute OIDs that will be accepted.     * @param in     * the contents of the DER encoding of the attribute set.     *     * @exception IOException     * on i/o error, encoding syntax error, unacceptable or     * unsupported attribute, or duplicate attribute.     *     * @see PKCS9Attribute     */    public PKCS9Attributes(ObjectIdentifier[] permittedAttributes,                           DerInputStream in) throws IOException {        if (permittedAttributes != null) {            this.permittedAttributes =                new Hashtable<ObjectIdentifier, ObjectIdentifier>(                                                permittedAttributes.length);             for (int i = 0; i < permittedAttributes.length; i++)                this.permittedAttributes.put(permittedAttributes[i],                                             permittedAttributes[i]);        } else {            this.permittedAttributes = null;        }         // derEncoding initialized in <code>decode()</code>        derEncoding = decode(in);    }     /**     * Construct a set of PKCS9 Attributes from the contents of its     * DER encoding on a DerInputStream.  Accept all attributes     * supported by class PKCS9Attribute and reject any unsupported     * attributes.     *     * @param in the contents of the DER encoding of the attribute set.     * @exception IOException     * on i/o error, encoding syntax error, or unsupported or     * duplicate attribute.     *     * @see PKCS9Attribute     */    public PKCS9Attributes(DerInputStream in) throws IOException {        this(in, false);    }     /**     * Construct a set of PKCS9 Attributes from the contents of its     * DER encoding on a DerInputStream.  Accept all attributes     * supported by class PKCS9Attribute and ignore any unsupported     * attributes, if directed.     *     * @param in the contents of the DER encoding of the attribute set.     * @param ignoreUnsupportedAttributes If true then any attributes     * not supported by the PKCS9Attribute class are ignored. Otherwise     * unsupported attributes cause an exception to be thrown.     * @exception IOException     * on i/o error, encoding syntax error, or unsupported or     * duplicate attribute.     *     * @see PKCS9Attribute     */    public PKCS9Attributes(DerInputStream in,        boolean ignoreUnsupportedAttributes) throws IOException {         this.ignoreUnsupportedAttributes = ignoreUnsupportedAttributes;        // derEncoding initialized in <code>decode()</code>        derEncoding = decode(in);        permittedAttributes = null;    }     /**     * Construct a set of PKCS9 Attributes from the given array of     * PKCS9 attributes.     * DER encoding on a DerInputStream.  All attributes in     * <code>attribs</code> must be     * supported by class PKCS9Attribute.     *     * @exception IOException     * on i/o error, encoding syntax error, or unsupported or     * duplicate attribute.     *     * @see PKCS9Attribute     */    public PKCS9Attributes(PKCS9Attribute[] attribs)    throws IllegalArgumentException, IOException {        ObjectIdentifier oid;        for (int i=0; i < attribs.length; i++) {            oid = attribs[i].getOID();            if (attributes.containsKey(oid))                throw new IllegalArgumentException(                          "PKCSAttribute " + attribs[i].getOID() +                          " duplicated while constructing " +                          "PKCS9Attributes.");             attributes.put(oid, attribs[i]);        }        derEncoding = generateDerEncoding();        permittedAttributes = null;    }      /**     * Decode this set of PKCS9 attributes from the contents of its     * DER encoding. Ignores unsupported attributes when directed.     *     * @param in     * the contents of the DER encoding of the attribute set.     *     * @exception IOException     * on i/o error, encoding syntax error, unacceptable or     * unsupported attribute, or duplicate attribute.     */    private byte[] decode(DerInputStream in) throws IOException {         DerValue val = in.getDerValue();         // save the DER encoding with its proper tag byte.        byte[] derEncoding = val.toByteArray();        derEncoding[0] = DerValue.tag_SetOf;         DerInputStream derIn = new DerInputStream(derEncoding);        DerValue[] derVals = derIn.getSet(3,true);         PKCS9Attribute attrib;        ObjectIdentifier oid;        boolean reuseEncoding = true;         for (int i=0; i < derVals.length; i++) {             try {                attrib = new PKCS9Attribute(derVals[i]);             } catch (ParsingException e) {                if (ignoreUnsupportedAttributes) {                    reuseEncoding = false; // cannot reuse supplied DER encoding                    continue; // skip                } else {                    throw e;                }            }            oid = attrib.getOID();             if (attributes.get(oid) != null)                throw new IOException("Duplicate PKCS9 attribute: " + oid);             if (permittedAttributes != null &&                !permittedAttributes.containsKey(oid))                throw new IOException("Attribute " + oid +                                      " not permitted in this attribute set");             attributes.put(oid, attrib);        }        return reuseEncoding ? derEncoding : generateDerEncoding();    }     /**     * Put the DER encoding of this PKCS9 attribute set on an     * DerOutputStream, tagged with the given implicit tag.     *     * @param tag the implicit tag to use in the DER encoding.     * @param out the output stream on which to put the DER encoding.     *     * @exception IOException  on output error.     */    public void encode(byte tag, OutputStream out) throws IOException {        out.write(tag);        out.write(derEncoding, 1, derEncoding.length -1);    }     private byte[] generateDerEncoding() throws IOException {        DerOutputStream out = new DerOutputStream();        Object[] attribVals = attributes.values().toArray();         out.putOrderedSetOf(DerValue.tag_SetOf,                            castToDerEncoder(attribVals));        return out.toByteArray();    }     /**     * Return the DER encoding of this attribute set, tagged with     * DerValue.tag_SetOf.     */    public byte[] getDerEncoding() throws IOException {        return derEncoding.clone();     }     /**     * Get an attribute from this set.     */    public PKCS9Attribute getAttribute(ObjectIdentifier oid) {        return attributes.get(oid);    }     /**     * Get an attribute from this set.     */    public PKCS9Attribute getAttribute(String name) {        return attributes.get(PKCS9Attribute.getOID(name));    }      /**     * Get an array of all attributes in this set, in order of OID.     */    public PKCS9Attribute[] getAttributes() {        PKCS9Attribute[] attribs = new PKCS9Attribute[attributes.size()];        ObjectIdentifier oid;         int j = 0;        for (int i=1; i < PKCS9Attribute.PKCS9_OIDS.length &&                      j < attribs.length; i++) {            attribs[j] = getAttribute(PKCS9Attribute.PKCS9_OIDS[i]);             if (attribs[j] != null)                j++;        }        return attribs;    }     /**     * Get an attribute value by OID.     */    public Object getAttributeValue(ObjectIdentifier oid)    throws IOException {        try {            Object value = getAttribute(oid).getValue();            return value;        } catch (NullPointerException ex) {            throw new IOException("No value found for attribute " + oid);        }     }     /**     *  Get an attribute value by type name.     */    public Object getAttributeValue(String name) throws IOException {        ObjectIdentifier oid = PKCS9Attribute.getOID(name);         if (oid == null)            throw new IOException("Attribute name " + name +                                  " not recognized or not supported.");         return getAttributeValue(oid);    }      /**     * Returns the PKCS9 block in a printable string form.     */    public String toString() {        StringBuffer buf = new StringBuffer(200);        buf.append("PKCS9 Attributes: [\n\t");         ObjectIdentifier oid;        PKCS9Attribute value;         boolean first = true;        for (int i = 1; i < PKCS9Attribute.PKCS9_OIDS.length; i++) {            value = getAttribute(PKCS9Attribute.PKCS9_OIDS[i]);             if (value == null) continue;             // we have a value; print it            if (first)                first = false;            else                buf.append(";\n\t");             buf.append(value.toString());        }         buf.append("\n\t] (end PKCS9 Attributes)");         return buf.toString();    }     /**     * Cast an object array whose components are     * <code>DerEncoder</code>s to <code>DerEncoder[]</code>.     */    static DerEncoder[] castToDerEncoder(Object[] objs) {         DerEncoder[] encoders = new DerEncoder[objs.length];         for (int i=0; i < encoders.length; i++)            encoders[i] = (DerEncoder) objs[i];         return encoders;    }}