An Introduction to
XML Signature and XML Encryption
with XMLSec

Philippe Camacho

Contents

1  Introduction

XMLSec is a C library that implements the standards XML Signature and XML Encryption This library is built upon other C libraries:

Like OpenSSL , XMLSec can be used as a toolbox with the command line tool. This tutorial shows how to use the XMLSec command line as a practical introduction to digital signature and data encryption using XML.

1.1  Installation

Under Linux you can download and compile the source code from XMLSec . But you should install the corresponding package as almost every linux distribution comes with XMLSec . Under Windows you can find precompiled binaries at Zlatkovic’s homepage. Do not forget to install the required libraries first: libxml2, libxslt, iconv and zlib. Once the installation is over, open a terminal and write:

 
> xmlsec
Usage: xmlsec <command> [<options>] [<file>]

xmlsec is a command line tool for signing, verifying, encrypting and
decrypting XML documents. The allowed <command> values are:
 --help        display this help information and exit
  --help-all    display help information for all commands/options and exit
  --help-<cmd>  display help information for command <cmd> and exit
  --version     print version information and exit
  --keys        keys XML file manipulation
  --sign        sign data and output XML document
  --verify      verify signed document
  --sign-tmpl   create and sign dynamicaly generated signature template
  --encrypt     encrypt data and output XML document
  --decrypt     decrypt data from XML document
	
		



--help displays the basic help information. With --help-all you can get more details. Finally if you want to know how to use a specific command: --help-<command>. Each command has got numerous options. In this tutorial we show some basic examples to encrypt/decrypt and sign/verify signature using XML documents.

1.2  Generation of public/private key pair and certificate

As to be able to digitally sign or to encrypt an XML file we need to generate a pair of public/private keys and the corresponding certificate. To do your task easier you can download all the files here: keysncerts.zip. The zip file contains:

Important note: the password for the user’s private key is hello (lowercase).

The last two files will be used to sign xml documents using X509 certificates. If you want to know how to create the keys and certificates have a look at: An Introduction to the OpenSSL command line tool.

2  Digital signatures

2.1  Basic example

To sign a XML document we need two things:

Here is an example of a XML template:

doc.xml

 {doc.xml}
<References>
 <Book>
  <Author>
   <FirstName>Bruce</FirstName>
    <LastName>Schneier</LastName>
  </Author>
  <Title>Applied Cryptography</Title>
 </Book>
 <Web>
  <Title>XMLSec</Title>
   <Url>http://www.aleksey.com/xmlsec/</Url>
 </Web>
 <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
   <CanonicalizationMethod Algorithm=
      "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
    <SignatureMethod Algorithm=
      "http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
     <Reference URI="">
      <Transforms>
       <Transform Algorithm=
         "http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
      </Transforms>
       <DigestMethod Algorithm=
          "http://www.w3.org/2000/09/xmldsig#sha1"/>
        <DigestValue></DigestValue>
     </Reference>
  </SignedInfo>
  <SignatureValue />
  <KeyInfo>
   <KeyValue />
  </KeyInfo>
 </Signature>
</References>
 	
		



There are three signature modes:

In our case we have an enveloped signature, i.e. the whole node References will be signed. This is defined in the node <Transform>.

 
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
  	
		



When adding the node <KeyValue> inside the node <KeyInfo> you can obtain the value of the public key that is needed to verify the signature inside the signed xml. To create the signature:

 
> xmlsec --sign --output doc-signed.xml \
     --privkey-pem userkey.pem doc.xml
 	
		



The obtained signed document is:

doc-signed.xml

 
<?xml version="1.0"?>
<References>
 <Book>
  <Author>
  <FirstName>Bruce</FirstName>
   <LastName>Schneier</LastName>
  </Author>
  <Title>Applied Cryptography</Title>
 </Book>
 <Web>
  <Title>XMLSec</Title>
   <Url>http://www.aleksey.com/xmlsec/</Url>
 </Web>
 <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
   <CanonicalizationMethod Algorithm=
       "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
    <SignatureMethod Algorithm=
       "http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
     <Reference URI="">
      <Transforms>
       <Transform Algorithm=
         "http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
      </Transforms>
      <DigestMethod Algorithm=
          "http://www.w3.org/2000/09/xmldsig#sha1"/>
      <DigestValue>V0ilDen0qBzCslw7EkJfhWO13/I=</DigestValue>
     </Reference>
  </SignedInfo>
  <SignatureValue>ZxS85XSwIVfbmjjF3I...</SignatureValue>
   <KeyInfo>
    <KeyValue>
     <RSAKeyValue>
      <Modulus>
      0SsRwFq8qy6gHmSMc3JuvXTgpByqgUpKl78G06EqXvu+8P6b1gI9KrNSKI3LfUAd
      H0AiuH49hl/KCPybe2u+Dqwg2syyVG9gvVGONZXSGJuWBREjQ7Ba683WIubkQuQ2
   r10jgx+7SBUyTqjzm05gmwiasyrXC9kDMCLPx7K3k3s=
   </Modulus>
   <Exponent>
   AQAB
   </Exponent>
   </RSAKeyValue>
    </KeyValue>
   </KeyInfo>
  </Signature>
