diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/layer/PdfLayerTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/layer/PdfLayerTest.cs index 5a1073eb2d..7f532ececb 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/layer/PdfLayerTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/layer/PdfLayerTest.cs @@ -27,8 +27,11 @@ You should have received a copy of the GNU Affero General Public License using iText.IO.Source; using iText.Kernel.Exceptions; using iText.Kernel.Font; +using iText.Kernel.Geom; using iText.Kernel.Pdf; +using iText.Kernel.Pdf.Annot; using iText.Kernel.Pdf.Canvas; +using iText.Kernel.Pdf.Xobject; using iText.Kernel.Utils; using iText.Test; @@ -357,6 +360,112 @@ public virtual void TestInStamperMode2() { sourceFolder + "cmp_output_layered.pdf", destinationFolder, "diff")); } + [NUnit.Framework.Test] + public virtual void TestReadAllLayersFromPage1() { + PdfDocument pdfDoc = new PdfDocument(new PdfReader(sourceFolder + "input_layered.pdf"), CompareTool.CreateTestPdfWriter + (destinationFolder + "output_layered_2.pdf")); + PdfCanvas canvas = new PdfCanvas(pdfDoc, 1); + //create layer on page + PdfLayer newLayer = new PdfLayer("appended", pdfDoc); + canvas.SetFontAndSize(PdfFontFactory.CreateFont(StandardFonts.HELVETICA), 18); + PdfLayerTestUtils.AddTextInsideLayer(newLayer, canvas, "APPENDED CONTENT", 200, 600); + IList layersFromCatalog = pdfDoc.GetCatalog().GetOCProperties(true).GetLayers(); + NUnit.Framework.Assert.AreEqual(13, layersFromCatalog.Count); + PdfPage page = pdfDoc.GetPage(1); + ICollection layersFromPage = page.GetPdfLayers(); + NUnit.Framework.Assert.AreEqual(11, layersFromPage.Count); + pdfDoc.Close(); + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(destinationFolder + "output_layered_2.pdf" + , sourceFolder + "cmp_output_layered_2.pdf", destinationFolder, "diff")); + } + + [NUnit.Framework.Test] + public virtual void TestReadAllLayersFromDocumentWithComplexOCG() { + PdfDocument pdfDoc = new PdfDocument(new PdfReader(sourceFolder + "input_complex_layers.pdf"), CompareTool + .CreateTestPdfWriter(destinationFolder + "output_complex_layers.pdf")); + IList layersFromCatalog = pdfDoc.GetCatalog().GetOCProperties(true).GetLayers(); + NUnit.Framework.Assert.AreEqual(12, layersFromCatalog.Count); + PdfPage page = pdfDoc.GetPage(1); + ICollection layersFromPage = page.GetPdfLayers(); + NUnit.Framework.Assert.AreEqual(10, layersFromPage.Count); + pdfDoc.Close(); + } + + //Read OCGs from different locations (annotations, content streams, xObjects) test block + [NUnit.Framework.Test] + public virtual void TestReadOcgFromStreamProperties() { + using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + using (PdfDocument document = new PdfDocument(new PdfWriter(outputStream))) { + PdfPage page = document.AddNewPage(); + PdfResources pdfResource = page.GetResources(); + pdfResource.AddProperties(new PdfLayer("name", document).GetPdfObject()); + pdfResource.MakeIndirect(document); + ICollection layersFromPage = page.GetPdfLayers(); + NUnit.Framework.Assert.AreEqual(1, layersFromPage.Count); + } + } + } + + [NUnit.Framework.Test] + public virtual void TestReadOcgFromAnnotation() { + using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + using (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) { + PdfPage page = fromDocument.AddNewPage(); + PdfAnnotation annotation = new PdfTextAnnotation(new Rectangle(50, 10)); + annotation.SetLayer(new PdfLayer("name", fromDocument)); + page.AddAnnotation(annotation); + ICollection layersFromPage = page.GetPdfLayers(); + NUnit.Framework.Assert.AreEqual(1, layersFromPage.Count); + } + } + } + + [NUnit.Framework.Test] + public virtual void TestReadOcgFromFlushedAnnotation() { + using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + using (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) { + PdfPage page = fromDocument.AddNewPage(); + PdfAnnotation annotation = new PdfTextAnnotation(new Rectangle(50, 10)); + annotation.SetLayer(new PdfLayer("name", fromDocument)); + page.AddAnnotation(annotation); + annotation.Flush(); + ICollection layersFromPage = page.GetPdfLayers(); + NUnit.Framework.Assert.AreEqual(1, layersFromPage.Count); + } + } + } + + [NUnit.Framework.Test] + public virtual void TestReadOcgFromApAnnotation() { + using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + using (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) { + PdfPage page = fromDocument.AddNewPage(); + PdfAnnotation annotation = new PdfTextAnnotation(new Rectangle(50, 10)); + PdfFormXObject formXObject = new PdfFormXObject(new Rectangle(50, 10)); + formXObject.SetLayer(new PdfLayer("someName1", fromDocument)); + formXObject.MakeIndirect(fromDocument); + PdfDictionary nDict = new PdfDictionary(); + nDict.Put(PdfName.ON, formXObject.GetPdfObject()); + annotation.SetAppearance(PdfName.N, nDict); + formXObject = new PdfFormXObject(new Rectangle(50, 10)); + formXObject.SetLayer(new PdfLayer("someName2", fromDocument)); + PdfResources formResources = formXObject.GetResources(); + formResources.AddProperties(new PdfLayer("someName3", fromDocument).GetPdfObject()); + formXObject.MakeIndirect(fromDocument); + PdfDictionary rDict = new PdfDictionary(); + rDict.Put(PdfName.OFF, formXObject.GetPdfObject()); + annotation.SetAppearance(PdfName.R, rDict); + formXObject = new PdfFormXObject(new Rectangle(50, 10)); + formXObject.SetLayer(new PdfLayer("someName4", fromDocument)); + formXObject.MakeIndirect(fromDocument); + annotation.SetAppearance(PdfName.D, formXObject.GetPdfObject()); + page.AddAnnotation(annotation); + ICollection layersFromPage = page.GetPdfLayers(); + NUnit.Framework.Assert.AreEqual(4, layersFromPage.Count); + } + } + } + //TODO DEVSIX-8490 remove this test when implemented [NUnit.Framework.Test] public virtual void AddSecondParentlayerTest() { diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/cmp_output_layered_2.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/cmp_output_layered_2.pdf new file mode 100644 index 0000000000..92af7c8e89 Binary files /dev/null and b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/cmp_output_layered_2.pdf differ diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/input_complex_layers.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/input_complex_layers.pdf new file mode 100644 index 0000000000..4dbe49cf99 Binary files /dev/null and b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/input_complex_layers.pdf differ 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/DocumentRevisionsValidatorIntegrationTest.cs b/itext.tests/itext.sign.tests/itext/signatures/validation/DocumentRevisionsValidatorIntegrationTest.cs index 778d715937..7fb6b362a1 100644 --- a/itext.tests/itext.sign.tests/itext/signatures/validation/DocumentRevisionsValidatorIntegrationTest.cs +++ b/itext.tests/itext.sign.tests/itext/signatures/validation/DocumentRevisionsValidatorIntegrationTest.cs @@ -79,10 +79,8 @@ public virtual void LinearizedDocTest(bool continueValidationAfterFail) { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "linearizedDoc.pdf"))) { DocumentRevisionsValidator validator = builder.BuildDocumentRevisionsValidator(); ValidationReport report = validator.ValidateAllDocumentRevisions(validationContext, document); - AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INDETERMINATE - ).HasNumberOfFailures(1).HasNumberOfLogs(1).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator - .DOC_MDP_CHECK).WithMessage(DocumentRevisionsValidator.LINEARIZED_NOT_SUPPORTED).WithStatus(ReportItem.ReportItemStatus - .INDETERMINATE))); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID).HasNumberOfFailures + (0).HasNumberOfLogs(0)); NUnit.Framework.Assert.AreEqual(AccessPermissions.ANNOTATION_MODIFICATION, validator.GetAccessPermissions( )); } 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.kernel/itext/kernel/pdf/OcgPropertiesCopier.cs b/itext/itext.kernel/itext/kernel/pdf/OcgPropertiesCopier.cs index a323d1124b..2138e88d47 100644 --- a/itext/itext.kernel/itext/kernel/pdf/OcgPropertiesCopier.cs +++ b/itext/itext.kernel/itext/kernel/pdf/OcgPropertiesCopier.cs @@ -40,25 +40,30 @@ private OcgPropertiesCopier() { } // Empty constructor - public static void CopyOCGProperties(PdfDocument fromDocument, PdfDocument toDocument, IDictionary page2page) { + /// Copy unique page OCGs stored inside annotations/xobjects/resources from source pages to destination pages. + /// + /// document from which OCGs should be copied + /// document to which OCGs should be copied + /// page mapping, linking source pages to destination ones + public static void CopyOCGProperties(PdfDocument sourceDocument, PdfDocument destinationDocument, IDictionary + sourceToDestPageMapping) { try { // Configs are not copied - PdfDictionary toOcProperties = toDocument.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.OCProperties + PdfDictionary toOcProperties = destinationDocument.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.OCProperties ); - ICollection fromOcgsToCopy = iText.Kernel.Pdf.OcgPropertiesCopier.GetAllUsedNonFlushedOCGs - (page2page, toOcProperties); - if (fromOcgsToCopy.IsEmpty()) { + ICollection ocgsToCopy = iText.Kernel.Pdf.OcgPropertiesCopier.GetAllUsedNonFlushedOCGs + (sourceToDestPageMapping, toOcProperties); + if (ocgsToCopy.IsEmpty()) { return; } // Reset ocProperties field in order to create it a new at the // method end using the new (merged) OCProperties dictionary - toOcProperties = toDocument.GetCatalog().FillAndGetOcPropertiesDictionary(); - PdfDictionary fromOcProperties = fromDocument.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.OCProperties + toOcProperties = destinationDocument.GetCatalog().FillAndGetOcPropertiesDictionary(); + PdfDictionary fromOcProperties = sourceDocument.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.OCProperties ); - iText.Kernel.Pdf.OcgPropertiesCopier.CopyOCGs(fromOcgsToCopy, toOcProperties, toDocument); - iText.Kernel.Pdf.OcgPropertiesCopier.CopyDDictionary(fromOcgsToCopy, fromOcProperties.GetAsDictionary(PdfName - .D), toOcProperties, toDocument); + iText.Kernel.Pdf.OcgPropertiesCopier.CopyOCGs(ocgsToCopy, toOcProperties, destinationDocument); + iText.Kernel.Pdf.OcgPropertiesCopier.CopyDDictionary(ocgsToCopy, fromOcProperties.GetAsDictionary(PdfName. + D), toOcProperties, destinationDocument); } catch (Exception e) { LOGGER.LogError(MessageFormatUtil.Format(iText.IO.Logs.IoLogMessageConstant.OCG_COPYING_ERROR, e.ToString( @@ -66,6 +71,24 @@ public static void CopyOCGProperties(PdfDocument fromDocument, PdfDocument toDoc } } + /// Get all OCGs from a given page annotations/xobjects/resources, including ones already stored in catalog + /// + /// where to search for OCGs. + /// set of indirect references pointing to found OCGs. + public static ICollection GetOCGsFromPage(PdfPage page) { + //Using linked hash set for elements order consistency (e.g. in tests) + ICollection ocgs = new LinkedHashSet(); + IList annotations = page.GetAnnotations(); + foreach (PdfAnnotation annotation in annotations) { + //Pass null instead of catalog OCProperties value, to include ocg clashing with catalog + GetUsedNonFlushedOCGsFromAnnotation(annotation, annotation, ocgs, null); + } + PdfDictionary resources = page.GetPdfObject().GetAsDictionary(PdfName.Resources); + iText.Kernel.Pdf.OcgPropertiesCopier.GetUsedNonFlushedOCGsFromResources(resources, resources, ocgs, null, + new HashSet()); + return ocgs; + } + private static ICollection GetAllUsedNonFlushedOCGs(IDictionary page2page , PdfDictionary toOcProperties) { // NOTE: the PDF is considered to be valid and therefore the presence of OСG in OCProperties.OCGs is not checked @@ -81,19 +104,10 @@ private static ICollection GetAllUsedNonFlushedOCGs(IDicti IList fromAnnotations = fromPage.GetAnnotations(); for (int j = 0; j < toAnnotations.Count; j++) { if (!toAnnotations[j].IsFlushed()) { - PdfDictionary toAnnotDict = toAnnotations[j].GetPdfObject(); - PdfDictionary fromAnnotDict = fromAnnotations[j].GetPdfObject(); PdfAnnotation toAnnot = toAnnotations[j]; PdfAnnotation fromAnnot = fromAnnotations[j]; - if (!toAnnotDict.IsFlushed()) { - iText.Kernel.Pdf.OcgPropertiesCopier.GetUsedNonFlushedOCGsFromOcDict(toAnnotDict.GetAsDictionary(PdfName.OC - ), fromAnnotDict.GetAsDictionary(PdfName.OC), fromUsedOcgs, toOcProperties); - iText.Kernel.Pdf.OcgPropertiesCopier.GetUsedNonFlushedOCGsFromXObject(toAnnot.GetNormalAppearanceObject(), - fromAnnot.GetNormalAppearanceObject(), fromUsedOcgs, toOcProperties, new HashSet()); - iText.Kernel.Pdf.OcgPropertiesCopier.GetUsedNonFlushedOCGsFromXObject(toAnnot.GetRolloverAppearanceObject( - ), fromAnnot.GetRolloverAppearanceObject(), fromUsedOcgs, toOcProperties, new HashSet()); - iText.Kernel.Pdf.OcgPropertiesCopier.GetUsedNonFlushedOCGsFromXObject(toAnnot.GetDownAppearanceObject(), fromAnnot - .GetDownAppearanceObject(), fromUsedOcgs, toOcProperties, new HashSet()); + if (!toAnnot.GetPdfObject().IsFlushed()) { + GetUsedNonFlushedOCGsFromAnnotation(toAnnot, fromAnnot, fromUsedOcgs, toOcProperties); } } } @@ -105,6 +119,18 @@ private static ICollection GetAllUsedNonFlushedOCGs(IDicti return fromUsedOcgs; } + private static void GetUsedNonFlushedOCGsFromAnnotation(PdfAnnotation toAnnot, PdfAnnotation fromAnnot, ICollection + fromUsedOcgs, PdfDictionary toOcProperties) { + iText.Kernel.Pdf.OcgPropertiesCopier.GetUsedNonFlushedOCGsFromOcDict(toAnnot.GetPdfObject().GetAsDictionary + (PdfName.OC), fromAnnot.GetPdfObject().GetAsDictionary(PdfName.OC), fromUsedOcgs, toOcProperties); + iText.Kernel.Pdf.OcgPropertiesCopier.GetUsedNonFlushedOCGsFromXObject(toAnnot.GetNormalAppearanceObject(), + fromAnnot.GetNormalAppearanceObject(), fromUsedOcgs, toOcProperties, new HashSet()); + iText.Kernel.Pdf.OcgPropertiesCopier.GetUsedNonFlushedOCGsFromXObject(toAnnot.GetRolloverAppearanceObject( + ), fromAnnot.GetRolloverAppearanceObject(), fromUsedOcgs, toOcProperties, new HashSet()); + iText.Kernel.Pdf.OcgPropertiesCopier.GetUsedNonFlushedOCGsFromXObject(toAnnot.GetDownAppearanceObject(), fromAnnot + .GetDownAppearanceObject(), fromUsedOcgs, toOcProperties, new HashSet()); + } + private static void GetUsedNonFlushedOCGsFromResources(PdfDictionary toResources, PdfDictionary fromResources , ICollection fromUsedOcgs, PdfDictionary toOcProperties, ICollection visitedObjects) { diff --git a/itext/itext.kernel/itext/kernel/pdf/PdfPage.cs b/itext/itext.kernel/itext/kernel/pdf/PdfPage.cs index 31ddd33550..4293bd1ed9 100644 --- a/itext/itext.kernel/itext/kernel/pdf/PdfPage.cs +++ b/itext/itext.kernel/itext/kernel/pdf/PdfPage.cs @@ -31,6 +31,7 @@ You should have received a copy of the GNU Affero General Public License using iText.Kernel.Pdf.Action; using iText.Kernel.Pdf.Annot; using iText.Kernel.Pdf.Filespec; +using iText.Kernel.Pdf.Layer; using iText.Kernel.Pdf.Tagging; using iText.Kernel.Pdf.Tagutils; using iText.Kernel.Pdf.Xobject; @@ -543,6 +544,24 @@ public virtual iText.Kernel.Pdf.PdfPage CopyTo(PdfDocument toDocument, IPdfPageE return CopyTo(page, toDocument, copier); } + /// Get all pdf layers stored under this page's annotations/xobjects/resources. + /// + /// Get all pdf layers stored under this page's annotations/xobjects/resources. + /// Note that it will include all layers, even those already stored under /OCProperties entry in catalog. + /// To get only unique layers, you can simply exclude ocgs, which already present in catalog. + /// + /// set of pdf layers, associated with this page. + public virtual ICollection GetPdfLayers() { + ICollection ocgs = OcgPropertiesCopier.GetOCGsFromPage(this); + ICollection result = new LinkedHashSet(); + foreach (PdfIndirectReference ocg in ocgs) { + if (ocg.GetRefersTo() != null && ocg.GetRefersTo().IsDictionary()) { + result.Add(new PdfLayer((PdfDictionary)ocg.GetRefersTo())); + } + } + return result; + } + /// Copies page as FormXObject to the specified document. /// a document to copy to. /// 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/SignExtensions.cs b/itext/itext.sign/itext/signatures/SignExtensions.cs index ecded872e0..e63a98b1a6 100644 --- a/itext/itext.sign/itext/signatures/SignExtensions.cs +++ b/itext/itext.sign/itext/signatures/SignExtensions.cs @@ -88,6 +88,10 @@ public static void AddAll(this IDictionary c, IDicti c[pair.Key] = pair.Value; } } + + public static void Add(this IList list, int index, T elem) { + list.Insert(index, elem); + } public static T JRemoveAt(this IList list, int index) { T value = list[index]; 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/DocumentRevisionsValidator.cs b/itext/itext.sign/itext/signatures/validation/DocumentRevisionsValidator.cs index 9a051511ec..6b38310377 100644 --- a/itext/itext.sign/itext/signatures/validation/DocumentRevisionsValidator.cs +++ b/itext/itext.sign/itext/signatures/validation/DocumentRevisionsValidator.cs @@ -103,10 +103,6 @@ public class DocumentRevisionsValidator { internal const String FIELD_REMOVED = "Form field {0} was removed or unexpectedly modified."; //\endcond -//\cond DO_NOT_DOCUMENT - internal const String LINEARIZED_NOT_SUPPORTED = "Linearized PDF documents are not supported by DocumentRevisionsValidator."; -//\endcond - //\cond DO_NOT_DOCUMENT internal const String LOCKED_FIELD_KIDS_ADDED = "Kids were added to locked form field \"{0}\"."; //\endcond @@ -390,6 +386,7 @@ internal virtual ValidationReport ValidateAllDocumentRevisions(ValidationContext .INDETERMINATE)); return report; } + MergeRevisionsInLinearizedDocument(document, documentRevisions); SignatureUtil signatureUtil = new SignatureUtil(document); IList signatures = new List(signatureUtil.GetSignatureNames()); if (signatures.IsEmpty()) { @@ -473,6 +470,29 @@ internal virtual void ValidateRevision(DocumentRevision previousRevision, Docume } //\endcond + private void MergeRevisionsInLinearizedDocument(PdfDocument document, IList documentRevisions + ) { + if (documentRevisions.Count > 1) { + // We need to check if document is linearized in first revision + // We don't need to populate validation report in case of exceptions, it will happen later + CreateDocumentAndPerformOperation(documentRevisions[0], document, new ValidationReport(), (firstRevisionDocument + ) => { + if (IsLinearizedPdf(document)) { + ICollection mergedModifiedReferences = new HashSet(documentRevisions + [0].GetModifiedObjects()); + mergedModifiedReferences.AddAll(documentRevisions[1].GetModifiedObjects()); + DocumentRevision mergedRevision = new DocumentRevision(documentRevisions[0].GetEofOffset(), mergedModifiedReferences + ); + documentRevisions.Add(0, mergedRevision); + documentRevisions.JRemoveAt(1); + documentRevisions.JRemoveAt(1); + } + return true; + } + ); + } + } + private bool ValidateRevision(ValidationReport validationReport, ValidationContext context, PdfDocument documentWithoutRevision , PdfDocument documentWithRevision, DocumentRevision currentRevision) { usuallyModifiedObjects = new Pair, ICollection>(CreateUsuallyModifiedObjectsSet @@ -737,25 +757,13 @@ private bool CreateDocumentAndPerformOperation(DocumentRevision revision, PdfDoc } } catch (System.IO.IOException exception) { - if (IsLinearizedPdf(originalDocument)) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, LINEARIZED_NOT_SUPPORTED, exception, ReportItem.ReportItemStatus - .INDETERMINATE)); - } - else { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, REVISIONS_READING_EXCEPTION, exception, ReportItem.ReportItemStatus - .INDETERMINATE)); - } + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, REVISIONS_READING_EXCEPTION, exception, ReportItem.ReportItemStatus + .INDETERMINATE)); return false; } catch (Exception exception) { - if (IsLinearizedPdf(originalDocument)) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, LINEARIZED_NOT_SUPPORTED, exception, ReportItem.ReportItemStatus - .INDETERMINATE)); - } - else { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, REVISIONS_READING_EXCEPTION, exception, ReportItem.ReportItemStatus - .INDETERMINATE)); - } + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, REVISIONS_READING_EXCEPTION, exception, ReportItem.ReportItemStatus + .INDETERMINATE)); return false; } } 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 238dce8913..dc88712c80 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -20941942038f765b1cbc9df1c8ea7f895b03a730 +a6e77ae175f64fa2b5f619945eab96b1d23c371d