TrustAnchor.java revision fd6bb3510c2f94d636f3572dcf5f7f4dcd1a2726
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.security.cert;
19
20import java.io.IOException;
21import java.security.PublicKey;
22
23import javax.security.auth.x500.X500Principal;
24
25import org.apache.harmony.security.internal.nls.Messages;
26import org.apache.harmony.security.utils.Array;
27import org.apache.harmony.security.x509.NameConstraints;
28
29
30
31/**
32 * This class represents a trust anchor for validation of X.509 certification
33 * path.
34 * <p>
35 * It is a <i>trusted</i> certificate authority (CA) and includes the public key
36 * of the CA, the CA's name and the constraints for the validation of
37 * certification paths. The constructor also allows to specify a binary
38 * representation of a so called "Name Constraints" extension as a byte array.
39 */
40public class TrustAnchor {
41    // Most trusted CA as a X500Principal
42    private final X500Principal caPrincipal;
43    // Most trusted CA name
44    private final String caName;
45    // Most trusted CA public key
46    private final PublicKey caPublicKey;
47    // Most trusted CA certificate
48    private final X509Certificate trustedCert;
49    // Name constraints extension
50    private final byte[] nameConstraints;
51
52    /**
53     * Creates a new {@code TrustAnchor} with the specified certificate and name
54     * constraints.
55     * <p>
56     * The name constraints will be used as additional constraints during the
57     * validation of certification paths.
58     *
59     * @param trustedCert
60     *            the trusted certificate
61     * @param nameConstraints
62     *            the ASN.1 DER encoded form of the name constraints or {@code
63     *            null} if none.
64     * @throws IllegalArgumentException
65     *             if the decoding of the name constraints fail.
66     */
67    public TrustAnchor(X509Certificate trustedCert, byte[] nameConstraints) {
68        if (trustedCert == null) {
69            throw new NullPointerException(Messages.getString("security.5C"));
70        }
71        this.trustedCert = trustedCert;
72        // copy nameConstraints if not null
73        if (nameConstraints != null) {
74            this.nameConstraints = new byte[nameConstraints.length];
75            System.arraycopy(nameConstraints, 0,
76                    this.nameConstraints, 0, this.nameConstraints.length);
77            processNameConstraints();
78        } else {
79            this.nameConstraints = null;
80        }
81        this.caName = null;
82        this.caPrincipal = null;
83        this.caPublicKey = null;
84    }
85
86    /**
87     * Creates a new {@code TrustAnchor} with the specified certificate
88     * authority name, its public key and the specified name constraints.
89     * <p>
90     * The name constraints will be used as additional constraints during the
91     * validation of certification paths.
92     *
93     * @param caName
94     *            the X.500 name of the certificate authority in RFC 2253
95     *            {@code String} format.
96     * @param caPublicKey
97     *            the public key of the certificate authority
98     * @param nameConstraints
99     *            the ASN.1 DER encoded form of the name constraints or {@code
100     *            null} if none.
101     * @throws IllegalArgumentException
102     *             if the {@code caName} is empty or if decoding of the name
103     *             constraints fail.
104     */
105    public TrustAnchor(String caName, PublicKey caPublicKey,
106            byte[] nameConstraints) {
107        if (caName == null) {
108            throw new NullPointerException(Messages.getString("security.5D"));
109        }
110        this.caName = caName;
111        if (caPublicKey == null) {
112            throw new NullPointerException(Messages.getString("security.5E"));
113        }
114        this.caPublicKey = caPublicKey;
115        // copy nameConstraints if not null
116        if (nameConstraints != null) {
117            this.nameConstraints = new byte[nameConstraints.length];
118            System.arraycopy(nameConstraints, 0,
119                    this.nameConstraints, 0, this.nameConstraints.length);
120            processNameConstraints();
121        } else {
122            this.nameConstraints = null;
123        }
124
125        this.trustedCert = null;
126
127        // X500Principal checks caName validity
128        if (caName.length() == 0) {
129            throw new IllegalArgumentException(
130                    Messages.getString("security.5F"));
131        }
132        this.caPrincipal = new X500Principal(this.caName);
133    }
134
135    /**
136     * Creates a new {@code TrustAnchor} with the specified certificate
137     * authority name as principal, its public key and the specified name
138     * constraints.
139     * <p>
140     * The name constraints will be used as additional constraints during the
141     * validation of certification paths.
142     *
143     * @param caPrincipal
144     *            the name of the certificate authority as X500 principal.
145     * @param caPublicKey
146     *            the public key of the certificate authority.
147     * @param nameConstraints
148     *            the ASN.1 DER encoded form of the name constraints or {@code
149     *            null} if none.
150     * @throws IllegalArgumentException
151     *             if decoding of the name constraints fail.
152     */
153    public TrustAnchor(X500Principal caPrincipal,
154            PublicKey caPublicKey, byte[] nameConstraints) {
155        if (caPrincipal == null) {
156            throw new NullPointerException(Messages.getString("security.60"));
157        }
158        this.caPrincipal = caPrincipal;
159        if (caPublicKey == null) {
160            throw new NullPointerException(Messages.getString("security.5E"));
161        }
162        this.caPublicKey = caPublicKey;
163        // copy nameConstraints if not null
164        if (nameConstraints != null) {
165            this.nameConstraints = new byte[nameConstraints.length];
166            System.arraycopy(nameConstraints, 0,
167                    this.nameConstraints, 0, this.nameConstraints.length);
168            processNameConstraints();
169        } else {
170            this.nameConstraints = null;
171        }
172
173        this.trustedCert = null;
174        this.caName = caPrincipal.getName();
175    }
176
177    /**
178     * Returns a copy of the name constraints in ASN.1 DER encoded form.
179     *
180     * @return a copy of the name constraints in ASN.1 DER encoded form.
181     */
182    public final byte[] getNameConstraints() {
183        if (nameConstraints == null) {
184            return null;
185        }
186        byte[] ret = new byte[nameConstraints.length];
187            System.arraycopy(nameConstraints, 0,
188                    ret, 0, nameConstraints.length);
189        return ret;
190    }
191
192    /**
193     * Returns the certificate of this <i>trusted</i> certificate authority.
194     *
195     * @return the certificate of this CA or {@code null}, if the trust anchor
196     *         of this instance was not created with a certificate.
197     */
198    public final X509Certificate getTrustedCert() {
199        return trustedCert;
200    }
201
202    /**
203     * Returns the name of the certificate authority as {@code X500Principal}.
204     *
205     * @return the name of the certificate authority or {@code null} if the
206     *         trust anchor of this instance was not created with a {@code
207     *         X500Principal}.
208     */
209    public final X500Principal getCA() {
210        return caPrincipal;
211    }
212
213    /**
214     * Returns the name of the certificate authority as {@code String} in RFC
215     * 2253 format.
216     *
217     * @return the name of the certificate authority as {@code String} in RFC
218     *         2253 format or {@code null} if the trust anchor of this instance
219     *         was not created with a CA name.
220     */
221    public final String getCAName() {
222        return caName;
223    }
224
225    /**
226     * Returns the public key of the certificate authority.
227     *
228     * @return the public key of the certificate authority or {@code null} if
229     *         the trust anchor if this instance was not created with a public
230     *         key.
231     */
232    public final PublicKey getCAPublicKey() {
233        return caPublicKey;
234    }
235
236    /**
237     * Returns a string representation of this {@code TrustAnchor} instance.
238     *
239     * @return a string representation of this {@code TrustAnchor} instance.
240     */
241    public String toString() {
242        StringBuilder sb = new StringBuilder("TrustAnchor: [\n");
243        if (trustedCert != null) {
244            sb.append("Trusted CA certificate: ");
245            sb.append(trustedCert);
246            sb.append("\n");
247        }
248        if (caPrincipal != null) {
249            sb.append("Trusted CA Name: ");
250            sb.append(caPrincipal);
251            sb.append("\n");
252        }
253        if (caPublicKey != null) {
254            sb.append("Trusted CA Public Key: ");
255            sb.append(caPublicKey);
256            sb.append("\n");
257        }
258        // FIXME if needed:
259        if (nameConstraints != null) {
260            sb.append("Name Constraints:\n");
261            sb.append(Array.toString(nameConstraints, "    "));
262        }
263        sb.append("\n]");
264        return sb.toString();
265    }
266
267    //
268    // Private stuff
269    //
270
271    // Decodes and checks NameConstraints structure.
272    // Throws IllegalArgumentException if NameConstraints
273    // encoding is invalid.
274    private void processNameConstraints() {
275        try {
276            // decode and check nameConstraints
277            NameConstraints.ASN1.decode(nameConstraints);
278        } catch (IOException e) {
279            throw new IllegalArgumentException(e.getMessage());
280        }
281    }
282}
283