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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -619,6 +635,22 @@ QByteArray PDFSecurityHandler::parseName(const PDFDictionary* dictionary, const
|
|||
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)
|
||||
{
|
||||
const PDFObject& intObject = dictionary->get(key);
|
||||
|
@ -686,6 +718,9 @@ CryptFilter PDFSecurityHandler::parseCryptFilter(PDFInteger length, const PDFObj
|
|||
// Recipients
|
||||
filter.recipients = parseRecipients(cryptFilterDictionary);
|
||||
|
||||
// Encrypt metadata
|
||||
filter.encryptMetadata = parseBool(cryptFilterDictionary, "EncryptMetadata", false, true);
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
@ -1310,7 +1345,7 @@ PDFSecurityHandler::AuthorizationResult PDFStandardSecurityHandler::authenticate
|
|||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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_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.authorizationResult = AuthorizationResult::UserAuthorized;
|
||||
return AuthorizationResult::UserAuthorized;
|
||||
|
@ -2299,11 +2340,64 @@ PDFSecurityHandler::AuthorizationResult PDFPublicKeySecurityHandler::authenticat
|
|||
|
||||
bool PDFPublicKeySecurityHandler::isMetadataEncrypted() const
|
||||
{
|
||||
return true;
|
||||
return m_filterDefault.encryptMetadata;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ struct CryptFilter
|
|||
AuthEvent authEvent = AuthEvent::DocOpen;
|
||||
int keyLength = 0; ///< Key length in bytes
|
||||
QByteArrayList recipients; ///< Recipients for public key security handler
|
||||
bool encryptMetadata = true; ///< Encrypt metadata (for public key encryption)
|
||||
};
|
||||
|
||||
class PDFSecurityHandler;
|
||||
|
@ -200,6 +201,7 @@ public:
|
|||
static PDFSecurityHandlerPointer createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id);
|
||||
|
||||
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 PDFInteger parseInt(const PDFDictionary* dictionary, const char* key, bool required, PDFInteger defaultValue = -1);
|
||||
static CryptFilter parseCryptFilter(PDFInteger length, const PDFObject& object);
|
||||
|
@ -406,6 +408,24 @@ public:
|
|||
virtual bool isMetadataEncrypted() const override;
|
||||
virtual bool isAllowed(Permission permission) 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.
|
||||
|
|
Loading…
Reference in New Issue