Signing with X509 certificate.

Home Download News Documentation FAQ Tutorial API reference Examples XML Digital Signature Online Verifier XML Encryption XML Canonicalization Reporting Bugs Mailing list Related
XML Security Library Reference Manual
<<< Previous Page | Home | Up | Next Page >>>
# Signing with X509 certificate. ## sign3.c
    /**
     * XML Security Library example: Signing a file with a dynamicaly created template and an X509 certificate.
     *
     * Signs a file using a dynamicaly created template, key from PEM file and
     * an X509 certificate. The signature has one reference with one enveloped
     * transform to sign the whole document except the <dsig:Signature/> node
     * itself. The key certificate is written in the <dsig:X509Data/> node.
     *
     * This example was developed and tested with OpenSSL crypto library. The
     * certificates management policies for another crypto library may break it.
     *
     * Usage:
     *	sign3 <xml-doc> <pem-key>
     *
     * Example:
     *	./sign3 sign3-doc.xml rsakey.pem rsacert.pem > sign3-res.xml
     *
     * The result signature could be validated using verify3 example:
     *	./verify3 sign3-res.xml rootcert.pem
     *
     * This is free software; see Copyright file in the source
     * distribution for preciese wording.
     *
     * Copyrigth (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
     */
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>

    #include <libxml/tree.h>
    #include <libxml/xmlmemory.h>
    #include <libxml/parser.h>

    #ifndef XMLSEC_NO_XSLT
    #include <libxslt/xslt.h>
    #endif /* XMLSEC_NO_XSLT */

    #include <xmlsec/xmlsec.h>
    #include <xmlsec/xmltree.h>
    #include <xmlsec/xmldsig.h>
    #include <xmlsec/templates.h>
    #include <xmlsec/crypto.h>

    int sign_file(const char* xml_file, const char* key_file, const char* cert_file);

    int
    main(int argc, char **argv) {
        assert(argv);

        if(argc != 4) {
    	fprintf(stderr, "Error: wrong number of arguments.\n");
    	fprintf(stderr, "Usage: %s <xml-file> <key-file> <cert-file>\n", argv[0]);
    	return(1);
        }

        /* Init libxml and libxslt libraries */
        xmlInitParser();
        LIBXML_TEST_VERSION
        xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
        xmlSubstituteEntitiesDefault(1);
    #ifndef XMLSEC_NO_XSLT
        xmlIndentTreeOutput = 1;
    #endif /* XMLSEC_NO_XSLT */

        /* Init xmlsec library */
        if(xmlSecInit() < 0) {
    	fprintf(stderr, "Error: xmlsec initialization failed.\n");
    	return(-1);
        }

        /* Init crypto library */
        if(xmlSecCryptoAppInit(NULL) < 0) {
    	fprintf(stderr, "Error: crypto initialization failed.\n");
    	return(-1);
        }

        /* Init xmlsec-crypto library */
        if(xmlSecCryptoInit() < 0) {
    	fprintf(stderr, "Error: xmlsec-crypto initialization failed.\n");
    	return(-1);
        }

        if(sign_file(argv[1], argv[2], argv[3]) < 0) {
    	return(-1);
        }

        /* Shutdown xmlsec-crypto library */
        xmlSecCryptoShutdown();

        /* Shutdown crypto library */
        xmlSecCryptoAppShutdown();

        /* Shutdown xmlsec library */
        xmlSecShutdown();

        /* Shutdown libxslt/libxml */
    #ifndef XMLSEC_NO_XSLT
        xsltCleanupGlobals();
    #endif /* XMLSEC_NO_XSLT */
        xmlCleanupParser();

        return(0);
    }

    /**
     * sign_file:
     * @xml_file:		the XML file name.
     * @key_file:		the PEM private key file name.
     * @cert_file:		the x509 certificate PEM file.
     *
     * Signs the @xml_file using private key from @key_file and dynamicaly
     * created enveloped signature template. The certificate from @cert_file
     * is placed in the <dsig:X509Data/> node.
     *
     * Returns 0 on success or a negative value if an error occurs.
     */
    int
    sign_file(const char* xml_file, const char* key_file, const char* cert_file) {
        xmlDocPtr doc = NULL;
        xmlNodePtr signNode = NULL;
        xmlNodePtr refNode = NULL;
        xmlNodePtr keyInfoNode = NULL;
        xmlSecDSigCtxPtr dsigCtx = NULL;
        int res = -1;

        assert(xml_file);
        assert(key_file);
        assert(cert_file);

        /* load doc file */
        doc = xmlParseFile(xml_file);
        if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){
    	fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_file);
    	goto done;
        }

        /* create signature template for RSA-SHA1 enveloped signature */
        signNode = xmlSecTmplSignatureCreate(doc, xmlSecTransformExclC14NId,
    				         xmlSecTransformRsaSha1Id, NULL);
        if(signNode == NULL) {
    	fprintf(stderr, "Error: failed to create signature template\n");
    	goto done;
        }

        /* add <dsig:Signature/> node to the doc */
        xmlAddChild(xmlDocGetRootElement(doc), signNode);

        /* add reference */
        refNode = xmlSecTmplSignatureAddReference(signNode, xmlSecTransformSha1Id,
    					NULL, NULL, NULL);
        if(refNode == NULL) {
    	fprintf(stderr, "Error: failed to add reference to signature template\n");
    	goto done;
        }

        /* add enveloped transform */
        if(xmlSecTmplReferenceAddTransform(refNode, xmlSecTransformEnvelopedId) == NULL) {
    	fprintf(stderr, "Error: failed to add enveloped transform to reference\n");
    	goto done;
        }

        /* add <dsig:KeyInfo/> and <dsig:X509Data/> */
        keyInfoNode = xmlSecTmplSignatureEnsureKeyInfo(signNode, NULL);
        if(keyInfoNode == NULL) {
    	fprintf(stderr, "Error: failed to add key info\n");
    	goto done;
        }

        if(xmlSecTmplKeyInfoAddX509Data(keyInfoNode) == NULL) {
    	fprintf(stderr, "Error: failed to add X509Data node\n");
    	goto done;
        }

        /* create signature context, we don't need keys manager in this example */
        dsigCtx = xmlSecDSigCtxCreate(NULL);
        if(dsigCtx == NULL) {
            fprintf(stderr,"Error: failed to create signature context\n");
    	goto done;
        }

        /* load private key, assuming that there is not password */
        dsigCtx->signKey = xmlSecCryptoAppKeyLoad(key_file, xmlSecKeyDataFormatPem, NULL, NULL, NULL);
        if(dsigCtx->signKey == NULL) {
            fprintf(stderr,"Error: failed to load private pem key from \"%s\"\n", key_file);
    	goto done;
        }

        /* load certificate and add to the key */
        if(xmlSecCryptoAppKeyCertLoad(dsigCtx->signKey, cert_file, xmlSecKeyDataFormatPem) < 0) {
            fprintf(stderr,"Error: failed to load pem certificate \"%s\"\n", cert_file);
    	goto done;
        }

        /* set key name to the file name, this is just an example! */
        if(xmlSecKeySetName(dsigCtx->signKey, key_file) < 0) {
        	fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", key_file);
    	goto done;
        }

        /* sign the template */
        if(xmlSecDSigCtxSign(dsigCtx, signNode) < 0) {
            fprintf(stderr,"Error: signature failed\n");
    	goto done;
        }

        /* print signed document to stdout */
        xmlDocDump(stdout, doc);

        /* success */
        res = 0;

    done:
        /* cleanup */
        if(dsigCtx != NULL) {
    	xmlSecDSigCtxDestroy(dsigCtx);
        }

        if(doc != NULL) {
    	xmlFreeDoc(doc);
        }
        return(res);
    }
