@@ -23,6 +23,9 @@ This file is part of the iText (R) project.
2323package com .itextpdf .signatures ;
2424
2525import com .itextpdf .bouncycastleconnector .BouncyCastleFactoryCreator ;
26+ import com .itextpdf .commons .bouncycastle .IBouncyCastleFactory ;
27+ import com .itextpdf .commons .bouncycastle .asn1 .IASN1EncodableVector ;
28+ import com .itextpdf .commons .bouncycastle .asn1 .IASN1Sequence ;
2629import com .itextpdf .commons .bouncycastle .asn1 .esf .ISignaturePolicyIdentifier ;
2730import com .itextpdf .commons .utils .FileUtil ;
2831import com .itextpdf .commons .utils .MessageFormatUtil ;
@@ -46,6 +49,8 @@ This file is part of the iText (R) project.
4649import com .itextpdf .kernel .font .PdfFont ;
4750import com .itextpdf .kernel .geom .Rectangle ;
4851import com .itextpdf .kernel .mac .IMacContainerLocator ;
52+ import com .itextpdf .signatures .cms .CMSContainer ;
53+ import com .itextpdf .signatures .cms .CmsAttribute ;
4954import com .itextpdf .signatures .mac .SignatureContainerGenerationEvent ;
5055import com .itextpdf .kernel .pdf .PdfArray ;
5156import com .itextpdf .kernel .pdf .PdfDate ;
@@ -104,7 +109,9 @@ This file is part of the iText (R) project.
104109 * Takes care of the cryptographic options and appearances that form a signature.
105110 */
106111public class PdfSigner {
107- private static final int MAXIMUM_MAC_SIZE = 788 ;
112+ static final int MAXIMUM_MAC_SIZE = 788 ;
113+ private static final IBouncyCastleFactory FACTORY = BouncyCastleFactoryCreator .getFactory ();
114+ private static final String ID_ATTR_PDF_MAC_DATA = "1.0.32004.1.2" ;
108115
109116 /**
110117 * Enum containing the Cryptographic Standards. Possible values are "CMS" and "CADES".
@@ -598,8 +605,8 @@ public void signDetached(IExternalDigest externalDigest, IExternalSignature exte
598605 if (tsaClient != null ) {
599606 estimatedSize += tsaClient .getTokenSizeEstimate () + 96 ;
600607 }
601- if (document .getTrailer ().getAsDictionary ( PdfName . AuthCode ) != null ) {
602- // if AuthCode is found in trailer , we assume MAC will be embedded and allocate additional space.
608+ if (document .getDiContainer ().getInstance ( IMacContainerLocator . class ). isMacContainerLocated () ) {
609+ // If MAC container was located , we presume MAC will be embedded and allocate additional space.
603610 estimatedSize += MAXIMUM_MAC_SIZE ;
604611 }
605612 }
@@ -700,12 +707,18 @@ public void signExternalContainer(IExternalSignatureContainer externalSignatureC
700707 externalSignatureContainer .modifySigningDictionary (dic .getPdfObject ());
701708 cryptoDictionary = dic ;
702709
710+ if (document .getDiContainer ().getInstance (IMacContainerLocator .class ).isMacContainerLocated ()) {
711+ // If MAC container was located, we presume MAC will be embedded and allocate additional space.
712+ estimatedSize += MAXIMUM_MAC_SIZE ;
713+ }
714+
703715 Map <PdfName , Integer > exc = new HashMap <>();
704716 exc .put (PdfName .Contents , estimatedSize * 2 + 2 );
705717 preClose (exc );
706718
707719 InputStream data = getRangeStream ();
708720 byte [] encodedSig = externalSignatureContainer .sign (data );
721+ encodedSig = embedMacTokenIntoSignatureContainer (encodedSig );
709722
710723 if (estimatedSize < encodedSig .length ) {
711724 throw new IOException (SignExceptionMessageConstant .NOT_ENOUGH_SPACE );
@@ -744,6 +757,10 @@ public void timestamp(ITSAClient tsa, String signatureName) throws IOException,
744757 }
745758
746759 int contentEstimated = tsa .getTokenSizeEstimate ();
760+ if (document .getDiContainer ().getInstance (IMacContainerLocator .class ).isMacContainerLocated ()) {
761+ // If MAC container was located, we presume MAC will be embedded and allocate additional space.
762+ contentEstimated += MAXIMUM_MAC_SIZE ;
763+ }
747764 if (!isDocumentPdf2 ()) {
748765 addDeveloperExtension (PdfDeveloperExtension .ESIC_1_7_EXTENSIONLEVEL5 );
749766 }
@@ -771,6 +788,8 @@ public void timestamp(ITSAClient tsa, String signatureName) throws IOException,
771788 throw new GeneralSecurityException (e .getMessage (), e );
772789 }
773790
791+ tsToken = embedMacTokenIntoSignatureContainer (tsToken );
792+
774793 if (contentEstimated + 2 < tsToken .length ) {
775794 throw new IOException (MessageFormatUtil .format (
776795 SignExceptionMessageConstant .TOKEN_ESTIMATION_SIZE_IS_NOT_LARGE_ENOUGH ,
@@ -1308,6 +1327,19 @@ protected int getWidgetPageNumber(PdfWidgetAnnotation widget) {
13081327 return pageNumber ;
13091328 }
13101329
1330+ PdfSignature createSignatureDictionary (boolean includeDate ) {
1331+ PdfSignature dic = new PdfSignature ();
1332+ dic .setReason (this .signerProperties .getReason ());
1333+ dic .setLocation (this .signerProperties .getLocation ());
1334+ dic .setSignatureCreator (this .signerProperties .getSignatureCreator ());
1335+ dic .setContact (this .signerProperties .getContact ());
1336+ Calendar claimedSignDate = this .signerProperties .getClaimedSignDate ();
1337+ if (includeDate && claimedSignDate != TimestampConstants .UNDEFINED_TIMESTAMP_DATE ) {
1338+ dic .setDate (new PdfDate (claimedSignDate )); // time-stamp will over-rule this
1339+ }
1340+ return dic ;
1341+ }
1342+
13111343 private static String getSignerName (X509Certificate certificate ) {
13121344 String name = null ;
13131345 CertificateInfo .X500Name x500name = CertificateInfo .getSubjectFields (certificate );
@@ -1355,20 +1387,6 @@ private boolean isDocumentPdf2() {
13551387 return document .getPdfVersion ().compareTo (PdfVersion .PDF_2_0 ) >= 0 ;
13561388 }
13571389
1358- PdfSignature createSignatureDictionary (boolean includeDate ) {
1359- PdfSignature dic = new PdfSignature ();
1360- dic .setReason (this .signerProperties .getReason ());
1361- dic .setLocation (this .signerProperties .getLocation ());
1362- dic .setSignatureCreator (this .signerProperties .getSignatureCreator ());
1363- dic .setContact (this .signerProperties .getContact ());
1364- Calendar claimedSignDate = this .signerProperties .getClaimedSignDate ();
1365- if (includeDate && claimedSignDate != TimestampConstants .UNDEFINED_TIMESTAMP_DATE ) {
1366- dic .setDate (new PdfDate (claimedSignDate )); // time-stamp will over-rule this
1367- }
1368- return dic ;
1369- }
1370-
1371-
13721390 protected void applyAccessibilityProperties (PdfFormField formField , IAccessibleElement modelElement ,
13731391 PdfDocument pdfDocument ) {
13741392 if (!pdfDocument .isTagged ()) {
@@ -1381,6 +1399,30 @@ protected void applyAccessibilityProperties(PdfFormField formField, IAccessibleE
13811399 }
13821400 }
13831401
1402+ private byte [] embedMacTokenIntoSignatureContainer (byte [] signatureContainer ) {
1403+ if (document .getDiContainer ().getInstance (IMacContainerLocator .class ).isMacContainerLocated ()) {
1404+ try {
1405+ CMSContainer cmsContainer = new CMSContainer (signatureContainer );
1406+ // If MAC is in the signature already, we regenerate it anyway.
1407+ cmsContainer .getSignerInfo ().removeUnSignedAttribute (ID_ATTR_PDF_MAC_DATA );
1408+ IASN1EncodableVector unsignedVector = FACTORY .createASN1EncodableVector ();
1409+ document .dispatchEvent (new SignatureContainerGenerationEvent (unsignedVector ,
1410+ cmsContainer .getSignerInfo ().getSignatureData (), getRangeStream ()));
1411+ if (FACTORY .createDERSequence (unsignedVector ).size () != 0 ) {
1412+ IASN1Sequence sequence =
1413+ FACTORY .createASN1Sequence (FACTORY .createDERSequence (unsignedVector ).getObjectAt (0 ));
1414+ cmsContainer .getSignerInfo ().addUnSignedAttribute (new CmsAttribute (
1415+ FACTORY .createASN1ObjectIdentifier (sequence .getObjectAt (0 )).getId (),
1416+ sequence .getObjectAt (1 ).toASN1Primitive ()));
1417+ return cmsContainer .serialize ();
1418+ }
1419+ } catch (Exception exception ) {
1420+ throw new PdfException (SignExceptionMessageConstant .NOT_POSSIBLE_TO_EMBED_MAC_TO_SIGNATURE , exception );
1421+ }
1422+ }
1423+ return signatureContainer ;
1424+ }
1425+
13841426 private void applyDefaultPropertiesForTheNewField (PdfSignatureFormField sigField ) {
13851427 SignatureFieldAppearance formFieldElement = getSignatureAppearance ();
13861428 PdfFormAnnotation annotation = sigField .getFirstFormAnnotation ();
0 commit comments