1 /*
2  * Copyright (c) 1997, 2019, 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      */
PKCS10Attributes()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      */
PKCS10Attributes(PKCS10Attribute[] attrs)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      */
PKCS10Attributes(DerInputStream in)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      */
encode(OutputStream out)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} interface.
102      *
103      * @param out the OutputStream to marshal the contents to.
104      * @exception IOException on encoding errors.
105      */
derEncode(OutputStream out)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      */
setAttribute(String name, Object obj)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      */
getAttribute(String name)131     public Object getAttribute(String name) {
132         return map.get(name);
133     }
134 
135     /**
136      * Delete the attribute value.
137      */
deleteAttribute(String name)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      */
getElements()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      */
getAttributes()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} object is an
161      * {@code instanceof} {@code PKCS10Attributes}, 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      */
equals(Object other)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      */
hashCode()203     public int hashCode() {
204         return map.hashCode();
205     }
206 
207     /**
208      * Returns a string representation of this {@code PKCS10Attributes} object
209      * in the form of a set of entries, enclosed in braces and separated
210      * by the ASCII characters "{@code ,&nbsp;}" (comma and space).
211      * <p>Overrides the {@code toString} method of {@code Object}.
212      *
213      * @return  a string representation of this PKCS10Attributes.
214      */
toString()215     public String toString() {
216         String s = map.size() + "\n" + map.toString();
217         return s;
218     }
219 }
220