Add Timestamp in Digital Signature

The process of digitally signing and adding timestamp to a PDF file using a PKCS12 (.p12/.pfx) file will be explained in this guide.

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 the 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 import section imports the necessary dependencies. The init function loads the API license key from the system environment to authenticate the library request.

The main function which is defined in lines 39-164, signs and timestamps the document. The function starts by getting the necessary inputs from the command line arguments. In lines 51-59, it gets the private key and certificate using the following.

pfxData, err := ioutil.ReadFile(p12Path)
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)
	}

Then a new model.PdfReader is created from the input file in lines 62-71. From the PdfReader object a new PdfAppender is created which is later used to signed the document. Line 80 creates a new model.SignatureHandler using sighandler.NewAdobePKCS7Detached(priv.(*rsa.PrivateKey), cert). Here the private key and the certificate object are given as arguments in the function call.

In line 86, a new PdfSignature object is created using model.NewPdfSignature(handler). Then the Name, Reason and Date fields of the PdfSignature are set in the following 3 lines. Following this, the signature is initialized using signature.Initialize() in line 91. This prepares the signature dictionary for signing.

Then a new signature field with a visible appearance is created in lines 100-109 as follows:

field, err := annotator.NewSignatureField(
  signature,
  []*annotator.SignatureLine{
    annotator.NewSignatureLine("Name", "John Doe"),
    annotator.NewSignatureLine("Date", "2019.16.04"),
    annotator.NewSignatureLine("Reason", "External signature test"),
  },
  opts,
)
field.T = core.MakeString("Self signed PDF")

The styles for this appearance are specified in the annotator.SignatureFieldOpts object defined in lines 96-98 like so.

opts := annotator.NewSignatureFieldOpts()
opts.FontSize = 10
opts.Rect = []float64{10, 25, 75, 60}

After that, the document is signed in line 111 using appender.Sign(1, field).

In lines 151-118, a new PdfReader is created from the signed document. This is done by first writing the signed document to a data buffer and then creating a new reader from that buffer. In line 125, a new PdfAppender is created from the new reader. Then a new signature handler is created using sighandler.NewDocTimeStamp("https://freetsa.org/tsr", crypto.SHA512). This handler is used to sign the document with a time stamp. Finally, in line 158 the document is written to file.

Run the code

Run the code using the following command:

go run pdf_sign_timestamp.go <FILE.p12> <PASSWORD> <INPUT_PDF_PATH> <OUTPUT_PDF_PATH>

Got any Questions?

We're here to help you.