1/*
2 * Copyright (c) 1997, 2015, 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.*;
33
34/**
35 * Represent the Policy Mappings Extension.
36 *
37 * This extension, if present, identifies the certificate policies considered
38 * identical between the issuing and the subject CA.
39 * <p>Extensions are addiitonal attributes which can be inserted in a X509
40 * v3 certificate. For example a "Driving License Certificate" could have
41 * the driving license number as a extension.
42 *
43 * <p>Extensions are represented as a sequence of the extension identifier
44 * (Object Identifier), a boolean flag stating whether the extension is to
45 * be treated as being critical and the extension value itself (this is again
46 * a DER encoding of the extension value).
47 *
48 * @author Amit Kapoor
49 * @author Hemma Prafullchandra
50 * @see Extension
51 * @see CertAttrSet
52 */
53public class PolicyMappingsExtension extends Extension
54implements CertAttrSet<String> {
55    /**
56     * Identifier for this attribute, to be used with the
57     * get, set, delete methods of Certificate, x509 type.
58     */
59    public static final String IDENT = "x509.info.extensions.PolicyMappings";
60    /**
61     * Attribute names.
62     */
63    public static final String NAME = "PolicyMappings";
64    public static final String MAP = "map";
65
66    // Private data members
67    private List<CertificatePolicyMap> maps;
68
69    // Encode this extension value
70    private void encodeThis() throws IOException {
71        if (maps == null || maps.isEmpty()) {
72            this.extensionValue = null;
73            return;
74        }
75        DerOutputStream os = new DerOutputStream();
76        DerOutputStream tmp = new DerOutputStream();
77
78        for (CertificatePolicyMap map : maps) {
79            map.encode(tmp);
80        }
81
82        os.write(DerValue.tag_Sequence, tmp);
83        this.extensionValue = os.toByteArray();
84    }
85
86    /**
87     * Create a PolicyMappings with the List of CertificatePolicyMap.
88     *
89     * @param maps the List of CertificatePolicyMap.
90     */
91    public PolicyMappingsExtension(List<CertificatePolicyMap> maps)
92            throws IOException {
93        this.maps = maps;
94        this.extensionId = PKIXExtensions.PolicyMappings_Id;
95        this.critical = true;
96        encodeThis();
97    }
98
99    /**
100     * Create a default PolicyMappingsExtension.
101     */
102    public PolicyMappingsExtension() {
103        extensionId = PKIXExtensions.PolicyMappings_Id;
104        critical = true;
105        maps = Collections.<CertificatePolicyMap>emptyList();
106    }
107
108    /**
109     * Create the extension from the passed DER encoded value.
110     *
111     * @param critical true if the extension is to be treated as critical.
112     * @param value an array of DER encoded bytes of the actual value.
113     * @exception ClassCastException if value is not an array of bytes
114     * @exception IOException on error.
115     */
116    public PolicyMappingsExtension(Boolean critical, Object value)
117    throws IOException {
118        this.extensionId = PKIXExtensions.PolicyMappings_Id;
119        this.critical = critical.booleanValue();
120
121        this.extensionValue = (byte[]) value;
122        DerValue val = new DerValue(this.extensionValue);
123        if (val.tag != DerValue.tag_Sequence) {
124            throw new IOException("Invalid encoding for " +
125                                  "PolicyMappingsExtension.");
126        }
127        maps = new ArrayList<CertificatePolicyMap>();
128        while (val.data.available() != 0) {
129            DerValue seq = val.data.getDerValue();
130            CertificatePolicyMap map = new CertificatePolicyMap(seq);
131            maps.add(map);
132        }
133    }
134
135    /**
136     * Returns a printable representation of the policy map.
137     */
138    public String toString() {
139        if (maps == null) return "";
140        String s = super.toString() + "PolicyMappings [\n"
141                 + maps.toString() + "]\n";
142
143        return (s);
144    }
145
146    /**
147     * Write the extension to the OutputStream.
148     *
149     * @param out the OutputStream 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 (extensionValue == null) {
155            extensionId = PKIXExtensions.PolicyMappings_Id;
156            critical = true;
157            encodeThis();
158        }
159        super.encode(tmp);
160        out.write(tmp.toByteArray());
161    }
162
163    /**
164     * Set the attribute value.
165     */
166    @SuppressWarnings("unchecked") // Checked with instanceof
167    public void set(String name, Object obj) throws IOException {
168        if (name.equalsIgnoreCase(MAP)) {
169            if (!(obj instanceof List)) {
170              throw new IOException("Attribute value should be of" +
171                                    " type List.");
172            }
173            maps = (List<CertificatePolicyMap>)obj;
174        } else {
175          throw new IOException("Attribute name not recognized by " +
176                        "CertAttrSet:PolicyMappingsExtension.");
177        }
178        encodeThis();
179    }
180
181    /**
182     * Get the attribute value.
183     */
184    public List<CertificatePolicyMap> get(String name) throws IOException {
185        if (name.equalsIgnoreCase(MAP)) {
186            return (maps);
187        } else {
188          throw new IOException("Attribute name not recognized by " +
189                        "CertAttrSet:PolicyMappingsExtension.");
190        }
191    }
192
193    /**
194     * Delete the attribute value.
195     */
196    public void delete(String name) throws IOException {
197        if (name.equalsIgnoreCase(MAP)) {
198            maps = null;
199        } else {
200          throw new IOException("Attribute name not recognized by " +
201                        "CertAttrSet:PolicyMappingsExtension.");
202        }
203        encodeThis();
204    }
205
206    /**
207     * Return an enumeration of names of attributes existing within this
208     * attribute.
209     */
210    public Enumeration<String> getElements () {
211        AttributeNameEnumeration elements = new AttributeNameEnumeration();
212        elements.addElement(MAP);
213
214        return elements.elements();
215    }
216
217    /**
218     * Return the name of this attribute.
219     */
220    public String getName () {
221        return (NAME);
222    }
223}
224