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>