// Copyright 2020 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "public/fpdf_signature.h" #include #include #include "constants/form_fields.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fxcrt/stl_util.h" #include "fpdfsdk/cpdfsdk_helpers.h" #include "third_party/base/numerics/safe_conversions.h" namespace { std::vector> CollectSignatures( CPDF_Document* doc) { std::vector> signatures; const CPDF_Dictionary* root = doc->GetRoot(); if (!root) return signatures; RetainPtr acro_form = root->GetDictFor("AcroForm"); if (!acro_form) return signatures; RetainPtr fields = acro_form->GetArrayFor("Fields"); if (!fields) return signatures; CPDF_ArrayLocker locker(std::move(fields)); for (auto& field : locker) { RetainPtr field_dict = field->GetDict(); if (field_dict && field_dict->GetNameFor(pdfium::form_fields::kFT) == pdfium::form_fields::kSig) { signatures.push_back(std::move(field_dict)); } } return signatures; } } // namespace FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSignatureCount(FPDF_DOCUMENT document) { auto* doc = CPDFDocumentFromFPDFDocument(document); if (!doc) return -1; return fxcrt::CollectionSize(CollectSignatures(doc)); } FPDF_EXPORT FPDF_SIGNATURE FPDF_CALLCONV FPDF_GetSignatureObject(FPDF_DOCUMENT document, int index) { auto* doc = CPDFDocumentFromFPDFDocument(document); if (!doc) return nullptr; std::vector> signatures = CollectSignatures(doc); if (!fxcrt::IndexInBounds(signatures, index)) return nullptr; return FPDFSignatureFromCPDFDictionary(signatures[index].Get()); } FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetContents(FPDF_SIGNATURE signature, void* buffer, unsigned long length) { const CPDF_Dictionary* signature_dict = CPDFDictionaryFromFPDFSignature(signature); if (!signature_dict) return 0; RetainPtr value_dict = signature_dict->GetDictFor(pdfium::form_fields::kV); if (!value_dict) return 0; ByteString contents = value_dict->GetByteStringFor("Contents"); const unsigned long contents_len = pdfium::base::checked_cast(contents.GetLength()); if (buffer && length >= contents_len) memcpy(buffer, contents.c_str(), contents_len); return contents_len; } FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetByteRange(FPDF_SIGNATURE signature, int* buffer, unsigned long length) { const CPDF_Dictionary* signature_dict = CPDFDictionaryFromFPDFSignature(signature); if (!signature_dict) return 0; RetainPtr value_dict = signature_dict->GetDictFor(pdfium::form_fields::kV); if (!value_dict) return 0; RetainPtr byte_range = value_dict->GetArrayFor("ByteRange"); if (!byte_range) return 0; const unsigned long byte_range_len = fxcrt::CollectionSize(*byte_range); if (buffer && length >= byte_range_len) { for (size_t i = 0; i < byte_range_len; ++i) buffer[i] = byte_range->GetIntegerAt(i); } return byte_range_len; } FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetSubFilter(FPDF_SIGNATURE signature, char* buffer, unsigned long length) { const CPDF_Dictionary* signature_dict = CPDFDictionaryFromFPDFSignature(signature); if (!signature_dict) return 0; RetainPtr value_dict = signature_dict->GetDictFor(pdfium::form_fields::kV); if (!value_dict || !value_dict->KeyExist("SubFilter")) return 0; ByteString sub_filter = value_dict->GetNameFor("SubFilter"); return NulTerminateMaybeCopyAndReturnLength(sub_filter, buffer, length); } FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetReason(FPDF_SIGNATURE signature, void* buffer, unsigned long length) { const CPDF_Dictionary* signature_dict = CPDFDictionaryFromFPDFSignature(signature); if (!signature_dict) return 0; RetainPtr value_dict = signature_dict->GetDictFor(pdfium::form_fields::kV); if (!value_dict) return 0; RetainPtr obj = value_dict->GetObjectFor("Reason"); if (!obj || !obj->IsString()) return 0; return Utf16EncodeMaybeCopyAndReturnLength(obj->GetUnicodeText(), buffer, length); } FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFSignatureObj_GetTime(FPDF_SIGNATURE signature, char* buffer, unsigned long length) { const CPDF_Dictionary* signature_dict = CPDFDictionaryFromFPDFSignature(signature); if (!signature_dict) return 0; RetainPtr value_dict = signature_dict->GetDictFor(pdfium::form_fields::kV); if (!value_dict) return 0; RetainPtr obj = value_dict->GetObjectFor("M"); if (!obj || !obj->IsString()) return 0; return NulTerminateMaybeCopyAndReturnLength(obj->GetString(), buffer, length); } FPDF_EXPORT unsigned int FPDF_CALLCONV FPDFSignatureObj_GetDocMDPPermission(FPDF_SIGNATURE signature) { int permission = 0; const CPDF_Dictionary* signature_dict = CPDFDictionaryFromFPDFSignature(signature); if (!signature_dict) return permission; RetainPtr value_dict = signature_dict->GetDictFor(pdfium::form_fields::kV); if (!value_dict) return permission; RetainPtr references = value_dict->GetArrayFor("Reference"); if (!references) return permission; CPDF_ArrayLocker locker(std::move(references)); for (auto& reference : locker) { RetainPtr reference_dict = reference->GetDict(); if (!reference_dict) continue; ByteString transform_method = reference_dict->GetNameFor("TransformMethod"); if (transform_method != "DocMDP") continue; RetainPtr 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; }