1 /* 2 * Copyright (c) 2000, 2015, 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 /* 98 * Facilitate certification path construction with authority 99 * key identifier and subject key identifier. 100 */ 101 try { 102 X509CertImpl firstCertImpl = X509CertImpl.toImpl(firstCert); 103 selector.setSkiAndSerialNumber( 104 firstCertImpl.getAuthorityKeyIdentifierExtension()); 105 } catch (CertificateException | IOException e) { 106 // ignore 107 } 108 } 109 110 CertPathValidatorException lastException = null; 111 112 // We iterate through the set of trust anchors until we find 113 // one that works at which time we stop iterating 114 for (TrustAnchor anchor : params.trustAnchors()) { 115 X509Certificate trustedCert = anchor.getTrustedCert(); 116 if (trustedCert != null) { 117 // if this trust anchor is not worth trying, 118 // we move on to the next one 119 if (selector != null && !selector.match(trustedCert)) { 120 if (debug != null) { 121 debug.println("NO - don't try this trustedCert"); 122 } 123 continue; 124 } 125 126 if (debug != null) { 127 debug.println("YES - try this trustedCert"); 128 debug.println("anchor.getTrustedCert()." 129 + "getSubjectX500Principal() = " 130 + trustedCert.getSubjectX500Principal()); 131 } 132 } else { 133 if (debug != null) { 134 debug.println("PKIXCertPathValidator.engineValidate(): " 135 + "anchor.getTrustedCert() == null"); 136 } 137 } 138 139 try { 140 return validate(anchor, params); 141 } catch (CertPathValidatorException cpe) { 142 // remember this exception 143 lastException = cpe; 144 } 145 } 146 147 // could not find a trust anchor that verified 148 // (a) if we did a validation and it failed, use that exception 149 if (lastException != null) { 150 throw lastException; 151 } 152 // (b) otherwise, generate new exception 153 throw new CertPathValidatorException 154 ("Path does not chain with any of the trust anchors", 155 null, null, -1, PKIXReason.NO_TRUST_ANCHOR); 156 } 157 validate(TrustAnchor anchor, ValidatorParams params)158 private static PKIXCertPathValidatorResult validate(TrustAnchor anchor, 159 ValidatorParams params) 160 throws CertPathValidatorException 161 { 162 // add standard checkers that we will be using 163 // Android-removed: Android doesn't use this mechanism for checking untrusted certificates. 164 // check if anchor is untrusted 165 //UntrustedChecker untrustedChecker = new UntrustedChecker(); 166 //X509Certificate anchorCert = anchor.getTrustedCert(); 167 //if (anchorCert != null) { 168 // untrustedChecker.check(anchorCert); 169 //} 170 171 int certPathLen = params.certificates().size(); 172 173 // create PKIXCertPathCheckers 174 List<PKIXCertPathChecker> certPathCheckers = new ArrayList<>(); 175 // add standard checkers that we will be using 176 // Android-removed: Android doesn't use this mechanism for checking untrusted certificates. 177 // certPathCheckers.add(untrustedChecker); 178 certPathCheckers.add(new AlgorithmChecker(anchor)); 179 certPathCheckers.add(new KeyChecker(certPathLen, 180 params.targetCertConstraints())); 181 certPathCheckers.add(new ConstraintsChecker(certPathLen)); 182 PolicyNodeImpl rootNode = 183 new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false, 184 Collections.singleton(PolicyChecker.ANY_POLICY), 185 false); 186 PolicyChecker pc = new PolicyChecker(params.initialPolicies(), 187 certPathLen, 188 params.explicitPolicyRequired(), 189 params.policyMappingInhibited(), 190 params.anyPolicyInhibited(), 191 params.policyQualifiersRejected(), 192 rootNode); 193 certPathCheckers.add(pc); 194 // default value for date is current time 195 BasicChecker bc = new BasicChecker(anchor, params.date(), 196 params.sigProvider(), false); 197 certPathCheckers.add(bc); 198 199 boolean revCheckerAdded = false; 200 List<PKIXCertPathChecker> checkers = params.certPathCheckers(); 201 for (PKIXCertPathChecker checker : checkers) { 202 if (checker instanceof PKIXRevocationChecker) { 203 if (revCheckerAdded) { 204 throw new CertPathValidatorException( 205 "Only one PKIXRevocationChecker can be specified"); 206 } 207 revCheckerAdded = true; 208 // if it's our own, initialize it 209 if (checker instanceof RevocationChecker) { 210 ((RevocationChecker)checker).init(anchor, params); 211 } 212 } 213 } 214 // only add a RevocationChecker if revocation is enabled and 215 // a PKIXRevocationChecker has not already been added 216 if (params.revocationEnabled() && !revCheckerAdded) { 217 certPathCheckers.add(new RevocationChecker(anchor, params)); 218 } 219 // add user-specified checkers 220 certPathCheckers.addAll(checkers); 221 222 PKIXMasterCertPathValidator.validate(params.certPath(), 223 params.certificates(), 224 certPathCheckers); 225 226 return new PKIXCertPathValidatorResult(anchor, pc.getPolicyTree(), 227 bc.getPublicKey()); 228 } 229 } 230