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 3. Creating signature dynamically (including Reference ID and C14N inclusive Transform). This example is almost identical to Example 2, except it adds the ability to refer to the signed content by its reference ID. It also changes the Canonicalization method to C14N inclusive. This allows for the inclusion of comments in the XML content. 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; } /** * Create Signature Context */ dsigCtx = xmlSecDSigCtxCreate(keysMngr); if(dsigCtx == NULL) { fprintf(stderr,"Error: failed to create dsig context\n"); goto done; }` #### Step 2. Loading the document. In this example, we will load document from a file. The real application probably creates document itself. `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; }` `` #### Step 3. addSignature() function The XMLDSig standard defines <Signature> element that holds all signature information. XML Security Library provides functions to create the Signature element dynamically. However, you are not limited to use XML Security Library for this and can create the template yourself! In this example, we use a separate `addSignature` () function to add signature to the end of the document: `xmlNodePtr addSignature(xmlDocPtr doc) { xmlNodePtr signatureNode; xmlNodePtr signedInfoNode; xmlNodePtr keyInfoNode; xmlNodePtr referenceNode; xmlNodePtr cur; /** * Create Signature node */ signatureNode = xmlSecSignatureCreate("my-signature"); if(signatureNode == NULL) { fprintf(stderr,"Error: failed to create signature\n"); return(NULL); } /** * Add SignedInfo and set c14n and signature methods */ signedInfoNode = xmlSecSignatureAddSignedInfo(signatureNode, NULL); if(signedInfoNode == NULL) { fprintf(stderr,"Error: failed to add SignedInfo\n"); xmlSecSignatureDestroy(signatureNode); return(NULL); } cur = xmlSecSignedInfoAddC14NMethod(signedInfoNode, xmlSecC14NInclusive); if(cur == NULL) { fprintf(stderr,"Error: failed to add C14N method\n"); xmlSecSignatureDestroy(signatureNode); return(NULL); } cur = xmlSecSignedInfoAddSignMethod(signedInfoNode, xmlSecSignDsaSha1); if(cur == NULL) { fprintf(stderr,"Error: failed to add sign method\n");` ```xmlSecSignatureDestroy(signatureNode); return(NULL); } /** * Create Reference node with SHA1 as digest method and one * C14N transform to include comments in the digest */ referenceNode = xmlSecSignedInfoAddReference(signedInfoNode, "my-reference", "#xpointer(id('SomeData'))", NULL); if(referenceNode == NULL) { fprintf(stderr,"Error: failed to add Reference\n"); xmlSecSignatureDestroy(signatureNode); return(NULL); } cur = xmlSecReferenceAddDigestMethod(referenceNode, xmlSecDigestSha1); if(cur == NULL) { fprintf(stderr,"Error: failed to add digest method\n"); xmlSecSignatureDestroy(signatureNode); return(NULL); } cur = xmlSecReferenceAddTransform(referenceNode, xmlSecC14NExclusiveWithComments); if(cur == NULL) { fprintf(stderr,"Error: failed to add c14n transform\n"); xmlSecSignatureDestroy(signatureNode); return(NULL); } /** * Add KeyInfo node: for test purposes we will put * DSA key in the signature */ keyInfoNode = xmlSecSignatureAddKeyInfo(signatureNode, NULL); if(keyInfoNode == NULL) { fprintf(stderr,"Error: failed to add KeyInfo\n"); xmlSecSignatureDestroy(signatureNode); return(NULL); } cur = xmlSecKeyInfoAddKeyValue(keyInfoNode); if(cur == NULL) { fprintf(stderr,"Error: failed to add KeyValue node\n"); xmlSecSignatureDestroy(signatureNode); return(NULL); }` `/** * Add the signature to the end of the document */ if(xmlAddChild(xmlDocGetRootElement(doc), signatureNode) == NULL) { fprintf(stderr,"Error: failed to add Signature\n"); xmlSecSignatureDestroy(signatureNode); return(NULL); }` `return(signatureNode); }` #### Step 4. Add Signature node and sign! Add the Signature node using `addSignature` () function and sign : `xmlSecDSigResultPtr result;` `xmlNodePtr signatureNode; /** * Add Signature */ signatureNode = addSignature(doc); if(signatureNode == NULL) { fprintf(stderr,"Error: failed to add signature\n"); goto done; }``/** * Sign It! */ ret = xmlSecDSigGenerate(dsigCtx, NULL, NULL, signatureNode, &result); if(ret < 0) { fprintf(stderr,"Error: signature failed\n"); goto done; }` #### Step 5. Now we can print the result. Simply print the document to stdout: `xmlChar* string; /** * Print out result document */ xmlDocDumpMemoryEnc(doc, &string, &len, NULL); if(result == 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 (please note that we do not delete created Signature, Reference andKeyInfo nodes separately because all nodes are included in the XML document doc): `/* * Cleanup */ if(result != NULL) { xmlSecSignatureDestroy(result); } if(dsigCtx != NULL) { xmlSecDSigCtxDestroy(dsigCtx); } if(doc != NULL) { xmlFreeDoc(doc); } if(keysMngr != NULL) { xmlSecSimpleKeysMngrDestroy(keysMngr); } xmlSecShutdown(); /* * Shutdown libxml */ xmlCleanupParser(); /* * Shutdown OpenSSL */ RAND_cleanup(); ERR_clear_error();` #### Appendix A. The template document. `<?xml version="1.0" encoding="UTF-8"?> <Letter> Hello, World! <Info Id="SomeData"> <!-- Commentary --> <Data1> Some data </Data1> <Data2> More data </Data2> </Info> </Letter>` #### 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> <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>sSXCVpcCRydyUIebOFA1xw2Yfgy+YP0Dd41jIz/57iGbowwqyODPfA==</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>` Aleksey Sanin