## sign3-doc.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <!--
    XML Security Library example: Original XML doc file for sign3 example.
    -->
    <Envelope xmlns="urn:envelope">
      <Data>
    	Hello, World!
      </Data>
    </Envelope>
## sign3-res.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <!--
    XML Security Library example: Signed XML doc file (sign3 example).
    -->
    <Envelope xmlns="urn:envelope">
      <Data>
    	Hello, World!
      </Data>
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
    <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
    <Reference>
    <Transforms>
    <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
    </Transforms>
    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
    <DigestValue>HjY8ilZAIEM2tBbPn5mYO1ieIX4=</DigestValue>
    </Reference>
    </SignedInfo>
    <SignatureValue>SIaj/6KY3C1SmDXU2++Gm31U1xTadFp04WhBgfsJFbxrL+q7GKSKN9kfQ+UpN9+i
    D5fWmuavXEHe4Gw6RMaMEkq2URQo7F68+d5J/ajq8/l4n+xE6/reGScVwT6L4dEP
    XXVJcAi2ZnQ3O7GTNvNGCPibL9mUcyCWBFZ92Uemtc/vJFCQ7ZyKMdMfACgxOwyN
    T/9971oog241/2doudhonc0I/3mgPYWkZdX6yvr62mEjnG+oUZkhWYJ4ewZJ4hM4
    JjbFqZO+OEzDRSbw3DkmuBA/mtlx+3t13SESfEub5hqoMdVmtth/eTb64dsPdl9r
    3k1ACVX9f8aHfQQdJOmLFQ==</SignatureValue>
    <KeyInfo>
    <X509Data>
    <X509Certificate>MIIE3zCCBEigAwIBAgIBBTANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCVVMx
    EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
    ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
    eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
    a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMB4X
    DTAzMDMzMTA0MDIyMloXDTEzMDMyODA0MDIyMlowgb8xCzAJBgNVBAYTAlVTMRMw
    EQYDVQQIEwpDYWxpZm9ybmlhMT0wOwYDVQQKEzRYTUwgU2VjdXJpdHkgTGlicmFy
    eSAoaHR0cDovL3d3dy5hbGVrc2V5LmNvbS94bWxzZWMpMSEwHwYDVQQLExhFeGFt
    cGxlcyBSU0EgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAf
    BgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCCASIwDQYJKoZIhvcNAQEB
    BQADggEPADCCAQoCggEBAJe4/rQ/gzV4FokE7CthjL/EXwCBSkXm2c3p4jyXO0Wt
    quaNC3dxBwFPfPl94hmq3ZFZ9PHPPbp4RpYRnLZbRjlzVSOq954AXOXpSew7nD+E
    mTqQrd9+ZIbGJnLOMQh5fhMVuOW/1lYCjWAhTCcYZPv7VXD2M70vVXDVXn6ZrqTg
    qkVHE6gw1aCKncwg7OSOUclUxX8+Zi10v6N6+PPslFc5tKwAdWJhVLTQ4FKG+F53
    7FBDnNK6p4xiWryy/vPMYn4jYGvHUUk3eH4lFTCr+rSuJY8i/KNIf/IKim7g/o3w
    Ae3GM8xrof2mgO8GjK/2QDqOQhQgYRIf4/wFsQXVZcMCAwEAAaOCAVcwggFTMAkG
    A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp
    ZmljYXRlMB0GA1UdDgQWBBQkhCzy1FkgYosuXIaQo6owuicanDCB+AYDVR0jBIHw
    MIHtgBS0ue+a5pcOaGUemM76VQ2JBttMfKGB0aSBzjCByzELMAkGA1UEBhMCVVMx
    EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
    ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
    eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
    a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggEA
    MA0GCSqGSIb3DQEBBAUAA4GBALU/mzIxSv8vhDuomxFcplzwdlLZbvSQrfoNkMGY
    1UoS3YJrN+jZLWKSyWE3mIaPpElqXiXQGGkwD5iPQ1iJMbI7BeLvx6ZxX/f+c8Wn
    ss0uc1NxfahMaBoyG15IL4+beqO182fosaKJTrJNG3mc//ANGU9OsQM9mfBEt4oL
    NJ2D</X509Certificate>
    </X509Data>
    </KeyInfo>
    </Signature></Envelope>
<<< Previous Page | Home | Up | Next Page >>>
Signing a dynamicaly created template. | Verifying a signature with a single key.
Aleksey Sanin