1 /* 2 * Copyright (c) 2005, 2006, 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.x509; 27 28 import java.io.IOException; 29 import java.io.OutputStream; 30 31 import java.util.*; 32 33 import sun.security.util.DerInputStream; 34 import sun.security.util.DerOutputStream; 35 import 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 50 ate 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 */ 69 public 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 */ IssuingDistributionPointExtension( DistributionPointName distributionPoint, ReasonFlags revocationReasons, boolean hasOnlyUserCerts, boolean hasOnlyCACerts, boolean hasOnlyAttributeCerts, boolean isIndirectCRL)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 */ IssuingDistributionPointExtension(Boolean critical, Object value)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 */ getName()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 */ encode(OutputStream out)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 */ set(String name, Object obj)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 revocationReasons = (ReasonFlags)obj; 265 266 } else if (name.equalsIgnoreCase(INDIRECT_CRL)) { 267 if (!(obj instanceof Boolean)) { 268 throw new IOException( 269 "Attribute value should be of type Boolean."); 270 } 271 isIndirectCRL = ((Boolean)obj).booleanValue(); 272 273 } else if (name.equalsIgnoreCase(ONLY_USER_CERTS)) { 274 if (!(obj instanceof Boolean)) { 275 throw new IOException( 276 "Attribute value should be of type Boolean."); 277 } 278 hasOnlyUserCerts = ((Boolean)obj).booleanValue(); 279 280 } else if (name.equalsIgnoreCase(ONLY_CA_CERTS)) { 281 if (!(obj instanceof Boolean)) { 282 throw new IOException( 283 "Attribute value should be of type Boolean."); 284 } 285 hasOnlyCACerts = ((Boolean)obj).booleanValue(); 286 287 } else if (name.equalsIgnoreCase(ONLY_ATTRIBUTE_CERTS)) { 288 if (!(obj instanceof Boolean)) { 289 throw new IOException( 290 "Attribute value should be of type Boolean."); 291 } 292 hasOnlyAttributeCerts = ((Boolean)obj).booleanValue(); 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 */ get(String name)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 */ delete(String name)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 */ getElements()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 encodeThis()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 */ toString()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 } 478