From 3d6954dc415b184c8c448a0250d886ec4beaac5d Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Sun, 22 May 2022 17:17:06 +0200 Subject: [PATCH] Signature plugin: digital signing --- Pdf4QtLib/sources/pdfdocumentbuilder.cpp | 41 ++++- Pdf4QtLib/sources/pdfdocumentbuilder.h | 19 ++- .../SignaturePlugin/signatureplugin.cpp | 76 ++++++++- generated_code_definition.xml | 158 ++++++++++++++---- 4 files changed, 241 insertions(+), 53 deletions(-) diff --git a/Pdf4QtLib/sources/pdfdocumentbuilder.cpp b/Pdf4QtLib/sources/pdfdocumentbuilder.cpp index e7b04a5..900278d 100644 --- a/Pdf4QtLib/sources/pdfdocumentbuilder.cpp +++ b/Pdf4QtLib/sources/pdfdocumentbuilder.cpp @@ -4542,6 +4542,31 @@ PDFObjectReference PDFDocumentBuilder::createFileSpecification(QString fileName) } +PDFObjectReference PDFDocumentBuilder::createFormFieldSignature(QString fieldName, + PDFObjectReferenceVector kids, + PDFObjectReference signatureValue) +{ + PDFObjectFactory objectBuilder; + + objectBuilder.beginDictionary(); + objectBuilder.beginDictionaryItem("FT"); + objectBuilder << WrapName("Sig"); + objectBuilder.endDictionaryItem(); + objectBuilder.beginDictionaryItem("Kids"); + objectBuilder << kids; + objectBuilder.endDictionaryItem(); + objectBuilder.beginDictionaryItem("T"); + objectBuilder << fieldName; + objectBuilder.endDictionaryItem(); + objectBuilder.beginDictionaryItem("V"); + objectBuilder << signatureValue; + objectBuilder.endDictionaryItem(); + objectBuilder.endDictionary(); + PDFObjectReference formFieldSignature = addObject(objectBuilder.takeObject()); + return formFieldSignature; +} + + PDFObjectReference PDFDocumentBuilder::createSignatureDictionary(QByteArray filter, QByteArray subfilter, QByteArray contents, @@ -5075,6 +5100,14 @@ void PDFDocumentBuilder::setFormFieldValue(PDFObjectReference formField, } +void PDFDocumentBuilder::setLanguage(QLocale locale) +{ + PDFObjectFactory objectBuilder; + + setLanguage(locale.name()); +} + + void PDFDocumentBuilder::setLanguage(QString language) { PDFObjectFactory objectBuilder; @@ -5089,14 +5122,6 @@ void PDFDocumentBuilder::setLanguage(QString language) } -void PDFDocumentBuilder::setLanguage(QLocale locale) -{ - PDFObjectFactory objectBuilder; - - setLanguage(locale.name()); -} - - void PDFDocumentBuilder::setOutline(PDFObjectReference outline) { PDFObjectFactory objectBuilder; diff --git a/Pdf4QtLib/sources/pdfdocumentbuilder.h b/Pdf4QtLib/sources/pdfdocumentbuilder.h index efef069..3f27651 100644 --- a/Pdf4QtLib/sources/pdfdocumentbuilder.h +++ b/Pdf4QtLib/sources/pdfdocumentbuilder.h @@ -1226,6 +1226,15 @@ public: PDFObjectReference createFileSpecification(QString fileName); + /// Creates form field of type signature. + /// \param fieldName Field name + /// \param kids Kids of the signature field. + /// \param signatureValue Signature value + PDFObjectReference createFormFieldSignature(QString fieldName, + PDFObjectReferenceVector kids, + PDFObjectReference signatureValue); + + /// Creates signature dictionary used for preparation in signing process. Can define parameters of the /// signature. /// \param filter Filter (for example, Adobe.PPKLite, Entrust.PPKEF, CiCi.SignIt, ...) @@ -1441,6 +1450,11 @@ public: PDFObject value); + /// Set document language. + /// \param locale Locale, from which is language determined + void setLanguage(QLocale locale); + + /// Set document language. /// \param language Document language. It should be a language identifier, as defined in ISO 639 /// and ISO 3166. For example, "en-US", where first two letter means language code (en = @@ -1448,11 +1462,6 @@ public: void setLanguage(QString language); - /// Set document language. - /// \param locale Locale, from which is language determined - void setLanguage(QLocale locale); - - /// Set document outline. /// \param outline Document outline root void setOutline(PDFObjectReference outline); diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.cpp b/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.cpp index d5a28e8..3dea0f0 100644 --- a/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.cpp +++ b/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.cpp @@ -23,6 +23,7 @@ #include "pdfdocumentbuilder.h" #include "certificatemanagerdialog.h" #include "signdialog.h" +#include "pdfdocumentwriter.h" #include #include @@ -325,16 +326,77 @@ void SignaturePlugin::onSignDigitally() SignDialog dialog(m_dataExchangeInterface->getMainWindow(), m_scene.isEmpty()); if (dialog.exec() == SignDialog::Accepted) { - QByteArray data = "xxgaghre"; - QByteArray result; - SignatureFactory::sign(dialog.getCertificatePath(), dialog.getPassword(), data, result); - - for (int i = 1; i < 15; ++i) + QByteArray data = "SampleDataToBeSigned" + QByteArray::number(QDateTime::currentMSecsSinceEpoch()); + QByteArray signature; + if (!SignatureFactory::sign(dialog.getCertificatePath(), dialog.getPassword(), data, signature)) { - data.append(data); + QMessageBox::critical(m_widget, tr("Error"), tr("Failed to create digital signature.")); + return; } - SignatureFactory::sign(dialog.getCertificatePath(), dialog.getPassword(), data, result); + pdf::PDFInteger offsetMark = 123456789123; + constexpr const char* offsetMarkString = "123456789123"; + const auto offsetMarkStringLength = std::strlen(offsetMarkString); + + pdf::PDFDocumentBuilder builder(m_document); + pdf::PDFObjectReference signatureDictionary = builder.createSignatureDictionary("Adobe.PPKLite", "adbe.pkcs7.detached", signature, QDateTime::currentDateTime(), offsetMark); + pdf::PDFObjectReference formField = builder.createFormFieldSignature("signature", { }, signatureDictionary); + builder.createAcroForm({ formField }); + + pdf::PDFDocument signedDocument = builder.build(); + + // 1) Save the document with incorrect signature + QBuffer buffer; + pdf::PDFDocumentWriter writer(m_widget->getDrawWidgetProxy()->getProgress()); + buffer.open(QBuffer::ReadWrite); + writer.write(&buffer, &signedDocument); + + const int indexOfSignature = buffer.data().indexOf(signature.toHex()); + if (indexOfSignature == -1) + { + QMessageBox::critical(m_widget, tr("Error"), tr("Failed to create digital signature.")); + buffer.close(); + return; + } + + // 2) Write ranges to be checked + const pdf::PDFInteger i1 = 0; + const pdf::PDFInteger i2 = indexOfSignature; + const pdf::PDFInteger i3 = i2 + signature.size() * 2; + const pdf::PDFInteger i4 = buffer.data().size() - i3; + + auto writeInt = [&](pdf::PDFInteger offset) + { + QString offsetString = QString::number(offset); + offsetString = offsetString.leftJustified(static_cast(offsetMarkStringLength), ' ', true); + const auto index = buffer.data().lastIndexOf(QString(offsetMarkString), indexOfSignature); + buffer.seek(index); + buffer.write(offsetString.toLocal8Bit()); + }; + + writeInt(i4); + writeInt(i3); + writeInt(i2); + writeInt(i1); + + // 3) Sign the data + QByteArray dataToBeSigned; + buffer.seek(i1); + dataToBeSigned.append(buffer.read(i2)); + buffer.seek(i3); + dataToBeSigned.append(buffer.read(i4)); + + if (!SignatureFactory::sign(dialog.getCertificatePath(), dialog.getPassword(), dataToBeSigned, signature)) + { + QMessageBox::critical(m_widget, tr("Error"), tr("Failed to create digital signature.")); + buffer.close(); + return; + } + + buffer.seek(i2); + buffer.write(signature.toHex()); + + buffer.close(); } } diff --git a/generated_code_definition.xml b/generated_code_definition.xml index 8af42b7..e7ce281 100644 --- a/generated_code_definition.xml +++ b/generated_code_definition.xml @@ -8854,6 +8854,98 @@ return rootNodeReference; Creates file specification for external file. _PDFObjectReference + + + + + + + + + + fieldName + _QString + Field name + + + + + kids + _PDFObjectReferenceVector + Kids of the signature field. + + + + + signatureValue + _PDFObjectReference + Signature value + + + Parameters + + _void + + + + + + + + + + + + FT + DictionaryItemSimple + WrapName("Sig") + + + + + Kids + DictionaryItemSimple + kids + + + + + T + DictionaryItemSimple + fieldName + + + + + V + DictionaryItemSimple + signatureValue + + + + Dictionary + + + + CreateObject + formFieldSignature + _PDFObjectReference + + + + + + Code + + _void + return formFieldSignature; + + + Structure + createFormFieldSignature + Creates form field of type signature. + _PDFObjectReference + @@ -10938,6 +11030,39 @@ return rootNodeReference; Sets form field value. Value must be correct for this form field, no checking is performed. Also, if you use this function, annotation widgets, which are attached to this form field, should also be updated (for example, appearance state and sometimes appearance streams). _void + + + + + + + + + + locale + _QLocale + Locale, from which is language determined + + + Parameters + + _void + + + + + + Code + + _void + setLanguage(locale.name()); + + + Structure + setLanguage + Set document language. + _void + @@ -10995,39 +11120,6 @@ return rootNodeReference; Set document language. _void - - - - - - - - - - locale - _QLocale - Locale, from which is language determined - - - Parameters - - _void - - - - - - Code - - _void - setLanguage(locale.name()); - - - Structure - setLanguage - Set document language. - _void -