[poppler] glib/demo glib/poppler-document.cc glib/poppler-document.h glib/poppler-form-field.cc glib/poppler-form-field.h glib/poppler.h glib/poppler-private.h glib/reference poppler/Form.cc poppler/PDFDoc.cc poppler/PDFDoc.h poppler/SignatureHandler.cc poppler/SignatureInfo.cc poppler/SignatureInfo.h

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Nov 25 22:31:03 UTC 2021


 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 <mkasik at redhat.com>
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  <carlosgc at gnome.org>
+ * Copyright (C) 2021 André Guerreiro <aguerreiro1985 at gmail.com>
+ * Copyright (C) 2021 Marek Kasik <mkasik at redhat.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
@@ -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 <trueroad at trueroad.jp>
  * Copyright (C) 2019, 2021 Oliver Sander <oliver.sander at tu-dresden.de>
  * Copyright (C) 2020 Albert Astals Cid <aacid at kde.org>
+ * Copyright (C) 2021 André Guerreiro <aguerreiro1985 at gmail.com>
+ * Copyright (C) 2021 Marek Kasik <mkasik at redhat.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
@@ -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 <jakubalba at gmail.com>
- * Copyright (C) 2018-2019 Marek Kasik <mkasik at redhat.com>
+ * Copyright (C) 2018, 2019, 2021 Marek Kasik <mkasik at redhat.com>
  * Copyright (C) 2019 Masamichi Hosoda <trueroad at trueroad.jp>
+ * Copyright (C) 2021 André Guerreiro <aguerreiro1985 at 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
@@ -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 <carlosgc at gnome.org>
  * Copyright (C) 2006 Julien Rebetez
  * Copyright (C) 2020 Oliver Sander <oliver.sander at tu-dresden.de>
+ * Copyright (C) 2021 André Guerreiro <aguerreiro1985 at gmail.com>
+ * Copyright (C) 2021 Marek Kasik <mkasik at redhat.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
@@ -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 <carlosgc at gnome.org>
+ * Copyright (C) 2021 André Guerreiro <aguerreiro1985 at gmail.com>
+ * Copyright (C) 2021 Marek Kasik <mkasik at redhat.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
@@ -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 <aguerreiro1985 at 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
@@ -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 <oliver.sander at tu-dresden.de>
 // Copyright 2019 Tomoyuki Kubota <himajin100000 at gmail.com>
 // Copyright 2019 João Netto <joaonetto901 at gmail.com>
-// Copyright 2020 Marek Kasik <mkasik at redhat.com>
+// Copyright 2020, 2021 Marek Kasik <mkasik at redhat.com>
 // Copyright 2020 Thorsten Behrens <Thorsten.Behrens at CIB.de>
 // Copyright 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
 // Copyright 2021 Georgiy Sgibnev <georgiy at sgibnev.com>. 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 <Thorsten.Behrens at CIB.de>
 // Copyright 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
 // Copyright 2021 Theofilos Intzoglou <int.teo at gmail.com>
+// Copyright 2021 Marek Kasik <mkasik at redhat.com>
 //
 //========================================================================
 
@@ -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 <chinmoyrp65 at protonmail.com>
 // Copyright 2018 Oliver Sander <oliver.sander at tu-dresden.de>
 // Copyright 2021 Georgiy Sgibnev <georgiy at sgibnev.com>. Work sponsored by lab50.net.
+// Copyright 2021 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright 2021 Marek Kasik <mkasik at redhat.com>
 //
 //========================================================================
 
@@ -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 <chinmoyrp65 at protonmail.com>
 // Copyright 2018 Oliver Sander <oliver.sander at tu-dresden.de>
 // Copyright 2021 Georgiy Sgibnev <georgiy at sgibnev.com>. Work sponsored by lab50.net.
+// Copyright 2021 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright 2021 Marek Kasik <mkasik at redhat.com>
 //
 //========================================================================
 
@@ -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 *);


More information about the poppler mailing list