mirror of https://github.com/JakubMelka/PDF4QT.git
Signature dictionary parsing
This commit is contained in:
parent
958737f359
commit
a319bd611b
|
@ -68,6 +68,7 @@ SOURCES += \
|
|||
sources/pdfpattern.cpp \
|
||||
sources/pdfprogress.cpp \
|
||||
sources/pdfsecurityhandler.cpp \
|
||||
sources/pdfsignaturehandler.cpp \
|
||||
sources/pdfsnapper.cpp \
|
||||
sources/pdftextlayout.cpp \
|
||||
sources/pdfutils.cpp \
|
||||
|
@ -124,6 +125,8 @@ HEADERS += \
|
|||
sources/pdfpattern.h \
|
||||
sources/pdfprogress.h \
|
||||
sources/pdfsecurityhandler.h \
|
||||
sources/pdfsignaturehandler.h \
|
||||
sources/pdfsignaturehandler_impl.h \
|
||||
sources/pdfsnapper.h \
|
||||
sources/pdftextlayout.h \
|
||||
sources/pdfwidgettool.h \
|
||||
|
|
|
@ -898,6 +898,11 @@ PDFFormFieldPointer PDFFormField::parse(const PDFObjectStorage* storage, PDFObje
|
|||
formFieldChoice->m_topIndex = loader.readIntegerFromDictionary(fieldDictionary, "TI", 0);
|
||||
formFieldChoice->m_selection = fieldDictionary->get("I");
|
||||
}
|
||||
|
||||
if (formFieldSignature)
|
||||
{
|
||||
formFieldSignature->m_signature = PDFSignature::parse(storage, fieldDictionary->get("V"));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1612,8 +1617,8 @@ PDFFormManager::MouseEventInfo PDFFormManager::getMouseEventInfo(QWidget* widget
|
|||
|
||||
if (PDFFormField* formField = getFormFieldForWidget(pageAnnotation.annotation->getSelfReference()))
|
||||
{
|
||||
const PDFFormFieldWidgetEditor* editor = getEditor(formField);
|
||||
QRectF annotationRect = editor->getActiveEditorRectangle();
|
||||
PDFFormFieldWidgetEditor* editor = getEditor(formField);
|
||||
QRectF annotationRect = editor ? editor->getActiveEditorRectangle() : QRectF();
|
||||
if (!annotationRect.isValid())
|
||||
{
|
||||
annotationRect = pageAnnotation.annotation->getRectangle();
|
||||
|
@ -1629,7 +1634,7 @@ PDFFormManager::MouseEventInfo PDFFormManager::getMouseEventInfo(QWidget* widget
|
|||
result.formField = formField;
|
||||
result.deviceToWidget = widgetToDevice.inverted();
|
||||
result.mousePosition = result.deviceToWidget.map(point);
|
||||
result.editor = getEditor(formField);
|
||||
result.editor = editor;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "pdfdocument.h"
|
||||
#include "pdfannotation.h"
|
||||
#include "pdfdocumentdrawinterface.h"
|
||||
#include "pdfsignaturehandler.h"
|
||||
|
||||
#include <QTextLayout>
|
||||
|
||||
|
@ -395,9 +396,12 @@ class PDFFormFieldSignature : public PDFFormField
|
|||
public:
|
||||
explicit inline PDFFormFieldSignature() = default;
|
||||
|
||||
const PDFSignature& getSignature() const { return m_signature; }
|
||||
|
||||
private:
|
||||
friend static PDFFormFieldPointer PDFFormField::parse(const PDFObjectStorage* storage, PDFObjectReference reference, PDFFormField* parentField);
|
||||
|
||||
PDFSignature m_signature;
|
||||
};
|
||||
|
||||
/// This class represents interactive form. Interactive form fields can span multiple
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
// Copyright (C) 2020 Jakub Melka
|
||||
//
|
||||
// This file is part of PdfForQt.
|
||||
//
|
||||
// PdfForQt is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PdfForQt is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "pdfsignaturehandler.h"
|
||||
#include "pdfdocument.h"
|
||||
#include "pdfencoding.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFSignatureReference PDFSignatureReference::parse(const PDFObjectStorage* storage, PDFObject object)
|
||||
{
|
||||
PDFSignatureReference result;
|
||||
|
||||
if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
|
||||
{
|
||||
PDFDocumentDataLoaderDecorator loader(storage);
|
||||
|
||||
constexpr const std::array<std::pair<const char*, PDFSignatureReference::TransformMethod>, 3> types = {
|
||||
std::pair<const char*, PDFSignatureReference::TransformMethod>{ "DocMDP", PDFSignatureReference::TransformMethod::DocMDP },
|
||||
std::pair<const char*, PDFSignatureReference::TransformMethod>{ "UR", PDFSignatureReference::TransformMethod::UR },
|
||||
std::pair<const char*, PDFSignatureReference::TransformMethod>{ "FieldMDP", PDFSignatureReference::TransformMethod::FieldMDP }
|
||||
};
|
||||
|
||||
// Jakub Melka: parse the signature reference dictionary
|
||||
result.m_transformMethod = loader.readEnumByName(dictionary->get("TransformMethod"), types.cbegin(), types.cend(), PDFSignatureReference::TransformMethod::Invalid);
|
||||
result.m_transformParams = dictionary->get("TransformParams");
|
||||
result.m_data = dictionary->get("Data");
|
||||
result.m_digestMethod = loader.readNameFromDictionary(dictionary, "DigestMethod");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFSignature PDFSignature::parse(const PDFObjectStorage* storage, PDFObject object)
|
||||
{
|
||||
PDFSignature result;
|
||||
|
||||
if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
|
||||
{
|
||||
PDFDocumentDataLoaderDecorator loader(storage);
|
||||
|
||||
constexpr const std::array<std::pair<const char*, Type>, 2> types = {
|
||||
std::pair<const char*, Type>{ "Sig", Type::Sig },
|
||||
std::pair<const char*, Type>{ "DocTimeStamp", Type::DocTimeStamp }
|
||||
};
|
||||
|
||||
// Jakub Melka: parse the signature dictionary
|
||||
result.m_type = loader.readEnumByName(dictionary->get("Type"), types.cbegin(), types.cend(), Type::Sig);
|
||||
result.m_filter = loader.readNameFromDictionary(dictionary, "Filter");
|
||||
result.m_subfilter = loader.readNameFromDictionary(dictionary, "SubFilter");
|
||||
result.m_contents = loader.readStringFromDictionary(dictionary, "Contents");
|
||||
|
||||
if (dictionary->hasKey("Cert"))
|
||||
{
|
||||
PDFObject certificates = storage->getObject(dictionary->get("Cert"));
|
||||
if (certificates.isString())
|
||||
{
|
||||
result.m_certificates = { loader.readString(certificates) };
|
||||
}
|
||||
else if (certificates.isArray())
|
||||
{
|
||||
result.m_certificates = loader.readStringArray(certificates);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<PDFInteger> byteRangesArray = loader.readIntegerArrayFromDictionary(dictionary, "ByteRange");
|
||||
const size_t byteRangeCount = byteRangesArray.size() / 2;
|
||||
result.m_byteRanges.reserve(byteRangeCount);
|
||||
for (size_t i = 0; i < byteRangeCount; ++i)
|
||||
{
|
||||
ByteRange byteRange = { byteRangesArray[i], byteRangesArray[i + 1] };
|
||||
result.m_byteRanges.push_back(byteRange);
|
||||
}
|
||||
|
||||
result.m_references = loader.readObjectList<PDFSignatureReference>(dictionary->get("References"));
|
||||
std::vector<PDFInteger> changes = loader.readIntegerArrayFromDictionary(dictionary, "Changes");
|
||||
|
||||
if (changes.size() == 3)
|
||||
{
|
||||
result.m_changes = { changes[0], changes[1], changes[2] };
|
||||
}
|
||||
|
||||
result.m_name = loader.readTextStringFromDictionary(dictionary, "Name", QString());
|
||||
result.m_signingDateTime = PDFEncoding::convertToDateTime(loader.readStringFromDictionary(dictionary, "M"));
|
||||
result.m_location = loader.readTextStringFromDictionary(dictionary, "Location", QString());
|
||||
result.m_reason = loader.readTextStringFromDictionary(dictionary, "Reason", QString());
|
||||
result.m_contactInfo = loader.readTextStringFromDictionary(dictionary, "ContactInfo", QString());
|
||||
result.m_R = loader.readIntegerFromDictionary(dictionary, "R", 0);
|
||||
result.m_V = loader.readIntegerFromDictionary(dictionary, "V", 0);
|
||||
result.m_propBuild = dictionary->get("Prop_Build");
|
||||
result.m_propTime = loader.readIntegerFromDictionary(dictionary, "Prop_AuthTime", 0);
|
||||
|
||||
constexpr const std::array<std::pair<const char*, AuthentificationType>, 3> authentificationTypes = {
|
||||
std::pair<const char*, AuthentificationType>{ "PIN", AuthentificationType::PIN },
|
||||
std::pair<const char*, AuthentificationType>{ "Password", AuthentificationType::Password },
|
||||
std::pair<const char*, AuthentificationType>{ "Fingerprint", AuthentificationType::Fingerprint }
|
||||
};
|
||||
result.m_propType = loader.readEnumByName(dictionary->get("Prop_AuthType"), authentificationTypes.cbegin(), authentificationTypes.cend(), AuthentificationType::Invalid);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
|
@ -0,0 +1,153 @@
|
|||
// Copyright (C) 2020 Jakub Melka
|
||||
//
|
||||
// This file is part of PdfForQt.
|
||||
//
|
||||
// PdfForQt is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PdfForQt is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef PDFSIGNATUREHANDLER_H
|
||||
#define PDFSIGNATUREHANDLER_H
|
||||
|
||||
#include "pdfglobal.h"
|
||||
#include "pdfobject.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
class PDFObjectStorage;
|
||||
|
||||
/// Signature reference dictionary.
|
||||
class PDFSignatureReference
|
||||
{
|
||||
public:
|
||||
|
||||
enum class TransformMethod
|
||||
{
|
||||
Invalid,
|
||||
DocMDP,
|
||||
UR,
|
||||
FieldMDP
|
||||
};
|
||||
|
||||
TransformMethod getTransformMethod() const { return m_transformMethod; }
|
||||
const PDFObject& getTransformParams() const { return m_transformParams; }
|
||||
const PDFObject& getData() const { return m_data; }
|
||||
const QByteArray& getDigestMethod() const { return m_digestMethod; }
|
||||
|
||||
/// Tries to parse the signature reference. No exception is thrown, in case of error,
|
||||
/// invalid signature reference object is returned.
|
||||
/// \param storage Object storage
|
||||
/// \param object Object containing the signature
|
||||
static PDFSignatureReference parse(const PDFObjectStorage* storage, PDFObject object);
|
||||
|
||||
private:
|
||||
TransformMethod m_transformMethod = TransformMethod::Invalid;
|
||||
PDFObject m_transformParams;
|
||||
PDFObject m_data;
|
||||
QByteArray m_digestMethod;
|
||||
};
|
||||
|
||||
/// Signature dictionary. Contains digital signature. This signature can be validated by signature validator.
|
||||
/// This object contains certificates, digital signatures, and other information about signature.
|
||||
class PDFSignature
|
||||
{
|
||||
public:
|
||||
|
||||
enum class Type
|
||||
{
|
||||
Invalid,
|
||||
Sig,
|
||||
DocTimeStamp
|
||||
};
|
||||
|
||||
struct ByteRange
|
||||
{
|
||||
PDFInteger offset = 0;
|
||||
PDFInteger size = 0;
|
||||
};
|
||||
|
||||
using ByteRanges = std::vector<ByteRange>;
|
||||
|
||||
struct Changes
|
||||
{
|
||||
PDFInteger pagesAltered = 0;
|
||||
PDFInteger fieldsAltered = 0;
|
||||
PDFInteger fieldsFilled = 0;
|
||||
};
|
||||
|
||||
enum class AuthentificationType
|
||||
{
|
||||
Invalid,
|
||||
PIN,
|
||||
Password,
|
||||
Fingerprint
|
||||
};
|
||||
|
||||
/// Tries to parse the signature. No exception is thrown, in case of error,
|
||||
/// invalid signature object is returned.
|
||||
/// \param storage Object storage
|
||||
/// \param object Object containing the signature
|
||||
static PDFSignature parse(const PDFObjectStorage* storage, PDFObject object);
|
||||
|
||||
Type getType() const { return m_type; }
|
||||
const QByteArray& getFilter() const { return m_filter; }
|
||||
const QByteArray& getSubfilter() const { return m_subfilter; }
|
||||
const QByteArray& getContents() const { return m_contents; }
|
||||
const std::vector<QByteArray>* getCertificates() const { return m_certificates.has_value() ? &m_certificates.value() : nullptr; }
|
||||
const ByteRanges& getByteRanges() const { return m_byteRanges; }
|
||||
const std::vector<PDFSignatureReference>& getReferences() const { return m_references; }
|
||||
const Changes* getChanges() const { return m_changes.has_value() ? &m_changes.value() : nullptr; }
|
||||
|
||||
const QString& getName() const { return m_name; }
|
||||
const QDateTime& getSigningDateTime() const { return m_signingDateTime; }
|
||||
const QString& getLocation() const { return m_location; }
|
||||
const QString& getReason() const { return m_reason; }
|
||||
const QString& getContactInfo() const { return m_contactInfo; }
|
||||
PDFInteger getR() const { return m_R; }
|
||||
PDFInteger getV() const { return m_V; }
|
||||
const PDFObject& getPropBuild() const { return m_propBuild; }
|
||||
PDFInteger getPropTime() const { return m_propTime; }
|
||||
AuthentificationType getAuthentificationType() const { return m_propType; }
|
||||
|
||||
private:
|
||||
Type m_type = Type::Invalid;
|
||||
QByteArray m_filter; ///< Preferred signature handler name
|
||||
QByteArray m_subfilter; ///< Describes encoding of signature
|
||||
QByteArray m_contents;
|
||||
std::optional<std::vector<QByteArray>> m_certificates; ///< Certificate chain (only for adbe.x509.rsa_sha1)
|
||||
ByteRanges m_byteRanges;
|
||||
std::vector<PDFSignatureReference> m_references;
|
||||
std::optional<Changes> m_changes;
|
||||
|
||||
QString m_name; ///< Name of signer. Should rather be extracted from signature.
|
||||
QDateTime m_signingDateTime; ///< Signing date and time. Should be extracted from signature, if possible.
|
||||
QString m_location; ///< CPU hostname or physical location of signing
|
||||
QString m_reason; ///< Reason for signing
|
||||
QString m_contactInfo; ///< Contact info for verifying the signature
|
||||
PDFInteger m_R; ///< Version of signature handler. Obsolete.
|
||||
PDFInteger m_V; ///< Version of signature dictionary format. 1 if References should be used.
|
||||
PDFObject m_propBuild;
|
||||
PDFInteger m_propTime = 0;
|
||||
AuthentificationType m_propType = AuthentificationType::Invalid;
|
||||
};
|
||||
|
||||
class PDFSignatureHandler
|
||||
{
|
||||
public:
|
||||
PDFSignatureHandler();
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFSIGNATUREHANDLER_H
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (C) 2020 Jakub Melka
|
||||
//
|
||||
// This file is part of PdfForQt.
|
||||
//
|
||||
// PdfForQt is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PdfForQt is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef PDFSIGNATUREHANDLER_IMPL_H
|
||||
#define PDFSIGNATUREHANDLER_IMPL_H
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFSIGNATUREHANDLER_IMPL_H
|
Loading…
Reference in New Issue