[core] add flags parameter to lasso_server_load_metadata to tune signature checking on metadata files

The flags parameter allows to control the checking of digital signature
upon EntityDescriptor and EntitiesDescriptor nodes in SAML 2.0 metadata
files.

The default behaviour is to check all found signatures and to inherit
signature from EntitiesDescriptor to their children.

By only enabling checking of EntityDescrtiptor node signatures it's also
possible to only check signature at the EntityDescriptor level and so
only trust individual entities and not the aggregating provider.
This commit is contained in:
Benjamin Dauvergne 2011-04-14 16:45:43 +02:00
parent 1171ee2e8b
commit 8be7b0414d
6 changed files with 109 additions and 31 deletions

View File

@ -760,6 +760,8 @@ lasso_server_get_encryption_private_key(LassoServer *server)
* loaded, can be NULL.
* @loaded_entity_ids:(transfer full)(element-type string)(allow-none): an output parameter for the
* list of the loaded EntityID, can be NULL.
* @flags: flags modifying the behaviour for checking signatures on EntityDescriptor and
* EntitiesDescriptors nodes.
*
* Load all the SAML 2.0 entities from @federation_file which contains a declaration for @role. If
* @trusted_roots is non-NULL, use it to check a signature on the metadata file, otherwise ignore
@ -778,18 +780,24 @@ lasso_server_get_encryption_private_key(LassoServer *server)
*/
lasso_error_t
lasso_server_load_metadata(LassoServer *server, LassoProviderRole role, const gchar *federation_file,
const gchar *trusted_roots, GList *blacklisted_entity_ids, GList **loaded_entity_ids)
const gchar *trusted_roots, GList *blacklisted_entity_ids,
GList **loaded_entity_ids, enum LassoServerLoadMetadataFlag flags)
{
xmlDoc *doc = NULL;
xmlNode *root = NULL;
xmlSecKeysMngr *keys_mngr = NULL;
lasso_error_t rc = 0;
GList *uri_references = NULL;
lasso_bad_param(SERVER, server);
g_return_val_if_fail(role == LASSO_PROVIDER_ROLE_SP || role == LASSO_PROVIDER_ROLE_IDP,
LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
if (flags == LASSO_SERVER_LOAD_METADATA_FLAG_DEFAULT) {
flags = LASSO_SERVER_LOAD_METADATA_FLAG_CHECK_ENTITIES_DESCRIPTOR_SIGNATURE
| LASSO_SERVER_LOAD_METADATA_FLAG_CHECK_ENTITY_DESCRIPTOR_SIGNATURE
| LASSO_SERVER_LOAD_METADATA_FLAG_INHERIT_SIGNATURE;
}
if (trusted_roots) {
keys_mngr = lasso_load_certs_from_pem_certs_chain_file(trusted_roots);
lasso_return_val_if_fail(keys_mngr != NULL,
@ -798,20 +806,14 @@ lasso_server_load_metadata(LassoServer *server, LassoProviderRole role, const gc
doc = lasso_xml_parse_file(federation_file);
goto_cleanup_if_fail_with_rc(doc, LASSO_SERVER_ERROR_INVALID_XML);
root = xmlDocGetRootElement(doc);
if (trusted_roots) {
/* check metadata file signature */
lasso_check_good_rc(lasso_verify_signature(root, doc, "ID", keys_mngr, NULL,
EMPTY_URI, &uri_references));
}
if (lasso_strisequal((char*)root->ns->href, LASSO_SAML2_METADATA_HREF)) {
lasso_check_good_rc(lasso_saml20_server_load_metadata(server, role, root,
blacklisted_entity_ids, loaded_entity_ids));
lasso_check_good_rc(lasso_saml20_server_load_metadata(server, role, doc, root,
blacklisted_entity_ids, loaded_entity_ids, keys_mngr, flags));
} else {
goto_cleanup_with_rc(LASSO_ERROR_UNIMPLEMENTED);
}
cleanup:
lasso_release_list_of_strings(uri_references);
lasso_release_key_manager(keys_mngr);
lasso_release_doc(doc);
return rc;

View File

@ -67,6 +67,24 @@ struct _LassoServerClass {
LassoProviderClass parent;
};
/**
* LassoServerLoadMetadataFlag:
* @LASSO_SERVER_LOAD_METADATA_FLAG_DEFAULT: the default policy is to check signature on entity and
* entities descriptor, and to let signature be inherited by child nodes.
* @LASSO_SERVER_LOAD_METADATA_FLAG_CHECK_ENTITIES_DESCRIPTOR_SIGNATURE: check signature on
* EntitiesDesctiptor nodes,
* @LASSO_SERVER_LOAD_METADATA_FLAG_CHECK_ENTITY_DESCRIPTOR_SIGNATURE: check signature on
* EntityDescriptor nodes,
* @LASSO_SERVER_LOAD_METADATA_FLAG_INHERIT_SIGNATURE: when an EntitiesDescriptor is signed, all its
* children inherit the trust from this signature and their signature is not checked.
*/
enum LassoServerLoadMetadataFlag {
LASSO_SERVER_LOAD_METADATA_FLAG_DEFAULT = 0,
LASSO_SERVER_LOAD_METADATA_FLAG_CHECK_ENTITIES_DESCRIPTOR_SIGNATURE = 1,
LASSO_SERVER_LOAD_METADATA_FLAG_CHECK_ENTITY_DESCRIPTOR_SIGNATURE = 2,
LASSO_SERVER_LOAD_METADATA_FLAG_INHERIT_SIGNATURE = 4
};
LASSO_EXPORT GType lasso_server_get_type(void);
LASSO_EXPORT LassoServer* lasso_server_new(const gchar *metadata,
@ -104,7 +122,9 @@ LASSO_EXPORT lasso_error_t lasso_server_set_encryption_private_key_with_password
const gchar *filename_or_buffer, const gchar *password);
LASSO_EXPORT lasso_error_t lasso_server_load_metadata(LassoServer *server, LassoProviderRole role,
const gchar *federation_file, const gchar *trusted_roots, GList *blacklisted_entity_ids, GList **loaded_entity_ids);
const gchar *federation_file, const gchar *trusted_roots, GList
*blacklisted_entity_ids, GList **loaded_entity_ids,
enum LassoServerLoadMetadataFlag flags);
#ifdef __cplusplus
}

View File

@ -88,6 +88,15 @@ lasso_saml20_server_load_affiliation(LassoServer *server, xmlNode *node)
return 0;
}
static void
debug_report_signature_error(xmlNode *node, lasso_error_t result) {
xmlChar *path;
path = xmlGetNodePath(node);
debug("Could not check signature whose xpath is '%s': %s", path, lasso_strerror(result));
lasso_release_xml_string(path);
}
static gboolean
_lasso_test_sp_descriptor(xmlNode *node) {
return xmlSecFindChild(node,
@ -104,9 +113,11 @@ _lasso_test_idp_descriptor(xmlNode *node) {
static lasso_error_t
lasso_saml20_server_load_metadata_entity(LassoServer *server, LassoProviderRole role,
xmlNode *entity, GList *blacklisted_entity_ids, GList **loaded_end)
xmlDoc *doc, xmlNode *entity, GList *blacklisted_entity_ids, GList **loaded_end,
xmlSecKeysMngr *keys_mngr, enum LassoServerLoadMetadataFlag flags)
{
LassoProvider *provider = NULL;
gboolean check_signature = flags & LASSO_SERVER_LOAD_METADATA_FLAG_CHECK_ENTITY_DESCRIPTOR_SIGNATURE;
if (role == LASSO_PROVIDER_ROLE_IDP && ! _lasso_test_idp_descriptor(entity)) {
return 0;
@ -115,6 +126,17 @@ lasso_saml20_server_load_metadata_entity(LassoServer *server, LassoProviderRole
return 0;
}
if (keys_mngr && check_signature) {
lasso_error_t result;
result = lasso_verify_signature(entity, doc, "ID", keys_mngr, NULL, EMPTY_URI,
NULL);
if (result != 0) {
debug_report_signature_error(entity, result);
return result;
}
}
provider = lasso_provider_new_from_xmlnode(role, entity);
if (provider) {
char *name = g_strdup(provider->ProviderID);
@ -127,6 +149,7 @@ lasso_saml20_server_load_metadata_entity(LassoServer *server, LassoProviderRole
if (*loaded_end) {
GList *l = *loaded_end;
l->next = g_new0(GList, 1);
l->next->prev = l;
l->next->data = g_strdup(name);
*loaded_end = l->next;
}
@ -138,22 +161,41 @@ lasso_saml20_server_load_metadata_entity(LassoServer *server, LassoProviderRole
}
static lasso_error_t lasso_saml20_server_load_metadata_child(LassoServer *server,
LassoProviderRole role, xmlNode *child, GList *blacklisted_entity_ids,
GList **loaded_end);
LassoProviderRole role, xmlDoc *doc, xmlNode *child, GList *blacklisted_entity_ids,
GList **loaded_end, xmlSecKeysMngr *keys_mngr, enum LassoServerLoadMetadataFlag flags);
static lasso_error_t
lasso_saml20_server_load_metadata_entities(LassoServer *server, LassoProviderRole role, xmlNode *entities,
GList *blacklisted_entity_ids, GList **loaded_end)
lasso_saml20_server_load_metadata_entities(LassoServer *server, LassoProviderRole role, xmlDoc *doc, xmlNode *entities,
GList *blacklisted_entity_ids, GList **loaded_end,
xmlSecKeysMngr *keys_mngr, enum LassoServerLoadMetadataFlag flags)
{
xmlNode *child;
gboolean at_least_one = FALSE;
gboolean check_signature = flags & LASSO_SERVER_LOAD_METADATA_FLAG_CHECK_ENTITIES_DESCRIPTOR_SIGNATURE;
gboolean inherit_signature = flags & LASSO_SERVER_LOAD_METADATA_FLAG_INHERIT_SIGNATURE;
/* if a key store is passed, check signature */
if (keys_mngr && check_signature) {
lasso_error_t result;
result = lasso_verify_signature(entities, doc, "ID", keys_mngr, NULL, EMPTY_URI,
NULL);
if (result == 0) {
if (inherit_signature) {
keys_mngr = NULL;
}
} else {
debug_report_signature_error(entities, result);
return result;
}
}
child = xmlSecGetNextElementNode(entities->children);
while (child) {
lasso_error_t rc = 0;
rc = lasso_saml20_server_load_metadata_child(server, role, child,
blacklisted_entity_ids, loaded_end);
rc = lasso_saml20_server_load_metadata_child(server, role, doc, child,
blacklisted_entity_ids, loaded_end, keys_mngr, flags);
if (rc == 0) {
at_least_one = TRUE;
}
@ -163,19 +205,20 @@ lasso_saml20_server_load_metadata_entities(LassoServer *server, LassoProviderRol
}
static lasso_error_t
lasso_saml20_server_load_metadata_child(LassoServer *server, LassoProviderRole role, xmlNode *child,
GList *blacklisted_entity_ids, GList **loaded_end)
lasso_saml20_server_load_metadata_child(LassoServer *server, LassoProviderRole role, xmlDoc *doc,
xmlNode *child, GList *blacklisted_entity_ids, GList **loaded_end,
xmlSecKeysMngr *keys_mngr, enum LassoServerLoadMetadataFlag flags)
{
if (xmlSecCheckNodeName(child,
BAD_CAST LASSO_SAML2_METADATA_ELEMENT_ENTITY_DESCRIPTOR,
BAD_CAST LASSO_SAML2_METADATA_HREF)) {
return lasso_saml20_server_load_metadata_entity(server, role, child,
blacklisted_entity_ids, loaded_end);
return lasso_saml20_server_load_metadata_entity(server, role, doc, child,
blacklisted_entity_ids, loaded_end, keys_mngr, flags);
} else if (xmlSecCheckNodeName(child,
BAD_CAST LASSO_SAML2_METADATA_ELEMENT_ENTITIES_DESCRIPTOR,
BAD_CAST LASSO_SAML2_METADATA_HREF)) {
return lasso_saml20_server_load_metadata_entities(server, role, child,
blacklisted_entity_ids, loaded_end);
return lasso_saml20_server_load_metadata_entities(server, role, doc, child,
blacklisted_entity_ids, loaded_end, keys_mngr, flags);
}
return LASSO_SERVER_ERROR_INVALID_XML;
}
@ -195,8 +238,10 @@ lasso_saml20_server_load_metadata_child(LassoServer *server, LassoProviderRole r
* otherwise.
*/
lasso_error_t
lasso_saml20_server_load_metadata(LassoServer *server, LassoProviderRole role, xmlNode *root_node,
GList *blacklisted_entity_ids, GList **loaded_entity_ids)
lasso_saml20_server_load_metadata(LassoServer *server, LassoProviderRole role,
xmlDoc *doc, xmlNode *root_node,
GList *blacklisted_entity_ids, GList **loaded_entity_ids,
xmlSecKeysMngr *keys_mngr, enum LassoServerLoadMetadataFlag flags)
{
lasso_error_t rc = 0;
GList loaded = { .data = NULL, .next = NULL };
@ -206,7 +251,7 @@ lasso_saml20_server_load_metadata(LassoServer *server, LassoProviderRole role, x
loaded_end = &loaded;
}
rc = lasso_saml20_server_load_metadata_child(server, role,
root_node, blacklisted_entity_ids, &loaded_end);
doc, root_node, blacklisted_entity_ids, &loaded_end, keys_mngr, flags);
if (loaded_entity_ids) {
lasso_release_list_of_strings(*loaded_entity_ids);
*loaded_entity_ids = loaded.next;

View File

@ -34,7 +34,9 @@ extern "C" {
int lasso_saml20_server_load_affiliation(LassoServer *server, xmlNode *node);
lasso_error_t lasso_saml20_server_load_metadata(LassoServer *server, LassoProviderRole role,
xmlNode *root_node, GList *blacklisted_entity_ids, GList **loaded_entity_ids);
xmlDoc *doc, xmlNode *root_node, GList *blacklisted_entity_ids,
GList **loaded_entity_ids, xmlSecKeysMngr *keys_mngr,
enum LassoServerLoadMetadataFlag flags);
#ifdef __cplusplus
}

View File

@ -1956,9 +1956,17 @@ START_TEST(test13_test_lasso_server_load_metadata)
check_good_rc(lasso_server_load_metadata(server, LASSO_PROVIDER_ROLE_IDP,
TESTSDATADIR "/renater-metadata.xml",
TESTSDATADIR "/metadata-federation-renater.crt",
&blacklisted_1, &loaded_entity_ids));
&blacklisted_1, &loaded_entity_ids,
LASSO_SERVER_LOAD_METADATA_FLAG_DEFAULT));
check_equals(g_hash_table_size(server->providers), 101);
check_equals(g_list_length(loaded_entity_ids), 101);
check_good_rc(lasso_server_load_metadata(server, LASSO_PROVIDER_ROLE_IDP,
TESTSDATADIR "/ukfederation-metadata.xml",
TESTSDATADIR "/ukfederation.pem",
&blacklisted_1, &loaded_entity_ids,
LASSO_SERVER_LOAD_METADATA_FLAG_DEFAULT));
check_equals(g_list_length(loaded_entity_ids), 283);
check_equals(g_hash_table_size(server->providers), 384);
lasso_release_gobject(server);
}
@ -2005,6 +2013,7 @@ basic_suite()
tcase_add_test(tc_response_new_from_xmlNode, test11_get_default_name_id_format);
tcase_add_test(tc_custom_namespace, test12_custom_namespace);
tcase_add_test(tc_load_metadata, test13_test_lasso_server_load_metadata);
tcase_set_timeout(tc_load_metadata, 10);
return s;
}

View File

@ -12,7 +12,7 @@
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
X1YhQCh7ZYc4dN36bWBYviDKxxfishiqMdF3E7PNLYLxCK8wZL58dOvNVnYTJ1CkKa2iFp9Tejyc
1YhQCh7ZYc4dN36bWBYviDKxxfishiqMdF3E7PNLYLxCK8wZL58dOvNVnYTJ1CkKa2iFp9Tejyc
4DRkvzU6vGSGsX2M6k92ON16zanpekHgjFMv4DvtPevRyYHJaeoOzE/6k0Es1kIvbsYMWrVWZdsO
XNRvItqOZdBBWNyxXsQ=
</ds:SignatureValue>
@ -27411,4 +27411,4 @@ cHF5
</EntitiesDescriptor>
</EntitiesDescriptor>