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