1 /* 2 * Copyright (c) 2002, 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.x509; 27 28 import java.io.IOException; 29 import java.io.OutputStream; 30 31 import java.util.*; 32 import java.util.Collections; 33 34 import sun.security.util.DerOutputStream; 35 import sun.security.util.DerValue; 36 import sun.security.util.ObjectIdentifier; 37 38 /** 39 * Represent the CRL Distribution Points Extension (OID = 2.5.29.31). 40 * <p> 41 * The CRL distribution points extension identifies how CRL information 42 * is obtained. The extension SHOULD be non-critical, but the PKIX profile 43 * recommends support for this extension by CAs and applications. 44 * <p> 45 * For PKIX, if the cRLDistributionPoints extension contains a 46 * DistributionPointName of type URI, the following semantics MUST be 47 * assumed: the URI is a pointer to the current CRL for the associated 48 * reasons and will be issued by the associated cRLIssuer. The 49 * expected values for the URI conform to the following rules. The 50 * name MUST be a non-relative URL, and MUST follow the URL syntax and 51 * encoding rules specified in [RFC 1738]. The name must include both 52 * a scheme (e.g., "http" or "ftp") and a scheme-specific-part. The 53 * scheme- specific-part must include a fully qualified domain name or 54 * IP address as the host. As specified in [RFC 1738], the scheme 55 * name is not case-sensitive (e.g., "http" is equivalent to "HTTP"). 56 * The host part is also not case-sensitive, but other components of 57 * the scheme-specific-part may be case-sensitive. When comparing 58 * URIs, conforming implementations MUST compare the scheme and host 59 * without regard to case, but assume the remainder of the 60 * scheme-specific-part is case sensitive. Processing rules for other 61 * values are not defined by this specification. If the 62 * distributionPoint omits reasons, the CRL MUST include revocations 63 * for all reasons. If the distributionPoint omits cRLIssuer, the CRL 64 * MUST be issued by the CA that issued the certificate. 65 * <p> 66 * The ASN.1 definition for this is: 67 * <pre> 68 * id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 } 69 * 70 * cRLDistributionPoints ::= { 71 * CRLDistPointsSyntax } 72 * 73 * CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint 74 * </pre> 75 * <p> 76 * @author Anne Anderson 77 * @author Andreas Sterbenz 78 * @since 1.4.2 79 * @see DistributionPoint 80 * @see Extension 81 * @see CertAttrSet 82 */ 83 public class CRLDistributionPointsExtension extends Extension 84 implements CertAttrSet<String> { 85 86 /** 87 * Identifier for this attribute, to be used with the 88 * get, set, delete methods of Certificate, x509 type. 89 */ 90 public static final String IDENT = 91 "x509.info.extensions.CRLDistributionPoints"; 92 93 /** 94 * Attribute name. 95 */ 96 public static final String NAME = "CRLDistributionPoints"; 97 public static final String POINTS = "points"; 98 99 /** 100 * The List of DistributionPoint objects. 101 */ 102 private List<DistributionPoint> distributionPoints; 103 104 private String extensionName; 105 106 /** 107 * Create a CRLDistributionPointsExtension from a List of 108 * DistributionPoint; the criticality is set to false. 109 * 110 * @param distributionPoints the list of distribution points 111 * @throws IOException on error 112 */ CRLDistributionPointsExtension( List<DistributionPoint> distributionPoints)113 public CRLDistributionPointsExtension( 114 List<DistributionPoint> distributionPoints) throws IOException { 115 116 this(false, distributionPoints); 117 } 118 119 /** 120 * Create a CRLDistributionPointsExtension from a List of 121 * DistributionPoint. 122 * 123 * @param isCritical the criticality setting. 124 * @param distributionPoints the list of distribution points 125 * @throws IOException on error 126 */ CRLDistributionPointsExtension(boolean isCritical, List<DistributionPoint> distributionPoints)127 public CRLDistributionPointsExtension(boolean isCritical, 128 List<DistributionPoint> distributionPoints) throws IOException { 129 130 this(PKIXExtensions.CRLDistributionPoints_Id, isCritical, 131 distributionPoints, NAME); 132 } 133 134 /** 135 * Creates the extension (also called by the subclass). 136 */ CRLDistributionPointsExtension(ObjectIdentifier extensionId, boolean isCritical, List<DistributionPoint> distributionPoints, String extensionName)137 protected CRLDistributionPointsExtension(ObjectIdentifier extensionId, 138 boolean isCritical, List<DistributionPoint> distributionPoints, 139 String extensionName) throws IOException { 140 141 this.extensionId = extensionId; 142 this.critical = isCritical; 143 this.distributionPoints = distributionPoints; 144 encodeThis(); 145 this.extensionName = extensionName; 146 } 147 148 /** 149 * Create the extension from the passed DER encoded value of the same. 150 * 151 * @param critical true if the extension is to be treated as critical. 152 * @param value Array of DER encoded bytes of the actual value. 153 * @exception IOException on error. 154 */ CRLDistributionPointsExtension(Boolean critical, Object value)155 public CRLDistributionPointsExtension(Boolean critical, Object value) 156 throws IOException { 157 this(PKIXExtensions.CRLDistributionPoints_Id, critical, value, NAME); 158 } 159 160 /** 161 * Creates the extension (also called by the subclass). 162 */ CRLDistributionPointsExtension(ObjectIdentifier extensionId, Boolean critical, Object value, String extensionName)163 protected CRLDistributionPointsExtension(ObjectIdentifier extensionId, 164 Boolean critical, Object value, String extensionName) 165 throws IOException { 166 167 this.extensionId = extensionId; 168 this.critical = critical.booleanValue(); 169 170 if (!(value instanceof byte[])) { 171 throw new IOException("Illegal argument type"); 172 } 173 174 extensionValue = (byte[])value; 175 DerValue val = new DerValue(extensionValue); 176 if (val.tag != DerValue.tag_Sequence) { 177 throw new IOException("Invalid encoding for " + extensionName + 178 " extension."); 179 } 180 distributionPoints = new ArrayList<DistributionPoint>(); 181 while (val.data.available() != 0) { 182 DerValue seq = val.data.getDerValue(); 183 DistributionPoint point = new DistributionPoint(seq); 184 distributionPoints.add(point); 185 } 186 this.extensionName = extensionName; 187 } 188 189 /** 190 * Return the name of this attribute. 191 */ getName()192 public String getName() { 193 return extensionName; 194 } 195 196 /** 197 * Write the extension to the DerOutputStream. 198 * 199 * @param out the DerOutputStream to write the extension to. 200 * @exception IOException on encoding errors. 201 */ encode(OutputStream out)202 public void encode(OutputStream out) throws IOException { 203 encode(out, PKIXExtensions.CRLDistributionPoints_Id, false); 204 } 205 206 /** 207 * Write the extension to the DerOutputStream. 208 * (Also called by the subclass) 209 */ encode(OutputStream out, ObjectIdentifier extensionId, boolean isCritical)210 protected void encode(OutputStream out, ObjectIdentifier extensionId, 211 boolean isCritical) throws IOException { 212 213 DerOutputStream tmp = new DerOutputStream(); 214 if (this.extensionValue == null) { 215 this.extensionId = extensionId; 216 this.critical = isCritical; 217 encodeThis(); 218 } 219 super.encode(tmp); 220 out.write(tmp.toByteArray()); 221 } 222 223 /** 224 * Set the attribute value. 225 */ 226 @SuppressWarnings("unchecked") // Checked with instanceof set(String name, Object obj)227 public void set(String name, Object obj) throws IOException { 228 if (name.equalsIgnoreCase(POINTS)) { 229 if (!(obj instanceof List)) { 230 throw new IOException("Attribute value should be of type List."); 231 } 232 distributionPoints = (List<DistributionPoint>)obj; 233 } else { 234 throw new IOException("Attribute name [" + name + 235 "] not recognized by " + 236 "CertAttrSet:" + extensionName + "."); 237 } 238 encodeThis(); 239 } 240 241 /** 242 * Get the attribute value. 243 */ get(String name)244 public List<DistributionPoint> get(String name) throws IOException { 245 if (name.equalsIgnoreCase(POINTS)) { 246 return distributionPoints; 247 } else { 248 throw new IOException("Attribute name [" + name + 249 "] not recognized by " + 250 "CertAttrSet:" + extensionName + "."); 251 } 252 } 253 254 /** 255 * Delete the attribute value. 256 */ delete(String name)257 public void delete(String name) throws IOException { 258 if (name.equalsIgnoreCase(POINTS)) { 259 distributionPoints = 260 Collections.<DistributionPoint>emptyList(); 261 } else { 262 throw new IOException("Attribute name [" + name + 263 "] not recognized by " + 264 "CertAttrSet:" + extensionName + '.'); 265 } 266 encodeThis(); 267 } 268 269 /** 270 * Return an enumeration of names of attributes existing within this 271 * attribute. 272 */ getElements()273 public Enumeration<String> getElements() { 274 AttributeNameEnumeration elements = new AttributeNameEnumeration(); 275 elements.addElement(POINTS); 276 return elements.elements(); 277 } 278 279 // Encode this extension value encodeThis()280 private void encodeThis() throws IOException { 281 if (distributionPoints.isEmpty()) { 282 this.extensionValue = null; 283 } else { 284 DerOutputStream pnts = new DerOutputStream(); 285 for (DistributionPoint point : distributionPoints) { 286 point.encode(pnts); 287 } 288 DerOutputStream seq = new DerOutputStream(); 289 seq.write(DerValue.tag_Sequence, pnts); 290 this.extensionValue = seq.toByteArray(); 291 } 292 } 293 294 /** 295 * Return the extension as user readable string. 296 */ toString()297 public String toString() { 298 return super.toString() + extensionName + " [\n " 299 + distributionPoints + "]\n"; 300 } 301 302 } 303