|
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 to create the 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.
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 XML Security Library.
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
/**
* Init xmlsec
*/
xmlSecInit();
Step 1. Loading key and creating the DSig context.
Before signing or verifying the document you should create DSig context
object. In most case you will need only one DSig context object
per application
xmlSecKeysReadContext keysReadCtx;
xmlSecSimpleKeyMngrPtr keyMgr = NULL;
xmlDSigCtxPtr dsigCtx = NULL;
/**
* Create Keys managers
*/
keyMgr = xmlSecSimpleKeyMngrCreate();
if(keyMgr == NULL) {
fprintf(stderr, "Error: failed to create keys manager\n");
goto done;
}
/**
* load key
*/
if(xmlSecSimpleKeyMngrLoadPrivateKey(keyMgr, argv[1],
NULL, NULL) == NULL) {
fprintf(stderr, "Error: failed to load key from
\"%s\"\n", argv[1]);
goto done;
}
/**
* Create Keys Search context
*/
memset(&keysReadCtx, 0, sizeof(keysReadCtx));
keysReadCtx.allowedOrigins = xmlSecKeyOriginAll;
keysReadCtx.findKeyCallback = xmlSecSimpleKeyMngrFindKey;
keysReadCtx.findKeyContext = keyMgr;
/**
* Create Signature Context
*/
dsigCtx = xmlDSigCtxCreate(&keysReadCtx);
if(dsigCtx == NULL) {
fprintf(stderr,"Error: failed to create dsig context\n");
goto done;
}
Step 2. 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;
}
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 3. 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 4. Sign It!
We are ready to sign the document!
/**
* Sign It!
*/
ret = xmlDSigGenerate(dsigCtx, xmlDocGetRootElement(doc),
&signature);
if(ret < 0) {
fprintf(stderr,"Error: signature failed\n");
goto done;
}
Step 5. Now we can print the result.
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 XML Security Library, libxml and OpenSSL:
/*
* Cleanup
*/
if(doc != NULL) {
xmlFreeDoc(doc);
}
if(signature != NULL) {
xmlDSigSignatureDestroyAll(signature);
}
if(dsigCtx != NULL) {
xmlDSigCtxDestroy(dsigCtx);
}
if(keyMgr != NULL) {
xmlSecSimpleKeyMngrDestroy(keyMgr);
}
/**
* Shutdown XML Sec
*/
xmlSecShutdown();
/*
* 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/>
<KeyInfo>
<KeyValue/>
</KeyInfo>
</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>lUsn3fJYExos8S49s/cc6e1TMrM=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>AerkaAbF5Tneg5FlS1uSg571Af0toAbeRsfC/HRQyfLvQAbOYmd7RQ==</SignatureValue>
<KeyInfo>
<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>
<Something>Some important data</Something></Envelope>
|