summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Dauvergne <bdauvergne@entrouvert.com>2010-02-04 22:24:04 +0000
committerBenjamin Dauvergne <bdauvergne@entrouvert.com>2010-02-04 22:24:04 +0000
commite6a07df2bc362d57a422216a4af834d980b1b2d7 (patch)
treeea56882dd7010b018d3ed9d47b82e6e3fb98d5b6
parent38ef0a86d9075f75ae735409d7b59da2da93490d (diff)
Core: Finish support for all XMLDsig key formats
* lasso/xml/tools.c: xmlsec is not able to load a certificate public key without checking it against trusted root certificate, so we must work around and load the key by hand. lasso_xmlsec_load_private_key_from_buffer is made more robust in the same (loading of the key was extracted inside _lasso_xmlsec_load_key_from_buffer) and now can load certificates and keys directly embedded inside KeyValue nodes (in total opposition to the XMLDsig specification but...), with or without PEM headers. * tests/metadata/Makefile.am tests/metadata/metadata_06.xml tests/metadata_tests.c: add test case for RSAKeyValue public keys.
-rw-r--r--lasso/xml/tools.c119
-rw-r--r--tests/metadata/Makefile.am3
-rw-r--r--tests/metadata/metadata_06.xml23
-rw-r--r--tests/metadata_tests.c13
4 files changed, 116 insertions, 42 deletions
diff --git a/lasso/xml/tools.c b/lasso/xml/tools.c
index 85430d36..e0b82e6d 100644
--- a/lasso/xml/tools.c
+++ b/lasso/xml/tools.c
@@ -1717,23 +1717,18 @@ cleanup:
return new_url;
}
-/**
- * lasso_xmlsec_load_private_key_from_buffer:
- * @buffer: a buffer containing a key in any format
- * @length: length of the buffer
- * @password: eventually a password
- */
xmlSecKey*
-lasso_xmlsec_load_private_key_from_buffer(const char *buffer, size_t length, const char *password) {
+_lasso_xmlsec_load_key_from_buffer(const char *buffer, size_t length, const char *password)
+{
int i = 0;
xmlSecKeyDataFormat key_formats[] = {
+ xmlSecKeyDataFormatPem,
+ xmlSecKeyDataFormatCertPem,
xmlSecKeyDataFormatDer,
+ xmlSecKeyDataFormatBinary,
xmlSecKeyDataFormatCertDer,
xmlSecKeyDataFormatPkcs8Der,
- xmlSecKeyDataFormatCertPem,
xmlSecKeyDataFormatPkcs8Pem,
- xmlSecKeyDataFormatPem,
- xmlSecKeyDataFormatBinary,
0
};
xmlSecKey *private_key = NULL;
@@ -1743,17 +1738,32 @@ lasso_xmlsec_load_private_key_from_buffer(const char *buffer, size_t length, con
private_key = xmlSecCryptoAppKeyLoadMemory((xmlSecByte*)buffer, length,
key_formats[i], password, NULL, NULL);
}
+ xmlSecErrorsDefaultCallbackEnableOutput(TRUE);
+
+ return private_key;
+}
+
+/**
+ * lasso_xmlsec_load_private_key_from_buffer:
+ * @buffer: a buffer containing a key in any format
+ * @length: length of the buffer
+ * @password: eventually a password
+ */
+xmlSecKey*
+lasso_xmlsec_load_private_key_from_buffer(const char *buffer, size_t length, const char *password) {
+ xmlSecKey *private_key = NULL;
+
+ private_key = _lasso_xmlsec_load_key_from_buffer(buffer, length, password);
+
/* special lasso metadata hack */
if (! private_key) {
xmlChar *out;
int len;
out = xmlMalloc(length*4);
len = xmlSecBase64Decode(BAD_CAST buffer, out, length*4);
- private_key = xmlSecCryptoAppKeyLoadMemory((xmlSecByte*)buffer, length,
- xmlSecKeyDataFormatDer, password, NULL, NULL);
+ private_key = _lasso_xmlsec_load_key_from_buffer((char*)out, len, password);
xmlFree(out);
}
- xmlSecErrorsDefaultCallbackEnableOutput(TRUE);
return private_key;
}
@@ -1815,10 +1825,13 @@ xmlSecKeyPtr
lasso_xmlsec_load_key_info(xmlNode *key_descriptor)
{
xmlSecKeyPtr key, result = NULL;
- xmlNodePtr key_info;
- xmlSecKeyInfoCtxPtr ctx;
- xmlNodePtr key_value;
- int rc;
+ xmlNodePtr key_info = NULL;
+ xmlSecKeyInfoCtx ctx;
+ xmlSecKeysMngr *keys_mngr;
+ xmlNodePtr key_value = NULL;
+ int rc = 0;
+ xmlChar *content = NULL;
+ X509 *cert;
if (! key_descriptor)
return NULL;
@@ -1826,44 +1839,68 @@ lasso_xmlsec_load_key_info(xmlNode *key_descriptor)
key_info = xmlSecFindChild(key_descriptor, xmlSecNodeKeyInfo, xmlSecDSigNs);
if (! key_info)
return NULL;
+ keys_mngr = xmlSecKeysMngrCreate();
+ rc = xmlSecCryptoAppDefaultKeysMngrInit(keys_mngr);
+ if (rc < 0) {
+ goto next;
+ }
+ rc = xmlSecKeyInfoCtxInitialize(&ctx, keys_mngr);
+ if (rc < 0) {
+ goto next;
+ }
+ ctx.flags = XMLSEC_KEYINFO_FLAGS_DONT_STOP_ON_KEY_FOUND
+ | XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS;
+ ctx.mode = xmlSecKeyInfoModeRead;
+ ctx.keyReq.keyId = xmlSecKeyDataIdUnknown;
+ ctx.keyReq.keyType = xmlSecKeyDataTypePublic;
+ ctx.keyReq.keyUsage = xmlSecKeyDataUsageAny;
+ ctx.certsVerificationDepth = 0;
- ctx = xmlSecKeyInfoCtxCreate(NULL);
- ctx->flags |= XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS;
key = xmlSecKeyCreate();
/* anyway to make this reentrant and thread safe ? */
xmlSecErrorsDefaultCallbackEnableOutput(FALSE);
- rc = xmlSecKeyInfoNodeRead(key_info, key, ctx);
+ rc = xmlSecKeyInfoNodeRead(key_info, key, &ctx);
xmlSecErrorsDefaultCallbackEnableOutput(TRUE);
+ xmlSecKeyInfoCtxFinalize(&ctx);
- if (rc == -1 &&
- ((key_value = xmlSecFindChild(key_info, xmlSecNodeKeyValue, xmlSecDSigNs)) ||
- (key_value = xmlSecFindNode(key_info, xmlSecNodeX509Certificate, xmlSecDSigNs)))) {
- char *content;
- size_t length;
+ if (rc == 0) {
+ xmlSecKeyDataPtr cert_data;
- if (lasso_get_base64_content(key_value, &content, &length)) {
- result = lasso_xmlsec_load_private_key_from_buffer(content, length, NULL);
- g_free(content);
- } else {
- xmlChar *content;
+ cert_data = xmlSecKeyGetData(key, xmlSecOpenSSLKeyDataX509Id);
- content = xmlNodeGetContent(key_value);
- if (content) {
- result = lasso_xmlsec_load_private_key_from_buffer((char*)content, strlen((char*)content), NULL);
- xmlFree(content);
+ if (cert_data) {
+ cert = xmlSecOpenSSLKeyDataX509GetCert(cert_data, 0);
+ if (cert) {
+ xmlSecKeyDataPtr cert_key;
+
+ cert_key = xmlSecOpenSSLX509CertGetKey(cert);
+ rc = xmlSecKeySetValue(key, cert_key);
+ if (rc < 0) {
+ xmlSecKeyDataDestroy(cert_key);
+ goto next;
+ }
}
}
- } else {
- /* swap result and temporary key */
+ }
+
+ if (rc == 0 && xmlSecKeyIsValid(key)) {
result = key;
key = NULL;
+ goto cleanup;
}
-
- if (key) {
- xmlSecKeyDestroy(key);
+ xmlSecKeyDestroy(key);
+next:
+ if (! (key_value = xmlSecFindChild(key_info, xmlSecNodeKeyValue, xmlSecDSigNs)) &&
+ ! (key_value = xmlSecFindNode(key_info, xmlSecNodeX509Certificate, xmlSecDSigNs))) {
+ goto cleanup;
}
- if (ctx) {
- xmlSecKeyInfoCtxDestroy(ctx);
+
+ content = xmlNodeGetContent(key_value);
+ if (content) {
+ result = lasso_xmlsec_load_private_key_from_buffer((char*)content, strlen((char*)content), NULL);
+ xmlFree(content);
}
+
+cleanup:
return result;
}
diff --git a/tests/metadata/Makefile.am b/tests/metadata/Makefile.am
index 40d4798b..956054a0 100644
--- a/tests/metadata/Makefile.am
+++ b/tests/metadata/Makefile.am
@@ -4,4 +4,5 @@ EXTRA_DIST = \
metadata_02.xml \
metadata_03.xml \
metadata_04.xml \
- metadata_05.xml
+ metadata_05.xml \
+ metadata_06.xml
diff --git a/tests/metadata/metadata_06.xml b/tests/metadata/metadata_06.xml
new file mode 100644
index 00000000..bce00184
--- /dev/null
+++ b/tests/metadata/metadata_06.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<EntityDescriptor
+ providerID="http://test.local/liberty/metadata"
+ xmlns="urn:liberty:metadata:2003-08">
+
+<SPDescriptor protocolSupportEnumeration="urn:liberty:iff:2003-08">
+
+ <KeyDescriptor use="signing">
+ <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ <ds:KeyValue>
+ <ds:RSAKeyValue>
+ <ds:Modulus>xA7SEU+e0yQH5rm9kbCDN9o3aPIo7HbP7tX6WOocLZAtNfyxSZDU16ksL6W
+jubafOqNEpcwR3RdFsT7bCqnXPBe5ELh5u4VEy19MzxkXRgrMvavzyBpVRgBUwUlV
+5foK5hhmbktQhyNdy/6LpQRhDUDsTvK+g9Ucj47es9AQJ3U=
+ </ds:Modulus>
+ <ds:Exponent>AQAB</ds:Exponent>
+ </ds:RSAKeyValue>
+ </ds:KeyValue>
+ </ds:KeyInfo>
+ </KeyDescriptor>
+
+</SPDescriptor>
+</EntityDescriptor>
diff --git a/tests/metadata_tests.c b/tests/metadata_tests.c
index 33096965..6daf31f0 100644
--- a/tests/metadata_tests.c
+++ b/tests/metadata_tests.c
@@ -74,6 +74,14 @@ START_TEST(test05_metadata_load_public_key_from_x509_cert)
}
END_TEST
+START_TEST(test06_metadata_load_public_key_from_rsa_keyvalue)
+{
+ LassoProvider *provider = lasso_provider_new(LASSO_PROVIDER_ROLE_SP,
+ TESTSMETADATADIR "/metadata_06.xml", NULL, NULL);
+ fail_unless(provider != NULL, "Can't load RSAKeyValue node");
+ g_object_unref(provider);
+}
+END_TEST
Suite*
metadata_suite()
@@ -89,11 +97,14 @@ metadata_suite()
tcase_create("Load PEM public key from <ds:KeyValue>");
TCase *tc_metadata_load_public_key_from_x509_cert =
tcase_create("Load DER public key from <ds:X509Certificate>");
+ TCase *tc_metadata_load_public_key_from_rsa_keyvalue =
+ tcase_create("Load RSAKeyValue public key");
suite_add_tcase(s, tc_metadata_load_der_certificate_from_x509_cert);
suite_add_tcase(s, tc_metadata_load_pem_certificate_from_x509_cert);
suite_add_tcase(s, tc_metadata_load_der_public_key_from_keyvalue);
suite_add_tcase(s, tc_metadata_load_pem_public_key_from_keyvalue);
suite_add_tcase(s, tc_metadata_load_public_key_from_x509_cert);
+ suite_add_tcase(s, tc_metadata_load_public_key_from_rsa_keyvalue);
tcase_add_test(tc_metadata_load_der_certificate_from_x509_cert,
test01_metadata_load_der_certificate_from_x509_cert);
tcase_add_test(tc_metadata_load_pem_certificate_from_x509_cert,
@@ -104,5 +115,7 @@ metadata_suite()
test04_metadata_load_pem_public_key_from_keyvalue);
tcase_add_test(tc_metadata_load_public_key_from_x509_cert,
test05_metadata_load_public_key_from_x509_cert);
+ tcase_add_test(tc_metadata_load_public_key_from_rsa_keyvalue,
+ test06_metadata_load_public_key_from_rsa_keyvalue);
return s;
}