From 375cdd4b77c3e61815f9a4d9ca3cf4cae3f9cf80 Mon Sep 17 00:00:00 2001 From: Eugene Bochilo Date: Thu, 18 Jul 2024 21:54:25 +0000 Subject: [PATCH] Support noRevAvail certificate extension DEVSIX-8425 Autoported commit. Original commit hash: [9edc3b01a] --- .../v1/RevocationDataValidatorTest.cs | 56 ++++++++++++++----- .../noRevAvailCert.pem | 18 ++++++ .../noRevAvailCertWithoutCA.pem | 18 ++++++ itext/itext.sign/itext/signatures/OID.cs | 4 ++ .../validation/v1/RevocationDataValidator.cs | 21 +++++++ port-hash | 2 +- 6 files changed, 103 insertions(+), 16 deletions(-) create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/RevocationDataValidatorTest/noRevAvailCert.pem create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/RevocationDataValidatorTest/noRevAvailCertWithoutCA.pem diff --git a/itext.tests/itext.sign.tests/itext/signatures/validation/v1/RevocationDataValidatorTest.cs b/itext.tests/itext.sign.tests/itext/signatures/validation/v1/RevocationDataValidatorTest.cs index 6421d3462e..b8560be6bd 100644 --- a/itext.tests/itext.sign.tests/itext/signatures/validation/v1/RevocationDataValidatorTest.cs +++ b/itext.tests/itext.sign.tests/itext/signatures/validation/v1/RevocationDataValidatorTest.cs @@ -250,6 +250,32 @@ public virtual void ValidityAssuredTest() { .VALIDITY_ASSURED).WithCertificate(certificate))); } + [NUnit.Framework.Test] + public virtual void NoRevAvailTest() { + String checkCertFileName = SOURCE_FOLDER + "noRevAvailCertWithoutCA.pem"; + IX509Certificate certificate = (IX509Certificate)PemFileHelper.ReadFirstChain(checkCertFileName)[0]; + DateTime checkDate = TimeTestUtil.TEST_DATE_TIME; + ValidationReport report = new ValidationReport(); + RevocationDataValidator validator = validatorChainBuilder.BuildRevocationDataValidator(); + validator.Validate(report, baseContext, certificate, checkDate); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID).HasLogItem + ((la) => la.WithCheckName(RevocationDataValidator.REVOCATION_DATA_CHECK).WithMessage(RevocationDataValidator + .NO_REV_AVAILABLE, (m) => certificate.GetSubjectDN()).WithCertificate(certificate))); + } + + [NUnit.Framework.Test] + public virtual void NoRevAvailWithCATest() { + String checkCertFileName = SOURCE_FOLDER + "noRevAvailCert.pem"; + IX509Certificate certificate = (IX509Certificate)PemFileHelper.ReadFirstChain(checkCertFileName)[0]; + DateTime checkDate = TimeTestUtil.TEST_DATE_TIME; + ValidationReport report = new ValidationReport(); + RevocationDataValidator validator = validatorChainBuilder.BuildRevocationDataValidator(); + validator.Validate(report, baseContext, certificate, checkDate); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INDETERMINATE + ).HasLogItem((la) => la.WithCheckName(RevocationDataValidator.REVOCATION_DATA_CHECK).WithMessage(RevocationDataValidator + .NO_REV_AVAILABLE_CA, (m) => certificate.GetSubjectDN()).WithCertificate(certificate))); + } + [NUnit.Framework.Test] public virtual void SelfSignedCertificateIsNotValidatedTest() { DateTime checkDate = TimeTestUtil.TEST_DATE_TIME; @@ -385,7 +411,7 @@ public virtual void CrlEncodingErrorTest() { parameters.SetFreshness(ValidatorContexts.All(), CertificateSources.All(), TimeBasedContexts.All(), TimeSpan.FromDays (2)); RevocationDataValidator validator = validatorChainBuilder.BuildRevocationDataValidator(); - validator.AddCrlClient(new _ICrlClient_516(crl)).Validate(report, baseContext, checkCert, TimeTestUtil.TEST_DATE_TIME + validator.AddCrlClient(new _ICrlClient_557(crl)).Validate(report, baseContext, checkCert, TimeTestUtil.TEST_DATE_TIME ); AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INDETERMINATE ).HasLogItem((la) => la.WithCheckName(RevocationDataValidator.REVOCATION_DATA_CHECK).WithMessage(MessageFormatUtil @@ -394,8 +420,8 @@ public virtual void CrlEncodingErrorTest() { ))); } - private sealed class _ICrlClient_516 : ICrlClient { - public _ICrlClient_516(byte[] crl) { + private sealed class _ICrlClient_557 : ICrlClient { + public _ICrlClient_557(byte[] crl) { this.crl = crl; } @@ -493,7 +519,7 @@ public virtual void ResponsesFromValidationClientArePassedTest() { mockCrlValidator.OnCallDo((c) => NUnit.Framework.Assert.AreEqual(crlGeneration, c.responseGenerationDate)); ValidationReport report = new ValidationReport(); RevocationDataValidator validator = validatorChainBuilder.GetRevocationDataValidator(); - ValidationOcspClient ocspClient = new _ValidationOcspClient_635(); + ValidationOcspClient ocspClient = new _ValidationOcspClient_676(); TestOcspResponseBuilder ocspBuilder = new TestOcspResponseBuilder(responderCert, ocspRespPrivateKey); byte[] ocspResponseBytes = new TestOcspClient().AddBuilderForCertIssuer(caCert, ocspBuilder).GetEncoded(checkCert , caCert, null); @@ -501,7 +527,7 @@ public virtual void ResponsesFromValidationClientArePassedTest() { )); ocspClient.AddResponse(basicOCSPResp, ocspGeneration, TimeBasedContext.HISTORICAL); validator.AddOcspClient(ocspClient); - ValidationCrlClient crlClient = new _ValidationCrlClient_650(); + ValidationCrlClient crlClient = new _ValidationCrlClient_691(); TestCrlBuilder crlBuilder = new TestCrlBuilder(caCert, caPrivateKey, checkDate); byte[] crlResponseBytes = new List(new TestCrlClient().AddBuilderForCertIssuer(crlBuilder).GetEncoded (checkCert, null))[0]; @@ -511,8 +537,8 @@ public virtual void ResponsesFromValidationClientArePassedTest() { validator.Validate(report, baseContext, checkCert, checkDate); } - private sealed class _ValidationOcspClient_635 : ValidationOcspClient { - public _ValidationOcspClient_635() { + private sealed class _ValidationOcspClient_676 : ValidationOcspClient { + public _ValidationOcspClient_676() { } public override byte[] GetEncoded(IX509Certificate checkCert, IX509Certificate issuerCert, String url) { @@ -521,8 +547,8 @@ public override byte[] GetEncoded(IX509Certificate checkCert, IX509Certificate i } } - private sealed class _ValidationCrlClient_650 : ValidationCrlClient { - public _ValidationCrlClient_650() { + private sealed class _ValidationCrlClient_691 : ValidationCrlClient { + public _ValidationCrlClient_691() { } public override ICollection GetEncoded(IX509Certificate checkCert, String url) { @@ -588,18 +614,18 @@ public virtual void TimeBasedContextProperlySetOnlineClientsTest() { RevocationDataValidator validator = validatorChainBuilder.GetRevocationDataValidator(); TestOcspResponseBuilder ocspBuilder = new TestOcspResponseBuilder(responderCert, ocspRespPrivateKey); TestOcspClient testOcspClient = new TestOcspClient().AddBuilderForCertIssuer(caCert, ocspBuilder); - OcspClientBouncyCastle ocspClient = new _OcspClientBouncyCastle_729(testOcspClient); + OcspClientBouncyCastle ocspClient = new _OcspClientBouncyCastle_770(testOcspClient); validator.AddOcspClient(ocspClient); TestCrlBuilder crlBuilder = new TestCrlBuilder(caCert, caPrivateKey, checkDate); TestCrlClient testCrlClient = new TestCrlClient().AddBuilderForCertIssuer(crlBuilder); - CrlClientOnline crlClient = new _CrlClientOnline_739(testCrlClient); + CrlClientOnline crlClient = new _CrlClientOnline_780(testCrlClient); validator.AddCrlClient(crlClient); validator.Validate(report, baseContext.SetTimeBasedContext(TimeBasedContext.HISTORICAL), checkCert, checkDate ); } - private sealed class _OcspClientBouncyCastle_729 : OcspClientBouncyCastle { - public _OcspClientBouncyCastle_729(TestOcspClient testOcspClient) { + private sealed class _OcspClientBouncyCastle_770 : OcspClientBouncyCastle { + public _OcspClientBouncyCastle_770(TestOcspClient testOcspClient) { this.testOcspClient = testOcspClient; } @@ -610,8 +636,8 @@ public override byte[] GetEncoded(IX509Certificate checkCert, IX509Certificate r private readonly TestOcspClient testOcspClient; } - private sealed class _CrlClientOnline_739 : CrlClientOnline { - public _CrlClientOnline_739(TestCrlClient testCrlClient) { + private sealed class _CrlClientOnline_780 : CrlClientOnline { + public _CrlClientOnline_780(TestCrlClient testCrlClient) { this.testCrlClient = testCrlClient; } diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/RevocationDataValidatorTest/noRevAvailCert.pem b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/RevocationDataValidatorTest/noRevAvailCert.pem new file mode 100644 index 0000000000..1b86f4122b --- /dev/null +++ b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/RevocationDataValidatorTest/noRevAvailCert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIDijCCAnKgAwIBAgIGAZDC/HsyMA0GCSqGSIb3DQEBCwUAMDgxCzAJBgNVBAYTAkJZMQ4wDAYD +VQQKDAVpVGV4dDEZMBcGA1UEAwwQaVRleHRUZXN0Um9vdFJzYTAgFw0yNDA3MTcyMzE3MjRaGA8y +MTI0MDYyMzIzMTcyNFowPTEcMBoGA1UEAwwTaVRleHRUZXN0Tm9SZXZBdmFpbDENMAsGA1UECwwE +dGVzdDEOMAwGA1UECgwFaVRleHQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc9FG+ +7SqyynBdYM3sOxE8ls7lnlmNlyiHhIka7BjDlwu+7ANUta/a2xh5M3SGFJqyOQ9Z21SFyJ3/XRcQ +bvpn454ltu6QS0cusqKL3ipkF58v/shBBlxj/w+oGC+mkJiV8kKYA1n672aI04BZi0SI3dGWLxn9 +S90y6ewXYGAx+/mdPLxwtQWF67UZRfvyTSGRpRFgjSZLHrDydvp0UrbsZLFtJIsZm2kV/ALiX9Xj +BAD2ZdPa7vGfek695dOX03J/WsT/rBggRGKT9qxZMhBVzamdUV4y3bXnqcB7fPpqtVdYslBLKJaj +2XnBnfUrMUGv/DeBeK8KOjv91xBLRwczAgMBAAGjgZIwgY8wDwYDVR0TAQH/BAUwAwEB/zAPBgkr +BgEFBQcwAQUEAgUAMAsGA1UdDwQEAwIGwDATBgNVHSUEDDAKBggrBgEFBQcDCTAJBgNVHTgEAgUA +MB8GA1UdIwQYMBaAFCmDtomMMsK6Vi+UTmnCrNwKNIVBMB0GA1UdDgQWBBQpg7aJjDLCulYvlE5p +wqzcCjSFQTANBgkqhkiG9w0BAQsFAAOCAQEAQnCZWiSh43VOvCRNIo2/Iy6bNgqGEVTRpIo7c7i2 +pLBoln0LwSZq8qscba+0EZ16U6JRxpJ2qsQ1qSWCiv4OfwGDxqOKJT8EJxpR8MYjj2UVKHKPHdPI +cP2SWRNTxelVLg3A5Twgf/LhDXSUMXVmZ7oViYt/hQc37+tcmVmyHAfEkPnx0d8VQcpmS3TuF2/u +QfxtyRekPMAAmlYshwjeEGQ7tzO6QKdEvony+jSia+wnAvO/jyYVin17afwMcPYqEpQCXN0xC8QL +Im+4nIdVbeIVLkUD9wWmZyDulX6YCQwFkYqUnK9mop3nqNCYXxppKfdNYMk3MiPzPsFuCyapfQ== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/RevocationDataValidatorTest/noRevAvailCertWithoutCA.pem b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/RevocationDataValidatorTest/noRevAvailCertWithoutCA.pem new file mode 100644 index 0000000000..fdc4799d97 --- /dev/null +++ b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/RevocationDataValidatorTest/noRevAvailCertWithoutCA.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIDgTCCAmmgAwIBAgIGAZDFnFH8MA0GCSqGSIb3DQEBCwUAMDgxCzAJBgNVBAYTAkJZMQ4wDAYD +VQQKDAVpVGV4dDEZMBcGA1UEAwwQaVRleHRUZXN0Um9vdFJzYTAgFw0yNDA3MTgxMTMxMTRaGA8y +MTI0MDYyNDExMzExNFowRjElMCMGA1UEAwwcaVRleHRUZXN0Tm9SZXZBdmFpbFdpdGhvdXRDQTEN +MAsGA1UECwwEdGVzdDEOMAwGA1UECgwFaVRleHQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCNLM4D1cmHha3WodOrf6DmKsSIDNMP/FlUXWnbIqDQ3dbeb/JwHKVe2UicPzqZq5Ees6Qq +Pg8z9TzT/YRQDQglci3v82yn3ufy5REw7dGaGzoHU/vgCeDlygRd25tbhdsLfIfedKtz0tQIbJab +0jFlvvzgrmY6Q4Pk22IF5ujQE+N/z4ft8xs5BuII8szCaAacV6MsswzqeNbfYhmnmbs+25fZD0qs +wlVsO9OjVOqLlDVQAeSIO7ip1Ws/6LBG8fAjXsPm0BX7a1MxkyDsrUUFWfq3Pz2aK7DW1F34MPWE +YX0LAFIP269fG+S91fVtrw8b7b8WBQxWi8jv4OOl6kkTAgMBAAGjgYAwfjAPBgkrBgEFBQcwAQUE +AgUAMAsGA1UdDwQEAwIGwDATBgNVHSUEDDAKBggrBgEFBQcDCTAJBgNVHTgEAgUAMB8GA1UdIwQY +MBaAFCmDtomMMsK6Vi+UTmnCrNwKNIVBMB0GA1UdDgQWBBQpg7aJjDLCulYvlE5pwqzcCjSFQTAN +BgkqhkiG9w0BAQsFAAOCAQEAK93ANxcNwQCqM/ZDqcpkHtk+fXcKFLgSkpAQWxWjxEeumlRD61Yi +8dJ6VfIy95Flh4Kbg6EH1UsrkiquOQ2+k/V1oE5hJu7RT7RqSDu3VCcMAtekRwdfY6AGCX/9IHqE +CazzShdcCr/YZ2jz3Uy/kr6/fu4sq1enAunsM6WMuO7bZU/WYimzHu9TTRQ00oFjCW5s3TFgP3HV +BfaL4oSh7Ksvjsu2ZqjwFb8J5DT/oObIdeAw/Pl3NShjALbQ5PJkzkLp00FcT4A1ItKkW+p/xwPk +QCR2NnYjIk9yvhFgse5/VrYkNlJEknzN4upJ2ldVCC2F5yVyQ+mG7b8l7MgEKA== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/itext/itext.sign/itext/signatures/OID.cs b/itext/itext.sign/itext/signatures/OID.cs index fac2f1341b..20a268a852 100644 --- a/itext/itext.sign/itext/signatures/OID.cs +++ b/itext/itext.sign/itext/signatures/OID.cs @@ -130,6 +130,10 @@ public sealed class X509Extensions { /// Extension for certificates from ETSI EN 319 412-1 V1.4.4. public const String VALIDITY_ASSURED_SHORT_TERM = "0.4.0.194121.2.1"; + /// Extension for certificates from RFC 9608 which indicates that no revocation information is available. + /// + public const String NO_REV_AVAILABLE = "2.5.29.56"; + /// According to https://tools.ietf.org/html/rfc5280 4.2. /// /// According to https://tools.ietf.org/html/rfc5280 4.2. "Certificate Extensions": diff --git a/itext/itext.sign/itext/signatures/validation/v1/RevocationDataValidator.cs b/itext/itext.sign/itext/signatures/validation/v1/RevocationDataValidator.cs index 12dcdaa265..7ad381561c 100644 --- a/itext/itext.sign/itext/signatures/validation/v1/RevocationDataValidator.cs +++ b/itext/itext.sign/itext/signatures/validation/v1/RevocationDataValidator.cs @@ -58,6 +58,16 @@ public class RevocationDataValidator { internal const String VALIDITY_ASSURED = "Certificate is trusted due to validity assured - short term extension."; //\endcond +//\cond DO_NOT_DOCUMENT + internal const String NO_REV_AVAILABLE = "noRevAvail extension from RFC 9608 is present on {0} certificate. " + + "Revocation data checks are not required."; +//\endcond + +//\cond DO_NOT_DOCUMENT + internal const String NO_REV_AVAILABLE_CA = "noRevAvail extension from RFC 9608 is present on {0} certificate, " + + "however this certificate is a CA, which is not allowed."; +//\endcond + //\cond DO_NOT_DOCUMENT internal const String CANNOT_PARSE_OCSP = "OCSP response from \"{0}\" OCSP response cannot be parsed."; //\endcond @@ -184,6 +194,17 @@ public virtual void Validate(ValidationReport report, ValidationContext context, .INFO)); return; } + if (CertificateUtil.GetExtensionValueByOid(certificate, OID.X509Extensions.NO_REV_AVAILABLE) != null) { + if (certificate.GetBasicConstraints() < 0) { + report.AddReportItem(new CertificateReportItem(certificate, REVOCATION_DATA_CHECK, MessageFormatUtil.Format + (NO_REV_AVAILABLE, certificate.GetSubjectDN()), ReportItem.ReportItemStatus.INFO)); + } + else { + report.AddReportItem(new CertificateReportItem(certificate, REVOCATION_DATA_CHECK, MessageFormatUtil.Format + (NO_REV_AVAILABLE_CA, certificate.GetSubjectDN()), ReportItem.ReportItemStatus.INDETERMINATE)); + } + return; + } if (CertificateSource.OCSP_ISSUER == localContext.GetCertificateSource()) { // Check if Authorised OCSP Responder certificate has id-pkix-ocsp-nocheck extension, in which case we // do not perform revocation check for it. diff --git a/port-hash b/port-hash index d05bf71bb2..5cce292597 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -8a1d22133834a385483b26d6a61277ef590732da +9edc3b01ab28f67c9c46fdfeec48979abad3fd26