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

Added signing of PDF documents with digital signatures

via Qt5 interface and pdfsig with parameter -s.

Includes fix to write document then update byte offsets and sig on disk
by Adrian Johnson

Includes compile fixes by Oliver Sander and Albert Astals Cid

Fixes bug #99416
parent 732bc31d
Pipeline #25811 passed with stage
in 4 minutes and 34 seconds
......@@ -24,6 +24,7 @@
// Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com>
// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
// Copyright (C) 2019 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
......@@ -173,6 +174,8 @@ public:
bool hasUnicodeMarker() const { return size() >= 2 && (*this)[0] == char(0xfe) && (*this)[1] == char(0xff); }
bool hasJustUnicodeMarker() const { return size() == 2 && hasUnicodeMarker(); }
bool hasASN1Marker() const { return size() > 1 && (data()[0] & 0xff) == 0x30 && (data()[1] & 0xf0) == 0x80; }
void prependUnicodeMarker();
......
This diff is collapsed.
......@@ -6,11 +6,11 @@
//
// Copyright 2006 Julien Rebetez <julienr@svn.gnome.org>
// Copyright 2007, 2008, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
// Copyright 2007-2010, 2012, 2015-2018 Albert Astals Cid <aacid@kde.org>
// Copyright 2007-2010, 2012, 2015-2019 Albert Astals Cid <aacid@kde.org>
// Copyright 2010 Mark Riedesel <mark@klowner.com>
// Copyright 2011 Pino Toscano <pino@kde.org>
// Copyright 2012 Fabio D'Urso <fabiodurso@hotmail.it>
// Copyright 2013 Adrian Johnson <ajohnson@redneon.com>
// Copyright 2013, 2019 Adrian Johnson <ajohnson@redneon.com>
// Copyright 2015 André Guerreiro <aguerreiro1985@gmail.com>
// Copyright 2015 André Esser <bepandre@hotmail.com>
// Copyright 2017 Roland Hieber <r.hieber@pengutronix.de>
......@@ -263,9 +263,21 @@ public:
void updateWidgetAppearance() override;
FormSignatureType signatureType();
void setSignatureType(FormSignatureType type);
// Use -1 for now as validationTime
SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime);
// creates or replaces the dictionary name "V" in the signature dictionary and
// fills it with the fields of the signature; the field "Contents" is the signature
// in PKCS#7 format, which is calculated over the byte range encompassing the whole
// document except for the signature itself; this byte range is specified in the
// field "ByteRange" in the dictionary "V"
// return success
bool signDocument(const char *filename,
const char *certNickname, const char *digestName,
const char *password, const char *reason = nullptr);
// returns a list with the boundaries of the signed ranges
// the elements of the list are of type Goffset
std::vector<Goffset> getSignedRangeBounds();
......@@ -276,6 +288,15 @@ public:
GooString* getCheckedSignature(Goffset *checkedFileSize);
const GooString *getSignature() const;
private:
bool createSignature(Object &vObj, const GooString &name, const GooString &reason,
const GooString *signature);
bool getObjectStartEnd(GooString *filename, int objNum, Goffset *objStart, Goffset *objEnd);
bool updateOffsets(FILE *f, Goffset objStart, Goffset objEnd,
Goffset *sigStart, Goffset *sigEnd, Goffset *fileSize);
bool updateSignature(FILE *f, Goffset sigStart, Goffset sigEnd, const GooString* signature);
};
//------------------------------------------------------------------------
......@@ -524,6 +545,7 @@ public:
~FormFieldSignature();
Object* getByteRange() { return &byte_range; }
const GooString* getSignature() const { return signature; }
void setSignature(const GooString &sig);
private:
void parseInfo();
......
......@@ -1333,6 +1333,15 @@ void PDFDoc::writeString (const GooString* s, OutStream* outStr, const unsigned
outStr->printf("%c", unescaped);
}
outStr->printf(") ");
} else if (s->hasASN1Marker()) {
//format ASN1 strings hex encoded and enclosed in <>
const char* c = s->c_str();
outStr->printf("<");
for(int i=0; i<s->getLength(); i++) {
unsigned char value = *(c+i)&0x000000ff;
outStr->printf("%2.2x", value);
}
outStr->printf("> ");
} else {
const char* c = s->c_str();
outStr->printf("(");
......
......@@ -26,6 +26,18 @@
#include <dirent.h>
#include <Error.h>
/* NSS headers */
#include <secpkcs7.h>
void SignatureHandler::outputCallback(void* arg, const char* buf, unsigned long len)
{
if (arg && buf)
{
GooString* gSignature = reinterpret_cast<GooString*>(arg);
gSignature->append(buf, len);
}
}
unsigned int SignatureHandler::digestLength(SECOidTag digestAlgId)
{
switch(digestAlgId){
......@@ -43,28 +55,54 @@ unsigned int SignatureHandler::digestLength(SECOidTag digestAlgId)
}
}
SECOidTag SignatureHandler::getHashOidTag(const char* digestName)
{
SECOidTag tag = SEC_OID_UNKNOWN;
if (strcmp(digestName, "SHA1") == 0)
{
tag = SEC_OID_SHA1;
}
else if (strcmp(digestName, "SHA256") == 0)
{
tag = SEC_OID_SHA256;
}
else if (strcmp(digestName, "SHA384") == 0)
{
tag = SEC_OID_SHA384;
}
else if (strcmp(digestName, "SHA512") == 0)
{
tag = SEC_OID_SHA512;
}
return tag;
}
char *SignatureHandler::getSignerName()
{
if (!CMSSignerInfo || !NSS_IsInitialized())
return nullptr;
CERTCertificate *cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB());
if (!signing_cert)
signing_cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB());
if (!cert)
if (!signing_cert)
return nullptr;
return CERT_GetCommonName(&cert->subject);
return CERT_GetCommonName(&signing_cert->subject);
}
const char * SignatureHandler::getSignerSubjectDN()
{
if (!CMSSignerInfo)
if (!signing_cert && !CMSSignerInfo)
return nullptr;
CERTCertificate *cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB());
if (!cert)
if (!signing_cert)
signing_cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB());
if (!signing_cert)
return nullptr;
return cert->subjectName;
return signing_cert->subjectName;
}
HASH_HashType SignatureHandler::getHashAlgorithm()
......@@ -265,6 +303,7 @@ SignatureHandler::SignatureHandler(unsigned char *p7, int p7_length)
CMSMessage(nullptr),
CMSSignedData(nullptr),
CMSSignerInfo(nullptr),
signing_cert(nullptr),
temp_certs(nullptr)
{
setNSSDir({});
......@@ -278,6 +317,23 @@ SignatureHandler::SignatureHandler(unsigned char *p7, int p7_length)
}
}
SignatureHandler::SignatureHandler(const char *certNickname, SECOidTag digestAlgTag)
: hash_length(digestLength(digestAlgTag)),
digest_alg_tag(digestAlgTag),
CMSitem(),
hash_context(nullptr),
CMSMessage(nullptr),
CMSSignedData(nullptr),
CMSSignerInfo(nullptr),
signing_cert(nullptr),
temp_certs(nullptr)
{
setNSSDir({});
CMSMessage = NSS_CMSMessage_Create(nullptr);
signing_cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), certNickname);
hash_context = HASH_Create(HASH_GetHashTypeByOidTag(digestAlgTag));
}
HASHContext * SignatureHandler::initHashContext()
{
......@@ -295,12 +351,21 @@ void SignatureHandler::updateHash(unsigned char * data_block, int data_len)
}
}
void SignatureHandler::restartHash()
{
if (hash_context)
HASH_Destroy(hash_context);
hash_context = HASH_Create(HASH_GetHashTypeByOidTag(digest_alg_tag));
}
SignatureHandler::~SignatureHandler()
{
SECITEM_FreeItem(&CMSitem, PR_FALSE);
if (CMSMessage)
NSS_CMSMessage_Destroy(CMSMessage);
if (signing_cert)
CERT_DestroyCertificate(signing_cert);
if (hash_context)
HASH_Destroy(hash_context);
......@@ -493,3 +558,56 @@ CertificateValidationStatus SignatureHandler::validateCertificate(time_t validat
return CERTIFICATE_GENERIC_ERROR;
}
GooString* SignatureHandler::signDetached(const char* password)
{
if (!hash_context)
return nullptr;
unsigned char* digest_buffer = reinterpret_cast<unsigned char*>(PORT_Alloc(hash_length));
unsigned int result_len = 0;
HASH_End(hash_context, digest_buffer, &result_len, hash_length);
SECItem digest;
digest.data = digest_buffer;
digest.len = result_len;
SEC_PKCS7ContentInfo* p7_info =
SEC_PKCS7CreateSignedData(signing_cert, certUsageEmailSigner,
CERT_GetDefaultCertDB(), digest_alg_tag, &digest,
nullptr, nullptr);
if (!p7_info)
{
PORT_Free(reinterpret_cast<void*>(digest_buffer));
return nullptr;
}
SEC_PKCS7SignerInfo** signerinfos = p7_info->content.signedData->signerInfos;
if (!signerinfos)
{
PORT_Free(reinterpret_cast<void*>(digest_buffer));
SEC_PKCS7DestroyContentInfo(p7_info);
return nullptr;
}
for (SEC_PKCS7SignerInfo* si = *signerinfos; si; si = *++signerinfos)
{
if (si->cert)
{
si->certList = CERT_CertChainFromCert(si->cert, certUsageEmailSigner, PR_TRUE);
}
}
SEC_PKCS7AddSigningTime(p7_info);
GooString* signature = new GooString;
PWData pwdata =
{
password ? PWData::PW_PLAINTEXT : PWData::PW_NONE,
password
};
if (SEC_PKCS7Encode(p7_info, outputCallback, reinterpret_cast<void*>(signature),
nullptr, nullptr, &pwdata) != SECSuccess)
{
PORT_Free(reinterpret_cast<void*>(digest_buffer));
delete signature;
signature = nullptr;
}
SEC_PKCS7DestroyContentInfo(p7_info);
PORT_Free(reinterpret_cast<void*>(digest_buffer));
return signature;
}
......@@ -37,6 +37,7 @@ class SignatureHandler
{
public:
SignatureHandler(unsigned char *p7, int p7_length);
SignatureHandler(const char *certNickname, SECOidTag digestAlgTag);
~SignatureHandler();
time_t getSigningTime();
char * getSignerName();
......@@ -44,10 +45,14 @@ public:
HASH_HashType getHashAlgorithm();
void setSignature(unsigned char *, int);
void updateHash(unsigned char * data_block, int data_len);
void restartHash();
SignatureValidationStatus validateSignature();
// Use -1 as validation_time for now
CertificateValidationStatus validateCertificate(time_t validation_time);
std::unique_ptr<X509CertificateInfo> getCertificateInfo() const;
GooString * signDetached(const char * password);
static SECOidTag getHashOidTag(const char* digestName);
// Initializes the NSS dir with the custom given directory
// calling it with an empty string means use the default firefox db, /etc/pki/nssdb, ~/.pki/nssdb
......@@ -56,6 +61,16 @@ public:
static void setNSSDir(const GooString &nssDir);
private:
typedef struct {
enum {
PW_NONE = 0,
PW_FROMFILE = 1,
PW_PLAINTEXT = 2,
PW_EXTERNAL = 3
} source;
const char * data;
} PWData;
SignatureHandler(const SignatureHandler &);
SignatureHandler& operator=(const SignatureHandler &);
......@@ -65,13 +80,16 @@ private:
NSSCMSSignerInfo *CMS_SignerInfoCreate(NSSCMSSignedData * cms_sig_data);
HASHContext * initHashContext();
X509CertificateInfo::EntityInfo getEntityInfo(CERTName *entityName) const;
static void outputCallback(void* arg, const char* buf, unsigned long len);
unsigned int hash_length;
SECOidTag digest_alg_tag;
SECItem CMSitem;
HASHContext *hash_context;
NSSCMSMessage *CMSMessage;
NSSCMSSignedData *CMSSignedData;
NSSCMSSignerInfo *CMSSignerInfo;
CERTCertificate *signing_cert;
CERTCertificate **temp_certs;
};
......
......@@ -22,7 +22,7 @@
// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
// Copyright (C) 2012, 2013, 2016 Thomas Freitag <Thomas.Freitag@kabelmail.de>
// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
// Copyright (C) 2013, 2014, 2017 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2013, 2014, 2017, 2019 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2013 Pino Toscano <pino@kde.org>
// Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com>
// Copyright (C) 2018, 2019 Adam Reichold <adam.reichold@t-online.de>
......@@ -1076,7 +1076,7 @@ Object XRef::fetch(const Ref ref, int recursion)
return fetch(ref.num, ref.gen, recursion);
}
Object XRef::fetch(int num, int gen, int recursion) {
Object XRef::fetch(int num, int gen, int recursion, Goffset *endPos) {
XRefEntry *e;
Parser *parser;
Object obj1, obj2, obj3;
......@@ -1124,6 +1124,8 @@ Object XRef::fetch(int num, int gen, int recursion) {
if (longNumber <= INT_MAX && longNumber >= INT_MIN && *end_ptr == '\0') {
int number = longNumber;
error(errSyntaxWarning, -1, "Cmd was not obj but {0:s}, assuming the creator meant obj {1:d}", cmd, number);
if (endPos)
*endPos = parser->getPos();
delete parser;
return Object(number);
}
......@@ -1134,6 +1136,8 @@ Object XRef::fetch(int num, int gen, int recursion) {
}
Object obj = parser->getObj(false, (encrypted && !e->getFlag(XRefEntry::Unencrypted)) ? fileKey : nullptr,
encAlgorithm, keyLength, num, gen, recursion);
if (endPos)
*endPos = parser->getPos();
delete parser;
return obj;
}
......@@ -1164,6 +1168,8 @@ Object XRef::fetch(int num, int gen, int recursion) {
objStrs.put(e->offset, objStr);
}
}
if (endPos)
*endPos = -1;
return objStr->getObject(e->gen, num);
}
......@@ -1178,6 +1184,8 @@ Object XRef::fetch(int num, int gen, int recursion) {
constructXRef(&xrefReconstructed);
return fetch(num, gen, ++recursion);
}
if (endPos)
*endPos = -1;
return Object(objNull);
}
......
......@@ -21,7 +21,7 @@
// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
// Copyright (C) 2012, 2013, 2016 Thomas Freitag <Thomas.Freitag@kabelmail.de>
// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
// Copyright (C) 2013, 2017 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2013, 2017, 2019 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com>
// Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
// Copyright (C) 2018 Marek Kasik <mkasik@redhat.com>
......@@ -144,7 +144,10 @@ public:
// Fetch an indirect reference.
Object fetch(const Ref ref, int recursion = 0);
Object fetch(int num, int gen, int recursion = 0);
// If endPos is not null, returns file position after parsing the object. This will
// be a few bytes after the end of the object due to the parser reading ahead.
// Returns -1 if object is in compressed stream.
Object fetch(int num, int gen, int recursion = 0, Goffset *endPos = nullptr);
// Return the document's Info dictionary (if any).
Object getDocInfo();
......
......@@ -9,6 +9,7 @@
* Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
* Copyright (C) 2018 Chinmoy Ranjan Pradhan <chinmoyrp65@protonmail.com>
* Copyright (C) 2018 Oliver Sander <oliver.sander@tu-dresden.de>
* Copyright (C) 2019 Adrian Johnson <ajohnson@redneon.com>
*
* 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
......@@ -859,6 +860,58 @@ FormFieldSignature::SignatureType FormFieldSignature::signatureType() const
return sigType;
}
void FormFieldSignature::setSignatureType(SignatureType type)
{
FormWidgetSignature* fws = static_cast<FormWidgetSignature*>(m_formData->fm);
switch (type)
{
case AdbePkcs7sha1:
fws->setSignatureType(adbe_pkcs7_sha1);
break;
case AdbePkcs7detached:
fws->setSignatureType(adbe_pkcs7_detached);
break;
case EtsiCAdESdetached:
fws->setSignatureType(ETSI_CAdES_detached);
break;
}
}
bool FormFieldSignature::sign(const QString& saveFilename, const QString& certNickname, const QString& password,
DigestAlgorithm digestAlg, const QString& reason)
{
FormWidgetSignature* fws = static_cast<FormWidgetSignature*>(m_formData->fm);
const char* digest = nullptr;
const char* rs = nullptr;
char* pw = password.isEmpty() ? nullptr : strdup(password.toUtf8().constData());
char* name = strdup(certNickname.toUtf8().constData());
char* filename = strdup(saveFilename.toUtf8().constData());
switch (digestAlg)
{
case SHA1:
digest = "SHA1";
break;
case SHA256:
digest = "SHA256";
break;
case SHA384:
digest = "SHA384";
break;
case SHA512:
digest = "SHA512";
break;
default:
digest = "SHA256";
break;
}
if (!reason.isEmpty())
rs = reason.toUtf8().constData();
bool ok = fws->signDocument(filename, name, digest, pw, rs);
free(name);
free(pw);
return ok;
}
SignatureValidationInfo FormFieldSignature::validate(ValidateOptions opt) const
{
return validate(opt, QDateTime());
......
......@@ -8,6 +8,7 @@
* Copyright (C) 2018, Andre Heinecke <aheinecke@intevation.de>
* Copyright (C) 2018, Chinmoy Ranjan Pradhan <chinmoyrp65@protonmail.com>
* Copyright (C) 2018, Oliver Sander <oliver.sander@tu-dresden.de>
* Copyright (C) 2019, Adrian Johnson <ajohnson@redneon.com>
*
* 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
......@@ -36,6 +37,7 @@
#include "poppler-export.h"
#include "poppler-annotation.h"
class Object;
class Page;
class FormWidget;
class FormWidgetButton;
......@@ -690,6 +692,13 @@ namespace Poppler {
ValidateForceRevalidation = 2, ///< Force revalidation of the certificate.
};
enum DigestAlgorithm {
SHA1 = 1,
SHA256 = 2,
SHA384 = 3,
SHA512 = 4,
};
/// \cond PRIVATE
FormFieldSignature(DocumentData *doc, ::Page *p, ::FormWidgetSignature *w);
/// \endcond
......@@ -703,6 +712,20 @@ namespace Poppler {
*/
SignatureType signatureType() const;
void setSignatureType(SignatureType type);
/**
Sign the whole document in this signature field.
@param certNickname nickname of the signing certificate in the mozilla database
@param password password to unlock the private key
(may be empty if no password is set)
@param digestAlg digest algorithm to be used in the signature
@param reason a reason for the signature written to the signature field
*/
bool sign(const QString& saveFilename, const QString& certNickname, const QString& password,
DigestAlgorithm digestAlg = SHA256, const QString& reason = QString());
/**
Validate the signature with now as validation time.
......
......@@ -6,6 +6,7 @@ pdfsig \- Portable Document Format (PDF) digital signatures tool
.B pdfsig
[options]
.RI [ PDF-file ]
.RI [ Output-file ]
.SH DESCRIPTION
.B pdfsig
verifies the digital signatures in a PDF document.
......@@ -14,6 +15,7 @@ It also displays the identity of each signer
the time and date of the signature, the hash algorithm used for signing,
the type of the signature as stated in the PDF and
the signed ranges with a statement wether the total document is signed.
Moreover, with option -sign it can sign a PDF document.
.PP
The signer certificate validation uses the trusted certificates stored in the
Network Security Services (NSS) Database. The NSS Database is searched for in the following locations:
......@@ -37,6 +39,24 @@ Do not validate the certificate.
.TP
.B \-dump
Dump all signatures into current directory.
.B \-sign " number"
Sign the document in the signature field with the given number.
.TP
.B \-nick " nickname"
Use the certificate with the given nickname for signing.
.TP
.B \-kpw " password"
Use the given password for the signing key
(this might be missing if the key isn't password protected).
.TP
.B \-digest " algorithm"
Use the given digest algorithm for signing (default: SHA256).
.TP
.B \-reason " reason"
Set the given reason string for the signature (default: no reason set).
.TP
.B \-etsi
Create a signature of type ETSI.CAdES.detached instead of adbe.pkcs7.detached.
.TP
.B \-v
Print copyright and version information.
......
......@@ -122,6 +122,12 @@ static bool printVersion = false;
static bool printHelp = false;
static bool dontVerifyCert = false;
static bool dumpSignatures = false;
static bool etsiCAdESdetached = false;
static int signatureNumber = 0;
static char certNickname[256] = "";
static char password[256] = "";
static char digestName[256] = "SHA256";
static char reason[256] = "";
static const ArgDesc argDesc[] = {
{"-nssdir", argGooString, &nssDir, 0,
......@@ -130,7 +136,18 @@ static const ArgDesc argDesc[] = {
"don't perform certificate validation"},
{"-dump", argFlag, &dumpSignatures, 0,
"dump all signatures into current directory"},
{"-sign", argInt, &signatureNumber, 0,
"sign the document in the signature field with the given number"},
{"-etsi", argFlag, &etsiCAdESdetached , 0,
"create a signature of type ETSI.CAdES.detached instead of adbe.pkcs7.detached"},
{"-nick", argString, &certNickname, 256,
"use the certificate with the given nickname for signing"},
{"-kpw", argString, &password, 256,
"password for the signing key (might be missing if the key isn't password protected)"},
{"-digest", argString, &digestName, 256,
"name of the digest algorithm (default: SHA256)"},
{"-reason", argString, &reason, 256,
"reason for signing (default: no reason given)"},
{"-v", argFlag, &printVersion, 0,
"print copyright and version info"},
{"-h", argFlag, &printHelp, 0,
......@@ -159,19 +176,25 @@ int main(int argc, char *argv[])
ok = parseArgs(argDesc, &argc, argv);
if (!ok || argc != 2 || printVersion || printHelp) {
if (!ok || (signatureNumber > 0 && argc != 3) ||
(signatureNumber == 0 && argc != 2) || printVersion || printHelp) {
fprintf(stderr, "pdfsig version %s\n", PACKAGE_VERSION);
fprintf(stderr, "%s\n", popplerCopyright);
fprintf(stderr, "%s\n", xpdfCopyright);
if (signatureNumber > 0 && argc == 2) {
fprintf(stderr, "An output filename for the signed document must be given\n");
exitCode = 2;
goto end;
}
if (!printVersion) {
printUsage("pdfsig", "<PDF-file>", argDesc);
printUsage("pdfsig", "<PDF-file> [<output-file>]", argDesc);
}
if (printVersion || printHelp)
exitCode = 0;
goto end;
}
fileName = new GooString(argv[argc - 1]);
fileName = new GooString(argv[1]);
SignatureHandler::setNSSDir(nssDir);
......@@ -186,6 +209,39 @@ int main(int argc, char *argv[])
sig_widgets = doc->getSignatureWidgets();
sigCount = sig_widgets.size();
if (signatureNumber > static_cast<int>(sigCount)) {
printf("File '%s' does not contain a signature with number %d\n",
fileName->c_str(), signatureNumber);
exitCode = 2;
goto end;
} else if (signatureNumber > 0) {
if (strlen(certNickname) == 0) {
printf("A nickname of the signing certificate must be given\n");
exitCode = 2;
goto end;
}
FormWidgetSignature* fws = sig_widgets.at(signatureNumber-1);
Goffset file_size = 0;
GooString* sig = fws->getCheckedSignature(&file_size);
if (sig) {
delete sig;
printf("Signature number %d is already signed\n", signatureNumber);
exitCode = 2;
goto end;
}
if (etsiCAdESdetached)
fws->setSignatureType(ETSI_CAdES_detached);
const char* pw = (strlen(password) == 0) ? nullptr : password;
const char* rs = (strlen(reason) == 0) ? nullptr : reason;
if (fws->signDocument(argv[2], certNickname, digestName, pw, rs)) {
exitCode = 0;
goto end;
} else {
exitCode = 3;
goto end;
}
}
if (sigCount >= 1) {
if (dumpSignatures) {
printf("Dumping Signatures: %u\n", sigCount);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment