mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-01-01 02:58:08 +01:00
ETSI RFC 3161 certificate verification, minor bugfixing
This commit is contained in:
parent
8954f6410c
commit
a7ab92450a
@ -164,6 +164,10 @@ PDFSignatureHandler* PDFSignatureHandler::createHandler(const PDFFormFieldSignat
|
|||||||
{
|
{
|
||||||
return new PDFSignatureHandler_ETSI_CAdES_detached(signatureField, sourceData, parameters);
|
return new PDFSignatureHandler_ETSI_CAdES_detached(signatureField, sourceData, parameters);
|
||||||
}
|
}
|
||||||
|
else if (subfilter == "ETSI.RFC3161")
|
||||||
|
{
|
||||||
|
return new PDFSignatureHandler_ETSI_RFC3161(signatureField, sourceData, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -709,16 +713,26 @@ PDFSignatureVerificationResult PDFSignatureHandler_ETSI_CAdES_detached::verify()
|
|||||||
{
|
{
|
||||||
PDFSignatureVerificationResult result;
|
PDFSignatureVerificationResult result;
|
||||||
initializeResult(result);
|
initializeResult(result);
|
||||||
verifyCertificateCAdES(result);
|
verifyCertificateCAdES(result, X509_PURPOSE_SMIME_SIGN);
|
||||||
|
verifySignature(result);
|
||||||
|
result.validate();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFSignatureVerificationResult PDFSignatureHandler_ETSI_RFC3161::verify() const
|
||||||
|
{
|
||||||
|
PDFSignatureVerificationResult result;
|
||||||
|
initializeResult(result);
|
||||||
|
verifyCertificateCAdES(result, X509_PURPOSE_TIMESTAMP_SIGN);
|
||||||
verifySignature(result);
|
verifySignature(result);
|
||||||
result.validate();
|
result.validate();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is protected by global mutex, but it is ugly
|
// This is protected by global mutex, but it is ugly
|
||||||
static PDFSignatureVerificationResult* s_ETSI_CAdES_detached_currentResult = nullptr;
|
static PDFSignatureVerificationResult* s_ETSI_currentResult = nullptr;
|
||||||
|
|
||||||
int PDFSignatureHandler_ETSI_CAdES_detached::verifyCallback(int ok, X509_STORE_CTX* context)
|
int PDFSignatureHandler_ETSI_base::verifyCallback(int ok, X509_STORE_CTX* context)
|
||||||
{
|
{
|
||||||
const int errorCode = X509_STORE_CTX_get_error(context);
|
const int errorCode = X509_STORE_CTX_get_error(context);
|
||||||
|
|
||||||
@ -728,7 +742,7 @@ int PDFSignatureHandler_ETSI_CAdES_detached::verifyCallback(int ok, X509_STORE_C
|
|||||||
case X509_V_ERR_CRL_HAS_EXPIRED:
|
case X509_V_ERR_CRL_HAS_EXPIRED:
|
||||||
{
|
{
|
||||||
// We will treat this as only warning
|
// We will treat this as only warning
|
||||||
s_ETSI_CAdES_detached_currentResult->addCertificateCRLValidityTimeExpiredWarning();
|
s_ETSI_currentResult->addCertificateCRLValidityTimeExpiredWarning();
|
||||||
X509_STORE_CTX_set_error(context, X509_V_OK);
|
X509_STORE_CTX_set_error(context, X509_V_OK);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -761,7 +775,7 @@ int PDFSignatureHandler_ETSI_CAdES_detached::verifyCallback(int ok, X509_STORE_C
|
|||||||
case NID_qcStatements:
|
case NID_qcStatements:
|
||||||
{
|
{
|
||||||
// We will treat this as only warning
|
// We will treat this as only warning
|
||||||
s_ETSI_CAdES_detached_currentResult->addCertificateQualifiedStatementNotVerifiedWarning();
|
s_ETSI_currentResult->addCertificateQualifiedStatementNotVerifiedWarning();
|
||||||
X509_STORE_CTX_set_error(context, X509_V_OK);
|
X509_STORE_CTX_set_error(context, X509_V_OK);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -782,11 +796,11 @@ int PDFSignatureHandler_ETSI_CAdES_detached::verifyCallback(int ok, X509_STORE_C
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFSignatureHandler_ETSI_CAdES_detached::verifyCertificateCAdES(PDFSignatureVerificationResult& result) const
|
void PDFSignatureHandler_ETSI_base::verifyCertificateCAdES(PDFSignatureVerificationResult& result, int purpose) const
|
||||||
{
|
{
|
||||||
PDFOpenSSLGlobalLock lock;
|
PDFOpenSSLGlobalLock lock;
|
||||||
|
|
||||||
s_ETSI_CAdES_detached_currentResult = &result;
|
s_ETSI_currentResult = &result;
|
||||||
|
|
||||||
OpenSSL_add_all_algorithms();
|
OpenSSL_add_all_algorithms();
|
||||||
|
|
||||||
@ -868,7 +882,7 @@ void PDFSignatureHandler_ETSI_CAdES_detached::verifyCertificateCAdES(PDFSignatur
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!X509_STORE_CTX_set_purpose(context, X509_PURPOSE_SMIME_SIGN))
|
if (!X509_STORE_CTX_set_purpose(context, purpose))
|
||||||
{
|
{
|
||||||
result.addCertificateGenericError();
|
result.addCertificateGenericError();
|
||||||
break;
|
break;
|
||||||
@ -1378,7 +1392,7 @@ PDFCertificateInfo PDFPublicKeySignatureHandler::getCertificateInfo(X509* certif
|
|||||||
const int bits = EVP_PKEY_bits(evpKey);
|
const int bits = EVP_PKEY_bits(evpKey);
|
||||||
info.setKeySize(bits);
|
info.setKeySize(bits);
|
||||||
|
|
||||||
const uint32_t keyUsage = X509_get_key_usage(certificate);
|
uint32_t keyUsage = X509_get_key_usage(certificate);
|
||||||
if (keyUsage != UINT32_MAX)
|
if (keyUsage != UINT32_MAX)
|
||||||
{
|
{
|
||||||
static_assert(PDFCertificateInfo::KeyUsageDigitalSignature == KU_DIGITAL_SIGNATURE, "Fix this code!");
|
static_assert(PDFCertificateInfo::KeyUsageDigitalSignature == KU_DIGITAL_SIGNATURE, "Fix this code!");
|
||||||
@ -1391,6 +1405,24 @@ PDFCertificateInfo PDFPublicKeySignatureHandler::getCertificateInfo(X509* certif
|
|||||||
static_assert(PDFCertificateInfo::KeyUsageEncipherOnly == KU_ENCIPHER_ONLY, "Fix this code!");
|
static_assert(PDFCertificateInfo::KeyUsageEncipherOnly == KU_ENCIPHER_ONLY, "Fix this code!");
|
||||||
static_assert(PDFCertificateInfo::KeyUsageDecipherOnly == KU_DECIPHER_ONLY, "Fix this code!");
|
static_assert(PDFCertificateInfo::KeyUsageDecipherOnly == KU_DECIPHER_ONLY, "Fix this code!");
|
||||||
|
|
||||||
|
if (X509_get_extension_flags(certificate) & EXFLAG_XKUSAGE)
|
||||||
|
{
|
||||||
|
const uint32_t extendedKeyUsage = X509_get_extended_key_usage(certificate);
|
||||||
|
Q_ASSERT(extendedKeyUsage != UINT32_MAX);
|
||||||
|
|
||||||
|
static_assert(PDFCertificateInfo::KeyUsageExtended_SSL_SERVER >> 16 == XKU_SSL_SERVER, "Fix this code!");
|
||||||
|
static_assert(PDFCertificateInfo::KeyUsageExtended_SSL_CLIENT >> 16 == XKU_SSL_CLIENT, "Fix this code!");
|
||||||
|
static_assert(PDFCertificateInfo::KeyUsageExtended_SMIME >> 16 == XKU_SMIME, "Fix this code!");
|
||||||
|
static_assert(PDFCertificateInfo::KeyUsageExtended_CODE_SIGN >> 16 == XKU_CODE_SIGN, "Fix this code!");
|
||||||
|
static_assert(PDFCertificateInfo::KeyUsageExtended_SGC >> 16 == XKU_SGC, "Fix this code!");
|
||||||
|
static_assert(PDFCertificateInfo::KeyUsageExtended_OCSP_SIGN >> 16 == XKU_OCSP_SIGN, "Fix this code!");
|
||||||
|
static_assert(PDFCertificateInfo::KeyUsageExtended_TIMESTAMP >> 16 == XKU_TIMESTAMP, "Fix this code!");
|
||||||
|
static_assert(PDFCertificateInfo::KeyUsageExtended_DVCS >> 16 == XKU_DVCS, "Fix this code!");
|
||||||
|
static_assert(PDFCertificateInfo::KeyUsageExtended_ANYEKU >> 16 == XKU_ANYEKU, "Fix this code!");
|
||||||
|
|
||||||
|
keyUsage = keyUsage | (extendedKeyUsage << 16);
|
||||||
|
}
|
||||||
|
|
||||||
info.setKeyUsage(static_cast<PDFCertificateInfo::KeyUsageFlags>(keyUsage));
|
info.setKeyUsage(static_cast<PDFCertificateInfo::KeyUsageFlags>(keyUsage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,19 +198,30 @@ public:
|
|||||||
KeyUnknown
|
KeyUnknown
|
||||||
};
|
};
|
||||||
|
|
||||||
// This enum is defined in RFC 5280, chapter 4.2.1.3, Key Usage
|
// This enum is defined in RFC 5280, chapter 4.2.1.3, Key Usage. Second part,
|
||||||
|
// are defined in extended key usage entry, if it is defined.
|
||||||
enum KeyUsageFlag : uint32_t
|
enum KeyUsageFlag : uint32_t
|
||||||
{
|
{
|
||||||
KeyUsageNone = 0x0000,
|
KeyUsageNone = 0x00000000,
|
||||||
KeyUsageDigitalSignature = 0x0080,
|
KeyUsageDigitalSignature = 0x00000080,
|
||||||
KeyUsageNonRepudiation = 0x0040,
|
KeyUsageNonRepudiation = 0x00000040,
|
||||||
KeyUsageKeyEncipherment = 0x0020,
|
KeyUsageKeyEncipherment = 0x00000020,
|
||||||
KeyUsageDataEncipherment = 0x0010,
|
KeyUsageDataEncipherment = 0x00000010,
|
||||||
KeyUsageAgreement = 0x0008,
|
KeyUsageAgreement = 0x00000008,
|
||||||
KeyUsageCertSign = 0x0004,
|
KeyUsageCertSign = 0x00000004,
|
||||||
KeyUsageCrlSign = 0x0002,
|
KeyUsageCrlSign = 0x00000002,
|
||||||
KeyUsageEncipherOnly = 0x0001,
|
KeyUsageEncipherOnly = 0x00000001,
|
||||||
KeyUsageDecipherOnly = 0x8000,
|
KeyUsageDecipherOnly = 0x00008000,
|
||||||
|
|
||||||
|
KeyUsageExtended_SSL_SERVER = 0x1 << 16,
|
||||||
|
KeyUsageExtended_SSL_CLIENT = 0x2 << 16,
|
||||||
|
KeyUsageExtended_SMIME = 0x4 << 16,
|
||||||
|
KeyUsageExtended_CODE_SIGN = 0x8 << 16,
|
||||||
|
KeyUsageExtended_SGC = 0x10 << 16,
|
||||||
|
KeyUsageExtended_OCSP_SIGN = 0x20 << 16,
|
||||||
|
KeyUsageExtended_TIMESTAMP = 0x40 << 16,
|
||||||
|
KeyUsageExtended_DVCS = 0x80 << 16,
|
||||||
|
KeyUsageExtended_ANYEKU = 0x100 << 16,
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(KeyUsageFlags, KeyUsageFlag)
|
Q_DECLARE_FLAGS(KeyUsageFlags, KeyUsageFlag)
|
||||||
|
|
||||||
|
@ -116,22 +116,44 @@ protected:
|
|||||||
virtual BIO* getSignedDataBuffer(PDFSignatureVerificationResult& result, QByteArray& outputBuffer) const override;
|
virtual BIO* getSignedDataBuffer(PDFSignatureVerificationResult& result, QByteArray& outputBuffer) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PDFSignatureHandler_ETSI_CAdES_detached : public PDFPublicKeySignatureHandler
|
class PDFSignatureHandler_ETSI_base : public PDFPublicKeySignatureHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit PDFSignatureHandler_ETSI_CAdES_detached(const PDFFormFieldSignature* signatureField, const QByteArray& sourceData, const Parameters& parameters) :
|
explicit PDFSignatureHandler_ETSI_base(const PDFFormFieldSignature* signatureField, const QByteArray& sourceData, const Parameters& parameters) :
|
||||||
PDFPublicKeySignatureHandler(signatureField, sourceData, parameters)
|
PDFPublicKeySignatureHandler(signatureField, sourceData, parameters)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual PDFSignatureVerificationResult verify() const override;
|
protected:
|
||||||
|
void verifyCertificateCAdES(PDFSignatureVerificationResult& result, int purpose) const;
|
||||||
private:
|
|
||||||
void verifyCertificateCAdES(PDFSignatureVerificationResult& result) const;
|
|
||||||
static int verifyCallback(int ok, X509_STORE_CTX* context);
|
static int verifyCallback(int ok, X509_STORE_CTX* context);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PDFSignatureHandler_ETSI_CAdES_detached : public PDFSignatureHandler_ETSI_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFSignatureHandler_ETSI_CAdES_detached(const PDFFormFieldSignature* signatureField, const QByteArray& sourceData, const Parameters& parameters) :
|
||||||
|
PDFSignatureHandler_ETSI_base(signatureField, sourceData, parameters)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual PDFSignatureVerificationResult verify() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDFSignatureHandler_ETSI_RFC3161: public PDFSignatureHandler_ETSI_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFSignatureHandler_ETSI_RFC3161(const PDFFormFieldSignature* signatureField, const QByteArray& sourceData, const Parameters& parameters) :
|
||||||
|
PDFSignatureHandler_ETSI_base(signatureField, sourceData, parameters)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual PDFSignatureVerificationResult verify() const override;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
#endif // PDFSIGNATUREHANDLER_IMPL_H
|
#endif // PDFSIGNATUREHANDLER_IMPL_H
|
||||||
|
@ -138,6 +138,7 @@ void PDFSidebarWidget::setDocument(const pdf::PDFModifiedDocument& document, con
|
|||||||
{
|
{
|
||||||
m_document = document;
|
m_document = document;
|
||||||
m_optionalContentActivity = document.getOptionalContentActivity();
|
m_optionalContentActivity = document.getOptionalContentActivity();
|
||||||
|
m_signatures = signatures;
|
||||||
|
|
||||||
// Update outline
|
// Update outline
|
||||||
m_outlineTreeModel->setDocument(document);
|
m_outlineTreeModel->setDocument(document);
|
||||||
@ -248,7 +249,7 @@ bool PDFSidebarWidget::isEmpty(Page page) const
|
|||||||
return !m_textToSpeech->isValid();
|
return !m_textToSpeech->isValid();
|
||||||
|
|
||||||
case Signatures:
|
case Signatures:
|
||||||
return !m_signatures.empty();
|
return m_signatures.empty();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Q_ASSERT(false);
|
Q_ASSERT(false);
|
||||||
@ -534,6 +535,10 @@ void PDFSidebarWidget::updateSignatures(const std::vector<pdf::PDFSignatureVerif
|
|||||||
{
|
{
|
||||||
keyUsages << tr("Decipher data during key agreement");
|
keyUsages << tr("Decipher data during key agreement");
|
||||||
}
|
}
|
||||||
|
if (keyUsageFlags.testFlag(pdf::PDFCertificateInfo::KeyUsageExtended_TIMESTAMP))
|
||||||
|
{
|
||||||
|
keyUsages << tr("Trusted timestamping");
|
||||||
|
}
|
||||||
|
|
||||||
if (!keyUsages.isEmpty())
|
if (!keyUsages.isEmpty())
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user