Validating PAdES Signatures

This guide shows how to validate a digital signature with UniDoc for PAdES compatibility.

Before you begin

You should get your API key from your UniCloud account.

If this is your first time using UniPDF SDK, follow this guide to set up a local development environment.

Project setup

Clone the project repository

In your terminal, clone examples repository. It contains the Go code we will be using for this guide.

git clone https://github.com/unidoc/unipdf-examples.git

Navigate to the signatures folder in the unipdf-examples directory.

cd unipdf-examples/signatures

Configure environment variables

Replace the UNIDOC_LICENSE_API_KEY with your API credentials from your UniCloud account.

Linux/Mac

export UNIDOC_LICENSE_API_KEY=PUT_YOUR_API_KEY_HERE

Windows

set UNIDOC_LICENSE_API_KEY=PUT_YOUR_API_KEY_HERE

How it works

/*
* This example showcases how to validate a digital signature with UniDoc for PAdES compatibility.
*
* $ ./pdf_sign_validate_pades_b_b <INPUT_PDF_PATH>
*/
package main
import (
"fmt"
"log"
"os"
"github.com/unidoc/unipdf/v4/common/license"
"github.com/unidoc/unipdf/v4/model"
"github.com/unidoc/unipdf/v4/model/sighandler"
)
func init() {
// Make sure to load your metered License API key prior to using the library.
// If you need a key, you can sign up and create a free one at https://cloud.unidoc.io
err := license.SetMeteredKey(os.Getenv(`UNIDOC_LICENSE_API_KEY`))
if err != nil {
panic(err)
}
}
const usagef = "Usage: %s INPUT_PDF_PATH\n"
func main() {
args := os.Args
if len(args) < 2 {
fmt.Printf(usagef, os.Args[0])
return
}
inputPath := args[1]
// Create reader.
file, err := os.Open(inputPath)
if err != nil {
log.Fatal("Fail: %v\n", err)
}
defer file.Close()
reader, err := model.NewPdfReader(file)
if err != nil {
log.Fatal("Fail: %v\n", err)
}
// Create signature handler. It is possible to validate B-T level the same way if you create NewEtsiPAdESLevelT here
padesHandler, err := sighandler.NewEtsiPAdESLevelB(nil, nil, nil)
if err != nil {
log.Fatal("Fail: %v\n", err)
}
handlers := []model.SignatureHandler{
padesHandler,
}
// Validate signatures.
res, err := reader.ValidateSignatures(handlers)
if err != nil {
log.Fatal("Fail: %v\n", err)
}
if len(res) == 0 {
log.Fatal("Fail: no signature fields found")
}
if !res[0].IsSigned || !res[0].IsVerified {
log.Fatal("Fail: validation failed")
}
for i, item := range res {
fmt.Printf("--- Signature %d\n%s\n", i+1, item.String())
}
}

In the example code above, the import section imports the necessary UniPDF packages and other Go libraries. The init function defined in lines 18-25, loads the API keys and sets the license using license.SetMeteredKey(os.Getenv(`UNIDOC_LICENSE_API_KEY`)).

The main function in lines 29-75, contains the code that is used to validate the signature for PAdES compatibility. In lines 30-34, the input file is parsed from the command line arguments. Then a new PdfReader is created using model.NewPdfReader(file) in line 44. In line 50-53, a new signature handler is created using:

padesHandler, err := sighandler.NewEtsiPAdESLevelB(nil, nil, nil)
if err != nil {
	log.Fatal("Fail: %v\n", err)
}

The signature handler created using NewEtsiPAdESLevelB is used to validate PAdES Baseline B Signature. To validate a PAdES Baseline T Signature, use the NewEtsiPAdESLevelT function instead.

A list of handlers is instantiated in line 55. In lines 60-74, The ValidateSignatures method of the PdfReader is used to validate the signature as follows.

res, err := reader.ValidateSignatures(handlers)
if err != nil {
	log.Fatal("Fail: %v\n", err)
}
if len(res) == 0 {
	log.Fatal("Fail: no signature fields found")
}

if !res[0].IsSigned || !res[0].IsVerified {
	log.Fatal("Fail: validation failed")
}

for i, item := range res {
	fmt.Printf("--- Signature %d\n%s\n", i+1, item.String())
}

The IsSigned and IsVerified fields are checked in line 68. The for loop in line 72-74, iterates through each result and prints the validation results.

Run the code

To run the code use the following command.

 go run pdf_sign_validate_pades_b_b.go <INPUT_PDF_PATH>

Got any Questions?

We're here to help you.