[core] add the HMAC-SHA1 shared secret signature method

This commit is contained in:
Benjamin Dauvergne 2011-12-05 13:09:22 +01:00
parent 6c7114d5ce
commit 5ba292521b
6 changed files with 205 additions and 1 deletions

View File

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

View File

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

View File

@ -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();
@ -2264,6 +2313,40 @@ lasso_log_remove_handler(guint handler_id)
g_log_remove_handler(LASSO_LOG_DOMAIN, 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

View File

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

View File

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

View File

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