XMLSec Library

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

In this example we will verify a signature created in the previous example.
The source code for this example is included into the package: source code and the signed document .

Step 0. Initializing LibXML, OpenSSL and XMLSec. Creating DSig context.

Before using the libraries we need to initialize them. This should be done once in the beginning of your program.
   
 
  int rnd_seed = 0;   
    xmlSecSimpleKeyMngrPtr keyMgr = NULL;
    xmlDSigCtxPtr dsigCtx = NULL;
    xmlSecKeysReadContext keysReadCtx;


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

    /*
     * Init xmlsec
     */
    xmlSecInit();   

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

    /**
     * Create Signature Context
     */
    memset(&keysReadCtx, 0, sizeof(keysReadCtx));

    keysReadCtx.allowedOrigins = xmlSecKeyOriginAll; /* by default all keys are accepted */
    keysReadCtx.findKeyCallback = xmlSecSimpleKeyMngrFindKey;
    keysReadCtx.findKeyContext = keyMgr;
   
    dsigCtx = xmlDSigCtxCreate(&keysReadCtx);
    if(dsigCtx == NULL) {
        fprintf(stderr,"Error: failed to create dsig context\n");
        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[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. Verify It!

We are ready to sign the document!

    xmlDSigSignaturePtr signature = NULL;


     /**
     * Verify It!
     */
    ret = xmlDSigValidate(dsigCtx, xmlDocGetRootElement(doc), &signature);
    if(ret < 0) {
        fprintf(stderr,"Error: signature failed\n");
        goto done;
    }  
 

Step 3. Print results.

In our example we will use an XMLSec function to print the verification results. Real application should process signature objects list (there could be more than one signature in the document!) by itself.
    /*
     * Print out result    
     */
    xmlDSigDebugSignatureDumpAll(stdout, signature);

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(signature != NULL) {
       xmlDSigSignatureDestroyAll(signature);
    }
    if(dsigCtx != NULL) {
       xmlDSigCtxDestroy(dsigCtx);
    }
    if(doc != NULL) {
      xmlFreeDoc(doc);
    }
    
    if(keyMgr != NULL) {
      xmlSecSimpleKeyMngrDestroy(keyMgr);
    }
    
    xmlSecShutdown();
    
    /*
     * Shutdown libxml
     */
    xmlCleanupParser();
    
    /*
     * Shutdown OpenSSL
     */
    RAND_cleanup();
    ERR_clear_error();

Appendix A. The verification output.

= SIGNATURE (validate)
== result: OK
== sign method: http://www.w3.org/2000/09/xmldsig#dsa-sha1
== key name: (null)
== key origin: 0
== start buffer:
<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"></SignatureMethod>
<Reference Id="reference-1" URI="#xpointer(id('SomeData'))">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"></Transform>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue>x/tL8hKZQyExW6ba0pi5h8eWRCc=</DigestValue>
</Reference>
</SignedInfo>
== end buffer
== SIGNED INFO REFERENCES
==== REFERENCE
===== ref type: SignedInfo Reference
===== result: OK
===== digest method: http://www.w3.org/2000/09/xmldsig#sha1
===== uri: #xpointer(id('SomeData'))
===== type: NULL
===== id: reference-1
===== start buffer:
<Info Id="SomeData">
    <!-- Commentary -->
    <Data1> Some data </Data1>
    <Data2> More data </Data2>
    </Info>
===== end buffer

Appendix B. The signed document.

<?xml version="1.0" encoding="UTF-8"?>
<Letter>
    Hello, World!    
    <Info Id="SomeData">
    <!-- Commentary -->
    <Data1> Some data </Data1>
    <Data2> More data </Data2>
    </Info>
<Something>Some important data</Something><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 Id="reference-1" URI="#xpointer(id('SomeData'))">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>x/tL8hKZQyExW6ba0pi5h8eWRCc=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>uwYbk29Juoe8B0eCW6aAjw4t+QBT7oQsjAmQnu8fFQPNy0RwP6pWNA==</SignatureValue>
<KeyInfo Id="">
<KeyValue>
<DSAKeyValue>
<P>
imW6KYBPYXAf6itSAuYs1aLPfs8/vBEiusv/pl1XMiuMvB7vyiJgSj8/NTkRci/U
X/rVXv8rbCRjvYFX3x5/53f4hc6HKz7JQI4qqB7Fl5N86zp+BsQxNQ4tzous9S2H
Td2/zdTwVsvO+H9l3FahmVp/m2IHE4W27JYoF49qP10=
</P>
<Q>
v/xzWqjRviekk2rMW3wpYspT9Us=
</Q>
<G>
UIyzUDlLe6uCCgF4Rh98fiKZvg64UJ4FM5L+WbCSMmVsFN06fTwxy3naPPOCzzou
fsHv/Bve2gvrDvd078oXWJJf9A44pIZnJkdjEhm2RsDFpXNq0tPKZFcjVsdmqg4M
X6YNuwpvZuTwSoDG5u1QMN0mmH9gmbIT3j9x4MO+7EY=
</G>
<Y>
On+KBJE3q1TRhG9RspNX01VI5C0VzSy4N/QyC4YzEENoq3GJkKHIYq+grq9ZqV9x
g2Geo/3mqhdcENOtYRmWEfOZJj18oukD6TNceYRZ4HjHjK3WY3wK2OV6QOly+k3f
xgEQpP/7IlCka5YICLuHXrbqjn5b0XcK9L2GDtWOyjs=
</Y>
</DSAKeyValue>
</KeyValue>
</KeyInfo>
</Signature></Letter>