blob: e4258936b66d9a6fb0a739d7a1cb5b8f65ffa5ba [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-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.x509;
27
28import java.io.IOException;
29import java.io.OutputStream;
30
31import java.util.*;
32
33import sun.security.util.DerInputStream;
34import sun.security.util.DerOutputStream;
35import sun.security.util.DerValue;
36
37/**
38 * Represents the CRL Issuing Distribution Point Extension (OID = 2.5.29.28).
39 *
40 * <p>
41 * The issuing distribution point is a critical CRL extension that
42 * identifies the CRL distribution point and scope for a particular CRL,
43 * and it indicates whether the CRL covers revocation for end entity
44 * certificates only, CA certificates only, attribute certificates only,
45 * or a limited set of reason codes.
46 *
47 * <p>
48 * The extension is defined in Section 5.2.5 of
49 * <a href="http://www.ietf.org/rfc/rfc3280.txt">Internet X.509 PKI Certific
50ate and Certificate Revocation List (CRL) Profile</a>.
51 *
52 * <p>
53 * Its ASN.1 definition is as follows:
54 * <pre>
55 * id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 }
56 *
57 * issuingDistributionPoint ::= SEQUENCE {
58 * distributionPoint [0] DistributionPointName OPTIONAL,
59 * onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE,
60 * onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE,
61 * onlySomeReasons [3] ReasonFlags OPTIONAL,
62 * indirectCRL [4] BOOLEAN DEFAULT FALSE,
63 * onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
64 * </pre>
65 *
66 * @see DistributionPoint
67 * @since 1.6
68 */
69public class IssuingDistributionPointExtension extends Extension
70 implements CertAttrSet<String> {
71
72 /**
73 * Identifier for this attribute, to be used with the
74 * get, set, delete methods of Certificate, x509 type.
75 */
76 public static final String IDENT =
77 "x509.info.extensions.IssuingDistributionPoint";
78
79 /**
80 * Attribute names.
81 */
82 public static final String NAME = "IssuingDistributionPoint";
83 public static final String POINT = "point";
84 public static final String REASONS = "reasons";
85 public static final String ONLY_USER_CERTS = "only_user_certs";
86 public static final String ONLY_CA_CERTS = "only_ca_certs";
87 public static final String ONLY_ATTRIBUTE_CERTS = "only_attribute_certs";
88 public static final String INDIRECT_CRL = "indirect_crl";
89
90 /*
91 * The distribution point name for the CRL.
92 */
93 private DistributionPointName distributionPoint = null;
94
95 /*
96 * The scope settings for the CRL.
97 */
98 private ReasonFlags revocationReasons = null;
99 private boolean hasOnlyUserCerts = false;
100 private boolean hasOnlyCACerts = false;
101 private boolean hasOnlyAttributeCerts = false;
102 private boolean isIndirectCRL = false;
103
104 /*
105 * ASN.1 context specific tag values
106 */
107 private static final byte TAG_DISTRIBUTION_POINT = 0;
108 private static final byte TAG_ONLY_USER_CERTS = 1;
109 private static final byte TAG_ONLY_CA_CERTS = 2;
110 private static final byte TAG_ONLY_SOME_REASONS = 3;
111 private static final byte TAG_INDIRECT_CRL = 4;
112 private static final byte TAG_ONLY_ATTRIBUTE_CERTS = 5;
113
114 /**
115 * Creates a critical IssuingDistributionPointExtension.
116 *
117 * @param distributionPoint the name of the distribution point, or null for
118 * none.
119 * @param revocationReasons the revocation reasons associated with the
120 * distribution point, or null for none.
121 * @param hasOnlyUserCerts if <code>true</code> then scope of the CRL
122 * includes only user certificates.
123 * @param hasOnlyCACerts if <code>true</code> then scope of the CRL
124 * includes only CA certificates.
125 * @param hasOnlyAttributeCerts if <code>true</code> then scope of the CRL
126 * includes only attribute certificates.
127 * @param isIndirectCRL if <code>true</code> then the scope of the CRL
128 * includes certificates issued by authorities other than the CRL
129 * issuer. The responsible authority is indicated by a certificate
130 * issuer CRL entry extension.
131 * @throws IllegalArgumentException if more than one of
132 * <code>hasOnlyUserCerts</code>, <code>hasOnlyCACerts</code>,
133 * <code>hasOnlyAttributeCerts</code> is set to <code>true</code>.
134 * @throws IOException on encoding error.
135 */
136 public IssuingDistributionPointExtension(
137 DistributionPointName distributionPoint, ReasonFlags revocationReasons,
138 boolean hasOnlyUserCerts, boolean hasOnlyCACerts,
139 boolean hasOnlyAttributeCerts, boolean isIndirectCRL)
140 throws IOException {
141
142 if ((hasOnlyUserCerts && (hasOnlyCACerts || hasOnlyAttributeCerts)) ||
143 (hasOnlyCACerts && (hasOnlyUserCerts || hasOnlyAttributeCerts)) ||
144 (hasOnlyAttributeCerts && (hasOnlyUserCerts || hasOnlyCACerts))) {
145 throw new IllegalArgumentException(
146 "Only one of hasOnlyUserCerts, hasOnlyCACerts, " +
147 "hasOnlyAttributeCerts may be set to true");
148 }
149 this.extensionId = PKIXExtensions.IssuingDistributionPoint_Id;
150 this.critical = true;
151 this.distributionPoint = distributionPoint;
152 this.revocationReasons = revocationReasons;
153 this.hasOnlyUserCerts = hasOnlyUserCerts;
154 this.hasOnlyCACerts = hasOnlyCACerts;
155 this.hasOnlyAttributeCerts = hasOnlyAttributeCerts;
156 this.isIndirectCRL = isIndirectCRL;
157 encodeThis();
158 }
159
160 /**
161 * Creates a critical IssuingDistributionPointExtension from its
162 * DER-encoding.
163 *
164 * @param critical true if the extension is to be treated as critical.
165 * @param value the DER-encoded value. It must be a <code>byte[]</code>.
166 * @exception IOException on decoding error.
167 */
168 public IssuingDistributionPointExtension(Boolean critical, Object value)
169 throws IOException {
170 this.extensionId = PKIXExtensions.IssuingDistributionPoint_Id;
171 this.critical = critical.booleanValue();
172
173 if (!(value instanceof byte[])) {
174 throw new IOException("Illegal argument type");
175 }
176
177 extensionValue = (byte[])value;
178 DerValue val = new DerValue(extensionValue);
179 if (val.tag != DerValue.tag_Sequence) {
180 throw new IOException("Invalid encoding for " +
181 "IssuingDistributionPointExtension.");
182 }
183
184 // All the elements in issuingDistributionPoint are optional
185 if ((val.data == null) || (val.data.available() == 0)) {
186 return;
187 }
188
189 DerInputStream in = val.data;
190 while (in != null && in.available() != 0) {
191 DerValue opt = in.getDerValue();
192
193 if (opt.isContextSpecific(TAG_DISTRIBUTION_POINT) &&
194 opt.isConstructed()) {
195 distributionPoint =
196 new DistributionPointName(opt.data.getDerValue());
197 } else if (opt.isContextSpecific(TAG_ONLY_USER_CERTS) &&
198 !opt.isConstructed()) {
199 opt.resetTag(DerValue.tag_Boolean);
200 hasOnlyUserCerts = opt.getBoolean();
201 } else if (opt.isContextSpecific(TAG_ONLY_CA_CERTS) &&
202 !opt.isConstructed()) {
203 opt.resetTag(DerValue.tag_Boolean);
204 hasOnlyCACerts = opt.getBoolean();
205 } else if (opt.isContextSpecific(TAG_ONLY_SOME_REASONS) &&
206 !opt.isConstructed()) {
207 revocationReasons = new ReasonFlags(opt); // expects tag implicit
208 } else if (opt.isContextSpecific(TAG_INDIRECT_CRL) &&
209 !opt.isConstructed()) {
210 opt.resetTag(DerValue.tag_Boolean);
211 isIndirectCRL = opt.getBoolean();
212 } else if (opt.isContextSpecific(TAG_ONLY_ATTRIBUTE_CERTS) &&
213 !opt.isConstructed()) {
214 opt.resetTag(DerValue.tag_Boolean);
215 hasOnlyAttributeCerts = opt.getBoolean();
216 } else {
217 throw new IOException
218 ("Invalid encoding of IssuingDistributionPoint");
219 }
220 }
221 }
222
223 /**
224 * Returns the name of this attribute.
225 */
226 public String getName() {
227 return NAME;
228 }
229
230 /**
231 * Encodes the issuing distribution point extension and writes it to the
232 * DerOutputStream.
233 *
234 * @param out the output stream.
235 * @exception IOException on encoding error.
236 */
237 public void encode(OutputStream out) throws IOException {
238 DerOutputStream tmp = new DerOutputStream();
239 if (this.extensionValue == null) {
240 this.extensionId = PKIXExtensions.IssuingDistributionPoint_Id;
241 this.critical = false;
242 encodeThis();
243 }
244 super.encode(tmp);
245 out.write(tmp.toByteArray());
246 }
247
248 /**
249 * Sets the attribute value.
250 */
251 public void set(String name, Object obj) throws IOException {
252 if (name.equalsIgnoreCase(POINT)) {
253 if (!(obj instanceof DistributionPointName)) {
254 throw new IOException(
255 "Attribute value should be of type DistributionPointName.");
256 }
257 distributionPoint = (DistributionPointName)obj;
258
259 } else if (name.equalsIgnoreCase(REASONS)) {
260 if (!(obj instanceof ReasonFlags)) {
261 throw new IOException(
262 "Attribute value should be of type ReasonFlags.");
263 }
264
265 } else if (name.equalsIgnoreCase(INDIRECT_CRL)) {
266 if (!(obj instanceof Boolean)) {
267 throw new IOException(
268 "Attribute value should be of type Boolean.");
269 }
270 isIndirectCRL = ((Boolean)obj).booleanValue();
271
272 } else if (name.equalsIgnoreCase(ONLY_USER_CERTS)) {
273 if (!(obj instanceof Boolean)) {
274 throw new IOException(
275 "Attribute value should be of type Boolean.");
276 }
277 hasOnlyUserCerts = ((Boolean)obj).booleanValue();
278
279 } else if (name.equalsIgnoreCase(ONLY_CA_CERTS)) {
280 if (!(obj instanceof Boolean)) {
281 throw new IOException(
282 "Attribute value should be of type Boolean.");
283 }
284 hasOnlyCACerts = ((Boolean)obj).booleanValue();
285
286 } else if (name.equalsIgnoreCase(ONLY_ATTRIBUTE_CERTS)) {
287 if (!(obj instanceof Boolean)) {
288 throw new IOException(
289 "Attribute value should be of type Boolean.");
290 }
291 hasOnlyAttributeCerts = ((Boolean)obj).booleanValue();
292
293
294 } else {
295 throw new IOException("Attribute name [" + name +
296 "] not recognized by " +
297 "CertAttrSet:IssuingDistributionPointExtension.");
298 }
299 encodeThis();
300 }
301
302 /**
303 * Gets the attribute value.
304 */
305 public Object get(String name) throws IOException {
306 if (name.equalsIgnoreCase(POINT)) {
307 return distributionPoint;
308
309 } else if (name.equalsIgnoreCase(INDIRECT_CRL)) {
310 return Boolean.valueOf(isIndirectCRL);
311
312 } else if (name.equalsIgnoreCase(REASONS)) {
313 return revocationReasons;
314
315 } else if (name.equalsIgnoreCase(ONLY_USER_CERTS)) {
316 return Boolean.valueOf(hasOnlyUserCerts);
317
318 } else if (name.equalsIgnoreCase(ONLY_CA_CERTS)) {
319 return Boolean.valueOf(hasOnlyCACerts);
320
321 } else if (name.equalsIgnoreCase(ONLY_ATTRIBUTE_CERTS)) {
322 return Boolean.valueOf(hasOnlyAttributeCerts);
323
324 } else {
325 throw new IOException("Attribute name [" + name +
326 "] not recognized by " +
327 "CertAttrSet:IssuingDistributionPointExtension.");
328 }
329 }
330
331 /**
332 * Deletes the attribute value.
333 */
334 public void delete(String name) throws IOException {
335 if (name.equalsIgnoreCase(POINT)) {
336 distributionPoint = null;
337
338 } else if (name.equalsIgnoreCase(INDIRECT_CRL)) {
339 isIndirectCRL = false;
340
341 } else if (name.equalsIgnoreCase(REASONS)) {
342 revocationReasons = null;
343
344 } else if (name.equalsIgnoreCase(ONLY_USER_CERTS)) {
345 hasOnlyUserCerts = false;
346
347 } else if (name.equalsIgnoreCase(ONLY_CA_CERTS)) {
348 hasOnlyCACerts = false;
349
350 } else if (name.equalsIgnoreCase(ONLY_ATTRIBUTE_CERTS)) {
351 hasOnlyAttributeCerts = false;
352
353 } else {
354 throw new IOException("Attribute name [" + name +
355 "] not recognized by " +
356 "CertAttrSet:IssuingDistributionPointExtension.");
357 }
358 encodeThis();
359 }
360
361 /**
362 * Returns an enumeration of names of attributes existing within this
363 * attribute.
364 */
365 public Enumeration<String> getElements() {
366 AttributeNameEnumeration elements = new AttributeNameEnumeration();
367 elements.addElement(POINT);
368 elements.addElement(REASONS);
369 elements.addElement(ONLY_USER_CERTS);
370 elements.addElement(ONLY_CA_CERTS);
371 elements.addElement(ONLY_ATTRIBUTE_CERTS);
372 elements.addElement(INDIRECT_CRL);
373 return elements.elements();
374 }
375
376 // Encodes this extension value
377 private void encodeThis() throws IOException {
378
379 if (distributionPoint == null &&
380 revocationReasons == null &&
381 !hasOnlyUserCerts &&
382 !hasOnlyCACerts &&
383 !hasOnlyAttributeCerts &&
384 !isIndirectCRL) {
385
386 this.extensionValue = null;
387 return;
388
389 }
390
391 DerOutputStream tagged = new DerOutputStream();
392
393 if (distributionPoint != null) {
394 DerOutputStream tmp = new DerOutputStream();
395 distributionPoint.encode(tmp);
396 tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, true,
397 TAG_DISTRIBUTION_POINT), tmp);
398 }
399
400 if (hasOnlyUserCerts) {
401 DerOutputStream tmp = new DerOutputStream();
402 tmp.putBoolean(hasOnlyUserCerts);
403 tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, false,
404 TAG_ONLY_USER_CERTS), tmp);
405 }
406
407 if (hasOnlyCACerts) {
408 DerOutputStream tmp = new DerOutputStream();
409 tmp.putBoolean(hasOnlyCACerts);
410 tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, false,
411 TAG_ONLY_CA_CERTS), tmp);
412 }
413
414 if (revocationReasons != null) {
415 DerOutputStream tmp = new DerOutputStream();
416 revocationReasons.encode(tmp);
417 tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, false,
418 TAG_ONLY_SOME_REASONS), tmp);
419 }
420
421 if (isIndirectCRL) {
422 DerOutputStream tmp = new DerOutputStream();
423 tmp.putBoolean(isIndirectCRL);
424 tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, false,
425 TAG_INDIRECT_CRL), tmp);
426 }
427
428 if (hasOnlyAttributeCerts) {
429 DerOutputStream tmp = new DerOutputStream();
430 tmp.putBoolean(hasOnlyAttributeCerts);
431 tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, false,
432 TAG_ONLY_ATTRIBUTE_CERTS), tmp);
433 }
434
435 DerOutputStream seq = new DerOutputStream();
436 seq.write(DerValue.tag_Sequence, tagged);
437 this.extensionValue = seq.toByteArray();
438 }
439
440 /**
441 * Returns the extension as user readable string.
442 */
443 public String toString() {
444
445 StringBuilder sb = new StringBuilder(super.toString());
446 sb.append("IssuingDistributionPoint [\n ");
447
448 if (distributionPoint != null) {
449 sb.append(distributionPoint);
450 }
451
452 if (revocationReasons != null) {
453 sb.append(revocationReasons);
454 }
455
456 sb.append((hasOnlyUserCerts)
457 ? (" Only contains user certs: true")
458 : (" Only contains user certs: false")).append("\n");
459
460 sb.append((hasOnlyCACerts)
461 ? (" Only contains CA certs: true")
462 : (" Only contains CA certs: false")).append("\n");
463
464 sb.append((hasOnlyAttributeCerts)
465 ? (" Only contains attribute certs: true")
466 : (" Only contains attribute certs: false")).append("\n");
467
468 sb.append((isIndirectCRL)
469 ? (" Indirect CRL: true")
470 : (" Indirect CRL: false")).append("\n");
471
472 sb.append("]\n");
473
474 return sb.toString();
475 }
476
477}