summaryrefslogtreecommitdiffstats
path: root/lasso
diff options
context:
space:
mode:
authorBenjamin Dauvergne <bdauvergne@entrouvert.com>2009-01-24 09:33:50 +0000
committerBenjamin Dauvergne <bdauvergne@entrouvert.com>2009-01-24 09:33:50 +0000
commita3daa0d6653886587678929977ec57c6e5d5f02a (patch)
tree035b2fcb1712da24032114f398e9ef05da129af6 /lasso
parente77c4964877ea773b9114b6e54693af91b4220c6 (diff)
downloadlasso-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.h10
-rw-r--r--lasso/xml/tools.c135
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;
+}