1 /* 2 * Copyright (c) 2009, 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.Collections; 32 import java.util.*; 33 34 import sun.security.util.DerOutputStream; 35 import sun.security.util.DerValue; 36 37 /** 38 * The Subject Information Access Extension (OID = 1.3.6.1.5.5.7.1.11). 39 * <p> 40 * The subject information access extension indicates how to access 41 * information and services for the subject of the certificate in which 42 * the extension appears. When the subject is a CA, information and 43 * services may include certificate validation services and CA policy 44 * data. When the subject is an end entity, the information describes 45 * the type of services offered and how to access them. In this case, 46 * the contents of this extension are defined in the protocol 47 * specifications for the supported services. This extension may be 48 * included in end entity or CA certificates. Conforming CAs MUST mark 49 * this extension as non-critical. 50 * <p> 51 * This extension is defined in <a href="http://www.ietf.org/rfc/rfc3280.txt"> 52 * Internet X.509 PKI Certificate and Certificate Revocation List 53 * (CRL) Profile</a>. The profile permits 54 * the extension to be included in end-entity or CA certificates, 55 * and it must be marked as non-critical. Its ASN.1 definition is as follows: 56 * <pre> 57 * id-pe-subjectInfoAccess OBJECT IDENTIFIER ::= { id-pe 11 } 58 * 59 * SubjectInfoAccessSyntax ::= 60 * SEQUENCE SIZE (1..MAX) OF AccessDescription 61 * 62 * AccessDescription ::= SEQUENCE { 63 * accessMethod OBJECT IDENTIFIER, 64 * accessLocation GeneralName } 65 * </pre> 66 * <p> 67 * @see Extension 68 * @see CertAttrSet 69 */ 70 71 public class SubjectInfoAccessExtension extends Extension 72 implements CertAttrSet<String> { 73 74 /** 75 * Identifier for this attribute, to be used with the 76 * get, set, delete methods of Certificate, x509 type. 77 */ 78 public static final String IDENT = 79 "x509.info.extensions.SubjectInfoAccess"; 80 81 /** 82 * Attribute name. 83 */ 84 public static final String NAME = "SubjectInfoAccess"; 85 public static final String DESCRIPTIONS = "descriptions"; 86 87 /** 88 * The List of AccessDescription objects. 89 */ 90 private List<AccessDescription> accessDescriptions; 91 92 /** 93 * Create an SubjectInfoAccessExtension from a List of 94 * AccessDescription; the criticality is set to false. 95 * 96 * @param accessDescriptions the List of AccessDescription 97 * @throws IOException on error 98 */ SubjectInfoAccessExtension( List<AccessDescription> accessDescriptions)99 public SubjectInfoAccessExtension( 100 List<AccessDescription> accessDescriptions) throws IOException { 101 this.extensionId = PKIXExtensions.SubjectInfoAccess_Id; 102 this.critical = false; 103 this.accessDescriptions = accessDescriptions; 104 encodeThis(); 105 } 106 107 /** 108 * Create the extension from the passed DER encoded value of the same. 109 * 110 * @param critical true if the extension is to be treated as critical. 111 * @param value Array of DER encoded bytes of the actual value. 112 * @exception IOException on error. 113 */ SubjectInfoAccessExtension(Boolean critical, Object value)114 public SubjectInfoAccessExtension(Boolean critical, Object value) 115 throws IOException { 116 this.extensionId = PKIXExtensions.SubjectInfoAccess_Id; 117 this.critical = critical.booleanValue(); 118 119 if (!(value instanceof byte[])) { 120 throw new IOException("Illegal argument type"); 121 } 122 123 extensionValue = (byte[])value; 124 DerValue val = new DerValue(extensionValue); 125 if (val.tag != DerValue.tag_Sequence) { 126 throw new IOException("Invalid encoding for " + 127 "SubjectInfoAccessExtension."); 128 } 129 accessDescriptions = new ArrayList<AccessDescription>(); 130 while (val.data.available() != 0) { 131 DerValue seq = val.data.getDerValue(); 132 AccessDescription accessDescription = new AccessDescription(seq); 133 accessDescriptions.add(accessDescription); 134 } 135 } 136 137 /** 138 * Return the list of AccessDescription objects. 139 */ getAccessDescriptions()140 public List<AccessDescription> getAccessDescriptions() { 141 return accessDescriptions; 142 } 143 144 /** 145 * Return the name of this attribute. 146 */ getName()147 public String getName() { 148 return NAME; 149 } 150 151 /** 152 * Write the extension to the DerOutputStream. 153 * 154 * @param out the DerOutputStream to write the extension to. 155 * @exception IOException on encoding errors. 156 */ encode(OutputStream out)157 public void encode(OutputStream out) throws IOException { 158 DerOutputStream tmp = new DerOutputStream(); 159 if (this.extensionValue == null) { 160 this.extensionId = PKIXExtensions.SubjectInfoAccess_Id; 161 this.critical = false; 162 encodeThis(); 163 } 164 super.encode(tmp); 165 out.write(tmp.toByteArray()); 166 } 167 168 /** 169 * Set the attribute value. 170 */ 171 @SuppressWarnings("unchecked") // Checked with instanceof set(String name, Object obj)172 public void set(String name, Object obj) throws IOException { 173 if (name.equalsIgnoreCase(DESCRIPTIONS)) { 174 if (!(obj instanceof List)) { 175 throw new IOException("Attribute value should be of type List."); 176 } 177 accessDescriptions = (List<AccessDescription>)obj; 178 } else { 179 throw new IOException("Attribute name [" + name + 180 "] not recognized by " + 181 "CertAttrSet:SubjectInfoAccessExtension."); 182 } 183 encodeThis(); 184 } 185 186 /** 187 * Get the attribute value. 188 */ get(String name)189 public List<AccessDescription> get(String name) throws IOException { 190 if (name.equalsIgnoreCase(DESCRIPTIONS)) { 191 return accessDescriptions; 192 } else { 193 throw new IOException("Attribute name [" + name + 194 "] not recognized by " + 195 "CertAttrSet:SubjectInfoAccessExtension."); 196 } 197 } 198 199 /** 200 * Delete the attribute value. 201 */ delete(String name)202 public void delete(String name) throws IOException { 203 if (name.equalsIgnoreCase(DESCRIPTIONS)) { 204 accessDescriptions = 205 Collections.<AccessDescription>emptyList(); 206 } else { 207 throw new IOException("Attribute name [" + name + 208 "] not recognized by " + 209 "CertAttrSet:SubjectInfoAccessExtension."); 210 } 211 encodeThis(); 212 } 213 214 /** 215 * Return an enumeration of names of attributes existing within this 216 * attribute. 217 */ getElements()218 public Enumeration<String> getElements() { 219 AttributeNameEnumeration elements = new AttributeNameEnumeration(); 220 elements.addElement(DESCRIPTIONS); 221 return elements.elements(); 222 } 223 224 // Encode this extension value encodeThis()225 private void encodeThis() throws IOException { 226 if (accessDescriptions.isEmpty()) { 227 this.extensionValue = null; 228 } else { 229 DerOutputStream ads = new DerOutputStream(); 230 for (AccessDescription accessDescription : accessDescriptions) { 231 accessDescription.encode(ads); 232 } 233 DerOutputStream seq = new DerOutputStream(); 234 seq.write(DerValue.tag_Sequence, ads); 235 this.extensionValue = seq.toByteArray(); 236 } 237 } 238 239 /** 240 * Return the extension as user readable string. 241 */ toString()242 public String toString() { 243 return super.toString() + "SubjectInfoAccess [\n " 244 + accessDescriptions + "\n]\n"; 245 } 246 247 } 248