TrustedCertificateIndex.java revision 06fb2e026572e4f67ac80c927d30e9be787bbe6e
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
1906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport javax.security.auth.x500.X500Principal;
2006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
2106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.CertPath;
2206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.CertPathValidatorException;
2306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.CertificateEncodingException;
2406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.PKIXParameters;
2506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.TrustAnchor;
2606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.X509Certificate;
2706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.InvalidAlgorithmParameterException;
2806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.KeyStoreException;
2906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.ArrayList;
3006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.Arrays;
3106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.HashMap;
3206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.List;
3306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.Map;
3406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.Set;
3506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.logging.Logger;
3606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.logging.Level;
3706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
3806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom/**
3906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * Indexes trust anchors so they can be found in O(1) time instead of O(N).
4006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom */
4106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrompublic class IndexedPKIXParameters extends PKIXParameters {
4206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
4306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    final Map<Bytes, TrustAnchor> encodings
4406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            = new HashMap<Bytes, TrustAnchor>();
4506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    final Map<X500Principal, TrustAnchor> bySubject
4606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            = new HashMap<X500Principal, TrustAnchor>();
4706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    final Map<X500Principal, List<TrustAnchor>> byCA
4806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            = new HashMap<X500Principal, List<TrustAnchor>>();
4906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
5006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    public IndexedPKIXParameters(Set<TrustAnchor> anchors)
5106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            throws KeyStoreException, InvalidAlgorithmParameterException,
5206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            CertificateEncodingException {
5306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        super(anchors);
5406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
5506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        for (TrustAnchor anchor : anchors) {
5606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            X509Certificate cert = anchor.getTrustedCert();
5706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
5806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            Bytes encoded = new Bytes(cert.getEncoded());
5906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            encodings.put(encoded, anchor);
6006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
6106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            X500Principal subject = cert.getSubjectX500Principal();
6206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            if (bySubject.put(subject, anchor) != null) {
6306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                // TODO: Should we allow this?
6406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                throw new KeyStoreException("Two certs have the same subject: "
6506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                        + subject);
6606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            }
6706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
6806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            X500Principal ca = anchor.getCA();
6906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            List<TrustAnchor> caAnchors = byCA.get(ca);
7006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            if (caAnchors == null) {
7106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                caAnchors = new ArrayList<TrustAnchor>();
7206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                byCA.put(ca, caAnchors);
7306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            }
7406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            caAnchors.add(anchor);
7506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
7606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    }
7706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
7806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    public TrustAnchor findTrustAnchor(X509Certificate cert)
7906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            throws CertPathValidatorException {
8006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        // Mimic the alg in CertPathValidatorUtilities.findTrustAnchor().
8106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        Exception verificationException = null;
8206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        X500Principal issuer = cert.getIssuerX500Principal();
8306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
8406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        List<TrustAnchor> anchors = byCA.get(issuer);
8506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        if (anchors != null) {
8606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            for (TrustAnchor caAnchor : anchors) {
8706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                try {
8806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                    cert.verify(caAnchor.getCAPublicKey());
8906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                    return caAnchor;
9006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                } catch (Exception e) {
9106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                    verificationException = e;
9206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                }
9306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            }
9406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
9506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
9606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        TrustAnchor anchor = bySubject.get(issuer);
9706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        if (anchor != null) {
9806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            try {
9906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                cert.verify(anchor.getTrustedCert().getPublicKey());
10006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                return anchor;
10106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            } catch (Exception e) {
10206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                verificationException = e;
10306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            }
10406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
10506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom
10606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        try {
10706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            Bytes encoded = new Bytes(cert.getEncoded());
10806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            anchor = encodings.get(encoded);
10906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            if (anchor != null) {
11006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                return anchor;
11106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            }
11206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        } catch (Exception e) {
11306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            Logger.getLogger(IndexedPKIXParameters.class.getName()).log(
11406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                    Level.WARNING, "Error encoding cert.", e);
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
12706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    /**
12806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom     * Returns true if the given certificate is found in the trusted key
12906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom     * store.
13006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom     */
13106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom    public boolean isDirectlyTrusted(X509Certificate cert) {
13206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        try {
13306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            Bytes encoded = new Bytes(cert.getEncoded());
13406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            return encodings.containsKey(encoded);
13506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        } catch (Exception e) {
13606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            Logger.getLogger(IndexedPKIXParameters.class.getName()).log(
13706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom                    Level.WARNING, "Error encoding cert.", e);
13806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom            return false;
13906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom        }
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