mirror of https://github.com/JakubMelka/PDF4QT.git
Signature plugin: digital signing
This commit is contained in:
parent
aebed28c6d
commit
3d6954dc41
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
Loading…
Reference in New Issue