1 /* 2 * Copyright (c) 2000, 2017, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.provider.certpath; 27 28 import java.io.IOException; 29 import java.security.InvalidAlgorithmParameterException; 30 import java.security.cert.*; 31 import java.util.*; 32 33 import sun.security.provider.certpath.PKIX.ValidatorParams; 34 import sun.security.validator.Validator; 35 import sun.security.x509.X509CertImpl; 36 import sun.security.util.Debug; 37 38 /** 39 * This class implements the PKIX validation algorithm for certification 40 * paths consisting exclusively of <code>X509Certificates</code>. It uses 41 * the specified input parameter set (which must be a 42 * <code>PKIXParameters</code> object). 43 * 44 * @since 1.4 45 * @author Yassir Elley 46 */ 47 public final class PKIXCertPathValidator extends CertPathValidatorSpi { 48 49 private static final Debug debug = Debug.getInstance("certpath"); 50 51 /** 52 * Default constructor. 53 */ 54 public PKIXCertPathValidator() {} 55 56 @Override 57 public CertPathChecker engineGetRevocationChecker() { 58 return new RevocationChecker(); 59 } 60 61 /** 62 * Validates a certification path consisting exclusively of 63 * <code>X509Certificate</code>s using the PKIX validation algorithm, 64 * which uses the specified input parameter set. 65 * The input parameter set must be a <code>PKIXParameters</code> object. 66 * 67 * @param cp the X509 certification path 68 * @param params the input PKIX parameter set 69 * @return the result 70 * @throws CertPathValidatorException if cert path does not validate. 71 * @throws InvalidAlgorithmParameterException if the specified 72 * parameters are inappropriate for this CertPathValidator 73 */ 74 @Override 75 public CertPathValidatorResult engineValidate(CertPath cp, 76 CertPathParameters params) 77 throws CertPathValidatorException, InvalidAlgorithmParameterException 78 { 79 ValidatorParams valParams = PKIX.checkParams(cp, params); 80 return validate(valParams); 81 } 82 83 private static PKIXCertPathValidatorResult validate(ValidatorParams params) 84 throws CertPathValidatorException 85 { 86 if (debug != null) 87 debug.println("PKIXCertPathValidator.engineValidate()..."); 88 89 // Retrieve the first certificate in the certpath 90 // (to be used later in pre-screening) 91 AdaptableX509CertSelector selector = null; 92 List<X509Certificate> certList = params.certificates(); 93 if (!certList.isEmpty()) { 94 selector = new AdaptableX509CertSelector(); 95 X509Certificate firstCert = certList.get(0); 96 // check trusted certificate's subject 97 selector.setSubject(firstCert.getIssuerX500Principal()); 98 /* 99 * Facilitate certification path construction with authority 100 * key identifier and subject key identifier. 101 */ 102 try { 103 X509CertImpl firstCertImpl = X509CertImpl.toImpl(firstCert); 104 selector.setSkiAndSerialNumber( 105 firstCertImpl.getAuthorityKeyIdentifierExtension()); 106 } catch (CertificateException | IOException e) { 107 // ignore 108 } 109 } 110 111 CertPathValidatorException lastException = null; 112 113 // We iterate through the set of trust anchors until we find 114 // one that works at which time we stop iterating 115 for (TrustAnchor anchor : params.trustAnchors()) { 116 X509Certificate trustedCert = anchor.getTrustedCert(); 117 if (trustedCert != null) { 118 // if this trust anchor is not worth trying, 119 // we move on to the next one 120 if (selector != null && !selector.match(trustedCert)) { 121 if (debug != null && Debug.isVerbose()) { 122 debug.println("NO - don't try this trustedCert"); 123 } 124 continue; 125 } 126 127 if (debug != null) { 128 debug.println("YES - try this trustedCert"); 129 debug.println("anchor.getTrustedCert()." 130 + "getSubjectX500Principal() = " 131 + trustedCert.getSubjectX500Principal()); 132 } 133 } else { 134 if (debug != null) { 135 debug.println("PKIXCertPathValidator.engineValidate(): " 136 + "anchor.getTrustedCert() == null"); 137 } 138 } 139 140 try { 141 return validate(anchor, params); 142 } catch (CertPathValidatorException cpe) { 143 // remember this exception 144 lastException = cpe; 145 } 146 } 147 148 // could not find a trust anchor that verified 149 // (a) if we did a validation and it failed, use that exception 150 if (lastException != null) { 151 throw lastException; 152 } 153 // (b) otherwise, generate new exception 154 throw new CertPathValidatorException 155 ("Path does not chain with any of the trust anchors", 156 null, null, -1, PKIXReason.NO_TRUST_ANCHOR); 157 } 158 159 private static PKIXCertPathValidatorResult validate(TrustAnchor anchor, 160 ValidatorParams params) 161 throws CertPathValidatorException 162 { 163 // check if anchor is untrusted 164 UntrustedChecker untrustedChecker = new UntrustedChecker(); 165 X509Certificate anchorCert = anchor.getTrustedCert(); 166 if (anchorCert != null) { 167 untrustedChecker.check(anchorCert); 168 } 169 170 int certPathLen = params.certificates().size(); 171 172 // create PKIXCertPathCheckers 173 List<PKIXCertPathChecker> certPathCheckers = new ArrayList<>(); 174 // add standard checkers that we will be using 175 certPathCheckers.add(untrustedChecker); 176 certPathCheckers.add(new AlgorithmChecker(anchor, null, params.date(), 177 params.timestamp(), params.variant())); 178 certPathCheckers.add(new KeyChecker(certPathLen, 179 params.targetCertConstraints())); 180 certPathCheckers.add(new ConstraintsChecker(certPathLen)); 181 PolicyNodeImpl rootNode = 182 new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false, 183 Collections.singleton(PolicyChecker.ANY_POLICY), 184 false); 185 PolicyChecker pc = new PolicyChecker(params.initialPolicies(), 186 certPathLen, 187 params.explicitPolicyRequired(), 188 params.policyMappingInhibited(), 189 params.anyPolicyInhibited(), 190 params.policyQualifiersRejected(), 191 rootNode); 192 certPathCheckers.add(pc); 193 194 // the time that the certificate validity period should be 195 // checked against 196 Date timeToCheck = null; 197 // use timestamp if checking signed code that is timestamped, otherwise 198 // use date parameter from PKIXParameters 199 if ((params.variant() == Validator.VAR_CODE_SIGNING || 200 params.variant() == Validator.VAR_PLUGIN_CODE_SIGNING) && 201 params.timestamp() != null) { 202 timeToCheck = params.timestamp().getTimestamp(); 203 } else { 204 timeToCheck = params.date(); 205 } 206 BasicChecker bc = new BasicChecker(anchor, timeToCheck, 207 params.sigProvider(), false); 208 certPathCheckers.add(bc); 209 210 boolean revCheckerAdded = false; 211 List<PKIXCertPathChecker> checkers = params.certPathCheckers(); 212 for (PKIXCertPathChecker checker : checkers) { 213 if (checker instanceof PKIXRevocationChecker) { 214 if (revCheckerAdded) { 215 throw new CertPathValidatorException( 216 "Only one PKIXRevocationChecker can be specified"); 217 } 218 revCheckerAdded = true; 219 // if it's our own, initialize it 220 if (checker instanceof RevocationChecker) { 221 ((RevocationChecker)checker).init(anchor, params); 222 } 223 } 224 } 225 // only add a RevocationChecker if revocation is enabled and 226 // a PKIXRevocationChecker has not already been added 227 if (params.revocationEnabled() && !revCheckerAdded) { 228 certPathCheckers.add(new RevocationChecker(anchor, params)); 229 } 230 // add user-specified checkers 231 certPathCheckers.addAll(checkers); 232 233 PKIXMasterCertPathValidator.validate(params.certPath(), 234 params.certificates(), 235 certPathCheckers); 236 237 return new PKIXCertPathValidatorResult(anchor, pc.getPolicyTree(), 238 bc.getPublicKey()); 239 } 240 }