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