</References>
    	
		



To check the signature, you need the signed document and an access to the public key. In our case the public key is inside the document so we do not need to specify the place of the public key.



 
> xmlsec --verify doc-signed.xml
   OK
   SignedInfo References (ok/all): 1/1
   Manifests References (ok/all): 0/0
    	
		



If the public key is not inside the signed xml document (delete the node <KeyValue> to test it) you can specify the public key file with the option --pubkey-pem

 
> xmlsec --verify --pubkey-pem pub-userkey.pem doc-signed.xml
 OK
 SignedInfo References (ok/all): 1/1
 Manifests References (ok/all): 0/0
    	
		



Now you can change a character of the data (in the signature or elsewhere in the document) as check that the verification process does not pass anymore.

2.2  Signing part of the document

The next step is to be able to sign only a part(node) of the document. We propose two methods:

The xml template to sign a node identified by the ID atribute is the following:

doc-id.xml

 
<References>
 <Book xml:id="BookBSchneier">
  <Author>
   <FirstName>Bruce</FirstName>
    <LastName>Schneier</LastName>
  </Author>
  <Title>Applied Cryptography</Title>
 </Book>
 <Web>
  <Title>XMLSec</Title>
  <Url>http://www.aleksey.com/xmlsec/</Url>
 </Web>
 <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
   <CanonicalizationMethod Algorithm=
     "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
    <SignatureMethod Algorithm=
     "http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
     <Reference URI="#BookBSchneier">
      <Transforms>
       <Transform Algorithm=
        "http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
      </Transforms>
      <DigestMethod Algorithm=
         "http://www.w3.org/2000/09/xmldsig#sha1"/>
      <DigestValue></DigestValue>
   </Reference>
   </SignedInfo>
   <SignatureValue />
   <KeyInfo>
    <KeyValue />
   </KeyInfo>
  </Signature>
</References>  
    	
		



Now there is no transformation and the attribute URI of the <Reference> node has the value of the xml:id attribute of node Book. Use the same command as before to sign this document:

 
> xmlsec --sign --output doc-id-signed.xml \
    --privkey-pem userkey.pem doc-id.xml
  	
		



An interesting and simple exercise is to modify a node that has not been signed (like <Web>) and check that the verification process still passes due to the fact that the signed data (<Book> node) has not been corrupted.

The template to sign a node using XPath is the following:



doc-xpath.xml

 
<References>
 <Book>
      <Author>
          <FirstName>Bruce</FirstName>
          <LastName>Schneier</LastName>
      </Author>
      <Title>Applied Cryptography</Title>
  </Book>
  <Web>
      <Title>XMLSec</Title>
      <Url>http://www.aleksey.com/xmlsec/</Url>
  </Web>
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
      <SignedInfo>
          <CanonicalizationMethod Algorithm=
           "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
          <SignatureMethod Algorithm=
           "http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
          <Reference>
          <Transforms>
              <Transform Algorithm=
              "http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
              <Transform Algorithm=
              "http://www.w3.org/TR/1999/REC-xpath-19991116">
                  <XPath>ancestor::Book</XPath>
              </Transform>
          </Transforms>
          <DigestMethod Algorithm=
          "http://www.w3.org/2000/09/xmldsig#sha1"/>
          <DigestValue></DigestValue>
          </Reference>
      </SignedInfo>
      <SignatureValue />
      <KeyInfo>
          <KeyValue />
      </KeyInfo>
  </Signature>
</References>
    	
		



