diff options
| author | Benjamin Dauvergne <bdauvergne@entrouvert.com> | 2010-02-04 22:24:04 +0000 |
|---|---|---|
| committer | Benjamin Dauvergne <bdauvergne@entrouvert.com> | 2010-02-04 22:24:04 +0000 |
| commit | e6a07df2bc362d57a422216a4af834d980b1b2d7 (patch) | |
| tree | ea56882dd7010b018d3ed9d47b82e6e3fb98d5b6 | |
| parent | 38ef0a86d9075f75ae735409d7b59da2da93490d (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.c | 119 | ||||
| -rw-r--r-- | tests/metadata/Makefile.am | 3 | ||||
| -rw-r--r-- | tests/metadata/metadata_06.xml | 23 | ||||
| -rw-r--r-- | tests/metadata_tests.c | 13 |
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; } |
