Enabling LTV Using Second Revision And TimeStamp
This guide will demonstrate the process of digitally signing a PDF file using a PKCS12 (.p12/.pfx) file and LTV enabled the signature.
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 import
section in lines 12-32
, imports all the necessary dependencies.
The init
function in lines 34-41
, authenticates UniPDF library request by setting the metered license key using license.SetMeteredKey(os.Getenv(`UNIDOC_LICENSE_API_KEY`))
.
The main
function is defined in lines 45-115
. Inside this function the code in lines 51-54
gets the p12Path, password, inputPath and outputPath from the command line arguments. The private key and the certificate are loaded and decoded from the p12Path in lines 57-65
. The next section loads the certificate chain from the command line arguments and decodes it as follows:
certChain := []*x509.Certificate{cert}
if len(args) == 6 {
issuerCertData, err := ioutil.ReadFile(args[5])
if err != nil {
log.Fatal("Fail: %v\n", err)
}
for len(issuerCertData) != 0 {
var block *pem.Block
block, issuerCertData = pem.Decode(issuerCertData)
if block == nil {
break
}
issuer, err := x509.ParseCertificate(block.Bytes)
if err != nil {
log.Fatal("Fail: %v\n", err)
}
certChain = append(certChain, issuer)
}
}
The document is signed and written to buffer in line 91
. Then the buffer that contains the signed content is passed through the ltvEnableAndTimestamp
function to enable LTV, timestamp and then write to buffer. Then at line 103
, the timestamp signature is LTV enabled using ltvEnableTimestampSig(bytes.NewReader(signedBytes))
.
Finally, the document is written to file using ioutil.WriteFile(outputPath, signedBytes, 0644)
in line 109
.
The signFile
function in lines 117-179
, is used to sign a file and return signed content as byte buffer. In this function in line 137
, a new handler is created using sighandler.NewAdobePKCS7Detached(priv, cert)
. Then in line 142-146
, a new PdfSignature
object is created from the signature handler. Signature field and appearance is created in lines 153-166
. Finally, the document is signed in line 168
and returned as a buffer at line 178
.
The ltvEnableAndTimestamp
function is used to create a timeStamp signature with LTV enabled. In line 189
of this function a new PdfAppender
is created using model.NewPdfAppender(reader)
. Then a new model.LTV
object is created in line 200
. After this the LTV is enabled using ltv.EnableAll(certChain)
.
In line 205
, The timestamp handler is created using handler, err := sighandler.NewDocTimeStamp("https://freetsa.org/tsr", crypto.SHA512)
. Then in lines 211-226
, the PdfSignature
and PdfSignatureField
are created as follows:
signature := model.NewPdfSignature(handler)
signature.SetName("Test Sign Timestamp")
signature.SetReason("TestSignTimestamp")
if err := signature.Initialize(); err != nil {
return nil, err
}
sigField := model.NewPdfFieldSignature(signature)
sigField.T = core.MakeString("Test Sign Timestamp")
sigField.Rect = core.MakeArray(
core.MakeInteger(0),
core.MakeInteger(0),
core.MakeInteger(0),
core.MakeInteger(0),
)
Using the Sign
method of the Appender
object, the document is signed in line 228
. Finally, the signed document is returned as bytes.buffer
in line 238
.
The definition of the ltvEnableTimestampSig
function starts in line 241
. In line255
, a new model.LTV
object is created using ltv, err := model.NewLTV(appender)
. Then it is enabled in line 260
using ltv.EnableAll(nil)
. The document is returned as a buffer in line 270
.
Run the code
To run the code use the following command:
go run pdf_sign_ltv_timestamp_revision.go <FILE.p12> <P12_PASS> <INPUT_PDF_PATH> <OUTPUT_PDF_PATH> [<EXTRA_CERTS.pem>]