The first transformation (node <Transform>) allows to get the whole document (node <Reference>) then the second transformation only selects the <Book> node. Like before any modification outside the node <Book> (and the signature node obviously) should not invalidate the signature. We use the same command to sign this document

 
> xmlsec --sign --output doc-xpath-signed.xml \
     --privkey-pem userkey.pem doc-xpath.xml
  	
		



It is important to note that XPath transformation should be used with special care because the end-user may not know clearly what he is going to sign. See XML Signature: only what is seen should be signed for interesting security considerations.

2.3  Signing using a X509 certificate

The template to sign with X509 information is the same as doc.xml but with the additional node <X509Data>.

doc-x509.xml

 
<References>
 <Book>
  <Author>
   <FirstName>Bruce</FirstName>
   <LastName>Schneier</LastName>
  </Author>
  <Title>Applied Cryptography</Title>
 </Book>
 <Web>
  <Title>XMLSec</Title>
  <Url>http://www.aleksey.com/xmlsec/</Url>
 </Web>
 <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
   <CanonicalizationMethod Algorithm=
    "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
   <SignatureMethod Algorithm=
    "http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
   <Reference URI="">
    <Transforms>
     <Transform Algorithm=
      "http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
    </Transforms>
    <DigestMethod Algorithm=
      "http://www.w3.org/2000/09/xmldsig#sha1"/>
    <DigestValue></DigestValue>
   </Reference>
  </SignedInfo>
  <SignatureValue />
  <KeyInfo>
   <X509Data >
    <X509SubjectName/>
    <X509IssuerSerial/>
    <X509Certificate/>
   </X509Data>
   <KeyValue />
  </KeyInfo>
 </Signature>
</References>
   	
		



Now the command to sign is a little different as we need the user’s PKCS12 certificate and the certificate of the trusted authority.

 
> xmlsec --sign --output doc-signed-x509.xml --pkcs12 usercert.p12 \ 
   --pwd hello --trusted-pem cacert.pem doc-x509.xml
   	
		



We obtain this XML document where the information of the user’s certificate (name, subject...) appears in the <X509Data> node.

doc-signed-x509.xml

 
<?xml version="1.0"?>
<References>
 <Book>
  <Author>
   <FirstName>Bruce</FirstName>
   <LastName>Schneier</LastName>
  </Author>
  <Title>Applied Cryptography</Title>
 </Book>
 <Web>
  <Title>XMLSec</Title>
  <Url>http://www.aleksey.com/xmlsec/</Url>
 </Web>
 <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
   <CanonicalizationMethod Algorithm=
    "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
   <SignatureMethod Algorithm=
    "http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
   <Reference URI="">
    <Transforms>
     <Transform Algorithm=
      "http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
    </Transforms>
    <DigestMethod Algorithm=
     "http://www.w3.org/2000/09/xmldsig#sha1"/>
    <DigestValue>V0ilDen0qBzCslw7EkJfhWO13/I=</DigestValue>
   </Reference>
  </SignedInfo>
  <SignatureValue>jWDgAy5cp6+EnitDkTUiIaXMsN6tW5rEFQsTabuSm8kW7CMUEVqYxUZGT6YWtWLS
  lbCQNxOFChDSQpu30B5MIAaR+j8/FfrAmERlXv7RWzY5mb/4InvUoDF4Bs10Rqb2
  twHNsyLPpW9FTeQ7Z3ftaXShKcyPeh6zOvMwDRKLxdQ=</SignatureValue>
  <KeyInfo>
   <X509Data>
   <X509Certificate>MIIC6DCCAlGgAw...</X509Certificate>
   <X509SubjectName>emailAddress=jsmith@hello.com,CN=John Smith,
   O=littlecryptographer,ST=RM,C=CL</X509SubjectName>
   <X509IssuerSerial>
   <X509IssuerName>emailAddress=lostilos@free.fr,CN=PhilippeCamacho,
   O=littlecryptographer,L=Santiago,ST=RM,C=CL</X509IssuerName>
   <X509SerialNumber>286</X509SerialNumber>
   </X509IssuerSerial>
   </X509Data>
   <KeyValue>
    <RSAKeyValue>
     <Modulus>
      vBKEgNWKPb...
     </Modulus>
     <Exponent>
      AQAB
     </Exponent>
    </RSAKeyValue>
   </KeyValue>
  </KeyInfo>
 </Signature>
</References>
   	
		



