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