ETSI RFC 3161 certificate verification, minor bugfixing

This commit is contained in:
Jakub Melka 2020-07-06 16:31:41 +02:00
parent 8954f6410c
commit a7ab92450a
4 changed files with 97 additions and 27 deletions

View File

@ -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));
} }

View File

@ -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)

View File

@ -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

View File

@ -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())
{ {