From 5eb74724731ab4a345b3947c5e523dfd79fb966d Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Mon, 28 Sep 2020 14:41:42 +0200 Subject: [PATCH] Signature hash/signing time update --- PdfForQtLib/sources/pdfsignaturehandler.cpp | 117 ++++++++++++++++-- PdfForQtLib/sources/pdfsignaturehandler.h | 12 ++ .../sources/pdfsignaturehandler_impl.h | 14 +++ PdfForQtViewer/pdfsidebarwidget.cpp | 21 +++- 4 files changed, 154 insertions(+), 10 deletions(-) diff --git a/PdfForQtLib/sources/pdfsignaturehandler.cpp b/PdfForQtLib/sources/pdfsignaturehandler.cpp index f48a61e..deeb038 100644 --- a/PdfForQtLib/sources/pdfsignaturehandler.cpp +++ b/PdfForQtLib/sources/pdfsignaturehandler.cpp @@ -369,6 +369,36 @@ void PDFSignatureVerificationResult::validate() } } +QDateTime PDFSignatureVerificationResult::getSignatureDate() const +{ + return m_signatureDate; +} + +void PDFSignatureVerificationResult::setSignatureDate(const QDateTime& signatureDate) +{ + m_signatureDate = signatureDate; +} + +QDateTime PDFSignatureVerificationResult::getTimestampDate() const +{ + return m_timestampDate; +} + +void PDFSignatureVerificationResult::setTimestampDate(const QDateTime& timestampDate) +{ + m_timestampDate = timestampDate; +} + +QByteArray PDFSignatureVerificationResult::getSignatureFilter() const +{ + return m_signatureFilter; +} + +void PDFSignatureVerificationResult::setSignatureFilter(const QByteArray& signatureFilter) +{ + m_signatureFilter = signatureFilter; +} + PDFSignature::Type PDFSignatureVerificationResult::getType() const { return m_type; @@ -386,6 +416,7 @@ void PDFPublicKeySignatureHandler::initializeResult(PDFSignatureVerificationResu result.setType(m_signatureField->getSignature().getType()); result.setSignatureFieldReference(signatureFieldReference); result.setSignatureFieldQualifiedName(signatureFieldQualifiedName); + result.setSignatureFilter(m_signatureField->getSignature().getFilter()); } STACK_OF(X509)* PDFPublicKeySignatureHandler::getCertificates(PKCS7* pkcs7) @@ -652,6 +683,8 @@ void PDFPublicKeySignatureHandler::verifySignature(PDFSignatureVerificationResul } while (bytesRead > 0); STACK_OF(PKCS7_SIGNER_INFO)* signerInfo = PKCS7_get_signer_info(pkcs7); + addHashAlgorithmFromSignerInfoStack(signerInfo, result); + addSignatureDateFromSignerInfoStack(signerInfo, result); const int signerInfoCount = sk_PKCS7_SIGNER_INFO_num(signerInfo); STACK_OF(X509)* certificates = getCertificates(pkcs7); if (signerInfo && signerInfoCount > 0 && certificates) @@ -668,13 +701,6 @@ void PDFPublicKeySignatureHandler::verifySignature(PDFSignatureVerificationResul break; } - if (signerInfoValue->digest_alg && signerInfoValue->digest_alg->algorithm) - { - std::array buffer = { }; - OBJ_obj2txt(buffer.data(), int(buffer.size() - 1), signerInfoValue->digest_alg->algorithm, 0); - result.addHashAlgorithm(QString::fromLatin1(buffer.data())); - } - const int verification = PKCS7_signatureVerify(dataBio, pkcs7, signerInfoValue, signer); if (verification <= 0) { @@ -815,6 +841,18 @@ void PDFSignatureHandler_ETSI_RFC3161::verifySignatureTimestamp(PDFSignatureVeri TS_VERIFY_CTX_set_store(ts_context, store); TS_VERIFY_CTS_set_certs(ts_context, usedCertificates); + // Get timestamp and hash algorithm + if (TS_TST_INFO* info = PKCS7_to_TS_TST_INFO(pkcs7)) + { + // Date/time of timestamp + const ASN1_GENERALIZEDTIME* time = TS_TST_INFO_get_time(info); + result.setTimestampDate(getDateTimeFromASN(time)); + } + + STACK_OF(PKCS7_SIGNER_INFO)* signerInfos = PKCS7_get_signer_info(pkcs7); + addHashAlgorithmFromSignerInfoStack(signerInfos, result); + addSignatureDateFromSignerInfoStack(signerInfos, result); + const int verifyValue = TS_RESP_verify_token(ts_context, pkcs7); if (verifyValue <= 0) { @@ -1740,6 +1778,71 @@ QDateTime PDFPublicKeySignatureHandler::getDateTimeFromASN(const ASN1_TIME* time return result; } +void PDFPublicKeySignatureHandler::addHashAlgorithmFromSignerInfoStack(STACK_OF(PKCS7_SIGNER_INFO)* signerInfoStack, PDFSignatureVerificationResult& result) +{ + if (!signerInfoStack) + { + // No signature info provided + return; + } + + const int count = sk_PKCS7_SIGNER_INFO_num(signerInfoStack); + for (int i = 0; i < count; ++i) + { + PKCS7_SIGNER_INFO* signerInfoValue = sk_PKCS7_SIGNER_INFO_value(signerInfoStack, i); + if (signerInfoValue && signerInfoValue->digest_alg && signerInfoValue->digest_alg->algorithm) + { + std::array buffer = { }; + OBJ_obj2txt(buffer.data(), int(buffer.size() - 1), signerInfoValue->digest_alg->algorithm, 0); + result.addHashAlgorithm(QString::fromLatin1(buffer.data())); + } + } +} + +void PDFPublicKeySignatureHandler::addSignatureDateFromSignerInfoStack(STACK_OF(PKCS7_SIGNER_INFO)* signerInfoStack, PDFSignatureVerificationResult& result) +{ + if (!signerInfoStack) + { + // No signature info provided + return; + } + + if (sk_PKCS7_SIGNER_INFO_num(signerInfoStack) != 1) + { + // Multiple signature infos, or no signature info + return; + } + + // Jakub Melka: We will get signed attribute from signer info. If it fails, + // then try to get unsigned attribute. + PKCS7_SIGNER_INFO* signerInfo = sk_PKCS7_SIGNER_INFO_value(signerInfoStack, 0); + ASN1_TYPE* attribute = PKCS7_get_signed_attribute(signerInfo, NID_pkcs9_signingTime); + + if (!attribute) + { + attribute = PKCS7_get_attribute(signerInfo, NID_pkcs9_signingTime); + } + + if (!attribute) + { + return; + } + + switch (attribute->type) + { + case V_ASN1_UTCTIME: + result.setSignatureDate(getDateTimeFromASN(attribute->value.utctime)); + break; + + case V_ASN1_GENERALIZEDTIME: + result.setSignatureDate(getDateTimeFromASN(attribute->value.generalizedtime)); + break; + + default: + break; + } +} + void PDFCertificateStore::serialize(QDataStream& stream) const { stream << persist_version; diff --git a/PdfForQtLib/sources/pdfsignaturehandler.h b/PdfForQtLib/sources/pdfsignaturehandler.h index 5a72fba..590f608 100644 --- a/PdfForQtLib/sources/pdfsignaturehandler.h +++ b/PdfForQtLib/sources/pdfsignaturehandler.h @@ -377,14 +377,26 @@ public: /// Adds OK flag, if both certificate and signature are valid void validate(); + QDateTime getSignatureDate() const; + void setSignatureDate(const QDateTime& signatureDate); + + QDateTime getTimestampDate() const; + void setTimestampDate(const QDateTime& timestampDate); + + QByteArray getSignatureFilter() const; + void setSignatureFilter(const QByteArray& signatureFilter); + private: PDFSignature::Type m_type = PDFSignature::Type::Invalid; VerificationFlags m_flags = None; PDFObjectReference m_signatureFieldReference; QString m_signatureFieldQualifiedName; + QDateTime m_signatureDate; + QDateTime m_timestampDate; QStringList m_errors; QStringList m_warnings; QStringList m_hashAlgorithms; + QByteArray m_signatureFilter; PDFCertificateInfos m_certificateInfos; }; diff --git a/PdfForQtLib/sources/pdfsignaturehandler_impl.h b/PdfForQtLib/sources/pdfsignaturehandler_impl.h index a3634bb..a7712e5 100644 --- a/PdfForQtLib/sources/pdfsignaturehandler_impl.h +++ b/PdfForQtLib/sources/pdfsignaturehandler_impl.h @@ -63,6 +63,20 @@ public: /// datetime is returned. static QDateTime getDateTimeFromASN(const ASN1_TIME* time); +protected: + /// Add hash algorithm from signer info stack. If \p signerInfoStack is nullptr, + /// then nothing happens. If multiple signer hash algorithms are present, + /// then they are all added. + /// \param signerInfoStack Signer stack + /// \param result Result, to which algorithm is added + static void addHashAlgorithmFromSignerInfoStack(STACK_OF(PKCS7_SIGNER_INFO)* signerInfoStack, PDFSignatureVerificationResult& result); + + /// Add signing date/time from signer info stack. If there are multiple signature + /// infos, nothing is added (because we can't decide, which one is right). + /// \param signerInfoStack Signer info stack + /// \param result Verification, to which signature date is being set + static void addSignatureDateFromSignerInfoStack(STACK_OF(PKCS7_SIGNER_INFO)* signerInfoStack, PDFSignatureVerificationResult& result); + protected: const PDFFormFieldSignature* m_signatureField; QByteArray m_sourceData; diff --git a/PdfForQtViewer/pdfsidebarwidget.cpp b/PdfForQtViewer/pdfsidebarwidget.cpp index b7da064..af3f8e3 100644 --- a/PdfForQtViewer/pdfsidebarwidget.cpp +++ b/PdfForQtViewer/pdfsidebarwidget.cpp @@ -375,11 +375,11 @@ void PDFSidebarWidget::updateSignatures(const std::vectorsetIcon(0, infoIcon); + } + + + QDateTime signingDate = signature.getSignatureDate(); + if (signingDate.isValid()) + { + QTreeWidgetItem* item = new QTreeWidgetItem(rootItem, QStringList(QString("Signing date/time: %2").arg(signingDate.toString(Qt::DefaultLocaleShortDate)))); + item->setIcon(0, infoIcon); + } + + QDateTime timestampDate = signature.getTimestampDate(); + if (timestampDate.isValid()) + { + QTreeWidgetItem* item = new QTreeWidgetItem(rootItem, QStringList(QString("Timestamp: %2").arg(timestampDate.toString(Qt::DefaultLocaleShortDate)))); item->setIcon(0, infoIcon); }