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 26package sun.security.x509; 27 28import java.io.IOException; 29import java.io.OutputStream; 30import java.util.*; 31 32import sun.security.util.DerValue; 33import 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 */ 69public class CertificatePoliciesExtension extends Extension 70implements 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. 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 */ 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 */ 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 */ 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 */ 159 public String toString() { 160 if (certPolicies == null) { 161 return ""; 162 } 163 164 StringBuilder sb = new StringBuilder(); 165 sb.append(super.toString()) 166 .append("CertificatePolicies [\n"); 167 for (PolicyInformation info : certPolicies) { 168 sb.append(info); 169 } 170 sb.append("]\n"); 171 return sb.toString(); 172 } 173 174 /** 175 * Write the extension to the DerOutputStream. 176 * 177 * @param out the DerOutputStream to write the extension to. 178 * @exception IOException on encoding errors. 179 */ 180 public void encode(OutputStream out) throws IOException { 181 DerOutputStream tmp = new DerOutputStream(); 182 if (extensionValue == null) { 183 extensionId = PKIXExtensions.CertificatePolicies_Id; 184 critical = false; 185 encodeThis(); 186 } 187 super.encode(tmp); 188 out.write(tmp.toByteArray()); 189 } 190 191 /** 192 * Set the attribute value. 193 */ 194 @SuppressWarnings("unchecked") // Checked with an instanceof check 195 public void set(String name, Object obj) throws IOException { 196 if (name.equalsIgnoreCase(POLICIES)) { 197 if (!(obj instanceof List)) { 198 throw new IOException("Attribute value should be of type List."); 199 } 200 certPolicies = (List<PolicyInformation>)obj; 201 } else { 202 throw new IOException("Attribute name [" + name + 203 "] not recognized by " + 204 "CertAttrSet:CertificatePoliciesExtension."); 205 } 206 encodeThis(); 207 } 208 209 /** 210 * Get the attribute value. 211 */ 212 public List<PolicyInformation> get(String name) throws IOException { 213 if (name.equalsIgnoreCase(POLICIES)) { 214 //XXXX May want to consider cloning this 215 return certPolicies; 216 } else { 217 throw new IOException("Attribute name [" + name + 218 "] not recognized by " + 219 "CertAttrSet:CertificatePoliciesExtension."); 220 } 221 } 222 223 /** 224 * Delete the attribute value. 225 */ 226 public void delete(String name) throws IOException { 227 if (name.equalsIgnoreCase(POLICIES)) { 228 certPolicies = null; 229 } else { 230 throw new IOException("Attribute name [" + name + 231 "] not recognized by " + 232 "CertAttrSet:CertificatePoliciesExtension."); 233 } 234 encodeThis(); 235 } 236 237 /** 238 * Return an enumeration of names of attributes existing within this 239 * attribute. 240 */ 241 public Enumeration<String> getElements() { 242 AttributeNameEnumeration elements = new AttributeNameEnumeration(); 243 elements.addElement(POLICIES); 244 245 return (elements.elements()); 246 } 247 248 /** 249 * Return the name of this attribute. 250 */ 251 public String getName() { 252 return (NAME); 253 } 254} 255