diff options
author | Artem Strygin <art-snake@yandex-team.ru> | 2017-10-02 19:19:28 +0300 |
---|---|---|
committer | Chromium commit bot <commit-bot@chromium.org> | 2017-10-02 16:29:30 +0000 |
commit | d8169d7607b5084cdeceee3eaffca0ab16d2c14d (patch) | |
tree | 7741388e44b50f8a330f4724fa5ce29d6a0097bf /core/fpdfapi | |
parent | 73784e81928a664169f0ae013707fdfb0e82e70d (diff) | |
download | pdfium-d8169d7607b5084cdeceee3eaffca0ab16d2c14d.tar.xz |
Implement CPDF_CryptoHandler::DecryptObject
Decryption logic has been extracted from CPDF_SyntaxParser::GetObjectBody
into CPDF_CryptoHandler::DecryptObject
Performance comparison results:
https://pdfium-review.googlesource.com/c/pdfium/+/12970
Change-Id: Iaeaed56b7f96166bbbcf6db162192d2ba9af4698
Reviewed-on: https://pdfium-review.googlesource.com/12971
Commit-Queue: Art Snake <art-snake@yandex-team.ru>
Reviewed-by: dsinclair <dsinclair@chromium.org>
Diffstat (limited to 'core/fpdfapi')
-rw-r--r-- | core/fpdfapi/parser/cfdf_document.cpp | 5 | ||||
-rw-r--r-- | core/fpdfapi/parser/cpdf_crypto_handler.cpp | 113 | ||||
-rw-r--r-- | core/fpdfapi/parser/cpdf_crypto_handler.h | 24 | ||||
-rw-r--r-- | core/fpdfapi/parser/cpdf_data_avail.cpp | 6 | ||||
-rw-r--r-- | core/fpdfapi/parser/cpdf_dictionary.cpp | 6 | ||||
-rw-r--r-- | core/fpdfapi/parser/cpdf_parser.cpp | 41 | ||||
-rw-r--r-- | core/fpdfapi/parser/cpdf_parser.h | 3 | ||||
-rw-r--r-- | core/fpdfapi/parser/cpdf_syntax_parser.cpp | 96 | ||||
-rw-r--r-- | core/fpdfapi/parser/cpdf_syntax_parser.h | 22 | ||||
-rw-r--r-- | core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp | 3 |
10 files changed, 182 insertions, 137 deletions
diff --git a/core/fpdfapi/parser/cfdf_document.cpp b/core/fpdfapi/parser/cfdf_document.cpp index 9c833cedcf..55493b257d 100644 --- a/core/fpdfapi/parser/cfdf_document.cpp +++ b/core/fpdfapi/parser/cfdf_document.cpp @@ -66,8 +66,7 @@ void CFDF_Document::ParseStream( if (word != "obj") break; - std::unique_ptr<CPDF_Object> pObj = - parser.GetObjectBody(this, objnum, 0, false); + std::unique_ptr<CPDF_Object> pObj = parser.GetObjectBody(this); if (!pObj) break; @@ -80,7 +79,7 @@ void CFDF_Document::ParseStream( break; std::unique_ptr<CPDF_Dictionary> pMainDict = - ToDictionary(parser.GetObjectBody(this, 0, 0, false)); + ToDictionary(parser.GetObjectBody(this)); if (pMainDict) m_pRootDict = pMainDict->GetDictFor("Root"); diff --git a/core/fpdfapi/parser/cpdf_crypto_handler.cpp b/core/fpdfapi/parser/cpdf_crypto_handler.cpp index cae95f2c19..441ca8000d 100644 --- a/core/fpdfapi/parser/cpdf_crypto_handler.cpp +++ b/core/fpdfapi/parser/cpdf_crypto_handler.cpp @@ -8,10 +8,41 @@ #include <time.h> +#include <stack> +#include <utility> + #include "core/fdrm/crypto/fx_crypt.h" +#include "core/fpdfapi/edit/cpdf_encryptor.h" +#include "core/fpdfapi/edit/cpdf_flateencoder.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_object_walker.h" #include "core/fpdfapi/parser/cpdf_parser.h" #include "core/fpdfapi/parser/cpdf_security_handler.h" #include "core/fpdfapi/parser/cpdf_simple_parser.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_string.h" + +namespace { + +constexpr char kContentsKey[] = "Contents"; +constexpr char kTypeKey[] = "Type"; +constexpr char kFTKey[] = "FT"; +constexpr char kSignTypeValue[] = "Sig"; + +} // namespace + +// static +bool CPDF_CryptoHandler::IsSignatureDictionary( + const CPDF_Dictionary* dictionary) { + if (!dictionary) + return false; + const CPDF_Object* type_obj = dictionary->GetDirectObjectFor(kTypeKey); + if (!type_obj) + type_obj = dictionary->GetDirectObjectFor(kFTKey); + return type_obj && type_obj->GetString() == kSignTypeValue; +} void CPDF_CryptoHandler::CryptBlock(bool bEncrypt, uint32_t objnum, @@ -301,6 +332,88 @@ bool CPDF_CryptoHandler::IsCipherAES() const { return m_Cipher == FXCIPHER_AES; } +std::unique_ptr<CPDF_Object> CPDF_CryptoHandler::DecryptObjectTree( + std::unique_ptr<CPDF_Object> object) { + if (!object) + return nullptr; + + struct MayBeSignature { + const CPDF_Dictionary* parent; + CPDF_Object* contents; + }; + + std::stack<MayBeSignature> may_be_sign_dictionaries; + const uint32_t obj_num = object->GetObjNum(); + const uint32_t gen_num = object->GetGenNum(); + + CPDF_Object* object_to_decrypt = object.get(); + while (object_to_decrypt) { + CPDF_NonConstObjectWalker walker(object_to_decrypt); + object_to_decrypt = nullptr; + while (CPDF_Object* child = walker.GetNext()) { + const CPDF_Dictionary* parent_dict = + walker.GetParent() ? walker.GetParent()->GetDict() : nullptr; + if (walker.dictionary_key() == kContentsKey && + (parent_dict->KeyExist(kTypeKey) || parent_dict->KeyExist(kFTKey))) { + // This object may be contents of signature dictionary. + // But now values of 'Type' and 'FT' of dictionary keys are encrypted, + // and we can not check this. + // Temporary skip it, to prevent signature corruption. + // It will be decrypted on next interations, if this is not contents of + // signature dictionary. + may_be_sign_dictionaries.push(MayBeSignature({parent_dict, child})); + walker.SkipWalkIntoCurrentObject(); + continue; + } + // Strings decryption. + if (child->IsString()) { + // TODO(art-snake): Move decryption into the CPDF_String class. + CPDF_String* str = child->AsString(); + str->SetString(Decrypt(obj_num, gen_num, str->GetString())); + } + // Stream decryption. + if (child->IsStream()) { + // TODO(art-snake): Move decryption into the CPDF_Stream class. + CPDF_Stream* stream = child->AsStream(); + auto stream_access = pdfium::MakeRetain<CPDF_StreamAcc>(stream); + stream_access->LoadAllData(true); + + if (IsCipherAES() && stream_access->GetSize() < 16) { + stream->SetData(nullptr, 0); + continue; + } + + CFX_BinaryBuf decrypted_buf; + decrypted_buf.EstimateSize(DecryptGetSize(stream_access->GetSize())); + + void* context = DecryptStart(obj_num, gen_num); + bool decrypt_result = + DecryptStream(context, stream_access->GetData(), + stream_access->GetSize(), decrypted_buf); + decrypt_result &= DecryptFinish(context, decrypted_buf); + if (decrypt_result) { + const uint32_t decrypted_size = decrypted_buf.GetSize(); + stream->SetData(decrypted_buf.DetachBuffer(), decrypted_size); + } else { + // Decryption failed, set the stream to empty + stream->SetData(nullptr, 0); + } + } + } + // Signature dictionaries check. + while (!may_be_sign_dictionaries.empty()) { + auto dict_and_contents = std::move(may_be_sign_dictionaries.top()); + may_be_sign_dictionaries.pop(); + if (!IsSignatureDictionary(dict_and_contents.parent)) { + // This is not signature dictionary. Do decrypt its contents. + object_to_decrypt = dict_and_contents.contents; + break; + } + } + } + return object; +} + bool CPDF_CryptoHandler::DecryptStream(void* context, const uint8_t* src_buf, uint32_t src_size, diff --git a/core/fpdfapi/parser/cpdf_crypto_handler.h b/core/fpdfapi/parser/cpdf_crypto_handler.h index d815e786f6..60f32b70ba 100644 --- a/core/fpdfapi/parser/cpdf_crypto_handler.h +++ b/core/fpdfapi/parser/cpdf_crypto_handler.h @@ -17,6 +17,7 @@ #include "core/fxcrt/retain_ptr.h" class CPDF_Dictionary; +class CPDF_Object; class CPDF_SecurityHandler; class CPDF_CryptoHandler : public Retainable { @@ -24,16 +25,14 @@ class CPDF_CryptoHandler : public Retainable { template <typename T, typename... Args> friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + static bool IsSignatureDictionary(const CPDF_Dictionary* dictionary); + bool Init(CPDF_Dictionary* pEncryptDict, CPDF_SecurityHandler* pSecurityHandler); - uint32_t DecryptGetSize(uint32_t src_size); - void* DecryptStart(uint32_t objnum, uint32_t gennum); - ByteString Decrypt(uint32_t objnum, uint32_t gennum, const ByteString& str); - bool DecryptStream(void* context, - const uint8_t* src_buf, - uint32_t src_size, - CFX_BinaryBuf& dest_buf); - bool DecryptFinish(void* context, CFX_BinaryBuf& dest_buf); + + std::unique_ptr<CPDF_Object> DecryptObjectTree( + std::unique_ptr<CPDF_Object> object); + uint32_t EncryptGetSize(uint32_t objnum, uint32_t version, const uint8_t* src_buf, @@ -52,6 +51,15 @@ class CPDF_CryptoHandler : public Retainable { CPDF_CryptoHandler(); ~CPDF_CryptoHandler() override; + uint32_t DecryptGetSize(uint32_t src_size); + void* DecryptStart(uint32_t objnum, uint32_t gennum); + ByteString Decrypt(uint32_t objnum, uint32_t gennum, const ByteString& str); + bool DecryptStream(void* context, + const uint8_t* src_buf, + uint32_t src_size, + CFX_BinaryBuf& dest_buf); + bool DecryptFinish(void* context, CFX_BinaryBuf& dest_buf); + void PopulateKey(uint32_t objnum, uint32_t gennum, uint8_t* key); void CryptBlock(bool bEncrypt, uint32_t objnum, diff --git a/core/fpdfapi/parser/cpdf_data_avail.cpp b/core/fpdfapi/parser/cpdf_data_avail.cpp index 1db0470f37..8b378aab0e 100644 --- a/core/fpdfapi/parser/cpdf_data_avail.cpp +++ b/core/fpdfapi/parser/cpdf_data_avail.cpp @@ -670,14 +670,12 @@ std::unique_ptr<CPDF_Object> CPDF_DataAvail::ParseIndirectObjectAt( if (!bIsNumber) return nullptr; - uint32_t gennum = FXSYS_atoui(word.c_str()); if (m_syntaxParser.GetKeyword() != "obj") { m_syntaxParser.SetPos(SavedPos); return nullptr; } - std::unique_ptr<CPDF_Object> pObj = - m_syntaxParser.GetObjectBody(pObjList, parser_objnum, gennum, false); + std::unique_ptr<CPDF_Object> pObj = m_syntaxParser.GetObjectBody(pObjList); m_syntaxParser.SetPos(SavedPos); return pObj; } @@ -923,7 +921,7 @@ bool CPDF_DataAvail::CheckTrailer() { const CPDF_ReadValidator::Session read_session(GetValidator().Get()); m_syntaxParser.SetPos(m_dwTrailerOffset); const std::unique_ptr<CPDF_Object> pTrailer = - m_syntaxParser.GetObjectBody(nullptr, 0, 0, false); + m_syntaxParser.GetObjectBody(nullptr); if (!pTrailer) { if (!GetValidator()->has_read_problems()) m_docStatus = PDF_DATAAVAIL_ERROR; diff --git a/core/fpdfapi/parser/cpdf_dictionary.cpp b/core/fpdfapi/parser/cpdf_dictionary.cpp index 5cdcf34f81..1e7f6a9a9b 100644 --- a/core/fpdfapi/parser/cpdf_dictionary.cpp +++ b/core/fpdfapi/parser/cpdf_dictionary.cpp @@ -11,6 +11,7 @@ #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_boolean.h" +#include "core/fpdfapi/parser/cpdf_crypto_handler.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_reference.h" @@ -167,10 +168,7 @@ bool CPDF_Dictionary::KeyExist(const ByteString& key) const { } bool CPDF_Dictionary::IsSignatureDict() const { - CPDF_Object* pType = GetDirectObjectFor("Type"); - if (!pType) - pType = GetDirectObjectFor("FT"); - return pType && pType->GetString() == "Sig"; + return CPDF_CryptoHandler::IsSignatureDictionary(this); } CPDF_Object* CPDF_Dictionary::SetFor(const ByteString& key, diff --git a/core/fpdfapi/parser/cpdf_parser.cpp b/core/fpdfapi/parser/cpdf_parser.cpp index 6643cf5123..40d1b49ed6 100644 --- a/core/fpdfapi/parser/cpdf_parser.cpp +++ b/core/fpdfapi/parser/cpdf_parser.cpp @@ -22,6 +22,7 @@ #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fpdfapi/parser/cpdf_syntax_parser.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fxcrt/autorestorer.h" #include "core/fxcrt/cfx_memorystream.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/fx_safe_types.h" @@ -165,7 +166,7 @@ void CPDF_Parser::SetEncryptDictionary(CPDF_Dictionary* pDict) { } RetainPtr<CPDF_CryptoHandler> CPDF_Parser::GetCryptoHandler() const { - return m_pSyntax->m_pCryptoHandler; + return m_pCryptoHandler; } RetainPtr<IFX_SeekableReadStream> CPDF_Parser::GetFileAccess() const { @@ -292,7 +293,7 @@ CPDF_Parser::Error CPDF_Parser::StartParseInternal(CPDF_Document* pDocument) { CPDF_Reference* pMetadata = ToReference(m_pDocument->GetRoot()->GetObjectFor("Metadata")); if (pMetadata) - m_pSyntax->m_MetadataObjnum = pMetadata->GetRefObjNum(); + m_MetadataObjnum = pMetadata->GetRefObjNum(); } return SUCCESS; } @@ -327,13 +328,13 @@ CPDF_Parser::Error CPDF_Parser::SetEncryptHandler() { auto pCryptoHandler = pdfium::MakeRetain<CPDF_CryptoHandler>(); if (!pCryptoHandler->Init(m_pEncryptDict.Get(), m_pSecurityHandler.get())) return HANDLER_ERROR; - m_pSyntax->SetEncrypt(pCryptoHandler); + m_pCryptoHandler = pCryptoHandler; } return SUCCESS; } void CPDF_Parser::ReleaseEncryptHandler() { - m_pSyntax->m_pCryptoHandler.Reset(); + m_pCryptoHandler.Reset(); m_pSecurityHandler.reset(); SetEncryptDictionary(nullptr); } @@ -876,7 +877,7 @@ bool CPDF_Parser::RebuildCrossRef() { m_pSyntax->SetPos(pos + i - m_pSyntax->m_HeaderOffset); std::unique_ptr<CPDF_Object> pObj = - m_pSyntax->GetObjectBody(m_pDocument.Get(), 0, 0, false); + m_pSyntax->GetObjectBody(m_pDocument.Get()); if (pObj) { if (pObj->IsDictionary() || pObj->AsStream()) { CPDF_Stream* pStream = pObj->AsStream(); @@ -1237,7 +1238,7 @@ std::unique_ptr<CPDF_Object> CPDF_Parser::ParseIndirectObject( return nullptr; syntax.SetPos(offset + it->second); - return syntax.GetObjectBody(pObjList, 0, 0, false); + return syntax.GetObjectBody(pObjList); } RetainPtr<CPDF_StreamAcc> CPDF_Parser::GetObjectStream(uint32_t objnum) { @@ -1275,11 +1276,19 @@ std::unique_ptr<CPDF_Object> CPDF_Parser::ParseIndirectObjectAtInternal( FX_FILESIZE* pResultPos) { const FX_FILESIZE saved_pos = m_pSyntax->GetPos(); m_pSyntax->SetPos(pos); - auto result = - m_pSyntax->GetIndirectObject(pObjList, objnum, true, parse_type); + auto result = m_pSyntax->GetIndirectObject(pObjList, parse_type); + if (pResultPos) *pResultPos = m_pSyntax->GetPos(); m_pSyntax->SetPos(saved_pos); + + if (result && objnum && result->GetObjNum() != objnum) + return nullptr; + + const bool should_decrypt = m_pCryptoHandler && objnum != m_MetadataObjnum; + if (should_decrypt) + result = m_pCryptoHandler->DecryptObjectTree(std::move(result)); + return result; } @@ -1300,7 +1309,7 @@ std::unique_ptr<CPDF_Dictionary> CPDF_Parser::LoadTrailerV4() { if (m_pSyntax->GetKeyword() != "trailer") return nullptr; - return ToDictionary(m_pSyntax->GetObjectBody(m_pDocument.Get(), 0, 0, false)); + return ToDictionary(m_pSyntax->GetObjectBody(m_pDocument.Get())); } uint32_t CPDF_Parser::GetPermissions() const { @@ -1325,19 +1334,17 @@ bool CPDF_Parser::ParseLinearizedHeader() { if (!bIsNumber) return false; - uint32_t objnum = FXSYS_atoui(word.c_str()); word = m_pSyntax->GetNextWord(&bIsNumber); if (!bIsNumber) return false; - uint32_t gennum = FXSYS_atoui(word.c_str()); if (m_pSyntax->GetKeyword() != "obj") { m_pSyntax->SetPos(SavedPos); return false; } - m_pLinearized = CPDF_LinearizedHeader::CreateForObject( - m_pSyntax->GetObjectBody(nullptr, objnum, gennum, false)); + m_pLinearized = + CPDF_LinearizedHeader::CreateForObject(m_pSyntax->GetObjectBody(nullptr)); if (!m_pLinearized) return false; @@ -1421,7 +1428,7 @@ CPDF_Parser::Error CPDF_Parser::StartLinearizedParse( if (m_pSecurityHandler && m_pSecurityHandler->IsMetadataEncrypted()) { if (CPDF_Reference* pMetadata = ToReference(m_pDocument->GetRoot()->GetObjectFor("Metadata"))) - m_pSyntax->m_MetadataObjnum = pMetadata->GetRefObjNum(); + m_MetadataObjnum = pMetadata->GetRefObjNum(); } return SUCCESS; } @@ -1446,8 +1453,8 @@ bool CPDF_Parser::LoadLinearizedAllCrossRefV5(FX_FILESIZE xrefpos) { } CPDF_Parser::Error CPDF_Parser::LoadLinearizedMainXRefTable() { - uint32_t dwSaveMetadataObjnum = m_pSyntax->m_MetadataObjnum; - m_pSyntax->m_MetadataObjnum = 0; + const AutoRestorer<uint32_t> save_metadata_objnum(&m_MetadataObjnum); + m_MetadataObjnum = 0; m_pSyntax->SetPos(m_LastXRefOffset - m_pSyntax->m_HeaderOffset); uint8_t ch = 0; @@ -1474,10 +1481,8 @@ CPDF_Parser::Error CPDF_Parser::LoadLinearizedMainXRefTable() { m_dwLinearizedFirstPageXRefStartObjNum) && !LoadLinearizedAllCrossRefV5(m_LastXRefOffset)) { m_LastXRefOffset = 0; - m_pSyntax->m_MetadataObjnum = dwSaveMetadataObjnum; return FORMAT_ERROR; } - m_pSyntax->m_MetadataObjnum = dwSaveMetadataObjnum; return SUCCESS; } diff --git a/core/fpdfapi/parser/cpdf_parser.h b/core/fpdfapi/parser/cpdf_parser.h index fe3fe1084f..75d58e2e40 100644 --- a/core/fpdfapi/parser/cpdf_parser.h +++ b/core/fpdfapi/parser/cpdf_parser.h @@ -216,6 +216,9 @@ class CPDF_Parser { // All indirect object numbers that are being parsed. std::set<uint32_t> m_ParsingObjNums; + + RetainPtr<CPDF_CryptoHandler> m_pCryptoHandler; + uint32_t m_MetadataObjnum = 0; }; #endif // CORE_FPDFAPI_PARSER_CPDF_PARSER_H_ diff --git a/core/fpdfapi/parser/cpdf_syntax_parser.cpp b/core/fpdfapi/parser/cpdf_syntax_parser.cpp index ac401b351d..58cc60b85d 100644 --- a/core/fpdfapi/parser/cpdf_syntax_parser.cpp +++ b/core/fpdfapi/parser/cpdf_syntax_parser.cpp @@ -44,9 +44,7 @@ CPDF_SyntaxParser::CPDF_SyntaxParser() : CPDF_SyntaxParser(WeakPtr<ByteStringPool>()) {} CPDF_SyntaxParser::CPDF_SyntaxParser(const WeakPtr<ByteStringPool>& pPool) - : m_MetadataObjnum(0), - m_pFileAccess(nullptr), - m_pPool(pPool) {} + : m_pFileAccess(nullptr), m_pPool(pPool) {} CPDF_SyntaxParser::~CPDF_SyntaxParser() { } @@ -354,13 +352,9 @@ ByteString CPDF_SyntaxParser::GetKeyword() { } std::unique_ptr<CPDF_Object> CPDF_SyntaxParser::GetObjectBody( - CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum, - uint32_t gennum, - bool bDecrypt) { + CPDF_IndirectObjectHolder* pObjList) { const CPDF_ReadValidator::Session read_session(GetValidator().Get()); - auto result = GetObjectBodyInternal(pObjList, objnum, gennum, bDecrypt, - ParseType::kLoose); + auto result = GetObjectBodyInternal(pObjList, ParseType::kLoose); if (GetValidator()->has_read_problems()) return nullptr; return result; @@ -368,9 +362,6 @@ std::unique_ptr<CPDF_Object> CPDF_SyntaxParser::GetObjectBody( std::unique_ptr<CPDF_Object> CPDF_SyntaxParser::GetObjectBodyInternal( CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum, - uint32_t gennum, - bool bDecrypt, ParseType parse_type) { AutoRestorer<int> restorer(&s_CurrentRecursionDepth); if (++s_CurrentRecursionDepth > kParserMaxRecursionDepth) @@ -406,20 +397,16 @@ std::unique_ptr<CPDF_Object> CPDF_SyntaxParser::GetObjectBodyInternal( if (word == "(") { ByteString str = ReadString(); - if (m_pCryptoHandler && bDecrypt) - str = m_pCryptoHandler->Decrypt(objnum, gennum, str); return pdfium::MakeUnique<CPDF_String>(m_pPool, str, false); } if (word == "<") { ByteString str = ReadHexString(); - if (m_pCryptoHandler && bDecrypt) - str = m_pCryptoHandler->Decrypt(objnum, gennum, str); return pdfium::MakeUnique<CPDF_String>(m_pPool, str, true); } if (word == "[") { auto pArray = pdfium::MakeUnique<CPDF_Array>(); - while (std::unique_ptr<CPDF_Object> pObj = GetObjectBodyInternal( - pObjList, objnum, gennum, true, ParseType::kLoose)) { + while (std::unique_ptr<CPDF_Object> pObj = + GetObjectBodyInternal(pObjList, ParseType::kLoose)) { pArray->Add(std::move(pObj)); } return (parse_type == ParseType::kLoose || m_WordBuffer[0] == ']') @@ -432,7 +419,6 @@ std::unique_ptr<CPDF_Object> CPDF_SyntaxParser::GetObjectBodyInternal( PDF_NameDecode(ByteStringView(m_WordBuffer + 1, m_WordSize - 1))); } if (word == "<<") { - FX_FILESIZE dwSignValuePos = 0; std::unique_ptr<CPDF_Dictionary> pDict = pdfium::MakeUnique<CPDF_Dictionary>(m_pPool); while (1) { @@ -452,14 +438,12 @@ std::unique_ptr<CPDF_Object> CPDF_SyntaxParser::GetObjectBodyInternal( continue; key = PDF_NameDecode(key); - if (key == "/Contents") - dwSignValuePos = m_Pos; if (key.IsEmpty() && parse_type == ParseType::kLoose) continue; - std::unique_ptr<CPDF_Object> pObj = GetObjectBodyInternal( - pObjList, objnum, gennum, true, ParseType::kLoose); + std::unique_ptr<CPDF_Object> pObj = + GetObjectBodyInternal(pObjList, ParseType::kLoose); if (!pObj) { if (parse_type == ParseType::kLoose) continue; @@ -474,24 +458,13 @@ std::unique_ptr<CPDF_Object> CPDF_SyntaxParser::GetObjectBodyInternal( } } - // Only when this is a signature dictionary and has contents, we reset the - // contents to the un-decrypted form. - if (m_pCryptoHandler && bDecrypt && pDict->IsSignatureDict() && - dwSignValuePos) { - AutoRestorer<FX_FILESIZE> save_pos(&m_Pos); - m_Pos = dwSignValuePos; - pDict->SetFor("Contents", - GetObjectBodyInternal(pObjList, objnum, gennum, false, - ParseType::kLoose)); - } - FX_FILESIZE SavedPos = m_Pos; ByteString nextword = GetNextWord(nullptr); if (nextword != "stream") { m_Pos = SavedPos; return std::move(pDict); } - return ReadStream(std::move(pDict), objnum, gennum); + return ReadStream(std::move(pDict)); } if (word == ">>") m_Pos = SavedObjPos; @@ -500,13 +473,9 @@ std::unique_ptr<CPDF_Object> CPDF_SyntaxParser::GetObjectBodyInternal( } std::unique_ptr<CPDF_Object> CPDF_SyntaxParser::GetObjectBodyForStrict( - CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum, - uint32_t gennum, - bool bDecrypt) { + CPDF_IndirectObjectHolder* pObjList) { const CPDF_ReadValidator::Session read_session(GetValidator().Get()); - auto result = GetObjectBodyInternal(pObjList, objnum, gennum, bDecrypt, - ParseType::kStrict); + auto result = GetObjectBodyInternal(pObjList, ParseType::kStrict); if (GetValidator()->has_read_problems()) return nullptr; return result; @@ -514,8 +483,6 @@ std::unique_ptr<CPDF_Object> CPDF_SyntaxParser::GetObjectBodyForStrict( std::unique_ptr<CPDF_Object> CPDF_SyntaxParser::GetIndirectObject( CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum, - bool bDecrypt, ParseType parse_type) { const CPDF_ReadValidator::Session read_session(GetValidator().Get()); const FX_FILESIZE saved_pos = GetPos(); @@ -525,30 +492,24 @@ std::unique_ptr<CPDF_Object> CPDF_SyntaxParser::GetIndirectObject( SetPos(saved_pos); return nullptr; } - - uint32_t parser_objnum = FXSYS_atoui(word.c_str()); - if (objnum && parser_objnum != objnum) { - SetPos(saved_pos); - return nullptr; - } + const uint32_t parser_objnum = FXSYS_atoui(word.c_str()); word = GetNextWord(&is_number); if (!is_number || word.IsEmpty()) { SetPos(saved_pos); return nullptr; } - const uint32_t parser_gennum = FXSYS_atoui(word.c_str()); + if (GetKeyword() != "obj") { SetPos(saved_pos); return nullptr; } - std::unique_ptr<CPDF_Object> pObj = GetObjectBodyInternal( - pObjList, objnum, parser_gennum, bDecrypt, parse_type); + std::unique_ptr<CPDF_Object> pObj = + GetObjectBodyInternal(pObjList, parse_type); if (pObj) { - if (!objnum) - pObj->m_ObjNum = parser_objnum; + pObj->m_ObjNum = parser_objnum; pObj->m_GenNum = parser_gennum; } @@ -572,9 +533,7 @@ unsigned int CPDF_SyntaxParser::ReadEOLMarkers(FX_FILESIZE pos) { } std::unique_ptr<CPDF_Stream> CPDF_SyntaxParser::ReadStream( - std::unique_ptr<CPDF_Dictionary> pDict, - uint32_t objnum, - uint32_t gennum) { + std::unique_ptr<CPDF_Dictionary> pDict) { const CPDF_Number* pLenObj = ToNumber(pDict->GetDirectObjectFor("Length")); FX_FILESIZE len = pLenObj ? pLenObj->GetInteger() : -1; @@ -585,9 +544,6 @@ std::unique_ptr<CPDF_Stream> CPDF_SyntaxParser::ReadStream( const ByteStringView kEndStreamStr("endstream"); const ByteStringView kEndObjStr("endobj"); - CPDF_CryptoHandler* pCryptoHandler = - objnum == m_MetadataObjnum ? nullptr : m_pCryptoHandler.Get(); - if (!pCryptoHandler) { bool bSearchForKeyword = true; if (len >= 0) { pdfium::base::CheckedNumeric<FX_FILESIZE> pos = m_Pos; @@ -674,7 +630,7 @@ std::unique_ptr<CPDF_Stream> CPDF_SyntaxParser::ReadStream( pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(len)); } m_Pos = streamStartPos; - } + // Read up to the end of the buffer. Note, we allow zero length streams as // we need to pass them through when we are importing pages into a new // document. @@ -684,21 +640,8 @@ std::unique_ptr<CPDF_Stream> CPDF_SyntaxParser::ReadStream( std::unique_ptr<uint8_t, FxFreeDeleter> pData; if (len > 0) { - if (pCryptoHandler && pCryptoHandler->IsCipherAES() && len < 16) - return nullptr; - pData.reset(FX_Alloc(uint8_t, len)); ReadBlock(pData.get(), len); - if (pCryptoHandler) { - CFX_BinaryBuf dest_buf; - dest_buf.EstimateSize(pCryptoHandler->DecryptGetSize(len)); - - void* context = pCryptoHandler->DecryptStart(objnum, gennum); - pCryptoHandler->DecryptStream(context, pData.get(), len, dest_buf); - pCryptoHandler->DecryptFinish(context, dest_buf); - len = dest_buf.GetSize(); - pData = dest_buf.DetachBuffer(); - } } auto pStream = pdfium::MakeUnique<CPDF_Stream>(std::move(pData), len, std::move(pDict)); @@ -834,11 +777,6 @@ FX_FILESIZE CPDF_SyntaxParser::FindTag(const ByteStringView& tag, return -1; } -void CPDF_SyntaxParser::SetEncrypt( - const RetainPtr<CPDF_CryptoHandler>& pCryptoHandler) { - m_pCryptoHandler = pCryptoHandler; -} - RetainPtr<IFX_SeekableReadStream> CPDF_SyntaxParser::GetFileAccess() const { return m_pFileAccess; } diff --git a/core/fpdfapi/parser/cpdf_syntax_parser.h b/core/fpdfapi/parser/cpdf_syntax_parser.h index 2326362692..d025905858 100644 --- a/core/fpdfapi/parser/cpdf_syntax_parser.h +++ b/core/fpdfapi/parser/cpdf_syntax_parser.h @@ -40,21 +40,13 @@ class CPDF_SyntaxParser { void SetPos(FX_FILESIZE pos) { m_Pos = std::min(pos, m_FileLen); } std::unique_ptr<CPDF_Object> GetObjectBody( - CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum, - uint32_t gennum, - bool bDecrypt); + CPDF_IndirectObjectHolder* pObjList); std::unique_ptr<CPDF_Object> GetObjectBodyForStrict( - CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum, - uint32_t gennum, - bool bDecrypt); + CPDF_IndirectObjectHolder* pObjList); std::unique_ptr<CPDF_Object> GetIndirectObject( CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum, - bool bDecrypt, ParseType parse_type); ByteString GetKeyword(); @@ -62,7 +54,6 @@ class CPDF_SyntaxParser { void ToNextWord(); bool BackwardsSearchToWord(const ByteStringView& word, FX_FILESIZE limit); FX_FILESIZE FindTag(const ByteStringView& tag, FX_FILESIZE limit); - void SetEncrypt(const RetainPtr<CPDF_CryptoHandler>& pCryptoHandler); bool ReadBlock(uint8_t* pBuf, uint32_t size); bool GetCharAt(FX_FILESIZE pos, uint8_t& ch); ByteString GetNextWord(bool* bIsNumber); @@ -96,27 +87,20 @@ class CPDF_SyntaxParser { ByteString ReadHexString(); unsigned int ReadEOLMarkers(FX_FILESIZE pos); std::unique_ptr<CPDF_Stream> ReadStream( - std::unique_ptr<CPDF_Dictionary> pDict, - uint32_t objnum, - uint32_t gennum); + std::unique_ptr<CPDF_Dictionary> pDict); bool IsPositionRead(FX_FILESIZE pos) const; std::unique_ptr<CPDF_Object> GetObjectBodyInternal( CPDF_IndirectObjectHolder* pObjList, - uint32_t objnum, - uint32_t gennum, - bool bDecrypt, ParseType parse_type); FX_FILESIZE m_Pos; - uint32_t m_MetadataObjnum; RetainPtr<CPDF_ReadValidator> m_pFileAccess; FX_FILESIZE m_HeaderOffset; FX_FILESIZE m_FileLen; std::vector<uint8_t> m_pFileBuf; FX_FILESIZE m_BufOffset; - RetainPtr<CPDF_CryptoHandler> m_pCryptoHandler; uint8_t m_WordBuffer[257]; uint32_t m_WordSize; WeakPtr<ByteStringPool> m_pPool; diff --git a/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp b/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp index af559c5ba6..cb065eb4e2 100644 --- a/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp @@ -151,8 +151,7 @@ TEST(cpdf_syntax_parser, GetInvalidReference) { // Data with a reference with number CPDF_Object::kInvalidObjNum uint8_t data[] = "4294967295 0 R"; parser.InitParser(pdfium::MakeRetain<CFX_MemoryStream>(data, 14, false), 0); - std::unique_ptr<CPDF_Object> ref = - parser.GetObjectBody(nullptr, CPDF_Object::kInvalidObjNum, 0, false); + std::unique_ptr<CPDF_Object> ref = parser.GetObjectBody(nullptr); EXPECT_FALSE(ref); } |