diff --git a/CVE-2025-46404.patch b/CVE-2025-46404.patch new file mode 100644 index 0000000000000000000000000000000000000000..26aa602eeca4cc0c37f3f153e78e4d89abcf9654 --- /dev/null +++ b/CVE-2025-46404.patch @@ -0,0 +1,25 @@ +From c880cad13732bcb50cbd9fa376ea39edb53e7d68 Mon Sep 17 00:00:00 2001 +From: Benjamin Dauvergne +Date: Thu, 15 May 2025 15:51:08 +0200 +Subject: [PATCH] misc: check xmlSecGetNodeNsHref for possible NULL result + (#105693) + +--- + lasso/id-ff/provider.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lasso/id-ff/provider.c b/lasso/id-ff/provider.c +index 1dcd1b02..e3c9dce5 100644 +--- a/lasso/id-ff/provider.c ++++ b/lasso/id-ff/provider.c +@@ -1364,8 +1364,8 @@ lasso_provider_verify_saml_signature(LassoProvider *provider, + + /* ID-FF 1.2 Signatures case */ + node_ns = xmlSecGetNodeNsHref(signed_node); +- if ((strcmp((char*)node_ns, LASSO_SAML2_PROTOCOL_HREF) == 0) || +- (strcmp((char*)node_ns, LASSO_SAML2_ASSERTION_HREF) == 0)) { ++ if (node_ns && ((strcmp((char*)node_ns, LASSO_SAML2_PROTOCOL_HREF) == 0) || ++ (strcmp((char*)node_ns, LASSO_SAML2_ASSERTION_HREF) == 0))) { + id_attribute_name = "ID"; + } else if (xmlSecCheckNodeName(signed_node, (xmlChar*)"Request", (xmlChar*)LASSO_SAML_PROTOCOL_HREF)) { + id_attribute_name = "RequestID"; diff --git a/CVE-2025-46705-pre.patch b/CVE-2025-46705-pre.patch new file mode 100644 index 0000000000000000000000000000000000000000..c0ab541984825bb4704e8445d598593f2936ab3b --- /dev/null +++ b/CVE-2025-46705-pre.patch @@ -0,0 +1,76 @@ +From b140660709c341bb44f9b7ebbd8253cde9169e8b Mon Sep 17 00:00:00 2001 +From: Benjamin Dauvergne +Date: Thu, 15 May 2025 15:39:42 +0200 +Subject: [PATCH] tests: test that inserted comment do not change node value + and still validate signature (#105693) + +Origin: https://git.entrouvert.org/entrouvert/lasso/commit/b140660709c341bb44f9b7ebbd8253cde9169e8b +--- + bindings/python/tests/profiles_tests.py | 23 +++++++++++++++++++++++ + lasso/xml/xml.c | 2 +- + 2 files changed, 24 insertions(+), 1 deletion(-) + +diff --git a/bindings/python/tests/profiles_tests.py b/bindings/python/tests/profiles_tests.py +index 6ec6120..aacaf24 100755 +--- a/bindings/python/tests/profiles_tests.py ++++ b/bindings/python/tests/profiles_tests.py +@@ -24,6 +24,7 @@ + # along with this program; if not, see . + + ++import base64 + import os + import unittest + import sys +@@ -301,6 +302,28 @@ class LoginTestCase(unittest.TestCase): + idp_login.buildAssertion("None", "None", "None", "None", "None") + idp_login.buildAuthnResponseMsg() + ++ def test_09(self): ++ '''Login test between SP and IdP with encrypted private keys''' ++ sp_server = server('sp7-saml2', lasso.PROVIDER_ROLE_IDP, 'idp7-saml2') ++ idp_server = server('idp7-saml2', lasso.PROVIDER_ROLE_SP, 'sp7-saml2') ++ ++ sp_login = lasso.Login(sp_server) ++ sp_login.initAuthnRequest() ++ sp_login.request.protocolBinding = lasso.SAML2_METADATA_BINDING_POST ++ sp_login.buildAuthnRequestMsg() ++ idp_login = lasso.Login(idp_server) ++ idp_login.setSignatureVerifyHint(lasso.PROFILE_SIGNATURE_VERIFY_HINT_FORCE) ++ idp_login.processAuthnRequestMsg(sp_login.msgUrl.split('?')[1]) ++ idp_login.validateRequestMsg(True, True) ++ idp_login.buildAssertion("None", "None", "None", "None", "None") ++ idp_login.buildAuthnResponseMsg() ++ sp_login.setSignatureVerifyHint(lasso.PROFILE_SIGNATURE_VERIFY_HINT_FORCE) ++ # insert comment inside NameID ++ msg = base64.b64encode(base64.b64decode(idp_login.msgBody).decode().replace(idp_login.assertion.subject.nameId.content, idp_login.assertion.subject.nameId.content[:10] + '' + idp_login.assertion.subject.nameId.content[10:]).encode()) ++ sp_login.processAuthnResponseMsg(msg.decode()) ++ sp_login.acceptSso() ++ assert sp_login.assertion.subject.nameId.content == idp_login.assertion.subject.nameId.content ++ + class LogoutTestCase(unittest.TestCase): + def test01(self): + """SP logout without session and identity; testing initRequest.""" +diff --git a/lasso/xml/xml.c b/lasso/xml/xml.c +index 938844b..e5948e7 100644 +--- a/lasso/xml/xml.c ++++ b/lasso/xml/xml.c +@@ -1740,7 +1740,6 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode) + ERROR; + } + #undef ADVANCE +-#undef ERROR + + if (matched_snippet->offset || (matched_snippet->type & SNIPPET_PRIVATE)) { + switch (matched_snippet->type & 0xff) { +@@ -1802,6 +1801,7 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode) + g_assert_not_reached(); + } + } ++#undef ERROR + if (t) { /* t is an ELEMENT that dont match any snippet, when taken in order */ + if (snippet_any && is_snippet_type(snippet_any, SNIPPET_LIST_XMLNODES)) { + value = SNIPPET_STRUCT_MEMBER_P(node, g_type_any, snippet_any); +-- +2.51.1 + diff --git a/CVE-2025-46705.patch b/CVE-2025-46705.patch new file mode 100644 index 0000000000000000000000000000000000000000..db08469d20c9784425de409d61a8a2c0d45c0e02 --- /dev/null +++ b/CVE-2025-46705.patch @@ -0,0 +1,24 @@ +From 37836a9cf14234ce720edb5c43f6ed0491f72cf6 Mon Sep 17 00:00:00 2001 +From: Benjamin Dauvergne +Date: Thu, 15 May 2025 16:02:25 +0200 +Subject: [PATCH] xml: do not terminate on an unknown XML node type (#105693) + +Origin: https://git.entrouvert.org/entrouvert/lasso/commit/37836a9cf14234ce720edb5c43f6ed0491f72cf6 +--- + lasso/xml/xml.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/lasso/xml/xml.c b/lasso/xml/xml.c +index ca8d72fa..10732f3b 100644 +--- a/lasso/xml/xml.c ++++ b/lasso/xml/xml.c +@@ -1771,7 +1771,8 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode) + lasso_node_set_original_xmlnode(subnode, t); + } + } else { +- g_assert_not_reached(); ++ /* Anything else should not be there, abort. */ ++ ERROR; + } + } + #undef ERROR diff --git a/CVE-2025-46784-pre.patch b/CVE-2025-46784-pre.patch new file mode 100644 index 0000000000000000000000000000000000000000..b597fa8add190536ee31411c336158ea41624c63 --- /dev/null +++ b/CVE-2025-46784-pre.patch @@ -0,0 +1,85 @@ +From 228ac9470f383c5c9dad9f4d314b708c9fd45f16 Mon Sep 17 00:00:00 2001 +From: Benjamin Dauvergne +Date: Wed, 16 Nov 2022 15:36:53 +0100 +Subject: [PATCH] Make lasso_inflate output the inflated buffer size (#71399) + +Origin: https://git.entrouvert.org/entrouvert/lasso/commit/228ac9470f383c5c9dad9f4d314b708c9fd45f16 +--- + lasso/xml/tools.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/lasso/xml/tools.c b/lasso/xml/tools.c +index bc0510c7..cc3d5f2e 100644 +--- a/lasso/xml/tools.c ++++ b/lasso/xml/tools.c +@@ -1357,17 +1357,19 @@ lasso_get_query_string_param_value(const char *qs, const char *param_key, const + } + + unsigned char* +-lasso_inflate(unsigned char *input, size_t len) ++lasso_inflate(unsigned char *input, size_t len, size_t *outlen) + { + z_stream zstr; + unsigned char *output; + int z_err; + ++ *outlen = 0; + zstr.zalloc = NULL; + zstr.zfree = NULL; + zstr.opaque = NULL; + +- output = g_malloc(len*20); ++ // add one to account for the zero byte ++ output = g_malloc(len*20+1); + zstr.avail_in = len; + zstr.next_in = (unsigned char*)input; + zstr.total_in = 0; +@@ -1391,6 +1393,7 @@ lasso_inflate(unsigned char *input, size_t len) + } + output[zstr.total_out] = 0; + inflateEnd(&zstr); ++ *outlen = zstr.total_out; + + return output; + } +@@ -1400,6 +1403,7 @@ gboolean + lasso_node_init_from_deflated_query_part(LassoNode *node, char *deflate_string) + { + int len; ++ size_t outlen = 0; + xmlChar *b64_zre, *zre, *re; + xmlDoc *doc; + xmlNode *root; +@@ -1415,13 +1419,13 @@ lasso_node_init_from_deflated_query_part(LassoNode *node, char *deflate_string) + return FALSE; + } + +- re = lasso_inflate(zre, len); ++ re = lasso_inflate(zre, len, &outlen); + xmlFree(zre); + + if (! re) + return FALSE; + +- doc = lasso_xml_parse_memory((char*)re, strlen((char*)re)); ++ doc = lasso_xml_parse_memory((char*)re, outlen); + lasso_release_string(re); + + root = xmlDocGetRootElement(doc); +@@ -3166,6 +3170,7 @@ lasso_get_saml_message(xmlChar **query_fields) { + char *t = NULL; + int rc = 0; + int len = 0; ++ size_t outlen = 0; + + for (i=0; (field=query_fields[i]); i++) { + t = strchr((char*)field, '='); +@@ -3201,7 +3206,7 @@ lasso_get_saml_message(xmlChar **query_fields) { + goto cleanup; + } + /* rc contains the length of the result */ +- saml_message = (char*)lasso_inflate((unsigned char*) decoded_message, rc); ++ saml_message = (char*)lasso_inflate((unsigned char*) decoded_message, rc, &outlen); + cleanup: + if (decoded_message) { + lasso_release(decoded_message); diff --git a/CVE-2025-46784.patch b/CVE-2025-46784.patch new file mode 100644 index 0000000000000000000000000000000000000000..caf1baab7e56ee72cde73f8cf264a1bad181d7af --- /dev/null +++ b/CVE-2025-46784.patch @@ -0,0 +1,563 @@ +From 8a588a8acb4a9cb7c7cb4dfd91a8278264a6d15a Mon Sep 17 00:00:00 2001 +From: Benjamin Dauvergne +Date: Wed, 16 Nov 2022 15:40:19 +0100 +Subject: [PATCH] Replace all use of xmlSecBase64Decode by lasso_base64_decode + (#71399) + +Origin: https://git.entrouvert.org/entrouvert/lasso/commit/8a588a8acb4a9cb7c7cb4dfd91a8278264a6d15a +--- + lasso/id-ff/login.c | 12 ++- + lasso/id-ff/provider.c | 8 +- + lasso/id-ff/session.c | 15 ++-- + lasso/saml-2.0/profile.c | 35 ++++---- + lasso/xml/tools.c | 176 ++++++++++++++++----------------------- + lasso/xml/xml.c | 16 ++-- + 6 files changed, 112 insertions(+), 150 deletions(-) + +diff --git a/lasso/id-ff/login.c b/lasso/id-ff/login.c +index f1f1bce3..d5559901 100644 +--- a/lasso/id-ff/login.c ++++ b/lasso/id-ff/login.c +@@ -1652,7 +1652,8 @@ lasso_login_init_request(LassoLogin *login, gchar *response_msg, + int i; + char *artifact_b64 = NULL, *provider_succinct_id_b64; + char provider_succinct_id[21]; +- char artifact[43]; ++ char *artifact = NULL; ++ int artifact_len = 0; + LassoSamlpRequestAbstract *request; + LassoProfile *profile; + +@@ -1689,18 +1690,23 @@ lasso_login_init_request(LassoLogin *login, gchar *response_msg, + lasso_assign_string(artifact_b64, response_msg); + } + +- i = xmlSecBase64Decode((xmlChar*)artifact_b64, (xmlChar*)artifact, 43); +- if (i < 0 || i > 42) { ++ if (! lasso_base64_decode(artifact_b64, &artifact, &artifact_len)) { ++ return LASSO_PROFILE_ERROR_INVALID_ARTIFACT; ++ } ++ if (artifact_len != 42) { + lasso_release_string(artifact_b64); ++ lasso_release_string(artifact); + return LASSO_PROFILE_ERROR_INVALID_ARTIFACT; + } + + if (artifact[0] != 0 || artifact[1] != 3) { /* wrong type code */ + lasso_release_string(artifact_b64); ++ lasso_release_string(artifact); + return LASSO_PROFILE_ERROR_INVALID_ARTIFACT; + } + + memcpy(provider_succinct_id, artifact+2, 20); ++ lasso_release_string(artifact); + provider_succinct_id[20] = 0; + + provider_succinct_id_b64 = (char*)xmlSecBase64Encode((xmlChar*)provider_succinct_id, 20, 0); +diff --git a/lasso/id-ff/provider.c b/lasso/id-ff/provider.c +index a4b29337..496a961c 100644 +--- a/lasso/id-ff/provider.c ++++ b/lasso/id-ff/provider.c +@@ -1434,12 +1434,12 @@ lasso_provider_verify_signature(LassoProvider *provider, + + if (format == LASSO_MESSAGE_FORMAT_BASE64) { + int len; +- char *msg = g_malloc(strlen(message)); +- len = xmlSecBase64Decode((xmlChar*)message, (xmlChar*)msg, strlen(message)); +- if (len < 0) { ++ char *msg = NULL; ++ ++ if (! lasso_base64_decode(message, &msg, &len)) { + goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_MSG); + } +- doc = lasso_xml_parse_memory(msg, strlen(msg)); ++ doc = lasso_xml_parse_memory(msg, len); + lasso_release_string(msg); + } else { + doc = lasso_xml_parse_memory(message, strlen(message)); +diff --git a/lasso/id-ff/session.c b/lasso/id-ff/session.c +index e22a5e80..c303470c 100644 +--- a/lasso/id-ff/session.c ++++ b/lasso/id-ff/session.c +@@ -797,25 +797,22 @@ get_xmlNode(LassoNode *node, G_GNUC_UNUSED gboolean lasso_dump) + + xmlNode* + base64_to_xmlNode(xmlChar *buffer) { +- xmlChar *decoded = NULL; ++ char *decoded = NULL; ++ int decoded_len = 0; + xmlDoc *doc = NULL; + xmlNode *ret = NULL; +- int l1,l2; + +- l1 = 4*strlen((char*)buffer)+2; +- decoded = g_malloc(l1); +- l2 = xmlSecBase64Decode(buffer, decoded, l1); +- if (l2 < 0) ++ if (! lasso_base64_decode((char*)buffer, &decoded, &decoded_len)) + goto cleanup; +- doc = xmlParseMemory((char*)decoded, l2); ++ doc = xmlParseMemory(decoded, decoded_len); + if (doc == NULL) + goto cleanup; + ret = xmlDocGetRootElement(doc); + if (ret) { +- ret = xmlCopyNode(ret, 1); ++ ret = xmlCopyNode(ret, 1); + } + cleanup: +- lasso_release(decoded); ++ lasso_release_string(decoded); + lasso_release_doc(doc); + + return ret; +diff --git a/lasso/saml-2.0/profile.c b/lasso/saml-2.0/profile.c +index 9f2b5156..378f072d 100644 +--- a/lasso/saml-2.0/profile.c ++++ b/lasso/saml-2.0/profile.c +@@ -288,7 +288,8 @@ lasso_saml20_profile_init_artifact_resolve(LassoProfile *profile, + char *artifact_b64 = NULL; + xmlChar *provider_succinct_id_b64 = NULL; + char *provider_succinct_id[21]; +- char artifact[45]; ++ char *artifact = NULL; ++ int artifact_len = 0; + LassoSamlp2RequestAbstract *request = NULL; + LassoProvider *remote_provider = NULL; + int i = 0; +@@ -307,21 +308,17 @@ lasso_saml20_profile_init_artifact_resolve(LassoProfile *profile, + return LASSO_PROFILE_ERROR_MISSING_ARTIFACT; + } + } else if (method == LASSO_HTTP_METHOD_ARTIFACT_POST) { +- artifact_b64 = g_strdup(msg); ++ lasso_assign_string(artifact_b64, msg); + } else { + return critical_error(LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD); + } + +- i = xmlSecBase64Decode((xmlChar*)artifact_b64, (xmlChar*)artifact, 45); +- if (i < 0 || i > 44) { +- lasso_release_string(artifact_b64); +- return LASSO_PROFILE_ERROR_INVALID_ARTIFACT; +- } ++ goto_cleanup_if_fail_with_rc(lasso_base64_decode(artifact_b64, &artifact, &artifact_len), LASSO_PROFILE_ERROR_INVALID_ARTIFACT); + +- if (artifact[0] != 0 || artifact[1] != 4) { /* wrong type code */ +- lasso_release_string(artifact_b64); +- return LASSO_PROFILE_ERROR_INVALID_ARTIFACT; +- } ++ goto_cleanup_if_fail_with_rc(artifact_len == 44, LASSO_PROFILE_ERROR_INVALID_ARTIFACT); ++ ++ /* wrong type code */ ++ goto_cleanup_if_fail_with_rc(artifact[0] == 0 && artifact[1] == 4, LASSO_PROFILE_ERROR_INVALID_ARTIFACT); + + memcpy(provider_succinct_id, artifact+4, 20); + provider_succinct_id[20] = 0; +@@ -330,10 +327,7 @@ lasso_saml20_profile_init_artifact_resolve(LassoProfile *profile, + + lasso_assign_new_string(profile->remote_providerID, lasso_server_get_providerID_from_hash( + profile->server, (char*)provider_succinct_id_b64)); +- lasso_release_xml_string(provider_succinct_id_b64); +- if (profile->remote_providerID == NULL) { +- return LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND; +- } ++ goto_cleanup_if_fail_with_rc(profile->remote_providerID, LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND); + + /* resolve the resolver url using the endpoint index in the artifact string */ + remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID); +@@ -342,15 +336,11 @@ lasso_saml20_profile_init_artifact_resolve(LassoProfile *profile, + remote_provider_role, + LASSO_SAML2_METADATA_ELEMENT_ARTIFACT_RESOLUTION_SERVICE, NULL, FALSE, + FALSE, index_endpoint)); +- if (! profile->msg_url) { +- debug("looking for index endpoint %d", index_endpoint); +- return LASSO_PROFILE_ERROR_ENDPOINT_INDEX_NOT_FOUND; +- } +- ++ goto_cleanup_if_fail_with_rc(profile->msg_url, LASSO_PROFILE_ERROR_ENDPOINT_INDEX_NOT_FOUND); + + lasso_assign_new_gobject(profile->request, lasso_samlp2_artifact_resolve_new()); + request = LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request); +- lasso_assign_new_string(LASSO_SAMLP2_ARTIFACT_RESOLVE(request)->Artifact, artifact_b64); ++ lasso_transfer_string(LASSO_SAMLP2_ARTIFACT_RESOLVE(request)->Artifact, artifact_b64); + request->ID = lasso_build_unique_id(32); + lasso_assign_string(request->Version, "2.0"); + request->Issuer = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string( +@@ -361,6 +351,9 @@ lasso_saml20_profile_init_artifact_resolve(LassoProfile *profile, + (LassoNode*)request)); + + cleanup: ++ lasso_release_string(artifact_b64); ++ lasso_release_string(artifact); ++ lasso_release_xml_string(provider_succinct_id_b64); + return rc; + } + +diff --git a/lasso/xml/tools.c b/lasso/xml/tools.c +index 9b928daa..24f82169 100644 +--- a/lasso/xml/tools.c ++++ b/lasso/xml/tools.c +@@ -1403,37 +1403,32 @@ lasso_inflate(unsigned char *input, size_t len, size_t *outlen) + gboolean + lasso_node_init_from_deflated_query_part(LassoNode *node, char *deflate_string) + { +- int len; +- size_t outlen = 0; +- xmlChar *b64_zre, *zre, *re; +- xmlDoc *doc; +- xmlNode *root; ++ xmlChar *buffer= NULL; ++ char *decoded = NULL; ++ int decoded_len = 0; ++ xmlChar *re = NULL; ++ size_t re_len = 0; ++ xmlDoc *doc = NULL; ++ xmlNode *root = NULL; ++ gboolean rc = TRUE; + +- b64_zre = (xmlChar*)xmlURIUnescapeString(deflate_string, 0, NULL); +- len = strlen((char*)b64_zre); +- zre = xmlMalloc(len*4); +- len = xmlSecBase64Decode(b64_zre, zre, len*4); +- xmlFree(b64_zre); +- if (len == -1) { +- message(G_LOG_LEVEL_CRITICAL, "Failed to base64-decode query"); +- xmlFree(zre); +- return FALSE; +- } ++ buffer = (xmlChar*)xmlURIUnescapeString(deflate_string, 0, NULL); ++ goto_cleanup_if_fail_with_rc(lasso_base64_decode((char*)buffer, &decoded, &decoded_len), FALSE); + +- re = lasso_inflate(zre, len, &outlen); +- xmlFree(zre); ++ re = lasso_inflate((unsigned char*)decoded, decoded_len, &re_len); ++ goto_cleanup_if_fail_with_rc_with_warning(re != NULL, FALSE); + +- if (! re) +- return FALSE; +- +- doc = lasso_xml_parse_memory((char*)re, outlen); +- lasso_release_string(re); ++ doc = lasso_xml_parse_memory((char*)re, strlen((char*)re)); ++ goto_cleanup_if_fail_with_rc_with_warning(doc != NULL, FALSE); + + root = xmlDocGetRootElement(doc); + lasso_node_init_from_xml(node, root); ++cleanup: ++ lasso_release_xml_string(buffer); ++ lasso_release_string(decoded); ++ lasso_release_string(re); + lasso_release_doc(doc); +- +- return TRUE; ++ return rc; + } + + char* +@@ -1894,40 +1889,44 @@ lasso_xml_get_soap_content(xmlNode *root) + LassoMessageFormat + lasso_xml_parse_message(const char *message, LassoMessageFormat constraint, xmlDoc **doc_out, xmlNode **root_out) + { +- char *msg = NULL; +- gboolean b64 = FALSE; ++ const char *msg = NULL; ++ int msg_len = 0; ++ char *base64_decoded_message = NULL; + LassoMessageFormat rc = LASSO_MESSAGE_FORMAT_UNKNOWN; + xmlDoc *doc = NULL; + xmlNode *root = NULL; + gboolean any = constraint == LASSO_MESSAGE_FORMAT_UNKNOWN; + +- msg = (char*)message; +- + /* BASE64 case */ + if (any || constraint == LASSO_MESSAGE_FORMAT_BASE64) { + if (message[0] != 0 && is_base64(message)) { +- msg = g_malloc(strlen(message)); +- rc = xmlSecBase64Decode((xmlChar*)message, (xmlChar*)msg, strlen(message)); +- if (rc >= 0) { +- b64 = TRUE; +- } else { +- lasso_release(msg); +- msg = (char*)message; ++ if (lasso_base64_decode(message, &base64_decoded_message, &msg_len)) { ++ rc = LASSO_MESSAGE_FORMAT_BASE64; ++ msg = base64_decoded_message; + } + } + } + ++ if (! msg) { ++ msg = message; ++ msg_len = strlen(message); ++ } ++ + /* XML case */ + if (any || constraint == LASSO_MESSAGE_FORMAT_BASE64 || + constraint == LASSO_MESSAGE_FORMAT_XML || + constraint == LASSO_MESSAGE_FORMAT_SOAP) { + if (strchr(msg, '<')) { +- doc = lasso_xml_parse_memory(msg, strlen(msg)); ++ doc = lasso_xml_parse_memory(msg, msg_len); + if (doc == NULL) { + rc = LASSO_MESSAGE_FORMAT_UNKNOWN; + goto cleanup; + } + root = xmlDocGetRootElement(doc); ++ if (! root) { ++ rc = LASSO_MESSAGE_FORMAT_ERROR; ++ goto cleanup; ++ } + + if (any || constraint == LASSO_MESSAGE_FORMAT_SOAP) { + gboolean is_soap = FALSE; +@@ -1936,26 +1935,20 @@ lasso_xml_parse_message(const char *message, LassoMessageFormat constraint, xmlD + if (is_soap) { + root = lasso_xml_get_soap_content(root); + } +- if (! root) { +- rc = LASSO_MESSAGE_FORMAT_ERROR; +- goto cleanup; +- } + if (is_soap) { + rc = LASSO_MESSAGE_FORMAT_SOAP; + goto cleanup; + } +- if (b64) { +- lasso_release(msg); +- rc = LASSO_MESSAGE_FORMAT_BASE64; ++ if (rc == LASSO_MESSAGE_FORMAT_BASE64) { + goto cleanup; + } + rc = LASSO_MESSAGE_FORMAT_XML; +- goto cleanup; + } + } + } + + cleanup: ++ lasso_release(base64_decoded_message); + if (doc_out) { + *doc_out = doc; + if (root_out) { +@@ -1963,7 +1956,6 @@ cleanup: + } + } else { + lasso_release_doc(doc); +- lasso_release_xml_node(root); + } + return rc; + } +@@ -2667,36 +2659,30 @@ lasso_xmlsec_load_private_key(const char *filename_or_buffer, const char *passwo + + gboolean + lasso_get_base64_content(xmlNode *node, char **content, size_t *length) { +- xmlChar *base64, *stripped_base64; +- xmlChar *result; +- int base64_length; +- int rc = 0; ++ xmlChar *base64 = NULL; ++ xmlChar *stripped_base64 = NULL; ++ char *decoded = NULL; ++ int decoded_length = 0; ++ int rc = TRUE; + +- if (! node || ! content || ! length) +- return FALSE; ++ goto_cleanup_if_fail_with_rc(node && content && length, FALSE); + + base64 = xmlNodeGetContent(node); +- if (! base64) +- return FALSE; +- stripped_base64 = base64; ++ goto_cleanup_if_fail_with_rc(base64, FALSE); ++ + /* skip spaces */ ++ stripped_base64 = base64; + while (*stripped_base64 && isspace(*stripped_base64)) + stripped_base64++; + +- base64_length = strlen((char*)stripped_base64); +- result = g_new(xmlChar, base64_length); +- xmlSecErrorsDefaultCallbackEnableOutput(FALSE); +- rc = xmlSecBase64Decode(stripped_base64, result, base64_length); +- xmlSecErrorsDefaultCallbackEnableOutput(TRUE); +- xmlFree(base64); +- if (rc < 0) { +- return FALSE; +- } else { +- *content = (char*)g_memdup(result, rc); +- xmlFree(result); +- *length = rc; +- return TRUE; +- } ++ goto_cleanup_if_fail_with_rc(lasso_base64_decode((char*)stripped_base64, &decoded, &decoded_length), FALSE); ++ lasso_transfer_string(*content, decoded); ++ *length = decoded_length; ++cleanup: ++ lasso_release_xml_string(base64); ++ lasso_release_string(decoded); ++ return rc; ++ + } + + xmlSecKeyPtr +@@ -3193,14 +3179,13 @@ static char* + lasso_get_saml_message(xmlChar **query_fields) { + int i = 0; + char *enc = NULL; +- char *message = NULL; ++ char *raw_message = NULL; ++ char *gziped_message = NULL; ++ int gziped_message_len = 0; + char *saml_message = NULL; +- char *decoded_message = NULL; ++ size_t saml_message_len = 0; + xmlChar *field = NULL; + char *t = NULL; +- int rc = 0; +- int len = 0; +- size_t outlen = 0; + + for (i=0; (field=query_fields[i]); i++) { + t = strchr((char*)field, '='); +@@ -3212,11 +3197,11 @@ lasso_get_saml_message(xmlChar **query_fields) { + continue; + } + if (strcmp((char*)field, LASSO_SAML2_FIELD_REQUEST) == 0 || strcmp((char*)field, LASSO_SAML2_FIELD_RESPONSE) == 0) { +- message = t+1; ++ raw_message = t+1; + continue; + } + } +- if (message == NULL) { ++ if (raw_message == NULL) { + return NULL; + } + if (enc && strcmp(enc, LASSO_SAML2_DEFLATE_ENCODING) != 0) { +@@ -3224,23 +3209,12 @@ lasso_get_saml_message(xmlChar **query_fields) { + debug("Unknown URL encoding: %64s", enc); + return NULL; + } +- len = strlen(message); +- decoded_message = g_malloc(len); +- if (! is_base64(message)) { +- debug("message is not base64"); +- goto cleanup; +- } +- rc = xmlSecBase64Decode((xmlChar*)message, (xmlChar*)decoded_message, len); +- if (rc < 0) { +- debug("could not decode redirect SAML message"); +- goto cleanup; +- } +- /* rc contains the length of the result */ +- saml_message = (char*)lasso_inflate((unsigned char*) decoded_message, rc, &outlen); ++ ++ goto_cleanup_if_fail(lasso_base64_decode(raw_message, &gziped_message, &gziped_message_len)) ++ saml_message = (char*)lasso_inflate((unsigned char*)gziped_message, gziped_message_len, &saml_message_len); + cleanup: +- if (decoded_message) { +- lasso_release(decoded_message); +- } ++ lasso_release_string(gziped_message); ++ + return saml_message; + } + +@@ -3256,6 +3230,7 @@ lasso_xmltextreader_from_message(const char *message, char **to_free) { + char *needle; + xmlChar **query_fields = NULL; + char *decoded_message = NULL; ++ int decoded_message_len = 0; + xmlTextReader *reader = NULL; + + g_assert(to_free); +@@ -3271,22 +3246,17 @@ lasso_xmltextreader_from_message(const char *message, char **to_free) { + } + len = strlen(message); + } else { /* POST */ +- int rc = 0; +- + if (! is_base64(message)) { + debug("POST message is not base64"); + goto cleanup; + } +- decoded_message = g_malloc(len); +- rc = xmlSecBase64Decode((xmlChar*)message, (xmlChar*)decoded_message, len); +- if (rc < 0) { ++ if (! lasso_base64_decode(message, &decoded_message, &decoded_message_len)) { + debug("could not decode POST SAML message"); + goto cleanup; + } +- len = rc; +- decoded_message[len] = '\0'; +- message = *to_free = decoded_message; +- decoded_message = NULL; ++ message = decoded_message; ++ len = decoded_message_len; ++ lasso_transfer_string(*to_free, decoded_message); + } + } + +@@ -3294,9 +3264,7 @@ lasso_xmltextreader_from_message(const char *message, char **to_free) { + reader = xmlReaderForMemory(message, len, "", NULL, XML_PARSE_NONET); + + cleanup: +- if (query_fields) +- lasso_release_array_of_xml_strings(query_fields); +- if (decoded_message) +- lasso_release_string(decoded_message); ++ lasso_release_array_of_xml_strings(query_fields); ++ lasso_release_string(decoded_message); + return reader; + } +diff --git a/lasso/xml/xml.c b/lasso/xml/xml.c +index a921b2c4..0d5c6e31 100644 +--- a/lasso/xml/xml.c ++++ b/lasso/xml/xml.c +@@ -2534,7 +2534,9 @@ is_base64(const char *message) + LassoMessageFormat + lasso_node_init_from_message_with_format(LassoNode *node, const char *message, LassoMessageFormat constraint, xmlDoc **doc_out, xmlNode **root_out) + { +- char *msg = NULL; ++ char *decoded_msg = NULL; ++ int decoded_msg_len = 0; ++ const char *msg = NULL; + gboolean b64 = FALSE; + LassoMessageFormat rc = LASSO_MESSAGE_FORMAT_ERROR; + xmlDoc *doc = NULL; +@@ -2546,15 +2548,11 @@ lasso_node_init_from_message_with_format(LassoNode *node, const char *message, L + /* BASE64 case */ + if (any || constraint == LASSO_MESSAGE_FORMAT_BASE64) { + if (message[0] != 0 && is_base64(message)) { +- int rc = 0; +- +- msg = g_malloc(strlen(message)); +- rc = xmlSecBase64Decode((xmlChar*)message, (xmlChar*)msg, strlen(message)); +- if (rc >= 0) { ++ if (lasso_base64_decode(message, &decoded_msg, &decoded_msg_len)) { + b64 = TRUE; ++ msg = decoded_msg; + } else { +- lasso_release(msg); +- msg = (char*)message; ++ msg = message; + } + } + } +@@ -2589,7 +2587,6 @@ lasso_node_init_from_message_with_format(LassoNode *node, const char *message, L + goto cleanup; + } + if (b64) { +- lasso_release(msg); + rc = LASSO_MESSAGE_FORMAT_BASE64; + goto cleanup; + } +@@ -2612,6 +2609,7 @@ lasso_node_init_from_message_with_format(LassoNode *node, const char *message, L + } + + cleanup: ++ lasso_release_string(decoded_msg); + if (doc_out) { + *doc_out = doc; + if (root_out) { diff --git a/CVE-2025-47151.patch b/CVE-2025-47151.patch new file mode 100644 index 0000000000000000000000000000000000000000..ffc9665db06dffaad1bf3614c09f09519aa176e5 --- /dev/null +++ b/CVE-2025-47151.patch @@ -0,0 +1,63 @@ +From 8d12e6263fd6add923469bd5704e05a1ccfa8c69 Mon Sep 17 00:00:00 2001 +From: Benjamin Dauvergne +Date: Thu, 15 May 2025 15:44:58 +0200 +Subject: [PATCH] xml: prevent assignment of attribute value inside any + attribute + +Origin: https://git.entrouvert.org/entrouvert/lasso/commit/8d12e6263fd6add923469bd5704e05a1ccfa8c69 +--- + lasso/xml/misc_text_node.c | 2 +- + lasso/xml/saml-2.0/saml2_attribute_value.c | 2 +- + lasso/xml/xml.c | 3 +++ + 3 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/lasso/xml/misc_text_node.c b/lasso/xml/misc_text_node.c +index 59d98c5..1f9d980 100644 +--- a/lasso/xml/misc_text_node.c ++++ b/lasso/xml/misc_text_node.c +@@ -41,7 +41,7 @@ typedef struct { + static struct XmlSnippet schema_snippets[] = { + { "content", SNIPPET_TEXT_CHILD, + G_STRUCT_OFFSET(LassoMiscTextNode, content), NULL, NULL, NULL}, +- { "any_attributes", SNIPPET_ATTRIBUTE | SNIPPET_ANY | SNIPPET_PRIVATE, ++ { "", SNIPPET_ATTRIBUTE | SNIPPET_ANY | SNIPPET_PRIVATE, + G_STRUCT_OFFSET(LassoMiscTextNodePrivate, any_attributes), NULL, NULL, NULL}, + {NULL, 0, 0, NULL, NULL, NULL} + }; +diff --git a/lasso/xml/saml-2.0/saml2_attribute_value.c b/lasso/xml/saml-2.0/saml2_attribute_value.c +index c8a588c..4526805 100644 +--- a/lasso/xml/saml-2.0/saml2_attribute_value.c ++++ b/lasso/xml/saml-2.0/saml2_attribute_value.c +@@ -53,7 +53,7 @@ struct _LassoSaml2AttributeValuePrivate { + static struct XmlSnippet schema_snippets[] = { + { "any", SNIPPET_LIST_NODES | SNIPPET_ANY | SNIPPET_ALLOW_TEXT, + G_STRUCT_OFFSET(LassoSaml2AttributeValue, any), NULL, NULL, NULL}, +- { "any_attributes", SNIPPET_ATTRIBUTE | SNIPPET_ANY | SNIPPET_PRIVATE, ++ { "", SNIPPET_ATTRIBUTE | SNIPPET_ANY | SNIPPET_PRIVATE, + G_STRUCT_OFFSET(struct _LassoSaml2AttributeValuePrivate, any_attributes), NULL, + NULL, NULL }, + {NULL, 0, 0, NULL, NULL, NULL} +diff --git a/lasso/xml/xml.c b/lasso/xml/xml.c +index 0d5c6e3..61a5e17 100644 +--- a/lasso/xml/xml.c ++++ b/lasso/xml/xml.c +@@ -1569,6 +1569,7 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode) + type = snippet->type & 0xff; + /* assign attribute content if attribute has the same name as the + * snippet and: ++ * - the snippet is not the any attribute snippet, + * - the snippet and the attribute have no namespace + * - the snippet has no namespace but the attribute has the same + * namespace as the node +@@ -1576,6 +1577,8 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode) + */ + if (type != SNIPPET_ATTRIBUTE) + continue; ++ if (snippet->type & SNIPPET_ANY) ++ continue; + if (! lasso_strisequal((char*)attr->name, (char*)snippet->name)) + continue; + if (attr->ns) { +-- +2.51.1 + diff --git a/lasso.spec b/lasso.spec index c91e32a2c17ea4c93d37b78946b4605539c7f6aa..89c4ec9ce63053824db14fda1ea14ee7d7134415 100644 --- a/lasso.spec +++ b/lasso.spec @@ -1,12 +1,18 @@ Name: lasso Version: 2.7.0 -Release: 1 +Release: 2 Summary: Liberty Alliance Single Sign On License: GPLv2+ URL: http://lasso.entrouvert.org/ Source: http://dev.entrouvert.org/lasso/lasso-%{version}.tar.gz Requires: xmlsec1 >= 1.2.25-4 Patch1: lasso-python-dont-decref-true-false.patch +Patch2: CVE-2025-46404.patch +Patch3: CVE-2025-46705-pre.patch +Patch4: CVE-2025-46705.patch +Patch5: CVE-2025-46784-pre.patch +Patch6: CVE-2025-46784.patch +Patch7: CVE-2025-47151.patch BuildRequires: autoconf automake check-devel glib2-devel gtk-doc libtool BuildRequires: libxml2-devel openssl-devel swig xmlsec1-devel >= 1.2.25-4 @@ -111,6 +117,9 @@ fi %doc AUTHORS NEWS README %changelog +* Fri Nov 07 2025 yaoxin <1024769339@qq.com> - 2.7.0-2 +- Fix CVE-2025-46404, CVE-2025-46705, CVE-2025-46784 and CVE-2025-47151 + * Mon Oct 17 2022 wangkai - 2.7.0-1 - Upgrade to 2.7.0