1 /* 2 * Copyright (c) 2000, 2013, 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.x509.X509CertImpl; 35 import sun.security.util.Debug; 36 37 /** 38 * This class implements the PKIX validation algorithm for certification 39 * paths consisting exclusively of <code>X509Certificates</code>. It uses 40 * the specified input parameter set (which must be a 41 * <code>PKIXParameters</code> object). 42 * 43 * @since 1.4 44 * @author Yassir Elley 45 */ 46 public final class PKIXCertPathValidator extends CertPathValidatorSpi { 47 48 private static final Debug debug = Debug.getInstance("certpath"); 49 50 /** 51 * Default constructor. 52 */ PKIXCertPathValidator()53 public PKIXCertPathValidator() {} 54 55 @Override engineGetRevocationChecker()56 public CertPathChecker engineGetRevocationChecker() { 57 return new RevocationChecker(); 58 } 59 60 /** 61 * Validates a certification path consisting exclusively of 62 * <code>X509Certificate</code>s using the PKIX validation algorithm, 63 * which uses the specified input parameter set. 64 * The input parameter set must be a <code>PKIXParameters</code> object. 65 * 66 * @param cp the X509 certification path 67 * @param params the input PKIX parameter set 68 * @return the result 69 * @throws CertPathValidatorException if cert path does not validate. 70 * @throws InvalidAlgorithmParameterException if the specified 71 * parameters are inappropriate for this CertPathValidator 72 */ 73 @Override engineValidate(CertPath cp, CertPathParameters params)74 public CertPathValidatorResult engineValidate(CertPath cp, 75 CertPathParameters params) 76 throws CertPathValidatorException, InvalidAlgorithmParameterException 77 { 78 ValidatorParams valParams = PKIX.checkParams(cp, params); 79 return validate(valParams); 80 } 81 validate(ValidatorParams params)82 private static PKIXCertPathValidatorResult validate(ValidatorParams params) 83 throws CertPathValidatorException 84 { 85 if (debug != null) 86 debug.println("PKIXCertPathValidator.engineValidate()..."); 87 88 // Retrieve the first certificate in the certpath 89 // (to be used later in pre-screening) 90 AdaptableX509CertSelector selector = null; 91 List<X509Certificate> certList = params.certificates(); 92 if (!certList.isEmpty()) { 93 selector = new AdaptableX509CertSelector(); 94 X509Certificate firstCert = certList.get(0); 95 // check trusted certificate's subject 96 selector.setSubject(firstCert.getIssuerX500Principal()); 97 // check the validity period 98 selector.setValidityPeriod(firstCert.getNotBefore(), 99 firstCert.getNotAfter()); 100 /* 101 * Facilitate certification path construction with authority 102 * key identifier and subject key identifier. 103 */ 104 try { 105 X509CertImpl firstCertImpl = X509CertImpl.toImpl(firstCert); 106 selector.parseAuthorityKeyIdentifierExtension( 107 firstCertImpl.getAuthorityKeyIdentifierExtension()); 108 } catch (CertificateException | IOException e) { 109 // ignore 110 } 111 } 112 113 CertPathValidatorException lastException = null; 114 115 // We iterate through the set of trust anchors until we find 116 // one that works at which time we stop iterating 117 for (TrustAnchor anchor : params.trustAnchors()) { 118 X509Certificate trustedCert = anchor.getTrustedCert(); 119 if (trustedCert != null) { 120 // if this trust anchor is not worth trying, 121 // we move on to the next one 122 if (selector != null && !selector.match(trustedCert)) { 123 if (debug != null) { 124 debug.println("NO - don't try this trustedCert"); 125 } 126 continue; 127 } 128 129 if (debug != null) { 130 debug.println("YES - try this trustedCert"); 131 debug.println("anchor.getTrustedCert()." 132 + "getSubjectX500Principal() = " 133 + trustedCert.getSubjectX500Principal()); 134 } 135 } else { 136 if (debug != null) { 137 debug.println("PKIXCertPathValidator.engineValidate(): " 138 + "anchor.getTrustedCert() == null"); 139 } 140 } 141 142 try { 143 return validate(anchor, params); 144 } catch (CertPathValidatorException cpe) { 145 // remember this exception 146 lastException = cpe; 147 } 148 } 149 150 // could not find a trust anchor that verified 151 // (a) if we did a validation and it failed, use that exception 152 if (lastException != null) { 153 throw lastException; 154 } 155 // (b) otherwise, generate new exception 156 throw new CertPathValidatorException 157 ("Path does not chain with any of the trust anchors", 158 null, null, -1, PKIXReason.NO_TRUST_ANCHOR); 159 } 160 validate(TrustAnchor anchor, ValidatorParams params)161 private static PKIXCertPathValidatorResult validate(TrustAnchor anchor, 162 ValidatorParams params) 163 throws CertPathValidatorException 164 { 165 int certPathLen = params.certificates().size(); 166 167 // create PKIXCertPathCheckers 168 List<PKIXCertPathChecker> certPathCheckers = new ArrayList<>(); 169 // add standard checkers that we will be using 170 certPathCheckers.add(new UntrustedChecker()); 171 certPathCheckers.add(new AlgorithmChecker(anchor)); 172 certPathCheckers.add(new KeyChecker(certPathLen, 173 params.targetCertConstraints())); 174 certPathCheckers.add(new ConstraintsChecker(certPathLen)); 175 PolicyNodeImpl rootNode = 176 new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false, 177 Collections.singleton(PolicyChecker.ANY_POLICY), 178 false); 179 PolicyChecker pc = new PolicyChecker(params.initialPolicies(), 180 certPathLen, 181 params.explicitPolicyRequired(), 182 params.policyMappingInhibited(), 183 params.anyPolicyInhibited(), 184 params.policyQualifiersRejected(), 185 rootNode); 186 certPathCheckers.add(pc); 187 // default value for date is current time 188 BasicChecker bc = new BasicChecker(anchor, params.date(), 189 params.sigProvider(), false); 190 certPathCheckers.add(bc); 191 192 boolean revCheckerAdded = false; 193 List<PKIXCertPathChecker> checkers = params.certPathCheckers(); 194 for (PKIXCertPathChecker checker : checkers) { 195 if (checker instanceof PKIXRevocationChecker) { 196 if (revCheckerAdded) { 197 throw new CertPathValidatorException( 198 "Only one PKIXRevocationChecker can be specified"); 199 } 200 revCheckerAdded = true; 201 // if it's our own, initialize it 202 if (checker instanceof RevocationChecker) { 203 ((RevocationChecker)checker).init(anchor, params); 204 } 205 } 206 } 207 // only add a RevocationChecker if revocation is enabled and 208 // a PKIXRevocationChecker has not already been added 209 if (params.revocationEnabled() && !revCheckerAdded) { 210 certPathCheckers.add(new RevocationChecker(anchor, params)); 211 } 212 // add user-specified checkers 213 certPathCheckers.addAll(checkers); 214 215 PKIXMasterCertPathValidator.validate(params.certPath(), 216 params.certificates(), 217 certPathCheckers); 218 219 return new PKIXCertPathValidatorResult(anchor, pc.getPolicyTree(), 220 bc.getPublicKey()); 221 } 222 } 223