List of usage examples for org.bouncycastle.asn1.x509 SubjectKeyIdentifier equals
public boolean equals(Object o)
From source file:org.keycloak.common.util.OCSPUtils.java
License:Apache License
private static void verifyResponse(BasicOCSPResp basicOcspResponse, X509Certificate issuerCertificate, X509Certificate responderCertificate, byte[] requestNonce, Date date) throws NoSuchProviderException, NoSuchAlgorithmException, CertificateNotYetValidException, CertificateExpiredException, CertPathValidatorException { List<X509CertificateHolder> certs = new ArrayList<>(Arrays.asList(basicOcspResponse.getCerts())); X509Certificate signingCert = null; try {// w w w. ja va2 s .c o m certs.add(new JcaX509CertificateHolder(issuerCertificate)); if (responderCertificate != null) { certs.add(new JcaX509CertificateHolder(responderCertificate)); } } catch (CertificateEncodingException e) { e.printStackTrace(); } if (certs.size() > 0) { X500Name responderName = basicOcspResponse.getResponderId().toASN1Primitive().getName(); byte[] responderKey = basicOcspResponse.getResponderId().toASN1Primitive().getKeyHash(); if (responderName != null) { logger.log(Level.INFO, "Responder Name: {0}", responderName.toString()); for (X509CertificateHolder certHolder : certs) { try { X509Certificate tempCert = new JcaX509CertificateConverter().setProvider("BC") .getCertificate(certHolder); X500Name respName = new X500Name(tempCert.getSubjectX500Principal().getName()); if (responderName.equals(respName)) { signingCert = tempCert; logger.log(Level.INFO, "Found a certificate whose principal \"{0}\" matches the responder name \"{1}\"", new Object[] { tempCert.getSubjectDN().getName(), responderName.toString() }); break; } } catch (CertificateException e) { logger.log(Level.FINE, e.getMessage()); } } } else if (responderKey != null) { SubjectKeyIdentifier responderSubjectKey = new SubjectKeyIdentifier(responderKey); logger.log(Level.INFO, "Responder Key: {0}", Arrays.toString(responderKey)); for (X509CertificateHolder certHolder : certs) { try { X509Certificate tempCert = new JcaX509CertificateConverter().setProvider("BC") .getCertificate(certHolder); SubjectKeyIdentifier subjectKeyIdentifier = null; if (certHolder.getExtensions() != null) { subjectKeyIdentifier = SubjectKeyIdentifier.fromExtensions(certHolder.getExtensions()); } if (subjectKeyIdentifier != null) { logger.log(Level.INFO, "Certificate: {0}\nSubject Key Id: {1}", new Object[] { tempCert.getSubjectDN().getName(), Arrays.toString(subjectKeyIdentifier.getKeyIdentifier()) }); } if (subjectKeyIdentifier != null && responderSubjectKey.equals(subjectKeyIdentifier)) { signingCert = tempCert; logger.log(Level.INFO, "Found a signer certificate \"{0}\" with the subject key extension value matching the responder key", signingCert.getSubjectDN().getName()); break; } subjectKeyIdentifier = new JcaX509ExtensionUtils() .createSubjectKeyIdentifier(tempCert.getPublicKey()); if (responderSubjectKey.equals(subjectKeyIdentifier)) { signingCert = tempCert; logger.log(Level.INFO, "Found a certificate \"{0}\" with the subject key matching the OCSP responder key", signingCert.getSubjectDN().getName()); break; } } catch (CertificateException e) { logger.log(Level.FINE, e.getMessage()); } } } } if (signingCert != null) { if (signingCert.equals(issuerCertificate)) { logger.log(Level.INFO, "OCSP response is signed by the target''s Issuing CA"); } else if (responderCertificate != null && signingCert.equals(responderCertificate)) { // https://www.ietf.org/rfc/rfc2560.txt // 2.6 OCSP Signature Authority Delegation // - The responder certificate is issued to the responder by CA logger.log(Level.INFO, "OCSP response is signed by an authorized responder certificate"); } else { // 4.2.2.2 Authorized Responders // 3. Includes a value of id-ad-ocspSigning in an ExtendedKeyUsage // extension and is issued by the CA that issued the certificate in // question." if (!signingCert.getIssuerX500Principal().equals(issuerCertificate.getSubjectX500Principal())) { logger.log(Level.INFO, "Signer certificate''s Issuer: {0}\nIssuer certificate''s Subject: {1}", new Object[] { signingCert.getIssuerX500Principal().getName(), issuerCertificate.getSubjectX500Principal().getName() }); throw new CertPathValidatorException( "Responder\'s certificate is not authorized to sign OCSP responses"); } try { List<String> purposes = signingCert.getExtendedKeyUsage(); if (purposes != null && !purposes.contains(KeyPurposeId.id_kp_OCSPSigning.getId())) { logger.log(Level.INFO, "OCSPSigning extended usage is not set"); throw new CertPathValidatorException( "Responder\'s certificate not valid for signing OCSP responses"); } } catch (CertificateParsingException e) { logger.log(Level.FINE, "Failed to get certificate''s extended key usage extension\n{0}", e.getMessage()); } if (date == null) { signingCert.checkValidity(); } else { signingCert.checkValidity(date); } try { Extension noOCSPCheck = new JcaX509CertificateHolder(signingCert) .getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nocheck); // TODO If the extension is present, the OCSP client can trust the // responder's certificate for the lifetime of the certificate. logger.log(Level.INFO, "OCSP no-check extension is {0} present", noOCSPCheck == null ? "not" : ""); } catch (CertificateEncodingException e) { logger.log(Level.FINE, "Certificate encoding exception: {0}", e.getMessage()); } try { signingCert.verify(issuerCertificate.getPublicKey()); logger.log(Level.INFO, "OCSP response is signed by an Authorized Responder"); } catch (GeneralSecurityException ex) { signingCert = null; } } } if (signingCert == null) { throw new CertPathValidatorException("Unable to verify OCSP Response\'s signature"); } else { if (!verifySignature(basicOcspResponse, signingCert)) { throw new CertPathValidatorException("Error verifying OCSP Response\'s signature"); } else { Extension responseNonce = basicOcspResponse.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce); if (responseNonce != null && requestNonce != null && !Arrays.equals(requestNonce, responseNonce.getExtnValue().getOctets())) { throw new CertPathValidatorException("Nonces do not match."); } else { // See Sun's OCSP implementation. // https://www.ietf.org/rfc/rfc2560.txt, if nextUpdate is not set, // the responder is indicating that newer update is avilable all the time long current = date == null ? System.currentTimeMillis() : date.getTime(); Date stop = new Date(current + (long) TIME_SKEW); Date start = new Date(current - (long) TIME_SKEW); Iterator<SingleResp> iter = Arrays.asList(basicOcspResponse.getResponses()).iterator(); SingleResp singleRes = null; do { if (!iter.hasNext()) { return; } singleRes = iter.next(); } while (!stop.before(singleRes.getThisUpdate()) && !start.after(singleRes.getNextUpdate() != null ? singleRes.getNextUpdate() : singleRes.getThisUpdate())); throw new CertPathValidatorException( "Response is unreliable: its validity interval is out-of-date"); } } } }