Signature plugin: digital signing

This commit is contained in:
Jakub Melka 2022-05-22 17:17:06 +02:00
parent aebed28c6d
commit 3d6954dc41
4 changed files with 241 additions and 53 deletions

View File

@ -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;

View File

@ -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);

View File

@ -23,6 +23,7 @@
#include "pdfdocumentbuilder.h"
#include "certificatemanagerdialog.h"
#include "signdialog.h"
#include "pdfdocumentwriter.h"
#include <QAction>
#include <QToolButton>
@ -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<int>(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();
}
}

View File

@ -8854,6 +8854,98 @@ return rootNodeReference;</property>
<property name="functionDescription">Creates file specification for external file.</property>
<property name="returnType">_PDFObjectReference</property>
</QObject>
<QObject class="codegen::GeneratedFunction">
<property name="objectName"></property>
<property name="items">
<QObject class="codegen::GeneratedAction">
<property name="objectName"></property>
<property name="items">
<QObject class="codegen::GeneratedParameter">
<property name="objectName"></property>
<property name="items"/>
<property name="parameterName">fieldName</property>
<property name="parameterType">_QString</property>
<property name="parameterDescription">Field name</property>
</QObject>
<QObject class="codegen::GeneratedParameter">
<property name="objectName"></property>
<property name="items"/>
<property name="parameterName">kids</property>
<property name="parameterType">_PDFObjectReferenceVector</property>
<property name="parameterDescription">Kids of the signature field.</property>
</QObject>
<QObject class="codegen::GeneratedParameter">
<property name="objectName"></property>
<property name="items"/>
<property name="parameterName">signatureValue</property>
<property name="parameterType">_PDFObjectReference</property>
<property name="parameterDescription">Signature value</property>
</QObject>
</property>
<property name="actionType">Parameters</property>
<property name="variableName"></property>
<property name="variableType">_void</property>
<property name="code"></property>
</QObject>
<QObject class="codegen::GeneratedAction">
<property name="objectName"></property>
<property name="items">
<QObject class="codegen::GeneratedPDFObject">
<property name="objectName"></property>
<property name="items">
<QObject class="codegen::GeneratedPDFObject">
<property name="objectName"></property>
<property name="items"/>
<property name="dictionaryItemName">FT</property>
<property name="objectType">DictionaryItemSimple</property>
<property name="value">WrapName("Sig")</property>
</QObject>
<QObject class="codegen::GeneratedPDFObject">
<property name="objectName"></property>
<property name="items"/>
<property name="dictionaryItemName">Kids</property>
<property name="objectType">DictionaryItemSimple</property>
<property name="value">kids</property>
</QObject>
<QObject class="codegen::GeneratedPDFObject">
<property name="objectName"></property>
<property name="items"/>
<property name="dictionaryItemName">T</property>
<property name="objectType">DictionaryItemSimple</property>
<property name="value">fieldName</property>
</QObject>
<QObject class="codegen::GeneratedPDFObject">
<property name="objectName"></property>
<property name="items"/>
<property name="dictionaryItemName">V</property>
<property name="objectType">DictionaryItemSimple</property>
<property name="value">signatureValue</property>
</QObject>
</property>
<property name="dictionaryItemName"></property>
<property name="objectType">Dictionary</property>
<property name="value"></property>
</QObject>
</property>
<property name="actionType">CreateObject</property>
<property name="variableName">formFieldSignature</property>
<property name="variableType">_PDFObjectReference</property>
<property name="code"></property>
</QObject>
<QObject class="codegen::GeneratedAction">
<property name="objectName"></property>
<property name="items"/>
<property name="actionType">Code</property>
<property name="variableName"></property>
<property name="variableType">_void</property>
<property name="code">return formFieldSignature;</property>
</QObject>
</property>
<property name="functionType">Structure</property>
<property name="functionName">createFormFieldSignature</property>
<property name="functionDescription">Creates form field of type signature.</property>
<property name="returnType">_PDFObjectReference</property>
</QObject>
<QObject class="codegen::GeneratedFunction">
<property name="objectName"></property>
<property name="items">
@ -10938,6 +11030,39 @@ return rootNodeReference;</property>
<property name="functionDescription">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).</property>
<property name="returnType">_void</property>
</QObject>
<QObject class="codegen::GeneratedFunction">
<property name="objectName"></property>
<property name="items">
<QObject class="codegen::GeneratedAction">
<property name="objectName"></property>
<property name="items">
<QObject class="codegen::GeneratedParameter">
<property name="objectName"></property>
<property name="items"/>
<property name="parameterName">locale</property>
<property name="parameterType">_QLocale</property>
<property name="parameterDescription">Locale, from which is language determined</property>
</QObject>
</property>
<property name="actionType">Parameters</property>
<property name="variableName"></property>
<property name="variableType">_void</property>
<property name="code"></property>
</QObject>
<QObject class="codegen::GeneratedAction">
<property name="objectName"></property>
<property name="items"/>
<property name="actionType">Code</property>
<property name="variableName"></property>
<property name="variableType">_void</property>
<property name="code">setLanguage(locale.name());</property>
</QObject>
</property>
<property name="functionType">Structure</property>
<property name="functionName">setLanguage</property>
<property name="functionDescription">Set document language.</property>
<property name="returnType">_void</property>
</QObject>
<QObject class="codegen::GeneratedFunction">
<property name="objectName"></property>
<property name="items">
@ -10995,39 +11120,6 @@ return rootNodeReference;</property>
<property name="functionDescription">Set document language.</property>
<property name="returnType">_void</property>
</QObject>
<QObject class="codegen::GeneratedFunction">
<property name="objectName"></property>
<property name="items">
<QObject class="codegen::GeneratedAction">
<property name="objectName"></property>
<property name="items">
<QObject class="codegen::GeneratedParameter">
<property name="objectName"></property>
<property name="items"/>
<property name="parameterName">locale</property>
<property name="parameterType">_QLocale</property>
<property name="parameterDescription">Locale, from which is language determined</property>
</QObject>
</property>
<property name="actionType">Parameters</property>
<property name="variableName"></property>
<property name="variableType">_void</property>
<property name="code"></property>
</QObject>
<QObject class="codegen::GeneratedAction">
<property name="objectName"></property>
<property name="items"/>
<property name="actionType">Code</property>
<property name="variableName"></property>
<property name="variableType">_void</property>
<property name="code">setLanguage(locale.name());</property>
</QObject>
</property>
<property name="functionType">Structure</property>
<property name="functionName">setLanguage</property>
<property name="functionDescription">Set document language.</property>
<property name="returnType">_void</property>
</QObject>
<QObject class="codegen::GeneratedFunction">
<property name="objectName"></property>
<property name="items">