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