From 96cc626858f35c3784625de581599f7b48295b61 Mon Sep 17 00:00:00 2001 From: Alexander Pliushchou Date: Sun, 24 Dec 2023 21:07:26 +0000 Subject: [PATCH 1/4] fix id pad in preserve encryption mode. add tests. move preserve tests DEVSIX-7597 Autoported commit. Original commit hash: [dc0cad357] --- .../{ => pdfencryption}/PdfEncryptionTest.cs | 192 +++++------------- .../pdfencryption/PdfEncryptionTestUtils.cs | 72 +++++++ .../PdfPreserveEncryptionTest.cs | 89 ++++++++ .../UnicodeBasedPasswordEncryptionTest.cs | 24 ++- .../itext/kernel/pdf/PdfEncryptionUnitTest.cs | 80 ++++++++ .../PdfEncryptionTest/AdobeAes256.pdf | Bin ..._appended_encryptAes256FullCompression.pdf | Bin ...ed_encryptAes256Pdf2NotEncryptMetadata.pdf | Bin ..._encryptAes256Pdf2NotEncryptMetadata02.pdf | Bin ...cmp_appended_encryptWithPasswordAes128.pdf | Bin ...encryptWithPasswordAes128NoCompression.pdf | Bin ...appended_encryptWithPasswordAes128Pdf2.pdf | Bin ...cmp_appended_encryptWithPasswordAes256.pdf | Bin ...encryptWithPasswordAes256NoCompression.pdf | Bin ...appended_encryptWithPasswordAes256Pdf2.pdf | Bin ...ppended_encryptWithPasswordStandard128.pdf | Bin ...ptWithPasswordStandard128NoCompression.pdf | Bin ...appended_encryptWithPasswordStandard40.pdf | Bin ...yptWithPasswordStandard40NoCompression.pdf | Bin .../cmp_copiedEncryptedDoc.pdf | Bin ...p_encryptAes256EncryptedStampingUpdate.pdf | Bin .../cmp_encryptAes256FullCompression.pdf | Bin ...mp_encryptAes256Pdf2NotEncryptMetadata.pdf | Bin ..._encryptAes256Pdf2NotEncryptMetadata02.pdf | Bin .../cmp_encryptAes256Pdf2Permissions.pdf | Bin .../cmp_encryptWithPasswordAes128.pdf | Bin ...encryptWithPasswordAes128NoCompression.pdf | Bin ...ithPasswordAes128NoMetadataCompression.pdf | Bin .../cmp_encryptWithPasswordAes128Pdf2.pdf | Bin .../cmp_encryptWithPasswordAes256.pdf | Bin ...encryptWithPasswordAes256NoCompression.pdf | Bin .../cmp_encryptWithPasswordAes256Pdf2.pdf | Bin .../cmp_encryptWithPasswordStandard128.pdf | Bin ...ptWithPasswordStandard128NoCompression.pdf | Bin .../cmp_encryptWithPasswordStandard40.pdf | Bin ...yptWithPasswordStandard40NoCompression.pdf | Bin .../cmp_stampAndUpdateVersionNewAes256.pdf | Bin ...p_stamped_encryptAes256FullCompression.pdf | Bin ..._encryptAes256Pdf2NotEncryptMetadata02.pdf | Bin .../encryptedAes128EmbeddedFilesOnly.pdf | Bin .../encryptedWithCertificateAes128.pdf | Bin .../encryptedWithPasswordAes256.pdf | Bin .../encryptedWithPasswordStandard40.pdf | Bin ...ryptedWithPasswordWithDefaultKeyLength.pdf | Bin .../encryptedWithPlainMetadata.pdf | Bin .../PdfEncryptionTest/noUserPassword.pdf | Bin .../PdfEncryptionTest/pageWithContent.pdf | Bin ...ithPasswordAes128NoMetadataCompression.pdf | Bin .../PdfEncryptionTest/test.cer | Bin .../PdfEncryptionTest/test.pem | 0 .../PdfEncryptionTest/wrong.cer | Bin .../PdfEncryptionTest/wrong.pem | 0 ...encryptAes256EncryptedStampingPreserve.pdf | Bin .../cmp_preserveEncryptionWithShortId.pdf | Bin 0 -> 1999 bytes ...mp_stampAndUpdateVersionPreserveAes256.pdf | Bin ...tampAndUpdateVersionPreserveStandard40.pdf | Bin .../encryptedWithPasswordAes256.pdf | Bin 0 -> 4324 bytes .../encryptedWithPasswordStandard40.pdf | Bin 0 -> 3933 bytes .../encryptedWithPlainMetadata.pdf | Bin 0 -> 3846 bytes .../encryptedWithShortId.pdf | Bin 0 -> 1873 bytes .../cmp_unicodePassword_arabic01.pdf | Bin .../cmp_unicodePassword_arabic02.pdf | Bin .../cmp_unicodePassword_arabic03.pdf | Bin .../cmp_unicodePassword_arabic04.pdf | Bin .../cmp_unicodePassword_arabic05.pdf | Bin .../cmp_unicodePassword_devanagari01.pdf | Bin .../cmp_unicodePassword_devanagari02.pdf | Bin .../cmp_unicodePassword_emoji01.pdf | Bin .../cmp_unicodePassword_gurmukhi01.pdf | Bin .../cmp_unicodePassword_khmer01.pdf | Bin ...mp_unicodePassword_nfkcNormalization01.pdf | Bin ...mp_unicodePassword_nfkcNormalization02.pdf | Bin ...mp_unicodePassword_nfkcNormalization03.pdf | Bin ...mp_unicodePassword_nfkcNormalization04.pdf | Bin ...mp_unicodePassword_nfkcNormalization05.pdf | Bin .../cmp_unicodePassword_nonAsciiSpace01.pdf | Bin .../cmp_unicodePassword_rfc4013Example01.pdf | Bin .../cmp_unicodePassword_rfc4013Example02.pdf | Bin .../cmp_unicodePassword_rfc4013Example03.pdf | Bin .../cmp_unicodePassword_rfc4013Example04.pdf | Bin .../cmp_unicodePassword_tamil01.pdf | Bin .../cmp_unicodePassword_thai01.pdf | Bin .../cmp_unicodePassword_unicodeBom01.pdf | Bin .../itext/kernel/pdf/PdfDocument.cs | 2 +- .../itext/kernel/pdf/PdfEncryption.cs | 27 ++- port-hash | 2 +- 86 files changed, 333 insertions(+), 155 deletions(-) rename itext.tests/itext.kernel.tests/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest.cs (77%) create mode 100644 itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTestUtils.cs create mode 100644 itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest.cs rename itext.tests/itext.kernel.tests/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest.cs (91%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/AdobeAes256.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_appended_encryptAes256FullCompression.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_appended_encryptAes256Pdf2NotEncryptMetadata.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_appended_encryptAes256Pdf2NotEncryptMetadata02.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128NoCompression.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128Pdf2.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256NoCompression.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256Pdf2.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard128.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard128NoCompression.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard40.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard40NoCompression.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_copiedEncryptedDoc.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptAes256EncryptedStampingUpdate.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptAes256FullCompression.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptAes256Pdf2NotEncryptMetadata.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptAes256Pdf2NotEncryptMetadata02.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptAes256Pdf2Permissions.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptWithPasswordAes128.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptWithPasswordAes128NoCompression.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptWithPasswordAes128NoMetadataCompression.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptWithPasswordAes128Pdf2.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptWithPasswordAes256.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptWithPasswordAes256NoCompression.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptWithPasswordAes256Pdf2.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptWithPasswordStandard128.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptWithPasswordStandard128NoCompression.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptWithPasswordStandard40.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_encryptWithPasswordStandard40NoCompression.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_stampAndUpdateVersionNewAes256.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_stamped_encryptAes256FullCompression.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/cmp_stamped_encryptAes256Pdf2NotEncryptMetadata02.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/encryptedAes128EmbeddedFilesOnly.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/encryptedWithCertificateAes128.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/encryptedWithPasswordAes256.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/encryptedWithPasswordStandard40.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/encryptedWithPasswordWithDefaultKeyLength.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/encryptedWithPlainMetadata.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/noUserPassword.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/pageWithContent.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/srcEncryptWithPasswordAes128NoMetadataCompression.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/test.cer (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/test.pem (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/wrong.cer (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/PdfEncryptionTest/wrong.pem (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{PdfEncryptionTest => pdfencryption/PdfPreserveEncryptionTest}/cmp_encryptAes256EncryptedStampingPreserve.pdf (100%) create mode 100644 itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/cmp_preserveEncryptionWithShortId.pdf rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{PdfEncryptionTest => pdfencryption/PdfPreserveEncryptionTest}/cmp_stampAndUpdateVersionPreserveAes256.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{PdfEncryptionTest => pdfencryption/PdfPreserveEncryptionTest}/cmp_stampAndUpdateVersionPreserveStandard40.pdf (100%) create mode 100644 itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/encryptedWithPasswordAes256.pdf create mode 100644 itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/encryptedWithPasswordStandard40.pdf create mode 100644 itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/encryptedWithPlainMetadata.pdf create mode 100644 itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/encryptedWithShortId.pdf rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic01.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic02.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic03.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic04.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic05.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_devanagari01.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_devanagari02.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_emoji01.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_gurmukhi01.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_khmer01.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization01.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization02.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization03.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization04.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization05.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nonAsciiSpace01.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example01.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example02.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example03.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example04.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_tamil01.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_thai01.pdf (100%) rename itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/{ => pdfencryption}/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_unicodeBom01.pdf (100%) diff --git a/itext.tests/itext.kernel.tests/itext/kernel/crypto/PdfEncryptionTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTest.cs similarity index 77% rename from itext.tests/itext.kernel.tests/itext/kernel/crypto/PdfEncryptionTest.cs rename to itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTest.cs index 45d19eb831..5c380f451f 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/crypto/PdfEncryptionTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTest.cs @@ -27,10 +27,9 @@ You should have received a copy of the GNU Affero General Public License using iText.Commons.Bouncycastle; using iText.Commons.Bouncycastle.Cert; using iText.Commons.Bouncycastle.Crypto; -using iText.IO.Font.Constants; +using iText.Kernel.Crypto; using iText.Kernel.Crypto.Securityhandler; using iText.Kernel.Exceptions; -using iText.Kernel.Font; using iText.Kernel.Logs; using iText.Kernel.Pdf; using iText.Kernel.Pdf.Canvas.Parser; @@ -41,7 +40,7 @@ You should have received a copy of the GNU Affero General Public License using iText.Test; using iText.Test.Attributes; -namespace iText.Kernel.Crypto { +namespace iText.Kernel.Crypto.Pdfencryption { /// /// Due to import control restrictions by the governments of a few countries, /// the encryption libraries shipped by default with the Java SDK restrict the @@ -66,10 +65,10 @@ public class PdfEncryptionTest : ExtendedITextTest { private static readonly IBouncyCastleFactory FACTORY = BouncyCastleFactoryCreator.GetFactory(); public static readonly String destinationFolder = NUnit.Framework.TestContext.CurrentContext.TestDirectory - + "/test/itext/kernel/crypto/PdfEncryptionTest/"; + + "/test/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/"; public static readonly String sourceFolder = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext - .CurrentContext.TestDirectory) + "/resources/itext/kernel/crypto/PdfEncryptionTest/"; + .CurrentContext.TestDirectory) + "/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/"; public static readonly char[] PRIVATE_KEY_PASS = "testpassphrase".ToCharArray(); @@ -77,21 +76,11 @@ public class PdfEncryptionTest : ExtendedITextTest { public static readonly String PRIVATE_KEY = sourceFolder + "test.pem"; - internal const String pageTextContent = "Hello world!"; - - // Custom entry in Info dictionary is used because standard entried are gone into metadata in PDF 2.0 - internal const String customInfoEntryKey = "Custom"; - - internal const String customInfoEntryValue = "String"; - - /// User password. - public static byte[] USER = "Hello".GetBytes(iText.Commons.Utils.EncodingUtil.ISO_8859_1); - - /// Owner password. - public static byte[] OWNER = "World".GetBytes(iText.Commons.Utils.EncodingUtil.ISO_8859_1); - private IPrivateKey privateKey; + internal PdfEncryptionTestUtils encryptionUtil = new PdfEncryptionTestUtils(destinationFolder, sourceFolder + ); + [NUnit.Framework.OneTimeSetUp] public static void BeforeClass() { CreateOrClearDestinationFolder(destinationFolder); @@ -229,7 +218,7 @@ public virtual void OpenEncryptedDocWithWrongCertificateAndPrivateKey() { [LogMessage(KernelLogMessageConstant.MD5_IS_NOT_FIPS_COMPLIANT, Ignore = true)] public virtual void MetadataReadingInEncryptedDoc() { PdfReader reader = new PdfReader(sourceFolder + "encryptedWithPlainMetadata.pdf", new ReaderProperties().SetPassword - (OWNER)); + (PdfEncryptionTestUtils.OWNER)); PdfDocument doc = new PdfDocument(reader); XMPMeta xmpMeta = XMPMetaFactory.ParseFromBuffer(doc.GetXmpMetadata()); XMPProperty creatorToolXmp = xmpMeta.GetProperty(XMPConst.NS_XMP, "CreatorTool"); @@ -270,7 +259,8 @@ public virtual void OpenDocNoUserPassword() { String fileName = "noUserPassword.pdf"; PdfDocument document = new PdfDocument(new PdfReader(sourceFolder + fileName)); document.Close(); - CheckDecryptedWithPasswordContent(sourceFolder + fileName, null, pageTextContent); + encryptionUtil.CheckDecryptedWithPasswordContent(sourceFolder + fileName, null, PdfEncryptionTestUtils.PAGE_TEXT_CONTENT + ); } [NUnit.Framework.Test] @@ -294,12 +284,14 @@ public virtual void EncryptWithPasswordAes128EmbeddedFilesOnly() { String outFileName = destinationFolder + filename; int permissions = EncryptionConstants.ALLOW_SCREENREADERS; PdfWriter writer = CompareTool.CreateTestPdfWriter(outFileName, new WriterProperties().SetStandardEncryption - (USER, OWNER, permissions, encryptionType).AddXmpMetadata()); + (PdfEncryptionTestUtils.USER, PdfEncryptionTestUtils.OWNER, permissions, encryptionType).AddXmpMetadata + ()); PdfDocument document = new PdfDocument(writer); - document.GetDocumentInfo().SetMoreInfo(customInfoEntryKey, customInfoEntryValue); + document.GetDocumentInfo().SetMoreInfo(PdfEncryptionTestUtils.CUSTOM_INFO_ENTRY_KEY, PdfEncryptionTestUtils + .CUSTOM_INFO_ENTRY_VALUE); PdfPage page = document.AddNewPage(); String textContent = "Hello world!"; - WriteTextBytesOnPageContent(page, textContent); + PdfEncryptionTestUtils.WriteTextBytesOnPageContent(page, textContent); String descripton = "encryptedFile"; String path = sourceFolder + "pageWithContent.pdf"; document.AddFileAttachment(descripton, PdfFileSpec.CreateEmbeddedFileSpec(document, path, descripton, path @@ -309,8 +301,10 @@ public virtual void EncryptWithPasswordAes128EmbeddedFilesOnly() { //TODO DEVSIX-5355 Specific crypto filters for EFF StmF and StrF are not supported at the moment. // However we can read embedded files only mode. bool ERROR_IS_EXPECTED = false; - CheckDecryptedWithPasswordContent(destinationFolder + filename, OWNER, textContent, ERROR_IS_EXPECTED); - CheckDecryptedWithPasswordContent(destinationFolder + filename, USER, textContent, ERROR_IS_EXPECTED); + encryptionUtil.CheckDecryptedWithPasswordContent(destinationFolder + filename, PdfEncryptionTestUtils.OWNER + , textContent, ERROR_IS_EXPECTED); + encryptionUtil.CheckDecryptedWithPasswordContent(destinationFolder + filename, PdfEncryptionTestUtils.USER + , textContent, ERROR_IS_EXPECTED); } [NUnit.Framework.Test] @@ -329,36 +323,20 @@ public virtual void EncryptAes256Pdf2NotEncryptMetadata02() { EncryptWithPassword(filename, encryptionType, CompressionConstants.DEFAULT_COMPRESSION, true); } - [NUnit.Framework.Test] - [LogMessage(KernelLogMessageConstant.MD5_IS_NOT_FIPS_COMPLIANT, Ignore = true)] - public virtual void EncryptAes256EncryptedStampingPreserve() { - String filename = "encryptAes256EncryptedStampingPreserve.pdf"; - String src = sourceFolder + "encryptedWithPlainMetadata.pdf"; - String @out = destinationFolder + filename; - PdfDocument pdfDoc = new PdfDocument(new PdfReader(src, new ReaderProperties().SetPassword(OWNER)), CompareTool - .CreateTestPdfWriter(@out, new WriterProperties()), new StampingProperties().PreserveEncryption()); - pdfDoc.Close(); - CompareTool compareTool = new CompareTool().EnableEncryptionCompare(); - String compareResult = compareTool.CompareByContent(@out, sourceFolder + "cmp_" + filename, destinationFolder - , "diff_", USER, USER); - if (compareResult != null) { - NUnit.Framework.Assert.Fail(compareResult); - } - } - [NUnit.Framework.Test] [LogMessage(KernelLogMessageConstant.MD5_IS_NOT_FIPS_COMPLIANT, Ignore = true)] public virtual void EncryptAes256EncryptedStampingUpdate() { String filename = "encryptAes256EncryptedStampingUpdate.pdf"; String src = sourceFolder + "encryptedWithPlainMetadata.pdf"; String @out = destinationFolder + filename; - PdfDocument pdfDoc = new PdfDocument(new PdfReader(src, new ReaderProperties().SetPassword(OWNER)), CompareTool - .CreateTestPdfWriter(@out, new WriterProperties().SetStandardEncryption(USER, OWNER, EncryptionConstants - .ALLOW_PRINTING, EncryptionConstants.STANDARD_ENCRYPTION_40)), new StampingProperties()); + PdfDocument pdfDoc = new PdfDocument(new PdfReader(src, new ReaderProperties().SetPassword(PdfEncryptionTestUtils + .OWNER)), CompareTool.CreateTestPdfWriter(@out, new WriterProperties().SetStandardEncryption(PdfEncryptionTestUtils + .USER, PdfEncryptionTestUtils.OWNER, EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.STANDARD_ENCRYPTION_40 + )), new StampingProperties()); pdfDoc.Close(); CompareTool compareTool = new CompareTool().EnableEncryptionCompare(); String compareResult = compareTool.CompareByContent(@out, sourceFolder + "cmp_" + filename, destinationFolder - , "diff_", USER, USER); + , "diff_", PdfEncryptionTestUtils.USER, PdfEncryptionTestUtils.USER); if (compareResult != null) { NUnit.Framework.Assert.Fail(compareResult); } @@ -389,41 +367,16 @@ public virtual void EncryptWithPasswordAes128Pdf2() { EncryptWithPassword2(filename, encryptionType, CompressionConstants.DEFAULT_COMPRESSION, true); } - [NUnit.Framework.Test] - [LogMessage(KernelLogMessageConstant.MD5_IS_NOT_FIPS_COMPLIANT, Ignore = true)] - [LogMessage(VersionConforming.DEPRECATED_ENCRYPTION_ALGORITHMS)] - public virtual void StampAndUpdateVersionPreserveStandard40() { - String filename = "stampAndUpdateVersionPreserveStandard40.pdf"; - PdfDocument doc = new PdfDocument(new PdfReader(sourceFolder + "encryptedWithPasswordStandard40.pdf", new - ReaderProperties().SetPassword(OWNER)), CompareTool.CreateTestPdfWriter(destinationFolder + filename, - new WriterProperties().SetPdfVersion(PdfVersion.PDF_2_0)), new StampingProperties().PreserveEncryption - ()); - doc.Close(); - CompareEncryptedPdf(filename); - } - - [NUnit.Framework.Test] - [LogMessage(KernelLogMessageConstant.MD5_IS_NOT_FIPS_COMPLIANT, Ignore = true)] - [LogMessage(VersionConforming.DEPRECATED_AES256_REVISION)] - public virtual void StampAndUpdateVersionPreserveAes256() { - String filename = "stampAndUpdateVersionPreserveAes256.pdf"; - PdfDocument doc = new PdfDocument(new PdfReader(sourceFolder + "encryptedWithPasswordAes256.pdf", new ReaderProperties - ().SetPassword(OWNER)), CompareTool.CreateTestPdfWriter(destinationFolder + filename, new WriterProperties - ().SetPdfVersion(PdfVersion.PDF_2_0)), new StampingProperties().PreserveEncryption()); - doc.Close(); - CompareEncryptedPdf(filename); - } - [NUnit.Framework.Test] [LogMessage(KernelLogMessageConstant.MD5_IS_NOT_FIPS_COMPLIANT, Ignore = true)] public virtual void StampAndUpdateVersionNewAes256() { String filename = "stampAndUpdateVersionNewAes256.pdf"; PdfDocument doc = new PdfDocument(new PdfReader(sourceFolder + "encryptedWithPasswordAes256.pdf", new ReaderProperties - ().SetPassword(OWNER)), CompareTool.CreateTestPdfWriter(destinationFolder + filename, new WriterProperties - ().SetPdfVersion(PdfVersion.PDF_2_0).SetStandardEncryption(USER, OWNER, 0, EncryptionConstants.ENCRYPTION_AES_256 - ))); + ().SetPassword(PdfEncryptionTestUtils.OWNER)), CompareTool.CreateTestPdfWriter(destinationFolder + filename + , new WriterProperties().SetPdfVersion(PdfVersion.PDF_2_0).SetStandardEncryption(PdfEncryptionTestUtils + .USER, PdfEncryptionTestUtils.OWNER, 0, EncryptionConstants.ENCRYPTION_AES_256))); doc.Close(); - CompareEncryptedPdf(filename); + encryptionUtil.CompareEncryptedPdf(filename); } [NUnit.Framework.Test] @@ -433,12 +386,14 @@ public virtual void EncryptAes256Pdf2Permissions() { int permissions = EncryptionConstants.ALLOW_FILL_IN | EncryptionConstants.ALLOW_SCREENREADERS | EncryptionConstants .ALLOW_DEGRADED_PRINTING; PdfDocument doc = new PdfDocument(CompareTool.CreateTestPdfWriter(destinationFolder + filename, new WriterProperties - ().SetPdfVersion(PdfVersion.PDF_2_0).SetStandardEncryption(USER, OWNER, permissions, EncryptionConstants - .ENCRYPTION_AES_256))); - doc.GetDocumentInfo().SetMoreInfo(customInfoEntryKey, customInfoEntryValue); - WriteTextBytesOnPageContent(doc.AddNewPage(), pageTextContent); + ().SetPdfVersion(PdfVersion.PDF_2_0).SetStandardEncryption(PdfEncryptionTestUtils.USER, PdfEncryptionTestUtils + .OWNER, permissions, EncryptionConstants.ENCRYPTION_AES_256))); + doc.GetDocumentInfo().SetMoreInfo(PdfEncryptionTestUtils.CUSTOM_INFO_ENTRY_KEY, PdfEncryptionTestUtils.CUSTOM_INFO_ENTRY_VALUE + ); + PdfEncryptionTestUtils.WriteTextBytesOnPageContent(doc.AddNewPage(), PdfEncryptionTestUtils.PAGE_TEXT_CONTENT + ); doc.Close(); - CompareEncryptedPdf(filename); + encryptionUtil.CompareEncryptedPdf(filename); } [NUnit.Framework.Test] @@ -513,8 +468,8 @@ public virtual void EncryptWithPassword2(String filename, int encryptionType, in public virtual void EncryptWithPassword2(String filename, int encryptionType, int compression, bool isPdf2 ) { int permissions = EncryptionConstants.ALLOW_SCREENREADERS; - WriterProperties writerProperties = new WriterProperties().SetStandardEncryption(USER, OWNER, permissions, - encryptionType); + WriterProperties writerProperties = new WriterProperties().SetStandardEncryption(PdfEncryptionTestUtils.USER + , PdfEncryptionTestUtils.OWNER, permissions, encryptionType); if (isPdf2) { writerProperties.SetPdfVersion(PdfVersion.PDF_2_0); } @@ -522,14 +477,15 @@ public virtual void EncryptWithPassword2(String filename, int encryptionType, in ()); writer.SetCompressionLevel(compression); PdfDocument document = new PdfDocument(writer); - document.GetDocumentInfo().SetMoreInfo(customInfoEntryKey, customInfoEntryValue); + document.GetDocumentInfo().SetMoreInfo(PdfEncryptionTestUtils.CUSTOM_INFO_ENTRY_KEY, PdfEncryptionTestUtils + .CUSTOM_INFO_ENTRY_VALUE); PdfPage page = document.AddNewPage(); - WriteTextBytesOnPageContent(page, pageTextContent); + PdfEncryptionTestUtils.WriteTextBytesOnPageContent(page, PdfEncryptionTestUtils.PAGE_TEXT_CONTENT); page.Flush(); document.Close(); - CompareEncryptedPdf(filename); - CheckEncryptedWithPasswordDocumentStamping(filename, OWNER); - CheckEncryptedWithPasswordDocumentAppending(filename, OWNER); + encryptionUtil.CompareEncryptedPdf(filename); + CheckEncryptedWithPasswordDocumentStamping(filename, PdfEncryptionTestUtils.OWNER); + CheckEncryptedWithPasswordDocumentAppending(filename, PdfEncryptionTestUtils.OWNER); } public virtual void EncryptWithPassword(String filename, int encryptionType, int compression, bool fullCompression @@ -537,17 +493,19 @@ public virtual void EncryptWithPassword(String filename, int encryptionType, int String outFileName = destinationFolder + filename; int permissions = EncryptionConstants.ALLOW_SCREENREADERS; PdfWriter writer = CompareTool.CreateTestPdfWriter(outFileName, new WriterProperties().SetStandardEncryption - (USER, OWNER, permissions, encryptionType).AddXmpMetadata().SetFullCompressionMode(fullCompression)); + (PdfEncryptionTestUtils.USER, PdfEncryptionTestUtils.OWNER, permissions, encryptionType).AddXmpMetadata + ().SetFullCompressionMode(fullCompression)); writer.SetCompressionLevel(compression); PdfDocument document = new PdfDocument(writer); - document.GetDocumentInfo().SetMoreInfo(customInfoEntryKey, customInfoEntryValue); + document.GetDocumentInfo().SetMoreInfo(PdfEncryptionTestUtils.CUSTOM_INFO_ENTRY_KEY, PdfEncryptionTestUtils + .CUSTOM_INFO_ENTRY_VALUE); PdfPage page = document.AddNewPage(); - WriteTextBytesOnPageContent(page, pageTextContent); + PdfEncryptionTestUtils.WriteTextBytesOnPageContent(page, PdfEncryptionTestUtils.PAGE_TEXT_CONTENT); page.Flush(); document.Close(); - CompareEncryptedPdf(filename); - CheckEncryptedWithPasswordDocumentStamping(filename, OWNER); - CheckEncryptedWithPasswordDocumentAppending(filename, OWNER); + encryptionUtil.CompareEncryptedPdf(filename); + CheckEncryptedWithPasswordDocumentStamping(filename, PdfEncryptionTestUtils.OWNER); + CheckEncryptedWithPasswordDocumentAppending(filename, PdfEncryptionTestUtils.OWNER); } public virtual IX509Certificate GetPublicCertificate(String path) { @@ -563,30 +521,6 @@ public virtual IPrivateKey GetPrivateKey() { return privateKey; } - public static void CheckDecryptedWithPasswordContent(String src, byte[] password, String pageContent) { - CheckDecryptedWithPasswordContent(src, password, pageContent, false); - } - - private static void CheckDecryptedWithPasswordContent(String src, byte[] password, String pageContent, bool - expectError) { - PdfReader reader = CompareTool.CreateOutputReader(src, new ReaderProperties().SetPassword(password)); - PdfDocument document = new PdfDocument(reader); - PdfPage page = document.GetPage(1); - bool expectedContentFound = iText.Commons.Utils.JavaUtil.GetStringForBytes(page.GetStreamBytes(0)).Contains - (pageContent); - String actualCustomInfoEntry = document.GetTrailer().GetAsDictionary(PdfName.Info).GetAsString(new PdfName - (customInfoEntryKey)).ToUnicodeString(); - if (!expectError) { - NUnit.Framework.Assert.IsTrue(expectedContentFound, "Expected content: \n" + pageContent); - NUnit.Framework.Assert.AreEqual(customInfoEntryValue, actualCustomInfoEntry, "Encrypted custom"); - } - else { - NUnit.Framework.Assert.IsFalse(expectedContentFound, "Expected content: \n" + pageContent); - NUnit.Framework.Assert.AreNotEqual(customInfoEntryValue, actualCustomInfoEntry, "Encrypted custom"); - } - document.Close(); - } - // basically this is comparing content of decrypted by itext document with content of encrypted document public virtual void CheckEncryptedWithPasswordDocumentStamping(String filename, byte[] password) { String srcFileName = destinationFolder + filename; @@ -597,7 +531,7 @@ public virtual void CheckEncryptedWithPasswordDocumentStamping(String filename, document.Close(); CompareTool compareTool = new CompareTool(); String compareResult = compareTool.CompareByContent(outFileName, sourceFolder + "cmp_" + filename, destinationFolder - , "diff_", USER, USER); + , "diff_", PdfEncryptionTestUtils.USER, PdfEncryptionTestUtils.USER); if (compareResult != null) { NUnit.Framework.Assert.Fail(compareResult); } @@ -612,29 +546,11 @@ public virtual void CheckEncryptedWithPasswordDocumentAppending(String filename, ().UseAppendMode()); PdfPage newPage = document.AddNewPage(); newPage.Put(PdfName.Default, new PdfString("Hello world string")); - WriteTextBytesOnPageContent(newPage, "Hello world page_2!"); + PdfEncryptionTestUtils.WriteTextBytesOnPageContent(newPage, "Hello world page_2!"); document.Close(); CompareTool compareTool = new CompareTool().EnableEncryptionCompare(); String compareResult = compareTool.CompareByContent(outFileName, sourceFolder + "cmp_appended_" + filename - , destinationFolder, "diff_", USER, USER); - if (compareResult != null) { - NUnit.Framework.Assert.Fail(compareResult); - } - } - - internal static void WriteTextBytesOnPageContent(PdfPage page, String text) { - page.GetFirstContentStream().GetOutputStream().WriteBytes(("q\n" + "BT\n" + "36 706 Td\n" + "0 0 Td\n" + "/F1 24 Tf\n" - + "(" + text + ")Tj\n" + "0 0 Td\n" + "ET\n" + "Q ").GetBytes(iText.Commons.Utils.EncodingUtil.ISO_8859_1 - )); - page.GetResources().AddFont(page.GetDocument(), PdfFontFactory.CreateFont(StandardFonts.HELVETICA)); - } - - internal static void CompareEncryptedPdf(String filename) { - CheckDecryptedWithPasswordContent(destinationFolder + filename, OWNER, pageTextContent); - CheckDecryptedWithPasswordContent(destinationFolder + filename, USER, pageTextContent); - CompareTool compareTool = new CompareTool().EnableEncryptionCompare(); - String compareResult = compareTool.CompareByContent(destinationFolder + filename, sourceFolder + "cmp_" + - filename, destinationFolder, "diff_", USER, USER); + , destinationFolder, "diff_", PdfEncryptionTestUtils.USER, PdfEncryptionTestUtils.USER); if (compareResult != null) { NUnit.Framework.Assert.Fail(compareResult); } diff --git a/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTestUtils.cs b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTestUtils.cs new file mode 100644 index 0000000000..9a2ee50996 --- /dev/null +++ b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTestUtils.cs @@ -0,0 +1,72 @@ +using System; +using iText.IO.Font.Constants; +using iText.Kernel.Font; +using iText.Kernel.Pdf; +using iText.Kernel.Utils; + +namespace iText.Kernel.Crypto.Pdfencryption { + public class PdfEncryptionTestUtils { + private readonly String destinationFolder; + + private readonly String sourceFolder; + + public const String PAGE_TEXT_CONTENT = "Hello world!"; + + public const String CUSTOM_INFO_ENTRY_KEY = "Custom"; + + public const String CUSTOM_INFO_ENTRY_VALUE = "String"; + + /// User password. + public static byte[] USER = "Hello".GetBytes(iText.Commons.Utils.EncodingUtil.ISO_8859_1); + + /// Owner password. + public static byte[] OWNER = "World".GetBytes(iText.Commons.Utils.EncodingUtil.ISO_8859_1); + + public PdfEncryptionTestUtils(String destinationFolder, String sourceFolder) { + this.destinationFolder = destinationFolder; + this.sourceFolder = sourceFolder; + } + + public virtual void CompareEncryptedPdf(String filename) { + CheckDecryptedWithPasswordContent(destinationFolder + filename, OWNER, PAGE_TEXT_CONTENT); + CheckDecryptedWithPasswordContent(destinationFolder + filename, USER, PAGE_TEXT_CONTENT); + CompareTool compareTool = new CompareTool().EnableEncryptionCompare(); + String compareResult = compareTool.CompareByContent(destinationFolder + filename, sourceFolder + "cmp_" + + filename, destinationFolder, "diff_", USER, USER); + if (compareResult != null) { + NUnit.Framework.Assert.Fail(compareResult); + } + } + + public virtual void CheckDecryptedWithPasswordContent(String src, byte[] password, String pageContent) { + CheckDecryptedWithPasswordContent(src, password, pageContent, false); + } + + public virtual void CheckDecryptedWithPasswordContent(String src, byte[] password, String pageContent, bool + expectError) { + PdfReader reader = CompareTool.CreateOutputReader(src, new ReaderProperties().SetPassword(password)); + PdfDocument document = new PdfDocument(reader); + PdfPage page = document.GetPage(1); + bool expectedContentFound = iText.Commons.Utils.JavaUtil.GetStringForBytes(page.GetStreamBytes(0)).Contains + (pageContent); + String actualCustomInfoEntry = document.GetTrailer().GetAsDictionary(PdfName.Info).GetAsString(new PdfName + (CUSTOM_INFO_ENTRY_KEY)).ToUnicodeString(); + if (!expectError) { + NUnit.Framework.Assert.IsTrue(expectedContentFound, "Expected content: \n" + pageContent); + NUnit.Framework.Assert.AreEqual(CUSTOM_INFO_ENTRY_VALUE, actualCustomInfoEntry, "Encrypted custom"); + } + else { + NUnit.Framework.Assert.IsFalse(expectedContentFound, "Expected content: \n" + pageContent); + NUnit.Framework.Assert.AreNotEqual(CUSTOM_INFO_ENTRY_VALUE, actualCustomInfoEntry, "Encrypted custom"); + } + document.Close(); + } + + public static void WriteTextBytesOnPageContent(PdfPage page, String text) { + page.GetFirstContentStream().GetOutputStream().WriteBytes(("q\n" + "BT\n" + "36 706 Td\n" + "0 0 Td\n" + "/F1 24 Tf\n" + + "(" + text + ")Tj\n" + "0 0 Td\n" + "ET\n" + "Q ").GetBytes(iText.Commons.Utils.EncodingUtil.ISO_8859_1 + )); + page.GetResources().AddFont(page.GetDocument(), PdfFontFactory.CreateFont(StandardFonts.HELVETICA)); + } + } +} diff --git a/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest.cs new file mode 100644 index 0000000000..fc3a62eb91 --- /dev/null +++ b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest.cs @@ -0,0 +1,89 @@ +using System; +using iText.Kernel.Logs; +using iText.Kernel.Pdf; +using iText.Kernel.Utils; +using iText.Test; +using iText.Test.Attributes; + +namespace iText.Kernel.Crypto.Pdfencryption { + [NUnit.Framework.Category("IntegrationTest")] + public class PdfPreserveEncryptionTest : ExtendedITextTest { + public static readonly String destinationFolder = NUnit.Framework.TestContext.CurrentContext.TestDirectory + + "/test/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/"; + + public static readonly String sourceFolder = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext + .CurrentContext.TestDirectory) + "/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/"; + + public PdfEncryptionTestUtils encryptionUtil = new PdfEncryptionTestUtils(destinationFolder, sourceFolder); + + [NUnit.Framework.OneTimeSetUp] + public static void BeforeClass() { + CreateOrClearDestinationFolder(destinationFolder); + } + + [NUnit.Framework.OneTimeTearDown] + public static void AfterClass() { + CompareTool.Cleanup(destinationFolder); + } + + [NUnit.Framework.Test] + [LogMessage(KernelLogMessageConstant.MD5_IS_NOT_FIPS_COMPLIANT, Ignore = true)] + [LogMessage(VersionConforming.DEPRECATED_ENCRYPTION_ALGORITHMS)] + public virtual void StampAndUpdateVersionPreserveStandard40() { + String filename = "stampAndUpdateVersionPreserveStandard40.pdf"; + PdfDocument doc = new PdfDocument(new PdfReader(sourceFolder + "encryptedWithPasswordStandard40.pdf", new + ReaderProperties().SetPassword(PdfEncryptionTestUtils.OWNER)), CompareTool.CreateTestPdfWriter(destinationFolder + + filename, new WriterProperties().SetPdfVersion(PdfVersion.PDF_2_0)), new StampingProperties().PreserveEncryption + ()); + doc.Close(); + encryptionUtil.CompareEncryptedPdf(filename); + } + + [NUnit.Framework.Test] + [LogMessage(KernelLogMessageConstant.MD5_IS_NOT_FIPS_COMPLIANT, Ignore = true)] + [LogMessage(VersionConforming.DEPRECATED_AES256_REVISION)] + public virtual void StampAndUpdateVersionPreserveAes256() { + String filename = "stampAndUpdateVersionPreserveAes256.pdf"; + PdfDocument doc = new PdfDocument(new PdfReader(sourceFolder + "encryptedWithPasswordAes256.pdf", new ReaderProperties + ().SetPassword(PdfEncryptionTestUtils.OWNER)), CompareTool.CreateTestPdfWriter(destinationFolder + filename + , new WriterProperties().SetPdfVersion(PdfVersion.PDF_2_0)), new StampingProperties().PreserveEncryption + ()); + doc.Close(); + encryptionUtil.CompareEncryptedPdf(filename); + } + + [NUnit.Framework.Test] + [LogMessage(KernelLogMessageConstant.MD5_IS_NOT_FIPS_COMPLIANT, Ignore = true)] + public virtual void EncryptAes256EncryptedStampingPreserve() { + String filename = "encryptAes256EncryptedStampingPreserve.pdf"; + String src = sourceFolder + "encryptedWithPlainMetadata.pdf"; + String @out = destinationFolder + filename; + PdfDocument pdfDoc = new PdfDocument(new PdfReader(src, new ReaderProperties().SetPassword(PdfEncryptionTestUtils + .OWNER)), CompareTool.CreateTestPdfWriter(@out, new WriterProperties()), new StampingProperties().PreserveEncryption + ()); + pdfDoc.Close(); + CompareTool compareTool = new CompareTool().EnableEncryptionCompare(); + String compareResult = compareTool.CompareByContent(@out, sourceFolder + "cmp_" + filename, destinationFolder + , "diff_", PdfEncryptionTestUtils.USER, PdfEncryptionTestUtils.USER); + if (compareResult != null) { + NUnit.Framework.Assert.Fail(compareResult); + } + } + + [NUnit.Framework.Test] + public virtual void PreserveEncryptionShorterDocumentId() { + String filename = "preserveEncryptionWithShortId.pdf"; + String src = sourceFolder + "encryptedWithShortId.pdf"; + String @out = destinationFolder + filename; + PdfDocument pdfDoc = new PdfDocument(new PdfReader(src, new ReaderProperties().SetPassword(PdfEncryptionTestUtils + .OWNER)), new PdfWriter(@out, new WriterProperties()), new StampingProperties().PreserveEncryption()); + pdfDoc.Close(); + CompareTool compareTool = new CompareTool().EnableEncryptionCompare(); + String compareResult = compareTool.CompareByContent(@out, sourceFolder + "cmp_" + filename, destinationFolder + , "diff_", null, null); + if (compareResult != null) { + NUnit.Framework.Assert.Fail(compareResult); + } + } + } +} diff --git a/itext.tests/itext.kernel.tests/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest.cs similarity index 91% rename from itext.tests/itext.kernel.tests/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest.cs rename to itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest.cs index d9ea585c4f..eb8f653779 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest.cs @@ -29,17 +29,20 @@ You should have received a copy of the GNU Affero General Public License using iText.Test; using iText.Test.Attributes; -namespace iText.Kernel.Crypto { +namespace iText.Kernel.Crypto.Pdfencryption { [NUnit.Framework.Category("BouncyCastleIntegrationTest")] public class UnicodeBasedPasswordEncryptionTest : ExtendedITextTest { public static readonly String destinationFolder = NUnit.Framework.TestContext.CurrentContext.TestDirectory - + "/test/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/"; + + "/test/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/"; public static readonly String sourceFolder = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext - .CurrentContext.TestDirectory) + "/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/"; + .CurrentContext.TestDirectory) + "/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/"; private static IDictionary nameToSaslPrepared; + internal PdfEncryptionTestUtils encryptionUtil = new PdfEncryptionTestUtils(destinationFolder, sourceFolder + ); + static UnicodeBasedPasswordEncryptionTest() { // values are calculated with com.ibm.icu.text.StringPrep class in icu4j v58.2 lib nameToSaslPrepared = new LinkedDictionary(); @@ -160,19 +163,20 @@ public virtual void Aes256EncryptedPdfWithUnicodeBasedPassword() { // 3. Try open encrypted document with password that contains unassigned code points and ensure error is due to wrong password instead of the invalid input string. private void EncryptAes256AndCheck(String filename, byte[] ownerPassword) { int permissions = EncryptionConstants.ALLOW_SCREENREADERS; - WriterProperties writerProperties = new WriterProperties().SetStandardEncryption(PdfEncryptionTest.USER, ownerPassword - , permissions, EncryptionConstants.ENCRYPTION_AES_256).SetPdfVersion(PdfVersion.PDF_2_0); + WriterProperties writerProperties = new WriterProperties().SetStandardEncryption(PdfEncryptionTestUtils.USER + , ownerPassword, permissions, EncryptionConstants.ENCRYPTION_AES_256).SetPdfVersion(PdfVersion.PDF_2_0 + ); PdfWriter writer = CompareTool.CreateTestPdfWriter(destinationFolder + filename, writerProperties.AddXmpMetadata ()); PdfDocument document = new PdfDocument(writer); - document.GetDocumentInfo().SetMoreInfo(PdfEncryptionTest.customInfoEntryKey, PdfEncryptionTest.customInfoEntryValue - ); + document.GetDocumentInfo().SetMoreInfo(PdfEncryptionTestUtils.CUSTOM_INFO_ENTRY_KEY, PdfEncryptionTestUtils + .CUSTOM_INFO_ENTRY_VALUE); PdfPage page = document.AddNewPage(); - PdfEncryptionTest.WriteTextBytesOnPageContent(page, PdfEncryptionTest.pageTextContent); + PdfEncryptionTestUtils.WriteTextBytesOnPageContent(page, PdfEncryptionTestUtils.PAGE_TEXT_CONTENT); page.Flush(); document.Close(); - PdfEncryptionTest.CheckDecryptedWithPasswordContent(destinationFolder + filename, ownerPassword, PdfEncryptionTest - .pageTextContent); + encryptionUtil.CheckDecryptedWithPasswordContent(destinationFolder + filename, ownerPassword, PdfEncryptionTestUtils + .PAGE_TEXT_CONTENT); CompareTool compareTool = new CompareTool().EnableEncryptionCompare(); String compareResult = compareTool.CompareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_", ownerPassword, ownerPassword); diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfEncryptionUnitTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfEncryptionUnitTest.cs index 172d0c10f3..af880137eb 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfEncryptionUnitTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfEncryptionUnitTest.cs @@ -84,5 +84,85 @@ public virtual void ReadEncryptEmbeddedFilesOnlyFromPdfDocumentIncorrectCfTest() cryptDictionary.Put(PdfName.CF, cfDictionary); NUnit.Framework.Assert.IsFalse(PdfEncryption.ReadEmbeddedFilesOnlyFromEncryptDictionary(cryptDictionary)); } + + [NUnit.Framework.Test] + public virtual void CreateIdNormalLength() { + byte[] originalId = new byte[] { 0x33, 0x39, 0x62, 0x38, 0x65, 0x61, 0x30, 0x33, 0x65, 0x32, 0x39, 0x31, 0x38 + , 0x32, 0x66, 0x31, 0x39, 0x63, 0x62, 0x65, 0x64, 0x32, 0x33, 0x37, 0x37, 0x33, 0x61, 0x63, 0x39, 0x65 + , 0x34, 0x39 }; + byte[] modifiedId = new byte[] { 0x08, 0x27, 0x04, 0x30, 0x20, 0x42, 0x22, 0x6A, 0x5F, 0x40, 0x56, 0x57, 0x44 + , 0x4A, 0x6E, 0x1C, 0x18, 0x76, 0x71, (byte)0x80, 0x37, (byte)0x80, 0x71, 0x5C, 0x68, 0x7E, 0x35, 0x41 + , 0x76, 0x30, (byte)0x83, 0x49, 0x2F, 0x07, 0x61, (byte)0xBC, (byte)0xBA, 0x04, 0x37, 0x1B, 0x0E, (byte + )0x80, 0x34, 0x30, 0x4A, 0x3B, 0x0E, 0x27, 0x4F, 0x01, 0x1D, 0x36, 0x71, 0x7A, 0x42, 0x2B, 0x2C, 0x14, + 0x6A, 0x52, 0x07, 0x1E, 0x4C }; + PdfObject fileId = PdfEncryption.CreateInfoId(originalId, modifiedId); + PdfObject expectedFileId = new PdfLiteral("[<3339623865613033653239313832663139636265643233373733616" + "339653439><082704302042226a5f405657444a6e1c187671803780715c687e3541763083492f0761bcba04371b0e80343" + + "04a3b0e274f011d36717a422b2c146a52071e4c>]"); + NUnit.Framework.Assert.AreEqual(expectedFileId, fileId); + } + + [NUnit.Framework.Test] + public virtual void CreateIdNormalLengthWithoutPreserveEncryption() { + byte[] originalId = new byte[] { (byte)0xEB, (byte)0xE3, (byte)0x89, (byte)0xDD, 0x5C, (byte)0xB0, 0x77, 0x59 + , (byte)0xED, (byte)0x9E, 0x17, 0x49, (byte)0xFE, (byte)0x8B, (byte)0x93, (byte)0xB2, 0x2F, 0x6C, (byte + )0x9B, 0x37, 0x6C, 0x5D, 0x5C, (byte)0x9A, 0x6C, 0x10, 0x56, 0x2A, (byte)0xAB, 0x38, (byte)0xFE, 0x1B, + (byte)0xB4, (byte)0xA0, 0x0C, (byte)0xAF, 0x3F, (byte)0xED, (byte)0x99, 0x03, (byte)0x88, (byte)0x9D, + 0x05, 0x5F, (byte)0xE1, 0x5C, (byte)0x99, (byte)0xC4, 0x30, 0x34, 0x5C, (byte)0xEA, 0x68, (byte)0x83, + (byte)0xD2, (byte)0xEC, 0x14, 0x77, 0x52, (byte)0xBE, (byte)0xA5, 0x04, 0x47, 0x07, 0x01 }; + byte[] modifiedId = new byte[] { (byte)0xF5, (byte)0xBF, (byte)0x98, 0x2C, 0x35, (byte)0xAA, 0x0F, (byte)0xFE + , 0x0C, 0x4C, 0x50, (byte)0xE5, 0x0D, (byte)0x9F, 0x09, (byte)0x8E, (byte)0xFC, (byte)0xE8, (byte)0xB6 + , (byte)0xBC, (byte)0xA7, 0x14, (byte)0xFE, 0x7B, 0x26, (byte)0xAC, (byte)0xC0, (byte)0xEB, (byte)0xDC + , (byte)0xCA, (byte)0xF9, 0x09, 0x67, (byte)0x8D, 0x25, (byte)0xF9, 0x2A, (byte)0x82, (byte)0xD4, (byte + )0xA9, (byte)0x83, (byte)0xE3, 0x4F, (byte)0x8F, 0x71, (byte)0x97, (byte)0x8F, (byte)0x9A, 0x58, 0x10, + 0x04, (byte)0xEB, 0x67, (byte)0xC0 }; + PdfObject fileId = PdfEncryption.CreateInfoId(originalId, modifiedId, false); + PdfObject expectedFileId = new PdfLiteral("[]"); + NUnit.Framework.Assert.AreEqual(expectedFileId, fileId); + } + + [NUnit.Framework.Test] + public virtual void CreateINormalLengthWithPreserveEncryption() { + byte[] originalId = new byte[] { (byte)0xB6, (byte)0xE8, (byte)0xF7, 0x65, 0x67, (byte)0xD2, (byte)0xC6, 0x13 + , 0x07, 0x7E, 0x24, (byte)0xB1, (byte)0x94, (byte)0xA9, (byte)0xF6, 0x2E, 0x1F, 0x45, (byte)0xF5, 0x75 + , (byte)0xC2, (byte)0xA1, 0x43, 0x02, 0x5A, 0x31, 0x7B, (byte)0xBF, (byte)0xD5, 0x3B, (byte)0x92, (byte + )0xC8, (byte)0x93, (byte)0xFA, (byte)0xD3, 0x2D, (byte)0x94, (byte)0xA7, 0x43, (byte)0xA1, (byte)0xE7, + (byte)0xAA, 0x6E, 0x75, (byte)0xEC, (byte)0xAF, (byte)0xB7, 0x1A, (byte)0xA1, 0x32, 0x04, (byte)0xAB, + 0x54, 0x58, (byte)0xA1, 0x28, (byte)0xB4, 0x39, 0x6E, (byte)0x97, (byte)0xCF, (byte)0xD2, 0x20, 0x16, + 0x5E }; + byte[] modifiedId = new byte[] { 0x05, 0x2B, 0x7C, 0x61, 0x4A, (byte)0xE8, 0x02, (byte)0x8A, (byte)0xF7, 0x4B + , (byte)0xD8, (byte)0xFF, (byte)0xE6, 0x38, (byte)0xB7, (byte)0x82, (byte)0x84, (byte)0x8A, (byte)0xF5 + , (byte)0x9C, (byte)0xDD, (byte)0xF6, 0x79, 0x38, 0x1A, (byte)0xAD, (byte)0xA8, (byte)0x88, 0x23, (byte + )0xC0, (byte)0xA3, (byte)0x8C, 0x1B, 0x43, 0x28, 0x3B, 0x3A, 0x2A, 0x27, 0x20, 0x19, (byte)0xA8, 0x5E, + (byte)0xD3, (byte)0xD6, (byte)0xF5, 0x04, (byte)0xFA, 0x5E, 0x14, (byte)0xC1, (byte)0xF9, (byte)0xDE, + 0x77, (byte)0xC8, (byte)0x93, 0x6D, (byte)0xB3, (byte)0xE9, (byte)0xDF, (byte)0x80, 0x5D, 0x21, 0x0D }; + PdfObject fileId = PdfEncryption.CreateInfoId(originalId, modifiedId, true); + PdfObject expectedFileId = new PdfLiteral("[<052b7c614ae8028af74bd8" + + "ffe638b782848af59cddf679381aada88823c0a38c1b43283b3a2a272019a85ed3d6f504fa5e14c1f9de77c8936db3e9df" + + "805d210d>]"); + NUnit.Framework.Assert.AreEqual(expectedFileId, fileId); + } + + [NUnit.Framework.Test] + public virtual void CreateIdShortLengthWithoutPreserveEncryption() { + byte[] originalId = new byte[] { (byte)0xE4, 0x04, (byte)0xD5, 0x40, (byte)0xF7, 0x09, 0x4B, (byte)0xE1 }; + byte[] modifiedId = new byte[] { (byte)0xD3, (byte)0xC4, (byte)0xE2, (byte)0x91, (byte)0xBD, (byte)0xFF, 0x7B + , (byte)0xC2, (byte)0xFB, 0x4B, 0x13, 0x3E }; + PdfObject fileId = PdfEncryption.CreateInfoId(originalId, modifiedId, false); + PdfObject expectedFileId = new PdfLiteral("[]" + ); + NUnit.Framework.Assert.AreEqual(expectedFileId, fileId); + } + + [NUnit.Framework.Test] + public virtual void CreateIdShortLengthWithPreserveEncryption() { + byte[] originalId = new byte[] { 0x3B, 0x0D, 0x7A, (byte)0xED, (byte)0xE4, (byte)0xA3, 0x4B, (byte)0xA6, 0x12 + , 0x24, 0x0C, 0x65 }; + byte[] modifiedId = new byte[] { 0x4E, (byte)0x84, 0x4F, (byte)0xC2, (byte)0x86, 0x50, 0x3A, 0x6C, (byte)0x82 + , (byte)0xDF, (byte)0xAB, 0x7D, 0x16, (byte)0x80, 0x75 }; + PdfObject fileId = PdfEncryption.CreateInfoId(originalId, modifiedId, true); + PdfObject expectedFileId = new PdfLiteral("[<3b0d7aede4a34ba612240c65><4e844fc286503a6c82dfab7d168075>]"); + NUnit.Framework.Assert.AreEqual(expectedFileId, fileId); + } } } diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/AdobeAes256.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/AdobeAes256.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/AdobeAes256.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/AdobeAes256.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptAes256FullCompression.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptAes256FullCompression.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptAes256FullCompression.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptAes256FullCompression.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptAes256Pdf2NotEncryptMetadata.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptAes256Pdf2NotEncryptMetadata.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptAes256Pdf2NotEncryptMetadata.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptAes256Pdf2NotEncryptMetadata.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptAes256Pdf2NotEncryptMetadata02.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptAes256Pdf2NotEncryptMetadata02.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptAes256Pdf2NotEncryptMetadata02.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptAes256Pdf2NotEncryptMetadata02.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128NoCompression.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128NoCompression.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128NoCompression.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128NoCompression.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128Pdf2.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128Pdf2.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128Pdf2.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes128Pdf2.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256NoCompression.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256NoCompression.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256NoCompression.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256NoCompression.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256Pdf2.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256Pdf2.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256Pdf2.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordAes256Pdf2.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard128.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard128.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard128.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard128.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard128NoCompression.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard128NoCompression.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard128NoCompression.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard128NoCompression.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard40.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard40.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard40.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard40.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard40NoCompression.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard40NoCompression.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard40NoCompression.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_appended_encryptWithPasswordStandard40NoCompression.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_copiedEncryptedDoc.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_copiedEncryptedDoc.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_copiedEncryptedDoc.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_copiedEncryptedDoc.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptAes256EncryptedStampingUpdate.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptAes256EncryptedStampingUpdate.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptAes256EncryptedStampingUpdate.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptAes256EncryptedStampingUpdate.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptAes256FullCompression.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptAes256FullCompression.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptAes256FullCompression.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptAes256FullCompression.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptAes256Pdf2NotEncryptMetadata.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptAes256Pdf2NotEncryptMetadata.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptAes256Pdf2NotEncryptMetadata.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptAes256Pdf2NotEncryptMetadata.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptAes256Pdf2NotEncryptMetadata02.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptAes256Pdf2NotEncryptMetadata02.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptAes256Pdf2NotEncryptMetadata02.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptAes256Pdf2NotEncryptMetadata02.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptAes256Pdf2Permissions.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptAes256Pdf2Permissions.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptAes256Pdf2Permissions.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptAes256Pdf2Permissions.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes128.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes128.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes128.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes128.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes128NoCompression.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes128NoCompression.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes128NoCompression.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes128NoCompression.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes128NoMetadataCompression.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes128NoMetadataCompression.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes128NoMetadataCompression.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes128NoMetadataCompression.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes128Pdf2.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes128Pdf2.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes128Pdf2.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes128Pdf2.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes256.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes256.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes256.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes256.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes256NoCompression.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes256NoCompression.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes256NoCompression.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes256NoCompression.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes256Pdf2.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes256Pdf2.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordAes256Pdf2.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordAes256Pdf2.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordStandard128.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordStandard128.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordStandard128.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordStandard128.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordStandard128NoCompression.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordStandard128NoCompression.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordStandard128NoCompression.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordStandard128NoCompression.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordStandard40.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordStandard40.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordStandard40.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordStandard40.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordStandard40NoCompression.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordStandard40NoCompression.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptWithPasswordStandard40NoCompression.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_encryptWithPasswordStandard40NoCompression.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_stampAndUpdateVersionNewAes256.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_stampAndUpdateVersionNewAes256.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_stampAndUpdateVersionNewAes256.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_stampAndUpdateVersionNewAes256.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_stamped_encryptAes256FullCompression.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_stamped_encryptAes256FullCompression.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_stamped_encryptAes256FullCompression.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_stamped_encryptAes256FullCompression.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_stamped_encryptAes256Pdf2NotEncryptMetadata02.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_stamped_encryptAes256Pdf2NotEncryptMetadata02.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_stamped_encryptAes256Pdf2NotEncryptMetadata02.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/cmp_stamped_encryptAes256Pdf2NotEncryptMetadata02.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/encryptedAes128EmbeddedFilesOnly.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/encryptedAes128EmbeddedFilesOnly.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/encryptedAes128EmbeddedFilesOnly.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/encryptedAes128EmbeddedFilesOnly.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/encryptedWithCertificateAes128.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/encryptedWithCertificateAes128.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/encryptedWithCertificateAes128.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/encryptedWithCertificateAes128.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/encryptedWithPasswordAes256.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/encryptedWithPasswordAes256.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/encryptedWithPasswordAes256.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/encryptedWithPasswordAes256.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/encryptedWithPasswordStandard40.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/encryptedWithPasswordStandard40.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/encryptedWithPasswordStandard40.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/encryptedWithPasswordStandard40.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/encryptedWithPasswordWithDefaultKeyLength.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/encryptedWithPasswordWithDefaultKeyLength.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/encryptedWithPasswordWithDefaultKeyLength.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/encryptedWithPasswordWithDefaultKeyLength.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/encryptedWithPlainMetadata.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/encryptedWithPlainMetadata.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/encryptedWithPlainMetadata.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/encryptedWithPlainMetadata.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/noUserPassword.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/noUserPassword.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/noUserPassword.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/noUserPassword.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/pageWithContent.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/pageWithContent.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/pageWithContent.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/pageWithContent.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/srcEncryptWithPasswordAes128NoMetadataCompression.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/srcEncryptWithPasswordAes128NoMetadataCompression.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/srcEncryptWithPasswordAes128NoMetadataCompression.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/srcEncryptWithPasswordAes128NoMetadataCompression.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/test.cer b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/test.cer similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/test.cer rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/test.cer diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/test.pem b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/test.pem similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/test.pem rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/test.pem diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/wrong.cer b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/wrong.cer similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/wrong.cer rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/wrong.cer diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/wrong.pem b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/wrong.pem similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/wrong.pem rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfEncryptionTest/wrong.pem diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptAes256EncryptedStampingPreserve.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/cmp_encryptAes256EncryptedStampingPreserve.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_encryptAes256EncryptedStampingPreserve.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/cmp_encryptAes256EncryptedStampingPreserve.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/cmp_preserveEncryptionWithShortId.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/cmp_preserveEncryptionWithShortId.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b1064e29fea36957b5ecedbba6a173abc098cb08 GIT binary patch literal 1999 zcmbVNdu$X%7*C86y+~rvL=FEekE2&YyF2?nDOcL-om7REUbzNtE9_&oJ!p69-d>?q zBd-u!Bo>R{0}3bxk`_hK29-bwMMQZDgg{C}c^L$xSW-hp{HCw=7lp*rsVPdbnfsmk4!O?twj(Csdv1+qdn$-*dM+T`lCAYq1c|q^Q+Iae&E5D(Ps)Xf-L;U9fs8Y zux+TXe%OrzJqt5mTekUn>%FNWk5%H;rg0|&i%T2_{O&3w*Hi{?`aZxEf85?mm z*Pa(+U@iCsO6J*8x=?k%fntdbU4#>M($R5(BnY6$fG9uF1)$NzPP}puLUBzM2ADD& z2$0xF7C7+e%X1JC>Bem<5Ay6Ay-Hy?A^Z4|#-o8tjh#7fu3Y}(QH5d9iYKVlxlHiYbXs?C6Oe0fD&tTnWHRN4M-*I;ZOH zu{geY?uK3Y&t43UYfjeIfdleF$0_E`EnCII&C}m+IDhfE&v!2UWo>20k`F<}t{w%h z+@`vwnf1BpDVCrVO9*`ueI)GVQ&4r)3cD<2ObFUfDLV;_MfCG=BM~Fy2XYUPFp+X0 zyzO(zRTG#Hnx2F!s<9i_RXSur(TQ7SbV=OGu@dotbtI{|gwg~O-32DDDO@py8w|q} ziMU4Zn3HtNL)Gw_=sa65sKOQ<3{R$WLXjxjU)zw_`;PjGU&K`{Lv@S+Ei2OnJ|Tg~ zbrq0=Y%C~mZ9Ln3=HTgB8$c-4b&r%sbCFXsSjAk`1-zv)c)EzRRSG*z_OrqDU$mlIzNw!WnsC|o$*G!TFtV!anuJ6_$D*nSvP20Ztc4Qz6}#KUK(Iwvrafmu$K1W^}x)6is1mL=6dGA1j?I;#mh;tXD7 z3`RtZ?Dsepp?$HOq(Lb7)rZs!<*@yM&h*? w(gd0F#*6VhHzQ~}I77~4GP#V%l$^rIq=I5k!c`r&H>F5GqQ~nE6@)#10o}}`fdBvi literal 0 HcmV?d00001 diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_stampAndUpdateVersionPreserveAes256.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/cmp_stampAndUpdateVersionPreserveAes256.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_stampAndUpdateVersionPreserveAes256.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/cmp_stampAndUpdateVersionPreserveAes256.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_stampAndUpdateVersionPreserveStandard40.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/cmp_stampAndUpdateVersionPreserveStandard40.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/PdfEncryptionTest/cmp_stampAndUpdateVersionPreserveStandard40.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/cmp_stampAndUpdateVersionPreserveStandard40.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/encryptedWithPasswordAes256.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/encryptedWithPasswordAes256.pdf new file mode 100644 index 0000000000000000000000000000000000000000..047927cfdaf60fd3f9bd02976f404a37e74910a8 GIT binary patch literal 4324 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 literal 0 HcmV?d00001 diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/encryptedWithPasswordStandard40.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/encryptedWithPasswordStandard40.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8004a85fd4dda6ce6d57d97d2525d92814ecc82a GIT binary patch literal 3933 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 literal 0 HcmV?d00001 diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/encryptedWithPlainMetadata.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/encryptedWithPlainMetadata.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2cc6b0e189205183e8fbfd2040daffacce2848b0 GIT binary patch literal 3846 zcmd5v*tXfNVwc@E(s;gbwi+9D`PXQy2+zP;)*Yv?KwuKoKCdI)H2GX(m%5FK~(v5c5e)z=>!O3(txi?_eZf z0EIM*-g2K100eYMJm+C$Q3ANeWP(lawygs?lYV77`zanhAo^(zuq;QiRzw z4Ned^K3GHnT6uMgKo^Rb%?l-RDIiG&ScNia66T4b4Cqj|6R`wv9n7!t^Kfz=?}i0M zIM4tLu@R6Zp7A9nl%99FxTIoNaYDRndTO6OLsR=4;m20LIN;FroK)L_!P%XI@5c51 zRh%*7iBA&~5QP!L2$=zyk>sGnyAueSN!AitG6qL?A^DjUEXwgQOX}ZZpjXx{l2&FLT4<-t zg}yV(?;P zmyJe?QZ;P@L$ysBh0px->E=l@Y}@Pwc$@BG>h6zghQd!SZusx~Wb*Zfsp(hkOJrfA zI8~Z{y(;eKebQmBHEn7-*B-y{_1y>G9mkUOJ7o6d5c=zHgaA)!Hr!K5&ykc4Q%(-_qF6!5BSo}JNaO&rsVO%<#XiXEg zEy{l`xwCNl*tH^dP^p~`!&TA3FG_1;!8D~TF=Mt>G&x5!ItE&FZ7R5gE-Qo9{^?ZNCCu1R|(O& zu)r&dmg|~{(k}}3=A7w%=b6_1S8RRDMqRk5pMQJnZLjg{xsh!%-e)gAziFB8_y5|o zwzmDo&b>9?jLqo1WmT{mzoSn4@-5N-MqeRobowpJ%fZ>RpWXMwpkJ@(bbg(7a2V@fav4MCsZhr|a2eO@78 z2xg=(Xp`d&=v`@sDIhdNF3U*CR64+9y91a-i3hYASFsp|1BzB_7>v_%^eCXgGz7#5 zh?6QDH{i5^)OCq@ib>IRqr|xlc@|qF9{QD$QYy=S1B8{8mFh}DElMR2r)e5u8mQ5z z&z>DJk6>h!Q(IF^=ty<1d%Ip(q>+ zc`xr%Y7OFQ9LBQq_W&pa)FE=ztmuQN0~rx9jS#2Z(H=4iGJa%)eV>ut{=;TIAM7ST z;ecZeZc*|vvWfBgy&jfPm{5=zVYDkshBBT-yEZz0gw{e~C-j6C#mUclxD|DUI=miJ zrk4+*t%#R^xzr<+AeE^wLWObE7xk|ggjyeV6$0~kTqDA1a7ZFo&hnDUlg|g`)+`}2P zZi>MeEu(VlDMm$7456a+TD^*NleRvxx}%p;ZjaV=6sI(ge@xXqF*EIAv|zVtp&#A4hYpk( zDH2k(7&7})wg|FIa?wFDbO(sFMX2|`GP?8foF(3)50aPTn_HO8#b*cB*3P;0+qUK3 z{Byv`HJ9!&m)}mB|3OE5&cTi?-}Y+if4Vc!{E>b4?0L89%I>Xr=Y^zsf_0_ky&-dt znW~CnVC`{>h_T0px3g}nIIa19u+JYDbeG*$eTD3|_zh>R>vYzIzclV_oU-n#cA~Uq z%8J(}*Wc(jrFWLQb$h+;+O;g=i{njeo44Bh)8E`xI{On#-PVTY)zuZYN_Y9(!}bFD zZ0`2G8dcM)ofD6ann0Zaf8DWC&9J_EQ;*b6BW~SXdbnifIolG?v3SQzWmDbQpY|*r z)UdJPk2~_`)(x!tKyG>V$=vgWO#6ZZ#`+vD#SC`sT)%ioTiUXAEbY&k=d)^FGdr3G z4=WtMR)4+Y=`p|ARTYCAR^$TzA7`XIA-=yNW)ce2qWei$++@f$?*L{!rAN3j8u>b%7 literal 0 HcmV?d00001 diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/encryptedWithShortId.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest/encryptedWithShortId.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8923e8c95656fbe5212971b429149673e661c742 GIT binary patch literal 1873 zcmbVNeQXp(6iryd_~)qPq+4cDanbn0aN7EU0M zNY3}D-WK@bK>q6LU%U1j-EZytJf%IT#jnNwD1;wKeYSFG;bPZ&0qU3oTVcjBOaJkN z5lg<=GcvS#)V1UN%fl~kIDF!<(0$kacfV|Td{$%c%EfOFKSB97C#Y!X8&;>VKWbjp z=!c$oblOCR5WWiBC&)h>N-Ak{9KCNbb@2Ik>D8OL^D5w znzlaGU6ewwmNbb|MbgaI>mCGfgze!IH0S0$gXS1PkcthM)0i&;jc@SmwqY3>7PnJK zlckXe!^T(;AYy>$C=lt}u2Ta%hsJG8BSESen}{|MqkmAv`w>4sq<9 z4};iSOVWrauqJz!gHNVqtl#_dxh0)xgq8E@5crg|U(U~P&3{U}wle`yg1D(?;=-zy z>0>YXXLf!x7Xsx&wC4B5?nx)-N=Gi2^Yxx<<_+rI3tHnW2826fmOT%-lzG*$DN_rT zvHrAWUJd(StmyCOKONHzIfakYUKzi8D|`w8@JJ&2Iww43Z6$7@dBOHyCau53fO|db zn6In02?mit;U;}>eDcy|3)7j)(Q_*{zt*wC9h0Ay_T$^qe&x*twYy*=-c)tLhEeEy znyrqkJO83{bgk0e)P#B`uR8kE6=gEm~RGgWekS@Q2*)3sV+3wBG%)R~B z)iv4M8Q4cYIkB(2#1k&@#0bm{$e_q*RQL5(H(T1wWH3PLR6R$TKKN<0wLpE_(D|4H zZ`gLS{A}B)c5?R6I+@S-Od%{OF7`!fmGUy_4T{ChgBCIWjBVypOx7UVA$jFWA@bis z;vmwbZ${Zzo%dT}1<*5J;~I7C)ZwG?8GLmt*+d4b3zmyY9wx| zr`xU6V}BSRC~tAQⓈ3d~FSvs-zh!W9n4RSc0BWOr+|Dkx{TL8C2GdNF`A%QM8C* z=sFfOQ!t1wnb;5wOIHM4kTgw{WXXaDEM|~uB4TNpj*&nS(vc=pP0&q~2qw}*qMI_o zq9Q5;6Wzd~Of1PjqKGoo%!m?|1VS{)Aea&vuEbCcNr*J_wT|U-tQYn? literal 0 HcmV?d00001 diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic01.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic01.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic01.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic01.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic02.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic02.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic02.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic02.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic03.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic03.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic03.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic03.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic04.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic04.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic04.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic04.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic05.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic05.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic05.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_arabic05.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_devanagari01.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_devanagari01.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_devanagari01.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_devanagari01.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_devanagari02.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_devanagari02.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_devanagari02.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_devanagari02.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_emoji01.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_emoji01.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_emoji01.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_emoji01.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_gurmukhi01.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_gurmukhi01.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_gurmukhi01.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_gurmukhi01.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_khmer01.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_khmer01.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_khmer01.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_khmer01.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization01.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization01.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization01.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization01.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization02.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization02.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization02.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization02.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization03.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization03.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization03.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization03.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization04.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization04.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization04.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization04.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization05.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization05.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization05.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nfkcNormalization05.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nonAsciiSpace01.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nonAsciiSpace01.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nonAsciiSpace01.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_nonAsciiSpace01.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example01.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example01.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example01.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example01.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example02.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example02.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example02.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example02.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example03.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example03.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example03.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example03.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example04.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example04.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example04.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_rfc4013Example04.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_tamil01.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_tamil01.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_tamil01.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_tamil01.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_thai01.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_thai01.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_thai01.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_thai01.pdf diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_unicodeBom01.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_unicodeBom01.pdf similarity index 100% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_unicodeBom01.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/crypto/pdfencryption/UnicodeBasedPasswordEncryptionTest/cmp_unicodePassword_unicodeBom01.pdf diff --git a/itext/itext.kernel/itext/kernel/pdf/PdfDocument.cs b/itext/itext.kernel/itext/kernel/pdf/PdfDocument.cs index 3f1c1ea214..2555264386 100644 --- a/itext/itext.kernel/itext/kernel/pdf/PdfDocument.cs +++ b/itext/itext.kernel/itext/kernel/pdf/PdfDocument.cs @@ -883,7 +883,7 @@ public virtual void Close() { // either writer properties, or in the writer init section on document open or from pdfreader. So we // shouldn't worry about it being null next PdfObject fileId = PdfEncryption.CreateInfoId(ByteUtils.GetIsoBytes(originalDocumentId.GetValue()), ByteUtils - .GetIsoBytes(modifiedDocumentId.GetValue())); + .GetIsoBytes(modifiedDocumentId.GetValue()), this.properties.preserveEncryption); xref.WriteXrefTableAndTrailer(this, fileId, crypto); writer.Flush(); if (writer.GetOutputStream() is CountOutputStream) { diff --git a/itext/itext.kernel/itext/kernel/pdf/PdfEncryption.cs b/itext/itext.kernel/itext/kernel/pdf/PdfEncryption.cs index b9c3b97522..2b983254aa 100644 --- a/itext/itext.kernel/itext/kernel/pdf/PdfEncryption.cs +++ b/itext/itext.kernel/itext/kernel/pdf/PdfEncryption.cs @@ -368,12 +368,29 @@ public static PdfObject CreateInfoId(byte[] id, bool modified) { /// the first id /// the second id /// PdfObject containing the two entries. + [System.ObsoleteAttribute(@"Use CreateInfoId(byte[], byte[], bool) instead")] public static PdfObject CreateInfoId(byte[] firstId, byte[] secondId) { - if (firstId.Length < 16) { - firstId = PadByteArrayTo16(firstId); - } - if (secondId.Length < 16) { - secondId = PadByteArrayTo16(secondId); + return CreateInfoId(firstId, secondId, false); + } + + /// Creates a PdfLiteral that contains an array of two id entries. + /// + /// Creates a PdfLiteral that contains an array of two id entries. These entries are both hexadecimal + /// strings containing up to 16 hex characters. The first entry is the original id, the second entry + /// should be different from the first one if the document has changed. + /// + /// the first id + /// the second id + /// the encryption preserve + /// PdfObject containing the two entries. + public static PdfObject CreateInfoId(byte[] firstId, byte[] secondId, bool preserveEncryption) { + if (!preserveEncryption) { + if (firstId.Length < 16) { + firstId = PadByteArrayTo16(firstId); + } + if (secondId.Length < 16) { + secondId = PadByteArrayTo16(secondId); + } } ByteBuffer buf = new ByteBuffer(90); buf.Append('[').Append('<'); diff --git a/port-hash b/port-hash index 1bbbc24ab4..4c444e4c62 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -08a48fa84a99696e352373caeaf7d8809ccf8b5c +dc0cad35799ce13a2006d086bd118e28bb814868 From a7b631dbab46c84d1f7a481773945596ab6891a0 Mon Sep 17 00:00:00 2001 From: iText Software Date: Sun, 24 Dec 2023 21:10:07 +0000 Subject: [PATCH 2/4] Add missing copyright headers Autoported commit. Original commit hash: [e42df9900] --- .../pdfencryption/PdfEncryptionTestUtils.cs | 22 +++++++++++++++++++ .../PdfPreserveEncryptionTest.cs | 22 +++++++++++++++++++ port-hash | 2 +- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTestUtils.cs b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTestUtils.cs index 9a2ee50996..9b93702b8e 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTestUtils.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTestUtils.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2023 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.IO.Font.Constants; using iText.Kernel.Font; diff --git a/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest.cs index fc3a62eb91..3288bd3aef 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfPreserveEncryptionTest.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2023 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.Kernel.Logs; using iText.Kernel.Pdf; diff --git a/port-hash b/port-hash index 4c444e4c62..8c700c033a 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -dc0cad35799ce13a2006d086bd118e28bb814868 +e42df9900a85efce83693203f1dc9e3a98459e0c From 2e048ba27a8f257895d099c687200d647cce829c Mon Sep 17 00:00:00 2001 From: Guust Ysebie Date: Tue, 26 Dec 2023 13:16:04 +0000 Subject: [PATCH 3/4] Place caption tag in tables in correct location DEVSIX-7951 Autoported commit. Original commit hash: [6ef7dd755] --- .../itext/layout/LayoutTaggingTest.cs | 19 +++++++ .../itext/layout/PdfUA2Test.cs | 46 +++++++++++++++- .../cmp_unexpectedTableHintChildTest.pdf | Bin 0 -> 2154 bytes .../layout/PdfUA2Test/cmp_captionTest.pdf | Bin 24855 -> 24855 bytes ...p_checkCaptionPlacementInTreeStructure.pdf | Bin 0 -> 34149 bytes .../cmp_taggedTableWithCaptionTest01.pdf | Bin 32253 -> 32456 bytes .../itext/layout/tagging/ITaggingRule.cs | 18 +++++++ .../layout/tagging/LayoutTaggingHelper.cs | 23 ++++---- .../itext/layout/tagging/TableTaggingRule.cs | 37 ++++++++++++- .../layout/tagging/TaggingDummyElement.cs | 28 ++++++++++ .../itext/layout/tagging/TaggingHintKey.cs | 51 ++++++++++++++++++ port-hash | 2 +- 12 files changed, 211 insertions(+), 13 deletions(-) create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/LayoutTaggingTest/cmp_unexpectedTableHintChildTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/PdfUA2Test/cmp_checkCaptionPlacementInTreeStructure.pdf diff --git a/itext.tests/itext.layout.tests/itext/layout/LayoutTaggingTest.cs b/itext.tests/itext.layout.tests/itext/layout/LayoutTaggingTest.cs index 2990d720c1..d47cb720aa 100644 --- a/itext.tests/itext.layout.tests/itext/layout/LayoutTaggingTest.cs +++ b/itext.tests/itext.layout.tests/itext/layout/LayoutTaggingTest.cs @@ -865,6 +865,25 @@ public virtual void NeutralRoleTaggingTest() { CompareResult(outFile, "cmp_" + outFile); } + [NUnit.Framework.Test] + public virtual void UnexpectedTableHintChildTest() { + String outFile = "unexpectedTableHintChildTest.pdf"; + using (PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + outFile))) { + Document document = new Document(pdfDocument); + pdfDocument.SetTagged(); + Div div = new Div(); + div.GetAccessibilityProperties().SetRole(StandardRoles.TABLE); + Paragraph c1 = new Paragraph("c1"); + c1.GetAccessibilityProperties().SetRole(StandardRoles.LINK); + div.Add(c1); + Paragraph p1 = new Paragraph("c"); + p1.GetAccessibilityProperties().SetRole(StandardRoles.TD); + div.Add(p1); + document.Add(div); + } + CompareResult(outFile, "cmp_" + outFile); + } + private Paragraph CreateParagraph1() { PdfFont font = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLD); Paragraph p = new Paragraph().Add("text chunk. ").Add("explicitly added separate text chunk"); diff --git a/itext.tests/itext.layout.tests/itext/layout/PdfUA2Test.cs b/itext.tests/itext.layout.tests/itext/layout/PdfUA2Test.cs index 7add8163b1..4fa68db60e 100644 --- a/itext.tests/itext.layout.tests/itext/layout/PdfUA2Test.cs +++ b/itext.tests/itext.layout.tests/itext/layout/PdfUA2Test.cs @@ -455,13 +455,55 @@ public virtual void CheckCaptionTest() { document.Add(table); PdfStructTreeRoot structTreeRoot = pdfDocument.GetStructTreeRoot(); IStructureNode tableNode = structTreeRoot.GetKids()[0].GetKids()[0]; - // TODO DEVSIX-7951 Table caption is added as the 2nd child of the table into struct tree - String tableChildRole = tableNode.GetKids()[1].GetRole().ToString(); + String tableChildRole = tableNode.GetKids()[0].GetRole().ToString(); NUnit.Framework.Assert.AreEqual("/Caption", tableChildRole); } CompareAndValidate(outFile, cmpFile); } + [NUnit.Framework.Test] + public virtual void CheckCaptionPlacementInTreeStructure() { + String outFile = DESTINATION_FOLDER + "checkCaptionPlacementInTreeStructure.pdf"; + String cmpFile = SOURCE_FOLDER + "cmp_checkCaptionPlacementInTreeStructure.pdf"; + using (PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFile, new WriterProperties().SetPdfVersion + (PdfVersion.PDF_2_0)))) { + Document document = new Document(pdfDocument); + PdfFont font = PdfFontFactory.CreateFont(FONT_FOLDER + "FreeSans.ttf", "WinAnsi", PdfFontFactory.EmbeddingStrategy + .FORCE_EMBEDDED); + document.SetFont(font); + CreateSimplePdfUA2Document(pdfDocument); + Table tableCaptionBottom = new Table(new float[] { 1, 2, 2 }); + Paragraph caption = new Paragraph("This is Caption to the bottom").SetBackgroundColor(ColorConstants.GREEN + ); + tableCaptionBottom.SetCaption(new Div().Add(caption), CaptionSide.BOTTOM); + tableCaptionBottom.SetHorizontalAlignment(HorizontalAlignment.CENTER); + tableCaptionBottom.SetWidth(200); + tableCaptionBottom.AddHeaderCell("ID"); + tableCaptionBottom.AddHeaderCell("Name"); + tableCaptionBottom.AddHeaderCell("Age"); + for (int i = 1; i <= 5; i++) { + tableCaptionBottom.AddCell("ID: " + i); + tableCaptionBottom.AddCell("Name " + i); + tableCaptionBottom.AddCell("Age: " + (20 + i)); + } + document.Add(tableCaptionBottom); + Table captionTopTable = new Table(new float[] { 1, 2, 3 }); + captionTopTable.SetCaption(new Div().Add(new Paragraph("Caption on top"))); + captionTopTable.SetHorizontalAlignment(HorizontalAlignment.CENTER); + captionTopTable.SetWidth(200); + captionTopTable.AddHeaderCell("ID"); + captionTopTable.AddHeaderCell("Name"); + captionTopTable.AddHeaderCell("Age"); + for (int i = 1; i <= 5; i++) { + captionTopTable.AddCell("ID: " + i); + captionTopTable.AddCell("Name " + i); + captionTopTable.AddCell("Age: " + (20 + i)); + } + document.Add(captionTopTable); + } + CompareAndValidate(outFile, cmpFile); + } + [NUnit.Framework.Test] public virtual void CheckFigurePropertiesTest() { String outFile = DESTINATION_FOLDER + "figurePropertiesTest.pdf"; diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/LayoutTaggingTest/cmp_unexpectedTableHintChildTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/LayoutTaggingTest/cmp_unexpectedTableHintChildTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ae012564ed50c2c801c9992106ab285bd9aa9e14 GIT binary patch literal 2154 zcmc&$OOM-B6z;NEMO0#qbT^~UfF{1zuWO?yQf4wQWga1k$|B9;#=Z%r89Q9tWzyfm z8i@@WghbbDDj^{urd_g`w(36swwz;ol1$PWv8y-sJwA``JicSEwHmvdtirXmSFitg zp>aY7cx^Zx`t1Cr={&r9aCx!syuA0@EA`=}_D21k zy}j6DzutfL!SMOh=ilG|xOMN&onQX?WJi-xPzHe~#N^DeZO2h6qckCix2+$^AQW5i zS&zce_H5!>Mqh6U1vVUrN5cf}ylJ9<}z zrz@Vj(}@K4BU!5XY?Cm(MOXo>H6oZ;8)9`PBGPl; z1(=<&JY9%@`lW|Dz~4exrbD=GRj5U5+auhi6$+W3=!aq&XDNF0Wqk;JBvx_QlEYX@ zVnN0LBgY6>+!8^zaZ7y6YnA~8D=)YD-wB}l%)Y47Lg>RVdVEW8Yi_&%cPkF2HydGA zw-?N%&b(S!l3vl3A~nJ=Y8xhrV0W=aFco8YbHuA5fc7-YqP9rx1Z*3zpPj-)-fX^* zWV4rtyqe;!l9I4uP>LBv$+0|3n{o={)Q-pUNKC3#NMd1vP^lfq>3oV7#&8=LoQ84K z0D`YKJ~yagGQ%(!H(g3UqviujA8hDHad5jrOT|IvOSK+$0nU$P8|TZd(2BX)Ij*-l z`zKxUXuZDIIwVh|N+95)4f2CQDc!`7q&`v8M3OxfXA^S#aAS@Y$yxUANT|mL(J+R> z;-d@*&=u&HvoI++Ua;mW=d$j3HMT`6#_?#u^@8s$kw{z#`o0`Lk!k1)eJ6r_7e*uf z%P^`(NjN)qvO$XEN3X1?G@8yGFOYOQ&S3p8y%`2cFK=DHu)xic%uVvPmU$j$rwMGa ze4DiUbDc9KhZ@Ma26Zbh;@GxnlOZW(jJZHjyht>Yna-+=Qeeh)J?c@Q=aS5|0QHiL zaj4vqj3V4688@L4OEQP8#;|P|`s;ekct;G&SjF;=+^EA>W0=NDzRbeae-$@XA{O~#!;-~oBK zZA)%BAeU57pSgkSaA~`s;F`n01AVaP_P`Vdr?%tqK*)jb2g3FxH{9C$N6^=iZlw4? s;0htg7+8VfQ&>bCCUY(4`zF$T^E%zNBo!*nN0wO@{93H-oa}1<0d+fDd;kCd literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/PdfUA2Test/cmp_captionTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/PdfUA2Test/cmp_captionTest.pdf index fa05e0553854e34b83aff3d19b4bb07d329938f7..6f88bfff02348769cff3cc611c00d58030780baa 100644 GIT binary patch delta 598 zcmc(ZyGlbr5QYgSXo!#|A~uEt!73Ird*3KlRt8Zd5KTbbv%9AetnC6?Suc`jNGEJz zA0I$01q&N1EqnxzmqKzLz^VTEW-`Q&x%GXvDpT*};M%4y>P7)VH-g9)wi9>_NVouRg zu2n8+PQ6glaHBobIkTXA&X8DQY#}KooKcEMW(>)d%QP=cZ~bS5YSF=l H`_uj>@+6%b delta 632 zcmc(bJxc>Y5QaG}NQe*{iIw3Xr53ZZvtLofMo>~{LMnye?%rK#Eg}T$tPk-ASfvy8 zAH>qa+D7cPu(I}IEF@>|R5Q=K^LaasZl}@xBn~gNW-Ux&5ry~q&1zjGkPH$@;d*^5 zS_WboCFdK!i>G$$cN{+2SDQ-JOe8CLj=I87V1+4Jt(AgRbV7+mhBRkk<>WHnMPyJ> zz#kJ$wG-0@i^tLDICU!bMA{ke$pUwVfw9Vp6eS>XsZ{2e(m4|3M7h^qSqVHX-;dUb zOs7_5mddM4E);pCSZdKY?{jTYr$E|!;jC4XIEa}9w9Gs=sb(<7o$dczp;qpI#lz|F E3rLTj=>Px# diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/PdfUA2Test/cmp_checkCaptionPlacementInTreeStructure.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/PdfUA2Test/cmp_checkCaptionPlacementInTreeStructure.pdf new file mode 100644 index 0000000000000000000000000000000000000000..350e63851fe8218cecfde3de2bdbd41396d81d8c GIT binary patch literal 34149 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 EA0@ZjE&u=k literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/TableTest/cmp_taggedTableWithCaptionTest01.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/TableTest/cmp_taggedTableWithCaptionTest01.pdf index f5a8142f5382b71b18a406bc67f081b903dd774c..d36bcd9f10508a22380c1bc1c3d55da6bdb0d2a4 100644 GIT binary patch delta 2402 zcmc&$&x=$?5N1$Nmmq-&s3C_Z{@T^7R##Vdb;)8};*T7RyP`w{3CzrUPd199g%t*_ul-| z`u$Do=T{IPnHTXDJR8m8FYk?tv!kP>f?XBmn_;lf; z2CYHk5hxfq0p=LMv8hv^_sesgVKsT~G{RWG{GeYh_Nu|;!nJB?_*3y|e^3?SB%HL< zS1-@bU;S+ET5)r7_Tv1d;$by-u+YDIbE^0O0bqLV#A5c|VEI8+TpaA`FWxIIe=!x! zLKSDedi^mQV~T_WDDD;$>pzfDRLzT(c;oit9qGJyV0d`6=gz_1J5qO?9zNbjp0Y#I zj3V*Zm39l_%aub1jCT?gh62aGhV6#cKf*Z$^U7=pPL#3G7^lb>Ag{;>YaET~wM6mCQhO%9F*E`5n?<8-onnaMcS|2A z8(@+&cPknpr93)Nx}lZa8i+PUP?j+mQsS)FqFuJ1Bz`%3y;nFgx|hIePNH@ZUHET7n(Yxv-l>}#Dgn37|;hsrU9lFKfU?UYrS(!iA5?UqoNy)vQez^+USh2C_6@Ah0JJ@2X@rml&J zT&kp3t*Mx?Q*p_LJa<6I_grnU*Q+|j4WF6$KPl`?960{CdSYVjOJ;igOD6ugx_`Hy MICA9t+=YpM0e?LUcK`qY delta 2388 zcmai0O=}Zj5GFSX-aL3vWG}U?ns#R1dB3z&iq$G;TWs;tinPrtvC_zPD=mn77EiJl z|3Vc+$-#qvK=9~~=tcSitVQ1>mSlGpB!?u!GdnZSJoB*Mj%&w9wNHnT@8i4t5WaS1 z=*#KOhxk&h^K1I^#r((P^c3pdK6ziu4_YhvwbuCz9THju ztq2>SMgd00C-1eJvukNQHhYzz60n%Gn>!nEGS*s-chirNoxlm*Sel<%T)Mrm9PJYT zG`hJ_4-m~I?Vab*{DWw9Y-VopZsSFqY`5B5tK+rt+&w+IV!ZNE$N`A9qI&NKS#ny$ zKtcX!^YvNuVWt8e$yn3*vx%qj-o@bjcCTQ7K2z-U@X)JKnrpbYh)1zh2(y&x3aJY5p&83 zW*lW!P~!+>%xb}m3p*(@5T z02FH?8_c%7=dXh>Dk3lZCd5$mso1#uV9y616a6Y9gilI~3noTstU*D7JmqzfyuclE zKX=&2!l)$V5_l4FF(?j+*lV$Ic9J}{b{N<5G1B2v*0V+ya?xPLblQ+$P-_%TYi5b_ zSw*sw>(Z8mG_4l8gsItn?Y3aotD{Ruq6M{f!nNLJ7RDiB) zIUqrtB>hehOwWPkCt|jSi5. */ namespace iText.Layout.Tagging { + /// + /// Implementation of the interface is used to create required children + /// structure for the specified role. + /// + /// + /// Implementation of the interface is used to create required children + /// structure for the specified role. E.g. table must have TRs as children. + /// internal interface ITaggingRule { + /// Action which creates required children structure for the role. + /// tagging helper. + /// element for which children structure will be created. + /// + /// + /// + /// if the structure was created successfully, + /// + /// otherwise. + /// bool OnTagFinish(LayoutTaggingHelper taggingHelper, TaggingHintKey taggingHintKey); } } diff --git a/itext/itext.layout/itext/layout/tagging/LayoutTaggingHelper.cs b/itext/itext.layout/itext/layout/tagging/LayoutTaggingHelper.cs index 52c6223599..e940823f8f 100644 --- a/itext/itext.layout/itext/layout/tagging/LayoutTaggingHelper.cs +++ b/itext/itext.layout/itext/layout/tagging/LayoutTaggingHelper.cs @@ -34,6 +34,10 @@ You should have received a copy of the GNU Affero General Public License using iText.Layout.Renderer; namespace iText.Layout.Tagging { + /// + /// The class is a helper which is used to correctly create structure + /// tree for layout element (with keeping right order for tags). + /// public class LayoutTaggingHelper { private TagStructureContext context; @@ -41,6 +45,8 @@ public class LayoutTaggingHelper { private bool immediateFlush; + // kidsHints and parentHints fields represent tree of TaggingHintKey, where parentHints + // stores a parent for the key, and kidsHints stores kids for key. private IDictionary> kidsHints; private IDictionary parentHints; @@ -49,7 +55,8 @@ public class LayoutTaggingHelper { private IDictionary> taggingRules; - private IDictionary existingTagsDummies; + // dummiesForPreExistingTags is used to process TaggingDummyElement + private IDictionary dummiesForPreExistingTags; private readonly int RETVAL_NO_PARENT = -1; @@ -64,7 +71,7 @@ public LayoutTaggingHelper(PdfDocument document, bool immediateFlush) { this.autoTaggingPointerSavedPosition = new Dictionary(); this.taggingRules = new Dictionary>(); RegisterRules(context.GetTagStructureTargetVersion()); - existingTagsDummies = new LinkedDictionary(); + dummiesForPreExistingTags = new LinkedDictionary(); } public static void AddTreeHints(iText.Layout.Tagging.LayoutTaggingHelper taggingHelper, IRenderer rootRenderer @@ -90,10 +97,10 @@ public static TaggingHintKey GetOrCreateHintKey(IPropertyContainer container) { public virtual void AddKidsHint<_T0>(TagTreePointer parentPointer, IEnumerable<_T0> newKids) where _T0 : IPropertyContainer { PdfDictionary pointerStructElem = context.GetPointerStructElem(parentPointer).GetPdfObject(); - TaggingDummyElement dummy = existingTagsDummies.Get(pointerStructElem); + TaggingDummyElement dummy = dummiesForPreExistingTags.Get(pointerStructElem); if (dummy == null) { dummy = new TaggingDummyElement(parentPointer.GetRole()); - existingTagsDummies.Put(pointerStructElem, dummy); + dummiesForPreExistingTags.Put(pointerStructElem, dummy); } context.GetWaitingTagsManager().AssignWaitingState(parentPointer, GetOrCreateHintKey(dummy)); AddKidsHint(dummy, newKids); @@ -285,11 +292,11 @@ public virtual void ReleaseFinishedHints() { } public virtual void ReleaseAllHints() { - foreach (TaggingDummyElement dummy in existingTagsDummies.Values) { + foreach (TaggingDummyElement dummy in dummiesForPreExistingTags.Values) { FinishTaggingHint(dummy); FinishDummyKids(GetKidsHint(GetHintKey(dummy))); } - existingTagsDummies.Clear(); + dummiesForPreExistingTags.Clear(); ReleaseFinishedHints(); ICollection hangingHints = new HashSet(); foreach (KeyValuePair entry in parentHints) { @@ -499,6 +506,7 @@ private void AddKidsHint(TaggingHintKey parentKey, ICollection n else { kidsHint.Add(kidKey); } + kidsHints.Put(parentKey, kidsHint); parentHints.Put(kidKey, parentKey); if (parentTagAlreadyCreated) { if (kidKey.GetAccessibleElement() is TaggingDummyElement) { @@ -517,9 +525,6 @@ private void AddKidsHint(TaggingHintKey parentKey, ICollection n } } } - if (!kidsHint.IsEmpty()) { - kidsHints.Put(parentKey, kidsHint); - } } private bool CreateSingleTag(TaggingHintKey hintKey, TagTreePointer tagPointer) { diff --git a/itext/itext.layout/itext/layout/tagging/TableTaggingRule.cs b/itext/itext.layout/itext/layout/tagging/TableTaggingRule.cs index 80221f4a8d..751a6d86ee 100644 --- a/itext/itext.layout/itext/layout/tagging/TableTaggingRule.cs +++ b/itext/itext.layout/itext/layout/tagging/TableTaggingRule.cs @@ -25,6 +25,7 @@ You should have received a copy of the GNU Affero General Public License using iText.Commons.Utils; using iText.Kernel.Pdf.Tagging; using iText.Layout.Element; +using iText.Layout.Properties; namespace iText.Layout.Tagging { internal class TableTaggingRule : ITaggingRule { @@ -66,7 +67,10 @@ public virtual bool OnTagFinish(LayoutTaggingHelper taggingHelper, TaggingHintKe tbodyTag = new TaggingDummyElement(createTBody ? StandardRoles.TBODY : null); foreach (TaggingHintKey nonCellKid in nonCellKids) { String kidRole = nonCellKid.GetAccessibleElement().GetAccessibilityProperties().GetRole(); - if (!StandardRoles.THEAD.Equals(kidRole) && !StandardRoles.TFOOT.Equals(kidRole)) { + if (!StandardRoles.THEAD.Equals(kidRole) && !StandardRoles.TFOOT.Equals(kidRole) && !StandardRoles.CAPTION + .Equals(kidRole)) { + // In usual cases it isn't expected that this for loop will work, but it is possible to + // create custom tag hierarchy by specifying role, and put any child to tableHintKey taggingHelper.MoveKidHint(nonCellKid, tableHintKey); } } @@ -98,7 +102,38 @@ public virtual bool OnTagFinish(LayoutTaggingHelper taggingHelper, TaggingHintKe } taggingHelper.AddKidsHint(tbodyTag, JavaCollectionsUtil.SingletonList(row), -1); } + foreach (TaggingHintKey nonCellKid in nonCellKids) { + String kidRole = nonCellKid.GetAccessibleElement().GetAccessibilityProperties().GetRole(); + if (StandardRoles.CAPTION.Equals(kidRole)) { + MoveCaption(taggingHelper, nonCellKid, tableHintKey); + } + } return true; } + + private static void MoveCaption(LayoutTaggingHelper taggingHelper, TaggingHintKey caption, TaggingHintKey + tableHintKey) { + if (!(tableHintKey.GetAccessibleElement() is Table)) { + return; + } + Table tableElem = (Table)tableHintKey.GetAccessibleElement(); + Div captionDiv = tableElem.GetCaption(); + if (captionDiv == null) { + return; + } + CaptionSide captionSide; + if (captionDiv.GetProperty(Property.CAPTION_SIDE) == null) { + captionSide = CaptionSide.TOP; + } + else { + captionSide = (CaptionSide)captionDiv.GetProperty(Property.CAPTION_SIDE); + } + if (CaptionSide.TOP.Equals(captionSide)) { + taggingHelper.MoveKidHint(caption, tableHintKey, 0); + } + else { + taggingHelper.MoveKidHint(caption, tableHintKey); + } + } } } diff --git a/itext/itext.layout/itext/layout/tagging/TaggingDummyElement.cs b/itext/itext.layout/itext/layout/tagging/TaggingDummyElement.cs index f88fda7026..dae4d013f9 100644 --- a/itext/itext.layout/itext/layout/tagging/TaggingDummyElement.cs +++ b/itext/itext.layout/itext/layout/tagging/TaggingDummyElement.cs @@ -26,19 +26,41 @@ You should have received a copy of the GNU Affero General Public License using iText.Layout.Properties; namespace iText.Layout.Tagging { + /// + /// Instances of the class are used for + /// + /// which don't have model element + /// e.g. TR or THEAD in the table. + /// + /// + /// Instances of the class are used for + /// + /// which don't have model element + /// e.g. TR or THEAD in the table. Nobody will call + /// + /// for them, it is why they should be handled separately. + /// public class TaggingDummyElement : IAccessibleElement, IPropertyContainer { private DefaultAccessibilityProperties properties; private Object id; + /// + /// Instantiate a new + /// + /// instance. + /// + /// the role. public TaggingDummyElement(String role) { this.properties = new DefaultAccessibilityProperties(role); } + /// public virtual AccessibilityProperties GetAccessibilityProperties() { return properties; } + /// public virtual T1 GetProperty(int property) { if (property == Property.TAGGING_HINT_KEY) { return (T1)id; @@ -46,28 +68,34 @@ public virtual T1 GetProperty(int property) { return (T1)(Object)null; } + /// public virtual void SetProperty(int property, Object value) { if (property == Property.TAGGING_HINT_KEY) { this.id = value; } } + /// public virtual bool HasProperty(int property) { throw new NotSupportedException(); } + /// public virtual bool HasOwnProperty(int property) { throw new NotSupportedException(); } + /// public virtual T1 GetOwnProperty(int property) { throw new NotSupportedException(); } + /// public virtual T1 GetDefaultProperty(int property) { throw new NotSupportedException(); } + /// public virtual void DeleteOwnProperty(int property) { throw new NotSupportedException(); } diff --git a/itext/itext.layout/itext/layout/tagging/TaggingHintKey.cs b/itext/itext.layout/itext/layout/tagging/TaggingHintKey.cs index 759aef908f..07fad733fe 100644 --- a/itext/itext.layout/itext/layout/tagging/TaggingHintKey.cs +++ b/itext/itext.layout/itext/layout/tagging/TaggingHintKey.cs @@ -23,6 +23,11 @@ You should have received a copy of the GNU Affero General Public License using System; namespace iText.Layout.Tagging { + /// + /// TaggingHintKey instances are created in the scope of + /// + /// to preserve logical order of layout elements from model elements. + /// public sealed class TaggingHintKey { private IAccessibleElement elem; @@ -34,39 +39,85 @@ public sealed class TaggingHintKey { private bool elementBasedFinishingOnly; + /// + /// Instantiate a new + /// + /// instance. + /// + /// element this hint key will be created for. + /// + /// + /// + /// if element implements + /// . + /// internal TaggingHintKey(IAccessibleElement elem, bool createdElementBased) { this.elem = elem; this.elementBasedFinishingOnly = createdElementBased; } + /// Get accessible element. + /// the accessible element. public IAccessibleElement GetAccessibleElement() { return elem; } + /// Retrieve hint key finished flag. + /// + /// + /// + /// if hint key is finished, + /// + /// otherwise. + /// internal bool IsFinished() { return isFinished; } + /// Set finished flag for hint key instance. internal void SetFinished() { this.isFinished = true; } + /// Retrieve information whether this hint key is artifact or not. + /// + /// + /// + /// if hint key corresponds to artifact, + /// + /// otherwise. + /// internal bool IsArtifact() { return isArtifact; } + /// Specify that hint key instance corresponds to artifact. internal void SetArtifact() { this.isArtifact = true; } + /// Get overridden role. + /// the overridden role. internal String GetOverriddenRole() { return overriddenRole; } + /// Set the overridden role. + /// overridden role. internal void SetOverriddenRole(String overriddenRole) { this.overriddenRole = overriddenRole; } + /// + /// Retrieve information whether the element backed by this hint key implements + /// . + /// + /// + /// + /// + /// true if element implements + /// . + /// internal bool IsElementBasedFinishingOnly() { return elementBasedFinishingOnly; } diff --git a/port-hash b/port-hash index 8c700c033a..3fdaf207d1 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -e42df9900a85efce83693203f1dc9e3a98459e0c +6ef7dd755c8cbfc82f9b769a9bd9cbb4c9e63be3 From 6d729e719533a50914d0309f9b1b0e4f80ad7960 Mon Sep 17 00:00:00 2001 From: Glenn Volckaert Date: Thu, 21 Dec 2023 22:19:12 +0000 Subject: [PATCH 4/4] Add CMS container class for use with 2 phase signing DEVSIX-7842 Autoported commit. Original commit hash: [0171de5c2] Manual files: bouncy-castle-adapter/src/main/java/com/itextpdf/bouncycastle/cert/X509CertificateHolderBC.java bouncy-castle-fips-adapter/src/main/java/com/itextpdf/bouncycastlefips/cert/X509CertificateHolderBCFips.java commons/src/main/java/com/itextpdf/commons/bouncycastle/cert/IX509CertificateHolder.java sharpenConfiguration.xml sign/src/main/java/com/itextpdf/signatures/SignUtils.java sign/src/test/java/com/itextpdf/signatures/sign/TwoPhaseSigningTest.java sign/src/test/java/com/itextpdf/signatures/testutils/SignTestPortUtil.java --- .../itext/signatures/PdfSignerUnitTest.cs | 13 +- .../itext/signatures/cms/CMSContainerTest.cs | 193 +++++ .../itext/signatures/cms/CMSTestHelper.cs | 739 ++++++++++++++++++ .../cms/EncapsulatedContentInfoTest.cs | 73 ++ .../itext/signatures/cms/SignerInfoTest.cs | 347 ++++++++ .../signatures/sign/TwoPhaseSigningTest.cs | 109 ++- .../signatures/testutils/SignTestPortUtil.cs | 6 + .../testutils/X509MockCertificate.cs | 10 + .../itext/signatures/certs/signCertRsa01.xml | 10 + .../cmp_2PhaseCompleteCycle.pdf | Bin 11688 -> 11708 bytes .../cmp_2PhaseCompleteCycleCMS.pdf | Bin 0 -> 11708 bytes .../bouncycastle/asn1/Asn1EncodableBC.cs | 2 +- .../bouncycastle/x509/X509CertificateBC.cs | 6 + .../asn1/Asn1EncodableBCFips.cs | 2 +- .../cert/X509CertificateBCFips.cs | 8 +- .../bouncycastle/cert/IX509Certificate.cs | 12 + .../itext/signatures/CertificateUtil.cs | 10 +- .../itext.sign/itext/signatures/PdfSigner.cs | 55 +- .../itext/signatures/SecurityIDs.cs | 2 + .../itext/signatures/SignExtensions.cs | 21 + .../itext.sign/itext/signatures/SignUtils.cs | 4 + .../signatures/cms/AlgorithmIdentifier.cs | 87 +++ .../itext/signatures/cms/Attribute.cs | 53 ++ .../itext/signatures/cms/CMSContainer.cs | 275 +++++++ .../signatures/cms/EncapsulatedContentInfo.cs | 89 +++ .../itext/signatures/cms/SignerInfo.cs | 532 +++++++++++++ .../SignExceptionMessageConstant.cs | 13 + port-hash | 2 +- 28 files changed, 2638 insertions(+), 35 deletions(-) create mode 100644 itext.tests/itext.sign.tests/itext/signatures/cms/CMSContainerTest.cs create mode 100644 itext.tests/itext.sign.tests/itext/signatures/cms/CMSTestHelper.cs create mode 100644 itext.tests/itext.sign.tests/itext/signatures/cms/EncapsulatedContentInfoTest.cs create mode 100644 itext.tests/itext.sign.tests/itext/signatures/cms/SignerInfoTest.cs create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/certs/signCertRsa01.xml create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/sign/TwoPhaseSigningTest/cmp_2PhaseCompleteCycleCMS.pdf create mode 100644 itext/itext.sign/itext/signatures/cms/AlgorithmIdentifier.cs create mode 100644 itext/itext.sign/itext/signatures/cms/Attribute.cs create mode 100644 itext/itext.sign/itext/signatures/cms/CMSContainer.cs create mode 100644 itext/itext.sign/itext/signatures/cms/EncapsulatedContentInfo.cs create mode 100644 itext/itext.sign/itext/signatures/cms/SignerInfo.cs diff --git a/itext.tests/itext.sign.tests/itext/signatures/PdfSignerUnitTest.cs b/itext.tests/itext.sign.tests/itext/signatures/PdfSignerUnitTest.cs index 44733c0eef..6175bd38e1 100644 --- a/itext.tests/itext.sign.tests/itext/signatures/PdfSignerUnitTest.cs +++ b/itext.tests/itext.sign.tests/itext/signatures/PdfSignerUnitTest.cs @@ -116,8 +116,7 @@ public virtual void SignWithFieldLockNotNullTest() { , new ByteArrayOutputStream(), new StampingProperties()); signer.cryptoDictionary = new PdfSignature(); signer.SetPageRect(new Rectangle(100, 100, 10, 10)); - PdfSigFieldLock fieldLock = new PdfSigFieldLock(); - signer.fieldLock = fieldLock; + signer.fieldLock = new PdfSigFieldLock(); IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256); signer.SignDetached(pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CADES); NUnit.Framework.Assert.IsTrue(signer.closed); @@ -259,7 +258,7 @@ public virtual void SignatureEventSetGetTest() { PdfSigner signer = new PdfSigner(new PdfReader(new MemoryStream(CreateSimplePdfaDocument())), new ByteArrayOutputStream (), new StampingProperties()); NUnit.Framework.Assert.IsNull(signer.GetSignatureEvent()); - PdfSigner.ISignatureEvent testEvent = new PdfSignerUnitTest.DummySignatureEvent(this); + PdfSigner.ISignatureEvent testEvent = new PdfSignerUnitTest.DummySignatureEvent(); signer.SetSignatureEvent(testEvent); NUnit.Framework.Assert.AreEqual(testEvent, signer.GetSignatureEvent()); } @@ -496,13 +495,7 @@ public ExtendedPdfSignatureFormField(PdfWidgetAnnotation widgetAnnotation, PdfDo internal class DummySignatureEvent : PdfSigner.ISignatureEvent { public virtual void GetSignatureDictionary(PdfSignature sig) { } - - internal DummySignatureEvent(PdfSignerUnitTest _enclosing) { - this._enclosing = _enclosing; - } - - private readonly PdfSignerUnitTest _enclosing; - // Do nothing + // Do nothing. } } } diff --git a/itext.tests/itext.sign.tests/itext/signatures/cms/CMSContainerTest.cs b/itext.tests/itext.sign.tests/itext/signatures/cms/CMSContainerTest.cs new file mode 100644 index 0000000000..b7aef69520 --- /dev/null +++ b/itext.tests/itext.sign.tests/itext/signatures/cms/CMSContainerTest.cs @@ -0,0 +1,193 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2023 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 System.Collections.Generic; +using System.Linq; +using iText.Bouncycastleconnector; +using iText.Commons.Bouncycastle; +using iText.Commons.Bouncycastle.Asn1; +using iText.Commons.Bouncycastle.Cert; +using iText.Commons.Bouncycastle.Crypto; +using iText.Commons.Utils; +using iText.Kernel.Exceptions; +using iText.Signatures; +using iText.Signatures.Exceptions; +using iText.Signatures.Testutils; +using iText.Signatures.Testutils.Builder; +using iText.Test; + +namespace iText.Signatures.Cms { + [NUnit.Framework.Category("BouncyCastleUnitTest")] + public class CMSContainerTest : ExtendedITextTest { + private static readonly IBouncyCastleFactory FACTORY = BouncyCastleFactoryCreator.GetFactory(); + + private static readonly String CERTS_SRC = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext + .CurrentContext.TestDirectory) + "/resources/itext/signatures/certs/"; + + private static readonly char[] PASSWORD = "testpassphrase".ToCharArray(); + + private static readonly byte[] EXPECTEDRESULT_1 = Convert.FromBase64String(CMSTestHelper.EXPECTED_RESULT_CMS_CONTAINER_TEST + ); + + private IX509Certificate[] chain; + + private IX509Certificate signCert; + + private byte[] testCrlResponse; + + [NUnit.Framework.SetUp] + public virtual void Init() { + IX509Certificate[] certChain = PemFileHelper.ReadFirstChain(CERTS_SRC + "signCertRsaWithChain.pem"); + chain = new IX509Certificate[certChain.Length]; + for (int i = 0; i < certChain.Length; i++) { + chain[i] = (IX509Certificate)certChain[i]; + } + signCert = chain[0]; + IPrivateKey caPrivateKey = PemFileHelper.ReadFirstKey(CERTS_SRC + "signCertRsaWithChain.pem", PASSWORD); + TestCrlBuilder testCrlBuilder = new TestCrlBuilder(signCert, caPrivateKey); + testCrlBuilder.AddCrlEntry(signCert, FACTORY.CreateCRLReason().GetKeyCompromise()); + testCrlResponse = testCrlBuilder.MakeCrl(); + } + + [NUnit.Framework.Test] + public virtual void TestSerialize() { + CMSContainer sut = new CMSContainer(); + sut.AddCertificates((IX509Certificate[])chain); + SignerInfo si = new SignerInfo(); + si.SetSigningCertificate(signCert); + List fakeOcspREsponses = new List(); + fakeOcspREsponses.Add(new byte[250]); + si.SetMessageDigest(new byte[256]); + si.SetOcspResponses(fakeOcspREsponses); + si.SetCrlResponses(JavaCollectionsUtil.SingletonList(testCrlResponse)); + si.SetDigestAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_SHA512)); + si.SetSigningCertificateAndAddToSignedAttributes(signCert, SecurityIDs.ID_SHA512); + si.SetSignature(new byte[256]); + sut.SetSignerInfo(si); + byte[] serRes = sut.Serialize(); + NUnit.Framework.Assert.AreEqual(SerializedAsString(EXPECTEDRESULT_1), SerializedAsString(serRes)); + } + + [NUnit.Framework.Test] + public virtual void TestGetSizeEstimation() { + CMSContainer sut = new CMSContainer(); + sut.AddCertificates((IX509Certificate[])chain); + SignerInfo si = new SignerInfo(); + si.SetSigningCertificate(signCert); + List fakeOcspREsponses = new List(); + fakeOcspREsponses.Add(new byte[250]); + si.SetMessageDigest(new byte[256]); + si.SetOcspResponses(fakeOcspREsponses); + si.SetCrlResponses(JavaCollectionsUtil.SingletonList(testCrlResponse)); + si.SetDigestAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_SHA512)); + si.SetSigningCertificateAndAddToSignedAttributes(signCert, SecurityIDs.ID_SHA512); + si.SetSignature(new byte[256]); + sut.SetSignerInfo(si); + long size = sut.GetSizeEstimation(); + NUnit.Framework.Assert.AreEqual(4825, size); + } + + [NUnit.Framework.Test] + public virtual void TestDeserialisation() { + byte[] rawData = Convert.FromBase64String(CMSTestHelper.SERIALIZED_B64_CASE1); + CMSContainer sd = new CMSContainer(rawData); + NUnit.Framework.Assert.AreEqual("2.16.840.1.101.3.4.2.1", sd.GetDigestAlgorithm().GetAlgorithmOid()); + NUnit.Framework.Assert.AreEqual("1.2.840.113549.1.7.1", sd.GetEncapContentInfo().GetContentType()); + NUnit.Framework.Assert.AreEqual(3, sd.GetCertificates().Count); + NUnit.Framework.Assert.IsTrue(sd.GetCertificates().Any((c) => "140282000747862710817410059465802198354".Equals + (c.GetSerialNumber().ToString()))); + NUnit.Framework.Assert.IsTrue(sd.GetCertificates().Any((c) => "151118660848720701053205649823964411794".Equals + (c.GetSerialNumber().ToString()))); + NUnit.Framework.Assert.IsTrue(sd.GetCertificates().Any((c) => "8380897714609953925".Equals(c.GetSerialNumber + ().ToString()))); + NUnit.Framework.Assert.AreEqual("8380897714609953925", sd.GetSignerInfo().GetSigningCertificate().GetSerialNumber + ().ToString()); + } + + [NUnit.Framework.Test] + public virtual void TestDeserialisationWithRevocationData() { + byte[] rawData = Convert.FromBase64String(CMSTestHelper.SERIALIZED_B64_CASE2); + CMSContainer sd = new CMSContainer(rawData); + NUnit.Framework.Assert.AreEqual("2.16.840.1.101.3.4.2.1", sd.GetDigestAlgorithm().GetAlgorithmOid()); + NUnit.Framework.Assert.AreEqual("1.2.840.113549.1.7.1", sd.GetEncapContentInfo().GetContentType()); + NUnit.Framework.Assert.AreEqual(3, sd.GetCertificates().Count); + NUnit.Framework.Assert.IsTrue(sd.GetCertificates().Any((c) => "3081".Equals(c.GetSerialNumber().ToString() + ))); + NUnit.Framework.Assert.IsTrue(sd.GetCertificates().Any((c) => "2776".Equals(c.GetSerialNumber().ToString() + ))); + NUnit.Framework.Assert.IsTrue(sd.GetCertificates().Any((c) => "1".Equals(c.GetSerialNumber().ToString()))); + NUnit.Framework.Assert.AreEqual("3081", sd.GetSignerInfo().GetSigningCertificate().GetSerialNumber().ToString + ()); + } + + [NUnit.Framework.Test] + public virtual void TestMultipleDigestAlgorithms() { + byte[] rawData = Convert.FromBase64String(CMSTestHelper.SERIALIZED_B64_2DIGEST_ALGOS); + Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => { + CMSContainer sd = new CMSContainer(rawData); + } + ); + NUnit.Framework.Assert.AreEqual(SignExceptionMessageConstant.CMS_ONLY_ONE_SIGNER_ALLOWED, e.Message); + } + + [NUnit.Framework.Test] + public virtual void TestMultipleSignerInfos() { + byte[] rawData = Convert.FromBase64String(CMSTestHelper.SERIALIZED_B64_2SIGNERS); + Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => { + CMSContainer sd = new CMSContainer(rawData); + } + ); + NUnit.Framework.Assert.AreEqual(SignExceptionMessageConstant.CMS_ONLY_ONE_SIGNER_ALLOWED, e.Message); + } + + [NUnit.Framework.Test] + public virtual void TestCertificatesMissing() { + byte[] rawData = Convert.FromBase64String(CMSTestHelper.SERIALIZED_B64_MISSING_CERTIFICATES); + Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => { + CMSContainer sd = new CMSContainer(rawData); + } + ); + NUnit.Framework.Assert.AreEqual(SignExceptionMessageConstant.CMS_MISSING_CERTIFICATES, e.Message); + } + + [NUnit.Framework.Test] + public virtual void TestCertificatesEmpty() { + byte[] rawData = Convert.FromBase64String(CMSTestHelper.SERIALIZED_B64_EMPTY_CERTIFICATES); + Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => { + CMSContainer sd = new CMSContainer(rawData); + } + ); + NUnit.Framework.Assert.AreEqual(SignExceptionMessageConstant.CMS_MISSING_CERTIFICATES, e.Message); + } + + private String ToUnixStringEnding(String @in) { + return @in.Replace("\r\n", "\n"); + } + + private String SerializedAsString(byte[] serialized) { + IAsn1InputStream @is = FACTORY.CreateASN1InputStream(serialized); + IAsn1Object obj1 = @is.ReadObject(); + return ToUnixStringEnding(FACTORY.CreateASN1Dump().DumpAsString(obj1, true)); + } + } +} diff --git a/itext.tests/itext.sign.tests/itext/signatures/cms/CMSTestHelper.cs b/itext.tests/itext.sign.tests/itext/signatures/cms/CMSTestHelper.cs new file mode 100644 index 0000000000..e341735a3c --- /dev/null +++ b/itext.tests/itext.sign.tests/itext/signatures/cms/CMSTestHelper.cs @@ -0,0 +1,739 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2023 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; + +namespace iText.Signatures.Cms { + /// + /// This class stores Base64-encoded cmp values for + /// + /// and + /// . + /// + internal class CMSTestHelper { + internal const String SERIALIZED_B64_CASE1 = "MIId9gYJKoZIhvcNAQcCoIId5zCCHeMCAQExDzANBglghkgBZQMEAgEFADALBgkqhkiG9w0BBwGgghMt" + + "MIIFzTCCBLWgAwIBAgIQaYlUoYntXRAHRVirF9EtUjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMC" + "RVMxMzAxBgNVBAoMKkNPTlNPUkNJIEFETUlOSVNUUkFDSU8gT0JFUlRBIERFIENBVEFMVU5ZQTEqMCgG" + + "A1UECwwhU2VydmVpcyBQw7pibGljcyBkZSBDZXJ0aWZpY2FjacOzMRgwFgYDVQQDDA9FQy1TZWN0b3JQ" + "dWJsaWMwHhcNMjEwNjE2MTUxNjIxWhcNMjIwNjE2MTUxNjIwWjCBojELMAkGA1UEBhMCRVMxNDAyBgNV" + + "BAoMK0NvbnNvcmNpIEFkbWluaXN0cmFjacOzIE9iZXJ0YSBkZSBDYXRhbHVueWExNDAyBgNVBAsMK1Zl" + "Z2V1IGh0dHBzOi8vd3d3LmFvYy5jYXQvQ0FUQ2VydC9SZWd1bGFjaW8xJzAlBgNVBAMMHlNlcnZlaSBP" + + "Q1NQIGRlIEVDLVNlY3RvclB1YmxpYzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMMVUaAi" + "SI4UFurSFP4h4UvPEWvCIEJvZFYTrc5FW5vUOiL5juyMcVzIRLZ9Zai6xLcsOKCywJsP2ZL7StHJOOQC" + + "IQoYOmcSee5RuuGmxHjhCy5BUgWNB5YVUR+ltJjwbkqrc1g8kdIbz3NhJlDZt8Q7c85ODC8rGYE5InWP" + "crU4hNk7qF3nooFPj3+Mbwp9W7dk0LagrTME5hrhHdaXyz+K2tUeZI9Ok3/9/sw+9J/w3vmyE9qfaFr5" + + "bIb7attwfzBgbB2YOLFsFy0Lot7vdKs7aMQonkqMtdEVZLrHmBe7uOJFRxl9NSDcwXMphVPGISc4wHba" + "90zTlIqZE5cOkpsCAwEAAaOCAhUwggIRMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAURzzeFHe7ak9H" + + "kakC/9QG4XPc4tkwdgYIKwYBBQUHAQEEajBoMEEGCCsGAQUFBzAChjVodHRwOi8vd3d3LmNhdGNlcnQu" + "Y2F0L2Rlc2NhcnJlZ2EvZWMtc2VjdG9ycHVibGljLmNydDAjBggrBgEFBQcwAYYXaHR0cDovL29jc3Au" + + "Y2F0Y2VydC5jYXQwgc8GA1UdIASBxzCBxDCBwQYLKwYBBAH1eAEDARMwgbEwMQYIKwYBBQUHAgEWJWh0" + "dHBzOi8vd3d3LmFvYy5jYXQvQ0FUQ2VydC9SZWd1bGFjaW8wfAYIKwYBBQUHAgIwcAxuQ2VydGlmaWNh" + + "dCBkZSBzZXJ2ZWkgT0NTUCwgZGUgY2xhc3NlIDEuIEFkcmXDp2EgaSBOSUYgZGVsIHByZXN0YWRvcjog" + "VmlhIExhaWV0YW5hIDI2IDA4MDAzIEJhcmNlbG9uYSBRMDgwMTE3NUEwDwYJKwYBBQUHMAEFBAIFADAT" + + "BgNVHSUEDDAKBggrBgEFBQcDCTBBBgNVHR8EOjA4MDagNKAyhjBodHRwOi8vZXBzY2QuY2F0Y2VydC5u" + "ZXQvY3JsL2VjLXNlY3RvcnB1YmxpYy5jcmwwHQYDVR0OBBYEFBWYlt4CY6CNoa/hjqqs/C8oB9/VMA4G" + + "A1UdDwEB/wQEAwIGwDANBgkqhkiG9w0BAQsFAAOCAQEAOcvn4Mocc6V5ezU8BVd1tueHvti071VJ9vX5" + "DIKC/9icc+W+amQ5ZrE4S7QBQIppxvZPzjIpYWtsOHrk7c4bOfTbiOTgFXszjMqpwJhTmdUbZ+N3tTG1" + + "3/BIoMvEdZjGrfX6T8Tzn956w1lB99cI811UDdJqzp3u3ImFxvLAWR1SaDlFgmVqetU+hh9nsh6ORlDI" + "2InJN962jnx0HdxuS7cXyg4Z1hgPJEjrTKHL6IcC0s/QFeHThJ6XrCmSjcXrnMj2fN95Wbt5PaVvnaqb" + + "OHzYfmB7jBKngUyyU8ph/92jO8k8UGs6Z2pWwCTvNYU57RZ00jj9DFRfIXdNhQV4MDCCBeMwggTLoAMC" + "AQICEHGwZTl8jgfSVBqWf3VZN5IwDQYJKoZIhvcNAQELBQAwgfMxCzAJBgNVBAYTAkVTMTswOQYDVQQK" + + "EzJBZ2VuY2lhIENhdGFsYW5hIGRlIENlcnRpZmljYWNpbyAoTklGIFEtMDgwMTE3Ni1JKTEoMCYGA1UE" + "CxMfU2VydmVpcyBQdWJsaWNzIGRlIENlcnRpZmljYWNpbzE1MDMGA1UECxMsVmVnZXUgaHR0cHM6Ly93" + + "d3cuY2F0Y2VydC5uZXQvdmVyYXJyZWwgKGMpMDMxNTAzBgNVBAsTLEplcmFycXVpYSBFbnRpdGF0cyBk" + "ZSBDZXJ0aWZpY2FjaW8gQ2F0YWxhbmVzMQ8wDQYDVQQDEwZFQy1BQ0MwHhcNMTQwOTE4MDgyMzI3WhcN" + + "MzAwOTE4MDgyMzI3WjCBiDELMAkGA1UEBhMCRVMxMzAxBgNVBAoMKkNPTlNPUkNJIEFETUlOSVNUUkFD" + "SU8gT0JFUlRBIERFIENBVEFMVU5ZQTEqMCgGA1UECwwhU2VydmVpcyBQw7pibGljcyBkZSBDZXJ0aWZp" + + "Y2FjacOzMRgwFgYDVQQDDA9FQy1TZWN0b3JQdWJsaWMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK" + "AoIBAQDLrk4xMbzx2xHxidzFPUc50nBCC/OkxE8GUztRmbBdb0axgCQVd0HF0l6ff6+Ye3MqtfQyi04q" + + "kbSpp8Eg30Ah27b+JiCVnPJmxGQkcENn6dU0VdWBhZ1GYIS4d9j40q45XGXEx+awGkvLhl3SE3+AJprP" + "cGvgMe9OVxQnedrI4geKlCbaeoTAuxAgh41my8NAJKeLz4j324SwMYONNPOvXmjMhHZELEGMYM8qxBPZ" + + "qDRUVeust4gfHp79UJjfzZDKnSpYMvOhz9tj60nneHzjRkgdps/04uKnxmNXqK6D55uUPCIlrb3w2gSo" + "vw1uY/qIFCe/tsOnzAG1WVLB1qPDAgMBAAGjggHaMIIB1jASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1Ud" + + "DwEB/wQEAwIBBjAdBgNVHQ4EFgQURzzeFHe7ak9HkakC/9QG4XPc4tkwHwYDVR0jBBgwFoAUoMOLRKo3" + "pUW/l4Ba0fF4opvpXY0wgdYGA1UdIASBzjCByzCByAYEVR0gADCBvzAxBggrBgEFBQcCARYlaHR0cHM6" + + "Ly93d3cuYW9jLmNhdC9DQVRDZXJ0L1JlZ3VsYWNpbzCBiQYIKwYBBQUHAgIwfQx7QXF1ZXN0IGNlcnRp" + "ZmljYXQgw6lzIGVtw6hzIMO6bmljYSBpIGV4Y2x1c2l2YW1lbnQgYSBFbnRpdGF0cyBkZSBDZXJ0aWZp" + + "Y2FjacOzLiBWZWdldSBodHRwczovL3d3dy5hb2MuY2F0L0NBVENlcnQvUmVndWxhY2lvMDMGCCsGAQUF" + "BwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuY2F0Y2VydC5jYXQwYgYDVR0fBFswWTBXoFWg" + + "U4YnaHR0cDovL2Vwc2NkLmNhdGNlcnQubmV0L2NybC9lYy1hY2MuY3JshihodHRwOi8vZXBzY2QyLmNh" + "dGNlcnQubmV0L2NybC9lYy1hY2MuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQAzETtHqhoqlHSBRW8asCl4" + + "fiuq1xiQJ34GCOGwATG2yAGWg5JX8F49twTvCcSzzM4CIpU14LMAUmU201RLo2EHz/pa1Iz9WRtlxTzP" + "rys7MheCt7Nxcn43UZo9HIbp9BZWqPoHfZ5eo+8ksx7KWW9bv4tC0s+P+PJmPqU8U9RwlcOM785vRPV9" + + "urisZ/1IpCPQeRBAhxgoccOQsdUUhe0x74RAV3wkOsLGOt9rr4Yvx+EAJM5jmZIdT1c83oZbCtrXpSRn" + "wLfsSMSx2L0VDkwuTEaUrdhM6r043bAvICsxr4KmBIWQaq6u1T521F/S7hfWniZWVz7HzUWiJACVvLJq" + + "MIIHcTCCBlmgAwIBAgIIdE7uEUo1nIUwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAkVTMTMwMQYD" + "VQQKDCpDT05TT1JDSSBBRE1JTklTVFJBQ0lPIE9CRVJUQSBERSBDQVRBTFVOWUExKjAoBgNVBAsMIVNl" + + "cnZlaXMgUMO6YmxpY3MgZGUgQ2VydGlmaWNhY2nDszEYMBYGA1UEAwwPRUMtU2VjdG9yUHVibGljMB4X" + "DTE5MDMxOTA4Mzg1OFoXDTIzMDMxOTA4Mzg1OFowggFrMQswCQYDVQQGEwJFUzE/MD0GA1UECgw2RnVu" + + "ZGFjacOzIFVuaXZlcnNpdMOgcmlhIEJhbG1lcy5Vbml2ZXJzaXRhdCBkZSBWaWMtVUNDMRgwFgYDVQRh" + "DA9WQVRFUy1HNTgwMjAxMjQxMzAxBgNVBAsMKlJlcHJlc2VudGFudCBkYXZhbnQgbGVzIEFBUFAgZGUg" + + "bml2ZWxsIGFsdDEVMBMGA1UEBAwMQmHDsW9zIETDrWV6MRQwEgYDVQQqDAtKb3NlcCBFbGFkaTEYMBYG" + "A1UEBRMPSURDRVMtMzM4NjI1NjREMTkwNwYDVQQDDDAzMzg2MjU2NEQgSm9zZXAgRWxhZGkgQmHDsW9z" + + "IETDrWV6IChSOkc1ODAyMDEyNCkxSjBIBgNVBA0MQUJ1dGxsZXTDrTo3Nzc2L0RhdGE6MjgtMTItMjAx" + "OC9Ow7ptZXJvIHJlc29sdWNpw7M6QS0xODM1NDA0OS0yMDE4MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A" + + "MIIBCgKCAQEAp+Omr4s7sLRKCY0q+BbTT1kX9flmmfFdIjR05penmOWAOy81gdJ2nikfXQXBldUI2fQQ" + "NuUCPWO7fq0wsaTcsdPpF4BrP2Wf9wnIK94ck+nK5RVKqijtEYnVAmHtRPIMDbo4UBuymgLY5k2JRVON" + + "HLWytLqs9msNjUzPTFghmRne6YsFMes1KmIa36Zom8ZjbpJOZGliRRlO/XhM9H3K0F5p1H1C7aV7amIv" + "a0cP+xbyskkpk+T3gexVFVehzhGbS3nycTO9yTvRLR9urjlmYIht4xhR7orE+7RXtVyn6yQU3gK9239/" + + "uNkbGInG/BNiQfHV1Dl7uTVmBiqYQuvXxQIDAQABo4IC9zCCAvMwdgYIKwYBBQUHAQEEajBoMEEGCCsG" + "AQUFBzAChjVodHRwOi8vd3d3LmNhdGNlcnQuY2F0L2Rlc2NhcnJlZ2EvZWMtc2VjdG9ycHVibGljLmNy" + + "dDAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuY2F0Y2VydC5jYXQwHQYDVR0OBBYEFFXoRqtROFLAXvY/" + "ZZfuaRFV2sP1MAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAURzzeFHe7ak9HkakC/9QG4XPc4tkwegYI" + + "KwYBBQUHAQMEbjBsMAgGBgQAjkYBATALBgYEAI5GAQMCAQ8wCAYGBACORgEEMBMGBgQAjkYBBjAJBgcE" + "AI5GAQYBMDQGBgQAjkYBBTAqMCgWImh0dHBzOi8vd3d3LmFvYy5jYXQvY2F0Y2VydC9wZHNfZW4TAmVu" + + "MIIBCQYDVR0gBIIBADCB/TCB5AYNKwYBBAH1eAEDAggBATCB0jAxBggrBgEFBQcCARYlaHR0cHM6Ly93" + "d3cuYW9jLmNhdC9DQVRDZXJ0L1JlZ3VsYWNpbzCBnAYIKwYBBQUHAgIwgY8MgYxDZXJ0aWZpY2F0IGVs" + + "ZWN0csOybmljIGRlIHJlcHJlc2VudGFudCBkYXZhbnQgbGVzIEFBUFAgZGUgbml2ZWxsIGFsdC4gQWRy" + "ZcOnYSBpIE5JRiBkZWwgcHJlc3RhZG9yOiBWaWEgTGFpZXRhbmEgMjYgMDgwMDMgQmFyY2Vsb25hIFEw" + + "ODAxMTc1QTAJBgdghVQBAwUIMAkGBwQAi+xAAQIwQQYDVR0fBDowODA2oDSgMoYwaHR0cDovL2Vwc2Nk" + "LmNhdGNlcnQubmV0L2NybC9lYy1zZWN0b3JwdWJsaWMuY3JsMA4GA1UdDwEB/wQEAwIF4DApBgNVHSUE" + + "IjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcUAgIwJAYDVR0RBB0wG4EZam9zZXBlbGFkaS5i" + "YW5vc0B1dmljLmNhdDANBgkqhkiG9w0BAQsFAAOCAQEAkQNfW7iZXxsfpwynCoBbxtT2UK8jqX02aeUC" + + "m1r8kBV7s8pq5+EicxrFAh3/GlIscm3qYwASqIl6s8gnWAvZtW4olAVnqYjE5+Ze4dKBiurjrhLG66oQ" + "/VrxNf8CN9kxpdwN4X2VUvtORHTieNUXmFTYhsYdZkIUTvX6vHeONre8eWdBjp22aoQQJ7TEqWW4Cnjl" + + "k7M7DJGUAp08nAmpUXJjg3Ubb+OIJnaYG9vhBf6ytCRzyYgVd4sa320yXxEp6WG769EfrALumUmr20dw" + "VQKIyiuc6lHEUuQ4grz8B5EIx2upMJn+gYjvm/ve0NeioLaKaTDnATDzyD9+mnBV7zGCCo0wggqJAgEB" + + "MIGVMIGIMQswCQYDVQQGEwJFUzEzMDEGA1UECgwqQ09OU09SQ0kgQURNSU5JU1RSQUNJTyBPQkVSVEEg" + "REUgQ0FUQUxVTllBMSowKAYDVQQLDCFTZXJ2ZWlzIFDDumJsaWNzIGRlIENlcnRpZmljYWNpw7MxGDAW" + + "BgNVBAMMD0VDLVNlY3RvclB1YmxpYwIIdE7uEUo1nIUwDQYJYIZIAWUDBAIBBQCgggjIMBgGCSqGSIb3" + "DQEJAzELBgkqhkiG9w0BBwEwLwYJKoZIhvcNAQkEMSIEICJ3ranF419TEnQQ9yFEvWVcoVAc1GXhaKqg" + + "zzM2sdndMIIIeQYJKoZIhvcvAQEIMYIIajCCCGahgghiMIIIXjCCCFoKAQCggghTMIIITwYJKwYBBQUH" + "MAEBBIIIQDCCCDwwggFLoYGlMIGiMQswCQYDVQQGEwJFUzE0MDIGA1UECgwrQ29uc29yY2kgQWRtaW5p" + + "c3RyYWNpw7MgT2JlcnRhIGRlIENhdGFsdW55YTE0MDIGA1UECwwrVmVnZXUgaHR0cHM6Ly93d3cuYW9j" + "LmNhdC9DQVRDZXJ0L1JlZ3VsYWNpbzEnMCUGA1UEAwweU2VydmVpIE9DU1AgZGUgRUMtU2VjdG9yUHVi" + + "bGljGA8yMDIyMDQyMTE1NTkzMlowazBpMEEwCQYFKw4DAhoFAAQULM0qepNxMuWZ4NYlqgUuKj/csfIE" + "FEc83hR3u2pPR5GpAv/UBuFz3OLZAgh0Tu4RSjWchYAAGA8yMDIyMDQyMTE1NTkzMlqgERgPMjAyMjA0" + + "MjExNjA0MzFaoSMwITAfBgkrBgEFBQcwAQIEEgQQPotpF5elSJ4KTZM7Ei3OZjANBgkqhkiG9w0BAQsF" + "AAOCAQEAci1WvetiQ38gKWo6LjTaGvXq0rWvQ8yUQTC/hyk3ZtY7DpBqJqElkNyhTCfCyGddhh4WClWp" + + "IjPCiSBB1SzIB2fzItD1LOW7UbCDcv3fmK9Wg6S8pQ9u30Jb+haqKUbUnuJa+LlZsTc9SOrYdl3EIqnc" + "rSvOm0o8B5t6EQBWI7WKqPujGdcmCjcnmBDTJdicLr58tkw/B79eSNhSxJ63/pRrcVqQipwpWoxIS2W2" + + "XlqZ615v61A5tbAIw1/CfTfZJPPwhbe+LRBZoDC9dXWVB3HhUZSw8au2cP2AbB9hadsNeXGq1oaORJ+Q" + "WS07qlIj7aMgxdbDz4u0efTk+bnJBKCCBdUwggXRMIIFzTCCBLWgAwIBAgIQaYlUoYntXRAHRVirF9Et" + + "UjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCRVMxMzAxBgNVBAoMKkNPTlNPUkNJIEFETUlOSVNU" + "UkFDSU8gT0JFUlRBIERFIENBVEFMVU5ZQTEqMCgGA1UECwwhU2VydmVpcyBQw7pibGljcyBkZSBDZXJ0" + + "aWZpY2FjacOzMRgwFgYDVQQDDA9FQy1TZWN0b3JQdWJsaWMwHhcNMjEwNjE2MTUxNjIxWhcNMjIwNjE2" + "MTUxNjIwWjCBojELMAkGA1UEBhMCRVMxNDAyBgNVBAoMK0NvbnNvcmNpIEFkbWluaXN0cmFjacOzIE9i" + + "ZXJ0YSBkZSBDYXRhbHVueWExNDAyBgNVBAsMK1ZlZ2V1IGh0dHBzOi8vd3d3LmFvYy5jYXQvQ0FUQ2Vy" + "dC9SZWd1bGFjaW8xJzAlBgNVBAMMHlNlcnZlaSBPQ1NQIGRlIEVDLVNlY3RvclB1YmxpYzCCASIwDQYJ" + + "KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMMVUaAiSI4UFurSFP4h4UvPEWvCIEJvZFYTrc5FW5vUOiL5" + "juyMcVzIRLZ9Zai6xLcsOKCywJsP2ZL7StHJOOQCIQoYOmcSee5RuuGmxHjhCy5BUgWNB5YVUR+ltJjw" + + "bkqrc1g8kdIbz3NhJlDZt8Q7c85ODC8rGYE5InWPcrU4hNk7qF3nooFPj3+Mbwp9W7dk0LagrTME5hrh" + "HdaXyz+K2tUeZI9Ok3/9/sw+9J/w3vmyE9qfaFr5bIb7attwfzBgbB2YOLFsFy0Lot7vdKs7aMQonkqM" + + "tdEVZLrHmBe7uOJFRxl9NSDcwXMphVPGISc4wHba90zTlIqZE5cOkpsCAwEAAaOCAhUwggIRMAwGA1Ud" + "EwEB/wQCMAAwHwYDVR0jBBgwFoAURzzeFHe7ak9HkakC/9QG4XPc4tkwdgYIKwYBBQUHAQEEajBoMEEG" + + "CCsGAQUFBzAChjVodHRwOi8vd3d3LmNhdGNlcnQuY2F0L2Rlc2NhcnJlZ2EvZWMtc2VjdG9ycHVibGlj" + "LmNydDAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuY2F0Y2VydC5jYXQwgc8GA1UdIASBxzCBxDCBwQYL" + + "KwYBBAH1eAEDARMwgbEwMQYIKwYBBQUHAgEWJWh0dHBzOi8vd3d3LmFvYy5jYXQvQ0FUQ2VydC9SZWd1" + "bGFjaW8wfAYIKwYBBQUHAgIwcAxuQ2VydGlmaWNhdCBkZSBzZXJ2ZWkgT0NTUCwgZGUgY2xhc3NlIDEu" + + "IEFkcmXDp2EgaSBOSUYgZGVsIHByZXN0YWRvcjogVmlhIExhaWV0YW5hIDI2IDA4MDAzIEJhcmNlbG9u" + "YSBRMDgwMTE3NUEwDwYJKwYBBQUHMAEFBAIFADATBgNVHSUEDDAKBggrBgEFBQcDCTBBBgNVHR8EOjA4" + + "MDagNKAyhjBodHRwOi8vZXBzY2QuY2F0Y2VydC5uZXQvY3JsL2VjLXNlY3RvcnB1YmxpYy5jcmwwHQYD" + "VR0OBBYEFBWYlt4CY6CNoa/hjqqs/C8oB9/VMA4GA1UdDwEB/wQEAwIGwDANBgkqhkiG9w0BAQsFAAOC" + + "AQEAOcvn4Mocc6V5ezU8BVd1tueHvti071VJ9vX5DIKC/9icc+W+amQ5ZrE4S7QBQIppxvZPzjIpYWts" + "OHrk7c4bOfTbiOTgFXszjMqpwJhTmdUbZ+N3tTG13/BIoMvEdZjGrfX6T8Tzn956w1lB99cI811UDdJq" + + "zp3u3ImFxvLAWR1SaDlFgmVqetU+hh9nsh6ORlDI2InJN962jnx0HdxuS7cXyg4Z1hgPJEjrTKHL6IcC" + "0s/QFeHThJ6XrCmSjcXrnMj2fN95Wbt5PaVvnaqbOHzYfmB7jBKngUyyU8ph/92jO8k8UGs6Z2pWwCTv" + + "NYU57RZ00jj9DFRfIXdNhQV4MDANBgkqhkiG9w0BAQsFAASCAQA/zbiTRgCfAbR0jWku39AHpc2BTuk2" + "LlHtzuogd/CNH7BcR3AmQ8vpIDad1ZVjh9l06xspbU04dPeFW1kISERqQYms1DKF7HnxY/IfI7iK7zRD" + + "Z6V0DBAVjc4dEGM/REULrERHtGasePl/tfkHeeNNBh/Sju6KjEhNoqQU9MeVD7uQ/y3GK+18YcagA71x" + "cI69GhIviAvsNPqzXKTKA4S+HU3/VdxiRIg3X4iUQ94zljNlmucE6U3YgdYkKdLTqKOFHm1INZo5YCMZ" + + "1ITGAjBkAmHqDXksRZe9d6EXhxoTnRx5OplbSCmrfiZYQ65mWS+Ur221VJthnoNTRmkSpcFm"; + + internal const String SERIALIZED_B64_CASE2 = "MII3WgYJKoZIhvcNAQcCoII3SzCCN0cCAQExDzANBglghkgBZQMEAgEFADALBgkqhkiG9w0BBwGgghOhMIIHZDCCBUygAwIBAgIC" + + "DAkwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNVBAYTAklUMRgwFgYDVQQKDA9JbmZvQ2VydCBTLnAuQS4xHzAdBgNVBAsMFlRydXN0" + + "IFNlcnZpY2UgUHJvdmlkZXIxGjAYBgNVBGEMEVZBVElULTA3OTQ1MjExMDA2MTAwLgYDVQQDDCdJbmZvQ2VydCBDZXJ0aWZpY2F0" + + "aW9uIFNlcnZpY2VzIENBIDMgQ0wwHhcNMjMxMDI0MDgwMDU4WhcNMjQxMDI0MDAwMDAwWjCBsDEYMBYGA1UELhMPMjAyMzk5OTg1" + + "MEEyNTIzMQ8wDQYDVQQEDAZJdmFub3YxDDAKBgNVBCoMA0tlbjEkMCIGCSqGSIb3DQEJARYVaXZhbm92QGFsbGllZGJpdHMuY29t" + + "MRMwEQYDVQQDDApLZW4gSXZhbm92MRgwFgYDVQQKDA9BbGxpZWQgQml0cyBMdGQxEzARBgNVBAcMCkNoZWx0ZW5oYW0xCzAJBgNV" + + "BAYTAkdCMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxTWSmSwv955zvlCbfLtArNlFs5d7Vm7+eU6Hcfa4OUgQj75Q" + + "aIBgJn5P2DU00vrTVjtLS9zIUXroWKRhhUf0bTW3KhUX1l5THN1tT8Fy6Qef2lfZT/cUG1FviOQONuveX/hvZE9BdjRoIG/ceSL/" + + "CANrLVQ+w+3HXxlbzffWenIaHE/Fhsg+rpGci6T7nEWqS6iy0SErXgrKBZJ1gcDw0QVWyoIdZSBcZ4h5CK8YjzNbRHop1tFrx35x" + + "7iXZG5wL+dAFGwjD+8I4JjbkJv3t8OINkwR3gcLAZ1fODzPv24RM1DafC/dFYmCegLiZekjCrto36Bj+1t4zc2iBeDWrgwIDAQAB" + + "o4ICnjCCApowHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMIGhBgNVHSAEgZkwgZYwgZMGBitMJAEBCDCBiDBBBggrBgEF" + + "BQcCAjA1DDNTU0wsIFNNSU1FIGFuZCBEaWdpdGFsIFNpZ25hdHVyZSBDbGllbnQgQ2VydGlmaWNhdGUwQwYIKwYBBQUHAgEWN2h0" + + "dHA6Ly93d3cuZmlybWEuaW5mb2NlcnQuaXQvZG9jdW1lbnRhemlvbmUvbWFudWFsaS5waHAwcgYIKwYBBQUHAQEEZjBkMC0GCCsG" + + "AQUFBzABhiFodHRwOi8vb2NzcGNsLmNzLmNhMy5pbmZvY2VydC5pdC8wMwYIKwYBBQUHMAKGJ2h0dHA6Ly9jZXJ0Y2wuaW5mb2Nl" + + "cnQuaXQvY2EzL2NzL0NBLmNydDCB7gYDVR0fBIHmMIHjMIHgoIHdoIHahilodHRwOi8vY3JsY2wuaW5mb2NlcnQuaXQvY2EzL2Nz" + + "L0NSTDAxLmNybIaBrGxkYXA6Ly9sZGFwY2wuaW5mb2NlcnQuaXQvY24lM0RJbmZvQ2VydCUyMENlcnRpZmljYXRpb24lMjBTZXJ2" + + "aWNlcyUyMENBJTIwMyUyMENMJTIwQ1JMMDEsb3UlM0RUcnVzdCUyMFNlcnZpY2UlMjBQcm92aWRlcixvJTNESU5GT0NFUlQlMjBT" + + "UEEsYyUzRElUP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3QwDgYDVR0PAQH/BAQDAgSwMCAGA1UdEQQZMBeBFWl2YW5vdkBhbGxp" + + "ZWRiaXRzLmNvbTAfBgNVHSMEGDAWgBSKt+EIOuxJR6TEC9yMHqtLdN4XhTAdBgNVHQ4EFgQUoNLMA2794xfqMT/tVQcd/2Zn9Osw" + + "DQYJKoZIhvcNAQELBQADggIBABMpLL3BRMuyl3SqYumWpAB5Qhhdu7C/gFEeUXyiQZCiD9qfl26clrOCXCk4StFVWayrhy7tx3Ah" + + "yD3jNm568o0kCga8YcacFh44vXiG8c25lLowbHs6pDHsxqN6fIEbrT7eaWzgmWBbHCSPmDSchZ1zIh2sKP8ZyTPQAyAdDSwbhtgM" + + "bBno3t1boKB4sElA5pSPGNa8C7pPclqE9jrU1GI9wmL5FiBdwc5NKrZfv9fmSH+q5sukmVkak7a2fKW6Nj3tm68aF/nhtRro56U1" + + "/ymgfmqtWQCsmk7gHdQW0MqcXsiNZYrBf/2GV7IOC78xTnHtT06Ql9noRkrYoHZqgITz5/kEnHZHfblZmIRA3lbtqgkWnpMB+3rg" + + "bYNH5iunCIITgpDqPssAfYKCnj3Szg++dxHYhYaKpc9WFUCNZEVIvdFb6RHJSW2Et3XgGgR1PT9QmWUjv00HKSylC6bAyGRBKBWq" + + "eXjFTEfm/DPdI92oXbMYpsF/FQvwg/F2n4Cl6lAfDkJmQppYZ6aam9GVq2piIVgKZUGXU1Ur1c+J+BifDTagCmo3KpG1MPsmewEL" + + "QkMCmG/+DT0vC/tQu3PsU2wWVbWNHfXzZvb8ukmIhNK/6UFvgzyA1BQwZPq5qTSJ0/TUbtFZphws7xjStpi/v5pCbpt48ipcR9bz" + + "bOSEbypHMIIFAzCCAuugAwIBAgICCtgwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNVBAYTAklUMRgwFgYDVQQKDA9JbmZvQ2VydCBT" + + "LnAuQS4xHzAdBgNVBAsMFlRydXN0IFNlcnZpY2UgUHJvdmlkZXIxGjAYBgNVBGEMEVZBVElULTA3OTQ1MjExMDA2MTAwLgYDVQQD" + + "DCdJbmZvQ2VydCBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIENBIDMgQ0wwHhcNMjMwMjE0MTYwMjM5WhcNMjYwMjE0MTYwMjM5WjBr" + + "MQswCQYDVQQGEwJJVDEYMBYGA1UECgwPSW5mb0NlcnQgUy5wLkEuMR8wHQYDVQQLDBZUcnVzdCBTZXJ2aWNlIFByb3ZpZGVyMSEw" + + "HwYDVQQDDBhPQ1NQIFJlc3BvbmRlciBDUyBDQTMgQ0wwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4E4jNB8W8PS9x" + + "ua2T/EIez+LKBssGuG/+btUsCRwcr2SLKHLDZquWG1uqJZEElulzY1x2u46+PgO1ZtGoeCRazZt7NdYaU4kQBsrkmKRc72WITR7b" + + "cA8f2DelArlivtYswLO/RrgTO0CcrhTNy8njB17nGyJwn6pPrHAWii7i+5qaHnTfs97Y/uyghUBh5yfpLZD5CneT0085R5wDQCzA" + + "SCu7TO9cAkT84Ax5P8NvIutVLpfXVw2DYdx5gRsvtZMFdb00wBwFlj66PEonTvZ3SUb4JU/NPEpA80q59lBGKJd9vccrGJoiUf7d" + + "agVl9fpqayNO5hkFv3bfqtuqUr3nAgMBAAGjgYQwgYEwCQYDVR0TBAIwADAPBgkrBgEFBQcwAQUEAgUAMBMGA1UdJQQMMAoGCCsG" + + "AQUFBwMJMA4GA1UdDwEB/wQEAwIHgDAfBgNVHSMEGDAWgBSKt+EIOuxJR6TEC9yMHqtLdN4XhTAdBgNVHQ4EFgQUxMdBvrytW0xO" + + "nDzFvSjgFqO58rowDQYJKoZIhvcNAQELBQADggIBADXer+pOSAXKtUVBYEtmV2cEWARXQhvn77Yu+r8NCfAqKX7ND9N7up9eYYyq" + + "7huuyHgBUACrhoxDVLBJiefSC/NSN72vI/wfSbo6RjZWlz+OnySEsD6Qw3IPk+bivFyP3gAHq++nMZwOH/oeuHZCYDHvvUzsmwed" + + "zMTbX2QjgXlb/qfxAQmHYgMuyAcLE7+o9zXP7cqhxOX5+/XFexWjtOr5P4ngVlJezwi4ouT1RpgpEZr3o9JlOGAUxFhTHlE7jZ2/" + + "o4VRPuFY47ufMh3wJPo3DrKaGeLR4w+d7JiLFMMO0rq8E1MCFUHgbLjUDlprwwZDY9yFQgtt0pQ8yrqHDqpNALcVYxTTTcoqnF64" + + "Dbb//qHBfyKs+wJ+y+dzNWmFyQEr9Kng/6/orNHhSbmyRkE3aXcVvmlfUnBaK53zkP5m7Dr3XYxyJnzAZLw2LdUTmPVXjwvPARGl" + + "oxYJwOsdyDUgAKPJlNWU/7X1HLqzKm2TRcq7zs4tpwdYkRAf0NhUm733ITNsnRepxc7NCi0L+sDLZXwq+to8bad53HJodVcZBeCS" + + "nE9xm1bFQ9pdtvXueDCDH1SHUdSGdzTa3stnEJ40hGiqpDrb7MWwSgrH/NReZVxF7Rngnk70FGgu0udxoWWHUm85rK8enT7yDizn" + + "BZI3aQvMSHvkmYzlNQ7omGokMIIHLjCCBRagAwIBAgIBATANBgkqhkiG9w0BAQsFADCBljELMAkGA1UEBhMCSVQxGDAWBgNVBAoM" + + "D0luZm9DZXJ0IFMucC5BLjEfMB0GA1UECwwWVHJ1c3QgU2VydmljZSBQcm92aWRlcjEaMBgGA1UEYQwRVkFUSVQtMDc5NDUyMTEw" + + "MDYxMDAuBgNVBAMMJ0luZm9DZXJ0IENlcnRpZmljYXRpb24gU2VydmljZXMgQ0EgMyBDTDAeFw0xNjEyMDExNjA5MDhaFw0zMjEy" + + "MDExNzA5MDhaMIGWMQswCQYDVQQGEwJJVDEYMBYGA1UECgwPSW5mb0NlcnQgUy5wLkEuMR8wHQYDVQQLDBZUcnVzdCBTZXJ2aWNl" + + "IFByb3ZpZGVyMRowGAYDVQRhDBFWQVRJVC0wNzk0NTIxMTAwNjEwMC4GA1UEAwwnSW5mb0NlcnQgQ2VydGlmaWNhdGlvbiBTZXJ2" + + "aWNlcyBDQSAzIENMMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuH6H2wNQ5jPehDSGh96J0nmb+RmXl3nfaGs9XIpn" + + "2wVRpa1G2UD2Uax1qhy7PVW+VCPbSQwCfWRNGj6y0tFrNLtGNIqD7HUaN9AXtbpCWzq9WMw+KdrE5b7tSA5mXfTeLQZo0+kxwJdB" + + "XABsXAZoO+Ev620omIMKNK2xuHd4Q9B3rrjFd6Q8boZHaBnFlx61aWv8RZ1KoAattuuCYa1ANq2v0iN/I0+HGV8yFQyAaBgt328z" + + "XxTHJy9/+Xb7EbLbQLSgNKCFphtKNS12WXwD/hPJnIwr6Jj+UCqqt7EZVOhkwKClSj3xBydzHhRn6LJiX+Z+U5jESrjv5OrK96zJ" + + "BInZPGL9KyWpyIzGw2edtbhaXytDwUi0cCq3rBiR8AJ+57PtuGvhWLcWa3mITrGSO++h1vkv4H6OoX6Qm4dydxlYPw9ZMA0TZx+n" + + "dX+HAS8xfsbf2NXnOySd5tX8cyLNL8k8jgw8SYY2yVlH6/esSzPDUBzOJQGIqrhs0Q9bfg0JUdVIapJ5uYkhnHuxt7aQ26bAOu+1" + + "gKOSsGk1g9cJGBch/Q52z0K7+UCb9nDotvrS1yfriJW9CxZ9Jy0la4Jm1QpCujTtWK/QCL9DcIcYcd7sDXAAJHJ7h2NgrUraE6i3" + + "Oc/U7/op5E0NPAbR1Fm2STU25UDgfmry1Gyr8Rxcun8CAwEAAaOCAYMwggF/MA8GA1UdEwEB/wQFMAMBAf8wWAYDVR0gBFEwTzBN" + + "BgRVHSAAMEUwQwYIKwYBBQUHAgEWN2h0dHA6Ly93d3cuZmlybWEuaW5mb2NlcnQuaXQvZG9jdW1lbnRhemlvbmUvbWFudWFsaS5w" + + "aHAwgeIGA1UdHwSB2jCB1zCB1KCB0aCBzoYnaHR0cDovL2NybGNsLmluZm9jZXJ0Lml0L2NhMy9jcy9BUkwuY3JshoGibGRhcDov" + + "L2xkYXBjbC5pbmZvY2VydC5pdC9jbiUzREluZm9DZXJ0JTIwQ2VydGlmaWNhdGlvbiUyMFNlcnZpY2VzJTIwQ0ElMjAzJTIwQ0ws" + + "b3UlM0RUcnVzdCUyMFNlcnZpY2UlMjBQcm92aWRlcixvJTNESU5GT0NFUlQlMjBTUEEsYyUzRElUP2F1dGhvcml0eVJldm9jYXRp" + + "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" + + "MIGjMIGcpIGZMIGWMQswCQYDVQQGEwJJVDEYMBYGA1UECgwPSW5mb0NlcnQgUy5wLkEuMR8wHQYDVQQLDBZUcnVzdCBTZXJ2aWNl" + + "IFByb3ZpZGVyMRowGAYDVQRhDBFWQVRJVC0wNzk0NTIxMTAwNjEwMC4GA1UEAwwnSW5mb0NlcnQgQ2VydGlmaWNhdGlvbiBTZXJ2" + + "aWNlcyBDQSAzIENMAgIMCTCCCu0GCSqGSIb3LwEBCDGCCt4wggraoIIDeDCCA3QwggNwMIIBWAIBATANBgkqhkiG9w0BAQsFADCB" + + "ljELMAkGA1UEBhMCSVQxGDAWBgNVBAoMD0luZm9DZXJ0IFMucC5BLjEfMB0GA1UECwwWVHJ1c3QgU2VydmljZSBQcm92aWRlcjEa" + + "MBgGA1UEYQwRVkFUSVQtMDc5NDUyMTEwMDYxMDAuBgNVBAMMJ0luZm9DZXJ0IENlcnRpZmljYXRpb24gU2VydmljZXMgQ0EgMyBD" + + "TBcNMjMxMjAzMTIwMDAwWhcNMjMxMjA1MTEwMDAwWjAAoIGKMIGHMB8GA1UdIwQYMBaAFIq34Qg67ElHpMQL3Iweq0t03heFMAwG" + + "A1UdFAQFAgMA5dgwGAYDVR08BBEYDzIwMTYxMjAxMTYwOTA4WjA8BgNVHRwBAf8EMjAwoCugKYYnaHR0cDovL2NybGNsLmluZm9j" + + "ZXJ0Lml0L2NhMy9jcy9BUkwuY3JsggH/MA0GCSqGSIb3DQEBCwUAA4ICAQAy2Tc/zxyd6kzwsvwOeBl6/luC162hEWzupTOCrpiZ" + + "3kET4CkwQd/W62Iha02VChhsp+miBEphJFQcjU63iohgcRCjdB41bVocoq7c43KqK14s0up4zi+TwFKqTzPWYF5n1EHTYTUhlwfv" + + "QHo84X9iFC40YDaeybM7T78B8wqOmVXjqD0WmDslYlZgH1QDiVf+XSrwGmg0KjBX7PRMljN6cFP/kNS+i3D8WKUmqouYhTZrRbFs" + + "UwpgXVpJ6hCUZ4U7wLYzUhpIUV3w6VwrxQn6TmGgq0b9baRwivCpJIheZhISqXOMHLHTBBvjRe3GaWimTx0zneB2fZEq13sEDezK" + + "tGQ/CcPyaKIkVgflqdtKmxU6d8Yj4VfNA8G9/KFshunjmbOVph56n33ButTpMqtUHSf714GGNu1todQ+YxaVRTDhUQ80sOlq3iCA" + + "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" + + "MjA3oRswGQYIKwYBBQUHAQMEDTALMAkGBwQAgZdeAQGgggawMIIGrDCCBJSgAwIBAgIBDjANBgkqhkiG9w0BAQsFADCBgTELMAkG" + + "A1UEBhMCSVQxGDAWBgNVBAoMD0luZm9DZXJ0IFMucC5BLjEMMAoGA1UECwwDVFNBMRowGAYDVQRhDBFWQVRJVC0wNzk0NTIxMTAw" + + "NjEuMCwGA1UEAwwlSW5mb0NlcnQgVGltZSBTdGFtcGluZyBBdXRob3JpdHkgMyBDTDAeFw0yMjA3MjExMDAzMTlaFw0yNTA3MjEx" + + "MDAzMTlaMFExCzAJBgNVBAYTAklUMRgwFgYDVQQKDA9JbmZvQ2VydCBTLnAuQS4xDDAKBgNVBAsMA1RTQTEaMBgGA1UEAwwRSUNF" + + "RFRTUEQxQ0wyMDIyMDcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDW2cLIxkXEVbXqXt7PuNhEnvzsTYNj7QFfYNyu" + + "Y0gxT8TIQ7Lk0CgsHlP6C920eTuNOSB8aPKCOxEZZnOWQ3RcjN5bmPVERFkNIixAH8Tf7P/lqztHwWoAsC1MCWnn6JoosksF9hs+" + + "BGnR4FiZQGJRBOU0ffNTlBN2KpisCs2UnxHzxW0iUNtk3BP9qEHEJ4mJQhUQTYmra7SnsT74EP/egSXtLraJdRPpzC/VGZZl96xR" + + "BZqfXhhNsXro7CPalWGJT4kiO6dHBWKjbAIBr3xqppvpb4EFfU0w0HBqKcIClnhgtpzZx+EIk3n3PE01fgJttC7HmiaojNELDzEx" + + "5hkjAgMBAAGjggJcMIICWDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDBxBggrBgEFBQcBAwRlMGMwCAYGBACORgEBMAgGBgQAjkYB" + + "BDALBgYEAI5GAQMCARQwQAYGBACORgEFMDYwNBYuaHR0cHM6Ly93d3cuZmlybWEuaW5mb2NlcnQuaXQvcGRmL1BLSS1EVFNBLnBk" + + "ZhMCZW4wPgYIKwYBBQUHAQEEMjAwMC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcGNsLnRzYS5jYTMuaW5mb2NlcnQuaXQvMIHMBgNV" + + "HR8EgcQwgcEwgb6ggbuggbiGKGh0dHA6Ly9jcmxjbC5pbmZvY2VydC5pdC9jYTMvdHNhL0NSTC5jcmyGgYtsZGFwOi8vbGRhcGNs" + + "LmluZm9jZXJ0Lml0L2NuJTNESW5mb0NlcnQlMjBUaW1lJTIwU3RhbXBpbmclMjBBdXRob3JpdHklMjAzJTIwQ0wsb3UlM0RUU0Es" + + "byUzRElORk9DRVJUJTIwU1BBLGMlM0RJVD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0MGwGA1UdIARlMGMwCAYGBACPZwEBME8G" + + "BitMJAEBKDBFMEMGCCsGAQUFBwIBFjdodHRwOi8vd3d3LmZpcm1hLmluZm9jZXJ0Lml0L2RvY3VtZW50YXppb25lL21hbnVhbGku" + + "cGhwMAYGBCtMEAYwDgYDVR0PAQH/BAQDAgeAMB8GA1UdIwQYMBaAFEHldFezAI2xG0viX7DrARShKtuZMB0GA1UdDgQWBBQJ7Bf9" + + "kzBv8oTNyiECzlBLNSWcNTANBgkqhkiG9w0BAQsFAAOCAgEAyD+jZi6CR/Hfxu/IaN2TP+L10Sm4WzlVc4uQlOFrlrxiHuyZvqWj" + + "hebS2eCBJ/MQnbuzoJe6XAlZCRiQHL+bFR4EhlXb34c0NKGsNb0uJgwZM8WvxEE3kPNPFfb/QqJm+H9OTcLsFW9ZBMbpIGpzYHi1" + + "v1W8ETTQM8RR1cxbv5t4uc7VB2V0nHW5KwJadMNGPJgaL+7SHzxcOB4K8QcKkJLxAocd3xfRWBLexTfX3oH4zGb7YHuWgxxogWPx" + + "RGD9it4N3qGHVOgrgGsWWjza29AQSSnZaR+HmNuX6TTAt21Lm5JI79zfG1cgL5UxGpBloKJPIP0Ti0JQz01wJl/8wf8WFXi5oSAs" + + "OVMLXu6UiZJ5Dgm4aVooeU8fzin+SrF/m7iwKp4sibVhEwi6X+9xQV/abyNp0QemiHuNS3dNAuwIsUHYoFFMPTcbse+JSx6JyTTi" + + "N/CSivSjD6vh0L3lJ7vdG8sVT+sNOkjgVrDdJ5OonTnnqDNjWFF4PsIVkue9ZrCI9SFtLfi/RiCnc79QdrqkFcP96F9XzSyoSJwD" + + "NAMQKsjaOCXuGxtPBNJRoAVR2t4cnGJIkc/RrllvsZmrrt2eq8+qFCPEJgy3+7wx4noPtTcAcMBh2RVs8V91flJEcSr/e3CvzKaV" + + "8cmfNg1g00XmS7Ps3w0lGS9g/sRgcscxggLSMIICzgIBATCBhzCBgTELMAkGA1UEBhMCSVQxGDAWBgNVBAoMD0luZm9DZXJ0IFMu" + + "cC5BLjEMMAoGA1UECwwDVFNBMRowGAYDVQRhDBFWQVRJVC0wNzk0NTIxMTAwNjEuMCwGA1UEAwwlSW5mb0NlcnQgVGltZSBTdGFt" + + "cGluZyBBdXRob3JpdHkgMyBDTAIBDjANBglghkgBZQMEAgEFAKCCARswGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqG" + + "SIb3DQEJBDEiBCBoI+/W2jQpMcB1rsNP9IpssP0nHJz0zCYFh+GitSK3+zCBywYLKoZIhvcNAQkQAi8xgbswgbgwgbUwgbIEIGHM" + + "B34bFSWTFpXzd/r69zOYA6dNg/iE5qWFk9VWTmSMMIGNMIGHpIGEMIGBMQswCQYDVQQGEwJJVDEYMBYGA1UECgwPSW5mb0NlcnQg" + + "Uy5wLkEuMQwwCgYDVQQLDANUU0ExGjAYBgNVBGEMEVZBVElULTA3OTQ1MjExMDA2MS4wLAYDVQQDDCVJbmZvQ2VydCBUaW1lIFN0" + + "YW1waW5nIEF1dGhvcml0eSAzIENMAgEOMA0GCSqGSIb3DQEBAQUABIIBAAaGUELs/u4IAaVDY08a8qWKJomuqEKguYoDEh0auAxo" + + "2de7q3AwgrfqUnA0eJvGahqxidT5sL5tCylf8PXXP01Mm7wWf5dNOCVjY/DZCkvLB4+tRq9bFvJEAIpcQXcUh8anS+keY4jYLWZa" + + "c3j+75+TdcysA4yxXyGjWijLoKhDLCaOdOLmU0TftZ9hlWAfTsual6vIw86Kqv/o/NzxdGrDHrqfPF7prfFQQB7cnzG3tPX7owPM" + + "tTJa3Ijiad+UEkIQqzSgG8+lGL03SbGyhSiU3KvZR+wvnesq2VTdZq6g6gbgohAnhl5gLMLnJj/6CgGj51tU6/ViBBKfCxVu0EMA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; + + internal const String SERIALIZED_B64_2DIGEST_ALGOS = "MIIKCgYJKoZIhvcNAQcCoIIJ+zCCCfcCAQExHjANBglghkgBZQME" + + "AgEFADANBglghkgBZQMEAgIFADALBgkqhkiG9w0BBwGgggfb" + "MIID6TCCAtGgAwIBAgIEWOew7DANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJCWTEOMAwGA1UEBwwFTWluc2sxDjAMBgNVBAoM" + + "BWlUZXh0MQ0wCwYDVQQLDAR0ZXN0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MCAXDTE3MDQwNzE1MzM0MFoYDzIxMTcwNDA3MTUz" + + "MzQwWjBZMQswCQYDVQQGEwJCWTEOMAwGA1UEBwwFTWluc2sxDjAMBgNVBAoMBWlUZXh0MQ0wCwYDVQQLDAR0ZXN0MRswGQYDVQQD" + + "DBJpVGV4dFRlc3RSc2FDZXJ0MDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfr2PnZ6DjvrSYg0cWtDR6drgvCowB" + + "5hQH7CHSAMTeVGZxUOBT1ylfxySioRU4ckq3uQu7jOe7Te6YxEenjFhTv8bT0/ZrL2w6OGBH4iUs3Kwx5jzbRHPuZt7+gCKLBXhR" + + "H6ytDnbTHNgT4tjGXUmGa4sMbal1mXvKN/xaK+hGDskRW6cHZq7ZtdgfM8yBQWZzshAz7dQepmUHZYWxplTwJ8cuVLqjgXMXWfTa" + + "tio6yYwf+5AkWszBcCA6oxm16wN2pLUeNx5aBLiFDhtj6qqHLwN/7tPb0ojqXRU3AfocC2y8a4WeVOOp2du0ja4E9P7IQNKiBBlO" + + "fNcFD700qPFpAgMBAAGjgbswgbgwCQYDVR0TBAIwADB/BgNVHSMEeDB2gBRdKnF1rt3Yvlm6ILFmkcl2NlNc7qFYpFYwVDELMAkG" + + "A1UEBhMCQlkxDjAMBgNVBAcMBU1pbnNrMQ4wDAYDVQQKDAVpVGV4dDENMAsGA1UECwwEdGVzdDEWMBQGA1UEAwwNaVRleHRUZXN0" + + "Um9vdIIEWOeR1jAdBgNVHQ4EFgQUz41Jo8H/HAqxhMN/inuhKuLZU8gwCwYDVR0PBAQDAgXgMA0GCSqGSIb3DQEBCwUAA4IBAQCT" + + "597xhkVzrYP7NudRgIZCDwT3TDnL+Xv8H4c9p+CdHJtFMoxAQlzcQi4uEIo5nfBKMEXK0d1OnO8zEBfK98EPahUI++PDnNk82kh6" + + "4CbZQ95Ms1Usq1XGd31bkXWWRM3LY2P7VG0nR+eLutVAClIcbTLNyL9ZhiL33jCk1W5PeXJy13kL3XV/Awt8zb9fcinkuXkV5LoZ" + + "Hxh2Ob19R//5fGxHhnUywReGptnIbEPiWGYyX1QCQeOqi3vmqZaGr+RZfF8+zqtSP5p4gFpryuTJxkcZUOeroaBv3sHCI9rtzcwZ" + + "PYsW0BroFliEhNIDq5HxJgdwdu6uDOMMrC2QxB17MIID6jCCAtKgAwIBAgIEWOeR1jANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQG" + + "EwJCWTEOMAwGA1UEBwwFTWluc2sxDjAMBgNVBAoMBWlUZXh0MQ0wCwYDVQQLDAR0ZXN0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290" + + "MCAXDTE3MDQwNzEzMjAwMVoYDzIxMTcwNDA3MTMyMDAxWjBUMQswCQYDVQQGEwJCWTEOMAwGA1UEBwwFTWluc2sxDjAMBgNVBAoM" + + "BWlUZXh0MQ0wCwYDVQQLDAR0ZXN0MRYwFAYDVQQDDA1pVGV4dFRlc3RSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC" + + "AQEAz/fz7iq1wzhMMYcGfmMmteCY/ZtdE26PB1OTTBuDSN86sVNmur5FV/mLPU9ZK2ofrs+wMrqn0agmFlRl4dThf5u5WSEQ/ARw" + + "XzYOn2uEkwR/0dwwZUL3VWhrPSD5SxX5MzFo8UXTNlXW2bClLC0FQU2qLjIwwRFwwWDSQPR8r/Mv181RljVpEjPk6DfkDtHWWA4d" + + "aGlQU0nXbuZszplviPafXmyKn+2w4G9Jw/8pHIK2VhWYstLI+bUZk662ZVldNvnpMyHn12FfB0Nbf/Z6V2WTGviEr8EEE2cA7I+H" + + "7ZGUDzug7umNCCJn3ilC6vAt9i9OLaZRDh6jPMOjMUizTwIDAQABo4HBMIG+MA8GA1UdEwEB/wQFMAMBAf8wfwYDVR0jBHgwdoAU" + + "XSpxda7d2L5ZuiCxZpHJdjZTXO6hWKRWMFQxCzAJBgNVBAYTAkJZMQ4wDAYDVQQHDAVNaW5zazEOMAwGA1UECgwFaVRleHQxDTAL" + + "BgNVBAsMBHRlc3QxFjAUBgNVBAMMDWlUZXh0VGVzdFJvb3SCBFjnkdYwHQYDVR0OBBYEFF0qcXWu3di+WbogsWaRyXY2U1zuMAsG" + + "A1UdDwQEAwIB9jANBgkqhkiG9w0BAQsFAAOCAQEAdhby6EaopoUF8j7oR44Mhe/N3y9hzGb/zLmmgTavPd2plv6NlAPt9W+8rezK" + + "O6jQCsBRFw8JY+Lx6j3W0K6rWigBpPGU/B/0bXLlOIv2a4uW8nBmq6jxAe5Xbtwm8HcKOOLMzxPIChHJIJy5NWw9ArD4Ul+FEt/V" + + "uEW1NfPZm1U5ixMOrBfn0C8pxIX4+VSHN9I8WoFjSfYX4Y3ldRLTeqxQrhZQlbhGNymp3Kcvtuq5At6vopskyB8Q1b7L4e+hRWK2" + + "prz/7p4Bdhu2TmkEfWZcYKpgrkVFqa/Z1uZ0q4KVBOP3cyaQmqRXTV37SfpNyHAJdol5ueF68VVVNZFRXzGCAeQwggHgAgEBMFww" + + "VDELMAkGA1UEBhMCQlkxDjAMBgNVBAcMBU1pbnNrMQ4wDAYDVQQKDAVpVGV4dDENMAsGA1UECwwEdGVzdDEWMBQGA1UEAwwNaVRl" + + "eHRUZXN0Um9vdAIEWOew7DANBglghkgBZQMEAgIFAKBbMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwPwYJKoZIhvcNAQkEMTIE" + + "ML20ezScXHtsOE/X0HhTqz5/DL9/I6Q6mqsaADaHmEm4j4WmTlOuL/xqc0QEXi9eDTANBgkqhkiG9w0BAQwFAASCAQAefBoGX9+q" + + "J8O6VBRJZt4P1d4yTUYoCsvN76TpwuhiQen2tGZbgqu85aCSUwTFDqBu5gnuwAO3X7rPslnkPqBmBrCd+HXiJLGBqbxAyegwnQ8r" + + "szSVQQBWYSjXWEXRHb2HBXsHS0IsM51xDLRIiwXssGv99ixOIgjoT25zGuz100phXQEsVj7qtJenXF//IPHYqSsw+xyRRpXyG6KE" + + "ITgqfZ9dnvLL/Ncb34yHo0TVBy9bvbVEuWE/Skg5ygHQzBkXeETUMgvu+PhBCQq8BDFpv3o45LhZHnXWbRGUXnLhVrVE8F1FK7EW" + + "6y/NPLKNu3R1lt7g/zX7481b6g0z7Exj"; + + internal const String SERIALIZED_B64_2SIGNERS = "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"; + + internal const String SERIALIZED_B64_MISSING_CERTIFICATES = "MIICHAYJKoZIhvcNAQcCoIICDTCCAgkCAQExDzANBglghkgBZQMEAgIFADALBgkqhkiG9w0BBwExggHkMIIB4AIBATBcMFQxCzAJ" + + "BgNVBAYTAkJZMQ4wDAYDVQQHDAVNaW5zazEOMAwGA1UECgwFaVRleHQxDTALBgNVBAsMBHRlc3QxFjAUBgNVBAMMDWlUZXh0VGVz" + + "dFJvb3QCBFjnsOwwDQYJYIZIAWUDBAICBQCgWzAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMD8GCSqGSIb3DQEJBDEyBDC9tHs0" + + "nFx7bDhP19B4U6s+fwy/fyOkOpqrGgA2h5hJuI+Fpk5Tri/8anNEBF4vXg0wDQYJKoZIhvcNAQEMBQAEggEAHnwaBl/fqifDulQU" + + "SWbeD9XeMk1GKArLze+k6cLoYkHp9rRmW4KrvOWgklMExQ6gbuYJ7sADt1+6z7JZ5D6gZgawnfh14iSxgam8QMnoMJ0PK7M0lUEA" + + "VmEo11hF0R29hwV7B0tCLDOdcQy0SIsF7LBr/fYsTiII6E9ucxrs9dNKYV0BLFY+6rSXp1xf/yDx2KkrMPsckUaV8huihCE4Kn2f" + + "XZ7yy/zXG9+Mh6NE1QcvW721RLlhP0pIOcoB0MwZF3hE1DIL7vj4QQkKvAQxab96OOS4WR511m0RlF5y4Va1RPBdRSuxFusvzTyy" + + "jbt0dZbe4P81++PNW+oNM+xMYw=="; + + internal const String SERIALIZED_B64_EMPTY_CERTIFICATES = "MIICHgYJKoZIhvcNAQcCoIICDzCCAgsCAQExDzANBglghkgBZQMEAgIFADALBgkqhkiG9w0BBwGgADGCAeQwggHgAgEBMFwwVDEL" + + "MAkGA1UEBhMCQlkxDjAMBgNVBAcMBU1pbnNrMQ4wDAYDVQQKDAVpVGV4dDENMAsGA1UECwwEdGVzdDEWMBQGA1UEAwwNaVRleHRU" + + "ZXN0Um9vdAIEWOew7DANBglghkgBZQMEAgIFAKBbMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwPwYJKoZIhvcNAQkEMTIEML20" + + "ezScXHtsOE/X0HhTqz5/DL9/I6Q6mqsaADaHmEm4j4WmTlOuL/xqc0QEXi9eDTANBgkqhkiG9w0BAQwFAASCAQAefBoGX9+qJ8O6" + + "VBRJZt4P1d4yTUYoCsvN76TpwuhiQen2tGZbgqu85aCSUwTFDqBu5gnuwAO3X7rPslnkPqBmBrCd+HXiJLGBqbxAyegwnQ8rszSV" + + "QQBWYSjXWEXRHb2HBXsHS0IsM51xDLRIiwXssGv99ixOIgjoT25zGuz100phXQEsVj7qtJenXF//IPHYqSsw+xyRRpXyG6KEITgq" + + "fZ9dnvLL/Ncb34yHo0TVBy9bvbVEuWE/Skg5ygHQzBkXeETUMgvu+PhBCQq8BDFpv3o45LhZHnXWbRGUXnLhVrVE8F1FK7EW6y/N" + + "PLKNu3R1lt7g/zX7481b6g0z7Exj"; + + internal const String EXPECTED_RESULT_CMS_CONTAINER_TEST = "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" + + "CgEAoIIBDDCCAQgGCSsGAQUFBzABAQSB+gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwDQYJKoZIhvcN" + "AQELBQAEggEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; + + internal const String MESSAGE_DIGEST_STRING = "This a a 'long' string representing the message digest\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n"; + + internal const String BASE64_OCSP_RESPONSE = "MzA4MjA4M2MzMDgyMDE0YmExODFhNTMwODFhMjMxMGIzMDA5MDYwMzU1MDQwNjEzMDI0" + + "NTUzMzEzNDMwMzIwNjAzNTUwNDBhMGMyYjQzNmY2ZTczNmY3MjYzNjkyMDQxNjQ2ZDY5NmU2OTczNzQ3MjYxNjM2OWMzYjMyMDRmNjI2" + + "NTcyNzQ2MTIwNjQ2NTIwNDM2MTc0NjE2Yzc1NmU3OTYxMzEzNDMwMzIwNjAzNTUwNDBiMGMyYjU2NjU2NzY1NzUyMDY4NzQ3NDcwNzMz" + + "YTJmMmY3Nzc3NzcyZTYxNmY2MzJlNjM2MTc0MmY0MzQxNTQ0MzY1NzI3NDJmNTI2NTY3NzU2YzYxNjM2OTZmMzEyNzMwMjUwNjAzNTUw" + + "NDAzMGMxZTUzNjU3Mjc2NjU2OTIwNGY0MzUzNTAyMDY0NjUyMDQ1NDMyZDUzNjU2Mzc0NmY3MjUwNzU2MjZjNjk2MzE4MGYzMjMwMzIz" + + "MjMwMzQzMjMxMzEzNTM1MzkzMzMyNWEzMDZiMzA2OTMwNDEzMDA5MDYwNTJiMGUwMzAyMWEwNTIwMDQxNDJjY2QyYTdhOTM3MTMyZTU5" + + "OWUwZDYyNWFhMDUyZTJhM2ZkY2IxZjIwNDE0NDczY2RlMTQ3N2JiNmE0ZjQ3OTFhOTAyZmZkNDA2ZTE3M2RjZTJkOTAyMDg3NDRlZWUx" + + "MTRhMzU5Yzg1ODAyMDE4MGYzMjMwMzIzMjMwMzQzMjMxMzEzNTM1MzkzMzMyNWFhMDExMTgwZjMyMzAzMjMyMzAzNDMyMzEzMTM2MzAz" + + "NDMzMzE1YWExMjMzMDIxMzAxZjA2MDkyYjA2MDEwNTA1MDczMDAxMDIwNDEyMDQxMDNlOGI2OTE3OTdhNTQ4OWUwYTRkOTMzYjEyMmRj" + + "ZTY2MzAwZDA2MDkyYTg2NDg4NmY3MGQwMTAxMGIwNTIwMDM4MjAxMDEyMDcyMmQ1NmJkZWI2MjQzN2YyMDI5NmEzYTJlMzRkYTFhZjVl" + + "YWQyYjVhZjQzY2M5NDQxMzBiZjg3MjkzNzY2ZDYzYjBlOTA2YTI2YTEyNTkwZGNhMTRjMjdjMmM4Njc1ZDg2MWUxNjBhNTVhOTIyMzNj" + + "Mjg5MjA0MWQ1MmNjODA3NjdmMzIyZDBmNTJjZTViYjUxYjA4MzcyZmRkZjk4YWY1NjgzYTRiY2E1MGY2ZWRmNDI1YmZhMTZhYTI5NDZk" + + "NDllZTI1YWY4Yjk1OWIxMzczZDQ4ZWFkODc2NWRjNDIyYTlkY2FkMmJjZTliNGEzYzA3OWI3YTExMjA1NjIzYjU4YWE4ZmJhMzE5ZDcy" + + "NjBhMzcyNzk4MTBkMzI1ZDg5YzJlYmU3Y2I2NGMzZjA3YmY1ZTQ4ZDg1MmM0OWViN2ZlOTQ2YjcxNWE5MDhhOWMyOTVhOGM0ODRiNjVi" + + "NjVlNWE5OWViNWU2ZmViNTAzOWI1YjAwOGMzNWZjMjdkMzdkOTI0ZjNmMDg1YjdiZTJkMTA1OWEwMzBiZDc1NzU5NTA3NzFlMTUxOTRi" + + "MGYxYWJiNjcwZmQ4MDZjMWY2MTY5ZGIwZDc5NzFhYWQ2ODY4ZTQ0OWY5MDU5MmQzYmFhNTIyM2VkYTMyMGM1ZDZjM2NmOGJiNDc5ZjRl" + + "NGY5YjljOTA0YTA4MjA1ZDUzMDgyMDVkMTMwODIwNWNkMzA4MjA0YjVhMDAzMDIwMTAyMDIxMDY5ODk1NGExODllZDVkMTAwNzQ1NThh" + + "YjE3ZDEyZDUyMzAwZDA2MDkyYTg2NDg4NmY3MGQwMTAxMGIwNTIwMzA4MTg4MzEwYjMwMDkwNjAzNTUwNDA2MTMwMjQ1NTMzMTMzMzAz" + + "TA2MDM1NTA0MGEwYzJhNDM0ZjRlNTM0ZjUyNDM0OTIwNDE0NDRkNDk0ZTQ5NTM1NDUyNDE0MzQ5NGYyMDRmNDI0NTUyNTQ0MTIwNDQ0N" + + "TIwNDM0MTU0NDE0YzU1NGU1OTQxMzEyYTMwMjgwNjAzNTUwNDBiMGMyMTUzNjU3Mjc2NjU2OTczMjA1MGMzYmE2MjZjNjk2MzczMjA2N" + + "DY1MjA0MzY1NzI3NDY5NjY2OTYzNjE2MzY5YzNiMzMxMTgzMDE2MDYwMzU1MDQwMzBjMGY0NTQzMmQ1MzY1NjM3NDZmNzI1MDc1NjI2Y" + + "zY5NjMzMDFlMTcwZDMyMzEzMDM2MzEzNjMxMzUzMTM2MzIzMTVhMTcwZDMyMzIzMDM2MzEzNjMxMzUzMTM2MzIzMDVhMzA4MWEyMzEwY" + + "jMwMDkwNjAzNTUwNDA2MTMwMjQ1NTMzMTM0MzAzMjA2MDM1NTA0MGEwYzJiNDM2ZjZlNzM2ZjcyNjM2OTIwNDE2NDZkNjk2ZTY5NzM3N" + + "DcyNjE2MzY5YzNiMzIwNGY2MjY1NzI3NDYxMjA2NDY1MjA0MzYxNzQ2MTZjNzU2ZTc5NjEzMTM0MzAzMjA2MDM1NTA0MGIwYzJiNTY2N" + + "TY3NjU3NTIwNjg3NDc0NzA3MzNhMmYyZjc3Nzc3NzJlNjE2ZjYzMmU2MzYxNzQyZjQzNDE1NDQzNjU3Mjc0MmY1MjY1Njc3NTZjNjE2M" + + "zY5NmYzMTI3MzAyNTA2MDM1NTA0MDMwYzFlNTM2NTcyNzY2NTY5MjA0ZjQzNTM1MDIwNjQ2NTIwNDU0MzJkNTM2NTYzNzQ2ZjcyNTA3N" + + "TYyNmM2OTYzMzA4MjAxMjIzMDBkMDYwOTJhODY0ODg2ZjcwZDAxMDEwMTA1MjAwMzgyMDEwZjIwMzA4MjAxMGEwMjgyMDEwMTIwYzMxN" + + "TUxYTAyMjQ4OGUxNDE2ZWFkMjE0ZmUyMWUxNGJjZjEx="; + + internal const String B64_ENCODED_NO_SIGNED_ATTRIBS = "MIIBAgIBATBpMGExCzAJBgNVBAYTAkJZMQ4wDAYDVQQHDAVNaW5zazEOMAwGA1UECgwFaVRleHQxDTALBgNVBAsMBHRlc3QxIzAh" + + "BgNVBAMMGmlUZXh0VGVzdEludGVybWVkaWF0ZVJzYTAxAgRcbCwiMAsGCWCGSAFlAwQCAzALBgkqhkiG9w0BAQEEeAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; + + internal const String B64_ENCODED_SUBJECTKEY_IDENTIFIER = "MIGvAgEDgBYEFP2fo/szT6zFxBlouZPece/Ay1wOMAsGCWCGSAFlAwQCAzALBgkqhkiG9w0BAQEEeAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; + + internal const String EXPECTEDRESULT_1 = "MYIGYzAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMIIGRQYJKoZIhvcNAQkEMYIGNgSCBjJUaGlz" + + "IGEgYSAnbG9uZycgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgbWVzc2FnZSBkaWdlc3QNCjAxMjM0" + "NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAx" + + "MjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkNCjAxMjM0NTY3ODkwMTIzNDU2" + "Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIz" + + "NDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkNCjAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4" + "OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1" + + "Njc4OTAxMjM0NTY3ODkNCjAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkw" + "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3" + + "ODkNCjAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEy" + "MzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkNCjAxMjM0NTY3" + + "ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0" + "NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkNCjAxMjM0NTY3ODkwMTIzNDU2Nzg5" + + "MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2" + "Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkNCjAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAx" + + "MjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4" + "OTAxMjM0NTY3ODkNCjAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIz" + + "NDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkN" + "CjAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1" + + "Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkNCjAxMjM0NTY3ODkw" + "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3" + + "ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkNCjAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEy" + "MzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5" + + "MDEyMzQ1Njc4OTAxMjM0NTY3ODkNCjAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0" + "NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAx" + + "MjM0NTY3ODkNCjAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2" + "Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkNCjAx" + + "MjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4" + "OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkNCg=="; + + internal const String EXPECTEDRESULT_2 = "MYIOhTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMIIEEwYJKoZIhvcNAQkEMYIEBASCBAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIIKUAYJ" + + "KoZIhvcvAQEIMIIKQaCCAdgwggHUMIIB0DCBuQIBATANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQG" + "EwJCWTEOMAwGA1UEBwwFTWluc2sxDjAMBgNVBAoMBWlUZXh0MQ0wCwYDVQQLDAR0ZXN0MSIwIAYD" + + "VQQDDBlpVGV4dFRlc3RSc2FDZXJ0V2l0aENoYWluFw0wMDAyMTMxNDE0MDJaFw0wMDAzMTUxNDE0" + "MDJaMCUwIwIEXGwsIhcNMDAwMzE1MTQxNDAyWjAMMAoGA1UdFQQDCgEBMA0GCSqGSIb3DQEBCwUA" + + "A4IBAQCHiG6rCn46IpDvtHX2SRM/azq+rhrvZZ5axvoBIkeRo1efAwbn8f+0V2wRxBvGFWsEwguT" + "lzXS3bT9cDfvR1HKDsjUfvcSEc4tEzzvXrZonV1Q3Z3TEe4SBjJdlYvCoNOYXRlly48qi6IuL3Mh" + + "40EOz0AEhR8ShhEY43FbRN3DllSzHZOp//s/JeXXwTaw7CEv0molbl3gm6X3glWH0o9iAj37MIPd" + "NpAx1sjQq3aCbjMExLM7B6XIL4g6kRVSFaYupVUiUTyQJaQgaFm2qhQnB1FWeLREbzHCZEyiff6O" + + "BYTVq+paYvScEOgSUDkNSH3qYVhuBC0ZZMdMhn7sl2WdoYIIYTCCCF0wgghZCgEAoIIIUjCCCE4G" + "CSsGAQUFBzABAQSCCD8zMDgyMDgzYzMwODIwMTRiYTE4MWE1MzA4MWEyMzEwYjMwMDkwNjAzNTUw" + + "NDA2MTMwMjQ1NTMzMTM0MzAzMjA2MDM1NTA0MGEwYzJiNDM2ZjZlNzM2ZjcyNjM2OTIwNDE2NDZk" + "Njk2ZTY5NzM3NDcyNjE2MzY5YzNiMzIwNGY2MjY1NzI3NDYxMjA2NDY1MjA0MzYxNzQ2MTZjNzU2" + + "ZTc5NjEzMTM0MzAzMjA2MDM1NTA0MGIwYzJiNTY2NTY3NjU3NTIwNjg3NDc0NzA3MzNhMmYyZjc3" + "Nzc3NzJlNjE2ZjYzMmU2MzYxNzQyZjQzNDE1NDQzNjU3Mjc0MmY1MjY1Njc3NTZjNjE2MzY5NmYz" + + "MTI3MzAyNTA2MDM1NTA0MDMwYzFlNTM2NTcyNzY2NTY5MjA0ZjQzNTM1MDIwNjQ2NTIwNDU0MzJk" + "NTM2NTYzNzQ2ZjcyNTA3NTYyNmM2OTYzMTgwZjMyMzAzMjMyMzAzNDMyMzEzMTM1MzUzOTMzMzI1" + + "YTMwNmIzMDY5MzA0MTMwMDkwNjA1MmIwZTAzMDIxYTA1MjAwNDE0MmNjZDJhN2E5MzcxMzJlNTk5" + "ZTBkNjI1YWEwNTJlMmEzZmRjYjFmMjA0MTQ0NzNjZGUxNDc3YmI2YTRmNDc5MWE5MDJmZmQ0MDZl" + + "MTczZGNlMmQ5MDIwODc0NGVlZTExNGEzNTljODU4MDIwMTgwZjMyMzAzMjMyMzAzNDMyMzEzMTM1" + "MzUzOTMzMzI1YWEwMTExODBmMzIzMDMyMzIzMDM0MzIzMTMxMzYzMDM0MzMzMTVhYTEyMzMwMjEz" + + "MDFmMDYwOTJiMDYwMTA1MDUwNzMwMDEwMjA0MTIwNDEwM2U4YjY5MTc5N2E1NDg5ZTBhNGQ5MzNi" + "MTIyZGNlNjYzMDBkMDYwOTJhODY0ODg2ZjcwZDAxMDEwYjA1MjAwMzgyMDEwMTIwNzIyZDU2YmRl" + + "YjYyNDM3ZjIwMjk2YTNhMmUzNGRhMWFmNWVhZDJiNWFmNDNjYzk0NDEzMGJmODcyOTM3NjZkNjNi" + "MGU5MDZhMjZhMTI1OTBkY2ExNGMyN2MyYzg2NzVkODYxZTE2MGE1NWE5MjIzM2MyODkyMDQxZDUy" + + "Y2M4MDc2N2YzMjJkMGY1MmNlNWJiNTFiMDgzNzJmZGRmOThhZjU2ODNhNGJjYTUwZjZlZGY0MjVi" + "ZmExNmFhMjk0NmQ0OWVlMjVhZjhiOTU5YjEzNzNkNDhlYWQ4NzY1ZGM0MjJhOWRjYWQyYmNlOWI0" + + "YTNjMDc5YjdhMTEyMDU2MjNiNThhYThmYmEzMTlkNzI2MGEzNzI3OTgxMGQzMjVkODljMmViZTdj" + "YjY0YzNmMDdiZjVlNDhkODUyYzQ5ZWI3ZmU5NDZiNzE1YTkwOGE5YzI5NWE4YzQ4NGI2NWI2NWU1" + + "YTk5ZWI1ZTZmZWI1MDM5YjViMDA4YzM1ZmMyN2QzN2Q5MjRmM2YwODViN2JlMmQxMDU5YTAzMGJk" + "NzU3NTk1MDc3MWUxNTE5NGIwZjFhYmI2NzBmZDgwNmMxZjYxNjlkYjBkNzk3MWFhZDY4NjhlNDQ5" + + "ZjkwNTkyZDNiYWE1MjIzZWRhMzIwYzVkNmMzY2Y4YmI0NzlmNGU0ZjliOWM5MDRhMDgyMDVkNTMw" + "ODIwNWQxMzA4MjA1Y2QzMDgyMDRiNWEwMDMwMjAxMDIwMjEwNjk4OTU0YTE4OWVkNWQxMDA3NDU1" + + "OGFiMTdkMTJkNTIzMDBkMDYwOTJhODY0ODg2ZjcwZDAxMDEwYjA1MjAzMDgxODgzMTBiMzAwOTA2" + "MDM1NTA0MDYxMzAyNDU1MzMxMzMzMDNMDYwMzU1MDQwYTBjMmE0MzRmNGU1MzRmNTI0MzQ5MjA0M" + + "TQ0NGQ0OTRlNDk1MzU0NTI0MTQzNDk0ZjIwNGY0MjQ1NTI1NDQxMjA0NDQ1MjA0MzQxNTQ0MTRjN" + "TU0ZTU5NDEzMTJhMzAyODA2MDM1NTA0MGIwYzIxNTM2NTcyNzY2NTY5NzMyMDUwYzNiYTYyNmM2O" + + "TYzNzMyMDY0NjUyMDQzNjU3Mjc0Njk2NjY5NjM2MTYzNjljM2IzMzExODMwMTYwNjAzNTUwNDAzM" + "GMwZjQ1NDMyZDUzNjU2Mzc0NmY3MjUwNzU2MjZjNjk2MzMwMWUxNzBkMzIzMTMwMzYzMTM2MzEzN" + + "TMxMzYzMjMxNWExNzBkMzIzMjMwMzYzMTM2MzEzNTMxMzYzMjMwNWEzMDgxYTIzMTBiMzAwOTA2M" + "DM1NTA0MDYxMzAyNDU1MzMxMzQzMDMyMDYwMzU1MDQwYTBjMmI0MzZmNmU3MzZmNzI2MzY5MjA0M" + + "TY0NmQ2OTZlNjk3Mzc0NzI2MTYzNjljM2IzMjA0ZjYyNjU3Mjc0NjEyMDY0NjUyMDQzNjE3NDYxN" + "mM3NTZlNzk2MTMxMzQzMDMyMDYwMzU1MDQwYjBjMmI1NjY1Njc2NTc1MjA2ODc0NzQ3MDczM2EyZ" + + "jJmNzc3Nzc3MmU2MTZmNjMyZTYzNjE3NDJmNDM0MTU0NDM2NTcyNzQyZjUyNjU2Nzc1NmM2MTYzN" + "jk2ZjMxMjczMDI1MDYwMzU1MDQwMzBjMWU1MzY1NzI3NjY1NjkyMDRmNDM1MzUwMjA2NDY1MjA0N" + + "TQzMmQ1MzY1NjM3NDZmNzI1MDc1NjI2YzY5NjMzMDgyMDEyMjMwMGQwNjA5MmE4NjQ4ODZmNzBkM" + "DEwMTAxMDUyMDAzODIwMTBmMjAzMDgyMDEwYTAyODIwMTAxMjBjMzE1NTFhMDIyNDg4ZTE0MTZlY" + + "WQyMTRmZTIxZTE0YmNmMTA=="; + + internal const String EXPECTEDRESULT_3 = "MYIFCTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMIHVBgsqhkiG9w0BCRACLzGBxTCBwjCBvzCB" + + "vDALBglghkgBZQMEAgMEQAJAICi7FPbZ7MwuzR4m/aK+S1eD6bzTwuOyR7FTgIO8qLDmq9xnUmiZ" + "k1Qx7DIAZJkHriWUtM6HRka/few5zPQwa6RjMGExCzAJBgNVBAYTAkJZMQ4wDAYDVQQHDAVNaW5z" + + "azEOMAwGA1UECgwFaVRleHQxDTALBgNVBAsMBHRlc3QxIzAhBgNVBAMMGmlUZXh0VGVzdEludGVy" + "bWVkaWF0ZVJzYTAxAgRcbCwiMIIEEwYJKoZIhvcNAQkEMYIEBASCBAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + + internal const String EXPECTEDRESULT_4 = "MIIHswIBATBpMGExCzAJBgNVBAYTAkJZMQ4wDAYDVQQHDAVNaW5zazEOMAwGA1UECgwFaVRleHQx" + + "DTALBgNVBAsMBHRlc3QxIzAhBgNVBAMMGmlUZXh0VGVzdEludGVybWVkaWF0ZVJzYTAxAgRcbCwi" + "MA0GCWCGSAFlAwQCAwUAoIIFCTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMIHVBgsqhkiG9w0B" + + "CRACLzGBxTCBwjCBvzCBvDALBglghkgBZQMEAgMEQAJAICi7FPbZ7MwuzR4m/aK+S1eD6bzTwuOy" + "R7FTgIO8qLDmq9xnUmiZk1Qx7DIAZJkHriWUtM6HRka/few5zPQwa6RjMGExCzAJBgNVBAYTAkJZ" + + "MQ4wDAYDVQQHDAVNaW5zazEOMAwGA1UECgwFaVRleHQxDTALBgNVBAsMBHRlc3QxIzAhBgNVBAMM" + "GmlUZXh0VGVzdEludGVybWVkaWF0ZVJzYTAxAgRcbCwiMIIEEwYJKoZIhvcNAQkEMYIEBASCBAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMA0G" + + "CSqGSIb3DQEBCwUABIICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAoRQwEgYJKoZIhvcNAQkFMQUCAwHiQA=="; + + internal const String EXPECTEDRESULT_5 = "MYIGIDAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMIIB6wYJKoZIhvcvAQEIMIIB3KCCAdgwggHU" + + "MIIB0DCBuQIBATANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJCWTEOMAwGA1UEBwwFTWluc2sx" + "DjAMBgNVBAoMBWlUZXh0MQ0wCwYDVQQLDAR0ZXN0MSIwIAYDVQQDDBlpVGV4dFRlc3RSc2FDZXJ0" + + "V2l0aENoYWluFw0wMDAyMTMxNDE0MDJaFw0wMDAzMTUxNDE0MDJaMCUwIwIEXGwsIhcNMDAwMzE1" + "MTQxNDAyWjAMMAoGA1UdFQQDCgEBMA0GCSqGSIb3DQEBCwUAA4IBAQCHiG6rCn46IpDvtHX2SRM/" + + "azq+rhrvZZ5axvoBIkeRo1efAwbn8f+0V2wRxBvGFWsEwguTlzXS3bT9cDfvR1HKDsjUfvcSEc4t" + "EzzvXrZonV1Q3Z3TEe4SBjJdlYvCoNOYXRlly48qi6IuL3Mh40EOz0AEhR8ShhEY43FbRN3DllSz" + + "HZOp//s/JeXXwTaw7CEv0molbl3gm6X3glWH0o9iAj37MIPdNpAx1sjQq3aCbjMExLM7B6XIL4g6" + "kRVSFaYupVUiUTyQJaQgaFm2qhQnB1FWeLREbzHCZEyiff6OBYTVq+paYvScEOgSUDkNSH3qYVhu" + + "BC0ZZMdMhn7sl2WdMIIEEwYJKoZIhvcNAQkEMYIEBASCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + } +} diff --git a/itext.tests/itext.sign.tests/itext/signatures/cms/EncapsulatedContentInfoTest.cs b/itext.tests/itext.sign.tests/itext/signatures/cms/EncapsulatedContentInfoTest.cs new file mode 100644 index 0000000000..cf4c7ce413 --- /dev/null +++ b/itext.tests/itext.sign.tests/itext/signatures/cms/EncapsulatedContentInfoTest.cs @@ -0,0 +1,73 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2023 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.Bouncycastleconnector; +using iText.Commons.Bouncycastle; +using iText.Commons.Bouncycastle.Asn1; +using iText.Commons.Utils; +using iText.Signatures; +using iText.Test; + +namespace iText.Signatures.Cms { + [NUnit.Framework.Category("BouncyCastleUnitTest")] + public class EncapsulatedContentInfoTest : ExtendedITextTest { + private static readonly IBouncyCastleFactory FACTORY = BouncyCastleFactoryCreator.GetFactory(); + + private const String ENCODED_WITH_CONTENT_B64 = "MH0GCyqGSIb3DQEJEAEEoG4EbDBqAgEBBglghkgBhv1sBwEwMTANBglg" + + "hkgBZQMEAgEFAAQgSbIIRqXY9+m1GfDgEnVFrQw//OObVVmEk4sLQ4uirygCEHHvE6CzVVvOraJrAlIXOO8YDzIwMjMxMDMxMDU1ODQ" + + "5WgIEwrIa7w=="; + + [NUnit.Framework.Test] + public virtual void TestDeserializationWithoutContent() { + IAsn1EncodableVector v = FACTORY.CreateASN1EncodableVector(); + v.Add(FACTORY.CreateASN1ObjectIdentifier(SecurityIDs.ID_PKCS7_DATA)); + IAsn1Sequence testData = FACTORY.CreateDERSequence(v); + EncapsulatedContentInfo sut = new EncapsulatedContentInfo(testData); + NUnit.Framework.Assert.AreEqual(SecurityIDs.ID_PKCS7_DATA, sut.GetContentType()); + NUnit.Framework.Assert.IsNull(sut.GetContent()); + } + + [NUnit.Framework.Test] + public virtual void TestDeserializationWithContent() { + IAsn1Sequence testData = FACTORY.CreateASN1Sequence(Convert.FromBase64String(ENCODED_WITH_CONTENT_B64)); + EncapsulatedContentInfo sut = new EncapsulatedContentInfo(testData); + NUnit.Framework.Assert.AreEqual("1.2.840.113549.1.9.16.1.4", sut.GetContentType()); + NUnit.Framework.Assert.IsNotNull(sut.GetContent()); + } + + [NUnit.Framework.Test] + public virtual void TestCreation() { + EncapsulatedContentInfo sut = new EncapsulatedContentInfo(SecurityIDs.ID_PKCS7_DATA); + NUnit.Framework.Assert.AreEqual(SecurityIDs.ID_PKCS7_DATA, sut.GetContentType()); + NUnit.Framework.Assert.IsNull(sut.GetContent()); + } + + [NUnit.Framework.Test] + public virtual void TestCreationWithContent() { + EncapsulatedContentInfo sut = new EncapsulatedContentInfo(SecurityIDs.ID_PKCS7_DATA, FACTORY.CreateDEROctetString + (new byte[20])); + NUnit.Framework.Assert.AreEqual(SecurityIDs.ID_PKCS7_DATA, sut.GetContentType()); + NUnit.Framework.Assert.IsNotNull(sut.GetContent()); + } + } +} diff --git a/itext.tests/itext.sign.tests/itext/signatures/cms/SignerInfoTest.cs b/itext.tests/itext.sign.tests/itext/signatures/cms/SignerInfoTest.cs new file mode 100644 index 0000000000..e42772297f --- /dev/null +++ b/itext.tests/itext.sign.tests/itext/signatures/cms/SignerInfoTest.cs @@ -0,0 +1,347 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2023 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 System.Collections.Generic; +using System.Linq; +using iText.Bouncycastleconnector; +using iText.Commons.Bouncycastle; +using iText.Commons.Bouncycastle.Asn1; +using iText.Commons.Bouncycastle.Asn1.Util; +using iText.Commons.Bouncycastle.Cert; +using iText.Commons.Bouncycastle.Crypto; +using iText.Commons.Utils; +using iText.Kernel.Exceptions; +using iText.Signatures; +using iText.Signatures.Exceptions; +using iText.Signatures.Testutils; +using iText.Signatures.Testutils.Builder; +using iText.Test; + +namespace iText.Signatures.Cms { + [NUnit.Framework.Category("BouncyCastleUnitTest")] + public class SignerInfoTest : ExtendedITextTest { + private static readonly IBouncyCastleFactory FACTORY = BouncyCastleFactoryCreator.GetFactory(); + + private static readonly String CERTS_SRC = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext + .CurrentContext.TestDirectory) + "/resources/itext/signatures/certs/"; + + private static readonly char[] PASSWORD = "testpassphrase".ToCharArray(); + + private static readonly IAsn1Dump DUMP = FACTORY.CreateASN1Dump(); + + private static readonly byte[] MESSAGE_DIGEST = CMSTestHelper.MESSAGE_DIGEST_STRING.GetBytes(System.Text.Encoding + .UTF8); + + private static readonly byte[] EXPECTEDRESULT_1 = Convert.FromBase64String(CMSTestHelper.EXPECTEDRESULT_1); + + private static readonly byte[] EXPECTEDRESULT_2 = Convert.FromBase64String(CMSTestHelper.EXPECTEDRESULT_2); + + private static readonly byte[] EXPECTEDRESULT_3 = Convert.FromBase64String(CMSTestHelper.EXPECTEDRESULT_3); + + private static readonly byte[] EXPECTEDRESULT_4 = Convert.FromBase64String(CMSTestHelper.EXPECTEDRESULT_4); + + private static readonly byte[] EXPECTEDRESULT_5 = Convert.FromBase64String(CMSTestHelper.EXPECTEDRESULT_5); + + private static readonly IList chain = new List(); + + static SignerInfoTest() { + IX509Certificate[] certChain = new IX509Certificate[0]; + try { + certChain = PemFileHelper.ReadFirstChain(CERTS_SRC + "signCertRsaWithChain.pem"); + } + catch (Exception) { + } + // Ignore. + foreach (IX509Certificate cert in certChain) { + chain.Add((IX509Certificate)cert); + } + } + + private IX509Certificate signCert; + + private IList testCrlResponse; + + [NUnit.Framework.OneTimeSetUp] + public static void Before() { + } + + [NUnit.Framework.SetUp] + public virtual void Init() { + signCert = chain[0]; + IPrivateKey caPrivateKey = PemFileHelper.ReadFirstKey(CERTS_SRC + "signCertRsaWithChain.pem", PASSWORD); + TestCrlBuilder testCrlBuilder = new TestCrlBuilder(signCert, caPrivateKey); + testCrlBuilder.AddCrlEntry(signCert, FACTORY.CreateCRLReason().GetKeyCompromise()); + testCrlResponse = JavaCollectionsUtil.SingletonList(testCrlBuilder.MakeCrl()); + } + + [NUnit.Framework.Test] + public virtual void TestSignedAttributesReadonlyModeActivatedByGettingSerializedData() { + SignerInfo si = new SignerInfo(); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSA)); + si.SetSigningCertificate(signCert); + List fakeOcspREsponses = new List(); + fakeOcspREsponses.Add(Convert.FromBase64String(CMSTestHelper.BASE64_OCSP_RESPONSE)); + si.SetMessageDigest(new byte[1024]); + si.SetOcspResponses(fakeOcspREsponses); + si.SetCrlResponses(testCrlResponse); + si.SetDigestAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_SHA512)); + si.SerializeSignedAttributes(); + NUnit.Framework.Assert.Catch(typeof(InvalidOperationException), () => si.SetSerializedSignedAttributes(new + byte[1235])); + NUnit.Framework.Assert.Catch(typeof(InvalidOperationException), () => si.SetCrlResponses(testCrlResponse)); + NUnit.Framework.Assert.Catch(typeof(InvalidOperationException), () => si.SetOcspResponses(fakeOcspREsponses + )); + NUnit.Framework.Assert.Catch(typeof(InvalidOperationException), () => si.SetMessageDigest(new byte[1024])); + Attribute attribute = new Attribute("", FACTORY.CreateASN1Integer(1)); + NUnit.Framework.Assert.Catch(typeof(InvalidOperationException), () => si.AddSignedAttribute(attribute)); + NUnit.Framework.Assert.Catch(typeof(InvalidOperationException), () => si.AddSignerCertificateToSignedAttributes + (signCert, SecurityIDs.ID_SHA512)); + } + + [NUnit.Framework.Test] + public virtual void TestGetSerializedBasicSignedAttributes() { + SignerInfo si = new SignerInfo(); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSASSA_PSS)); + si.SetSigningCertificate(signCert); + si.SetMessageDigest(MESSAGE_DIGEST); + si.SetDigestAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_SHA512)); + byte[] serRes = si.SerializeSignedAttributes(); + NUnit.Framework.Assert.AreEqual(SerializedAsString(EXPECTEDRESULT_1), SerializedAsString(serRes)); + } + + [NUnit.Framework.Test] + public virtual void TestGetSerializedExtendedSignedAttributes() { + SignerInfo si = new SignerInfo(); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSASSA_PSS)); + si.SetSigningCertificate(signCert); + List fakeOcspREsponses = new List(); + fakeOcspREsponses.Add(Convert.FromBase64String(CMSTestHelper.BASE64_OCSP_RESPONSE)); + si.SetOcspResponses(fakeOcspREsponses); + si.SetCrlResponses(testCrlResponse); + si.SetMessageDigest(new byte[1024]); + si.SetDigestAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_SHA512)); + byte[] serRes = si.SerializeSignedAttributes(); + NUnit.Framework.Assert.AreEqual(SerializedAsString(EXPECTEDRESULT_2), SerializedAsString(serRes)); + } + + [NUnit.Framework.Test] + public virtual void TestGetSerializedExtendedSignedAttributesCrlOnly() { + SignerInfo si = new SignerInfo(); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSASSA_PSS)); + si.SetSigningCertificate(signCert); + si.SetCrlResponses(testCrlResponse); + si.SetMessageDigest(new byte[1024]); + si.SetDigestAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_SHA512)); + byte[] serRes = si.SerializeSignedAttributes(); + NUnit.Framework.Assert.AreEqual(SerializedAsString(EXPECTEDRESULT_5), SerializedAsString(serRes)); + } + + [NUnit.Framework.Test] + public virtual void TestAddSignedAttribute() { + SignerInfo si = new SignerInfo(); + NUnit.Framework.Assert.IsFalse(si.GetSignedAttributes().Any((a) => Object.Equals(a.GetType(), SecurityIDs. + ID_SIGNING_TIME))); + Attribute attrib = new Attribute(SecurityIDs.ID_SIGNING_TIME, FACTORY.CreateNullASN1Set()); + si.AddSignedAttribute(attrib); + NUnit.Framework.Assert.IsTrue(si.GetSignedAttributes().Any((a) => Object.Equals(a.GetType(), SecurityIDs.ID_SIGNING_TIME + ))); + } + + [NUnit.Framework.Test] + public virtual void TestAddUnsignedAttribute() { + SignerInfo si = new SignerInfo(); + Attribute attrib = new Attribute(SecurityIDs.ID_SIGNING_TIME, FACTORY.CreateNullASN1Set()); + si.AddUnSignedAttribute(attrib); + NUnit.Framework.Assert.AreEqual(SecurityIDs.ID_SIGNING_TIME, SignTestPortUtil.GetFirstElement(si + .GetUnSignedAttributes()).GetType()); + } + + [NUnit.Framework.Test] + public virtual void TestGetSerializedSignedAttributesWithCertificateId() { + SignerInfo si = new SignerInfo(); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSASSA_PSS)); + si.SetSigningCertificate(signCert); + si.SetMessageDigest(new byte[1024]); + si.SetDigestAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_SHA512)); + si.AddSignerCertificateToSignedAttributes(signCert, "2.16.840.1.101.3.4.2.3"); + byte[] serRes = si.SerializeSignedAttributes(); + NUnit.Framework.Assert.AreEqual(SerializedAsString(EXPECTEDRESULT_3), SerializedAsString(serRes)); + } + + [NUnit.Framework.Test] + public virtual void TestGetSerializedSignedAttributesWithCertificateIdTroughCertSetter() { + SignerInfo si = new SignerInfo(); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSASSA_PSS)); + si.SetSigningCertificateAndAddToSignedAttributes(signCert, "2.16.840.1.101.3.4.2.3"); + si.SetMessageDigest(new byte[1024]); + si.SetDigestAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_SHA512)); + byte[] serRes = si.SerializeSignedAttributes(); + NUnit.Framework.Assert.AreEqual(SerializedAsString(EXPECTEDRESULT_3), SerializedAsString(serRes)); + } + + [NUnit.Framework.Test] + public virtual void TestGetAsDerSequence() { + SignerInfo si = new SignerInfo(); + si.AddUnSignedAttribute(new Attribute(SecurityIDs.ID_SIGNING_TIME, FACTORY.CreateDERSet(FACTORY.CreateASN1Integer + (123456)))); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSASSA_PSS)); + si.SetSigningCertificateAndAddToSignedAttributes(signCert, "2.16.840.1.101.3.4.2.3"); + si.SetMessageDigest(new byte[1024]); + si.SetDigestAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_SHA512)); + si.SetSignature(new byte[512]); + IDerSequence res = si.GetAsDerSequence(); + NUnit.Framework.Assert.AreEqual(SerializedAsString(EXPECTEDRESULT_4), SerializedAsString(res.GetEncoded()) + ); + } + + [NUnit.Framework.Test] + public virtual void TestEstimatedSizeWithSignature() { + SignerInfo si = new SignerInfo(); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSA_WITH_SHA256)); + si.AddUnSignedAttribute(new Attribute(SecurityIDs.ID_SIGNING_TIME, FACTORY.CreateDERSet(FACTORY.CreateASN1Integer + (123456)))); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSASSA_PSS)); + si.SetSigningCertificateAndAddToSignedAttributes(signCert, "2.16.840.1.101.3.4.2.3"); + si.SetMessageDigest(new byte[1024]); + si.SetDigestAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_SHA512)); + si.SetSignature(new byte[512]); + long res = si.GetEstimatedSize(); + NUnit.Framework.Assert.AreEqual(1975, res); + } + + [NUnit.Framework.Test] + public virtual void TestSignedAttributesSerializationRoundTrip() { + SignerInfo si = new SignerInfo(); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSASSA_PSS)); + si.SetSigningCertificateAndAddToSignedAttributes(signCert, "2.16.840.1.101.3.4.2.3"); + si.SetMessageDigest(new byte[1024]); + si.SetDigestAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_SHA512)); + si.SetSignature(new byte[512]); + byte[] serialized = si.SerializeSignedAttributes(); + SignerInfo si2 = new SignerInfo(); + si2.SetSerializedSignedAttributes(serialized); + NUnit.Framework.Assert.AreEqual(si.GetSignedAttributes().Count, si2.GetSignedAttributes().Count); + foreach (Attribute attribute in si.GetSignedAttributes()) { + NUnit.Framework.Assert.IsTrue(si2.GetSignedAttributes().Any((a) => a.GetType().Equals(attribute.GetType()) + && a.GetValue().Equals(attribute.GetValue())), MessageFormatUtil.Format("Expected to find an attribute with id {0} and value {1}" + , attribute.GetType(), attribute.GetValue().ToString())); + } + } + + [NUnit.Framework.Test] + public virtual void TestEstimatedSizeEstimatedSignature() { + SignerInfo si = new SignerInfo(); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSA_WITH_SHA256)); + si.AddUnSignedAttribute(new Attribute(SecurityIDs.ID_SIGNING_TIME, FACTORY.CreateDERSet(FACTORY.CreateASN1Integer + (123456)))); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSASSA_PSS)); + si.SetSigningCertificateAndAddToSignedAttributes(signCert, "2.16.840.1.101.3.4.2.3"); + si.SetMessageDigest(new byte[1024]); + si.SetDigestAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_SHA512)); + long res = si.GetEstimatedSize(); + NUnit.Framework.Assert.AreEqual(2487, res); + } + + [NUnit.Framework.Test] + public virtual void TestSerializeAndDeserializeSignerInfo() { + SignerInfo si = new SignerInfo(); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSA_WITH_SHA256)); + si.AddUnSignedAttribute(new Attribute(SecurityIDs.ID_SIGNING_TIME, FACTORY.CreateDERSet(FACTORY.CreateASN1Integer + (123456)))); + si.SetSignatureAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_RSASSA_PSS)); + si.SetSigningCertificateAndAddToSignedAttributes(signCert, "2.16.840.1.101.3.4.2.3"); + si.SetMessageDigest(new byte[1024]); + si.SetDigestAlgorithm(new AlgorithmIdentifier(SecurityIDs.ID_SHA512)); + IDerSequence encoded = si.GetAsDerSequence(false); + SignerInfo si2 = new SignerInfo(encoded, JavaCollectionsUtil.SingletonList(signCert)); + NUnit.Framework.Assert.AreEqual(si.GetSignedAttributes().Count, si2.GetSignedAttributes().Count); + } + + [NUnit.Framework.Test] + public virtual void TestSerializeAndDeserializeSignedAttributes() { + SignerInfo si = new SignerInfo(); + si.AddSignerCertificateToSignedAttributes(signCert, SecurityIDs.ID_SHA256); + si.SetMessageDigest(new byte[20]); + byte[] attribs = si.SerializeSignedAttributes(); + SignerInfo si2 = new SignerInfo(); + si2.SetSerializedSignedAttributes(attribs); + NUnit.Framework.Assert.AreEqual(si.GetSignedAttributes().Count, si2.GetSignedAttributes().Count); + } + + [NUnit.Framework.Test] + public virtual void TestDeserializationMissingSignedAttributes() { + IAsn1Encodable testData = FACTORY.CreateASN1Primitive(Convert.FromBase64String(CMSTestHelper.B64_ENCODED_NO_SIGNED_ATTRIBS + )); + SignerInfo si = new SignerInfo(testData, chain); + NUnit.Framework.Assert.AreEqual(0, si.GetSignedAttributes().Count); + } + + [NUnit.Framework.Test] + public virtual void TestMissingSignerCertificate() { + IAsn1Encodable testData = FACTORY.CreateASN1Primitive(Convert.FromBase64String(CMSTestHelper.B64_ENCODED_NO_SIGNED_ATTRIBS + )); + Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => new SignerInfo(testData, chain.SubList + (1, chain.Count - 1))); + NUnit.Framework.Assert.AreEqual(SignExceptionMessageConstant.CMS_CERTIFICATE_NOT_FOUND, e.Message); + } + + [NUnit.Framework.Test] + public virtual void TestSidWithSubjectKeyIdentifier() { + IAsn1Encodable testData = FACTORY.CreateASN1Primitive(Convert.FromBase64String(CMSTestHelper.B64_ENCODED_SUBJECTKEY_IDENTIFIER + )); + SignerInfo si = new SignerInfo(testData, chain); + NUnit.Framework.Assert.AreEqual(signCert.GetSerialNumber(), si.GetSigningCertificate().GetSerialNumber()); + } + + [NUnit.Framework.Test] + public virtual void TestMissingCertificateWithSubjectKeyIdentifier() { + IAsn1Encodable testData = FACTORY.CreateASN1Primitive(Convert.FromBase64String(CMSTestHelper.B64_ENCODED_SUBJECTKEY_IDENTIFIER + )); + Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => new SignerInfo(testData, chain.SubList + (1, chain.Count - 1))); + NUnit.Framework.Assert.AreEqual(SignExceptionMessageConstant.CMS_CERTIFICATE_NOT_FOUND, e.Message); + } + + [NUnit.Framework.Test] + public virtual void TestInvalidStructure() { + IAsn1EncodableVector v = FACTORY.CreateASN1EncodableVector(); + v.Add(FACTORY.CreateASN1ObjectIdentifier("1.2.840.113549.1.7.2")); + //should be tagged with 0 + v.Add(FACTORY.CreateDERSequence(FACTORY.CreateASN1EncodableVector())); + IAsn1Encodable testData = FACTORY.CreateASN1Sequence(v); + Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => new SignerInfo(testData, chain.SubList + (1, chain.Count - 1))); + NUnit.Framework.Assert.AreEqual(SignExceptionMessageConstant.CMS_INVALID_CONTAINER_STRUCTURE, e.Message); + } + + private String ToUnixStringEnding(String @in) { + return @in.Replace("\r\n", "\n"); + } + + private String SerializedAsString(byte[] serialized) { + IAsn1InputStream @is = FACTORY.CreateASN1InputStream(serialized); + IAsn1Object obj1 = @is.ReadObject(); + return ToUnixStringEnding(DUMP.DumpAsString(obj1, true)); + } + } +} diff --git a/itext.tests/itext.sign.tests/itext/signatures/sign/TwoPhaseSigningTest.cs b/itext.tests/itext.sign.tests/itext/signatures/sign/TwoPhaseSigningTest.cs index c64b0f254d..84bf1927cf 100644 --- a/itext.tests/itext.sign.tests/itext/signatures/sign/TwoPhaseSigningTest.cs +++ b/itext.tests/itext.sign.tests/itext/signatures/sign/TwoPhaseSigningTest.cs @@ -22,6 +22,9 @@ You should have received a copy of the GNU Affero General Public License */ using System; using System.IO; +using System.Security.Cryptography; +using System.Xml.Serialization; +using Org.BouncyCastle.Asn1; using iText.Bouncycastleconnector; using iText.Commons.Bouncycastle; using iText.Commons.Bouncycastle.Cert; @@ -30,10 +33,12 @@ You should have received a copy of the GNU Affero General Public License using iText.IO.Source; using iText.Kernel.Exceptions; using iText.Kernel.Pdf; -using iText.Signatures; +using iText.Signatures.Cms; using iText.Signatures.Exceptions; using iText.Signatures.Testutils; using iText.Test; +using AlgorithmIdentifier = Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier; +using SignerInfo = iText.Signatures.Cms.SignerInfo; namespace iText.Signatures.Sign { [NUnit.Framework.Category("BouncyCastleIntegrationTest")] @@ -52,10 +57,14 @@ public class TwoPhaseSigningTest : ExtendedITextTest { private static readonly char[] PASSWORD = "testpassphrase".ToCharArray(); private static readonly String SIMPLE_DOC_PATH = SOURCE_FOLDER + "SimpleDoc.pdf"; + + private static readonly String RSA_PRIVATE_KEY_FILE = CERTS_SRC + "signCertRsa01.xml"; private const String DIGEST_ALGORITHM = DigestAlgorithms.SHA384; - public const String FIELD_NAME = "Signature1"; + private const string DIGEST_ALGORITHM_OID = "2.16.840.1.101.3.4.2.2"; + + private const String FIELD_NAME = "Signature1"; private IPrivateKey pk; @@ -225,6 +234,46 @@ public virtual void TestCompletion() { , SOURCE_FOLDER + "cmp_2PhaseCompleteCycle.pdf")); } + [NUnit.Framework.Test] + public virtual void TestWithCMS() { + String signatureName = "Signature1"; + using (ByteArrayOutputStream phaseOneOS = new ByteArrayOutputStream()) { + // Phase 1 prepare the document, add the partial CMS and get the documents digest of signed attributes + byte[] dataToEncrypt = PrepareDocumentAndCMS(new FileInfo(SIMPLE_DOC_PATH), phaseOneOS, signatureName); + // Phase 2 sign the document digest + //simulating server side + byte[] signaturedata = ServerSideSigning(dataToEncrypt); + + String signedDocumentName = DESTINATION_FOLDER + "2PhaseCompleteCycleCMS.pdf"; + // phase 2.1 extract CMS from the prepared document + using (Stream outputStreamPhase2 = FileUtil.GetFileOutputStream(signedDocumentName)) { + using (PdfDocument doc = new PdfDocument(new PdfReader(new MemoryStream(phaseOneOS.ToArray())))) { + SignatureUtil su = new SignatureUtil(doc); + PdfSignature sig = su.GetSignature(signatureName); + PdfString encodedCMS = sig.GetContents(); + byte[] encodedCMSdata = encodedCMS.GetValueBytes(); + CMSContainer cmsToUpdate = new CMSContainer(encodedCMSdata); + //phase 2.2 add the signatureValue to the CMS + cmsToUpdate.GetSignerInfo().SetSignature(signaturedata); + //if needed a time stamp could be added here + //Phase 2.3 add the updated CMS to the document + PdfSigner.AddSignatureToPreparedDocument(doc, signatureName, outputStreamPhase2, cmsToUpdate); + } + } + // validate signature + using (PdfReader reader = new PdfReader(signedDocumentName)) { + using (PdfDocument finalDoc = new PdfDocument(reader)) { + SignatureUtil su = new SignatureUtil(finalDoc); + PdfPKCS7 cms = su.ReadSignatureData(signatureName); + NUnit.Framework.Assert.IsTrue(cms.VerifySignatureIntegrityAndAuthenticity(), "Signature should be valid"); + } + } + // compare result + NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(signedDocumentName, SOURCE_FOLDER + + "cmp_2PhaseCompleteCycleCMS.pdf")); + } + } + private byte[] SignDigest(byte[] data, String hashAlgorithm) { PdfPKCS7 sgn = new PdfPKCS7((IPrivateKey)null, chain, hashAlgorithm, false); byte[] sh = sgn.GetAuthenticatedAttributeBytes(data, PdfSigner.CryptoStandard.CMS, null, null); @@ -234,5 +283,61 @@ private byte[] SignDigest(byte[] data, String hashAlgorithm) { ()); return sgn.GetEncodedPKCS7(data, PdfSigner.CryptoStandard.CMS, null, null, null); } + + private byte[] PrepareDocumentAndCMS(FileInfo document, ByteArrayOutputStream preparedOS, String signatureName + ) { + using (PdfReader reader = new PdfReader(FileUtil.GetInputStreamForFile(document))) { + using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + PdfSigner signer = new PdfSigner(reader, outputStream, new StampingProperties()); + signer.SetFieldName(signatureName); + byte[] digest = signer.PrepareDocumentForSignature(DIGEST_ALGORITHM, PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached + , 5000, false); + System.Console.Out.WriteLine("Document digest from prepare call: " + digest.Length + "bytes"); + System.Console.Out.WriteLine(Convert.ToBase64String(digest)); + String fieldName = signer.GetFieldName(); + // Phase 1.1 prepare the CMS + CMSContainer cms = new CMSContainer(); + SignerInfo signerInfo = new SignerInfo(); + //signerInfo.setSigningCertificateAndAddToSignedAttributes(chain[0], SecurityIDs.ID_SHA384); + signerInfo.SetSigningCertificate(chain[0]); + // in the two phase scenario,; we don't have the private key! So we start from the signing certificate + + signerInfo.SetSignatureAlgorithm(new Cms.AlgorithmIdentifier(chain[0].GetSigAlgOID())); + signerInfo.SetDigestAlgorithm(new Cms.AlgorithmIdentifier(DIGEST_ALGORITHM_OID)); + signerInfo.SetMessageDigest(digest); + cms.SetSignerInfo(signerInfo); + cms.AddCertificates(chain); + byte[] signedAttributesToSign = cms.GetSerializedSignedAttributes(); + + IDigest sha = iText.Bouncycastleconnector.BouncyCastleFactoryCreator.GetFactory().CreateIDigest(DIGEST_ALGORITHM + ); + byte[] dataToSign = sha.Digest(signedAttributesToSign); + + // now we store signedAttributesToSign together with the prepared document and send + // dataToSign to the signing instance + using (PdfDocument doc = new PdfDocument(new PdfReader(new MemoryStream(outputStream.ToArray())))) { + PdfSigner.AddSignatureToPreparedDocument(doc, fieldName, preparedOS, cms); + } + return dataToSign; + } + } + } + + private byte[] ServerSideSigning(byte[] dataToEncrypt) { + String signingAlgoritmName = pk.GetAlgorithm(); + if ("EC".Equals(signingAlgoritmName)) { + signingAlgoritmName = "ECDSA"; + } + + using (var fs = new StreamReader(RSA_PRIVATE_KEY_FILE)) { + RSA rsa = RSA.Create(); + XmlSerializer serializer = + new XmlSerializer(typeof(RSAParameters)); + var rsaParams = (RSAParameters)serializer.Deserialize(fs); + rsa.ImportParameters(rsaParams); + byte[] signaturedata = rsa.SignHash(dataToEncrypt, HashAlgorithmName.SHA384, RSASignaturePadding.Pkcs1); + return signaturedata; + } + } } } diff --git a/itext.tests/itext.sign.tests/itext/signatures/testutils/SignTestPortUtil.cs b/itext.tests/itext.sign.tests/itext/signatures/testutils/SignTestPortUtil.cs index 13c6783107..fc8ab58a8d 100644 --- a/itext.tests/itext.sign.tests/itext/signatures/testutils/SignTestPortUtil.cs +++ b/itext.tests/itext.sign.tests/itext/signatures/testutils/SignTestPortUtil.cs @@ -22,7 +22,9 @@ You should have received a copy of the GNU Affero General Public License */ using System; using System.Collections; +using System.Collections.Generic; using System.IO; +using System.Linq; using iText.Bouncycastleconnector; using iText.Commons.Bouncycastle; using iText.Commons.Bouncycastle.Cert; @@ -65,5 +67,9 @@ public static IX509Crl ParseCrlFromStream(Stream input) { public static IRsaKeyPairGenerator BuildRSA2048KeyPairGenerator() { return FACTORY.CreateRsa2048KeyPairGenerator(); } + + public static T GetFirstElement(ICollection collection) { + return collection.First(); + } } } diff --git a/itext.tests/itext.sign.tests/itext/signatures/testutils/X509MockCertificate.cs b/itext.tests/itext.sign.tests/itext/signatures/testutils/X509MockCertificate.cs index 6186caad19..e9ed42864f 100644 --- a/itext.tests/itext.sign.tests/itext/signatures/testutils/X509MockCertificate.cs +++ b/itext.tests/itext.sign.tests/itext/signatures/testutils/X509MockCertificate.cs @@ -64,6 +64,16 @@ public IPublicKey GetPublicKey() throw new NotImplementedException(); } + public string GetSigAlgOID() + { + throw new NotImplementedException(); + } + + public byte[] GetSigAlgParams() + { + throw new NotImplementedException(); + } + public byte[] GetEncoded() { throw new NotImplementedException(); diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/certs/signCertRsa01.xml b/itext.tests/itext.sign.tests/resources/itext/signatures/certs/signCertRsa01.xml new file mode 100644 index 0000000000..d889bbd430 --- /dev/null +++ b/itext.tests/itext.sign.tests/resources/itext/signatures/certs/signCertRsa01.xml @@ -0,0 +1,10 @@ + + n69j52eg4760mINHFrQ0ena4LwqMAeYUB+wh0gDE3lRmcVDgU9cpX8ckoqEVOHJKt7kLu4znu03umMRHp4xYU7/G09P2ay9sOjhgR+IlLNysMeY820Rz7mbe/oAiiwV4UR+srQ520xzYE+LYxl1JhmuLDG2pdZl7yjf8WivoRg7JEVunB2au2bXYHzPMgUFmc7IQM+3UHqZlB2WFsaZU8CfHLlS6o4FzF1n02rYqOsmMH/uQJFrMwXAgOqMZtesDdqS1HjceWgS4hQ4bY+qqhy8Df+7T29KI6l0VNwH6HAtsvGuFnlTjqdnbtI2uBPT+yEDSogQZTnzXBQ+9NKjxaQ== + AQAB +

zlwRHfo8rXcsPVMHW/tpignGVW/qIschwUtUJmyYbfMHSDBGCXYL/JJAzlLU+sg9zP52YcQ3lJfDH5h1VTVzQWesWTCM4TFVpW1BbOTx37/53x5V9VDMvXeY5Xv9b7T1tfsPi1Gxhn+fxhMfY+HA9z9wfrUU009K++e+LK50/X0=

+ xhkJhR/pwMzumCHGg2qGu65TMM9dGaje8fV2OK+1DnR0Fpxnn6gmsQCDKEqor+DTJEG8Cgq9vvXy4AJVuzWadl2zkwBhM36wLDwFM2ETSHuzKPzytbgPV/tP5Q0BP+08oeMNTfmj6iOdoqEqA3yWvwkui/ngNMGOu5GozFLvN10= + OXFRZnnY2CSbUPrCyq0CZOVxqyi7ETFDSS4x33xNNhX3ifW+GTYeAhGoLobKOIDzCxQuWeqn2hogu7PRvYVibutwA2fLX4g/Igx2sNxOJA2pfZ1RKjdytq8LBZ5tHuJNn3miixKTizANhrKeA0y9TVYAd5TqliO1aMfKnV92u3U= + C26KdBpBXRT2d+ULFa5iFBadSmXNE5wBMalepyrMogbqZBumhzom8XP8HakhTvUEekUo2tN/27NJzs+TrvgK7+W8ZTFSaqxW8laMXkit2jL5RdZDE2WJzSP9mlRDzDKemyEFNYjAgtSHVklCqWzZLjETdJR48dJxsDVZrmDi2Sk= + HI4zND9c/XYGGFEq9j/NEsixz+BjSQmZ29ZKDYHct5rrLQcX8Y5Hk3H/KPn7ymgO3IQ23c3sjKQhbyrT810zdt1ZqtLNh/27BLtepFaz87TiScrt+jnlW8KMA3/5Zl6KBz+bXFhyInz9aOoP1ZSrQmGlqJUEGh+YujvlozNkcQQ= + JZu+MMLkTp8ck4rflEZO0cTiLhoSzWOttgv0DyylMSO5mNiObNCQ6wDQ7Qh5IfkxBcIsNDjEXwXEuvAHXDueleLl5f/W2nmpyLB8ZJGrZbx3Ra1PCek+UJijzlbJS+q24oxOM9fjPmddsJlNqrJP3bu4XO366jqCwCadZXNP2ifEC0T4ssjeLR3767vjsvpRdj0/yIHv2W8mxnrGBIiPPuk0EEOzyay6sjZNUYfb66sJtsj9qKskd31Pr7XGwn4KFK75j4ETKJljL8H0ih8Cp9vuJE9J8B2hJjIaYI9f3AC3fIAU79s/8P+pyhdKeHU0nPKyT9ltmxGvHUpbIyP+MQ== +
\ No newline at end of file diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/sign/TwoPhaseSigningTest/cmp_2PhaseCompleteCycle.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/sign/TwoPhaseSigningTest/cmp_2PhaseCompleteCycle.pdf index 680b1d5391034925fc1a93925b8c9154d6ded43d..af331cfad4c68dad26a72c9ffe4e752db316c663 100644 GIT binary patch delta 899 zcmW-fKdV+p5Qlj|Qd~5ku`u0fLe!h9Gdq8Fx495fr4y4*1b234z$O>MMZ_X+8%X2j z6sZE1wqk2OO1^;~B6B^}IqaOB-#pK}fA;CwTe_jTJ-_;quAZEHxV*ak!j^G0;yz_o z(@BkE)djT)4I{4s)1pS9!8H09h68}K)!w*UYtdvVdscgim^vyk15191!`e>|-|m0h zxphRZGk;Zy6=Re-$%Zg8ch%((OO{jN#abGSX>)lD_CAX@EsWknja9{38D`UEKrceT zQ^50LcZKdgGo4il8#Am(cc$ypqk_ zMtu&z1@kzuW34SqnF^SDq`I86!>|cVs69OoYR=ZAr!HA(2C=8hS{y~MuMUvKlB5vT ztz-_GmY~ckSLvxTT?Qq8r@6$E{UY*tgQwERtGhS9+27s$YX9f^zYh5E!F@a2L;?g9 zfm6W!?+33Aw155ZzXR@{AHF`6-B15LLD(Q4++x4?!>6NILS9uHyHn_lMx?F;U~6QI z>y$>hT7@vILpM@UPjzL1u13bWis_nCZEkSnK+d(M;*n_zH*r&MUL4v~&HCnM#e0Y7 zOXU3d*(&$I1+ DaO?YO delta 864 zcmWlXy{gtn5XN~yQiv9brbrbVF~^f5GrRM(jS#$n6zN3B&de^c3IqvOc`qPM4*$YN zA*HPmtjrzdA~L607h8I* z1ZcfzBP4k!Z6BLEPv5((9Bhl+yBRjZzM8vi*yu_T9L$RvY_1!bZBEq{i4DjX?wFH7 zl$&;T+zpZU$gQj%J|~)wGq%~O2@KgH4%=F>mYeP{v2Ab2;w2VsnLCxQ9JpjHWUiW4 zO~BE!^v^vQC{0pP(cc|R>U*iCwS3ABhRHFVL;Gvi<^{rprAT%K-%@^9e>~d;&}Jy&l7yS_|8vv0BaKW-Y%gXZ!Ug6 zK3&N1?D6{(9REFjeZpg1{(H#x|C~!)GnP9x-J6LDe6fLa%P68jP#ZC66#*3Fz)?Y) zHj#zXwCryMMB-V0Fl0^ga?Z7-ur@1|71C>egw6AzpX2K0#DlU_Ugg^)q(R* diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/sign/TwoPhaseSigningTest/cmp_2PhaseCompleteCycleCMS.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/sign/TwoPhaseSigningTest/cmp_2PhaseCompleteCycleCMS.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c1c6b792ef7da27a3fa815a0a5eb9db4107b1470 GIT binary patch literal 11708 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
+ public string GetSigAlgOID() => this.certificate.SigAlgOid; + + /// + public byte[] GetSigAlgParams() => this.certificate.GetSigAlgParams(); + /// public byte[] GetEncoded() { return certificate.GetEncoded(); diff --git a/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/asn1/Asn1EncodableBCFips.cs b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/asn1/Asn1EncodableBCFips.cs index dda1281ca6..cf4d7d6d64 100644 --- a/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/asn1/Asn1EncodableBCFips.cs +++ b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/asn1/Asn1EncodableBCFips.cs @@ -71,7 +71,7 @@ public override bool Equals(Object o) { if (this == o) { return true; } - if (o == null || GetType() != o.GetType()) { + if (o == null || !this.GetType().IsAssignableFrom(o.GetType())) { return false; } Asn1EncodableBCFips that = (Asn1EncodableBCFips)o; diff --git a/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/cert/X509CertificateBCFips.cs b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/cert/X509CertificateBCFips.cs index 3623413e29..d354f8bd2d 100644 --- a/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/cert/X509CertificateBCFips.cs +++ b/itext/itext.bouncy-castle-fips-adapter/itext/bouncycastlefips/cert/X509CertificateBCFips.cs @@ -80,7 +80,13 @@ public IBigInteger GetSerialNumber() { public IPublicKey GetPublicKey() { return new PublicKeyBCFips(certificate.GetPublicKey()); } - + + /// + public string GetSigAlgOID() => certificate.SigAlgOid.Id; + + /// + public byte[] GetSigAlgParams() => certificate.GetSigAlgParams(); + /// public byte[] GetEncoded() { return certificate.GetEncoded(); diff --git a/itext/itext.commons/itext/commons/bouncycastle/cert/IX509Certificate.cs b/itext/itext.commons/itext/commons/bouncycastle/cert/IX509Certificate.cs index 009b81e828..0c4022bdc4 100644 --- a/itext/itext.commons/itext/commons/bouncycastle/cert/IX509Certificate.cs +++ b/itext/itext.commons/itext/commons/bouncycastle/cert/IX509Certificate.cs @@ -57,6 +57,18 @@ public interface IX509Certificate { /// /// Public key wrapper. IPublicKey GetPublicKey(); + + /// + /// Get the Signature Algorithms Object ID. + /// + /// A string containg a '.' separated object id. + string GetSigAlgOID(); + + /// + /// Get the signature algorithms parameters. (EG DSA Parameters) + /// + /// A byte array containing the Der encoded version of the parameters or null if there are none. + byte[] GetSigAlgParams(); /// /// Calls actual diff --git a/itext/itext.sign/itext/signatures/CertificateUtil.cs b/itext/itext.sign/itext/signatures/CertificateUtil.cs index de60925d75..80c4d9ac8a 100644 --- a/itext/itext.sign/itext/signatures/CertificateUtil.cs +++ b/itext/itext.sign/itext/signatures/CertificateUtil.cs @@ -156,6 +156,14 @@ public static String GetTSAURL(IX509Certificate certificate) { } } + /// Generates a certificate object and initializes it with the data read from the input stream inStream. + /// + /// the input stream with the certificates. + /// a certificate object initialized with the data from the input stream. + public static IX509Certificate GenerateCertificate(Stream data) { + return SignUtils.GenerateCertificate(data); + } + /// Checks if the certificate is signed by provided issuer certificate. /// a certificate to check /// an issuer certificate to check @@ -180,7 +188,7 @@ internal static bool IsSelfSigned(IX509Certificate certificate) { /// /// object. /// - private static IAsn1Object GetExtensionValue(IX509Certificate certificate, String oid) { + public static IAsn1Object GetExtensionValue(IX509Certificate certificate, String oid) { return GetExtensionValueFromByteArray(SignUtils.GetExtensionValueByOid(certificate, oid)); } diff --git a/itext/itext.sign/itext/signatures/PdfSigner.cs b/itext/itext.sign/itext/signatures/PdfSigner.cs index 79721cada2..29c0747ae5 100644 --- a/itext/itext.sign/itext/signatures/PdfSigner.cs +++ b/itext/itext.sign/itext/signatures/PdfSigner.cs @@ -37,6 +37,7 @@ You should have received a copy of the GNU Affero General Public License using iText.Kernel.Pdf; using iText.Kernel.Pdf.Annot; using iText.Pdfa; +using iText.Signatures.Cms; using iText.Signatures.Exceptions; namespace iText.Signatures { @@ -791,23 +792,8 @@ public virtual void Timestamp(ITSAClient tsa, String signatureName) { /// the message digest of the prepared document. public virtual byte[] PrepareDocumentForSignature(String digestAlgorithm, PdfName filter, PdfName subFilter , int estimatedSize, bool includeDate) { - if (closed) { - throw new PdfException(SignExceptionMessageConstant.THIS_INSTANCE_OF_PDF_SIGNER_ALREADY_CLOSED); - } - cryptoDictionary = CreateSignatureDictionary(includeDate); - cryptoDictionary.Put(PdfName.Filter, filter); - cryptoDictionary.Put(PdfName.SubFilter, subFilter); - IDictionary exc = new Dictionary(); - exc.Put(PdfName.Contents, estimatedSize * 2 + 2); - PreClose(exc); - Stream data = GetRangeStream(); - byte[] digest = DigestAlgorithms.Digest(data, SignUtils.GetMessageDigest(digestAlgorithm)); - byte[] paddedSig = new byte[estimatedSize]; - PdfDictionary dic2 = new PdfDictionary(); - dic2.Put(PdfName.Contents, new PdfString(paddedSig).SetHexWriting(true)); - Close(dic2); - closed = true; - return digest; + return PrepareDocumentForSignature(SignUtils.GetMessageDigest(digestAlgorithm), filter, subFilter, estimatedSize + , includeDate); } /// Adds an existing signature to a PDF where space was already reserved. @@ -821,6 +807,17 @@ public static void AddSignatureToPreparedDocument(PdfDocument document, String f applier.Apply((a) => signedContent); } + /// Adds an existing signature to a PDF where space was already reserved. + /// the original PDF + /// the field to sign. It must be the last field + /// the output PDF + /// the finalized CMS container + public static void AddSignatureToPreparedDocument(PdfDocument document, String fieldName, Stream outs, CMSContainer + cmsContainer) { + PdfSigner.SignatureApplier applier = new PdfSigner.SignatureApplier(document, fieldName, outs); + applier.Apply((a) => cmsContainer.Serialize()); + } + /// Signs a PDF where space was already reserved. /// the original PDF /// the field to sign. It must be the last field @@ -880,7 +877,8 @@ protected internal virtual bool IsPreClosed() { /// /// /// Map with names and sizes to be excluded in the signature - /// calculation. The key is a PdfName and the value an Integer. At least the /Contents must be present + /// calculation. The key is a PdfName and the value an Integer. + /// At least the /Contents must be present /// protected internal virtual void PreClose(IDictionary exclusionSizes) { if (preClosed) { @@ -1293,6 +1291,27 @@ protected internal virtual int GetWidgetPageNumber(PdfWidgetAnnotation widget) { return pageNumber; } + private byte[] PrepareDocumentForSignature(IDigest messageDigest, PdfName filter, PdfName subFilter, int estimatedSize + , bool includeDate) { + if (closed) { + throw new PdfException(SignExceptionMessageConstant.THIS_INSTANCE_OF_PDF_SIGNER_ALREADY_CLOSED); + } + cryptoDictionary = CreateSignatureDictionary(includeDate); + cryptoDictionary.Put(PdfName.Filter, filter); + cryptoDictionary.Put(PdfName.SubFilter, subFilter); + IDictionary exc = new Dictionary(); + exc.Put(PdfName.Contents, estimatedSize * 2 + 2); + PreClose(exc); + Stream data = GetRangeStream(); + byte[] digest = DigestAlgorithms.Digest(data, messageDigest); + byte[] paddedSig = new byte[estimatedSize]; + PdfDictionary dic2 = new PdfDictionary(); + dic2.Put(PdfName.Contents, new PdfString(paddedSig).SetHexWriting(true)); + Close(dic2); + closed = true; + return digest; + } + private bool IsDocumentPdf2() { return document.GetPdfVersion().CompareTo(PdfVersion.PDF_2_0) >= 0; } diff --git a/itext/itext.sign/itext/signatures/SecurityIDs.cs b/itext/itext.sign/itext/signatures/SecurityIDs.cs index 11bce2e40f..299250c6b5 100644 --- a/itext/itext.sign/itext/signatures/SecurityIDs.cs +++ b/itext/itext.sign/itext/signatures/SecurityIDs.cs @@ -47,6 +47,8 @@ public class SecurityIDs { public const String ID_SHA256 = "2.16.840.1.101.3.4.2.1"; + public const String ID_SHA384 = "2.16.840.1.101.3.4.2.2"; + public const String ID_SHA512 = "2.16.840.1.101.3.4.2.3"; public const String ID_SHAKE256 = "2.16.840.1.101.3.4.2.12"; diff --git a/itext/itext.sign/itext/signatures/SignExtensions.cs b/itext/itext.sign/itext/signatures/SignExtensions.cs index 5be78e00ad..763c9cd037 100644 --- a/itext/itext.sign/itext/signatures/SignExtensions.cs +++ b/itext/itext.sign/itext/signatures/SignExtensions.cs @@ -23,6 +23,8 @@ You should have received a copy of the GNU Affero General Public License using System; using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Text; namespace iText.Signatures { internal static class SignExtensions { @@ -33,6 +35,10 @@ public static String JSubstring(this String str, int beginIndex, int endIndex) { public static byte[] GetBytes(this String str) { return System.Text.Encoding.UTF8.GetBytes(str); } + + public static byte[] GetBytes(this String str, Encoding encoding) { + return encoding.GetBytes(str); + } public static void AddAll(this ICollection t, IEnumerable newItems) { foreach (T item in newItems) { @@ -56,6 +62,17 @@ public static T[] ToArray(this ICollection col, T[] toArray) { return r; } + + public static void RemoveIf(this ICollection collection, Func predicate) { + T element; + for (int i = 0; i < collection.Count; i++) { + element = collection.ElementAt(i); + if (predicate(element)) { + collection.Remove(element); + i--; + } + } + } public static void AddAll(this IDictionary c, IDictionary collectionToAdd) { foreach (KeyValuePair pair in collectionToAdd) { @@ -86,6 +103,10 @@ public static int Read(this Stream stream, byte[] buffer) { return stream.Read(buffer, 0, buffer.Length); } + public static ICollection SubList(this ICollection collection, int fromIndex, int toIndex) { + return collection.ToList().GetRange(fromIndex, toIndex - fromIndex); + } + public static void Write(this Stream stream, byte[] buffer) { stream.Write(buffer, 0, buffer.Length); } diff --git a/itext/itext.sign/itext/signatures/SignUtils.cs b/itext/itext.sign/itext/signatures/SignUtils.cs index 6a599644b8..a30fb91d26 100644 --- a/itext/itext.sign/itext/signatures/SignUtils.cs +++ b/itext/itext.sign/itext/signatures/SignUtils.cs @@ -272,5 +272,9 @@ public static ICertID GenerateCertificateId(IX509Certificate issuerCert, IBigInt IDerObjectIdentifier hashAlgOid) { return GenerateCertificateId(issuerCert, serialNumber, hashAlgOid.GetId()); } + + public static IX509Certificate GenerateCertificate(Stream data) { + return FACTORY.CreateX509Certificate(data); + } } } diff --git a/itext/itext.sign/itext/signatures/cms/AlgorithmIdentifier.cs b/itext/itext.sign/itext/signatures/cms/AlgorithmIdentifier.cs new file mode 100644 index 0000000000..615757d011 --- /dev/null +++ b/itext/itext.sign/itext/signatures/cms/AlgorithmIdentifier.cs @@ -0,0 +1,87 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2023 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.Bouncycastleconnector; +using iText.Commons.Bouncycastle; +using iText.Commons.Bouncycastle.Asn1; + +namespace iText.Signatures.Cms { + /// This class represents algorithm identifier structure. + public class AlgorithmIdentifier { + private static readonly IBouncyCastleFactory BC_FACTORY = BouncyCastleFactoryCreator.GetFactory(); + + private readonly String algorithm; + + private readonly IAsn1Object parameters; + + /// Creates an Algorithm identifier structure without parameters. + /// the Object id of the algorithm + public AlgorithmIdentifier(String algorithmId) { + this.algorithm = algorithmId; + parameters = BouncyCastleFactoryCreator.GetFactory().CreateDERNull(); + } + + /// Creates an Algorithm identifier structure with parameters. + /// the Object id of the algorithm + /// the algorithm parameters as an ASN1 structure + public AlgorithmIdentifier(String algorithmId, IAsn1Object parameters) { + this.algorithm = algorithmId; + this.parameters = parameters; + } + + /// Creates an Algorithm identifier structure with parameters. + /// asn1 encodable to retrieve algorithm identifier + internal AlgorithmIdentifier(IAsn1Encodable asnStruct) { + IAsn1Sequence algIdentifier = BC_FACTORY.CreateASN1Sequence(asnStruct); + IDerObjectIdentifier algOid = BC_FACTORY.CreateASN1ObjectIdentifier(algIdentifier.GetObjectAt(0)); + algorithm = algOid.GetId(); + if (algIdentifier.Size() > 1) { + parameters = BC_FACTORY.CreateASN1Primitive(algIdentifier.GetObjectAt(1)); + } + else { + parameters = null; + } + } + + /// Return the OID of the algorithm. + /// the OID of the algorithm. + public virtual String GetAlgorithmOid() { + return algorithm; + } + + /// Return the parameters for the algorithm. + /// the parameters for the algorithm. + public virtual IAsn1Object GetParameters() { + return parameters; + } + + internal virtual IAsn1Sequence GetAsASN1Sequence() { + IAsn1EncodableVector algorithmV = BC_FACTORY.CreateASN1EncodableVector(); + algorithmV.Add(BC_FACTORY.CreateASN1ObjectIdentifier(algorithm)); + if (parameters != null) { + algorithmV.Add(parameters); + } + return BC_FACTORY.CreateDERSequence(algorithmV); + } + } +} diff --git a/itext/itext.sign/itext/signatures/cms/Attribute.cs b/itext/itext.sign/itext/signatures/cms/Attribute.cs new file mode 100644 index 0000000000..f86f8c2faa --- /dev/null +++ b/itext/itext.sign/itext/signatures/cms/Attribute.cs @@ -0,0 +1,53 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2023 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.Asn1; + +namespace iText.Signatures.Cms { + /// This class represents Attribute structure. + public class Attribute { + private readonly String type; + + private readonly IAsn1Object value; + + /// Creates an attribute. + /// the type of the attribute + /// the value + public Attribute(String type, IAsn1Object value) { + this.type = type; + this.value = value; + } + + /// Returns the type of the attribute. + /// the type of the attribute. + public virtual String GetType() { + return type; + } + + /// Returns the value of the attribute. + /// the value of the attribute. + public virtual IAsn1Object GetValue() { + return value; + } + } +} diff --git a/itext/itext.sign/itext/signatures/cms/CMSContainer.cs b/itext/itext.sign/itext/signatures/cms/CMSContainer.cs new file mode 100644 index 0000000000..fa64e569f7 --- /dev/null +++ b/itext/itext.sign/itext/signatures/cms/CMSContainer.cs @@ -0,0 +1,275 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2023 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 System.Collections.Generic; +using System.IO; +using iText.Bouncycastleconnector; +using iText.Commons.Bouncycastle; +using iText.Commons.Bouncycastle.Asn1; +using iText.Commons.Bouncycastle.Cert; +using iText.Commons.Utils; +using iText.Kernel.Exceptions; +using iText.Signatures; +using iText.Signatures.Exceptions; + +namespace iText.Signatures.Cms { + /// + /// The CMS container which represents SignedData structure from + /// rfc5652 Cryptographic Message Syntax (CMS) + /// + public class CMSContainer { + private static readonly IBouncyCastleFactory BC_FACTORY = BouncyCastleFactoryCreator.GetFactory(); + + /// This represents the signed content. + /// + /// This represents the signed content. + /// In the case of a signed PDF document this will of type data with no content. + /// + private EncapsulatedContentInfo encapContentInfo = new EncapsulatedContentInfo(); + + /// Optional. + /// + /// Optional. + /// + /// It is intended to add all certificates to be able to validate the entire chain. + /// + private ICollection certificates = new List(); + + /// This class only supports one signer per signature field. + private SignerInfo signerInfo = new SignerInfo(); + + /// Creates an empty SignedData structure. + public CMSContainer() { + } + + // Empty constructor. + /// Creates a SignedData structure from a serialized ASN1 structure. + /// the serialized CMS container + public CMSContainer(byte[] encodedCMSdata) { + try { + using (IAsn1InputStream @is = BC_FACTORY.CreateASN1InputStream(new MemoryStream(encodedCMSdata))) { + IAsn1Sequence contentInfo = BC_FACTORY.CreateASN1Sequence(@is.ReadObject()); + IAsn1Sequence signedData = BC_FACTORY.CreateASN1Sequence(BC_FACTORY.CreateASN1TaggedObject(contentInfo.GetObjectAt + (1)).GetObject()); + // The digest algorithm is retrieved from SignerInfo later on, here we just validate + // that there is exactly 1 digest algorithm. + IAsn1Set digestAlgorithms = BC_FACTORY.CreateASN1Set(signedData.GetObjectAt(1)); + if (digestAlgorithms.Size() > 1) { + throw new PdfException(SignExceptionMessageConstant.CMS_ONLY_ONE_SIGNER_ALLOWED); + } + IAsn1Sequence lencapContentInfo = BC_FACTORY.CreateASN1Sequence(signedData.GetObjectAt(2)); + encapContentInfo = new EncapsulatedContentInfo(lencapContentInfo); + ProcessCertificates(signedData); + IAsn1Set signerInfosS = BC_FACTORY.CreateASN1Set(signedData.GetObjectAt(4)); + if (signerInfosS == null) { + // Most probably revocation data is in place, so read next item. + signerInfosS = BC_FACTORY.CreateASN1Set(signedData.GetObjectAt(5)); + } + if (signerInfosS.Size() != 1) { + throw new PdfException(SignExceptionMessageConstant.CMS_ONLY_ONE_SIGNER_ALLOWED); + } + signerInfo = new SignerInfo(signerInfosS.GetObjectAt(0), certificates); + } + } + catch (NullReferenceException npe) { + throw new PdfException(SignExceptionMessageConstant.CMS_INVALID_CONTAINER_STRUCTURE, npe); + } + } + + /// This class only supports one signer per signature field. + /// the singerInfo + public virtual void SetSignerInfo(SignerInfo signerInfo) { + this.signerInfo = signerInfo; + } + + /// This class only supports one signer per signature field. + /// the singerInfo + public virtual SignerInfo GetSignerInfo() { + return signerInfo; + } + + /// + /// When all fields except for signer.signedAttributes.digest and signer.signature are completed + /// it is possible to calculate the eventual size of the signature by serializing except for the signature + /// (that depends on the digest and cypher but is set at 1024 bytes) and later added unsigned attributes like + /// timestamps. + /// + /// + /// the estimated size of the complete CMS container before signature is added, size for the signature is + /// added, size for other attributes like timestamps is not. + /// + public virtual long GetSizeEstimation() { + byte[] result = Serialize(true); + return result.Length; + } + + /// Only version 1 is supported by this class. + /// 1 as CMSversion + public virtual int GetCmsVersion() { + return 1; + } + + /// The digest algorithm OID and parameters used by the signer. + /// + /// The digest algorithm OID and parameters used by the signer. + /// This class only supports one signer for use in pdf signatures, so only one digest algorithm is supported. + ///

+ /// This field is set when adding the signerInfo. + ///
+ public virtual AlgorithmIdentifier GetDigestAlgorithm() { + if (signerInfo == null) { + return null; + } + return signerInfo.GetDigestAlgorithm(); + } + + /// This represents the signed content. + /// + /// This represents the signed content. + /// In the case of a signed PDF document this will be of type data with no content. + /// + /// a representation of the data to be signed. + public virtual EncapsulatedContentInfo GetEncapContentInfo() { + return encapContentInfo; + } + + /// This represents the signed content. + /// + /// This represents the signed content. + /// In the case of a signed PDF document this will be of type data with no content. + /// Defaults to 1.2.840.113549.1.7.1 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-7(7) id-data(1)} + /// + /// a representation of the data to be signed. + public virtual void SetEncapContentInfo(EncapsulatedContentInfo encapContentInfo) { + this.encapContentInfo = encapContentInfo; + } + + /// Adds a certificate. + /// the certificate to be added + public virtual void AddCertificate(IX509Certificate cert) { + certificates.Add(cert); + } + + /// Adds a set of certificates. + /// the certificates to be added + public virtual void AddCertificates(IX509Certificate[] certs) { + certificates = JavaUtil.ArraysAsList(certs); + } + + /// Retrieves a copy of the list of certificates. + /// the list of certificates to be used for signing and certificate validation + public virtual ICollection GetCertificates() { + return JavaCollectionsUtil.UnmodifiableCollection(certificates); + } + + /// Sets the Signed Attributes of the signer info to this serialized version. + /// + /// Sets the Signed Attributes of the signer info to this serialized version. + /// The signed attributes will become read-only. + /// + /// the serialized Signed Attributes + public virtual void SetSerializedSignedAttributes(byte[] signedAttributesData) { + signerInfo.SetSerializedSignedAttributes(signedAttributesData); + } + + /// Retrieves the encoded signed attributes of the signer info. + /// + /// Retrieves the encoded signed attributes of the signer info. + /// This makes the signed attributes read only. + /// + /// the encoded signed attributes of the signer info. + public virtual byte[] GetSerializedSignedAttributes() { + if (signerInfo == null) { + throw new InvalidOperationException(SignExceptionMessageConstant.CMS_SIGNERINFO_NOT_INITIALIZED); + } + return signerInfo.SerializeSignedAttributes(); + } + + /// Serializes the SignedData structure and makes the signer infos signed attributes read only. + /// the encoded DignedData structure. + public virtual byte[] Serialize() { + return Serialize(false); + } + + private byte[] Serialize(bool forEstimation) { + /* ContentInfo SEQUENCE + ContentType OBJECT IDENTIFIER (1.2.840.113549.1.7.2) + Content [0] SEQUENCE + SignedData SEQUENCE + version INTEGER + digestAlgorithms SET + DigestAlgorithmIdentifier SEQUENCE + algorithm OBJECT IDENTIFIER + parameters ANY + encapContentInfo EncapsulatedContentInfo SEQUENCE + eContentType ContentType OBJECT IDENTIFIER (1.2.840.113549.1.7.1 data) + CertificateSet [0] (set?) + CertificateChoices SEQUENCE + tbsCertificate TBSCertificate SEQUENCE + signerInfos SignerInfos SET + */ + IAsn1EncodableVector contentInfoV = BC_FACTORY.CreateASN1EncodableVector(); + contentInfoV.Add(BC_FACTORY.CreateASN1ObjectIdentifier(SecurityIDs.ID_PKCS7_SIGNED_DATA)); + IAsn1EncodableVector singedDataV = BC_FACTORY.CreateASN1EncodableVector(); + singedDataV.Add(BC_FACTORY.CreateASN1Integer(GetCmsVersion())); + // version + IAsn1EncodableVector digestAlgorithmsV = BC_FACTORY.CreateASN1EncodableVector(); + digestAlgorithmsV.Add(GetDigestAlgorithm().GetAsASN1Sequence()); + singedDataV.Add(BC_FACTORY.CreateDERSet(digestAlgorithmsV)); + IAsn1EncodableVector encapContentInfoV = BC_FACTORY.CreateASN1EncodableVector(); + encapContentInfoV.Add(BC_FACTORY.CreateASN1ObjectIdentifier(encapContentInfo.GetContentType())); + if (encapContentInfo.GetContent() != null) { + encapContentInfoV.Add(encapContentInfo.GetContent()); + } + singedDataV.Add(BC_FACTORY.CreateDERSequence(encapContentInfoV)); + IAsn1EncodableVector certificateSetV = BC_FACTORY.CreateASN1EncodableVector(); + foreach (IX509Certificate cert in certificates) { + certificateSetV.Add(BC_FACTORY.CreateASN1Primitive(cert.GetEncoded())); + } + singedDataV.Add(BC_FACTORY.CreateDERTaggedObject(false, 0, BC_FACTORY.CreateDERSet(certificateSetV))); + IAsn1EncodableVector signerInfosV = BC_FACTORY.CreateASN1EncodableVector(); + signerInfosV.Add(signerInfo.GetAsDerSequence(forEstimation)); + singedDataV.Add(BC_FACTORY.CreateDERSet(signerInfosV)); + contentInfoV.Add(BC_FACTORY.CreateDERTaggedObject(0, BC_FACTORY.CreateDERSequence(singedDataV))); + return BC_FACTORY.CreateDERSequence(contentInfoV).GetEncoded(); + } + + private void ProcessCertificates(IAsn1Sequence signedData) { + // Certificates are optional according to the specs, but we do require at least the signing certificate. + IAsn1TaggedObject taggedCertificatesSet = BC_FACTORY.CreateASN1TaggedObject(signedData.GetObjectAt(3)); + if (taggedCertificatesSet == null) { + throw new PdfException(SignExceptionMessageConstant.CMS_MISSING_CERTIFICATES); + } + IAsn1Set certificatesSet = BC_FACTORY.CreateASN1Set(taggedCertificatesSet, false); + if (certificatesSet.IsNull() || certificatesSet.Size() == 0) { + throw new PdfException(SignExceptionMessageConstant.CMS_MISSING_CERTIFICATES); + } + foreach (IAsn1Encodable certObj in certificatesSet.ToArray()) { + using (Stream cis = new MemoryStream(certObj.ToASN1Primitive().GetEncoded(BC_FACTORY.CreateASN1Encoding(). + GetDer()))) { + certificates.Add((IX509Certificate)CertificateUtil.GenerateCertificate(cis)); + } + } + } + } +} diff --git a/itext/itext.sign/itext/signatures/cms/EncapsulatedContentInfo.cs b/itext/itext.sign/itext/signatures/cms/EncapsulatedContentInfo.cs new file mode 100644 index 0000000000..dad1bcffcb --- /dev/null +++ b/itext/itext.sign/itext/signatures/cms/EncapsulatedContentInfo.cs @@ -0,0 +1,89 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2023 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.Bouncycastleconnector; +using iText.Commons.Bouncycastle; +using iText.Commons.Bouncycastle.Asn1; + +namespace iText.Signatures.Cms { + /// This class represents the signed content. + public class EncapsulatedContentInfo { + private static readonly IBouncyCastleFactory BC_FACTORY = BouncyCastleFactoryCreator.GetFactory(); + + /// Object identifier of the content field + private String eContentType = "1.2.840.113549.1.7.1"; + + /// Optional. + /// + /// Optional. + /// + /// The actual content as an octet string. Does not have to be DER encoded. + /// + private IAsn1OctetString eContent; + + /// Creates an EncapsulatedContentInfo with contenttype and content. + /// the content type Oid (object id) + /// the content + public EncapsulatedContentInfo(String eContentType, IAsn1OctetString eContent) { + this.eContentType = eContentType; + this.eContent = eContent; + } + + /// Creates an EncapsulatedContentInfo with contenttype. + /// the content type Oid (object id) + public EncapsulatedContentInfo(String eContentType) { + this.eContentType = eContentType; + } + + /// Creates a default EncapsulatedContentInfo. + public EncapsulatedContentInfo() { + } + + // Empty constructor. + internal EncapsulatedContentInfo(IAsn1Sequence lencapContentInfo) { + IDerObjectIdentifier eContentTypeOid = BC_FACTORY.CreateASN1ObjectIdentifier(lencapContentInfo.GetObjectAt + (0)); + IAsn1OctetString eContentElem = null; + if (lencapContentInfo.Size() > 1) { + IAsn1TaggedObject taggedElement = BC_FACTORY.CreateASN1TaggedObject(lencapContentInfo.GetObjectAt(1)); + eContentElem = BC_FACTORY.CreateASN1OctetString(taggedElement.GetObject()); + if (eContentElem != null) { + eContent = eContentElem; + } + } + eContentType = eContentTypeOid.GetId(); + } + + /// Returns the contenttype oid. + /// the contenttype oid. + public virtual String GetContentType() { + return eContentType; + } + + /// Returns the content. + /// the content. + public virtual IAsn1OctetString GetContent() { + return eContent; + } + } +} diff --git a/itext/itext.sign/itext/signatures/cms/SignerInfo.cs b/itext/itext.sign/itext/signatures/cms/SignerInfo.cs new file mode 100644 index 0000000000..3f470ba943 --- /dev/null +++ b/itext/itext.sign/itext/signatures/cms/SignerInfo.cs @@ -0,0 +1,532 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2023 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 System.Collections.Generic; +using System.IO; +using iText.Bouncycastleconnector; +using iText.Commons.Bouncycastle; +using iText.Commons.Bouncycastle.Asn1; +using iText.Commons.Bouncycastle.Asn1.Ocsp; +using iText.Commons.Bouncycastle.Asn1.X509; +using iText.Commons.Bouncycastle.Cert; +using iText.Commons.Bouncycastle.Crypto; +using iText.Commons.Utils; +using iText.Kernel.Exceptions; +using iText.Signatures; +using iText.Signatures.Exceptions; + +namespace iText.Signatures.Cms { + /// + /// This class represents the SignerInfo structure from + /// rfc5652 Cryptographic Message Syntax (CMS) + /// + public class SignerInfo { + private static readonly IBouncyCastleFactory BC_FACTORY = BouncyCastleFactoryCreator.GetFactory(); + + private const int DEFAULT_SIGNATURE_SIZE = 1024; + + private AlgorithmIdentifier digestAlgorithm; + + private AlgorithmIdentifier signingAlgorithm; + + private readonly ICollection signedAttributes = new List(); + + private readonly ICollection unSignedAttributes; + + private byte[] serializedSignedAttributes; + + private ICollection ocspResponses; + + private ICollection crlResponses; + + private byte[] signatureData; + + private bool signedAttributesReadOnly; + + private IX509Certificate signerCertificate; + + /// Creates an empty SignerInfo structure. + public SignerInfo() { + Attribute contentType = new Attribute(SecurityIDs.ID_CONTENT_TYPE, BC_FACTORY.CreateDERSet(BC_FACTORY.CreateASN1ObjectIdentifier + (SecurityIDs.ID_PKCS7_DATA))); + signedAttributes.Add(contentType); + unSignedAttributes = new List(); + } + + /// Creates a SignerInfo structure from an ASN1 structure. + /// the ASN1 structure containing signerInfo + /// the certificates of the CMS, it should contain the signing certificate + public SignerInfo(IAsn1Encodable signerInfoStructure, ICollection certificates) { + int index = 0; + try { + IAsn1Sequence signerInfoSeq = BC_FACTORY.CreateASN1Sequence(signerInfoStructure); + IDerInteger version = BC_FACTORY.CreateASN1Integer(signerInfoSeq.GetObjectAt(index++)); + if (version.GetValue().GetIntValue() == 1) { + ProcessIssuerAndSerialNumberSignerCertificate(signerInfoSeq.GetObjectAt(index++), certificates); + } + else { + ProcessSubjectKeyIdentifierSignerCertificate(signerInfoSeq.GetObjectAt(index++), certificates); + } + digestAlgorithm = new AlgorithmIdentifier(signerInfoSeq.GetObjectAt(index++)); + IAsn1TaggedObject taggedSingedAttributes = BC_FACTORY.CreateASN1TaggedObject(signerInfoSeq.GetObjectAt(index + )); + if (taggedSingedAttributes != null) { + index++; + SetSerializedSignedAttributes(BC_FACTORY.CreateASN1Set(taggedSingedAttributes, false).GetEncoded(BC_FACTORY + .CreateASN1Encoding().GetDer())); + } + signingAlgorithm = new AlgorithmIdentifier(signerInfoSeq.GetObjectAt(index++)); + IDerOctetString signatureDataOS = BC_FACTORY.CreateDEROctetString(signerInfoSeq.GetObjectAt(index++)); + if (signatureDataOS != null) { + signatureData = signatureDataOS.GetOctets(); + } + if (signerInfoSeq.Size() > index) { + IAsn1TaggedObject taggedUnsingedAttributes = BC_FACTORY.CreateASN1TaggedObject(signerInfoSeq.GetObjectAt(index + )); + unSignedAttributes = ProcessAttributeSet(BC_FACTORY.CreateASN1Set(taggedUnsingedAttributes, false)); + } + else { + unSignedAttributes = new List(); + } + } + catch (NullReferenceException npe) { + throw new PdfException(SignExceptionMessageConstant.CMS_INVALID_CONTAINER_STRUCTURE, npe); + } + } + + /// Returns the algorithmId to create the digest of the data to sign. + /// the OID of the digest algorithm. + public virtual AlgorithmIdentifier GetDigestAlgorithm() { + return digestAlgorithm; + } + + /// Sets the algorithmId to create the digest of the data to sign. + /// the OID of the algorithm + public virtual void SetDigestAlgorithm(AlgorithmIdentifier algorithmId) { + digestAlgorithm = algorithmId; + } + + /// Adds or replaces the message digest signed attribute. + /// ASN.1 type MessageDigest + public virtual void SetMessageDigest(byte[] digest) { + if (signedAttributesReadOnly) { + throw new InvalidOperationException(SignExceptionMessageConstant.CMS_SIGNERINFO_READONLY); + } + Attribute digestAttribute = new Attribute(SecurityIDs.ID_MESSAGE_DIGEST, BC_FACTORY.CreateDERSet(BC_FACTORY + .CreateDEROctetString(digest))); + signedAttributes.Add(digestAttribute); + } + + /// Sets the certificate that is used to sign. + /// the certificate that is used to sign + public virtual void SetSigningCertificate(IX509Certificate certificate) { + this.signerCertificate = certificate; + if (certificate.GetSigAlgParams() != null) { + this.signingAlgorithm = new AlgorithmIdentifier(certificate.GetSigAlgOID(), BC_FACTORY.CreateASN1Primitive + (certificate.GetSigAlgParams())); + } + else { + this.signingAlgorithm = new AlgorithmIdentifier(certificate.GetSigAlgOID()); + } + } + + /// Gets the certificate that is used to sign. + /// the certificate that is used to sign. + public virtual IX509Certificate GetSigningCertificate() { + return signerCertificate; + } + + /// Sets the certificate that is used to sign a document and adds it to the signed attributes. + /// the certificate that is used to sign + /// the oid of the digest algorithm to be added to the signed attributes + public virtual void SetSigningCertificateAndAddToSignedAttributes(IX509Certificate certificate, String digestAlgorithmOid + ) { + SetSigningCertificate(certificate); + AddSignerCertificateToSignedAttributes(certificate, digestAlgorithmOid); + } + + /// Adds a set of OCSP responses as signed attributes. + /// a set of binary representations of OCSP responses. + public virtual void SetOcspResponses(ICollection ocspResponses) { + if (signedAttributesReadOnly) { + throw new InvalidOperationException(SignExceptionMessageConstant.CMS_SIGNERINFO_READONLY); + } + this.ocspResponses = JavaCollectionsUtil.UnmodifiableCollection(ocspResponses); + SetRevocationInfo(); + } + + /// Adds a set of CRL responses as signed attributes. + /// a set of binary representations of CRL responses. + public virtual void SetCrlResponses(ICollection crlResponses) { + if (signedAttributesReadOnly) { + throw new InvalidOperationException(SignExceptionMessageConstant.CMS_SIGNERINFO_READONLY); + } + this.crlResponses = JavaCollectionsUtil.UnmodifiableCollection(crlResponses); + SetRevocationInfo(); + } + + /// Adds the signer certificate to the signed attributes as a issuerAndSerialNumber structure. + /// the certificate to add + /// the digest algorithm oid that will be used + public virtual void AddSignerCertificateToSignedAttributes(IX509Certificate cert, String digestAlgorithmOid + ) { + if (signedAttributesReadOnly) { + throw new InvalidOperationException(SignExceptionMessageConstant.CMS_SIGNERINFO_READONLY); + } + IDigest md = DigestAlgorithms.GetMessageDigestFromOid(digestAlgorithmOid); + IAsn1EncodableVector certContents = BC_FACTORY.CreateASN1EncodableVector(); + // don't add if it is the default value + if (!SecurityIDs.ID_SHA256.Equals(digestAlgorithmOid)) { + IAlgorithmIdentifier algoId = BC_FACTORY.CreateAlgorithmIdentifier(BC_FACTORY.CreateASN1ObjectIdentifier(digestAlgorithmOid + )); + certContents.Add(algoId); + } + byte[] dig = md.Digest(cert.GetEncoded()); + certContents.Add(BC_FACTORY.CreateDEROctetString(dig)); + IAsn1Sequence issuer = BC_FACTORY.CreateASN1Sequence(CertificateInfo.GetIssuer(cert.GetTbsCertificate())); + IDerTaggedObject issuerTagged = BC_FACTORY.CreateDERTaggedObject(true, 4, issuer); + IDerInteger serial = BC_FACTORY.CreateASN1Integer(cert.GetSerialNumber()); + IAsn1EncodableVector v = BC_FACTORY.CreateASN1EncodableVector(); + v.Add(issuerTagged); + v.Add(serial); + IDerSequence issuerS = BC_FACTORY.CreateDERSequence(v); + certContents.Add(issuerS); + IDerSequence certContentsSeq = BC_FACTORY.CreateDERSequence(certContents); + IDerSequence certContentsSeqSeq = BC_FACTORY.CreateDERSequence(certContentsSeq); + IDerSequence certContentsSeqSeqSeq = BC_FACTORY.CreateDERSequence(certContentsSeqSeq); + IDerSet certContentsSeqSeqSeqSet = BC_FACTORY.CreateDERSet(certContentsSeqSeqSeq); + Attribute attribute = new Attribute(SecurityIDs.ID_AA_SIGNING_CERTIFICATE_V2, certContentsSeqSeqSeqSet); + signedAttributes.Add(attribute); + } + + /// Sets the actual signature. + /// a byte array containing the signature + public virtual void SetSignature(byte[] signatureData) { + this.signatureData = JavaUtil.ArraysCopyOf(signatureData, signatureData.Length); + } + + /// Optional. + /// + /// Optional. + /// Sets the OID and parameters of the algorithm that will be used to create the signature. + /// This will be overwritten when setting the signing certificate. + /// + /// The OID and parameters of the algorithm that will be used to create the signature. + /// + public virtual void SetSignatureAlgorithm(AlgorithmIdentifier algorithm) { + this.signingAlgorithm = algorithm; + } + + /// + /// Value 0 when no signerIdentifier is available + /// Value 1 when signerIdentifier is of type issuerAndSerialNumber + /// Value 3 when signerIdentifier is of type subjectKeyIdentifier + /// + public virtual int GetCmsVersion() { + return 1; + } + + /// Optional + /// + /// Optional + /// + /// Attributes that should be part of the signed content + /// optional, but it MUST be present if the content type of + /// the EncapsulatedContentInfo value being signed is not id-data. + /// In that case it must at least contain it MUSTthe following two attributes: + /// + /// A content-type attribute having as its value the content type + /// of the EncapsulatedContentInfo value being signed. Section + /// 11.1 defines the content-type attribute. However, the + /// content-type attribute MUST NOT be used as part of a + /// countersignature unsigned attribute as defined in Section 11.4. + /// + /// A message-digest attribute, having as its value the message + /// digest of the content. Section 11.2 defines the message-digest + /// attribute. + /// + public virtual ICollection GetSignedAttributes() { + return JavaCollectionsUtil.UnmodifiableCollection(signedAttributes); + } + + /// Adds a new attribute to the signed attributes. + /// + /// Adds a new attribute to the signed attributes. + /// This become readonly after retrieving the serialized version + /// . + /// + /// the attribute to add + public virtual void AddSignedAttribute(Attribute attribute) { + if (signedAttributesReadOnly) { + throw new InvalidOperationException(SignExceptionMessageConstant.CMS_SIGNERINFO_READONLY); + } + signedAttributes.Add(attribute); + } + + /// Retrieves the optional unsigned attributes. + /// the optional unsigned attributes. + public virtual ICollection GetUnSignedAttributes() { + return JavaCollectionsUtil.UnmodifiableCollection(unSignedAttributes); + } + + /// Optional. + /// + /// Optional. + /// + /// Adds attribute that should not or can not be part of the signed content. + /// + /// the attribute to add + public virtual void AddUnSignedAttribute(Attribute attribute) { + unSignedAttributes.Add(attribute); + } + + /// Retrieves the encoded signed attributes of the signer info. + /// + /// Retrieves the encoded signed attributes of the signer info. + /// This makes the signed attributes read only. + /// + /// the encoded signed attributes of the signer info. + public virtual byte[] SerializeSignedAttributes() { + if (!signedAttributesReadOnly) { + IDerSet derView = GetAttributesAsDERSet(signedAttributes); + serializedSignedAttributes = derView.GetEncoded(BC_FACTORY.CreateASN1Encoding().GetDer()); + signedAttributesReadOnly = true; + } + return JavaUtil.ArraysCopyOf(serializedSignedAttributes, serializedSignedAttributes.Length); + } + + /// Sets the signed attributes from a serialized version. + /// + /// Sets the signed attributes from a serialized version. + /// This makes the signed attributes read only. + /// + /// the encoded signed attributes. + public void SetSerializedSignedAttributes(byte[] serializedSignedAttributes) { + if (signedAttributesReadOnly) { + throw new InvalidOperationException(SignExceptionMessageConstant.CMS_SIGNERINFO_READONLY); + } + this.signedAttributesReadOnly = true; + this.serializedSignedAttributes = JavaUtil.ArraysCopyOf(serializedSignedAttributes, serializedSignedAttributes + .Length); + try { + signedAttributes.Clear(); + this.signedAttributes.AddAll(ProcessAttributeSet(BC_FACTORY.CreateASN1Primitive(serializedSignedAttributes + ))); + } + catch (System.IO.IOException e) { + throw new PdfException(e); + } + } + + /// Calculates an estimate size for the SignerInfo structure. + /// + /// Calculates an estimate size for the SignerInfo structure. + /// This takes into account the values added including the signature, but does not account for unset items like + /// a timestamp response added after actual signing. + /// + /// the estimated size of the structure. + public virtual long GetEstimatedSize() { + IDerSequence derView = GetAsDerSequence(true); + byte[] temp = derView.GetEncoded(BC_FACTORY.CreateASN1Encoding().GetDer()); + return temp.Length; + } + + /// Serializes the SignerInfo structure and makes the signed attributes readonly. + /// the encoded SignerInfo structure. + public virtual IDerSequence GetAsDerSequence() { + return GetAsDerSequence(false); + } + + /// Serializes the SignerInfo structure and makes the signed attributes readonly. + /// + /// Serializes the SignerInfo structure and makes the signed attributes readonly. + /// With the possibility to skip making the signed attributes read only for estimation purposes. + /// + /// set to true to not make signed attributes read only + /// the encoded SignerInfo structure. + internal virtual IDerSequence GetAsDerSequence(bool estimationRun) { + IAsn1EncodableVector signerInfoV = BC_FACTORY.CreateASN1EncodableVector(); + // version + signerInfoV.Add(BC_FACTORY.CreateASN1Integer(GetCmsVersion())); + // sid + IAsn1EncodableVector issuerAndSerialNumberV = BC_FACTORY.CreateASN1EncodableVector(); + issuerAndSerialNumberV.Add(CertificateInfo.GetIssuer(signerCertificate.GetTbsCertificate())); + issuerAndSerialNumberV.Add(BC_FACTORY.CreateASN1Integer(signerCertificate.GetSerialNumber())); + signerInfoV.Add(BC_FACTORY.CreateDERSequence(issuerAndSerialNumberV)); + // digestalgorithm + IAsn1EncodableVector digestalgorithmV = BC_FACTORY.CreateASN1EncodableVector(); + digestalgorithmV.Add(BC_FACTORY.CreateASN1ObjectIdentifier(this.digestAlgorithm.GetAlgorithmOid())); + digestalgorithmV.Add(digestAlgorithm.GetParameters()); + signerInfoV.Add(BC_FACTORY.CreateDERSequence(digestalgorithmV)); + // signedattributes + if (!signedAttributes.IsEmpty() || signedAttributesReadOnly) { + if (estimationRun || !signedAttributesReadOnly) { + signerInfoV.Add(BC_FACTORY.CreateDERTaggedObject(false, 0, GetAttributesAsDERSet(signedAttributes))); + } + else { + try { + using (IAsn1InputStream saIS = BC_FACTORY.CreateASN1InputStream(serializedSignedAttributes)) { + signerInfoV.Add(BC_FACTORY.CreateDERTaggedObject(false, 0, saIS.ReadObject())); + } + } + catch (System.IO.IOException e) { + throw new PdfException(e); + } + } + } + // signatureAlgorithm + IAsn1EncodableVector signatureAlgorithmV = BC_FACTORY.CreateASN1EncodableVector(); + signatureAlgorithmV.Add(BC_FACTORY.CreateASN1ObjectIdentifier(signingAlgorithm.GetAlgorithmOid())); + signatureAlgorithmV.Add(signingAlgorithm.GetParameters()); + signerInfoV.Add(BC_FACTORY.CreateDERSequence(signatureAlgorithmV)); + // signatureValue + byte[] workingSignatureData; + if (signatureData == null) { + workingSignatureData = new byte[DEFAULT_SIGNATURE_SIZE]; + } + else { + workingSignatureData = signatureData; + } + IAsn1OctetString signatureDataOS = BC_FACTORY.CreateDEROctetString(workingSignatureData); + signerInfoV.Add(signatureDataOS); + // UnsignedAttributes + if (!unSignedAttributes.IsEmpty()) { + signerInfoV.Add(BC_FACTORY.CreateDERTaggedObject(false, 1, GetAttributesAsDERSet(unSignedAttributes))); + } + return BC_FACTORY.CreateDERSequence(signerInfoV); + } + + private void ProcessSubjectKeyIdentifierSignerCertificate(IAsn1Encodable asnStruct, ICollection certificates) { + IAsn1OctetString subjectKeyIdentifierOs = BC_FACTORY.CreateASN1OctetString(BC_FACTORY.CreateASN1TaggedObject + (asnStruct).GetObject()); + using (IAsn1InputStream aIn = BC_FACTORY.CreateASN1InputStream(new MemoryStream(subjectKeyIdentifierOs.GetOctets + ()))) { + IAsn1Object subjectKeyIdentifier = aIn.ReadObject(); + foreach (IX509Certificate certificate in certificates) { + IAsn1Object ski = CertificateUtil.GetExtensionValue(certificate, OID.X509Extensions.SUBJECT_KEY_IDENTIFIER + ); + if (ski.Equals(subjectKeyIdentifier)) { + this.signerCertificate = certificate; + return; + } + } + } + throw new PdfException(SignExceptionMessageConstant.CMS_CERTIFICATE_NOT_FOUND); + } + + private void ProcessIssuerAndSerialNumberSignerCertificate(IAsn1Encodable asnStruct, ICollection certificates) { + IAsn1Sequence signIdSeq = BC_FACTORY.CreateASN1Sequence(asnStruct); + IDerInteger serial = BC_FACTORY.CreateASN1Integer(signIdSeq.GetObjectAt(1)); + foreach (IX509Certificate certificate in certificates) { + if (certificate.GetSerialNumber().Equals(serial.GetValue())) { + this.signerCertificate = certificate; + break; + } + } + if (signerCertificate == null) { + throw new PdfException(SignExceptionMessageConstant.CMS_CERTIFICATE_NOT_FOUND); + } + } + + private static ICollection ProcessAttributeSet(IAsn1Encodable asnStruct) { + IAsn1Set usaSet = BC_FACTORY.CreateASN1Set(asnStruct); + ICollection attributes = new List(usaSet.Size()); + for (int i = 0; i < usaSet.Size(); i++) { + IAsn1Sequence attrSeq = BC_FACTORY.CreateASN1Sequence(usaSet.GetObjectAt(i)); + IDerObjectIdentifier attrType = BC_FACTORY.CreateASN1ObjectIdentifier(attrSeq.GetObjectAt(0)); + IAsn1Object attrVal = BC_FACTORY.CreateASN1Primitive(attrSeq.GetObjectAt(1)); + attributes.Add(new Attribute(attrType.GetId(), attrVal)); + } + return attributes; + } + + private void SetRevocationInfo() { + signedAttributes.RemoveIf((a) => SecurityIDs.ID_ADBE_REVOCATION.Equals(a.GetType())); + if (ContainsRevocationData()) { + IAsn1EncodableVector revocationV = BC_FACTORY.CreateASN1EncodableVector(); + CreateCRLStructure(revocationV); + CreateOCPSStructure(revocationV); + Attribute digestAttribute = new Attribute(SecurityIDs.ID_ADBE_REVOCATION, BC_FACTORY.CreateDERSequence(revocationV + )); + signedAttributes.Add(digestAttribute); + } + } + + private void CreateCRLStructure(IAsn1EncodableVector revocationV) { + if (crlResponses != null && !crlResponses.IsEmpty()) { + IAsn1EncodableVector v2 = BC_FACTORY.CreateASN1EncodableVector(); + foreach (byte[] bCrl in crlResponses) { + if (bCrl == null) { + continue; + } + try { + using (IAsn1InputStream t = BC_FACTORY.CreateASN1InputStream(new MemoryStream(bCrl))) { + v2.Add(t.ReadObject()); + } + } + catch (System.IO.IOException e) { + throw new PdfException(e); + } + } + revocationV.Add(BC_FACTORY.CreateDERTaggedObject(true, 0, BC_FACTORY.CreateDERSequence(v2))); + } + } + + private void CreateOCPSStructure(IAsn1EncodableVector revocationV) { + if (ocspResponses != null && !ocspResponses.IsEmpty()) { + IAsn1EncodableVector vo1 = BC_FACTORY.CreateASN1EncodableVector(); + foreach (byte[] ocspBytes in ocspResponses) { + IDerOctetString doctet = BC_FACTORY.CreateDEROctetString(ocspBytes); + IAsn1EncodableVector v2 = BC_FACTORY.CreateASN1EncodableVector(); + IOcspObjectIdentifiers objectIdentifiers = BC_FACTORY.CreateOCSPObjectIdentifiers(); + v2.Add(objectIdentifiers.GetIdPkixOcspBasic()); + v2.Add(doctet); + IDerEnumerated den = BC_FACTORY.CreateASN1Enumerated(0); + IAsn1EncodableVector v3 = BC_FACTORY.CreateASN1EncodableVector(); + v3.Add(den); + v3.Add(BC_FACTORY.CreateDERTaggedObject(true, 0, BC_FACTORY.CreateDERSequence(v2))); + vo1.Add(BC_FACTORY.CreateDERSequence(v3)); + } + revocationV.Add(BC_FACTORY.CreateDERTaggedObject(true, 1, BC_FACTORY.CreateDERSequence(vo1))); + } + } + + private bool ContainsRevocationData() { + return (ocspResponses != null && !ocspResponses.IsEmpty()) || (crlResponses != null && !crlResponses.IsEmpty + ()); + } + + private static IDerSet GetAttributesAsDERSet(ICollection attributeSet) { + IAsn1EncodableVector attributes = BC_FACTORY.CreateASN1EncodableVector(); + foreach (Attribute attr in attributeSet) { + IAsn1EncodableVector v = BC_FACTORY.CreateASN1EncodableVector(); + v.Add(BC_FACTORY.CreateASN1ObjectIdentifier(attr.GetType())); + v.Add(attr.GetValue()); + attributes.Add(BC_FACTORY.CreateDERSequence(v)); + } + return BC_FACTORY.CreateDERSet(attributes); + } + } +} diff --git a/itext/itext.sign/itext/signatures/exceptions/SignExceptionMessageConstant.cs b/itext/itext.sign/itext/signatures/exceptions/SignExceptionMessageConstant.cs index 06375f14a9..8cc145a13a 100644 --- a/itext/itext.sign/itext/signatures/exceptions/SignExceptionMessageConstant.cs +++ b/itext/itext.sign/itext/signatures/exceptions/SignExceptionMessageConstant.cs @@ -133,6 +133,19 @@ public sealed class SignExceptionMessageConstant { public const String INVALID_ARGUMENTS = "Invalid parameters provided."; + public const String CMS_SIGNERINFO_READONLY = "Updating the signed attributes of this SignerInfo instance is" + + " not possible because it has been serialized or been initiated from a serialized version."; + + public const String CMS_SIGNERINFO_NOT_INITIALIZED = "Signer info is not yet initialized"; + + public const String CMS_INVALID_CONTAINER_STRUCTURE = "Provided data is not a CMS container"; + + public const String CMS_ONLY_ONE_SIGNER_ALLOWED = "Only one signer per CMS container is allowed"; + + public const String CMS_CERTIFICATE_NOT_FOUND = "Signer certificate not found in list of certificates"; + + public const String CMS_MISSING_CERTIFICATES = "The certificate set must at least contains the signer certificate"; + private SignExceptionMessageConstant() { } // Private constructor will prevent the instantiation of this class directly diff --git a/port-hash b/port-hash index 3fdaf207d1..1800e31a6b 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -6ef7dd755c8cbfc82f9b769a9bd9cbb4c9e63be3 +0171de5c2fffc772b0f7d9107ada5624e84c9b4a