1949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom/* 2949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom * Copyright (C) 2009 The Android Open Source Project 3949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom * 4949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License"); 5949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom * you may not use this file except in compliance with the License. 6949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom * You may obtain a copy of the License at 7949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom * 8949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom * http://www.apache.org/licenses/LICENSE-2.0 9949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom * 10949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom * Unless required by applicable law or agreed to in writing, software 11949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS, 12949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom * See the License for the specific language governing permissions and 14949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom * limitations under the License. 15949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom */ 16949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom 17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt; 18949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom 196e24f16869f652c340bb973069ec5fec21317137Brian Carlstromimport java.security.PublicKey; 20949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstromimport java.security.cert.TrustAnchor; 21949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstromimport java.security.cert.X509Certificate; 22949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstromimport java.util.ArrayList; 236e24f16869f652c340bb973069ec5fec21317137Brian Carlstromimport java.util.Collection; 24949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstromimport java.util.HashMap; 25949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstromimport java.util.List; 26949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstromimport java.util.Map; 27949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstromimport java.util.Set; 287a19bf9f5adcd53b524c0e54c97f7ed9107898cbJesse Wilsonimport javax.security.auth.x500.X500Principal; 29949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom 30949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom/** 311dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom * Indexes {@code TrustAnchor} instances so they can be found in O(1) 321dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom * time instead of O(N). 33949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom */ 341dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrompublic final class TrustedCertificateIndex { 35949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom 366e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom private final Map<X500Principal, List<TrustAnchor>> subjectToTrustAnchors 37949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom = new HashMap<X500Principal, List<TrustAnchor>>(); 38949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom 391dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom public TrustedCertificateIndex() {} 403a246337af275463275e608f6bd6f48b57322aacBrian Carlstrom 411dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom public TrustedCertificateIndex(Set<TrustAnchor> anchors) { 421dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom index(anchors); 436e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom } 44949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom 451dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom private void index(Set<TrustAnchor> anchors) { 461dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom for (TrustAnchor anchor : anchors) { 471dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom index(anchor); 483a246337af275463275e608f6bd6f48b57322aacBrian Carlstrom } 493a246337af275463275e608f6bd6f48b57322aacBrian Carlstrom } 503a246337af275463275e608f6bd6f48b57322aacBrian Carlstrom 511dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom public TrustAnchor index(X509Certificate cert) { 521dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom TrustAnchor anchor = new TrustAnchor(cert, null); 531dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom index(anchor); 541dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom return anchor; 55cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom } 56cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom 57cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom public void index(TrustAnchor anchor) { 58cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom X500Principal subject; 59cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom X509Certificate cert = anchor.getTrustedCert(); 60cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom if (cert != null) { 61cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom subject = cert.getSubjectX500Principal(); 62cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom } else { 63cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom subject = anchor.getCA(); 64cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom } 65949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom 66cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom synchronized (subjectToTrustAnchors) { 676e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject); 686e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom if (anchors == null) { 69756cf26dc1b2dcd53921d4ba80ff93566ed2f77cJesse Wilson anchors = new ArrayList<TrustAnchor>(1); 706e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom subjectToTrustAnchors.put(subject, anchors); 71949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom } 726e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom anchors.add(anchor); 73949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom } 74949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom } 75949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom 76b160186b1248f9d6720c5449ddef762734c2a756Selim Gurun public void reset() { 77b160186b1248f9d6720c5449ddef762734c2a756Selim Gurun synchronized (subjectToTrustAnchors) { 78b160186b1248f9d6720c5449ddef762734c2a756Selim Gurun subjectToTrustAnchors.clear(); 79b160186b1248f9d6720c5449ddef762734c2a756Selim Gurun } 80b160186b1248f9d6720c5449ddef762734c2a756Selim Gurun } 81b160186b1248f9d6720c5449ddef762734c2a756Selim Gurun 82b160186b1248f9d6720c5449ddef762734c2a756Selim Gurun public void reset(Set<TrustAnchor> anchors) { 83b160186b1248f9d6720c5449ddef762734c2a756Selim Gurun synchronized (subjectToTrustAnchors) { 84b160186b1248f9d6720c5449ddef762734c2a756Selim Gurun reset(); 85b160186b1248f9d6720c5449ddef762734c2a756Selim Gurun index(anchors); 86b160186b1248f9d6720c5449ddef762734c2a756Selim Gurun } 87b160186b1248f9d6720c5449ddef762734c2a756Selim Gurun } 88b160186b1248f9d6720c5449ddef762734c2a756Selim Gurun 891dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom public TrustAnchor findByIssuerAndSignature(X509Certificate cert) { 90949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom X500Principal issuer = cert.getIssuerX500Principal(); 91cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom synchronized (subjectToTrustAnchors) { 92cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom List<TrustAnchor> anchors = subjectToTrustAnchors.get(issuer); 93cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom if (anchors == null) { 94cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom return null; 95cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom } 96cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom 97cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom for (TrustAnchor anchor : anchors) { 98cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom PublicKey publicKey; 99cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom try { 100cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom X509Certificate caCert = anchor.getTrustedCert(); 101cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom if (caCert != null) { 102cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom publicKey = caCert.getPublicKey(); 103cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom } else { 104cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom publicKey = anchor.getCAPublicKey(); 105cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom } 106cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom cert.verify(publicKey); 107cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom return anchor; 1081dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom } catch (Exception ignored) { 1096e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom } 110949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom } 111949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom } 112949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom return null; 113949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom } 114949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom 1151dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom public TrustAnchor findBySubjectAndPublicKey(X509Certificate cert) { 1166e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom X500Principal subject = cert.getSubjectX500Principal(); 117cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom synchronized (subjectToTrustAnchors) { 118cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject); 119cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom if (anchors == null) { 1201dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom return null; 121cce4b13077f5a6303a276a780bc5994e900e98b2Brian Carlstrom } 1221dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom return findBySubjectAndPublicKey(cert, anchors); 123949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom } 1246e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom } 1256e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom 1261dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom private static TrustAnchor findBySubjectAndPublicKey(X509Certificate cert, 1271dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom Collection<TrustAnchor> anchors) { 1286e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom PublicKey certPublicKey = cert.getPublicKey(); 1296e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom for (TrustAnchor anchor : anchors) { 1306e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom PublicKey caPublicKey; 1316e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom try { 1326e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom X509Certificate caCert = anchor.getTrustedCert(); 1336e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom if (caCert != null) { 1346e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom caPublicKey = caCert.getPublicKey(); 1356e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom } else { 1366e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom caPublicKey = anchor.getCAPublicKey(); 1376e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom } 1386e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom if (caPublicKey.equals(certPublicKey)) { 1391dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom return anchor; 1406e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom } 1416e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom } catch (Exception e) { 1426e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom // can happen with unsupported public key types 1436e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom } 1446e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom } 1451dd0b8b7477cc7411ec1d9e8637bec69b819041aBrian Carlstrom return null; 146949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom } 147949d5570dea1a7b63c642a7e9e8f8c76dc9ff1faBrian Carlstrom} 148