TrustedCertificateIndex.java revision 21f21e9f56ab8c9abfd8728473533fcaafafeac0
106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom/*
206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * Copyright (C) 2009 The Android Open Source Project
306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom *
406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License");
506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * you may not use this file except in compliance with the License.
606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * You may obtain a copy of the License at
706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom *
806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom *      http://www.apache.org/licenses/LICENSE-2.0
906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom *
1006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * Unless required by applicable law or agreed to in writing, software
1106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS,
1206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * See the License for the specific language governing permissions and
1406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * limitations under the License.
1506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom */
1606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
1706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrompackage org.apache.harmony.xnet.provider.jsse;
1806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
197365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.security.InvalidAlgorithmParameterException;
20a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstromimport java.security.PublicKey;
2106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.CertPathValidatorException;
2206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.PKIXParameters;
2306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.TrustAnchor;
2406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.X509Certificate;
2506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.ArrayList;
2606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.Arrays;
27a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstromimport java.util.Collection;
2806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.HashMap;
2906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.List;
3006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.Map;
3106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.Set;
327365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport javax.security.auth.x500.X500Principal;
3306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
3406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom/**
3506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * Indexes trust anchors so they can be found in O(1) time instead of O(N).
3606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom */
3790ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrompublic final class IndexedPKIXParameters extends PKIXParameters {
3806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
39a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom    private final Map<X500Principal, List<TrustAnchor>> subjectToTrustAnchors
4006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            = new HashMap<X500Principal, List<TrustAnchor>>();
4106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
4206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    public IndexedPKIXParameters(Set<TrustAnchor> anchors)
43a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            throws InvalidAlgorithmParameterException {
4406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        super(anchors);
45a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        index();
46a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom    }
4706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
48a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom    private void index() {
49a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        for (TrustAnchor anchor : getTrustAnchors()) {
5090ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            index(anchor);
5190ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        }
5290ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom    }
5390ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom
5490ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom    public void index(TrustAnchor anchor) {
5590ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        X500Principal subject;
5690ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        X509Certificate cert = anchor.getTrustedCert();
5790ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        if (cert != null) {
5890ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            subject = cert.getSubjectX500Principal();
5990ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        } else {
6090ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            subject = anchor.getCA();
6190ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        }
6206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
6390ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        synchronized (subjectToTrustAnchors) {
64a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject);
65a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            if (anchors == null) {
6621f21e9f56ab8c9abfd8728473533fcaafafeac0Jesse Wilson                anchors = new ArrayList<TrustAnchor>(1);
67a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                subjectToTrustAnchors.put(subject, anchors);
6806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            }
69a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            anchors.add(anchor);
7006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
7106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    }
7206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
7306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    public TrustAnchor findTrustAnchor(X509Certificate cert)
7406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            throws CertPathValidatorException {
7506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        X500Principal issuer = cert.getIssuerX500Principal();
76a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        Exception verificationException = null;
7790ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        synchronized (subjectToTrustAnchors) {
7890ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            List<TrustAnchor> anchors = subjectToTrustAnchors.get(issuer);
7990ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            if (anchors == null) {
8090ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                return null;
8190ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            }
8290ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom
8390ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            for (TrustAnchor anchor : anchors) {
8490ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                PublicKey publicKey;
8590ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                try {
8690ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    X509Certificate caCert = anchor.getTrustedCert();
8790ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    if (caCert != null) {
8890ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                        publicKey = caCert.getPublicKey();
8990ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    } else {
9090ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                        publicKey = anchor.getCAPublicKey();
9190ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    }
9290ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    cert.verify(publicKey);
9390ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    return anchor;
9490ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                } catch (Exception e) {
9590ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    verificationException = e;
96a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                }
9706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            }
9806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
9906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
10006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        // Throw last verification exception.
10106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        if (verificationException != null) {
10206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            throw new CertPathValidatorException("TrustAnchor found but"
10306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                    + " certificate verification failed.",
10406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                    verificationException);
10506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
10606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
10706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        return null;
10806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    }
10906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
110a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom    public boolean isTrustAnchor(X509Certificate cert) {
111a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        X500Principal subject = cert.getSubjectX500Principal();
11290ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        synchronized (subjectToTrustAnchors) {
11390ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject);
11490ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            if (anchors == null) {
11590ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                return false;
11690ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            }
11790ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            return isTrustAnchor(cert, anchors);
11806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
119a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom    }
120a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom
12190ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom    private static boolean isTrustAnchor(X509Certificate cert, Collection<TrustAnchor> anchors) {
122a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        PublicKey certPublicKey = cert.getPublicKey();
123a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        for (TrustAnchor anchor : anchors) {
124a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            PublicKey caPublicKey;
125a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            try {
126a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                X509Certificate caCert = anchor.getTrustedCert();
127a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                if (caCert != null) {
128a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                    caPublicKey = caCert.getPublicKey();
129a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                } else {
130a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                    caPublicKey = anchor.getCAPublicKey();
131a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                }
132a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                if (caPublicKey.equals(certPublicKey)) {
133a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                    return true;
134a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                }
135a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            } catch (Exception e) {
136a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                // can happen with unsupported public key types
137a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            }
138a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        }
139a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        return false;
14006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    }
14106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
14206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    /**
14306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom     * Wraps a byte[] and adds equals() and hashCode() support.
14406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom     */
14506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    static class Bytes {
14606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        final byte[] bytes;
14706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        final int hash;
14806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        Bytes(byte[] bytes) {
14906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            this.bytes = bytes;
15006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            this.hash = Arrays.hashCode(bytes);
15106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
15206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        @Override public int hashCode() {
15306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            return hash;
15406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
15506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        @Override public boolean equals(Object o) {
15606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            return Arrays.equals(bytes, ((Bytes) o).bytes);
15706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
15806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    }
15906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom}
160