XMLSec Library

XML Digital Signature
Example 2. Creating signature and signing document "on-the-fly".

In this example we will add a signature to the document "on the fly". Comparing to the first example now we are going to create template ourselves instead of loading it from a file. This way gives an application more flexibility but requires more work from software developer. Moreover, you can add all required information to the document yourself! XMLSec simplifies this task but you are not required to use it! Of course, you have to read XMLDSig specification before.
The source code for this example is included into the package: source code , the original template and the signed document .

Step 0. Initializing LibXML, OpenSSL and loading keys for XMLSec.

Before using the libraries we need to initialize them. This should be done once in the beginning of your program.
   
    int rnd_seed = 0;   

    /**
     * Init OpenSSL
     */   
    while (RAND_status() != 1) {
    RAND_seed(&rnd_seed, sizeof(rnd_seed));
    }
   
    /**
     * Init libxml
     */    
    xmlInitParser();
    LIBXML_TEST_VERSION


The XMLSec library does not require any special initialization. However, we will need to load keys to sign the message (this example uses Simple KeysManager included in XMLSec package; since it stores all keys in clear text and by this provide no protection at all it is NOT RECOMMENDED to use Simple Keys Manager for storing your keys!):

    xmlSecSimpleKeyMngrPtr keyMgr = NULL;

    
/**
     * Create keys manager and load keys
     */
    keyMgr = xmlSecSimpleKeyMngrCreate();
    if(keyMgr == NULL) {
       fprintf(stderr, "Error: failed to create keys manager\n");
       goto done;   
    }

    if(xmlSecSimpleKeyMngrLoad(keyMgr, argv[1]) < 0) {
       fprintf(stderr, "Error: failed to load keys from \"%s\"\n", argv[1]);
       goto done;
    }

Step 1. Loading the document.

XMLDSig requires the XML document to be loaded with all default attributes propagated to the nodes, all entities replaced, etc. (this is required for correct document Canonicalization ). In the LibXML this means that you need to take special actions when loading document from an URI:

      xmlDocPtr doc = NULL;   

    /**
     * build an XML tree from a the file; we need to add default
     * attributes and resolve all character and entities references
     */
    xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
    xmlSubstituteEntitiesDefault(1);

    /**
     * Load doc
     */
    doc = xmlParseFile(argv[2]);
    if (doc == NULL) {
       fprintf(stderr, "Error    : unable to parse file \"%s\"\n", argv[2]);
       goto done;
    }
   
    /**
     * Check the document is of the right kind
     */   
    if(xmlDocGetRootElement(doc) == NULL) {
        fprintf(stderr,"Error: empty document for file \"%s\"\n", argv[2]);
        goto done;
    }


In this example we set global flags to control how the document is loaded. In the real life you would probably want to control the loading on "per-document" basis. Check the libxml/c14n.h header file from LibXML distribution for details.

Step 2. Creating the DSig context.

Before signing or verifying the document you should create DSIg context object.  This object is used by XMLSec library for accessing Keys Manager, storing information on what exactly was signed or verified:

    xmlDSigCtxPtr dsigCtx = NULL;

    /**
     * Create Signature Context
     */

    dsigCtx = xmlDSigCtxCreate(keyMgr, NULL);
    if(dsigCtx == NULL) {
        fprintf(stderr,"Error: failed to create dsig context\n");
        goto done;
    }

Step 3. Adding Signature node.

The SXMLDSig standard defines a Signature element that holds all signature information. Using one XMLSec function we will create Siganure node itself and all necessary child nodes. You are not limited to use XMLSec for this! If you wish you can create the template yourself! In this example we are creating a Signature node to produce octet stream using Canonicalization v 1.0 without comments and sign document using DSA-SHA1 algorithm (please,  refer XLDSig standard for details):
    xmlNodePtr signatureNode;  

    /**
     * Create Signature node
     */
    signatureNode = xmlDSigCreate(dsigCtx, doc,
                xmlSecC14NInclusive, NULL,
                xmlSecSignDsaSha1, NULL);
    if(signatureNode == NULL) {
        fprintf(stderr,"Error: failed to create signature\n");
        goto done;
    }

    /**
     * Add the signature to the end of the document
     */   
    if(xmlAddChild(xmlDocGetRootElement(doc), signatureNode) == NULL) {
        fprintf(stderr,"Error: failed to add signature\n");
        goto done;
    }

Step 4. Add Reference node.

The Reference nodes define which documents or document parts and how are signed by this SIgnature. In this example we will sign while subtree of element with id "SignedInfo" using SHA1 digest.

      xmlNodePtr referenceNode;

    /**
     * Create Reference node
     */
    referenceNode = xmlDSigReferenceAdd(dsigCtx, doc, signatureNode,
                    "#xpointer(id('SignedInfo'))",
                    xmlSecDigestSha1, NULL);
    if(referenceNode == NULL) {
        fprintf(stderr,"Error: failed to add reference\n");
        goto done;
    }

Step 5. Add transform to remove comments.

The original document has comments in the selected node. If we do not want to sign comments we can add to the Reference a transform (Canonicalization Without Comments) to remove them:

     /**
     * Add C14N Transform to remove comments
     */
    if(xmlDSigTransformAdd(dsigCtx, doc, referenceNode,
              xmlSecC14NInclusive, NULL) == NULL) {
        fprintf(stderr,"Error: failed to add c14n trasnform\n");
        goto done;    
    }

Step 6. Sign It!

We are ready to sign the document!

    /**
     * Sign It!
     */
    if(xmlDSigGenerate(dsigCtx, doc, signatureNode, NULL) < 0) {
        fprintf(stderr,"Error: signature failed\n");
        goto done;
    }   

Step 5. Now we can print the result.

