| // 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 <utility> | |
| #include <vector> | |
| #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<RetainPtr<CPDF_Dictionary>> CollectSignatures(CPDF_Document* doc) { | |
| std::vector<RetainPtr<CPDF_Dictionary>> signatures; | |
| const CPDF_Dictionary* root = doc->GetRoot(); | |
| if (!root) | |
| return signatures; | |
| RetainPtr<const CPDF_Dictionary> acro_form = root->GetDictFor("AcroForm"); | |
| if (!acro_form) | |
| return signatures; | |
| RetainPtr<const CPDF_Array> fields = acro_form->GetArrayFor("Fields"); | |
| if (!fields) | |
| return signatures; | |
| CPDF_ArrayLocker locker(std::move(fields)); | |
| for (auto& field : locker) { | |
| RetainPtr<CPDF_Dictionary> field_dict = field->GetMutableDict(); | |
| if (field_dict && field_dict->GetNameFor("FT") == "Sig") | |
| 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<int>(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<RetainPtr<CPDF_Dictionary>> 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<const CPDF_Dictionary> value_dict = signature_dict->GetDictFor("V"); | |
| if (!value_dict) | |
| return 0; | |
| ByteString contents = value_dict->GetByteStringFor("Contents"); | |
| const unsigned long contents_len = | |
| pdfium::base::checked_cast<unsigned long>(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<const CPDF_Dictionary> value_dict = signature_dict->GetDictFor("V"); | |
| if (!value_dict) | |
| return 0; | |
| RetainPtr<const CPDF_Array> byte_range = value_dict->GetArrayFor("ByteRange"); | |
| if (!byte_range) | |
| return 0; | |
| const unsigned long byte_range_len = | |
| fxcrt::CollectionSize<unsigned long>(*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<const CPDF_Dictionary> value_dict = signature_dict->GetDictFor("V"); | |
| 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<const CPDF_Dictionary> value_dict = signature_dict->GetDictFor("V"); | |
| if (!value_dict) | |
| return 0; | |
| RetainPtr<const CPDF_Object> 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<const CPDF_Dictionary> value_dict = signature_dict->GetDictFor("V"); | |
| if (!value_dict) | |
| return 0; | |
| RetainPtr<const CPDF_Object> 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<const CPDF_Dictionary> value_dict = signature_dict->GetDictFor("V"); | |
| if (!value_dict) | |
| return permission; | |
| RetainPtr<const CPDF_Array> references = value_dict->GetArrayFor("Reference"); | |
| if (!references) | |
| return permission; | |
| CPDF_ArrayLocker locker(std::move(references)); | |
| for (auto& reference : locker) { | |
| RetainPtr<const CPDF_Dictionary> reference_dict = reference->GetDict(); | |
| if (!reference_dict) | |
| continue; | |
| ByteString transform_method = reference_dict->GetNameFor("TransformMethod"); | |
| if (transform_method != "DocMDP") | |
| continue; | |
| RetainPtr<const 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; | |
| } |