Home Download News Documentation FAQ XML Digital Signature Interop report Online Verifier Example 1 Example 2 Example 3 Example 4 XML Encryption Interop report XML Canonicalization Reporting Bugs Mailing list | ## 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 `xmlSecKeysMngrPtr keysMngr = NULL; xmlSecDSigCtxPtr dsigCtx = NULL;``/** * Create Keys managers */ keysMngr = xmlSecSimpleKeysMngrCreate(); if(keysMngr == NULL) { fprintf(stderr, "Error: failed to create keys manager\n"); goto done; } /** * load key */ if(xmlSecSimpleKeysMngrLoadPemKey(keysMngr, argv[1], NULL, NULL, 1) == NULL) { fprintf(stderr, "Error: failed to load key from \"%s\"\n", argv[1]); goto done; } dsigCtx = xmlSecDSigCtxCreate(keysMngr); 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! `xmlSecDSigResultPtr result = NULL; /** * Sign It! */ ret = xmlSecDSigGenerate(dsigCtx, NULL, NULL, xmlDocGetRootElement(doc), &result); 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* string; /** * Print out result document */ xmlDocDumpMemoryEnc(doc, &string, &len, NULL); if(string == NULL) { fprintf(stderr,"Error: failed to dump document to memory\n"); goto done; } fwrite(string, len, 1, stdout); xmlFree(string);` #### 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(result != NULL) { xmlSecDSigResultDestroy(result); } if(doc != NULL) { xmlFreeDoc(doc); } if(dsigCtx != NULL) { xmlSecDSigCtxDestroy(dsigCtx); } if(keysMngr != NULL) { xmlSecSimpleKeysMngrDestroy(keysMngr); } /** * 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>``` Aleksey Sanin