1522b9174fca3ce4724ef8e032e26664697529e03Kenny Root/*
2522b9174fca3ce4724ef8e032e26664697529e03Kenny Root * Copyright 2016 The Android Open Source Project
3522b9174fca3ce4724ef8e032e26664697529e03Kenny Root *
4522b9174fca3ce4724ef8e032e26664697529e03Kenny Root * Licensed under the Apache License, Version 2.0 (the "License");
5522b9174fca3ce4724ef8e032e26664697529e03Kenny Root * you may not use this file except in compliance with the License.
6522b9174fca3ce4724ef8e032e26664697529e03Kenny Root * You may obtain a copy of the License at
7522b9174fca3ce4724ef8e032e26664697529e03Kenny Root *
8522b9174fca3ce4724ef8e032e26664697529e03Kenny Root *      http://www.apache.org/licenses/LICENSE-2.0
9522b9174fca3ce4724ef8e032e26664697529e03Kenny Root *
10522b9174fca3ce4724ef8e032e26664697529e03Kenny Root * Unless required by applicable law or agreed to in writing, software
11522b9174fca3ce4724ef8e032e26664697529e03Kenny Root * distributed under the License is distributed on an "AS IS" BASIS,
12522b9174fca3ce4724ef8e032e26664697529e03Kenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13522b9174fca3ce4724ef8e032e26664697529e03Kenny Root * See the License for the specific language governing permissions and
14522b9174fca3ce4724ef8e032e26664697529e03Kenny Root * limitations under the License.
15522b9174fca3ce4724ef8e032e26664697529e03Kenny Root */
16522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
17522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootpackage libcore.java.security.cert;
18522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
19522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.security.KeyStore.PrivateKeyEntry;
20522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.security.PrivateKey;
21522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.security.cert.CertPath;
22522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.security.cert.CertPathValidator;
23522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.security.cert.CertPathValidatorException;
24522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.security.cert.CertificateFactory;
25522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.security.cert.PKIXCertPathChecker;
26522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.security.cert.PKIXParameters;
27522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.security.cert.PKIXRevocationChecker;
28522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.security.cert.TrustAnchor;
29522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.security.cert.X509Certificate;
30522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.security.cert.PKIXRevocationChecker.Option;
31522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.util.ArrayList;
32522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.util.Collections;
33522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.util.Date;
34522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport java.util.List;
35522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.asn1.x509.CRLReason;
36522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
37522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.cert.X509CertificateHolder;
38522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
39522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.BasicOCSPResp;
40522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder;
41522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.CertificateID;
42522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.CertificateStatus;
43522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.OCSPResp;
44522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.OCSPRespBuilder;
45522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.RevokedStatus;
46522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.operator.DigestCalculatorProvider;
47522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.operator.bc.BcDigestCalculatorProvider;
48522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport com.android.org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
49522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport junit.framework.TestCase;
50522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootimport libcore.java.security.TestKeyStore;
51522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
52491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanianimport dalvik.system.VMRuntime;
53491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanianimport sun.security.jca.Providers;
54491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian
55522b9174fca3ce4724ef8e032e26664697529e03Kenny Rootpublic class CertPathValidatorTest extends TestCase {
56491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian
57491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian    // Allow access to deprecated BC algorithms in this test, so we can ensure they
58491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian    // continue to work
59491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian    @Override
60491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian    public void setUp() throws Exception {
61491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian        super.setUp();
62491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian        Providers.setMaximumAllowableApiLevelForBcDeprecation(
63491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian                VMRuntime.getRuntime().getTargetSdkVersion());
64491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian    }
65491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian
66491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian    @Override
67491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian    public void tearDown() throws Exception {
68491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian        Providers.setMaximumAllowableApiLevelForBcDeprecation(
69491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
70491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian        super.tearDown();
71491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian    }
72491d88834d8af35b9701f92d972212d873dbb6a0Adam Vartanian
73522b9174fca3ce4724ef8e032e26664697529e03Kenny Root    private OCSPResp generateOCSPResponse(X509Certificate serverCertJca, X509Certificate caCertJca,
74522b9174fca3ce4724ef8e032e26664697529e03Kenny Root            PrivateKey caKey, CertificateStatus status) throws Exception {
75522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        X509CertificateHolder caCert = new JcaX509CertificateHolder(caCertJca);
76522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
77522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        DigestCalculatorProvider digCalcProv = new BcDigestCalculatorProvider();
78522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        BasicOCSPRespBuilder basicBuilder = new BasicOCSPRespBuilder(
79522b9174fca3ce4724ef8e032e26664697529e03Kenny Root                SubjectPublicKeyInfo.getInstance(caCertJca.getPublicKey().getEncoded()),
80522b9174fca3ce4724ef8e032e26664697529e03Kenny Root                digCalcProv.get(CertificateID.HASH_SHA1));
81522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
82522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        CertificateID certId = new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1),
83522b9174fca3ce4724ef8e032e26664697529e03Kenny Root                caCert, serverCertJca.getSerialNumber());
84522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
85522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        basicBuilder.addResponse(certId, status);
86522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
87522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        BasicOCSPResp resp = basicBuilder.build(
88522b9174fca3ce4724ef8e032e26664697529e03Kenny Root                new JcaContentSignerBuilder("SHA1withRSA").build(caKey), null, new Date());
89522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
90522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        OCSPRespBuilder builder = new OCSPRespBuilder();
91522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        return builder.build(OCSPRespBuilder.SUCCESSFUL, resp);
92522b9174fca3ce4724ef8e032e26664697529e03Kenny Root    }
93522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
94522b9174fca3ce4724ef8e032e26664697529e03Kenny Root    private void runOCSPStapledTest(CertificateStatus certStatus, final boolean goodStatus)
95522b9174fca3ce4724ef8e032e26664697529e03Kenny Root            throws Exception {
96522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        PrivateKeyEntry serverEntry = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
97522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        PrivateKeyEntry caEntry = TestKeyStore.getIntermediateCa().getPrivateKey("RSA", "RSA");
98522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        PrivateKeyEntry rootCaEntry = TestKeyStore.getRootCa().getPrivateKey("RSA", "RSA");
99522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
100522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        X509Certificate serverCert = (X509Certificate) serverEntry.getCertificate();
101522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        OCSPResp ocspResponse = generateOCSPResponse(serverCert,
102522b9174fca3ce4724ef8e032e26664697529e03Kenny Root                (X509Certificate) caEntry.getCertificate(), caEntry.getPrivateKey(), certStatus);
103522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
104522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        PKIXParameters params = new PKIXParameters(Collections
105522b9174fca3ce4724ef8e032e26664697529e03Kenny Root                .singleton(new TrustAnchor((X509Certificate) rootCaEntry.getCertificate(), null)));
106522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
107522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        // By default we shouldn't have a PKIXRevocationChecker already.
108522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        for (PKIXCertPathChecker checker : params.getCertPathCheckers()) {
109522b9174fca3ce4724ef8e032e26664697529e03Kenny Root            assertFalse(checker instanceof PKIXRevocationChecker);
110522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        }
111522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
112522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
113522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
114522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        PKIXRevocationChecker revChecker = (PKIXRevocationChecker) cpv.getRevocationChecker();
115522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        revChecker.setOptions(Collections.singleton(Option.ONLY_END_ENTITY));
116522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        revChecker.setOcspResponses(
117522b9174fca3ce4724ef8e032e26664697529e03Kenny Root                Collections.singletonMap(serverCert, ocspResponse.getEncoded()));
118522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
119522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        List<PKIXCertPathChecker> checkers = new ArrayList<>(params.getCertPathCheckers());
120522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        checkers.add(revChecker);
121522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        params.setCertPathCheckers(checkers);
122522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
123522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        ArrayList<X509Certificate> chain = new ArrayList<>();
124522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        chain.add(serverCert);
125522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        chain.add((X509Certificate) caEntry.getCertificate());
126522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
127522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        CertificateFactory cf = CertificateFactory.getInstance("X.509");
128522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        CertPath certPath = cf.generateCertPath(chain);
129522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
130522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        try {
131522b9174fca3ce4724ef8e032e26664697529e03Kenny Root            cpv.validate(certPath, params);
132522b9174fca3ce4724ef8e032e26664697529e03Kenny Root            assertTrue("should fail with failure OCSP status", goodStatus);
133522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        } catch (CertPathValidatorException maybeExpected) {
134522b9174fca3ce4724ef8e032e26664697529e03Kenny Root            assertFalse("should not fail with good OCSP status", goodStatus);
135522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        }
136522b9174fca3ce4724ef8e032e26664697529e03Kenny Root    }
137522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
138522b9174fca3ce4724ef8e032e26664697529e03Kenny Root    public void test_OCSP_EndEntity_KeyCompromise_Failure() throws Exception {
139522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        runOCSPStapledTest(new RevokedStatus(new Date(), CRLReason.keyCompromise), false);
140522b9174fca3ce4724ef8e032e26664697529e03Kenny Root    }
141522b9174fca3ce4724ef8e032e26664697529e03Kenny Root
142522b9174fca3ce4724ef8e032e26664697529e03Kenny Root    public void test_OCSP_EndEntity_Good_Success() throws Exception {
143522b9174fca3ce4724ef8e032e26664697529e03Kenny Root        runOCSPStapledTest(CertificateStatus.GOOD, true);
144522b9174fca3ce4724ef8e032e26664697529e03Kenny Root    }
145522b9174fca3ce4724ef8e032e26664697529e03Kenny Root}
146