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