Commit a81700df authored by Hans-Ulrich Jüttner's avatar Hans-Ulrich Jüttner Committed by Albert Astals Cid

Various signature related improvements

Export signature via Qt5 interface.
Add support for signatures of SubFilter "ETSI.CAdES.detached".
Add an optional validation time to method validateSignature().
Print full Subject Distinguished Name, signing time, hash algorithm and a statement wether the total document is signed in pdfsig.

Fixes bug #99271
parent e15a0df1
......@@ -28,10 +28,12 @@
#endif
#include <set>
#include <limits>
#include <stddef.h>
#include <string.h>
#include "goo/gmem.h"
#include "goo/GooString.h"
#include "goo/GooList.h"
#include "Error.h"
#include "Object.h"
#include "Array.h"
......@@ -437,11 +439,151 @@ FormWidgetSignature::FormWidgetSignature(PDFDoc *docA, Object *aobj, unsigned nu
FormWidget(docA, aobj, num, ref, p)
{
type = formSignature;
file_size = 0;
}
SignatureInfo *FormWidgetSignature::validateSignature(bool doVerifyCert, bool forceRevalidation)
SignatureInfo *FormWidgetSignature::validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime)
{
return static_cast<FormFieldSignature*>(field)->validateSignature(doVerifyCert, forceRevalidation);
return static_cast<FormFieldSignature*>(field)->validateSignature(doVerifyCert, forceRevalidation, validationTime);
}
std::vector<Goffset> FormWidgetSignature::getSignedRangeBounds()
{
Object* obj = static_cast<FormFieldSignature*>(field)->getByteRange();
std::vector<Goffset> range_vec;
if (obj && obj->isArray())
{
if (obj->arrayGetLength() == 4)
{
for (int i = 0; i < 2; ++i)
{
Object offsetObj(obj->arrayGet(2*i));
Object lenObj(obj->arrayGet(2*i+1));
if (offsetObj.isIntOrInt64() && lenObj.isIntOrInt64())
{
Goffset offset = offsetObj.getIntOrInt64();
Goffset len = lenObj.getIntOrInt64();
range_vec.push_back(offset);
range_vec.push_back(offset+len);
}
}
}
}
return range_vec;
}
GooString* FormWidgetSignature::getCheckedSignature()
{
Goffset start = 0;
Goffset end = 0;
const std::vector<Goffset> ranges = getSignedRangeBounds();
if (ranges.size() == 4)
{
start = ranges[1];
end = ranges[2];
}
if (end >= start+6)
{
BaseStream* stream = doc->getBaseStream();
file_size = stream->getLength();
Goffset len = end-start;
stream->setPos(end-1);
int c2 = stream->lookChar();
stream->setPos(start);
int c1 = stream->getChar();
// PDF signatures are first ASN1 DER, then hex encoded PKCS#7 structures,
// possibly padded with 0 characters and enclosed in '<' and '>'.
// The ASN1 DER encoding of a PKCS#7 structure must start with the tag 0x30
// for SEQUENCE. The next byte must be 0x80 for ASN1 DER indefinite length
// encoding or (0x80 + n) for ASN1 DER definite length encoding
// where n is the number of subsequent "length bytes" which big-endian
// encode the length of the content of the SEQUENCE following them.
if (len <= std::numeric_limits<int>::max() && file_size > end && c1 == '<' && c2 == '>')
{
GooString gstr;
++start;
--end;
len = end-start;
Goffset pos = 0;
do
{
c1 = stream->getChar();
if (c1 == EOF)
return nullptr;
gstr.append(static_cast<char>(c1));
} while (++pos < len);
if (gstr.getChar(0) == '3' && gstr.getChar(1) == '0')
{
if (gstr.getChar(2) == '8' && gstr.getChar(3) == '0')
{
// ASN1 DER indefinite length encoding:
// We only check that all characters up to the enclosing '>'
// are hex characters and that there are two hex encoded 0 bytes
// just before the enclosing '>' marking the end of the indefinite
// length encoding.
int paddingCount = 0;
while (gstr.getChar(len-1) == '0' && gstr.getChar(len-2) == '0')
{
++paddingCount;
len -= 2;
}
if (paddingCount < 2 || len%2 == 1)
len = 0;
}
else if (gstr.getChar(2) == '8')
{
// ASN1 DER definite length encoding:
// We calculate the length of the following bytes from the length bytes and
// check that after the length bytes and the following calculated number of
// bytes all bytes up to the enclosing '>' character are hex encoded 0 bytes.
int lenBytes = gstr.getChar(3) - '0';
if (lenBytes > 0 && lenBytes <= 4)
{
int sigLen = 0;
for (int i = 0; i < 2*lenBytes; ++i)
{
sigLen <<= 4;
char c = gstr.getChar(i+4);
if (isdigit(c))
sigLen += c - '0';
else if (isxdigit(c) && c >= 'a')
sigLen += c - 'a' + 10;
else if (isxdigit(c) && c >= 'A')
sigLen += c - 'A' + 10;
else
{
len = 0;
break;
}
}
if (sigLen > 0 && 2*(sigLen+lenBytes) <= len-4)
{
for (int i = 2*(sigLen+lenBytes)+4; i < len; ++i)
{
if (gstr.getChar(i) != '0')
{
len = 0;
break;
}
}
}
else
len = 0;
}
}
for (int i = 0; i < len; ++i)
{
if (!isxdigit(gstr.getChar(i)))
len = 0;
}
if (len > 0)
{
return new GooString(&gstr, 0, len);
}
}
}
}
return nullptr;
}
void FormWidgetSignature::updateWidgetAppearance()
......@@ -1345,7 +1487,9 @@ GooString *FormFieldChoice::getSelectedChoice() {
// FormFieldSignature
//------------------------------------------------------------------------
FormFieldSignature::FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents)
: FormField(docA, dict, ref, parent, usedParents, formSignature)
: FormField(docA, dict, ref, parent, usedParents, formSignature),
signature_type(adbe_pkcs7_detached), byte_range(),
signature(nullptr), signature_info(nullptr)
{
signature = NULL;
......@@ -1375,7 +1519,7 @@ void FormFieldSignature::parseInfo()
signature = contents_obj.getString()->copy();
}
Object byte_range = sig_dict.dictLookup("ByteRange");
byte_range = sig_dict.dictLookup("ByteRange");
// retrieve SigningTime
Object time_of_signing = sig_dict.dictLookup("M");
......@@ -1386,7 +1530,16 @@ void FormFieldSignature::parseInfo()
// check if subfilter is supported for signature validation, only detached signatures work for now
Object subfilterName = sig_dict.dictLookup("SubFilter");
if (subfilterName.isName("adbe.pkcs7.detached") || subfilterName.isName("adbe.pkcs7.sha1")) {
if (subfilterName.isName("adbe.pkcs7.sha1")) {
signature_type = adbe_pkcs7_sha1;
signature_info->setSubFilterSupport(true);
}
else if (subfilterName.isName("adbe.pkcs7.detached")) {
signature_type = adbe_pkcs7_detached;
signature_info->setSubFilterSupport(true);
}
else if (subfilterName.isName("ETSI.CAdES.detached")) {
signature_type = ETSI_CAdES_detached;
signature_info->setSubFilterSupport(true);
}
}
......@@ -1417,8 +1570,17 @@ void FormFieldSignature::hashSignedDataBlock(SignatureHandler *handler, Goffset
#endif
}
FormSignatureType FormWidgetSignature::signatureType()
{
return static_cast<FormFieldSignature*>(field)->signature_type;
}
void FormWidgetSignature::setFormSignatureType(FormSignatureType type)
{
static_cast<FormFieldSignature*>(field)->signature_type = type;
}
SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation)
SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime)
{
#ifdef ENABLE_NSS3
if (!signature_info->isSubfilterSupported()) {
......@@ -1478,6 +1640,8 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
sig_val_state = signature_handler.validateSignature();
signature_info->setSignatureValStatus(SignatureHandler::NSS_SigTranslate(sig_val_state));
signature_info->setSignerName(signature_handler.getSignerName());
signature_info->setSubjectDN(signature_handler.getSignerSubjectDN());
signature_info->setHashAlgorithm(signature_handler.getHashAlgorithm());
// verify if signature contains a 'signing time' attribute
if (signature_handler.getSigningTime() != 0) {
......@@ -1488,7 +1652,7 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
return signature_info;
}
cert_val_state = signature_handler.validateCertificate();
cert_val_state = signature_handler.validateCertificate(validationTime);
signature_info->setCertificateValStatus(SignatureHandler::NSS_CertTranslate(cert_val_state));
#endif
......
......@@ -14,6 +14,7 @@
// Copyright 2015 André Guerreiro <aguerreiro1985@gmail.com>
// Copyright 2015 André Esser <bepandre@hotmail.com>
// Copyright 2017 Roland Hieber <r.hieber@pengutronix.de>
// Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
//
//========================================================================
......@@ -27,9 +28,11 @@
#include "Object.h"
#include "Annot.h"
#include <list>
#include <set>
#include <vector>
class GooList;
class GooString;
class Array;
class Dict;
......@@ -62,6 +65,12 @@ enum VariableTextQuadding {
quaddingRightJustified
};
enum FormSignatureType {
adbe_pkcs7_sha1,
adbe_pkcs7_detached,
ETSI_CAdES_detached
};
class Form;
class FormField;
class FormFieldButton;
......@@ -253,7 +262,23 @@ public:
FormWidgetSignature(PDFDoc *docA, Object *dict, unsigned num, Ref ref, FormField *p);
void updateWidgetAppearance() override;
SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation);
FormSignatureType signatureType();
void setFormSignatureType(FormSignatureType type);
SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime = -1);
// returns a list with the boundaries of the signed ranges
// the elements of the list are of type Goffset
std::vector<Goffset> getSignedRangeBounds();
// checks the length encoding of the signature and returns the hex encoded signature
// if the check passed otherwise a nullptr is returned
GooString* getCheckedSignature();
// this method only gives the correct file size if getCheckedSignature()
// has been called before
Goffset getCheckedFileSize() const { return file_size; }
protected:
Goffset file_size;
};
//------------------------------------------------------------------------
......@@ -492,16 +517,21 @@ protected:
//------------------------------------------------------------------------
class FormFieldSignature: public FormField {
friend class FormWidgetSignature;
public:
FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents);
SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation);
SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime = -1);
~FormFieldSignature();
Object* getByteRange() { return &byte_range; }
GooString* getSignature() { return signature; }
private:
void parseInfo();
void hashSignedDataBlock(SignatureHandler *handler, Goffset block_len);
FormSignatureType signature_type;
Object byte_range;
GooString *signature;
SignatureInfo *signature_info;
......
......@@ -9,6 +9,7 @@
// Copyright 2015, 2016 Albert Astals Cid <aacid@kde.org>
// Copyright 2015 Markus Kilås <digital@markuspage.com>
// Copyright 2017 Sebastian Rasmussen <sebras@gmail.com>
// Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
//
//========================================================================
......@@ -47,6 +48,26 @@ char *SignatureHandler::getSignerName()
return CERT_GetCommonName(&cert->subject);
}
const char * SignatureHandler::getSignerSubjectDN()
{
if (!CMSSignerInfo)
return nullptr;
CERTCertificate *cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB());
if (!cert)
return nullptr;
return cert->subjectName;
}
HASH_HashType SignatureHandler::getHashAlgorithm()
{
if (hash_context && hash_context->hashobj)
{
return hash_context->hashobj->type;
}
return HASH_AlgNULL;
}
time_t SignatureHandler::getSigningTime()
{
PRTime sTime; // time in microseconds since the epoch
......@@ -54,7 +75,7 @@ time_t SignatureHandler::getSigningTime()
if (NSS_CMSSignerInfo_GetSigningTime (CMSSignerInfo, &sTime) != SECSuccess)
return 0;
return (time_t) sTime/1000000;
return static_cast<time_t>(sTime/1000000);
}
......@@ -271,7 +292,7 @@ NSSCMSVerificationStatus SignatureHandler::validateSignature()
}
}
SECErrorCodes SignatureHandler::validateCertificate()
SECErrorCodes SignatureHandler::validateCertificate(time_t validation_time)
{
SECErrorCodes retVal;
CERTCertificate *cert;
......@@ -282,10 +303,15 @@ SECErrorCodes SignatureHandler::validateCertificate()
if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB())) == NULL)
CMSSignerInfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
CERTValInParam inParams[2];
PRTime vTime = 0; // time in microseconds since the epoch, special value 0 means now
if (validation_time > 0)
vTime = 1000000*(PRTime)validation_time;
CERTValInParam inParams[3];
inParams[0].type = cert_pi_revocationFlags;
inParams[0].value.pointer.revocation = CERT_GetClassicOCSPEnabledSoftFailurePolicy();
inParams[1].type = cert_pi_end;
inParams[1].type = cert_pi_date;
inParams[1].value.scalar.time = vTime;
inParams[2].type = cert_pi_end;
CERT_PKIXVerifyCert(cert, certificateUsageEmailSigner, inParams, NULL,
CMSSignerInfo->cmsg->pwfn_arg);
......
......@@ -7,6 +7,7 @@
// Copyright 2015 André Guerreiro <aguerreiro1985@gmail.com>
// Copyright 2015 André Esser <bepandre@hotmail.com>
// Copyright 2015 Albert Astals Cid <aacid@kde.org>
// Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
//
//========================================================================
......@@ -36,10 +37,12 @@ public:
~SignatureHandler();
time_t getSigningTime();
char * getSignerName();
const char * getSignerSubjectDN();
HASH_HashType getHashAlgorithm();
void setSignature(unsigned char *, int);
void updateHash(unsigned char * data_block, int data_len);
NSSCMSVerificationStatus validateSignature();
SECErrorCodes validateCertificate();
SECErrorCodes validateCertificate(time_t validation_time = -1);
//Translate NSS error codes
static SignatureValidationStatus NSS_SigTranslate(NSSCMSVerificationStatus nss_code);
......
......@@ -6,6 +6,7 @@
//
// Copyright 2015 André Guerreiro <aguerreiro1985@gmail.com>
// Copyright 2015 André Esser <bepandre@hotmail.com>
// Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
//
//========================================================================
......@@ -16,13 +17,17 @@
#include <stdlib.h>
#include <string.h>
#include <hasht.h>
/* Constructor & Destructor */
SignatureInfo::SignatureInfo()
{
sig_status = SIGNATURE_NOT_VERIFIED;
cert_status = CERTIFICATE_NOT_VERIFIED;
signer_name = NULL;
signer_name = nullptr;
subject_dn = nullptr;
hash_type = HASH_AlgNULL;
signing_time = 0;
sig_subfilter_supported = false;
}
......@@ -31,7 +36,9 @@ SignatureInfo::SignatureInfo(SignatureValidationStatus sig_val_status, Certifica
{
sig_status = sig_val_status;
cert_status = cert_val_status;
signer_name = NULL;
signer_name = nullptr;
subject_dn = nullptr;
hash_type = HASH_AlgNULL;
signing_time = 0;
sig_subfilter_supported = false;
}
......@@ -53,11 +60,21 @@ CertificateValidationStatus SignatureInfo::getCertificateValStatus()
return cert_status;
}
char *SignatureInfo::getSignerName()
const char *SignatureInfo::getSignerName()
{
return signer_name;
}
const char *SignatureInfo::getSubjectDN()
{
return subject_dn;
}
int SignatureInfo::getHashAlgorithm()
{
return hash_type;
}
time_t SignatureInfo::getSigningTime()
{
return signing_time;
......@@ -81,6 +98,16 @@ void SignatureInfo::setSignerName(char *signerName)
signer_name = signerName;
}
void SignatureInfo::setSubjectDN(const char *subjectDN)
{
subject_dn = subjectDN;
}
void SignatureInfo::setHashAlgorithm(int type)
{
hash_type = type;
}
void SignatureInfo::setSigningTime(time_t signingTime)
{
signing_time = signingTime;
......
......@@ -7,6 +7,7 @@
// Copyright 2015 André Guerreiro <aguerreiro1985@gmail.com>
// Copyright 2015 André Esser <bepandre@hotmail.com>
// Copyright 2015 Albert Astals Cid <aacid@kde.org>
// Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
//
//========================================================================
......@@ -46,7 +47,9 @@ public:
/* GETTERS */
SignatureValidationStatus getSignatureValStatus();
CertificateValidationStatus getCertificateValStatus();
char *getSignerName();
const char *getSignerName();
const char *getSubjectDN();
int getHashAlgorithm();
time_t getSigningTime();
bool isSubfilterSupported() { return sig_subfilter_supported; }
......@@ -54,6 +57,8 @@ public:
void setSignatureValStatus(enum SignatureValidationStatus );
void setCertificateValStatus(enum CertificateValidationStatus );
void setSignerName(char *);
void setSubjectDN(const char *);
void setHashAlgorithm(int);
void setSigningTime(time_t);
void setSubFilterSupport(bool isSupported) { sig_subfilter_supported = isSupported; }
......@@ -64,6 +69,8 @@ private:
SignatureValidationStatus sig_status;
CertificateValidationStatus cert_status;
char *signer_name;
const char *subject_dn;
int hash_type;
time_t signing_time;
bool sig_subfilter_supported;
};
......
......@@ -4,6 +4,7 @@
* Copyright (C) 2011 Carlos Garcia Campos <carlosgc@gnome.org>
* Copyright (C) 2012, Adam Reichold <adamreichold@myopera.com>
* Copyright (C) 2016, Hanno Meyer-Thurow <h.mth@web.de>
* Copyright (C) 2017, Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -35,6 +36,20 @@
#include "poppler-annotation-helper.h"
#include <math.h>
#include <ctype.h>
enum HASH_HashType
{
HASH_AlgNULL = 0,
HASH_AlgMD2 = 1,
HASH_AlgMD5 = 2,
HASH_AlgSHA1 = 3,
HASH_AlgSHA256 = 4,
HASH_AlgSHA384 = 5,
HASH_AlgSHA512 = 6,
HASH_AlgSHA224 = 7,
HASH_AlgTOTAL
};
namespace {
......@@ -447,8 +462,13 @@ struct SignatureValidationInfoPrivate {
SignatureValidationInfo::SignatureStatus signature_status;
SignatureValidationInfo::CertificateStatus certificate_status;
QByteArray signature;
QString signer_name;
QString signer_subject_dn;
int hash_algorithm;
time_t signing_time;
QList<qint64> range_bounds;
qint64 docLength;
};
......@@ -484,12 +504,62 @@ QString SignatureValidationInfo::signerName() const
return d->signer_name;
}
QString SignatureValidationInfo::signerSubjectDN() const
{
Q_D(const SignatureValidationInfo);
return d->signer_subject_dn;
}
SignatureValidationInfo::HashAlgorithm SignatureValidationInfo::hashAlgorithm() const
{
Q_D(const SignatureValidationInfo);
return static_cast<HashAlgorithm>(d->hash_algorithm);
}
time_t SignatureValidationInfo::signingTime() const
{
Q_D(const SignatureValidationInfo);
return d->signing_time;
}
QDateTime SignatureValidationInfo::signingDateTime() const
{
return QDateTime::fromTime_t(signingTime());
}
QByteArray SignatureValidationInfo::signature() const
{
Q_D(const SignatureValidationInfo);
return d->signature;
}
QList<qint64> SignatureValidationInfo::signedRangeBounds() const
{
Q_D(const SignatureValidationInfo);
return d->range_bounds;
}
bool SignatureValidationInfo::signsTotalDocument() const
{
Q_D(const SignatureValidationInfo);
if (d->range_bounds.size() == 4 && d->range_bounds.value(0) == 0 &&
d->range_bounds.value(1) >= 0 &&
d->range_bounds.value(2) > d->range_bounds.value(1) &&
d->range_bounds.value(3) >= d->range_bounds.value(2))
{
// The range from d->range_bounds.value(1) to d->range_bounds.value(2) is
// not authenticated by the signature and should only contain the signature
// itself padded with 0 bytes. This has been checked in readSignature().
// If it failed, d->signature is empty.
// A potential range after d->range_bounds.value(3) would be also not
// authenticated. Therefore d->range_bounds.value(3) should coincide with
// the end of the document.
if (d->docLength == d->range_bounds.value(3) && !d->signature.isEmpty())
return true;
}
return false;
}
SignatureValidationInfo &SignatureValidationInfo::operator=(const SignatureValidationInfo &other)
{
if ( this != &other )
......@@ -511,8 +581,32 @@ FormField::FormType FormFieldSignature::type() const
{
return FormField::FormSignature;
}
FormFieldSignature::SignatureType FormFieldSignature::signatureType() const
{
SignatureType sigType = AdbePkcs7detached;
FormWidgetSignature* fws = static_cast<FormWidgetSignature*>(m_formData->fm);
switch (fws->signatureType())
{
case adbe_pkcs7_sha1:
sigType = AdbePkcs7sha1;
break;
case adbe_pkcs7_detached:
sigType = AdbePkcs7detached;
break;
case ETSI_CAdES_detached:
sigType = EtsiCAdESdetached;
break;
}
return sigType;
}
SignatureValidationInfo FormFieldSignature::validate(ValidateOptions opt) const
{
return validate(opt, QDateTime());
}
SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime& validationTime) const
{
FormWidgetSignature* fws = static_cast<FormWidgetSignature*>(m_formData->fm);
SignatureInfo* si = fws->validateSignature(opt & ValidateVerifyCertificate, opt & ValidateForceRevalidation);
......@@ -566,7 +660,25 @@ SignatureValidationInfo FormFieldSignature::validate(ValidateOptions opt) const
break;
}
priv->signer_name = si->getSignerName();
priv->signer_subject_dn = si->getSubjectDN();
priv->hash_algorithm = si->getHashAlgorithm();
priv->signing_time = si->getSigningTime();
std::vector<Goffset> ranges = fws->getSignedRangeBounds();
if (!ranges.empty())
{
for (Goffset bound : ranges)
{
priv->range_bounds.append(bound);
}
}
GooString* checkedSignature = fws->getCheckedSignature();
if (priv->range_bounds.size() == 4 && checkedSignature)
{
priv->signature = QByteArray::fromHex(checkedSignature->getCString());
priv->docLength = fws->getCheckedFileSize();
}
delete checkedSignature;
return SignatureValidationInfo(priv);
}
......
......@@ -3,6 +3,7 @@
* Copyright (C) 2008, 2011, 2016, 2017, Albert Astals Cid <aacid@kde.org>
* Copyright (C) 2012, Adam Reichold <adamreichold@myopera.com>
* Copyright (C) 2016, Hanno Meyer-Thurow <h.mth@web.de>
* Copyright (C) 2017, Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -22,6 +23,8 @@
#ifndef _POPPLER_QT5_FORM_H_
#define _POPPLER_QT5_FORM_H_
#include <QtCore/QDateTime>
#include <QtCore/QList>
#include <QtCore/QRectF>
#include <QtCore/QStringList>
#include <QtCore/QSharedPointer>
......@@ -401,6 +404,22 @@ namespace Poppler {
CertificateNotVerified ///< The certificate is not yet verified.
};
/**
* The hash algorithme of the signature
*/
enum HashAlgorithm
{
HashAlgNULL = 0,
HashAlgMD2 = 1,
HashAlgMD5 = 2,
HashAlgSHA1 = 3,
HashAlgSHA256 = 4,
HashAlgSHA384 = 5,
HashAlgSHA512 = 6,
HashAlgSHA224 = 7,
HashAlgTOTAL
};
/// \cond PRIVATE
SignatureValidationInfo(SignatureValidationInfoPrivate *priv);
/// \endcond
......@@ -421,10 +440,37 @@ namespace Poppler {
*/
QString signerName() const;
/**
The signer subject distinguished name associated with the signature.
*/
QString signerSubjectDN() const;
/**
The the hash algorithm used for the signature.
*/
HashAlgorithm hashAlgorithm() const;
/**
The signing time associated with the signature.
*/
time_t signingTime() const;
QDateTime signingDateTime() const;
/**
Get the signature binary data.
*/
QByteArray signature() const;
/**
Get the bounds of the ranges of the document which are signed.