[core] introduce the LassoSignatureContext context, to pass around signature parameters

This structure is used to pass around the signature algorithm
and the signature key.
This commit is contained in:
Benjamin Dauvergne 2011-12-02 18:42:14 +01:00
parent 71721b370c
commit cd017964d0
11 changed files with 615 additions and 503 deletions

View File

@ -30,7 +30,7 @@ extern "C" {
#endif /* __cplusplus */
#include "profile.h"
#include "./profile.h"
struct _LassoProfilePrivate
{

View File

@ -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 {

View File

@ -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);

View File

@ -32,6 +32,7 @@
#include "../xml/private.h"
#include <xmlsec/base64.h>
#include <xmlsec/xmltree.h>
#include <config.h>
#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;
}
/**

View File

@ -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 */

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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 */

View File

@ -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();
}
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;
}

View File

@ -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 <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();
}
}

View File

@ -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");