From fd7c2c579f6b10531f1aad4c75ebfadc03652e90 Mon Sep 17 00:00:00 2001 From: m0gg Date: Wed, 29 Nov 2006 11:04:24 +0000 Subject: Message encryption added --- doc/Doxyfile.api | 4 +- examples/csoap/simpleclient.c | 30 +-- libcsoap/soap-addressing.c | 29 ++- libcsoap/soap-addressing.h | 5 +- libcsoap/soap-client.c | 72 ++++++- libcsoap/soap-client.h | 47 ++++- libcsoap/soap-nudp.c | 22 ++- libcsoap/soap-server.c | 47 +++-- libcsoap/soap-server.h | 26 ++- libcsoap/soap-transport.c | 23 ++- libcsoap/soap-xmlsec.c | 443 +++++++++++++++++------------------------- libcsoap/soap-xmlsec.h | 68 ++++++- 12 files changed, 482 insertions(+), 334 deletions(-) diff --git a/doc/Doxyfile.api b/doc/Doxyfile.api index ae52f80..0614bb7 100644 --- a/doc/Doxyfile.api +++ b/doc/Doxyfile.api @@ -1005,7 +1005,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = +PREDEFINED = __CSOAP_INTERNAL=1 __NHTTP_INTERNAL=1 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. @@ -1141,7 +1141,7 @@ INCLUDED_BY_GRAPH = YES # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. -CALL_GRAPH = NO +CALL_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. diff --git a/examples/csoap/simpleclient.c b/examples/csoap/simpleclient.c index 03beaae..757b2cf 100644 --- a/examples/csoap/simpleclient.c +++ b/examples/csoap/simpleclient.c @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: simpleclient.c,v 1.19 2006/11/28 23:45:57 m0gg Exp $ + * $Id: simpleclient.c,v 1.20 2006/11/29 11:04:24 m0gg Exp $ * * CSOAP Project: CSOAP examples project * Copyright (C) 2003-2004 Ferhat Ayaz @@ -24,12 +24,14 @@ #include #include +#include #include #include #include #include +#include #include static char *url = "http://localhost:10000/csoapserver"; @@ -39,7 +41,8 @@ static char *method = "sayHello"; int main(int argc, char **argv) { - struct SoapCtx *ctx, *ctx2; + struct SoapCtx *request; + struct SoapCtx *response; herror_t err; // hlog_set_level(HLOG_VERBOSE); @@ -52,7 +55,7 @@ main(int argc, char **argv) exit(1); } - err = soap_ctx_new_with_method(urn, method, &ctx); + err = soap_ctx_new_with_method(urn, method, &request); if (err != H_OK) { printf("%s():%s [%d]\n", herror_func(err), herror_message(err), herror_code(err)); @@ -60,28 +63,27 @@ main(int argc, char **argv) exit(1); } - soap_env_add_item(ctx->env, "xsd:string", "name", "Jonny B. Good"); - - printf("**** sending ****\n"); - xmlDocDump(stderr, ctx->env->root->doc); + soap_env_add_item(request->env, "xsd:string", "name", "Jonny B. Good"); if (argc > 1) url = argv[1]; - printf("destination: \"%s\"\n", url); - if ((err = soap_client_invoke(ctx, &ctx2, url, "")) != H_OK) + printf("**** sending to \"%s\" ****\n", url); + xmlDocFormatDump(stderr, request->env->root->doc, 1); + + if ((err = soap_client_invoke(request, &response, url, "")) != H_OK) { printf("[%d] %s(): %s\n", herror_code(err), herror_func(err), herror_message(err)); herror_release(err); - soap_ctx_free(ctx); + soap_ctx_free(request); exit(1); } - printf("**** received ****\n"); - xmlDocDump(stdout, ctx2->env->root->doc); + printf("**** received from \"%s\" ****\n", soap_addressing_get_from_address_string(response->env)); + xmlDocFormatDump(stdout, response->env->root->doc, 1); - soap_ctx_free(ctx2); - soap_ctx_free(ctx); + soap_ctx_free(response); + soap_ctx_free(request); soap_client_destroy(); diff --git a/libcsoap/soap-addressing.c b/libcsoap/soap-addressing.c index cde31ec..8cb11b8 100644 --- a/libcsoap/soap-addressing.c +++ b/libcsoap/soap-addressing.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: soap-addressing.c,v 1.8 2006/11/28 23:45:57 m0gg Exp $ +* $Id: soap-addressing.c,v 1.9 2006/11/29 11:04:24 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2006 Heiko Ronsdorf @@ -423,12 +423,6 @@ soap_addressing_set_reply_to_address(struct SoapEnv *envelope, xmlURI *address) return ret; } -xmlNodePtr -soap_addressing_get_from(struct SoapEnv *envelope) -{ - return _soap_addressing_get_child_element(envelope->header, WSA_FROM); -} - xmlNodePtr soap_addressing_set_from(struct SoapEnv *envelope, xmlNodePtr address) { @@ -463,6 +457,12 @@ soap_addressing_set_from_address_string(struct SoapEnv *envelope, const char *fr return ret; } +xmlNodePtr +soap_addressing_get_from(struct SoapEnv *envelope) +{ + return _soap_addressing_get_child_element(envelope->header, WSA_FROM); +} + xmlURI * soap_addressing_get_from_address(struct SoapEnv *envelope) { @@ -475,6 +475,21 @@ soap_addressing_get_from_address(struct SoapEnv *envelope) return soap_addressing_get_address(from); } +xmlChar * +soap_addressing_get_from_address_string(struct SoapEnv *envelope) +{ + xmlURI *uri; + xmlChar *ret; + + if (!(uri = soap_addressing_get_from_address(envelope))) + return NULL; + + ret = xmlSaveUri(uri); + xmlFreeURI(uri); + + return ret; +} + xmlNodePtr soap_addressing_set_from_address(struct SoapEnv *envelope, xmlURI *address) { diff --git a/libcsoap/soap-addressing.h b/libcsoap/soap-addressing.h index fa04038..fb31286 100644 --- a/libcsoap/soap-addressing.h +++ b/libcsoap/soap-addressing.h @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: soap-addressing.h,v 1.8 2006/11/28 23:45:57 m0gg Exp $ + * $Id: soap-addressing.h,v 1.9 2006/11/29 11:04:24 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2006 Heiko Ronsdorf @@ -37,7 +37,7 @@ * in a transport-neutral manner. * * @author H. Ronsdorf - * @version $Revision: 1.8 $ + * @version $Revision: 1.9 $ * * @see http://www.w3.org/TR/ws-addr-core/, * http://www.w3.org/TR/REC-xml-names/ @@ -230,6 +230,7 @@ xmlNodePtr soap_addressing_set_reply_to_address(struct SoapEnv *envelope, xmlURI xmlNodePtr soap_addressing_get_from(struct SoapEnv *envelope); xmlURI *soap_addressing_get_from_address(struct SoapEnv *envelope); +xmlChar *soap_addressing_get_from_address_string(struct SoapEnv *envelope); xmlNodePtr soap_addressing_set_from(struct SoapEnv *envelope, xmlNodePtr address); xmlNodePtr soap_addressing_set_from_address(struct SoapEnv *envelope, xmlURI *address); diff --git a/libcsoap/soap-client.c b/libcsoap/soap-client.c index 416054c..cf2479f 100644 --- a/libcsoap/soap-client.c +++ b/libcsoap/soap-client.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: soap-client.c,v 1.32 2006/11/28 23:45:57 m0gg Exp $ +* $Id: soap-client.c,v 1.33 2006/11/29 11:04:24 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -25,6 +25,10 @@ #include #endif +#ifdef HAVE_STRING_H +#include +#endif + #include #include @@ -43,12 +47,48 @@ #endif #include "soap-client.h" +#ifdef HAVE_XMLSEC1 +static int _soap_client_force_sign = 0; +static int _soap_client_force_verify = 0; +static int _soap_client_force_encrypt = 0; +static int _soap_client_force_decrypt = 0; + +static inline void +_soap_client_parse_arguments(int argc, char **argv) +{ + int i; + + for (i=0; ienv->root->doc); + log_verbose1("********************"); *response = soap_ctx_new(NULL); +#ifdef HAVE_XMLSEC1 + if ((err = soap_xmlsec_verify(request)) != H_OK) + { + log_error2("soap_xmlsec_verify failed (%s)", herror_message(err)); + sprintf(buffer, "Verification of message signature failed (%s)", herror_message(err)); + + _soap_server_env_new_with_fault("Internal server error", buffer, &((*response)->env)); + return H_OK; + } + + if ((err = soap_xmlsec_decrypt(request)) != H_OK) + { + log_error2("soap_xmlsec_decrypt failed (%s)", herror_message(err)); + sprintf(buffer, "Decryption of message body failed (%s)", herror_message(err)); + _soap_server_env_new_with_fault("Internal server error", buffer, &((*response)->env)); + return H_OK; + } +#endif + if ((method = soap_env_find_methodname(request->env))) { log_verbose2("method: \"%s\"", method); @@ -215,7 +224,13 @@ soap_server_process(struct SoapCtx *request, struct SoapCtx **response) _soap_server_fillup_header((*response)->env); - return _soap_server_xmlsec_sign((*response)->env); +#ifdef HAVE_XMLSEC1 + soap_xmlsec_encrypt(*response); + + soap_xmlsec_sign(*response); +#endif + + return H_OK; } herror_t diff --git a/libcsoap/soap-server.h b/libcsoap/soap-server.h index cafa9a5..afb3a3a 100644 --- a/libcsoap/soap-server.h +++ b/libcsoap/soap-server.h @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: soap-server.h,v 1.13 2006/11/23 15:27:33 m0gg Exp $ + * $Id: soap-server.h,v 1.14 2006/11/29 11:04:25 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -24,6 +24,30 @@ #ifndef __csoap_server_h #define __csoap_server_h +/** + * + * @mainpage Project overview + * + * @section seq_intro Introduction + * + * cSOAP is a client/server SOAP library implemented in pure C. It comes with + * embedded transport servers for UDP and HTTP (nanohttp). The transferred XML + * structures are handled by libxml2. + * + * @section seq_features Features + * + * - different transport services + * -- client/server HTTP transport service (with SSL) + * -- client/server UDP transport service (multicast) + * - attachments via MIME + * - message based security (encryption/signation) + * - automatic generation of WS-Inspection + * + * @author Ferhat Ayaz + * @version $Revision: 1.14 $ + * + */ + #ifdef __cplusplus extern "C" { #endif diff --git a/libcsoap/soap-transport.c b/libcsoap/soap-transport.c index 7d54ced..5cbdc46 100644 --- a/libcsoap/soap-transport.c +++ b/libcsoap/soap-transport.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: soap-transport.c,v 1.6 2006/11/28 23:45:57 m0gg Exp $ +* $Id: soap-transport.c,v 1.7 2006/11/29 11:04:25 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2007 Heiko Ronsdorf @@ -84,7 +84,7 @@ _soap_transport_new(const char *scheme, void *data, msg_exchange invoke) ret->data = data; ret->invoke = invoke; - log_verbose4("scheme=%s, data=%p, invoke=%p", ret->scheme, ret->data, ret->invoke); + log_verbose4("scheme=\"%s\", data=%p, invoke=%p", ret->scheme, ret->data, ret->invoke); return ret; } @@ -268,15 +268,26 @@ soap_transport_client_invoke(struct SoapCtx *request, struct SoapCtx **response) herror_t ret; xmlURI *dest; - log_verbose1(__FUNCTION__); - xmlDocFormatDump(stdout, request->env->root->doc, 1); + // log_verbose1(__FUNCTION__); + // xmlDocFormatDump(stdout, request->env->root->doc, 1); - dest = soap_addressing_get_to_address(request->env); + if (!(dest = soap_addressing_get_to_address(request->env))) + { + log_verbose1("soap_addressing_get_to_address failed"); + return herror_new("soap_transport_client_invoke", 0, "cannot find to address in SOAP envelope"); + } + + if (!dest->scheme) + { + log_verbose1("missing scheme (protocol) in to address"); + return herror_new("soap_transport_client_invoke", 0, "cannot find protocol in destination address"); + } log_verbose2("trying to contact \"%s\"", soap_addressing_get_to_address_string(request->env)); - for (walker = head; walker; walker = walker->next) + for (walker=head; walker; walker=walker->next) { + log_verbose3("testing transport server \"%s\" for \"%s\"", walker->scheme, dest->scheme); if (!strcmp(walker->scheme, dest->scheme)) { log_verbose3("found transport layer for \"%s\" (%p)", dest->scheme, walker->invoke); diff --git a/libcsoap/soap-xmlsec.c b/libcsoap/soap-xmlsec.c index 75cc187..55c341b 100644 --- a/libcsoap/soap-xmlsec.c +++ b/libcsoap/soap-xmlsec.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: soap-xmlsec.c,v 1.4 2006/11/28 23:45:57 m0gg Exp $ +* $Id: soap-xmlsec.c,v 1.5 2006/11/29 11:04:25 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -118,213 +118,14 @@ static void _soap_xmlsec_error_callback(const char *file, int line, const char * /** * - * decrypt_file: + * Lookups key in the @store. The caller is responsible for destroying returned + * key with #xmlSecKeyDestroy function. * - * @mngr: the pointer to keys manager. - * @enc_file: the encrypted XML file name. + * @param store the pointer to simple keys store. + * @param name the desired key name. + * @param keyInfoCtx the pointer to node processing context. * - * 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. - * - */ -static int _soap_xmlsec_decrypt_file(xmlSecKeysMngrPtr mngr, const char *enc_file) -{ - xmlDocPtr doc = NULL; - xmlNodePtr node = NULL; - xmlSecEncCtxPtr encCtx = NULL; - int res = -1; - - /* 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, "*** after decryption ***\n"); - xmlDocFormatDump(stdout, doc, 1); - fprintf(stdout, "************************\n"); - - } - 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); -} - -static int _soap_xmlsec_encrypt_file(xmlSecKeysMngrPtr mngr, const char *enc_file, const char *key_name) -{ - xmlDocPtr doc = NULL; - xmlNodePtr encDataNode = NULL; - xmlNodePtr keyInfoNode = NULL; - xmlNodePtr encKeyNode = NULL; - xmlNodePtr keyInfoNode2 = NULL; - xmlSecEncCtxPtr encCtx = NULL; - - doc = xmlParseFile(enc_file); - if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)) - { - log_error2("xmlParseFile failed (%s)", enc_file); - return -1; - } - - fprintf(stdout, "*** before encryption ***\n"); - xmlDocFormatDump(stdout, doc, 1); - fprintf(stdout, "*************************\n"); - - encDataNode = xmlSecTmplEncDataCreate(doc, xmlSecTransformDes3CbcId, NULL, xmlSecTypeEncElement, NULL, NULL); - if (encDataNode == NULL) - { - log_error1("xmlSecTmplEnvDataCreate failed"); - return -1; - } - - if (xmlSecTmplEncDataEnsureCipherValue(encDataNode) == NULL) - { - log_error1("failed to add CipherValue node"); - return -1; - } - - keyInfoNode = xmlSecTmplEncDataEnsureKeyInfo(encDataNode, NULL); - if (keyInfoNode == NULL) - { - log_error1("failed to add KeyInfo node"); - return -1; - } - - encKeyNode = xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode, xmlSecTransformRsaOaepId, NULL, NULL, NULL); - if (encKeyNode == NULL) - { - log_error1("failed to add KeyInfo"); - return -1; - } - - if (xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == NULL) - { - log_error1("failed to add CipherValue node"); - return -1; - } - - keyInfoNode2 = xmlSecTmplEncDataEnsureKeyInfo(encKeyNode, NULL); - if (keyInfoNode2 == NULL) - { - log_error1("failed to add key info (2)\n"); - return -1; - } - - // log_error2("adding key \"%s\"", key_name); - if (xmlSecTmplKeyInfoAddKeyName(keyInfoNode2, key_name) == NULL) - { - - log_error1("failed to add key name"); - return -1; - } - - encCtx = xmlSecEncCtxCreate(mngr); - if (encCtx == NULL) - { - log_error1("failed to create encryption context"); - return -1; - } - - encCtx->encKey = xmlSecKeyGenerate(xmlSecKeyDataDesId, 192, xmlSecKeyDataTypeSession); - if (encCtx->encKey == NULL) - { - log_error1("failed to generate session key"); - return -1; - } - - fprintf(stdout, "*** before encryption ***\n"); - xmlDocFormatDump(stdout, doc, 1); - fprintf(stdout, "*************************\n"); - - if (xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, xmlDocGetRootElement(doc)) < 0) - // if (xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, get_soap_body_content(xmlDocGetRootElement(doc))) < 0) - { - log_error1("encryption failed"); - return -1; - } - - { - FILE *fp; - - fp = fopen("test-enc-new.xml", "w"); - xmlDocDump(fp, doc); - fclose(fp); - } - fprintf(stdout, "*** after encryption ***\n"); - xmlDocFormatDump(stdout, doc, 1); - fprintf(stdout, "************************\n"); - - if (encCtx != NULL) - xmlSecEncCtxDestroy(encCtx); - - if (encDataNode != NULL) - xmlFreeNode(encDataNode); - - if (doc != NULL) - xmlFreeDoc(doc); - - return 0; -} - -/** - * - * files_keys_store_find_key: - * - * @store: the pointer to simple keys store. - * @name: the desired key name. - * @keyInfoCtx: the pointer to 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. + * @return pointer to key or NULL if key not found or an error occurs. * */ static xmlSecKeyPtr @@ -334,11 +135,12 @@ _soap_xmlsec_files_keys_store_find_key(xmlSecKeyStorePtr store, const xmlChar * xmlURI *uri; char *file; - fprintf(stderr, "trying to find key \"%s\"\n", name); + log_info2("trying to find key \"%s\"\n", name); /* - * it's possible to do not have the key name or desired key type * - * but we could do nothing in this case + * 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) { @@ -488,7 +290,7 @@ _soap_xmlsec_create_key_manager(void) if (keysStore == NULL) { log_error1("failed to create keys store"); - return herror_new("_soap_xmlxec_create_key_manager", 0, "failed to create keys store"); + return herror_new("_soap_xmlxec_create_key_manager", XMLSEC_ERROR_KEYSTORE, "failed to create keys store"); } /* create keys manager */ @@ -496,7 +298,7 @@ _soap_xmlsec_create_key_manager(void) { log_error1("failed to create keys manager"); xmlSecKeyStoreDestroy(keysStore); - return herror_new("_soap_xmlsec_key_manager", 0, "failed to create keys manager"); + return herror_new("_soap_xmlsec_key_manager", XMLSEC_ERROR_KEYMANAGER, "failed to create keys manager"); } /* @@ -509,7 +311,7 @@ _soap_xmlsec_create_key_manager(void) xmlSecKeyStoreDestroy(keysStore); xmlSecKeysMngrDestroy(_soap_xmlsec_key_manager); _soap_xmlsec_key_manager = NULL; - return herror_new("_soap_xmlsec_create_key_manager", 0, "failed to add keys store to keys manager"); + return herror_new("_soap_xmlsec_create_key_manager", XMLSEC_ERROR_KEYMANAGER, "failed to add keys store to keys manager"); } /* initialize crypto library specific data in keys manager */ @@ -518,7 +320,7 @@ _soap_xmlsec_create_key_manager(void) log_error1("failed to initialize crypto data in keys manager"); xmlSecKeysMngrDestroy(_soap_xmlsec_key_manager); _soap_xmlsec_key_manager = NULL; - return herror_new("_soap_xmlsec_create_key_manager", 0, "failed to initialize crypto data in keys manager"); + return herror_new("_soap_xmlsec_create_key_manager", XMLSEC_ERROR_KEYMANAGER, "failed to initialize crypto data in keys manager"); } /* set the get key callback */ @@ -536,7 +338,7 @@ _soap_xmlsec_load_key(void) if ((_soap_xmlsec_key = xmlSecCryptoAppKeyLoad(_soap_xmlsec_keyfile, xmlSecKeyDataFormatPem, _soap_xmlsec_password, NULL, NULL)) == NULL) { log_error2("xmlSecCryptoAppKeyLoad(\"%s\") failed", _soap_xmlsec_keyfile); - return herror_new("_soap_xmlsec_load_key", 0, "xmlSecCryptoAppKeyLoad(\"%s\") failed", _soap_xmlsec_keyfile); + return herror_new("_soap_xmlsec_load_key", XMLSEC_ERROR_KEY, "xmlSecCryptoAppKeyLoad(\"%s\") failed", _soap_xmlsec_keyfile); } if (_soap_xmlsec_certfile) @@ -545,7 +347,7 @@ _soap_xmlsec_load_key(void) { log_error2("xmlSecCryptoAppKeyCertLoad(\"%s\") failed", _soap_xmlsec_certfile); xmlSecKeyDestroy(_soap_xmlsec_key); - return herror_new("_soap_xmlsec_load_key", 0, "xmlSecCryptoAppKeyCertLoad(\"%s\") failed", _soap_xmlsec_certfile); + return herror_new("_soap_xmlsec_load_key", XMLSEC_ERROR_CERTIFICATE, "xmlSecCryptoAppKeyCertLoad(\"%s\") failed", _soap_xmlsec_certfile); } } @@ -555,11 +357,11 @@ _soap_xmlsec_load_key(void) { xmlSecKeyDestroy(_soap_xmlsec_key); log_error3("xmlSecKeySetName(\"%s\") failed (%i)", keyName, err); - return herror_new("_soap_xmlsec_load_key", 0, "xmlSecKeySetName(\"%s\") failed (%i)", keyName, err); + return herror_new("_soap_xmlsec_load_key", XMLSEC_ERROR_KEY, "xmlSecKeySetName(\"%s\") failed (%i)", keyName, err); } - xmlSecKeyDebugXmlDump(_soap_xmlsec_key, stdout); - xmlSecKeyDataDebugXmlDump(xmlSecKeyGetValue(_soap_xmlsec_key), stdout); +// xmlSecKeyDebugXmlDump(_soap_xmlsec_key, stdout); +// xmlSecKeyDataDebugXmlDump(xmlSecKeyGetValue(_soap_xmlsec_key), stdout); return H_OK; } @@ -647,13 +449,13 @@ _soap_xmlsec_init(void) if (xmlSecInit() < 0) { log_error1("xmlSecInit failed"); - return herror_new("soap_xmlsec_init", 0, "xmlSecInit failed"); + return herror_new("soap_xmlsec_init", XMLSEC_ERROR_INIT, "xmlSecInit failed"); } if (xmlSecCheckVersion() != 1) { log_error1("xmlSecCheckVersion failed, wrong xmlsec version"); - return herror_new("soap_xmlsec_init", 0, "Wrong xmlsec version"); + return herror_new("soap_xmlsec_init", XMLSEC_ERROR_VERSION, "Wrong xmlsec version"); } #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING @@ -661,20 +463,20 @@ _soap_xmlsec_init(void) if (xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { log_error1("xmlSecCryptoDLLoadLibrary failed"); - return herror_new("soap_xmlsec_init", 0, "xmlSecCryptoDLLoadLibrary failed"); + return herror_new("soap_xmlsec_init", XMLSEC_ERROR_DLLOAD, "xmlSecCryptoDLLoadLibrary failed"); } #endif if (xmlSecCryptoAppInit(NULL) < 0) { log_error1("xmlSecCryptoAppInit failed"); - return herror_new("soap_xmlsec_init", 0, "xmlSecCryptoAppInit failed"); + return herror_new("soap_xmlsec_init", XMLSEC_ERROR_INIT, "xmlSecCryptoAppInit failed"); } if (xmlSecCryptoInit() < 0) { log_error1("xmlSecCryptoInit failed"); - return herror_new("soap_xmlsec_init", 0, "xmlSecCryptoInit failed"); + return herror_new("soap_xmlsec_init", XMLSEC_ERROR_INIT, "xmlSecCryptoInit failed"); } if ((status = _soap_xmlsec_create_key_manager()) != H_OK) @@ -686,7 +488,7 @@ _soap_xmlsec_init(void) if ((err = pthread_mutex_init(&_soap_xmlsec_lock, NULL)) < 0) { log_error2("pthread_mutex_init failed (%s)", strerror(err)); - return herror_new("soap_xmlsec_init", 0, "pthread_mutex_init failed (%s)", strerror(err)); + return herror_new("soap_xmlsec_init", XMLSEC_ERROR_INIT, "pthread_mutex_init failed (%s)", strerror(err)); } if ((status = _soap_xmlsec_load_key()) != H_OK) @@ -759,7 +561,7 @@ herror_t soap_xmlsec_sign(struct SoapCtx *context) if (!(signNode = xmlSecTmplSignatureCreate(envelope->root->doc, xmlSecTransformExclC14NId, xmlSecTransformRsaSha1Id, NULL))) { log_error1("xmlSecTmplSignatureCreate failed"); - ret = herror_new("soap_xmlsec_sign", 0, "xmlSecTmplSignatureCreate failed"); + ret = herror_new("soap_xmlsec_sign", XMLSEC_ERROR_SIGN_INIT, "xmlSecTmplSignatureCreate failed"); goto out; } @@ -777,28 +579,28 @@ herror_t soap_xmlsec_sign(struct SoapCtx *context) if (!(refNode = xmlSecTmplSignatureAddReference(signNode, xmlSecTransformSha1Id, "#Body", NULL, NULL))) { log_error1("xmlSecTmplSignatureAddReference failed"); - ret = herror_new("soap_xmlsec_sign", 0, "xmlSecTmplSignatureAddReference failed"); + ret = herror_new("soap_xmlsec_sign", XMLSEC_ERROR_SIGN_INIT, "xmlSecTmplSignatureAddReference failed"); goto out; } if (!(keyInfoNode = xmlSecTmplSignatureEnsureKeyInfo(signNode, NULL))) { log_error1("xmlSecTmplSignatureEnsureKeyInfo failed"); - ret = herror_new("soap_xmlsec_sign", 0, "xmlSecTmplSignatureEnsureKeyInfo failed"); + ret = herror_new("soap_xmlsec_sign", XMLSEC_ERROR_SIGN_INIT, "xmlSecTmplSignatureEnsureKeyInfo failed"); goto out; } if (xmlSecTmplKeyInfoAddKeyName(keyInfoNode, soap_server_get_name()) == NULL) { log_error1("xmlSecTmplKeyInfoAddKeyName failed"); - ret = herror_new("soap_xmlsec_sign", 0, "xmlSecTmplKeyInfoAddKeyName failed"); + ret = herror_new("soap_xmlsec_sign", XMLSEC_ERROR_SIGN_INIT, "xmlSecTmplKeyInfoAddKeyName failed"); goto out; } if (!(dsigCtx = xmlSecDSigCtxCreate(_soap_xmlsec_key_manager))) { log_error1("xmlSecDSigCtxCreate failed"); - ret = herror_new("soap_xmlsec_sign", 0, "xmlSecDSigCtxCreate failed"); + ret = herror_new("soap_xmlsec_sign", XMLSEC_ERROR_SIGN_INIT, "xmlSecDSigCtxCreate failed"); goto out; } @@ -807,7 +609,7 @@ herror_t soap_xmlsec_sign(struct SoapCtx *context) if (xmlSecDSigCtxSign(dsigCtx, signNode) < 0) { log_error1("xmlSecDSigCtxSign failed"); - ret = herror_new("soap_xmlsec_sign", 0, "xmlSecDSigCtxSign failed"); + ret = herror_new("soap_xmlsec_sign", XMLSEC_ERROR_SIGN, "xmlSecDSigCtxSign failed"); goto out; } @@ -821,6 +623,7 @@ out: herror_t soap_xmlsec_encrypt(struct SoapCtx *context) { struct SoapEnv *envelope; + herror_t ret; xmlNodePtr encDataNode = NULL; xmlNodePtr keyInfoNode = NULL; xmlNodePtr encKeyNode = NULL; @@ -833,55 +636,70 @@ herror_t soap_xmlsec_encrypt(struct SoapCtx *context) if (!_soap_xmlsec_enabled) return H_OK; + ret = H_OK; + + pthread_mutex_lock(&_soap_xmlsec_lock); + envelope = context->env; doc = context->env->root->doc; - fprintf(stdout, "*** before encryption ***\n"); - xmlDocFormatDump(stdout, doc, 1); - fprintf(stdout, "*************************\n"); + // fprintf(stdout, "*** before encryption ***\n"); + // xmlDocFormatDump(stdout, doc, 1); + // fprintf(stdout, "*************************\n"); encDataNode = xmlSecTmplEncDataCreate(doc, xmlSecTransformDes3CbcId, NULL, xmlSecTypeEncElement, NULL, NULL); if (encDataNode == NULL) { log_error1("xmlSecTmplEnvDataCreate failed"); - return herror_new("soap_xmlsec_encrypt", 0, "xmlSecTmplEnvDataCreate failed"); + ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "xmlSecTmplEnvDataCreate failed"); + goto out; } if (xmlSecTmplEncDataEnsureCipherValue(encDataNode) == NULL) { log_error1("failed to add CipherValue node"); - return herror_new("soap_xmlsec_encrypt", 0, "failed to add CipherValue node"); + ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to add CipherValue node"); + goto out; } keyInfoNode = xmlSecTmplEncDataEnsureKeyInfo(encDataNode, NULL); if (keyInfoNode == NULL) { log_error1("failed to add KeyInfo node"); - return herror_new("soap_xmlsec_encrypt", 0, "failed to add KeyInfo node"); + ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to add KeyInfo node"); + goto out; } encKeyNode = xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode, xmlSecTransformRsaOaepId, NULL, NULL, NULL); if (encKeyNode == NULL) { log_error1("failed to add KeyInfo"); - return herror_new("soap_xmlsec_encrypt", 0, "failed to add KeyInfo"); + ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to add KeyInfo"); + goto out; } if (xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == NULL) { log_error1("failed to add CipherValue node"); - return herror_new("soap_xmlsec_encrypt", 0, "failed to add CipherValue node"); + ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to add CipherValue node"); + goto out; } keyInfoNode2 = xmlSecTmplEncDataEnsureKeyInfo(encKeyNode, NULL); if (keyInfoNode2 == NULL) { log_error1("failed to add key info (2)\n"); - return herror_new("soap_xmlsec_enrypt", 0, "failed to add key info (2)"); + ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to add key info (2)"); + goto out; } - to = soap_addressing_get_to_address(envelope); + if (!(to = soap_addressing_get_to_address(envelope))) + { + log_error1("cannot get to address"); + ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT, "cannot get to address"); + goto out; + } xmlStrPrintf(buf, 256, "http://%s:%i/key.pem", to->server, to->port); log_error2("adding key \"%s\"", buf); xmlFreeURI(to); @@ -889,76 +707,175 @@ herror_t soap_xmlsec_encrypt(struct SoapCtx *context) if (xmlSecTmplKeyInfoAddKeyName(keyInfoNode2, buf) == NULL) { log_error2("failed to add key name \"%s\"", buf); - return herror_new("soap_xmlsec_encrypt", 0, "failed to add key name \"%s\"", buf); + ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to add key name \"%s\"", buf); + goto out; } encCtx = xmlSecEncCtxCreate(_soap_xmlsec_key_manager); if (encCtx == NULL) { log_error1("failed to create encryption context"); - return herror_new("soap_xmlsec_encrypt", 0, "failed to create encryption context"); + ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to create encryption context"); + goto out; } encCtx->encKey = xmlSecKeyGenerate(xmlSecKeyDataDesId, 192, xmlSecKeyDataTypeSession); if (encCtx->encKey == NULL) { log_error1("failed to generate session key"); - return herror_new("soap_xmlsec_encrypt", 0, "failed to generate session key"); + ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to generate session key"); + goto out; } - fprintf(stdout, "*** before encryption ***\n"); - xmlDocFormatDump(stdout, doc, 1); - fprintf(stdout, "*************************\n"); + // fprintf(stdout, "*** before encryption ***\n"); + // xmlDocFormatDump(stdout, doc, 1); + // fprintf(stdout, "*************************\n"); if (xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, soap_env_get_method(envelope)) < 0) - // if (xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, get_soap_body_content(xmlDocGetRootElement(doc))) < 0) { log_error1("encryption failed"); - return herror_new("soap_xmlsec_encrypt", 0, "encryption failed"); + ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT, "encryption failed"); + goto out; } -/* { - FILE *fp; - - fp = fopen("test-enc-new.xml", "w"); - xmlDocDump(fp, doc); - fclose(fp); - } */ + // fprintf(stdout, "*** after encryption ***\n"); + // xmlDocFormatDump(stdout, doc, 1); + // fprintf(stdout, "************************\n"); - fprintf(stdout, "*** after encryption ***\n"); - xmlDocFormatDump(stdout, doc, 1); - fprintf(stdout, "************************\n"); +out: if (encCtx != NULL) xmlSecEncCtxDestroy(encCtx); - return H_OK; + pthread_mutex_unlock(&_soap_xmlsec_lock); + + return ret; } herror_t soap_xmlsec_decrypt(struct SoapCtx *context) { struct SoapEnv *envelope; + herror_t ret; + xmlNodePtr method; + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlSecEncCtxPtr encCtx = NULL; if (!_soap_xmlsec_enabled) return H_OK; + ret = H_OK; + envelope = context->env; - log_error1("not implemented"); - return herror_new("soap_xmlsec_decrupt", 0, "not implemented"); + if (!(method = soap_env_get_method(envelope))) + { + log_error1("cannot find messages method"); + return herror_new("soap_xmlsec_decrypt", 0, "cannot find message method"); + } + + if (xmlStrcmp(method->name, BAD_CAST "EncryptedData")) + { + log_error2("message doesn't contain encrypted data (%s)", method->name); + return H_OK; + } + + if (xmlStrcmp(method->ns->href, "http://www.w3.org/2001/04/xmlenc#")) + { + log_error2("message encryption isn't understood (%s)", method->ns->href); + return herror_new("soap_xmlsec_decrypt", 0, "message encryption isn't understood (%s)", method->ns->href); + } + + doc = envelope->root->doc; + + /* XXX already checked... */ + node = xmlSecFindNode(envelope->root, xmlSecNodeEncryptedData, xmlSecEncNs); + if (node == NULL) + { + log_error1("start node not found"); + ret = herror_new("soap_xmlsec_decrypt", 0, "start node not found"); + goto done; + } + + /* create encryption context */ + encCtx = xmlSecEncCtxCreate(_soap_xmlsec_key_manager); + if (encCtx == NULL) + { + log_error1("failed to create encryption context"); + ret = herror_new("soap_xmlsec_decrypt", 0, "failed to create encryption context"); + goto done; + } + + /* decrypt the data */ + if ((xmlSecEncCtxDecrypt(encCtx, node) < 0) || (encCtx->result == NULL)) + { + log_error1("decryption failed"); + ret = herror_new("soap_xmlsec_decrypt", 0, "decryption failed"); + goto done; + } + + /* print decrypted data to stdout */ + /* if (encCtx->resultReplaced != 0) + { + fprintf(stdout, "*** after decryption ***\n"); + xmlDocFormatDump(stdout, doc, 1); + fprintf(stdout, "************************\n"); + } + 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"); */ + +done: + + if (encCtx != NULL) + { + xmlSecEncCtxDestroy(encCtx); + } + + return ret; } herror_t soap_xmlsec_verify(struct SoapCtx *context) { struct SoapEnv *envelope; + xmlNodePtr walker; if (!_soap_xmlsec_enabled) return H_OK; envelope = context->env; - log_error1("not implemented"); - return herror_new("soap_xmlsec_verify", 0, "not implemented"); + if (!envelope->header) + { + log_error1("message doesn't contain a SOAP header"); + return herror_new("soap_xmlsec_verify", 0, "message doesn't contain a SOAP header"); + } + + for (walker=envelope->header->children; walker; walker=walker->next) + { + if (walker->type == XML_ELEMENT_NODE) + { + if (!xmlStrcmp(walker->name, "Signature")) + { + if (!xmlStrcmp(walker->ns->href, "http://schemas.xmlsoap.org/soap/security/2000-12")) + { + /* XXX do it */ + } + else + { + log_error2("message signature isn't understood (%s)", walker->ns->href); + return herror_new("soap_xmlsec_verify", 0, "message signature isn't understood (%s)", walker->ns->href); + } + } + } + } + return H_OK; } void soap_xmlsec_destroy(void) diff --git a/libcsoap/soap-xmlsec.h b/libcsoap/soap-xmlsec.h index 9943498..4a6209c 100644 --- a/libcsoap/soap-xmlsec.h +++ b/libcsoap/soap-xmlsec.h @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: soap-xmlsec.h,v 1.3 2006/11/28 23:45:57 m0gg Exp $ + * $Id: soap-xmlsec.h,v 1.4 2006/11/29 11:04:25 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2006 Heiko Ronsdorf @@ -31,7 +31,7 @@ * This module is implemented using the xmlsec1 library. * * @author H. Ronsdorf - * @version $Revision: 1.3 $ + * @version $Revision: 1.4 $ * * @see http://www.w3.org/TR/SOAP-dsig/, * http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wss, @@ -71,6 +71,20 @@ */ #define CSOAP_XMLSEC_CERTFILE "-CSOAPcertfile" +#define XMLSEC_ERROR 5100 +#define XMLSEC_ERROR_GENERIC (XMLSEC_ERROR + 0) +#define XMLSEC_ERROR_KEYSTORE (XMLSEC_ERROR + 10) +#define XMLSEC_ERROR_KEYMANAGER (XMLSEC_ERROR + 20) +#define XMLSEC_ERROR_KEY (XMLSEC_ERROR + 30) +#define XMLSEC_ERROR_CERTIFICATE (XMLSEC_ERROR + 40) +#define XMLSEC_ERROR_INIT (XMLSEC_ERROR + 50) +#define XMLSEC_ERROR_VERSION (XMLSEC_ERROR + 60) +#define XMLSEC_ERROR_DLLOAD (XMLSEC_ERROR + 70) +#define XMLSEC_ERROR_SIGN (XMLSEC_ERROR + 80) +#define XMLSEC_ERROR_SIGN_INIT (XMLSEC_ERROR + 90) +#define XMLSEC_ERROR_ENCRYPT (XMLSEC_ERROR + 100) +#define XMLSEC_ERROR_ENCRYPT_INIT (XMLSEC_ERROR + 110) + #ifdef __cplusplus extern "C" { #endif @@ -101,24 +115,68 @@ extern herror_t soap_xmlsec_client_init_args(int argc, char **argv); /** * - * Sign a XML document contained in a SOAP Envelope. The key specified on the - * commandline is used for signating the document. + * Sign a XML document contained in a SOAP Envelope with the key specified on + * the commandline. Our way to create a header entry is as + * follows: + * + * # Prepare the target SOAP Envelope with the body and necessary headers. + * # Create a template of a element. The template is assumed to + * contain empty contents for or elements, + * but contains appropriate values for the elements such as + * and required to calculate them. + * # Create a new header entry and add the template to this + * entry. + * # Add the header entry to the SOAP Header. + * # Add the SOAP "actor" and "mustUnderstand" attributes to the entry, if + * necessary. + * # Calculate the and elements according + * to the core generation of the XML-Signature specification. + * + * XPath filtering can be used to specify objects to be signed, as described in + * the XML-Signature specification. However, since the SOAP message exchange + * model allows intermediate applications to modify the Envelope (add or delete + * a header entry, for example), XPath filtering does not always result in the + * same objects after message delivery. Care should be taken in using XPath + * filtering so that there is no subsequent validation failure due to such + * modifications. + * + * The transform http://www.w3.org/2000/09/xmldsig#enveloped-signature defined + * in the XML-Signature specification may be useful when signing the entire + * Envelope including other header entries, if any. * * @param envelope The SOAP envelope to be signed. * * @return H_OK on success * + * @see http://www.w3.org/TR/SOAP-dsig/, + * http://www.w3.org/TR/xmldsig-core/ + * */ extern herror_t soap_xmlsec_sign(struct SoapCtx *context); /** * - * Verify a XML documents signature contained in a SOAP Envelope. + * Verify a XML documents signature contained in a SOAP Envelope. The validation + * of a header entry fails if: + * + * # The syntax of the content of the header entry does not conform to SOAP + * Security Extensions: Digital Signature specification, or + * # The validation of the signature contained in the header entry fails + * according to the core validation of the XML-Signature specification, or + * # The receiving application program rejects the signature for some reason + * (e.g., the signature is created by an untrusted key). + * + * If the validation of the signature header entry fails, applications MAY report + * the failure to the sender. It is out of the scope of this library how to deal + * with it. * * @param envelope The SOAP envelope to be verified. * * @return H_OK on success * + * @see http://www.w3.org/TR/SOAP-dsig/, + * http://www.w3.org/TR/xmldsig-core/ + * */ extern herror_t soap_xmlsec_verify(struct SoapCtx *context); -- cgit v1.1-32-gdbae