private static void runTest(CertificateFactory cf, List<X509Certificate> certList, TrustAnchor anchor) throws Exception { CertPath path = cf.generateCertPath(certList); CertPathValidator validator = CertPathValidator.getInstance("PKIX"); System.out.println(anchor); // Attach the OCSP responses to a PKIXParameters object PKIXRevocationChecker pkrev = (PKIXRevocationChecker)validator.getRevocationChecker(); Map<X509Certificate, byte[]> responseMap = new HashMap<>(); responseMap.put(certList.get(0), DECODER.decode(EE_OCSP_RESP)); responseMap.put(certList.get(1), DECODER.decode(INT_CA_OCSP_RESP)); pkrev.setOcspResponses(responseMap); PKIXParameters params = new PKIXParameters(Collections.singleton(anchor)); params.addCertPathChecker(pkrev); params.setDate(EVAL_DATE); validator.validate(path, params); }
/** * Test a case where client-side stapling is attempted, but does not * occur because OCSP responders are unreachable. Client-side OCSP * checking is enabled for this, with SOFT_FAIL. */ static void testSoftFailFallback() throws Exception { ClientParameters cliParams = new ClientParameters(); ServerParameters servParams = new ServerParameters(); serverReady = false; // make OCSP responders reject connections intOcsp.rejectConnections(); rootOcsp.rejectConnections(); System.out.println("======================================="); System.out.println("Stapling enbled in client and server,"); System.out.println("but OCSP responders disabled."); System.out.println("PKIXParameters with Revocation checking"); System.out.println("enabled and SOFT_FAIL."); System.out.println("======================================="); Security.setProperty("ocsp.enable", "true"); cliParams.pkixParams = new PKIXBuilderParameters(trustStore, new X509CertSelector()); cliParams.pkixParams.setRevocationEnabled(true); CertPathValidator cpv = CertPathValidator.getInstance("PKIX"); cliParams.revChecker = (PKIXRevocationChecker)cpv.getRevocationChecker(); cliParams.revChecker.setOptions(EnumSet.of(Option.SOFT_FAIL)); SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams, servParams); TestResult tr = sslTest.getResult(); if (tr.clientExc != null) { throw tr.clientExc; } else if (tr.serverExc != null) { throw tr.serverExc; } // make sure getSoftFailExceptions is not empty if (cliParams.revChecker.getSoftFailExceptions().isEmpty()) { throw new Exception("No soft fail exceptions"); } System.out.println(" PASS"); System.out.println("=======================================\n"); // Make OCSP responders accept connections intOcsp.acceptConnections(); rootOcsp.acceptConnections(); // Wait 5 seconds for server ready for (int i = 0; (i < 100 && (!intOcsp.isServerReady() || !rootOcsp.isServerReady())); i++) { Thread.sleep(50); } if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) { throw new RuntimeException("Server not ready yet"); } }
/** * Update the state with the specified trust anchor. * * @param anchor the most-trusted CA * @param buildParams builder parameters */ public void updateState(TrustAnchor anchor, BuilderParams buildParams) throws CertificateException, IOException, CertPathValidatorException { trustAnchor = anchor; X509Certificate trustedCert = anchor.getTrustedCert(); if (trustedCert != null) { updateState(trustedCert); } else { X500Principal caName = anchor.getCA(); updateState(anchor.getCAPublicKey(), caName); } // The user specified AlgorithmChecker and RevocationChecker may not be // able to set the trust anchor until now. boolean revCheckerAdded = false; for (PKIXCertPathChecker checker : userCheckers) { if (checker instanceof AlgorithmChecker) { ((AlgorithmChecker)checker).trySetTrustAnchor(anchor); } else if (checker instanceof PKIXRevocationChecker) { if (revCheckerAdded) { throw new CertPathValidatorException( "Only one PKIXRevocationChecker can be specified"); } // if it's our own, initialize it if (checker instanceof RevocationChecker) { ((RevocationChecker)checker).init(anchor, buildParams); } ((PKIXRevocationChecker)checker).init(false); revCheckerAdded = true; } } // only create a RevocationChecker if revocation is enabled and // a PKIXRevocationChecker has not already been added if (buildParams.revocationEnabled() && !revCheckerAdded) { revChecker = new RevocationChecker(anchor, buildParams); revChecker.init(false); } init = false; }
/** * Test a case where client-side stapling is attempted, but does not * occur because OCSP responders are unreachable. Client-side OCSP * checking is enabled for this, with SOFT_FAIL. */ static void testSoftFailFallback() throws Exception { ClientParameters cliParams = new ClientParameters(); ServerParameters servParams = new ServerParameters(); serverReady = false; // Stop the OCSP responders and give a 1 second delay before // running the test. intOcsp.stop(); rootOcsp.stop(); Thread.sleep(1000); System.out.println("======================================="); System.out.println("Stapling enbled in client and server,"); System.out.println("but OCSP responders disabled."); System.out.println("PKIXParameters with Revocation checking"); System.out.println("enabled and SOFT_FAIL."); System.out.println("======================================="); Security.setProperty("ocsp.enable", "true"); cliParams.pkixParams = new PKIXBuilderParameters(trustStore, new X509CertSelector()); cliParams.pkixParams.setRevocationEnabled(true); CertPathValidator cpv = CertPathValidator.getInstance("PKIX"); cliParams.revChecker = (PKIXRevocationChecker)cpv.getRevocationChecker(); cliParams.revChecker.setOptions(EnumSet.of(Option.SOFT_FAIL)); SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams, servParams); TestResult tr = sslTest.getResult(); if (tr.clientExc != null) { throw tr.clientExc; } else if (tr.serverExc != null) { throw tr.serverExc; } System.out.println(" PASS"); System.out.println("=======================================\n"); // Start the OCSP responders up again intOcsp.start(); rootOcsp.start(); // Wait 5 seconds for server ready for (int i = 0; (i < 100 && (!intOcsp.isServerReady() || !rootOcsp.isServerReady())); i++) { Thread.sleep(50); } if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) { throw new RuntimeException("Server not ready yet"); } }
/** * Verify that a chain of trust can be established for a certificate or chain of certificates. * <p> * The chain must begin with the end-entity certificate at index 0 followed by the remaining certificates in the * chain, if any, in the correct order. * <p> * If the end-entity certificate is present in the {@code trustedCertificates} set then trust is immediately * verified. Otherwise, an attempt to build a path to a trusted anchor is made using the provided * {@code issuerCertificates} as the anchors. * * @param certificateChain the certificate chain to verify. * @param trustedCertificates the set of known-trusted certificates. * @param issuerCertificates the set of CA certificates to use as trust anchors. * @param issuerCrls the set of {@link X509CRL}s, if any, to use while verifying trust. * @throws UaException if a chain of trust could not be established. */ public static void verifyTrustChain( List<X509Certificate> certificateChain, Set<X509Certificate> trustedCertificates, Set<X509Certificate> issuerCertificates, Set<X509CRL> issuerCrls) throws UaException { Preconditions.checkArgument(!certificateChain.isEmpty(), "certificateChain must not be empty"); X509Certificate certificate = certificateChain.get(0); boolean certificateTrusted = trustedCertificates.stream() .anyMatch(c -> Arrays.equals(certificate.getSignature(), c.getSignature())); if (certificateTrusted) { LOGGER.debug("Found certificate in trusted certificates: {}", certificate); return; } try { Set<TrustAnchor> trustAnchors = new HashSet<>(); issuerCertificates.forEach(ca -> trustAnchors.add(new TrustAnchor(ca, null))); X509CertSelector selector = new X509CertSelector(); selector.setCertificate(certificate); PKIXBuilderParameters params = new PKIXBuilderParameters(trustAnchors, selector); // Add a CertStore containing any intermediate certs and CRLs if (certificateChain.size() > 0 || issuerCrls.size() > 0) { Collection<Object> collection = Lists.newArrayList(); collection.addAll(certificateChain); collection.addAll(issuerCrls); CertStore certStore = CertStore.getInstance( "Collection", new CollectionCertStoreParameters(collection) ); params.addCertStore(certStore); } // Only enable revocation checking if the CRL list is non-empty params.setRevocationEnabled(!issuerCrls.isEmpty()); CertPathBuilder builder = CertPathBuilder.getInstance("PKIX"); // Set up revocation options regardless of whether it's actually enabled CertPathChecker revocationChecker = builder.getRevocationChecker(); if (revocationChecker instanceof PKIXRevocationChecker) { ((PKIXRevocationChecker) revocationChecker).setOptions(Sets.newHashSet( PKIXRevocationChecker.Option.NO_FALLBACK, PKIXRevocationChecker.Option.PREFER_CRLS, PKIXRevocationChecker.Option.SOFT_FAIL )); } PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult) builder.build(params); LOGGER.debug("Validated certificate chain: {}", result.getCertPath()); } catch (Throwable t) { LOGGER.debug("PKIX path validation failed: {}", t.getMessage()); throw new UaException(StatusCodes.Bad_SecurityChecksFailed); } }