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 <tsepez@chromium.org> Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/fpdfsdk/fpdf_signature.cpp b/fpdfsdk/fpdf_signature.cpp index b438b8f..975c252 100644 --- a/fpdfsdk/fpdf_signature.cpp +++ b/fpdfsdk/fpdf_signature.cpp
@@ -157,3 +157,44 @@ 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 d2fd9c6..e91d9c2 100644 --- a/fpdfsdk/fpdf_signature_embeddertest.cpp +++ b/fpdfsdk/fpdf_signature_embeddertest.cpp
@@ -187,3 +187,16 @@ 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 7708cba..1142725 100644 --- a/fpdfsdk/fpdf_view_c_api_test.c +++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -320,6 +320,7 @@ // 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 f20d9ad..702b67b 100644 --- a/public/fpdf_signature.h +++ b/public/fpdf_signature.h
@@ -137,6 +137,17 @@ 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 0000000..a8fe283 --- /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 0000000..0191a00 --- /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