soap-xmlsec.c

Go to the documentation of this file.
00001 /******************************************************************
00002 *  $Id: soap-xmlsec.c,v 1.8 2006/12/14 19:36:49 m0gg Exp $
00003 *
00004 * CSOAP Project:  A SOAP client/server library in C
00005 * Copyright (C) 2003  Ferhat Ayaz
00006 *
00007 * This library is free software; you can redistribute it and/or
00008 * modify it under the terms of the GNU Library General Public
00009 * License as published by the Free Software Foundation; either
00010 * version 2 of the License, or (at your option) any later version.
00011 *
00012 * This library is distributed in the hope that it will be useful,
00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 * Library General Public License for more details.
00016 *
00017 * You should have received a copy of the GNU Library General Public
00018 * License along with this library; if not, write to the
00019 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020 * Boston, MA  02111-1307, USA.
00021 * 
00022 * Email: ayaz@jprogrammer.net
00023 ******************************************************************/
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #ifdef HAVE_SYS_TYPES_H
00029 #include <sys/types.h>
00030 #endif
00031 
00032 #ifdef HAVE_SYS_UIO_H
00033 #include <sys/uio.h>
00034 #endif
00035 
00036 #ifdef HAVE_STDIO_H
00037 #include <stdio.h>
00038 #endif
00039 
00040 #ifdef HAVE_STRING_H
00041 #include <string.h>
00042 #endif
00043 
00044 #ifdef HAVE_STDLIB_H
00045 #include <stdlib.h>
00046 #endif
00047 
00048 #ifdef HAVE_ERRNO_H
00049 #include <errno.h>
00050 #endif
00051 
00052 #ifdef HAVE_FCNTL_H
00053 #include <fcntl.h>
00054 #endif
00055 
00056 #ifdef HAVE_CTYPE_H
00057 #include <ctype.h>
00058 #endif
00059 
00060 #ifdef HAVE_UNISTD_H
00061 #include <unistd.h>
00062 #endif
00063 
00064 #ifdef HAVE_PTHREAD_H
00065 #include <pthread.h>
00066 #endif
00067 
00068 #include <libxml/tree.h>
00069 #include <libxml/uri.h>
00070 #include <libxml/parser.h>
00071 #include <libxml/xmlmemory.h>
00072 #include <libxml/xmlstring.h>
00073 #include <libxml/xpath.h>
00074 #include <libxml/xpathInternals.h>
00075 
00076 #ifndef XMLSEC_NO_XSLT
00077 #include <libxslt/xslt.h>
00078 #endif
00079 
00080 #include <xmlsec/xmlsec.h>
00081 #include <xmlsec/xmltree.h>
00082 #include <xmlsec/xmlenc.h>
00083 #include <xmlsec/xmldsig.h>
00084 #include <xmlsec/templates.h>
00085 #include <xmlsec/crypto.h>
00086 #include <xmlsec/errors.h>
00087 
00088 #include <nanohttp/nanohttp-logging.h>
00089 #include <nanohttp/nanohttp-error.h>
00090 #include <nanohttp/nanohttp-common.h>
00091 #include <nanohttp/nanohttp-stream.h>
00092 #include <nanohttp/nanohttp-request.h>
00093 #include <nanohttp/nanohttp-response.h>
00094 #include <nanohttp/nanohttp-client.h>
00095 #include <nanohttp/nanohttp-server.h>
00096 
00097 #include "soap-env.h"
00098 #include "soap-ctx.h"
00099 #include "soap-service.h"
00100 #include "soap-router.h"
00101 #include "soap-server.h"
00102 #include "soap-transport.h"
00103 #include "soap-addressing.h"
00104 #include "soap-xmlsec.h"
00105 
00106 static int _soap_xmlsec_enabled = 0;
00107 static pthread_mutex_t _soap_xmlsec_lock;
00108 
00109 static char *_soap_xmlsec_keyfile = NULL;
00110 static char *_soap_xmlsec_password = NULL;
00111 static char *_soap_xmlsec_certfile = NULL;
00112 
00113 static xmlSecKeysMngrPtr _soap_xmlsec_key_manager = NULL;
00114 static xmlSecKeyPtr _soap_xmlsec_key = NULL;
00115 
00116 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)
00117 {
00118   log_error5("xmlsec error func=\"%s\" obj=\"%s\" sub=\"%s\" %s", func, errorObject, errorSubject, msg);
00119 
00120   return;
00121 }
00122 
00135 static xmlSecKeyPtr
00136 _soap_xmlsec_files_keys_store_find_key(xmlSecKeyStorePtr store, const xmlChar * name, xmlSecKeyInfoCtxPtr keyInfoCtx)
00137 {
00138   xmlSecKeyPtr  key;
00139   xmlURI *uri;
00140   char *file;
00141 
00142   log_verbose2("trying to find key \"%s\"\n", name);
00143 
00144   /*
00145    * it's possible to do not have the key name or desired key type but we could
00146    * do nothing in this case
00147    *
00148    */
00149   if (name == NULL)
00150   {
00151     printf("key name is NULL\n");
00152     return NULL;
00153   }
00154 
00155   if (keyInfoCtx->keyReq.keyId == xmlSecKeyDataIdUnknown)
00156          {
00157     printf("keyReq.keyID == xmlSecKeyDataIdUnkown\n");
00158     return NULL;
00159   }
00160 
00161   if (!(uri = xmlParseURI(name)))
00162   {
00163     printf("xmlParseURI failed\n");
00164     return NULL;
00165   }
00166 
00167   /* printf("uri->scheme=\"%s\"\n", uri->scheme);
00168    printf("uri->server=\"%s\"\n", uri->server);
00169    printf("uri->port=\"%i\"\n", uri->port);
00170    printf("uri->path=\"%s\"\n", uri->path); */
00171 
00172   {
00173           char *tmp;
00174     char buf[4096];
00175     FILE *fp;
00176 
00177     if (!(tmp = getenv("CSOAP_TEMP")))
00178     {
00179       tmp = "/tmp";
00180     }
00181     sprintf(buf, "%s/csoap-XXXXXX-key.pem", tmp);
00182 
00183     if (mkstemps(buf, 8) < 0)
00184     {
00185       printf("mkstemps failed (%s)", strerror(errno));
00186       return NULL;
00187     }
00188 
00189     file = strdup(buf);
00190 
00191     if (!(fp = fopen(buf, "w")))
00192     {
00193       printf("fopen failed (%s)\n", strerror(errno));
00194       return NULL;
00195     }
00196 
00197     if (!strcmp("https", uri->scheme) || !strcmp("http", uri->scheme))
00198     {
00199       size_t len;
00200       httpc_conn_t *conn;
00201       hresponse_t *res;
00202       herror_t status;
00203       
00204       conn = httpc_new();
00205 
00206       if ((status = (httpc_get(conn, &res, name))) != H_OK)
00207       {
00208         log_error2("httpc_get failed (%s)", herror_message(status));
00209         herror_release(status);
00210         return NULL;
00211       }
00212 
00213       while (http_input_stream_is_ready(res->in))
00214       {
00215         len = http_input_stream_read(res->in, buf, 4096);
00216         fwrite(buf, len, 1, fp);
00217       }
00218       hresponse_free(res);
00219 
00220       httpc_free(conn);
00221     }
00222     fclose(fp);
00223   }
00224 
00225   if ((keyInfoCtx->keyReq.keyId == xmlSecKeyDataDsaId) || (keyInfoCtx->keyReq.keyId == xmlSecKeyDataRsaId)) {
00226     /*
00227      * load key from a pem file, if key is not found then it's an
00228      * error (is it?)
00229      */
00230     key = xmlSecCryptoAppKeyLoad(file, xmlSecKeyDataFormatPem, NULL, NULL, NULL);
00231     if (key == NULL) {
00232       fprintf(stderr, "Error: failed to load public pem key from \"%s\"\n", name);
00233       return (NULL);
00234     }
00235   }
00236   else {
00237     /*
00238      * otherwise it's a binary key, if key is not found then it's
00239      * an error (is it?)
00240      */
00241     key = xmlSecKeyReadBinaryFile(keyInfoCtx->keyReq.keyId, file);
00242     if (key == NULL) {
00243       fprintf(stderr, "Error: failed to load key from binary file \"%s\"\n", name);
00244       return (NULL);
00245     }
00246   }
00247 
00248   /* set key name */
00249   if (xmlSecKeySetName(key, name) < 0) {
00250     fprintf(stderr, "Error: failed to set key name for key from \"%s\"\n", name);
00251     xmlSecKeyDestroy(key);
00252     return (NULL);
00253   }
00254 
00255   if (unlink(file) < 0)
00256   {
00257     log_error2("unlink file failed (%s)", strerror(errno));
00258   }
00259   free(file);
00260 
00261   return (key);
00262 }
00263 
00264 static xmlSecKeyStoreKlass _soap_xmlsec_files_keys_store_klass =
00265 {
00266   sizeof(xmlSecKeyStoreKlass),
00267   sizeof(xmlSecKeyStore),
00268   BAD_CAST "uri-based-keys-store",  /* const xmlChar* name; */
00269   NULL,      /* xmlSecKeyStoreInitializeMethod initialize; */
00270   NULL,      /* xmlSecKeyStoreFinalizeMethod finalize; */
00271   _soap_xmlsec_files_keys_store_find_key,  /* xmlSecKeyStoreFindKeyMethod findKey; */
00272   /* reserved for the future */
00273   NULL,      /* void* reserved0; */
00274   NULL,      /* void* reserved1; */
00275 };
00276 
00277 static inline xmlSecKeyStoreId
00278 _soap_xmlsec_files_keys_store_get_klass(void)
00279 {
00280   return (&_soap_xmlsec_files_keys_store_klass);
00281 }
00282 
00283 static herror_t 
00284 _soap_xmlsec_create_key_manager(void)
00285 {
00286   xmlSecKeyStorePtr keysStore;
00287 
00288   /* create files based keys store */
00289   keysStore = xmlSecKeyStoreCreate(_soap_xmlsec_files_keys_store_get_klass());
00290   if (keysStore == NULL)
00291   {
00292     log_error1("failed to create keys store");
00293     return herror_new("_soap_xmlxec_create_key_manager", XMLSEC_ERROR_KEYSTORE, "failed to create keys store");
00294   }
00295 
00296   /* create keys manager */
00297   if ((_soap_xmlsec_key_manager = xmlSecKeysMngrCreate()) == NULL)
00298   {
00299     log_error1("failed to create keys manager");
00300     xmlSecKeyStoreDestroy(keysStore);
00301     return herror_new("_soap_xmlsec_key_manager", XMLSEC_ERROR_KEYMANAGER, "failed to create keys manager");
00302   }
00303 
00304   /*
00305    * add store to keys manager, from now on keys manager destroys the
00306    * store if needed
00307    */
00308   if (xmlSecKeysMngrAdoptKeysStore(_soap_xmlsec_key_manager, keysStore) < 0)
00309   {
00310     log_error1("failed to add keys store to keys manager");
00311     xmlSecKeyStoreDestroy(keysStore);
00312     xmlSecKeysMngrDestroy(_soap_xmlsec_key_manager);
00313     _soap_xmlsec_key_manager = NULL;
00314     return herror_new("_soap_xmlsec_create_key_manager", XMLSEC_ERROR_KEYMANAGER, "failed to add keys store to keys manager");
00315   }
00316 
00317   /* initialize crypto library specific data in keys manager */
00318   if (xmlSecCryptoKeysMngrInit(_soap_xmlsec_key_manager) < 0)
00319   {
00320     log_error1("failed to initialize crypto data in keys manager");
00321     xmlSecKeysMngrDestroy(_soap_xmlsec_key_manager);
00322     _soap_xmlsec_key_manager = NULL;
00323     return herror_new("_soap_xmlsec_create_key_manager", XMLSEC_ERROR_KEYMANAGER, "failed to initialize crypto data in keys manager");
00324   }
00325 
00326   /* set the get key callback */
00327   _soap_xmlsec_key_manager->getKey = xmlSecKeysMngrGetKey;
00328 
00329   return H_OK;
00330 }
00331 
00332 static herror_t
00333 _soap_xmlsec_load_key(void)
00334 {
00335   int err;
00336   xmlChar keyName[256];
00337 
00338   if ((_soap_xmlsec_key = xmlSecCryptoAppKeyLoad(_soap_xmlsec_keyfile, xmlSecKeyDataFormatPem, _soap_xmlsec_password, NULL, NULL)) == NULL)
00339   {
00340     log_error2("xmlSecCryptoAppKeyLoad(\"%s\") failed", _soap_xmlsec_keyfile);
00341     return herror_new("_soap_xmlsec_load_key", XMLSEC_ERROR_KEY, "xmlSecCryptoAppKeyLoad(\"%s\") failed", _soap_xmlsec_keyfile);
00342   }
00343 
00344   if (_soap_xmlsec_certfile)
00345   {
00346     if (xmlSecCryptoAppKeyCertLoad(_soap_xmlsec_key, _soap_xmlsec_certfile, xmlSecKeyDataFormatPem) < 0)
00347     {
00348       log_error2("xmlSecCryptoAppKeyCertLoad(\"%s\") failed", _soap_xmlsec_certfile);
00349       xmlSecKeyDestroy(_soap_xmlsec_key);
00350       return herror_new("_soap_xmlsec_load_key", XMLSEC_ERROR_CERTIFICATE, "xmlSecCryptoAppKeyCertLoad(\"%s\") failed", _soap_xmlsec_certfile);
00351     }
00352   }
00353 
00354   xmlStrPrintf(keyName, 256, "%s/key.pem", soap_server_get_name());
00355   log_error2("keyName is \"%s\"", keyName);
00356   if ((err = xmlSecKeySetName(_soap_xmlsec_key, keyName)) < 0)
00357   {
00358     xmlSecKeyDestroy(_soap_xmlsec_key);
00359     log_error3("xmlSecKeySetName(\"%s\") failed (%i)", keyName, err);
00360     return herror_new("_soap_xmlsec_load_key", XMLSEC_ERROR_KEY, "xmlSecKeySetName(\"%s\") failed (%i)", keyName, err);
00361   }
00362 
00363 /*  xmlSecKeyDebugXmlDump(_soap_xmlsec_key, stdout);
00364     xmlSecKeyDataDebugXmlDump(xmlSecKeyGetValue(_soap_xmlsec_key), stdout); */
00365 
00366   return H_OK;
00367 }
00368 
00369 static void
00370 _soap_xmlsec_key_service(httpd_conn_t *conn, struct hrequest_t *req)
00371 {
00372   char buf[4096];
00373   size_t len;
00374   int fd;
00375 
00376   httpd_set_header(conn, HEADER_CONTENT_TYPE, "text/plain");
00377   if (!(fd = open(_soap_xmlsec_keyfile, O_RDONLY)))
00378   {
00379     httpd_send_header(conn, 404, HTTP_STATUS_404_REASON_PHRASE);
00380     http_output_stream_write_string(conn->out, "Public key not found!\n");
00381   }
00382   else
00383   {
00384     httpd_send_header(conn, 200, HTTP_STATUS_200_REASON_PHRASE);
00385 
00386     while ((len = read(fd, buf, 4096)) > 0)
00387       http_output_stream_write(conn->out, buf, len);
00388   }
00389 
00390   return;
00391 }
00392 
00393 static herror_t
00394 _soap_xmlsec_publish_key(void)
00395 {
00396   herror_t status;
00397 
00398   if ((status = httpd_register("/key.pem", _soap_xmlsec_key_service)) != H_OK)
00399   {
00400     log_error2("Cannot register key service (%s)", herror_message(status));
00401     return status;
00402   }
00403 
00404   return H_OK;
00405 }
00406 
00407 static inline void
00408 _soap_xmlsec_parse_arguments(int argc, char **argv)
00409 {
00410   int i;
00411 
00412   for (i=1; i<=argc; i++)
00413   {
00414     if (!strcmp(argv[i-1], CSOAP_ENABLE_XMLSEC))
00415     {
00416       _soap_xmlsec_enabled = 1;
00417     }
00418     else if (!strcmp(argv[i-1], CSOAP_XMLSEC_KEYFILE))
00419     {
00420       _soap_xmlsec_keyfile = strdup(argv[i]);
00421     }
00422     else if (!strcmp(argv[i-1], CSOAP_XMLSEC_PASSWORD))
00423     {
00424       _soap_xmlsec_password = strdup(argv[i]);
00425     }
00426     else if (!strcmp(argv[i-1], CSOAP_XMLSEC_CERTFILE))
00427     {
00428       _soap_xmlsec_certfile = strdup(argv[i]);
00429     }
00430   }
00431   return;
00432 }
00433 
00434 herror_t
00435 _soap_xmlsec_init(void)
00436 {
00437   static int initialized = 0;
00438   int err;
00439   herror_t status;
00440 
00441   if (initialized)
00442     return H_OK;
00443 
00444   log_info1("initializing xmlsec1");
00445 
00446   xmlSecErrorsDefaultCallbackEnableOutput(1);
00447   xmlSecErrorsSetCallback(_soap_xmlsec_error_callback);
00448 
00449   if (xmlSecInit() < 0)
00450   {
00451     log_error1("xmlSecInit failed");
00452     return herror_new("soap_xmlsec_init", XMLSEC_ERROR_INIT, "xmlSecInit failed");
00453   }
00454 
00455   if (xmlSecCheckVersion() != 1)
00456   {
00457     log_error1("xmlSecCheckVersion failed, wrong xmlsec version");
00458     return herror_new("soap_xmlsec_init", XMLSEC_ERROR_VERSION, "Wrong xmlsec version");
00459   }
00460 
00461 #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
00462   log_verbose2("loading \"%s\" dynamic", XMLSEC_CRYPTO);
00463   if (xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0)
00464   {
00465     log_error1("xmlSecCryptoDLLoadLibrary failed");
00466     return herror_new("soap_xmlsec_init", XMLSEC_ERROR_DLLOAD, "xmlSecCryptoDLLoadLibrary failed");
00467   }
00468 #endif
00469 
00470   if (xmlSecCryptoAppInit(NULL) < 0)
00471   {
00472     log_error1("xmlSecCryptoAppInit failed");
00473     return herror_new("soap_xmlsec_init", XMLSEC_ERROR_INIT, "xmlSecCryptoAppInit failed");
00474   }
00475 
00476   if (xmlSecCryptoInit() < 0)
00477   {
00478     log_error1("xmlSecCryptoInit failed");
00479     return herror_new("soap_xmlsec_init", XMLSEC_ERROR_INIT, "xmlSecCryptoInit failed");
00480   }
00481 
00482   if ((status = _soap_xmlsec_create_key_manager()) != H_OK)
00483   {
00484     log_error2("_soap_xmlsec_create_key_manager failed (%s)", herror_message(status));
00485     return status;
00486   }
00487 
00488   if ((err = pthread_mutex_init(&_soap_xmlsec_lock, NULL)) < 0)
00489   {
00490     log_error2("pthread_mutex_init failed (%s)", strerror(err));
00491     return herror_new("soap_xmlsec_init", XMLSEC_ERROR_INIT, "pthread_mutex_init failed (%s)", strerror(err));
00492   }
00493 
00494   if ((status = _soap_xmlsec_load_key()) != H_OK)
00495   {
00496     log_error2("_soap_xmlsec_load_key failed (%s)", herror_message(status));
00497     return status;
00498   }
00499 
00500   initialized = 1;
00501 
00502   return H_OK;
00503 }
00504 
00505 herror_t
00506 soap_xmlsec_client_init_args(int argc, char **argv)
00507 {
00508   _soap_xmlsec_parse_arguments(argc, argv);
00509 
00510   if (!_soap_xmlsec_enabled)
00511     return H_OK;
00512 
00513   return _soap_xmlsec_init();
00514 }
00515 
00516 herror_t
00517 soap_xmlsec_server_init_args(int argc, char **argv)
00518 {
00519   herror_t status;
00520 
00521   _soap_xmlsec_parse_arguments(argc, argv);
00522 
00523   if (!_soap_xmlsec_enabled)
00524     return H_OK;
00525 
00526   if ((status = _soap_xmlsec_init()) != H_OK)
00527   {
00528     log_error2("_soap_xmlsec_init failed (%s)", herror_message(status));
00529     return status;
00530   }
00531 
00532   if ((status = _soap_xmlsec_publish_key()) != H_OK)
00533   {
00534     log_error2("_soap_xmlsec_publish_key failed (%s)", herror_message(status));
00535     return status;
00536   }
00537 
00538   return H_OK;
00539 }
00540 
00541 herror_t soap_xmlsec_sign(struct SoapCtx *context)
00542 {
00543   xmlNodePtr signature;
00544   xmlNsPtr ns;
00545   xmlNodePtr signNode;
00546   xmlNodePtr refNode;
00547   xmlNodePtr keyInfoNode;
00548   xmlSecDSigCtxPtr dsigCtx;
00549   herror_t ret;
00550   struct SoapEnv *envelope;
00551 
00552   if (!_soap_xmlsec_enabled)
00553     return H_OK;
00554 
00555   envelope = context->env;
00556 
00557   ret = H_OK;
00558 
00559   pthread_mutex_lock(&_soap_xmlsec_lock);
00560 
00561   if (!(signNode = xmlSecTmplSignatureCreate(envelope->root->doc, xmlSecTransformExclC14NId, xmlSecTransformRsaSha1Id, NULL)))
00562   {
00563     log_error1("xmlSecTmplSignatureCreate failed");
00564     ret = herror_new("soap_xmlsec_sign", XMLSEC_ERROR_SIGN_INIT, "xmlSecTmplSignatureCreate failed");
00565     goto out;
00566   }
00567 
00568   signature = xmlNewNode(NULL, "Signature");
00569   ns = xmlNewNs(signature, SOAP_SECURITY_NAMESPACE, SOAP_SECURITY_PREFIX);
00570   xmlSetNs(signature, ns);
00571 
00572   xmlSetNsProp(signature, envelope->root->ns, BAD_CAST "actor", soap_transport_get_name());
00573   xmlSetNsProp(signature, envelope->root->ns, BAD_CAST "mustUnderstand", BAD_CAST "1");
00574 
00575   xmlAddChild(envelope->header, signature);
00576 
00577   xmlAddChild(signature, signNode);
00578 
00579   if (!(refNode = xmlSecTmplSignatureAddReference(signNode, xmlSecTransformSha1Id, "#Body", NULL, NULL)))
00580   {
00581     log_error1("xmlSecTmplSignatureAddReference failed");
00582     ret = herror_new("soap_xmlsec_sign", XMLSEC_ERROR_SIGN_INIT, "xmlSecTmplSignatureAddReference failed");
00583     goto out;
00584   }
00585 
00586   if (!(keyInfoNode = xmlSecTmplSignatureEnsureKeyInfo(signNode, NULL)))
00587   {
00588     log_error1("xmlSecTmplSignatureEnsureKeyInfo failed");
00589     ret = herror_new("soap_xmlsec_sign", XMLSEC_ERROR_SIGN_INIT, "xmlSecTmplSignatureEnsureKeyInfo failed");
00590     goto out;
00591   }
00592 
00593   if (xmlSecTmplKeyInfoAddKeyName(keyInfoNode, soap_server_get_name()) == NULL)
00594   {
00595     log_error1("xmlSecTmplKeyInfoAddKeyName failed");
00596     ret = herror_new("soap_xmlsec_sign", XMLSEC_ERROR_SIGN_INIT, "xmlSecTmplKeyInfoAddKeyName failed");
00597     goto out;
00598   }
00599 
00600   if (!(dsigCtx = xmlSecDSigCtxCreate(_soap_xmlsec_key_manager)))
00601   {
00602     log_error1("xmlSecDSigCtxCreate failed");
00603     ret = herror_new("soap_xmlsec_sign", XMLSEC_ERROR_SIGN_INIT, "xmlSecDSigCtxCreate failed");
00604     goto out;
00605   }
00606 
00607   dsigCtx->signKey = _soap_xmlsec_key;
00608 
00609   if (xmlSecDSigCtxSign(dsigCtx, signNode) < 0)
00610   {
00611     log_error1("xmlSecDSigCtxSign failed");
00612     ret = herror_new("soap_xmlsec_sign", XMLSEC_ERROR_SIGN, "xmlSecDSigCtxSign failed");
00613     goto out;
00614   }
00615 
00616 out:
00617 
00618   pthread_mutex_unlock(&_soap_xmlsec_lock);
00619 
00620   return H_OK;
00621 }
00622 
00623 herror_t soap_xmlsec_encrypt(struct SoapCtx *context)
00624 {
00625   struct SoapEnv *envelope;
00626   herror_t ret;
00627   xmlNodePtr encDataNode = NULL;
00628   xmlNodePtr keyInfoNode = NULL;
00629   xmlNodePtr encKeyNode = NULL;
00630   xmlNodePtr keyInfoNode2 = NULL;
00631   xmlSecEncCtxPtr encCtx = NULL;
00632   xmlURI *to;
00633   xmlChar buf[256];
00634   xmlDocPtr doc;
00635 
00636   if (!_soap_xmlsec_enabled)
00637     return H_OK;
00638 
00639   ret = H_OK;
00640 
00641   pthread_mutex_lock(&_soap_xmlsec_lock);
00642 
00643   envelope = context->env;
00644 
00645   doc = context->env->root->doc;
00646 
00647   /* fprintf(stdout, "*** before encryption ***\n");
00648    xmlDocFormatDump(stdout, doc, 1);
00649    fprintf(stdout, "*************************\n"); */
00650 
00651   encDataNode = xmlSecTmplEncDataCreate(doc, xmlSecTransformDes3CbcId, NULL, xmlSecTypeEncElement, NULL, NULL);
00652   if (encDataNode == NULL)
00653   {
00654     log_error1("xmlSecTmplEnvDataCreate failed");
00655     ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "xmlSecTmplEnvDataCreate failed");
00656     goto out;
00657   }
00658 
00659   if (xmlSecTmplEncDataEnsureCipherValue(encDataNode) == NULL)
00660   {
00661     log_error1("failed to add CipherValue node");
00662     ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to add CipherValue node");
00663     goto out;
00664   }
00665 
00666   keyInfoNode = xmlSecTmplEncDataEnsureKeyInfo(encDataNode, NULL);
00667   if (keyInfoNode == NULL)
00668   {
00669     log_error1("failed to add KeyInfo node");
00670     ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to add KeyInfo node");
00671     goto out;
00672   }
00673 
00674   encKeyNode = xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode, xmlSecTransformRsaOaepId, NULL, NULL, NULL);
00675   if (encKeyNode == NULL)
00676   {
00677     log_error1("failed to add KeyInfo");
00678     ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to add KeyInfo");
00679     goto out;
00680   }
00681 
00682   if (xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == NULL)
00683   {
00684     log_error1("failed to add CipherValue node");
00685     ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to add CipherValue node");
00686     goto out;
00687   }
00688 
00689   keyInfoNode2 = xmlSecTmplEncDataEnsureKeyInfo(encKeyNode, NULL);
00690   if (keyInfoNode2 == NULL)
00691   {
00692     log_error1("failed to add key info (2)\n");
00693     ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to add key info (2)");
00694     goto out;
00695   }
00696 
00697   if (!(to = soap_addressing_get_to_address(envelope)))
00698   {
00699     log_error1("cannot get to address");
00700     ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT, "cannot get to address");
00701     goto out;
00702   }
00703   xmlStrPrintf(buf, 256, "http://%s:%i/key.pem", to->server, to->port);
00704   log_error2("adding key \"%s\"", buf);
00705   xmlFreeURI(to);
00706 
00707   if (xmlSecTmplKeyInfoAddKeyName(keyInfoNode2, buf) == NULL)
00708   {
00709     log_error2("failed to add key name \"%s\"", buf);
00710     ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to add key name \"%s\"", buf);
00711     goto out;
00712   }
00713 
00714   encCtx = xmlSecEncCtxCreate(_soap_xmlsec_key_manager);
00715   if (encCtx == NULL)
00716   {
00717     log_error1("failed to create encryption context");
00718     ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to create encryption context");
00719     goto out;
00720   }
00721 
00722   encCtx->encKey = xmlSecKeyGenerate(xmlSecKeyDataDesId, 192, xmlSecKeyDataTypeSession);
00723   if (encCtx->encKey == NULL)
00724   {
00725     log_error1("failed to generate session key");
00726     ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT_INIT, "failed to generate session key");
00727     goto out;
00728   }
00729 
00730   /* fprintf(stdout, "*** before encryption ***\n");
00731    xmlDocFormatDump(stdout, doc, 1);
00732    fprintf(stdout, "*************************\n"); */
00733 
00734   if (xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, soap_env_get_method(envelope)) < 0)
00735   {
00736     log_error1("encryption failed");
00737     ret = herror_new("soap_xmlsec_encrypt", XMLSEC_ERROR_ENCRYPT, "encryption failed");
00738     goto out;
00739   }
00740 
00741   /*
00742    fprintf(stdout, "*** after encryption ***\n");
00743    xmlDocFormatDump(stdout, doc, 1);
00744    fprintf(stdout, "************************\n");
00745   */
00746 
00747 out:
00748 
00749   if (encCtx != NULL)
00750     xmlSecEncCtxDestroy(encCtx);
00751 
00752   pthread_mutex_unlock(&_soap_xmlsec_lock);
00753 
00754   return ret;
00755 }
00756 
00757 herror_t soap_xmlsec_decrypt(struct SoapCtx *context)
00758 {
00759   struct SoapEnv *envelope;
00760   herror_t ret;
00761   xmlNodePtr method;
00762   xmlDocPtr  doc = NULL;
00763   xmlNodePtr  node = NULL;
00764   xmlSecEncCtxPtr  encCtx = NULL;
00765 
00766   if (!_soap_xmlsec_enabled)
00767     return H_OK;
00768 
00769   ret = H_OK;
00770 
00771   envelope = context->env;
00772 
00773   if (!(method = soap_env_get_method(envelope)))
00774   {
00775     log_error1("cannot find messages method");
00776     return herror_new("soap_xmlsec_decrypt", 0, "cannot find message method");
00777   }
00778 
00779   if (xmlStrcmp(method->name, BAD_CAST "EncryptedData"))
00780   {
00781     log_error2("message doesn't contain encrypted data (%s)", method->name);
00782     return H_OK;
00783   }
00784  
00785   if (xmlStrcmp(method->ns->href, "http://www.w3.org/2001/04/xmlenc#"))
00786   {
00787     log_error2("message encryption isn't understood (%s)", method->ns->href);
00788     return herror_new("soap_xmlsec_decrypt", 0, "message encryption isn't understood (%s)", method->ns->href);
00789   }
00790 
00791   doc = envelope->root->doc;
00792 
00793   /* XXX already checked... */
00794   node = xmlSecFindNode(envelope->root, xmlSecNodeEncryptedData, xmlSecEncNs);
00795   if (node == NULL)
00796   {
00797     log_error1("start node not found");
00798     ret = herror_new("soap_xmlsec_decrypt", 0, "start node not found");
00799     goto done;
00800   }
00801 
00802   /* create encryption context */
00803   encCtx = xmlSecEncCtxCreate(_soap_xmlsec_key_manager);
00804   if (encCtx == NULL)
00805   {
00806     log_error1("failed to create encryption context");
00807     ret = herror_new("soap_xmlsec_decrypt", 0, "failed to create encryption context");
00808     goto done;
00809   }
00810 
00811   /* decrypt the data */
00812   if ((xmlSecEncCtxDecrypt(encCtx, node) < 0) || (encCtx->result == NULL))
00813   {
00814     log_error1("decryption failed");
00815     ret = herror_new("soap_xmlsec_decrypt", 0, "decryption failed");
00816     goto done;
00817   }
00818 
00819   /* print decrypted data to stdout */
00820   /* if (encCtx->resultReplaced != 0)
00821   {
00822     fprintf(stdout, "*** after decryption ***\n");
00823     xmlDocFormatDump(stdout, doc, 1);
00824     fprintf(stdout, "************************\n");
00825   }
00826   else
00827   {
00828     fprintf(stdout, "Decrypted binary data (%d bytes):\n", xmlSecBufferGetSize(encCtx->result));
00829     if (xmlSecBufferGetData(encCtx->result) != NULL)
00830     {
00831       fwrite(xmlSecBufferGetData(encCtx->result), 1, xmlSecBufferGetSize(encCtx->result), stdout);
00832     }
00833   }
00834   fprintf(stdout, "\n"); */
00835 
00836 done:
00837 
00838   if (encCtx != NULL)
00839   {
00840     xmlSecEncCtxDestroy(encCtx);
00841   }
00842 
00843   return ret;
00844 }
00845 
00846 herror_t soap_xmlsec_verify(struct SoapCtx *context)
00847 {
00848   struct SoapEnv *envelope;
00849   xmlNodePtr walker;
00850 
00851   if (!_soap_xmlsec_enabled)
00852     return H_OK;
00853 
00854   envelope = context->env;
00855 
00856   if (!envelope->header)
00857   {
00858     log_error1("message doesn't contain a SOAP header");
00859     return herror_new("soap_xmlsec_verify", 0, "message doesn't contain a SOAP header");
00860   }
00861 
00862   for (walker=envelope->header->children; walker; walker=walker->next)
00863   {
00864     if (walker->type == XML_ELEMENT_NODE)
00865     {
00866       if (!xmlStrcmp(walker->name, "Signature"))
00867       {
00868         if (!xmlStrcmp(walker->ns->href, SOAP_SECURITY_NAMESPACE))
00869         {
00870           xmlNodePtr node;
00871           xmlSecDSigCtxPtr dsigCtx;
00872 
00873           node = xmlSecFindNode(envelope->root, xmlSecNodeSignature, xmlSecDSigNs);
00874           if (node == NULL)
00875           {
00876             log_error1("cannot find message signature");
00877             return herror_new("soap_xmlsec_verify", 0, "message signature wasn't found");
00878           }
00879 
00880           dsigCtx = xmlSecDSigCtxCreate(_soap_xmlsec_key_manager);
00881           if (dsigCtx == NULL)
00882           {
00883             log_error1("cannot create signature context");
00884             return herror_new("soap_xmlsec_verify", 0, "cannot create signatur context");
00885           }
00886 
00887           if (xmlSecDSigCtxVerify(dsigCtx, node) < 0)
00888           {
00889             log_error1("xmlsecDSigCtxVerify failed");
00890             return herror_new("soap_xmlsec_verify", 0, "verification failed");
00891           }
00892 
00893           if (dsigCtx->status == xmlSecDSigStatusSucceeded)
00894           {
00895             return H_OK;
00896           }
00897           else
00898           {
00899             log_error1("signature invalid");
00900             return herror_new("soap_xmlsec_verify", 0, "signature invalid");
00901           }
00902         }
00903         else
00904         {
00905           log_error2("message signature isn't understood (%s)", walker->ns->href);
00906           return herror_new("soap_xmlsec_verify", 0, "message signature isn't understood (%s)", walker->ns->href);
00907         }
00908       }
00909     }
00910   }
00911   return H_OK;
00912 }
00913 
00914 void soap_xmlsec_destroy(void)
00915 {
00916   if (!_soap_xmlsec_enabled)
00917     return;
00918 
00919   xmlSecKeysMngrDestroy(_soap_xmlsec_key_manager);
00920 
00921   xmlSecCryptoShutdown();
00922 
00923   xmlSecCryptoAppShutdown();
00924 
00925   xmlSecShutdown();
00926 
00927 #ifndef XMLSEC_NO_XSLT
00928   xsltCleanupGlobals();
00929 #endif
00930 
00931   return;
00932 }

Generated on Thu Jan 25 23:36:03 2007 for csoap by  doxygen 1.4.6