Skip to content

Instantly share code, notes, and snippets.

@bseddon
Last active May 10, 2021 17:27
Show Gist options
  • Save bseddon/e064a06e270bc66ddc266b0ac58f288d to your computer and use it in GitHub Desktop.
Save bseddon/e064a06e270bc66ddc266b0ac58f288d to your computer and use it in GitHub Desktop.
xml digital signature

When wanting to sign XML documents using a protocol such as https://www.w3.org/TR/xmldsig-core/ or https://www.w3.org/TR/xmldsig-core2/ its necessary to have a certificate and its corresponding private key. Sure, you can buy a certificate and key from a certificate authority (CA) but if the purpose of the certificate is only to generate certificates for internal consumption, for testing or when verifiers will trust a CA you provide, then creating your own certificates and keys is free.

Here's how to do it using a tool like OpenSSL. Another tool could be used as this example uses only standard public key infrastructure (PKI) techniques. Throughtout I'm using a domain in the file names. This hints that the certificate will be available online so others will be able to access it to verify any certificates it is used to sign.

Create certificate authority

A certificate authority is just the owner of a certificate and public key where the subject and issuer fields of the certificate are the same. That is, the certificate is its own parent. Begin by creating a key. PKI allows keys to be of different strengths but this detail is not relevant to this gist.

openssl ecparam -out signing.example.com.key -name prime256v1 -genkey

Now a certificate can be created. The details of the certificate are taken from a certificate signing request (CSR) which has to be created first. Normally the CSR will be forwarded to a CA that will return a certificate and associated private key. In this case we are the CA so can use the CSR directly:

openssl req -new -key signing.example.com.key -sha256 -nodes -out signing.example.com.csr -config signing.example.com.config

The CSR configuration, which is stored in a file (in this case signing.example.com.config), might be:

emailAddress					= signing@examppe.com
orgName						= Example Co

[ req ]
default_bits					= 2048
distinguished_name				= req_distinguished_name
req_extensions					= v3_req
prompt						= no
encrypt_key					= no

#About the user for the request
[ req_distinguished_name ]
countryName					= UK
stateOrProvinceName				= Co State
localityName					= Co Town
organizationName				= $orgName
commonName					= $orgName
emailAddress					= $emailAddress
organizationalUnitName				= Certification

#Extensions to add to a certificate request for how it will be used
[ v3_req ]
basicConstraints             		   	= CA:true
subjectAltName					= @alt_names

#The other names your server may be connected to as
[alt_names]
email						= $emailAddress

The structure and content of a CSR configuration file are described on the OpenSSL request manual page. Note the basicConstraint field includes the value CA:true which tells OpenSSL that a CA certificate is being created (the subject should be the same as the issuer).

OK, now the CA root certificate can be generated:

openssl x509 -req -sha256 -days 365 -in signing.example.com.csr -signkey signing.example.com.key -out signing.example.com.crt

Now there is a certificate in signing.example.com.crt. This is the root certificate for a private CA. It can be opened and reviewed using a certificate viewer however this OpenSSL command will list its contents:

openssl x509 -in signing.example.com.crt -noout -text

Creating and signing a client certificate

With a root certificate (signing.example.com.crt) and associated private key (signing.example.com.key) its possible to create and sign any number of client certificates. It is the client certificate that are used to sign XML and other documents. The process is the same as for creating a CA root certificate and begins with the creation of a private key in this case called client.key. This key will be used when signing a client document.

openssl req -new -newkey rsa:2048 -keyout client.key -sha256 -nodes -x509 -out client-cert.csr -config client-cert-req.config

This command also creates a CSR (client-cert.csr) which is based on the configuration in client-cert-req.config.

oid_section					= OIDs
emailAddress					= client@example.com
orgName						= Example co

[ req ]
default_bits					= 2048
distinguished_name				= req_distinguished_name
req_extensions					= v3_req
x509_extensions					= x509_ext
prompt						= no
encrypt_key					= no

[ OIDs ]
LEIOID						= 1.3.6.1.4.1.52266.1
RoleOID						= 1.3.6.1.4.1.52266.2

#About the user for the request
[ req_distinguished_name ]
countryName					= UK
stateOrProvinceName				= Client state
localityName					= Client Town
organizationName				= $orgName
commonName					= $orgName
emailAddress					= $emailAddress
givenName					= Client first name
surname						= Client last name
title						= Client role
organizationalUnitName				= Head office

#Extensions to add to a certificate request for how it will be used
[ v3_req ]
subjectAltName					= @alt_names
LEIOID						= ASN1:PRINTABLESTRING:A1B2C3D3E5F6G7H8I9J0
RoleOID						= ASN1:PRINTABLESTRING:CEO

#The other names your server may be connected to as
[alt_names]
email						= $emailAddress

[x509_ext]
basicConstraints            			= CA:FALSE
keyUsage					= critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage				= critical, clientAuth
LEIOID						= ASN1:PRINTABLESTRING:A1B2C3D3E5F6G7H8I9J0
RoleOID						= ASN1:PRINTABLESTRING:CEO
crlDistributionPoints				= URI:http://example.com/crl/

Its not the purpose of this gist to describe the configuration though it is worth noting that the basicConstraint value is CA:false. The configuration also shows how to add non-standard object identifiers (OIDs).

Next its time to create client certificate and sign it:

openssl x509 -in client-cert.csr -CA signing.example.com.crt -CAkey signing.example.com.key -CAcreateserial -out client-cert.crt -days 365 -sha256

So what's going on here? The CSR is being used to defined the certificate being created. The CSR will be used to define the subject of the certificate. The -CA parameter is the CA root certificate which defines the issuer of the client certificate. The client certificate is signed using the CA key (signing.example.com.key) and output as client-cert.crt. The CA defines how long the certificate will be valid (365 days in this case) and what hashing algorithm will be use (sha256 in this case).

The client will be sent the two files client-cert.crt and client.key. Using an appropriate software application and these two files, a client will be able to sign a document.

Verifiying a client certificate

Having received the two files a client may wish to verify the certificate. In addition to the two 'client' files the client may also be sent the CA certificate (but not the CA key) or the client will be told from where on-line the CA certificate can be retrived. With the client and CA certificates the client certificate can be verified using the OpenSSL command:

openssl verify -CAfile signing.xbrlquery.com.crt client.crt

It's also possible to verify the client's private key. This is done using two commands. One command retrives the 'modulus' of the client key while the other retrieves the modulus of the client's certificate. Both output values should be identical.

openssl rsa -modulus -noout -in client.key

openssl x509 -modulus -noout -in client.crt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment