/** * Search the given Set of TrustAnchor's for one that is the issuer of the given X509 certificate. * Uses the specified provider for signature verification, or the default provider if null. * * @param cert the X509 certificate * @param trustAnchors a Set of TrustAnchor's * @param sigProvider the provider to use for signature verification * @return the <code>TrustAnchor</code> object if found or <code>null</code> if not. * @throws AnnotatedException if a TrustAnchor was found but the signature verification on the * given certificate has thrown an exception. */ protected static TrustAnchor findTrustAnchor( X509Certificate cert, Set trustAnchors, String sigProvider) throws AnnotatedException { TrustAnchor trust = null; PublicKey trustPublicKey = null; Exception invalidKeyEx = null; X509CertSelector certSelectX509 = new X509CertSelector(); X500Principal certIssuer = getEncodedIssuerPrincipal(cert); try { certSelectX509.setSubject(certIssuer.getEncoded()); } catch (IOException ex) { throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex); } Iterator iter = trustAnchors.iterator(); while (iter.hasNext() && trust == null) { trust = (TrustAnchor) iter.next(); if (trust.getTrustedCert() != null) { if (certSelectX509.match(trust.getTrustedCert())) { trustPublicKey = trust.getTrustedCert().getPublicKey(); } else { trust = null; } } else if (trust.getCAName() != null && trust.getCAPublicKey() != null) { try { X500Principal caName = new X500Principal(trust.getCAName()); if (certIssuer.equals(caName)) { trustPublicKey = trust.getCAPublicKey(); } else { trust = null; } } catch (IllegalArgumentException ex) { trust = null; } } else { trust = null; } if (trustPublicKey != null) { try { verifyX509Certificate(cert, trustPublicKey, sigProvider); } catch (Exception ex) { invalidKeyEx = ex; trust = null; trustPublicKey = null; } } } if (trust == null && invalidKeyEx != null) { throw new AnnotatedException( "TrustAnchor found but certificate validation failed.", invalidKeyEx); } return trust; }
/** * Search the given Set of TrustAnchor's for one that is the issuer of the given X509 certificate. * * @param cert the X509 certificate * @param params with trust anchors * @return the <code>TrustAnchor</code> object if found or <code>null</code> if not. * @exception CertPathValidatorException if a TrustAnchor was found but the signature verification * on the given certificate has thrown an exception. This Exception can be obtainted with * <code>getCause()</code> method. */ static final TrustAnchor findTrustAnchor( X509Certificate cert, CertPath certPath, int index, PKIXParameters params) throws CertPathValidatorException { // If we have a trust anchor index, use it. if (params instanceof IndexedPKIXParameters) { IndexedPKIXParameters indexed = (IndexedPKIXParameters) params; return indexed.findTrustAnchor(cert, certPath, index); } Iterator iter = params.getTrustAnchors().iterator(); TrustAnchor found = null; PublicKey trustPublicKey = null; Exception invalidKeyEx = null; X509CertSelector certSelectX509 = new X509CertSelector(); try { certSelectX509.setSubject(getEncodedIssuerPrincipal(cert).getEncoded()); } catch (IOException ex) { throw new CertPathValidatorException(ex); } byte[] certBytes = null; try { certBytes = cert.getEncoded(); } catch (Exception e) { // ignore, just continue } while (iter.hasNext() && found == null) { found = (TrustAnchor) iter.next(); X509Certificate foundCert = found.getTrustedCert(); if (foundCert != null) { // If the trust anchor is identical to the certificate we're // done. Just return the anchor. // There is similar code in PKIXCertPathValidatorSpi. try { byte[] foundBytes = foundCert.getEncoded(); if (certBytes != null && Arrays.equals(foundBytes, certBytes)) { return found; } } catch (Exception e) { // ignore, continue and verify the certificate } if (certSelectX509.match(foundCert)) { trustPublicKey = foundCert.getPublicKey(); } else { found = null; } } else if (found.getCAName() != null && found.getCAPublicKey() != null) { try { X500Principal certIssuer = getEncodedIssuerPrincipal(cert); X500Principal caName = new X500Principal(found.getCAName()); if (certIssuer.equals(caName)) { trustPublicKey = found.getCAPublicKey(); } else { found = null; } } catch (IllegalArgumentException ex) { found = null; } } else { found = null; } if (trustPublicKey != null) { try { cert.verify(trustPublicKey); } catch (Exception ex) { invalidKeyEx = ex; found = null; } } } if (found == null && invalidKeyEx != null) { throw new CertPathValidatorException( "TrustAnchor found but certificate validation failed.", invalidKeyEx, certPath, index); } return found; }
/** * Verifies a matching certificate. * * <p>This method executes any of the validation steps in the PKIX path validation algorithm which * were not satisfied via filtering out non-compliant certificates with certificate matching * rules. * * <p>If the last certificate is being verified (the one whose subject matches the target subject, * then the steps in Section 6.1.4 of the Certification Path Validation algorithm are NOT * executed, regardless of whether or not the last cert is an end-entity cert or not. This allows * callers to certify CA certs as well as EE certs. * * @param cert the certificate to be verified * @param currentState the current state against which the cert is verified * @param certPathList the certPathList generated thus far */ void verifyCert(X509Certificate cert, State currState, List certPathList) throws GeneralSecurityException { if (debug != null) debug.println( "ReverseBuilder.verifyCert(SN: " + Debug.toHexString(cert.getSerialNumber()) + "\n Subject: " + cert.getSubjectX500Principal() + ")"); ReverseState currentState = (ReverseState) currState; /* we don't perform any validation of the trusted cert */ if (currentState.isInitial()) { return; } /* * check for looping - abort a loop if * ((we encounter the same certificate twice) AND * ((policyMappingInhibited = true) OR (no policy mapping * extensions can be found between the occurences of the same * certificate))) * in order to facilitate the check to see if there are * any policy mapping extensions found between the occurences * of the same certificate, we reverse the certpathlist first */ if ((certPathList != null) && (!certPathList.isEmpty())) { List reverseCertList = new ArrayList(); Iterator iter = certPathList.iterator(); while (iter.hasNext()) { reverseCertList.add(0, iter.next()); } Iterator cpListIter = reverseCertList.iterator(); boolean policyMappingFound = false; while (cpListIter.hasNext()) { X509Certificate cpListCert = (X509Certificate) cpListIter.next(); X509CertImpl cpListCertImpl = X509CertImpl.toImpl(cpListCert); PolicyMappingsExtension policyMappingsExt = cpListCertImpl.getPolicyMappingsExtension(); if (policyMappingsExt != null) { policyMappingFound = true; } if (debug != null) debug.println("policyMappingFound = " + policyMappingFound); if (cert.equals(cpListCert)) { if ((buildParams.isPolicyMappingInhibited()) || (!policyMappingFound)) { if (debug != null) debug.println("loop detected!!"); throw new CertPathValidatorException("loop detected"); } } } } /* check if target cert */ boolean finalCert = cert.getSubjectX500Principal().equals(targetSubjectDN); /* check if CA cert */ boolean caCert = (cert.getBasicConstraints() != -1 ? true : false); /* if there are more certs to follow, verify certain constraints */ if (!finalCert) { /* check if CA cert */ if (!caCert) throw new CertPathValidatorException("cert is NOT a CA cert"); /* If the certificate was not self-issued, verify that * remainingCerts is greater than zero */ if ((currentState.remainingCACerts <= 0) && !X509CertImpl.isSelfIssued(cert)) { throw new CertPathValidatorException("pathLenConstraint violated, path too long"); } /* * Check keyUsage extension (only if CA cert and not final cert) */ KeyChecker.verifyCAKeyUsage(cert); } else { /* * If final cert, check that it satisfies specified target * constraints */ if (targetCertSelector.match(cert) == false) { throw new CertPathValidatorException("target certificate " + "constraints check failed"); } } /* * Check revocation. */ if (buildParams.isRevocationEnabled()) { boolean crlSign = currentState.crlChecker.check(cert, currentState.pubKey, true); // if this cert can't vouch for the CRL on the next cert, and // if this wasn't the last cert in the chain, then we can't // keep going from here! // NOTE: if we ever add indirect/idp support, this will have // to change... if ((!crlSign) && (!finalCert)) throw new CertPathValidatorException("cert can't vouch for crl"); } /* Check name constraints if this is not a self-issued cert */ if (finalCert || !X509CertImpl.isSelfIssued(cert)) { if (currentState.nc != null) { try { if (!currentState.nc.verify(cert)) { throw new CertPathValidatorException("name constraints check failed"); } } catch (IOException ioe) { throw new CertPathValidatorException(ioe); } } } /* * Check policy */ X509CertImpl certImpl = X509CertImpl.toImpl(cert); currentState.rootNode = PolicyChecker.processPolicies( currentState.certIndex, initPolicies, currentState.explicitPolicy, currentState.policyMapping, currentState.inhibitAnyPolicy, buildParams.getPolicyQualifiersRejected(), currentState.rootNode, certImpl, finalCert); /* * Check CRITICAL private extensions */ Set unresolvedCritExts = cert.getCriticalExtensionOIDs(); if (unresolvedCritExts == null) { unresolvedCritExts = Collections.EMPTY_SET; } Iterator i = currentState.userCheckers.iterator(); while (i.hasNext()) { PKIXCertPathChecker checker = (PKIXCertPathChecker) i.next(); checker.check(cert, unresolvedCritExts); } /* * Look at the remaining extensions and remove any ones we have * already checked. If there are any left, throw an exception! */ if (!unresolvedCritExts.isEmpty()) { unresolvedCritExts.remove(PKIXExtensions.BasicConstraints_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.NameConstraints_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.CertificatePolicies_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.PolicyMappings_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.PolicyConstraints_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.InhibitAnyPolicy_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.SubjectAlternativeName_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.KeyUsage_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.ExtendedKeyUsage_Id.toString()); if (!unresolvedCritExts.isEmpty()) throw new CertificateException("Unrecognized critical extension(s)"); } /* * Check signature. */ if (buildParams.getSigProvider() != null) { cert.verify(currentState.pubKey, buildParams.getSigProvider()); } else { cert.verify(currentState.pubKey); } }