Now to verify the validity of the xml document you need to provide the trusted certificate of the Certificate Authority that issued the user’s certificate:

 
> xmlsec --verify --trusted-pem cacert.pem doc-signed-x509.xml 
OK
SignedInfo References (ok/all): 1/1
Manifests References (ok/all): 0/0
 	
		



3  Encryption

The standard XML Encryption defines how to encrypt XML documents. Encryption comes basically in two flavours:

The main advantage of symmetric key encryption is that it is fast. Its main default is that both participants (sender and receiver) have to agree first on a secret key which can be difficult in practice (telephone, paper...): symmetric key encryption does not solve the key distribution problem.

The great advantage of using public key algorithms is that they solves the key distribution problem. Why? Because if I want to send a confidential message to Bob I only have to look for its public key, then encrypt the message using this public key. Bob when receiving the encrypted message will be the only person able to decrypt it using his private key. Obviously I must be sure that the public key I used is really Bob’s one... But this is another problem (Man in the middle attack) that is solved using a Public Key Infrastructure or some more distributed model of trust like PGP. A big practical default of public key encryption is that it is slow.

So to get the best of both worlds (speed and ease of key distribution) in practice we use hybrid encryption: Let’s suppose I want to send a confidential message to Bob:

  1. I look for Bob’s public key PublicKeyBob.
  2. I generate a random session key SessionKey.
  3. I encrypt my message using a symmetric encryption algorithm with SessionKey.
  4. I encrypt the session key (which is much shorter than a long message) SessionKey using the public key algorithm with PublicKeyBob.
  5. Bob when receiving the message, first recovers the session key SessionKey using his private key PrivateKeyBob and the public key algorithm.
  6. Bob is now able to decrypt the message with the SessionKey and the symmetric encryption algorithm.

XML Encryption implements many forms of encryption including hybrid encryption. As this kind of encryption is the most desirable in practice we will focus on it. So let’s imagine that the pair of keys we generated in the beginning is Bob’s one.

3.1  Encryption of a whole XML document

The document we want to encrypt is:

doc-plain.xml

 
<?xml version="1.0" encoding="utf-8" ?> 
<PayInfo> 
  <Name>John Smith</Name> 
  <CreditCard Limit='2,000' Currency='USD'> 
    <Number>1076 2478 0678 5589</Number> 
    <Issuer>CitiBank</Issuer>
    <Expiration>06/10</Expiration> 
  </CreditCard> 
</PayInfo> 
 	
		



The template used to apply hybrid encryption is:

session-key-template.xml

 
<?xml version="1.0" encoding="UTF-8"?>
<!-- 
XML Security Library example: Original XML
 doc file before encryption (encrypt3 example). 
-->
<EncryptedData 
  xmlns="http://www.w3.org/2001/04/xmlenc#" 
  Type="http://www.w3.org/2001/04/xmlenc#Element">
 <EncryptionMethod Algorithm=
   "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
 <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
  <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
   <EncryptionMethod Algorithm=
     "http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
   <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
    <KeyName/>
   </KeyInfo>
   <CipherData>
    <CipherValue/>
   </CipherData>
  </EncryptedKey>
 </KeyInfo>
 <CipherData>
  <CipherValue/>
 </CipherData>
</EncryptedData>
 	
		



This template shows the symmetric algorithm (tripledes-cbc) and the public key algorithm (rsa-1_5) that are used. Obviously these two algorithms can be changed. To encrypt the XML document:

 
> xmlsec encrypt --pubkey-pem pub-userkey.pem \
  --session-key des-192 --xml-data doc-plain.xml \ 
  --output doc-encrypted.xml session-key-template.xml
 	
		



Now to decrypt:

 
> xmlsec decrypt --privkey-pem userkey.pem doc-encrypted.xml
 	
		



3.2  Encryption of a single value

It is also possible to only encrypt a single value of a XML document using a XPath. To do this, only use the --node-xpath option.

 
> xmlsec encrypt --pubkey-pem pub-userkey.pem \
  --session-key des-192 --xml-data doc-plain.xml  \
  --output doc-encrypted-xpath.xml \ 
  --node-xpath /PayInfo/CreditCard/Number/text() \ 
  session-key-template.xml
 	
		



The decryption is similar:

 
> xmlsec decrypt --privkey-pem userkey.pem \
   doc-encrypted-xpath.xml 
 	
		




This document was translated from LATEX by HEVEA.