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>