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