From 9a0670ad01e00ab01cfb4f308f1b124941968fa2 Mon Sep 17 00:00:00 2001 From: m0gg Date: Tue, 28 Nov 2006 23:45:57 +0000 Subject: XML signature improvements --- libcsoap/soap-addressing.c | 4 +- libcsoap/soap-addressing.h | 6 +- libcsoap/soap-client.c | 67 +++- libcsoap/soap-env.h | 3 +- libcsoap/soap-nhttp.c | 8 +- libcsoap/soap-server.c | 21 +- libcsoap/soap-transport.c | 37 +- libcsoap/soap-xmlsec.c | 830 ++++++++++++++++++++++++++++++++++++++++++--- libcsoap/soap-xmlsec.h | 84 ++++- 9 files changed, 975 insertions(+), 85 deletions(-) (limited to 'libcsoap') diff --git a/libcsoap/soap-addressing.c b/libcsoap/soap-addressing.c index 2069bd7..cde31ec 100644 --- a/libcsoap/soap-addressing.c +++ b/libcsoap/soap-addressing.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: soap-addressing.c,v 1.7 2006/11/26 20:13:05 m0gg Exp $ +* $Id: soap-addressing.c,v 1.8 2006/11/28 23:45:57 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2006 Heiko Ronsdorf @@ -451,7 +451,7 @@ soap_addressing_set_from(struct SoapEnv *envelope, xmlNodePtr address) } xmlNodePtr -soap_addressing_set_from_string(struct SoapEnv *envelope, const char *from) +soap_addressing_set_from_address_string(struct SoapEnv *envelope, const char *from) { xmlURI *uri; xmlNodePtr ret; diff --git a/libcsoap/soap-addressing.h b/libcsoap/soap-addressing.h index 7b6aed1..fa04038 100644 --- a/libcsoap/soap-addressing.h +++ b/libcsoap/soap-addressing.h @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: soap-addressing.h,v 1.7 2006/11/27 12:47:27 m0gg Exp $ + * $Id: soap-addressing.h,v 1.8 2006/11/28 23:45:57 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.7 $ + * @version $Revision: 1.8 $ * * @see http://www.w3.org/TR/ws-addr-core/, * http://www.w3.org/TR/REC-xml-names/ @@ -233,7 +233,7 @@ xmlURI *soap_addressing_get_from_address(struct SoapEnv *envelope); xmlNodePtr soap_addressing_set_from(struct SoapEnv *envelope, xmlNodePtr address); xmlNodePtr soap_addressing_set_from_address(struct SoapEnv *envelope, xmlURI *address); -xmlNodePtr soap_addressing_set_from_string(struct SoapEnv *envelope, const char *from); +xmlNodePtr soap_addressing_set_from_address_string(struct SoapEnv *envelope, const char *from); xmlNodePtr soap_addressing_get_fault_to(struct SoapEnv *envelope); xmlURI *soap_addressing_get_fault_to_address(struct SoapEnv *envelope); diff --git a/libcsoap/soap-client.c b/libcsoap/soap-client.c index 5d34f8f..416054c 100644 --- a/libcsoap/soap-client.c +++ b/libcsoap/soap-client.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: soap-client.c,v 1.31 2006/11/25 15:06:57 m0gg Exp $ +* $Id: soap-client.c,v 1.32 2006/11/28 23:45:57 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -38,12 +38,31 @@ #include "soap-service.h" #include "soap-router.h" #include "soap-transport.h" +#ifdef HAVE_XMLSEC1 +#include "soap-xmlsec.h" +#endif #include "soap-client.h" herror_t soap_client_init_args(int argc, char **argv) { - return soap_transport_client_init_args(argc, argv); + herror_t status; + +#ifdef HAVE_XMLSEC1 + if ((status = soap_xmlsec_client_init_args(argc, argv)) != H_OK) + { + log_error2("soap_xmlsec_client_init_args failed (%s)", herror_message(status)); + return status; + } +#endif + + if ((status = soap_transport_client_init_args(argc, argv)) != H_OK) + { + log_error2("soap_transport_client_init_args failed (%s)", herror_message(status)); + return status; + } + + return H_OK; } void @@ -57,6 +76,7 @@ soap_client_destroy(void) herror_t soap_client_invoke(struct SoapCtx *req, struct SoapCtx **res, const char *url, const char *action) { + herror_t status; char *id; log_verbose2("action = \"%s\"", action); @@ -65,10 +85,49 @@ soap_client_invoke(struct SoapCtx *req, struct SoapCtx **res, const char *url, c log_verbose2("url = \"%s\"", url); soap_addressing_set_to_address_string(req->env, url); + log_verbose2("from = \"%s\"", soap_transport_get_name()); + soap_addressing_set_from_address_string(req->env, soap_transport_get_name()); + soap_addressing_set_message_id_string(req->env, NULL); id = soap_addressing_get_message_id_string(req->env); - log_verbose2("message id = \"%s\"", id); + log_verbose2("generated message id = \"%s\"", id); free(id); - return soap_transport_client_invoke(req, res); +#ifdef HAVE_XMLSEC1 + log_error1("trying encryption and signation"); + + if ((status = soap_xmlsec_encrypt(req)) != H_OK) + { + log_error2("soap_xmlsec_encrypt failed (%s)", herror_message(status)); + return status; + } + + if ((status = soap_xmlsec_sign(req)) != H_OK) + { + log_error2("soap_xmlsec_sign failed (%s)", herror_message(status)); + return status; + } +#endif + + if ((status = soap_transport_client_invoke(req, res)) != H_OK) + { + log_error2("soap_transport_client_invoke failed (%s)", herror_message(status)); + return status; + } + +#ifdef HAVE_XMLSEC1 + if ((status = soap_xmlsec_verify(*res)) != H_OK) + { + log_error2("soap_xmlsec_verify failed (%s)", herror_message(status)); + return status; + } + + if ((status = soap_xmlsec_decrypt(*res)) != H_OK) + { + log_error2("soap_xmlsec_decrypt failed (%s)", herror_message(status)); + return status; + } +#endif + + return H_OK; } diff --git a/libcsoap/soap-env.h b/libcsoap/soap-env.h index d1c0d3e..45f013a 100644 --- a/libcsoap/soap-env.h +++ b/libcsoap/soap-env.h @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: soap-env.h,v 1.19 2006/11/27 10:49:57 m0gg Exp $ + * $Id: soap-env.h,v 1.20 2006/11/28 23:45:57 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -372,7 +372,6 @@ extern void soap_env_free(struct SoapEnv *env); */ extern xmlNodePtr soap_env_get_body(struct SoapEnv * env); - /** * * Get the xml node pointing to SOAP method (call) diff --git a/libcsoap/soap-nhttp.c b/libcsoap/soap-nhttp.c index 84a9ddc..fe5539d 100644 --- a/libcsoap/soap-nhttp.c +++ b/libcsoap/soap-nhttp.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: soap-nhttp.c,v 1.5 2006/11/26 20:13:05 m0gg Exp $ +* $Id: soap-nhttp.c,v 1.6 2006/11/28 23:45:57 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -195,12 +195,12 @@ soap_nhttp_process(httpd_conn_t * conn, struct hrequest_t * req) xmlFree(uri); } - xmlDocDump(stdout, ctx->env->root->doc); + xmlDocFormatDump(stdout, ctx->env->root->doc, 1); soap_ctx_add_files(ctx, req->attachments); /* only local part is interesting... */ - soap_addressing_set_to_address_string(ctx->env, req->path); + // soap_addressing_set_to_address_string(ctx->env, req->path); soap_transport_process(ctx, &response); @@ -285,7 +285,7 @@ _soap_nhttp_client_invoke(void *unused, struct SoapCtx *request, struct SoapCtx xmlNodeDump(buffer, request->env->root->doc, request->env->root, 1, 0); content = (char *) xmlBufferContent(buffer); - xmlDocDump(stdout, request->env->root->doc); + xmlDocFormatDump(stdout, request->env->root->doc, 1); /* Transport via HTTP */ if (!(conn = httpc_new())) diff --git a/libcsoap/soap-server.c b/libcsoap/soap-server.c index cee9643..e40c798 100644 --- a/libcsoap/soap-server.c +++ b/libcsoap/soap-server.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: soap-server.c,v 1.33 2006/11/26 20:13:05 m0gg Exp $ +* $Id: soap-server.c,v 1.34 2006/11/28 23:45:57 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -118,7 +118,7 @@ _soap_server_fillup_header(struct SoapEnv *envelope) xmlFreeURI(uri); if (!(uri = soap_addressing_get_from_address(envelope))) - soap_addressing_set_from_string(envelope, soap_server_get_name()); + soap_addressing_set_from_address_string(envelope, soap_server_get_name()); else xmlFreeURI(uri); @@ -144,8 +144,8 @@ soap_server_process(struct SoapCtx *request, struct SoapCtx **response) { char buffer[1054]; const char *urn; + xmlURI *uri; const char *method; - char *to; struct SoapRouter *router; SoapService *service; herror_t err; @@ -161,10 +161,10 @@ soap_server_process(struct SoapCtx *request, struct SoapCtx **response) if ((urn = soap_env_find_urn(request->env))) { log_verbose2("urn: \"%s\"", urn); - if ((to = soap_addressing_get_to_address_string(request->env))) + if ((uri = soap_addressing_get_to_address(request->env))) { - log_verbose2("searching router for \"%s\"", to); - if ((router = soap_server_find_router(to))) + log_verbose2("searching router for \"%s\"", uri->path); + if ((router = soap_server_find_router(uri->path))) { log_verbose2("router: %p", router); if ((service = soap_router_find_service(router, urn, method))) @@ -193,11 +193,10 @@ soap_server_process(struct SoapCtx *request, struct SoapCtx **response) } else { - sprintf(buffer, "no router for context \"%s\" found", to); + sprintf(buffer, "no router for context \"%s\" found", uri->path); _soap_server_env_new_with_fault(buffer, "The method is unknown by the server", &((*response)->env)); - free(to); } - free(to); + xmlFreeURI(uri); } else { @@ -231,9 +230,9 @@ soap_server_init_args(int argc, char **argv) } #ifdef HAVE_XMLSEC1 - if ((status = soap_xmlsec_init_args(argc, argv)) != H_OK) + if ((status = soap_xmlsec_server_init_args(argc, argv)) != H_OK) { - log_error2("soap_xmlsec_init_args failed (%s)", herror_message(status)); + log_error2("soap_xmlsec_server_init_args failed (%s)", herror_message(status)); return status; } #endif diff --git a/libcsoap/soap-transport.c b/libcsoap/soap-transport.c index 3cd46e8..7d54ced 100644 --- a/libcsoap/soap-transport.c +++ b/libcsoap/soap-transport.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: soap-transport.c,v 1.5 2006/11/26 20:13:05 m0gg Exp $ +* $Id: soap-transport.c,v 1.6 2006/11/28 23:45:57 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2007 Heiko Ronsdorf @@ -110,11 +110,27 @@ soap_transport_process(struct SoapCtx *request, struct SoapCtx **response) return soap_server_process(request, response); } +static herror_t +_soap_transport_set_name(void) +{ + static int set = 0; + char hostname[256]; + + if (set) + return H_OK; + + gethostname(hostname, 256); + sprintf(soap_transport_name, "%s://%s:%i", soap_nhttp_get_protocol(), hostname, soap_nhttp_get_port()); + + set = 1; + + return H_OK; +} + herror_t soap_transport_server_init_args(int argc, char **argv) { herror_t status; - char hostname[256]; if ((status = soap_nhttp_server_init_args(argc, argv)) != H_OK) { @@ -128,8 +144,11 @@ soap_transport_server_init_args(int argc, char **argv) return status; } - gethostname(hostname, 256); - sprintf(soap_transport_name, "%s://%s:%i", soap_nhttp_get_protocol(), hostname, soap_nhttp_get_port()); + if ((status = _soap_transport_set_name()) != H_OK) + { + log_error2("_soap_transport_set_name failed (%s)", herror_message(status)); + return status; + } return H_OK; } @@ -233,6 +252,12 @@ soap_transport_client_init_args(int argc, char **argv) return status; } + if ((status = _soap_transport_set_name()) != H_OK) + { + log_error2("_soap_transport_set_name failed (%s)", herror_message(status)); + return status; + } + return H_OK; } @@ -244,7 +269,7 @@ soap_transport_client_invoke(struct SoapCtx *request, struct SoapCtx **response) xmlURI *dest; log_verbose1(__FUNCTION__); - xmlDocDump(stdout, request->env->root->doc); + xmlDocFormatDump(stdout, request->env->root->doc, 1); dest = soap_addressing_get_to_address(request->env); @@ -260,8 +285,10 @@ soap_transport_client_invoke(struct SoapCtx *request, struct SoapCtx **response) return ret; } } + ret = herror_new("soap_transport_client_invoke", 0, "no transport service found for \"%s\"", dest->scheme); xmlFreeURI(dest); + return ret; } diff --git a/libcsoap/soap-xmlsec.c b/libcsoap/soap-xmlsec.c index 07e12fe..75cc187 100644 --- a/libcsoap/soap-xmlsec.c +++ b/libcsoap/soap-xmlsec.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: soap-xmlsec.c,v 1.3 2006/11/25 17:03:20 m0gg Exp $ +* $Id: soap-xmlsec.c,v 1.4 2006/11/28 23:45:57 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -25,6 +25,14 @@ #include #endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_SYS_UIO_H +#include +#endif + #ifdef HAVE_STDIO_H #include #endif @@ -33,6 +41,22 @@ #include #endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_FCNTL_H +#include +#endif + +#ifdef HAVE_CTYPE_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + #ifdef HAVE_PTHREAD_H #include #endif @@ -40,30 +64,50 @@ #include #include #include +#include +#include #include #include +#ifndef XMLSEC_NO_XSLT +#include +#endif + #include #include +#include #include #include #include #include -#include #include +#include +#include +#include +#include +#include +#include +#include #include "soap-env.h" #include "soap-ctx.h" #include "soap-service.h" #include "soap-router.h" #include "soap-server.h" +#include "soap-transport.h" #include "soap-addressing.h" #include "soap-xmlsec.h" +static int _soap_xmlsec_enabled = 0; static pthread_mutex_t _soap_xmlsec_lock; -static xmlSecKeyPtr _soap_xmlsec_sign_key; -static int _soap_xmlsec_enabled; + +static char *_soap_xmlsec_keyfile = NULL; +static char *_soap_xmlsec_password = NULL; +static char *_soap_xmlsec_certfile = NULL; + +static xmlSecKeysMngrPtr _soap_xmlsec_key_manager = NULL; +static xmlSecKeyPtr _soap_xmlsec_key = NULL; static void _soap_xmlsec_error_callback(const char *file, int line, const char *func, const char *errorObject, const char *errorSubject, int reason, const char *msg) { @@ -72,62 +116,544 @@ static void _soap_xmlsec_error_callback(const char *file, int line, const char * return; } +/** + * + * 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. + * + */ +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. + * + */ +static xmlSecKeyPtr +_soap_xmlsec_files_keys_store_find_key(xmlSecKeyStorePtr store, const xmlChar * name, xmlSecKeyInfoCtxPtr keyInfoCtx) +{ + xmlSecKeyPtr key; + xmlURI *uri; + char *file; + + fprintf(stderr, "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 + */ + if (name == NULL) + { + printf("key name is NULL\n"); + return NULL; + } + + if (keyInfoCtx->keyReq.keyId == xmlSecKeyDataIdUnknown) + { + printf("keyReq.keyID == xmlSecKeyDataIdUnkown\n"); + return NULL; + } + + if (!(uri = xmlParseURI(name))) + { + printf("xmlParseURI failed\n"); + return NULL; + } + + // printf("uri->scheme=\"%s\"\n", uri->scheme); + // printf("uri->server=\"%s\"\n", uri->server); + // printf("uri->port=\"%i\"\n", uri->port); + // printf("uri->path=\"%s\"\n", uri->path); + + { + char *tmp; + char buf[4096]; + FILE *fp; + + if (!(tmp = getenv("CSOAP_TEMP"))) + { + tmp = "/tmp"; + } + // printf("tmp = \"%s\"\n", tmp); + + sprintf(buf, "%s/csoap-XXXXXX-key.pem", tmp); + // printf("buf = \"%s\"\n", buf); + + if (mkstemps(buf, 8) < 0) + { + printf("mkstemps failed (%s)", strerror(errno)); + return NULL; + } + + // printf("fopen(\"%s\")\n", buf); + file = strdup(buf); + + if (!(fp = fopen(buf, "w"))) + { + printf("fopen failed (%s)\n", strerror(errno)); + return NULL; + } + + if (!strcmp("https", uri->scheme) || !strcmp("http", uri->scheme)) + { + size_t len; + httpc_conn_t *conn; + hresponse_t *res; + herror_t status; + + conn = httpc_new(); + + if ((status = (httpc_get(conn, &res, name))) != H_OK) + { + log_error2("httpc_get failed (%s)", herror_message(status)); + herror_release(status); + return NULL; + } + + while (http_input_stream_is_ready(res->in)) + { + len = http_input_stream_read(res->in, buf, 4096); + fwrite(buf, len, 1, fp); + } + hresponse_free(res); + + httpc_free(conn); + } + fclose(fp); + } + + 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(file, 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, file); + 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); + } + + if (unlink(file) < 0) + { + log_error2("unlink file failed (%s)", strerror(errno)); + } + free(file); + + return (key); +} + +static xmlSecKeyStoreKlass _soap_xmlsec_files_keys_store_klass = +{ + sizeof(xmlSecKeyStoreKlass), + sizeof(xmlSecKeyStore), + BAD_CAST "uri-based-keys-store", /* const xmlChar* name; */ + NULL, /* xmlSecKeyStoreInitializeMethod initialize; */ + NULL, /* xmlSecKeyStoreFinalizeMethod finalize; */ + _soap_xmlsec_files_keys_store_find_key, /* xmlSecKeyStoreFindKeyMethod findKey; */ + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +static inline xmlSecKeyStoreId +_soap_xmlsec_files_keys_store_get_klass(void) +{ + return (&_soap_xmlsec_files_keys_store_klass); +} + +static herror_t +_soap_xmlsec_create_key_manager(void) +{ + xmlSecKeyStorePtr keysStore; + + /* create files based keys store */ + keysStore = xmlSecKeyStoreCreate(_soap_xmlsec_files_keys_store_get_klass()); + if (keysStore == NULL) + { + log_error1("failed to create keys store"); + return herror_new("_soap_xmlxec_create_key_manager", 0, "failed to create keys store"); + } + + /* create keys manager */ + if ((_soap_xmlsec_key_manager = xmlSecKeysMngrCreate()) == NULL) + { + log_error1("failed to create keys manager"); + xmlSecKeyStoreDestroy(keysStore); + return herror_new("_soap_xmlsec_key_manager", 0, "failed to create keys manager"); + } + + /* + * add store to keys manager, from now on keys manager destroys the + * store if needed + */ + if (xmlSecKeysMngrAdoptKeysStore(_soap_xmlsec_key_manager, keysStore) < 0) + { + log_error1("failed to add keys store to keys manager"); + 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"); + } + + /* initialize crypto library specific data in keys manager */ + if (xmlSecCryptoKeysMngrInit(_soap_xmlsec_key_manager) < 0) + { + 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"); + } + + /* set the get key callback */ + _soap_xmlsec_key_manager->getKey = xmlSecKeysMngrGetKey; + + return H_OK; +} + static herror_t _soap_xmlsec_load_key(void) { - char *key = "key.pem"; - char *cert = "cert.pem"; + int err; + xmlChar keyName[256]; - if ((_soap_xmlsec_sign_key = xmlSecCryptoAppKeyLoad(key, xmlSecKeyDataFormatPem, "password", NULL, NULL)) == NULL) + if ((_soap_xmlsec_key = xmlSecCryptoAppKeyLoad(_soap_xmlsec_keyfile, xmlSecKeyDataFormatPem, _soap_xmlsec_password, NULL, NULL)) == NULL) { - log_error2("xmlSecCryptoAppKeyLoad(\"%s\") failed", key); - return herror_new("_soap_xmlsec_load_key", 0, "xmlSecCryptoAppKeyLoad(\"%s\") failed", key); + log_error2("xmlSecCryptoAppKeyLoad(\"%s\") failed", _soap_xmlsec_keyfile); + return herror_new("_soap_xmlsec_load_key", 0, "xmlSecCryptoAppKeyLoad(\"%s\") failed", _soap_xmlsec_keyfile); } - if (xmlSecCryptoAppKeyCertLoad(_soap_xmlsec_sign_key, cert, xmlSecKeyDataFormatPem) < 0) + if (_soap_xmlsec_certfile) { - log_error2("xmlSecCryptoAppKeyCertLoad(\"%s\") failed", cert); - return herror_new("_soap_xmlsec_load_key", 0, "xmlSecCryptoAppKeyCertLoad(\"%s\") failed", cert); + if (xmlSecCryptoAppKeyCertLoad(_soap_xmlsec_key, _soap_xmlsec_certfile, xmlSecKeyDataFormatPem) < 0) + { + 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); + } } - if (xmlSecKeySetName(_soap_xmlsec_sign_key, soap_server_get_name()) < 0) + xmlStrPrintf(keyName, 256, "%s/key.pem", soap_server_get_name()); + log_error2("keyName is \"%s\"", keyName); + if ((err = xmlSecKeySetName(_soap_xmlsec_key, keyName)) < 0) { - log_error1("xmlSecKeySetName failed"); - return herror_new("_soap_xmlsec_load_key", 0, "xmlSecKeySetName failed"); + 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); } + xmlSecKeyDebugXmlDump(_soap_xmlsec_key, stdout); + xmlSecKeyDataDebugXmlDump(xmlSecKeyGetValue(_soap_xmlsec_key), stdout); + return H_OK; } -herror_t -soap_xmlsec_init_args(int argc, char **argv) +static void +_soap_xmlsec_key_service(httpd_conn_t *conn, struct hrequest_t *req) +{ + char buf[4096]; + size_t len; + int fd; + + httpd_set_header(conn, HEADER_CONTENT_TYPE, "text/plain"); + if (!(fd = open(_soap_xmlsec_keyfile, O_RDONLY))) + { + httpd_send_header(conn, 404, HTTP_STATUS_404_REASON_PHRASE); + http_output_stream_write_string(conn->out, "Public key not found!\n"); + } + else + { + httpd_send_header(conn, 200, HTTP_STATUS_200_REASON_PHRASE); + + while ((len = read(fd, buf, 4096)) > 0) + http_output_stream_write(conn->out, buf, len); + } + + return; +} + +static herror_t +_soap_xmlsec_publish_key(void) { - int err, i; herror_t status; - _soap_xmlsec_enabled = 0; - for (i=0; ienv; + + ret = H_OK; + pthread_mutex_lock(&_soap_xmlsec_lock); if (!(signNode = xmlSecTmplSignatureCreate(envelope->root->doc, xmlSecTransformExclC14NId, xmlSecTransformRsaSha1Id, NULL))) { log_error1("xmlSecTmplSignatureCreate failed"); - return herror_new("soap_xmlsec_sign", 0, "xmlSecTmplSignatureCreate failed"); + ret = herror_new("soap_xmlsec_sign", 0, "xmlSecTmplSignatureCreate failed"); + goto out; } - if (!(refNode = xmlSecTmplSignatureAddReference(signNode, xmlSecTransformSha1Id, NULL, NULL, NULL))) + signature = xmlNewNode(NULL, "Signature"); + ns = xmlNewNs(signature, SOAP_SECURITY_NAMESPACE, SOAP_SECURITY_PREFIX); + xmlSetNs(signature, ns); + + xmlSetNsProp(signature, envelope->root->ns, BAD_CAST "actor", soap_transport_get_name()); + xmlSetNsProp(signature, envelope->root->ns, BAD_CAST "mustUnderstand", BAD_CAST "1"); + + xmlAddChild(envelope->header, signature); + + xmlAddChild(signature, signNode); + + if (!(refNode = xmlSecTmplSignatureAddReference(signNode, xmlSecTransformSha1Id, "#Body", NULL, NULL))) { log_error1("xmlSecTmplSignatureAddReference failed"); - return herror_new("soap_xmlsec_sign", 0, "xmlSecTmplSignatureAddReference failed"); + ret = herror_new("soap_xmlsec_sign", 0, "xmlSecTmplSignatureAddReference failed"); + goto out; } if (!(keyInfoNode = xmlSecTmplSignatureEnsureKeyInfo(signNode, NULL))) { log_error1("xmlSecTmplSignatureEnsureKeyInfo failed"); - return herror_new("soap_xmlsec_sign", 0, "xmlSecTmplSignatureEnsureKeyInfo failed"); + ret = herror_new("soap_xmlsec_sign", 0, "xmlSecTmplSignatureEnsureKeyInfo failed"); + goto out; } - if (xmlSecTmplKeyInfoAddKeyName(keyInfoNode, NULL) == NULL) + if (xmlSecTmplKeyInfoAddKeyName(keyInfoNode, soap_server_get_name()) == NULL) { log_error1("xmlSecTmplKeyInfoAddKeyName failed"); - return herror_new("soap_xmlsec_sign", 0, "xmlSecTmplKeyInfoAddKeyName failed"); + ret = herror_new("soap_xmlsec_sign", 0, "xmlSecTmplKeyInfoAddKeyName failed"); + goto out; } - if (!(dsigCtx = xmlSecDSigCtxCreate(NULL))) + if (!(dsigCtx = xmlSecDSigCtxCreate(_soap_xmlsec_key_manager))) { log_error1("xmlSecDSigCtxCreate failed"); - return herror_new("soap_xmlsec_sign", 0, "xmlSecDSigCtxCreate failed"); + ret = herror_new("soap_xmlsec_sign", 0, "xmlSecDSigCtxCreate failed"); + goto out; } - dsigCtx->signKey = _soap_xmlsec_sign_key; - + dsigCtx->signKey = _soap_xmlsec_key; + if (xmlSecDSigCtxSign(dsigCtx, signNode) < 0) { log_error1("xmlSecDSigCtxSign failed"); - return herror_new("soap_xmlsec_sign", 0, "xmlSecDSigCtxSign failed"); + ret = herror_new("soap_xmlsec_sign", 0, "xmlSecDSigCtxSign failed"); + goto out; } - xmlAddChild(envelope->header, signNode); + +out: pthread_mutex_unlock(&_soap_xmlsec_lock); return H_OK; } -herror_t soap_xmlsec_encrypt(struct SoapEnv *envelope) +herror_t soap_xmlsec_encrypt(struct SoapCtx *context) { + struct SoapEnv *envelope; + xmlNodePtr encDataNode = NULL; + xmlNodePtr keyInfoNode = NULL; + xmlNodePtr encKeyNode = NULL; + xmlNodePtr keyInfoNode2 = NULL; + xmlSecEncCtxPtr encCtx = NULL; + xmlURI *to; + xmlChar buf[256]; + xmlDocPtr doc; + if (!_soap_xmlsec_enabled) return H_OK; + envelope = context->env; + + doc = context->env->root->doc; + + 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"); + } + + if (xmlSecTmplEncDataEnsureCipherValue(encDataNode) == NULL) + { + log_error1("failed to add CipherValue node"); + return herror_new("soap_xmlsec_encrypt", 0, "failed to add CipherValue node"); + } + + 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"); + } + + 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"); + } + + if (xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == NULL) + { + log_error1("failed to add CipherValue node"); + return herror_new("soap_xmlsec_encrypt", 0, "failed to add CipherValue node"); + } + + 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)"); + } + + to = soap_addressing_get_to_address(envelope); + xmlStrPrintf(buf, 256, "http://%s:%i/key.pem", to->server, to->port); + log_error2("adding key \"%s\"", buf); + xmlFreeURI(to); + + 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); + } + + 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"); + } + + 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"); + } + + 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"); + } + +/* { + 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); + return H_OK; } +herror_t soap_xmlsec_decrypt(struct SoapCtx *context) +{ + struct SoapEnv *envelope; + + if (!_soap_xmlsec_enabled) + return H_OK; + + envelope = context->env; + + log_error1("not implemented"); + return herror_new("soap_xmlsec_decrupt", 0, "not implemented"); +} + +herror_t soap_xmlsec_verify(struct SoapCtx *context) +{ + struct SoapEnv *envelope; + + if (!_soap_xmlsec_enabled) + return H_OK; + + envelope = context->env; + + log_error1("not implemented"); + return herror_new("soap_xmlsec_verify", 0, "not implemented"); +} + void soap_xmlsec_destroy(void) { + if (!_soap_xmlsec_enabled) + return; + + xmlSecKeysMngrDestroy(_soap_xmlsec_key_manager); + xmlSecCryptoShutdown(); xmlSecCryptoAppShutdown(); xmlSecShutdown(); +#ifndef XMLSEC_NO_XSLT + xsltCleanupGlobals(); +#endif + return; } diff --git a/libcsoap/soap-xmlsec.h b/libcsoap/soap-xmlsec.h index fc24fc5..9943498 100644 --- a/libcsoap/soap-xmlsec.h +++ b/libcsoap/soap-xmlsec.h @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: soap-xmlsec.h,v 1.2 2006/11/27 11:15:27 m0gg Exp $ + * $Id: soap-xmlsec.h,v 1.3 2006/11/28 23:45:57 m0gg Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2006 Heiko Ronsdorf @@ -31,13 +31,17 @@ * This module is implemented using the xmlsec1 library. * * @author H. Ronsdorf - * @version $Revision: 1.2 $ + * @version $Revision: 1.3 $ * - * @see http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wss - * http://www.aleksey.com/xmlsec/, + * @see http://www.w3.org/TR/SOAP-dsig/, + * http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wss, + * http://www.aleksey.com/xmlsec/ * */ +#define SOAP_SECURITY_NAMESPACE "http://schemas.xmlsoap.org/soap/security/2000-12" +#define SOAP_SECURITY_PREFIX "SOAP-SEC" + /** * * Commandline argument to enabled WS-Security. @@ -45,6 +49,28 @@ */ #define CSOAP_ENABLE_XMLSEC "-CSOAPxmlsec" +/** + * + * Commandline argument to set the keyfile. If this argument is not specified a + * random key will be used. + * + */ +#define CSOAP_XMLSEC_KEYFILE "-CSOAPkeyfile" + +/** + * + * Commandline argument to set the password of the key. + * + */ +#define CSOAP_XMLSEC_PASSWORD "-CSOAPpassword" + +/** + * + * Commandline argument to set a file of certificates. + * + */ +#define CSOAP_XMLSEC_CERTFILE "-CSOAPcertfile" + #ifdef __cplusplus extern "C" { #endif @@ -56,19 +82,45 @@ extern "C" { * @param argc commandline arg count * @param argv commandline arg vector * - * @returns H_OK on success + * @return H_OK on success * */ -extern herror_t soap_xmlsec_init_args(int argc, char **argv); +extern herror_t soap_xmlsec_server_init_args(int argc, char **argv); /** * - * Sign a XML document contained in a SOAP Envelope + * Initializes the WS-Security subsystem. + * + * @param argc commandline arg count + * @param argv commandline arg vector + * + * @return H_OK on success + * + */ +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. * * @param envelope The SOAP envelope to be signed. * + * @return H_OK on success + * */ -extern herror_t soap_xmlsec_sign(struct SoapEnv *envelope); +extern herror_t soap_xmlsec_sign(struct SoapCtx *context); + +/** + * + * Verify a XML documents signature contained in a SOAP Envelope. + * + * @param envelope The SOAP envelope to be verified. + * + * @return H_OK on success + * + */ +extern herror_t soap_xmlsec_verify(struct SoapCtx *context); /** * @@ -76,8 +128,22 @@ extern herror_t soap_xmlsec_sign(struct SoapEnv *envelope); * * @param envelope The SOAP envelope to be encrypted. * + * @return H_OK on success + * + */ +extern herror_t soap_xmlsec_encrypt(struct SoapCtx *context); + +/** + * + * Decrupt a XML document contained in a SOAP envelope. + * + * @param envelope The SOAP envelope to be decrypted. + * + * @return H_OK on success + * */ -extern herror_t soap_xmlsec_encrypt(struct SoapEnv *envelope); +extern herror_t soap_xmlsec_decrypt(struct SoapCtx *context); + /** * -- cgit v1.1-32-gdbae