XMLSec Library

XML Digital Signature
Example 3. Verifying signatures in the document.

In this example we will verify a signature created on one of the previous examples. The current version of XMLSec library does not provide an application the information what ACTUALLY was signed. The reason for this is that I have no good ideas on what exactly the application wants to have (References URIs? --- but transforms can change the original document at the URI; return the document "just before digest"? --- but it's a lot of memory and applications will have to compare these processed documents with original ones found at URIs). Please let me know if you have thoughts about this.
The source code for this example is included into the package: source code 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. And we do not need keys to verify the signature because we used DSA-SHA1 and stored public key in the document! Depending on the signature/digest algorithms your use and your application security model in general you can have to use keys for verification. In this case, you can load keys in the exactly same way as when you create a signature.

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[1]);
       goto done;
    }
   
    /**
     * Check the document is of the right kind
     */   
    if(xmlDocGetRootElement(doc) == NULL) {
        fprintf(stderr,"Error: empty document for file \"%s\"\n", argv[1]);
        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.  Please note, that we pass NULL instead of Keys Manager object because all required keys are in the document:

    xmlDSigCtxPtr dsigCtx = NULL;

    /**
     * Create Signature Context
     */

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

Step 3. Verify It!

We are ready to sign the document!

   /**
     * Verify It!
     */
    if(xmlDSigValidate(dsigCtx, doc, NULL, NULL) < 0) {
        fprintf(stderr,"validation failed\n");
    } else {
        fprintf(stderr,"validation succeeded\n");
    }
   

Step 4. 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);
    }
   
    /**
     * Shutdown libxml
     */
    xmlCleanupParser();
   
    /**
     * Shutdown OpenSSL
     */
    RAND_cleanup();
    ERR_clear_error();

Appendix A. 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>