blob: 88ff7af40c9a5f51a07acabaedc3cd13f60f4043 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.security.pkcs;
27
28import java.io.IOException;
29import java.io.OutputStream;
30import java.util.Hashtable;
31import sun.security.util.DerEncoder;
32import sun.security.util.DerValue;
33import sun.security.util.DerInputStream;
34import sun.security.util.DerOutputStream;
35import sun.security.util.ObjectIdentifier;
36
37/**
38 * A set of attributes of class PKCS9Attribute.
39 *
40 * @author Douglas Hoover
41 */
42public class PKCS9Attributes {
43 /**
44 * Attributes in this set indexed by OID.
45 */
46 private final Hashtable<ObjectIdentifier, PKCS9Attribute> attributes =
47 new Hashtable<ObjectIdentifier, PKCS9Attribute>(3);
48
49 /**
50 * The keys of this hashtable are the OIDs of permitted attributes.
51 */
52 private final Hashtable<ObjectIdentifier, ObjectIdentifier> permittedAttributes;
53
54 /**
55 * The DER encoding of this attribute set. The tag byte must be
56 * DerValue.tag_SetOf.
57 */
58 private final byte[] derEncoding;
59
60 /*
61 * Contols how attributes, which are not recognized by the PKCS9Attribute
62 * class, are handled during parsing.
63 */
64 private boolean ignoreUnsupportedAttributes = false;
65
66 /**
67 * Construct a set of PKCS9 Attributes from its
68 * DER encoding on a DerInputStream, accepting only attributes
69 * with OIDs on the given
70 * list. If the array is null, accept all attributes supported by
71 * class PKCS9Attribute.
72 *
73 * @param permittedAttributes
74 * Array of attribute OIDs that will be accepted.
75 * @param in
76 * the contents of the DER encoding of the attribute set.
77 *
78 * @exception IOException
79 * on i/o error, encoding syntax error, unacceptable or
80 * unsupported attribute, or duplicate attribute.
81 *
82 * @see PKCS9Attribute
83 */
84 public PKCS9Attributes(ObjectIdentifier[] permittedAttributes,
85 DerInputStream in) throws IOException {
86 if (permittedAttributes != null) {
87 this.permittedAttributes =
88 new Hashtable<ObjectIdentifier, ObjectIdentifier>(
89 permittedAttributes.length);
90
91 for (int i = 0; i < permittedAttributes.length; i++)
92 this.permittedAttributes.put(permittedAttributes[i],
93 permittedAttributes[i]);
94 } else {
95 this.permittedAttributes = null;
96 }
97
98 // derEncoding initialized in <code>decode()</code>
99 derEncoding = decode(in);
100 }
101
102 /**
103 * Construct a set of PKCS9 Attributes from the contents of its
104 * DER encoding on a DerInputStream. Accept all attributes
105 * supported by class PKCS9Attribute and reject any unsupported
106 * attributes.
107 *
108 * @param in the contents of the DER encoding of the attribute set.
109 * @exception IOException
110 * on i/o error, encoding syntax error, or unsupported or
111 * duplicate attribute.
112 *
113 * @see PKCS9Attribute
114 */
115 public PKCS9Attributes(DerInputStream in) throws IOException {
116 this(in, false);
117 }
118
119 /**
120 * Construct a set of PKCS9 Attributes from the contents of its
121 * DER encoding on a DerInputStream. Accept all attributes
122 * supported by class PKCS9Attribute and ignore any unsupported
123 * attributes, if directed.
124 *
125 * @param in the contents of the DER encoding of the attribute set.
126 * @param ignoreUnsupportedAttributes If true then any attributes
127 * not supported by the PKCS9Attribute class are ignored. Otherwise
128 * unsupported attributes cause an exception to be thrown.
129 * @exception IOException
130 * on i/o error, encoding syntax error, or unsupported or
131 * duplicate attribute.
132 *
133 * @see PKCS9Attribute
134 */
135 public PKCS9Attributes(DerInputStream in,
136 boolean ignoreUnsupportedAttributes) throws IOException {
137
138 this.ignoreUnsupportedAttributes = ignoreUnsupportedAttributes;
139 // derEncoding initialized in <code>decode()</code>
140 derEncoding = decode(in);
141 permittedAttributes = null;
142 }
143
144 /**
145 * Construct a set of PKCS9 Attributes from the given array of
146 * PKCS9 attributes.
147 * DER encoding on a DerInputStream. All attributes in
148 * <code>attribs</code> must be
149 * supported by class PKCS9Attribute.
150 *
151 * @exception IOException
152 * on i/o error, encoding syntax error, or unsupported or
153 * duplicate attribute.
154 *
155 * @see PKCS9Attribute
156 */
157 public PKCS9Attributes(PKCS9Attribute[] attribs)
158 throws IllegalArgumentException, IOException {
159 ObjectIdentifier oid;
160 for (int i=0; i < attribs.length; i++) {
161 oid = attribs[i].getOID();
162 if (attributes.containsKey(oid))
163 throw new IllegalArgumentException(
164 "PKCSAttribute " + attribs[i].getOID() +
165 " duplicated while constructing " +
166 "PKCS9Attributes.");
167
168 attributes.put(oid, attribs[i]);
169 }
170 derEncoding = generateDerEncoding();
171 permittedAttributes = null;
172 }
173
174
175 /**
176 * Decode this set of PKCS9 attributes from the contents of its
177 * DER encoding. Ignores unsupported attributes when directed.
178 *
179 * @param in
180 * the contents of the DER encoding of the attribute set.
181 *
182 * @exception IOException
183 * on i/o error, encoding syntax error, unacceptable or
184 * unsupported attribute, or duplicate attribute.
185 */
186 private byte[] decode(DerInputStream in) throws IOException {
187
188 DerValue val = in.getDerValue();
189
190 // save the DER encoding with its proper tag byte.
191 byte[] derEncoding = val.toByteArray();
192 derEncoding[0] = DerValue.tag_SetOf;
193
194 DerInputStream derIn = new DerInputStream(derEncoding);
195 DerValue[] derVals = derIn.getSet(3,true);
196
197 PKCS9Attribute attrib;
198 ObjectIdentifier oid;
199 boolean reuseEncoding = true;
200
201 for (int i=0; i < derVals.length; i++) {
202
203 try {
204 attrib = new PKCS9Attribute(derVals[i]);
205
206 } catch (ParsingException e) {
207 if (ignoreUnsupportedAttributes) {
208 reuseEncoding = false; // cannot reuse supplied DER encoding
209 continue; // skip
210 } else {
211 throw e;
212 }
213 }
214 oid = attrib.getOID();
215
216 if (attributes.get(oid) != null)
217 throw new IOException("Duplicate PKCS9 attribute: " + oid);
218
219 if (permittedAttributes != null &&
220 !permittedAttributes.containsKey(oid))
221 throw new IOException("Attribute " + oid +
222 " not permitted in this attribute set");
223
224 attributes.put(oid, attrib);
225 }
226 return reuseEncoding ? derEncoding : generateDerEncoding();
227 }
228
229 /**
230 * Put the DER encoding of this PKCS9 attribute set on an
231 * DerOutputStream, tagged with the given implicit tag.
232 *
233 * @param tag the implicit tag to use in the DER encoding.
234 * @param out the output stream on which to put the DER encoding.
235 *
236 * @exception IOException on output error.
237 */
238 public void encode(byte tag, OutputStream out) throws IOException {
239 out.write(tag);
240 out.write(derEncoding, 1, derEncoding.length -1);
241 }
242
243 private byte[] generateDerEncoding() throws IOException {
244 DerOutputStream out = new DerOutputStream();
245 Object[] attribVals = attributes.values().toArray();
246
247 out.putOrderedSetOf(DerValue.tag_SetOf,
248 castToDerEncoder(attribVals));
249 return out.toByteArray();
250 }
251
252 /**
253 * Return the DER encoding of this attribute set, tagged with
254 * DerValue.tag_SetOf.
255 */
256 public byte[] getDerEncoding() throws IOException {
257 return derEncoding.clone();
258
259 }
260
261 /**
262 * Get an attribute from this set.
263 */
264 public PKCS9Attribute getAttribute(ObjectIdentifier oid) {
265 return attributes.get(oid);
266 }
267
268 /**
269 * Get an attribute from this set.
270 */
271 public PKCS9Attribute getAttribute(String name) {
272 return attributes.get(PKCS9Attribute.getOID(name));
273 }
274
275
276 /**
277 * Get an array of all attributes in this set, in order of OID.
278 */
279 public PKCS9Attribute[] getAttributes() {
280 PKCS9Attribute[] attribs = new PKCS9Attribute[attributes.size()];
281 ObjectIdentifier oid;
282
283 int j = 0;
284 for (int i=1; i < PKCS9Attribute.PKCS9_OIDS.length &&
285 j < attribs.length; i++) {
286 attribs[j] = getAttribute(PKCS9Attribute.PKCS9_OIDS[i]);
287
288 if (attribs[j] != null)
289 j++;
290 }
291 return attribs;
292 }
293
294 /**
295 * Get an attribute value by OID.
296 */
297 public Object getAttributeValue(ObjectIdentifier oid)
298 throws IOException {
299 try {
300 Object value = getAttribute(oid).getValue();
301 return value;
302 } catch (NullPointerException ex) {
303 throw new IOException("No value found for attribute " + oid);
304 }
305
306 }
307
308 /**
309 * Get an attribute value by type name.
310 */
311 public Object getAttributeValue(String name) throws IOException {
312 ObjectIdentifier oid = PKCS9Attribute.getOID(name);
313
314 if (oid == null)
315 throw new IOException("Attribute name " + name +
316 " not recognized or not supported.");
317
318 return getAttributeValue(oid);
319 }
320
321
322 /**
323 * Returns the PKCS9 block in a printable string form.
324 */
325 public String toString() {
326 StringBuffer buf = new StringBuffer(200);
327 buf.append("PKCS9 Attributes: [\n\t");
328
329 ObjectIdentifier oid;
330 PKCS9Attribute value;
331
332 boolean first = true;
333 for (int i = 1; i < PKCS9Attribute.PKCS9_OIDS.length; i++) {
334 value = getAttribute(PKCS9Attribute.PKCS9_OIDS[i]);
335
336 if (value == null) continue;
337
338 // we have a value; print it
339 if (first)
340 first = false;
341 else
342 buf.append(";\n\t");
343
344 buf.append(value.toString());
345 }
346
347 buf.append("\n\t] (end PKCS9 Attributes)");
348
349 return buf.toString();
350 }
351
352 /**
353 * Cast an object array whose components are
354 * <code>DerEncoder</code>s to <code>DerEncoder[]</code>.
355 */
356 static DerEncoder[] castToDerEncoder(Object[] objs) {
357
358 DerEncoder[] encoders = new DerEncoder[objs.length];
359
360 for (int i=0; i < encoders.length; i++)
361 encoders[i] = (DerEncoder) objs[i];
362
363 return encoders;
364 }
365}