mirror of
				https://github.com/JakubMelka/PDF4QT.git
				synced 2025-06-05 21:59:17 +02:00 
			
		
		
		
	Public key encryption: fixing bugs
This commit is contained in:
		| @@ -460,6 +460,22 @@ PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObj | |||||||
|                     typedHandler->m_filterDefault = it->second; |                     typedHandler->m_filterDefault = it->second; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             QString name = parseName(dictionary, "SubFilter", true, nullptr); | ||||||
|  |             if (name == "adbe.pkcs7.s3") | ||||||
|  |             { | ||||||
|  |                 typedHandler->m_pkcs7Type = PDFPublicKeySecurityHandler::PKCS7_Type::PKCS7_S3; | ||||||
|  |             } | ||||||
|  |             if (name == "adbe.pkcs7.s4") | ||||||
|  |             { | ||||||
|  |                 typedHandler->m_pkcs7Type = PDFPublicKeySecurityHandler::PKCS7_Type::PKCS7_S4; | ||||||
|  |             } | ||||||
|  |             if (name == "adbe.pkcs7.s5") | ||||||
|  |             { | ||||||
|  |                 typedHandler->m_pkcs7Type = PDFPublicKeySecurityHandler::PKCS7_Type::PKCS7_S5; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             typedHandler->m_permissions = static_cast<uint32_t>(static_cast<int>(parseInt(dictionary, "P", false, 0))); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -619,6 +635,22 @@ QByteArray PDFSecurityHandler::parseName(const PDFDictionary* dictionary, const | |||||||
|     return nameObject.getString(); |     return nameObject.getString(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool PDFSecurityHandler::parseBool(const PDFDictionary* dictionary, const char* key, bool required, bool defaultValue) | ||||||
|  | { | ||||||
|  |     const PDFObject& intObject = dictionary->get(key); | ||||||
|  |     if (!intObject.isBool()) | ||||||
|  |     { | ||||||
|  |         if (required) | ||||||
|  |         { | ||||||
|  |             throw PDFException(PDFTranslationContext::tr("Invalid value for entry '%1' in encryption dictionary. Boolean expected.").arg(QString::fromLatin1(key))); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return defaultValue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return intObject.getBool(); | ||||||
|  | } | ||||||
|  |  | ||||||
| PDFInteger PDFSecurityHandler::parseInt(const PDFDictionary* dictionary, const char* key, bool required, PDFInteger defaultValue) | PDFInteger PDFSecurityHandler::parseInt(const PDFDictionary* dictionary, const char* key, bool required, PDFInteger defaultValue) | ||||||
| { | { | ||||||
|     const PDFObject& intObject = dictionary->get(key); |     const PDFObject& intObject = dictionary->get(key); | ||||||
| @@ -686,6 +718,9 @@ CryptFilter PDFSecurityHandler::parseCryptFilter(PDFInteger length, const PDFObj | |||||||
|     // Recipients |     // Recipients | ||||||
|     filter.recipients = parseRecipients(cryptFilterDictionary); |     filter.recipients = parseRecipients(cryptFilterDictionary); | ||||||
|  |  | ||||||
|  |     // Encrypt metadata | ||||||
|  |     filter.encryptMetadata = parseBool(cryptFilterDictionary, "EncryptMetadata", false, true); | ||||||
|  |  | ||||||
|     return filter; |     return filter; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1310,7 +1345,7 @@ PDFSecurityHandler::AuthorizationResult PDFStandardSecurityHandler::authenticate | |||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     // 2) Verify, that bytes 0-3 are valid permissions entry |                     // 2) Verify, that bytes 0-3 are valid permissions entry | ||||||
|                     const uint32_t permissions = qFromLittleEndian(*reinterpret_cast<const uint32_t*>(decodedPerms.data())); |                     const uint32_t permissions = qFromLittleEndian<uint32_t>(decodedPerms.data()); | ||||||
|                     if (permissions != m_permissions) |                     if (permissions != m_permissions) | ||||||
|                     { |                     { | ||||||
|                         throw PDFException(PDFTranslationContext::tr("Security permissions are manipulated. Can't open the document.")); |                         throw PDFException(PDFTranslationContext::tr("Security permissions are manipulated. Can't open the document.")); | ||||||
| @@ -2282,6 +2317,12 @@ PDFSecurityHandler::AuthorizationResult PDFPublicKeySecurityHandler::authenticat | |||||||
|                             EVP_DigestFinal_ex(context, convertByteArrayToUcharPtr(digestBuffer), &size); |                             EVP_DigestFinal_ex(context, convertByteArrayToUcharPtr(digestBuffer), &size); | ||||||
|                             EVP_MD_CTX_free(context); |                             EVP_MD_CTX_free(context); | ||||||
|  |  | ||||||
|  |                             if (decryptedData.size() == 20 + sizeof(uint32_t)) | ||||||
|  |                             { | ||||||
|  |                                 // We shall set permissions | ||||||
|  |                                 m_permissions = qFromLittleEndian<uint32_t>(decryptedData.data() + 20); | ||||||
|  |                             } | ||||||
|  |  | ||||||
|                             m_authorizationData.fileEncryptionKey = digestBuffer.left(m_keyLength / 8); |                             m_authorizationData.fileEncryptionKey = digestBuffer.left(m_keyLength / 8); | ||||||
|                             m_authorizationData.authorizationResult = AuthorizationResult::UserAuthorized; |                             m_authorizationData.authorizationResult = AuthorizationResult::UserAuthorized; | ||||||
|                             return AuthorizationResult::UserAuthorized; |                             return AuthorizationResult::UserAuthorized; | ||||||
| @@ -2299,11 +2340,64 @@ PDFSecurityHandler::AuthorizationResult PDFPublicKeySecurityHandler::authenticat | |||||||
|  |  | ||||||
| bool PDFPublicKeySecurityHandler::isMetadataEncrypted() const | bool PDFPublicKeySecurityHandler::isMetadataEncrypted() const | ||||||
| { | { | ||||||
|     return true; |     return m_filterDefault.encryptMetadata; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool PDFPublicKeySecurityHandler::isAllowed(Permission permission) const | bool PDFPublicKeySecurityHandler::isAllowed(Permission permission) const | ||||||
| { | { | ||||||
|  |     if (m_pkcs7Type == PKCS7_Type::PKCS7_S3) | ||||||
|  |     { | ||||||
|  |         // Jakub Melka: for S3, default standard permissions applies | ||||||
|  |         return m_permissions & static_cast<uint32_t>(permission); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     enum PermissionFlag : uint32_t | ||||||
|  |     { | ||||||
|  |         PKSH_Owner = 1 << 1, | ||||||
|  |         PKSH_PrintLowResolution = 1 << 2, | ||||||
|  |         PKSH_Modify = 1 << 3, | ||||||
|  |         PKSH_CopyContent = 1 << 4, | ||||||
|  |         PKSH_ModifyAnnotationsFillFormFields = 1 << 5, | ||||||
|  |         PKSH_FillFormFields = 1 << 8, | ||||||
|  |         PKSH_Assemble = 1 << 10, | ||||||
|  |         PKSH_PrintHighResolution = 1 << 11 | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     if (m_permissions & PKSH_Owner) | ||||||
|  |     { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     switch (permission) | ||||||
|  |     { | ||||||
|  |         case Permission::PrintLowResolution: | ||||||
|  |             return m_permissions & PKSH_PrintLowResolution; | ||||||
|  |  | ||||||
|  |         case Permission::Modify: | ||||||
|  |             return m_permissions & PKSH_Modify; | ||||||
|  |  | ||||||
|  |         case Permission::CopyContent: | ||||||
|  |             return m_permissions & PKSH_CopyContent; | ||||||
|  |  | ||||||
|  |         case Permission::ModifyInteractiveItems: | ||||||
|  |             return m_permissions & PKSH_ModifyAnnotationsFillFormFields; | ||||||
|  |  | ||||||
|  |         case Permission::ModifyFormFields: | ||||||
|  |             return m_permissions & PKSH_FillFormFields; | ||||||
|  |  | ||||||
|  |         case Permission::Accessibility: | ||||||
|  |             return m_permissions & PKSH_CopyContent; | ||||||
|  |  | ||||||
|  |         case Permission::Assemble: | ||||||
|  |             return m_permissions & PKSH_Assemble; | ||||||
|  |  | ||||||
|  |         case Permission::PrintHighResolution: | ||||||
|  |             return m_permissions & PKSH_PrintHighResolution; | ||||||
|  |  | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -70,6 +70,7 @@ struct CryptFilter | |||||||
|     AuthEvent authEvent = AuthEvent::DocOpen; |     AuthEvent authEvent = AuthEvent::DocOpen; | ||||||
|     int keyLength = 0; ///< Key length in bytes |     int keyLength = 0; ///< Key length in bytes | ||||||
|     QByteArrayList recipients; ///< Recipients for public key security handler |     QByteArrayList recipients; ///< Recipients for public key security handler | ||||||
|  |     bool encryptMetadata = true; ///< Encrypt metadata (for public key encryption) | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class PDFSecurityHandler; | class PDFSecurityHandler; | ||||||
| @@ -200,6 +201,7 @@ public: | |||||||
|     static PDFSecurityHandlerPointer createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id); |     static PDFSecurityHandlerPointer createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id); | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|  |     static bool parseBool(const PDFDictionary* dictionary, const char* key, bool required, bool defaultValue = true); | ||||||
|     static QByteArray parseName(const PDFDictionary* dictionary, const char* key, bool required, const char* defaultValue = nullptr); |     static QByteArray parseName(const PDFDictionary* dictionary, const char* key, bool required, const char* defaultValue = nullptr); | ||||||
|     static PDFInteger parseInt(const PDFDictionary* dictionary, const char* key, bool required, PDFInteger defaultValue = -1); |     static PDFInteger parseInt(const PDFDictionary* dictionary, const char* key, bool required, PDFInteger defaultValue = -1); | ||||||
|     static CryptFilter parseCryptFilter(PDFInteger length, const PDFObject& object); |     static CryptFilter parseCryptFilter(PDFInteger length, const PDFObject& object); | ||||||
| @@ -406,6 +408,24 @@ public: | |||||||
|     virtual bool isMetadataEncrypted() const override; |     virtual bool isMetadataEncrypted() const override; | ||||||
|     virtual bool isAllowed(Permission permission) const override; |     virtual bool isAllowed(Permission permission) const override; | ||||||
|     virtual PDFObject createEncryptionDictionaryObject() const override; |     virtual PDFObject createEncryptionDictionaryObject() const override; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     friend class PDFSecurityHandler; | ||||||
|  |     friend class PDFSecurityHandlerFactory; | ||||||
|  |  | ||||||
|  |     enum class PKCS7_Type | ||||||
|  |     { | ||||||
|  |         Unknown, | ||||||
|  |         PKCS7_S3, | ||||||
|  |         PKCS7_S4, | ||||||
|  |         PKCS7_S5 | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /// What operations shall be permitted, when document is opened with user access. | ||||||
|  |     uint32_t m_permissions = 0; | ||||||
|  |  | ||||||
|  |     /// Type of the PKCS7 subfilter | ||||||
|  |     PKCS7_Type m_pkcs7Type = PKCS7_Type::Unknown; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /// Factory, which creates security handler based on settings. | /// Factory, which creates security handler based on settings. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user