glib/demo/forms.c | 19 ++ glib/poppler-document.cc | 22 ++ glib/poppler-document.h | 7 glib/poppler-form-field.cc | 303 ++++++++++++++++++++++++++++++++++++ glib/poppler-form-field.h | 92 ++++++++++ glib/poppler-private.h | 1 glib/poppler.h | 2 glib/reference/poppler-sections.txt | 22 ++ glib/reference/poppler.types | 4 poppler/Form.cc | 8 poppler/PDFDoc.cc | 10 + poppler/PDFDoc.h | 1 poppler/SignatureHandler.cc | 9 - poppler/SignatureInfo.cc | 6 poppler/SignatureInfo.h | 4 15 files changed, 502 insertions(+), 8 deletions(-)
New commits: commit 7b7b3f8018d652a0e8f38a69e28d535d98843df8 Author: Marek Kasik <[email protected]> Date: Thu Nov 25 22:31:01 2021 +0000 Add validation of signatures API to glib frontend diff --git a/glib/demo/forms.c b/glib/demo/forms.c index 4ce8e9eb..37412e0b 100644 --- a/glib/demo/forms.c +++ b/glib/demo/forms.c @@ -1,5 +1,7 @@ /* * Copyright (C) 2007 Carlos Garcia Campos <[email protected]> + * Copyright (C) 2021 André Guerreiro <[email protected]> + * Copyright (C) 2021 Marek Kasik <[email protected]> * * 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 @@ -126,6 +128,7 @@ static void pgd_form_field_view_set_field(GtkWidget *field_view, PopplerFormFiel GEnumValue *enum_value; gchar *text; gint row = 0; + PopplerSignatureInfo *psig_info; table = gtk_bin_get_child(GTK_BIN(field_view)); if (table) { @@ -266,7 +269,21 @@ static void pgd_form_field_view_set_field(GtkWidget *field_view, PopplerFormFiel pgd_table_add_property(GTK_GRID(table), "<b>Contents:</b>", text, &row); g_free(text); } break; - case POPPLER_FORM_FIELD_SIGNATURE: + case POPPLER_FORM_FIELD_SIGNATURE: { + const gchar *signer_name; + + psig_info = poppler_form_field_signature_validate_sync( + field, POPPLER_SIGNATURE_VALIDATION_FLAG_VALIDATE_CERTIFICATE | POPPLER_SIGNATURE_VALIDATION_FLAG_WITHOUT_OCSP_REVOCATION_CHECK | POPPLER_SIGNATURE_VALIDATION_FLAG_USE_AIA_CERTIFICATE_FETCH, NULL, NULL); + signer_name = poppler_signature_info_get_signer_name(psig_info); + pgd_table_add_property(GTK_GRID(table), "<b>Signer Name:</b>", signer_name ? signer_name : "Signers name found", &row); + text = g_date_time_format(poppler_signature_info_get_local_signing_time(psig_info), "%b %d %Y %H:%M:%S"); + pgd_table_add_property(GTK_GRID(table), "<b>Signing Time:</b>", text, &row); + pgd_table_add_property(GTK_GRID(table), "<b>Signature Val Status:</b>", poppler_signature_info_get_signature_status(psig_info) == POPPLER_SIGNATURE_VALID ? "Signature is Valid" : "Signature is Invalid", &row); + pgd_table_add_property(GTK_GRID(table), "<b>Certificate Val Status:</b>", poppler_signature_info_get_certificate_status(psig_info) == POPPLER_CERTIFICATE_TRUSTED ? "Certificate is Trusted" : "Certificate cannot be Trusted", &row); + + poppler_signature_info_free(psig_info); + g_free(text); + } break; case POPPLER_FORM_FIELD_UNKNOWN: break; default: diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc index 1f5b5433..3f03b9f8 100644 --- a/glib/poppler-document.cc +++ b/glib/poppler-document.cc @@ -6,6 +6,8 @@ * Copyright (C) 2019 Masamichi Hosoda <[email protected]> * Copyright (C) 2019, 2021 Oliver Sander <[email protected]> * Copyright (C) 2020 Albert Astals Cid <[email protected]> + * Copyright (C) 2021 André Guerreiro <[email protected]> + * Copyright (C) 2021 Marek Kasik <[email protected]> * * 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 @@ -42,6 +44,7 @@ # include <FILECacheLoader.h> # include <GlobalParams.h> # include <PDFDoc.h> +# include <SignatureInfo.h> # include <Outline.h> # include <ErrorCodes.h> # include <UnicodeMap.h> @@ -1729,6 +1732,25 @@ gboolean poppler_document_is_linearized(PopplerDocument *document) return document->doc->isLinearized(); } +/** + * poppler_document_get_n_signatures: + * @document: A #PopplerDocument + * + * Returns how many digital signatures @document contains. + * PDF digital signatures ensure that the content hash not been altered since last edit and + * that it was produced by someone the user can trust + * + * Return value: The number of signatures found in the document + * + * Since: 21.12.0 + **/ +gint poppler_document_get_n_signatures(const PopplerDocument *document) +{ + g_return_val_if_fail(POPPLER_IS_DOCUMENT(document), 0); + + return document->doc->getNumSignatureFields(); +} + /** * poppler_document_get_page_layout: * @document: A #PopplerDocument diff --git a/glib/poppler-document.h b/glib/poppler-document.h index 5a0afd53..c6a3ef0f 100644 --- a/glib/poppler-document.h +++ b/glib/poppler-document.h @@ -2,8 +2,9 @@ * Copyright (C) 2004, Red Hat, Inc. * * Copyright (C) 2016 Jakub Alba <[email protected]> - * Copyright (C) 2018-2019 Marek Kasik <[email protected]> + * Copyright (C) 2018, 2019, 2021 Marek Kasik <[email protected]> * Copyright (C) 2019 Masamichi Hosoda <[email protected]> + * Copyright (C) 2021 André Guerreiro <[email protected]> * * 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 @@ -412,6 +413,10 @@ void poppler_document_reset_form(PopplerDocument *document, GList *fields, gbool POPPLER_PUBLIC gboolean poppler_document_has_javascript(PopplerDocument *document); +/* Signatures */ +POPPLER_PUBLIC +gint poppler_document_get_n_signatures(const PopplerDocument *document); + /* Interface for getting the Index of a poppler_document */ #define POPPLER_TYPE_INDEX_ITER (poppler_index_iter_get_type()) POPPLER_PUBLIC diff --git a/glib/poppler-form-field.cc b/glib/poppler-form-field.cc index 093ddfee..9504194d 100644 --- a/glib/poppler-form-field.cc +++ b/glib/poppler-form-field.cc @@ -3,6 +3,8 @@ * Copyright (C) 2007 Carlos Garcia Campos <[email protected]> * Copyright (C) 2006 Julien Rebetez * Copyright (C) 2020 Oliver Sander <[email protected]> + * Copyright (C) 2021 André Guerreiro <[email protected]> + * Copyright (C) 2021 Marek Kasik <[email protected]> * * 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 @@ -381,6 +383,307 @@ gchar *poppler_form_field_get_alternate_ui_name(PopplerFormField *field) return tmp ? _poppler_goo_string_to_utf8(tmp) : nullptr; } +/** + * PopplerSignatureInfo: + * + * PopplerSignatureInfo contains detailed info about a signature + * contained in a form field. + * + * Since: 21.12.0 + **/ +struct _PopplerSignatureInfo +{ + PopplerSignatureStatus sig_status; + PopplerCertificateStatus cert_status; + char *signer_name; + GDateTime *local_signing_time; +}; + +static PopplerSignatureInfo *_poppler_form_field_signature_validate(PopplerFormField *field, PopplerSignatureValidationFlags flags, gboolean force_revalidation, GError **error) +{ + FormFieldSignature *sig_field; + SignatureInfo *sig_info; + PopplerSignatureInfo *poppler_sig_info; + + if (poppler_form_field_get_field_type(field) != POPPLER_FORM_FIELD_SIGNATURE) { + g_set_error(error, POPPLER_ERROR, POPPLER_ERROR_INVALID, "Wrong FormField type"); + return nullptr; + } + + sig_field = static_cast<FormFieldSignature *>(field->widget->getField()); + + sig_info = sig_field->validateSignature(flags & POPPLER_SIGNATURE_VALIDATION_FLAG_VALIDATE_CERTIFICATE, force_revalidation, -1, flags & POPPLER_SIGNATURE_VALIDATION_FLAG_WITHOUT_OCSP_REVOCATION_CHECK, + flags & POPPLER_SIGNATURE_VALIDATION_FLAG_USE_AIA_CERTIFICATE_FETCH); + + poppler_sig_info = g_new0(PopplerSignatureInfo, 1); + switch (sig_info->getSignatureValStatus()) { + case SIGNATURE_VALID: + poppler_sig_info->sig_status = POPPLER_SIGNATURE_VALID; + break; + case SIGNATURE_INVALID: + poppler_sig_info->sig_status = POPPLER_SIGNATURE_INVALID; + break; + case SIGNATURE_DIGEST_MISMATCH: + poppler_sig_info->sig_status = POPPLER_SIGNATURE_DIGEST_MISMATCH; + break; + case SIGNATURE_DECODING_ERROR: + poppler_sig_info->sig_status = POPPLER_SIGNATURE_DECODING_ERROR; + break; + case SIGNATURE_GENERIC_ERROR: + poppler_sig_info->sig_status = POPPLER_SIGNATURE_GENERIC_ERROR; + break; + case SIGNATURE_NOT_FOUND: + poppler_sig_info->sig_status = POPPLER_SIGNATURE_NOT_FOUND; + break; + case SIGNATURE_NOT_VERIFIED: + poppler_sig_info->sig_status = POPPLER_SIGNATURE_NOT_VERIFIED; + break; + } + + switch (sig_info->getCertificateValStatus()) { + case CERTIFICATE_TRUSTED: + poppler_sig_info->cert_status = POPPLER_CERTIFICATE_TRUSTED; + break; + case CERTIFICATE_UNTRUSTED_ISSUER: + poppler_sig_info->cert_status = POPPLER_CERTIFICATE_UNTRUSTED_ISSUER; + break; + case CERTIFICATE_UNKNOWN_ISSUER: + poppler_sig_info->cert_status = POPPLER_CERTIFICATE_UNKNOWN_ISSUER; + break; + case CERTIFICATE_REVOKED: + poppler_sig_info->cert_status = POPPLER_CERTIFICATE_REVOKED; + break; + case CERTIFICATE_EXPIRED: + poppler_sig_info->cert_status = POPPLER_CERTIFICATE_EXPIRED; + break; + case CERTIFICATE_GENERIC_ERROR: + poppler_sig_info->cert_status = POPPLER_CERTIFICATE_GENERIC_ERROR; + break; + case CERTIFICATE_NOT_VERIFIED: + poppler_sig_info->cert_status = POPPLER_CERTIFICATE_NOT_VERIFIED; + break; + } + + poppler_sig_info->signer_name = g_strdup(sig_info->getSignerName()); + poppler_sig_info->local_signing_time = g_date_time_new_from_unix_local(sig_info->getSigningTime()); + + return poppler_sig_info; +} + +static void signature_validate_thread(GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) +{ + PopplerSignatureValidationFlags flags = (PopplerSignatureValidationFlags)GPOINTER_TO_INT(task_data); + PopplerSignatureInfo *signature_info; + PopplerFormField *field = (PopplerFormField *)source_object; + GError *error = nullptr; + + signature_info = _poppler_form_field_signature_validate(field, flags, FALSE, &error); + if (signature_info == nullptr && error != nullptr) { + g_task_return_error(task, error); + return; + } + + if (g_task_set_return_on_cancel(task, FALSE)) { + g_task_return_pointer(task, signature_info, (GDestroyNotify)poppler_signature_info_free); + } +} + +/** + * poppler_form_field_signature_validate_sync: + * @field: a #PopplerFormField that represents a signature annotation + * @flags: #PopplerSignatureValidationFlags flags influencing process of validation of the field signature + * @cancellable: (nullable): optional #GCancellable object + * @error: a #GError + * + * Synchronously validates the cryptographic signature contained in @signature_field. + * + * Return value: (transfer full): a #PopplerSignatureInfo structure containing signature metadata and validation status + * Free the returned structure with poppler_signature_info_free(). + * + * Since: 21.12.0 + **/ +PopplerSignatureInfo *poppler_form_field_signature_validate_sync(PopplerFormField *field, PopplerSignatureValidationFlags flags, GCancellable *cancellable, GError **error) +{ + PopplerSignatureInfo *signature_info; + GTask *task; + + g_return_val_if_fail(error == NULL || *error == NULL, NULL); + + task = g_task_new(field, cancellable, nullptr, nullptr); + g_task_set_task_data(task, GINT_TO_POINTER(flags), nullptr); + g_task_set_return_on_cancel(task, TRUE); + + g_task_run_in_thread_sync(task, signature_validate_thread); + + signature_info = (PopplerSignatureInfo *)g_task_propagate_pointer(task, error); + g_object_unref(task); + + return signature_info; +} + +/** + * poppler_form_field_signature_validate_async: + * @field: a #PopplerFormField that represents a signature annotation + * @flags: #PopplerSignatureValidationFlags flags influencing process of validation of the field signature + * @cancellable: (nullable): optional #GCancellable object + * @callback: (scope async): a #GAsyncReadyCallback to call when the signature is validated + * @user_data: (closure): the data to pass to callback function + * + * Asynchronously validates the cryptographic signature contained in @signature_field. + * + * Since: 21.12.0 + **/ +void poppler_form_field_signature_validate_async(PopplerFormField *field, PopplerSignatureValidationFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) +{ + GTask *task; + + task = g_task_new(field, cancellable, callback, user_data); + g_task_set_task_data(task, GINT_TO_POINTER(flags), nullptr); + g_task_set_return_on_cancel(task, TRUE); + + g_task_run_in_thread(task, signature_validate_thread); + + g_object_unref(task); +} + +/** + * poppler_form_field_signature_validate_finish: + * @field: a #PopplerFormField that represents a signature annotation + * @result: a #GAsyncResult + * @error: a #GError + * + * Finishes validation of the cryptographic signature contained in @signature_field. + * See poppler_form_field_signature_validate_async(). + * + * Return value: (transfer full): a #PopplerSignatureInfo structure containing signature metadata and validation status + * Free the returned structure with poppler_signature_info_free(). + * + * Since: 21.12.0 + **/ +PopplerSignatureInfo *poppler_form_field_signature_validate_finish(PopplerFormField *field, GAsyncResult *result, GError **error) +{ + g_return_val_if_fail(g_task_is_valid(result, field), NULL); + + return (PopplerSignatureInfo *)g_task_propagate_pointer(G_TASK(result), error); +} + +G_DEFINE_BOXED_TYPE(PopplerSignatureInfo, poppler_signature_info, poppler_signature_info_copy, poppler_signature_info_free) + +/** + * poppler_signature_info_copy: + * @siginfo: a #PopplerSignatureInfo structure containing signature metadata and validation status + * + * Copies @siginfo, creating an identical #PopplerSignatureInfo. + * + * Return value: (transfer full): a new #PopplerSignatureInfo structure identical to @siginfo + * + * Since: 21.12.0 + **/ +PopplerSignatureInfo *poppler_signature_info_copy(const PopplerSignatureInfo *siginfo) +{ + PopplerSignatureInfo *new_info; + + g_return_val_if_fail(siginfo != NULL, NULL); + + new_info = g_new(PopplerSignatureInfo, 1); + new_info->sig_status = siginfo->sig_status; + new_info->cert_status = siginfo->cert_status; + new_info->signer_name = g_strdup(siginfo->signer_name); + new_info->local_signing_time = g_date_time_ref(siginfo->local_signing_time); + + return new_info; +} + +/** + * poppler_signature_info_free: + * @siginfo: a #PopplerSignatureInfo structure containing signature metadata and validation status + * + * Frees @siginfo + * + * Since: 21.12.0 + **/ +void poppler_signature_info_free(PopplerSignatureInfo *siginfo) +{ + if (siginfo == nullptr) + return; + + g_date_time_unref(siginfo->local_signing_time); + g_free(siginfo->signer_name); + g_free(siginfo); +} + +/** + * poppler_signature_info_get_signature_status: + * @siginfo: a #PopplerSignatureInfo + * + * Returns status of the signature for given PopplerSignatureInfo. + * + * Return value: signature status of the signature + * + * Since: 21.12.0 + **/ +PopplerSignatureStatus poppler_signature_info_get_signature_status(const PopplerSignatureInfo *siginfo) +{ + g_return_val_if_fail(siginfo != NULL, POPPLER_SIGNATURE_GENERIC_ERROR); + + return siginfo->sig_status; +} + +/** + * poppler_signature_info_get_certificate_status: + * @siginfo: a #PopplerSignatureInfo + * + * Returns status of the certificate for given PopplerSignatureInfo. + * + * Return value: certificate status of the signature + * + * Since: 21.12.0 + **/ +PopplerCertificateStatus poppler_signature_info_get_certificate_status(const PopplerSignatureInfo *siginfo) +{ + g_return_val_if_fail(siginfo != NULL, POPPLER_CERTIFICATE_GENERIC_ERROR); + + return siginfo->cert_status; +} + +/** + * poppler_signature_info_get_signer_name: + * @siginfo: a #PopplerSignatureInfo + * + * Returns name of signer for given PopplerSignatureInfo. + * + * Return value: (transfer none): A string. + * + * Since: 21.12.0 + **/ +const gchar *poppler_signature_info_get_signer_name(const PopplerSignatureInfo *siginfo) +{ + g_return_val_if_fail(siginfo != NULL, NULL); + + return siginfo->signer_name; +} + +/** + * poppler_signature_info_get_local_signing_time: + * @siginfo: a #PopplerSignatureInfo + * + * Returns local time of signing as GDateTime. This does not + * contain information about time zone since it has not been + * preserved during conversion. + * Do not modify returned value since it is internal to + * PopplerSignatureInfo. + * + * Return value: (transfer none): GDateTime + * + * Since: 21.12.0 + **/ +GDateTime *poppler_signature_info_get_local_signing_time(const PopplerSignatureInfo *siginfo) +{ + g_return_val_if_fail(siginfo != NULL, NULL); + + return siginfo->local_signing_time; +} + /* Text Field */ /** * poppler_form_field_text_get_text_type: diff --git a/glib/poppler-form-field.h b/glib/poppler-form-field.h index c895973c..b48c5064 100644 --- a/glib/poppler-form-field.h +++ b/glib/poppler-form-field.h @@ -1,6 +1,8 @@ /* poppler-form-field.h: glib interface to poppler * * Copyright (C) 2007 Carlos Garcia Campos <[email protected]> + * Copyright (C) 2021 André Guerreiro <[email protected]> + * Copyright (C) 2021 Marek Kasik <[email protected]> * * 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 @@ -29,6 +31,73 @@ G_BEGIN_DECLS #define POPPLER_FORM_FIELD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), POPPLER_TYPE_FORM_FIELD, PopplerFormField)) #define POPPLER_IS_FORM_FIELD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), POPPLER_TYPE_FORM_FIELD)) +/** + * PopplerSignatureStatus + * @POPPLER_SIGNATURE_VALID: signature is cryptographically valid + * @POPPLER_SIGNATURE_INVALID: signature is cryptographically invalid + * @POPPLER_SIGNATURE_DIGEST_MISMATCH: document content was changed after the signature was applied + * @POPPLER_SIGNATURE_DECODING_ERROR: signature CMS/PKCS7 structure is malformed + * @POPPLER_SIGNATURE_GENERIC_ERROR: failed to verify signature + * @POPPLER_SIGNATURE_NOT_FOUND: requested signature is not present in the document + * @POPPLER_SIGNATURE_NOT_VERIFIED: signature not yet verified + * + * Signature verification results + * + * Since: 21.12.0 + */ +typedef enum +{ + POPPLER_SIGNATURE_VALID, + POPPLER_SIGNATURE_INVALID, + POPPLER_SIGNATURE_DIGEST_MISMATCH, + POPPLER_SIGNATURE_DECODING_ERROR, + POPPLER_SIGNATURE_GENERIC_ERROR, + POPPLER_SIGNATURE_NOT_FOUND, + POPPLER_SIGNATURE_NOT_VERIFIED +} PopplerSignatureStatus; + +/** + * PopplerCertificateStatus + * @POPPLER_CERTIFICATE_TRUSTED: certificate is considered trusted + * @POPPLER_CERTIFICATE_UNTRUSTED_ISSUER: the issuer of this certificate has been marked as untrusted by the user + * @POPPLER_CERTIFICATE_UNKNOWN_ISSUER: this certificate trust chain has not finished in a trusted root certificate + * @POPPLER_CERTIFICATE_REVOKED: certificate was revoked by the issuing certificate authority + * @POPPLER_CERTIFICATE_EXPIRED: signing time is outside the validity bounds of this certificate + * @POPPLER_CERTIFICATE_GENERIC_ERROR: failed to verify certificate + * @POPPLER_CERTIFICATE_NOT_VERIFIED: certificate not yet verified + * + * Signature certificate verification results + * + * Since: 21.12.0 + */ +typedef enum +{ + POPPLER_CERTIFICATE_TRUSTED, + POPPLER_CERTIFICATE_UNTRUSTED_ISSUER, + POPPLER_CERTIFICATE_UNKNOWN_ISSUER, + POPPLER_CERTIFICATE_REVOKED, + POPPLER_CERTIFICATE_EXPIRED, + POPPLER_CERTIFICATE_GENERIC_ERROR, + POPPLER_CERTIFICATE_NOT_VERIFIED +} PopplerCertificateStatus; + +/** + * PopplerSignatureValidationFlags + * @POPPLER_SIGNATURE_VALIDATION_FLAG_VALIDATE_CERTIFICATE: Whether to validate also the certificate of the signature + * @POPPLER_SIGNATURE_VALIDATION_FLAG_WITHOUT_OCSP_REVOCATION_CHECK: Whether to not do OCSP (Online Certificate Status Protocol) revocation check + * @POPPLER_SIGNATURE_VALIDATION_FLAG_USE_AIA_CERTIFICATE_FETCH: Whether to use AIA (Authority Information Access) extension for certificate fetching + * + * Signature validation flags + * + * Since: 21.12.0 + */ +typedef enum /*< flags >*/ +{ + POPPLER_SIGNATURE_VALIDATION_FLAG_VALIDATE_CERTIFICATE = 1 << 0, + POPPLER_SIGNATURE_VALIDATION_FLAG_WITHOUT_OCSP_REVOCATION_CHECK = 1 << 1, + POPPLER_SIGNATURE_VALIDATION_FLAG_USE_AIA_CERTIFICATE_FETCH = 1 << 2, +} PopplerSignatureValidationFlags; + typedef enum { POPPLER_FORM_FIELD_UNKNOWN, @@ -156,6 +225,29 @@ POPPLER_PUBLIC void poppler_form_field_choice_set_text(PopplerFormField *field, const gchar *text); POPPLER_PUBLIC gchar *poppler_form_field_choice_get_text(PopplerFormField *field); +POPPLER_PUBLIC +PopplerSignatureInfo *poppler_form_field_signature_validate_sync(PopplerFormField *field, PopplerSignatureValidationFlags flags, GCancellable *cancellable, GError **error); +POPPLER_PUBLIC +void poppler_form_field_signature_validate_async(PopplerFormField *field, PopplerSignatureValidationFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); +POPPLER_PUBLIC +PopplerSignatureInfo *poppler_form_field_signature_validate_finish(PopplerFormField *field, GAsyncResult *result, GError **error); + +/* Signature Field */ +#define POPPLER_TYPE_SIGNATURE_INFO (poppler_signature_info_get_type()) +POPPLER_PUBLIC +GType poppler_signature_info_get_type(void) G_GNUC_CONST; +POPPLER_PUBLIC +PopplerSignatureInfo *poppler_signature_info_copy(const PopplerSignatureInfo *siginfo); +POPPLER_PUBLIC +void poppler_signature_info_free(PopplerSignatureInfo *siginfo); +POPPLER_PUBLIC +PopplerSignatureStatus poppler_signature_info_get_signature_status(const PopplerSignatureInfo *siginfo); +POPPLER_PUBLIC +PopplerCertificateStatus poppler_signature_info_get_certificate_status(const PopplerSignatureInfo *siginfo); +POPPLER_PUBLIC +const gchar *poppler_signature_info_get_signer_name(const PopplerSignatureInfo *siginfo); +POPPLER_PUBLIC +GDateTime *poppler_signature_info_get_local_signing_time(const PopplerSignatureInfo *siginfo); G_END_DECLS diff --git a/glib/poppler-private.h b/glib/poppler-private.h index 6c09d039..ce2c4733 100644 --- a/glib/poppler-private.h +++ b/glib/poppler-private.h @@ -18,6 +18,7 @@ # include <CairoOutputDev.h> # include <FileSpec.h> # include <StructElement.h> +# include <SignatureInfo.h> #endif #define SUPPORTED_ROTATION(r) (r == 90 || r == 180 || r == 270) diff --git a/glib/poppler.h b/glib/poppler.h index 35a3bfd4..e2001504 100644 --- a/glib/poppler.h +++ b/glib/poppler.h @@ -1,5 +1,6 @@ /* poppler.h: glib interface to poppler * Copyright (C) 2004, Red Hat, Inc. + * Copyright (C) 2021 André Guerreiro <[email protected]> * * 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 @@ -217,6 +218,7 @@ typedef struct _PopplerStructureElement PopplerStructureElement; typedef struct _PopplerStructureElementIter PopplerStructureElementIter; typedef struct _PopplerTextSpan PopplerTextSpan; typedef struct _PopplerPageRange PopplerPageRange; +typedef struct _PopplerSignatureInfo PopplerSignatureInfo; /** * PopplerBackend: diff --git a/glib/reference/poppler-sections.txt b/glib/reference/poppler-sections.txt index f77aad35..ac542e78 100644 --- a/glib/reference/poppler-sections.txt +++ b/glib/reference/poppler-sections.txt @@ -134,6 +134,7 @@ poppler_print_flags_get_type poppler_quadrilateral_get_type poppler_rectangle_get_type poppler_selection_style_get_type +poppler_signature_info_get_type poppler_text_attributes_get_type </SECTION> @@ -172,6 +173,7 @@ poppler_document_get_modification_date poppler_document_get_modification_date_time poppler_document_get_n_attachments poppler_document_get_n_pages +poppler_document_get_n_signatures poppler_document_get_page poppler_document_get_page_by_label poppler_document_get_page_layout @@ -363,10 +365,14 @@ poppler_attachment_get_type <TITLE>PopplerFormField</TITLE> PopplerFormField PopplerAdditionalActionType +PopplerCertificateStatus PopplerFormFieldType PopplerFormButtonType PopplerFormChoiceType PopplerFormTextType +PopplerSignatureInfo +PopplerSignatureStatus +PopplerSignatureValidationFlags poppler_form_field_button_get_button_type poppler_form_field_button_get_state poppler_form_field_button_set_state @@ -393,6 +399,9 @@ poppler_form_field_get_mapping_name poppler_form_field_get_name poppler_form_field_get_partial_name poppler_form_field_is_read_only +poppler_form_field_signature_validate_async +poppler_form_field_signature_validate_finish +poppler_form_field_signature_validate_sync poppler_form_field_text_do_scroll poppler_form_field_text_do_spell_check poppler_form_field_text_get_max_len @@ -401,22 +410,35 @@ poppler_form_field_text_get_text_type poppler_form_field_text_is_password poppler_form_field_text_is_rich_text poppler_form_field_text_set_text +poppler_signature_info_copy +poppler_signature_info_free +poppler_signature_info_get_certificate_status +poppler_signature_info_get_signature_status +poppler_signature_info_get_signer_name +poppler_signature_info_get_local_signing_time <SUBSECTION Standard> POPPLER_FORM_FIELD POPPLER_IS_FORM_FIELD POPPLER_TYPE_ADDITIONAL_ACTION_TYPE +POPPLER_TYPE_CERTIFICATE_STATUS POPPLER_TYPE_FORM_BUTTON_TYPE POPPLER_TYPE_FORM_CHOICE_TYPE POPPLER_TYPE_FORM_FIELD POPPLER_TYPE_FORM_FIELD_TYPE POPPLER_TYPE_FORM_TEXT_TYPE +POPPLER_TYPE_SIGNATURE_INFO +POPPLER_TYPE_SIGNATURE_STATUS poppler_additional_action_type_get_type +poppler_certificate_status_get_type poppler_form_button_type_get_type poppler_form_choice_type_get_type poppler_form_field_get_type poppler_form_field_type_get_type poppler_form_text_type_get_type +poppler_signature_info_get_type +poppler_signature_status_get_type +poppler_signature_validation_flags_get_type </SECTION> <SECTION> diff --git a/glib/reference/poppler.types b/glib/reference/poppler.types index a8712f81..da524e0e 100644 --- a/glib/reference/poppler.types +++ b/glib/reference/poppler.types @@ -24,6 +24,7 @@ poppler_annot_text_state_get_type poppler_annot_type_get_type poppler_attachment_get_type poppler_backend_get_type +poppler_certificate_status_get_type poppler_color_get_type poppler_dest_get_type poppler_dest_type_get_type @@ -66,6 +67,9 @@ poppler_ps_file_get_type poppler_quadrilateral_get_type poppler_rectangle_get_type poppler_selection_style_get_type +poppler_signature_info_get_type +poppler_signature_status_get_type +poppler_signature_validation_flags_get_type poppler_structure_block_align_get_type poppler_structure_border_style_get_type poppler_structure_element_get_type diff --git a/poppler/Form.cc b/poppler/Form.cc index 87a635c1..921a89e6 100644 --- a/poppler/Form.cc +++ b/poppler/Form.cc @@ -27,7 +27,7 @@ // Copyright 2019, 2020 Oliver Sander <[email protected]> // Copyright 2019 Tomoyuki Kubota <[email protected]> // Copyright 2019 João Netto <[email protected]> -// Copyright 2020 Marek Kasik <[email protected]> +// Copyright 2020, 2021 Marek Kasik <[email protected]> // Copyright 2020 Thorsten Behrens <[email protected]> // Copyright 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <[email protected]>. Work sponsored by Technische Universität Dresden // Copyright 2021 Georgiy Sgibnev <[email protected]>. Work sponsored by lab50.net. @@ -2191,10 +2191,14 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for hashSignedDataBlock(&signature_handler, len); } - signature_info->setSignerName(signature_handler.getSignerName()); + char *signerName = signature_handler.getSignerName(); + + signature_info->setSignerName(signerName); signature_info->setSubjectDN(signature_handler.getSignerSubjectDN()); signature_info->setHashAlgorithm(signature_handler.getHashAlgorithm()); + free(signerName); + if (!signature_info->isSubfilterSupported()) { error(errUnimplemented, 0, "Unable to validate this type of signature"); return signature_info; diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc index ea8e391d..f977cbba 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -636,6 +636,16 @@ std::vector<FormFieldSignature *> PDFDoc::getSignatureFields() return res; } +int PDFDoc::getNumSignatureFields() +{ + const Form *f = catalog->getForm(); + + if (!f) + return 0; + + return f->getNumFields(); +} + void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, int rotate, bool useMediaBox, bool crop, bool printing, bool (*abortCheckCbk)(void *data), void *abortCheckCbkData, bool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), void *annotDisplayDecideCbkData, bool copyXRef) { diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h index cea59282..53eeb7fe 100644 --- a/poppler/PDFDoc.h +++ b/poppler/PDFDoc.h @@ -226,6 +226,7 @@ public: bool isEncrypted() { return xref->isEncrypted(); } std::vector<FormFieldSignature *> getSignatureFields(); + int getNumSignatureFields(); // Check various permissions. bool okToPrint(bool ignoreOwnerPW = false) { return xref->okToPrint(ignoreOwnerPW); } diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc index ac40547f..f5d4c284 100644 --- a/poppler/SignatureHandler.cc +++ b/poppler/SignatureHandler.cc @@ -15,6 +15,7 @@ // Copyright 2020 Thorsten Behrens <[email protected]> // Copyright 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <[email protected]>. Work sponsored by Technische Universität Dresden // Copyright 2021 Theofilos Intzoglou <[email protected]> +// Copyright 2021 Marek Kasik <[email protected]> // //======================================================================== @@ -502,6 +503,8 @@ SECOidTag SignatureHandler::getHashOidTag(const char *digestName) char *SignatureHandler::getSignerName() { + char *commonName, *name; + if (!CMSSignerInfo || !NSS_IsInitialized()) return nullptr; @@ -511,7 +514,11 @@ char *SignatureHandler::getSignerName() if (!signing_cert) return nullptr; - return CERT_GetCommonName(&signing_cert->subject); + commonName = CERT_GetCommonName(&signing_cert->subject); + name = strdup(commonName); + PORT_Free(commonName); + + return name; } const char *SignatureHandler::getSignerSubjectDN() diff --git a/poppler/SignatureInfo.cc b/poppler/SignatureInfo.cc index 2d2707b4..923860b0 100644 --- a/poppler/SignatureInfo.cc +++ b/poppler/SignatureInfo.cc @@ -11,6 +11,8 @@ // Copyright 2018 Chinmoy Ranjan Pradhan <[email protected]> // Copyright 2018 Oliver Sander <[email protected]> // Copyright 2021 Georgiy Sgibnev <[email protected]>. Work sponsored by lab50.net. +// Copyright 2021 André Guerreiro <[email protected]> +// Copyright 2021 Marek Kasik <[email protected]> // //======================================================================== @@ -119,10 +121,10 @@ void SignatureInfo::setCertificateValStatus(enum CertificateValidationStatus cer cert_status = cert_val_status; } -void SignatureInfo::setSignerName(char *signerName) +void SignatureInfo::setSignerName(const char *signerName) { free(signer_name); - signer_name = signerName; + signer_name = signerName ? strdup(signerName) : nullptr; } void SignatureInfo::setSubjectDN(const char *subjectDN) diff --git a/poppler/SignatureInfo.h b/poppler/SignatureInfo.h index 8384cedb..eb1f0077 100644 --- a/poppler/SignatureInfo.h +++ b/poppler/SignatureInfo.h @@ -11,6 +11,8 @@ // Copyright 2018 Chinmoy Ranjan Pradhan <[email protected]> // Copyright 2018 Oliver Sander <[email protected]> // Copyright 2021 Georgiy Sgibnev <[email protected]>. Work sponsored by lab50.net. +// Copyright 2021 André Guerreiro <[email protected]> +// Copyright 2021 Marek Kasik <[email protected]> // //======================================================================== @@ -72,7 +74,7 @@ public: /* SETTERS */ void setSignatureValStatus(enum SignatureValidationStatus); void setCertificateValStatus(enum CertificateValidationStatus); - void setSignerName(char *); + void setSignerName(const char *); void setSubjectDN(const char *); void setLocation(const GooString *); void setReason(const GooString *);
