Home | History | Annotate | Download | only in x509
      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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    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      */
    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      */
    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      */
    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
    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      */
    295     public String toString() {
    296         return super.toString() + extensionName + " [\n  "
    297                + distributionPoints + "]\n";
    298     }
    299 
    300 }
    301