1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.*; 25 import java.math.BigInteger; 26 import java.security.*; 27 import java.security.cert.*; 28 import java.time.*; 29 import java.util.*; 30 import javax.net.ssl.*; 31 import sun.security.validator.Validator; 32 import sun.security.validator.ValidatorException; 33 34 35 /** 36 * @test 37 * @bug 8207258 38 * @summary Check that TLS Server certificates chaining back to distrusted 39 * Symantec roots are invalid 40 * @library /lib/security 41 * @run main/othervm Distrust true 42 * @run main/othervm Distrust false 43 */ 44 45 public class Distrust { 46 47 private static final String TEST_SRC = System.getProperty("test.src", "."); 48 private static CertificateFactory cf; 49 50 // Each of the roots have a test certificate chain stored in a file 51 // named "<root>-chain.pem". 52 private static String[] rootsToTest = new String[] { 53 "geotrustglobalca", "geotrustprimarycag2", "geotrustprimarycag3", 54 "geotrustuniversalca", "thawteprimaryrootca", "thawteprimaryrootcag2", 55 "thawteprimaryrootcag3", "verisignclass3g3ca", "verisignclass3g4ca", 56 "verisignclass3g5ca", "verisignuniversalrootca" }; 57 58 // A date that is after the restrictions take affect 59 private static final Date APRIL_17_2019 = 60 Date.from(LocalDate.of(2019, 4, 17) 61 .atStartOfDay(ZoneOffset.UTC) 62 .toInstant()); 63 64 public static void main(String[] args) throws Exception { 65 66 cf = CertificateFactory.getInstance("X.509"); 67 boolean distrust = args[0].equals("true"); 68 if (!distrust) { 69 // disable policy 70 Security.setProperty("jdk.security.caDistrustPolicies", ""); 71 } 72 73 X509TrustManager pkixTM = getTMF("PKIX", null); 74 X509TrustManager sunX509TM = getTMF("SunX509", null); 75 for (String test : rootsToTest) { 76 System.err.println("Testing " + test); 77 X509Certificate[] chain = loadCertificateChain(test); 78 79 testTM(sunX509TM, chain, !distrust); 80 testTM(pkixTM, chain, !distrust); 81 } 82 83 // test chain if params are passed to TrustManager 84 System.err.println("Testing verisignuniversalrootca with params"); 85 testTM(getTMF("PKIX", getParams()), 86 loadCertificateChain("verisignuniversalrootca"), !distrust); 87 88 // test code-signing chain (should be valid as restrictions don't apply) 89 System.err.println("Testing verisignclass3g5ca code-signing chain"); 90 Validator v = Validator.getInstance(Validator.TYPE_PKIX, 91 Validator.VAR_CODE_SIGNING, 92 getParams()); 93 // set validation date so this will still pass when cert expires 94 v.setValidationDate(new Date(1544197375493l)); 95 v.validate(loadCertificateChain("verisignclass3g5ca-codesigning")); 96 } 97 98 private static X509TrustManager getTMF(String type, 99 PKIXBuilderParameters params) throws Exception { 100 TrustManagerFactory tmf = TrustManagerFactory.getInstance(type); 101 if (params == null) { 102 tmf.init((KeyStore)null); 103 } else { 104 tmf.init(new CertPathTrustManagerParameters(params)); 105 } 106 TrustManager[] tms = tmf.getTrustManagers(); 107 for (TrustManager tm : tms) { 108 X509TrustManager xtm = (X509TrustManager)tm; 109 return xtm; 110 } 111 throw new Exception("No TrustManager for " + type); 112 } 113 114 private static PKIXBuilderParameters getParams() throws Exception { 115 PKIXBuilderParameters pbp = 116 new PKIXBuilderParameters(SecurityUtils.getCacertsKeyStore(), 117 new X509CertSelector()); 118 pbp.setRevocationEnabled(false); 119 return pbp; 120 } 121 122 private static void testTM(X509TrustManager xtm, X509Certificate[] chain, 123 boolean valid) throws Exception { 124 // Check if TLS Server certificate (the first element of the chain) 125 // is issued after April 16, 2019 (should be rejected unless distrust 126 // property is false). To do this, we need to fake the notBefore date 127 // since none of the test certs are issued after then. 128 chain[0] = new DistrustedTLSServerCert(chain[0], APRIL_17_2019); 129 130 try { 131 xtm.checkServerTrusted(chain, "ECDHE_RSA"); 132 if (!valid) { 133 throw new Exception("chain should be invalid"); 134 } 135 } catch (CertificateException ce) { 136 if (valid) { 137 throw new Exception("Unexpected exception, chain " + 138 "should be valid", ce); 139 } 140 if (ce instanceof ValidatorException) { 141 ValidatorException ve = (ValidatorException)ce; 142 if (ve.getErrorType() != ValidatorException.T_UNTRUSTED_CERT) { 143 throw new Exception("Unexpected exception: " + ce); 144 } 145 } else { 146 throw new Exception("Unexpected exception: " + ce); 147 } 148 } 149 } 150 151 private static X509Certificate[] loadCertificateChain(String name) 152 throws Exception { 153 try (InputStream in = new FileInputStream(TEST_SRC + File.separator + 154 name + "-chain.pem")) { 155 Collection<X509Certificate> certs = 156 (Collection<X509Certificate>)cf.generateCertificates(in); 157 return certs.toArray(new X509Certificate[0]); 158 } 159 } 160 161 private static class DistrustedTLSServerCert extends X509Certificate { 162 private final X509Certificate cert; 163 private final Date notBefore; 164 DistrustedTLSServerCert(X509Certificate cert, Date notBefore) { 165 this.cert = cert; 166 this.notBefore = notBefore; 167 } 168 public Set<String> getCriticalExtensionOIDs() { 169 return cert.getCriticalExtensionOIDs(); 170 } 171 public byte[] getExtensionValue(String oid) { 172 return cert.getExtensionValue(oid); 173 } 174 public Set<String> getNonCriticalExtensionOIDs() { 175 return cert.getNonCriticalExtensionOIDs(); 176 } 177 public boolean hasUnsupportedCriticalExtension() { 178 return cert.hasUnsupportedCriticalExtension(); 179 } 180 public void checkValidity() throws CertificateExpiredException, 181 CertificateNotYetValidException { 182 // always pass 183 } 184 public void checkValidity(Date date) throws CertificateExpiredException, 185 CertificateNotYetValidException { 186 // always pass 187 } 188 public int getVersion() { return cert.getVersion(); } 189 public BigInteger getSerialNumber() { return cert.getSerialNumber(); } 190 public Principal getIssuerDN() { return cert.getIssuerDN(); } 191 public Principal getSubjectDN() { return cert.getSubjectDN(); } 192 public Date getNotBefore() { return notBefore; } 193 public Date getNotAfter() { return cert.getNotAfter(); } 194 public byte[] getTBSCertificate() throws CertificateEncodingException { 195 return cert.getTBSCertificate(); 196 } 197 public byte[] getSignature() { return cert.getSignature(); } 198 public String getSigAlgName() { return cert.getSigAlgName(); } 199 public String getSigAlgOID() { return cert.getSigAlgOID(); } 200 public byte[] getSigAlgParams() { return cert.getSigAlgParams(); } 201 public boolean[] getIssuerUniqueID() { 202 return cert.getIssuerUniqueID(); 203 } 204 public boolean[] getSubjectUniqueID() { 205 return cert.getSubjectUniqueID(); 206 } 207 public boolean[] getKeyUsage() { return cert.getKeyUsage(); } 208 public int getBasicConstraints() { return cert.getBasicConstraints(); } 209 public byte[] getEncoded() throws CertificateEncodingException { 210 return cert.getEncoded(); 211 } 212 public void verify(PublicKey key) throws CertificateException, 213 InvalidKeyException, NoSuchAlgorithmException, 214 NoSuchProviderException, SignatureException { 215 cert.verify(key); 216 } 217 public void verify(PublicKey key, String sigProvider) throws 218 CertificateException, InvalidKeyException, NoSuchAlgorithmException, 219 NoSuchProviderException, SignatureException { 220 cert.verify(key, sigProvider); 221 } 222 public PublicKey getPublicKey() { return cert.getPublicKey(); } 223 public String toString() { return cert.toString(); } 224 } 225 }