Home | History | Annotate | Download | only in conscrypt
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package org.conscrypt;
     18 
     19 import java.security.PublicKey;
     20 import java.security.cert.TrustAnchor;
     21 import java.security.cert.X509Certificate;
     22 import java.util.ArrayList;
     23 import java.util.Collection;
     24 import java.util.HashMap;
     25 import java.util.List;
     26 import java.util.Map;
     27 import java.util.Set;
     28 import javax.security.auth.x500.X500Principal;
     29 
     30 /**
     31  * Indexes {@code TrustAnchor} instances so they can be found in O(1)
     32  * time instead of O(N).
     33  */
     34 public final class TrustedCertificateIndex {
     35 
     36     private final Map<X500Principal, List<TrustAnchor>> subjectToTrustAnchors
     37             = new HashMap<X500Principal, List<TrustAnchor>>();
     38 
     39     public TrustedCertificateIndex() {}
     40 
     41     public TrustedCertificateIndex(Set<TrustAnchor> anchors) {
     42         index(anchors);
     43     }
     44 
     45     private void index(Set<TrustAnchor> anchors) {
     46         for (TrustAnchor anchor : anchors) {
     47             index(anchor);
     48         }
     49     }
     50 
     51     public TrustAnchor index(X509Certificate cert) {
     52         TrustAnchor anchor = new TrustAnchor(cert, null);
     53         index(anchor);
     54         return anchor;
     55     }
     56 
     57     public void index(TrustAnchor anchor) {
     58         X500Principal subject;
     59         X509Certificate cert = anchor.getTrustedCert();
     60         if (cert != null) {
     61             subject = cert.getSubjectX500Principal();
     62         } else {
     63             subject = anchor.getCA();
     64         }
     65 
     66         synchronized (subjectToTrustAnchors) {
     67             List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject);
     68             if (anchors == null) {
     69                 anchors = new ArrayList<TrustAnchor>(1);
     70                 subjectToTrustAnchors.put(subject, anchors);
     71             }
     72             anchors.add(anchor);
     73         }
     74     }
     75 
     76     public void reset() {
     77         synchronized (subjectToTrustAnchors) {
     78             subjectToTrustAnchors.clear();
     79         }
     80     }
     81 
     82     public void reset(Set<TrustAnchor> anchors) {
     83         synchronized (subjectToTrustAnchors) {
     84             reset();
     85             index(anchors);
     86         }
     87     }
     88 
     89     public TrustAnchor findByIssuerAndSignature(X509Certificate cert) {
     90         X500Principal issuer = cert.getIssuerX500Principal();
     91         synchronized (subjectToTrustAnchors) {
     92             List<TrustAnchor> anchors = subjectToTrustAnchors.get(issuer);
     93             if (anchors == null) {
     94                 return null;
     95             }
     96 
     97             for (TrustAnchor anchor : anchors) {
     98                 PublicKey publicKey;
     99                 try {
    100                     X509Certificate caCert = anchor.getTrustedCert();
    101                     if (caCert != null) {
    102                         publicKey = caCert.getPublicKey();
    103                     } else {
    104                         publicKey = anchor.getCAPublicKey();
    105                     }
    106                     cert.verify(publicKey);
    107                     return anchor;
    108                 } catch (Exception ignored) {
    109                 }
    110             }
    111         }
    112         return null;
    113     }
    114 
    115     public TrustAnchor findBySubjectAndPublicKey(X509Certificate cert) {
    116         X500Principal subject = cert.getSubjectX500Principal();
    117         synchronized (subjectToTrustAnchors) {
    118             List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject);
    119             if (anchors == null) {
    120                 return null;
    121             }
    122             return findBySubjectAndPublicKey(cert, anchors);
    123         }
    124     }
    125 
    126     private static TrustAnchor findBySubjectAndPublicKey(X509Certificate cert,
    127                                                          Collection<TrustAnchor> anchors) {
    128         PublicKey certPublicKey = cert.getPublicKey();
    129         for (TrustAnchor anchor : anchors) {
    130             PublicKey caPublicKey;
    131             try {
    132                 X509Certificate caCert = anchor.getTrustedCert();
    133                 if (caCert != null) {
    134                     caPublicKey = caCert.getPublicKey();
    135                 } else {
    136                     caPublicKey = anchor.getCAPublicKey();
    137                 }
    138                 if (caPublicKey.equals(certPublicKey)) {
    139                     return anchor;
    140                 }
    141             } catch (Exception e) {
    142                 // can happen with unsupported public key types
    143             }
    144         }
    145         return null;
    146     }
    147 }
    148