From be477cbed1681cfb8cb4493c840ded91bc946aef Mon Sep 17 00:00:00 2001 From: Mart Somermaa Date: Mon, 15 Jul 2024 17:24:01 +0300 Subject: [PATCH] Use system time in OcspService.validateResponderCertificate() WE2-868 Signed-off-by: Mart Somermaa --- README.md | 4 ++-- ...SubjectCertificateNotRevokedValidator.java | 6 ++++-- .../ocsp/service/AiaOcspService.java | 6 +++--- .../ocsp/service/DesignatedOcspService.java | 4 ++-- .../validator/ocsp/service/OcspService.java | 2 +- ...ectCertificateNotRevokedValidatorTest.java | 21 ++++++++++++++++--- 6 files changed, 30 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a286669..ed41dd9 100644 --- a/README.md +++ b/README.md @@ -287,8 +287,8 @@ CertificateData.getSubjectCN(userCertificate).orElseThrow(); // "JÕEORG\\,JAAK- CertificateData.getSubjectIdCode(userCertificate).orElseThrow(); // "PNOEE-38001085718" CertificateData.getSubjectCountryCode(userCertificate).orElseThrow(); // "EE" -toTitleCase(CertUtil.getSubjectGivenName(userCertificate)).orElseThrow(); // "Jaak-Kristjan" -toTitleCase(CertUtil.getSubjectSurname(userCertificate)).orElseThrow(); // "Jõeorg" +toTitleCase(CertificateData.getSubjectGivenName(userCertificate).orElseThrow()); // "Jaak-Kristjan" +toTitleCase(CertificateData.getSubjectSurname(userCertificate).orElseThrow()); // "Jõeorg" ``` ## Extended configuration diff --git a/src/main/java/eu/webeid/security/validator/certvalidators/SubjectCertificateNotRevokedValidator.java b/src/main/java/eu/webeid/security/validator/certvalidators/SubjectCertificateNotRevokedValidator.java index b876e93..fb33957 100644 --- a/src/main/java/eu/webeid/security/validator/certvalidators/SubjectCertificateNotRevokedValidator.java +++ b/src/main/java/eu/webeid/security/validator/certvalidators/SubjectCertificateNotRevokedValidator.java @@ -24,6 +24,7 @@ import eu.webeid.security.exceptions.AuthTokenException; import eu.webeid.security.exceptions.UserCertificateOCSPCheckFailedException; +import eu.webeid.security.util.DateAndTime; import eu.webeid.security.validator.ocsp.DigestCalculatorImpl; import eu.webeid.security.validator.ocsp.OcspClient; import eu.webeid.security.validator.ocsp.OcspRequestBuilder; @@ -163,8 +164,9 @@ private void verifyOcspResponse(BasicOCSPResp basicResponse, OcspService ocspSer // 4. The signer is currently authorized to provide a response for the // certificate in question. - final Date producedAt = basicResponse.getProducedAt(); - ocspService.validateResponderCertificate(responderCert, producedAt); + // Use the clock instance so that the date can be mocked in tests. + final Date now = DateAndTime.DefaultClock.getInstance().now(); + ocspService.validateResponderCertificate(responderCert, now); // 5. The time at which the status being indicated is known to be // correct (thisUpdate) is sufficiently recent. diff --git a/src/main/java/eu/webeid/security/validator/ocsp/service/AiaOcspService.java b/src/main/java/eu/webeid/security/validator/ocsp/service/AiaOcspService.java index e808f52..596474e 100644 --- a/src/main/java/eu/webeid/security/validator/ocsp/service/AiaOcspService.java +++ b/src/main/java/eu/webeid/security/validator/ocsp/service/AiaOcspService.java @@ -71,13 +71,13 @@ public URI getAccessLocation() { } @Override - public void validateResponderCertificate(X509CertificateHolder cert, Date producedAt) throws AuthTokenException { + public void validateResponderCertificate(X509CertificateHolder cert, Date now) throws AuthTokenException { try { final X509Certificate certificate = certificateConverter.getCertificate(cert); - CertificateValidator.certificateIsValidOnDate(certificate, producedAt, "AIA OCSP responder"); + CertificateValidator.certificateIsValidOnDate(certificate, now, "AIA OCSP responder"); // Trusted certificates' validity has been already verified in validateCertificateExpiry(). OcspResponseValidator.validateHasSigningExtension(certificate); - CertificateValidator.validateIsSignedByTrustedCA(certificate, trustedCACertificateAnchors, trustedCACertificateCertStore, producedAt); + CertificateValidator.validateIsSignedByTrustedCA(certificate, trustedCACertificateAnchors, trustedCACertificateCertStore, now); } catch (CertificateException e) { throw new OCSPCertificateException("Invalid responder certificate", e); } diff --git a/src/main/java/eu/webeid/security/validator/ocsp/service/DesignatedOcspService.java b/src/main/java/eu/webeid/security/validator/ocsp/service/DesignatedOcspService.java index 43a5b89..e9dfae2 100644 --- a/src/main/java/eu/webeid/security/validator/ocsp/service/DesignatedOcspService.java +++ b/src/main/java/eu/webeid/security/validator/ocsp/service/DesignatedOcspService.java @@ -59,7 +59,7 @@ public URI getAccessLocation() { } @Override - public void validateResponderCertificate(X509CertificateHolder cert, Date producedAt) throws AuthTokenException { + public void validateResponderCertificate(X509CertificateHolder cert, Date now) throws AuthTokenException { try { final X509Certificate responderCertificate = certificateConverter.getCertificate(cert); // Certificate pinning is implemented simply by comparing the certificates or their public keys, @@ -68,7 +68,7 @@ public void validateResponderCertificate(X509CertificateHolder cert, Date produc throw new OCSPCertificateException("Responder certificate from the OCSP response is not equal to " + "the configured designated OCSP responder certificate"); } - certificateIsValidOnDate(responderCertificate, producedAt, "Designated OCSP responder"); + certificateIsValidOnDate(responderCertificate, now, "Designated OCSP responder"); } catch (CertificateException e) { throw new OCSPCertificateException("X509CertificateHolder conversion to X509Certificate failed", e); } diff --git a/src/main/java/eu/webeid/security/validator/ocsp/service/OcspService.java b/src/main/java/eu/webeid/security/validator/ocsp/service/OcspService.java index a2dfb90..c386719 100644 --- a/src/main/java/eu/webeid/security/validator/ocsp/service/OcspService.java +++ b/src/main/java/eu/webeid/security/validator/ocsp/service/OcspService.java @@ -34,6 +34,6 @@ public interface OcspService { URI getAccessLocation(); - void validateResponderCertificate(X509CertificateHolder cert, Date date) throws AuthTokenException; + void validateResponderCertificate(X509CertificateHolder cert, Date now) throws AuthTokenException; } diff --git a/src/test/java/eu/webeid/security/validator/certvalidators/SubjectCertificateNotRevokedValidatorTest.java b/src/test/java/eu/webeid/security/validator/certvalidators/SubjectCertificateNotRevokedValidatorTest.java index 98da6a5..4046978 100644 --- a/src/test/java/eu/webeid/security/validator/certvalidators/SubjectCertificateNotRevokedValidatorTest.java +++ b/src/test/java/eu/webeid/security/validator/certvalidators/SubjectCertificateNotRevokedValidatorTest.java @@ -22,6 +22,7 @@ package eu.webeid.security.validator.certvalidators; +import eu.webeid.security.exceptions.CertificateExpiredException; import eu.webeid.security.exceptions.CertificateNotTrustedException; import eu.webeid.security.exceptions.JceException; import eu.webeid.security.exceptions.UserCertificateOCSPCheckFailedException; @@ -251,14 +252,28 @@ void whenOcspResponseUnknown_thenThrows() throws Exception { } @Test - void whenOcspResponseCANotTrusted_thenThrows() throws Exception { + void whenOcspResponseCACertNotTrusted_thenThrows() throws Exception { final SubjectCertificateNotRevokedValidator validator = getSubjectCertificateNotRevokedValidatorWithAiaOcsp( getMockedResponse(getOcspResponseBytesFromResources("ocsp_response_unknown.der")) ); - assertThatExceptionOfType(CertificateNotTrustedException.class) + try (var mockedClock = mockStatic(DateAndTime.DefaultClock.class)) { + mockDate("2021-09-18T00:16:25", mockedClock); + assertThatExceptionOfType(CertificateNotTrustedException.class) + .isThrownBy(() -> + validator.validateCertificateNotRevoked(estEid2018Cert)) + .withMessage("Certificate EMAILADDRESS=pki@sk.ee, CN=TEST of SK OCSP RESPONDER 2020, OU=OCSP, O=AS Sertifitseerimiskeskus, C=EE is not trusted"); + } + } + + @Test + void whenOcspResponseCACertExpired_thenThrows() throws Exception { + final SubjectCertificateNotRevokedValidator validator = getSubjectCertificateNotRevokedValidatorWithAiaOcsp( + getMockedResponse(getOcspResponseBytesFromResources("ocsp_response_unknown.der")) + ); + assertThatExceptionOfType(CertificateExpiredException.class) .isThrownBy(() -> validator.validateCertificateNotRevoked(estEid2018Cert)) - .withMessage("Certificate EMAILADDRESS=pki@sk.ee, CN=TEST of SK OCSP RESPONDER 2020, OU=OCSP, O=AS Sertifitseerimiskeskus, C=EE is not trusted"); + .withMessage("AIA OCSP responder certificate has expired"); } @Test