Home | History | Annotate | Download | only in x509
      1 /*
      2  * Copyright (c) 1997, 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 import java.security.cert.CertificateException;
     31 import java.util.Enumeration;
     32 import java.util.Vector;
     33 
     34 import sun.security.util.*;
     35 
     36 /**
     37  * This class defines the certificate extension which specifies the
     38  * Policy constraints.
     39  * <p>
     40  * The policy constraints extension can be used in certificates issued
     41  * to CAs. The policy constraints extension constrains path validation
     42  * in two ways. It can be used to prohibit policy mapping or require
     43  * that each certificate in a path contain an acceptable policy
     44  * identifier.<p>
     45  * The ASN.1 syntax for this is (IMPLICIT tagging is defined in the
     46  * module definition):
     47  * <pre>
     48  * PolicyConstraints ::= SEQUENCE {
     49  *     requireExplicitPolicy [0] SkipCerts OPTIONAL,
     50  *     inhibitPolicyMapping  [1] SkipCerts OPTIONAL
     51  * }
     52  * SkipCerts ::= INTEGER (0..MAX)
     53  * </pre>
     54  * @author Amit Kapoor
     55  * @author Hemma Prafullchandra
     56  * @see Extension
     57  * @see CertAttrSet
     58  */
     59 public class PolicyConstraintsExtension extends Extension
     60 implements CertAttrSet<String> {
     61     /**
     62      * Identifier for this attribute, to be used with the
     63      * get, set, delete methods of Certificate, x509 type.
     64      */
     65     public static final String IDENT = "x509.info.extensions.PolicyConstraints";
     66     /**
     67      * Attribute names.
     68      */
     69     public static final String NAME = "PolicyConstraints";
     70     public static final String REQUIRE = "require";
     71     public static final String INHIBIT = "inhibit";
     72 
     73     private static final byte TAG_REQUIRE = 0;
     74     private static final byte TAG_INHIBIT = 1;
     75 
     76     private int require = -1;
     77     private int inhibit = -1;
     78 
     79     // Encode this extension value.
     80     private void encodeThis() throws IOException {
     81         if (require == -1 && inhibit == -1) {
     82             this.extensionValue = null;
     83             return;
     84         }
     85         DerOutputStream tagged = new DerOutputStream();
     86         DerOutputStream seq = new DerOutputStream();
     87 
     88         if (require != -1) {
     89             DerOutputStream tmp = new DerOutputStream();
     90             tmp.putInteger(require);
     91             tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
     92                          false, TAG_REQUIRE), tmp);
     93         }
     94         if (inhibit != -1) {
     95             DerOutputStream tmp = new DerOutputStream();
     96             tmp.putInteger(inhibit);
     97             tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
     98                          false, TAG_INHIBIT), tmp);
     99         }
    100         seq.write(DerValue.tag_Sequence, tagged);
    101         this.extensionValue = seq.toByteArray();
    102     }
    103 
    104     /**
    105      * Create a PolicyConstraintsExtension object with both
    106      * require explicit policy and inhibit policy mapping. The
    107      * extension is marked non-critical.
    108      *
    109      * @param require require explicit policy (-1 for optional).
    110      * @param inhibit inhibit policy mapping (-1 for optional).
    111      */
    112     public PolicyConstraintsExtension(int require, int inhibit)
    113     throws IOException {
    114         this(Boolean.FALSE, require, inhibit);
    115     }
    116 
    117     /**
    118      * Create a PolicyConstraintsExtension object with specified
    119      * criticality and both require explicit policy and inhibit
    120      * policy mapping.
    121      *
    122      * @param critical true if the extension is to be treated as critical.
    123      * @param require require explicit policy (-1 for optional).
    124      * @param inhibit inhibit policy mapping (-1 for optional).
    125      */
    126     public PolicyConstraintsExtension(Boolean critical, int require, int inhibit)
    127     throws IOException {
    128         this.require = require;
    129         this.inhibit = inhibit;
    130         this.extensionId = PKIXExtensions.PolicyConstraints_Id;
    131         this.critical = critical.booleanValue();
    132         encodeThis();
    133     }
    134 
    135     /**
    136      * Create the extension from its DER encoded value and criticality.
    137      *
    138      * @param critical true if the extension is to be treated as critical.
    139      * @param value an array of DER encoded bytes of the actual value.
    140      * @exception ClassCastException if value is not an array of bytes
    141      * @exception IOException on error.
    142      */
    143     public PolicyConstraintsExtension(Boolean critical, Object value)
    144     throws IOException {
    145         this.extensionId = PKIXExtensions.PolicyConstraints_Id;
    146         this.critical = critical.booleanValue();
    147 
    148         this.extensionValue = (byte[]) value;
    149         DerValue val = new DerValue(this.extensionValue);
    150         if (val.tag != DerValue.tag_Sequence) {
    151             throw new IOException("Sequence tag missing for PolicyConstraint.");
    152         }
    153         DerInputStream in = val.data;
    154         while (in != null && in.available() != 0) {
    155             DerValue next = in.getDerValue();
    156 
    157             if (next.isContextSpecific(TAG_REQUIRE) && !next.isConstructed()) {
    158                 if (this.require != -1)
    159                     throw new IOException("Duplicate requireExplicitPolicy" +
    160                           "found in the PolicyConstraintsExtension");
    161                 next.resetTag(DerValue.tag_Integer);
    162                 this.require = next.getInteger();
    163 
    164             } else if (next.isContextSpecific(TAG_INHIBIT) &&
    165                        !next.isConstructed()) {
    166                 if (this.inhibit != -1)
    167                     throw new IOException("Duplicate inhibitPolicyMapping" +
    168                           "found in the PolicyConstraintsExtension");
    169                 next.resetTag(DerValue.tag_Integer);
    170                 this.inhibit = next.getInteger();
    171             } else
    172                 throw new IOException("Invalid encoding of PolicyConstraint");
    173         }
    174     }
    175 
    176     /**
    177      * Return the extension as user readable string.
    178      */
    179     public String toString() {
    180         String s;
    181         s = super.toString() + "PolicyConstraints: [" + "  Require: ";
    182         if (require == -1)
    183             s += "unspecified;";
    184         else
    185             s += require + ";";
    186         s += "\tInhibit: ";
    187         if (inhibit == -1)
    188             s += "unspecified";
    189         else
    190             s += inhibit;
    191         s += " ]\n";
    192         return s;
    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         DerOutputStream tmp = new DerOutputStream();
    203         if (extensionValue == null) {
    204           extensionId = PKIXExtensions.PolicyConstraints_Id;
    205           critical = false;
    206           encodeThis();
    207         }
    208         super.encode(tmp);
    209         out.write(tmp.toByteArray());
    210     }
    211 
    212     /**
    213      * Set the attribute value.
    214      */
    215     public void set(String name, Object obj) throws IOException {
    216         if (!(obj instanceof Integer)) {
    217             throw new IOException("Attribute value should be of type Integer.");
    218         }
    219         if (name.equalsIgnoreCase(REQUIRE)) {
    220             require = ((Integer)obj).intValue();
    221         } else if (name.equalsIgnoreCase(INHIBIT)) {
    222             inhibit = ((Integer)obj).intValue();
    223         } else {
    224           throw new IOException("Attribute name " + "[" + name + "]" +
    225                                 " not recognized by " +
    226                                 "CertAttrSet:PolicyConstraints.");
    227         }
    228         encodeThis();
    229     }
    230 
    231     /**
    232      * Get the attribute value.
    233      */
    234     public Integer get(String name) throws IOException {
    235         if (name.equalsIgnoreCase(REQUIRE)) {
    236             return new Integer(require);
    237         } else if (name.equalsIgnoreCase(INHIBIT)) {
    238             return new Integer(inhibit);
    239         } else {
    240           throw new IOException("Attribute name not recognized by " +
    241                                 "CertAttrSet:PolicyConstraints.");
    242         }
    243     }
    244 
    245     /**
    246      * Delete the attribute value.
    247      */
    248     public void delete(String name) throws IOException {
    249         if (name.equalsIgnoreCase(REQUIRE)) {
    250             require = -1;
    251         } else if (name.equalsIgnoreCase(INHIBIT)) {
    252             inhibit = -1;
    253         } else {
    254           throw new IOException("Attribute name not recognized by " +
    255                                 "CertAttrSet:PolicyConstraints.");
    256         }
    257         encodeThis();
    258     }
    259 
    260     /**
    261      * Return an enumeration of names of attributes existing within this
    262      * attribute.
    263      */
    264     public Enumeration<String> getElements() {
    265         AttributeNameEnumeration elements = new AttributeNameEnumeration();
    266         elements.addElement(REQUIRE);
    267         elements.addElement(INHIBIT);
    268 
    269         return (elements.elements());
    270     }
    271 
    272     /**
    273      * Return the name of this attribute.
    274      */
    275     public String getName() {
    276         return (NAME);
    277     }
    278 }
    279