Sign with External Services

This guide will explain the process of digitally signing a PDF file using an external signing service which returns PKCS7 package. The task of an external service is simulated by signing the file with UniPDF.

Sample Input

sample PDF file

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

The next section will explain the example code.

How it works

The import section in lines 10-29, imports the necessary UniPDF packages and other libraries. The init function initializes the program by setting the metered license key.

The main function is defined in lines 44-93. In lines 45-51, the input path and the output path are parsed from the command line arguments. Then in line 59, the generateSignedFile function is used to get the signed version of the file by providing the input path and a model.SignatureHandler. The signature handler is created in line 54 using handler, err := sighandler.NewEmptyAdobePKCS7Detached(8192). Here the signature length is specified in the argument which is 8192. Then in line 65 the Byte range value of the signature field is parsed using the parseByteRange(signature.ByteRange) function. The external signing service is simulated in line 73 using getExternalSignature(inputPath) function.

In lines 81-90, the external signature obtained from an external signing service are applied to the PDF buffer using:

sigBytes := make([]byte, 8192)
copy(sigBytes, signatureData)

sig := core.MakeHexString(string(sigBytes)).WriteString()
copy(pdfData[byteRange[1]:byteRange[2]], []byte(sig))

Then the document is written to file in line 88.

The generateSignedFile function which is used to generate the signed version of the provided document is defined in lines 97-153. In this function in lines 117-120, a model.PdfSignature is created from the signature handler provided in the function parameters. Then by calling the Initialize() method, the signature dictionary is prepared for signing. In lines 126-140, the signature field and appearance is created using the annotator function. This can be shown below.

// Create signature field and appearance.
opts := annotator.NewSignatureFieldOpts()
opts.FontSize = 10
opts.Rect = []float64{10, 25, 75, 60}

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("External signature")

After preparing the model.PdfFieldSignature this way, the document is signed using appender.Sign(1, field). Then the document is written to a buffer which then gets returned from the function.

The function getExternalSignature, which simulates an external signing service is defined in lines 157-201. First a private key is generated using rsa.GenerateKey(rand.Reader, 2048). Then an X509 certificate template is initialized by providing basic certificate information. A certificate data is created from the template using x509.CreateCertificate function. After that the data is parsed to get an x509.Certificate object. This is done using x509.ParseCertificate(certData) function call. By providing the private key and the certificate object, a new signature handler is created using sighandler.NewAdobePKCS7Detached(priv, cert) in line 190. Using this handler the signed file is generated by calling generateSignedFile function. Finally, the byte content of the model.PdfSignature is returned at the end of the function execution.

The function parseByteRange defined in lines 204-231, is used to parse the byte range value of the signature field.

Run the code

Run the code using the following terminal command.

go run pdf_sign_external.go <INPUT_PDF_PATH> <OUTPUT_PDF_PATH>

Sample output

Signed with External Service

Got any Questions?

We're here to help you.