summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Dauvergne <bdauvergne@entrouvert.com>2012-03-17 15:26:21 +0100
committerBenjamin Dauvergne <bdauvergne@entrouvert.com>2012-03-17 15:26:21 +0100
commitf42bef083667ce29e43dced8947e905febd158ef (patch)
tree420a8f236fd8c0f785fe298b13f3a2dde1b6e867
parentf55c92725510f102a778878b45561aaba8ab887d (diff)
downloadlasso-f42bef083667ce29e43dced8947e905febd158ef.tar.gz
lasso-f42bef083667ce29e43dced8947e905febd158ef.tar.xz
lasso-f42bef083667ce29e43dced8947e905febd158ef.zip
[key] add methods to send message using SAML 2.0 redirect and post bindings
-rw-r--r--lasso/key.c153
-rw-r--r--lasso/key.h10
-rw-r--r--lasso/xml/private.h8
-rw-r--r--lasso/xml/tools.c120
-rw-r--r--lasso/xml/xml.c143
-rw-r--r--lasso/xml/xml.h5
6 files changed, 368 insertions, 71 deletions
diff --git a/lasso/key.c b/lasso/key.c
index b75352b5..2f6dcecc 100644
--- a/lasso/key.c
+++ b/lasso/key.c
@@ -24,6 +24,7 @@
#include "key.h"
#include "keyprivate.h"
#include "xml/private.h"
+#include "xmlsec/xmltree.h"
/*****************************************************************************/
/* private methods */
@@ -172,7 +173,7 @@ lasso_key_new_for_signature_from_file(char *filename_or_buffer,
* Return value:(transfer full): a newly allocated #LassoKey object
*/
LassoKey*
-lasso_key_new_for_signature_from_memory(void *buffer,
+lasso_key_new_for_signature_from_memory(const void *buffer,
size_t size,
char *password,
LassoSignatureMethod signature_method,
@@ -221,6 +222,149 @@ lasso_key_new_for_signature_from_base64_string(char *base64_string,
return key;
}
+static xmlNode *
+find_xmlnode_with_saml2_id(xmlNode *xmlnode, const char *id)
+{
+ xmlNode *found = NULL;
+ xmlNode *t;
+
+ if (! xmlnode)
+ return NULL;
+
+ if (xmlHasProp(xmlnode, BAD_CAST "ID")) {
+ xmlChar *value;
+
+ value = xmlGetProp(xmlnode, BAD_CAST "ID");
+ if (lasso_strisequal((char*)value, id)) {
+ found = xmlnode;
+ }
+ xmlFree(value);
+ }
+ if (found) {
+ return found;
+ }
+ t = xmlSecGetNextElementNode(xmlnode->children);
+ while (t) {
+ found = find_xmlnode_with_saml2_id(t, id);
+ if (found) {
+ return found;
+ }
+ t = xmlSecGetNextElementNode(t->next);
+ }
+ return NULL;
+}
+
+/**
+ * lasso_key_saml2_xml_verify:
+ * @key: a #LassoKey object
+ * @id: the value of the ID attribute of signed node
+ * @document: the document containing the signed node
+ *
+ * Verify the first signature node child of the node with the given id. It follows from the profile
+ * of XMLDsig used by the SAML 2.0 specification.
+ *
+ * Return value: 0 if the signature validate, an error code otherwise.
+ */
+lasso_error_t
+lasso_key_saml2_xml_verify(LassoKey *key, char *id, xmlNode *document)
+{
+ xmlNode *signed_node;
+ LassoSignatureContext signature_context;
+
+
+ signed_node = find_xmlnode_with_saml2_id(document, id);
+ if (! signed_node) {
+ return LASSO_DS_ERROR_INVALID_REFERENCE_FOR_SAML;
+ }
+ signature_context = lasso_key_get_signature_context(key);
+ return lasso_verify_signature(signed_node, signed_node->doc, "ID", NULL,
+ signature_context.signature_key, NO_OPTION, NULL);
+}
+
+/**
+ * lasso_key_saml2_xml_sign:
+ * @key: a #LassoKey object
+ * @id: the value of the ID attribute of signed node
+ * @document: the document containing the signed node
+ *
+ * Sign the first signature node child of the node with the given id. It no signature node is found
+ * a new one is added at the end of the children list of the signed node.
+ *
+ * The passed document node is modified in-place.
+ *
+ * Return value: The modified xmlNode object, or NULL if the signature failed.
+ */
+xmlNode*
+lasso_key_saml2_xml_sign(LassoKey *key, const char *id, xmlNode *document)
+{
+ xmlNode *signed_node;
+ LassoSignatureContext signature_context;
+
+ signed_node = find_xmlnode_with_saml2_id(document, id);
+ if (! signed_node) {
+ return NULL;
+ }
+ signature_context = lasso_key_get_signature_context(key);
+ lasso_xmlnode_add_saml2_signature_template(signed_node, signature_context, id);
+ if (lasso_sign_node(signed_node, signature_context,
+ "ID", id) == 0) {
+ return document;
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ * lasso_key_query_verify:
+ * key: a #LassoKey object
+ * query: a raw HTTP query string
+ *
+ * Check if this query string contains a proper SAML2 signature for this key.
+ *
+ * Return value: 0 if a valid signature was found, an error code otherwise.
+ */
+lasso_error_t
+lasso_key_query_verify(LassoKey *key, const char *query)
+{
+ LassoSignatureContext signature_context;
+ lasso_bad_param(KEY, key);
+
+ signature_context = lasso_key_get_signature_context(key);
+ if (! lasso_validate_signature_context(signature_context))
+ return LASSO_ERROR_UNDEFINED;
+ return lasso_saml2_query_verify_signature(query, signature_context.signature_key);
+}
+
+/**
+ * lasso_key_query_verify:
+ * key: a #LassoKey object
+ * query: a raw HTTP query string
+ *
+ * Sign the given query string using the given key.
+ *
+ * Return value: the signed query string.
+ */
+char*
+lasso_key_query_sign(LassoKey *key, const char *query)
+{
+ LassoSignatureContext signature_context;
+
+ if (! LASSO_IS_KEY(key))
+ return NULL;
+ signature_context = lasso_key_get_signature_context(key);
+ if (! lasso_validate_signature_context(signature_context))
+ return NULL;
+ return lasso_query_sign((char*)query, signature_context);
+}
+
+/**
+ * lasso_key_get_signature_context:
+ * @key: a #LassoKey object
+ *
+ * Private method to extract the signature context embedded in a LassoKey object.
+ *
+ * Return value: a #LassoSignatureContext structure value.
+ */
LassoSignatureContext
lasso_key_get_signature_context(LassoKey *key) {
if (key->private_data && key->private_data->type == LASSO_KEY_TYPE_FOR_SIGNATURE) {
@@ -228,6 +372,13 @@ lasso_key_get_signature_context(LassoKey *key) {
}
return LASSO_SIGNATURE_CONTEXT_NONE;
}
+
+/**
+ * lasso_key_get_key_type:
+ * @key: a #LassoKey object
+ *
+ * Return the type of key, i.e. which operation it supports.
+ */
LassoKeyType
lasso_key_get_key_type(LassoKey *key) {
lasso_return_val_if_fail(LASSO_IS_KEY(key),
diff --git a/lasso/key.h b/lasso/key.h
index a225b0b4..ca6241ad 100644
--- a/lasso/key.h
+++ b/lasso/key.h
@@ -65,7 +65,7 @@ struct _LassoKeyClass {
LASSO_EXPORT GType lasso_key_get_type();
-LASSO_EXPORT LassoKey* lasso_key_new_for_signature_from_memory(void *buffer, size_t size,
+LASSO_EXPORT LassoKey* lasso_key_new_for_signature_from_memory(const void *buffer, size_t size,
char *password, LassoSignatureMethod signature_method, char *certificate);
LASSO_EXPORT LassoKey* lasso_key_new_for_signature_from_base64_string(char *base64_string,
@@ -74,6 +74,14 @@ LASSO_EXPORT LassoKey* lasso_key_new_for_signature_from_base64_string(char *base
LASSO_EXPORT LassoKey* lasso_key_new_for_signature_from_file(char *filename_or_buffer,
char *password, LassoSignatureMethod signature_method, char *certificate);
+LASSO_EXPORT lasso_error_t lasso_key_query_verify(LassoKey* key, const char *query);
+
+LASSO_EXPORT char* lasso_key_query_sign(LassoKey *key, const char *query);
+
+LASSO_EXPORT lasso_error_t lasso_key_saml2_xml_verify(LassoKey *key, char *id, xmlNode *document);
+
+LASSO_EXPORT xmlNode *lasso_key_saml2_xml_sign(LassoKey *key, const char *id, xmlNode *document);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/lasso/xml/private.h b/lasso/xml/private.h
index 009596d8..629d6ca5 100644
--- a/lasso/xml/private.h
+++ b/lasso/xml/private.h
@@ -275,7 +275,7 @@ lasso_create_hmac_key(const xmlSecByte * buf, xmlSecSize size);
lasso_error_t
lasso_get_hmac_key(const xmlSecKey *key, void **buffer, size_t *size);
-LassoSignatureContext lasso_make_signature_context_from_buffer(const char *buffer, size_t length,
+LassoSignatureContext lasso_make_signature_context_from_buffer(const void *buffer, size_t length,
const char *password, LassoSignatureMethod signature_method,
const char *certificate);
@@ -299,6 +299,12 @@ void set_xsi_type(xmlNode *node,
const xmlChar *type_ns_prefix,
const xmlChar *type_ns_href,
const xmlChar *type_name);
+
+void lasso_xmlnode_add_saml2_signature_template(xmlNode *node, LassoSignatureContext context,
+ const char *id);
+
+gchar* lasso_xmlnode_build_deflated_query(xmlNode *xmlnode);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/lasso/xml/tools.c b/lasso/xml/tools.c
index b31e7187..36c76a05 100644
--- a/lasso/xml/tools.c
+++ b/lasso/xml/tools.c
@@ -1012,6 +1012,17 @@ lasso_node_build_deflated_query(LassoNode *node)
{
/* actually deflated and b64'ed and url-escaped */
xmlNode *xmlnode;
+ gchar *result;
+
+ xmlnode = lasso_node_get_xmlNode(node, FALSE);
+ result = lasso_xmlnode_build_deflated_query(xmlnode);
+ xmlFreeNode(node);
+ return result;
+}
+
+gchar*
+lasso_xmlnode_build_deflated_query(xmlNode *xmlnode)
+{
xmlOutputBufferPtr buf;
xmlCharEncodingHandlerPtr handler = NULL;
xmlChar *buffer;
@@ -1021,17 +1032,12 @@ lasso_node_build_deflated_query(LassoNode *node)
int rc = 0;
z_stream stream;
- xmlnode = lasso_node_get_xmlNode(node, FALSE);
-
handler = xmlFindCharEncodingHandler("utf-8");
buf = xmlAllocOutputBuffer(handler);
xmlNodeDumpOutput(buf, NULL, xmlnode, 0, 0, "utf-8");
xmlOutputBufferFlush(buf);
buffer = buf->conv ? buf->conv->content : buf->buffer->content;
- xmlFreeNode(xmlnode);
- xmlnode = NULL;
-
in_len = strlen((char*)buffer);
ret = g_malloc(in_len * 2);
/* deflating should never increase the required size but we are
@@ -1079,6 +1085,35 @@ lasso_node_build_deflated_query(LassoNode *node)
return rret;
}
+void
+lasso_get_query_string_param_value(const char *qs, const char *param_key, char **value,
+ size_t *length)
+{
+ size_t key_size = strlen(param_key);
+
+ *value = NULL;
+ *length = 0;
+ while (qs) {
+ if (strncmp(qs, param_key, key_size) == 0 &&
+ qs[key_size] == '=')
+ {
+ char *end;
+ *value = qs[key_size+1];
+ end = strchr(*value, '&');
+ if (! end) {
+ end = strchr(*value, ';');
+ }
+ if (end) {
+ *length = (ptrdiff_t)(end - *value)
+ } else {
+ *length = strlen(*value);
+ }
+ return;
+ }
+ qs = strchr(qs, '&');
+ }
+}
+
gboolean
lasso_node_init_from_deflated_query_part(LassoNode *node, char *deflate_string)
{
@@ -2367,7 +2402,7 @@ lasso_get_hmac_key(const xmlSecKey *key, void **buffer, size_t *size)
* 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,
+lasso_make_signature_context_from_buffer(const void *buffer, size_t length, const char *password,
LassoSignatureMethod signature_method, const char *certificate) {
LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE;
@@ -2466,3 +2501,76 @@ set_xsi_type(xmlNode *node,
type_ns_href,
type_name);
}
+
+void
+lasso_xmlnode_add_saml2_signature_template(xmlNode *node, LassoSignatureContext context,
+ const char *id) {
+ xmlSecTransformId transform_id;
+ xmlNode *existing_signature = NULL, *signature = NULL, *reference, *key_info;
+ char *uri;
+
+ if (! lasso_validate_signature_context(context) || ! node)
+ return;
+
+ switch (context.signature_method) {
+ case LASSO_SIGNATURE_METHOD_RSA_SHA1:
+ transform_id = xmlSecTransformRsaSha1Id;
+ break;
+ case LASSO_SIGNATURE_METHOD_DSA_SHA1:
+ transform_id = xmlSecTransformDsaSha1Id;
+ break;
+ case LASSO_SIGNATURE_METHOD_HMAC_SHA1:
+ transform_id = xmlSecTransformHmacSha1Id;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ existing_signature = xmlSecFindChild(node, xmlSecNodeSignature, xmlSecDSigNs);
+ signature = xmlSecTmplSignatureCreate(NULL,
+ xmlSecTransformExclC14NId,
+ transform_id, NULL);
+ if (existing_signature) {
+ xmlSecReplaceNode(existing_signature, signature);
+ } else {
+ xmlAddChild(node, signature);
+ }
+
+ /* Normally the signature is son of the signed node, which holds an Id attribute, but in
+ * other cases, set snippet->offset to 0 and use xmlSecTmpSignatureAddReference from another
+ * node get_xmlNode virtual method to add the needed reference.
+ */
+ if (id) {
+ uri = g_strdup_printf("#%s", id);
+ reference = xmlSecTmplSignatureAddReference(signature,
+ xmlSecTransformSha1Id, NULL, (xmlChar*)uri, NULL);
+ lasso_release(uri);
+ }
+
+ /* add enveloped transform */
+ xmlSecTmplReferenceAddTransform(reference, xmlSecTransformEnvelopedId);
+ /* add exclusive C14N transform */
+ xmlSecTmplReferenceAddTransform(reference, xmlSecTransformExclC14NId);
+ /* if the key is the public part of an asymetric key, add its certificate or the key itself */
+ switch (context.signature_method) {
+ case LASSO_SIGNATURE_METHOD_RSA_SHA1:
+ case LASSO_SIGNATURE_METHOD_DSA_SHA1:
+ /* asymetric cryptography methods */
+ key_info = xmlSecTmplSignatureEnsureKeyInfo(signature, NULL);
+ if (xmlSecKeyGetData(context.signature_key, xmlSecOpenSSLKeyDataX509Id)) {
+ /* add <dsig:KeyInfo/> */
+ xmlSecTmplKeyInfoAddX509Data(key_info);
+ } else {
+ xmlSecTmplKeyInfoAddKeyValue(key_info);
+ }
+ break;
+ case LASSO_SIGNATURE_METHOD_HMAC_SHA1:
+ if (context.signature_key->name) {
+ key_info = xmlSecTmplSignatureEnsureKeyInfo(signature, NULL);
+ xmlSecTmplKeyInfoAddKeyName(key_info, NULL);
+
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
diff --git a/lasso/xml/xml.c b/lasso/xml/xml.c
index 53d733bd..dcdad0e9 100644
--- a/lasso/xml/xml.c
+++ b/lasso/xml/xml.c
@@ -2809,11 +2809,7 @@ lasso_node_add_signature_template(LassoNode *node, xmlNode *xmlnode,
LassoNodeClass *klass = NULL;
LassoNodeClassData *node_data = NULL;
LassoSignatureContext context;
- xmlSecTransformId transform_id;
- xmlNode *signature = NULL, *reference, *key_info;
- char *uri;
- char *id;
-
+ char *id = NULL;
node_data = lasso_legacy_get_signature_node_data(node, &klass);
if (! node_data)
@@ -2827,66 +2823,11 @@ lasso_node_add_signature_template(LassoNode *node, xmlNode *xmlnode,
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;
- case LASSO_SIGNATURE_METHOD_DSA_SHA1:
- transform_id = xmlSecTransformDsaSha1Id;
- break;
- case LASSO_SIGNATURE_METHOD_HMAC_SHA1:
- transform_id = xmlSecTransformHmacSha1Id;
- break;
- default:
- g_assert_not_reached();
- }
- signature = xmlSecTmplSignatureCreate(NULL,
- xmlSecTransformExclC14NId,
- transform_id, NULL);
- xmlAddChild(xmlnode, signature);
-
- /* Normally the signature is son of the signed node, which holds an Id attribute, but in
- * other cases, set snippet->offset to 0 and use xmlSecTmpSignatureAddReference from another
- * node get_xmlNode virtual method to add the needed reference.
- */
if (snippet_signature->offset) {
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);
- lasso_release(uri);
- }
-
- /* add enveloped transform */
- xmlSecTmplReferenceAddTransform(reference, xmlSecTransformEnvelopedId);
- /* add exclusive C14N transform */
- xmlSecTmplReferenceAddTransform(reference, xmlSecTransformExclC14NId);
- /* 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;
- case LASSO_SIGNATURE_METHOD_HMAC_SHA1:
- if (context.signature_key->name) {
- key_info = xmlSecTmplSignatureEnsureKeyInfo(signature, NULL);
- xmlSecTmplKeyInfoAddKeyName(key_info, NULL);
-
- }
- break;
- default:
- g_assert_not_reached();
}
+
+ lasso_xmlnode_add_saml2_signature_template(xmlnode, context, id);
}
static struct XmlSnippet*
@@ -3474,3 +3415,81 @@ lasso_node_get_namespace(LassoNode *node)
return (const char*)klass->node_data->ns->href;
return NULL;
}
+
+
+/**
+ * lasso_node_export_to_saml2_query:
+ * @node: the #LassoNode object to pass as a query
+ * @param_name: the key value for the query string parameter
+ * @url:(allow-none): an optional URL to prepend to the query string
+ * @key:(allow-none): a #LassoKey object
+ *
+ * Export a node as signed query string, the node must support serialization as a query.
+ *
+ * Return value: an HTTP URL or query string if successful, NULL otherwise.
+ */
+char*
+lasso_node_export_to_saml2_query(LassoNode *node, const char *param_name, const char *url,
+ LassoKey *key)
+{
+ char *value = NULL, *query = NULL, *signed_query = NULL, *result = NULL;
+ xmlChar *encoded_param = NULL;
+
+ value = lasso_node_build_deflated_query(xmlnode);
+ if (! value)
+ goto cleanup;
+ encoded_param = xmlURIEscapeStr(BAD_CAST param_name, NULL);
+ if (! encoded_param)
+ goto cleanup;
+ query = g_strdup_printf("%s=%s", encoded_param, value);
+ if (! query)
+ goto cleanup;
+ if (LASSO_IS_KEY(key)) {
+ signed_query = lasso_key_query_sign(key, query);
+ } else {
+ lasso_transfer_string(signed_query, query);
+ }
+ if (! signed_query)
+ goto cleanup;
+ if (url) {
+ result = lasso_concat_url_query(url, signed_query);
+ } else {
+ lasso_transfer_string(result, signed_query);
+ }
+
+cleanup:
+ lasso_release_string(value);
+ lasso_release_xml_string(encoded_param);
+ lasso_release_string(query);
+ lasso_release_string(signed_query);
+ return result;
+}
+
+/**
+ * lasso_node_new_from_saml2_query:
+ * @url_or_qs: an URL containing a query string or a query string only
+ * @param_name: the key value for the query string parameter to extract as a #LassoNode.
+ * @key:(allow-none): a #LassoKey object
+ *
+ * Verify the signature on a SAML-2 encoded query string and return the encoded node.
+ *
+ * Return value: a newly build #LassoNode if successful, NULL otherwise.
+ */
+LassoNode*
+lasso_node_new_from_saml2_query(const char *url_or_qs, const char *param_name, LassoKey *key)
+{
+ char *needle = NULL;
+ LassoNode *result = NULL;
+
+ if (! url_or_qs || ! param_name)
+ return NULL;
+ needle = strchr(url_or_qs, '?');
+ if (needle) {
+ url_or_qs = (const char*)(needle+1);
+ }
+ if (key) {
+ goto_cleanup_if_fail(lasso_key_query_verify(key, url_or_qs) == 0);
+ }
+cleanup:
+ return result;
+}
diff --git a/lasso/xml/xml.h b/lasso/xml/xml.h
index a0630aab..22d8b9c9 100644
--- a/lasso/xml/xml.h
+++ b/lasso/xml/xml.h
@@ -195,6 +195,11 @@ LASSO_EXPORT gchar* lasso_get_prefix_for_idwsf2_dst_service_href(const gchar *hr
LASSO_EXPORT char* lasso_node_debug(LassoNode *node, int level);
+typedef struct _LassoKey LassoKey;
+
+LASSO_EXPORT char* lasso_node_export_to_saml2_query(LassoNode *node, const char *param_name, const
+ char *url, LassoKey *key);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */