diff --git a/lasso/id-ff/profileprivate.h b/lasso/id-ff/profileprivate.h index df449ca6..3a9f563f 100644 --- a/lasso/id-ff/profileprivate.h +++ b/lasso/id-ff/profileprivate.h @@ -30,7 +30,7 @@ extern "C" { #endif /* __cplusplus */ -#include "profile.h" +#include "./profile.h" struct _LassoProfilePrivate { diff --git a/lasso/id-ff/provider.c b/lasso/id-ff/provider.c index 396f2c19..c1a157bd 100644 --- a/lasso/id-ff/provider.c +++ b/lasso/id-ff/provider.c @@ -896,6 +896,7 @@ instance_init(LassoProvider *provider) provider->private_data->encryption_public_keys = NULL; provider->private_data->encryption_mode = LASSO_ENCRYPTION_MODE_NONE; provider->private_data->encryption_sym_key_type = LASSO_ENCRYPTION_SYM_KEY_TYPE_AES_128; + provider->private_data->signature_context = LASSO_SIGNATURE_CONTEXT_NONE; /* no value_destroy_func since it shouldn't destroy the GList on insert */ provider->private_data->Descriptors = g_hash_table_new_full( @@ -1239,7 +1240,8 @@ lasso_provider_load_public_key(LassoProvider *provider, LassoPublicKeyType publi } if (public_key != NULL) { - xmlSecKey *key = lasso_xmlsec_load_private_key(public_key, NULL); + xmlSecKey *key = lasso_xmlsec_load_private_key(public_key, NULL, + LASSO_SIGNATURE_METHOD_RSA_SHA1, NULL); if (key) { lasso_list_add_new_sec_key(keys, key); } else { diff --git a/lasso/id-ff/providerprivate.h b/lasso/id-ff/providerprivate.h index 89e384d0..ff186adf 100644 --- a/lasso/id-ff/providerprivate.h +++ b/lasso/id-ff/providerprivate.h @@ -25,10 +25,14 @@ #ifndef __LASSO_PROVIDER_PRIVATE_H__ #define __LASSO_PROVIDER_PRIVATE_H__ +#include <./serverprivate.h> +#include "../xml/private.h" + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ + /** * LassoPublicKeyType: * @LASSO_PUBLIC_KEY_SIGNING: Signing public key @@ -78,6 +82,7 @@ struct _LassoProviderPrivate char *valid_until; char *cache_duration; GList *endpoints; /* of EndpointType_s */ + LassoSignatureContext signature_context; }; gboolean lasso_provider_load_metadata(LassoProvider *provider, const gchar *metadata); diff --git a/lasso/id-ff/server.c b/lasso/id-ff/server.c index f865c92f..e5d75c4a 100644 --- a/lasso/id-ff/server.c +++ b/lasso/id-ff/server.c @@ -32,6 +32,7 @@ #include "../xml/private.h" #include +#include #include #include "server.h" @@ -46,6 +47,9 @@ #include "../id-wsf-2.0/serverprivate.h" #endif +#define RSA_SHA1 "RSA_SHA1" +#define DSA_SHA1 "DSA_SHA1" + /*****************************************************************************/ /* public methods */ /*****************************************************************************/ @@ -79,9 +83,7 @@ lasso_server_add_provider_helper(LassoServer *server, LassoProviderRole role, return LASSO_SERVER_ERROR_ADD_PROVIDER_PROTOCOL_MISMATCH; } - g_hash_table_insert(server->providers, g_strdup(provider->ProviderID), provider); - - return 0; + return lasso_server_add_provider2(server, provider); } /** @@ -200,7 +202,8 @@ lasso_server_set_encryption_private_key_with_password(LassoServer *server, const gchar *filename_or_buffer, const gchar *password) { if (filename_or_buffer) { - xmlSecKey *key = lasso_xmlsec_load_private_key(filename_or_buffer, password); + xmlSecKey *key = lasso_xmlsec_load_private_key(filename_or_buffer, password, + server->signature_method, NULL); if (! key || ! (xmlSecKeyGetType(key) & xmlSecKeyDataTypePrivate)) { return LASSO_SERVER_ERROR_SET_ENCRYPTION_PRIVATE_KEY_FAILED; } @@ -271,10 +274,12 @@ get_xmlNode(LassoNode *node, gboolean lasso_dump) { LassoServer *server = LASSO_SERVER(node); char *signature_methods[] = { NULL, "RSA_SHA1", "DSA_SHA1"}; - xmlNode *xmlnode; + xmlNode *xmlnode = NULL, *ret_xmlnode = NULL; xmlnode = parent_class->get_xmlNode(node, lasso_dump); xmlSetProp(xmlnode, (xmlChar*)"ServerDumpVersion", (xmlChar*)"2"); + if (server->signature_method >= G_N_ELEMENTS(signature_methods)) + goto cleanup; xmlSetProp(xmlnode, (xmlChar*)"SignatureMethod", (xmlChar*)signature_methods[server->signature_method]); @@ -292,8 +297,11 @@ get_xmlNode(LassoNode *node, gboolean lasso_dump) #endif xmlCleanNs(xmlnode); + lasso_transfer_xml_node(ret_xmlnode, xmlnode); - return xmlnode; +cleanup: + lasso_release_xml_node(xmlnode); + return ret_xmlnode; } @@ -315,41 +323,39 @@ init_from_xml(LassoNode *node, xmlNode *xmlnode) return rc; s = xmlGetProp(xmlnode, (xmlChar*)"SignatureMethod"); - if (s && strcmp((char*)s, "RSA_SHA1") == 0) + if (lasso_strisequal((char*) s, RSA_SHA1)) server->signature_method = LASSO_SIGNATURE_METHOD_RSA_SHA1; - if (s && strcmp((char*)s, "DSA_SHA1") == 0) + else if (lasso_strisequal((char*) s, DSA_SHA1)) server->signature_method = LASSO_SIGNATURE_METHOD_DSA_SHA1; - if (s) - xmlFree(s); + else { + warning("Unable to rebuild a LassoServer object from XML, bad SignatureMethod: %s", + s); + goto_cleanup_with_rc(LASSO_XML_ERROR_OBJECT_CONSTRUCTION_FAILED); + } - t = xmlnode->children; + t = xmlSecGetNextElementNode(xmlnode->children); while (t) { - xmlNode *t2 = t->children; - - if (t->type != XML_ELEMENT_NODE) { - t = t->next; - continue; - } - /* Providers */ if (strcmp((char*)t->name, "Providers") == 0) { + xmlNode *t2 = xmlSecGetNextElementNode(t->children); + while (t2) { LassoProvider *p; - if (t2->type != XML_ELEMENT_NODE) { - t2 = t2->next; - continue; - } + p = g_object_new(LASSO_TYPE_PROVIDER, NULL); - LASSO_NODE_GET_CLASS(p)->init_from_xml(LASSO_NODE(p), t2); + lasso_check_good_rc(lasso_node_init_from_xml((LassoNode*)p, + t2)) if (lasso_provider_load_public_key(p, LASSO_PUBLIC_KEY_SIGNING)) { g_hash_table_insert(server->providers, g_strdup(p->ProviderID), p); } else { - message(G_LOG_LEVEL_CRITICAL, - "Failed to load signing public key for %s.", + critical("Failed to load signing public key for %s.", p->ProviderID); + lasso_release_gobject(p); + goto_cleanup_with_rc( + LASSO_XML_ERROR_OBJECT_CONSTRUCTION_FAILED); } - t2 = t2->next; + t2 = xmlSecGetNextElementNode(t2->next); } } @@ -358,9 +364,12 @@ init_from_xml(LassoNode *node, xmlNode *xmlnode) lasso_server_init_id_wsf20_svcmds(server, t); #endif - t = t->next; + t = xmlSecGetNextElementNode(t->next); } +cleanup: + lasso_release_xml_string(s); + return 0; } @@ -746,7 +755,154 @@ lasso_server_get_private_key(LassoServer *server) if (! server->private_key) return NULL; - return lasso_xmlsec_load_private_key(server->private_key, server->private_key_password); + return lasso_xmlsec_load_private_key(server->private_key, server->private_key_password, + server->signature_method, server->certificate); +} + +/** + * lasso_server_get_signature_context_for_provider: + * @server: a #LassoServer object + * @provider: a #LassoProvider object + * + * Find the key and signature method to sign messages adressed to @provider. If @provider has an + * override over the private key of the @server object, use this override. + * + * The returned context content is now owned by the caller, if it must survives the @server or + * @provider object life, the key should be copied. + * + * Return value: 0 if successful, an error code otherwise. + * + */ +lasso_error_t +lasso_server_get_signature_context_for_provider(LassoServer *server, + LassoProvider *provider, LassoSignatureContext *signature_context) +{ + lasso_error_t rc = 0; + LassoSignatureContext *private_context = NULL; + + lasso_bad_param(SERVER, server); + lasso_null_param(signature_context); + + if (provider) { + lasso_bad_param(PROVIDER, provider); + private_context = &provider->private_data->signature_context; + } + + if (private_context && lasso_validate_signature_method(private_context->signature_method)) { + lasso_assign_signature_context(*signature_context, *private_context); + } else { + rc = lasso_server_get_signature_context(server, signature_context); + } + + return rc; + +} + +/** + * lasso_server_get_signature_context: + * @server: a #LassoServer object + * @context: a pointer to an allocated and initialized #LassoSignatureContext structure + * + * Try to create a signature context for this server. Beware that you should better use + * lasso_server_get_signature_context_for_provider() or + * lasso_server_get_signature_context_for_provider_by_name() in mot of the case when you know the + * target for your signature, because the provider could have special signature needs, like using a + * shared secret signature. + * + * Return value: 0 if successful, an error code otherwise. + */ +lasso_error_t +lasso_server_get_signature_context(LassoServer *server, LassoSignatureContext *context) +{ + lasso_bad_param(SERVER, server); + lasso_null_param(context); + + lasso_assign_new_signature_context(*context, + lasso_make_signature_context_from_path_or_string( + server->private_key, server->private_key_password, + server->signature_method, server->certificate)); + if (! lasso_validate_signature_context(*context)) { + return LASSO_DS_ERROR_PRIVATE_KEY_LOAD_FAILED; + } + return 0; +} + +/** + * lasso_server_get_signature_context_for_provider_by_name: + * @server: a #LassoServer object + * @provider_id: the identifier of a known provider + * + * Find the key and signature method to sign messages adressed to @provider. If @provider has an + * override over the private key of the @server object, use this override. + * + * The returned context content is now owned by the caller, if it must survives the @server or + * provider object life, the key should be copied. + * + * Return value: 0 if successful, an error code otherwise. + * + */ +lasso_error_t +lasso_server_get_signature_context_for_provider_by_name(LassoServer *server, + const char *provider_id, LassoSignatureContext *signature_context) +{ + LassoProvider *provider; + lasso_bad_param(SERVER, server); + + provider = lasso_server_get_provider(server, provider_id); + return lasso_server_get_signature_context_for_provider(server, + provider, signature_context); +} + +/** + * lasso_server_set_signature_for_provider_by_name: + * @server: a #LassoServer object + * @provider_id: the identifier of a known provider + * @node: a #LassoNode object + * + * Return value: 0 if successful, an error code otherwise. + */ +lasso_error_t +lasso_server_set_signature_for_provider_by_name(LassoServer *server, const char *provider_id, LassoNode *node) +{ + LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE; + lasso_error_t rc = 0; + + lasso_check_good_rc(lasso_server_get_signature_context_for_provider_by_name(server, + provider_id, &context)); + lasso_node_set_signature(node, context); +cleanup: + return rc; +} + +/** + * lasso_server_export_to_query_for_provider_by_name: + * @server: a #LassoServer object + * @provider_id: the identifier of a known provider + * @node: a #LassoNode object + * + * Return value: 0 if successful, an error code otherwise. + */ +lasso_error_t +lasso_server_export_to_query_for_provider_by_name(LassoServer *server, const char *provider_id, LassoNode *node, char **out) +{ + LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE; + lasso_error_t rc = 0; + char *query = NULL; + + lasso_check_good_rc(lasso_server_get_signature_context_for_provider_by_name(server, + provider_id, &context)); + query = lasso_node_build_query(node); + goto_cleanup_if_fail_with_rc(query, LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED); + if (lasso_validate_signature_method(context.signature_method)) { + lasso_assign_new_string(query, lasso_query_sign(query, context)); + } + goto_cleanup_if_fail_with_rc(query, + LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED); + lasso_assign_new_string(*out, query); + context = LASSO_SIGNATURE_CONTEXT_NONE; +cleanup: + lasso_assign_new_signature_context(context, LASSO_SIGNATURE_CONTEXT_NONE); + return rc; } /** diff --git a/lasso/id-ff/serverprivate.h b/lasso/id-ff/serverprivate.h index c800edc2..4c56b42c 100644 --- a/lasso/id-ff/serverprivate.h +++ b/lasso/id-ff/serverprivate.h @@ -25,10 +25,14 @@ #ifndef __LASSO_SERVER_PRIVATE_H__ #define __LASSO_SERVER_PRIVATE_H__ +#include "./server.h" +#include "../xml/private.h" + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ + struct _LassoServerPrivate { gboolean dispose_has_run; @@ -42,6 +46,21 @@ gchar* lasso_server_get_providerID_from_hash(LassoServer *server, gchar *b64_has xmlSecKey* lasso_server_get_private_key(LassoServer *server); GList* lasso_server_get_encryption_private_keys(LassoServer *server); +lasso_error_t lasso_server_get_signature_context_for_provider(LassoServer *server, + LassoProvider *provider, LassoSignatureContext *signature_context); + +lasso_error_t lasso_server_get_signature_context_for_provider_by_name(LassoServer *server, + const char *provider_id, LassoSignatureContext *signature_context); + +lasso_error_t lasso_server_set_signature_for_provider_by_name(LassoServer *server, + const char *provider_id, LassoNode *node); + +lasso_error_t lasso_server_export_to_query_for_provider_by_name(LassoServer *server, + const char *provider_id, LassoNode *node, char **query); + +lasso_error_t lasso_server_get_signature_context(LassoServer *server, LassoSignatureContext + *context); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/lasso/saml-2.0/profile.c b/lasso/saml-2.0/profile.c index 97b5ac69..466dd576 100644 --- a/lasso/saml-2.0/profile.c +++ b/lasso/saml-2.0/profile.c @@ -52,7 +52,7 @@ static char* lasso_saml20_profile_build_artifact(LassoProvider *provider); static int lasso_saml20_profile_export_to_query(LassoProfile *profile, LassoNode *msg, char **query, - LassoSignatureMethod method, const char *private_key, const char *private_key_password); + LassoSignatureContext context); static gint lasso_profile_saml20_build_artifact_get_request_msg(LassoProfile *profile, const char *service); static gint lasso_profile_saml20_build_artifact_post_request_msg(LassoProfile *profile, @@ -61,8 +61,6 @@ static gint lasso_profile_saml20_build_artifact_get_response_msg(LassoProfile *p const char *service); static gint lasso_profile_saml20_build_artifact_post_response_msg(LassoProfile *profile, const char *service); -static gboolean has_signature(LassoNode *node, LassoSignatureMethod *signature_method, - char **private_key_file, char **private_key_password); static char* lasso_saml20_profile_generate_artifact(LassoProfile *profile, int part); #define check_msg_body \ @@ -1097,8 +1095,7 @@ cleanup: */ static int lasso_saml20_profile_export_to_query(LassoProfile *profile, LassoNode *msg, char **query, - LassoSignatureMethod signature_method, const char *private_key_file, - const char *private_key_password) { + LassoSignatureContext context) { char *unsigned_query = NULL; char *result = NULL; int rc = 0; @@ -1115,9 +1112,8 @@ lasso_saml20_profile_export_to_query(LassoProfile *profile, LassoNode *msg, char "see #3.4.3 of saml-bindings-2.0-os"); } } - if (signature_method && private_key_file && lasso_flag_add_signature) { - result = lasso_query_sign(unsigned_query, signature_method, private_key_file, - private_key_password); + if (lasso_validate_signature_method(context.signature_method)) { + result = lasso_query_sign(unsigned_query, context); goto_cleanup_if_fail_with_rc(result != NULL, LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED); lasso_transfer_string(*query, result); @@ -1130,48 +1126,6 @@ cleanup: return rc; } -static gboolean -has_signature(LassoNode *node, LassoSignatureMethod *method, char **private_key_file, - char **private_key_password) { - LassoNodeClass *klass; - LassoSignatureType sign_type; - LassoSignatureMethod sign_method; - char *key = NULL; - char *password = NULL; - - if (node == NULL) - return FALSE; - - /* new signature parameters storage */ - lasso_node_get_signature(node, &sign_type, &sign_method, &key, &password, NULL); - if (sign_type) { - *method = sign_method; - lasso_assign_string(*private_key_file, key); - lasso_assign_string(*private_key_password, password); - return TRUE; - } - - klass = LASSO_NODE_GET_CLASS(node); - /* follow the class parenting chain */ - while (klass && LASSO_IS_NODE_CLASS(klass)) { - if (klass && klass->node_data && klass->node_data->sign_type_offset != 0) { - if (G_STRUCT_MEMBER(LassoSignatureType, node, - klass->node_data->sign_type_offset) - != LASSO_SIGNATURE_TYPE_NONE) { - *method = G_STRUCT_MEMBER(LassoSignatureMethod, node, - klass->node_data->sign_method_offset); - lasso_assign_string(*private_key_file, G_STRUCT_MEMBER(char*, node, - klass->node_data->private_key_file_offset)); - /** FIXME: retrieve the stored key password */ - *private_key_password = NULL; - return TRUE; - } - } - klass = g_type_class_peek_parent(klass); - } - return FALSE; -} - /** * lasso_saml20_profile_build_http_redirect: * @profile: a #LassoProfile object @@ -1191,26 +1145,23 @@ lasso_saml20_profile_build_http_redirect(LassoProfile *profile, { char *query = NULL; int rc = 0; - LassoSignatureMethod signature_method = 0; - char *private_key_file = NULL; - char *private_key_password = NULL; + LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE; goto_cleanup_if_fail_with_rc (url != NULL, LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL); /* if message is signed, remove XML signature, add query signature */ - if (has_signature(msg, &signature_method, (char **)&private_key_file, - (char **)&private_key_password)) { + context = lasso_node_get_signature(msg); + /* We must duplicate the key since lasso_node_remove_signature will free it. */ + context.signature_key = xmlSecKeyDuplicate(context.signature_key); + if (lasso_validate_signature_method(context.signature_method)) { lasso_node_remove_signature(msg); } - lasso_check_good_rc(lasso_saml20_profile_export_to_query(profile, msg, &query, - signature_method, private_key_file, private_key_password)); + lasso_check_good_rc(lasso_saml20_profile_export_to_query(profile, msg, &query, context)); lasso_assign_new_string(profile->msg_url, lasso_concat_url_query(url, query)); lasso_release(profile->msg_body); lasso_release(query); cleanup: - lasso_release_string(private_key_file); - lasso_release_string(private_key_password); return rc; } @@ -1549,6 +1500,8 @@ gint lasso_profile_saml20_setup_message_signature(LassoProfile *profile, LassoNode *request_or_response) { lasso_bad_param(PROFILE, profile); + LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE; + lasso_error_t rc = 0; switch (lasso_profile_get_signature_hint(profile)) { case LASSO_PROFILE_SIGNATURE_HINT_MAYBE: @@ -1567,49 +1520,11 @@ lasso_profile_saml20_setup_message_signature(LassoProfile *profile, LassoNode *r if (! LASSO_IS_SERVER(profile->server)) { return LASSO_PROFILE_ERROR_MISSING_SERVER; } - if (! profile->server->private_key) { - return LASSO_DS_ERROR_PRIVATE_KEY_LOAD_FAILED; - } - if (LASSO_IS_SAMLP2_REQUEST_ABSTRACT(request_or_response)) { - LassoSamlp2RequestAbstract *request; - - request = (LassoSamlp2RequestAbstract*)request_or_response; - if (profile->server->certificate) { - request->sign_type = LASSO_SIGNATURE_TYPE_WITHX509; - } else { - request->sign_type = LASSO_SIGNATURE_TYPE_SIMPLE; - } - request->sign_method = profile->server->signature_method; - lasso_assign_string(request->private_key_file, - profile->server->private_key); - lasso_assign_string(request->certificate_file, - profile->server->certificate); - lasso_node_set_signature(request_or_response, request->sign_type, - request->sign_method, profile->server->private_key, - profile->server->private_key_password, - profile->server->certificate); - } else if (LASSO_IS_SAMLP2_STATUS_RESPONSE(request_or_response)) { - LassoSamlp2StatusResponse *response; - - response = (LassoSamlp2StatusResponse*)request_or_response; - if (profile->server->certificate) { - response->sign_type = LASSO_SIGNATURE_TYPE_WITHX509; - } else { - response->sign_type = LASSO_SIGNATURE_TYPE_SIMPLE; - } - response->sign_method = profile->server->signature_method; - lasso_assign_string(response->private_key_file, - profile->server->private_key); - lasso_assign_string(response->certificate_file, - profile->server->certificate); - lasso_node_set_signature(request_or_response, response->sign_type, - response->sign_method, profile->server->private_key, - profile->server->private_key_password, - profile->server->certificate); - } else { - return LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ; - } - return 0; + lasso_check_good_rc(lasso_server_get_signature_context_for_provider_by_name(profile->server, + profile->remote_providerID, &context)); + lasso_check_good_rc(lasso_node_set_signature(request_or_response, context)); +cleanup: + return rc; } /** diff --git a/lasso/saml-2.0/saml2_helper.c b/lasso/saml-2.0/saml2_helper.c index 4151a7b4..fdb93029 100644 --- a/lasso/saml-2.0/saml2_helper.c +++ b/lasso/saml-2.0/saml2_helper.c @@ -678,27 +678,19 @@ int lasso_server_saml2_assertion_setup_signature(LassoServer *server, LassoSaml2Assertion *saml2_assertion) { + LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE; + lasso_error_t rc = 0; + lasso_bad_param(SERVER, server); lasso_bad_param(SAML2_ASSERTION, saml2_assertion); - if (server->certificate) { - saml2_assertion->sign_type = LASSO_SIGNATURE_TYPE_WITHX509; - } else { - saml2_assertion->sign_type = LASSO_SIGNATURE_TYPE_SIMPLE; - } - saml2_assertion->sign_method = server->signature_method; - lasso_assign_string(saml2_assertion->private_key_file, - server->private_key); - lasso_assign_string(saml2_assertion->certificate_file, - server->certificate); - lasso_node_set_signature((LassoNode*)saml2_assertion, saml2_assertion->sign_type, - saml2_assertion->sign_method, server->private_key, - server->private_key_password, server->certificate); if (! saml2_assertion->ID) { lasso_assign_new_string(saml2_assertion->ID, lasso_build_unique_id(32)); } - - return 0; + lasso_check_good_rc(lasso_server_get_signature_context(server, &context)); + lasso_check_good_rc(lasso_node_set_signature((LassoNode*)saml2_assertion, context)); +cleanup: + return rc; } /** 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 #include #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 #include #include +#include +#include #include #include @@ -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(); + } + 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_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; - lasso_node_get_signature(node, &sign_type, &sign_method, &private_key_file, &private_key_password, - &certificate_file); - - if (!sign_type) { - sign_type = old_sign_type; - private_key_password = NULL; - private_key_file = old_private_key_file; - certificate_file = old_certificate_file; - } - - 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; - - 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_from_buffer(buffer, length, password, + signature_method, certificate); + if (context.signature_key) { + context.signature_method = signature_method; } + return context; +} + +/** + * 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; + + 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; - } - class = g_type_class_peek_parent(class); + 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); - /* 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); + 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); + } } 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) + + node_data = lasso_legacy_get_signature_node_data(node, &klass); + if (! node_data) + return; + + if (node_data->sign_type_offset == 0) + return; + + 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; + + switch (context.signature_method) { + case LASSO_SIGNATURE_METHOD_RSA_SHA1: + transform_id = xmlSecTransformRsaSha1Id; break; - klass = g_type_class_peek_parent(klass); + case LASSO_SIGNATURE_METHOD_DSA_SHA1: + transform_id = xmlSecTransformDsaSha1Id; + break; + default: + g_assert_not_reached(); } - - if (klass->node_data->sign_type_offset == 0) - 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 (sign_type == LASSO_SIGNATURE_TYPE_NONE) - return; - - if (sign_method == LASSO_SIGNATURE_METHOD_RSA_SHA1) { - signature = xmlSecTmplSignatureCreate(NULL, - xmlSecTransformExclC14NId, - xmlSecTransformRsaSha1Id, NULL); - } else { - signature = xmlSecTmplSignatureCreate(NULL, - xmlSecTransformExclC14NId, - xmlSecTransformDsaSha1Id, NULL); - } - /* 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 */ - 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 */ + xmlSecTmplKeyInfoAddX509Data(key_info); + } else { + xmlSecTmplKeyInfoAddKeyValue(key_info); + } + break; + default: + g_assert_not_reached(); } } diff --git a/tests/random_tests.c b/tests/random_tests.c index 100d5f6b..cb2d4171 100644 --- a/tests/random_tests.c +++ b/tests/random_tests.c @@ -278,7 +278,8 @@ START_TEST(test06_lib_statuscode) } END_TEST -extern xmlSecKey* lasso_xmlsec_load_private_key_from_buffer(const char *buffer, size_t length, const char *password); +extern xmlSecKey* lasso_xmlsec_load_private_key_from_buffer(const char *buffer, size_t length, const + char *password, LassoSignatureMethod method, const char *certificate); extern int lasso_saml2_query_verify_signature(const char *query, const xmlSecKey *sender_public_key); @@ -315,7 +316,8 @@ NC1/bzp8cGOcJ88BD5+Ny6qgPVCrMLE5twQumJ12V3SvjGNtzFBvg2c/9S5OmVqR\n\ LlTxKnCrWAXftSm1rNtewTsF\n\ -----END CERTIFICATE-----"; - xmlSecKeyPtr key = lasso_xmlsec_load_private_key_from_buffer(pkey, sizeof(pkey)-1, NULL); + xmlSecKeyPtr key = lasso_xmlsec_load_private_key_from_buffer(pkey, sizeof(pkey)-1, NULL, + LASSO_SIGNATURE_METHOD_RSA_SHA1, NULL); fail_unless(key != NULL, "Cannot load public key"); fail_unless(lasso_saml2_query_verify_signature(query1, key) == 0, "Signature was not validated");