|
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>
|