summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Dauvergne <bdauvergne@entrouvert.com>2011-12-05 13:09:22 +0100
committerBenjamin Dauvergne <bdauvergne@entrouvert.com>2011-12-05 13:11:53 +0100
commit5ba292521bd6fbc2a2095769880f709042bcc68f (patch)
tree62df860dbe9e27d794e7a8daa684d05e24eb76d1
parent6c7114d5cee37e50837cf2b8d27a9f291a489773 (diff)
downloadlasso-5ba292521bd6fbc2a2095769880f709042bcc68f.tar.gz
lasso-5ba292521bd6fbc2a2095769880f709042bcc68f.tar.xz
lasso-5ba292521bd6fbc2a2095769880f709042bcc68f.zip
[core] add the HMAC-SHA1 shared secret signature method
-rw-r--r--lasso/id-ff/server.c5
-rw-r--r--lasso/xml/private.h6
-rw-r--r--lasso/xml/tools.c83
-rw-r--r--lasso/xml/xml.c10
-rw-r--r--lasso/xml/xml.h2
-rw-r--r--tests/login_tests_saml2.c100
6 files changed, 205 insertions, 1 deletions
diff --git a/lasso/id-ff/server.c b/lasso/id-ff/server.c
index e5d75c4a..c95e2713 100644
--- a/lasso/id-ff/server.c
+++ b/lasso/id-ff/server.c
@@ -49,6 +49,7 @@
#define RSA_SHA1 "RSA_SHA1"
#define DSA_SHA1 "DSA_SHA1"
+#define HMAC_SHA1 "HMAC_SHA1"
/*****************************************************************************/
/* public methods */
@@ -273,7 +274,7 @@ static xmlNode*
get_xmlNode(LassoNode *node, gboolean lasso_dump)
{
LassoServer *server = LASSO_SERVER(node);
- char *signature_methods[] = { NULL, "RSA_SHA1", "DSA_SHA1"};
+ char *signature_methods[] = { NULL, RSA_SHA1, DSA_SHA1, HMAC_SHA1};
xmlNode *xmlnode = NULL, *ret_xmlnode = NULL;
xmlnode = parent_class->get_xmlNode(node, lasso_dump);
@@ -327,6 +328,8 @@ init_from_xml(LassoNode *node, xmlNode *xmlnode)
server->signature_method = LASSO_SIGNATURE_METHOD_RSA_SHA1;
else if (lasso_strisequal((char*) s, DSA_SHA1))
server->signature_method = LASSO_SIGNATURE_METHOD_DSA_SHA1;
+ else if (lasso_strisequal((char*) s, HMAC_SHA1))
+ server->signature_method = LASSO_SIGNATURE_METHOD_HMAC_SHA1;
else {
warning("Unable to rebuild a LassoServer object from XML, bad SignatureMethod: %s",
s);
diff --git a/lasso/xml/private.h b/lasso/xml/private.h
index cc46ac64..0a301112 100644
--- a/lasso/xml/private.h
+++ b/lasso/xml/private.h
@@ -264,6 +264,12 @@ 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);
+xmlSecKeyPtr
+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,
const char *password, LassoSignatureMethod signature_method,
const char *certificate);
diff --git a/lasso/xml/tools.c b/lasso/xml/tools.c
index 47062a66..156de4b6 100644
--- a/lasso/xml/tools.c
+++ b/lasso/xml/tools.c
@@ -479,6 +479,9 @@ lasso_query_sign(char *query, LassoSignatureContext context)
char *new_query = NULL, *s_new_query = NULL;
int status = 0;
const xmlChar *algo_href = NULL;
+ char *hmac_key;
+ size_t hmac_key_length;
+ const EVP_MD *md;
xmlSecKey *key;
xmlSecKeyData *key_data;
unsigned int sigret_size = 0;
@@ -500,6 +503,9 @@ lasso_query_sign(char *query, LassoSignatureContext context)
case LASSO_SIGNATURE_METHOD_DSA_SHA1:
algo_href = xmlSecHrefDsaSha1;
break;
+ case LASSO_SIGNATURE_METHOD_HMAC_SHA1:
+ algo_href = xmlSecHrefHmacSha1;
+ break;
case LASSO_SIGNATURE_METHOD_NONE:
case LASSO_SIGNATURE_METHOD_LAST:
g_assert_not_reached();
@@ -531,6 +537,18 @@ lasso_query_sign(char *query, LassoSignatureContext context)
/* alloc memory for sigret */
sigret_size = DSA_size(dsa);
break;
+ case LASSO_SIGNATURE_METHOD_HMAC_SHA1:
+ lasso_get_hmac_key(key, (void**)&hmac_key,
+ &hmac_key_length);
+ g_assert(hmac_key);
+ md = EVP_sha1();
+ sigret_size = EVP_MD_size(md);
+ /* key should be at least 128 bits long */
+ if (hmac_key_length < 16) {
+ critical("HMAC key should be at least 128 bits long");
+ goto done;
+ }
+ break;
default:
g_assert_not_reached();
}
@@ -546,6 +564,11 @@ lasso_query_sign(char *query, LassoSignatureContext context)
status = DSA_sign(NID_sha1, (unsigned char*)digest, 20, sigret,
&siglen, dsa);
break;
+ case LASSO_SIGNATURE_METHOD_HMAC_SHA1:
+ HMAC(md, hmac_key, hmac_key_length, (unsigned char *)new_query,
+ strlen(new_query), sigret, &siglen);
+ status = 1;
+ break;
case LASSO_SIGNATURE_METHOD_LAST:
case LASSO_SIGNATURE_METHOD_NONE:
g_assert_not_reached();
@@ -566,6 +589,7 @@ lasso_query_sign(char *query, LassoSignatureContext context)
switch (sign_method) {
case LASSO_SIGNATURE_METHOD_RSA_SHA1:
case LASSO_SIGNATURE_METHOD_DSA_SHA1:
+ case LASSO_SIGNATURE_METHOD_HMAC_SHA1:
s_new_query = g_strdup_printf("%s&Signature=%s", new_query, (char*)
e_b64_sigret);
break;
@@ -613,6 +637,9 @@ lasso_query_verify_helper(const char *signed_content, const char *b64_signature,
char *digest = NULL;
xmlSecByte *signature = NULL;
int key_size = 0;
+ unsigned char *hmac_key = NULL;
+ unsigned int hmac_key_length = 0;
+ const EVP_MD *md = NULL;
lasso_error_t rc = 0;
LassoSignatureMethod method = LASSO_SIGNATURE_METHOD_NONE;
@@ -627,6 +654,11 @@ lasso_query_verify_helper(const char *signed_content, const char *b64_signature,
dsa = xmlSecOpenSSLKeyDataDsaGetDsa(key->value);
key_size = DSA_size(dsa);
method = LASSO_SIGNATURE_METHOD_DSA_SHA1;
+ } else if (lasso_strisequal(algorithm, (char*)xmlSecHrefHmacSha1)) {
+ lasso_check_good_rc(lasso_get_hmac_key(key, (void**)&hmac_key, &hmac_key_length));
+ md = EVP_sha1();
+ key_size = EVP_MD_size(md);
+ method = LASSO_SIGNATURE_METHOD_HMAC_SHA1;
} else {
goto_cleanup_with_rc(LASSO_DS_ERROR_INVALID_SIGALG);
}
@@ -665,6 +697,15 @@ lasso_query_verify_helper(const char *signed_content, const char *b64_signature,
key_size, dsa) == 1,
LASSO_DS_ERROR_INVALID_SIGNATURE);
break;
+ case LASSO_SIGNATURE_METHOD_HMAC_SHA1:
+ digest = g_malloc(key_size);
+ HMAC(md, hmac_key, hmac_key_length, (unsigned char*)signed_content,
+ strlen(signed_content), (unsigned char*)digest, NULL);
+
+ goto_cleanup_if_fail_with_rc(lasso_crypto_memequal(digest, signature,
+ key_size),
+ LASSO_DS_ERROR_INVALID_SIGNATURE);
+ break;
case LASSO_SIGNATURE_METHOD_NONE:
case LASSO_SIGNATURE_METHOD_LAST:
g_assert_not_reached();
@@ -1164,6 +1205,7 @@ lasso_saml_constrain_dsigctxt(xmlSecDSigCtxPtr dsigCtx) {
if((xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformInclC14NId) < 0) ||
(xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformExclC14NId) < 0) ||
(xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformSha1Id) < 0) ||
+ (xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformHmacSha1Id) < 0) ||
(xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformDsaSha1Id) < 0) ||
(xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformRsaSha1Id) < 0)) {
@@ -1181,6 +1223,7 @@ lasso_saml_constrain_dsigctxt(xmlSecDSigCtxPtr dsigCtx) {
/* Limit possible key info to X509, RSA and DSA */
if((xmlSecPtrListAdd(&(dsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecKeyDataX509Id) < 0) ||
+ (xmlSecPtrListAdd(&(dsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecKeyDataHmacId) < 0) ||
(xmlSecPtrListAdd(&(dsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecKeyDataRsaId) < 0) ||
(xmlSecPtrListAdd(&(dsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecKeyDataDsaId) < 0)) {
message(G_LOG_LEVEL_CRITICAL, "Error: failed to limit allowed key data");
@@ -1912,6 +1955,12 @@ _lasso_xmlsec_load_key_from_buffer(const char *buffer, size_t length, const char
key_formats[i], password, NULL, NULL);
}
break;
+ case LASSO_SIGNATURE_METHOD_HMAC_SHA1:
+ private_key = xmlSecKeyReadMemory(xmlSecKeyDataHmacId, (xmlSecByte*)buffer, length);
+ if (private_key) {
+ xmlSecKeySetName(private_key, BAD_CAST "shared");
+ }
+ break;
case LASSO_SIGNATURE_METHOD_LAST:
case LASSO_SIGNATURE_METHOD_NONE:
g_assert_not_reached();
@@ -2265,6 +2314,40 @@ lasso_log_remove_handler(guint handler_id)
}
/**
+ * lasso_get_hmac_key:
+ * @key: an #xmlSecKey object
+ * @buffer: a byte buffer of size @size
+ * @size: the size of @buffer as bytes
+ *
+ * Extract the symetric HMAC key from the #xmlSecKey structure and place a pointer to i into the
+ * buffer variable.
+ *
+ * Return value: 0 if successful, an error code otherwise.
+ */
+lasso_error_t
+lasso_get_hmac_key(const xmlSecKey *key, void **buffer, size_t *size)
+{
+ xmlSecKeyDataPtr key_data;
+ xmlSecBufferPtr key_data_buffer;
+
+ lasso_null_param(key);
+ lasso_null_param(buffer);
+ lasso_null_param(size);
+
+ if (key->value->id != xmlSecKeyDataHmacId) {
+ return LASSO_PARAM_ERROR_INVALID_VALUE;
+ }
+ key_data = xmlSecKeyGetValue((xmlSecKeyPtr)key);
+ g_return_val_if_fail(key_data, LASSO_PARAM_ERROR_INVALID_VALUE);
+ key_data_buffer = xmlSecKeyDataBinaryValueGetBuffer(key_data);
+ g_return_val_if_fail(key_data_buffer, LASSO_PARAM_ERROR_INVALID_VALUE);
+ *buffer = xmlSecBufferGetData(key_data_buffer);
+ *size = xmlSecBufferGetSize(key_data_buffer);
+ g_return_val_if_fail(*buffer && *size, LASSO_PARAM_ERROR_INVALID_VALUE);
+ return 0;
+}
+
+/**
* lasso_make_signature_context_from_buffer:
* @buffer: a byte buffer of size @length
* @length: the size of @buffer as bytes
diff --git a/lasso/xml/xml.c b/lasso/xml/xml.c
index 5eda2415..ed6aa5ce 100644
--- a/lasso/xml/xml.c
+++ b/lasso/xml/xml.c
@@ -2758,6 +2758,9 @@ lasso_node_add_signature_template(LassoNode *node, xmlNode *xmlnode,
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();
}
@@ -2789,6 +2792,13 @@ lasso_node_add_signature_template(LassoNode *node, xmlNode *xmlnode,
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.h b/lasso/xml/xml.h
index cf735e7b..a0630aab 100644
--- a/lasso/xml/xml.h
+++ b/lasso/xml/xml.h
@@ -93,6 +93,7 @@ typedef enum {
* LassoSignatureMethod:
* @LASSO_SIGNATURE_METHOD_RSA_SHA1: sign using a RSA private key
* @LASSO_SIGNATURE_METHOD_DSA_SHA1: sign using a DSA private key
+ * @LASSO_SIGNATURE_METHOD_HMAC_SHA1: sign using a an HMAC-SHA1 secret key
*
* Signature method.
**/
@@ -100,6 +101,7 @@ typedef enum {
LASSO_SIGNATURE_METHOD_NONE = 0,
LASSO_SIGNATURE_METHOD_RSA_SHA1,
LASSO_SIGNATURE_METHOD_DSA_SHA1,
+ LASSO_SIGNATURE_METHOD_HMAC_SHA1,
LASSO_SIGNATURE_METHOD_LAST
} LassoSignatureMethod;
diff --git a/tests/login_tests_saml2.c b/tests/login_tests_saml2.c
index 448e1fa6..bd174e50 100644
--- a/tests/login_tests_saml2.c
+++ b/tests/login_tests_saml2.c
@@ -900,6 +900,103 @@ START_TEST(test06_sso_sp_with_key_rollover)
}
END_TEST
+#define test07_make_context(ctx, server_prefix, provider_role, provider_prefix, key) \
+ ctx = lasso_server_new( \
+ TESTSDATADIR server_prefix "/metadata.xml", \
+ NULL, \
+ NULL, /* Secret key to unlock private key */ \
+ NULL); \
+ check_not_null(ctx); \
+ check_good_rc(lasso_server_add_provider( \
+ ctx, \
+ provider_role, \
+ TESTSDATADIR provider_prefix "/metadata.xml", \
+ NULL, \
+ NULL)); \
+ providers = g_hash_table_get_values(ctx->providers); \
+ check_not_null(providers); \
+ lasso_provider_set_specific_signing_key(LASSO_PROVIDER(providers->data), \
+ key); \
+ lasso_provider_add_key(LASSO_PROVIDER(providers->data), key, FALSE); \
+ g_list_free(providers);
+
+static void
+sso_initiated_by_sp(LassoServer *idp_context, LassoServer *sp_context)
+{
+ LassoLogin *idp_login_context;
+ LassoLogin *sp_login_context;
+ char *authn_request_query;
+
+ check_not_null(idp_login_context = lasso_login_new(idp_context));
+ check_not_null(sp_login_context = lasso_login_new(sp_context))
+
+ /* Create response */
+ check_good_rc(lasso_login_init_authn_request(sp_login_context, NULL, LASSO_HTTP_METHOD_REDIRECT));
+
+ lasso_assign_string(LASSO_SAMLP2_AUTHN_REQUEST(sp_login_context->parent.request)->ProtocolBinding,
+ LASSO_SAML2_METADATA_BINDING_POST);
+ lasso_assign_string(LASSO_SAMLP2_AUTHN_REQUEST(sp_login_context->parent.request)->NameIDPolicy->Format,
+ LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT);
+ LASSO_SAMLP2_AUTHN_REQUEST(sp_login_context->parent.request)->NameIDPolicy->AllowCreate = 1;
+ check_good_rc(lasso_login_build_authn_request_msg(sp_login_context));
+ check_not_null(sp_login_context->parent.msg_url);
+ printf("authn_request: %s", sp_login_context->parent.msg_url);
+ authn_request_query = strchr(sp_login_context->parent.msg_url, '?');
+ check_not_null(authn_request_query);
+ authn_request_query += 1;
+ check_good_rc(lasso_login_process_authn_request_msg(idp_login_context, authn_request_query));
+
+ check_good_rc(lasso_login_validate_request_msg(idp_login_context,
+ 1, /* authentication_result */
+ 0 /* is_consent_obtained */
+ ));
+
+ check_good_rc(lasso_login_build_assertion(idp_login_context,
+ LASSO_SAML_AUTHENTICATION_METHOD_PASSWORD,
+ "FIXME: authenticationInstant",
+ "FIXME: reauthenticateOnOrAfter",
+ "FIXME: notBefore",
+ "FIXME: notOnOrAfter"));
+ check_good_rc(lasso_login_build_authn_response_msg(idp_login_context));
+ check_not_null(idp_login_context->parent.msg_body);
+ check_not_null(idp_login_context->parent.msg_url);
+ printf("Xml Response: %s\n", lasso_node_export_to_xml(idp_login_context->parent.response));
+
+ /* Process response */
+ check_good_rc(lasso_login_process_authn_response_msg(sp_login_context,
+ idp_login_context->parent.msg_body));
+ check_good_rc(lasso_login_accept_sso(sp_login_context));
+
+ /* Cleanup */
+ lasso_release_gobject(idp_login_context);
+ lasso_release_gobject(sp_login_context);
+}
+
+START_TEST(test07_sso_sp_with_hmac_sha1_signatures)
+{
+ LassoServer *idp_context = NULL;
+ LassoServer *sp_context = NULL;
+ GList *providers;
+ LassoKey *key = NULL;
+
+ /* Create the shared key */
+ key = lasso_key_new_for_signature_from_memory("xxxxxxxxxxxxxxxx", 16,
+ NULL, LASSO_SIGNATURE_METHOD_HMAC_SHA1, NULL);
+ check_true(LASSO_IS_KEY(key));
+
+ /* Create an IdP context for IdP initiated SSO with provider metadata 1 */
+ test07_make_context(idp_context, "idp6-saml2", LASSO_PROVIDER_ROLE_SP, "sp6-saml2", key)
+ test07_make_context(sp_context, "sp6-saml2", LASSO_PROVIDER_ROLE_IDP, "idp6-saml2", key)
+
+ sso_initiated_by_sp(idp_context, sp_context);
+
+ /* Cleanup */
+ lasso_release_gobject(idp_context);
+ lasso_release_gobject(sp_context);
+ lasso_release_gobject(key);
+}
+END_TEST
+
Suite*
login_saml2_suite()
{
@@ -910,18 +1007,21 @@ login_saml2_suite()
TCase *tc_spSloSoap = tcase_create("Login initiated by service provider without key loading and with SLO SOAP");
TCase *tc_idpKeyRollover = tcase_create("Login initiated by idp, idp use two differents signing keys (simulate key roll-over)");
TCase *tc_spKeyRollover = tcase_create("Login initiated by idp, sp use two differents encrypting keys (simulate key roll-over)");
+ TCase *tc_hmacSignature = tcase_create("Login initiated by sp, using shared-key signature");
suite_add_tcase(s, tc_generate);
suite_add_tcase(s, tc_spLogin);
suite_add_tcase(s, tc_spLoginMemory);
suite_add_tcase(s, tc_spSloSoap);
suite_add_tcase(s, tc_idpKeyRollover);
suite_add_tcase(s, tc_spKeyRollover);
+ suite_add_tcase(s, tc_hmacSignature);
tcase_add_test(tc_generate, test01_saml2_generateServersContextDumps);
tcase_add_test(tc_spLogin, test02_saml2_serviceProviderLogin);
tcase_add_test(tc_spLoginMemory, test03_saml2_serviceProviderLogin);
tcase_add_test(tc_spSloSoap, test04_sso_then_slo_soap);
tcase_add_test(tc_idpKeyRollover, test05_sso_idp_with_key_rollover);
tcase_add_test(tc_spKeyRollover, test06_sso_sp_with_key_rollover);
+ tcase_add_test(tc_hmacSignature, test07_sso_sp_with_hmac_sha1_signatures);
return s;
}