1 /*
   2  * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.pkcs10;
  27 
  28 import java.io.IOException;
  29 import java.io.OutputStream;
  30 import java.security.cert.CertificateException;
  31 import java.util.Collection;
  32 import java.util.Collections;
  33 import java.util.Enumeration;
  34 import java.util.Hashtable;
  35 
  36 import sun.security.util.*;
  37 
  38 /**
  39  * This class defines the PKCS10 attributes for the request.
  40  * The ASN.1 syntax for this is:
  41  * <pre>
  42  * Attributes ::= SET OF Attribute
  43  * </pre>
  44  *
  45  * @author Amit Kapoor
  46  * @author Hemma Prafullchandra
  47  * @see PKCS10
  48  * @see PKCS10Attribute
  49  */
  50 public class PKCS10Attributes implements DerEncoder {
  51 
  52     private Hashtable<String, PKCS10Attribute> map =
  53                         new Hashtable<String, PKCS10Attribute>(3);
  54 
  55     /**
  56      * Default constructor for the PKCS10 attribute.
  57      */
  58     public PKCS10Attributes() { }
  59 
  60     /**
  61      * Create the object from the array of PKCS10Attribute objects.
  62      *
  63      * @param attrs the array of PKCS10Attribute objects.
  64      */
  65     public PKCS10Attributes(PKCS10Attribute[] attrs) {
  66         for (int i = 0; i < attrs.length; i++) {
  67             map.put(attrs[i].getAttributeId().toString(), attrs[i]);
  68         }
  69     }
  70 
  71     /**
  72      * Create the object, decoding the values from the passed DER stream.
  73      * The DER stream contains the SET OF Attribute.
  74      *
  75      * @param in the DerInputStream to read the attributes from.
  76      * @exception IOException on decoding errors.
  77      */
  78     public PKCS10Attributes(DerInputStream in) throws IOException {
  79         DerValue[] attrs = in.getSet(3, true);
  80 
  81         if (attrs == null)
  82             throw new IOException("Illegal encoding of attributes");
  83         for (int i = 0; i < attrs.length; i++) {
  84             PKCS10Attribute attr = new PKCS10Attribute(attrs[i]);
  85             map.put(attr.getAttributeId().toString(), attr);
  86         }
  87     }
  88 
  89     /**
  90      * Encode the attributes in DER form to the stream.
  91      *
  92      * @param out the OutputStream to marshal the contents to.
  93      * @exception IOException on encoding errors.
  94      */
  95     public void encode(OutputStream out) throws IOException {
  96         derEncode(out);
  97     }
  98 
  99     /**
 100      * Encode the attributes in DER form to the stream.
 101      * Implements the <code>DerEncoder</code> interface.
 102      *
 103      * @param out the OutputStream to marshal the contents to.
 104      * @exception IOException on encoding errors.
 105      */
 106     public void derEncode(OutputStream out) throws IOException {
 107         // first copy the elements into an array
 108         Collection<PKCS10Attribute> allAttrs = map.values();
 109         PKCS10Attribute[] attribs =
 110                 allAttrs.toArray(new PKCS10Attribute[map.size()]);
 111 
 112         DerOutputStream attrOut = new DerOutputStream();
 113         attrOut.putOrderedSetOf(DerValue.createTag(DerValue.TAG_CONTEXT,
 114                                                    true, (byte)0),
 115                                 attribs);
 116         out.write(attrOut.toByteArray());
 117     }
 118 
 119     /**
 120      * Set the attribute value.
 121      */
 122     public void setAttribute(String name, Object obj) {
 123         if (obj instanceof PKCS10Attribute) {
 124             map.put(name, (PKCS10Attribute)obj);
 125         }
 126     }
 127 
 128     /**
 129      * Get the attribute value.
 130      */
 131     public Object getAttribute(String name) {
 132         return map.get(name);
 133     }
 134 
 135     /**
 136      * Delete the attribute value.
 137      */
 138     public void deleteAttribute(String name) {
 139         map.remove(name);
 140     }
 141 
 142     /**
 143      * Return an enumeration of names of attributes existing within this
 144      * attribute.
 145      */
 146     public Enumeration<PKCS10Attribute> getElements() {
 147         return (map.elements());
 148     }
 149 
 150     /**
 151      * Return a Collection of attributes existing within this
 152      * PKCS10Attributes object.
 153      */
 154     public Collection<PKCS10Attribute> getAttributes() {
 155         return (Collections.unmodifiableCollection(map.values()));
 156     }
 157 
 158     /**
 159      * Compares this PKCS10Attributes for equality with the specified
 160      * object. If the <code>other</code> object is an
 161      * <code>instanceof</code> <code>PKCS10Attributes</code>, then
 162      * all the entries are compared with the entries from this.
 163      *
 164      * @param other the object to test for equality with this PKCS10Attributes.
 165      * @return true if all the entries match that of the Other,
 166      * false otherwise.
 167      */
 168     public boolean equals(Object other) {
 169         if (this == other)
 170             return true;
 171         if (!(other instanceof PKCS10Attributes))
 172             return false;
 173 
 174         Collection<PKCS10Attribute> othersAttribs =
 175                 ((PKCS10Attributes)other).getAttributes();
 176         PKCS10Attribute[] attrs =
 177             othersAttribs.toArray(new PKCS10Attribute[othersAttribs.size()]);
 178         int len = attrs.length;
 179         if (len != map.size())
 180             return false;
 181         PKCS10Attribute thisAttr, otherAttr;
 182         String key = null;
 183         for (int i=0; i < len; i++) {
 184             otherAttr = attrs[i];
 185             key = otherAttr.getAttributeId().toString();
 186 
 187             if (key == null)
 188                 return false;
 189             thisAttr = map.get(key);
 190             if (thisAttr == null)
 191                 return false;
 192             if (! thisAttr.equals(otherAttr))
 193                 return false;
 194         }
 195         return true;
 196     }
 197 
 198     /**
 199      * Returns a hashcode value for this PKCS10Attributes.
 200      *
 201      * @return the hashcode value.
 202      */
 203     public int hashCode() {
 204         return map.hashCode();
 205     }
 206 
 207     /**
 208      * Returns a string representation of this <tt>PKCS10Attributes</tt> object
 209      * in the form of a set of entries, enclosed in braces and separated
 210      * by the ASCII characters "<tt>,&nbsp;</tt>" (comma and space).
 211      * <p>Overrides the <tt>toString</tt> method of <tt>Object</tt>.
 212      *
 213      * @return  a string representation of this PKCS10Attributes.
 214      */
 215     public String toString() {
 216         String s = map.size() + "\n" + map.toString();
 217         return s;
 218     }
 219 }