Sign with Global Sign DSS Service

This guide will explain the process of digitally signing a PDF file using the GlobalSign DSS (Digital Signing Service) API.

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 imports the UniPDF packages and other necessary libraries. The init function initializes the program by setting the metered license key from the system environment using license.SetMeteredKey(os.Getenv(`UNIDOC_LICENSE_API_KEY`)).

The main function defined in lines 52-79 signs the document using an external signature, which in this case is simulated by signing it using UniPDF, and finally writes it to a file. In this function in lines 53-64 the necessary paths are parsed from the command line arguments. In line 68, the getExternalSignatureAndSign function is used to sign the document. The ioutil.WriteFile function writes the document to file using the output path provided via the command line arguments.

The generateSignedFile function returns a signed version of the provided input file. The document is signed using the model.PdfAppender object which is created from a model.PdfReader. This is done in lines 97-104 using the following code:

// Create appender.
appender, err := model.NewPdfAppender(reader)
if err != nil {
  return nil, err
}

if err = appender.Sign(1, field); err != nil {
  return nil, err
}

In lines 107-127, LTV (Long-Term Validation) is added to the signature. Then the document is written to buffer and returned.

The getExternalSignatureAndSign function gets an external signature and signs the document using the obtained signature. Here in line 142, a new SignatureHandler is created using NewGlobalSignPdfSignature(). Then a SignOption object is created in lines 147-152. Using the SignOption and the SignatureHandler, a signature filed is created by calling createSignatureField(option, handler). Then the document is signed using the generateSignedFile(inputPath, handler, signatureField) function.

The externalSigner type, which is a wrapper for third-party signer, is defined in lines 169-179. It implements the model.SignatureHandler interface. The NewGlobalSignPdfSignature() function wraps the externalSigner to SignatureHandler type. This gets a new client by calling globalsign.NewClient function by providing apiKey, apiSecret, certFilepat and keyFilepath as arguments to the function. Then it adds this client and a new context.Background() to a new externalSigner and returns it.

The InitSignature method in lines 198-270, is part of the model.SignatureHandler interface implementation. What this method does is, it sets the PdfSignature parameter. It starts by getting globalsign.Client in line 199. Then it gets globalsign.DSSIdentity using:

identity, err := globalsign.DSSService.DSSGetIdentity(gsClient.DSSService, es.ctx, "GLOBALSIGN TEST ACCOUNT - FOR TESTING PURPOSE ONLY", &globalsign.IdentityRequest{
  SubjectDn: globalsign.SubjectDn{},
})

This identity is then converted to base 64 format using base64.StdEncoding.DecodeString(identity.OCSP) in line 213. After this value is then set to the ocsp field of the external signature. In lines 220-252 a certificate chain is created from identity.SigningCert and identity.CA. This certificate chain is set to the external signature using es.certChain = certChain. A PDF array object which is used to contain the certificate chain data is created in lines 255-258. In lines 261-267, the reset of the model.PdfSignature parameters are set using:

sig.Cert = pdfCerts
handler := *es
sig.Handler = &handler
sig.Filter = core.MakeName("Adobe.PPKLite")
sig.SubFilter = core.MakeName("adbe.pkcs7.detached")
sig.Reference = nil

Finally, the Sign method of the external signature is called, and the result is returned to the caller.

The Sign method is defined in lines 273-373. This method signs the digest using the provided PdfSignature. It returns an error if the singing fails.

The methods IsApplicable, NewDigest, Validate are part of the model.SignatureHandler interface implementation. The IsApplicable checks if the signature handler is applicable for the PdfSignature. The NewDigest creates, as its name indicates, a new digest data. The Validate method, you guessed it, validates the PdfSignature.

The getCertificateChain function, which can be found in lines 398-400, returns the certificate chain of externalSigner. A RevocationInfoArchival type is defined in lines 403-407. Then the SignerCallback which is part of the Signer type is defined in line 410. The Signer type is defined below that, in lines 414-417. This type implements the crypto.Signer interface.

The EncryptionAlgorithmOID() method of the Signer returns the pkcs7.OIDEncryptionAlgorithmRSA. The Sign and Public() methods are implementation the crypto.Signer interface. The newSigner function returns a new Singer object.

A SignOption type which contains both digital signing and annotation properties, is defined in lines 446-469. The createSignatureField function creates and returns model.PdfSignature and PdfFieldSignature.

The createSignatureField function defined in lines 473-540, creates a signature field and an associated signature, based on the provided options.

Run the code

To run the code, use the following command on your terminal while in the corresponding example directory.

go run pdf_sign_external_globalsign.go <INPUT_PDF_PATH> <OUTPUT_PDF_PATH> <API_KEY> <API_SECRET> <CERT_FILE_PATH> <KEY_FILE_PATH>

Got any Questions?

We're here to help you.