diff --git a/itext.tests/itext.sign.tests/itext/signatures/PdfTwoPhaseSignerUnitTest.cs b/itext.tests/itext.sign.tests/itext/signatures/PdfTwoPhaseSignerUnitTest.cs index e203733b68..066eb4c97c 100644 --- a/itext.tests/itext.sign.tests/itext/signatures/PdfTwoPhaseSignerUnitTest.cs +++ b/itext.tests/itext.sign.tests/itext/signatures/PdfTwoPhaseSignerUnitTest.cs @@ -96,21 +96,48 @@ public virtual void AddSignatureToPreparedDocumentTest() { PdfTwoPhaseSigner signer = new PdfTwoPhaseSigner(reader, outputStream); int estimatedSize = 8079; SignerProperties signerProperties = new SignerProperties(); - byte[] digest = signer.PrepareDocumentForSignature(signerProperties, DigestAlgorithms.SHA256, PdfName.Adobe_PPKLite - , PdfName.Adbe_pkcs7_detached, estimatedSize, false); + signer.PrepareDocumentForSignature(signerProperties, DigestAlgorithms.SHA256, PdfName.Adobe_PPKLite, PdfName + .Adbe_pkcs7_detached, estimatedSize, false); String fieldName = signerProperties.GetFieldName(); - PdfReader resultReader = new PdfReader(new MemoryStream(outputStream.ToArray())); - PdfDocument resultDoc = new PdfDocument(resultReader); - ByteArrayOutputStream completedOutputStream = new ByteArrayOutputStream(); - byte[] testData = ByteUtils.GetIsoBytes("Some data to test the signature addition with"); - PdfTwoPhaseSigner.AddSignatureToPreparedDocument(resultDoc, fieldName, completedOutputStream, testData); - resultReader = new PdfReader(new MemoryStream(completedOutputStream.ToArray())); - resultDoc = new PdfDocument(resultReader); - SignatureUtil signatureUtil = new SignatureUtil(resultDoc); - PdfSignature signature = signatureUtil.GetSignature(fieldName); - byte[] content = signature.GetContents().GetValueBytes(); - for (int i = 0; i < testData.Length; i++) { - NUnit.Framework.Assert.AreEqual(testData[i], content[i]); + using (PdfReader resultReader = new PdfReader(new MemoryStream(outputStream.ToArray()))) { + ByteArrayOutputStream completedOutputStream = new ByteArrayOutputStream(); + byte[] testData = ByteUtils.GetIsoBytes("Some data to test the signature addition with"); + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(resultReader, fieldName, completedOutputStream, testData); + using (PdfDocument resultDoc = new PdfDocument(new PdfReader(new MemoryStream(completedOutputStream.ToArray + ())))) { + SignatureUtil signatureUtil = new SignatureUtil(resultDoc); + PdfSignature signature = signatureUtil.GetSignature(fieldName); + byte[] content = signature.GetContents().GetValueBytes(); + for (int i = 0; i < testData.Length; i++) { + NUnit.Framework.Assert.AreEqual(testData[i], content[i]); + } + } + } + } + + [NUnit.Framework.Test] + public virtual void AddSignatureToPreparedDocumentDeprecatedApiTest() { + PdfReader reader = new PdfReader(new MemoryStream(CreateSimpleDocument())); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PdfTwoPhaseSigner signer = new PdfTwoPhaseSigner(reader, outputStream); + int estimatedSize = 8079; + SignerProperties signerProperties = new SignerProperties(); + signer.PrepareDocumentForSignature(signerProperties, DigestAlgorithms.SHA256, PdfName.Adobe_PPKLite, PdfName + .Adbe_pkcs7_detached, estimatedSize, false); + String fieldName = signerProperties.GetFieldName(); + using (PdfDocument document = new PdfDocument(new PdfReader(new MemoryStream(outputStream.ToArray())))) { + ByteArrayOutputStream completedOutputStream = new ByteArrayOutputStream(); + byte[] testData = ByteUtils.GetIsoBytes("Some data to test the signature addition with"); + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(document, fieldName, completedOutputStream, testData); + using (PdfDocument resultDoc = new PdfDocument(new PdfReader(new MemoryStream(completedOutputStream.ToArray + ())))) { + SignatureUtil signatureUtil = new SignatureUtil(resultDoc); + PdfSignature signature = signatureUtil.GetSignature(fieldName); + byte[] content = signature.GetContents().GetValueBytes(); + for (int i = 0; i < testData.Length; i++) { + NUnit.Framework.Assert.AreEqual(testData[i], content[i]); + } + } } } diff --git a/itext.tests/itext.sign.tests/itext/signatures/mac/SignedDocumentWithMacTest.cs b/itext.tests/itext.sign.tests/itext/signatures/mac/SignedDocumentWithMacTest.cs index 94c695cf3a..098532da03 100644 --- a/itext.tests/itext.sign.tests/itext/signatures/mac/SignedDocumentWithMacTest.cs +++ b/itext.tests/itext.sign.tests/itext/signatures/mac/SignedDocumentWithMacTest.cs @@ -30,7 +30,6 @@ You should have received a copy of the GNU Affero General Public License using iText.Commons.Bouncycastle.Crypto; using iText.Commons.Utils; using iText.Kernel.Crypto; -using iText.Kernel.Exceptions; using iText.Kernel.Logs; using iText.Kernel.Pdf; using iText.Signatures; @@ -82,20 +81,12 @@ public virtual void SignMacProtectedDocTest(String certName, String signingOpera ))) { using (Stream outputStream = FileUtil.GetFileOutputStream(outputFileName)) { PdfSigner pdfSigner = new PdfSigner(reader, outputStream, new StampingProperties()); - if (signingOperation.Equals("signExternalContainerBlank")) { - NUnit.Framework.Assert.Catch(typeof(PdfException), () => PerformSigningOperation(signingOperation, pdfSigner - , signRsaPrivateKey, signRsaChain)); - } - else { - PerformSigningOperation(signingOperation, pdfSigner, signRsaPrivateKey, signRsaChain); - } + PerformSigningOperation(signingOperation, pdfSigner, signRsaPrivateKey, signRsaChain); } } - if (!signingOperation.Equals("signExternalContainerBlank")) { - ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); - NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties - , properties)); - } + ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); + NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties + , properties)); } [NUnit.Framework.TestCaseSource("CreateParameters")] @@ -112,20 +103,12 @@ public virtual void SignNotMacProtectedDocTest(String certName, String signingOp ))) { using (Stream outputStream = FileUtil.GetFileOutputStream(outputFileName)) { PdfSigner pdfSigner = new PdfSigner(reader, outputStream, new StampingProperties()); - if (signingOperation.Equals("signExternalContainerBlank")) { - NUnit.Framework.Assert.Catch(typeof(PdfException), () => PerformSigningOperation(signingOperation, pdfSigner - , signRsaPrivateKey, signRsaChain)); - } - else { - PerformSigningOperation(signingOperation, pdfSigner, signRsaPrivateKey, signRsaChain); - } + PerformSigningOperation(signingOperation, pdfSigner, signRsaPrivateKey, signRsaChain); } } - if (!signingOperation.Equals("signExternalContainerBlank")) { - ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); - NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties - , properties)); - } + ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); + NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties + , properties)); } [NUnit.Framework.TestCaseSource("CreateParameters")] @@ -145,7 +128,6 @@ public virtual void SignNotMacProtectedDoc17Test(String certName, String signing PerformSigningOperation(signingOperation, pdfSigner, signRsaPrivateKey, signRsaChain); } } - // TODO DEVSIX-8637 Add else statement for empty signature container if (!signingOperation.Equals("signExternalContainerBlank")) { ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties @@ -171,7 +153,6 @@ public virtual void SignNotMacProtectedDocInAppendModeTest(String certName, Stri PerformSigningOperation(signingOperation, pdfSigner, signRsaPrivateKey, signRsaChain); } } - // TODO DEVSIX-8637 Add else statement for empty signature container if (!signingOperation.Equals("signExternalContainerBlank")) { ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties @@ -193,20 +174,12 @@ public virtual void SignMacProtectedDocInAppendModeTest(String certName, String ))) { using (Stream outputStream = FileUtil.GetFileOutputStream(outputFileName)) { PdfSigner pdfSigner = new PdfSigner(reader, outputStream, new StampingProperties().UseAppendMode()); - if (signingOperation.Equals("signExternalContainerBlank")) { - NUnit.Framework.Assert.Catch(typeof(PdfException), () => PerformSigningOperation(signingOperation, pdfSigner - , signRsaPrivateKey, signRsaChain)); - } - else { - PerformSigningOperation(signingOperation, pdfSigner, signRsaPrivateKey, signRsaChain); - } + PerformSigningOperation(signingOperation, pdfSigner, signRsaPrivateKey, signRsaChain); } } - if (!signingOperation.Equals("signExternalContainerBlank")) { - ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); - NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties - , properties)); - } + ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); + NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties + , properties)); } [NUnit.Framework.TestCaseSource("CreateParameters")] @@ -223,20 +196,12 @@ public virtual void SignMacProtectedDocWithSHA3_384Test(String certName, String ))) { using (Stream outputStream = FileUtil.GetFileOutputStream(outputFileName)) { PdfSigner pdfSigner = new PdfSigner(reader, outputStream, new StampingProperties()); - if (signingOperation.Equals("signExternalContainerBlank")) { - NUnit.Framework.Assert.Catch(typeof(PdfException), () => PerformSigningOperation(signingOperation, pdfSigner - , signRsaPrivateKey, signRsaChain)); - } - else { - PerformSigningOperation(signingOperation, pdfSigner, signRsaPrivateKey, signRsaChain); - } + PerformSigningOperation(signingOperation, pdfSigner, signRsaPrivateKey, signRsaChain); } } - if (!signingOperation.Equals("signExternalContainerBlank")) { - ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); - NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties - , properties)); - } + ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); + NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties + , properties)); } [NUnit.Framework.TestCaseSource("CreateParameters")] @@ -262,19 +227,11 @@ public virtual void SignMacPublicEncryptionDocTest(String certName, String signi using (PdfReader reader = new PdfReader(srcFileName, properties)) { using (Stream outputStream = FileUtil.GetFileOutputStream(outputFileName)) { PdfSigner pdfSigner = new PdfSigner(reader, outputStream, new StampingProperties()); - if (signingOperation.Equals("signExternalContainerBlank")) { - NUnit.Framework.Assert.Catch(typeof(PdfException), () => PerformSigningOperation(signingOperation, pdfSigner - , signRsaPrivateKey, signRsaChain)); - } - else { - PerformSigningOperation(signingOperation, pdfSigner, signRsaPrivateKey, signRsaChain); - } + PerformSigningOperation(signingOperation, pdfSigner, signRsaPrivateKey, signRsaChain); } } - if (!signingOperation.Equals("signExternalContainerBlank")) { - NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties - , properties)); - } + NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties + , properties)); } private static void PerformSigningOperation(String signingOperation, PdfSigner pdfSigner, IPrivateKey privateKey diff --git a/itext.tests/itext.sign.tests/itext/signatures/mac/TwoStepSigningWithMacTest.cs b/itext.tests/itext.sign.tests/itext/signatures/mac/TwoStepSigningWithMacTest.cs new file mode 100644 index 0000000000..5e5a5ff8e4 --- /dev/null +++ b/itext.tests/itext.sign.tests/itext/signatures/mac/TwoStepSigningWithMacTest.cs @@ -0,0 +1,184 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +using System; +using System.IO; +using iText.Bouncycastleconnector; +using iText.Commons.Bouncycastle; +using iText.Commons.Bouncycastle.Cert; +using iText.Commons.Bouncycastle.Crypto; +using iText.Commons.Utils; +using iText.Kernel.Pdf; +using iText.Signatures; +using iText.Signatures.Testutils; +using iText.Test; + +namespace iText.Signatures.Mac { + [NUnit.Framework.Category("BouncyCastleIntegrationTest")] + public class TwoStepSigningWithMacTest : 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 String SOURCE_FOLDER = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext + .CurrentContext.TestDirectory) + "/resources/itext/signatures/mac/TwoStepSigningWithMacTest/"; + + private static readonly String DESTINATION_FOLDER = NUnit.Framework.TestContext.CurrentContext.TestDirectory + + "/test/itext/signatures/mac/TwoStepSigningWithMacTest/"; + + private static readonly byte[] ENCRYPTION_PASSWORD = "123".GetBytes(); + + private static readonly char[] PRIVATE_KEY_PASSWORD = "testpassphrase".ToCharArray(); + + [NUnit.Framework.OneTimeSetUp] + public static void Before() { + CreateOrClearDestinationFolder(DESTINATION_FOLDER); + } + + [NUnit.Framework.Test] + public virtual void SignDeferredWithReaderTest() { + String fileName = "signDeferredWithReaderTest.pdf"; + String srcFileName = SOURCE_FOLDER + "macEncryptedDoc.pdf"; + String outputFileName = DESTINATION_FOLDER + fileName; + String signCertFileName = CERTS_SRC + "signCertRsa01.pem"; + String cmpFileName = SOURCE_FOLDER + "cmp_" + fileName; + IX509Certificate[] signRsaChain = PemFileHelper.ReadFirstChain(signCertFileName); + IPrivateKey signRsaPrivateKey = PemFileHelper.ReadFirstKey(signCertFileName, PRIVATE_KEY_PASSWORD); + ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); + MemoryStream preparedDocument = new MemoryStream(); + using (PdfReader reader = new PdfReader(srcFileName, properties)) { + using (Stream outputStream = preparedDocument) { + PdfSigner pdfSigner = new PdfSigner(reader, outputStream, new StampingProperties()); + pdfSigner.SignExternalContainer(new ExternalBlankSignatureContainer(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached + ), 5000); + } + } + using (PdfReader reader_1 = new PdfReader(new MemoryStream(preparedDocument.ToArray()), properties)) { + using (Stream outputStream_1 = FileUtil.GetFileOutputStream(outputFileName)) { + PdfSigner.SignDeferred(reader_1, "Signature1", outputStream_1, new PKCS7ExternalSignatureContainer(signRsaPrivateKey + , signRsaChain, "SHA-512")); + } + } + NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties + , properties)); + } + + [NUnit.Framework.Test] + public virtual void SignDeferredWithDocumentTest() { + String fileName = "signDeferredWithDocumentTest.pdf"; + String srcFileName = SOURCE_FOLDER + "macEncryptedDoc.pdf"; + String outputFileName = DESTINATION_FOLDER + fileName; + String signCertFileName = CERTS_SRC + "signCertRsa01.pem"; + String cmpFileName = SOURCE_FOLDER + "cmp_" + fileName; + IX509Certificate[] signRsaChain = PemFileHelper.ReadFirstChain(signCertFileName); + IPrivateKey signRsaPrivateKey = PemFileHelper.ReadFirstKey(signCertFileName, PRIVATE_KEY_PASSWORD); + ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); + MemoryStream preparedDocument = new MemoryStream(); + using (PdfReader reader = new PdfReader(srcFileName, properties)) { + using (Stream outputStream = preparedDocument) { + PdfSigner pdfSigner = new PdfSigner(reader, outputStream, new StampingProperties()); + pdfSigner.SignExternalContainer(new ExternalBlankSignatureContainer(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached + ), 5000); + } + } + using (PdfDocument document = new PdfDocument(new PdfReader(new MemoryStream(preparedDocument.ToArray()), + properties))) { + using (Stream outputStream_1 = FileUtil.GetFileOutputStream(outputFileName)) { + PdfSigner.SignDeferred(document, "Signature1", outputStream_1, new PKCS7ExternalSignatureContainer(signRsaPrivateKey + , signRsaChain, "SHA-512")); + } + } + NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties + , properties)); + } + + [NUnit.Framework.Test] + public virtual void TwoPhaseSignerWithReaderTest() { + String fileName = "twoPhaseSignerWithReaderTest.pdf"; + String srcFileName = SOURCE_FOLDER + "macEncryptedDoc.pdf"; + String outputFileName = DESTINATION_FOLDER + fileName; + String signCertFileName = CERTS_SRC + "signCertRsa01.pem"; + String cmpFileName = SOURCE_FOLDER + "cmp_" + fileName; + IX509Certificate[] signRsaChain = PemFileHelper.ReadFirstChain(signCertFileName); + IPrivateKey signRsaPrivateKey = PemFileHelper.ReadFirstKey(signCertFileName, PRIVATE_KEY_PASSWORD); + ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); + using (PdfReader reader = new PdfReader(FileUtil.GetInputStreamForFile(srcFileName), properties)) { + using (MemoryStream outputStream = new MemoryStream()) { + PdfTwoPhaseSigner signer = new PdfTwoPhaseSigner(reader, outputStream); + SignerProperties signerProperties = new SignerProperties(); + byte[] digest = signer.PrepareDocumentForSignature(signerProperties, "SHA-512", PdfName.Adobe_PPKLite, PdfName + .Adbe_pkcs7_detached, 5000, false); + String fieldName = signerProperties.GetFieldName(); + byte[] signData = SignDigest(digest, signRsaChain, signRsaPrivateKey); + using (Stream outputStreamPhase2 = FileUtil.GetFileOutputStream(outputFileName)) { + using (PdfReader newReader = new PdfReader(new MemoryStream(outputStream.ToArray()), properties)) { + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(newReader, fieldName, outputStreamPhase2, signData); + } + } + } + } + NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties + , properties)); + } + + [NUnit.Framework.Test] + public virtual void TwoPhaseSignerWithDocumentTest() { + String fileName = "twoPhaseSignerWithDocumentTest.pdf"; + String srcFileName = SOURCE_FOLDER + "macEncryptedDoc.pdf"; + String outputFileName = DESTINATION_FOLDER + fileName; + String signCertFileName = CERTS_SRC + "signCertRsa01.pem"; + String cmpFileName = SOURCE_FOLDER + "cmp_" + fileName; + IX509Certificate[] signRsaChain = PemFileHelper.ReadFirstChain(signCertFileName); + IPrivateKey signRsaPrivateKey = PemFileHelper.ReadFirstKey(signCertFileName, PRIVATE_KEY_PASSWORD); + ReaderProperties properties = new ReaderProperties().SetPassword(ENCRYPTION_PASSWORD); + using (PdfReader reader = new PdfReader(FileUtil.GetInputStreamForFile(srcFileName), properties)) { + using (MemoryStream outputStream = new MemoryStream()) { + PdfTwoPhaseSigner signer = new PdfTwoPhaseSigner(reader, outputStream); + SignerProperties signerProperties = new SignerProperties(); + byte[] digest = signer.PrepareDocumentForSignature(signerProperties, "SHA-512", PdfName.Adobe_PPKLite, PdfName + .Adbe_pkcs7_detached, 5000, false); + String fieldName = signerProperties.GetFieldName(); + byte[] signData = SignDigest(digest, signRsaChain, signRsaPrivateKey); + using (Stream outputStreamPhase2 = FileUtil.GetFileOutputStream(outputFileName)) { + using (PdfDocument document = new PdfDocument(new PdfReader(new MemoryStream(outputStream.ToArray()), properties + ))) { + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(document, fieldName, outputStreamPhase2, signData); + } + } + } + } + NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outputFileName, cmpFileName, properties + , properties)); + } + + private byte[] SignDigest(byte[] data, IX509Certificate[] chain, IPrivateKey pk) { + PdfPKCS7 sgn = new PdfPKCS7((IPrivateKey)null, chain, "SHA-512", new BouncyCastleDigest(), false); + byte[] sh = sgn.GetAuthenticatedAttributeBytes(data, PdfSigner.CryptoStandard.CMS, null, null); + PrivateKeySignature pkSign = new PrivateKeySignature(pk, "SHA-512"); + byte[] signData = pkSign.Sign(sh); + sgn.SetExternalSignatureValue(signData, null, pkSign.GetSignatureAlgorithmName(), pkSign.GetSignatureMechanismParameters + ()); + return sgn.GetEncodedPKCS7(data, PdfSigner.CryptoStandard.CMS, null, null, null); + } + } +} diff --git a/itext.tests/itext.sign.tests/itext/signatures/sign/SignDeferredTest.cs b/itext.tests/itext.sign.tests/itext/signatures/sign/SignDeferredTest.cs index 272031bc8b..56e49bafa1 100644 --- a/itext.tests/itext.sign.tests/itext/signatures/sign/SignDeferredTest.cs +++ b/itext.tests/itext.sign.tests/itext/signatures/sign/SignDeferredTest.cs @@ -136,11 +136,34 @@ public virtual void DeferredHashCalcAndSignTest01() { IExternalSignatureContainer extSigContainer = new SignDeferredTest.CmsDeferredSigner(signPrivateKey, signChain ); String sigFieldName = "DeferredSignature1"; - PdfDocument docToSign = new PdfDocument(new PdfReader(srcFileName)); - Stream outStream = FileUtil.GetFileOutputStream(outFileName); - PdfSigner.SignDeferred(docToSign, sigFieldName, outStream, extSigContainer); - docToSign.Close(); - outStream.Dispose(); + using (PdfReader reader = new PdfReader(srcFileName)) { + using (Stream outStream = FileUtil.GetFileOutputStream(outFileName)) { + PdfSigner.SignDeferred(reader, sigFieldName, outStream, extSigContainer); + } + } + // validate result + TestSignUtils.BasicCheckSignedDoc(outFileName, sigFieldName); + NUnit.Framework.Assert.IsNull(new CompareTool().CompareVisually(outFileName, cmpFileName, destinationFolder + , null)); + NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(outFileName, cmpFileName)); + } + + [NUnit.Framework.Test] + public virtual void DeferredDeprecatedApiTest() { + String srcFileName = sourceFolder + "templateForSignCMSDeferred.pdf"; + String outFileName = destinationFolder + "deferredDeprecatedApiTest.pdf"; + String cmpFileName = sourceFolder + "cmp_deferredDeprecatedApiTest.pdf"; + String signCertFileName = certsSrc + "signCertRsa01.pem"; + IX509Certificate[] signChain = PemFileHelper.ReadFirstChain(signCertFileName); + IPrivateKey signPrivateKey = PemFileHelper.ReadFirstKey(signCertFileName, password); + IExternalSignatureContainer extSigContainer = new SignDeferredTest.CmsDeferredSigner(signPrivateKey, signChain + ); + String sigFieldName = "DeferredSignature1"; + using (PdfDocument document = new PdfDocument(new PdfReader(srcFileName))) { + using (Stream outStream = FileUtil.GetFileOutputStream(outFileName)) { + PdfSigner.SignDeferred(document, sigFieldName, outStream, extSigContainer); + } + } // validate result TestSignUtils.BasicCheckSignedDoc(outFileName, sigFieldName); NUnit.Framework.Assert.IsNull(new CompareTool().CompareVisually(outFileName, cmpFileName, destinationFolder @@ -181,11 +204,11 @@ public virtual void CalcHashOnDocCreationThenDeferredSignTest01() { // fill the signature to the presigned document SignDeferredTest.ReadySignatureSigner extSigContainer = new SignDeferredTest.ReadySignatureSigner(cmsSignature ); - PdfDocument docToSign = new PdfDocument(new PdfReader(new MemoryStream(preSignedBytes))); - Stream outStream = FileUtil.GetFileOutputStream(outFileName); - PdfSigner.SignDeferred(docToSign, sigFieldName, outStream, extSigContainer); - docToSign.Close(); - outStream.Dispose(); + using (PdfReader newReader = new PdfReader(new MemoryStream(preSignedBytes))) { + using (Stream outStream = FileUtil.GetFileOutputStream(outFileName)) { + PdfSigner.SignDeferred(newReader, sigFieldName, outStream, extSigContainer); + } + } // validate result TestSignUtils.BasicCheckSignedDoc(outFileName, sigFieldName); NUnit.Framework.Assert.IsNull(new CompareTool().CompareVisually(outFileName, cmpFileName, destinationFolder 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 93f90c7a01..9529bbafdd 100644 --- a/itext.tests/itext.sign.tests/itext/signatures/sign/TwoPhaseSigningTest.cs +++ b/itext.tests/itext.sign.tests/itext/signatures/sign/TwoPhaseSigningTest.cs @@ -104,15 +104,33 @@ public virtual void TestPreparationWithClosedPdfTwoPhaseSigner() { [NUnit.Framework.Test] public virtual void TestCompletionWithWrongFieldName() { + byte[] signData = new byte[4096]; + // open prepared document + using (PdfReader reader = new PdfReader(new FileInfo(SOURCE_FOLDER + "2PhasePreparedSignature.pdf" + ))) { + using (Stream signedDoc = new ByteArrayOutputStream()) { + // add signature + Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => { + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(reader, "wrong" + FIELD_NAME, signedDoc, signData); + } + ); + NUnit.Framework.Assert.AreEqual(MessageFormatUtil.Format(SignExceptionMessageConstant.THERE_IS_NO_FIELD_IN_THE_DOCUMENT_WITH_SUCH_NAME + , "wrong" + FIELD_NAME), e.Message); + } + } + } + + [NUnit.Framework.Test] + public virtual void TestCompletionWithWrongFieldNameAndDeprecatedApiTest() { byte[] signData = new byte[4096]; // open prepared document using (PdfDocument preparedDoc = new PdfDocument(new PdfReader(new FileInfo(SOURCE_FOLDER + "2PhasePreparedSignature.pdf" - )))) { + )))) { using (Stream signedDoc = new ByteArrayOutputStream()) { // add signature Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => { - PdfTwoPhaseSigner.AddSignatureToPreparedDocument(preparedDoc, "wrong" + FIELD_NAME, signedDoc, signData); - } + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(preparedDoc, "wrong" + FIELD_NAME, signedDoc, signData); + } ); NUnit.Framework.Assert.AreEqual(MessageFormatUtil.Format(SignExceptionMessageConstant.THERE_IS_NO_FIELD_IN_THE_DOCUMENT_WITH_SUCH_NAME , "wrong" + FIELD_NAME), e.Message); @@ -124,12 +142,12 @@ public virtual void TestCompletionWithWrongFieldName() { public virtual void TestCompletionWithNotEnoughSpace() { byte[] signData = new byte[20000]; // open prepared document - using (PdfDocument preparedDoc = new PdfDocument(new PdfReader(new FileInfo(SOURCE_FOLDER + "2PhasePreparedSignature.pdf" - )))) { + using (PdfReader reader = new PdfReader(new FileInfo(SOURCE_FOLDER + "2PhasePreparedSignature.pdf" + ))) { using (Stream signedDoc = new ByteArrayOutputStream()) { // add signature Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => { - PdfTwoPhaseSigner.AddSignatureToPreparedDocument(preparedDoc, FIELD_NAME, signedDoc, signData); + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(reader, FIELD_NAME, signedDoc, signData); } ); NUnit.Framework.Assert.AreEqual(SignExceptionMessageConstant.AVAILABLE_SPACE_IS_NOT_ENOUGH_FOR_SIGNATURE, @@ -151,9 +169,9 @@ public virtual void TestCompletionWithSignatureFieldNotLastOne() { byte[] signData = new byte[1024]; using (Stream outputStreamPhase2 = FileUtil.GetFileOutputStream(DESTINATION_FOLDER + "2PhaseCompleteCycle.pdf" )) { - using (PdfDocument doc = new PdfDocument(new PdfReader(new MemoryStream(outputStream.ToArray())))) { + using (PdfReader newReader = new PdfReader(new MemoryStream(outputStream.ToArray()))) { Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => { - PdfTwoPhaseSigner.AddSignatureToPreparedDocument(doc, FIELD_NAME, outputStreamPhase2, signData); + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(newReader, FIELD_NAME, outputStreamPhase2, signData); } ); NUnit.Framework.Assert.AreEqual(MessageFormatUtil.Format(SignExceptionMessageConstant.SIGNATURE_WITH_THIS_NAME_IS_NOT_THE_LAST_IT_DOES_NOT_COVER_WHOLE_DOCUMENT @@ -210,8 +228,8 @@ public virtual void TestCompleteCycle() { byte[] signData = SignDigest(digest, DIGEST_ALGORITHM); using (Stream outputStreamPhase2 = FileUtil.GetFileOutputStream(DESTINATION_FOLDER + "2PhaseCompleteCycle.pdf" )) { - using (PdfDocument doc = new PdfDocument(new PdfReader(new MemoryStream(outputStream.ToArray())))) { - PdfTwoPhaseSigner.AddSignatureToPreparedDocument(doc, fieldName, outputStreamPhase2, signData); + using (PdfReader newReader = new PdfReader(new MemoryStream(outputStream.ToArray()))) { + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(newReader, fieldName, outputStreamPhase2, signData); } } NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(DESTINATION_FOLDER + "2PhaseCompleteCycle.pdf" @@ -228,11 +246,11 @@ public virtual void TestCompletion() { signdataS.Read(signData); } // open prepared document - using (PdfDocument preparedDoc = new PdfDocument(new PdfReader(new FileInfo(SOURCE_FOLDER + "2PhasePreparedSignature.pdf" - )))) { + using (PdfReader reader = new PdfReader(new FileInfo(SOURCE_FOLDER + "2PhasePreparedSignature.pdf" + ))) { using (Stream signedDoc = FileUtil.GetFileOutputStream(DESTINATION_FOLDER + "2PhaseCompletion.pdf")) { // add signature - PdfTwoPhaseSigner.AddSignatureToPreparedDocument(preparedDoc, FIELD_NAME, signedDoc, signData); + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(reader, FIELD_NAME, signedDoc, signData); } } NUnit.Framework.Assert.IsNull(SignaturesCompareTool.CompareSignatures(DESTINATION_FOLDER + "2PhaseCompletion.pdf" @@ -262,7 +280,7 @@ public virtual void TestWithCMS() { cmsToUpdate.GetSignerInfo().SetSignature(signaturedata); //if needed a time stamp could be added here //Phase 2.3 add the updated CMS to the document - PdfTwoPhaseSigner.AddSignatureToPreparedDocument(doc, signatureName, outputStreamPhase2, cmsToUpdate); + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(new PdfReader(new MemoryStream(phaseOneOS.ToArray())), signatureName, outputStreamPhase2, cmsToUpdate); } } // validate signature @@ -320,8 +338,8 @@ private byte[] PrepareDocumentAndCMS(FileInfo document, ByteArrayOutputStream pr // 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())))) { - PdfTwoPhaseSigner.AddSignatureToPreparedDocument(doc, fieldName, preparedOS, cms); + using (PdfReader newReader = new PdfReader(new MemoryStream(outputStream.ToArray()))) { + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(newReader, fieldName, preparedOS, cms); } return dataToSign; } diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signMacProtectedDocInAppendModeTest_signExternalContainerBlank.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signMacProtectedDocInAppendModeTest_signExternalContainerBlank.pdf new file mode 100644 index 0000000000..158ab1bd07 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signMacProtectedDocInAppendModeTest_signExternalContainerBlank.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signMacProtectedDocTest_signExternalContainerBlank.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signMacProtectedDocTest_signExternalContainerBlank.pdf new file mode 100644 index 0000000000..00078686df Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signMacProtectedDocTest_signExternalContainerBlank.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signMacProtectedDocWithSHA3_384Test_signExternalContainerBlank.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signMacProtectedDocWithSHA3_384Test_signExternalContainerBlank.pdf new file mode 100644 index 0000000000..6fc6a8d3c4 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signMacProtectedDocWithSHA3_384Test_signExternalContainerBlank.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signMacPublicEncryptionDocTest_signExternalContainerBlank.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signMacPublicEncryptionDocTest_signExternalContainerBlank.pdf new file mode 100644 index 0000000000..324528ee3e Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signMacPublicEncryptionDocTest_signExternalContainerBlank.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signNotMacProtectedDocTest_signExternalContainerBlank.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signNotMacProtectedDocTest_signExternalContainerBlank.pdf new file mode 100644 index 0000000000..97885c7ea7 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/SignedDocumentWithMacTest/cmp_signNotMacProtectedDocTest_signExternalContainerBlank.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/cmp_signDeferredWithDocumentTest.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/cmp_signDeferredWithDocumentTest.pdf new file mode 100644 index 0000000000..d94baba4e0 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/cmp_signDeferredWithDocumentTest.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/cmp_signDeferredWithReaderTest.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/cmp_signDeferredWithReaderTest.pdf new file mode 100644 index 0000000000..ef7ac3368a Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/cmp_signDeferredWithReaderTest.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/cmp_twoPhaseSignerWithDocumentTest.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/cmp_twoPhaseSignerWithDocumentTest.pdf new file mode 100644 index 0000000000..a77c6fcc21 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/cmp_twoPhaseSignerWithDocumentTest.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/cmp_twoPhaseSignerWithReaderTest.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/cmp_twoPhaseSignerWithReaderTest.pdf new file mode 100644 index 0000000000..fa361b5b40 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/cmp_twoPhaseSignerWithReaderTest.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/macEncryptedDoc.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/macEncryptedDoc.pdf new file mode 100644 index 0000000000..f8bffedbdc Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/mac/TwoStepSigningWithMacTest/macEncryptedDoc.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/sign/SignDeferredTest/cmp_deferredDeprecatedApiTest.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/sign/SignDeferredTest/cmp_deferredDeprecatedApiTest.pdf new file mode 100644 index 0000000000..abcdc7adc6 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/sign/SignDeferredTest/cmp_deferredDeprecatedApiTest.pdf differ diff --git a/itext/itext.kernel/itext/kernel/utils/IdleOutputStream.cs b/itext/itext.kernel/itext/kernel/utils/IdleOutputStream.cs index 428e370481..ac2949666e 100644 --- a/itext/itext.kernel/itext/kernel/utils/IdleOutputStream.cs +++ b/itext/itext.kernel/itext/kernel/utils/IdleOutputStream.cs @@ -24,55 +24,66 @@ You should have received a copy of the GNU Affero General Public License using System.IO; namespace iText.Kernel.Utils { - //\cond DO_NOT_DOCUMENT - internal class IdleOutputStream : Stream + /// + /// Stream implementation which doesn't write anything. + /// + public class IdleOutputStream : Stream { + /// public override void Flush() { } + /// public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } + /// public override void SetLength(long value) { throw new NotSupportedException(); } + /// public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } + /// public override void Write(byte[] buffer, int offset, int count) { } + /// public override bool CanRead { get { return false; } } + /// public override bool CanSeek { get { return false; } } + /// public override bool CanWrite { get { return true; } } + /// public override long Length { get { throw new NotSupportedException(); } } + /// public override long Position { get; set; } } - //\endcond } diff --git a/itext/itext.sign/itext/signatures/PadesTwoPhaseSigningHelper.cs b/itext/itext.sign/itext/signatures/PadesTwoPhaseSigningHelper.cs index c7078208ea..7971033a97 100644 --- a/itext/itext.sign/itext/signatures/PadesTwoPhaseSigningHelper.cs +++ b/itext/itext.sign/itext/signatures/PadesTwoPhaseSigningHelper.cs @@ -368,9 +368,8 @@ public virtual void SignCMSContainerWithBaselineBProfile(IExternalSignature exte , Stream outputStream, String signatureFieldName, CMSContainer cmsContainer) { SetSignatureAlgorithmAndSignature(externalSignature, cmsContainer); try { - using (PdfDocument document = new PdfDocument(inputDocument, stampingProperties)) { - PdfTwoPhaseSigner.AddSignatureToPreparedDocument(document, signatureFieldName, outputStream, cmsContainer); - } + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(inputDocument, signatureFieldName, outputStream, cmsContainer + ); } finally { outputStream.Dispose(); @@ -401,9 +400,8 @@ public virtual void SignCMSContainerWithBaselineTProfile(IExternalSignature exte cmsContainer.GetSignerInfo().AddUnSignedAttribute(timestampAttribute); } try { - using (PdfDocument document = new PdfDocument(inputDocument, stampingProperties)) { - PdfTwoPhaseSigner.AddSignatureToPreparedDocument(document, signatureFieldName, outputStream, cmsContainer); - } + PdfTwoPhaseSigner.AddSignatureToPreparedDocument(inputDocument, signatureFieldName, outputStream, cmsContainer + ); } finally { outputStream.Dispose(); diff --git a/itext/itext.sign/itext/signatures/PdfSigner.cs b/itext/itext.sign/itext/signatures/PdfSigner.cs index b593ff6125..1c277d370b 100644 --- a/itext/itext.sign/itext/signatures/PdfSigner.cs +++ b/itext/itext.sign/itext/signatures/PdfSigner.cs @@ -46,6 +46,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.Kernel.Pdf.Tagutils; +using iText.Kernel.Utils; using iText.Kernel.Validation; using iText.Kernel.Validation.Context; using iText.Layout.Properties; @@ -613,7 +614,9 @@ public virtual void SignExternalContainer(IExternalSignatureContainer externalSi PreClose(exc); Stream data = GetRangeStream(); byte[] encodedSig = externalSignatureContainer.Sign(data); - encodedSig = EmbedMacTokenIntoSignatureContainer(encodedSig); + if (document.GetDiContainer().GetInstance().IsMacContainerLocated()) { + encodedSig = EmbedMacTokenIntoSignatureContainer(encodedSig); + } if (estimatedSize < encodedSig.Length) { throw new System.IO.IOException(SignExceptionMessageConstant.NOT_ENOUGH_SPACE); } @@ -675,7 +678,9 @@ public virtual void Timestamp(ITSAClient tsa, String signatureName) { throw iText.Bouncycastleconnector.BouncyCastleFactoryCreator.GetFactory().CreateGeneralSecurityException(e .Message, e); } - tsToken = EmbedMacTokenIntoSignatureContainer(tsToken); + if (document.GetDiContainer().GetInstance().IsMacContainerLocated()) { + tsToken = EmbedMacTokenIntoSignatureContainer(tsToken); + } if (contentEstimated + 2 < tsToken.Length) { throw new System.IO.IOException(MessageFormatUtil.Format(SignExceptionMessageConstant.TOKEN_ESTIMATION_SIZE_IS_NOT_LARGE_ENOUGH , contentEstimated, tsToken.Length)); @@ -696,12 +701,32 @@ public virtual void Timestamp(ITSAClient tsa, String signatureName) { /// the signature container doing the actual signing. Only the /// method ExternalSignatureContainer.sign is used /// + [System.ObsoleteAttribute(@"SignDeferred(iText.Kernel.Pdf.PdfReader, System.String, System.IO.Stream, IExternalSignatureContainer) should be used instead." + )] public static void SignDeferred(PdfDocument document, String fieldName, Stream outs, IExternalSignatureContainer externalSignatureContainer) { PdfSigner.SignatureApplier applier = new PdfSigner.SignatureApplier(document, fieldName, outs); applier.Apply((a) => externalSignatureContainer.Sign(a.GetDataToSign())); } + /// Signs a PDF where space was already reserved. + /// + /// + /// + /// that reads the PDF file + /// + /// the field to sign. It must be the last field + /// the output PDF + /// + /// the signature container doing the actual signing. Only the + /// method ExternalSignatureContainer.sign is used + /// + public static void SignDeferred(PdfReader reader, String fieldName, Stream outs, IExternalSignatureContainer + externalSignatureContainer) { + PdfSigner.SignatureApplier applier = new PdfSigner.SignatureApplier(reader, fieldName, outs); + applier.Apply((a) => externalSignatureContainer.Sign(a.GetDataToSign())); + } + /// Processes a CRL list. /// a Certificate if one of the CrlList implementations needs to retrieve the CRL URL from it. /// @@ -1243,6 +1268,54 @@ internal virtual PdfSignature CreateSignatureDictionary(bool includeDate) { } //\endcond +//\cond DO_NOT_DOCUMENT + internal virtual byte[] EmbedMacTokenIntoSignatureContainer(byte[] signatureContainer) { + using (Stream rangeStream = GetRangeStream()) { + return EmbedMacTokenIntoSignatureContainer(signatureContainer, rangeStream, document); + } + } +//\endcond + +//\cond DO_NOT_DOCUMENT + internal static byte[] EmbedMacTokenIntoSignatureContainer(byte[] signatureContainer, Stream rangeStream, + PdfDocument document) { + try { + CMSContainer cmsContainer; + if (JavaUtil.ArraysEquals(new byte[signatureContainer.Length], signatureContainer)) { + // Signature container is empty most likely due two two-step signing process. + // We will create blank signature container in order to add MAC in there. + cmsContainer = new CMSContainer(); + SignerInfo signerInfo = new SignerInfo(); + String digestAlgorithmOid = DigestAlgorithms.GetAllowedDigest(DigestAlgorithms.SHA256); + signerInfo.SetDigestAlgorithm(new AlgorithmIdentifier(digestAlgorithmOid)); + signerInfo.SetSignatureAlgorithm(new AlgorithmIdentifier(OID.RSA)); + signerInfo.SetSignature("This is a placeholder signature. It's value shall be replaced with a real signature." + .GetBytes(System.Text.Encoding.UTF8)); + cmsContainer.SetSignerInfo(signerInfo); + } + else { + cmsContainer = new CMSContainer(signatureContainer); + } + // If MAC is in the signature already, we regenerate it anyway. + cmsContainer.GetSignerInfo().RemoveUnSignedAttribute(ID_ATTR_PDF_MAC_DATA); + IAsn1EncodableVector unsignedVector = FACTORY.CreateASN1EncodableVector(); + document.DispatchEvent(new SignatureContainerGenerationEvent(unsignedVector, cmsContainer.GetSignerInfo(). + GetSignatureData(), rangeStream)); + if (FACTORY.CreateDERSequence(unsignedVector).Size() != 0) { + IAsn1Sequence sequence = FACTORY.CreateASN1Sequence(FACTORY.CreateDERSequence(unsignedVector).GetObjectAt( + 0)); + cmsContainer.GetSignerInfo().AddUnSignedAttribute(new CmsAttribute(FACTORY.CreateASN1ObjectIdentifier(sequence + .GetObjectAt(0)).GetId(), sequence.GetObjectAt(1).ToASN1Primitive())); + return cmsContainer.Serialize(); + } + } + catch (Exception exception) { + throw new PdfException(SignExceptionMessageConstant.NOT_POSSIBLE_TO_EMBED_MAC_TO_SIGNATURE, exception); + } + return signatureContainer; + } +//\endcond + private static String GetSignerName(IX509Certificate certificate) { String name = null; CertificateInfo.X500Name x500name = CertificateInfo.GetSubjectFields(certificate); @@ -1301,30 +1374,6 @@ protected internal virtual void ApplyAccessibilityProperties(PdfFormField formFi } } - private byte[] EmbedMacTokenIntoSignatureContainer(byte[] signatureContainer) { - if (document.GetDiContainer().GetInstance().IsMacContainerLocated()) { - try { - CMSContainer cmsContainer = new CMSContainer(signatureContainer); - // If MAC is in the signature already, we regenerate it anyway. - cmsContainer.GetSignerInfo().RemoveUnSignedAttribute(ID_ATTR_PDF_MAC_DATA); - IAsn1EncodableVector unsignedVector = FACTORY.CreateASN1EncodableVector(); - document.DispatchEvent(new SignatureContainerGenerationEvent(unsignedVector, cmsContainer.GetSignerInfo(). - GetSignatureData(), GetRangeStream())); - if (FACTORY.CreateDERSequence(unsignedVector).Size() != 0) { - IAsn1Sequence sequence = FACTORY.CreateASN1Sequence(FACTORY.CreateDERSequence(unsignedVector).GetObjectAt( - 0)); - cmsContainer.GetSignerInfo().AddUnSignedAttribute(new CmsAttribute(FACTORY.CreateASN1ObjectIdentifier(sequence - .GetObjectAt(0)).GetId(), sequence.GetObjectAt(1).ToASN1Primitive())); - return cmsContainer.Serialize(); - } - } - catch (Exception exception) { - throw new PdfException(SignExceptionMessageConstant.NOT_POSSIBLE_TO_EMBED_MAC_TO_SIGNATURE, exception); - } - } - return signatureContainer; - } - private void ApplyDefaultPropertiesForTheNewField(PdfSignatureFormField sigField) { SignatureFieldAppearance formFieldElement = GetSignatureAppearance(); PdfFormAnnotation annotation = sigField.GetFirstFormAnnotation(); @@ -1411,6 +1460,8 @@ public interface ISignatureEvent { internal class SignatureApplier { private readonly PdfDocument document; + private readonly PdfReader reader; + private readonly String fieldName; private readonly Stream outs; @@ -1419,13 +1470,46 @@ internal class SignatureApplier { private long[] gaps; + public SignatureApplier(PdfReader reader, String fieldName, Stream outs) { + this.reader = reader; + this.fieldName = fieldName; + this.outs = outs; + this.document = null; + } + public SignatureApplier(PdfDocument document, String fieldName, Stream outs) { this.document = document; this.fieldName = fieldName; this.outs = outs; + this.reader = null; } public virtual void Apply(PdfSigner.ISignatureDataProvider signatureDataProvider) { + StampingProperties properties = new StampingProperties().PreserveEncryption(); + properties.RegisterDependency(typeof(IMacContainerLocator), new SignatureMacContainerLocator()); + // This IdleOutputStream writer does nothing and only required to be able to apply MAC if needed. + using (PdfWriter dummyWriter = new PdfWriter(new IdleOutputStream())) { + if (document == null) { + using (PdfDocument newDocument = new PdfDocument(reader, dummyWriter, properties)) { + Apply(newDocument, signatureDataProvider); + } + } + else { + RandomAccessFileOrArray raf = document.GetReader().GetSafeFile(); + WindowRandomAccessSource source = new WindowRandomAccessSource(raf.CreateSourceView(), 0, raf.Length()); + using (Stream inputStream = new RASInputStream(source)) { + using (PdfReader newReader = new PdfReader(inputStream, document.GetReader().GetPropertiesCopy())) { + using (PdfDocument newDocument = new PdfDocument(newReader, dummyWriter, properties)) { + Apply(newDocument, signatureDataProvider); + } + } + } + } + } + } + +//\cond DO_NOT_DOCUMENT + internal virtual void Apply(PdfDocument document, PdfSigner.ISignatureDataProvider signatureDataProvider) { SignatureUtil signatureUtil = new SignatureUtil(document); PdfSignature signature = signatureUtil.GetSignature(fieldName); if (signature == null) { @@ -1444,6 +1528,12 @@ public virtual void Apply(PdfSigner.ISignatureDataProvider signatureDataProvider throw new ArgumentException("Gap is not a multiple of 2"); } byte[] signedContent = signatureDataProvider(this); + if (document.GetDiContainer().GetInstance().IsMacContainerLocated()) { + RandomAccessSourceFactory fac = new RandomAccessSourceFactory(); + IRandomAccessSource randomAccessSource = fac.CreateRanged(readerSource, gaps); + RASInputStream signedDocumentStream = new RASInputStream(randomAccessSource); + signedContent = EmbedMacTokenIntoSignatureContainer(signedContent, signedDocumentStream, document); + } spaceAvailable /= 2; if (spaceAvailable < signedContent.Length) { throw new PdfException(SignExceptionMessageConstant.AVAILABLE_SPACE_IS_NOT_ENOUGH_FOR_SIGNATURE); @@ -1462,6 +1552,7 @@ public virtual void Apply(PdfSigner.ISignatureDataProvider signatureDataProvider StreamUtil.CopyBytes(readerSource, gaps[2] - 1, gaps[3] + 1, outs); document.Close(); } +//\endcond public virtual Stream GetDataToSign() { return new RASInputStream(new RandomAccessSourceFactory().CreateRanged(readerSource, gaps)); diff --git a/itext/itext.sign/itext/signatures/PdfTwoPhaseSigner.cs b/itext/itext.sign/itext/signatures/PdfTwoPhaseSigner.cs index 723e3e46e0..08591a39cd 100644 --- a/itext/itext.sign/itext/signatures/PdfTwoPhaseSigner.cs +++ b/itext/itext.sign/itext/signatures/PdfTwoPhaseSigner.cs @@ -111,23 +111,57 @@ public virtual byte[] PrepareDocumentForSignature(SignerProperties signerPropert /// the field to sign. It must be the last field /// the output PDF /// the finalized CMS container + [System.ObsoleteAttribute(@"AddSignatureToPreparedDocument(iText.Kernel.Pdf.PdfReader, System.String, System.IO.Stream, iText.Signatures.Cms.CMSContainer) should be used instead." + )] 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()); } + /// Adds an existing signature to a PDF where space was already reserved. + /// + /// + /// + /// that reads the PDF file + /// + /// the field to sign. It must be the last field + /// the output PDF + /// the finalized CMS container + public static void AddSignatureToPreparedDocument(PdfReader reader, String fieldName, Stream outs, CMSContainer + cmsContainer) { + PdfSigner.SignatureApplier applier = new PdfSigner.SignatureApplier(reader, fieldName, outs); + applier.Apply((a) => cmsContainer.Serialize()); + } + /// 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 bytes for the signed data + [System.ObsoleteAttribute(@"AddSignatureToPreparedDocument(iText.Kernel.Pdf.PdfReader, System.String, System.IO.Stream, byte[]) should be used instead." + )] public static void AddSignatureToPreparedDocument(PdfDocument document, String fieldName, Stream outs, byte [] signedContent) { PdfSigner.SignatureApplier applier = new PdfSigner.SignatureApplier(document, fieldName, outs); applier.Apply((a) => signedContent); } + /// Adds an existing signature to a PDF where space was already reserved. + /// + /// + /// + /// that reads the PDF file + /// + /// the field to sign. It must be the last field + /// the output PDF + /// the bytes for the signed data + public static void AddSignatureToPreparedDocument(PdfReader reader, String fieldName, Stream outs, byte[] + signedContent) { + PdfSigner.SignatureApplier applier = new PdfSigner.SignatureApplier(reader, fieldName, outs); + applier.Apply((a) => signedContent); + } + /// Use the external digest to inject specific digest implementations /// the IExternalDigest instance to use to generate Digests /// @@ -173,9 +207,6 @@ private byte[] PrepareDocumentForSignature(SignerProperties signerProperties, IM } PdfSigner pdfSigner = CreatePdfSigner(signerProperties); PdfDocument document = pdfSigner.GetDocument(); - if (document.GetDiContainer().GetInstance().IsMacContainerLocated()) { - throw new PdfException(SignExceptionMessageConstant.NOT_POSSIBLE_TO_EMBED_MAC_TO_SIGNATURE); - } if (document.GetPdfVersion().CompareTo(PdfVersion.PDF_2_0) < 0) { document.GetCatalog().AddDeveloperExtension(PdfDeveloperExtension.ESIC_1_7_EXTENSIONLEVEL2); } @@ -191,6 +222,13 @@ private byte[] PrepareDocumentForSignature(SignerProperties signerProperties, IM Stream data = pdfSigner.GetRangeStream(); byte[] digest = DigestAlgorithms.Digest(data, messageDigest); byte[] paddedSig = new byte[estimatedSize]; + if (document.GetDiContainer().GetInstance().IsMacContainerLocated()) { + byte[] encodedSig = pdfSigner.EmbedMacTokenIntoSignatureContainer(paddedSig); + if (estimatedSize < encodedSig.Length) { + throw new System.IO.IOException(SignExceptionMessageConstant.NOT_ENOUGH_SPACE); + } + Array.Copy(encodedSig, 0, paddedSig, 0, encodedSig.Length); + } PdfDictionary dic2 = new PdfDictionary(); dic2.Put(PdfName.Contents, new PdfString(paddedSig).SetHexWriting(true)); pdfSigner.Close(dic2); diff --git a/itext/itext.sign/itext/signatures/cms/SignerInfo.cs b/itext/itext.sign/itext/signatures/cms/SignerInfo.cs index 71a175dd24..932f060914 100644 --- a/itext/itext.sign/itext/signatures/cms/SignerInfo.cs +++ b/itext/itext.sign/itext/signatures/cms/SignerInfo.cs @@ -402,8 +402,10 @@ internal virtual IDerSequence GetAsDerSequence(bool estimationRun) { 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())); + if (signerCertificate != null) { + issuerAndSerialNumberV.Add(CertificateInfo.GetIssuer(signerCertificate.GetTbsCertificate())); + issuerAndSerialNumberV.Add(BC_FACTORY.CreateASN1Integer(signerCertificate.GetSerialNumber())); + } signerInfoV.Add(BC_FACTORY.CreateDERSequence(issuerAndSerialNumberV)); // digest algorithm IAsn1EncodableVector digestalgorithmV = BC_FACTORY.CreateASN1EncodableVector(); diff --git a/itext/itext.sign/itext/signatures/exceptions/SignExceptionMessageConstant.cs b/itext/itext.sign/itext/signatures/exceptions/SignExceptionMessageConstant.cs index 1595678b1d..8b04738c43 100644 --- a/itext/itext.sign/itext/signatures/exceptions/SignExceptionMessageConstant.cs +++ b/itext/itext.sign/itext/signatures/exceptions/SignExceptionMessageConstant.cs @@ -90,7 +90,7 @@ public sealed class SignExceptionMessageConstant { public const String NOT_A_VALID_PKCS7_OBJECT_NOT_SIGNED_DATA = "Not a valid PKCS#7 object - not signed " + "data."; - public const String NOT_ENOUGH_SPACE = "Not enough space."; + public const String NOT_ENOUGH_SPACE = "Not enough space allocated for the signature."; public const String NOT_POSSIBLE_TO_EMBED_MAC_TO_SIGNATURE = "It was not possible to embed MAC token into signature. Most likely signature container is empty."; diff --git a/port-hash b/port-hash index 653f9be508..6ef01d1ffb 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -8c0e38d0ef4a27061abdb53952d163b387ba005c +5309178a5193a7909c6a53f405e526a80b29540b \ No newline at end of file