diff options
| author | Benjamin Dauvergne <bdauvergne@entrouvert.com> | 2011-12-02 18:42:14 +0100 |
|---|---|---|
| committer | Benjamin Dauvergne <bdauvergne@entrouvert.com> | 2011-12-05 12:03:13 +0100 |
| commit | cd017964d04782f015771d00b6dffd360499c49a (patch) | |
| tree | 5690bf9af94b0d0a3d1c187116b8e1dffd7f84db /lasso/xml | |
| parent | 71721b370caa64589b238b3c6d56f275a47eceb7 (diff) | |
[core] introduce the LassoSignatureContext context, to pass around signature parameters
This structure is used to pass around the signature algorithm
and the signature key.
Diffstat (limited to 'lasso/xml')
| -rw-r--r-- | lasso/xml/private.h | 32 | ||||
| -rw-r--r-- | lasso/xml/tools.c | 374 | ||||
| -rw-r--r-- | lasso/xml/xml.c | 309 |
3 files changed, 368 insertions, 347 deletions
diff --git a/lasso/xml/private.h b/lasso/xml/private.h index 84b2ec36..cc46ac64 100644 --- a/lasso/xml/private.h +++ b/lasso/xml/private.h @@ -34,6 +34,7 @@ extern "C" { #include <xmlsec/crypto.h> #include <xmlsec/xmlenc.h> #include "saml-2.0/saml2_encrypted_element.h" +#include "../utils.h" typedef enum { SNIPPET_NODE, @@ -186,8 +187,7 @@ xmlSecKeyPtr lasso_get_public_key_from_pem_file(const char *file); xmlSecKeyPtr lasso_get_public_key_from_pem_cert_file(const char *file); xmlSecKeysMngr* lasso_load_certs_from_pem_certs_chain_file (const char *file); -char* lasso_query_sign(char *query, LassoSignatureMethod sign_method, - const char *private_key_file, const char *private_key_file_password); +char* lasso_query_sign(char *query, LassoSignatureContext signature_context); int lasso_query_verify_signature(const char *query, const xmlSecKey *public_key); @@ -197,9 +197,7 @@ char* lasso_sha1(const char *str); char** urlencoded_to_strings(const char *str); -int lasso_sign_node(xmlNode *xmlnode, const char *id_attr_name, const char *id_value, - const char *private_key_file, const char *private_key_password, - const char *certificate_file); +int lasso_sign_node(xmlNode *xmlnode, LassoSignatureContext context, const char *id_attr_name, const char *id_value); int lasso_verify_signature(xmlNode *signed_node, xmlDoc *doc, const char *id_attr_name, xmlSecKeysMngr *keys_manager, xmlSecKey *public_key, @@ -243,8 +241,9 @@ gboolean lasso_eval_xpath_expression(xmlXPathContextPtr xpath_ctx, const char *e char * lasso_get_relaystate_from_query(const char *query); char * lasso_url_add_parameters(char *url, gboolean free, ...); -xmlSecKey* lasso_xmlsec_load_private_key_from_buffer(const char *buffer, size_t length, const char *password); -xmlSecKey* lasso_xmlsec_load_private_key(const char *filename_or_buffer, const char *password); +xmlSecKey* lasso_xmlsec_load_private_key_from_buffer(const char *buffer, size_t length, const char *password, LassoSignatureMethod signature_method, const char *certificate); +xmlSecKey* lasso_xmlsec_load_private_key(const char *filename_or_buffer, const char *password, + LassoSignatureMethod signature_method, const char *certificate); xmlDocPtr lasso_xml_parse_file(const char *filepath); xmlDocPtr lasso_xml_parse_memory_with_error(const char *buffer, int size, xmlError *error); xmlSecKeyPtr lasso_xmlsec_load_key_info(xmlNode *key_descriptor); @@ -254,16 +253,9 @@ void lasso_set_string_from_prop(char **str, xmlNode *node, xmlChar *name, xmlCha void lasso_node_add_custom_namespace(LassoNode *node, const char *prefix, const char *href); -void lasso_apply_signature(LassoNode *node, gboolean lasso_dump, - xmlNode **xmlnode, char *id_attribute, char *id_value, LassoSignatureType sign_type, - char *private_key_file, char *certificate_file); +int lasso_node_set_signature(LassoNode *node, LassoSignatureContext context); -int lasso_node_set_signature(LassoNode *node, LassoSignatureType type, LassoSignatureMethod method, - const char *private_key, const char *private_key_password, const char *certificate); - -void lasso_node_get_signature(LassoNode *node, LassoSignatureType *type, LassoSignatureMethod *method, - char **private_key, char **private_key_password, - char **certificate); +LassoSignatureContext lasso_node_get_signature(LassoNode *node); void lasso_node_set_encryption(LassoNode *node, xmlSecKey *encryption_public_key, LassoEncryptionSymKeyType encryption_sym_key_type); @@ -272,6 +264,14 @@ void lasso_node_get_encryption(LassoNode *node, xmlSecKey **encryption_public_ke LassoEncryptionSymKeyType *encryption_sym_key_type); gboolean lasso_base64_decode(const char *from, char **buffer, int *buffer_len); +LassoSignatureContext lasso_make_signature_context_from_buffer(const char *buffer, size_t length, + const char *password, LassoSignatureMethod signature_method, + const char *certificate); + +LassoSignatureContext lasso_make_signature_context_from_path_or_string(char *filename_or_buffer, + const char *password, LassoSignatureMethod signature_method, + const char *certificate); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/lasso/xml/tools.c b/lasso/xml/tools.c index 5cf50637..29aa7208 100644 --- a/lasso/xml/tools.c +++ b/lasso/xml/tools.c @@ -40,6 +40,8 @@ #include <openssl/pem.h> #include <openssl/sha.h> #include <openssl/engine.h> +#include <openssl/hmac.h> +#include <openssl/evp.h> #include <xmlsec/base64.h> #include <xmlsec/crypto.h> @@ -454,16 +456,6 @@ cleanup: return keys_mngr; } -static int -_lasso_openssl_pwd_callback(char *buf, int size, G_GNUC_UNUSED int rwflag, void *u) -{ - if (u) { - strncpy(buf, u, size); - return strlen(u); - } - return 0; -} - /* * lasso_query_sign: * @query: a query (an url-encoded node) @@ -476,83 +468,87 @@ _lasso_openssl_pwd_callback(char *buf, int size, G_GNUC_UNUSED int rwflag, void * Return value: a newly allocated query signed or NULL if an error occurs. **/ char* -lasso_query_sign(char *query, LassoSignatureMethod sign_method, const char *private_key_file, - const char *private_key_file_password) +lasso_query_sign(char *query, LassoSignatureContext context) { - BIO *bio = NULL; char *digest = NULL; /* 160 bit buffer */ RSA *rsa = NULL; DSA *dsa = NULL; unsigned char *sigret = NULL; unsigned int siglen; - char *b64_sigret = NULL, *e_b64_sigret = NULL; + xmlChar *b64_sigret = NULL, *e_b64_sigret = NULL; char *new_query = NULL, *s_new_query = NULL; int status = 0; - char *t; + const xmlChar *algo_href = NULL; + xmlSecKey *key; + xmlSecKeyData *key_data; + int sigret_size; + LassoSignatureMethod sign_method; g_return_val_if_fail(query != NULL, NULL); - g_return_val_if_fail(sign_method == LASSO_SIGNATURE_METHOD_RSA_SHA1 || - sign_method == LASSO_SIGNATURE_METHOD_DSA_SHA1, NULL); - g_return_val_if_fail(private_key_file != NULL, NULL); + g_return_val_if_fail(lasso_validate_signature_method(context.signature_method), NULL); + + key = context.signature_key; + sign_method = context.signature_method; + key_data = xmlSecKeyGetValue(key); - if (access(private_key_file, R_OK) == 0) { - bio = BIO_new_file(private_key_file, "rb"); - } else { - // Safe deconst cast, the BIO is read-only - bio = BIO_new_mem_buf((char*)private_key_file, -1); - } - if (bio == NULL) { - message(G_LOG_LEVEL_CRITICAL, "Failed to open %s private key file", - private_key_file); - return NULL; - } /* add SigAlg */ switch (sign_method) { case LASSO_SIGNATURE_METHOD_RSA_SHA1: - t = (char*)xmlURIEscapeStr(xmlSecHrefRsaSha1, NULL); - new_query = g_strdup_printf("%s&SigAlg=%s", query, t); - xmlFree(t); + algo_href = xmlSecHrefRsaSha1; break; case LASSO_SIGNATURE_METHOD_DSA_SHA1: - t = (char*)xmlURIEscapeStr(xmlSecHrefDsaSha1, NULL); - new_query = g_strdup_printf("%s&SigAlg=%s", query, t); - xmlFree(t); + algo_href = xmlSecHrefDsaSha1; break; case LASSO_SIGNATURE_METHOD_NONE: case LASSO_SIGNATURE_METHOD_LAST: g_assert_not_reached(); } + { + const char *t = (char*)xmlURIEscapeStr(algo_href, NULL); + new_query = g_strdup_printf("%s&SigAlg=%s", query, t); + xmlFree(BAD_CAST t); + } + /* build buffer digest */ digest = lasso_sha1(new_query); if (digest == NULL) { message(G_LOG_LEVEL_CRITICAL, "Failed to build the buffer digest"); goto done; } + /* extract the OpenSSL key */ + switch (sign_method) { + case LASSO_SIGNATURE_METHOD_RSA_SHA1: + rsa = xmlSecOpenSSLKeyDataRsaGetRsa(key_data); + g_assert(rsa); + /* alloc memory for sigret */ + sigret_size = RSA_size(rsa); + break; + case LASSO_SIGNATURE_METHOD_DSA_SHA1: + dsa = xmlSecOpenSSLKeyDataDsaGetDsa(key_data); + g_assert(dsa); + /* alloc memory for sigret */ + sigret_size = DSA_size(dsa); + break; + default: + g_assert_not_reached(); + } + sigret = (unsigned char *)g_malloc (sigret_size); - /* calculate signature value */ - if (sign_method == LASSO_SIGNATURE_METHOD_RSA_SHA1) { - /* load private key */ - rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, _lasso_openssl_pwd_callback, - (void*)private_key_file_password); - if (rsa == NULL) { - goto done; - } - /* alloc memory for sigret */ - sigret = (unsigned char *)g_malloc (RSA_size(rsa)); - /* sign digest message */ - status = RSA_sign(NID_sha1, (unsigned char*)digest, 20, sigret, &siglen, rsa); - RSA_free(rsa); - } else if (sign_method == LASSO_SIGNATURE_METHOD_DSA_SHA1) { - dsa = PEM_read_bio_DSAPrivateKey(bio, NULL, _lasso_openssl_pwd_callback, - (void*)private_key_file_password); - if (dsa == NULL) { - goto done; - } - sigret = (unsigned char *)g_malloc (DSA_size(dsa)); - status = DSA_sign(NID_sha1, (unsigned char*)digest, 20, sigret, &siglen, dsa); - DSA_free(dsa); + switch (sign_method) { + case LASSO_SIGNATURE_METHOD_RSA_SHA1: + /* sign digest message */ + status = RSA_sign(NID_sha1, (unsigned char*)digest, 20, sigret, + &siglen, rsa); + break; + case LASSO_SIGNATURE_METHOD_DSA_SHA1: + status = DSA_sign(NID_sha1, (unsigned char*)digest, 20, sigret, + &siglen, dsa); + break; + case LASSO_SIGNATURE_METHOD_LAST: + case LASSO_SIGNATURE_METHOD_NONE: + g_assert_not_reached(); } if (status == 0) { @@ -560,17 +556,16 @@ lasso_query_sign(char *query, LassoSignatureMethod sign_method, const char *priv } /* Base64 encode the signature value */ - b64_sigret = (char*)xmlSecBase64Encode(sigret, siglen, 0); + b64_sigret = xmlSecBase64Encode(sigret, siglen, 0); /* escape b64_sigret */ - e_b64_sigret = (char*)xmlURIEscapeStr((xmlChar*)b64_sigret, NULL); + e_b64_sigret = xmlURIEscapeStr((xmlChar*)b64_sigret, NULL); /* add signature */ switch (sign_method) { case LASSO_SIGNATURE_METHOD_RSA_SHA1: - s_new_query = g_strdup_printf("%s&Signature=%s", new_query, e_b64_sigret); - break; case LASSO_SIGNATURE_METHOD_DSA_SHA1: - s_new_query = g_strdup_printf("%s&Signature=%s", new_query, e_b64_sigret); + s_new_query = g_strdup_printf("%s&Signature=%s", new_query, (char*) + e_b64_sigret); break; case LASSO_SIGNATURE_METHOD_NONE: case LASSO_SIGNATURE_METHOD_LAST: @@ -579,11 +574,10 @@ lasso_query_sign(char *query, LassoSignatureMethod sign_method, const char *priv done: lasso_release(new_query); - xmlFree(digest); - BIO_free(bio); + lasso_release_string(digest); lasso_release(sigret); - xmlFree(b64_sigret); - xmlFree(e_b64_sigret); + lasso_release_xml_string(b64_sigret); + lasso_release_xml_string(e_b64_sigret); return s_new_query; } @@ -722,7 +716,7 @@ lasso_query_verify_signature(const char *query, const xmlSecKey *sender_public_k done: xmlFree(b64_signature); xmlFree(signature); - xmlFree(digest); + lasso_release_string(digest); xmlFree(usig_alg); g_strfreev(str_split); @@ -884,7 +878,7 @@ lasso_saml2_query_verify_signature(const char *query, const xmlSecKey *sender_pu done: xmlFree(b64_signature); xmlFree(signature); - xmlFree(digest); + lasso_release_string(digest); xmlFree(usig_alg); lasso_release(components); lasso_release(query_copy); @@ -970,22 +964,21 @@ void _lasso_xmlsec_password_callback() { * Return value: 0 if successful, an error code otherwise. */ int -lasso_sign_node(xmlNode *xmlnode, const char *id_attr_name, const char *id_value, - const char *private_key_file, const char *private_key_password, - const char *certificate_file) +lasso_sign_node(xmlNode *xmlnode, LassoSignatureContext context, const char *id_attr_name, + const char *id_value) { - xmlDoc *doc; - xmlNode *sign_tmpl, *old_parent; - xmlSecDSigCtx *dsig_ctx; + xmlDoc *doc = NULL; + xmlNode *sign_tmpl = NULL, *old_parent = NULL; + xmlSecDSigCtx *dsig_ctx = NULL; xmlAttr *id_attr = NULL; - void *password_callback = NULL; + lasso_error_t rc = 0; - if (private_key_file == NULL || xmlnode == NULL) - return LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ; + g_return_val_if_fail(context.signature_method, LASSO_DS_ERROR_INVALID_SIGALG); + g_return_val_if_fail(context.signature_key, LASSO_DS_ERROR_PRIVATE_KEY_LOAD_FAILED); sign_tmpl = xmlSecFindNode(xmlnode, xmlSecNodeSignature, xmlSecDSigNs); - if (sign_tmpl == NULL) - return LASSO_DS_ERROR_SIGNATURE_TEMPLATE_NOT_FOUND; + goto_cleanup_if_fail_with_rc(sign_tmpl != NULL, + LASSO_DS_ERROR_SIGNATURE_TEMPLATE_NOT_FOUND); doc = xmlNewDoc((xmlChar*)"1.0"); old_parent = xmlnode->parent; @@ -998,52 +991,21 @@ lasso_sign_node(xmlNode *xmlnode, const char *id_attr_name, const char *id_value } dsig_ctx = xmlSecDSigCtxCreate(NULL); - if (! private_key_password) { - password_callback = _lasso_openssl_pwd_callback; - } - if (access(private_key_file, R_OK) == 0) { - dsig_ctx->signKey = xmlSecCryptoAppKeyLoad(private_key_file, - xmlSecKeyDataFormatPem, private_key_password, - password_callback, NULL /* password_callback_ctx */); - } else { - int len = private_key_file ? strlen(private_key_file) : 0; - dsig_ctx->signKey = xmlSecCryptoAppKeyLoadMemory((xmlSecByte*)private_key_file, len, - xmlSecKeyDataFormatPem, private_key_password, - password_callback, NULL /* password_callback_ctx */); - } - if (dsig_ctx->signKey == NULL) { - xmlSecDSigCtxDestroy(dsig_ctx); - return critical_error(LASSO_DS_ERROR_PRIVATE_KEY_LOAD_FAILED); - } - if (certificate_file != NULL && certificate_file[0] != 0) { - int rc = -1; - - if (access(certificate_file, R_OK) == 0) { - rc = xmlSecCryptoAppKeyCertLoad(dsig_ctx->signKey, certificate_file, - xmlSecKeyDataFormatPem); - } else { - int len = certificate_file ? strlen(certificate_file) : 0; - - rc = xmlSecCryptoAppKeyCertLoadMemory(dsig_ctx->signKey, (xmlSecByte*)certificate_file, - len, xmlSecKeyDataFormatPem); - } - if (rc < 0) { - xmlSecDSigCtxDestroy(dsig_ctx); - return critical_error(LASSO_DS_ERROR_CERTIFICATE_LOAD_FAILED); - } - } + lasso_assign_sec_key(dsig_ctx->signKey, context.signature_key); if (xmlSecDSigCtxSign(dsig_ctx, sign_tmpl) < 0) { - xmlSecDSigCtxDestroy(dsig_ctx); - return critical_error(LASSO_DS_ERROR_SIGNATURE_FAILED); + goto_cleanup_with_rc(LASSO_DS_ERROR_SIGNATURE_FAILED); } - xmlSecDSigCtxDestroy(dsig_ctx); - xmlRemoveID(doc, id_attr); - xmlUnlinkNode(xmlnode); - lasso_release_doc(doc); - xmlnode->parent = old_parent; - xmlSetTreeDoc(xmlnode, NULL); - return 0; +cleanup: + if (doc) { + xmlRemoveID(doc, id_attr); + xmlUnlinkNode(xmlnode); + lasso_release_doc(doc); + xmlnode->parent = old_parent; + xmlSetTreeDoc(xmlnode, NULL); + } + lasso_release_signature_context(dsig_ctx); + return rc; } gchar* @@ -1975,7 +1937,8 @@ cleanup: } xmlSecKey* -_lasso_xmlsec_load_key_from_buffer(const char *buffer, size_t length, const char *password) +_lasso_xmlsec_load_key_from_buffer(const char *buffer, size_t length, const char *password, + LassoSignatureMethod signature_method, const char *certificate) { int i = 0; xmlSecKeyDataFormat key_formats[] = { @@ -1988,15 +1951,53 @@ _lasso_xmlsec_load_key_from_buffer(const char *buffer, size_t length, const char xmlSecKeyDataFormatPkcs8Pem, 0 }; + xmlSecKeyDataFormat cert_formats[] = { + xmlSecKeyDataFormatCertPem, + xmlSecKeyDataFormatCertDer, + 0 + }; xmlSecKey *private_key = NULL; xmlSecErrorsDefaultCallbackEnableOutput(FALSE); - for (i = 0; key_formats[i] && private_key == NULL; i++) { - private_key = xmlSecCryptoAppKeyLoadMemory((xmlSecByte*)buffer, length, - key_formats[i], password, NULL, NULL); + switch (signature_method) { + case LASSO_SIGNATURE_METHOD_RSA_SHA1: + case LASSO_SIGNATURE_METHOD_DSA_SHA1: + for (i = 0; key_formats[i] && private_key == NULL; i++) { + private_key = xmlSecCryptoAppKeyLoadMemory((xmlSecByte*)buffer, length, + key_formats[i], password, NULL, NULL); + } + break; + case LASSO_SIGNATURE_METHOD_LAST: + case LASSO_SIGNATURE_METHOD_NONE: + g_assert_not_reached(); } - xmlSecErrorsDefaultCallbackEnableOutput(TRUE); + goto_cleanup_if_fail(private_key != NULL); + if (certificate) { + if (signature_method == LASSO_SIGNATURE_METHOD_RSA_SHA1 || signature_method == LASSO_SIGNATURE_METHOD_DSA_SHA1) { + int done = 0; + for (i=0; cert_formats[i]; i++) { + if (xmlSecCryptoAppKeyCertLoad(private_key, certificate, cert_formats[i]) + == 0) { + done = 1; + break; + } + if (xmlSecCryptoAppKeyCertLoadMemory(private_key, BAD_CAST certificate, + strlen(certificate), cert_formats[i]) == 0) { + done = 1; + break; + } + } + if (done == 0) { + warning("Unable to load certificate: %s", certificate); + } + } else { + warning("Attaching a certificate for signature only " + "works with DSA and RSA algorithms."); + } + } + xmlSecErrorsDefaultCallbackEnableOutput(TRUE); +cleanup: return private_key; } /** @@ -2040,28 +2041,29 @@ lasso_base64_decode(const char *from, char **buffer, int *buffer_len) * @password: eventually a password */ xmlSecKey* -lasso_xmlsec_load_private_key_from_buffer(const char *buffer, size_t length, const char *password) { +lasso_xmlsec_load_private_key_from_buffer(const char *buffer, size_t length, const char *password, + LassoSignatureMethod signature_method, const char *certificate) { xmlSecKey *private_key = NULL; - private_key = _lasso_xmlsec_load_key_from_buffer(buffer, length, password); + private_key = _lasso_xmlsec_load_key_from_buffer(buffer, length, password, signature_method, certificate); /* special lasso metadata hack */ if (! private_key) { - xmlChar *out; + char *out = NULL; int len; - out = xmlMalloc(length*4); - xmlSecErrorsDefaultCallbackEnableOutput(FALSE); - len = xmlSecBase64Decode(BAD_CAST buffer, out, length*4); - xmlSecErrorsDefaultCallbackEnableOutput(TRUE); - private_key = _lasso_xmlsec_load_key_from_buffer((char*)out, len, password); - xmlFree(out); + + if (lasso_base64_decode(buffer, &out, &len)) { + private_key = _lasso_xmlsec_load_key_from_buffer((char*)out, len, password, + signature_method, certificate); + } + lasso_release_string(out); } return private_key; } xmlSecKey* -lasso_xmlsec_load_private_key(const char *filename_or_buffer, const char *password) { +lasso_xmlsec_load_private_key(const char *filename_or_buffer, const char *password, LassoSignatureMethod signature_method, const char *certificate) { char *buffer = NULL; size_t length; xmlSecKey *ret; @@ -2070,9 +2072,11 @@ lasso_xmlsec_load_private_key(const char *filename_or_buffer, const char *passwo return NULL; if (g_file_get_contents(filename_or_buffer, &buffer, &length, NULL)) { - ret = lasso_xmlsec_load_private_key_from_buffer(buffer, length, password); + ret = lasso_xmlsec_load_private_key_from_buffer(buffer, length, password, signature_method, certificate); } else { - ret = lasso_xmlsec_load_private_key_from_buffer(filename_or_buffer, strlen(filename_or_buffer), password); + ret = lasso_xmlsec_load_private_key_from_buffer(filename_or_buffer, + strlen(filename_or_buffer), password, signature_method, + certificate); } lasso_release_string(buffer); return ret; @@ -2189,7 +2193,8 @@ next: content = xmlNodeGetContent(key_value); if (content) { - result = lasso_xmlsec_load_private_key_from_buffer((char*)content, strlen((char*)content), NULL); + result = lasso_xmlsec_load_private_key_from_buffer((char*)content, + strlen((char*)content), NULL, LASSO_SIGNATURE_METHOD_RSA_SHA1, NULL); xmlFree(content); } @@ -2314,46 +2319,61 @@ lasso_log_remove_handler(guint handler_id) g_log_remove_handler(LASSO_LOG_DOMAIN, handler_id); } -void -lasso_apply_signature(LassoNode *node, gboolean lasso_dump, - xmlNode **xmlnode, char *id_attribute, char *id_value, LassoSignatureType old_sign_type, char *old_private_key_file, char *old_certificate_file) -{ - int rc = 0; - LassoSignatureType sign_type = LASSO_SIGNATURE_TYPE_NONE; - LassoSignatureMethod sign_method = LASSO_SIGNATURE_METHOD_RSA_SHA1; - char *private_key_file = NULL; - char *private_key_password = NULL; - char *certificate_file = NULL; - - lasso_node_get_signature(node, &sign_type, &sign_method, &private_key_file, &private_key_password, - &certificate_file); +/** + * lasso_make_signature_context_from_buffer: + * @buffer: a byte buffer of size @length + * @length: the size of @buffer as bytes + * @password: an eventual password to decoded the private key contained in @buffer + * @signature_method: the signature method to associate to this key + * @certificate: a certificate as a file path or PEM encoded in a NULL-terminated string, to + * associate with the key, it will be used to fill the KeyInfo node in an eventual signature. + * + * Load a signature key and return an initialized #LassoSignatureContext structure. If the structure + * contains a new #xmlSecKey it must be freed by the caller. If your must store it. use + * lasso_assign_new_signature_context and not lasso_assign_signature_context which is gonna + * duplicate the key and so make a leak. + * + * Return value: an initialized LassoSignatureContext containing a freshly created @xmlSecKey object + * successful, LASSO_SIGNATURE_CONTEXT_NONE otherwise. The caller must free the #xmlSecKey. + */ +LassoSignatureContext +lasso_make_signature_context_from_buffer(const char *buffer, size_t length, const char *password, + LassoSignatureMethod signature_method, const char *certificate) { + LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE; - if (!sign_type) { - sign_type = old_sign_type; - private_key_password = NULL; - private_key_file = old_private_key_file; - certificate_file = old_certificate_file; + context.signature_key = lasso_xmlsec_load_private_key_from_buffer(buffer, length, password, + signature_method, certificate); + if (context.signature_key) { + context.signature_method = signature_method; } + return context; +} - if (lasso_dump == FALSE && sign_type) { - char *node_name; - char *prefix; - - node_name = LASSO_NODE_GET_CLASS(node)->node_data->node_name; - prefix = (char*)LASSO_NODE_GET_CLASS(node)->node_data->ns->prefix; +/** + * lasso_make_signature_context_from_path_or_string: + * @filename_or_buffer: a file path of a string containing the key PEM or Base64 encoded + * @password: an eventual password to decoded the private key contained in @buffer + * @signature_method: the signature method to associate to this key + * @certificate: a certificate as a file path or PEM encoded in a NULL-terminated string, to + * associate with the key, it will be used to fill the KeyInfo node in an eventual signature. + * + * Load a signature key and return an initialized #LassoSignatureContext structure. If the structure + * contains a new #xmlSecKey it must be freed by the caller. If your must store it. use + * lasso_assign_new_signature_context and not lasso_assign_signature_context which is gonna + * duplicate the key and so make a leak. + * + * Return value: an initialized LassoSignatureContext containing a freshly created @xmlSecKey object + * successful, LASSO_SIGNATURE_CONTEXT_NONE otherwise. + */ +LassoSignatureContext +lasso_make_signature_context_from_path_or_string(char *filename_or_buffer, const char *password, + LassoSignatureMethod signature_method, const char *certificate) { + LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE; - if (private_key_file == NULL) { - message(G_LOG_LEVEL_WARNING, - "No Private Key set for signing %s:%s", prefix, node_name); - } else { - rc = lasso_sign_node(*xmlnode, id_attribute, id_value, private_key_file, - private_key_password, certificate_file); - if (rc != 0) { - message(G_LOG_LEVEL_WARNING, "Signing of %s:%s: %s", prefix, node_name, lasso_strerror(rc)); - } - } - if (rc != 0) { - lasso_release_xml_node(*xmlnode); - } + context.signature_key = lasso_xmlsec_load_private_key(filename_or_buffer, password, + signature_method, certificate); + if (context.signature_key) { + context.signature_method = signature_method; } + return context; } diff --git a/lasso/xml/xml.c b/lasso/xml/xml.c index e4ad4465..5eda2415 100644 --- a/lasso/xml/xml.c +++ b/lasso/xml/xml.c @@ -402,22 +402,28 @@ lasso_node_export_to_query_with_password(LassoNode *node, const char *private_key_file_password) { char *unsigned_query, *query = NULL; + LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE; g_return_val_if_fail(LASSO_IS_NODE(node), NULL); - unsigned_query = lasso_node_build_query(node); - if (unsigned_query == NULL) { + context.signature_method = sign_method; + context.signature_key = lasso_xmlsec_load_private_key(private_key_file, + private_key_file_password, sign_method, NULL); + + if (! context.signature_key) { return NULL; } - if (private_key_file) { - query = lasso_query_sign(unsigned_query, sign_method, private_key_file, - private_key_file_password); - } else { - lasso_transfer_string(query, unsigned_query); - } - lasso_release(unsigned_query); - return query; + unsigned_query = lasso_node_build_query(node); + if (unsigned_query){ + query = lasso_query_sign(unsigned_query, context); + if (query) { + lasso_release(unsigned_query); + unsigned_query = query; + } + } + lasso_release_sec_key(context.signature_key); + return unsigned_query; } /** @@ -724,6 +730,52 @@ lasso_node_build_query(LassoNode *node) return class->build_query(node); } +static LassoNodeClassData* +lasso_legacy_get_signature_node_data(LassoNode *node, LassoNodeClass **out_klass) +{ + LassoNodeClass *klass = NULL; + LassoNodeClassData *node_data = NULL; + + klass = LASSO_NODE_GET_CLASS(node); + /* find a klass defining a signature */ + while (klass && LASSO_IS_NODE_CLASS(klass)) { + if (klass->node_data && klass->node_data->sign_type_offset) { + if (out_klass) { + *out_klass = klass; + } + node_data = klass->node_data; + break; + } + klass = g_type_class_peek_parent(klass); + } + + return node_data; +} + +static gboolean +lasso_legacy_extract_and_copy_signature_parameters(LassoNode *node, LassoNodeClassData *node_data) +{ + LassoSignatureMethod signature_method = LASSO_SIGNATURE_METHOD_NONE; + char *private_key_file = NULL; + char *certificate_file = NULL; + + if (! node_data) { + return FALSE; + } + signature_method = G_STRUCT_MEMBER(LassoSignatureMethod, node, + node_data->sign_method_offset); + private_key_file = G_STRUCT_MEMBER(char *, node, node_data->private_key_file_offset); + certificate_file = G_STRUCT_MEMBER(char *, node, node_data->certificate_file_offset); + if (! lasso_validate_signature_method(signature_method)) { + return FALSE; + } + if (lasso_node_set_signature(node, + lasso_make_signature_context_from_path_or_string(private_key_file, NULL, + signature_method, certificate_file)) != 0) { + return FALSE; + } + return TRUE; +} /** * lasso_node_get_xmlNode: @@ -737,35 +789,31 @@ lasso_node_build_query(LassoNode *node) xmlNode* lasso_node_get_xmlNode(LassoNode *node, gboolean lasso_dump) { - LassoNodeClass *class; - xmlNode *xmlnode; - LassoNodeClassData *node_data = NULL; + xmlNode *xmlnode = NULL; + LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE; + LassoNodeClassData *node_data; g_return_val_if_fail (LASSO_IS_NODE(node), NULL); - class = LASSO_NODE_GET_CLASS(node); - xmlnode = class->get_xmlNode(node, lasso_dump); - - /* find a class defining a signature */ - while (class && LASSO_IS_NODE_CLASS(class)) { - if (class->node_data && class->node_data->sign_type_offset) { - node_data = class->node_data; - break; + xmlnode = LASSO_NODE_GET_CLASS(node)->get_xmlNode(node, lasso_dump); + node_data = lasso_legacy_get_signature_node_data(node, NULL); + context = lasso_node_get_signature(node); + /* support for legacy way to put a signature on a node */ + if (! lasso_validate_signature_context(context)) { + if (lasso_legacy_extract_and_copy_signature_parameters(node, node_data)) + context = lasso_node_get_signature(node); + } + if (! lasso_dump && node_data && xmlnode && lasso_validate_signature_context(context)) { + int rc; + char *id_attribute = G_STRUCT_MEMBER(char*, node, + node_data->id_attribute_offset); + + rc = lasso_sign_node(xmlnode, context, node_data->id_attribute_name, + id_attribute); + if (rc != 0) { + warning("Signing of %s:%s failed: %s", xmlnode->ns->prefix, + xmlnode->name, lasso_strerror(rc)); + lasso_release_xml_node(xmlnode); } - class = g_type_class_peek_parent(class); - } - - /* add signature */ - if (xmlnode && node_data && node_data->sign_type_offset) { - LassoSignatureType sign_type = G_STRUCT_MEMBER(LassoSignatureType, node, - node_data->sign_type_offset); - char *id_attribute = G_STRUCT_MEMBER(char*, node, node_data->id_attribute_offset); - char *private_key_file = G_STRUCT_MEMBER(char*, node, - node_data->private_key_file_offset); - char *certificate_file = G_STRUCT_MEMBER(char*, node, - node_data->certificate_file_offset); - - lasso_apply_signature(node, lasso_dump, &xmlnode, node_data->id_attribute_name, - id_attribute, sign_type, private_key_file, certificate_file); } return xmlnode; @@ -873,11 +921,7 @@ struct _CustomElement { char *href; char *nodename; GHashTable *namespaces; - LassoSignatureType signature_type; - LassoSignatureMethod signature_method; - char *private_key; - char *private_key_password; - char *certificate; + LassoSignatureContext signature_context; xmlSecKey *encryption_public_key; LassoEncryptionSymKeyType encryption_sym_key_type; }; @@ -898,10 +942,8 @@ _lasso_node_free_custom_element(struct _CustomElement *custom_element) lasso_release_string(custom_element->href); lasso_release_string(custom_element->nodename); lasso_release_ghashtable(custom_element->namespaces); - lasso_release_string(custom_element->private_key); - lasso_release_string(custom_element->private_key_password); - lasso_release_string(custom_element->certificate); lasso_release_sec_key(custom_element->encryption_public_key); + lasso_release_sec_key(custom_element->signature_context.signature_key); } lasso_release(custom_element); } @@ -965,19 +1007,14 @@ lasso_node_set_custom_namespace(LassoNode *node, const char *prefix, const char /** * lasso_node_set_signature: * @node: a #LassoNode object - * @signature_type: a #LassoSignatureType enum - * @signature_method: a #LassoSignatureMethod enum - * @private_key: a private key as file path or a PEM string - * @private_key_password: the password for the private key - * @certificate: an eventual certificate to bind with the signature + * @signature_context: a #LassoSignatureContext structure * * Setup a signature on @node. * * Return value: 0 if successful, an error code otherwise. */ int -lasso_node_set_signature(LassoNode *node, LassoSignatureType type, LassoSignatureMethod method, - const char *private_key, const char *private_key_password, const char *certificate) +lasso_node_set_signature(LassoNode *node, LassoSignatureContext context) { struct _CustomElement *custom_element; int rc = 0; @@ -985,11 +1022,13 @@ lasso_node_set_signature(LassoNode *node, LassoSignatureType type, LassoSignatur lasso_bad_param(NODE, node); custom_element = _lasso_node_get_custom_element_or_create(node); g_return_val_if_fail (custom_element != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - custom_element->signature_type = type; - custom_element->signature_method = method; - lasso_assign_string(custom_element->private_key, private_key); - lasso_assign_string(custom_element->private_key_password, private_key_password); - lasso_assign_string(custom_element->certificate, certificate); + + if (custom_element->signature_context.signature_key) { + lasso_release_sec_key(custom_element->signature_context.signature_key); + } + custom_element->signature_context.signature_method = context.signature_method; + lasso_assign_new_sec_key(custom_element->signature_context.signature_key, + context.signature_key); return rc; } @@ -1004,37 +1043,17 @@ lasso_node_set_signature(LassoNode *node, LassoSignatureType type, LassoSignatur * * Return signature parameters stored with this node. */ -void -lasso_node_get_signature(LassoNode *node, LassoSignatureType *type, LassoSignatureMethod *method, - char **private_key, char **private_key_password, char **certificate) +LassoSignatureContext +lasso_node_get_signature(LassoNode *node) { struct _CustomElement *custom_element; - g_return_if_fail (LASSO_IS_NODE(node)); + g_return_val_if_fail (LASSO_IS_NODE(node), LASSO_SIGNATURE_CONTEXT_NONE); custom_element = _lasso_node_get_custom_element(node); if (! custom_element) { - if (type) - *type = 0; - if (method) - *method = 0; - if (private_key) - lasso_assign_string(*private_key, NULL); - if (private_key_password) - lasso_assign_string(*private_key_password, NULL); - if (certificate) - lasso_assign_string(*certificate, NULL); - return; + return LASSO_SIGNATURE_CONTEXT_NONE; } - if (type) - *type = custom_element->signature_type; - if (method) - *method = custom_element->signature_method; - if (private_key) - *private_key = custom_element->private_key; - if (private_key_password) - *private_key_password = custom_element->private_key_password; - if (certificate) - *certificate = custom_element->certificate; + return custom_element->signature_context; } /** @@ -1542,11 +1561,12 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode) /* Collect signature parameters */ { - LassoSignatureMethod method; - LassoSignatureType type; + LassoSignatureMethod method = 0; + LassoSignatureType type = 0; xmlChar *private_key = NULL; xmlChar *private_key_password = NULL; xmlChar *certificate = NULL; + LassoSignatureContext signature_context = LASSO_SIGNATURE_CONTEXT_NONE; while (snippet_signature) { int what; @@ -1561,7 +1581,7 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode) LASSO_SIGNATURE_TYPE_LAST)) break; type = what; - private_key = xmlGetNsProp(xmlnode, LASSO_PRIVATE_KEY_PASSWORD_ATTRIBUTE, + private_key_password = xmlGetNsProp(xmlnode, LASSO_PRIVATE_KEY_PASSWORD_ATTRIBUTE, BAD_CAST LASSO_LIB_HREF); if (! private_key) break; @@ -1569,8 +1589,11 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode) LASSO_LIB_HREF); certificate = xmlGetNsProp(xmlnode, LASSO_CERTIFICATE_ATTRIBUTE, BAD_CAST LASSO_LIB_HREF); - lasso_node_set_signature(node, type, - method, (char*) private_key, (char*) private_key_password, (char*) certificate); + + signature_context.signature_method = method; + signature_context.signature_key = lasso_xmlsec_load_private_key((char*) private_key, + (char*) private_key_password, method, (char*) certificate); + lasso_node_set_signature(node, signature_context); } lasso_release_xml_string(private_key); lasso_release_xml_string(private_key_password); @@ -1652,8 +1675,7 @@ lasso_node_remove_signature(LassoNode *node) { } klass = g_type_class_peek_parent(klass); } - lasso_node_set_signature(node, LASSO_SIGNATURE_TYPE_NONE, LASSO_SIGNATURE_METHOD_RSA_SHA1, - NULL, NULL, NULL); + lasso_node_set_signature(node, LASSO_SIGNATURE_CONTEXT_NONE); } /*****************************************************************************/ @@ -1797,37 +1819,6 @@ lasso_node_impl_get_xmlNode(LassoNode *node, gboolean lasso_dump) } } - /* store signature parameters */ - if (lasso_dump) - { - LassoSignatureType type; - LassoSignatureMethod method; - const char *private_key = NULL; - const char *private_key_password = NULL; - const char *certificate = NULL; - xmlNsPtr ns = NULL; - char buffer[64] = { 0 }; - - lasso_node_get_signature(node, &type, &method, (char **)&private_key, - (char **)&private_key_password, - (char **)&certificate); - if (private_key) { - ns = get_or_define_ns(xmlnode, BAD_CAST LASSO_LASSO_HREF); - sprintf(buffer, "%u", type); - xmlSetNsProp(xmlnode, ns, LASSO_SIGNATURE_TYPE_ATTRIBUTE, BAD_CAST buffer); - sprintf(buffer, "%u", method); - xmlSetNsProp(xmlnode, ns, LASSO_SIGNATURE_METHOD_ATTRIBUTE, BAD_CAST buffer); - xmlSetNsProp(xmlnode, ns, LASSO_PRIVATE_KEY_ATTRIBUTE, BAD_CAST private_key); - if (private_key_password) { - xmlSetNsProp(xmlnode, ns, LASSO_PRIVATE_KEY_PASSWORD_ATTRIBUTE, BAD_CAST private_key_password); - } - if (certificate) { - xmlSetNsProp(xmlnode, ns, LASSO_CERTIFICATE_ATTRIBUTE, BAD_CAST certificate); - } - } - } - - return xmlnode; } @@ -2732,50 +2723,50 @@ lasso_node_build_xmlNode_from_snippets(LassoNode *node, LassoNodeClass *class, x } } -static -void lasso_node_add_signature_template(LassoNode *node, xmlNode *xmlnode, +static void +lasso_node_add_signature_template(LassoNode *node, xmlNode *xmlnode, struct XmlSnippet *snippet_signature) { - LassoNodeClass *klass = LASSO_NODE_GET_CLASS(node); - GType g_type = G_TYPE_FROM_CLASS(klass); - LassoSignatureType sign_type; - LassoSignatureMethod sign_method; - xmlNode *signature = NULL, *reference, *key_info, *t; + LassoNodeClass *klass = NULL; + LassoNodeClassData *node_data = NULL; + LassoSignatureContext context; + xmlSecTransformId transform_id; + xmlNode *signature = NULL, *reference, *key_info; char *uri; char *id; - while (klass && LASSO_IS_NODE_CLASS(klass) && klass->node_data) { - if (klass->node_data->sign_type_offset) - break; - klass = g_type_class_peek_parent(klass); - } - if (klass->node_data->sign_type_offset == 0) + node_data = lasso_legacy_get_signature_node_data(node, &klass); + if (! node_data) return; - sign_type = G_STRUCT_MEMBER( - LassoSignatureType, node, - klass->node_data->sign_type_offset); - sign_method = G_STRUCT_MEMBER( - LassoSignatureMethod, node, - klass->node_data->sign_method_offset); + if (node_data->sign_type_offset == 0) + return; - if (sign_type == LASSO_SIGNATURE_TYPE_NONE) + context = lasso_node_get_signature(node); + if (! lasso_validate_signature_context(context)) + if (lasso_legacy_extract_and_copy_signature_parameters(node, node_data)) + context = lasso_node_get_signature(node); + + if (! lasso_validate_signature_context(context)) return; - if (sign_method == LASSO_SIGNATURE_METHOD_RSA_SHA1) { - signature = xmlSecTmplSignatureCreate(NULL, - xmlSecTransformExclC14NId, - xmlSecTransformRsaSha1Id, NULL); - } else { - signature = xmlSecTmplSignatureCreate(NULL, - xmlSecTransformExclC14NId, - xmlSecTransformDsaSha1Id, NULL); + switch (context.signature_method) { + case LASSO_SIGNATURE_METHOD_RSA_SHA1: + transform_id = xmlSecTransformRsaSha1Id; + break; + case LASSO_SIGNATURE_METHOD_DSA_SHA1: + transform_id = xmlSecTransformDsaSha1Id; + break; + default: + g_assert_not_reached(); } - /* XXX: get out if signature == NULL ? */ + signature = xmlSecTmplSignatureCreate(NULL, + xmlSecTransformExclC14NId, + transform_id, NULL); xmlAddChild(xmlnode, signature); - id = SNIPPET_STRUCT_MEMBER(char *, node, g_type, snippet_signature); + id = SNIPPET_STRUCT_MEMBER(char *, node, G_TYPE_FROM_CLASS(klass), snippet_signature); uri = g_strdup_printf("#%s", id); reference = xmlSecTmplSignatureAddReference(signature, xmlSecTransformSha1Id, NULL, (xmlChar*)uri, NULL); @@ -2785,11 +2776,21 @@ void lasso_node_add_signature_template(LassoNode *node, xmlNode *xmlnode, xmlSecTmplReferenceAddTransform(reference, xmlSecTransformEnvelopedId); /* add exclusive C14N transform */ xmlSecTmplReferenceAddTransform(reference, xmlSecTransformExclC14NId); - - if (sign_type == LASSO_SIGNATURE_TYPE_WITHX509) { - /* add <dsig:KeyInfo/> */ - key_info = xmlSecTmplSignatureEnsureKeyInfo(signature, NULL); - t = xmlSecTmplKeyInfoAddX509Data(key_info); + /* if the key is the public part of a symetric key, add its certificate or the key itself */ + switch (context.signature_method) { + case LASSO_SIGNATURE_METHOD_RSA_SHA1: + case LASSO_SIGNATURE_METHOD_DSA_SHA1: + /* symetric cryptography methods */ + key_info = xmlSecTmplSignatureEnsureKeyInfo(signature, NULL); + if (xmlSecKeyGetData(context.signature_key, xmlSecOpenSSLKeyDataX509Id)) { + /* add <dsig:KeyInfo/> */ + xmlSecTmplKeyInfoAddX509Data(key_info); + } else { + xmlSecTmplKeyInfoAddKeyValue(key_info); + } + break; + default: + g_assert_not_reached(); } } |
