Signature hash/signing time update

This commit is contained in:
Jakub Melka 2020-09-28 14:41:42 +02:00
parent ddf852d34e
commit 5eb7472473
4 changed files with 154 additions and 10 deletions

View File

@ -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 PDFSignature::Type PDFSignatureVerificationResult::getType() const
{ {
return m_type; return m_type;
@ -386,6 +416,7 @@ void PDFPublicKeySignatureHandler::initializeResult(PDFSignatureVerificationResu
result.setType(m_signatureField->getSignature().getType()); result.setType(m_signatureField->getSignature().getType());
result.setSignatureFieldReference(signatureFieldReference); result.setSignatureFieldReference(signatureFieldReference);
result.setSignatureFieldQualifiedName(signatureFieldQualifiedName); result.setSignatureFieldQualifiedName(signatureFieldQualifiedName);
result.setSignatureFilter(m_signatureField->getSignature().getFilter());
} }
STACK_OF(X509)* PDFPublicKeySignatureHandler::getCertificates(PKCS7* pkcs7) STACK_OF(X509)* PDFPublicKeySignatureHandler::getCertificates(PKCS7* pkcs7)
@ -652,6 +683,8 @@ void PDFPublicKeySignatureHandler::verifySignature(PDFSignatureVerificationResul
} while (bytesRead > 0); } while (bytesRead > 0);
STACK_OF(PKCS7_SIGNER_INFO)* signerInfo = PKCS7_get_signer_info(pkcs7); 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); const int signerInfoCount = sk_PKCS7_SIGNER_INFO_num(signerInfo);
STACK_OF(X509)* certificates = getCertificates(pkcs7); STACK_OF(X509)* certificates = getCertificates(pkcs7);
if (signerInfo && signerInfoCount > 0 && certificates) if (signerInfo && signerInfoCount > 0 && certificates)
@ -668,13 +701,6 @@ void PDFPublicKeySignatureHandler::verifySignature(PDFSignatureVerificationResul
break; break;
} }
if (signerInfoValue->digest_alg && signerInfoValue->digest_alg->algorithm)
{
std::array<char, 64> 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); const int verification = PKCS7_signatureVerify(dataBio, pkcs7, signerInfoValue, signer);
if (verification <= 0) if (verification <= 0)
{ {
@ -815,6 +841,18 @@ void PDFSignatureHandler_ETSI_RFC3161::verifySignatureTimestamp(PDFSignatureVeri
TS_VERIFY_CTX_set_store(ts_context, store); TS_VERIFY_CTX_set_store(ts_context, store);
TS_VERIFY_CTS_set_certs(ts_context, usedCertificates); 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); const int verifyValue = TS_RESP_verify_token(ts_context, pkcs7);
if (verifyValue <= 0) if (verifyValue <= 0)
{ {
@ -1740,6 +1778,71 @@ QDateTime PDFPublicKeySignatureHandler::getDateTimeFromASN(const ASN1_TIME* time
return result; 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<char, 64> 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 void PDFCertificateStore::serialize(QDataStream& stream) const
{ {
stream << persist_version; stream << persist_version;

View File

@ -377,14 +377,26 @@ public:
/// Adds OK flag, if both certificate and signature are valid /// Adds OK flag, if both certificate and signature are valid
void validate(); 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: private:
PDFSignature::Type m_type = PDFSignature::Type::Invalid; PDFSignature::Type m_type = PDFSignature::Type::Invalid;
VerificationFlags m_flags = None; VerificationFlags m_flags = None;
PDFObjectReference m_signatureFieldReference; PDFObjectReference m_signatureFieldReference;
QString m_signatureFieldQualifiedName; QString m_signatureFieldQualifiedName;
QDateTime m_signatureDate;
QDateTime m_timestampDate;
QStringList m_errors; QStringList m_errors;
QStringList m_warnings; QStringList m_warnings;
QStringList m_hashAlgorithms; QStringList m_hashAlgorithms;
QByteArray m_signatureFilter;
PDFCertificateInfos m_certificateInfos; PDFCertificateInfos m_certificateInfos;
}; };

View File

@ -63,6 +63,20 @@ public:
/// datetime is returned. /// datetime is returned.
static QDateTime getDateTimeFromASN(const ASN1_TIME* time); 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: protected:
const PDFFormFieldSignature* m_signatureField; const PDFFormFieldSignature* m_signatureField;
QByteArray m_sourceData; QByteArray m_sourceData;

View File

@ -375,11 +375,11 @@ void PDFSidebarWidget::updateSignatures(const std::vector<pdf::PDFSignatureVerif
switch (signature.getType()) switch (signature.getType())
{ {
case pdf::PDFSignature::Type::Sig: case pdf::PDFSignature::Type::Sig:
templateString = tr("Signed by - %1"); templateString = tr("Signature - %1");
break; break;
case pdf::PDFSignature::Type::DocTimeStamp: case pdf::PDFSignature::Type::DocTimeStamp:
templateString = tr("Timestamped by - %1"); templateString = tr("Timestamp - %1");
break; break;
case pdf::PDFSignature::Type::Invalid: case pdf::PDFSignature::Type::Invalid:
@ -433,7 +433,22 @@ void PDFSidebarWidget::updateSignatures(const std::vector<pdf::PDFSignatureVerif
QString hashAlgorithms = signature.getHashAlgorithms().join(", "); QString hashAlgorithms = signature.getHashAlgorithms().join(", ");
if (!hashAlgorithms.isEmpty()) if (!hashAlgorithms.isEmpty())
{ {
QTreeWidgetItem* item = new QTreeWidgetItem(rootItem, QStringList(tr("Hash algorithms: %1").arg(hashAlgorithms))); QTreeWidgetItem* item = new QTreeWidgetItem(rootItem, QStringList(tr("Hash algorithm: %1").arg(hashAlgorithms.toUpper())));
item->setIcon(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); item->setIcon(0, infoIcon);
} }