15a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker/*
25a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker * Copyright (C) 2015 The Android Open Source Project
35a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker *
45a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker * Licensed under the Apache License, Version 2.0 (the "License");
55a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker * you may not use this file except in compliance with the License.
65a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker * You may obtain a copy of the License at
75a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker *
85a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker *      http://www.apache.org/licenses/LICENSE-2.0
95a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker *
105a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker * Unless required by applicable law or agreed to in writing, software
115a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker * distributed under the License is distributed on an "AS IS" BASIS,
125a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker * See the License for the specific language governing permissions and
145a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker * limitations under the License.
155a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker */
165a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker
175a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubakerpackage android.security.net.config;
185a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker
195a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubakerimport android.util.ArraySet;
205a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubakerimport java.security.KeyStore;
215a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubakerimport java.security.KeyStoreException;
225a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubakerimport java.security.cert.Certificate;
235a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubakerimport java.security.cert.X509Certificate;
24aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubakerimport java.util.Collections;
255a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubakerimport java.util.Enumeration;
265a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubakerimport java.util.Set;
275a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker
28d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubakerimport com.android.org.conscrypt.TrustedCertificateIndex;
29d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker
305a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker/**
315a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker * {@link CertificateSource} which provides certificates from trusted certificate entries of a
325a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker * {@link KeyStore}.
335a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker */
345a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubakerclass KeyStoreCertificateSource implements CertificateSource {
355a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker    private final Object mLock = new Object();
365a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker    private final KeyStore mKeyStore;
37d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker    private TrustedCertificateIndex mIndex;
385a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker    private Set<X509Certificate> mCertificates;
395a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker
405a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker    public KeyStoreCertificateSource(KeyStore ks) {
415a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker        mKeyStore = ks;
425a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker    }
435a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker
445a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker    @Override
455a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker    public Set<X509Certificate> getCertificates() {
46d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker        ensureInitialized();
47d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker        return mCertificates;
48d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker    }
49d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker
50d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker    private void ensureInitialized() {
515a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker        synchronized (mLock) {
525a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker            if (mCertificates != null) {
53d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker                return;
545a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker            }
55d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker
565a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker            try {
57d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker                TrustedCertificateIndex localIndex = new TrustedCertificateIndex();
585a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker                Set<X509Certificate> certificates = new ArraySet<>(mKeyStore.size());
595a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker                for (Enumeration<String> en = mKeyStore.aliases(); en.hasMoreElements();) {
605a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker                    String alias = en.nextElement();
615a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker                    X509Certificate cert = (X509Certificate) mKeyStore.getCertificate(alias);
625a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker                    if (cert != null) {
635a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker                        certificates.add(cert);
64d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker                        localIndex.index(cert);
655a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker                    }
665a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker                }
67d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker                mIndex = localIndex;
685a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker                mCertificates = certificates;
695a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker            } catch (KeyStoreException e) {
705a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker                throw new RuntimeException("Failed to load certificates from KeyStore", e);
715a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker            }
725a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker        }
735a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker    }
74d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker
75d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker    @Override
76d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker    public X509Certificate findBySubjectAndPublicKey(X509Certificate cert) {
77d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker        ensureInitialized();
78d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker        java.security.cert.TrustAnchor anchor = mIndex.findBySubjectAndPublicKey(cert);
79d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker        if (anchor == null) {
80d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker            return null;
81d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker        }
82d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker        return anchor.getTrustedCert();
83d3af9620817220d737fdb532c1ae1032bdd65e11Chad Brubaker    }
84fa9beebb83abe38fa04c14dc628bc5c1b4b068cdChad Brubaker
85fa9beebb83abe38fa04c14dc628bc5c1b4b068cdChad Brubaker    @Override
86fa9beebb83abe38fa04c14dc628bc5c1b4b068cdChad Brubaker    public X509Certificate findByIssuerAndSignature(X509Certificate cert) {
87fa9beebb83abe38fa04c14dc628bc5c1b4b068cdChad Brubaker        ensureInitialized();
88fa9beebb83abe38fa04c14dc628bc5c1b4b068cdChad Brubaker        java.security.cert.TrustAnchor anchor = mIndex.findByIssuerAndSignature(cert);
89fa9beebb83abe38fa04c14dc628bc5c1b4b068cdChad Brubaker        if (anchor == null) {
90fa9beebb83abe38fa04c14dc628bc5c1b4b068cdChad Brubaker            return null;
91fa9beebb83abe38fa04c14dc628bc5c1b4b068cdChad Brubaker        }
92fa9beebb83abe38fa04c14dc628bc5c1b4b068cdChad Brubaker        return anchor.getTrustedCert();
93fa9beebb83abe38fa04c14dc628bc5c1b4b068cdChad Brubaker    }
94aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker
95aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker    @Override
96aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker    public Set<X509Certificate> findAllByIssuerAndSignature(X509Certificate cert) {
97aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker        ensureInitialized();
98aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker        Set<java.security.cert.TrustAnchor> anchors = mIndex.findAllByIssuerAndSignature(cert);
99aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker        if (anchors.isEmpty()) {
100aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker            return Collections.<X509Certificate>emptySet();
101aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker        }
102aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker        Set<X509Certificate> certs = new ArraySet<X509Certificate>(anchors.size());
103aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker        for (java.security.cert.TrustAnchor anchor : anchors) {
104aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker            certs.add(anchor.getTrustedCert());
105aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker        }
106aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker        return certs;
107aa6c3c3e252252b80c3900bd4c1ff27d37265c6dChad Brubaker    }
108bf9a82a6433701aa2f02761f3a7c425ffef4fa09Chad Brubaker
109bf9a82a6433701aa2f02761f3a7c425ffef4fa09Chad Brubaker    @Override
110bf9a82a6433701aa2f02761f3a7c425ffef4fa09Chad Brubaker    public void handleTrustStorageUpdate() {
111bf9a82a6433701aa2f02761f3a7c425ffef4fa09Chad Brubaker        // Nothing to do.
112bf9a82a6433701aa2f02761f3a7c425ffef4fa09Chad Brubaker    }
1135a1078f40dd511901c33ccf78be6e2d5081d6637Chad Brubaker}
114