TrustedCertificateIndex.java revision 1b3c5388d0fffde4392007eb1b0be011a5dfae82
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;
26a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstromimport java.util.Collection;
271b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstromimport java.util.Collections;
2806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.HashMap;
291b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstromimport java.util.HashSet;
3006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.List;
3106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.Map;
3206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.Set;
337365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport javax.security.auth.x500.X500Principal;
3406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
3506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom/**
3606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * Indexes trust anchors so they can be found in O(1) time instead of O(N).
3706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom */
3890ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrompublic final class IndexedPKIXParameters extends PKIXParameters {
3906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
40a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom    private final Map<X500Principal, List<TrustAnchor>> subjectToTrustAnchors
4106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            = new HashMap<X500Principal, List<TrustAnchor>>();
4206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
431b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom    public IndexedPKIXParameters() {}
441b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom
4506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    public IndexedPKIXParameters(Set<TrustAnchor> anchors)
46a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            throws InvalidAlgorithmParameterException {
4706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        super(anchors);
48a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        index();
49a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom    }
5006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
511b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom    @Override public Set<TrustAnchor> getTrustAnchors() {
521b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom        Set<TrustAnchor> result = new HashSet<TrustAnchor>();
531b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom        synchronized (subjectToTrustAnchors) {
541b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom            for (List<TrustAnchor> trustAnchors : subjectToTrustAnchors.values()) {
551b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom                result.addAll(trustAnchors);
561b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom            }
571b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom        }
581b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom        return Collections.unmodifiableSet(result);
591b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom    }
601b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom
611b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom    @Override public void setTrustAnchors(Set<TrustAnchor> trustAnchors) {
621b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom        throw new UnsupportedOperationException();
631b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom    }
641b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom
65a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom    private void index() {
661b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom        for (TrustAnchor anchor : super.getTrustAnchors()) {
6790ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            index(anchor);
6890ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        }
6990ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom    }
7090ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom
7190ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom    public void index(TrustAnchor anchor) {
7290ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        X500Principal subject;
7390ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        X509Certificate cert = anchor.getTrustedCert();
7490ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        if (cert != null) {
7590ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            subject = cert.getSubjectX500Principal();
7690ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        } else {
7790ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            subject = anchor.getCA();
7890ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        }
7906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
8090ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        synchronized (subjectToTrustAnchors) {
81a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject);
82a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            if (anchors == null) {
8321f21e9f56ab8c9abfd8728473533fcaafafeac0Jesse Wilson                anchors = new ArrayList<TrustAnchor>(1);
84a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                subjectToTrustAnchors.put(subject, anchors);
8506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            }
86a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            anchors.add(anchor);
8706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
8806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    }
8906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
9006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    public TrustAnchor findTrustAnchor(X509Certificate cert)
9106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            throws CertPathValidatorException {
9206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        X500Principal issuer = cert.getIssuerX500Principal();
93a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        Exception verificationException = null;
9490ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        synchronized (subjectToTrustAnchors) {
9590ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            List<TrustAnchor> anchors = subjectToTrustAnchors.get(issuer);
9690ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            if (anchors == null) {
9790ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                return null;
9890ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            }
9990ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom
10090ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            for (TrustAnchor anchor : anchors) {
10190ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                PublicKey publicKey;
10290ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                try {
10390ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    X509Certificate caCert = anchor.getTrustedCert();
10490ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    if (caCert != null) {
10590ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                        publicKey = caCert.getPublicKey();
10690ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    } else {
10790ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                        publicKey = anchor.getCAPublicKey();
10890ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    }
10990ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    cert.verify(publicKey);
11090ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    return anchor;
11190ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                } catch (Exception e) {
11290ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                    verificationException = e;
113a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                }
11406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            }
11506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
11606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
11706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        // Throw last verification exception.
11806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        if (verificationException != null) {
11906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            throw new CertPathValidatorException("TrustAnchor found but"
12006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                    + " certificate verification failed.",
12106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                    verificationException);
12206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
12306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
12406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        return null;
12506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    }
12606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
127a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom    public boolean isTrustAnchor(X509Certificate cert) {
128a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        X500Principal subject = cert.getSubjectX500Principal();
12990ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom        synchronized (subjectToTrustAnchors) {
13090ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject);
13190ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            if (anchors == null) {
13290ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom                return false;
13390ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            }
13490ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom            return isTrustAnchor(cert, anchors);
13506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
136a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom    }
137a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom
13890ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom    private static boolean isTrustAnchor(X509Certificate cert, Collection<TrustAnchor> anchors) {
139a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        PublicKey certPublicKey = cert.getPublicKey();
140a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        for (TrustAnchor anchor : anchors) {
141a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            PublicKey caPublicKey;
142a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            try {
143a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                X509Certificate caCert = anchor.getTrustedCert();
144a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                if (caCert != null) {
145a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                    caPublicKey = caCert.getPublicKey();
146a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                } else {
147a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                    caPublicKey = anchor.getCAPublicKey();
148a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                }
149a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                if (caPublicKey.equals(certPublicKey)) {
150a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                    return true;
151a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                }
152a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            } catch (Exception e) {
153a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                // can happen with unsupported public key types
154a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom            }
155a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        }
156a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom        return false;
15706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    }
15806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom}
159