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
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>