TrustedCertificateIndex.java revision c77290eaef032e5e8952d65e0456b091b6b50804
11f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project/*
21f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * Copyright (C) 2009 The Android Open Source Project
31f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project *
41f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
51f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * you may not use this file except in compliance with the License.
61f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * You may obtain a copy of the License at
71f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project *
81f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
91f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project *
101f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
111f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
121f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * See the License for the specific language governing permissions and
141f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * limitations under the License.
151f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project */
161f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
171f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectpackage org.apache.harmony.xnet.provider.jsse;
186014527c350895383b99ba91d3d009a32b1d22a6Dianne Hackborn
196014527c350895383b99ba91d3d009a32b1d22a6Dianne Hackbornimport java.security.PublicKey;
206014527c350895383b99ba91d3d009a32b1d22a6Dianne Hackbornimport java.security.cert.CertPathValidatorException;
21cc6828c676c0bfabbcbefa27f4be9183352f5feeRomain Guyimport java.security.cert.TrustAnchor;
22491293ef234d093adccf442d76cbd0db12632692svetoslavganovimport java.security.cert.X509Certificate;
23491293ef234d093adccf442d76cbd0db12632692svetoslavganovimport java.util.ArrayList;
24491293ef234d093adccf442d76cbd0db12632692svetoslavganovimport java.util.Collection;
25491293ef234d093adccf442d76cbd0db12632692svetoslavganovimport java.util.HashMap;
264bf7bcf89b459132e743ebbd8df895dc5e129989Dianne Hackbornimport java.util.List;
2746e75294d540fe807d78aec2582ae02cc38c7d42Jeff Brownimport java.util.Map;
28491293ef234d093adccf442d76cbd0db12632692svetoslavganovimport java.util.Set;
29dc8a7f69d7df5f1ca29763995a0d55acf7936fc6Dianne Hackbornimport javax.security.auth.x500.X500Principal;
305d27977f9da482627ceb19317a2cd70467aff046Adam Powell
311f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project/**
32696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell * Indexes {@code TrustAnchor} instances so they can be found in O(1)
33640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell * time instead of O(N).
341f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project */
351f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectpublic final class TrustedCertificateIndex {
36696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
37640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell    private final Map<X500Principal, List<TrustAnchor>> subjectToTrustAnchors
38640a66eac612b850b5dabd3b93bd94f83ed2d567Adam Powell            = new HashMap<X500Principal, List<TrustAnchor>>();
395d27977f9da482627ceb19317a2cd70467aff046Adam Powell
4089e0645b4157961e8c465eb9c819f965fdb453d8Adam Powell    public TrustedCertificateIndex() {}
411f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
421f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    public TrustedCertificateIndex(Set<TrustAnchor> anchors) {
431f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        index(anchors);
44269248d112e35fe8e9f0d5d11c96dcb2ac1118b0Adam Powell    }
451f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
461f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    private void index(Set<TrustAnchor> anchors) {
471f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        for (TrustAnchor anchor : anchors) {
481f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            index(anchor);
491f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        }
501f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
511f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
521f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    public TrustAnchor index(X509Certificate cert) {
531f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        TrustAnchor anchor = new TrustAnchor(cert, null);
541f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        index(anchor);
551f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        return anchor;
561f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
576014527c350895383b99ba91d3d009a32b1d22a6Dianne Hackborn
581f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    public void index(TrustAnchor anchor) {
591f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        X500Principal subject;
601f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        X509Certificate cert = anchor.getTrustedCert();
6185446e95afa480cee2247bb96795fccc8cf812afAdam Powell        if (cert != null) {
626e34636749217654f43221885afb7a29bb5ca96aAdam Powell            subject = cert.getSubjectX500Principal();
631f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        } else {
641e4b9f3936d6f357e89360293e05a0e16d5fa440Dianne Hackborn            subject = anchor.getCA();
651f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        }
661f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
671f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        synchronized (subjectToTrustAnchors) {
681f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject);
691f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            if (anchors == null) {
701f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                anchors = new ArrayList<TrustAnchor>(1);
71dc8a7f69d7df5f1ca29763995a0d55acf7936fc6Dianne Hackborn                subjectToTrustAnchors.put(subject, anchors);
721f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            }
731f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            anchors.add(anchor);
741f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        }
758e552630e72a17d7340f1bebccbc6fd6faef82fbAdam Powell    }
761f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
771f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    public TrustAnchor findByIssuerAndSignature(X509Certificate cert) {
78491293ef234d093adccf442d76cbd0db12632692svetoslavganov        X500Principal issuer = cert.getIssuerX500Principal();
79491293ef234d093adccf442d76cbd0db12632692svetoslavganov        synchronized (subjectToTrustAnchors) {
801f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            List<TrustAnchor> anchors = subjectToTrustAnchors.get(issuer);
811f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            if (anchors == null) {
821f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                return null;
831f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            }
8485446e95afa480cee2247bb96795fccc8cf812afAdam Powell
851f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            for (TrustAnchor anchor : anchors) {
861f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                PublicKey publicKey;
871f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                try {
881f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                    X509Certificate caCert = anchor.getTrustedCert();
891f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                    if (caCert != null) {
901f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                        publicKey = caCert.getPublicKey();
911f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                    } else {
921f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                        publicKey = anchor.getCAPublicKey();
931f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                    }
941f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                    cert.verify(publicKey);
95491293ef234d093adccf442d76cbd0db12632692svetoslavganov                    return anchor;
961f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                } catch (Exception ignored) {
971f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                }
981f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            }
991f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        }
1001f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        return null;
1011f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
1021f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
1031f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    public TrustAnchor findBySubjectAndPublicKey(X509Certificate cert) {
1046014527c350895383b99ba91d3d009a32b1d22a6Dianne Hackborn        X500Principal subject = cert.getSubjectX500Principal();
1056014527c350895383b99ba91d3d009a32b1d22a6Dianne Hackborn        synchronized (subjectToTrustAnchors) {
1066014527c350895383b99ba91d3d009a32b1d22a6Dianne Hackborn            List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject);
1076014527c350895383b99ba91d3d009a32b1d22a6Dianne Hackborn            if (anchors == null) {
1081f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                return null;
1091f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            }
1101f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            return findBySubjectAndPublicKey(cert, anchors);
1111f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        }
1121f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
1131f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
1141f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    private static TrustAnchor findBySubjectAndPublicKey(X509Certificate cert,
1151f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                                                         Collection<TrustAnchor> anchors) {
116d76b67c340d1564abf8d14d976fdaf83bf2b3320Dianne Hackborn        PublicKey certPublicKey = cert.getPublicKey();
117dc8a7f69d7df5f1ca29763995a0d55acf7936fc6Dianne Hackborn        for (TrustAnchor anchor : anchors) {
1181e4b9f3936d6f357e89360293e05a0e16d5fa440Dianne Hackborn            PublicKey caPublicKey;
119a95e4cb62f3642cb190d032dbf7dc40d9ecc6973Dianne Hackborn            try {
1201f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                X509Certificate caCert = anchor.getTrustedCert();
1211f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                if (caCert != null) {
1221f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                    caPublicKey = caCert.getPublicKey();
1231f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                } else {
1241f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                    caPublicKey = anchor.getCAPublicKey();
12533b974393b6fadcefc896ec4a0f9b66724f61e9fAdam Powell                }
12633b974393b6fadcefc896ec4a0f9b66724f61e9fAdam Powell                if (caPublicKey.equals(certPublicKey)) {
127696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                    return anchor;
128696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                }
1291f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            } catch (Exception e) {
1301f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                // can happen with unsupported public key types
1311f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            }
1321f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        }
1331f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        return null;
1341f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
1351f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project}
1361f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project