diff --git a/itext.tests/itext.sign.tests/itext/signatures/TrustedCerrtificatesStoreTest.cs b/itext.tests/itext.sign.tests/itext/signatures/TrustedCerrtificatesStoreTest.cs
new file mode 100644
index 0000000000..37a552d811
--- /dev/null
+++ b/itext.tests/itext.sign.tests/itext/signatures/TrustedCerrtificatesStoreTest.cs
@@ -0,0 +1,252 @@
+/*
+This file is part of the iText (R) project.
+Copyright (c) 1998-2024 Apryse Group NV
+Authors: Apryse Software.
+
+This program is offered under a commercial and under the AGPL license.
+For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
+
+AGPL licensing:
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+*/
+using System;
+using iText.Commons.Bouncycastle.Cert;
+using iText.Commons.Utils;
+using iText.Signatures.Testutils;
+using iText.Signatures.Validation;
+using iText.Test;
+
+namespace iText.Signatures {
+ [NUnit.Framework.Category("BouncyCastleUnitTest")]
+ public class TrustedCerrtificatesStoreTest : ExtendedITextTest {
+ private static readonly String SOURCE_FOLDER = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext
+ .CurrentContext.TestDirectory) + "/resources/itext/signatures/certs/";
+
+ private static readonly char[] KEY_PASSWORD = "testpassphrase".ToCharArray();
+
+ private static IX509Certificate crlCert;
+
+ private static IX509Certificate crlRootCert;
+
+ private static IX509Certificate intermediateCert;
+
+ private static IX509Certificate ocspCert;
+
+ private static IX509Certificate rootCert;
+
+ private static IX509Certificate signCert;
+
+ private static IX509Certificate tsaCert;
+
+ private static IX509Certificate tsaRootCert;
+
+ [NUnit.Framework.OneTimeSetUp]
+ public static void SetUpOnce() {
+ crlCert = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER + "crlCert.pem")[0];
+ crlRootCert = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER + "crlRoot.pem")[0];
+ intermediateCert = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER + "intermediate.pem")[0];
+ ocspCert = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER + "ocspCert.pem")[0];
+ rootCert = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER + "root.pem")[0];
+ signCert = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER + "sign.pem")[0];
+ tsaCert = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER + "tsaCert.pem")[0];
+ tsaRootCert = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER + "tsaRoot.pem")[0];
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestIsCertificateGenerallyTrusted() {
+ TrustedCertificatesStore sut = new TrustedCertificatesStore();
+ sut.AddCATrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddTimestampTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddOcspTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddCrlTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ NUnit.Framework.Assert.IsFalse(sut.IsCertificateGenerallyTrusted(rootCert));
+ sut.AddGenerallyTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ NUnit.Framework.Assert.IsTrue(sut.IsCertificateGenerallyTrusted(rootCert));
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestIsCertificateTrustedForCA() {
+ TrustedCertificatesStore sut = new TrustedCertificatesStore();
+ sut.AddGenerallyTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddTimestampTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddOcspTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddCrlTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ NUnit.Framework.Assert.IsFalse(sut.IsCertificateTrustedForCA(rootCert));
+ sut.AddCATrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ NUnit.Framework.Assert.IsTrue(sut.IsCertificateTrustedForCA(rootCert));
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestIsCertificateTrustedForTimestamp() {
+ TrustedCertificatesStore sut = new TrustedCertificatesStore();
+ sut.AddGenerallyTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddCATrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddOcspTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddCrlTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ NUnit.Framework.Assert.IsFalse(sut.IsCertificateTrustedForTimestamp(rootCert));
+ sut.AddTimestampTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ NUnit.Framework.Assert.IsTrue(sut.IsCertificateTrustedForTimestamp(rootCert));
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestIsCertificateTrustedForOcsp() {
+ TrustedCertificatesStore sut = new TrustedCertificatesStore();
+ sut.AddGenerallyTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddCATrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddTimestampTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddCrlTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ NUnit.Framework.Assert.IsFalse(sut.IsCertificateTrustedForOcsp(rootCert));
+ sut.AddOcspTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ NUnit.Framework.Assert.IsTrue(sut.IsCertificateTrustedForOcsp(rootCert));
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestIsCertificateTrustedForCrl() {
+ TrustedCertificatesStore sut = new TrustedCertificatesStore();
+ sut.AddGenerallyTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddCATrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddTimestampTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddOcspTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ NUnit.Framework.Assert.IsFalse(sut.IsCertificateTrustedForCrl(rootCert));
+ sut.AddCrlTrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ NUnit.Framework.Assert.IsTrue(sut.IsCertificateTrustedForCrl(rootCert));
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestGetKnownCertificates() {
+ TrustedCertificatesStore sut = new TrustedCertificatesStore();
+ sut.AddCrlTrustedCertificates(JavaCollectionsUtil.SingletonList(crlCert));
+ sut.AddCATrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddOcspTrustedCertificates(JavaCollectionsUtil.SingletonList(ocspCert));
+ sut.AddTimestampTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaCert));
+ sut.AddGenerallyTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaRootCert));
+ NUnit.Framework.Assert.AreEqual(1, sut.GetKnownCertificates(crlCert.GetSubjectDN().ToString()).Count);
+ NUnit.Framework.Assert.AreEqual(1, sut.GetKnownCertificates(rootCert.GetSubjectDN().ToString()).Count);
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestGetAllTrustedCertificates() {
+ TrustedCertificatesStore sut = new TrustedCertificatesStore();
+ sut.AddCrlTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaRootCert));
+ sut.AddCATrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddOcspTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaRootCert));
+ sut.AddTimestampTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaCert));
+ sut.AddGenerallyTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaRootCert));
+ //duplicates should be removed
+ NUnit.Framework.Assert.AreEqual(3, sut.GetAllTrustedCertificates().Count);
+ NUnit.Framework.Assert.IsTrue(sut.GetAllTrustedCertificates().Contains(tsaRootCert));
+ NUnit.Framework.Assert.IsTrue(sut.GetAllTrustedCertificates().Contains(rootCert));
+ NUnit.Framework.Assert.IsTrue(sut.GetAllTrustedCertificates().Contains(tsaCert));
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestGetAllTrustedCertificatesByName() {
+ TrustedCertificatesStore sut = new TrustedCertificatesStore();
+ sut.AddCrlTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaRootCert));
+ sut.AddCATrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddOcspTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaRootCert));
+ sut.AddTimestampTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaCert));
+ sut.AddGenerallyTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaRootCert));
+ //duplicates should be removed
+ NUnit.Framework.Assert.AreEqual(1, sut.GetAllTrustedCertificates(tsaRootCert.GetSubjectDN().ToString()).Count
+ );
+ NUnit.Framework.Assert.IsTrue(sut.GetAllTrustedCertificates(tsaRootCert.GetSubjectDN().ToString()).Contains
+ (tsaRootCert));
+ NUnit.Framework.Assert.IsTrue(sut.GetAllTrustedCertificates(rootCert.GetSubjectDN().ToString()).Contains(rootCert
+ ));
+ NUnit.Framework.Assert.IsTrue(sut.GetAllTrustedCertificates(tsaCert.GetSubjectDN().ToString()).Contains(tsaCert
+ ));
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestGetGenerallyTrustedCertificates() {
+ TrustedCertificatesStore sut = new TrustedCertificatesStore();
+ sut.AddGenerallyTrustedCertificates(JavaCollectionsUtil.SingletonList(signCert));
+ sut.AddCATrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddTimestampTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaCert));
+ sut.AddOcspTrustedCertificates(JavaCollectionsUtil.SingletonList(ocspCert));
+ sut.AddCrlTrustedCertificates(JavaCollectionsUtil.SingletonList(crlCert));
+ String name = signCert.GetSubjectDN().ToString();
+ NUnit.Framework.Assert.AreEqual(1, sut.GetGenerallyTrustedCertificates(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForCA(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForCrl(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForOcsp(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForTimestamp(name).Count);
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestGetCertificatesTrustedForCA() {
+ TrustedCertificatesStore sut = new TrustedCertificatesStore();
+ sut.AddGenerallyTrustedCertificates(JavaCollectionsUtil.SingletonList(signCert));
+ sut.AddCATrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddTimestampTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaCert));
+ sut.AddOcspTrustedCertificates(JavaCollectionsUtil.SingletonList(ocspCert));
+ sut.AddCrlTrustedCertificates(JavaCollectionsUtil.SingletonList(crlCert));
+ String name = rootCert.GetSubjectDN().ToString();
+ NUnit.Framework.Assert.AreEqual(0, sut.GetGenerallyTrustedCertificates(name).Count);
+ NUnit.Framework.Assert.AreEqual(1, sut.GetCertificatesTrustedForCA(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForCrl(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForOcsp(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForTimestamp(name).Count);
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestGetCertificatesTrustedForTimeStamp() {
+ TrustedCertificatesStore sut = new TrustedCertificatesStore();
+ sut.AddGenerallyTrustedCertificates(JavaCollectionsUtil.SingletonList(signCert));
+ sut.AddCATrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddTimestampTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaCert));
+ sut.AddOcspTrustedCertificates(JavaCollectionsUtil.SingletonList(ocspCert));
+ sut.AddCrlTrustedCertificates(JavaCollectionsUtil.SingletonList(crlCert));
+ String name = tsaCert.GetSubjectDN().ToString();
+ NUnit.Framework.Assert.AreEqual(0, sut.GetGenerallyTrustedCertificates(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForCA(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForCrl(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForOcsp(name).Count);
+ NUnit.Framework.Assert.AreEqual(1, sut.GetCertificatesTrustedForTimestamp(name).Count);
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestGetCertificatesTrustedForOcsp() {
+ TrustedCertificatesStore sut = new TrustedCertificatesStore();
+ sut.AddGenerallyTrustedCertificates(JavaCollectionsUtil.SingletonList(signCert));
+ sut.AddCATrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddTimestampTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaCert));
+ sut.AddOcspTrustedCertificates(JavaCollectionsUtil.SingletonList(ocspCert));
+ sut.AddCrlTrustedCertificates(JavaCollectionsUtil.SingletonList(crlCert));
+ String name = ocspCert.GetSubjectDN().ToString();
+ NUnit.Framework.Assert.AreEqual(0, sut.GetGenerallyTrustedCertificates(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForCA(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForCrl(name).Count);
+ NUnit.Framework.Assert.AreEqual(1, sut.GetCertificatesTrustedForOcsp(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForTimestamp(name).Count);
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestGetCertificatesTrustedForCrl() {
+ TrustedCertificatesStore sut = new TrustedCertificatesStore();
+ sut.AddGenerallyTrustedCertificates(JavaCollectionsUtil.SingletonList(signCert));
+ sut.AddCATrustedCertificates(JavaCollectionsUtil.SingletonList(rootCert));
+ sut.AddTimestampTrustedCertificates(JavaCollectionsUtil.SingletonList(tsaCert));
+ sut.AddOcspTrustedCertificates(JavaCollectionsUtil.SingletonList(ocspCert));
+ sut.AddCrlTrustedCertificates(JavaCollectionsUtil.SingletonList(crlCert));
+ String name = crlCert.GetSubjectDN().ToString();
+ NUnit.Framework.Assert.AreEqual(0, sut.GetGenerallyTrustedCertificates(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForCA(name).Count);
+ NUnit.Framework.Assert.AreEqual(1, sut.GetCertificatesTrustedForCrl(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForOcsp(name).Count);
+ NUnit.Framework.Assert.AreEqual(0, sut.GetCertificatesTrustedForTimestamp(name).Count);
+ }
+ }
+}
diff --git a/itext.tests/itext.sign.tests/itext/signatures/validation/CRLValidatorTest.cs b/itext.tests/itext.sign.tests/itext/signatures/validation/CRLValidatorTest.cs
index 2b70ff0899..26f4e4c8eb 100644
--- a/itext.tests/itext.sign.tests/itext/signatures/validation/CRLValidatorTest.cs
+++ b/itext.tests/itext.sign.tests/itext/signatures/validation/CRLValidatorTest.cs
@@ -83,6 +83,46 @@ public virtual void HappyPathTest() {
AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID));
}
+ [NUnit.Framework.Test]
+ public virtual void MultipleIssuersWithOneMatch() {
+ RetrieveTestResources("multipleCrlIssuerCandidates");
+ byte[] crl = CreateCrl(crlIssuerCert, crlIssuerKey, TimeTestUtil.TEST_DATE_TIME.AddDays(-5), TimeTestUtil.
+ TEST_DATE_TIME.AddDays(+5));
+ IX509Certificate candidateCrlIssuerCert1 = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER +
+ "multipleCrlIssuerCandidates/crl-issuer-candidate1.cert.pem")[0];
+ IX509Certificate candidateCrlIssuerCert2 = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER +
+ "multipleCrlIssuerCandidates/crl-issuer-candidate2.cert.pem")[0];
+ certificateRetriever.AddTrustedCertificates(JavaUtil.ArraysAsList(candidateCrlIssuerCert1, crlIssuerCert,
+ candidateCrlIssuerCert2));
+ ValidationReport report = PerformValidation("multipleCrlIssuerCandidates", TimeTestUtil.TEST_DATE_TIME, crl
+ );
+ AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID));
+ // expected the CRL validator to stop after correct issuer was found
+ NUnit.Framework.Assert.AreEqual(2, mockChainValidator.verificationCalls.Count);
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void MultipleIssuersWithNoMatch() {
+ RetrieveTestResources("multipleCrlIssuerCandidates");
+ byte[] crl = CreateCrl(crlIssuerCert, crlIssuerKey, TimeTestUtil.TEST_DATE_TIME.AddDays(-5), TimeTestUtil.
+ TEST_DATE_TIME.AddDays(+5));
+ IX509Certificate candidateCrlIssuerCert1 = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER +
+ "multipleCrlIssuerCandidates/crl-issuer-candidate1.cert.pem")[0];
+ IX509Certificate candidateCrlIssuerCert2 = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER +
+ "multipleCrlIssuerCandidates/crl-issuer-candidate2.cert.pem")[0];
+ certificateRetriever.AddTrustedCertificates(JavaUtil.ArraysAsList(candidateCrlIssuerCert1, candidateCrlIssuerCert2
+ ));
+ IX509Certificate certificateUnderTest = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER + "multipleCrlIssuerCandidates/sign.cert.pem"
+ )[0];
+ ValidationReport result = new ValidationReport();
+ ValidationContext context = new ValidationContext(ValidatorContext.REVOCATION_DATA_VALIDATOR, CertificateSource
+ .SIGNER_CERT, TimeBasedContext.PRESENT);
+ validatorChainBuilder.GetCRLValidator().Validate(result, context, certificateUnderTest, (IX509Crl)CertificateUtil
+ .ParseCrlFromStream(new MemoryStream(crl)), TimeTestUtil.TEST_DATE_TIME, TimeTestUtil.TEST_DATE_TIME);
+ AssertValidationReport.AssertThat(result, (a) => a.HasStatus(ValidationReport.ValidationResult.INDETERMINATE
+ ));
+ }
+
[NUnit.Framework.Test]
public virtual void NextUpdateBeforeValidationTest() {
RetrieveTestResources("happyPath");
@@ -334,7 +374,7 @@ public virtual void CertificateRetrieverFailureTest() {
byte[] crl = CreateCrl(crlIssuerCert, crlIssuerKey, TimeTestUtil.TEST_DATE_TIME.AddDays(-5), TimeTestUtil.
TEST_DATE_TIME.AddDays(+5));
MockIssuingCertificateRetriever mockCertificateRetriever = new MockIssuingCertificateRetriever();
- mockCertificateRetriever.OngetCrlIssuerCertificatesDo((c) => {
+ mockCertificateRetriever.OngetCrlIssuerCertificatesByNameDo((c) => {
throw new Exception("just testing");
}
);
diff --git a/itext.tests/itext.sign.tests/itext/signatures/validation/CertificateChainValidatorTest.cs b/itext.tests/itext.sign.tests/itext/signatures/validation/CertificateChainValidatorTest.cs
index 9b2a27045e..c2b98495a9 100644
--- a/itext.tests/itext.sign.tests/itext/signatures/validation/CertificateChainValidatorTest.cs
+++ b/itext.tests/itext.sign.tests/itext/signatures/validation/CertificateChainValidatorTest.cs
@@ -601,6 +601,7 @@ public virtual void TestStopOnInvalidRevocationResultTest() {
);
AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INVALID));
NUnit.Framework.Assert.AreEqual(0, mockCertificateRetriever.getCrlIssuerCertificatesCalls.Count);
+ NUnit.Framework.Assert.AreEqual(0, mockCertificateRetriever.getCrlIssuerCertificatesByNameCalls.Count);
NUnit.Framework.Assert.AreEqual(1, mockRevocationDataValidator.calls.Count);
}
}
diff --git a/itext.tests/itext.sign.tests/itext/signatures/validation/OCSPValidatorIntegrationTest.cs b/itext.tests/itext.sign.tests/itext/signatures/validation/OCSPValidatorIntegrationTest.cs
index d39fbc2e04..c258d771bb 100644
--- a/itext.tests/itext.sign.tests/itext/signatures/validation/OCSPValidatorIntegrationTest.cs
+++ b/itext.tests/itext.sign.tests/itext/signatures/validation/OCSPValidatorIntegrationTest.cs
@@ -99,10 +99,11 @@ public virtual void ValidateResponderOcspNoCheckTest() {
[NUnit.Framework.Test]
public virtual void ValidateAuthorizedOCSPResponderWithOcspTest() {
ValidationReport report = VerifyResponderWithOcsp(false);
- AssertValidationReport.AssertThat(report, (a) => a.HasNumberOfFailures(0).HasNumberOfLogs(2).HasLogItems(2
- , (al) => al.WithCheckName(CertificateChainValidator.CERTIFICATE_CHECK).WithMessage(CertificateChainValidator
- .CERTIFICATE_TRUSTED, (l) => ((CertificateReportItem)l).GetCertificate().GetSubjectDN())).HasStatus(ValidationReport.ValidationResult
- .VALID));
+ AssertValidationReport.AssertThat(report, (a) => a.HasNumberOfFailures(0).HasNumberOfLogs(2).HasLogItem((al
+ ) => al.WithCheckName(CertificateChainValidator.CERTIFICATE_CHECK).WithMessage(CertificateChainValidator
+ .CERTIFICATE_TRUSTED, (l) => ((CertificateReportItem)l).GetCertificate().GetSubjectDN())).HasLogItem((
+ al) => al.WithCheckName(OCSPValidator.OCSP_CHECK).WithMessage(OCSPValidator.OCSP_RESPONDER_IS_CA)).HasStatus
+ (ValidationReport.ValidationResult.VALID));
}
[NUnit.Framework.Test]
diff --git a/itext.tests/itext.sign.tests/itext/signatures/validation/OCSPValidatorTest.cs b/itext.tests/itext.sign.tests/itext/signatures/validation/OCSPValidatorTest.cs
index 0a28863bd9..def5ead493 100644
--- a/itext.tests/itext.sign.tests/itext/signatures/validation/OCSPValidatorTest.cs
+++ b/itext.tests/itext.sign.tests/itext/signatures/validation/OCSPValidatorTest.cs
@@ -21,6 +21,7 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
using System;
+using System.Collections.Generic;
using iText.Bouncycastleconnector;
using iText.Commons.Bouncycastle;
using iText.Commons.Bouncycastle.Asn1.Ocsp;
@@ -96,6 +97,49 @@ public virtual void HappyPathTest() {
AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID));
}
+ [NUnit.Framework.Test]
+ public virtual void MultipleIssuerCandidatesHappyPathTest() {
+ IX509Certificate candidateOcspIssuerCert1 = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER +
+ "candidate1-ocsp-issuer.cert.pem")[0];
+ IX509Certificate candidateOcspIssuerCert2 = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER +
+ "candidate2-ocsp-issuer.cert.pem")[0];
+ certificateRetriever.AddTrustedCertificates(JavaUtil.ArraysAsList(candidateOcspIssuerCert1, responderCert,
+ candidateOcspIssuerCert2));
+ TestOcspResponseBuilder builder = new TestOcspResponseBuilder(responderCert, ocspRespPrivateKey);
+ builder.SetOcspCertsChain(new IX509Certificate[] { caCert });
+ TestOcspClient ocspClient = new TestOcspClient().AddBuilderForCertIssuer(caCert, builder);
+ IBasicOcspResponse basicOCSPResp = FACTORY.CreateBasicOCSPResponse(FACTORY.CreateASN1Primitive(ocspClient.
+ GetEncoded(checkCert, caCert, null)));
+ ValidationReport report = new ValidationReport();
+ certificateRetriever.AddTrustedCertificates(JavaCollectionsUtil.SingletonList(caCert));
+ OCSPValidator validator = validatorChainBuilder.BuildOCSPValidator();
+ validator.Validate(report, baseContext, checkCert, basicOCSPResp.GetResponses()[0], basicOCSPResp, TimeTestUtil
+ .TEST_DATE_TIME, TimeTestUtil.TEST_DATE_TIME);
+ AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID));
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void MultipleIssuerCandidatesFailingTest() {
+ IX509Certificate candidateOcspIssuerCert1 = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER +
+ "candidate1-ocsp-issuer.cert.pem")[0];
+ IX509Certificate candidateOcspIssuerCert2 = (IX509Certificate)PemFileHelper.ReadFirstChain(SOURCE_FOLDER +
+ "candidate2-ocsp-issuer.cert.pem")[0];
+ certificateRetriever.AddTrustedCertificates(JavaUtil.ArraysAsList(candidateOcspIssuerCert1, candidateOcspIssuerCert2
+ ));
+ TestOcspResponseBuilder builder = new TestOcspResponseBuilder(responderCert, ocspRespPrivateKey);
+ builder.SetOcspCertsChain(new IX509Certificate[] { caCert });
+ TestOcspClient ocspClient = new TestOcspClient().AddBuilderForCertIssuer(caCert, builder);
+ IBasicOcspResponse basicOCSPResp = FACTORY.CreateBasicOCSPResponse(FACTORY.CreateASN1Primitive(ocspClient.
+ GetEncoded(checkCert, caCert, null)));
+ ValidationReport report = new ValidationReport();
+ certificateRetriever.AddTrustedCertificates(JavaCollectionsUtil.SingletonList(caCert));
+ OCSPValidator validator = validatorChainBuilder.BuildOCSPValidator();
+ validator.Validate(report, baseContext, checkCert, basicOCSPResp.GetResponses()[0], basicOCSPResp, TimeTestUtil
+ .TEST_DATE_TIME, TimeTestUtil.TEST_DATE_TIME);
+ AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INDETERMINATE
+ ));
+ }
+
[NUnit.Framework.Test]
public virtual void OcpsIssuerChainValidationsUsesCorrectParametersTest() {
DateTime checkDate = TimeTestUtil.TEST_DATE_TIME;
@@ -419,6 +463,12 @@ public virtual void CertificateRetrieverIsCertificateTrustedFailureTest() {
throw new Exception("Test isCertificateTrusted failure");
}
);
+ MockTrustedCertificatesStore mockTrustStore = new MockTrustedCertificatesStore();
+ mockTrustStore.OnIsCertificateTrustedForOcspDo((c) => {
+ throw new Exception("Test isCertificateTrusted failure");
+ }
+ );
+ mockCertificateRetriever.OnGetTrustedCertificatesStoreDo(() => mockTrustStore);
ValidationReport report = ValidateTest(checkDate);
AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INDETERMINATE
).HasLogItem((l) => l.WithMessage(OCSPValidator.OCSP_RESPONDER_TRUST_NOT_RETRIEVED)));
@@ -500,8 +550,8 @@ public TestIssuingCertificateRetriever(String issuerPath)
this.issuerCertificate = PemFileHelper.ReadFirstChain(issuerPath)[0];
}
- public override IX509Certificate RetrieveIssuerCertificate(IX509Certificate certificate) {
- return issuerCertificate;
+ public override IList RetrieveIssuerCertificate(IX509Certificate certificate) {
+ return JavaCollectionsUtil.SingletonList((IX509Certificate)issuerCertificate);
}
}
}
diff --git a/itext.tests/itext.sign.tests/itext/signatures/validation/RevocationDataValidatorTest.cs b/itext.tests/itext.sign.tests/itext/signatures/validation/RevocationDataValidatorTest.cs
index 5f76316bad..a497b715b9 100644
--- a/itext.tests/itext.sign.tests/itext/signatures/validation/RevocationDataValidatorTest.cs
+++ b/itext.tests/itext.sign.tests/itext/signatures/validation/RevocationDataValidatorTest.cs
@@ -733,7 +733,7 @@ public virtual void CertificateRetrieverRetrieveIssuerCertificateFailureTest() {
mockOCSPValidator.OnCallDo((c) => c.report.AddReportItem(reportItem));
validator.Validate(report, baseContext, checkCert, checkDate);
AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INDETERMINATE
- ).HasLogItem((l) => l.WithMessage(RevocationDataValidator.ISSUER_RETRIEVAL_FAILED)));
+ ).HasLogItem((l) => l.WithMessage(RevocationDataValidator.UNABLE_TO_RETRIEVE_REV_DATA_ONLINE)));
}
[NUnit.Framework.Test]
diff --git a/itext.tests/itext.sign.tests/itext/signatures/validation/SignatureValidatorIntegrationTest.cs b/itext.tests/itext.sign.tests/itext/signatures/validation/SignatureValidatorIntegrationTest.cs
index b846e83843..dd3d1bec17 100644
--- a/itext.tests/itext.sign.tests/itext/signatures/validation/SignatureValidatorIntegrationTest.cs
+++ b/itext.tests/itext.sign.tests/itext/signatures/validation/SignatureValidatorIntegrationTest.cs
@@ -80,9 +80,11 @@ public virtual void ValidLatestSignatureTest() {
SignatureValidator signatureValidator = builder.BuildSignatureValidator(document);
report = signatureValidator.ValidateSignatures();
}
- AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID).HasLogItems
- (3, (al) => al.WithCertificate(rootCert).WithCheckName(CertificateChainValidator.CERTIFICATE_CHECK).WithMessage
- (CertificateChainValidator.CERTIFICATE_TRUSTED, (i) => rootCert.GetSubjectDN())));
+ AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID).HasLogItem
+ ((al) => al.WithCertificate(rootCert).WithCheckName(CertificateChainValidator.CERTIFICATE_CHECK).WithMessage
+ (CertificateChainValidator.CERTIFICATE_TRUSTED, (i) => rootCert.GetSubjectDN())).HasLogItem((al) => al
+ .WithCheckName(OCSPValidator.OCSP_CHECK).WithMessage(OCSPValidator.OCSP_RESPONDER_TRUSTED)).HasLogItem
+ ((al) => al.WithCheckName(OCSPValidator.OCSP_CHECK).WithMessage(OCSPValidator.OCSP_RESPONDER_IS_CA)));
}
[NUnit.Framework.Test]
@@ -107,9 +109,9 @@ public virtual void ShortValidityCertsWithOcspTest() {
.UNEXPECTED_ENTRY_IN_XREF, (i) => 30)).HasLogItem((al) => al.WithCheckName(SignatureValidator.SIGNATURE_VERIFICATION
).WithMessage(SignatureValidator.VALIDATING_SIGNATURE_NAME, (i) => "timestampSig1")).HasLogItem((al) =>
al.WithCheckName(SignatureValidator.SIGNATURE_VERIFICATION).WithMessage(SignatureValidator.VALIDATING_SIGNATURE_NAME
- , (i) => "Signature1")).HasLogItems(2, (al) => al.WithCertificate(rootCert).WithCheckName(CertificateChainValidator
+ , (i) => "Signature1")).HasLogItem((al) => al.WithCertificate(rootCert).WithCheckName(CertificateChainValidator
.CERTIFICATE_CHECK).WithMessage(CertificateChainValidator.CERTIFICATE_TRUSTED, (i) => rootCert.GetSubjectDN
- ())).HasLogItems(4, (al) => al.WithCertificate(tsRootCert).WithCheckName(CertificateChainValidator.CERTIFICATE_CHECK
+ ())).HasLogItems(2, (al) => al.WithCertificate(tsRootCert).WithCheckName(CertificateChainValidator.CERTIFICATE_CHECK
).WithMessage(CertificateChainValidator.CERTIFICATE_TRUSTED, (i) => tsRootCert.GetSubjectDN())));
}
@@ -195,16 +197,18 @@ public virtual void ValidateSingleSignatureTest1() {
(4).HasNumberOfFailures(0).HasLogItem((al) => al.WithCheckName(DocumentRevisionsValidator.DOC_MDP_CHECK
).WithMessage(DocumentRevisionsValidator.UNEXPECTED_ENTRY_IN_XREF, (i) => 17).WithStatus(ReportItem.ReportItemStatus
.INFO)).HasLogItem((al) => al.WithCheckName(SignatureValidator.SIGNATURE_VERIFICATION).WithMessage(SignatureValidator
- .VALIDATING_SIGNATURE_NAME, (p) => "Signature1")).HasLogItems(2, (al) => al.WithCertificate(rootCert).
- WithCheckName(CertificateChainValidator.CERTIFICATE_CHECK).WithMessage(CertificateChainValidator.CERTIFICATE_TRUSTED
- , (i) => rootCert.GetSubjectDN())));
+ .VALIDATING_SIGNATURE_NAME, (p) => "Signature1")).HasLogItem((al) => al.WithCertificate(rootCert).WithCheckName
+ (CertificateChainValidator.CERTIFICATE_CHECK).WithMessage(CertificateChainValidator.CERTIFICATE_TRUSTED
+ , (i) => rootCert.GetSubjectDN())).HasLogItem((al) => al.WithCheckName(OCSPValidator.OCSP_CHECK).WithMessage
+ (OCSPValidator.OCSP_RESPONDER_IS_CA)));
AssertValidationReport.AssertThat(report2, (a) => a.HasStatus(ValidationReport.ValidationResult.INVALID).HasNumberOfLogs
(4).HasNumberOfFailures(1).HasLogItem((al) => al.WithCheckName(DocumentRevisionsValidator.DOC_MDP_CHECK
).WithMessage(DocumentRevisionsValidator.PAGE_ANNOTATIONS_MODIFIED).WithStatus(ReportItem.ReportItemStatus
.INVALID)).HasLogItem((al) => al.WithCheckName(SignatureValidator.SIGNATURE_VERIFICATION).WithMessage(
- SignatureValidator.VALIDATING_SIGNATURE_NAME, (p) => "Signature2")).HasLogItems(2, (al) => al.WithCertificate
+ SignatureValidator.VALIDATING_SIGNATURE_NAME, (p) => "Signature2")).HasLogItem((al) => al.WithCertificate
(rootCert).WithCheckName(CertificateChainValidator.CERTIFICATE_CHECK).WithMessage(CertificateChainValidator
- .CERTIFICATE_TRUSTED, (i) => rootCert.GetSubjectDN())));
+ .CERTIFICATE_TRUSTED, (i) => rootCert.GetSubjectDN())).HasLogItem((al) => al.WithCheckName(OCSPValidator
+ .OCSP_CHECK).WithMessage(OCSPValidator.OCSP_RESPONDER_IS_CA)));
}
[NUnit.Framework.Test]
@@ -314,8 +318,8 @@ public virtual void LatestSignatureIsTimestampTest() {
SignatureValidator signatureValidator = builder.BuildSignatureValidator(document);
report = signatureValidator.ValidateLatestSignature(document);
}
- AssertValidationReport.AssertThat(report, (a) => a.HasNumberOfFailures(0).HasNumberOfLogs(3).HasLogItems(2
- , (la) => la.WithCheckName(CertificateChainValidator.CERTIFICATE_CHECK).WithMessage(CertificateChainValidator
+ AssertValidationReport.AssertThat(report, (a) => a.HasNumberOfFailures(0).HasNumberOfLogs(3).HasLogItem((la
+ ) => la.WithCheckName(CertificateChainValidator.CERTIFICATE_CHECK).WithMessage(CertificateChainValidator
.CERTIFICATE_TRUSTED, (l) => rootCert.GetSubjectDN()).WithCertificate(rootCert)));
}
@@ -356,9 +360,11 @@ public virtual void CertificatesNotInLatestSignatureButSetAsKnownTest() {
SignatureValidator signatureValidator = builder.BuildSignatureValidator(document);
report = signatureValidator.ValidateLatestSignature(document);
}
- AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID).HasLogItems
- (3, (al) => al.WithCheckName(CertificateChainValidator.CERTIFICATE_CHECK).WithMessage(CertificateChainValidator
- .CERTIFICATE_TRUSTED, (i) => rootCert.GetSubjectDN()).WithCertificate(rootCert)));
+ AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID).HasLogItem
+ ((al) => al.WithCheckName(CertificateChainValidator.CERTIFICATE_CHECK).WithMessage(CertificateChainValidator
+ .CERTIFICATE_TRUSTED, (i) => rootCert.GetSubjectDN()).WithCertificate(rootCert)).HasLogItem((al) => al
+ .WithCheckName(OCSPValidator.OCSP_CHECK).WithMessage(OCSPValidator.OCSP_RESPONDER_TRUSTED)).HasLogItem
+ ((al) => al.WithCheckName(OCSPValidator.OCSP_CHECK).WithMessage(OCSPValidator.OCSP_RESPONDER_IS_CA)));
}
[NUnit.Framework.Test]
diff --git a/itext.tests/itext.sign.tests/itext/signatures/validation/mocks/MockIssuingCertificateRetriever.cs b/itext.tests/itext.sign.tests/itext/signatures/validation/mocks/MockIssuingCertificateRetriever.cs
index dfa106d10f..aedc046b96 100644
--- a/itext.tests/itext.sign.tests/itext/signatures/validation/mocks/MockIssuingCertificateRetriever.cs
+++ b/itext.tests/itext.sign.tests/itext/signatures/validation/mocks/MockIssuingCertificateRetriever.cs
@@ -25,6 +25,7 @@ You should have received a copy of the GNU Affero General Public License
using System.IO;
using iText.Commons.Bouncycastle.Asn1.Ocsp;
using iText.Commons.Bouncycastle.Cert;
+using iText.Commons.Utils;
using iText.Signatures;
using iText.Signatures.Validation;
@@ -36,6 +37,8 @@ public class MockIssuingCertificateRetriever : IssuingCertificateRetriever {
public IList getCrlIssuerCertificatesCalls = new List();
+ public IList getCrlIssuerCertificatesByNameCalls = new List();
+
public IList retrieveIssuerCertificateCalls = new List();
public IList retrieveOCSPResponderCertificateCalls = new List();
@@ -59,9 +62,11 @@ public class MockIssuingCertificateRetriever : IssuingCertificateRetriever {
private Func getCrlIssuerCertificatesHandler;
+ private Func getCrlIssuerCertificatesByNameHandler;
+
private Func retrieveIssuerCertificateHandler;
- private Func retrieveOCSPResponderCertificateHandler;
+ private Func> retrieveOCSPResponderCertificateHandler;
private Action> setTrustedCertificatesHandler;
@@ -105,10 +110,22 @@ public override IX509Certificate[] GetCrlIssuerCertificates(IX509Crl crl) {
return new IX509Certificate[0];
}
- public override IX509Certificate RetrieveIssuerCertificate(IX509Certificate certificate) {
+ public override IX509Certificate[][] GetCrlIssuerCertificatesByName(IX509Crl crl) {
+ getCrlIssuerCertificatesByNameCalls.Add(crl);
+ if (getCrlIssuerCertificatesByNameHandler != null) {
+ return getCrlIssuerCertificatesByNameHandler.Invoke(crl);
+ }
+ if (wrapped != null) {
+ return wrapped.GetCrlIssuerCertificatesByName(crl);
+ }
+ return new IX509Certificate[0][];
+ }
+
+ public override IList RetrieveIssuerCertificate(IX509Certificate certificate) {
retrieveIssuerCertificateCalls.Add(certificate);
if (retrieveIssuerCertificateHandler != null) {
- return retrieveIssuerCertificateHandler.Invoke(certificate);
+ return JavaCollectionsUtil.SingletonList((IX509Certificate)retrieveIssuerCertificateHandler.Invoke(certificate
+ ));
}
if (wrapped != null) {
return wrapped.RetrieveIssuerCertificate(certificate);
@@ -116,13 +133,14 @@ public override IX509Certificate RetrieveIssuerCertificate(IX509Certificate cert
return null;
}
- public override IX509Certificate RetrieveOCSPResponderCertificate(IBasicOcspResponse ocspResp) {
+ public override ICollection RetrieveOCSPResponderByNameCertificate(IBasicOcspResponse ocspResp
+ ) {
retrieveOCSPResponderCertificateCalls.Add(ocspResp);
if (retrieveOCSPResponderCertificateHandler != null) {
return retrieveOCSPResponderCertificateHandler.Invoke(ocspResp);
}
if (wrapped != null) {
- return wrapped.RetrieveOCSPResponderCertificate(ocspResp);
+ return wrapped.RetrieveOCSPResponderByNameCertificate(ocspResp);
}
return null;
}
@@ -202,6 +220,12 @@ public virtual iText.Signatures.Validation.Mocks.MockIssuingCertificateRetriever
return this;
}
+ public virtual iText.Signatures.Validation.Mocks.MockIssuingCertificateRetriever OngetCrlIssuerCertificatesByNameDo
+ (Func callback) {
+ getCrlIssuerCertificatesByNameHandler = callback;
+ return this;
+ }
+
public virtual iText.Signatures.Validation.Mocks.MockIssuingCertificateRetriever OnRetrieveIssuerCertificateDo
(Func callback) {
retrieveIssuerCertificateHandler = callback;
@@ -209,7 +233,7 @@ public virtual iText.Signatures.Validation.Mocks.MockIssuingCertificateRetriever
}
public virtual iText.Signatures.Validation.Mocks.MockIssuingCertificateRetriever OnRetrieveOCSPResponderCertificateDo
- (Func callback) {
+ (Func> callback) {
retrieveOCSPResponderCertificateHandler = callback;
return this;
}
diff --git a/itext.tests/itext.sign.tests/itext/signatures/validation/mocks/MockTrustedCertificatesStore.cs b/itext.tests/itext.sign.tests/itext/signatures/validation/mocks/MockTrustedCertificatesStore.cs
index 226433363f..929b6f7e02 100644
--- a/itext.tests/itext.sign.tests/itext/signatures/validation/mocks/MockTrustedCertificatesStore.cs
+++ b/itext.tests/itext.sign.tests/itext/signatures/validation/mocks/MockTrustedCertificatesStore.cs
@@ -63,17 +63,17 @@ public class MockTrustedCertificatesStore : TrustedCertificatesStore {
private Func isCertificateTrustedForCAHandler;
- private Func getGenerallyTrustedCertificateHandler;
+ private Func> getGenerallyTrustedCertificateHandler;
- private Func getCertificateTrustedForOcspHandler;
+ private Func> getCertificateTrustedForOcspHandler;
- private Func getCertificateTrustedForCrlHandler;
+ private Func> getCertificateTrustedForCrlHandler;
- private Func getCertificateTrustedForTimestampHandler;
+ private Func> getCertificateTrustedForTimestampHandler;
- private Func getCertificateTrustedForCAHandler;
+ private Func> getCertificateTrustedForCAHandler;
- private Func getKnownCertificateHandler;
+ private Func> getKnownCertificateHandler;
private Func> getAllTrustedCertificatesHandler;
@@ -140,68 +140,68 @@ public override bool IsCertificateTrustedForCA(IX509Certificate certificate) {
return true;
}
- public override IX509Certificate GetGenerallyTrustedCertificate(String certificateName) {
+ public override ICollection GetGenerallyTrustedCertificates(String certificateName) {
getGenerallyTrustedCertificateCalls.Add(certificateName);
if (getGenerallyTrustedCertificateHandler != null) {
return getGenerallyTrustedCertificateHandler.Invoke(certificateName);
}
if (wrapped != null) {
- return wrapped.GetGenerallyTrustedCertificate(certificateName);
+ return wrapped.GetGenerallyTrustedCertificates(certificateName);
}
return null;
}
- public override IX509Certificate GetCertificateTrustedForOcsp(String certificateName) {
+ public override ICollection GetCertificatesTrustedForOcsp(String certificateName) {
getCertificateTrustedForOcspCalls.Add(certificateName);
if (getCertificateTrustedForOcspHandler != null) {
return getCertificateTrustedForOcspHandler.Invoke(certificateName);
}
if (wrapped != null) {
- return wrapped.GetCertificateTrustedForOcsp(certificateName);
+ return wrapped.GetCertificatesTrustedForOcsp(certificateName);
}
return null;
}
- public override IX509Certificate GetCertificateTrustedForCrl(String certificateName) {
+ public override ICollection GetCertificatesTrustedForCrl(String certificateName) {
getCertificateTrustedForCrlCalls.Add(certificateName);
if (getCertificateTrustedForCrlHandler != null) {
return getCertificateTrustedForCrlHandler.Invoke(certificateName);
}
if (wrapped != null) {
- return wrapped.GetCertificateTrustedForCrl(certificateName);
+ return wrapped.GetCertificatesTrustedForCrl(certificateName);
}
return null;
}
- public override IX509Certificate GetCertificateTrustedForTimestamp(String certificateName) {
+ public override ICollection GetCertificatesTrustedForTimestamp(String certificateName) {
getCertificateTrustedForTimestampCalls.Add(certificateName);
if (getCertificateTrustedForTimestampHandler != null) {
return getCertificateTrustedForTimestampHandler.Invoke(certificateName);
}
if (wrapped != null) {
- return wrapped.GetCertificateTrustedForTimestamp(certificateName);
+ return wrapped.GetCertificatesTrustedForTimestamp(certificateName);
}
return null;
}
- public override IX509Certificate GetCertificateTrustedForCA(String certificateName) {
+ public override ICollection GetCertificatesTrustedForCA(String certificateName) {
getCertificateTrustedForCACalls.Add(certificateName);
if (getCertificateTrustedForCAHandler != null) {
return getCertificateTrustedForCAHandler.Invoke(certificateName);
}
if (wrapped != null) {
- return wrapped.GetCertificateTrustedForCA(certificateName);
+ return wrapped.GetCertificatesTrustedForCA(certificateName);
}
return null;
}
- public override IX509Certificate GetKnownCertificate(String certificateName) {
+ public override ICollection GetKnownCertificates(String certificateName) {
getKnownCertificateCalls.Add(certificateName);
if (getKnownCertificateHandler != null) {
return getKnownCertificateHandler.Invoke(certificateName);
}
if (wrapped != null) {
- return wrapped.GetKnownCertificate(certificateName);
+ return wrapped.GetKnownCertificates(certificateName);
}
return null;
}
@@ -248,37 +248,37 @@ public virtual iText.Signatures.Validation.Mocks.MockTrustedCertificatesStore On
}
public virtual iText.Signatures.Validation.Mocks.MockTrustedCertificatesStore OnGetGenerallyTrustedCertificateDo
- (Func callBack) {
+ (Func> callBack) {
getGenerallyTrustedCertificateHandler = callBack;
return this;
}
public virtual iText.Signatures.Validation.Mocks.MockTrustedCertificatesStore OnGetCertificateTrustedForOcspDo
- (Func callBack) {
+ (Func> callBack) {
getCertificateTrustedForOcspHandler = callBack;
return this;
}
public virtual iText.Signatures.Validation.Mocks.MockTrustedCertificatesStore OnGetCertificateTrustedForCrlDo
- (Func callBack) {
+ (Func> callBack) {
getCertificateTrustedForCrlHandler = callBack;
return this;
}
public virtual iText.Signatures.Validation.Mocks.MockTrustedCertificatesStore OnGetCertificateTrustedForTimestampDo
- (Func callBack) {
+ (Func> callBack) {
getCertificateTrustedForTimestampHandler = callBack;
return this;
}
public virtual iText.Signatures.Validation.Mocks.MockTrustedCertificatesStore OnGetCertificateTrustedForCADo
- (Func callBack) {
+ (Func> callBack) {
getCertificateTrustedForCAHandler = callBack;
return this;
}
public virtual iText.Signatures.Validation.Mocks.MockTrustedCertificatesStore OnGetKnownCertificateDo(Func
- callBack) {
+ > callBack) {
getKnownCertificateHandler = callBack;
return this;
}
diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/createTestData.cmd b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/createTestData.cmd
index 47638363fd..ba87e44b37 100644
--- a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/createTestData.cmd
+++ b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/createTestData.cmd
@@ -12,6 +12,7 @@ call :runTestCase happyPath
call :runTestCase crlIssuerRevokedBeforeSigningDate
call :runTestCase crlIssuerAndSignCertHaveNoSharedRoot
call :runTestCase crlSignerInValidatedChain
+call :runTestCase multipleCrlIssuerCandidates
EXIT
:runTestCase
diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates.yml b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates.yml
new file mode 100644
index 0000000000..28a382457b
--- /dev/null
+++ b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates.yml
@@ -0,0 +1,113 @@
+external-url-prefix: "http://localhost.test"
+keysets:
+ testkeys:
+ keys:
+ ca:
+ path: keys/root_key.pem
+ password: testpassphrase
+ intermediate:
+ path: keys/im_key.pem
+ password: testpassphrase
+ sign:
+ path: keys/sign-key.pem
+ password: testpassphrase
+ crl-issuer:
+ path: keys/crl-key.pem
+ password: testpassphrase
+ crl-issuer-candidate1:
+ path: keys/im_key.pem
+ password: testpassphrase
+ crl-issuer-candidate2:
+ path: keys/sign-key.pem
+ password: testpassphrase
+
+pki-architectures:
+ default:
+ keyset: testkeys
+ entity-defaults:
+ country-name: BE
+ organization-name: iText
+ entities:
+ ca:
+ common-name: iTextTestRoot
+ intermediate:
+ common-name: iTextTestIntermediate
+ sign:
+ common-name: iTextTestSign
+ crl-issuer:
+ common-name: iTextTestCrlIssuer
+ crl-issuer-candidate1:
+ common-name: iTextTestCrlIssuer
+ crl-issuer-candidate2:
+ common-name: iTextTestCrlIssuer
+ certs:
+ ca:
+ subject: ca
+ issuer: ca
+ validity:
+ valid-from: "2000-01-01T00:00:00+0000"
+ valid-to: "2500-01-01T00:00:00+0000"
+ extensions:
+ - id: basic_constraints
+ critical: true
+ value:
+ ca: true
+ - id: key_usage
+ critical: true
+ smart-value:
+ schema: key-usage
+ params: [digital_signature, non_repudiation, key_encipherment, key_cert_sign]
+ intermediate:
+ issuer: ca
+ validity:
+ valid-from: "2000-01-01T00:00:00+0000"
+ valid-to: "2450-01-01T00:00:00+0000"
+ extensions:
+ - id: key_usage
+ critical: true
+ smart-value:
+ schema: key-usage
+ params: [digital_signature, non_repudiation, key_encipherment, key_cert_sign, crl_sign]
+ sign:
+ issuer: intermediate
+ validity:
+ valid-from: "2000-01-01T00:00:00+0000"
+ valid-to: "2400-01-01T00:00:00+0000"
+ extensions:
+ - id: key_usage
+ critical: true
+ smart-value:
+ schema: key-usage
+ params: [digital_signature, non_repudiation]
+ crl-issuer:
+ issuer: ca
+ validity:
+ valid-from: "2000-01-01T00:00:00+0000"
+ valid-to: "2450-01-01T00:00:00+0000"
+ extensions:
+ - id: key_usage
+ critical: true
+ smart-value:
+ schema: key-usage
+ params: [ digital_signature, non_repudiation, crl_sign]
+ - id: crl_distribution_points
+ smart-value:
+ schema: crl-dist-url
+ params:
+ crl-repo-names: [crl]
+ crl-issuer-candidate1:
+ issuer: ca
+ validity:
+ valid-from: "2000-01-01T00:00:00+0000"
+ valid-to: "2450-01-01T00:00:00+0000"
+ crl-issuer-candidate2:
+ issuer: ca
+ validity:
+ valid-from: "2000-01-01T00:00:00+0000"
+ valid-to: "2450-01-01T00:00:00+0000"
+ services:
+ crl-repo:
+ crl:
+ for-issuer: crl-issuer
+ signing-key: crl-issuer
+ simulated-update-schedule: "P90D"
\ No newline at end of file
diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/ca.cert.pem b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/ca.cert.pem
new file mode 100644
index 0000000000..efb7717302
--- /dev/null
+++ b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/ca.cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDSzCCAjOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwNTELMAkGA1UEBhMCQkUx
+DjAMBgNVBAoMBWlUZXh0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MCAXDTAwMDEw
+MTAwMDAwMFoYDzI1MDAwMTAxMDAwMDAwWjA1MQswCQYDVQQGEwJCRTEOMAwGA1UE
+CgwFaVRleHQxFjAUBgNVBAMMDWlUZXh0VGVzdFJvb3QwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDYxUs+SgZkRkOhOfddCnPeuE1QP2kAm6gAsg4qjNzr
+rZpZvwziyWaz6bXXq8fATjXEAdypAiWL/BDZscdCM/M11jds9mMv7dMvCtLns6Oe
+4GbChYxxloN2rVxElFPK2siKBaEeWyItr2Ms0P+hSR5uHjFt+krzl2zv828fyEnH
+fPvln42SAcuCKsLmfjtutus5jFKBFF8oiqDFlI2eXYggKV7JELttgPLobv2ZyFa5
+nXo/xbtzlPb8AvV3/mxpX4prFhBXupJXuCwmqmzVRqGbwKSz/Bewb/4aJGSpg32x
+yIWeXTld58f+Jntfes8xHwK0aJB/Tm2WrH+RWoV+TN/pAgMBAAGjYzBhMB0GA1Ud
+DgQWBBR0MlTFwFzoq8mPVusDjIEnL5avqzAfBgNVHSMEGDAWgBR0MlTFwFzoq8mP
+VusDjIEnL5avqzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIC5DANBgkq
+hkiG9w0BAQsFAAOCAQEAK2dbxbQ7jEdtqvnMpKOZsB55PDO5OZ2hPYilT5ZVZNt1
+jdE94HdCBHED3upmOeBH+XtsK/MLk+eYICM5SZwWVCBY0aQQR0URyTsX4SA/12A5
+VhrnP6bqy4b+3mO3J9s0go59cZOtSkxQ7191teEQMsDeh8GxXGLW/7Tf4x6v7U34
+B7UghMhUD2bHJ7U8MOqto9fVar/9S93tc9vRtYOXZbfRwjFKOYD4IFm7cH3VnrX7
+od3KUEKGKhQ2ZaqrtnW19xNTbdRcMT3+8QSai9DLV0kGGSSY09AHDO3WvxkAs9ZI
+cIsMM/n+mLK0Km9fh5uE3k6NmiN3GV+QMyjbmFnVNg==
+-----END CERTIFICATE-----
diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/chain.pem b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/chain.pem
new file mode 100644
index 0000000000..c5a2a1b14e
--- /dev/null
+++ b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/chain.pem
@@ -0,0 +1,121 @@
+-----BEGIN CERTIFICATE-----
+MIIDSzCCAjOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwNTELMAkGA1UEBhMCQkUx
+DjAMBgNVBAoMBWlUZXh0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MCAXDTAwMDEw
+MTAwMDAwMFoYDzI1MDAwMTAxMDAwMDAwWjA1MQswCQYDVQQGEwJCRTEOMAwGA1UE
+CgwFaVRleHQxFjAUBgNVBAMMDWlUZXh0VGVzdFJvb3QwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDYxUs+SgZkRkOhOfddCnPeuE1QP2kAm6gAsg4qjNzr
+rZpZvwziyWaz6bXXq8fATjXEAdypAiWL/BDZscdCM/M11jds9mMv7dMvCtLns6Oe
+4GbChYxxloN2rVxElFPK2siKBaEeWyItr2Ms0P+hSR5uHjFt+krzl2zv828fyEnH
+fPvln42SAcuCKsLmfjtutus5jFKBFF8oiqDFlI2eXYggKV7JELttgPLobv2ZyFa5
+nXo/xbtzlPb8AvV3/mxpX4prFhBXupJXuCwmqmzVRqGbwKSz/Bewb/4aJGSpg32x
+yIWeXTld58f+Jntfes8xHwK0aJB/Tm2WrH+RWoV+TN/pAgMBAAGjYzBhMB0GA1Ud
+DgQWBBR0MlTFwFzoq8mPVusDjIEnL5avqzAfBgNVHSMEGDAWgBR0MlTFwFzoq8mP
+VusDjIEnL5avqzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIC5DANBgkq
+hkiG9w0BAQsFAAOCAQEAK2dbxbQ7jEdtqvnMpKOZsB55PDO5OZ2hPYilT5ZVZNt1
+jdE94HdCBHED3upmOeBH+XtsK/MLk+eYICM5SZwWVCBY0aQQR0URyTsX4SA/12A5
+VhrnP6bqy4b+3mO3J9s0go59cZOtSkxQ7191teEQMsDeh8GxXGLW/7Tf4x6v7U34
+B7UghMhUD2bHJ7U8MOqto9fVar/9S93tc9vRtYOXZbfRwjFKOYD4IFm7cH3VnrX7
+od3KUEKGKhQ2ZaqrtnW19xNTbdRcMT3+8QSai9DLV0kGGSSY09AHDO3WvxkAs9ZI
+cIsMM/n+mLK0Km9fh5uE3k6NmiN3GV+QMyjbmFnVNg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDLzCCAhegAwIBAgICEAMwDQYJKoZIhvcNAQELBQAwNTELMAkGA1UEBhMCQkUx
+DjAMBgNVBAoMBWlUZXh0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MCAXDTAwMDEw
+MTAwMDAwMFoYDzI0NTAwMTAxMDAwMDAwWjA6MQswCQYDVQQGEwJCRTEOMAwGA1UE
+CgwFaVRleHQxGzAZBgNVBAMMEmlUZXh0VGVzdENybElzc3VlcjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAJ6M9OSQgx20Fw14rYFeM6HQuQxBD276e6kX
+MpmdsbbkvExq5mrAWPvFGYHCmRAtH7pGm1pL91Zlgh1CbUPzwSa/Lfp9FeAX83G7
+OJn0sY3kJRthtj5B0dGinXSIFCIb6gx9ICzoVpY9Ljvl4tyBr0dkGmED3MBxSFlt
+OMPplDhYwFekL7woNXMFIAxMnDWuS7dZ7xEpLAwNfH9D92I4lzSrQ9TrxwDPdW2g
+WGvi2eu77W4YqFQgydgbKmFHAzDUTA01LNmKZkASBcLUoiLnLBMmVYgDMH4fo4oj
++2/J/OZNuGv5DK9dRCryAhnY3f8/9b8JzoPeRCmgRO9IU7ObZ/0CAwEAAaNCMEAw
+HQYDVR0OBBYEFIlAkiqUVGkQL00y55tlNrfwvGTVMB8GA1UdIwQYMBaAFHQyVMXA
+XOiryY9W6wOMgScvlq+rMA0GCSqGSIb3DQEBCwUAA4IBAQAPKoa+iFhdqGoBXjuj
++m/xG2NAetvfpN4Sfy8RGOhEypsre2Xk/MzL6UBa59IYK3cd/x8ceAqPoBozL+NZ
+Xu3WzvD65zoLDJxBtHpOjaz3Mi/Yjxlfw7mb+loUj8tusouGhqhvJuKTzpXafFYu
+Ue1gwk+Lb3KsunkMhPc5s2h/yTkgbnrBbHuP5g8HRW0pbk3xZC4qHmrMsWHFGLba
+CAZ+AcyRaIGHqFQwnflWuMBNXr2KNL6J9IBs33mPNEaJZEqyIr5N7urXcTUS0Cog
+ZA3eugW6tacN8hR+6RA4dBIpPVth/tV2V3OtyeRUFKPrFYmaalgfSXYQPzoKDZpr
+SP8t
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDLzCCAhegAwIBAgICEAQwDQYJKoZIhvcNAQELBQAwNTELMAkGA1UEBhMCQkUx
+DjAMBgNVBAoMBWlUZXh0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MCAXDTAwMDEw
+MTAwMDAwMFoYDzI0NTAwMTAxMDAwMDAwWjA6MQswCQYDVQQGEwJCRTEOMAwGA1UE
+CgwFaVRleHQxGzAZBgNVBAMMEmlUZXh0VGVzdENybElzc3VlcjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBALMHHzTZo1BOQkZzEZl2Q3leNfBH20YfO4R0
+l0ZBWbnpg/099ON4I8ItO0f24Wq0gs//+1adlJqeUMeUVxQ0fpu0cHQOc9h7CWJL
+nPAJjEvItZ5WXW4l8/ppo1bo4WLB1hToF42NfHgh7Laoj2gqVLWXS6Ngd8chVxIT
+axfKA9PG56dje+PlJnTNi+ayudB/O57dhoaAu+sbxBhog/7zRAV87OsH9zxcNuw+
+3ZzHhss5Lpn6F+/WDcHPyXsT7QkX6rvbRvxUOpcysXtCH3v5+ZRKyUqRPlI63/hy
+MMZBDqYtFDHiawk587hbMp2swHF6z56d10Za22Vq9lxiX4MdftsCAwEAAaNCMEAw
+HQYDVR0OBBYEFFVqj/1gRbt6YJdo1/zMvcyOmY1cMB8GA1UdIwQYMBaAFHQyVMXA
+XOiryY9W6wOMgScvlq+rMA0GCSqGSIb3DQEBCwUAA4IBAQC5ZQAycuP/G9srjdfF
+nT33PWTfQn98+YybTBcb1Zj1zsD8ELBvN1esksMknNyYwL212CuY0pN32adV9eUQ
+A3GrLWEeBICJB6TR6UJ/BSI/0kLeN5TaAb0aRzjENQDAe3tJPXD1vVmNWvYxrDCk
+ncdKVOODsz4N+v0+EO8iUUNENDp69VyPBbw0oLjTHCwtqx5B3m35oHibXT3BuQPd
+OVDxFfd3PB/CrDWibobVOWw6MaTt5Oiv9WKbo0l0qZ76vyKdjqbQwqHdSfr23k/Y
+5PB9YYlqqPPxdSExzka/Oi7n21x1NhAr2T42p1Ff3ph3oQ2P3Qwn72ESu3riImmK
+18vH
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDhTCCAm2gAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwNTELMAkGA1UEBhMCQkUx
+DjAMBgNVBAoMBWlUZXh0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MCAXDTAwMDEw
+MTAwMDAwMFoYDzI0NTAwMTAxMDAwMDAwWjA6MQswCQYDVQQGEwJCRTEOMAwGA1UE
+CgwFaVRleHQxGzAZBgNVBAMMEmlUZXh0VGVzdENybElzc3VlcjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAMJ7DjX87Zpw3SySm1nfLBP9rcaJse9hwZ6w
+TNxtmy6Rn3LwBZvZ/xdFi39XTw2GPeCQBSrARhtBJ4eHgSe+d2R4LoP6sAyIheQ5
+0R+e3thLaCVsF43kpuSiyLGlnFLFBhyQ30vEn1g6jiAwqfqptpr9TPfKaCrCKOJU
+R8jOFwy+RERlAGJJQNIeZ6Bz9VdSZwkNP+Gfo+HV9LX057MaeMAPgrvAJrHy/lD9
+y07u0qKN62xzLZ/Mn9do+3qITEU1+9XkX9X0dTXrNMAO9kT3ukR6XdZIl8lvD/2P
+gTTaaro51v0ei3I7FZXNokjyuF6J8ARMVxqeOMlVUIxLeBv7j60CAwEAAaOBlzCB
+lDAdBgNVHQ4EFgQUEm6hMPB11w1J72tXumBhewwWxnUwHwYDVR0jBBgwFoAUdDJU
+xcBc6KvJj1brA4yBJy+Wr6swDgYDVR0PAQH/BAQDAgHCMEIGA1UdHwQ7MDkwN6A1
+oDOGMWh0dHA6Ly9sb2NhbGhvc3QudGVzdC9kZWZhdWx0L2NybHMvY3JsL2xhdGVz
+dC5jcmwwDQYJKoZIhvcNAQELBQADggEBAEg69NBvQJkOO25o1UxRoJqKb7PdwF5K
+xiidxXjJQTZHVR56rWoMfg/31eDwBdc6bmSAELd2wPSs3Ov3HJJP4f31+plXB3Qb
+B5pQUEc5i4IZiE0jz7Be4GLqSVNaLh9ay4o8PnpvcIZiKNukJzPhGsOzW8xrTF7R
+Cc6VSjmLHG2UnEt2CBbkaWnVXV8ibENSawv4Ar2AKpcU9LLoT1F92zx/7YpUQLr1
+k/RwWxkKByV5ko001DuwiWf/BjZ67pu5WTgdHQP9KaNMahnSqrjERCTLWVipdvJ2
+o3bHCe9I0OQMVlMeesKMWPRqLiAMpz7f7q09AXlqjvZT9+FPSi6nsss=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDQjCCAiqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwNTELMAkGA1UEBhMCQkUx
+DjAMBgNVBAoMBWlUZXh0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MCAXDTAwMDEw
+MTAwMDAwMFoYDzI0NTAwMTAxMDAwMDAwWjA9MQswCQYDVQQGEwJCRTEOMAwGA1UE
+CgwFaVRleHQxHjAcBgNVBAMMFWlUZXh0VGVzdEludGVybWVkaWF0ZTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ6M9OSQgx20Fw14rYFeM6HQuQxBD276
+e6kXMpmdsbbkvExq5mrAWPvFGYHCmRAtH7pGm1pL91Zlgh1CbUPzwSa/Lfp9FeAX
+83G7OJn0sY3kJRthtj5B0dGinXSIFCIb6gx9ICzoVpY9Ljvl4tyBr0dkGmED3MBx
+SFltOMPplDhYwFekL7woNXMFIAxMnDWuS7dZ7xEpLAwNfH9D92I4lzSrQ9TrxwDP
+dW2gWGvi2eu77W4YqFQgydgbKmFHAzDUTA01LNmKZkASBcLUoiLnLBMmVYgDMH4f
+o4oj+2/J/OZNuGv5DK9dRCryAhnY3f8/9b8JzoPeRCmgRO9IU7ObZ/0CAwEAAaNS
+MFAwHQYDVR0OBBYEFIlAkiqUVGkQL00y55tlNrfwvGTVMB8GA1UdIwQYMBaAFHQy
+VMXAXOiryY9W6wOMgScvlq+rMA4GA1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQsF
+AAOCAQEAMoIJ86nzczzR41l5EFHlxGvUEQY/w7BJ42LICN3F12WPmJ+A3i/GAJSQ
+14W+Jy8CXEhEFZF3R45vuOAGhOkF7igtbXeeVXunM3rmi8XIlpGjqbBZxC5w1Fd8
+IPOTArrzcF8agwthRzKOEpFSklmpUDT4MYZkdzR7TVM6TkdL+ModYFrhf9/+OFGb
+qHzKUPVv+dvNaKn6JvKfQ311MKG3fLU7vyKEUNoolAnLMy3VETsnhMTk6Wa5rfzJ
+eq2sdBiLxgwC3xhYk33Cla0X3hsr++Yqb8BX1ztKaRxu0PSi+KKJ9kvXAxRkFlwh
+Xa7iIRXelUhftWRF/4VgDsDhWx+eDQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDQjCCAiqgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UEBhMCQkUx
+DjAMBgNVBAoMBWlUZXh0MR4wHAYDVQQDDBVpVGV4dFRlc3RJbnRlcm1lZGlhdGUw
+IBcNMDAwMTAxMDAwMDAwWhgPMjQwMDAxMDEwMDAwMDBaMDUxCzAJBgNVBAYTAkJF
+MQ4wDAYDVQQKDAVpVGV4dDEWMBQGA1UEAwwNaVRleHRUZXN0U2lnbjCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALMHHzTZo1BOQkZzEZl2Q3leNfBH20Yf
+O4R0l0ZBWbnpg/099ON4I8ItO0f24Wq0gs//+1adlJqeUMeUVxQ0fpu0cHQOc9h7
+CWJLnPAJjEvItZ5WXW4l8/ppo1bo4WLB1hToF42NfHgh7Laoj2gqVLWXS6Ngd8ch
+VxITaxfKA9PG56dje+PlJnTNi+ayudB/O57dhoaAu+sbxBhog/7zRAV87OsH9zxc
+Nuw+3ZzHhss5Lpn6F+/WDcHPyXsT7QkX6rvbRvxUOpcysXtCH3v5+ZRKyUqRPlI6
+3/hyMMZBDqYtFDHiawk587hbMp2swHF6z56d10Za22Vq9lxiX4MdftsCAwEAAaNS
+MFAwHQYDVR0OBBYEFFVqj/1gRbt6YJdo1/zMvcyOmY1cMB8GA1UdIwQYMBaAFIlA
+kiqUVGkQL00y55tlNrfwvGTVMA4GA1UdDwEB/wQEAwIGwDANBgkqhkiG9w0BAQsF
+AAOCAQEAMsIeJp6AHJwChOEddcGu5dD/Q4R6l7dMIe3Q8g8vDVz94572jmvHIOa5
+Q/xJALRFn5rG1oC06q6Gy4ffbUm5S1dNBXdmwyfNzAa5yAwXraIWkXLPM5zFUueB
+qu2ekfPhHq0NjCqhVCCYkhngaf+mqeuw8usML6mMf8o0aC6TlQu7GXm/6Z4SSKmY
+wDyM4iSVR3fZHb3R/VBP7+GNKsamapZPThdxueWnm6o2vsMKSfgGHRV/41BrUqb7
+t5SXDihXCImTpUr89EL7kix42Q/BFQ60hO3LYsKn4w8gjUQffQdlB2zR6cQJx2eK
+9jrkP1+J6xcuWHHrn2l9YXw6rI7r0g==
+-----END CERTIFICATE-----
diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/crl-issuer-candidate1.cert.pem b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/crl-issuer-candidate1.cert.pem
new file mode 100644
index 0000000000..cb1f374156
--- /dev/null
+++ b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/crl-issuer-candidate1.cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDLzCCAhegAwIBAgICEAMwDQYJKoZIhvcNAQELBQAwNTELMAkGA1UEBhMCQkUx
+DjAMBgNVBAoMBWlUZXh0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MCAXDTAwMDEw
+MTAwMDAwMFoYDzI0NTAwMTAxMDAwMDAwWjA6MQswCQYDVQQGEwJCRTEOMAwGA1UE
+CgwFaVRleHQxGzAZBgNVBAMMEmlUZXh0VGVzdENybElzc3VlcjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAJ6M9OSQgx20Fw14rYFeM6HQuQxBD276e6kX
+MpmdsbbkvExq5mrAWPvFGYHCmRAtH7pGm1pL91Zlgh1CbUPzwSa/Lfp9FeAX83G7
+OJn0sY3kJRthtj5B0dGinXSIFCIb6gx9ICzoVpY9Ljvl4tyBr0dkGmED3MBxSFlt
+OMPplDhYwFekL7woNXMFIAxMnDWuS7dZ7xEpLAwNfH9D92I4lzSrQ9TrxwDPdW2g
+WGvi2eu77W4YqFQgydgbKmFHAzDUTA01LNmKZkASBcLUoiLnLBMmVYgDMH4fo4oj
++2/J/OZNuGv5DK9dRCryAhnY3f8/9b8JzoPeRCmgRO9IU7ObZ/0CAwEAAaNCMEAw
+HQYDVR0OBBYEFIlAkiqUVGkQL00y55tlNrfwvGTVMB8GA1UdIwQYMBaAFHQyVMXA
+XOiryY9W6wOMgScvlq+rMA0GCSqGSIb3DQEBCwUAA4IBAQAPKoa+iFhdqGoBXjuj
++m/xG2NAetvfpN4Sfy8RGOhEypsre2Xk/MzL6UBa59IYK3cd/x8ceAqPoBozL+NZ
+Xu3WzvD65zoLDJxBtHpOjaz3Mi/Yjxlfw7mb+loUj8tusouGhqhvJuKTzpXafFYu
+Ue1gwk+Lb3KsunkMhPc5s2h/yTkgbnrBbHuP5g8HRW0pbk3xZC4qHmrMsWHFGLba
+CAZ+AcyRaIGHqFQwnflWuMBNXr2KNL6J9IBs33mPNEaJZEqyIr5N7urXcTUS0Cog
+ZA3eugW6tacN8hR+6RA4dBIpPVth/tV2V3OtyeRUFKPrFYmaalgfSXYQPzoKDZpr
+SP8t
+-----END CERTIFICATE-----
diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/crl-issuer-candidate2.cert.pem b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/crl-issuer-candidate2.cert.pem
new file mode 100644
index 0000000000..dba77cd210
--- /dev/null
+++ b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/crl-issuer-candidate2.cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDLzCCAhegAwIBAgICEAQwDQYJKoZIhvcNAQELBQAwNTELMAkGA1UEBhMCQkUx
+DjAMBgNVBAoMBWlUZXh0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MCAXDTAwMDEw
+MTAwMDAwMFoYDzI0NTAwMTAxMDAwMDAwWjA6MQswCQYDVQQGEwJCRTEOMAwGA1UE
+CgwFaVRleHQxGzAZBgNVBAMMEmlUZXh0VGVzdENybElzc3VlcjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBALMHHzTZo1BOQkZzEZl2Q3leNfBH20YfO4R0
+l0ZBWbnpg/099ON4I8ItO0f24Wq0gs//+1adlJqeUMeUVxQ0fpu0cHQOc9h7CWJL
+nPAJjEvItZ5WXW4l8/ppo1bo4WLB1hToF42NfHgh7Laoj2gqVLWXS6Ngd8chVxIT
+axfKA9PG56dje+PlJnTNi+ayudB/O57dhoaAu+sbxBhog/7zRAV87OsH9zxcNuw+
+3ZzHhss5Lpn6F+/WDcHPyXsT7QkX6rvbRvxUOpcysXtCH3v5+ZRKyUqRPlI63/hy
+MMZBDqYtFDHiawk587hbMp2swHF6z56d10Za22Vq9lxiX4MdftsCAwEAAaNCMEAw
+HQYDVR0OBBYEFFVqj/1gRbt6YJdo1/zMvcyOmY1cMB8GA1UdIwQYMBaAFHQyVMXA
+XOiryY9W6wOMgScvlq+rMA0GCSqGSIb3DQEBCwUAA4IBAQC5ZQAycuP/G9srjdfF
+nT33PWTfQn98+YybTBcb1Zj1zsD8ELBvN1esksMknNyYwL212CuY0pN32adV9eUQ
+A3GrLWEeBICJB6TR6UJ/BSI/0kLeN5TaAb0aRzjENQDAe3tJPXD1vVmNWvYxrDCk
+ncdKVOODsz4N+v0+EO8iUUNENDp69VyPBbw0oLjTHCwtqx5B3m35oHibXT3BuQPd
+OVDxFfd3PB/CrDWibobVOWw6MaTt5Oiv9WKbo0l0qZ76vyKdjqbQwqHdSfr23k/Y
+5PB9YYlqqPPxdSExzka/Oi7n21x1NhAr2T42p1Ff3ph3oQ2P3Qwn72ESu3riImmK
+18vH
+-----END CERTIFICATE-----
diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/crl-issuer.cert.pem b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/crl-issuer.cert.pem
new file mode 100644
index 0000000000..3656f9e733
--- /dev/null
+++ b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/crl-issuer.cert.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDhTCCAm2gAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwNTELMAkGA1UEBhMCQkUx
+DjAMBgNVBAoMBWlUZXh0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MCAXDTAwMDEw
+MTAwMDAwMFoYDzI0NTAwMTAxMDAwMDAwWjA6MQswCQYDVQQGEwJCRTEOMAwGA1UE
+CgwFaVRleHQxGzAZBgNVBAMMEmlUZXh0VGVzdENybElzc3VlcjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAMJ7DjX87Zpw3SySm1nfLBP9rcaJse9hwZ6w
+TNxtmy6Rn3LwBZvZ/xdFi39XTw2GPeCQBSrARhtBJ4eHgSe+d2R4LoP6sAyIheQ5
+0R+e3thLaCVsF43kpuSiyLGlnFLFBhyQ30vEn1g6jiAwqfqptpr9TPfKaCrCKOJU
+R8jOFwy+RERlAGJJQNIeZ6Bz9VdSZwkNP+Gfo+HV9LX057MaeMAPgrvAJrHy/lD9
+y07u0qKN62xzLZ/Mn9do+3qITEU1+9XkX9X0dTXrNMAO9kT3ukR6XdZIl8lvD/2P
+gTTaaro51v0ei3I7FZXNokjyuF6J8ARMVxqeOMlVUIxLeBv7j60CAwEAAaOBlzCB
+lDAdBgNVHQ4EFgQUEm6hMPB11w1J72tXumBhewwWxnUwHwYDVR0jBBgwFoAUdDJU
+xcBc6KvJj1brA4yBJy+Wr6swDgYDVR0PAQH/BAQDAgHCMEIGA1UdHwQ7MDkwN6A1
+oDOGMWh0dHA6Ly9sb2NhbGhvc3QudGVzdC9kZWZhdWx0L2NybHMvY3JsL2xhdGVz
+dC5jcmwwDQYJKoZIhvcNAQELBQADggEBAEg69NBvQJkOO25o1UxRoJqKb7PdwF5K
+xiidxXjJQTZHVR56rWoMfg/31eDwBdc6bmSAELd2wPSs3Ov3HJJP4f31+plXB3Qb
+B5pQUEc5i4IZiE0jz7Be4GLqSVNaLh9ay4o8PnpvcIZiKNukJzPhGsOzW8xrTF7R
+Cc6VSjmLHG2UnEt2CBbkaWnVXV8ibENSawv4Ar2AKpcU9LLoT1F92zx/7YpUQLr1
+k/RwWxkKByV5ko001DuwiWf/BjZ67pu5WTgdHQP9KaNMahnSqrjERCTLWVipdvJ2
+o3bHCe9I0OQMVlMeesKMWPRqLiAMpz7f7q09AXlqjvZT9+FPSi6nsss=
+-----END CERTIFICATE-----
diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/intermediate.cert.pem b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/intermediate.cert.pem
new file mode 100644
index 0000000000..ca4cf7ba9c
--- /dev/null
+++ b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/intermediate.cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDQjCCAiqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwNTELMAkGA1UEBhMCQkUx
+DjAMBgNVBAoMBWlUZXh0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MCAXDTAwMDEw
+MTAwMDAwMFoYDzI0NTAwMTAxMDAwMDAwWjA9MQswCQYDVQQGEwJCRTEOMAwGA1UE
+CgwFaVRleHQxHjAcBgNVBAMMFWlUZXh0VGVzdEludGVybWVkaWF0ZTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ6M9OSQgx20Fw14rYFeM6HQuQxBD276
+e6kXMpmdsbbkvExq5mrAWPvFGYHCmRAtH7pGm1pL91Zlgh1CbUPzwSa/Lfp9FeAX
+83G7OJn0sY3kJRthtj5B0dGinXSIFCIb6gx9ICzoVpY9Ljvl4tyBr0dkGmED3MBx
+SFltOMPplDhYwFekL7woNXMFIAxMnDWuS7dZ7xEpLAwNfH9D92I4lzSrQ9TrxwDP
+dW2gWGvi2eu77W4YqFQgydgbKmFHAzDUTA01LNmKZkASBcLUoiLnLBMmVYgDMH4f
+o4oj+2/J/OZNuGv5DK9dRCryAhnY3f8/9b8JzoPeRCmgRO9IU7ObZ/0CAwEAAaNS
+MFAwHQYDVR0OBBYEFIlAkiqUVGkQL00y55tlNrfwvGTVMB8GA1UdIwQYMBaAFHQy
+VMXAXOiryY9W6wOMgScvlq+rMA4GA1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQsF
+AAOCAQEAMoIJ86nzczzR41l5EFHlxGvUEQY/w7BJ42LICN3F12WPmJ+A3i/GAJSQ
+14W+Jy8CXEhEFZF3R45vuOAGhOkF7igtbXeeVXunM3rmi8XIlpGjqbBZxC5w1Fd8
+IPOTArrzcF8agwthRzKOEpFSklmpUDT4MYZkdzR7TVM6TkdL+ModYFrhf9/+OFGb
+qHzKUPVv+dvNaKn6JvKfQ311MKG3fLU7vyKEUNoolAnLMy3VETsnhMTk6Wa5rfzJ
+eq2sdBiLxgwC3xhYk33Cla0X3hsr++Yqb8BX1ztKaRxu0PSi+KKJ9kvXAxRkFlwh
+Xa7iIRXelUhftWRF/4VgDsDhWx+eDQ==
+-----END CERTIFICATE-----
diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/sign.cert.pem b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/sign.cert.pem
new file mode 100644
index 0000000000..bfcfbf0242
--- /dev/null
+++ b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/CRLValidatorTest/multipleCrlIssuerCandidates/sign.cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDQjCCAiqgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UEBhMCQkUx
+DjAMBgNVBAoMBWlUZXh0MR4wHAYDVQQDDBVpVGV4dFRlc3RJbnRlcm1lZGlhdGUw
+IBcNMDAwMTAxMDAwMDAwWhgPMjQwMDAxMDEwMDAwMDBaMDUxCzAJBgNVBAYTAkJF
+MQ4wDAYDVQQKDAVpVGV4dDEWMBQGA1UEAwwNaVRleHRUZXN0U2lnbjCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALMHHzTZo1BOQkZzEZl2Q3leNfBH20Yf
+O4R0l0ZBWbnpg/099ON4I8ItO0f24Wq0gs//+1adlJqeUMeUVxQ0fpu0cHQOc9h7
+CWJLnPAJjEvItZ5WXW4l8/ppo1bo4WLB1hToF42NfHgh7Laoj2gqVLWXS6Ngd8ch
+VxITaxfKA9PG56dje+PlJnTNi+ayudB/O57dhoaAu+sbxBhog/7zRAV87OsH9zxc
+Nuw+3ZzHhss5Lpn6F+/WDcHPyXsT7QkX6rvbRvxUOpcysXtCH3v5+ZRKyUqRPlI6
+3/hyMMZBDqYtFDHiawk587hbMp2swHF6z56d10Za22Vq9lxiX4MdftsCAwEAAaNS
+MFAwHQYDVR0OBBYEFFVqj/1gRbt6YJdo1/zMvcyOmY1cMB8GA1UdIwQYMBaAFIlA
+kiqUVGkQL00y55tlNrfwvGTVMA4GA1UdDwEB/wQEAwIGwDANBgkqhkiG9w0BAQsF
+AAOCAQEAMsIeJp6AHJwChOEddcGu5dD/Q4R6l7dMIe3Q8g8vDVz94572jmvHIOa5
+Q/xJALRFn5rG1oC06q6Gy4ffbUm5S1dNBXdmwyfNzAa5yAwXraIWkXLPM5zFUueB
+qu2ekfPhHq0NjCqhVCCYkhngaf+mqeuw8usML6mMf8o0aC6TlQu7GXm/6Z4SSKmY
+wDyM4iSVR3fZHb3R/VBP7+GNKsamapZPThdxueWnm6o2vsMKSfgGHRV/41BrUqb7
+t5SXDihXCImTpUr89EL7kix42Q/BFQ60hO3LYsKn4w8gjUQffQdlB2zR6cQJx2eK
+9jrkP1+J6xcuWHHrn2l9YXw6rI7r0g==
+-----END CERTIFICATE-----
diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/OCSPValidatorTest/candidate1-ocsp-issuer.cert.pem b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/OCSPValidatorTest/candidate1-ocsp-issuer.cert.pem
new file mode 100644
index 0000000000..d65da4d99c
--- /dev/null
+++ b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/OCSPValidatorTest/candidate1-ocsp-issuer.cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDMzCCAhugAwIBAgICEAMwDQYJKoZIhvcNAQELBQAwNTELMAkGA1UEBhMCQlkx
+DjAMBgNVBAoMBWlUZXh0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MCAXDTAwMDEw
+MTAwMDAwMFoYDzI0NTAwMTAxMDAwMDAwWjA+MQswCQYDVQQGEwJCWTEOMAwGA1UE
+CgwFaVRleHQxHzAdBgNVBAMMFmlUZXh0VGVzdE9jc3BSZXNwb25kZXIwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCejPTkkIMdtBcNeK2BXjOh0LkMQQ9u
++nupFzKZnbG25LxMauZqwFj7xRmBwpkQLR+6RptaS/dWZYIdQm1D88Emvy36fRXg
+F/NxuziZ9LGN5CUbYbY+QdHRop10iBQiG+oMfSAs6FaWPS475eLcga9HZBphA9zA
+cUhZbTjD6ZQ4WMBXpC+8KDVzBSAMTJw1rku3We8RKSwMDXx/Q/diOJc0q0PU68cA
+z3VtoFhr4tnru+1uGKhUIMnYGyphRwMw1EwNNSzZimZAEgXC1KIi5ywTJlWIAzB+
+H6OKI/tvyfzmTbhr+QyvXUQq8gIZ2N3/P/W/Cc6D3kQpoETvSFOzm2f9AgMBAAGj
+QjBAMB0GA1UdDgQWBBSJQJIqlFRpEC9NMuebZTa38Lxk1TAfBgNVHSMEGDAWgBR0
+MlTFwFzoq8mPVusDjIEnL5avqzANBgkqhkiG9w0BAQsFAAOCAQEAlA1IOlUFvoOj
+HM1VqwYmbTNUUSFpuZV9+njFCLNg6FaLDSB28uszcEzH4NhWfA8YydM+zPLwqIxg
+0mOBjaeFaLgWAjPR3ejCexc4jcF6gc3hZTBx5m7i6REiDChWvodCwoa6fZ7dBDvH
+3vd4Rlj/h3Ir67L7lTwI9AnBqmrQ49UhkGRHHK4RK9hHdhr1pqZnvRKjuAtApFWC
+McTQYJxFIhZPdhF6fHjoozUbEtq6GrviuaYMBul306lXCd5/OzkW84CvOihgT1q7
+OtgCRuOawdMFZTqjk6OHqQ50GFhEfp3WqubYFkH7ADYNO5E8k3rWNVK08ldfKF1s
+McB+a0FXzw==
+-----END CERTIFICATE-----
diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/OCSPValidatorTest/candidate2-ocsp-issuer.cert.pem b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/OCSPValidatorTest/candidate2-ocsp-issuer.cert.pem
new file mode 100644
index 0000000000..25be340dad
--- /dev/null
+++ b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/OCSPValidatorTest/candidate2-ocsp-issuer.cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDMzCCAhugAwIBAgICEAQwDQYJKoZIhvcNAQELBQAwNTELMAkGA1UEBhMCQlkx
+DjAMBgNVBAoMBWlUZXh0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MCAXDTAwMDEw
+MTAwMDAwMFoYDzI0NTAwMTAxMDAwMDAwWjA+MQswCQYDVQQGEwJCWTEOMAwGA1UE
+CgwFaVRleHQxHzAdBgNVBAMMFmlUZXh0VGVzdE9jc3BSZXNwb25kZXIwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzBx802aNQTkJGcxGZdkN5XjXwR9tG
+HzuEdJdGQVm56YP9PfTjeCPCLTtH9uFqtILP//tWnZSanlDHlFcUNH6btHB0DnPY
+ewliS5zwCYxLyLWeVl1uJfP6aaNW6OFiwdYU6BeNjXx4Iey2qI9oKlS1l0ujYHfH
+IVcSE2sXygPTxuenY3vj5SZ0zYvmsrnQfzue3YaGgLvrG8QYaIP+80QFfOzrB/c8
+XDbsPt2cx4bLOS6Z+hfv1g3Bz8l7E+0JF+q720b8VDqXMrF7Qh97+fmUSslKkT5S
+Ot/4cjDGQQ6mLRQx4msJOfO4WzKdrMBxes+enddGWttlavZcYl+DHX7bAgMBAAGj
+QjBAMB0GA1UdDgQWBBRVao/9YEW7emCXaNf8zL3MjpmNXDAfBgNVHSMEGDAWgBR0
+MlTFwFzoq8mPVusDjIEnL5avqzANBgkqhkiG9w0BAQsFAAOCAQEAte8X2bL+SorE
+EK4pU75vmhr1X8W8rSNXJfy6p6m6GaigNIK4rmAu6bR9B4ai3qZNX9LE/eeKhwZu
+yinLPGHema9vbG23FpHnM31mU7P3XAKprjrnrpxWBZ/dNx4IEYKtvDOKFIrR31Pt
+stCOm7WXsPc8ovGQj+OnBh+lKaAy7yLNg7o8/8RxOwH9T2VbXcUBcMTnvKVsGiWa
+tAiqa15EqnAEN7wAi9OpRkDKOfHdnR/bIv8CC6F3WWIwWmWcyi9st7ISv4ywtBmm
+RriPwkjsBmyUu5DKBzFSfLEfnPpD1PjW+XMx0aHFuCf+HYAG8TDRkrhASwFCVb2B
+6fFX5LBgew==
+-----END CERTIFICATE-----
diff --git a/itext/itext.bouncy-castle-adapter/itext/bouncycastle/BouncyCastleFactory.cs b/itext/itext.bouncy-castle-adapter/itext/bouncycastle/BouncyCastleFactory.cs
index 088e964085..ffccd18ef9 100644
--- a/itext/itext.bouncy-castle-adapter/itext/bouncycastle/BouncyCastleFactory.cs
+++ b/itext/itext.bouncy-castle-adapter/itext/bouncycastle/BouncyCastleFactory.cs
@@ -875,6 +875,11 @@ public virtual IX500Name CreateX500Name(String s) {
return new X509NameBC(new X509Name(s));
}
+ public IX500Name CreateX500Name(IAsn1Sequence s)
+ {
+ return new X509NameBC(X509Name.GetInstance(((Asn1SequenceBC) s).GetAsn1Sequence()));
+ }
+
///
public virtual IRespID CreateRespID(IX500Name x500Name) {
return new RespIDBC(x500Name);
diff --git a/itext/itext.bouncy-castle-adapter/itext/bouncycastle/asn1/ocsp/BasicOcspResponseBC.cs b/itext/itext.bouncy-castle-adapter/itext/bouncycastle/asn1/ocsp/BasicOcspResponseBC.cs
index 78f8c1ddf4..7edd145ca7 100644
--- a/itext/itext.bouncy-castle-adapter/itext/bouncycastle/asn1/ocsp/BasicOcspResponseBC.cs
+++ b/itext/itext.bouncy-castle-adapter/itext/bouncycastle/asn1/ocsp/BasicOcspResponseBC.cs
@@ -22,6 +22,7 @@ You should have received a copy of the GNU Affero General Public License
*/
using System;
using System.Collections.Generic;
+using iText.Bouncycastle.Asn1.X509;
using Org.BouncyCastle.Asn1.Ocsp;
using iText.Bouncycastle.Cert.Ocsp;
using iText.Bouncycastle.Crypto;
@@ -127,5 +128,10 @@ public IAsn1Encodable GetExtensionParsedValue(IDerObjectIdentifier objectIdentif
return new Asn1EncodableBC(GetBasicOcspResponse().TbsResponseData.ResponseExtensions
.GetExtensionParsedValue(((DerObjectIdentifierBC)objectIdentifier).GetDerObjectIdentifier()));
}
+
+ public IRespID GetResponderId()
+ {
+ return new RespIDBC(new X509NameBC(GetBasicOcspResponse().TbsResponseData.ResponderID.Name));
+ }
}
}
diff --git a/itext/itext.bouncy-castle-adapter/itext/bouncycastle/asn1/x509/X509NameBC.cs b/itext/itext.bouncy-castle-adapter/itext/bouncycastle/asn1/x509/X509NameBC.cs
index 52bf9c4b58..14410a20e3 100644
--- a/itext/itext.bouncy-castle-adapter/itext/bouncycastle/asn1/x509/X509NameBC.cs
+++ b/itext/itext.bouncy-castle-adapter/itext/bouncycastle/asn1/x509/X509NameBC.cs
@@ -51,5 +51,10 @@ public X509NameBC(X509Name x500Name)
public virtual X509Name GetX509Name() {
return (X509Name)GetEncodable();
}
+
+ public string GetName()
+ {
+ return GetX509Name().ToString();
+ }
}
}
diff --git a/itext/itext.bouncy-castle-adapter/itext/bouncycastle/cert/ocsp/RespIDBC.cs b/itext/itext.bouncy-castle-adapter/itext/bouncycastle/cert/ocsp/RespIDBC.cs
index b21175562f..9cfc196fb2 100644
--- a/itext/itext.bouncy-castle-adapter/itext/bouncycastle/cert/ocsp/RespIDBC.cs
+++ b/itext/itext.bouncy-castle-adapter/itext/bouncycastle/cert/ocsp/RespIDBC.cs
@@ -69,6 +69,11 @@ public virtual RespID GetRespID() {
return respID;
}
+ ///
+ public virtual IResponderID ToASN1Primitive() {
+ return new ResponderIDBC(respID.ToAsn1Object());
+ }
+
/// Indicates whether some other object is "equal to" this one.
/// Indicates whether some other object is "equal to" this one. Compares wrapped objects.
public override bool Equals(Object o) {
diff --git a/itext/itext.bouncy-castle-adapter/itext/bouncycastle/cert/ocsp/ResponderIDBC.cs b/itext/itext.bouncy-castle-adapter/itext/bouncycastle/cert/ocsp/ResponderIDBC.cs
new file mode 100644
index 0000000000..4f458913fa
--- /dev/null
+++ b/itext/itext.bouncy-castle-adapter/itext/bouncycastle/cert/ocsp/ResponderIDBC.cs
@@ -0,0 +1,59 @@
+/*
+This file is part of the iText (R) project.
+Copyright (c) 1998-2024 Apryse Group NV
+Authors: Apryse Software.
+
+This program is offered under a commercial and under the AGPL license.
+For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
+
+AGPL licensing:
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+*/
+using Org.BouncyCastle.Asn1.Ocsp;
+using iText.Bouncycastle.Asn1.X509;
+using iText.Commons.Bouncycastle.Asn1.X500;
+using iText.Commons.Bouncycastle.Cert.Ocsp;
+
+namespace iText.Bouncycastle.Cert.Ocsp {
+ public class ResponderIDBC : IResponderID {
+ private readonly ResponderID responderID;
+
+ ///
+ /// Creates new wrapper instance for
+ /// .
+ ///
+ ///
+ ///
+ ///
+ /// to be wrapped
+ ///
+ public ResponderIDBC(ResponderID responderID) {
+ this.responderID = responderID;
+ }
+
+ ///
+ public virtual IX500Name GetName() {
+ return new X509NameBC(responderID.Name);
+ }
+
+ /// Gets actual org.bouncycastle object being wrapped.
+ ///
+ /// wrapped
+ /// .
+ ///
+ public virtual ResponderID GetResponderID() {
+ return responderID;
+ }
+ }
+}
diff --git a/itext/itext.bouncy-castle-connector/itext/bouncycastleconnector/BouncyCastleDefaultFactory.cs b/itext/itext.bouncy-castle-connector/itext/bouncycastleconnector/BouncyCastleDefaultFactory.cs
index d80dc474b7..5951924310 100644
--- a/itext/itext.bouncy-castle-connector/itext/bouncycastleconnector/BouncyCastleDefaultFactory.cs
+++ b/itext/itext.bouncy-castle-connector/itext/bouncycastleconnector/BouncyCastleDefaultFactory.cs
@@ -522,6 +522,11 @@ public IX500Name CreateX500Name(string s) {
throw new NotSupportedException(BouncyCastleLogMessageConstant.BOUNCY_CASTLE_DEPENDENCY_MUST_PRESENT);
}
+ public IX500Name CreateX500Name(IAsn1Sequence s)
+ {
+ throw new NotSupportedException(BouncyCastleLogMessageConstant.BOUNCY_CASTLE_DEPENDENCY_MUST_PRESENT);
+ }
+
public IRespID CreateRespID(IX500Name x500Name) {
throw new NotSupportedException(BouncyCastleLogMessageConstant.BOUNCY_CASTLE_DEPENDENCY_MUST_PRESENT);
}
diff --git a/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/BouncyCastleFipsFactory.cs b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/BouncyCastleFipsFactory.cs
index 8ad6eb745b..aa7018c4e2 100644
--- a/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/BouncyCastleFipsFactory.cs
+++ b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/BouncyCastleFipsFactory.cs
@@ -877,6 +877,11 @@ public virtual IX500Name CreateX500Name(String s) {
return new X500NameBCFips(new X500Name(s));
}
+ public IX500Name CreateX500Name(IAsn1Sequence s)
+ {
+ return new X500NameBCFips(X500Name.GetInstance(((Asn1SequenceBCFips) s).GetAsn1Sequence()));
+ }
+
///
public virtual IRespID CreateRespID(IX500Name x500Name) {
return new RespIDBCFips(x500Name);
diff --git a/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/asn1/ocsp/BasicOcspResponseBCFips.cs b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/asn1/ocsp/BasicOcspResponseBCFips.cs
index d66cb978fb..c462dbac3c 100644
--- a/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/asn1/ocsp/BasicOcspResponseBCFips.cs
+++ b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/asn1/ocsp/BasicOcspResponseBCFips.cs
@@ -129,5 +129,10 @@ public IAsn1Encodable GetExtensionParsedValue(IDerObjectIdentifier objectIdentif
return new Asn1EncodableBCFips(GetBasicOcspResponse().TbsResponseData.ResponseExtensions.GetExtension(
((DerObjectIdentifierBCFips)objectIdentifier).GetDerObjectIdentifier())?.GetParsedValue());
}
+
+ public IRespID GetResponderId()
+ {
+ return new RespIDBCFips(GetBasicOcspResponse().TbsResponseData.ResponderID);
+ }
}
}
diff --git a/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/asn1/x500/X500NameBCFips.cs b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/asn1/x500/X500NameBCFips.cs
index f7c1e96604..f68380a71a 100644
--- a/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/asn1/x500/X500NameBCFips.cs
+++ b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/asn1/x500/X500NameBCFips.cs
@@ -51,5 +51,10 @@ public X500NameBCFips(X500Name x500Name)
public virtual X500Name GetX500Name() {
return (X500Name)GetEncodable();
}
+
+ public string GetName()
+ {
+ return GetX500Name().ToString();
+ }
}
}
diff --git a/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/cert/ocsp/RespIDBCFips.cs b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/cert/ocsp/RespIDBCFips.cs
index 2a17c0e146..fcc64f6999 100644
--- a/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/cert/ocsp/RespIDBCFips.cs
+++ b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/cert/ocsp/RespIDBCFips.cs
@@ -95,5 +95,10 @@ public override int GetHashCode() {
public override String ToString() {
return respID.ToString();
}
+
+ public IResponderID ToASN1Primitive()
+ {
+ return new ResponderIDBCFips(respID);
+ }
}
}
diff --git a/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/cert/ocsp/ResponderIDBCFips.cs b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/cert/ocsp/ResponderIDBCFips.cs
new file mode 100644
index 0000000000..5fa28964cb
--- /dev/null
+++ b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/cert/ocsp/ResponderIDBCFips.cs
@@ -0,0 +1,59 @@
+/*
+This file is part of the iText (R) project.
+Copyright (c) 1998-2024 Apryse Group NV
+Authors: Apryse Software.
+
+This program is offered under a commercial and under the AGPL license.
+For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
+
+AGPL licensing:
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+*/
+using Org.BouncyCastle.Asn1.Ocsp;
+using iText.Bouncycastlefips.Asn1.X500;
+using iText.Commons.Bouncycastle.Asn1.X500;
+using iText.Commons.Bouncycastle.Cert.Ocsp;
+
+namespace iText.Bouncycastlefips.Cert.Ocsp {
+ public class ResponderIDBCFips : IResponderID {
+ private readonly ResponderID responderID;
+
+ ///
+ /// Creates new wrapper instance for
+ /// .
+ ///
+ ///
+ ///
+ ///
+ /// to be wrapped
+ ///
+ public ResponderIDBCFips(ResponderID responderID) {
+ this.responderID = responderID;
+ }
+
+ ///
+ public virtual IX500Name GetName() {
+ return new X500NameBCFips(responderID.Name);
+ }
+
+ /// Gets actual org.bouncycastle object being wrapped.
+ ///
+ /// wrapped
+ /// .
+ ///
+ public virtual ResponderID GetResponderID() {
+ return responderID;
+ }
+ }
+}
diff --git a/itext/itext.commons/itext/commons/bouncycastle/IBouncyCastleFactory.cs b/itext/itext.commons/itext/commons/bouncycastle/IBouncyCastleFactory.cs
index 451b308e64..5eac94997c 100644
--- a/itext/itext.commons/itext/commons/bouncycastle/IBouncyCastleFactory.cs
+++ b/itext/itext.commons/itext/commons/bouncycastle/IBouncyCastleFactory.cs
@@ -1054,6 +1054,19 @@ ITimeStampTokenGenerator CreateTimeStampTokenGenerator(IPrivateKey pk, IX509Cert
///
/// created X500 Name wrapper
IX500Name CreateX500Name(String s);
+
+
+ ///
+ /// Create X500 Name wrapper from
+ /// .
+ ///
+ ///
+ ///
+ ///
+ /// to create X500 Name wrapper from
+ ///
+ /// created X500 Name wrapper
+ IX500Name CreateX500Name(IAsn1Sequence s);
/// Create resp ID wrapper from X500 Name wrapper.
/// X500 Name wrapper to create resp ID wrapper from
diff --git a/itext/itext.commons/itext/commons/bouncycastle/asn1/ocsp/IBasicOcspResponse.cs b/itext/itext.commons/itext/commons/bouncycastle/asn1/ocsp/IBasicOcspResponse.cs
index 6d6251afc5..e33fffa079 100644
--- a/itext/itext.commons/itext/commons/bouncycastle/asn1/ocsp/IBasicOcspResponse.cs
+++ b/itext/itext.commons/itext/commons/bouncycastle/asn1/ocsp/IBasicOcspResponse.cs
@@ -93,5 +93,7 @@ public interface IBasicOcspResponse : IAsn1Encodable {
///
/// Parsed extension value.
IAsn1Encodable GetExtensionParsedValue(IDerObjectIdentifier getIdPkixOcspArchiveCutoff);
+
+ IRespID GetResponderId();
}
}
diff --git a/itext/itext.commons/itext/commons/bouncycastle/asn1/x500/IX500Name.cs b/itext/itext.commons/itext/commons/bouncycastle/asn1/x500/IX500Name.cs
index 5268d45cbb..d57d4d7fec 100644
--- a/itext/itext.commons/itext/commons/bouncycastle/asn1/x500/IX500Name.cs
+++ b/itext/itext.commons/itext/commons/bouncycastle/asn1/x500/IX500Name.cs
@@ -20,6 +20,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
+using System;
using iText.Commons.Bouncycastle.Asn1;
namespace iText.Commons.Bouncycastle.Asn1.X500 {
@@ -28,5 +29,8 @@ namespace iText.Commons.Bouncycastle.Asn1.X500 {
/// to switch between bouncy-castle and bouncy-castle FIPS implementations.
///
public interface IX500Name : IAsn1Encodable {
+ /// Gets the RFC2253 name.
+ /// the RFC2253 name
+ String GetName();
}
}
diff --git a/itext/itext.commons/itext/commons/bouncycastle/cert/ocsp/IRespID.cs b/itext/itext.commons/itext/commons/bouncycastle/cert/ocsp/IRespID.cs
index bab491d4ee..1b8062bb6a 100644
--- a/itext/itext.commons/itext/commons/bouncycastle/cert/ocsp/IRespID.cs
+++ b/itext/itext.commons/itext/commons/bouncycastle/cert/ocsp/IRespID.cs
@@ -26,5 +26,12 @@ namespace iText.Commons.Bouncycastle.Cert.Ocsp {
/// to switch between bouncy-castle and bouncy-castle FIPS implementations.
///
public interface IRespID {
+ ///
+ /// Calls actual
+ /// toASN1Primitive
+ /// method for the wrapped BasicOCSPResp object.
+ ///
+ /// Responder ID as a ASN1 primitive.
+ IResponderID ToASN1Primitive();
}
}
diff --git a/itext/itext.commons/itext/commons/bouncycastle/cert/ocsp/IResponderID.cs b/itext/itext.commons/itext/commons/bouncycastle/cert/ocsp/IResponderID.cs
new file mode 100644
index 0000000000..7199184abc
--- /dev/null
+++ b/itext/itext.commons/itext/commons/bouncycastle/cert/ocsp/IResponderID.cs
@@ -0,0 +1,39 @@
+/*
+This file is part of the iText (R) project.
+Copyright (c) 1998-2024 Apryse Group NV
+Authors: Apryse Software.
+
+This program is offered under a commercial and under the AGPL license.
+For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
+
+AGPL licensing:
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+*/
+using iText.Commons.Bouncycastle.Asn1.X500;
+
+namespace iText.Commons.Bouncycastle.Cert.Ocsp {
+ ///
+ /// This interface represents the wrapper for ResponderID that provides the ability
+ /// to switch between bouncy-castle and bouncy-castle FIPS implementations.
+ ///
+ public interface IResponderID {
+ ///
+ /// Calls actual
+ /// getName
+ /// method for the wrapped BasicOCSPResp object.
+ ///
+ /// wrapped X500NAme.
+ IX500Name GetName();
+ }
+}
diff --git a/itext/itext.commons/itext/commons/utils/Collections/MapExtensions.cs b/itext/itext.commons/itext/commons/utils/Collections/MapExtensions.cs
index df1ad21f57..f44e899d6b 100644
--- a/itext/itext.commons/itext/commons/utils/Collections/MapExtensions.cs
+++ b/itext/itext.commons/itext/commons/utils/Collections/MapExtensions.cs
@@ -38,5 +38,14 @@ public static V ComputeIfAbsent(this IDictionary dict, K key, Func(this IDictionary dict, K key, V defaultValue)
+ {
+ if (!dict.ContainsKey(key))
+ {
+ return defaultValue;
+ }
+ return dict[key];
+ }
}
}
\ No newline at end of file
diff --git a/itext/itext.sign/itext/signatures/DefaultIssuingCertificateRetriever.cs b/itext/itext.sign/itext/signatures/DefaultIssuingCertificateRetriever.cs
index 4afd4f6920..9e152d182c 100644
--- a/itext/itext.sign/itext/signatures/DefaultIssuingCertificateRetriever.cs
+++ b/itext/itext.sign/itext/signatures/DefaultIssuingCertificateRetriever.cs
@@ -66,6 +66,10 @@ public virtual IX509Certificate[] GetCrlIssuerCertificates(IX509Crl crl) {
return new IX509Certificate[0];
}
+ public virtual IX509Certificate[][] GetCrlIssuerCertificatesByName(IX509Crl crl) {
+ return new IX509Certificate[0][];
+ }
+
///
///
///
diff --git a/itext/itext.sign/itext/signatures/IIssuingCertificateRetriever.cs b/itext/itext.sign/itext/signatures/IIssuingCertificateRetriever.cs
index 403414c66a..ba3005e74e 100644
--- a/itext/itext.sign/itext/signatures/IIssuingCertificateRetriever.cs
+++ b/itext/itext.sign/itext/signatures/IIssuingCertificateRetriever.cs
@@ -39,14 +39,23 @@ public interface IIssuingCertificateRetriever {
IX509Certificate[] RetrieveMissingCertificates(IX509Certificate[] chain);
///
- /// Retrieves certificates that can be used to verify the signature on the CRL response using CRL
- /// Authority Information Access (AIA) Extension.
+ /// Retrieves the certificate chain for the certificate that should be used to verify the signature on the
+ /// CRL response using CRL Authority Information Access (AIA) Extension and known certificates.
///
/// CRL response to retrieve issuer for.
/// certificates retrieved from CRL AIA extension or an empty list in case certificates cannot be retrieved.
///
IX509Certificate[] GetCrlIssuerCertificates(IX509Crl crl);
+ ///
+ /// Retrieves the certificate chaind for the certificates that could be used to verify the signature on the
+ /// CRL response using CRL Authority Information Access (AIA) Extension and known certificates.
+ ///
+ /// CRL response to retrieve issuer for.
+ /// certificates retrieved from CRL AIA extension or an empty list in case certificates cannot be retrieved.
+ ///
+ IX509Certificate[][] GetCrlIssuerCertificatesByName(IX509Crl crl);
+
/// Sets trusted certificate list to be used for the missing certificates retrieving by the issuer name.
///
///
diff --git a/itext/itext.sign/itext/signatures/IssuingCertificateRetriever.cs b/itext/itext.sign/itext/signatures/IssuingCertificateRetriever.cs
index efc476716a..cc21beb6de 100644
--- a/itext/itext.sign/itext/signatures/IssuingCertificateRetriever.cs
+++ b/itext/itext.sign/itext/signatures/IssuingCertificateRetriever.cs
@@ -24,9 +24,13 @@ You should have received a copy of the GNU Affero General Public License
using System.Collections.Generic;
using System.IO;
using Microsoft.Extensions.Logging;
+using iText.Bouncycastleconnector;
using iText.Commons;
+using iText.Commons.Bouncycastle;
using iText.Commons.Bouncycastle.Asn1.Ocsp;
using iText.Commons.Bouncycastle.Cert;
+using iText.Commons.Utils;
+using iText.Commons.Utils.Collections;
using iText.Signatures.Logs;
using iText.Signatures.Validation;
@@ -36,13 +40,15 @@ namespace iText.Signatures {
/// default implementation.
///
public class IssuingCertificateRetriever : IIssuingCertificateRetriever {
+ private static readonly IBouncyCastleFactory FACTORY = BouncyCastleFactoryCreator.GetFactory();
+
private static readonly ILogger LOGGER = ITextLogManager.GetLogger(typeof(iText.Signatures.IssuingCertificateRetriever
));
private readonly TrustedCertificatesStore trustedCertificatesStore = new TrustedCertificatesStore();
- private readonly IDictionary knownCertificates = new Dictionary();
+ private readonly IDictionary> knownCertificates = new Dictionary>();
///
/// Creates
@@ -80,10 +86,11 @@ public virtual IX509Certificate[] RetrieveMissingCertificates(IX509Certificate[]
ICollection certificatesFromAIA = ProcessCertificatesFromAIA(url);
if (certificatesFromAIA == null || certificatesFromAIA.IsEmpty()) {
// Retrieve Issuer from the certificate store
- IX509Certificate issuer = trustedCertificatesStore.GetKnownCertificate(lastAddedCert.GetIssuerDN().ToString
- ());
- if (issuer == null) {
- issuer = knownCertificates.Get(lastAddedCert.GetIssuerDN().ToString());
+ IX509Certificate issuer = GetIssuerFromCertificateSet(lastAddedCert, trustedCertificatesStore.GetKnownCertificates
+ (lastAddedCert.GetIssuerDN().ToString()));
+ if (issuer == null || !IsSignedBy(lastAddedCert, issuer)) {
+ issuer = GetIssuerFromCertificateSet(lastAddedCert, knownCertificates.Get(lastAddedCert.GetIssuerDN().ToString
+ ()));
if (issuer == null) {
// Unable to retrieve missing certificates
while (i < chain.Length) {
@@ -104,6 +111,97 @@ public virtual IX509Certificate[] RetrieveMissingCertificates(IX509Certificate[]
return fullChain.ToArray(new IX509Certificate[0]);
}
+ /// This method tries to rebuild certificate issuer chain.
+ ///
+ /// This method tries to rebuild certificate issuer chain. The result contains all possible chains
+ /// starting with the given certificate based on issuer names and public keys.
+ ///
+ ///
+ ///
+ ///
+ /// for which issuer chains shall be built
+ ///
+ /// all possible issuer chains
+ public virtual IList BuildCertificateChains(IX509Certificate certificate) {
+ return BuildCertificateChains(new IX509Certificate[] { certificate });
+ }
+
+ /// This method tries to rebuild certificate issuer chain.
+ ///
+ /// This method tries to rebuild certificate issuer chain. The result contains all possible chains
+ /// starting with the given certificate array based on issuer names and public keys.
+ ///
+ ///
+ ///
+ ///
+ /// array for which issuer chains shall be built
+ ///
+ /// all possible issuer chains
+ public virtual IList BuildCertificateChains(IX509Certificate[] certificate) {
+ IList> allCertificateChains = BuildCertificateChainsList(certificate);
+ IList result = new List(allCertificateChains.Count * 5);
+ foreach (IList chain in allCertificateChains) {
+ JavaCollectionsUtil.Reverse(chain);
+ result.Add(chain.ToArray(new IX509Certificate[0]));
+ }
+ return result;
+ }
+
+ private IList> BuildCertificateChainsList(IX509Certificate[] certificates) {
+ IList> allChains = new List>(BuildCertificateChainsList(certificates
+ [certificates.Length - 1]));
+ foreach (IList issuerChain in allChains) {
+ for (int i = certificates.Length - 2; i >= 0; --i) {
+ issuerChain.Add(certificates[i]);
+ }
+ }
+ return allChains;
+ }
+
+ private IList> BuildCertificateChainsList(IX509Certificate certificate) {
+ if (CertificateUtil.IsSelfSigned(certificate)) {
+ IList> singleChain = new List>();
+ IList chain = new List();
+ chain.Add(certificate);
+ singleChain.Add(chain);
+ return singleChain;
+ }
+ IList> allChains = new List>();
+ // Get missing certificates using AIA Extensions
+ String url = CertificateUtil.GetIssuerCertURL(certificate);
+ ICollection certificatesFromAIA = ProcessCertificatesFromAIA(url);
+ if (certificatesFromAIA != null && !certificatesFromAIA.IsEmpty()) {
+ IList> issuerChains = BuildCertificateChainsList(certificatesFromAIA.ToArray(new IX509Certificate
+ [0]));
+ foreach (IList issuerChain in issuerChains) {
+ issuerChain.Add(certificate);
+ allChains.Add(issuerChain);
+ }
+ }
+ else {
+ ICollection possibleIssuers = trustedCertificatesStore.GetKnownCertificates(certificate.
+ GetIssuerDN().ToString());
+ if (knownCertificates.Get(certificate.GetIssuerDN().ToString()) != null) {
+ possibleIssuers.AddAll(knownCertificates.Get(certificate.GetIssuerDN().ToString()));
+ }
+ if (possibleIssuers.IsEmpty()) {
+ IList> singleChain = new List>();
+ IList chain = new List();
+ chain.Add(certificate);
+ singleChain.Add(chain);
+ return singleChain;
+ }
+ foreach (IX509Certificate possibleIssuer in possibleIssuers) {
+ IList> issuerChains = BuildCertificateChainsList((IX509Certificate)possibleIssuer);
+ foreach (IList issuerChain in issuerChains) {
+ issuerChain.Add(certificate);
+ allChains.Add(issuerChain);
+ }
+ }
+ }
+ return allChains;
+ }
+
/// Retrieve issuer certificate for the provided certificate.
///
///
@@ -115,51 +213,41 @@ public virtual IX509Certificate[] RetrieveMissingCertificates(IX509Certificate[]
///
/// if there is no issuer certificate, or it cannot be retrieved.
///
- public virtual IX509Certificate RetrieveIssuerCertificate(IX509Certificate certificate) {
- IX509Certificate[] certificateChain = RetrieveMissingCertificates(new IX509Certificate[] { certificate });
- if (certificateChain.Length > 1) {
- return certificateChain[1];
+ public virtual IList RetrieveIssuerCertificate(IX509Certificate certificate) {
+ IList result = new List();
+ foreach (IX509Certificate[] certificateChain in BuildCertificateChains((IX509Certificate)certificate)) {
+ if (certificateChain.Length > 1) {
+ result.Add(certificateChain[1]);
+ }
}
- return null;
+ return result;
}
///
- /// Retrieves OCSP responder certificate either from the response certs or
+ /// Retrieves OCSP responder certificate candidates either from the response certs or
/// trusted store in case responder certificate isn't found in /Certs.
///
/// basic OCSP response to get responder certificate for
- /// retrieved OCSP responder certificate or null in case it wasn't found.
- public virtual IX509Certificate RetrieveOCSPResponderCertificate(IBasicOcspResponse ocspResp) {
+ /// retrieved OCSP responder candidates or an empty set in case none were found.
+ public virtual ICollection RetrieveOCSPResponderByNameCertificate(IBasicOcspResponse ocspResp
+ ) {
+ String name = null;
+ name = FACTORY.CreateX500Name(FACTORY.CreateASN1Sequence(ocspResp.GetResponderId().ToASN1Primitive().GetName
+ ().ToASN1Primitive())).GetName();
// Look for the existence of an Authorized OCSP responder inside the cert chain in the ocsp response.
IEnumerable certs = SignUtils.GetCertsFromOcspResponse(ocspResp);
foreach (IX509Certificate cert in certs) {
try {
- if (CertificateUtil.IsSignatureValid(ocspResp, cert)) {
- return cert;
+ if (name.Equals(cert.GetSubjectDN().ToString())) {
+ return JavaCollectionsUtil.Singleton(cert);
}
}
catch (Exception) {
}
}
// Ignore.
- // Certificate chain is not present in the response.
- // Try to verify using trusted store according to RFC 6960 2.2. Response:
- // "The key used to sign the response MUST belong to one of the following:
- // - ...
- // - a Trusted Responder whose public key is trusted by the requester;
- // - ..."
- try {
- foreach (IX509Certificate anchor in trustedCertificatesStore.GetAllTrustedCertificates()) {
- if (CertificateUtil.IsSignatureValid(ocspResp, anchor)) {
- // Certificate from the root store is considered trusted and valid by this method.
- return anchor;
- }
- }
- }
- catch (Exception) {
- }
- // Ignore.
- return null;
+ // Certificate chain is not present in the response, or is does not contain the responder.
+ return trustedCertificatesStore.GetKnownCertificates(name);
}
///
@@ -172,27 +260,59 @@ public virtual IX509Certificate RetrieveOCSPResponderCertificate(IBasicOcspRespo
///
///
public virtual IX509Certificate[] GetCrlIssuerCertificates(IX509Crl crl) {
+ IX509Certificate[][] result = GetCrlIssuerCertificatesGeneric(crl, true);
+ if (result.Length == 0) {
+ return new IX509Certificate[0];
+ }
+ return result[0];
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual IX509Certificate[][] GetCrlIssuerCertificatesByName(IX509Crl crl) {
+ return GetCrlIssuerCertificatesGeneric(crl, false);
+ }
+
+ private IX509Certificate[][] GetCrlIssuerCertificatesGeneric(IX509Crl crl, bool verify) {
// Usually CRLs are signed using CA certificate, so we don’t need to do anything extra and the revocation data
// is already collected. However, it is possible to sign it with any other certificate.
// IssuingDistributionPoint extension: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.5
// Nothing special for the indirect CRLs.
// AIA Extension
+ List matches = new List();
String url = CertificateUtil.GetIssuerCertURL(crl);
IList certificatesFromAIA = (IList)ProcessCertificatesFromAIA(url);
if (certificatesFromAIA == null) {
// Retrieve Issuer from the certificate store
- IX509Certificate issuer = trustedCertificatesStore.GetKnownCertificate(((IX509Crl)crl).GetIssuerDN().ToString
- ());
- if (issuer == null) {
- issuer = knownCertificates.Get(((IX509Crl)crl).GetIssuerDN().ToString());
- if (issuer == null) {
- // Unable to retrieve CRL issuer
- return new IX509Certificate[0];
+ ICollection issuers = trustedCertificatesStore.GetKnownCertificates(((IX509Crl)crl).GetIssuerDN
+ ().ToString());
+ if (issuers == null) {
+ issuers = new HashSet();
+ }
+ IList localIssuers = GetCrlIssuersFromKnownCertificates((IX509Crl)crl);
+ if (localIssuers != null) {
+ issuers.AddAll(localIssuers);
+ }
+ if (issuers.IsEmpty()) {
+ // Unable to retrieve CRL issuer
+ return new IX509Certificate[0][];
+ }
+ foreach (IX509Certificate i in issuers) {
+ if (!verify || IsSignedBy((IX509Crl)crl, i)) {
+ matches.AddAll(BuildCertificateChains((IX509Certificate)i));
}
}
- return RetrieveMissingCertificates(new IX509Certificate[] { issuer });
+ return matches.ToArray(new IX509Certificate[][] { });
}
- return RetrieveMissingCertificates(certificatesFromAIA.ToArray(new IX509Certificate[0]));
+ return BuildCertificateChains(certificatesFromAIA.ToArray(new IX509Certificate[0])).ToArray(new IX509Certificate
+ [][] { });
}
/// Sets trusted certificate list to be used as certificates trusted for any possible usage.
@@ -226,7 +346,10 @@ public virtual void AddTrustedCertificates(ICollection certifi
///
public virtual void AddKnownCertificates(ICollection certificates) {
foreach (IX509Certificate certificate in certificates) {
- knownCertificates.Put(((IX509Certificate)certificate).GetSubjectDN().ToString(), certificate);
+ String name = ((IX509Certificate)certificate).GetSubjectDN().ToString();
+ IList certs = knownCertificates.ComputeIfAbsent(name, (k) => new List(
+ ));
+ certs.Add(certificate);
}
}
@@ -301,5 +424,41 @@ private ICollection ProcessCertificatesFromAIA(String url) {
return null;
}
}
+
+ private static bool IsSignedBy(IX509Certificate certificate, IX509Certificate issuer) {
+ try {
+ certificate.Verify(issuer.GetPublicKey());
+ return true;
+ }
+ catch (Exception) {
+ return false;
+ }
+ }
+
+ private static bool IsSignedBy(IX509Crl crl, IX509Certificate issuer) {
+ try {
+ crl.Verify(issuer.GetPublicKey());
+ return true;
+ }
+ catch (Exception) {
+ return false;
+ }
+ }
+
+ private static IX509Certificate GetIssuerFromCertificateSet(IX509Certificate lastAddedCert, ICollection certs) {
+ if (certs != null) {
+ foreach (IX509Certificate cert in certs) {
+ if (IsSignedBy(lastAddedCert, cert)) {
+ return cert;
+ }
+ }
+ }
+ return null;
+ }
+
+ private IList GetCrlIssuersFromKnownCertificates(IX509Crl crl) {
+ return knownCertificates.Get(crl.GetIssuerDN().ToString());
+ }
}
}
diff --git a/itext/itext.sign/itext/signatures/validation/CRLValidator.cs b/itext/itext.sign/itext/signatures/validation/CRLValidator.cs
index 3bce29d1a3..681633ed90 100644
--- a/itext/itext.sign/itext/signatures/validation/CRLValidator.cs
+++ b/itext/itext.sign/itext/signatures/validation/CRLValidator.cs
@@ -299,47 +299,60 @@ private static int ComputeInterimReasonsMask(IIssuingDistributionPoint issuingDi
private void VerifyCrlIntegrity(ValidationReport report, ValidationContext context, IX509Certificate certificate
, IX509Crl crl, DateTime responseGenerationDate) {
- IX509Certificate[] certs = null;
+ IX509Certificate[][] certificateSets = null;
try {
- certs = certificateRetriever.GetCrlIssuerCertificates(crl);
+ certificateSets = certificateRetriever.GetCrlIssuerCertificatesByName(crl);
}
catch (Exception e) {
report.AddReportItem(new CertificateReportItem(certificate, CRL_CHECK, CRL_ISSUER_REQUEST_FAILED, e, ReportItem.ReportItemStatus
.INDETERMINATE));
return;
}
- if (certs == null || certs.Length == 0) {
+ if (certificateSets == null || certificateSets.Length == 0) {
report.AddReportItem(new CertificateReportItem(certificate, CRL_CHECK, CRL_ISSUER_NOT_FOUND, ReportItem.ReportItemStatus
.INDETERMINATE));
return;
}
- if (JavaUtil.ArraysToEnumerable(certs).Any((c) => c.Equals(certificate))) {
- report.AddReportItem(new CertificateReportItem(certificate, CRL_CHECK, CERTIFICATE_IN_ISSUER_CHAIN, ReportItem.ReportItemStatus
- .INDETERMINATE));
- return;
+ ValidationReport[] candidateReports = new ValidationReport[certificateSets.Length];
+ for (int i = 0; i < certificateSets.Length; i++) {
+ ValidationReport candidateReport = new ValidationReport();
+ candidateReports[i] = candidateReport;
+ IX509Certificate[] certs = certificateSets[i];
+ if (JavaUtil.ArraysAsList(certs).Contains(certificate)) {
+ candidateReport.AddReportItem(new CertificateReportItem(certificate, CRL_CHECK, CERTIFICATE_IN_ISSUER_CHAIN
+ , ReportItem.ReportItemStatus.INDETERMINATE));
+ continue;
+ }
+ IX509Certificate crlIssuer = certs[0];
+ IList crlIssuerRoots = GetRoots(crlIssuer);
+ IList subjectRoots = GetRoots(certificate);
+ if (!crlIssuerRoots.Any((cert) => subjectRoots.Contains(cert))) {
+ candidateReport.AddReportItem(new CertificateReportItem(certificate, CRL_CHECK, CRL_ISSUER_NO_COMMON_ROOT,
+ ReportItem.ReportItemStatus.INDETERMINATE));
+ continue;
+ }
+ SafeCalling.OnExceptionLog(() => crl.Verify(crlIssuer.GetPublicKey()), candidateReport, (e) => new CertificateReportItem
+ (certificate, CRL_CHECK, CRL_INVALID, e, ReportItem.ReportItemStatus.INDETERMINATE));
+ ValidationReport responderReport = new ValidationReport();
+ SafeCalling.OnExceptionLog(() => builder.GetCertificateChainValidator().Validate(responderReport, context.
+ SetCertificateSource(CertificateSource.CRL_ISSUER), (IX509Certificate)crlIssuer, responseGenerationDate
+ ), candidateReport, (e) => new CertificateReportItem(certificate, CRL_CHECK, CRL_ISSUER_CHAIN_FAILED,
+ e, ReportItem.ReportItemStatus.INDETERMINATE));
+ AddResponderValidationReport(candidateReport, responderReport);
+ if (candidateReport.GetValidationResult() == ValidationReport.ValidationResult.VALID) {
+ report.Merge(candidateReport);
+ return;
+ }
}
- IX509Certificate crlIssuer = certs[0];
- IX509Certificate crlIssuerRoot = GetRoot(crlIssuer);
- IX509Certificate subjectRoot = GetRoot(certificate);
- if (!crlIssuerRoot.Equals(subjectRoot)) {
- report.AddReportItem(new CertificateReportItem(certificate, CRL_CHECK, CRL_ISSUER_NO_COMMON_ROOT, ReportItem.ReportItemStatus
- .INDETERMINATE));
- return;
+ // if failed, add all logs
+ foreach (ValidationReport candidateReport in candidateReports) {
+ report.Merge(candidateReport);
}
- SafeCalling.OnExceptionLog(() => crl.Verify(crlIssuer.GetPublicKey()), report, (e) => new CertificateReportItem
- (certificate, CRL_CHECK, CRL_INVALID, e, ReportItem.ReportItemStatus.INDETERMINATE));
- ValidationReport responderReport = new ValidationReport();
- SafeCalling.OnExceptionLog(() => builder.GetCertificateChainValidator().Validate(responderReport, context.
- SetCertificateSource(CertificateSource.CRL_ISSUER), (IX509Certificate)crlIssuer, responseGenerationDate
- ), report, (e) => new CertificateReportItem(certificate, CRL_CHECK, CRL_ISSUER_CHAIN_FAILED, e, ReportItem.ReportItemStatus
- .INDETERMINATE));
- AddResponderValidationReport(report, responderReport);
}
- private IX509Certificate GetRoot(IX509Certificate cert) {
- IX509Certificate[] chain = certificateRetriever.RetrieveMissingCertificates(new IX509Certificate[] { cert }
- );
- return chain[chain.Length - 1];
+ private IList GetRoots(IX509Certificate cert) {
+ IList chains = certificateRetriever.BuildCertificateChains((IX509Certificate)cert);
+ return chains.Select((certArray) => certArray[certArray.Length - 1]).ToList();
}
private static void AddResponderValidationReport(ValidationReport report, ValidationReport responderReport
diff --git a/itext/itext.sign/itext/signatures/validation/CertificateChainValidator.cs b/itext/itext.sign/itext/signatures/validation/CertificateChainValidator.cs
index 0c43de5b6b..8c510611a5 100644
--- a/itext/itext.sign/itext/signatures/validation/CertificateChainValidator.cs
+++ b/itext/itext.sign/itext/signatures/validation/CertificateChainValidator.cs
@@ -305,37 +305,50 @@ private void ValidateRevocationData(ValidationReport report, ValidationContext c
private void ValidateChain(ValidationReport result, ValidationContext context, IX509Certificate certificate
, DateTime validationDate, int certificateChainSize) {
- IX509Certificate issuerCertificate = null;
+ IList issuerCertificates;
try {
- issuerCertificate = (IX509Certificate)certificateRetriever.RetrieveIssuerCertificate(certificate);
+ issuerCertificates = certificateRetriever.RetrieveIssuerCertificate(certificate);
}
catch (Exception e) {
result.AddReportItem(new CertificateReportItem(certificate, CERTIFICATE_CHECK, ISSUER_RETRIEVAL_FAILED, e,
ReportItem.ReportItemStatus.INDETERMINATE));
return;
}
- if (issuerCertificate == null) {
+ if (issuerCertificates.IsEmpty()) {
result.AddReportItem(new CertificateReportItem(certificate, CERTIFICATE_CHECK, MessageFormatUtil.Format(ISSUER_MISSING
, certificate.GetSubjectDN()), ReportItem.ReportItemStatus.INDETERMINATE));
return;
}
- try {
- certificate.Verify(issuerCertificate.GetPublicKey());
- }
- catch (AbstractGeneralSecurityException e) {
- result.AddReportItem(new CertificateReportItem(certificate, CERTIFICATE_CHECK, MessageFormatUtil.Format(ISSUER_CANNOT_BE_VERIFIED
- , issuerCertificate.GetSubjectDN(), certificate.GetSubjectDN()), e, ReportItem.ReportItemStatus.INVALID
- ));
- return;
+ ValidationReport[] candidateReports = new ValidationReport[issuerCertificates.Count];
+ for (int i = 0; i < issuerCertificates.Count; i++) {
+ candidateReports[i] = new ValidationReport();
+ try {
+ certificate.Verify(issuerCertificates[i].GetPublicKey());
+ }
+ catch (AbstractGeneralSecurityException e) {
+ candidateReports[i].AddReportItem(new CertificateReportItem(certificate, CERTIFICATE_CHECK, MessageFormatUtil
+ .Format(ISSUER_CANNOT_BE_VERIFIED, issuerCertificates[i].GetSubjectDN(), certificate.GetSubjectDN()),
+ e, ReportItem.ReportItemStatus.INVALID));
+ continue;
+ }
+ catch (Exception e) {
+ candidateReports[i].AddReportItem(new CertificateReportItem(certificate, CERTIFICATE_CHECK, MessageFormatUtil
+ .Format(ISSUER_VERIFICATION_FAILED, issuerCertificates[i].GetSubjectDN(), certificate.GetSubjectDN()),
+ e, ReportItem.ReportItemStatus.INVALID));
+ continue;
+ }
+ this.Validate(candidateReports[i], context.SetCertificateSource(CertificateSource.CERT_ISSUER), issuerCertificates
+ [i], validationDate, certificateChainSize + 1);
+ if (candidateReports[i].GetValidationResult() == ValidationReport.ValidationResult.VALID) {
+ // We found valid issuer, no need to try other ones.
+ result.Merge(candidateReports[i]);
+ return;
+ }
}
- catch (Exception e) {
- result.AddReportItem(new CertificateReportItem(certificate, CERTIFICATE_CHECK, MessageFormatUtil.Format(ISSUER_VERIFICATION_FAILED
- , issuerCertificate.GetSubjectDN(), certificate.GetSubjectDN()), e, ReportItem.ReportItemStatus.INVALID
- ));
- return;
+ // Valid issuer wasn't found, add all the reports
+ foreach (ValidationReport candidateReport in candidateReports) {
+ result.Merge(candidateReport);
}
- this.Validate(result, context.SetCertificateSource(CertificateSource.CERT_ISSUER), issuerCertificate, validationDate
- , certificateChainSize + 1);
}
}
}
diff --git a/itext/itext.sign/itext/signatures/validation/OCSPValidator.cs b/itext/itext.sign/itext/signatures/validation/OCSPValidator.cs
index 546b19dc1f..6a32859904 100644
--- a/itext/itext.sign/itext/signatures/validation/OCSPValidator.cs
+++ b/itext/itext.sign/itext/signatures/validation/OCSPValidator.cs
@@ -21,6 +21,7 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
using System;
+using System.Collections.Generic;
using iText.Bouncycastleconnector;
using iText.Commons.Bouncycastle;
using iText.Commons.Bouncycastle.Asn1;
@@ -57,6 +58,10 @@ public class OCSPValidator {
internal const String ISSUERS_DO_NOT_MATCH = "OCSP: Issuers don't match.";
//\endcond
+//\cond DO_NOT_DOCUMENT
+ internal const String ISSUER_MISSING = "Issuer certificate wasn't found.";
+//\endcond
+
//\cond DO_NOT_DOCUMENT
internal const String FRESHNESS_CHECK = "OCSP response is not fresh enough: " + "this update: {0}, validation date: {1}, freshness: {2}.";
//\endcond
@@ -74,11 +79,23 @@ public class OCSPValidator {
internal const String OCSP_RESPONDER_NOT_VERIFIED = "OCSP response could not be verified: \" +\n" + " \" Unexpected exception occurred while validating responder certificate.";
//\endcond
+//\cond DO_NOT_DOCUMENT
+ internal const String OCSP_RESPONDER_DID_NOT_SIGN = "OCSP response could not be verified against this responder.";
+//\endcond
+
//\cond DO_NOT_DOCUMENT
internal const String OCSP_RESPONDER_TRUST_NOT_RETRIEVED = "OCSP response could not be verified: \" +\n" +
" \"responder trust state could not be retrieved.";
//\endcond
+//\cond DO_NOT_DOCUMENT
+ internal const String OCSP_RESPONDER_TRUSTED = "Responder certificate is a trusted certificate.";
+//\endcond
+
+//\cond DO_NOT_DOCUMENT
+ internal const String OCSP_RESPONDER_IS_CA = "Responder certificate is the CA certificate.";
+//\endcond
+
//\cond DO_NOT_DOCUMENT
internal const String OCSP_IS_NO_LONGER_VALID = "OCSP is no longer valid: {0} after {1}";
//\endcond
@@ -88,11 +105,13 @@ public class OCSPValidator {
//\endcond
//\cond DO_NOT_DOCUMENT
- internal const String UNABLE_TO_CHECK_IF_ISSUERS_MATCH = "OCSP response could not be verified: Unexpected exception occurred checking if issuers match.";
+ internal const String UNABLE_TO_CHECK_IF_ISSUERS_MATCH = "OCSP response could not be verified: Unexpected exception"
+ + " occurred checking if issuers match.";
//\endcond
//\cond DO_NOT_DOCUMENT
- internal const String UNABLE_TO_RETRIEVE_ISSUER = "OCSP response could not be verified: Unexpected exception occurred while retrieving issuer";
+ internal const String UNABLE_TO_RETRIEVE_ISSUER = "OCSP response could not be verified: Unexpected exception "
+ + "occurred while retrieving issuer";
//\endcond
//\cond DO_NOT_DOCUMENT
@@ -147,79 +166,100 @@ public virtual void Validate(ValidationReport report, ValidationContext context,
.INDETERMINATE));
return;
}
- IX509Certificate issuerCert;
+ IList issuerCerts;
try {
- issuerCert = certificateRetriever.RetrieveIssuerCertificate(certificate);
+ issuerCerts = certificateRetriever.RetrieveIssuerCertificate(certificate);
}
catch (Exception e) {
report.AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, UNABLE_TO_RETRIEVE_ISSUER, e, ReportItem.ReportItemStatus
.INDETERMINATE));
return;
}
- // Check if the issuer of the certID and signCert matches, i.e. check that issuerNameHash and issuerKeyHash
- // fields of the certID is the hash of the issuer's name and public key:
- try {
- if (!CertificateUtil.CheckIfIssuersMatch(singleResp.GetCertID(), (IX509Certificate)issuerCert)) {
- report.AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, ISSUERS_DO_NOT_MATCH, ReportItem.ReportItemStatus
- .INDETERMINATE));
- return;
- }
- }
- catch (Exception e) {
- report.AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, UNABLE_TO_CHECK_IF_ISSUERS_MATCH,
- e, ReportItem.ReportItemStatus.INDETERMINATE));
- return;
- }
- // So, since the issuer name and serial number identify a unique certificate, we found the single response
- // for the provided certificate.
- TimeSpan freshness = properties.GetFreshness(localContext);
- // Check that thisUpdate + freshness < validation.
- if (DateTimeUtil.AddMillisToDate(singleResp.GetThisUpdate(), (long)freshness.TotalMilliseconds).Before(validationDate
- )) {
- report.AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, MessageFormatUtil.Format(FRESHNESS_CHECK
- , singleResp.GetThisUpdate(), validationDate, freshness), ReportItem.ReportItemStatus.INDETERMINATE));
+ if (issuerCerts.IsEmpty()) {
+ report.AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, MessageFormatUtil.Format(ISSUER_MISSING
+ , certificate.GetSubjectDN()), ReportItem.ReportItemStatus.INDETERMINATE));
return;
}
- // If nextUpdate is not set, the responder is indicating that newer revocation information
- // is available all the time.
- if (singleResp.GetNextUpdate() != TimestampConstants.UNDEFINED_TIMESTAMP_DATE && validationDate.After(singleResp
- .GetNextUpdate())) {
- report.AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, MessageFormatUtil.Format(OCSP_IS_NO_LONGER_VALID
- , validationDate, singleResp.GetNextUpdate()), ReportItem.ReportItemStatus.INDETERMINATE));
- return;
- }
- // Check the status of the certificate:
- ICertStatus status = singleResp.GetCertStatus();
- IRevokedCertStatus revokedStatus = BOUNCY_CASTLE_FACTORY.CreateRevokedStatus(status);
- bool isStatusGood = BOUNCY_CASTLE_FACTORY.CreateCertificateStatus().GetGood().Equals(status);
- // Check OCSP Archive Cutoff extension in case OCSP response was generated after the certificate is expired.
- if (isStatusGood && certificate.GetNotAfter().Before(ocspResp.GetProducedAt())) {
- DateTime startExpirationDate = GetArchiveCutoffExtension(ocspResp);
- if (TimestampConstants.UNDEFINED_TIMESTAMP_DATE == startExpirationDate || certificate.GetNotAfter().Before
- (startExpirationDate)) {
- report.AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, MessageFormatUtil.Format(CERT_IS_EXPIRED
- , certificate.GetNotAfter()), ReportItem.ReportItemStatus.INDETERMINATE));
- return;
+ ValidationReport[] candidateReports = new ValidationReport[issuerCerts.Count];
+ for (int i = 0; i < issuerCerts.Count; i++) {
+ candidateReports[i] = new ValidationReport();
+ // Check if the issuer of the certID and signCert matches, i.e. check that issuerNameHash and issuerKeyHash
+ // fields of the certID is the hash of the issuer's name and public key:
+ try {
+ if (!CertificateUtil.CheckIfIssuersMatch(singleResp.GetCertID(), issuerCerts[i])) {
+ candidateReports[i].AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, ISSUERS_DO_NOT_MATCH,
+ ReportItem.ReportItemStatus.INDETERMINATE));
+ continue;
+ }
}
- }
- if (isStatusGood || (revokedStatus != null && validationDate.Before(revokedStatus.GetRevocationTime()))) {
- // Check if the OCSP response is genuine.
- VerifyOcspResponder(report, localContext, ocspResp, (IX509Certificate)issuerCert, responseGenerationDate);
- if (!isStatusGood) {
- report.AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, MessageFormatUtil.Format(SignLogMessageConstant
- .VALID_CERTIFICATE_IS_REVOKED, revokedStatus.GetRevocationTime()), ReportItem.ReportItemStatus.INFO));
+ catch (Exception e) {
+ candidateReports[i].AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, UNABLE_TO_CHECK_IF_ISSUERS_MATCH
+ , e, ReportItem.ReportItemStatus.INDETERMINATE));
+ continue;
}
- }
- else {
- if (revokedStatus != null) {
- report.AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, CERT_IS_REVOKED, ReportItem.ReportItemStatus
- .INVALID));
+ // So, since the issuer name and serial number identify a unique certificate, we found the single response
+ // for the provided certificate.
+ TimeSpan freshness = properties.GetFreshness(localContext);
+ // Check that thisUpdate + freshness < validation.
+ if (DateTimeUtil.AddMillisToDate(singleResp.GetThisUpdate(), (long)freshness.TotalMilliseconds).Before(validationDate
+ )) {
+ candidateReports[i].AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, MessageFormatUtil.Format
+ (FRESHNESS_CHECK, singleResp.GetThisUpdate(), validationDate, freshness), ReportItem.ReportItemStatus.
+ INDETERMINATE));
+ continue;
+ }
+ // If nextUpdate is not set, the responder is indicating that newer revocation information
+ // is available all the time.
+ if (singleResp.GetNextUpdate() != TimestampConstants.UNDEFINED_TIMESTAMP_DATE && validationDate.After(singleResp
+ .GetNextUpdate())) {
+ candidateReports[i].AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, MessageFormatUtil.Format
+ (OCSP_IS_NO_LONGER_VALID, validationDate, singleResp.GetNextUpdate()), ReportItem.ReportItemStatus.INDETERMINATE
+ ));
+ continue;
+ }
+ // Check the status of the certificate:
+ ICertStatus status = singleResp.GetCertStatus();
+ IRevokedCertStatus revokedStatus = BOUNCY_CASTLE_FACTORY.CreateRevokedStatus(status);
+ bool isStatusGood = BOUNCY_CASTLE_FACTORY.CreateCertificateStatus().GetGood().Equals(status);
+ // Check OCSP Archive Cutoff extension in case OCSP response was generated after the certificate is expired.
+ if (isStatusGood && certificate.GetNotAfter().Before(ocspResp.GetProducedAt())) {
+ DateTime startExpirationDate = GetArchiveCutoffExtension(ocspResp);
+ if (TimestampConstants.UNDEFINED_TIMESTAMP_DATE == startExpirationDate || certificate.GetNotAfter().Before
+ (startExpirationDate)) {
+ candidateReports[i].AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, MessageFormatUtil.Format
+ (CERT_IS_EXPIRED, certificate.GetNotAfter()), ReportItem.ReportItemStatus.INDETERMINATE));
+ continue;
+ }
+ }
+ if (isStatusGood || (revokedStatus != null && validationDate.Before(revokedStatus.GetRevocationTime()))) {
+ // Check if the OCSP response is genuine.
+ VerifyOcspResponder(candidateReports[i], localContext, ocspResp, issuerCerts[i], responseGenerationDate);
+ if (!isStatusGood) {
+ candidateReports[i].AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, MessageFormatUtil.Format
+ (SignLogMessageConstant.VALID_CERTIFICATE_IS_REVOKED, revokedStatus.GetRevocationTime()), ReportItem.ReportItemStatus
+ .INFO));
+ }
}
else {
- report.AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, CERT_STATUS_IS_UNKNOWN, ReportItem.ReportItemStatus
- .INDETERMINATE));
+ if (revokedStatus != null) {
+ candidateReports[i].AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, CERT_IS_REVOKED, ReportItem.ReportItemStatus
+ .INVALID));
+ }
+ else {
+ candidateReports[i].AddReportItem(new CertificateReportItem(certificate, OCSP_CHECK, CERT_STATUS_IS_UNKNOWN
+ , ReportItem.ReportItemStatus.INDETERMINATE));
+ }
+ }
+ if (candidateReports[i].GetValidationResult() == ValidationReport.ValidationResult.VALID) {
+ // We found valid issuer, no need to try other ones.
+ report.Merge(candidateReports[i]);
+ return;
}
}
+ // Valid issuer wasn't found, add all the reports
+ foreach (ValidationReport candidateReport in candidateReports) {
+ report.Merge(candidateReport);
+ }
}
/// Verifies if an OCSP response is genuine.
@@ -239,90 +279,87 @@ public virtual void Validate(ValidationReport report, ValidationContext context,
private void VerifyOcspResponder(ValidationReport report, ValidationContext context, IBasicOcspResponse ocspResp
, IX509Certificate issuerCert, DateTime responseGenerationDate) {
ValidationContext localContext = context.SetCertificateSource(CertificateSource.OCSP_ISSUER);
- ValidationReport responderReport = new ValidationReport();
// OCSP response might be signed by the issuer certificate or
// the Authorized OCSP responder certificate containing the id-kp-OCSPSigning extended key usage extension.
- IX509Certificate responderCert = null;
// First check if the issuer certificate signed the response since it is expected to be the most common case:
+ // the CA will already be validated by the chain validator
if (CertificateUtil.IsSignatureValid(ocspResp, issuerCert)) {
- responderCert = issuerCert;
+ report.AddReportItem(new CertificateReportItem(issuerCert, OCSP_CHECK, OCSP_RESPONDER_IS_CA, ReportItem.ReportItemStatus
+ .INFO));
+ return;
}
// If the issuer certificate didn't sign the ocsp response, look for authorized ocsp responses
// from the properties or from the certificate chain received with response.
- if (responderCert == null) {
- try {
- responderCert = (IX509Certificate)certificateRetriever.RetrieveOCSPResponderCertificate(ocspResp);
- }
- catch (Exception e) {
- report.AddReportItem(new CertificateReportItem(issuerCert, OCSP_CHECK, OCSP_RESPONDER_NOT_RETRIEVED, e, ReportItem.ReportItemStatus
- .INDETERMINATE));
- return;
- }
- if (responderCert == null) {
- report.AddReportItem(new CertificateReportItem(issuerCert, OCSP_CHECK, OCSP_COULD_NOT_BE_VERIFIED, ReportItem.ReportItemStatus
- .INDETERMINATE));
- return;
+ ICollection candidates = SafeCalling.OnRuntimeExceptionLog(() => certificateRetriever.RetrieveOCSPResponderByNameCertificate
+ (ocspResp), JavaCollectionsUtil.EmptySet(), report, (e) => new CertificateReportItem
+ (issuerCert, OCSP_CHECK, OCSP_RESPONDER_NOT_RETRIEVED, e, ReportItem.ReportItemStatus.INDETERMINATE));
+ if (candidates.IsEmpty()) {
+ report.AddReportItem(new CertificateReportItem(issuerCert, OCSP_CHECK, OCSP_COULD_NOT_BE_VERIFIED, ReportItem.ReportItemStatus
+ .INDETERMINATE));
+ return;
+ }
+ ValidationReport[] candidateReports = new ValidationReport[candidates.Count];
+ int reportIndex = 0;
+ foreach (IX509Certificate cert in candidates) {
+ IX509Certificate responderCert = (IX509Certificate)cert;
+ ValidationReport candidateReport = new ValidationReport();
+ candidateReports[reportIndex++] = candidateReport;
+ // if the response was not signed by this candidate we can stop further processing
+ if (!CertificateUtil.IsSignatureValid(ocspResp, responderCert)) {
+ candidateReport.AddReportItem(new CertificateReportItem(responderCert, OCSP_CHECK, OCSP_RESPONDER_DID_NOT_SIGN
+ , ReportItem.ReportItemStatus.INDETERMINATE));
+ continue;
}
- bool needsToBeSignedByIssuer = false;
+ // if the responder is trusted validation is successful
try {
- needsToBeSignedByIssuer = (!certificateRetriever.IsCertificateTrusted(responderCert) && !certificateRetriever
- .GetTrustedCertificatesStore().IsCertificateTrustedForOcsp(responderCert));
+ if (certificateRetriever.GetTrustedCertificatesStore().IsCertificateTrustedForOcsp(responderCert) || certificateRetriever
+ .GetTrustedCertificatesStore().IsCertificateGenerallyTrusted(responderCert)) {
+ candidateReport.AddReportItem(new CertificateReportItem(responderCert, OCSP_CHECK, OCSP_RESPONDER_TRUSTED,
+ ReportItem.ReportItemStatus.INFO));
+ report.Merge(candidateReport);
+ return;
+ }
}
catch (Exception e) {
report.AddReportItem(new CertificateReportItem(responderCert, OCSP_CHECK, OCSP_RESPONDER_TRUST_NOT_RETRIEVED
, e, ReportItem.ReportItemStatus.INDETERMINATE));
- return;
+ continue;
}
- if (needsToBeSignedByIssuer) {
- // RFC 6960 4.2.2.2. Authorized Responders:
- // "Systems relying on OCSP responses MUST recognize a delegation certificate as being issued
- // by the CA that issued the certificate in question only if the delegation certificate and the
- // certificate being checked for revocation were signed by the same key."
- // and "This certificate MUST be issued directly by the CA that is identified in the request".
- try {
- responderCert.Verify(issuerCert.GetPublicKey());
- }
- catch (Exception e) {
- report.AddReportItem(new CertificateReportItem(responderCert, OCSP_CHECK, INVALID_OCSP, e, ReportItem.ReportItemStatus
- .INVALID));
- return;
- }
- // Validating of the ocsp signer's certificate (responderCert) described in the
- // RFC6960 4.2.2.2.1. Revocation Checking of an Authorized Responder.
- try {
- builder.GetCertificateChainValidator().Validate(responderReport, localContext, responderCert, responseGenerationDate
- );
- }
- catch (Exception e) {
- report.AddReportItem(new CertificateReportItem(responderCert, OCSP_CHECK, OCSP_RESPONDER_NOT_VERIFIED, e,
- ReportItem.ReportItemStatus.INDETERMINATE));
- return;
- }
+ // RFC 6960 4.2.2.2. Authorized Responders:
+ // "Systems relying on OCSP responses MUST recognize a delegation certificate as being issued
+ // by the CA that issued the certificate in question only if the delegation certificate and the
+ // certificate being checked for revocation were signed by the same key."
+ // and "This certificate MUST be issued directly by the CA that is identified in the request".
+ try {
+ responderCert.Verify(issuerCert.GetPublicKey());
}
- else {
- try {
- builder.GetCertificateChainValidator().Validate(responderReport, localContext.SetCertificateSource(CertificateSource
- .TRUSTED), responderCert, responseGenerationDate);
- }
- catch (Exception e) {
- report.AddReportItem(new CertificateReportItem(responderCert, OCSP_CHECK, OCSP_RESPONDER_NOT_VERIFIED, e,
- ReportItem.ReportItemStatus.INDETERMINATE));
- return;
- }
+ catch (Exception e) {
+ candidateReport.AddReportItem(new CertificateReportItem(responderCert, OCSP_CHECK, INVALID_OCSP, e, ReportItem.ReportItemStatus
+ .INVALID));
+ continue;
}
- }
- else {
+ // Validating of the ocsp signer's certificate (responderCert) described in the
+ // RFC6960 4.2.2.2.1. Revocation Checking of an Authorized Responder.
+ ValidationReport responderReport = new ValidationReport();
try {
- builder.GetCertificateChainValidator().Validate(responderReport, localContext.SetCertificateSource(CertificateSource
- .CERT_ISSUER), responderCert, responseGenerationDate);
+ builder.GetCertificateChainValidator().Validate(responderReport, localContext, responderCert, responseGenerationDate
+ );
}
catch (Exception e) {
- report.AddReportItem(new CertificateReportItem(responderCert, OCSP_CHECK, OCSP_RESPONDER_NOT_VERIFIED, e,
- ReportItem.ReportItemStatus.INDETERMINATE));
+ candidateReport.AddReportItem(new CertificateReportItem(responderCert, OCSP_CHECK, OCSP_RESPONDER_NOT_VERIFIED
+ , e, ReportItem.ReportItemStatus.INDETERMINATE));
+ continue;
+ }
+ AddResponderValidationReport(candidateReport, responderReport);
+ if (candidateReport.GetValidationResult() == ValidationReport.ValidationResult.VALID) {
+ AddResponderValidationReport(report, candidateReport);
return;
}
}
- AddResponderValidationReport(report, responderReport);
+ //if we get here, none of the candidates were successful
+ foreach (ValidationReport subReport in candidateReports) {
+ report.Merge(subReport);
+ }
}
private static void AddResponderValidationReport(ValidationReport report, ValidationReport responderReport
diff --git a/itext/itext.sign/itext/signatures/validation/RevocationDataValidator.cs b/itext/itext.sign/itext/signatures/validation/RevocationDataValidator.cs
index ce245731ea..11aed3377f 100644
--- a/itext/itext.sign/itext/signatures/validation/RevocationDataValidator.cs
+++ b/itext/itext.sign/itext/signatures/validation/RevocationDataValidator.cs
@@ -97,6 +97,10 @@ public class RevocationDataValidator {
internal const String CRL_VALIDATOR_FAILURE = "Unexpected exception occurred in CRL validator.";
//\endcond
+//\cond DO_NOT_DOCUMENT
+ internal const String UNABLE_TO_RETRIEVE_REV_DATA_ONLINE = "Online revocation data wasn't generated: Unexpected exception occurred.";
+//\endcond
+
private static readonly IBouncyCastleFactory BOUNCY_CASTLE_FACTORY = BouncyCastleFactoryCreator.GetFactory
();
@@ -233,7 +237,13 @@ public virtual void Validate(ValidationReport report, ValidationContext context,
>();
IList onlineOcspResponses = new List();
- TryToFetchRevInfoOnline(report, context, certificate, onlineCrlResponses, onlineOcspResponses);
+ try {
+ TryToFetchRevInfoOnline(report, context, certificate, onlineCrlResponses, onlineOcspResponses);
+ }
+ catch (Exception e) {
+ report.AddReportItem(new CertificateReportItem(certificate, REVOCATION_DATA_CHECK, UNABLE_TO_RETRIEVE_REV_DATA_ONLINE
+ , e, ReportItem.ReportItemStatus.INFO));
+ }
if (!onlineCrlResponses.IsEmpty() || !onlineOcspResponses.IsEmpty()) {
// Merge the report excluding NO_REVOCATION_DATA message.
foreach (ReportItem reportItem in revDataValidationReport.GetLogs()) {
@@ -330,9 +340,9 @@ private void ValidateRevocationData(ValidationReport report, ValidationContext c
report, ValidationContext context, IX509Certificate certificate) {
IList ocspResponses = new List();
- IX509Certificate issuerCert;
+ IList issuerCerts;
try {
- issuerCert = (IX509Certificate)certificateRetriever.RetrieveIssuerCertificate(certificate);
+ issuerCerts = certificateRetriever.RetrieveIssuerCertificate(certificate);
}
catch (Exception e) {
report.AddReportItem(new CertificateReportItem(certificate, REVOCATION_DATA_CHECK, ISSUER_RETRIEVAL_FAILED
@@ -349,24 +359,26 @@ private void ValidateRevocationData(ValidationReport report, ValidationContext c
}
}
else {
- byte[] basicOcspRespBytes = null;
- basicOcspRespBytes = SafeCalling.OnRuntimeExceptionLog(() => ocspClient.GetEncoded(certificate, issuerCert
- , null), null, report, (e) => new CertificateReportItem(certificate, REVOCATION_DATA_CHECK, MessageFormatUtil
- .Format(OCSP_CLIENT_FAILURE, ocspClient), e, ReportItem.ReportItemStatus.INFO));
- if (basicOcspRespBytes != null) {
- try {
- IBasicOcspResponse basicOCSPResp = BOUNCY_CASTLE_FACTORY.CreateBasicOCSPResponse(BOUNCY_CASTLE_FACTORY.CreateASN1Primitive
- (basicOcspRespBytes));
- FillOcspResponses(ocspResponses, basicOCSPResp, DateTimeUtil.GetCurrentUtcTime(), TimeBasedContext.PRESENT
- );
- }
- catch (System.IO.IOException e) {
- report.AddReportItem(new ReportItem(REVOCATION_DATA_CHECK, MessageFormatUtil.Format(CANNOT_PARSE_OCSP, ocspClient
- ), e, ReportItem.ReportItemStatus.INFO));
- }
- catch (Exception e) {
- report.AddReportItem(new ReportItem(REVOCATION_DATA_CHECK, MessageFormatUtil.Format(CANNOT_PARSE_OCSP, ocspClient
- ), e, ReportItem.ReportItemStatus.INFO));
+ foreach (IX509Certificate issuerCert in issuerCerts) {
+ byte[] basicOcspRespBytes = null;
+ basicOcspRespBytes = SafeCalling.OnRuntimeExceptionLog(() => ocspClient.GetEncoded(certificate, issuerCert
+ , null), null, report, (e) => new CertificateReportItem(certificate, REVOCATION_DATA_CHECK, MessageFormatUtil
+ .Format(OCSP_CLIENT_FAILURE, ocspClient), e, ReportItem.ReportItemStatus.INFO));
+ if (basicOcspRespBytes != null) {
+ try {
+ IBasicOcspResponse basicOCSPResp = BOUNCY_CASTLE_FACTORY.CreateBasicOCSPResponse(BOUNCY_CASTLE_FACTORY.CreateASN1Primitive
+ (basicOcspRespBytes));
+ FillOcspResponses(ocspResponses, basicOCSPResp, DateTimeUtil.GetCurrentUtcTime(), TimeBasedContext.PRESENT
+ );
+ }
+ catch (System.IO.IOException e) {
+ report.AddReportItem(new ReportItem(REVOCATION_DATA_CHECK, MessageFormatUtil.Format(CANNOT_PARSE_OCSP, ocspClient
+ ), e, ReportItem.ReportItemStatus.INFO));
+ }
+ catch (Exception e) {
+ report.AddReportItem(new ReportItem(REVOCATION_DATA_CHECK, MessageFormatUtil.Format(CANNOT_PARSE_OCSP, ocspClient
+ ), e, ReportItem.ReportItemStatus.INFO));
+ }
}
}
}
@@ -374,14 +386,16 @@ private void ValidateRevocationData(ValidationReport report, ValidationContext c
SignatureValidationProperties.OnlineFetching onlineFetching = properties.GetRevocationOnlineFetching(context
.SetValidatorContext(ValidatorContext.OCSP_VALIDATOR));
if (SignatureValidationProperties.OnlineFetching.ALWAYS_FETCH == onlineFetching) {
- SafeCalling.OnRuntimeExceptionLog(() => {
- IBasicOcspResponse basicOCSPResp = new OcspClientBouncyCastle().GetBasicOCSPResp(certificate, issuerCert,
- null);
- FillOcspResponses(ocspResponses, basicOCSPResp, DateTimeUtil.GetCurrentUtcTime(), TimeBasedContext.PRESENT
- );
+ foreach (IX509Certificate issuerCert in issuerCerts) {
+ SafeCalling.OnRuntimeExceptionLog(() => {
+ IBasicOcspResponse basicOCSPResp = new OcspClientBouncyCastle().GetBasicOCSPResp(certificate, issuerCert,
+ null);
+ FillOcspResponses(ocspResponses, basicOCSPResp, DateTimeUtil.GetCurrentUtcTime(), TimeBasedContext.PRESENT
+ );
+ }
+ , report, (e) => new CertificateReportItem(certificate, REVOCATION_DATA_CHECK, MessageFormatUtil.Format(OCSP_CLIENT_FAILURE
+ , "OcspClientBouncyCastle"), e, ReportItem.ReportItemStatus.INDETERMINATE));
}
- , report, (e) => new CertificateReportItem(certificate, REVOCATION_DATA_CHECK, MessageFormatUtil.Format(OCSP_CLIENT_FAILURE
- , "OcspClientBouncyCastle"), e, ReportItem.ReportItemStatus.INDETERMINATE));
}
return ocspResponses;
}
@@ -415,19 +429,21 @@ private void TryToFetchRevInfoOnline(ValidationReport report, ValidationContext
SignatureValidationProperties.OnlineFetching ocspOnlineFetching = properties.GetRevocationOnlineFetching(context
.SetValidatorContext(ValidatorContext.OCSP_VALIDATOR));
if (SignatureValidationProperties.OnlineFetching.FETCH_IF_NO_OTHER_DATA_AVAILABLE == ocspOnlineFetching) {
- SafeCalling.OnRuntimeExceptionLog(() => {
- IBasicOcspResponse basicOCSPResp = new OcspClientBouncyCastle().GetBasicOCSPResp(certificate, (IX509Certificate
- )certificateRetriever.RetrieveIssuerCertificate(certificate), null);
- IList ocspResponses = new List();
- FillOcspResponses(ocspResponses, basicOCSPResp, DateTimeUtil.GetCurrentUtcTime(), TimeBasedContext.PRESENT
- );
- // Sort all the OCSP responses available based on the most recent revocation data.
- onlineOcspResponses.AddAll(ocspResponses.Sorted((o1, o2) => o2.singleResp.GetThisUpdate().CompareTo(o1.singleResp
- .GetThisUpdate())).ToList());
+ foreach (IX509Certificate issuerCert in certificateRetriever.RetrieveIssuerCertificate(certificate)) {
+ SafeCalling.OnRuntimeExceptionLog(() => {
+ IBasicOcspResponse basicOCSPResp = new OcspClientBouncyCastle().GetBasicOCSPResp(certificate, issuerCert,
+ null);
+ IList ocspResponses = new List();
+ FillOcspResponses(ocspResponses, basicOCSPResp, DateTimeUtil.GetCurrentUtcTime(), TimeBasedContext.PRESENT
+ );
+ // Sort all the OCSP responses available based on the most recent revocation data.
+ onlineOcspResponses.AddAll(ocspResponses.Sorted((o1, o2) => o2.singleResp.GetThisUpdate().CompareTo(o1.singleResp
+ .GetThisUpdate())).ToList());
+ }
+ , report, (e) => new CertificateReportItem(certificate, REVOCATION_DATA_CHECK, MessageFormatUtil.Format(OCSP_CLIENT_FAILURE
+ , "OcspClientBouncyCastle"), e, ReportItem.ReportItemStatus.INDETERMINATE));
}
- , report, (e) => new CertificateReportItem(certificate, REVOCATION_DATA_CHECK, MessageFormatUtil.Format(OCSP_CLIENT_FAILURE
- , "OcspClientBouncyCastle"), e, ReportItem.ReportItemStatus.INDETERMINATE));
}
}
diff --git a/itext/itext.sign/itext/signatures/validation/TrustedCertificatesStore.cs b/itext/itext.sign/itext/signatures/validation/TrustedCertificatesStore.cs
index dffea35280..0117a37df5 100644
--- a/itext/itext.sign/itext/signatures/validation/TrustedCertificatesStore.cs
+++ b/itext/itext.sign/itext/signatures/validation/TrustedCertificatesStore.cs
@@ -23,25 +23,27 @@ You should have received a copy of the GNU Affero General Public License
using System;
using System.Collections.Generic;
using iText.Commons.Bouncycastle.Cert;
+using iText.Commons.Utils;
+using iText.Commons.Utils.Collections;
namespace iText.Signatures.Validation {
/// Trusted certificates storage class to be used to configure trusted certificates in a particular way.
///
public class TrustedCertificatesStore {
- private readonly IDictionary generallyTrustedCertificates = new Dictionary();
+ private readonly IDictionary> generallyTrustedCertificates = new Dictionary
+ >();
- private readonly IDictionary ocspTrustedCertificates = new Dictionary();
+ private readonly IDictionary> ocspTrustedCertificates = new Dictionary
+ >();
- private readonly IDictionary timestampTrustedCertificates = new Dictionary();
+ private readonly IDictionary> timestampTrustedCertificates = new Dictionary
+ >();
- private readonly IDictionary crlTrustedCertificates = new Dictionary();
+ private readonly IDictionary> crlTrustedCertificates = new Dictionary
+ >();
- private readonly IDictionary caTrustedCertificates = new Dictionary();
+ private readonly IDictionary> caTrustedCertificates = new Dictionary
+ >();
/// Add collection of certificates to be trusted for any possible usage.
///
@@ -53,7 +55,7 @@ public class TrustedCertificatesStore {
///
public virtual void AddGenerallyTrustedCertificates(ICollection certificates) {
foreach (IX509Certificate certificate in certificates) {
- generallyTrustedCertificates.Put(((IX509Certificate)certificate).GetSubjectDN().ToString(), certificate);
+ AddCertificateToMap(certificate, generallyTrustedCertificates);
}
}
@@ -72,7 +74,7 @@ public virtual void AddGenerallyTrustedCertificates(ICollection
public virtual void AddOcspTrustedCertificates(ICollection certificates) {
foreach (IX509Certificate certificate in certificates) {
- ocspTrustedCertificates.Put(((IX509Certificate)certificate).GetSubjectDN().ToString(), certificate);
+ AddCertificateToMap(certificate, ocspTrustedCertificates);
}
}
@@ -91,7 +93,7 @@ public virtual void AddOcspTrustedCertificates(ICollection cer
///
public virtual void AddCrlTrustedCertificates(ICollection certificates) {
foreach (IX509Certificate certificate in certificates) {
- crlTrustedCertificates.Put(((IX509Certificate)certificate).GetSubjectDN().ToString(), certificate);
+ AddCertificateToMap(certificate, crlTrustedCertificates);
}
}
@@ -110,7 +112,7 @@ public virtual void AddCrlTrustedCertificates(ICollection cert
///
public virtual void AddTimestampTrustedCertificates(ICollection certificates) {
foreach (IX509Certificate certificate in certificates) {
- timestampTrustedCertificates.Put(((IX509Certificate)certificate).GetSubjectDN().ToString(), certificate);
+ AddCertificateToMap(certificate, timestampTrustedCertificates);
}
}
@@ -128,7 +130,7 @@ public virtual void AddTimestampTrustedCertificates(ICollection
public virtual void AddCATrustedCertificates(ICollection certificates) {
foreach (IX509Certificate certificate in certificates) {
- caTrustedCertificates.Put(((IX509Certificate)certificate).GetSubjectDN().ToString(), certificate);
+ AddCertificateToMap(certificate, caTrustedCertificates);
}
}
@@ -146,7 +148,7 @@ public virtual void AddCATrustedCertificates(ICollection certi
/// otherwise
///
public virtual bool IsCertificateGenerallyTrusted(IX509Certificate certificate) {
- return generallyTrustedCertificates.ContainsKey(((IX509Certificate)certificate).GetSubjectDN().ToString());
+ return MapContainsCertificate(certificate, generallyTrustedCertificates);
}
/// Check if provided certificate is configured to be trusted for OCSP response generation.
@@ -163,7 +165,7 @@ public virtual bool IsCertificateGenerallyTrusted(IX509Certificate certificate)
/// otherwise
///
public virtual bool IsCertificateTrustedForOcsp(IX509Certificate certificate) {
- return ocspTrustedCertificates.ContainsKey(((IX509Certificate)certificate).GetSubjectDN().ToString());
+ return MapContainsCertificate(certificate, ocspTrustedCertificates);
}
/// Check if provided certificate is configured to be trusted for CRL generation.
@@ -180,7 +182,7 @@ public virtual bool IsCertificateTrustedForOcsp(IX509Certificate certificate) {
/// otherwise
///
public virtual bool IsCertificateTrustedForCrl(IX509Certificate certificate) {
- return crlTrustedCertificates.ContainsKey(((IX509Certificate)certificate).GetSubjectDN().ToString());
+ return MapContainsCertificate(certificate, crlTrustedCertificates);
}
/// Check if provided certificate is configured to be trusted for timestamp generation.
@@ -197,7 +199,7 @@ public virtual bool IsCertificateTrustedForCrl(IX509Certificate certificate) {
/// otherwise
///
public virtual bool IsCertificateTrustedForTimestamp(IX509Certificate certificate) {
- return timestampTrustedCertificates.ContainsKey(((IX509Certificate)certificate).GetSubjectDN().ToString());
+ return MapContainsCertificate(certificate, timestampTrustedCertificates);
}
/// Check if provided certificate is configured to be trusted to be CA.
@@ -214,10 +216,10 @@ public virtual bool IsCertificateTrustedForTimestamp(IX509Certificate certificat
/// otherwise
///
public virtual bool IsCertificateTrustedForCA(IX509Certificate certificate) {
- return caTrustedCertificates.ContainsKey(((IX509Certificate)certificate).GetSubjectDN().ToString());
+ return MapContainsCertificate(certificate, caTrustedCertificates);
}
- /// Get certificate, if any, which is trusted for any usage, which corresponds to the provided certificate name.
+ /// Get certificates, if any, which is trusted for any usage, which corresponds to the provided certificate name.
///
///
///
@@ -225,16 +227,17 @@ public virtual bool IsCertificateTrustedForCA(IX509Certificate certificate) {
/// certificate name
///
///
- ///
+ /// set of
///
- /// which corresponds to the provided certificate name
+ /// which correspond to the provided certificate name
///
- public virtual IX509Certificate GetGenerallyTrustedCertificate(String certificateName) {
- return generallyTrustedCertificates.Get(certificateName);
+ public virtual ICollection GetGenerallyTrustedCertificates(String certificateName) {
+ return generallyTrustedCertificates.GetOrDefault(certificateName, JavaCollectionsUtil.EmptySet());
}
///
- /// Get certificate, if any, which is trusted for OCSP response generation,
+ /// Get certificates, if any, which is trusted for OCSP response generation,
/// which corresponds to the provided certificate name.
///
///
@@ -243,28 +246,32 @@ public virtual IX509Certificate GetGenerallyTrustedCertificate(String certificat
/// certificate name
///
///
- ///
+ /// set of
///
- /// which corresponds to the provided certificate name
+ /// which correspond to the provided certificate name
///
- public virtual IX509Certificate GetCertificateTrustedForOcsp(String certificateName) {
- return ocspTrustedCertificates.Get(certificateName);
+ public virtual ICollection GetCertificatesTrustedForOcsp(String certificateName) {
+ return ocspTrustedCertificates.GetOrDefault(certificateName, JavaCollectionsUtil.EmptySet());
}
- /// Get certificate, if any, which is trusted for CRL generation, which corresponds to the provided certificate name.
- ///
+ ///
+ /// Get certificates, if any, which is trusted for CRL generation,
+ /// which corresponds to the provided certificate name.
+ ///
///
///
///
/// certificate name
///
///
- ///
+ /// set of
///
- /// which corresponds to the provided certificate name
+ /// which correspond to the provided certificate name
///
- public virtual IX509Certificate GetCertificateTrustedForCrl(String certificateName) {
- return crlTrustedCertificates.Get(certificateName);
+ public virtual ICollection GetCertificatesTrustedForCrl(String certificateName) {
+ return crlTrustedCertificates.GetOrDefault(certificateName, JavaCollectionsUtil.EmptySet
+ ());
}
///
@@ -277,55 +284,53 @@ public virtual IX509Certificate GetCertificateTrustedForCrl(String certificateNa
/// certificate name
///
///
- ///
+ /// set of
///
- /// which corresponds to the provided certificate name
+ /// which correspond to the provided certificate name
///
- public virtual IX509Certificate GetCertificateTrustedForTimestamp(String certificateName) {
- return timestampTrustedCertificates.Get(certificateName);
+ public virtual ICollection GetCertificatesTrustedForTimestamp(String certificateName) {
+ return timestampTrustedCertificates.GetOrDefault(certificateName, JavaCollectionsUtil.EmptySet());
}
- /// Get certificate, if any, which is trusted to be a CA, which corresponds to the provided certificate name.
- ///
+ ///
+ /// Get certificates, if any,
+ /// which is trusted to be a CA, which corresponds to the provided certificate name.
+ ///
///
///
///
/// certificate name
///
///
- ///
+ /// set of
///
- /// which corresponds to the provided certificate name
+ /// which correspond to the provided certificate name
///
- public virtual IX509Certificate GetCertificateTrustedForCA(String certificateName) {
- return caTrustedCertificates.Get(certificateName);
+ public virtual ICollection GetCertificatesTrustedForCA(String certificateName) {
+ return caTrustedCertificates.GetOrDefault(certificateName, JavaCollectionsUtil.EmptySet(
+ ));
}
- /// Get certificate, if any, which corresponds to the provided certificate name.
+ /// Get certificates, if any, which corresponds to the provided certificate name.
///
///
///
/// certificate name
///
///
- ///
+ /// set of
///
- /// which corresponds to the provided certificate name
+ /// which correspond to the provided certificate name
///
- public virtual IX509Certificate GetKnownCertificate(String certificateName) {
- if (generallyTrustedCertificates.ContainsKey(certificateName)) {
- return generallyTrustedCertificates.Get(certificateName);
- }
- if (ocspTrustedCertificates.ContainsKey(certificateName)) {
- return ocspTrustedCertificates.Get(certificateName);
- }
- if (crlTrustedCertificates.ContainsKey(certificateName)) {
- return crlTrustedCertificates.Get(certificateName);
- }
- if (timestampTrustedCertificates.ContainsKey(certificateName)) {
- return timestampTrustedCertificates.Get(certificateName);
- }
- return caTrustedCertificates.Get(certificateName);
+ public virtual ICollection GetKnownCertificates(String certificateName) {
+ ICollection result = new HashSet();
+ AddMatched(result, generallyTrustedCertificates, certificateName);
+ AddMatched(result, ocspTrustedCertificates, certificateName);
+ AddMatched(result, crlTrustedCertificates, certificateName);
+ AddMatched(result, timestampTrustedCertificates, certificateName);
+ AddMatched(result, caTrustedCertificates, certificateName);
+ return result;
}
/// Get all the certificates, which where provided to this storage as trusted certificate.
@@ -337,13 +342,80 @@ public virtual IX509Certificate GetKnownCertificate(String certificateName) {
/// instances
///
public virtual ICollection GetAllTrustedCertificates() {
- IList certificates = new List();
- certificates.AddAll(generallyTrustedCertificates.Values);
- certificates.AddAll(ocspTrustedCertificates.Values);
- certificates.AddAll(crlTrustedCertificates.Values);
- certificates.AddAll(timestampTrustedCertificates.Values);
- certificates.AddAll(caTrustedCertificates.Values);
+ ICollection certificates = new HashSet();
+ foreach (ICollection set in generallyTrustedCertificates.Values) {
+ certificates.AddAll(set);
+ }
+ foreach (ICollection set in ocspTrustedCertificates.Values) {
+ certificates.AddAll(set);
+ }
+ foreach (ICollection set in crlTrustedCertificates.Values) {
+ certificates.AddAll(set);
+ }
+ foreach (ICollection set in timestampTrustedCertificates.Values) {
+ certificates.AddAll(set);
+ }
+ foreach (ICollection set in caTrustedCertificates.Values) {
+ certificates.AddAll(set);
+ }
return certificates;
}
+
+ /// Get all the certificates having name as subject, which where provided to this storage as trusted certificate.
+ ///
+ /// the subject name value for which to retrieve all trusted certificate
+ ///
+ /// set of
+ ///
+ /// which correspond to the provided certificate name
+ ///
+ public virtual ICollection GetAllTrustedCertificates(String name) {
+ ICollection certificates = new HashSet();
+ ICollection set = generallyTrustedCertificates.Get(name);
+ if (set != null) {
+ certificates.AddAll(set);
+ }
+ set = ocspTrustedCertificates.Get(name);
+ if (set != null) {
+ certificates.AddAll(set);
+ }
+ set = crlTrustedCertificates.Get(name);
+ if (set != null) {
+ certificates.AddAll(set);
+ }
+ set = timestampTrustedCertificates.Get(name);
+ if (set != null) {
+ certificates.AddAll(set);
+ }
+ set = caTrustedCertificates.Get(name);
+ if (set != null) {
+ certificates.AddAll(set);
+ }
+ return certificates;
+ }
+
+ private static void AddCertificateToMap(IX509Certificate certificate, IDictionary> map) {
+ String name = ((IX509Certificate)certificate).GetSubjectDN().ToString();
+ ICollection set = map.ComputeIfAbsent(name, (k) => new HashSet());
+ set.Add(certificate);
+ }
+
+ private static bool MapContainsCertificate(IX509Certificate certificate, IDictionary> map) {
+ ICollection set = map.Get(((IX509Certificate)certificate).GetSubjectDN().ToString());
+ if (set == null) {
+ return false;
+ }
+ return set.Contains(certificate);
+ }
+
+ private static void AddMatched(ICollection target, IDictionary> source, String certificateName) {
+ ICollection subset = source.Get(certificateName);
+ if (subset != null) {
+ target.AddAll(subset);
+ }
+ }
}
}
diff --git a/port-hash b/port-hash
index d583678927..dc88712c80 100644
--- a/port-hash
+++ b/port-hash
@@ -1 +1 @@
-1156fe6f2e4a2ea0794e650746efc2cf312edf2f
\ No newline at end of file
+a6e77ae175f64fa2b5f619945eab96b1d23c371d