|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.provider.certpath; |
|
|
|
import java.io.IOException; |
|
import java.security.InvalidAlgorithmParameterException; |
|
import java.security.cert.*; |
|
import java.util.*; |
|
import java.util.concurrent.atomic.AtomicLong; |
|
|
|
import jdk.internal.event.X509ValidationEvent; |
|
import jdk.internal.event.EventHelper; |
|
import sun.security.provider.certpath.PKIX.ValidatorParams; |
|
import sun.security.x509.X509CertImpl; |
|
import sun.security.util.Debug; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final class PKIXCertPathValidator extends CertPathValidatorSpi { |
|
|
|
private static final Debug debug = Debug.getInstance("certpath"); |
|
private static final AtomicLong validationCounter = new AtomicLong(); |
|
|
|
|
|
|
|
*/ |
|
public PKIXCertPathValidator() {} |
|
|
|
@Override |
|
public CertPathChecker engineGetRevocationChecker() { |
|
return new RevocationChecker(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public CertPathValidatorResult engineValidate(CertPath cp, |
|
CertPathParameters params) |
|
throws CertPathValidatorException, InvalidAlgorithmParameterException |
|
{ |
|
ValidatorParams valParams = PKIX.checkParams(cp, params); |
|
return validate(valParams); |
|
} |
|
|
|
private static PKIXCertPathValidatorResult validate(ValidatorParams params) |
|
throws CertPathValidatorException |
|
{ |
|
if (debug != null) |
|
debug.println("PKIXCertPathValidator.engineValidate()..."); |
|
|
|
// Retrieve the first certificate in the certpath |
|
|
|
AdaptableX509CertSelector selector = null; |
|
List<X509Certificate> certList = params.certificates(); |
|
if (!certList.isEmpty()) { |
|
selector = new AdaptableX509CertSelector(); |
|
X509Certificate firstCert = certList.get(0); |
|
|
|
selector.setSubject(firstCert.getIssuerX500Principal()); |
|
|
|
|
|
|
|
*/ |
|
try { |
|
X509CertImpl firstCertImpl = X509CertImpl.toImpl(firstCert); |
|
selector.setSkiAndSerialNumber( |
|
firstCertImpl.getAuthorityKeyIdentifierExtension()); |
|
} catch (CertificateException | IOException e) { |
|
// ignore |
|
} |
|
} |
|
|
|
CertPathValidatorException lastException = null; |
|
|
|
// We iterate through the set of trust anchors until we find |
|
|
|
for (TrustAnchor anchor : params.trustAnchors()) { |
|
X509Certificate trustedCert = anchor.getTrustedCert(); |
|
if (trustedCert != null) { |
|
// if this trust anchor is not worth trying, |
|
|
|
if (selector != null && !selector.match(trustedCert)) { |
|
if (debug != null && Debug.isVerbose()) { |
|
debug.println("NO - don't try this trustedCert"); |
|
} |
|
continue; |
|
} |
|
|
|
if (debug != null) { |
|
debug.println("YES - try this trustedCert"); |
|
debug.println("anchor.getTrustedCert()." |
|
+ "getSubjectX500Principal() = " |
|
+ trustedCert.getSubjectX500Principal()); |
|
} |
|
} else { |
|
if (debug != null) { |
|
debug.println("PKIXCertPathValidator.engineValidate(): " |
|
+ "anchor.getTrustedCert() == null"); |
|
} |
|
} |
|
|
|
try { |
|
return validate(anchor, params); |
|
} catch (CertPathValidatorException cpe) { |
|
|
|
lastException = cpe; |
|
} |
|
} |
|
|
|
// could not find a trust anchor that verified |
|
|
|
if (lastException != null) { |
|
throw lastException; |
|
} |
|
|
|
throw new CertPathValidatorException |
|
("Path does not chain with any of the trust anchors", |
|
null, null, -1, PKIXReason.NO_TRUST_ANCHOR); |
|
} |
|
|
|
private static PKIXCertPathValidatorResult validate(TrustAnchor anchor, |
|
ValidatorParams params) |
|
throws CertPathValidatorException |
|
{ |
|
|
|
UntrustedChecker untrustedChecker = new UntrustedChecker(); |
|
X509Certificate anchorCert = anchor.getTrustedCert(); |
|
if (anchorCert != null) { |
|
untrustedChecker.check(anchorCert); |
|
} |
|
|
|
int certPathLen = params.certificates().size(); |
|
|
|
|
|
List<PKIXCertPathChecker> certPathCheckers = new ArrayList<>(); |
|
|
|
certPathCheckers.add(untrustedChecker); |
|
certPathCheckers.add(new AlgorithmChecker(anchor, null, params.date(), |
|
params.variant())); |
|
certPathCheckers.add(new KeyChecker(certPathLen, |
|
params.targetCertConstraints())); |
|
certPathCheckers.add(new ConstraintsChecker(certPathLen)); |
|
PolicyNodeImpl rootNode = |
|
new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false, |
|
Collections.singleton(PolicyChecker.ANY_POLICY), |
|
false); |
|
PolicyChecker pc = new PolicyChecker(params.initialPolicies(), |
|
certPathLen, |
|
params.explicitPolicyRequired(), |
|
params.policyMappingInhibited(), |
|
params.anyPolicyInhibited(), |
|
params.policyQualifiersRejected(), |
|
rootNode); |
|
certPathCheckers.add(pc); |
|
|
|
BasicChecker bc = new BasicChecker(anchor, params.date(), |
|
params.sigProvider(), false); |
|
certPathCheckers.add(bc); |
|
|
|
boolean revCheckerAdded = false; |
|
List<PKIXCertPathChecker> checkers = params.certPathCheckers(); |
|
for (PKIXCertPathChecker checker : checkers) { |
|
if (checker instanceof PKIXRevocationChecker) { |
|
if (revCheckerAdded) { |
|
throw new CertPathValidatorException( |
|
"Only one PKIXRevocationChecker can be specified"); |
|
} |
|
revCheckerAdded = true; |
|
|
|
if (checker instanceof RevocationChecker) { |
|
((RevocationChecker)checker).init(anchor, params); |
|
} |
|
} |
|
} |
|
// only add a RevocationChecker if revocation is enabled and |
|
|
|
if (params.revocationEnabled() && !revCheckerAdded) { |
|
certPathCheckers.add(new RevocationChecker(anchor, params)); |
|
} |
|
|
|
certPathCheckers.addAll(checkers); |
|
|
|
PKIXMasterCertPathValidator.validate(params.certPath(), |
|
params.certificates(), |
|
certPathCheckers); |
|
|
|
X509ValidationEvent xve = new X509ValidationEvent(); |
|
if (xve.shouldCommit() || EventHelper.isLoggingSecurity()) { |
|
int[] certIds = params.certificates().stream() |
|
.mapToInt(Certificate::hashCode) |
|
.toArray(); |
|
int anchorCertId = (anchorCert != null) ? |
|
anchorCert.hashCode() : anchor.getCAPublicKey().hashCode(); |
|
if (xve.shouldCommit()) { |
|
xve.certificateId = anchorCertId; |
|
int certificatePos = 1; |
|
xve.certificatePosition = certificatePos; |
|
xve.validationCounter = validationCounter.incrementAndGet(); |
|
xve.commit(); |
|
|
|
for (int id : certIds) { |
|
xve.certificateId = id; |
|
xve.certificatePosition = ++certificatePos; |
|
xve.commit(); |
|
|
|
} |
|
} |
|
if (EventHelper.isLoggingSecurity()) { |
|
EventHelper.logX509ValidationEvent(anchorCertId, certIds); |
|
} |
|
} |
|
return new PKIXCertPathValidatorResult(anchor, pc.getPolicyTree(), |
|
bc.getPublicKey()); |
|
} |
|
|
|
} |