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