From f63c9650bca285932fb4dced804f9eec7e40b5ff Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Tue, 3 Nov 2020 16:32:12 +0000 Subject: [PATCH] Add FPDFSignatureObj_GetDocMDPPermission() A document is OK to not contain any explicit markup for this, in which case 0 is returned. If a permission parameter is found, then the returned level of 1, 2 or 3 controls if no incremental updates are allowed (1) or incremental updates are OK, but annotations are not allowed (2) or even annotations are allowed (3). Note how there is a difference between omitting just the /P key (implicitly means 2) and omitting the more of this markup, which will return 0. This API is meant to be used in combination with the FPDF_GetTrailerEnds() API, which allows detecting additional incremental updates after a signature. For example, if a comment is added after signing, then Permission=1 would result in an invalid signature, while Permission=3 just results in a partial signature. Change-Id: I911e9ddaff3a687729e7fe610c013b2ce3283d36 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/75910 Commit-Queue: Tom Sepez Reviewed-by: Tom Sepez --- fpdfsdk/fpdf_signature.cpp | 41 ++++++++++ fpdfsdk/fpdf_signature_embeddertest.cpp | 13 +++ fpdfsdk/fpdf_view_c_api_test.c | 1 + public/fpdf_signature.h | 11 +++ testing/resources/docmdp.in | 88 ++++++++++++++++++++ testing/resources/docmdp.pdf | 102 ++++++++++++++++++++++++ 6 files changed, 256 insertions(+) create mode 100644 testing/resources/docmdp.in create mode 100644 testing/resources/docmdp.pdf diff --git a/fpdfsdk/fpdf_signature.cpp b/fpdfsdk/fpdf_signature.cpp index b438b8f6a..975c2522e 100644 --- a/fpdfsdk/fpdf_signature.cpp +++ b/fpdfsdk/fpdf_signature.cpp @@ -157,3 +157,44 @@ FPDFSignatureObj_GetTime(FPDF_SIGNATURE signature, return NulTerminateMaybeCopyAndReturnLength(obj->GetString(), buffer, length); } + +FPDF_EXPORT unsigned int FPDF_CALLCONV +FPDFSignatureObj_GetDocMDPPermission(FPDF_SIGNATURE signature) { + int permission = 0; + CPDF_Dictionary* signature_dict = CPDFDictionaryFromFPDFSignature(signature); + if (!signature_dict) + return permission; + + CPDF_Dictionary* value_dict = signature_dict->GetDictFor("V"); + if (!value_dict) + return permission; + + CPDF_Array* references = value_dict->GetArrayFor("Reference"); + if (!references) + return permission; + + CPDF_ArrayLocker locker(references); + for (auto& reference : locker) { + CPDF_Dictionary* reference_dict = reference->GetDict(); + if (!reference_dict) + continue; + + ByteString transform_method = reference_dict->GetNameFor("TransformMethod"); + if (transform_method != "DocMDP") + continue; + + CPDF_Dictionary* transform_params = + reference_dict->GetDictFor("TransformParams"); + if (!transform_params) + continue; + + // Valid values are 1, 2 and 3; 2 is the default. + permission = transform_params->GetIntegerFor("P", 2); + if (permission < 1 || permission > 3) + permission = 0; + + return permission; + } + + return permission; +} diff --git a/fpdfsdk/fpdf_signature_embeddertest.cpp b/fpdfsdk/fpdf_signature_embeddertest.cpp index d2fd9c663..e91d9c221 100644 --- a/fpdfsdk/fpdf_signature_embeddertest.cpp +++ b/fpdfsdk/fpdf_signature_embeddertest.cpp @@ -187,3 +187,16 @@ TEST_F(FPDFSignatureEmbedderTest, GetTime) { EXPECT_EQ('x', time_buffer[0]); EXPECT_EQ('\0', time_buffer[1]); } + +TEST_F(FPDFSignatureEmbedderTest, GetDocMDPPermission) { + ASSERT_TRUE(OpenDocument("docmdp.pdf")); + FPDF_SIGNATURE signature = FPDF_GetSignatureObject(document(), 0); + ASSERT_NE(nullptr, signature); + + // FPDFSignatureObj_GetDocMDPPermission() positive testing. + unsigned int permission = FPDFSignatureObj_GetDocMDPPermission(signature); + EXPECT_EQ(1U, permission); + + // FPDFSignatureObj_GetDocMDPPermission() negative testing. + EXPECT_EQ(0U, FPDFSignatureObj_GetDocMDPPermission(nullptr)); +} diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c index 7708cbab9..1142725d6 100644 --- a/fpdfsdk/fpdf_view_c_api_test.c +++ b/fpdfsdk/fpdf_view_c_api_test.c @@ -320,6 +320,7 @@ int CheckPDFiumCApi() { // fpdf_signature.h CHK(FPDFSignatureObj_GetByteRange); CHK(FPDFSignatureObj_GetContents); + CHK(FPDFSignatureObj_GetDocMDPPermission); CHK(FPDFSignatureObj_GetReason); CHK(FPDFSignatureObj_GetSubFilter); CHK(FPDFSignatureObj_GetTime); diff --git a/public/fpdf_signature.h b/public/fpdf_signature.h index f20d9add3..702b67bae 100644 --- a/public/fpdf_signature.h +++ b/public/fpdf_signature.h @@ -137,6 +137,17 @@ FPDFSignatureObj_GetTime(FPDF_SIGNATURE signature, char* buffer, unsigned long length); +// Experimental API. +// Function: FPDFSignatureObj_GetDocMDPPermission +// Get the DocMDP permission of a signature object. +// Parameters: +// signature - Handle to the signature object. Returned by +// FPDF_GetSignatureObject(). +// Return value: +// Returns the permission (1, 2 or 3) on success, 0 on error. +FPDF_EXPORT unsigned int FPDF_CALLCONV +FPDFSignatureObj_GetDocMDPPermission(FPDF_SIGNATURE signature); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/testing/resources/docmdp.in b/testing/resources/docmdp.in new file mode 100644 index 000000000..a8fe28373 --- /dev/null +++ b/testing/resources/docmdp.in @@ -0,0 +1,88 @@ +{{header}} +{{object 1 0}} << + /Type /Catalog + /Pages 2 0 R + /AcroForm << + /Fields [7 0 R] + /SigFlags 3 + >> +>> +endobj +endobj +{{object 2 0}} << + /Type /Pages + /MediaBox [0 0 200 300] + /Count 1 + /Kids [3 0 R] +>> +endobj +{{object 3 0}} << + /Type /Page + /Parent 2 0 R + /Contents 4 0 R + /Annots [7 0 R] +>> +endobj +{{object 4 0}} << + {{streamlen}} +>> +stream +q +0 0 0 rg +0 290 10 10 re B* +10 150 50 30 re B* +0 0 1 rg +190 290 10 10 re B* +70 232 50 30 re B* +0 1 0 rg +190 0 10 10 re B* +130 150 50 30 re B* +1 0 0 rg +0 0 10 10 re B* +70 67 50 30 re B* +Q +endstream +endobj +{{object 5 0}} << + /Type /Sig + /Reference [ + << + /Type /SigRef + /TransformMethod /DocMDP + /TransformParams << + /Type /TransformParams + /P 1 + /V /1.2 + >> + >> + ] +>> +endobj +{{object 6 0}} << + /Type /XObject + /Subtype /Form + /BBox [0 0 0 0] + /Length 0 +>> +stream +endstream +endobj +{{object 7 0}} << + /Type /Annot + /Subtype /Widget + /FT /Sig + /F 132 + /Rect [0 0 0 0] + /P 3 0 R + /T (Signature1) + /V 5 0 R + /DV 5 0 R + /AP << + /N 6 0 R + >> +>> +endobj +{{xref}} +{{trailer}} +{{startxref}} +%%EOF diff --git a/testing/resources/docmdp.pdf b/testing/resources/docmdp.pdf new file mode 100644 index 000000000..0191a0029 --- /dev/null +++ b/testing/resources/docmdp.pdf @@ -0,0 +1,102 @@ +%PDF-1.7 +% ò¤ô +1 0 obj << + /Type /Catalog + /Pages 2 0 R + /AcroForm << + /Fields [7 0 R] + /SigFlags 3 + >> +>> +endobj +endobj +2 0 obj << + /Type /Pages + /MediaBox [0 0 200 300] + /Count 1 + /Kids [3 0 R] +>> +endobj +3 0 obj << + /Type /Page + /Parent 2 0 R + /Contents 4 0 R + /Annots [7 0 R] +>> +endobj +4 0 obj << + /Length 188 +>> +stream +q +0 0 0 rg +0 290 10 10 re B* +10 150 50 30 re B* +0 0 1 rg +190 290 10 10 re B* +70 232 50 30 re B* +0 1 0 rg +190 0 10 10 re B* +130 150 50 30 re B* +1 0 0 rg +0 0 10 10 re B* +70 67 50 30 re B* +Q +endstream +endobj +5 0 obj << + /Type /Sig + /Reference [ + << + /Type /SigRef + /TransformMethod /DocMDP + /TransformParams << + /Type /TransformParams + /P 1 + /V /1.2 + >> + >> + ] +>> +endobj +6 0 obj << + /Type /XObject + /Subtype /Form + /BBox [0 0 0 0] + /Length 0 +>> +stream +endstream +endobj +7 0 obj << + /Type /Annot + /Subtype /Widget + /FT /Sig + /F 132 + /Rect [0 0 0 0] + /P 3 0 R + /T (Signature1) + /V 5 0 R + /DV 5 0 R + /AP << + /N 6 0 R + >> +>> +endobj +xref +0 8 +0000000000 65535 f +0000000015 00000 n +0000000131 00000 n +0000000220 00000 n +0000000307 00000 n +0000000547 00000 n +0000000760 00000 n +0000000862 00000 n +trailer << + /Root 1 0 R + /Size 8 +>> +startxref +1034 +%%EOF -- 2.26.2