Creating PAdES B-LT Signature

This guide will demonstrate the process of applying PAdES B-LT signature to a PDF document using UniPDF.

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 using the following command: It contains the Go code we will be using for this guide.

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

Then navigate to the signatures folder in the unipdf-examples directory.

cd unipdf-examples/signatures

Configure environment variables

Configure your license key using the following command: 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

The following section will explain the example code line by line.

The import section in lines 8-26, imports the necessary dependencies. Then in lines 28-35, the license key is loaded and set to authenticate library request. In line 37 a usage message is defined. This holds the information to be displayed to the user when the code is run.

The main function starts in line 39. In the beginning section of this function, i.e. in line 39-49, the necessary values are obtained from the command line arguments.

In line 52-60, The private key and X509 certificate are decoded from the PFX file using:

pfxData, err := ioutil.ReadFile(pfxPath)
if err != nil {
  log.Fatal("Fail: %v\n", err)
}

priv, cert, err := pkcs12.Decode(pfxData, password)
if err != nil {
  log.Fatal("Fail: %v\n", err)
}

The PEM file, whose path is provided via the command line arguments, is decoded to get a CA Certificate in lines 63-75. The following code accomplishes the decoding process.

caCertF, err := ioutil.ReadFile(pemPath)
if err != nil {
  log.Fatal("Fail: %v\n", err)
}

certDERBlock, _ := pem.Decode(caCertF)

cacert, err := x509.ParseCertificate(certDERBlock.Bytes)

Following this, in lines 78-93, a new PdfReader is created from the input file using:


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)
}
  

Then using this model.PdfReader, a new model.PdfAppendr is created by calling model.NewPdfAppender(reader) in line 90. After this, a new signature handler is instantiated in line 99 using:

sighandler.NewEtsiPAdESLevelLT(priv.(*rsa.PrivateKey), cert, cacert, timestampServerURL, appender)

The private key, X509 certificate, the time stamp server URL and the appender object are passed as arguments on this function call. Following this, a new model.NewPdfSignature is created using:

signature := model.NewPdfSignature(handler)
signature.SetName("PAdES B-LT Signature PDF")
signature.SetReason("TestPAdESPDF")
signature.SetDate(time.Now(), "")

if err := signature.Initialize(); err != nil {
  log.Fatal("Fail: %v\n", err)
}

As can be seen from the above snippet, the Name, Reason and Date fields of the model.PdfSignature are set before calling the Initialize method. The signature field and appearance are set in lines 115-128. Then, In line 130, the signature is applied using:

if err = appender.Sign(1, field); err != nil {
	log.Fatal("Fail: %v\n", err)
}

Then in lines 135-139 the signed document is written to a buffer as follows:

// Write output to buffer.
buffer := bytes.NewBuffer(nil)
err = appender.Write(buffer)
if err != nil {
  log.Fatal("Fail: %v\n", err)
}

To correctly save DSS/VRI a second pass is done using:


pdf2, err := model.NewPdfReader(bytes.NewReader(buffer.Bytes()))
if err != nil {
  log.Fatal("Fail: %v\n", err)
}

appender2, err := model.NewPdfAppender(pdf2)
if err != nil {
  log.Fatal("Fail: %v\n", err)
}

appender2.SetDSS(appender.GetDSS())

Finally, the document is written to a file using:

err = appender2.WriteToFile(outputPath)
if err != nil {
  log.Fatal("Fail: %v\n", err)
}

Run the code

Run the code using the following command:

go run pdf_sign_pades_b_lt.go <FILE.PFX> <PASSWORD> <FILE.PEM> <INPUT_PDF_PATH> <OUTPUT_PDF_PATH>

Got any Questions?

We're here to help you.