| /* poppler-form.h: qt interface to poppler |
| * Copyright (C) 2007-2008, 2011, Pino Toscano <pino@kde.org> |
| * Copyright (C) 2008, 2011, 2012, 2015-2019 Albert Astals Cid <aacid@kde.org> |
| * Copyright (C) 2011 Carlos Garcia Campos <carlosgc@gnome.org> |
| * Copyright (C) 2012, Adam Reichold <adamreichold@myopera.com> |
| * Copyright (C) 2016, Hanno Meyer-Thurow <h.mth@web.de> |
| * Copyright (C) 2017, Hans-Ulrich Jüttner <huj@froreich-bioscientia.de> |
| * Copyright (C) 2018, Andre Heinecke <aheinecke@intevation.de> |
| * Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich |
| * Copyright (C) 2018 Chinmoy Ranjan Pradhan <chinmoyrp65@protonmail.com> |
| * Copyright (C) 2018 Oliver Sander <oliver.sander@tu-dresden.de> |
| * Copyright (C) 2019 João Netto <joaonetto901@gmail.com> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2, or (at your option) |
| * any later version. |
| * |
| * This program 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 General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
| */ |
| |
| #include "poppler-qt5.h" |
| |
| #include <QtCore/QSizeF> |
| |
| #include <Form.h> |
| #include <Object.h> |
| #include <Link.h> |
| #include <SignatureInfo.h> |
| #include <CertificateInfo.h> |
| |
| #include "poppler-form.h" |
| #include "poppler-page-private.h" |
| #include "poppler-private.h" |
| #include "poppler-annotation-helper.h" |
| |
| #include <math.h> |
| #include <ctype.h> |
| |
| #ifdef ENABLE_NSS3 |
| #include <hasht.h> |
| #endif |
| |
| namespace { |
| |
| Qt::Alignment formTextAlignment(::FormWidget *fm) |
| { |
| Qt::Alignment qtalign = Qt::AlignLeft; |
| switch (fm->getField()->getTextQuadding()) |
| { |
| case quaddingCentered: |
| qtalign = Qt::AlignHCenter; |
| break; |
| case quaddingRightJustified: |
| qtalign = Qt::AlignRight; |
| break; |
| case quaddingLeftJustified: |
| qtalign = Qt::AlignLeft; |
| } |
| return qtalign; |
| } |
| |
| } |
| |
| namespace Poppler { |
| |
| FormFieldIcon::FormFieldIcon(FormFieldIconData *data) |
| : d_ptr(data) |
| { |
| } |
| |
| FormFieldIcon::FormFieldIcon(const FormFieldIcon &ffIcon) |
| { |
| d_ptr = new FormFieldIconData; |
| d_ptr->icon = ffIcon.d_ptr->icon; |
| } |
| |
| FormFieldIcon& FormFieldIcon::operator=(const FormFieldIcon &ffIcon) |
| { |
| if(this != &ffIcon) |
| { |
| delete d_ptr; |
| d_ptr = nullptr; |
| |
| d_ptr = new FormFieldIconData; |
| *d_ptr = *ffIcon.d_ptr; |
| } |
| |
| return *this; |
| } |
| |
| FormFieldIcon::~FormFieldIcon() |
| { |
| delete d_ptr; |
| } |
| |
| FormField::FormField(FormFieldData &dd) |
| : m_formData(&dd) |
| { |
| const int rotation = m_formData->page->getRotate(); |
| // reading the coords |
| double left, top, right, bottom; |
| m_formData->fm->getRect(&left, &bottom, &right, &top); |
| // build a normalized transform matrix for this page at 100% scale |
| GfxState gfxState( 72.0, 72.0, m_formData->page->getCropBox(), rotation, true ); |
| const double * gfxCTM = gfxState.getCTM(); |
| double MTX[6]; |
| double pageWidth = m_formData->page->getCropWidth(); |
| double pageHeight = m_formData->page->getCropHeight(); |
| // landscape and seascape page rotation: be sure to use the correct (== rotated) page size |
| if (((rotation / 90) % 2) == 1) |
| qSwap(pageWidth, pageHeight); |
| for ( int i = 0; i < 6; i+=2 ) |
| { |
| MTX[i] = gfxCTM[i] / pageWidth; |
| MTX[i+1] = gfxCTM[i+1] / pageHeight; |
| } |
| QPointF topLeft; |
| XPDFReader::transform( MTX, qMin( left, right ), qMax( top, bottom ), topLeft ); |
| QPointF bottomRight; |
| XPDFReader::transform( MTX, qMax( left, right ), qMin( top, bottom ), bottomRight ); |
| m_formData->box = QRectF(topLeft, QSizeF(bottomRight.x() - topLeft.x(), bottomRight.y() - topLeft.y())); |
| } |
| |
| FormField::~FormField() |
| { |
| delete m_formData; |
| m_formData = nullptr; |
| } |
| |
| QRectF FormField::rect() const |
| { |
| return m_formData->box; |
| } |
| |
| int FormField::id() const |
| { |
| return m_formData->fm->getID(); |
| } |
| |
| QString FormField::name() const |
| { |
| QString name; |
| if (const GooString *goo = m_formData->fm->getPartialName()) |
| { |
| name = QString::fromLatin1(goo->c_str()); |
| } |
| return name; |
| } |
| |
| void FormField::setName(const QString &name) const |
| { |
| GooString * goo = QStringToGooString( name ); |
| m_formData->fm->setPartialName(*goo); |
| delete goo; |
| } |
| |
| QString FormField::fullyQualifiedName() const |
| { |
| QString name; |
| if (GooString *goo = m_formData->fm->getFullyQualifiedName()) |
| { |
| name = UnicodeParsedString(goo); |
| } |
| return name; |
| } |
| |
| QString FormField::uiName() const |
| { |
| QString name; |
| if (const GooString *goo = m_formData->fm->getAlternateUiName()) |
| { |
| name = QString::fromLatin1(goo->c_str()); |
| } |
| return name; |
| } |
| |
| bool FormField::isReadOnly() const |
| { |
| return m_formData->fm->isReadOnly(); |
| } |
| |
| void FormField::setReadOnly(bool value) |
| { |
| m_formData->fm->setReadOnly(value); |
| } |
| |
| bool FormField::isVisible() const |
| { |
| return !(m_formData->fm->getWidgetAnnotation()->getFlags() & Annot::flagHidden); |
| } |
| |
| void FormField::setVisible(bool value) |
| { |
| unsigned int flags = m_formData->fm->getWidgetAnnotation()->getFlags(); |
| if (value) { |
| flags &= ~Annot::flagHidden; |
| } else { |
| flags |= Annot::flagHidden; |
| } |
| m_formData->fm->getWidgetAnnotation()->setFlags(flags); |
| } |
| |
| bool FormField::isPrintable() const |
| { |
| return (m_formData->fm->getWidgetAnnotation()->getFlags() & Annot::flagPrint); |
| } |
| |
| void FormField::setPrintable(bool value) |
| { |
| unsigned int flags = m_formData->fm->getWidgetAnnotation()->getFlags(); |
| if (value) { |
| flags |= Annot::flagPrint; |
| } else { |
| flags &= ~Annot::flagPrint; |
| } |
| m_formData->fm->getWidgetAnnotation()->setFlags(flags); |
| } |
| |
| Link* FormField::activationAction() const |
| { |
| Link* action = nullptr; |
| if (::LinkAction *act = m_formData->fm->getActivationAction()) |
| { |
| action = PageData::convertLinkActionToLink(act, m_formData->doc, QRectF()); |
| } |
| return action; |
| } |
| |
| Link *FormField::additionalAction(AdditionalActionType type) const |
| { |
| Annot::FormAdditionalActionsType actionType = Annot::actionFieldModified; |
| switch ( type ) |
| { |
| case FieldModified: actionType = Annot::actionFieldModified; break; |
| case FormatField: actionType = Annot::actionFormatField; break; |
| case ValidateField: actionType = Annot::actionValidateField; break; |
| case CalculateField: actionType = Annot::actionCalculateField; break; |
| |
| } |
| |
| Link* action = nullptr; |
| if (::LinkAction *act = m_formData->fm->getAdditionalAction(actionType)) |
| { |
| action = PageData::convertLinkActionToLink(act, m_formData->doc, QRectF()); |
| } |
| return action; |
| } |
| |
| Link *FormField::additionalAction(Annotation::AdditionalActionType type) const |
| { |
| ::AnnotWidget *w = m_formData->fm->getWidgetAnnotation(); |
| if (!w) |
| { |
| return nullptr; |
| } |
| |
| const Annot::AdditionalActionsType actionType = toPopplerAdditionalActionType(type); |
| |
| Link* action = nullptr; |
| if (::LinkAction *act = w->getAdditionalAction(actionType)) |
| { |
| action = PageData::convertLinkActionToLink(act, m_formData->doc, QRectF()); |
| } |
| return action; |
| } |
| |
| FormFieldButton::FormFieldButton(DocumentData *doc, ::Page *p, ::FormWidgetButton *w) |
| : FormField(*new FormFieldData(doc, p, w)) |
| { |
| } |
| |
| FormFieldButton::~FormFieldButton() |
| { |
| } |
| |
| FormFieldButton::FormType FormFieldButton::type() const |
| { |
| return FormField::FormButton; |
| } |
| |
| FormFieldButton::ButtonType FormFieldButton::buttonType() const |
| { |
| FormWidgetButton* fwb = static_cast<FormWidgetButton*>(m_formData->fm); |
| switch (fwb->getButtonType()) |
| { |
| case formButtonCheck: |
| return FormFieldButton::CheckBox; |
| break; |
| case formButtonPush: |
| return FormFieldButton::Push; |
| break; |
| case formButtonRadio: |
| return FormFieldButton::Radio; |
| break; |
| } |
| return FormFieldButton::CheckBox; |
| } |
| |
| QString FormFieldButton::caption() const |
| { |
| FormWidgetButton* fwb = static_cast<FormWidgetButton*>(m_formData->fm); |
| QString ret; |
| if (fwb->getButtonType() == formButtonPush) |
| { |
| Dict *dict = m_formData->fm->getObj()->getDict(); |
| Object obj1 = dict->lookup("MK"); |
| if (obj1.isDict()) |
| { |
| AnnotAppearanceCharacs appearCharacs(obj1.getDict()); |
| if (appearCharacs.getNormalCaption()) |
| { |
| ret = UnicodeParsedString(appearCharacs.getNormalCaption()); |
| } |
| } |
| } |
| else |
| { |
| if (const char *goo = fwb->getOnStr()) |
| { |
| ret = QString::fromUtf8(goo); |
| } |
| } |
| return ret; |
| } |
| |
| FormFieldIcon FormFieldButton::icon() const |
| { |
| FormWidgetButton* fwb = static_cast<FormWidgetButton*>(m_formData->fm); |
| if (fwb->getButtonType() == formButtonPush) |
| { |
| Dict *dict = m_formData->fm->getObj()->getDict(); |
| FormFieldIconData *data = new FormFieldIconData; |
| data->icon = dict; |
| return FormFieldIcon(data); |
| } |
| return FormFieldIcon(nullptr); |
| } |
| |
| void FormFieldButton::setIcon(const FormFieldIcon &icon) |
| { |
| if(FormFieldIconData::getData( icon ) == nullptr) |
| return; |
| |
| FormWidgetButton* fwb = static_cast<FormWidgetButton*>(m_formData->fm); |
| if (fwb->getButtonType() == formButtonPush) |
| { |
| ::AnnotWidget *w = m_formData->fm->getWidgetAnnotation(); |
| FormFieldIconData *data = FormFieldIconData::getData( icon ); |
| if(data->icon != nullptr) |
| w->setNewAppearance(data->icon->lookup("AP")); |
| } |
| } |
| |
| bool FormFieldButton::state() const |
| { |
| FormWidgetButton* fwb = static_cast<FormWidgetButton*>(m_formData->fm); |
| return fwb->getState(); |
| } |
| |
| void FormFieldButton::setState( bool state ) |
| { |
| FormWidgetButton* fwb = static_cast<FormWidgetButton*>(m_formData->fm); |
| fwb->setState((bool)state); |
| } |
| |
| QList<int> FormFieldButton::siblings() const |
| { |
| FormWidgetButton* fwb = static_cast<FormWidgetButton*>(m_formData->fm); |
| ::FormFieldButton* ffb = static_cast< ::FormFieldButton* >(fwb->getField()); |
| if (fwb->getButtonType() == formButtonPush) |
| return QList<int>(); |
| |
| QList<int> ret; |
| for (int i = 0; i < ffb->getNumSiblings(); ++i) |
| { |
| ::FormFieldButton* sibling = static_cast< ::FormFieldButton* >(ffb->getSibling(i)); |
| for (int j = 0; j < sibling->getNumWidgets(); ++j) |
| { |
| FormWidget *w = sibling->getWidget(j); |
| if (w) ret.append(w->getID()); |
| } |
| } |
| |
| return ret; |
| } |
| |
| |
| FormFieldText::FormFieldText(DocumentData *doc, ::Page *p, ::FormWidgetText *w) |
| : FormField(*new FormFieldData(doc, p, w)) |
| { |
| } |
| |
| FormFieldText::~FormFieldText() |
| { |
| } |
| |
| FormField::FormType FormFieldText::type() const |
| { |
| return FormField::FormText; |
| } |
| |
| FormFieldText::TextType FormFieldText::textType() const |
| { |
| FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm); |
| if (fwt->isFileSelect()) |
| return FormFieldText::FileSelect; |
| else if (fwt->isMultiline()) |
| return FormFieldText::Multiline; |
| return FormFieldText::Normal; |
| } |
| |
| QString FormFieldText::text() const |
| { |
| const GooString *goo = static_cast<FormWidgetText*>(m_formData->fm)->getContent(); |
| return UnicodeParsedString(goo); |
| } |
| |
| void FormFieldText::setText( const QString& text ) |
| { |
| FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm); |
| GooString * goo = QStringToUnicodeGooString( text ); |
| fwt->setContent( goo ); |
| delete goo; |
| } |
| |
| bool FormFieldText::isPassword() const |
| { |
| FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm); |
| return fwt->isPassword(); |
| } |
| |
| bool FormFieldText::isRichText() const |
| { |
| FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm); |
| return fwt->isRichText(); |
| } |
| |
| int FormFieldText::maximumLength() const |
| { |
| FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm); |
| const int maxlen = fwt->getMaxLen(); |
| return maxlen > 0 ? maxlen : -1; |
| } |
| |
| Qt::Alignment FormFieldText::textAlignment() const |
| { |
| return formTextAlignment(m_formData->fm); |
| } |
| |
| bool FormFieldText::canBeSpellChecked() const |
| { |
| FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm); |
| return !fwt->noSpellCheck(); |
| } |
| |
| double FormFieldText::getFontSize() const |
| { |
| FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm); |
| return fwt->getTextFontSize(); |
| } |
| |
| void FormFieldText::setFontSize(int fontSize) |
| { |
| FormWidgetText* fwt = static_cast<FormWidgetText*>(m_formData->fm); |
| fwt->setTextFontSize(fontSize); |
| } |
| |
| FormFieldChoice::FormFieldChoice(DocumentData *doc, ::Page *p, ::FormWidgetChoice *w) |
| : FormField(*new FormFieldData(doc, p, w)) |
| { |
| } |
| |
| FormFieldChoice::~FormFieldChoice() |
| { |
| } |
| |
| FormFieldChoice::FormType FormFieldChoice::type() const |
| { |
| return FormField::FormChoice; |
| } |
| |
| FormFieldChoice::ChoiceType FormFieldChoice::choiceType() const |
| { |
| FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm); |
| if (fwc->isCombo()) |
| return FormFieldChoice::ComboBox; |
| return FormFieldChoice::ListBox; |
| } |
| |
| QStringList FormFieldChoice::choices() const |
| { |
| FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm); |
| QStringList ret; |
| int num = fwc->getNumChoices(); |
| ret.reserve(num); |
| for (int i = 0; i < num; ++i) |
| { |
| ret.append(UnicodeParsedString(fwc->getChoice(i))); |
| } |
| return ret; |
| } |
| |
| bool FormFieldChoice::isEditable() const |
| { |
| FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm); |
| return fwc->isCombo() ? fwc->hasEdit() : false; |
| } |
| |
| bool FormFieldChoice::multiSelect() const |
| { |
| FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm); |
| return !fwc->isCombo() ? fwc->isMultiSelect() : false; |
| } |
| |
| QList<int> FormFieldChoice::currentChoices() const |
| { |
| FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm); |
| int num = fwc->getNumChoices(); |
| QList<int> choices; |
| for ( int i = 0; i < num; ++i ) |
| if ( fwc->isSelected( i ) ) |
| choices.append( i ); |
| return choices; |
| } |
| |
| void FormFieldChoice::setCurrentChoices( const QList<int> &choice ) |
| { |
| FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm); |
| fwc->deselectAll(); |
| for ( int i = 0; i < choice.count(); ++i ) |
| fwc->select( choice.at( i ) ); |
| } |
| |
| QString FormFieldChoice::editChoice() const |
| { |
| FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm); |
| |
| if ( fwc->isCombo() && fwc->hasEdit() ) |
| return UnicodeParsedString(fwc->getEditChoice()); |
| else |
| return QString(); |
| } |
| |
| void FormFieldChoice::setEditChoice(const QString& text) |
| { |
| FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm); |
| |
| if ( fwc->isCombo() && fwc->hasEdit() ) |
| { |
| GooString* goo = QStringToUnicodeGooString( text ); |
| fwc->setEditChoice( goo ); |
| delete goo; |
| } |
| } |
| |
| Qt::Alignment FormFieldChoice::textAlignment() const |
| { |
| return formTextAlignment(m_formData->fm); |
| } |
| |
| bool FormFieldChoice::canBeSpellChecked() const |
| { |
| FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm); |
| return !fwc->noSpellCheck(); |
| } |
| |
| class CertificateInfoPrivate |
| { |
| public: |
| struct EntityInfo |
| { |
| QString common_name; |
| QString email_address; |
| QString org_name; |
| QString distinguished_name; |
| }; |
| |
| EntityInfo issuer_info; |
| EntityInfo subject_info; |
| QByteArray certificate_der; |
| QByteArray serial_number; |
| QByteArray public_key; |
| QDateTime validity_start; |
| QDateTime validity_end; |
| int public_key_type; |
| int public_key_strength; |
| int ku_extensions; |
| int version; |
| bool is_self_signed; |
| bool is_null; |
| }; |
| |
| CertificateInfo::CertificateInfo(CertificateInfoPrivate* priv) |
| : d_ptr( priv ) |
| { |
| } |
| |
| CertificateInfo::CertificateInfo(const CertificateInfo &other) |
| : d_ptr( other.d_ptr ) |
| { |
| } |
| |
| CertificateInfo::~CertificateInfo() = default; |
| |
| CertificateInfo &CertificateInfo::operator=(const CertificateInfo &other) |
| { |
| if ( this != &other ) |
| d_ptr = other.d_ptr; |
| |
| return *this; |
| } |
| |
| bool CertificateInfo::isNull() const |
| { |
| Q_D(const CertificateInfo); |
| return d->is_null; |
| } |
| |
| int CertificateInfo::version() const |
| { |
| Q_D(const CertificateInfo); |
| return d->version; |
| } |
| |
| QByteArray CertificateInfo::serialNumber() const |
| { |
| Q_D(const CertificateInfo); |
| return d->serial_number; |
| } |
| |
| QString CertificateInfo::issuerInfo(EntityInfoKey key) const |
| { |
| Q_D(const CertificateInfo); |
| switch (key) |
| { |
| case CommonName: |
| return d->issuer_info.common_name; |
| case DistinguishedName: |
| return d->issuer_info.distinguished_name; |
| case EmailAddress: |
| return d->issuer_info.email_address; |
| case Organization: |
| return d->issuer_info.org_name; |
| default: |
| return QString(); |
| } |
| } |
| |
| QString CertificateInfo::subjectInfo(EntityInfoKey key) const |
| { |
| Q_D(const CertificateInfo); |
| switch (key) |
| { |
| case CommonName: |
| return d->subject_info.common_name; |
| case DistinguishedName: |
| return d->subject_info.distinguished_name; |
| case EmailAddress: |
| return d->subject_info.email_address; |
| case Organization: |
| return d->subject_info.org_name; |
| default: |
| return QString(); |
| } |
| } |
| |
| QDateTime CertificateInfo::validityStart() const |
| { |
| Q_D(const CertificateInfo); |
| return d->validity_start; |
| } |
| |
| QDateTime CertificateInfo::validityEnd() const |
| { |
| Q_D(const CertificateInfo); |
| return d->validity_end; |
| } |
| |
| CertificateInfo::KeyUsageExtensions CertificateInfo::keyUsageExtensions() const |
| { |
| Q_D(const CertificateInfo); |
| |
| KeyUsageExtensions kuExtensions = KuNone; |
| if (d->ku_extensions & KU_DIGITAL_SIGNATURE) |
| kuExtensions |= KuDigitalSignature; |
| if (d->ku_extensions & KU_NON_REPUDIATION) |
| kuExtensions |= KuNonRepudiation; |
| if (d->ku_extensions & KU_KEY_ENCIPHERMENT) |
| kuExtensions |= KuKeyEncipherment; |
| if (d->ku_extensions & KU_DATA_ENCIPHERMENT) |
| kuExtensions |= KuDataEncipherment; |
| if (d->ku_extensions & KU_KEY_AGREEMENT) |
| kuExtensions |= KuKeyAgreement; |
| if (d->ku_extensions & KU_KEY_CERT_SIGN) |
| kuExtensions |= KuKeyCertSign; |
| if (d->ku_extensions & KU_CRL_SIGN) |
| kuExtensions |= KuClrSign; |
| if (d->ku_extensions & KU_ENCIPHER_ONLY) |
| kuExtensions |= KuEncipherOnly; |
| |
| return kuExtensions; |
| } |
| |
| QByteArray CertificateInfo::publicKey() const |
| { |
| Q_D(const CertificateInfo); |
| return d->public_key; |
| } |
| |
| CertificateInfo::PublicKeyType CertificateInfo::publicKeyType() const |
| { |
| Q_D(const CertificateInfo); |
| switch (d->public_key_type) |
| { |
| case RSAKEY: |
| return RsaKey; |
| case DSAKEY: |
| return DsaKey; |
| case ECKEY: |
| return EcKey; |
| default: |
| return OtherKey; |
| } |
| } |
| |
| int CertificateInfo::publicKeyStrength() const |
| { |
| Q_D(const CertificateInfo); |
| return d->public_key_strength; |
| } |
| |
| bool CertificateInfo::isSelfSigned() const |
| { |
| Q_D(const CertificateInfo); |
| return d->is_self_signed; |
| } |
| |
| QByteArray CertificateInfo::certificateData() const |
| { |
| Q_D(const CertificateInfo); |
| return d->certificate_der; |
| } |
| |
| class SignatureValidationInfoPrivate { |
| public: |
| SignatureValidationInfoPrivate(CertificateInfo &&ci) |
| : cert_info(ci) |
| { |
| } |
| |
| SignatureValidationInfo::SignatureStatus signature_status; |
| SignatureValidationInfo::CertificateStatus certificate_status; |
| CertificateInfo cert_info; |
| |
| QByteArray signature; |
| QString signer_name; |
| QString signer_subject_dn; |
| QString location; |
| QString reason; |
| int hash_algorithm; |
| time_t signing_time; |
| QList<qint64> range_bounds; |
| qint64 docLength; |
| }; |
| |
| |
| SignatureValidationInfo::SignatureValidationInfo(SignatureValidationInfoPrivate* priv) |
| : d_ptr(priv) |
| { |
| } |
| |
| SignatureValidationInfo::SignatureValidationInfo(const SignatureValidationInfo &other) |
| : d_ptr( other.d_ptr ) |
| { |
| } |
| |
| SignatureValidationInfo::~SignatureValidationInfo() |
| { |
| } |
| |
| SignatureValidationInfo::SignatureStatus SignatureValidationInfo::signatureStatus() const |
| { |
| Q_D(const SignatureValidationInfo); |
| return d->signature_status; |
| } |
| |
| SignatureValidationInfo::CertificateStatus SignatureValidationInfo::certificateStatus() const |
| { |
| Q_D(const SignatureValidationInfo); |
| return d->certificate_status; |
| } |
| |
| QString SignatureValidationInfo::signerName() const |
| { |
| Q_D(const SignatureValidationInfo); |
| return d->signer_name; |
| } |
| |
| QString SignatureValidationInfo::signerSubjectDN() const |
| { |
| Q_D(const SignatureValidationInfo); |
| return d->signer_subject_dn; |
| } |
| |
| QString SignatureValidationInfo::location() const |
| { |
| Q_D(const SignatureValidationInfo); |
| return d->location; |
| } |
| |
| QString SignatureValidationInfo::reason() const |
| { |
| Q_D(const SignatureValidationInfo); |
| return d->reason; |
| } |
| |
| SignatureValidationInfo::HashAlgorithm SignatureValidationInfo::hashAlgorithm() const |
| { |
| #ifdef ENABLE_NSS3 |
| Q_D(const SignatureValidationInfo); |
| |
| switch (d->hash_algorithm) |
| { |
| case HASH_AlgMD2: |
| return HashAlgorithmMd2; |
| case HASH_AlgMD5: |
| return HashAlgorithmMd5; |
| case HASH_AlgSHA1: |
| return HashAlgorithmSha1; |
| case HASH_AlgSHA256: |
| return HashAlgorithmSha256; |
| case HASH_AlgSHA384: |
| return HashAlgorithmSha384; |
| case HASH_AlgSHA512: |
| return HashAlgorithmSha512; |
| case HASH_AlgSHA224: |
| return HashAlgorithmSha224; |
| } |
| #endif |
| return HashAlgorithmUnknown; |
| } |
| |
| time_t SignatureValidationInfo::signingTime() const |
| { |
| Q_D(const SignatureValidationInfo); |
| return d->signing_time; |
| } |
| |
| QByteArray SignatureValidationInfo::signature() const |
| { |
| Q_D(const SignatureValidationInfo); |
| return d->signature; |
| } |
| |
| QList<qint64> SignatureValidationInfo::signedRangeBounds() const |
| { |
| Q_D(const SignatureValidationInfo); |
| return d->range_bounds; |
| } |
| |
| bool SignatureValidationInfo::signsTotalDocument() const |
| { |
| Q_D(const SignatureValidationInfo); |
| if (d->range_bounds.size() == 4 && d->range_bounds.value(0) == 0 && |
| d->range_bounds.value(1) >= 0 && |
| d->range_bounds.value(2) > d->range_bounds.value(1) && |
| d->range_bounds.value(3) >= d->range_bounds.value(2)) |
| { |
| // The range from d->range_bounds.value(1) to d->range_bounds.value(2) is |
| // not authenticated by the signature and should only contain the signature |
| // itself padded with 0 bytes. This has been checked in readSignature(). |
| // If it failed, d->signature is empty. |
| // A potential range after d->range_bounds.value(3) would be also not |
| // authenticated. Therefore d->range_bounds.value(3) should coincide with |
| // the end of the document. |
| if (d->docLength == d->range_bounds.value(3) && !d->signature.isEmpty()) |
| return true; |
| } |
| return false; |
| } |
| |
| CertificateInfo SignatureValidationInfo::certificateInfo() const |
| { |
| Q_D(const SignatureValidationInfo); |
| return d->cert_info; |
| } |
| |
| SignatureValidationInfo &SignatureValidationInfo::operator=(const SignatureValidationInfo &other) |
| { |
| if ( this != &other ) |
| d_ptr = other.d_ptr; |
| |
| return *this; |
| } |
| |
| FormFieldSignature::FormFieldSignature(DocumentData *doc, ::Page *p, ::FormWidgetSignature *w) |
| : FormField(*new FormFieldData(doc, p, w)) |
| { |
| } |
| |
| FormFieldSignature::~FormFieldSignature() |
| { |
| } |
| |
| FormField::FormType FormFieldSignature::type() const |
| { |
| return FormField::FormSignature; |
| } |
| |
| FormFieldSignature::SignatureType FormFieldSignature::signatureType() const |
| { |
| SignatureType sigType = AdbePkcs7detached; |
| FormWidgetSignature* fws = static_cast<FormWidgetSignature*>(m_formData->fm); |
| switch (fws->signatureType()) |
| { |
| case adbe_pkcs7_sha1: |
| sigType = AdbePkcs7sha1; |
| break; |
| case adbe_pkcs7_detached: |
| sigType = AdbePkcs7detached; |
| break; |
| case ETSI_CAdES_detached: |
| sigType = EtsiCAdESdetached; |
| break; |
| } |
| return sigType; |
| } |
| |
| SignatureValidationInfo FormFieldSignature::validate(ValidateOptions opt) const |
| { |
| return validate(opt, QDateTime()); |
| } |
| |
| SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime& validationTime) const |
| { |
| FormWidgetSignature* fws = static_cast<FormWidgetSignature*>(m_formData->fm); |
| const time_t validationTimeT = validationTime.isValid() ? validationTime.toTime_t() : -1; |
| SignatureInfo* si = fws->validateSignature(opt & ValidateVerifyCertificate, opt & ValidateForceRevalidation, validationTimeT); |
| |
| // get certificate info |
| const X509CertificateInfo *ci = si->getCertificateInfo(); |
| CertificateInfoPrivate* certPriv = new CertificateInfoPrivate; |
| certPriv->is_null = true; |
| if (ci) |
| { |
| certPriv->version = ci->getVersion(); |
| certPriv->ku_extensions = ci->getKeyUsageExtensions(); |
| |
| const GooString &certSerial = ci->getSerialNumber(); |
| certPriv->serial_number = QByteArray(certSerial.c_str(), certSerial.getLength()); |
| |
| const X509CertificateInfo::EntityInfo &issuerInfo = ci->getIssuerInfo(); |
| certPriv->issuer_info.common_name = issuerInfo.commonName.c_str(); |
| certPriv->issuer_info.distinguished_name = issuerInfo.distinguishedName.c_str(); |
| certPriv->issuer_info.email_address = issuerInfo.email.c_str(); |
| certPriv->issuer_info.org_name = issuerInfo.organization.c_str(); |
| |
| const X509CertificateInfo::EntityInfo &subjectInfo = ci->getSubjectInfo(); |
| certPriv->subject_info.common_name = subjectInfo.commonName.c_str(); |
| certPriv->subject_info.distinguished_name = subjectInfo.distinguishedName.c_str(); |
| certPriv->subject_info.email_address = subjectInfo.email.c_str(); |
| certPriv->subject_info.org_name = subjectInfo.organization.c_str(); |
| |
| X509CertificateInfo::Validity certValidity = ci->getValidity(); |
| certPriv->validity_start = QDateTime::fromTime_t(certValidity.notBefore, Qt::UTC); |
| certPriv->validity_end = QDateTime::fromTime_t(certValidity.notAfter, Qt::UTC); |
| |
| const X509CertificateInfo::PublicKeyInfo &pkInfo = ci->getPublicKeyInfo(); |
| certPriv->public_key = QByteArray(pkInfo.publicKey.c_str(), pkInfo.publicKey.getLength()); |
| certPriv->public_key_type = static_cast<int>(pkInfo.publicKeyType); |
| certPriv->public_key_strength = pkInfo.publicKeyStrength; |
| |
| const GooString &certDer = ci->getCertificateDER(); |
| certPriv->certificate_der = QByteArray(certDer.c_str(), certDer.getLength()); |
| |
| certPriv->is_null = false; |
| } |
| |
| SignatureValidationInfoPrivate* priv = new SignatureValidationInfoPrivate(CertificateInfo(certPriv)); |
| switch (si->getSignatureValStatus()) { |
| case SIGNATURE_VALID: |
| priv->signature_status = SignatureValidationInfo::SignatureValid; |
| break; |
| case SIGNATURE_INVALID: |
| priv->signature_status = SignatureValidationInfo::SignatureInvalid; |
| break; |
| case SIGNATURE_DIGEST_MISMATCH: |
| priv->signature_status = SignatureValidationInfo::SignatureDigestMismatch; |
| break; |
| case SIGNATURE_DECODING_ERROR: |
| priv->signature_status = SignatureValidationInfo::SignatureDecodingError; |
| break; |
| default: |
| case SIGNATURE_GENERIC_ERROR: |
| priv->signature_status = SignatureValidationInfo::SignatureGenericError; |
| break; |
| case SIGNATURE_NOT_FOUND: |
| priv->signature_status = SignatureValidationInfo::SignatureNotFound; |
| break; |
| case SIGNATURE_NOT_VERIFIED: |
| priv->signature_status = SignatureValidationInfo::SignatureNotVerified; |
| break; |
| } |
| switch (si->getCertificateValStatus()) { |
| case CERTIFICATE_TRUSTED: |
| priv->certificate_status = SignatureValidationInfo::CertificateTrusted; |
| break; |
| case CERTIFICATE_UNTRUSTED_ISSUER: |
| priv->certificate_status = SignatureValidationInfo::CertificateUntrustedIssuer; |
| break; |
| case CERTIFICATE_UNKNOWN_ISSUER: |
| priv->certificate_status = SignatureValidationInfo::CertificateUnknownIssuer; |
| break; |
| case CERTIFICATE_REVOKED: |
| priv->certificate_status = SignatureValidationInfo::CertificateRevoked; |
| break; |
| case CERTIFICATE_EXPIRED: |
| priv->certificate_status = SignatureValidationInfo::CertificateExpired; |
| break; |
| default: |
| case CERTIFICATE_GENERIC_ERROR: |
| priv->certificate_status = SignatureValidationInfo::CertificateGenericError; |
| break; |
| case CERTIFICATE_NOT_VERIFIED: |
| priv->certificate_status = SignatureValidationInfo::CertificateNotVerified; |
| break; |
| } |
| priv->signer_name = si->getSignerName(); |
| priv->signer_subject_dn = si->getSubjectDN(); |
| priv->hash_algorithm = si->getHashAlgorithm(); |
| priv->location = si->getLocation(); |
| priv->reason = si->getReason(); |
| |
| priv->signing_time = si->getSigningTime(); |
| const std::vector<Goffset> ranges = fws->getSignedRangeBounds(); |
| if (!ranges.empty()) |
| { |
| for (Goffset bound : ranges) |
| { |
| priv->range_bounds.append(bound); |
| } |
| } |
| GooString* checkedSignature = fws->getCheckedSignature(&priv->docLength); |
| if (priv->range_bounds.size() == 4 && checkedSignature) |
| { |
| priv->signature = QByteArray::fromHex(checkedSignature->c_str()); |
| } |
| delete checkedSignature; |
| |
| return SignatureValidationInfo(priv); |
| } |
| |
| } |