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