Signature plugin: invisible digital signature

This commit is contained in:
Jakub Melka
2022-05-28 19:42:52 +02:00
parent 3d6954dc41
commit c7e7b76e5b
7 changed files with 497 additions and 120 deletions

View File

@ -29,6 +29,7 @@
#include <QToolButton>
#include <QMainWindow>
#include <QMessageBox>
#include <QFileDialog>
namespace pdfplugin
{
@ -334,15 +335,39 @@ void SignaturePlugin::onSignDigitally()
return;
}
QString signatureName = QString("pdf4qt_signature_%1").arg(QString::number(QDateTime::currentMSecsSinceEpoch()));
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);
pdf::PDFObjectReference formField = builder.createFormFieldSignature(signatureName, { }, signatureDictionary);
builder.createAcroForm({ formField });
if (dialog.getSignMethod() == SignDialog::SignDigitallyInvisible)
{
const pdf::PDFCatalog* catalog = m_document->getCatalog();
if (catalog->getPageCount() > 0)
{
const pdf::PDFObjectReference pageReference = catalog->getPage(0)->getPageReference();
builder.createInvisibleFormFieldWidget(formField, pageReference);
}
}
QString reasonText = dialog.getReasonText();
if (!reasonText.isEmpty())
{
builder.setSignatureReason(signatureDictionary, reasonText);
}
QString contactInfoText = dialog.getContactInfoText();
if (!contactInfoText.isEmpty())
{
builder.setSignatureContactInfo(signatureDictionary, contactInfoText);
}
pdf::PDFDocument signedDocument = builder.build();
// 1) Save the document with incorrect signature
@ -361,8 +386,8 @@ void SignaturePlugin::onSignDigitally()
// 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 i2 = indexOfSignature - 1;
const pdf::PDFInteger i3 = i2 + signature.size() * 2 + 2;
const pdf::PDFInteger i4 = buffer.data().size() - i3;
auto writeInt = [&](pdf::PDFInteger offset)
@ -393,13 +418,31 @@ void SignaturePlugin::onSignDigitally()
return;
}
buffer.seek(i2);
buffer.seek(i2 + 1);
buffer.write(signature.toHex());
buffer.close();
QString fileName = QFileDialog::getSaveFileName(m_dataExchangeInterface->getMainWindow(), tr("Save Signed Document"), getSignedFileName(), tr("Portable Document (*.pdf);;All files (*.*)"));
if (!fileName.isEmpty())
{
QFile signedFile(fileName);
if (signedFile.open(QFile::WriteOnly | QFile::Truncate))
{
signedFile.write(buffer.data());
signedFile.close();
}
}
}
}
QString SignaturePlugin::getSignedFileName() const
{
QFileInfo fileInfo(m_dataExchangeInterface->getOriginalFileName());
return fileInfo.path() + "/" + fileInfo.baseName() + "_SIGNED.pdf";
}
void SignaturePlugin::onOpenCertificatesManager()
{
CertificateManagerDialog dialog(m_dataExchangeInterface->getMainWindow());

View File

@ -112,6 +112,8 @@ private:
void updateGraphics();
void updateDockWidget();
QString getSignedFileName() const;
std::array<QAction*, LastAction> m_actions;
std::array<pdf::PDFWidgetTool*, LastTool> m_tools;
pdf::PDFPageContentEditorWidget* m_editorWidget;

View File

@ -68,6 +68,16 @@ QString SignDialog::getPassword() const
return ui->certificatePasswordEdit->text();
}
QString SignDialog::getReasonText() const
{
return ui->reasonEdit->text();
}
QString SignDialog::getContactInfoText() const
{
return ui->contactInfoEdit->text();
}
void SignDialog::accept()
{
// Check certificate

View File

@ -47,6 +47,8 @@ public:
SignMethod getSignMethod() const;
QString getCertificatePath() const;
QString getPassword() const;
QString getReasonText() const;
QString getContactInfoText() const;
private:
Ui::SignDialog* ui;