diff options
author | Benjamin Dauvergne <bdauvergne@entrouvert.com> | 2009-01-24 09:33:50 +0000 |
---|---|---|
committer | Benjamin Dauvergne <bdauvergne@entrouvert.com> | 2009-01-24 09:33:50 +0000 |
commit | a3daa0d6653886587678929977ec57c6e5d5f02a (patch) | |
tree | 035b2fcb1712da24032114f398e9ef05da129af6 /lasso | |
parent | e77c4964877ea773b9114b6e54693af91b4220c6 (diff) | |
download | lasso-a3daa0d6653886587678929977ec57c6e5d5f02a.tar.gz lasso-a3daa0d6653886587678929977ec57c6e5d5f02a.tar.xz lasso-a3daa0d6653886587678929977ec57c6e5d5f02a.zip |
XML: Add internal API to validate XMLDsig signatures
* lasso/xml/tools.c:
- lasso_saml_constrain_dsigctxt() add constraints following SAML
specifications on XMLDsig signatures to an libxmlsec DSig context.
- lasso_verify_signature() this function given an xmlNode and a key or
a keys manager (for a set of AC or AC chains) validate the
envelopped signature set upon this node. It can be instructed to
follow constraints of the SAML 1.0 specification.
Diffstat (limited to 'lasso')
-rw-r--r-- | lasso/xml/private.h | 10 | ||||
-rw-r--r-- | lasso/xml/tools.c | 135 |
2 files changed, 145 insertions, 0 deletions
diff --git a/lasso/xml/private.h b/lasso/xml/private.h index 858632f5..1e4bf033 100644 --- a/lasso/xml/private.h +++ b/lasso/xml/private.h @@ -57,6 +57,12 @@ typedef enum { SNIPPET_ALLOW_TEXT = 1 << 26 /* allow text childs in list of nodes */ } SnippetType; +typedef enum { + NO_OPTION = 0, + NO_SINGLE_REFERENCE = 1 /* SAML signature should contain a single reference, + * but WS-Security signatures can contain many */ +} SignatureVerificationOption; + struct XmlSnippet { char *name; SnippetType type; @@ -121,6 +127,10 @@ 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 *certificate_file); +gboolean lasso_verify_signature(xmlNode *signed_node, const char *id_attr_name, + xmlSecKeysMngr *keys_manager, xmlSecKey *public_key, + SignatureVerificationOption signature_verification_option, + GList **uri_references); void xmlCleanNs(xmlNode *root_node); void xml_insure_namespace(xmlNode *xmlnode, xmlNs *ns, gboolean force, diff --git a/lasso/xml/tools.c b/lasso/xml/tools.c index a9915f4f..b7ed3b9b 100644 --- a/lasso/xml/tools.c +++ b/lasso/xml/tools.c @@ -42,6 +42,7 @@ #include <zlib.h> +#include <glib.h> #include <lasso/xml/xml.h> #include <lasso/xml/xml_enc.h> #include <lasso/xml/saml-2.0/saml2_assertion.h> @@ -938,3 +939,137 @@ lasso_concat_url_query(char *url, char *query) } } +static gboolean +lasso_saml_constrain_dsigctxt(xmlSecDSigCtxPtr dsigCtx) { + /* Limit allowed transforms for signature and reference processing */ + if((xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformInclC14NId) < 0) || + (xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformExclC14NId) < 0) || + (xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformSha1Id) < 0) || + (xmlSecDSigCtxEnableSignatureTransform(dsigCtx, xmlSecTransformRsaSha1Id) < 0)) { + + g_warning("Error: failed to limit allowed signature transforms"); + return FALSE; + } + if((xmlSecDSigCtxEnableReferenceTransform(dsigCtx, xmlSecTransformInclC14NId) < 0) || + (xmlSecDSigCtxEnableReferenceTransform(dsigCtx, xmlSecTransformExclC14NId) < 0) || + (xmlSecDSigCtxEnableReferenceTransform(dsigCtx, xmlSecTransformSha1Id) < 0) || + (xmlSecDSigCtxEnableReferenceTransform(dsigCtx, xmlSecTransformEnvelopedId) < 0)) { + + g_warning("Error: failed to limit allowed reference transforms"); + return FALSE; + } + + /* Limit possible key info to X509, RSA and DSA */ + if((xmlSecPtrListAdd(&(dsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecKeyDataX509Id) < 0) || + (xmlSecPtrListAdd(&(dsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecKeyDataRsaId) < 0) || + (xmlSecPtrListAdd(&(dsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecKeyDataDsaId) < 0)) { + g_warning("Error: failed to limit allowed key data"); + return FALSE; + } + return TRUE; +} + +/** + * lasso_verify_signature: + * @signed_node: an #xmlNode containing an enveloped xmlDSig signature + * @id_attr_name: the id attribune name for this node + * @keys_manager: an #xmlSecKeysMnr containing the CA cert chain, to validate the key in the + * signature if there is one. + * @public_key: a public key to validate the signature, if present the function ignore the key + * contained in the signature. + * + * This function validate a signature on an xmlNode following the instructions given in the document + * Assertions and Protocol or the OASIS Security Markup Language (SAML) V1.1. + * + * Beware that it does not validate every needed properties for a SAML assertion, request or + * response to be acceptable. + * + * Return: 0 if signature was validated, and error code otherwise. + */ + +gboolean +lasso_verify_signature(xmlNode *signed_node, const char *id_attr_name, + xmlSecKeysMngr *keys_manager, xmlSecKey *public_key, + SignatureVerificationOption signature_verification_option, + GList **uri_references) +{ + int rc = LASSO_DS_ERROR_SIGNATURE_VERIFICATION_FAILED; + xmlDoc *doc = NULL; + xmlNodePtr signature = NULL; + xmlSecDSigCtx *dsigCtx = NULL; + xmlChar *id = NULL; + char *reference_uri = NULL; + xmlSecDSigReferenceCtx *dsig_reference_ctx = NULL; + + g_return_val_if_fail(signed_node && id_attr_name && (keys_manager || public_key), + LASSO_PARAM_ERROR_INVALID_VALUE); + + /* Find signature */ + signature = xmlSecFindNode(signed_node, xmlSecNodeSignature, xmlSecDSigNs); + goto_exit_if_fail (signature, LASSO_DS_ERROR_SIGNATURE_NOT_FOUND); + + /* Create a temporary doc */ + doc = xmlNewDoc((xmlChar*)XML_DEFAULT_VERSION); + goto_exit_if_fail(doc, LASSO_ERROR_OUT_OF_MEMORY); + xmlDocSetRootElement(doc, signed_node); + + /* Find ID */ + id = xmlGetProp(signed_node, (xmlChar*)id_attr_name); + if (id) { + xmlAddID(NULL, doc, id, xmlHasProp(signed_node, (xmlChar*)id_attr_name)); + } + + /* Create DSig context */ + dsigCtx = xmlSecDSigCtxCreate(keys_manager); + goto_exit_if_fail(doc, LASSO_DS_ERROR_CONTEXT_CREATION_FAILED); + /* XXX: Is xmlSecTransformUriTypeSameEmpty permitted ? + * I would say yes only if signed_node == signature->parent. */ + dsigCtx->enabledReferenceUris = xmlSecTransformUriTypeSameDocument; + goto_exit_if_fail(lasso_saml_constrain_dsigctxt(dsigCtx), + LASSO_DS_ERROR_SIGNATURE_VERIFICATION_FAILED); + /* Given a public key use it to validate the signature ! */ + if (public_key) { + dsigCtx->signKey = xmlSecKeyDuplicate(public_key); + } + + /* Verify signature */ + goto_exit_if_fail(xmlSecDSigCtxVerify(dsigCtx, signature) >= 0, + LASSO_DS_ERROR_SIGNATURE_VERIFICATION_FAILED); + goto_exit_if_fail(dsigCtx->status == xmlSecDSigStatusSucceeded, + LASSO_DS_ERROR_SIGNATURE_VERIFICATION_FAILED); + + /* There should be only one reference */ + goto_exit_if_fail(((signature_verification_option & NO_SINGLE_REFERENCE) == 0) && + xmlSecPtrListGetSize(&(dsigCtx->signedInfoReferences)) == 1, LASSO_DS_ERROR_TOO_MUCH_REFERENCES); + /* The reference should be to the signed node */ + reference_uri = g_strdup_printf("#%s", id); + dsig_reference_ctx = (xmlSecDSigReferenceCtx*)xmlSecPtrListGetItem(&(dsigCtx->signedInfoReferences), 0); + goto_exit_if_fail(dsig_reference_ctx != 0 && + strcmp((char*)dsig_reference_ctx->uri, reference_uri) == 0, + LASSO_DS_ERROR_INVALID_REFERENCE_FOR_SAML); + /* Keep URI of all nodes signed if asked */ + if (uri_references) { + gint size = xmlSecPtrListGetSize(&(dsigCtx->signedInfoReferences)); + int i; + for (i = 0; i < size; ++i) { + dsig_reference_ctx = (xmlSecDSigReferenceCtx*)xmlSecPtrListGetItem(&(dsigCtx->signedInfoReferences), i); + if (dsig_reference_ctx->uri == NULL) { + g_warning("dsig_reference_ctx->uri cannot be null"); + continue; + } + lasso_list_add_string(*uri_references, (char*)dsig_reference_ctx->uri); + } + } + + if (dsigCtx->status == xmlSecDSigStatusSucceeded) { + rc = 0; + } + +exit: + lasso_release(reference_uri); + lasso_release_signature_context(dsigCtx); + xmlUnlinkNode(signed_node); + lasso_release_doc(doc); + lasso_release(id); + return rc; +} |