Sign with AWS KMS Service
This guide explains the process of digitally signing a PDF file using an external signing service AWS KMS (AWS Key Management Service).
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
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
In the provided example code, the import
section imports the necessary UniPDF packages and other Go libraries. The init
function gets the metered license key and authenticates your library request.
The main
function of the program starts in line 56
. The input path, output path and key ID are parsed from the command line arguments in lines 57-64
. A PDF file signed with empty signature is generated using the following steps in lines 67-75
:
handler, err := sighandler.NewEmptyAdobePKCS7Detached(sigLen)
if err != nil {
log.Fatalf("Fail: %v\n", err)
}
_, signature, err := generateSignedFile(inputPath, handler)
if err != nil {
log.Fatalf("Fail: %v\n", err)
}
Then the byte ranges are parsed using parseByteRange(signature.ByteRange)
. The part where the external signing is simulated is in line 88
. This part returns a signature data which is then used to apply the signature to the PDF data buffer. This is done using:
sigBytes := make([]byte, sigLen)
copy(sigBytes, signatureData)
sig := core.MakeHexString(string(sigBytes)).WriteString()
copy(pdfData[byteRange[1]:byteRange[2]], []byte(sig))
The document is written to file in line 103
.
The generateSignedFile
function generates a signed version of the input PDF file using the specified signature handler. This function generates private key, creates certificate, and then signs the document using appender.Sign
method. After signing the document, it returns document buffer and signature.
The function that is used to simulate an external service by signing the specified PDF file and return its signed bytes and signature is defined in lines 176-222
. This function first gets an externalSigner
type AwsKmsExternalSigner(keyId)
in lines 177
. Then a new certificate template is initialized by providing basic certificate information such as CommonName
, Organization
, NotBefore
, NotAfter
etc. Using this template and awsKmsSign
external signer, a certificate data is prepared and then parsed by x509.ParseCertificate(certData)
to a certificate object. From this certificate a certificate chain is initialized and assigned to awsKmsSign.certChain
in line 211
.
Finally, the file is signed by calling generateSignedFile
and the signature.Contents.Bytes()
and pdfBytes
are returned from the function.
The parseByteRange
function parses the ByteRange
value of the signature field.
In line 255
, a call back function is defined to be used in the CryptoSigner
type which is defined in lines 258-263
. An EncryptionAlgorithmOID()
method of the CryptoSigner
is defined. This returns a asn1.ObjectIdentifier
type of encryption OID algorithm supported by the external services. The CryptoSigner
type implements the crypto.Signer
interface by defining the Public()
and Sign()
methods in lines 271-289
and 292-314
respectively. The Public()
method returns the public key corresponding to the private key and the Sign()
method signs digest with the private key.
The NewCryptoSigner
function in lines 316-322
returns a new CryptoSigner
object.
The externalSigner
type which is a wrapper for a third-party signer is defined in lines 327-340
. The AwsKmsExternalSigner
function wraps externalSigner
to model.SignatureHandler
.
The InitSignature
method of externalSigner
, initializes a model.PdfSignature
by setting the necessary fields of the object. This is defined in lines 369-391
. The Sign
method signs the given digest and returns an error in case of a fail. IsApplicable
method checks if the handler is applicable for the given model.PdfSignature
. NewDigest
creates a new model.Hasher
digest.
The Validate
method in lines 469-474
, validates the given model.PdfSignature
. The getPublicKey()
function returns crypto.PublicKey
of the externalSigner
object. And finally the toSigHandler
method converts the externalSigner
to model.SignatureHandler
type.
Run the code
Run the code using the following terminal command.
go run pdf_sign_external_aws_kms.go <INPUT_PDF_PATH> <OUTPUT_PDF_PATH> <KEY_ID>