|
XML Digital Signature
Example 1. Signing document from template
In this example we will load a simple signature template from a file,
add some data and sign the document. The template contains all information
required create a signature (except keys). If you need to sign many similar
documents using the same algorithms, transforms, etc. then probably it's
the way to go because you can application needs to call only a couple
function and have the document signed.
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:
* this is a BAD way to init random numbers
* generator
*/
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 template.
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;
}
/**
* Add Data to the document
*/
if(xmlNewChild(xmlDocGetRootElement(doc), NULL,
"Something", "Some important data") == NULL) {
fprintf(stderr,"Error:
failed to add data\n");
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. Adding or changing data in the template.
Now it's time to change the data in the template. We will simply add
one more node with some text:
/**
* Add Data to the document
*/
if(xmlNewChild(xmlDocGetRootElement(doc), NULL,
"Something",
"Some important data") == NULL) {
fprintf(stderr,"Error:
failed to add data\n");
goto done;
}
Step 3. 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 4. Sign It!
We are ready to sign the document!
/**
* Sign It!
*/
if(xmlDSigGenerate(dsigCtx, doc, NULL, 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 6. Cleanup.
At the end we need to destroy DSig context, the doc and KeysManager;
shutdown libxml and OpenSSL:
/**
* 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"?>
<Envelope xmlns="urn:envelope">
<Data>
Hello, World!
</Data>
<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="">
<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/>
</Signature>
</Envelope>
Appendix B. The signed document.
<?xml version="1.0" encoding="UTF-8"?>
<Envelope xmlns="urn:envelope">
<Data>
Hello, World!
</Data>
<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="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>VfHCiBvt0+tbmOWj8JXIr+AK174=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>vMdfMzuix3KCdo7vxjasuUDuNR5dFGuBQR7WUA435XVyeqe2AZAlYg==</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>
<Something>Some important data</Something></Envelope>
|