diff options
Diffstat (limited to 'examples')
41 files changed, 5381 insertions, 0 deletions
diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 00000000..5c87150f --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,40 @@ +# +# +# +PROGRAMS = \ + sign1 sign2 sign3 \ + verify1 verify2 verify3 verify4 \ + encrypt1 encrypt2 encrypt3 \ + decrypt1 decrypt2 decrypt3 \ + xmldsigverify \ + xkms-server + +CC = gcc +CFLAGS += -g $(shell xmlsec1-config --cflags) -DUNIX_SOCKETS +LDFLAGS += -g $(shell xmlsec1-config --libs) + +all: $(PROGRAMS) + +clean: + @rm -rf $(PROGRAMS) + +check: $(PROGRAMS) + ./sign1 sign1-tmpl.xml rsakey.pem + ./sign2 sign2-doc.xml rsakey.pem + ./sign3 sign3-doc.xml rsakey.pem rsacert.pem + ./verify1 sign1-res.xml rsapub.pem + ./verify1 sign2-res.xml rsapub.pem + ./verify2 sign1-res.xml rsapub.pem + ./verify2 sign2-res.xml rsapub.pem + ./verify3 sign3-res.xml rootcert.pem + ./verify4 verify4-res.xml rootcert.pem + ./encrypt1 encrypt1-tmpl.xml deskey.bin + ./encrypt2 encrypt2-doc.xml deskey.bin + ./encrypt3 encrypt3-doc.xml rsakey.pem + ./decrypt1 encrypt1-res.xml deskey.bin + ./decrypt1 encrypt2-res.xml deskey.bin + ./decrypt2 encrypt1-res.xml deskey.bin + ./decrypt2 encrypt2-res.xml deskey.bin + ./decrypt3 encrypt1-res.xml + ./decrypt3 encrypt2-res.xml + ./decrypt3 encrypt3-res.xml diff --git a/examples/Makefile.w32 b/examples/Makefile.w32 new file mode 100644 index 00000000..ee81ab39 --- /dev/null +++ b/examples/Makefile.w32 @@ -0,0 +1,88 @@ +# Makefile for xmlsec, specific for Windows, MSVC and NMAKE. +# +# Take a look at the beginning and modify the variables to suit your +# environment. Having done that, you can do a + +XMLSEC_STATIC = yes +XMLSEC_CRYPTO = openssl +XMLSEC_CFLAGS = +XMLSEC_LIBS = + +# There should never be a need to modify anything below this line. +XMLSEC_OBJS_DIR = build +XMLSEC_EXAMPLES = \ + $(XMLSEC_OBJS_DIR)\sign1.exe \ + $(XMLSEC_OBJS_DIR)\sign2.exe \ + $(XMLSEC_OBJS_DIR)\sign3.exe \ + $(XMLSEC_OBJS_DIR)\verify1.exe \ + $(XMLSEC_OBJS_DIR)\verify2.exe \ + $(XMLSEC_OBJS_DIR)\verify3.exe \ + $(XMLSEC_OBJS_DIR)\verify4.exe \ + $(XMLSEC_OBJS_DIR)\encrypt1.exe \ + $(XMLSEC_OBJS_DIR)\encrypt2.exe \ + $(XMLSEC_OBJS_DIR)\encrypt3.exe \ + $(XMLSEC_OBJS_DIR)\decrypt1.exe \ + $(XMLSEC_OBJS_DIR)\decrypt2.exe \ + $(XMLSEC_OBJS_DIR)\decrypt3.exe \ + $(XMLSEC_OBJS_DIR)\xkms-server.exe \ + +# +!IF "$(XMLSEC_CRYPTO)" == "openssl" +XMLSEC_CFLAGS = $(XMLSEC_CFLAGS) /D "XMLSEC_CRYPTO_OPENSSL" /D "XMLSEC_CRYPTO=\"openssl\"" +XMLSEC_SOLIBS = libxmlsec-openssl.lib libeay32.lib wsock32.lib user32.lib gdi32.lib +XMLSEC_ALIBS = libxmlsec-openssl_a.lib libeay32.lib wsock32.lib user32.lib gdi32.lib +!ENDIF + +!IF "$(XMLSEC_CRYPTO)" == "nss" +XMLSEC_CFLAGS = $(XMLSEC_CFLAGS) /D "XMLSEC_CRYPTO_NSS" /D "XMLSEC_CRYPTO=\"nss\"" +XMLSEC_SOLIBS = libxmlsec-nss.lib nss3.lib nspr4.lib plds4.lib plc4.lib +XMLSEC_ALIBS = libxmlsec-nss_a.lib nss3.lib nspr4.lib plds4.lib plc4.lib +!ENDIF + +!IF "$(XMLSEC_CRYPTO)" == "mscrypto" +XMLSEC_CFLAGS = $(XMLSEC_CFLAGS) /D "XMLSEC_CRYPTO_MSCRYPTO" /D "XMLSEC_CRYPTO=\"mscrypto\"" +XMLSEC_SOLIBS = libxmlsec-mscrypto.lib user32.lib gdi32.lib crypt32.lib advapi32.lib +XMLSEC_ALIBS = libxmlsec-mscrypto_a.lib user32.lib gdi32.lib crypt32.lib advapi32.lib +!ENDIF + +!IF "$(XMLSEC_STATIC)" == "yes" +XMLSEC_CFLAGS = $(XMLSEC_CFLAGS) /D "LIBXML_STATIC" /D "LIBXSLT_STATIC" /D "XMLSEC_STATIC" +XMLSEC_LIBS = $(XMLSEC_LIBS) $(XMLSEC_ALIBS) libxmlsec_a.lib \ + libxml2_a.lib libxslt_a.lib libexslt_a.lib +!ELSE +XMLSEC_LIBS = $(XMLSEC_LIBS) $(XMLSEC_SOLIBS) libxmlsec.lib libxml2.lib \ + libxslt.lib libexslt.lib +!ENDIF + +# The preprocessor and its options. +CPP = cl.exe /EP +CPPFLAGS = /nologo + +# The compiler and its options. +CC = cl.exe +CFLAGS = /nologo /D "WIN32" /D "_WINDOWS" /D "_MBCS" /DWIN32_SOCKETS /W1 /MD $(XMLSEC_CFLAGS) + +# The linker and its options. +LD = link.exe +LDFLAGS = /nologo $(XMLSEC_LIBS) wsock32.lib + +# Optimisation and debug symbols. +!if "$(DEBUG)" == "1" +CFLAGS = $(CFLAGS) /D "_DEBUG" /Od /Z7 +LDFLAGS = $(LDFLAGS) /DEBUG +!else +CFLAGS = $(CFLAGS) /D "NDEBUG" /O2 +LDFLAGS = $(LDFLAGS) /OPT:NOWIN98 +!endif + +all : $(XMLSEC_OBJS_DIR) $(XMLSEC_EXAMPLES) + +$(XMLSEC_OBJS_DIR) : + if not exist $(XMLSEC_OBJS_DIR) mkdir $(XMLSEC_OBJS_DIR) + +.c{$(XMLSEC_OBJS_DIR)}.exe : + $(CC) /c $(CFLAGS) /Fo$(XMLSEC_OBJS_DIR)\ $< + $(LD) $(LDFLAGS) /OUT:$*.exe $*.obj + +clean: + if exist $(XMLSEC_OBJS_DIR) rmdir /S /Q $(XMLSEC_OBJS_DIR) diff --git a/examples/README b/examples/README new file mode 100644 index 00000000..bd680289 --- /dev/null +++ b/examples/README @@ -0,0 +1,126 @@ +This folder contains XML Security Library examples. + +1. Files List +------------------------- + + README This file. + Makefile *nix makefile. + Makefile.w32 Win32 makefile. + rsakey.pem Private PEM key file + rsapub.pem Public PEM key file + rsacert.pem Certificate for rsakey.pem signed with rootcert.pem + rootcert.pem Root (trusted) certificate + deskey.bin A DES keys + sign1.c Signing with a template file + sign1-tmpl.xml An example template file for sign1 example + sign1-res.xml The result of processing sign1_tmpl.xml by sign1.c + sign2.c Signing a file with a dynamicaly created template + sign2-doc.xml An example XML file for signing by sign2.c + sign2-res.xml The result of signing sign2-doc.xml by sign2.c + sign3.c Signing a file with a dynamicaly created template and an X509 certificate + sign3-doc.xml An example XML file for signing by sign3.c + sign3-res.xml The result of signing sign3-doc.xml by sign3.c + verify1.c Verifying a signed document with a single key + verify2.c Verifying a signed document using keys manager + verify3.c Verifying a signed document using X509 certificate + verify4.c Verifying a simple SAML response using X509 certificate + verify4-tmpl.xml An example template file with a simple SAML response for verify4 example + verify4-res.xml Signed simple SAML response for verification by verify4.c + encrypt1.c Encrypting binary data with a template file + encrypt1-res.xml An example template file for encrypt1.c + encrypt1-tmpl.xml The result of processing encrypt1_tmpl.xml by encrypt1.c + encrypt2.c Encrypting XML file using a dynamicaly created template + encrypt2-doc.xml An example XML file for encryption by encrypt2.c + encrypt2-res.xml The result of encryptin encrypt2-doc.xml by encrypt2.c + encrypt2.c Encrypting XML file using a session DES key + encrypt2-doc.xml An example XML file for encryption by encrypt3.c + encrypt2-res.xml The result of encryptin encrypt3-doc.xml by encrypt3.c + decrypt1.c Decrypting binary data using a single key + decrypt2.c Decrypting binary data using keys manager + decrypt3.c Decrypting binary file using custom keys manager + xmldsigverify.c CGI script for signatures verifications + +2. Building Examples +------------------------- + +Unixes: + Just run the usual 'make' command (assuming that xmlsec, libxml and + all other required libraries are already installed). + +Windows: + - Add paths to include and library files for xmlsec, libxml2, libexslt and + openssl or nss to the environment variables INCLUDE and LIB. + - Edit 'Makefile.w32' file and specify correct crypto engine (openssl or + nss for now). You can also specify necessary include and library paths + or change from static linking to using DLLs. + - Run 'nmake -f Makefile.w32' + + If something does not work, check the README file in the top level + "win32" folder and have fun :) + +Other platforms: + If none of the above works for you and you've managed to compile xmlsec + library by yourself then you probably know what to do. + + + +3. Runnning Examples. +------------------------- + +The following are just examples and you can use the programs from this +folder with any other input files: + + ./sign1 sign1-tmpl.xml rsakey.pem + ./sign2 sign2-doc.xml rsakey.pem + ./sign3 sign3-doc.xml rsakey.pem rsacert.pem + + ./verify1 sign1-res.xml rsapub.pem + ./verify1 sign2-res.xml rsapub.pem + ./verify2 sign1-res.xml rsapub.pem + ./verify2 sign2-res.xml rsapub.pem + ./verify3 sign3-res.xml rootcert.pem + ./verify4 verify4-res.xml rootcert.pem + + ./encrypt1 encrypt1-tmpl.xml deskey.bin + ./encrypt2 encrypt2-doc.xml deskey.bin + ./encrypt3 encrypt3-doc.xml rsakey.pem + + ./decrypt1 encrypt1-res.xml deskey.bin + ./decrypt1 encrypt2-res.xml deskey.bin + ./decrypt2 encrypt1-res.xml deskey.bin + ./decrypt2 encrypt2-res.xml deskey.bin + ./decrypt3 encrypt1-res.xml + ./decrypt3 encrypt2-res.xml + ./decrypt3 encrypt3-res.xml + +4. Using xmlsec command line tool. +------------------------- +For Windows, use "xmlsec" instead of "xmlsec1". + xmlsec1 sign --privkey rsakey.pem --output sign1.xml sign1-tmpl.xml + xmlsec1 verify --pubkey rsapub.pem sign1.xml + xmlsec1 verify --pubkey rsapub.pem sign1-res.xml + xmlsec1 verify --pubkey rsapub.pem sign2-res.xml + xmlsec1 verify --trusted rootcert.pem sign3-res.xml + xmlsec1 verify --trusted rootcert.pem verify4-res.xml + + xmlsec1 encrypt --deskey deskey.bin --binary-data binary.dat --output encrypt1.xml encrypt1-tmpl.xml + xmlsec1 decrypt --deskey deskey.bin encrypt1.xml + xmlsec1 decrypt --deskey deskey.bin encrypt1-res.xml + xmlsec1 decrypt --deskey deskey.bin encrypt2-res.xml + xmlsec1 decrypt --privkey rsakey.pem encrypt3-res.xml + + + + + + + + + + + + + + + + diff --git a/examples/binary.dat b/examples/binary.dat new file mode 100644 index 00000000..a039696a --- /dev/null +++ b/examples/binary.dat @@ -0,0 +1 @@ +Big secret
\ No newline at end of file diff --git a/examples/decrypt1.c b/examples/decrypt1.c new file mode 100644 index 00000000..bfc1dd03 --- /dev/null +++ b/examples/decrypt1.c @@ -0,0 +1,205 @@ +/** + * XML Security Library example: Decrypting an encrypted file using a single key. + * + * Decrypts encrypted XML file using a single DES key from a binary file + * + * Usage: + * ./decrypt1 <xml-enc> <des-key-file> + * + * Example: + * ./decrypt1 encrypt1-res.xml deskey.bin + * ./decrypt1 encrypt2-res.xml deskey.bin + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (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/xmlenc.h> +#include <xmlsec/crypto.h> + +int decrypt_file(const char* enc_file, const char* key_file); + +int +main(int argc, char **argv) { + assert(argv); + + if(argc != 3) { + fprintf(stderr, "Error: wrong number of arguments.\n"); + fprintf(stderr, "Usage: %s <enc-file> <key-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); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* 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(decrypt_file(argv[1], argv[2]) < 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); +} + +/** + * decrypt_file: + * @enc_file: the encrypted XML file name. + * @key_file: the Triple DES key file. + * + * Decrypts the XML file #enc_file using DES key from #key_file and + * prints results to stdout. + * + * Returns 0 on success or a negative value if an error occurs. + */ +int +decrypt_file(const char* enc_file, const char* key_file) { + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlSecEncCtxPtr encCtx = NULL; + int res = -1; + + assert(enc_file); + assert(key_file); + + /* load template */ + doc = xmlParseFile(enc_file); + if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){ + fprintf(stderr, "Error: unable to parse file \"%s\"\n", enc_file); + goto done; + } + + /* find start node */ + node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeEncryptedData, xmlSecEncNs); + if(node == NULL) { + fprintf(stderr, "Error: start node not found in \"%s\"\n", enc_file); + goto done; + } + + /* create encryption context, we don't need keys manager in this example */ + encCtx = xmlSecEncCtxCreate(NULL); + if(encCtx == NULL) { + fprintf(stderr,"Error: failed to create encryption context\n"); + goto done; + } + + /* load DES key */ + encCtx->encKey = xmlSecKeyReadBinaryFile(xmlSecKeyDataDesId, key_file); + if(encCtx->encKey == NULL) { + fprintf(stderr,"Error: failed to load des key from binary file \"%s\"\n", key_file); + goto done; + } + + /* set key name to the file name, this is just an example! */ + if(xmlSecKeySetName(encCtx->encKey, key_file) < 0) { + fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", key_file); + goto done; + } + + /* decrypt the data */ + if((xmlSecEncCtxDecrypt(encCtx, node) < 0) || (encCtx->result == NULL)) { + fprintf(stderr,"Error: decryption failed\n"); + goto done; + } + + /* print decrypted data to stdout */ + if(encCtx->resultReplaced != 0) { + fprintf(stdout, "Decrypted XML data:\n"); + xmlDocDump(stdout, doc); + } else { + fprintf(stdout, "Decrypted binary data (%d bytes):\n", xmlSecBufferGetSize(encCtx->result)); + if(xmlSecBufferGetData(encCtx->result) != NULL) { + fwrite(xmlSecBufferGetData(encCtx->result), + 1, + xmlSecBufferGetSize(encCtx->result), + stdout); + } + } + fprintf(stdout, "\n"); + + /* success */ + res = 0; + +done: + /* cleanup */ + if(encCtx != NULL) { + xmlSecEncCtxDestroy(encCtx); + } + + if(doc != NULL) { + xmlFreeDoc(doc); + } + return(res); +} + diff --git a/examples/decrypt2.c b/examples/decrypt2.c new file mode 100644 index 00000000..051cbf97 --- /dev/null +++ b/examples/decrypt2.c @@ -0,0 +1,275 @@ +/** + * XML Security Library example: Decrypting an encrypted file using keys manager. + * + * Decrypts encrypted XML file using keys manager and a list of + * DES key from a binary file + * + * Usage: + * ./decrypt2 <xml-enc> <des-key-file1> [<des-key-file2> [...]] + * + * Example: + * ./decrypt2 encrypt1-res.xml deskey.bin + * ./decrypt2 encrypt2-res.xml deskey.bin + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (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/xmlenc.h> +#include <xmlsec/crypto.h> + +xmlSecKeysMngrPtr load_des_keys(char** files, int files_size); +int decrypt_file(xmlSecKeysMngrPtr mngr, const char* enc_file); + +int +main(int argc, char **argv) { + xmlSecKeysMngrPtr mngr; + + assert(argv); + + if(argc != 3) { + fprintf(stderr, "Error: wrong number of arguments.\n"); + fprintf(stderr, "Usage: %s <enc-file> <key-file1> [<key-file2> [...]]\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); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* 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); + } + + /* create keys manager and load keys */ + mngr = load_des_keys(&(argv[2]), argc - 2); + if(mngr == NULL) { + return(-1); + } + + if(decrypt_file(mngr, argv[1]) < 0) { + xmlSecKeysMngrDestroy(mngr); + return(-1); + } + + /* destroy keys manager */ + xmlSecKeysMngrDestroy(mngr); + + /* 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); +} + +/** + * load_des_keys: + * @files: the list of filenames. + * @files_size: the number of filenames in #files. + * + * Creates simple keys manager and load DES keys from #files in it. + * The caller is responsible for destroing returned keys manager using + * @xmlSecKeysMngrDestroy. + * + * Returns the pointer to newly created keys manager or NULL if an error + * occurs. + */ +xmlSecKeysMngrPtr +load_des_keys(char** files, int files_size) { + xmlSecKeysMngrPtr mngr; + xmlSecKeyPtr key; + int i; + + assert(files); + assert(files_size > 0); + + /* create and initialize keys manager, we use a simple list based + * keys manager, implement your own xmlSecKeysStore klass if you need + * something more sophisticated + */ + mngr = xmlSecKeysMngrCreate(); + if(mngr == NULL) { + fprintf(stderr, "Error: failed to create keys manager.\n"); + return(NULL); + } + if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) { + fprintf(stderr, "Error: failed to initialize keys manager.\n"); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + for(i = 0; i < files_size; ++i) { + assert(files[i]); + + /* load DES key */ + key = xmlSecKeyReadBinaryFile(xmlSecKeyDataDesId, files[i]); + if(key == NULL) { + fprintf(stderr,"Error: failed to load des key from binary file \"%s\"\n", files[i]); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + /* set key name to the file name, this is just an example! */ + if(xmlSecKeySetName(key, BAD_CAST files[i]) < 0) { + fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", files[i]); + xmlSecKeyDestroy(key); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + /* add key to keys manager, from now on keys manager is responsible + * for destroying key + */ + if(xmlSecCryptoAppDefaultKeysMngrAdoptKey(mngr, key) < 0) { + fprintf(stderr,"Error: failed to add key from \"%s\" to keys manager\n", files[i]); + xmlSecKeyDestroy(key); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + } + + return(mngr); +} + +/** + * decrypt_file: + * @mngr: the pointer to keys manager. + * @enc_file: the encrypted XML file name. + * + * Decrypts the XML file #enc_file using DES key from #key_file and + * prints results to stdout. + * + * Returns 0 on success or a negative value if an error occurs. + */ +int +decrypt_file(xmlSecKeysMngrPtr mngr, const char* enc_file) { + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlSecEncCtxPtr encCtx = NULL; + int res = -1; + + assert(mngr); + assert(enc_file); + + /* load template */ + doc = xmlParseFile(enc_file); + if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){ + fprintf(stderr, "Error: unable to parse file \"%s\"\n", enc_file); + goto done; + } + + /* find start node */ + node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeEncryptedData, xmlSecEncNs); + if(node == NULL) { + fprintf(stderr, "Error: start node not found in \"%s\"\n", enc_file); + goto done; + } + + /* create encryption context */ + encCtx = xmlSecEncCtxCreate(mngr); + if(encCtx == NULL) { + fprintf(stderr,"Error: failed to create encryption context\n"); + goto done; + } + + /* decrypt the data */ + if((xmlSecEncCtxDecrypt(encCtx, node) < 0) || (encCtx->result == NULL)) { + fprintf(stderr,"Error: decryption failed\n"); + goto done; + } + + /* print decrypted data to stdout */ + if(encCtx->resultReplaced != 0) { + fprintf(stdout, "Decrypted XML data:\n"); + xmlDocDump(stdout, doc); + } else { + fprintf(stdout, "Decrypted binary data (%d bytes):\n", xmlSecBufferGetSize(encCtx->result)); + if(xmlSecBufferGetData(encCtx->result) != NULL) { + fwrite(xmlSecBufferGetData(encCtx->result), + 1, + xmlSecBufferGetSize(encCtx->result), + stdout); + } + } + fprintf(stdout, "\n"); + + /* success */ + res = 0; + +done: + /* cleanup */ + if(encCtx != NULL) { + xmlSecEncCtxDestroy(encCtx); + } + + if(doc != NULL) { + xmlFreeDoc(doc); + } + return(res); +} + diff --git a/examples/decrypt3.c b/examples/decrypt3.c new file mode 100644 index 00000000..eb0d581a --- /dev/null +++ b/examples/decrypt3.c @@ -0,0 +1,355 @@ +/** + * XML Security Library example: Decrypting an encrypted file using a custom keys manager. + * + * Decrypts encrypted XML file using a custom files based keys manager. + * We assume that key's name in <dsig:KeyName/> element is just + * key's file name in the current folder. + * + * Usage: + * ./decrypt3 <xml-enc> + * + * Example: + * ./decrypt3 encrypt1-res.xml + * ./decrypt3 encrypt2-res.xml + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include <stdlib.h> +#include <string.h> +#include <ctype.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/xmlenc.h> +#include <xmlsec/crypto.h> + +xmlSecKeyStoreId files_keys_store_get_klass(void); +xmlSecKeysMngrPtr create_files_keys_mngr(void); +int decrypt_file(xmlSecKeysMngrPtr mngr, const char* enc_file); + +int +main(int argc, char **argv) { + xmlSecKeysMngrPtr mngr; + + assert(argv); + + if(argc != 2) { + fprintf(stderr, "Error: wrong number of arguments.\n"); + fprintf(stderr, "Usage: %s <enc-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); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* 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); + } + + /* create keys manager and load keys */ + mngr = create_files_keys_mngr(); + if(mngr == NULL) { + return(-1); + } + + if(decrypt_file(mngr, argv[1]) < 0) { + xmlSecKeysMngrDestroy(mngr); + return(-1); + } + + /* destroy keys manager */ + xmlSecKeysMngrDestroy(mngr); + + /* 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); +} + +/** + * decrypt_file: + * @mngr: the pointer to keys manager. + * @enc_file: the encrypted XML file name. + * + * Decrypts the XML file #enc_file using DES key from #key_file and + * prints results to stdout. + * + * Returns 0 on success or a negative value if an error occurs. + */ +int +decrypt_file(xmlSecKeysMngrPtr mngr, const char* enc_file) { + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlSecEncCtxPtr encCtx = NULL; + int res = -1; + + assert(mngr); + assert(enc_file); + + /* load template */ + doc = xmlParseFile(enc_file); + if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){ + fprintf(stderr, "Error: unable to parse file \"%s\"\n", enc_file); + goto done; + } + + /* find start node */ + node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeEncryptedData, xmlSecEncNs); + if(node == NULL) { + fprintf(stderr, "Error: start node not found in \"%s\"\n", enc_file); + goto done; + } + + /* create encryption context */ + encCtx = xmlSecEncCtxCreate(mngr); + if(encCtx == NULL) { + fprintf(stderr,"Error: failed to create encryption context\n"); + goto done; + } + + /* decrypt the data */ + if((xmlSecEncCtxDecrypt(encCtx, node) < 0) || (encCtx->result == NULL)) { + fprintf(stderr,"Error: decryption failed\n"); + goto done; + } + + /* print decrypted data to stdout */ + if(encCtx->resultReplaced != 0) { + fprintf(stdout, "Decrypted XML data:\n"); + xmlDocDump(stdout, doc); + } else { + fprintf(stdout, "Decrypted binary data (%d bytes):\n", xmlSecBufferGetSize(encCtx->result)); + if(xmlSecBufferGetData(encCtx->result) != NULL) { + fwrite(xmlSecBufferGetData(encCtx->result), + 1, + xmlSecBufferGetSize(encCtx->result), + stdout); + } + } + fprintf(stdout, "\n"); + + /* success */ + res = 0; + +done: + /* cleanup */ + if(encCtx != NULL) { + xmlSecEncCtxDestroy(encCtx); + } + + if(doc != NULL) { + xmlFreeDoc(doc); + } + return(res); +} + +/** + * create_files_keys_mngr: + * + * Creates a files based keys manager: we assume that key name is + * the key file name, + * + * Returns pointer to newly created keys manager or NULL if an error occurs. + */ +xmlSecKeysMngrPtr +create_files_keys_mngr(void) { + xmlSecKeyStorePtr keysStore; + xmlSecKeysMngrPtr mngr; + + /* create files based keys store */ + keysStore = xmlSecKeyStoreCreate(files_keys_store_get_klass()); + if(keysStore == NULL) { + fprintf(stderr, "Error: failed to create keys store.\n"); + return(NULL); + } + + /* create keys manager */ + mngr = xmlSecKeysMngrCreate(); + if(mngr == NULL) { + fprintf(stderr, "Error: failed to create keys manager.\n"); + xmlSecKeyStoreDestroy(keysStore); + return(NULL); + } + + /* add store to keys manager, from now on keys manager destroys the store if needed */ + if(xmlSecKeysMngrAdoptKeysStore(mngr, keysStore) < 0) { + fprintf(stderr, "Error: failed to add keys store to keys manager.\n"); + xmlSecKeyStoreDestroy(keysStore); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + /* initialize crypto library specific data in keys manager */ + if(xmlSecCryptoKeysMngrInit(mngr) < 0) { + fprintf(stderr, "Error: failed to initialize crypto data in keys manager.\n"); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + /* set the get key callback */ + mngr->getKey = xmlSecKeysMngrGetKey; + return(mngr); +} + +/**************************************************************************** + * + * Files Keys Store: we assume that key's name (content of the + * <dsig:KeyName/> element is a name of the file with a key (in the + * current folder). + * Attention: this probably not a good solution for high traffic systems. + * + ***************************************************************************/ +static xmlSecKeyPtr files_keys_store_find_key (xmlSecKeyStorePtr store, + const xmlChar* name, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static xmlSecKeyStoreKlass files_keys_store_klass = { + sizeof(xmlSecKeyStoreKlass), + sizeof(xmlSecKeyStore), + BAD_CAST "files-based-keys-store", /* const xmlChar* name; */ + NULL, /* xmlSecKeyStoreInitializeMethod initialize; */ + NULL, /* xmlSecKeyStoreFinalizeMethod finalize; */ + files_keys_store_find_key, /* xmlSecKeyStoreFindKeyMethod findKey; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * files_keys_store_get_klass: + * + * The files based keys store klass: we assume that key name is the + * key file name, + * + * Returns files based keys store klass. + */ +xmlSecKeyStoreId +files_keys_store_get_klass(void) { + return(&files_keys_store_klass); +} + +/** + * files_keys_store_find_key: + * @store: the pointer to simple keys store. + * @name: the desired key name. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> node processing context. + * + * Lookups key in the @store. The caller is responsible for destroying + * returned key with #xmlSecKeyDestroy function. + * + * Returns pointer to key or NULL if key not found or an error occurs. + */ +static xmlSecKeyPtr +files_keys_store_find_key(xmlSecKeyStorePtr store, const xmlChar* name, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyPtr key; + const xmlChar* p; + + assert(store); + assert(keyInfoCtx); + + /* it's possible to do not have the key name or desired key type + * but we could do nothing in this case */ + if((name == NULL) || (keyInfoCtx->keyReq.keyId == xmlSecKeyDataIdUnknown)){ + return(NULL); + } + + /* we don't want to open files in a folder other than "current"; + * to prevent it limit the characters in the key name to alpha/digit, + * '.', '-' or '_'. + */ + for(p = name; (*p) != '\0'; ++p) { + if(!isalnum((*p)) && ((*p) != '.') && ((*p) != '-') && ((*p) != '_')) { + return(NULL); + } + } + + if((keyInfoCtx->keyReq.keyId == xmlSecKeyDataDsaId) || (keyInfoCtx->keyReq.keyId == xmlSecKeyDataRsaId)) { + /* load key from a pem file, if key is not found then it's an error (is it?) */ + key = xmlSecCryptoAppKeyLoad(name, xmlSecKeyDataFormatPem, NULL, NULL, NULL); + if(key == NULL) { + fprintf(stderr,"Error: failed to load public pem key from \"%s\"\n", name); + return(NULL); + } + } else { + /* otherwise it's a binary key, if key is not found then it's an error (is it?) */ + key = xmlSecKeyReadBinaryFile(keyInfoCtx->keyReq.keyId, name); + if(key == NULL) { + fprintf(stderr,"Error: failed to load key from binary file \"%s\"\n", name); + return(NULL); + } + } + + /* set key name */ + if(xmlSecKeySetName(key, name) < 0) { + fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", name); + xmlSecKeyDestroy(key); + return(NULL); + } + + return(key); +} + diff --git a/examples/deskey.bin b/examples/deskey.bin new file mode 100644 index 00000000..019924a7 --- /dev/null +++ b/examples/deskey.bin @@ -0,0 +1 @@ +012345670123456701234567
\ No newline at end of file diff --git a/examples/encrypt1-res.xml b/examples/encrypt1-res.xml new file mode 100644 index 00000000..cc436a0e --- /dev/null +++ b/examples/encrypt1-res.xml @@ -0,0 +1,13 @@ +<?xml version="1.0"?> +<!-- +XML Security Library example: Encrypted binary data (encrypt1 example). +--> +<EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#"> + <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/> + <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> + <KeyName>deskey.bin</KeyName> + </KeyInfo> + <CipherData> + <CipherValue>t6JVBMihIgRyiK8AS8AX5NcXTfkdXPTK</CipherValue> + </CipherData> +</EncryptedData> diff --git a/examples/encrypt1-tmpl.xml b/examples/encrypt1-tmpl.xml new file mode 100644 index 00000000..3d61a901 --- /dev/null +++ b/examples/encrypt1-tmpl.xml @@ -0,0 +1,13 @@ +<?xml version="1.0"?> +<!-- +XML Security Library example: Simple encryption template file for encrypt1 example. +--> +<EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#"> + <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/> + <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> + <KeyName/> + </KeyInfo> + <CipherData> + <CipherValue></CipherValue> + </CipherData> +</EncryptedData> diff --git a/examples/encrypt1.c b/examples/encrypt1.c new file mode 100644 index 00000000..bdd16b14 --- /dev/null +++ b/examples/encrypt1.c @@ -0,0 +1,202 @@ +/** + * XML Security Library example: Encrypting data using a template file. + * + * Encrypts binary data using a template file and a DES key from a binary file + * + * Usage: + * ./encrypt1 <xml-tmpl> <des-key-file> + * + * Example: + * ./encrypt1 encrypt1-tmpl.xml deskey.bin > encrypt1-res.xml + * + * The result could be decrypted with decrypt1 example: + * ./decrypt1 encrypt1-res.xml deskey.bin + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (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/xmlenc.h> +#include <xmlsec/crypto.h> + +int encrypt_file(const char* tmpl_file, const char* key_file, + const unsigned char* data, size_t dataSize); +int +main(int argc, char **argv) { + static const char secret_data[] = "Big secret"; + + assert(argv); + + if(argc != 3) { + fprintf(stderr, "Error: wrong number of arguments.\n"); + fprintf(stderr, "Usage: %s <tmpl-file> <key-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); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* 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(encrypt_file(argv[1], argv[2], secret_data, strlen(secret_data)) < 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); +} + +/** + * encrypt_file: + * @tmpl_file: the encryption template file name. + * @key_file: the Triple DES key file. + * @data: the binary data to encrypt. + * @dataSize: the binary data size. + * + * Encrypts binary #data using template from #tmpl_file and DES key from + * #key_file. + * + * Returns 0 on success or a negative value if an error occurs. + */ +int +encrypt_file(const char* tmpl_file, const char* key_file, + const unsigned char* data, size_t dataSize) { + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlSecEncCtxPtr encCtx = NULL; + int res = -1; + + assert(tmpl_file); + assert(key_file); + assert(data); + + /* load template */ + doc = xmlParseFile(tmpl_file); + if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){ + fprintf(stderr, "Error: unable to parse file \"%s\"\n", tmpl_file); + goto done; + } + + /* find start node */ + node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeEncryptedData, xmlSecEncNs); + if(node == NULL) { + fprintf(stderr, "Error: start node not found in \"%s\"\n", tmpl_file); + goto done; + } + + /* create encryption context, we don't need keys manager in this example */ + encCtx = xmlSecEncCtxCreate(NULL); + if(encCtx == NULL) { + fprintf(stderr,"Error: failed to create encryption context\n"); + goto done; + } + + /* load DES key, assuming that there is not password */ + encCtx->encKey = xmlSecKeyReadBinaryFile(xmlSecKeyDataDesId, key_file); + if(encCtx->encKey == NULL) { + fprintf(stderr,"Error: failed to load des key from binary file \"%s\"\n", key_file); + goto done; + } + + /* set key name to the file name, this is just an example! */ + if(xmlSecKeySetName(encCtx->encKey, key_file) < 0) { + fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", key_file); + goto done; + } + + /* encrypt the data */ + if(xmlSecEncCtxBinaryEncrypt(encCtx, node, data, dataSize) < 0) { + fprintf(stderr,"Error: encryption failed\n"); + goto done; + } + + /* print encrypted data with document to stdout */ + xmlDocDump(stdout, doc); + + /* success */ + res = 0; + +done: + + /* cleanup */ + if(encCtx != NULL) { + xmlSecEncCtxDestroy(encCtx); + } + + if(doc != NULL) { + xmlFreeDoc(doc); + } + return(res); +} + diff --git a/examples/encrypt2-doc.xml b/examples/encrypt2-doc.xml new file mode 100644 index 00000000..d01549d8 --- /dev/null +++ b/examples/encrypt2-doc.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +XML Security Library example: Original XML doc file before encryption (encrypt2 example). +--> +<Envelope xmlns="urn:envelope"> + <Data> + Hello, World! + </Data> +</Envelope> diff --git a/examples/encrypt2-res.xml b/examples/encrypt2-res.xml new file mode 100644 index 00000000..d2a0a573 --- /dev/null +++ b/examples/encrypt2-res.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +XML Security Library example: Encrypted XML file (encrypt2 example). +--> +<EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Element"> +<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/> +<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> +<KeyName>deskey.bin</KeyName> +</KeyInfo> +<CipherData> +<CipherValue>WXlDyktaADlUe+PywKwS3KdKlahCteEKxi/hRlHcXNQlGwNGrYKy8aQ6dLtX1bKg +IgL/XoAQN3B27zD91b1ZLGh6QQ9CjnVD98+hYJ9TPp4piPnII4vGUA==</CipherValue> +</CipherData> +</EncryptedData> diff --git a/examples/encrypt2.c b/examples/encrypt2.c new file mode 100644 index 00000000..9bbd52ff --- /dev/null +++ b/examples/encrypt2.c @@ -0,0 +1,226 @@ +/** + * XML Security Library example: Encrypting XML file with a dynamicaly created template. + * + * Encrypts XML file using a dynamicaly created template file and a DES key + * from a binary file + * + * Usage: + * ./encrypt2 <xml-doc> <des-key-file> + * + * Example: + * ./encrypt2 encrypt2-doc.xml deskey.bin > encrypt2-res.xml + * + * The result could be decrypted with decrypt1 example: + * ./decrypt1 encrypt2-res.xml deskey.bin + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (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/xmlenc.h> +#include <xmlsec/templates.h> +#include <xmlsec/crypto.h> + +int encrypt_file(const char* xml_file, const char* key_file); + +int +main(int argc, char **argv) { + assert(argv); + + if(argc != 3) { + fprintf(stderr, "Error: wrong number of arguments.\n"); + fprintf(stderr, "Usage: %s <xml-file> <key-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); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* 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(encrypt_file(argv[1], argv[2]) < 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); +} + +/** + * encrypt_file: + * @xml_file: the encryption template file name. + * @key_file: the Triple DES key file. + * + * Encrypts #xml_file using a dynamicaly created template and DES key from + * #key_file. + * + * Returns 0 on success or a negative value if an error occurs. + */ +int +encrypt_file(const char* xml_file, const char* key_file) { + xmlDocPtr doc = NULL; + xmlNodePtr encDataNode = NULL; + xmlNodePtr keyInfoNode = NULL; + xmlSecEncCtxPtr encCtx = NULL; + int res = -1; + + assert(xml_file); + assert(key_file); + + /* load template */ + doc = xmlParseFile(xml_file); + if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){ + fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_file); + goto done; + } + + /* create encryption template to encrypt XML file and replace + * its content with encryption result */ + encDataNode = xmlSecTmplEncDataCreate(doc, xmlSecTransformDes3CbcId, + NULL, xmlSecTypeEncElement, NULL, NULL); + if(encDataNode == NULL) { + fprintf(stderr, "Error: failed to create encryption template\n"); + goto done; + } + + /* we want to put encrypted data in the <enc:CipherValue/> node */ + if(xmlSecTmplEncDataEnsureCipherValue(encDataNode) == NULL) { + fprintf(stderr, "Error: failed to add CipherValue node\n"); + goto done; + } + + /* add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to put key name in the signed document */ + keyInfoNode = xmlSecTmplEncDataEnsureKeyInfo(encDataNode, NULL); + if(keyInfoNode == NULL) { + fprintf(stderr, "Error: failed to add key info\n"); + goto done; + } + + if(xmlSecTmplKeyInfoAddKeyName(keyInfoNode, NULL) == NULL) { + fprintf(stderr, "Error: failed to add key name\n"); + goto done; + } + + /* create encryption context, we don't need keys manager in this example */ + encCtx = xmlSecEncCtxCreate(NULL); + if(encCtx == NULL) { + fprintf(stderr,"Error: failed to create encryption context\n"); + goto done; + } + + /* load DES key, assuming that there is not password */ + encCtx->encKey = xmlSecKeyReadBinaryFile(xmlSecKeyDataDesId, key_file); + if(encCtx->encKey == NULL) { + fprintf(stderr,"Error: failed to load des key from binary file \"%s\"\n", key_file); + goto done; + } + + /* set key name to the file name, this is just an example! */ + if(xmlSecKeySetName(encCtx->encKey, key_file) < 0) { + fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", key_file); + goto done; + } + + /* encrypt the data */ + if(xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, xmlDocGetRootElement(doc)) < 0) { + fprintf(stderr,"Error: encryption failed\n"); + goto done; + } + + /* we template is inserted in the doc */ + encDataNode = NULL; + + /* print encrypted data with document to stdout */ + xmlDocDump(stdout, doc); + + /* success */ + res = 0; + +done: + + /* cleanup */ + if(encCtx != NULL) { + xmlSecEncCtxDestroy(encCtx); + } + + if(encDataNode != NULL) { + xmlFreeNode(encDataNode); + } + + if(doc != NULL) { + xmlFreeDoc(doc); + } + return(res); +} + diff --git a/examples/encrypt3-doc.xml b/examples/encrypt3-doc.xml new file mode 100644 index 00000000..e017c35a --- /dev/null +++ b/examples/encrypt3-doc.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +XML Security Library example: Original XML doc file before encryption (encrypt3 example). +--> +<Envelope xmlns="urn:envelope"> + <Data> + Hello, World! + </Data> +</Envelope> diff --git a/examples/encrypt3-res.xml b/examples/encrypt3-res.xml new file mode 100644 index 00000000..bcf7439c --- /dev/null +++ b/examples/encrypt3-res.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +XML Security Library example: XML doc file encrypted with a session DES key (encrypt3 example). +--> +<EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Element"> +<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/> +<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> +<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#"> +<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/> +<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> +<KeyName>rsakey.pem</KeyName> +</KeyInfo> +<CipherData> +<CipherValue>IPiEu9Nv+EsGyvVeXO9nl5iZhhi+uzQH1I3/DTs3+eamBvioyaawRIlvTql7LYL5 +Mi91Qs8ozfW/fWZ8zB8AE2PosaX37SqiuEta68+65/Ed4v1rkGN0Awux8+gJqJmp +c2kJhzAoQIAIGAW4nTGP9tl9QUHfwKh2KPA104vezk70ijvF7TrbTmhdfmULAuWK +Tbsg8sXAPhGmPh5KckM2Xe387iPh4ue2+2TGdWqwXygVdvIUIbcIMq6F+/mWlcmf +Gs5FVI7CTjaLmeyO4ho+FGmicmqH2hEkZW0a2ktDh4BU/MxYF6L7oayrVWDGp2IH +dzQAwUT2qJcFjElO8xUz3g==</CipherValue> +</CipherData> +</EncryptedKey> +</KeyInfo> +<CipherData> +<CipherValue>xrfPSA+BEI+8ca23RN34gtee5lOMx8Cn+ZGWyxitiktdZ1+XREH+57li63VutCwp +s6ifbZgXIBsFdxPpMBUFlyTWAAO+NLooIwGoczXi14z62lHr7Ck6FA==</CipherValue> +</CipherData> +</EncryptedData> diff --git a/examples/encrypt3.c b/examples/encrypt3.c new file mode 100644 index 00000000..788c964e --- /dev/null +++ b/examples/encrypt3.c @@ -0,0 +1,323 @@ +/** + * XML Security Library example: Encrypting XML file with a session key and dynamicaly created template. + * + * Encrypts XML file using a dynamicaly created template file and a session + * DES key (encrypted with an RSA key). + * + * Usage: + * ./encrypt3 <xml-doc> <rsa-pem-key-file> + * + * Example: + * ./encrypt3 encrypt3-doc.xml rsakey.pem > encrypt3-res.xml + * + * The result could be decrypted with decrypt3 example: + * ./decrypt3 encrypt3-res.xml + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (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/xmlenc.h> +#include <xmlsec/templates.h> +#include <xmlsec/crypto.h> + +xmlSecKeysMngrPtr load_rsa_keys(char* key_file); +int encrypt_file(xmlSecKeysMngrPtr mngr, const char* xml_file, const char* key_name); + +int +main(int argc, char **argv) { + xmlSecKeysMngrPtr mngr; + + assert(argv); + + if(argc != 3) { + fprintf(stderr, "Error: wrong number of arguments.\n"); + fprintf(stderr, "Usage: %s <xml-file> <key-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); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* 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); + } + + /* create keys manager and load keys */ + mngr = load_rsa_keys(argv[2]); + if(mngr == NULL) { + return(-1); + } + + /* we use key filename as key name here */ + if(encrypt_file(mngr, argv[1], argv[2]) < 0) { + xmlSecKeysMngrDestroy(mngr); + return(-1); + } + + /* destroy keys manager */ + xmlSecKeysMngrDestroy(mngr); + + /* 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); +} + +/** + * load_rsa_keys: + * @key_file: the key filename. + * + * Creates simple keys manager and load RSA key from #key_file in it. + * The caller is responsible for destroing returned keys manager using + * @xmlSecKeysMngrDestroy. + * + * Returns the pointer to newly created keys manager or NULL if an error + * occurs. + */ +xmlSecKeysMngrPtr +load_rsa_keys(char* key_file) { + xmlSecKeysMngrPtr mngr; + xmlSecKeyPtr key; + + assert(key_file); + + /* create and initialize keys manager, we use a simple list based + * keys manager, implement your own xmlSecKeysStore klass if you need + * something more sophisticated + */ + mngr = xmlSecKeysMngrCreate(); + if(mngr == NULL) { + fprintf(stderr, "Error: failed to create keys manager.\n"); + return(NULL); + } + if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) { + fprintf(stderr, "Error: failed to initialize keys manager.\n"); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + /* load private RSA key */ + key = xmlSecCryptoAppKeyLoad(key_file, xmlSecKeyDataFormatPem, NULL, NULL, NULL); + if(key == NULL) { + fprintf(stderr,"Error: failed to load rsa key from file \"%s\"\n", key_file); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + /* set key name to the file name, this is just an example! */ + if(xmlSecKeySetName(key, BAD_CAST key_file) < 0) { + fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", key_file); + xmlSecKeyDestroy(key); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + /* add key to keys manager, from now on keys manager is responsible + * for destroying key + */ + if(xmlSecCryptoAppDefaultKeysMngrAdoptKey(mngr, key) < 0) { + fprintf(stderr,"Error: failed to add key from \"%s\" to keys manager\n", key_file); + xmlSecKeyDestroy(key); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + return(mngr); +} + +/** + * encrypt_file: + * @mngr: the pointer to keys manager. + * @xml_file: the encryption template file name. + * @key_name: the RSA key name. + * + * Encrypts #xml_file using a dynamicaly created template, a session DES key + * and an RSA key from keys manager. + * + * Returns 0 on success or a negative value if an error occurs. + */ +int +encrypt_file(xmlSecKeysMngrPtr mngr, const char* xml_file, const char* key_name) { + xmlDocPtr doc = NULL; + xmlNodePtr encDataNode = NULL; + xmlNodePtr keyInfoNode = NULL; + xmlNodePtr encKeyNode = NULL; + xmlNodePtr keyInfoNode2 = NULL; + xmlSecEncCtxPtr encCtx = NULL; + int res = -1; + + assert(mngr); + assert(xml_file); + assert(key_name); + + /* load template */ + doc = xmlParseFile(xml_file); + if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){ + fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_file); + goto done; + } + + /* create encryption template to encrypt XML file and replace + * its content with encryption result */ + encDataNode = xmlSecTmplEncDataCreate(doc, xmlSecTransformDes3CbcId, + NULL, xmlSecTypeEncElement, NULL, NULL); + if(encDataNode == NULL) { + fprintf(stderr, "Error: failed to create encryption template\n"); + goto done; + } + + /* we want to put encrypted data in the <enc:CipherValue/> node */ + if(xmlSecTmplEncDataEnsureCipherValue(encDataNode) == NULL) { + fprintf(stderr, "Error: failed to add CipherValue node\n"); + goto done; + } + + /* add <dsig:KeyInfo/> */ + keyInfoNode = xmlSecTmplEncDataEnsureKeyInfo(encDataNode, NULL); + if(keyInfoNode == NULL) { + fprintf(stderr, "Error: failed to add key info\n"); + goto done; + } + + /* add <enc:EncryptedKey/> to store the encrypted session key */ + encKeyNode = xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode, + xmlSecTransformRsaPkcs1Id, + NULL, NULL, NULL); + if(encKeyNode == NULL) { + fprintf(stderr, "Error: failed to add key info\n"); + goto done; + } + + /* we want to put encrypted key in the <enc:CipherValue/> node */ + if(xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == NULL) { + fprintf(stderr, "Error: failed to add CipherValue node\n"); + goto done; + } + + /* add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to <enc:EncryptedKey/> */ + keyInfoNode2 = xmlSecTmplEncDataEnsureKeyInfo(encKeyNode, NULL); + if(keyInfoNode2 == NULL) { + fprintf(stderr, "Error: failed to add key info\n"); + goto done; + } + + /* set key name so we can lookup key when needed */ + if(xmlSecTmplKeyInfoAddKeyName(keyInfoNode2, key_name) == NULL) { + fprintf(stderr, "Error: failed to add key name\n"); + goto done; + } + + /* create encryption context */ + encCtx = xmlSecEncCtxCreate(mngr); + if(encCtx == NULL) { + fprintf(stderr,"Error: failed to create encryption context\n"); + goto done; + } + + /* generate a Triple DES key */ + encCtx->encKey = xmlSecKeyGenerate(xmlSecKeyDataDesId, 192, xmlSecKeyDataTypeSession); + if(encCtx->encKey == NULL) { + fprintf(stderr,"Error: failed to generate session des key\n"); + goto done; + } + + /* encrypt the data */ + if(xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, xmlDocGetRootElement(doc)) < 0) { + fprintf(stderr,"Error: encryption failed\n"); + goto done; + } + + /* we template is inserted in the doc */ + encDataNode = NULL; + + /* print encrypted data with document to stdout */ + xmlDocDump(stdout, doc); + + /* success */ + res = 0; + +done: + + /* cleanup */ + if(encCtx != NULL) { + xmlSecEncCtxDestroy(encCtx); + } + + if(encDataNode != NULL) { + xmlFreeNode(encDataNode); + } + + if(doc != NULL) { + xmlFreeDoc(doc); + } + return(res); +} + diff --git a/examples/mywin32make.bat b/examples/mywin32make.bat new file mode 100644 index 00000000..84c5777e --- /dev/null +++ b/examples/mywin32make.bat @@ -0,0 +1,18 @@ +@echo off +REM +REM This is my personal configuration file. +REM I am lazy to type all this crap again and again +REM You are welcome to customize this file for your +REM needs but do not check it into the CVS, please. +REM +REM Aleksey Sanin <aleksey@aleksey.com> +REM + +SET XMLSEC_PREFIX=d:\sdk +SET XMLSEC_INCLUDE=%XMLSEC_PREFIX%\include +SET XMLSEC_LIB=%XMLSEC_PREFIX%\lib + +SET INCLUDE=%XMLSEC_INCLUDE%;%INCLUDE% +SET LIB=%XMLSEC_LIB%;%LIB% + +nmake -f Makefile.w32 %1 %2 %3 diff --git a/examples/rootcert.pem b/examples/rootcert.pem new file mode 100644 index 00000000..38144d65 --- /dev/null +++ b/examples/rootcert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEPDCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCVVMx +EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE +ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v +eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl +a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMB4X +DTAyMDIwMjA4MDAzOFoXDTEyMDEzMTA4MDAzOFowgcsxCzAJBgNVBAYTAlVTMRMw +EQYDVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQHEwlTdW5ueXZhbGUxPTA7BgNVBAoT +NFhNTCBTZWN1cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3ht +bHNlYykxGTAXBgNVBAsTEFJvb3QgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUFsZWtz +ZXkgU2FuaW4xITAfBgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvSvv4RNOzsjL+FQEoMwkidOOjJQciB2x +WxI1QPkwFVC5Z86BcQugOWVJ+4JVTtE2uDjFElNI9SMINhd+4GkxlK+TVHvSZfCT +Ia/EichBfRfZcPjVnXH3pzFCC9JkbGOIFAzuhBcz+KvN8gntuumolN2/fBYCbFZX +4otzgMd5Rm8CAwEAAaOCASwwggEoMB0GA1UdDgQWBBS0ue+a5pcOaGUemM76VQ2J +BttMfDCB+AYDVR0jBIHwMIHtgBS0ue+a5pcOaGUemM76VQ2JBttMfKGB0aSBzjCB +yzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1 +bm55dmFsZTE9MDsGA1UEChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93 +d3cuYWxla3NleS5jb20veG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0 +ZTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2Vj +QGFsZWtzZXkuY29tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEA +J/+WEipxRms7bdg0ORf+ipHNwgdvWDxaLeQqqKMSacHDFVZyKdurm4onypNI2w9K +Gk6XKipJT67ew4QpVMgv5LAIoErMxIcVYu1tAfhjtNK5neF6X5v/r/cRQkdIYaaF +BlnBUmHY6x83aiSMC2ASG2MKL8UDqF/y2/SlPuxmG50= +-----END CERTIFICATE----- diff --git a/examples/rsacert.pem b/examples/rsacert.pem new file mode 100644 index 00000000..02489a43 --- /dev/null +++ b/examples/rsacert.pem @@ -0,0 +1,83 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 5 (0x5) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=US, ST=California, L=Sunnyvale, O=XML Security Library (http://www.aleksey.com/xmlsec), OU=Root Certificate, CN=Aleksey Sanin/emailAddress=xmlsec@aleksey.com + Validity + Not Before: Mar 31 04:02:22 2003 GMT + Not After : Mar 28 04:02:22 2013 GMT + Subject: C=US, ST=California, O=XML Security Library (http://www.aleksey.com/xmlsec), OU=Examples RSA Certificate, CN=Aleksey Sanin/emailAddress=xmlsec@aleksey.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:97:b8:fe:b4:3f:83:35:78:16:89:04:ec:2b:61: + 8c:bf:c4:5f:00:81:4a:45:e6:d9:cd:e9:e2:3c:97: + 3b:45:ad:aa:e6:8d:0b:77:71:07:01:4f:7c:f9:7d: + e2:19:aa:dd:91:59:f4:f1:cf:3d:ba:78:46:96:11: + 9c:b6:5b:46:39:73:55:23:aa:f7:9e:00:5c:e5:e9: + 49:ec:3b:9c:3f:84:99:3a:90:ad:df:7e:64:86:c6: + 26:72:ce:31:08:79:7e:13:15:b8:e5:bf:d6:56:02: + 8d:60:21:4c:27:18:64:fb:fb:55:70:f6:33:bd:2f: + 55:70:d5:5e:7e:99:ae:a4:e0:aa:45:47:13:a8:30: + d5:a0:8a:9d:cc:20:ec:e4:8e:51:c9:54:c5:7f:3e: + 66:2d:74:bf:a3:7a:f8:f3:ec:94:57:39:b4:ac:00: + 75:62:61:54:b4:d0:e0:52:86:f8:5e:77:ec:50:43: + 9c:d2:ba:a7:8c:62:5a:bc:b2:fe:f3:cc:62:7e:23: + 60:6b:c7:51:49:37:78:7e:25:15:30:ab:fa:b4:ae: + 25:8f:22:fc:a3:48:7f:f2:0a:8a:6e:e0:fe:8d:f0: + 01:ed:c6:33:cc:6b:a1:fd:a6:80:ef:06:8c:af:f6: + 40:3a:8e:42:14:20:61:12:1f:e3:fc:05:b1:05:d5: + 65:c3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 24:84:2C:F2:D4:59:20:62:8B:2E:5C:86:90:A3:AA:30:BA:27:1A:9C + X509v3 Authority Key Identifier: + keyid:B4:B9:EF:9A:E6:97:0E:68:65:1E:98:CE:FA:55:0D:89:06:DB:4C:7C + DirName:/C=US/ST=California/L=Sunnyvale/O=XML Security Library (http://www.aleksey.com/xmlsec)/OU=Root Certificate/CN=Aleksey Sanin/emailAddress=xmlsec@aleksey.com + serial:00 + + Signature Algorithm: md5WithRSAEncryption + b5:3f:9b:32:31:4a:ff:2f:84:3b:a8:9b:11:5c:a6:5c:f0:76: + 52:d9:6e:f4:90:ad:fa:0d:90:c1:98:d5:4a:12:dd:82:6b:37: + e8:d9:2d:62:92:c9:61:37:98:86:8f:a4:49:6a:5e:25:d0:18: + 69:30:0f:98:8f:43:58:89:31:b2:3b:05:e2:ef:c7:a6:71:5f: + f7:fe:73:c5:a7:b2:cd:2e:73:53:71:7d:a8:4c:68:1a:32:1b: + 5e:48:2f:8f:9b:7a:a3:b5:f3:67:e8:b1:a2:89:4e:b2:4d:1b: + 79:9c:ff:f0:0d:19:4f:4e:b1:03:3d:99:f0:44:b7:8a:0b:34: + 9d:83 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/examples/rsakey.pem b/examples/rsakey.pem new file mode 100644 index 00000000..55d2fd9b --- /dev/null +++ b/examples/rsakey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAl7j+tD+DNXgWiQTsK2GMv8RfAIFKRebZzeniPJc7Ra2q5o0L +d3EHAU98+X3iGardkVn08c89unhGlhGctltGOXNVI6r3ngBc5elJ7DucP4SZOpCt +335khsYmcs4xCHl+ExW45b/WVgKNYCFMJxhk+/tVcPYzvS9VcNVefpmupOCqRUcT +qDDVoIqdzCDs5I5RyVTFfz5mLXS/o3r48+yUVzm0rAB1YmFUtNDgUob4XnfsUEOc +0rqnjGJavLL+88xifiNga8dRSTd4fiUVMKv6tK4ljyL8o0h/8gqKbuD+jfAB7cYz +zGuh/aaA7waMr/ZAOo5CFCBhEh/j/AWxBdVlwwIDAQABAoIBAQCAvt6DnZF9gdW9 +l4vAlBqXb88d4phgELCp5tmviLUnP2NSGEWuqR7Eoeru2z9NgIxblvYfazh6Ty22 +kmNk6rcAcTnB9oYAcVZjUj8EUuEXlTFhXPvuNpafNu3RZd59znqJP1mSu+LpQWku +NZMlabHnkTLDlGf7FXtvL9/rlgV4qk3QcDVF793JFszWrtK3mnld3KHQ6cuo9iSm +0rQKtkDjeHsRell8qTQvfBsgG1q2bv8QWT45/eQrra9mMbGTr3DbnXvoeJmTj1VN +XJV7tBNllxxPahlYMByJaf/Tuva5j6HWUEIfYky5ihr2z1P/fNQ2OSCM6SQHpkiG +EXQDueXBAoGBAMfW7KcmToEQEcTiqfey6C1LOLoemcX0/ROUktPq/5JQJRRrT4t7 +XevLX0ed8sLyR5T29XQtdnuV0DJfvcJD+6ZwfOcQ+f6ZzCaNXJP97JtEt5kSWY01 +Ei+nphZ0RFvPb04V3qDU9dElU26GR36CRBYJyM2WQPx4v+/YyDSZH9kLAoGBAMJc +ZBU8pRbIia/FFOHUlS3v5P18nVmXyOd0fvRq0ZelaQCebTZ4K9wjnCfw//yzkb2Z +0vZFNB+xVBKB0Pt6nVvnSNzxdQ8EAXVFwHtXa25FUyP2RERQgTvmajqmgWjZsDYp +6GHcK3ZhmdmscQHF/Q2Uo4scvBcheahm9IXiNskpAoGAXelEgTBhSAmTMCEMmti6 +fz6QQ/bJcNu2apMxhOE0hT+gjT34vaWV9481EWTKho5w0TJVGumaem1mz6VqeXaV +Nhw6tiOmN91ysNNRpEJ6BGWAmjCjYNaF21s/k+HDlhmfRuTEIHSzqDuQP6pewrbY +5Dpo4SQxGfRsznvjacRj0Q0CgYBN247oBvQnDUxCkhNMZ8kersOvW5T4x9neBge5 +R3UQZ12Jtu0O7dK8C7PJODyDcTeHmTAuIQjBTVrdUw1xP+v7XcoNX9hBnJws6zUw +85MAiFrGxCcSqqEqaqHRPtQGOXXiLKV/ViA++tgTn4VhbXtyTkG5P1iFd45xjFSV +sUm7CQKBgDn92tHxzePly1L1mK584TkVryx4cP9RFHpebnmNduGwwjnRuYipoj8y +pPPAkVbbaA3f9OB2go48rN0Ft9nHdlqgh9BpIKCVtkIb1XN0K3Oa/8BW8W/GAiNG +HJcsrOtIrGVRdlyJG6bDaN8T49DnhOcsqMbf+IkIvfh50VeE9L/e +-----END RSA PRIVATE KEY----- diff --git a/examples/rsapub.pem b/examples/rsapub.pem new file mode 100644 index 00000000..838a346d --- /dev/null +++ b/examples/rsapub.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl7j+tD+DNXgWiQTsK2GM +v8RfAIFKRebZzeniPJc7Ra2q5o0Ld3EHAU98+X3iGardkVn08c89unhGlhGctltG +OXNVI6r3ngBc5elJ7DucP4SZOpCt335khsYmcs4xCHl+ExW45b/WVgKNYCFMJxhk ++/tVcPYzvS9VcNVefpmupOCqRUcTqDDVoIqdzCDs5I5RyVTFfz5mLXS/o3r48+yU +Vzm0rAB1YmFUtNDgUob4XnfsUEOc0rqnjGJavLL+88xifiNga8dRSTd4fiUVMKv6 +tK4ljyL8o0h/8gqKbuD+jfAB7cYzzGuh/aaA7waMr/ZAOo5CFCBhEh/j/AWxBdVl +wwIDAQAB +-----END PUBLIC KEY----- diff --git a/examples/sign1-res.xml b/examples/sign1-res.xml new file mode 100644 index 00000000..04d8fed0 --- /dev/null +++ b/examples/sign1-res.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +XML Security Library example: Signed file (sign1 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/TR/2001/REC-xml-c14n-20010315"/> + <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-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>9H/rQr2Axe9hYTV2n/tCp+3UIQQ=</DigestValue> + </Reference> + </SignedInfo> + <SignatureValue>Mx4psIy9/UY+u8QBJRDrwQWKRaCGz0WOVftyDzAe6WHAFSjMNr7qb2ojq9kdipT8 +Oub5q2OQ7mzdSLiiejkrO1VeqM/90yEIGI4En6KEB6ArEzw+iq4N1wm6EptcyxXx +M9StAOOa9ilWYqR9Tfx3SW1urUIuKYgUitxsONiUHBVaW6HeX51bsXoTF++4ZI+D +jiPBjN4HHmr0cbJ6BXk91S27ffZIfp1Qj5nL9onFLUGbR6EFgu2luiRzQbPuM2tP +XxyI7GZ8AfHnRJK28ARvBC9oi+O1ej20S79CIV7gdBxbLbFprozBHAwOEC57YgJc +x+YEjSjcO7SBIR1FiUA7pw==</SignatureValue> + <KeyInfo> + <KeyName>rsakey.pem</KeyName> + </KeyInfo> + </Signature> +</Envelope> diff --git a/examples/sign1-tmpl.xml b/examples/sign1-tmpl.xml new file mode 100644 index 00000000..ac71a949 --- /dev/null +++ b/examples/sign1-tmpl.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +XML Security Library example: Simple signature template file for sign1 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/TR/2001/REC-xml-c14n-20010315" /> + <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-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> + <KeyName/> + </KeyInfo> + </Signature> +</Envelope> + diff --git a/examples/sign1.c b/examples/sign1.c new file mode 100644 index 00000000..f17bf96f --- /dev/null +++ b/examples/sign1.c @@ -0,0 +1,194 @@ +/** + * XML Security Library example: Signing a template file. + * + * Signs a template file using a key from PEM file + * + * Usage: + * ./sign1 <xml-tmpl> <pem-key> + * + * Example: + * ./sign1 sign1-tmpl.xml rsakey.pem > sign1-res.xml + * + * The result signature could be validated using verify1 example: + * ./verify1 sign1-res.xml rsapub.pem + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (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/crypto.h> + +int sign_file(const char* tmpl_file, const char* key_file); + +int +main(int argc, char **argv) { + assert(argv); + + if(argc != 3) { + fprintf(stderr, "Error: wrong number of arguments.\n"); + fprintf(stderr, "Usage: %s <tmpl-file> <key-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); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* 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]) < 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: + * @tmpl_file: the signature template file name. + * @key_file: the PEM private key file name. + * + * Signs the #tmpl_file using private key from #key_file. + * + * Returns 0 on success or a negative value if an error occurs. + */ +int +sign_file(const char* tmpl_file, const char* key_file) { + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlSecDSigCtxPtr dsigCtx = NULL; + int res = -1; + + assert(tmpl_file); + assert(key_file); + + /* load template */ + doc = xmlParseFile(tmpl_file); + if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){ + fprintf(stderr, "Error: unable to parse file \"%s\"\n", tmpl_file); + goto done; + } + + /* find start node */ + node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs); + if(node == NULL) { + fprintf(stderr, "Error: start node not found in \"%s\"\n", tmpl_file); + 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; + } + + /* 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, node) < 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); +} + diff --git a/examples/sign2-doc.xml b/examples/sign2-doc.xml new file mode 100644 index 00000000..5d9fb352 --- /dev/null +++ b/examples/sign2-doc.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +XML Security Library example: Original XML doc file for sign2 example. +--> +<Envelope xmlns="urn:envelope"> + <Data> + Hello, World! + </Data> +</Envelope> diff --git a/examples/sign2-res.xml b/examples/sign2-res.xml new file mode 100644 index 00000000..b37cad94 --- /dev/null +++ b/examples/sign2-res.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +XML Security Library example: Signed XML doc file (sign2 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> +<KeyName>rsakey.pem</KeyName> +</KeyInfo> +</Signature></Envelope> diff --git a/examples/sign2.c b/examples/sign2.c new file mode 100644 index 00000000..3bb858ce --- /dev/null +++ b/examples/sign2.c @@ -0,0 +1,230 @@ +/** + * XML Security Library example: Signing a file with a dynamicaly created template. + * + * Signs a file using a dynamicaly created template and key from PEM file. + * The signature has one reference with one enveloped transform to sign + * the whole document except the <dsig:Signature/> node itself. + * + * Usage: + * sign2 <xml-doc> <pem-key> + * + * Example: + * ./sign2 sign2-doc.xml rsakey.pem > sign2-res.xml + * + * The result signature could be validated using verify1 example: + * ./verify1 sign2-res.xml rsapub.pem + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (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); + +int +main(int argc, char **argv) { + assert(argv); + + if(argc != 3) { + fprintf(stderr, "Error: wrong number of arguments.\n"); + fprintf(stderr, "Usage: %s <xml-file> <key-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); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* 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]) < 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. + * + * Signs the #xml_file using private key from #key_file and dynamicaly + * created enveloped signature template. + * + * Returns 0 on success or a negative value if an error occurs. + */ +int +sign_file(const char* xml_file, const char* key_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); + + /* 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:KeyName/> nodes to put key name in the signed document */ + keyInfoNode = xmlSecTmplSignatureEnsureKeyInfo(signNode, NULL); + if(keyInfoNode == NULL) { + fprintf(stderr, "Error: failed to add key info\n"); + goto done; + } + + if(xmlSecTmplKeyInfoAddKeyName(keyInfoNode, NULL) == NULL) { + fprintf(stderr, "Error: failed to add key name\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; + } + + /* 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); +} + diff --git a/examples/sign3-doc.xml b/examples/sign3-doc.xml new file mode 100644 index 00000000..f75da16a --- /dev/null +++ b/examples/sign3-doc.xml @@ -0,0 +1,9 @@ +<?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> diff --git a/examples/sign3-res.xml b/examples/sign3-res.xml new file mode 100644 index 00000000..847e1af2 --- /dev/null +++ b/examples/sign3-res.xml @@ -0,0 +1,58 @@ +<?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> diff --git a/examples/sign3.c b/examples/sign3.c new file mode 100644 index 00000000..8a367083 --- /dev/null +++ b/examples/sign3.c @@ -0,0 +1,243 @@ +/** + * 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. + * + * Copyright (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); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* 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); +} + diff --git a/examples/verify1.c b/examples/verify1.c new file mode 100644 index 00000000..9f2eff5b --- /dev/null +++ b/examples/verify1.c @@ -0,0 +1,197 @@ +/** + * XML Security Library example: Verifying a file using a single key. + * + * Verifies a file using a key from PEM file. + * + * Usage: + * verify1 <signed-file> <pem-key> + * + * Example: + * ./verify1 sign1-res.xml rsapub.pem + * ./verify1 sign2-res.xml rsapub.pem + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (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/crypto.h> + +int verify_file(const char* xml_file, const char* key_file); + +int +main(int argc, char **argv) { + assert(argv); + + if(argc != 3) { + fprintf(stderr, "Error: wrong number of arguments.\n"); + fprintf(stderr, "Usage: %s <xml-file> <key-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); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* 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(verify_file(argv[1], argv[2]) < 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); +} + +/** + * verify_file: + * @xml_file: the signed XML file name. + * @key_file: the PEM public key file name. + * + * Verifies XML signature in #xml_file using public key from #key_file. + * + * Returns 0 on success or a negative value if an error occurs. + */ +int +verify_file(const char* xml_file, const char* key_file) { + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlSecDSigCtxPtr dsigCtx = NULL; + int res = -1; + + assert(xml_file); + assert(key_file); + + /* load file */ + doc = xmlParseFile(xml_file); + if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){ + fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_file); + goto done; + } + + /* find start node */ + node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs); + if(node == NULL) { + fprintf(stderr, "Error: start node not found in \"%s\"\n", xml_file); + 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 public key */ + dsigCtx->signKey = xmlSecCryptoAppKeyLoad(key_file, xmlSecKeyDataFormatPem, NULL, NULL, NULL); + if(dsigCtx->signKey == NULL) { + fprintf(stderr,"Error: failed to load public pem key from \"%s\"\n", key_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; + } + + /* Verify signature */ + if(xmlSecDSigCtxVerify(dsigCtx, node) < 0) { + fprintf(stderr,"Error: signature verify\n"); + goto done; + } + + /* print verification result to stdout */ + if(dsigCtx->status == xmlSecDSigStatusSucceeded) { + fprintf(stdout, "Signature is OK\n"); + } else { + fprintf(stdout, "Signature is INVALID\n"); + } + + /* success */ + res = 0; + +done: + /* cleanup */ + if(dsigCtx != NULL) { + xmlSecDSigCtxDestroy(dsigCtx); + } + + if(doc != NULL) { + xmlFreeDoc(doc); + } + return(res); +} + + diff --git a/examples/verify2.c b/examples/verify2.c new file mode 100644 index 00000000..a56bb551 --- /dev/null +++ b/examples/verify2.c @@ -0,0 +1,267 @@ +/** + * XML Security Library example: Verifying a file using keys manager. + * + * Verifies a file using keys manager + * + * Usage: + * verify2 <signed-file> <public-pem-key1> [<public-pem-key2> [...]] + * + * Example: + * ./verify2 sign1-res.xml rsapub.pem + * ./verify2 sign2-res.xml rsapub.pem + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (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/crypto.h> + +xmlSecKeysMngrPtr load_keys(char** files, int files_size); +int verify_file(xmlSecKeysMngrPtr mngr, const char* xml_file); + +int +main(int argc, char **argv) { + xmlSecKeysMngrPtr mngr; + + assert(argv); + + if(argc < 3) { + fprintf(stderr, "Error: wrong number of arguments.\n"); + fprintf(stderr, "Usage: %s <xml-file> <key-file1> [<key-file2> [...]]\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); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* 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); + } + + /* create keys manager and load keys */ + mngr = load_keys(&(argv[2]), argc - 2); + if(mngr == NULL) { + return(-1); + } + + /* verify file */ + if(verify_file(mngr, argv[1]) < 0) { + xmlSecKeysMngrDestroy(mngr); + return(-1); + } + + /* destroy keys manager */ + xmlSecKeysMngrDestroy(mngr); + + /* 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); +} + +/** + * load_keys: + * @files: the list of filenames. + * @files_size: the number of filenames in #files. + * + * Creates simple keys manager and load PEM keys from #files in it. + * The caller is responsible for destroing returned keys manager using + * @xmlSecKeysMngrDestroy. + * + * Returns the pointer to newly created keys manager or NULL if an error + * occurs. + */ +xmlSecKeysMngrPtr +load_keys(char** files, int files_size) { + xmlSecKeysMngrPtr mngr; + xmlSecKeyPtr key; + int i; + + assert(files); + assert(files_size > 0); + + /* create and initialize keys manager, we use a simple list based + * keys manager, implement your own xmlSecKeysStore klass if you need + * something more sophisticated + */ + mngr = xmlSecKeysMngrCreate(); + if(mngr == NULL) { + fprintf(stderr, "Error: failed to create keys manager.\n"); + return(NULL); + } + if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) { + fprintf(stderr, "Error: failed to initialize keys manager.\n"); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + for(i = 0; i < files_size; ++i) { + assert(files[i]); + + /* load key */ + key = xmlSecCryptoAppKeyLoad(files[i], xmlSecKeyDataFormatPem, NULL, NULL, NULL); + if(key == NULL) { + fprintf(stderr,"Error: failed to load pem key from \"%s\"\n", files[i]); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + /* set key name to the file name, this is just an example! */ + if(xmlSecKeySetName(key, BAD_CAST files[i]) < 0) { + fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", files[i]); + xmlSecKeyDestroy(key); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + /* add key to keys manager, from now on keys manager is responsible + * for destroying key + */ + if(xmlSecCryptoAppDefaultKeysMngrAdoptKey(mngr, key) < 0) { + fprintf(stderr,"Error: failed to add key from \"%s\" to keys manager\n", files[i]); + xmlSecKeyDestroy(key); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + } + + return(mngr); +} + +/** + * verify_file: + * @mngr: the pointer to keys manager. + * @xml_file: the signed XML file name. + * + * Verifies XML signature in #xml_file. + * + * Returns 0 on success or a negative value if an error occurs. + */ +int +verify_file(xmlSecKeysMngrPtr mngr, const char* xml_file) { + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlSecDSigCtxPtr dsigCtx = NULL; + int res = -1; + + assert(mngr); + assert(xml_file); + + /* load file */ + doc = xmlParseFile(xml_file); + if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){ + fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_file); + goto done; + } + + /* find start node */ + node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs); + if(node == NULL) { + fprintf(stderr, "Error: start node not found in \"%s\"\n", xml_file); + goto done; + } + + /* create signature context */ + dsigCtx = xmlSecDSigCtxCreate(mngr); + if(dsigCtx == NULL) { + fprintf(stderr,"Error: failed to create signature context\n"); + goto done; + } + + /* Verify signature */ + if(xmlSecDSigCtxVerify(dsigCtx, node) < 0) { + fprintf(stderr,"Error: signature verify\n"); + goto done; + } + + /* print verification result to stdout */ + if(dsigCtx->status == xmlSecDSigStatusSucceeded) { + fprintf(stdout, "Signature is OK\n"); + } else { + fprintf(stdout, "Signature is INVALID\n"); + } + + /* success */ + res = 0; + +done: + /* cleanup */ + if(dsigCtx != NULL) { + xmlSecDSigCtxDestroy(dsigCtx); + } + + if(doc != NULL) { + xmlFreeDoc(doc); + } + return(res); +} + + diff --git a/examples/verify3.c b/examples/verify3.c new file mode 100644 index 00000000..b7746a0d --- /dev/null +++ b/examples/verify3.c @@ -0,0 +1,249 @@ +/** + * XML Security Library example: Verifying a file signed with X509 certificate + * + * Verifies a file signed with X509 certificate. + * + * This example was developed and tested with OpenSSL crypto library. The + * certificates management policies for another crypto library may break it. + * + * Usage: + * verify3 <signed-file> <trusted-cert-pem-file1> [<trusted-cert-pem-file2> [...]] + * + * Example: + * ./verify3 sign3-res.xml rootcert.pem + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (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/crypto.h> + +xmlSecKeysMngrPtr load_trusted_certs(char** files, int files_size); +int verify_file(xmlSecKeysMngrPtr mngr, const char* xml_file); + +int +main(int argc, char **argv) { + xmlSecKeysMngrPtr mngr; + + assert(argv); + + if(argc < 3) { + fprintf(stderr, "Error: wrong number of arguments.\n"); + fprintf(stderr, "Usage: %s <xml-file> <cert-file1> [<cert-file2> [...]]\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); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* 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); + } + + /* create keys manager and load trusted certificates */ + mngr = load_trusted_certs(&(argv[2]), argc - 2); + if(mngr == NULL) { + return(-1); + } + + /* verify file */ + if(verify_file(mngr, argv[1]) < 0) { + xmlSecKeysMngrDestroy(mngr); + return(-1); + } + + /* destroy keys manager */ + xmlSecKeysMngrDestroy(mngr); + + /* 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); +} + +/** + * load_trusted_certs: + * @files: the list of filenames. + * @files_size: the number of filenames in #files. + * + * Creates simple keys manager and load trusted certificates from PEM #files. + * The caller is responsible for destroing returned keys manager using + * @xmlSecKeysMngrDestroy. + * + * Returns the pointer to newly created keys manager or NULL if an error + * occurs. + */ +xmlSecKeysMngrPtr +load_trusted_certs(char** files, int files_size) { + xmlSecKeysMngrPtr mngr; + int i; + + assert(files); + assert(files_size > 0); + + /* create and initialize keys manager, we use a simple list based + * keys manager, implement your own xmlSecKeysStore klass if you need + * something more sophisticated + */ + mngr = xmlSecKeysMngrCreate(); + if(mngr == NULL) { + fprintf(stderr, "Error: failed to create keys manager.\n"); + return(NULL); + } + if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) { + fprintf(stderr, "Error: failed to initialize keys manager.\n"); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + for(i = 0; i < files_size; ++i) { + assert(files[i]); + + /* load trusted cert */ + if(xmlSecCryptoAppKeysMngrCertLoad(mngr, files[i], xmlSecKeyDataFormatPem, xmlSecKeyDataTypeTrusted) < 0) { + fprintf(stderr,"Error: failed to load pem certificate from \"%s\"\n", files[i]); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + } + + return(mngr); +} + +/** + * verify_file: + * @mngr: the pointer to keys manager. + * @xml_file: the signed XML file name. + * + * Verifies XML signature in #xml_file. + * + * Returns 0 on success or a negative value if an error occurs. + */ +int +verify_file(xmlSecKeysMngrPtr mngr, const char* xml_file) { + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlSecDSigCtxPtr dsigCtx = NULL; + int res = -1; + + assert(mngr); + assert(xml_file); + + /* load file */ + doc = xmlParseFile(xml_file); + if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){ + fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_file); + goto done; + } + + /* find start node */ + node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs); + if(node == NULL) { + fprintf(stderr, "Error: start node not found in \"%s\"\n", xml_file); + goto done; + } + + /* create signature context */ + dsigCtx = xmlSecDSigCtxCreate(mngr); + if(dsigCtx == NULL) { + fprintf(stderr,"Error: failed to create signature context\n"); + goto done; + } + + /* Verify signature */ + if(xmlSecDSigCtxVerify(dsigCtx, node) < 0) { + fprintf(stderr,"Error: signature verify\n"); + goto done; + } + + /* print verification result to stdout */ + if(dsigCtx->status == xmlSecDSigStatusSucceeded) { + fprintf(stdout, "Signature is OK\n"); + } else { + fprintf(stdout, "Signature is INVALID\n"); + } + + /* success */ + res = 0; + +done: + /* cleanup */ + if(dsigCtx != NULL) { + xmlSecDSigCtxDestroy(dsigCtx); + } + + if(doc != NULL) { + xmlFreeDoc(doc); + } + return(res); +} + + diff --git a/examples/verify4-bad-res.xml b/examples/verify4-bad-res.xml new file mode 100644 index 00000000..15928e2c --- /dev/null +++ b/examples/verify4-bad-res.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +XML Security Library example: A simple bad SAML response (verify4 example). + +This file could be verified with verify3 example (signature is valid) +but verify4 example fails because of XPath transform which is not allowed +in a simple SAML response. + +This file was created from a template with the following command (replace __ with double dashes): + ../apps/xmlsec sign __privkey rsakey.pem,rsacert.pem __output verify4-bad-res.xml verify4-bad-tmpl.xml +--> +<Response xmlns="urn:oasis:names:tc:SAML:1.0:protocol" xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2002-04-18T16:56:54Z" MajorVersion="1" MinorVersion="0" Recipient="https://shire.target.com" ResponseID="7ddc31-ed4a03d703-FB24AD27D96135B68C99FB9AACFE2FFC"> + <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"> + <dsig:SignedInfo> + <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> + <dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> + <dsig:Reference URI=""> + <dsig:Transforms> + <dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> + <dsig:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> + <dsig:XPath xmlns:samlp_xpath="urn:oasis:names:tc:SAML:1.0:protocol"> + count(ancestor-or-self::samlp_xpath:Response | + here()/ancestor::samlp_xpath:Response[1]) = + count(ancestor-or-self::samlp_xpath:Response) + </dsig:XPath> + </dsig:Transform> + </dsig:Transforms> + <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> + <dsig:DigestValue>t1nvDq1bZXEhBIXc/DHcqIrjRyI=</dsig:DigestValue> + </dsig:Reference> + </dsig:SignedInfo> + <dsig:SignatureValue>PipZFFmmYcSnSU9p5AcOmFbRYoeatERYPy4IRk+jU26xk9sAM6yfhXtbK8csl/0w +rjODj1jGcydBGP9I8kFAfHyZ+Ls+A+53oMNl+tGWfe8iICMowIU1HCxJtPrgbTKk +1gc+VnYJ3IXhoVneeQKqzilXwA5X7FW7hgIecb5KwLShYV3iO8+z8pzt3NEGKAGQ +p/lQmO3EQR4Zu0bCSOk6zXdlOhe5dPVFXJQLlE8Zz3WjGQNo0l4op0ZXKf1B+syH +blHx0tnPQDtSBzQdKohJV39UgkGnL3rd5ggBzyXemjMTX8eFxNZ7bh4UgZ+Wo74W +Zb4ompTc2ImxJfbpszWp8w==</dsig:SignatureValue> + <dsig:KeyInfo> + <dsig:X509Data> +<X509Certificate xmlns="http://www.w3.org/2000/09/xmldsig#">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> +</dsig:X509Data> + </dsig:KeyInfo> + </dsig:Signature> + <Status> + <StatusCode Value="samlp:Success"/> + </Status> + <Assertion xmlns="urn:oasis:names:tc:SAML:1.0:assertion" AssertionID="7ddc31-ed4a03d735-FB24AD27D96135B68C99FB9AACFE2FFC" IssueInstant="2002-04-18T16:56:54Z" Issuer="hs.osu.edu" MajorVersion="1" MinorVersion="0"> + <Conditions NotBefore="2002-04-18T16:56:54Z" NotOnOrAfter="2002-04-18T17:01:54Z"> + <AudienceRestrictionCondition> + <Audience>http://middleware.internet2.edu/shibboleth/clubs/clubshib/1.0/</Audience> + </AudienceRestrictionCondition> + </Conditions> + <AuthenticationStatement AuthenticationInstant="2002-04-18T16:56:53Z" AuthenticationMethod="urn:mace:shibboleth:authmethod"> + <Subject> + <NameIdentifier Format="urn:mace:shibboleth:1.0:handle" NameQualifier="osu.edu">foo</NameIdentifier> + <SubjectConfirmation> + <ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:Bearer</ConfirmationMethod> + </SubjectConfirmation> + </Subject> + <SubjectLocality IPAddress="127.0.0.1"/> + <AuthorityBinding AuthorityKind="samlp:AttributeQuery" Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding" Location="https://aa.osu.edu/"/> + </AuthenticationStatement> + </Assertion> +</Response> diff --git a/examples/verify4-bad-tmpl.xml b/examples/verify4-bad-tmpl.xml new file mode 100644 index 00000000..5cd026f3 --- /dev/null +++ b/examples/verify4-bad-tmpl.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +XML Security Library example: A simple bad SAML response template (verify4 example). + +Sign it using the following command (replace __ with double dashes): + + ../apps/xmlsec sign __privkey rsakey.pem,rsacert.pem __output verify4--bad-res.xml verify4-bad-tmpl.xml +--> +<Response xmlns="urn:oasis:names:tc:SAML:1.0:protocol" xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2002-04-18T16:56:54Z" MajorVersion="1" MinorVersion="0" Recipient="https://shire.target.com" ResponseID="7ddc31-ed4a03d703-FB24AD27D96135B68C99FB9AACFE2FFC"> + <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"> + <dsig:SignedInfo> + <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> + <dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> + <dsig:Reference URI=""> + <dsig:Transforms> + <dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> + <dsig:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> + <dsig:XPath xmlns:samlp_xpath="urn:oasis:names:tc:SAML:1.0:protocol" > + count(ancestor-or-self::samlp_xpath:Response | + here()/ancestor::samlp_xpath:Response[1]) = + count(ancestor-or-self::samlp_xpath:Response) + </dsig:XPath> + </dsig:Transform> + </dsig:Transforms> + <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> + <dsig:DigestValue/> + </dsig:Reference> + </dsig:SignedInfo> + <dsig:SignatureValue/> + <dsig:KeyInfo> + <dsig:X509Data/> + </dsig:KeyInfo> + </dsig:Signature> + <Status> + <StatusCode Value="samlp:Success"/> + </Status> + <Assertion xmlns="urn:oasis:names:tc:SAML:1.0:assertion" AssertionID="7ddc31-ed4a03d735-FB24AD27D96135B68C99FB9AACFE2FFC" IssueInstant="2002-04-18T16:56:54Z" Issuer="hs.osu.edu" MajorVersion="1" MinorVersion="0"> + <Conditions NotBefore="2002-04-18T16:56:54Z" NotOnOrAfter="2002-04-18T17:01:54Z"> + <AudienceRestrictionCondition> + <Audience>http://middleware.internet2.edu/shibboleth/clubs/clubshib/1.0/</Audience> + </AudienceRestrictionCondition> + </Conditions> + <AuthenticationStatement AuthenticationInstant="2002-04-18T16:56:53Z" AuthenticationMethod="urn:mace:shibboleth:authmethod"> + <Subject> + <NameIdentifier Format="urn:mace:shibboleth:1.0:handle" NameQualifier="osu.edu">foo</NameIdentifier> + <SubjectConfirmation> + <ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:Bearer</ConfirmationMethod> + </SubjectConfirmation> + </Subject> + <SubjectLocality IPAddress="127.0.0.1"/> + <AuthorityBinding AuthorityKind="samlp:AttributeQuery" Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding" Location="https://aa.osu.edu/"/> + </AuthenticationStatement> + </Assertion> +</Response> diff --git a/examples/verify4-res.xml b/examples/verify4-res.xml new file mode 100644 index 00000000..7abe539f --- /dev/null +++ b/examples/verify4-res.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +XML Security Library example: A simple SAML response template (verify4 example). + +This file was signed using the following command (replace __ with double dashes): + + ../apps/xmlsec sign __privkey rsakey.pem,rsacert.pem __output verify4-res.xml verify4-tmpl.xml +--> +<Response xmlns="urn:oasis:names:tc:SAML:1.0:protocol" xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2002-04-18T16:56:54Z" MajorVersion="1" MinorVersion="0" Recipient="https://shire.target.com" ResponseID="7ddc31-ed4a03d703-FB24AD27D96135B68C99FB9AACFE2FFC"> + <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"> + <dsig:SignedInfo> + <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> + <dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> + <dsig:Reference URI=""> + <dsig:Transforms> + <dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> + </dsig:Transforms> + <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> + <dsig:DigestValue>t1nvDq1bZXEhBIXc/DHcqIrjRyI=</dsig:DigestValue> + </dsig:Reference> + </dsig:SignedInfo> + <dsig:SignatureValue>EsNm7mOj9XY6pq1bfeuzFd1F/LQwbc1K/YgOYgrElk4tr8BhSd5OcrzXBgsivPvm +HpjvSOBkjctGOFVE7x+6+G8TMudTja1IchEmGMh+pjMBlGNpvxSTedwtnoZBGWAz +RlfRhRFThskup0T7Or+VBHYygPGM3gmwX0ZWVYpNzM/rfYSk7+obgIp9DxLDIXlW +oLrJGVivubE+T63CPfBPaUIv1CbfBAzdo+11+8CiVsdWn2qwtGe5Fsmc3eCg06Oj +sl1nyCIu3AONq1w8jIPOgmITF8PpwDm0+XoQUH0P4kHJqNLphnJZY+GlPAC6VlAW +2bcAFr4Ul5yzHUBpxCDZfg==</dsig:SignatureValue> + <dsig:KeyInfo> + <dsig:X509Data> +<X509Certificate xmlns="http://www.w3.org/2000/09/xmldsig#">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> +</dsig:X509Data> + </dsig:KeyInfo> + </dsig:Signature> + <Status> + <StatusCode Value="samlp:Success"/> + </Status> + <Assertion xmlns="urn:oasis:names:tc:SAML:1.0:assertion" AssertionID="7ddc31-ed4a03d735-FB24AD27D96135B68C99FB9AACFE2FFC" IssueInstant="2002-04-18T16:56:54Z" Issuer="hs.osu.edu" MajorVersion="1" MinorVersion="0"> + <Conditions NotBefore="2002-04-18T16:56:54Z" NotOnOrAfter="2002-04-18T17:01:54Z"> + <AudienceRestrictionCondition> + <Audience>http://middleware.internet2.edu/shibboleth/clubs/clubshib/1.0/</Audience> + </AudienceRestrictionCondition> + </Conditions> + <AuthenticationStatement AuthenticationInstant="2002-04-18T16:56:53Z" AuthenticationMethod="urn:mace:shibboleth:authmethod"> + <Subject> + <NameIdentifier Format="urn:mace:shibboleth:1.0:handle" NameQualifier="osu.edu">foo</NameIdentifier> + <SubjectConfirmation> + <ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:Bearer</ConfirmationMethod> + </SubjectConfirmation> + </Subject> + <SubjectLocality IPAddress="127.0.0.1"/> + <AuthorityBinding AuthorityKind="samlp:AttributeQuery" Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding" Location="https://aa.osu.edu/"/> + </AuthenticationStatement> + </Assertion> +</Response> diff --git a/examples/verify4-tmpl.xml b/examples/verify4-tmpl.xml new file mode 100644 index 00000000..0546b905 --- /dev/null +++ b/examples/verify4-tmpl.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +XML Security Library example: A simple SAML response template (verify4 example). + +Sign it using the following command (replace __ with double dashes): + + ../apps/xmlsec sign __privkey rsakey.pem,rsacert.pem __output verify4-res.xml verify4-tmpl.xml +--> +<Response xmlns="urn:oasis:names:tc:SAML:1.0:protocol" xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2002-04-18T16:56:54Z" MajorVersion="1" MinorVersion="0" Recipient="https://shire.target.com" ResponseID="7ddc31-ed4a03d703-FB24AD27D96135B68C99FB9AACFE2FFC"> + <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"> + <dsig:SignedInfo> + <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> + <dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> + <dsig:Reference URI=""> + <dsig:Transforms> + <dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> + </dsig:Transforms> + <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> + <dsig:DigestValue/> + </dsig:Reference> + </dsig:SignedInfo> + <dsig:SignatureValue/> + <dsig:KeyInfo> + <dsig:X509Data/> + </dsig:KeyInfo> + </dsig:Signature> + <Status> + <StatusCode Value="samlp:Success"/> + </Status> + <Assertion xmlns="urn:oasis:names:tc:SAML:1.0:assertion" AssertionID="7ddc31-ed4a03d735-FB24AD27D96135B68C99FB9AACFE2FFC" IssueInstant="2002-04-18T16:56:54Z" Issuer="hs.osu.edu" MajorVersion="1" MinorVersion="0"> + <Conditions NotBefore="2002-04-18T16:56:54Z" NotOnOrAfter="2002-04-18T17:01:54Z"> + <AudienceRestrictionCondition> + <Audience>http://middleware.internet2.edu/shibboleth/clubs/clubshib/1.0/</Audience> + </AudienceRestrictionCondition> + </Conditions> + <AuthenticationStatement AuthenticationInstant="2002-04-18T16:56:53Z" AuthenticationMethod="urn:mace:shibboleth:authmethod"> + <Subject> + <NameIdentifier Format="urn:mace:shibboleth:1.0:handle" NameQualifier="osu.edu">foo</NameIdentifier> + <SubjectConfirmation> + <ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:Bearer</ConfirmationMethod> + </SubjectConfirmation> + </Subject> + <SubjectLocality IPAddress="127.0.0.1"/> + <AuthorityBinding AuthorityKind="samlp:AttributeQuery" Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding" Location="https://aa.osu.edu/"/> + </AuthenticationStatement> + </Assertion> +</Response> diff --git a/examples/verify4.c b/examples/verify4.c new file mode 100644 index 00000000..3d82af69 --- /dev/null +++ b/examples/verify4.c @@ -0,0 +1,292 @@ +/** + * XML Security Library example: Verifying a simple SAML response with X509 certificate + * + * Verifies a simple SAML response. In addition to refular verification + * we ensure that the signature has only one <dsig:Reference/> element + * with an empty or NULL URI attribute and one enveloped signature transform + * as it is required by SAML specification. + * + * This example was developed and tested with OpenSSL crypto library. The + * certificates management policies for another crypto library may break it. + * + * Usage: + * verify4 <signed-file> <trusted-cert-pem-file1> [<trusted-cert-pem-file2> [...]] + * + * Example (sucecess): + * ./verify4 verify4-res.xml rootcert.pem + * + * Example (failure): + * ./verify4 verify4-bad-res.xml rootcert.pem + * In the same time, verify3 example successfuly verifies this signature: + * ./verify3 verify4-bad-res.xml rootcert.pem + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (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/crypto.h> + +xmlSecKeysMngrPtr load_trusted_certs(char** files, int files_size); +int verify_file(xmlSecKeysMngrPtr mngr, const char* xml_file); + +int +main(int argc, char **argv) { + xmlSecKeysMngrPtr mngr; + + assert(argv); + + if(argc < 3) { + fprintf(stderr, "Error: wrong number of arguments.\n"); + fprintf(stderr, "Usage: %s <xml-file> <cert-file1> [<cert-file2> [...]]\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); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* 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); + } + + /* create keys manager and load trusted certificates */ + mngr = load_trusted_certs(&(argv[2]), argc - 2); + if(mngr == NULL) { + return(-1); + } + + /* verify file */ + if(verify_file(mngr, argv[1]) < 0) { + xmlSecKeysMngrDestroy(mngr); + return(-1); + } + + /* destroy keys manager */ + xmlSecKeysMngrDestroy(mngr); + + /* 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); +} + +/** + * load_trusted_certs: + * @files: the list of filenames. + * @files_size: the number of filenames in #files. + * + * Creates simple keys manager and load trusted certificates from PEM #files. + * The caller is responsible for destroing returned keys manager using + * @xmlSecKeysMngrDestroy. + * + * Returns the pointer to newly created keys manager or NULL if an error + * occurs. + */ +xmlSecKeysMngrPtr +load_trusted_certs(char** files, int files_size) { + xmlSecKeysMngrPtr mngr; + int i; + + assert(files); + assert(files_size > 0); + + /* create and initialize keys manager, we use a simple list based + * keys manager, implement your own xmlSecKeysStore klass if you need + * something more sophisticated + */ + mngr = xmlSecKeysMngrCreate(); + if(mngr == NULL) { + fprintf(stderr, "Error: failed to create keys manager.\n"); + return(NULL); + } + if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) { + fprintf(stderr, "Error: failed to initialize keys manager.\n"); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + + for(i = 0; i < files_size; ++i) { + assert(files[i]); + + /* load trusted cert */ + if(xmlSecCryptoAppKeysMngrCertLoad(mngr, files[i], xmlSecKeyDataFormatPem, xmlSecKeyDataTypeTrusted) < 0) { + fprintf(stderr,"Error: failed to load pem certificate from \"%s\"\n", files[i]); + xmlSecKeysMngrDestroy(mngr); + return(NULL); + } + } + + return(mngr); +} + +/** + * verify_file: + * @mngr: the pointer to keys manager. + * @xml_file: the signed XML file name. + * + * Verifies XML signature in #xml_file. + * + * Returns 0 on success or a negative value if an error occurs. + */ +int +verify_file(xmlSecKeysMngrPtr mngr, const char* xml_file) { + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlSecDSigCtxPtr dsigCtx = NULL; + int res = -1; + + assert(mngr); + assert(xml_file); + + /* load file */ + doc = xmlParseFile(xml_file); + if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){ + fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_file); + goto done; + } + + /* find start node */ + node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs); + if(node == NULL) { + fprintf(stderr, "Error: start node not found in \"%s\"\n", xml_file); + goto done; + } + + /* create signature context */ + dsigCtx = xmlSecDSigCtxCreate(mngr); + if(dsigCtx == NULL) { + fprintf(stderr,"Error: failed to create signature context\n"); + goto done; + } + + /* limit the Reference URI attributes to empty or NULL */ + dsigCtx->enabledReferenceUris = xmlSecTransformUriTypeEmpty; + + /* limit allowed transforms for siganture and reference processing */ + if((xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformInclC14NId) < 0) || + (xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformExclC14NId) < 0) || + (xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformSha1Id) < 0) || + (xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformRsaSha1Id) < 0)) { + + fprintf(stderr,"Error: failed to limit allowed siganture transforms\n"); + goto done; + } + if((xmlSecDSigCtxEnableReferenceTransform(dsigCtx, xmlSecTransformInclC14NId) < 0) || + (xmlSecDSigCtxEnableReferenceTransform(dsigCtx, xmlSecTransformExclC14NId) < 0) || + (xmlSecDSigCtxEnableReferenceTransform(dsigCtx, xmlSecTransformSha1Id) < 0) || + (xmlSecDSigCtxEnableReferenceTransform(dsigCtx, xmlSecTransformEnvelopedId) < 0)) { + + fprintf(stderr,"Error: failed to limit allowed reference transforms\n"); + goto done; + } + + /* in addition, limit possible key data to valid X509 certificates only */ + if(xmlSecPtrListAdd(&(dsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecKeyDataX509Id) < 0) { + fprintf(stderr,"Error: failed to limit allowed key data\n"); + goto done; + } + + /* Verify signature */ + if(xmlSecDSigCtxVerify(dsigCtx, node) < 0) { + fprintf(stderr,"Error: signature verify\n"); + goto done; + } + + /* check that we have only one Reference */ + if((dsigCtx->status == xmlSecDSigStatusSucceeded) && + (xmlSecPtrListGetSize(&(dsigCtx->signedInfoReferences)) != 1)) { + + fprintf(stderr,"Error: only one reference is allowed\n"); + goto done; + } + + /* print verification result to stdout */ + if(dsigCtx->status == xmlSecDSigStatusSucceeded) { + fprintf(stdout, "Signature is OK\n"); + } else { + fprintf(stdout, "Signature is INVALID\n"); + } + + /* success */ + res = 0; + +done: + /* cleanup */ + if(dsigCtx != NULL) { + xmlSecDSigCtxDestroy(dsigCtx); + } + + if(doc != NULL) { + xmlFreeDoc(doc); + } + return(res); +} + + diff --git a/examples/xkms-server.c b/examples/xkms-server.c new file mode 100644 index 00000000..1021b182 --- /dev/null +++ b/examples/xkms-server.c @@ -0,0 +1,822 @@ +/** + * XML Security Library example: simple XKMS server + * + * Starts XKMS server on specified port. + * + * Usage: + * ./xkms-server [--port <port>] [--format plain|soap-1.1|soap-1.2] <keys-file> + * + * Example: + * ./xkms-server --port 8080 --format soap-1.1 keys.xml + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#ifdef XMLSEC_NO_XKMS + +int main(int argc, char** argv) { + fprintf(stderr, "ERROR: XKMS is disabled.\n"); + return 1; +} + +#else /* XMLSEC_NO_XKMS */ + +#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/buffer.h> +#include <xmlsec/xkms.h> +#include <xmlsec/crypto.h> + +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING +#include <xmlsec/app.h> +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + +#ifdef UNIX_SOCKETS +#include <netinet/in.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/tcp.h> +#include <netdb.h> +#include <fcntl.h> +#include <signal.h> +#else /* UNIX_SOCKETS */ +#ifdef WIN32_SOCKETS +#include <windows.h> +#include <winsock.h> +#else /* WIN32_SOCKETS */ +#error "Your operating system is not supported" +#endif /* WIN32_SOCKETS */ +#endif /* UNIX_SOCKETS */ + +#define DEFAULT_PORT 1234 +#define PENDING_QUEUE_SIZE 100 + +#define LOG_LEVEL_SILENT 0 +#define LOG_LEVEL_INFO 1 +#define LOG_LEVEL_DATA 2 +#define LOG_LEVEL_DEBUG 3 + +#ifdef UNIX_SOCKETS +static int sockfd = -1; +#endif /* UNIX_SOCKETS */ + +#ifdef WIN32_SOCKETS +static SOCKET sockfd = -1; +#endif /* WIN32_SOCKETS */ + +static int finished = 0; +static int log_level = LOG_LEVEL_INFO; + +static int init_server(unsigned short port); +static void stop_server(); +static void int_signal_handler(int sig_num); +static const xmlChar* my_strnstr(const xmlChar* str, xmlSecSize strLen, const xmlChar* tmpl, xmlSecSize tmplLen); + +static int handle_connection(int fd, xmlSecXkmsServerCtxPtr xkmsCtx, xmlSecXkmsServerFormat format); +static int read_request(int fd, const char* in_ip, xmlSecBufferPtr buffer); +static int send_response(int fd, const char* in_ip, int resp_code, + const char* body, int body_size); + +static char usage[] = "[--port <port>] [--format plain|soap-1.1|soap-1.2] <keys-file>"; +static char http_header[] = + "HTTP/1.0 %d\n" + "Server: XML Security Library: Simple XKMS Server/1.0\n" + "Content-length: %d\n" + "\n"; +static char http_503[] = + "Error 503 - Service Unavailable\n"; + +int main(int argc, char** argv) { + int argpos; + unsigned short port = DEFAULT_PORT; + xmlSecKeysMngrPtr mngr = NULL; + xmlSecXkmsServerCtxPtr xkmsCtx = NULL; + xmlSecXkmsServerFormat format = xmlSecXkmsServerFormatPlain; + int ret; + + fprintf(stdout, "Log: server is starting up\n"); + + /* 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 %d: xmlsec initialization failed.\n", errno); + return(-1); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stderr, "Error %d: loaded xmlsec library version is not compatible.\n", errno); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stderr, "Error %d: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n", errno); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* Init crypto library */ + if(xmlSecCryptoAppInit(NULL) < 0) { + fprintf(stderr, "Error %d: crypto initialization failed.\n", errno); + return(-1); + } + + /* Init xmlsec-crypto library */ + if(xmlSecCryptoInit() < 0) { + fprintf(stderr, "Error %d: xmlsec-crypto initialization failed.\n", errno); + return(-1); + } + + /* Create and initialize keys manager */ + mngr = xmlSecKeysMngrCreate(); + if(mngr == NULL) { + fprintf(stderr, "Error %d: failed to create keys manager.\n", errno); + goto done; + } + if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) { + fprintf(stderr, "Error %d: failed to initialize keys manager.\n", errno); + goto done; + } + + /* Create XKMS server context */ + xkmsCtx = xmlSecXkmsServerCtxCreate(mngr); + if(xkmsCtx == NULL) { + fprintf(stderr, "Error %d: XKMS server context initialization failed\n", errno); + goto done; + } + + /* Process input parameters */ + for(argpos = 1; (argpos < argc) && (argv[argpos][0] == '-'); argpos++) { + if((strcmp(argv[argpos], "--port") == 0) || (strcmp(argv[argpos], "-p") == 0)) { + argpos++; + port = atoi(argv[argpos]); + if(port == 0) { + fprintf(stderr, "Error %d: invalid port number \"%s\".\nUsage: %s %s\n", errno, argv[argpos], argv[0], usage); + goto done; + } + } else if((strcmp(argv[argpos], "--format") == 0) || (strcmp(argv[argpos], "-f") == 0)) { + argpos++; + format = xmlSecXkmsServerFormatFromString(BAD_CAST argv[argpos]); + if(format == xmlSecXkmsServerFormatUnknown) { + fprintf(stderr, "Error %d: invalid format \"%s\".\nUsage: %s %s\n", errno, argv[argpos], argv[0], usage); + goto done; + } + } else if((strcmp(argv[argpos], "--log-level") == 0) || (strcmp(argv[argpos], "-l") == 0)) { + argpos++; + log_level = atoi(argv[argpos]); + } else { + fprintf(stderr, "Error %d: unknown parameter \"%s\".\nUsage: %s %s\n", errno, argv[argpos], argv[0], usage); + goto done; + } + } + if(argpos >= argc) { + fprintf(stderr, "Error %d: keys file is not specified.\nUsage: %s %s\n", errno, argv[0], usage); + goto done; + } + + /* Load keys */ + for(; argpos < argc; argpos++) { + if(xmlSecCryptoAppDefaultKeysMngrLoad(mngr, argv[argpos]) < 0) { + fprintf(stderr, "Error %d: failed to load xml keys file \"%s\".\nUsage: %s %s\n", errno, argv[argpos], argv[0], usage); + goto done; + } + if(log_level >= LOG_LEVEL_INFO) { + fprintf(stdout, "Log: loaded keys from \"%s\"\n", argv[argpos]); + } + } + + /* Startup TCP server */ + if(init_server(port) < 0) { + fprintf(stderr, "Error, errno: server initialization failed\n", errno); + goto done; + } + assert(sockfd != -1); + + /* main loop: accept connections and process requests */ + while(finished == 0) { + fd_set fds; + struct timeval timeout; + + /* Set up polling using select() */ + FD_ZERO(&fds); + FD_SET(sockfd, &fds); + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_sec = 1; + ret = select(sockfd + 1, &fds, NULL, NULL, &timeout); + if((ret <= 0) || !FD_ISSET(sockfd, &fds)) { + /* error, timed out or not our socket: try again */ + continue; + } + + if(handle_connection(sockfd, xkmsCtx, format) < 0) { + fprintf(stderr, "Error %d: unable to accept incomming connection\n"); + goto done; + } + } + +done: + if(log_level >= LOG_LEVEL_INFO) { + fprintf(stdout, "Log: server is shutting down\n"); + } + + /* Shutdown TCP server */ + stop_server(); + + /* Destroy xkms server context */ + if(xkmsCtx != NULL) { + xmlSecXkmsServerCtxDestroy(xkmsCtx); + xkmsCtx = NULL; + } + + /* Destroy keys manager */ + if(mngr != NULL) { + xmlSecKeysMngrDestroy(mngr); + mngr = NULL; + } + + /* 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(); + + fprintf(stdout, "Log: server is down, bye!\n"); + return(0); +} + +/** + * init_server: + * @port: the server'xmlSecBufferGetData(buffer) TCP port number. + * + * Starts up a TCP server listening on given @port. + * + * Returns 0 on success or a negative value if an error occurs. + */ +static int +init_server(unsigned short port) { +#ifdef WIN32_SOCKETS + WSADATA data; +#endif /* WIN32_SOCKETS */ + struct sockaddr_in saddr; + int flags; + +#ifdef WIN32_SOCKETS + if(WSAStartup(MAKEWORD(1,1), &data)) { + fprintf(stderr, "Error %d: WSAStartup() failed\n", errno); + return(-1); + } +#endif /* WIN32_SOCKETS */ + + /* create socket */ + sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); +#ifdef UNIX_SOCKETS + if(sockfd == -1) { +#endif /* UNIX_SOCKETS */ + +#ifdef WIN32_SOCKETS + if(sockfd == INVALID_SOCKET) { +#endif /* WIN32_SOCKETS */ + + fprintf(stderr, "Error %d: socket() failed\n", errno); + return(-1); + } + + /* enable reuse of address */ + flags = 1; + if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&flags, sizeof(flags)) != 0) { + fprintf(stderr, "Error %d: setsockopt(SO_REUSEADDR) failed\n", errno); + return(-1); + } + +#ifdef UNIX_SOCKETS + /* set non-blocking */ + flags = fcntl(sockfd, F_GETFL); + if(flags < 0) { + fprintf(stderr, "Error %d: fcntl(F_GETFL) failed\n", errno); + return(-1); + } + if(fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) { + fprintf(stderr, "Error %d: fcntl(F_SETFL) failed\n", errno); + return(-1); + } +#endif /* UNIX_SOCKETS */ + + /* preset socket structure for socket binding */ + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_port = htons(port); + saddr.sin_addr.s_addr = INADDR_ANY; + if(bind(sockfd, (struct sockaddr *)&saddr, sizeof(struct sockaddr)) != 0) { + fprintf(stderr, "Error %d: bind() failed\n", errno); + return(-1); + } + + /* prepare for listening */ + if(listen(sockfd, PENDING_QUEUE_SIZE) != 0) { + fprintf(stderr, "Error %d: listen() failed\n", errno); + return(-1); + } + +#ifdef UNIX_SOCKETS + /* setup SIGINT handler that will stop the server */ + signal(SIGINT, int_signal_handler); +#endif /* UNIX_SOCKETS */ + + if(log_level >= LOG_LEVEL_INFO) { + fprintf(stdout, "Log: server is ready and listening on port %d\n", port); + } + return(0); +} + +/** + * stop_server: + * + * Shuts down TCP server. + */ +static void +stop_server() { +#ifdef UNIX_SOCKETS + if(sockfd != -1) { + shutdown(sockfd, SHUT_RDWR); + close(sockfd); + sockfd = -1; + } +#endif /* UNIX_SOCKETS */ + +#ifdef WIN32_SOCKETS + if(sockfd != -1) { + close(sockfd); + sockfd = -1; + } +#endif /* WIN32_SOCKETS */ + if(log_level >= LOG_LEVEL_INFO) { + fprintf(stdout, "Log: server is shutted down\n"); + } +} + +/** + * int_signal_handler: + * @sig_num: the signal number. + * + * Unix's Ctrl-C signal handler that stops the server. + */ +static void +int_signal_handler(int sig_num) { + if(log_level >= LOG_LEVEL_INFO) { + fprintf(stdout, "Log: server is asked to shutdown\n"); + } + finished = 1; +} + +/** + * handle_connection: + * @sockfd: the server's socket. + * @xkmsCtx: the template XKMS server context. + * @format: the expected format of XKMS requests. + * + * Establishs a connection, forks a child process (onUnix), reads the request, + * processes it and writes back the response. + * + * Returns 0 on success or a negative value if an error occurs. + */ +static int +handle_connection(int sockfd, xmlSecXkmsServerCtxPtr xkmsCtx, xmlSecXkmsServerFormat format) { +#ifdef UNIX_SOCKETS + int fd = -1; +#endif /* UNIX_SOCKETS */ + +#ifdef WIN32_SOCKETS + SOCKET fd = -1; +#endif /* WIN32_SOCKETS */ + + int in_child_process = 0; + struct sockaddr_in saddr; + int saddr_size; + xmlSecXkmsServerCtxPtr xkmsCtx2 = NULL; + xmlSecBufferPtr buffer = NULL; + xmlDocPtr inDoc = NULL; + xmlDocPtr outDoc = NULL; + xmlNodePtr result = NULL; + xmlOutputBufferPtr output = NULL; + int resp_ready = 0; + int ret; + + assert(sockfd != -1); + assert(xkmsCtx != NULL); + + /* Get the socket connection */ + saddr_size = sizeof(struct sockaddr_in); + fd = accept(sockfd, (struct sockaddr *)&saddr, &saddr_size); + +#ifdef UNIX_SOCKETS + if(sockfd == -1) { +#endif /* UNIX_SOCKETS */ + +#ifdef WIN32_SOCKETS + if(sockfd == INVALID_SOCKET) { +#endif /* WIN32_SOCKETS */ + + fprintf(stderr, "Error %d: accept() failed\n", errno); + return(-1); + } + if(log_level >= LOG_LEVEL_INFO) { + fprintf(stdout, "Log [%s]: got connection\n", inet_ntoa(saddr.sin_addr)); + } + + /* Create a copy of XKMS server context */ + xkmsCtx2 = xmlSecXkmsServerCtxCreate(NULL); + if(xkmsCtx2 == NULL) { + fprintf(stderr, "Error %d [%s]: a copy of XKMS server context initialization failed\n", errno, inet_ntoa(saddr.sin_addr)); + goto done; + } + if(xmlSecXkmsServerCtxCopyUserPref(xkmsCtx2, xkmsCtx) < 0) { + fprintf(stderr, "Error %d [%s]: XKMS server context copy failed\n", errno, inet_ntoa(saddr.sin_addr)); + goto done; + } + +#ifdef UNIX_SOCKETS + /* on Unix we use child process to process requests */ + if(fork()) { + /* parent process */ + return(0); + } + + /* child process */ + in_child_process = 1; + close(sockfd); /* we don't need listening socket */ +#endif /* UNIX_SOCKETS */ + + buffer = xmlSecBufferCreate(0); + if(buffer == NULL) { + fprintf(stderr, "Error %d [%s]: xmlSecBufferCreate() failed\n", errno, inet_ntoa(saddr.sin_addr)); + goto done; + } + + /* read input request */ + ret = read_request(fd, inet_ntoa(saddr.sin_addr), buffer); + if(ret < 0) { + fprintf(stderr, "Error %d [%s]: read_request() failed\n", errno, inet_ntoa(saddr.sin_addr)); + goto done; + } + + /* parse request */ + inDoc = xmlParseMemory(xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer) ); + if((inDoc == NULL) || (xmlDocGetRootElement(inDoc) == NULL)) { + fprintf(stderr, "Error %d [%s]: failed to parse request\n", errno, inet_ntoa(saddr.sin_addr)); + goto done; + } + xmlSecBufferEmpty(buffer); + + /* prepare result document */ + outDoc = xmlNewDoc(BAD_CAST "1.0"); + if(outDoc == NULL) { + fprintf(stderr, "Error %d [%s]: failed to create result doc\n", errno, inet_ntoa(saddr.sin_addr)); + goto done; + } + + result = xmlSecXkmsServerCtxProcess(xkmsCtx2, xmlDocGetRootElement(inDoc), format, outDoc); + if(result == NULL) { + fprintf(stderr, "Error %d [%s]: failed to process xkms server request\n", errno, inet_ntoa(saddr.sin_addr)); + goto done; + } + + /* apppend returned result node to the output document */ + xmlDocSetRootElement(outDoc, result); + + /* create LibXML2 output buffer */ + output = xmlSecBufferCreateOutputBuffer(buffer); + if(output == NULL) { + fprintf(stderr, "Error %d [%s]: xmlSecBufferCreateOutputBuffer() failed\n", errno, inet_ntoa(saddr.sin_addr)); + goto done; + } + xmlNodeDumpOutput(output, result->doc, result, 0, 0, NULL); + + xmlOutputBufferClose(output); output = NULL; + resp_ready = 1; +done: + /* send back response */ + if((resp_ready == 1) && (xmlSecBufferGetData(buffer) != NULL)) { + ret = send_response(fd, inet_ntoa(saddr.sin_addr), 200, xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer)); + if(log_level >= LOG_LEVEL_INFO) { + fprintf(stdout, "Log [%s]: processed request\n", inet_ntoa(saddr.sin_addr)); + } + } else if(fd >= 0) { + ret = send_response(fd, inet_ntoa(saddr.sin_addr), 503, http_503, strlen(http_503)); + if(log_level >= LOG_LEVEL_INFO) { + fprintf(stdout, "Log [%s]: failed to process request\n", inet_ntoa(saddr.sin_addr)); + } + } else { + ret = -1; + } + if(ret < 0) { + fprintf(stderr, "Error %d [%s]: send_response() failed\n", errno, inet_ntoa(saddr.sin_addr)); + } + + /* cleanup */ + if(output != NULL) { + xmlOutputBufferClose(output); + output = NULL; + } + + if(outDoc != NULL) { + xmlFreeDoc(outDoc); + outDoc = NULL; + } + + if(inDoc != NULL) { + xmlFreeDoc(inDoc); + inDoc = NULL; + } + + if(buffer != NULL) { + xmlSecBufferDestroy(buffer); + buffer = NULL; + } + + if(xkmsCtx2 != NULL) { + xmlSecXkmsServerCtxDestroy(xkmsCtx2); + xkmsCtx2 = NULL; + } + + if(fd >= 0) { +#ifdef UNIX_SOCKETS + shutdown(fd, SHUT_RDWR); + close(fd); +#endif /* UNIX_SCOKETS */ + +#ifdef WIN32_SOCKETS + close(fd); +#endif /* WIN32_SCOKETS */ + + fd = -1; + } + + if(in_child_process) { + exit(0); + } + return(0); +} + +/** + * read_request: + * @fd: the request's socket. + * @in_ip: the request's IP address (for logging). + * @buffer: the output buffer. + * + * Reads the request from socket @fd and stores it in the @buffer. + * + * Returns 0 on success or a negative value if an error occurs. + */ +static int +read_request(int fd, const char* in_ip, xmlSecBufferPtr buffer) { + char buf[1024]; + const xmlChar* s; + const xmlChar* p; + int nread; + int length = 0; + int found = 0; + int counter; + + assert(fd != -1); + assert(in_ip != NULL); + assert(buffer); + + /* first read the http headers */ + counter = 5; + while(my_strnstr(xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer), BAD_CAST "\r\n\r\n", 4) == NULL) { + nread = recv(fd, buf, sizeof(buf), 0); + if(nread < 0) { + fprintf(stderr, "Error %d [%s]: read() failed\n", errno, in_ip); + return(-1); + } + + if((nread > 0) && (xmlSecBufferAppend(buffer, buf, nread) < 0)) { + fprintf(stderr, "Error %d [%s]: xmlSecBufferAppend(%d) failed\n", errno, in_ip, nread); + return(-1); + } + + if(nread < sizeof(buffer)) { + counter--; + if(counter <= 0) { + break; + } + } + } + + if(xmlSecBufferGetData(buffer) == NULL) { + fprintf(stderr, "Error %d [%s]: no bytes read\n", errno, in_ip); + return(-1); + } + + if(log_level >= LOG_LEVEL_DEBUG) { + xmlSecBufferAppend(buffer, BAD_CAST "\0", 1); + fprintf(stdout, "Debug [%s]: request headers:\n%s\n", in_ip, xmlSecBufferGetData(buffer)); + xmlSecBufferRemoveTail(buffer, 1); + } + + /* Parse the request and extract the body. We expect the request to look + * like this: + * POST <path> HTTP/1.x\r\n + * <header1>\r\n + * <header2>\r\n + * ... + * <headerN>\r\n + * \r\n + * <body> + */ + + /* analyze the first line */ + p = my_strnstr(xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer), BAD_CAST "\r\n", 2); + if(p == NULL) { + fprintf(stderr, "Error %d [%s]: there is no HTTP header\n", errno, in_ip); + return(-1); + } + if(xmlStrncasecmp(xmlSecBufferGetData(buffer), BAD_CAST "POST ", 5) != 0) { + fprintf(stderr, "Error %d [%s]: not a POST request\n", errno, in_ip); + return(-1); + } + /* "POST " + " HTTP/1.x" == 14 */ + s = xmlSecBufferGetData(buffer); + if(p - s <= 14) { + fprintf(stderr, "Error %d [%s]: first line has bad length\n", errno, in_ip); + return(-1); + } + if((xmlStrncasecmp(p - 9, BAD_CAST " HTTP/1.0", 9) != 0) && + (xmlStrncasecmp(p - 9, BAD_CAST " HTTP/1.1", 9) != 0)) { + + fprintf(stderr, "Error %d [%s]: first line does not end with \" HTTP/1.x\"\n", errno, in_ip); + return(-1); + } + if(xmlSecBufferRemoveHead(buffer, p - xmlSecBufferGetData(buffer) + 2) < 0) { + fprintf(stderr, "Error %d [%s]: failed to skip first line\n", errno, in_ip); + return(-1); + } + + /* now skip all the headers (i.e. everything until empty line) */ + found = 0; + while(!found) { + p = my_strnstr(xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer), BAD_CAST "\r\n", 2); + if(p == NULL) { + fprintf(stderr, "Error %d [%s]: there is no HTTP body\n", errno, in_ip); + return(-1); + } + + if(p == xmlSecBufferGetData(buffer)) { + found = 1; + } else if(xmlStrncasecmp(xmlSecBufferGetData(buffer), BAD_CAST "Content-length: ", 16) == 0) { + length = atoi(xmlSecBufferGetData(buffer) + 16); + } + + if(xmlSecBufferRemoveHead(buffer, p - xmlSecBufferGetData(buffer) + 2) < 0) { + fprintf(stderr, "Error %d [%s]: failed to skip header line\n", errno, in_ip); + return(-1); + } + } + + /* remove the trailing \0 we added */ + xmlSecBufferRemoveTail(buffer, 1); + + /* now read the body */ + counter = 5; + while(xmlSecBufferGetSize(buffer) < length) { + nread = recv(fd, buf, sizeof(buf), 0); + if(nread < 0) { + fprintf(stderr, "Error %d [%s]: read() failed\n", errno, in_ip); + return(-1); + } + + if((nread > 0) && (xmlSecBufferAppend(buffer, buf, nread) < 0)) { + fprintf(stderr, "Error %d [%s]: xmlSecBufferAppend(%d) failed\n", errno, in_ip, nread); + return(-1); + } + if(nread < sizeof(buffer)) { + counter--; + if(counter <= 0) { + break; + } + } + } + if(log_level >= LOG_LEVEL_INFO) { + fprintf(stdout, "Log [%s]: body size is %d bytes\n", in_ip, xmlSecBufferGetSize(buffer)); + } + if(log_level >= LOG_LEVEL_DATA) { + xmlSecBufferAppend(buffer, BAD_CAST "\0", 1); + fprintf(stdout, "Log [%s]: request body:\n%s\n", in_ip, xmlSecBufferGetData(buffer)); + xmlSecBufferRemoveTail(buffer, 1); + } + return(0); +} + +/** + * send_response: + * @fd: the request's socket. + * @in_ip: the request's IP address (for logging). + * @resp_code: the HTTP response code. + * @body: the response body. + * @body_len: the response body length. + * + * Writes HTTP response headers and @body to the @socket. + * + * Returns 0 on success or a negative value if an error occurs. + */ +static int +send_response(int fd, const char* in_ip, int resp_code, const char* body, int body_size) { + char header[sizeof(http_header) + 100]; + + assert(fd != -1); + assert(in_ip != NULL); + assert(resp_code > 0); + assert(body != NULL); + + /* prepare and send http header */ + sprintf(header, http_header, resp_code, body_size); + if(send(fd, header, strlen(header), 0) == -1) { + fprintf(stderr, "Error %d [%s]: send(header) failed\n", errno, in_ip); + return(-1); + } + + if(log_level >= LOG_LEVEL_DATA) { + xmlChar* tmp = xmlStrndup(body, body_size); + fprintf(stdout, "Log [%s]: response is\n%s\n", in_ip, tmp); + xmlFree(tmp); + } + + /* send body */ + if(send(fd, body, body_size, 0) == -1) { + fprintf(stderr, "Error %d [%s]: send(body) failed\n", errno, in_ip); + return(-1); + } + + return(0); +} + +/** + * my_strnstr: + * @str: the soruce string. + * @strLen: the source string length. + * @tmpl: the template string. + * @tmplLen: the template string length. + * + * Searches for the first occurence of @tmpl in @str. + * + * Returns pointer to the first occurence of @tmpl in @str or NULL if it is not found. + */ +static const xmlChar* +my_strnstr(const xmlChar* str, xmlSecSize strLen, const xmlChar* tmpl, xmlSecSize tmplLen) { + xmlSecSize pos; + + if((str == NULL) || (tmpl == NULL)) { + return(NULL); + } + for(pos = 0; pos + tmplLen <= strLen; pos++) { + if(xmlStrncmp(str + pos, tmpl, tmplLen) == 0) { + return(str + pos); + } + } + + return(NULL); +} + +#endif /* XMLSEC_NO_XKMS */ + diff --git a/examples/xmldsigverify.c b/examples/xmldsigverify.c new file mode 100644 index 00000000..a4c9f532 --- /dev/null +++ b/examples/xmldsigverify.c @@ -0,0 +1,363 @@ +/** + * XML Security Library example: CGI verification script. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <dirent.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/crypto.h> + +/* #define XMLDSIGVERIFY_DEFAULT_TRUSTED_CERTS_FOLDER "/etc/httpd/conf/ssl.crt" */ +#define XMLDSIGVERIFY_DEFAULT_TRUSTED_CERTS_FOLDER "/var/www/cgi-bin/keys-certs.def" +#define XMLDSIGVERIFY_KEY_AND_CERTS_FOLDER "/var/www/cgi-bin/keys-certs" + + +int load_keys(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_keys); +int load_trusted_certs(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_certs); +int verify_request(xmlSecKeysMngrPtr mngr); +int url_decode(char *buf, size_t size); + +int +main(int argc, char **argv) { + xmlSecKeysMngrPtr mngr; + + /* start response */ + fprintf(stdout, "Content-type: text/plain\n"); + fprintf(stdout, "\n"); + + /* 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 */ + + /* make sure that we print out everything to stdout */ + xmlGenericErrorContext = stdout; + + /* Init xmlsec library */ + if(xmlSecInit() < 0) { + fprintf(stdout, "Error: xmlsec initialization failed.\n"); + return(-1); + } + + /* Check loaded library version */ + if(xmlSecCheckVersion() != 1) { + fprintf(stdout, "Error: loaded xmlsec library version is not compatible.\n"); + return(-1); + } + + /* Load default crypto engine if we are supporting dynamic + * loading for xmlsec-crypto libraries. Use the crypto library + * name ("openssl", "nss", etc.) to load corresponding + * xmlsec-crypto library. + */ +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + fprintf(stdout, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH) envornment variable.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* Init crypto library */ + if(xmlSecCryptoAppInit(XMLDSIGVERIFY_DEFAULT_TRUSTED_CERTS_FOLDER) < 0) { + fprintf(stdout, "Error: crypto initialization failed.\n"); + return(-1); + } + + /* Init xmlsec-crypto library */ + if(xmlSecCryptoInit() < 0) { + fprintf(stdout, "Error: xmlsec-crypto initialization failed.\n"); + return(-1); + } + + /* create keys manager */ + mngr = xmlSecKeysMngrCreate(); + if(mngr == NULL) { + fprintf(stdout, "Error: failed to create keys manager.\n"); + return(-1); + } + if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) { + fprintf(stdout, "Error: failed to initialize keys manager.\n"); + return(-1); + } + + if(load_keys(mngr, XMLDSIGVERIFY_KEY_AND_CERTS_FOLDER, 0) < 0) { + xmlSecKeysMngrDestroy(mngr); + return(-1); + } + + if(load_trusted_certs(mngr, XMLDSIGVERIFY_KEY_AND_CERTS_FOLDER, 0) < 0) { + xmlSecKeysMngrDestroy(mngr); + return(-1); + } + + if(verify_request(mngr) < 0) { + xmlSecKeysMngrDestroy(mngr); + return(-1); + } + + /* Destroy keys manager */ + xmlSecKeysMngrDestroy(mngr); + + /* 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); +} + +/** + * load_trusted_certs: + * @mngr: the keys manager. + * @path: the path to a folder that contains trusted certificates. + * + * Loads trusted certificates from @path. + * + * Returns 0 on success or a negative value if an error occurs. + */ +int load_trusted_certs(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_certs) { + DIR* dir; + struct dirent* entry; + char filename[256]; + int len; + + assert(mngr); + assert(path); + + dir = opendir(path); + if(dir == NULL) { + fprintf(stdout, "Error: failed to open folder \"%s\".\n", path); + return(-1); + } + while((entry = readdir(dir)) != NULL) { + assert(entry->d_name); + len = strlen(entry->d_name); + if((len > 4) && (strcmp(entry->d_name + len - 4, ".pem") == 0)) { + snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name); + if(xmlSecCryptoAppKeysMngrCertLoad(mngr, filename, xmlSecKeyDataFormatPem, xmlSecKeyDataTypeTrusted) < 0) { + fprintf(stdout,"Error: failed to load pem certificate from \"%s\"\n", filename); + closedir(dir); + return(-1); + } + if(report_loaded_certs) { + fprintf(stdout, "Loaded trusted certificate from \"%s\"...\n", filename); + } + } else if((len > 4) && (strcmp(entry->d_name + len - 4, ".der") == 0)) { + snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name); + if(xmlSecCryptoAppKeysMngrCertLoad(mngr, filename, xmlSecKeyDataFormatDer, xmlSecKeyDataTypeTrusted) < 0) { + fprintf(stdout,"Error: failed to load der certificate from \"%s\"\n", filename); + closedir(dir); + return(-1); + } + if(report_loaded_certs) { + fprintf(stdout, "Loaded trusted certificate from \"%s\"...\n", filename); + } + } + } + closedir(dir); + return(0); +} + +int load_keys(xmlSecKeysMngrPtr mngr, const char* path, int report_loaded_keys) { + char filename[256]; + + assert(mngr); + + snprintf(filename, sizeof(filename), "%s/keys.xml", path); + if(xmlSecCryptoAppDefaultKeysMngrLoad(mngr, filename) < 0) { + fprintf(stdout,"Error: failed to load keys from \"%s\"\n", filename); + return(-1); + } + + if(report_loaded_keys) { + fprintf(stdout, "Loaded keys from \"%s\"...\n", filename); + } + return(0); +} + + +/** + * verify_request: + * @mng: the keys manager + * + * Verifies XML signature in the request (stdin). + * + * Returns 0 on success or a negative value if an error occurs. + */ +int +verify_request(xmlSecKeysMngrPtr mngr) { + xmlBufferPtr buffer = NULL; + char buf[256]; + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlSecDSigCtxPtr dsigCtx = NULL; + int ret; + int res = -1; + + assert(mngr); + + /* load request in the buffer */ + buffer = xmlBufferCreate(); + if(buffer == NULL) { + fprintf(stdout,"Error: failed to create buffer\n"); + goto done; + } + + while(!feof(stdin)) { + ret = fread(buf, 1, sizeof(buf), stdin); + if(ret < 0) { + fprintf(stdout,"Error: read failed\n"); + goto done; + } + xmlBufferAdd(buffer, buf, ret); + } + + /* is the document subbmitted from the form? */ + if(strncmp((char*)xmlBufferContent(buffer), "_xmldoc=", 8) == 0) { + xmlBufferShrink(buffer, 8); + buffer->use = url_decode((char*)xmlBufferContent(buffer), xmlBufferLength(buffer)); + } + + /** + * Load doc + */ + doc = xmlReadMemory(xmlBufferContent(buffer), xmlBufferLength(buffer), + NULL, NULL, + XML_PARSE_NOENT | XML_PARSE_NOCDATA | + XML_PARSE_PEDANTIC | XML_PARSE_NOCDATA); + if (doc == NULL) { + fprintf(stdout, "Error: unable to parse xml document (syntax error)\n"); + goto done; + } + + /* + * Check the document is of the right kind + */ + if(xmlDocGetRootElement(doc) == NULL) { + fprintf(stdout,"Error: empty document\n"); + goto done; + } + + /* find start node */ + node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs); + if(node == NULL) { + fprintf(stdout, "Error: start <dsig:Signature/> node not found\n"); + goto done; + } + + /* create signature context */ + dsigCtx = xmlSecDSigCtxCreate(mngr); + if(dsigCtx == NULL) { + fprintf(stdout,"Error: failed to create signature context\n"); + goto done; + } + + /* we would like to store and print out everything */ + /* actually we would not because it opens a security hole + dsigCtx->flags = XMLSEC_DSIG_FLAGS_STORE_SIGNEDINFO_REFERENCES | + XMLSEC_DSIG_FLAGS_STORE_MANIFEST_REFERENCES | + XMLSEC_DSIG_FLAGS_STORE_SIGNATURE; + */ + + /* Verify signature */ + if(xmlSecDSigCtxVerify(dsigCtx, node) < 0) { + fprintf(stdout,"Error: signature verification failed\n"); + goto done; + } + + /* print verification result to stdout */ + if(dsigCtx->status == xmlSecDSigStatusSucceeded) { + fprintf(stdout, "RESULT: Signature is OK\n"); + } else { + fprintf(stdout, "RESULT: Signature is INVALID\n"); + } + fprintf(stdout, "---------------------------------------------------\n"); + xmlSecDSigCtxDebugDump(dsigCtx, stdout); + + /* success */ + res = 0; + +done: + /* cleanup */ + if(dsigCtx != NULL) { + xmlSecDSigCtxDestroy(dsigCtx); + } + + if(doc != NULL) { + xmlFreeDoc(doc); + } + + if(buffer != NULL) { + xmlBufferFree(buffer); + } + return(res); +} + +/* not the best way to do it */ +#define toHex(c) ( ( ('0' <= (c)) && ((c) <= '9') ) ? (c) - '0' : \ + ( ( ('A' <= (c)) && ((c) <= 'F') ) ? (c) - 'A' + 10 : 0 ) ) + +/** + * url_decode: + * @buf: the input buffer. + * @size: the input buffer size. + * + * Does url decoding in-place. + * + * Returns length of the decoded result on success or + * a negative value if an error occurs. + */ +int url_decode(char *buf, size_t size) { + char *p1, *p2; + + assert(buf); + + p1 = p2 = buf; + while(p1 - buf < size) { + if(((*p1) == '%') && ((p1 - buf) <= (size - 3))) { + *(p2++) = (char)(toHex(p1[1]) * 16 + toHex(p1[2])); + p1 += 3; + } else if((*p1) == '+') { + *(p2++) = ' '; + p1++; + } else { + *(p2++) = *(p1++); + } + } + return(p2 - buf); +} + + |