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 1738375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Rootpackage org.conscrypt; 1806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 19a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstromimport java.security.PublicKey; 2006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.CertPathValidatorException; 2106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.TrustAnchor; 2206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.X509Certificate; 2306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.ArrayList; 24a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstromimport java.util.Collection; 2506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.HashMap; 2606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.List; 2706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.Map; 2806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.Set; 297365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport javax.security.auth.x500.X500Principal; 3006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 3106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom/** 32c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom * Indexes {@code TrustAnchor} instances so they can be found in O(1) 33c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom * time instead of O(N). 3406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom */ 35c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrompublic final class TrustedCertificateIndex { 3606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 37a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom private final Map<X500Principal, List<TrustAnchor>> subjectToTrustAnchors 3806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom = new HashMap<X500Principal, List<TrustAnchor>>(); 3906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 40c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom public TrustedCertificateIndex() {} 411b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom 42c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom public TrustedCertificateIndex(Set<TrustAnchor> anchors) { 43c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom index(anchors); 44a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } 4506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 46c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom private void index(Set<TrustAnchor> anchors) { 47c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom for (TrustAnchor anchor : anchors) { 48c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom index(anchor); 491b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 501b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 511b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom 52c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom public TrustAnchor index(X509Certificate cert) { 53c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom TrustAnchor anchor = new TrustAnchor(cert, null); 54c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom index(anchor); 55c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom return anchor; 5690ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom } 5790ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom 5890ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom public void index(TrustAnchor anchor) { 5990ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom X500Principal subject; 6090ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom X509Certificate cert = anchor.getTrustedCert(); 6190ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom if (cert != null) { 6290ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom subject = cert.getSubjectX500Principal(); 6390ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom } else { 6490ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom subject = anchor.getCA(); 6590ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom } 6606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 6790ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom synchronized (subjectToTrustAnchors) { 68a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject); 69a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom if (anchors == null) { 7021f21e9f56ab8c9abfd8728473533fcaafafeac0Jesse Wilson anchors = new ArrayList<TrustAnchor>(1); 71a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom subjectToTrustAnchors.put(subject, anchors); 7206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 73a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom anchors.add(anchor); 7406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 7506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 7606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 777a61ad51ba5f5a0b439b2f3eacb1e0f99f909606Selim Gurun public void reset() { 787a61ad51ba5f5a0b439b2f3eacb1e0f99f909606Selim Gurun synchronized (subjectToTrustAnchors) { 797a61ad51ba5f5a0b439b2f3eacb1e0f99f909606Selim Gurun subjectToTrustAnchors.clear(); 807a61ad51ba5f5a0b439b2f3eacb1e0f99f909606Selim Gurun } 817a61ad51ba5f5a0b439b2f3eacb1e0f99f909606Selim Gurun } 827a61ad51ba5f5a0b439b2f3eacb1e0f99f909606Selim Gurun 837a61ad51ba5f5a0b439b2f3eacb1e0f99f909606Selim Gurun public void reset(Set<TrustAnchor> anchors) { 847a61ad51ba5f5a0b439b2f3eacb1e0f99f909606Selim Gurun synchronized (subjectToTrustAnchors) { 857a61ad51ba5f5a0b439b2f3eacb1e0f99f909606Selim Gurun reset(); 867a61ad51ba5f5a0b439b2f3eacb1e0f99f909606Selim Gurun index(anchors); 877a61ad51ba5f5a0b439b2f3eacb1e0f99f909606Selim Gurun } 887a61ad51ba5f5a0b439b2f3eacb1e0f99f909606Selim Gurun } 897a61ad51ba5f5a0b439b2f3eacb1e0f99f909606Selim Gurun 90c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom public TrustAnchor findByIssuerAndSignature(X509Certificate cert) { 9106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom X500Principal issuer = cert.getIssuerX500Principal(); 9290ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom synchronized (subjectToTrustAnchors) { 9390ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom List<TrustAnchor> anchors = subjectToTrustAnchors.get(issuer); 9490ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom if (anchors == null) { 9590ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom return null; 9690ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom } 9790ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom 9890ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom for (TrustAnchor anchor : anchors) { 9990ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom PublicKey publicKey; 10090ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom try { 10190ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom X509Certificate caCert = anchor.getTrustedCert(); 10290ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom if (caCert != null) { 10390ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom publicKey = caCert.getPublicKey(); 10490ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom } else { 10590ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom publicKey = anchor.getCAPublicKey(); 10690ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom } 10790ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom cert.verify(publicKey); 10890ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom return anchor; 109c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom } catch (Exception ignored) { 110a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } 11106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 11206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 11306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom return null; 11406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 11506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 116c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom public TrustAnchor findBySubjectAndPublicKey(X509Certificate cert) { 117a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom X500Principal subject = cert.getSubjectX500Principal(); 11890ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom synchronized (subjectToTrustAnchors) { 11990ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject); 12090ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom if (anchors == null) { 121c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom return null; 12290ff8e2c017c4332686ff79ea9968a009a703b7eBrian Carlstrom } 123c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom return findBySubjectAndPublicKey(cert, anchors); 12406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 125a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } 126a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom 127c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom private static TrustAnchor findBySubjectAndPublicKey(X509Certificate cert, 128c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom Collection<TrustAnchor> anchors) { 129a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom PublicKey certPublicKey = cert.getPublicKey(); 130a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom for (TrustAnchor anchor : anchors) { 131a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom PublicKey caPublicKey; 132a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom try { 133a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom X509Certificate caCert = anchor.getTrustedCert(); 134a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom if (caCert != null) { 135a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom caPublicKey = caCert.getPublicKey(); 136a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } else { 137a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom caPublicKey = anchor.getCAPublicKey(); 138a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } 139a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom if (caPublicKey.equals(certPublicKey)) { 140c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom return anchor; 141a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } 142a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } catch (Exception e) { 143a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom // can happen with unsupported public key types 144a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } 145a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } 146c77290eaef032e5e8952d65e0456b091b6b50804Brian Carlstrom return null; 14706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 14806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom} 149