mirror of https://github.com/JakubMelka/PDF4QT.git
Public key encryption: fixing bugs
This commit is contained in:
parent
44fc1e021c
commit
08697b902a
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue