1 /* 2 * Copyright (c) 2000, 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.util.*; 31 32 import sun.security.util.DerValue; 33 import sun.security.util.DerOutputStream; 34 35 /** 36 * This class defines the certificate policies extension which specifies the 37 * policies under which the certificate has been issued 38 * and the purposes for which the certificate may be used. 39 * <p> 40 * Applications with specific policy requirements are expected to have a 41 * list of those policies which they will accept and to compare the 42 * policy OIDs in the certificate to that list. If this extension is 43 * critical, the path validation software MUST be able to interpret this 44 * extension (including the optional qualifier), or MUST reject the 45 * certificate. 46 * <p> 47 * Optional qualifiers are not supported in this implementation, as they are 48 * not recommended by RFC2459. 49 * 50 * The ASN.1 syntax for this is (IMPLICIT tagging is defined in the 51 * module definition): 52 * <pre> 53 * id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } 54 * 55 * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation 56 * 57 * PolicyInformation ::= SEQUENCE { 58 * policyIdentifier CertPolicyId, 59 * policyQualifiers SEQUENCE SIZE (1..MAX) OF 60 * PolicyQualifierInfo OPTIONAL } 61 * 62 * CertPolicyId ::= OBJECT IDENTIFIER 63 * </pre> 64 * @author Anne Anderson 65 * @since 1.4 66 * @see Extension 67 * @see CertAttrSet 68 */ 69 public class CertificatePoliciesExtension extends Extension 70 implements CertAttrSet<String> { 71 /** 72 * Identifier for this attribute, to be used with the 73 * get, set, delete methods of Certificate, x509 type. 74 */ 75 public static final String IDENT = "x509.info.extensions.CertificatePolicies"; 76 /** 77 * Attribute names. 78 */ 79 public static final String NAME = "CertificatePolicies"; 80 public static final String POLICIES = "policies"; 81 82 /** 83 * List of PolicyInformation for this object. 84 */ 85 private List<PolicyInformation> certPolicies; 86 87 // Encode this extension value. encodeThis()88 private void encodeThis() throws IOException { 89 if (certPolicies == null || certPolicies.isEmpty()) { 90 this.extensionValue = null; 91 } else { 92 DerOutputStream os = new DerOutputStream(); 93 DerOutputStream tmp = new DerOutputStream(); 94 95 for (PolicyInformation info : certPolicies) { 96 info.encode(tmp); 97 } 98 99 os.write(DerValue.tag_Sequence, tmp); 100 this.extensionValue = os.toByteArray(); 101 } 102 } 103 104 /** 105 * Create a CertificatePoliciesExtension object from 106 * a List of PolicyInformation; the criticality is set to false. 107 * 108 * @param certPolicies the List of PolicyInformation. 109 */ CertificatePoliciesExtension(List<PolicyInformation> certPolicies)110 public CertificatePoliciesExtension(List<PolicyInformation> certPolicies) 111 throws IOException { 112 this(Boolean.FALSE, certPolicies); 113 } 114 115 /** 116 * Create a CertificatePoliciesExtension object from 117 * a List of PolicyInformation with specified criticality. 118 * 119 * @param critical true if the extension is to be treated as critical. 120 * @param certPolicies the List of PolicyInformation. 121 */ CertificatePoliciesExtension(Boolean critical, List<PolicyInformation> certPolicies)122 public CertificatePoliciesExtension(Boolean critical, 123 List<PolicyInformation> certPolicies) throws IOException { 124 this.certPolicies = certPolicies; 125 this.extensionId = PKIXExtensions.CertificatePolicies_Id; 126 this.critical = critical.booleanValue(); 127 encodeThis(); 128 } 129 130 /** 131 * Create the extension from its DER encoded value and criticality. 132 * 133 * @param critical true if the extension is to be treated as critical. 134 * @param value an array of DER encoded bytes of the actual value. 135 * @exception ClassCastException if value is not an array of bytes 136 * @exception IOException on error. 137 */ CertificatePoliciesExtension(Boolean critical, Object value)138 public CertificatePoliciesExtension(Boolean critical, Object value) 139 throws IOException { 140 this.extensionId = PKIXExtensions.CertificatePolicies_Id; 141 this.critical = critical.booleanValue(); 142 this.extensionValue = (byte[]) value; 143 DerValue val = new DerValue(this.extensionValue); 144 if (val.tag != DerValue.tag_Sequence) { 145 throw new IOException("Invalid encoding for " + 146 "CertificatePoliciesExtension."); 147 } 148 certPolicies = new ArrayList<PolicyInformation>(); 149 while (val.data.available() != 0) { 150 DerValue seq = val.data.getDerValue(); 151 PolicyInformation policy = new PolicyInformation(seq); 152 certPolicies.add(policy); 153 } 154 } 155 156 /** 157 * Return the extension as user readable string. 158 */ toString()159 public String toString() { 160 if (certPolicies == null) { 161 return ""; 162 } 163 StringBuilder sb = new StringBuilder(super.toString()); 164 sb.append("CertificatePolicies [\n"); 165 for (PolicyInformation info : certPolicies) { 166 sb.append(info.toString()); 167 } 168 sb.append("]\n"); 169 return sb.toString(); 170 } 171 172 /** 173 * Write the extension to the DerOutputStream. 174 * 175 * @param out the DerOutputStream to write the extension to. 176 * @exception IOException on encoding errors. 177 */ encode(OutputStream out)178 public void encode(OutputStream out) throws IOException { 179 DerOutputStream tmp = new DerOutputStream(); 180 if (extensionValue == null) { 181 extensionId = PKIXExtensions.CertificatePolicies_Id; 182 critical = false; 183 encodeThis(); 184 } 185 super.encode(tmp); 186 out.write(tmp.toByteArray()); 187 } 188 189 /** 190 * Set the attribute value. 191 */ 192 @SuppressWarnings("unchecked") // Checked with an instanceof check set(String name, Object obj)193 public void set(String name, Object obj) throws IOException { 194 if (name.equalsIgnoreCase(POLICIES)) { 195 if (!(obj instanceof List)) { 196 throw new IOException("Attribute value should be of type List."); 197 } 198 certPolicies = (List<PolicyInformation>)obj; 199 } else { 200 throw new IOException("Attribute name [" + name + 201 "] not recognized by " + 202 "CertAttrSet:CertificatePoliciesExtension."); 203 } 204 encodeThis(); 205 } 206 207 /** 208 * Get the attribute value. 209 */ get(String name)210 public List<PolicyInformation> get(String name) throws IOException { 211 if (name.equalsIgnoreCase(POLICIES)) { 212 //XXXX May want to consider cloning this 213 return certPolicies; 214 } else { 215 throw new IOException("Attribute name [" + name + 216 "] not recognized by " + 217 "CertAttrSet:CertificatePoliciesExtension."); 218 } 219 } 220 221 /** 222 * Delete the attribute value. 223 */ delete(String name)224 public void delete(String name) throws IOException { 225 if (name.equalsIgnoreCase(POLICIES)) { 226 certPolicies = null; 227 } else { 228 throw new IOException("Attribute name [" + name + 229 "] not recognized by " + 230 "CertAttrSet:CertificatePoliciesExtension."); 231 } 232 encodeThis(); 233 } 234 235 /** 236 * Return an enumeration of names of attributes existing within this 237 * attribute. 238 */ getElements()239 public Enumeration<String> getElements() { 240 AttributeNameEnumeration elements = new AttributeNameEnumeration(); 241 elements.addElement(POLICIES); 242 243 return (elements.elements()); 244 } 245 246 /** 247 * Return the name of this attribute. 248 */ getName()249 public String getName() { 250 return (NAME); 251 } 252 } 253