Simply print the document to stdout:

    xmlChar* result;
    /**
     * Print out result document
     */
    xmlDocDumpMemoryEnc(doc, &result, &len, NULL);
    if(result == NULL) {
      fprintf(stderr,"Error: failed to dump document to memory\n");
      goto done;
    }
    fwrite(result, len, 1, stdout);
    xmlFree(result);

Step 7. Cleanup.

At the end we need to destroy DSig context, the doc and KeysManager; shutdown libxml and OpenSSL
(please note that we do not delete creted Signature and Reference nodes separatelly because both nodes are included into the XML document doc):
     /**
     * Cleanup
     */
    if(dsigCtx != NULL) {
       xmlDSigCtxDestroy(dsigCtx);
    }
    if(doc != NULL) {
       xmlFreeDoc(doc);
    }
   
    if(keyMgr != NULL) {
       xmlSecKeyMngrDestroy(keyMgr);
    }
   
    /**
     * Shutdown libxml
     */
    xmlCleanupParser();
   
    /**
     * Shutdown OpenSSL
     */
    RAND_cleanup();
    ERR_clear_error();

Appendix A. The template document.

<?xml version="1.0" encoding="UTF-8"?>
<Letter>
    Hello, World!   
    <Info Id="SignedInfo">
    <!-- Commentary -->
    <Data1> Some data </Data1>
    <Data2> More data </Data2>
    </Info>
</Letter>

Appendix B. The signed document.

<?xml version="1.0" encoding="UTF-8"?>
<Letter>
    Hello, World!    
    <Info Id="SignedInfo">
    <!-- Commentary -->
    <Data1> Some data </Data1>
    <Data2> More data </Data2>
    </Info>
<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#dsa-sha1"/>
<Reference URI="#xpointer(id('SignedInfo'))"><Transforms>
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/></Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>9kcY1lsgjKB/e6cjCRPtEqWV/Mo=</DigestValue></Reference></SignedInfo>
<SignatureValue>Ieejhvqr2BwanNSyTAqhq51xc9XGPdfM/+VJ7BzMOB004iIpYmUmbQ==</SignatureValue>
<KeyInfo>
<KeyValue>
<DSAKeyValue>
<P>
kHdlgLHebphia+zPtG4WxRuVjFibJqi1LlZIriphHsm8FvIaMSwmVe7SOE+nkotv
erHLLaNWYTVPfnzIaSLd/PQl572GP1v2expC0lbexpQP7qf1dldJaF6gRiffy8Bc
klE3iL5/9S84CM6HeRXqtQMycP0iyopBUgf7++XrLcE=
</P>
<Q>
+rWwn0xfWSsT9q3Y+kHS017b5ZE=
</Q>
<G>
ZixjyhKXEUghkbIq8AlwHyzsuZOGJANTT6yCKuHB6bx8p0H9kzidI+L+Te4RN8ct
5szNvmJfYnkCRVxtMXj+y1onMbKfHCchrjqHLxrdk8XA2ab5p4qz9TVBWkk/zgDW
P/y0IWu1JS6BR3ekKfVNWNhNlLu1LsSTmnijT4hFESE=
</G>
<Y>
CitV6+fsYum95FDqwMQI2EZn6dnJC9y4ZpteKziHjQcg8zdks5Rl+lB+pUO7QHcV
Irddxc2IQR7QBar9Wk4JGTcNOy+3scQ0Dgv4GUJoNDByak09G46rOpNii3KadMI/
sQH/OSzwFdj5R2eqRpcW07azxaUyu6qQDejMyWzC0YM=
</Y></DSAKeyValue></KeyValue></KeyInfo></Signature></Letter><?xml version="1.0" encoding="UTF-8"?>
<Letter>
    Hello, World!    
    <Info Id="SignedInfo">
    <!-- Commentary -->
    <Data1> Some data </Data1>
    <Data2> More data </Data2>
    </Info>
<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#dsa-sha1"/>
<Reference URI="#xpointer(id('SignedInfo'))"><Transforms>
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/></Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>9kcY1lsgjKB/e6cjCRPtEqWV/Mo=</DigestValue></Reference></SignedInfo>
<SignatureValue>Ieejhvqr2BwanNSyTAqhq51xc9XGPdfM/+VJ7BzMOB004iIpYmUmbQ==</SignatureValue>
<KeyInfo>
<KeyValue>
<DSAKeyValue>
<P>
kHdlgLHebphia+zPtG4WxRuVjFibJqi1LlZIriphHsm8FvIaMSwmVe7SOE+nkotv
erHLLaNWYTVPfnzIaSLd/PQl572GP1v2expC0lbexpQP7qf1dldJaF6gRiffy8Bc
klE3iL5/9S84CM6HeRXqtQMycP0iyopBUgf7++XrLcE=
</P>
<Q>
+rWwn0xfWSsT9q3Y+kHS017b5ZE=
</Q>
<G>
ZixjyhKXEUghkbIq8AlwHyzsuZOGJANTT6yCKuHB6bx8p0H9kzidI+L+Te4RN8ct
5szNvmJfYnkCRVxtMXj+y1onMbKfHCchrjqHLxrdk8XA2ab5p4qz9TVBWkk/zgDW
P/y0IWu1JS6BR3ekKfVNWNhNlLu1LsSTmnijT4hFESE=
</G>
<Y>
CitV6+fsYum95FDqwMQI2EZn6dnJC9y4ZpteKziHjQcg8zdks5Rl+lB+pUO7QHcV
Irddxc2IQR7QBar9Wk4JGTcNOy+3scQ0Dgv4GUJoNDByak09G46rOpNii3KadMI/
sQH/OSzwFdj5R2eqRpcW07azxaUyu6qQDejMyWzC0YM=
</Y></DSAKeyValue></KeyValue></KeyInfo></Signature></Letter>