The proposed source debdiff for stretch-security: diff -Nru xml-security-c-1.7.3/debian/changelog xml-security-c-1.7.3/debian/changelog --- xml-security-c-1.7.3/debian/changelog 2016-11-08 21:52:45.000000000 +0100 +++ xml-security-c-1.7.3/debian/changelog 2018-08-03 11:32:52.000000000 +0200 @@ -1,3 +1,19 @@ +xml-security-c (1.7.3-4+deb9u1) stretch-security; urgency=high + + * [c16e40f] New patch: Default KeyInfo resolver doesn't check for empty + element content. + The Apache Santuario XML Security for C++ library contained a + number of code paths at risk of dereferencing null pointers when + processing various kinds of malformed KeyInfo hints typically found + in signed or encrypted XML. The usual effect is a crash, and in the + case of the Shibboleth SP software, a crash in the shibd daemon. + Upstream bug: + https://issues.apache.org/jira/projects/SANTUARIO/issues/SANTUARIO-491 + CVE: not assigned yet + Thanks to Scott Cantor (Closes: #905332) + + -- Ferenc Wágner <wf...@debian.org> Fri, 03 Aug 2018 11:32:52 +0200 + xml-security-c (1.7.3-4) unstable; urgency=medium [ Etienne Dysli Metref ] diff -Nru xml-security-c-1.7.3/debian/gbp.conf xml-security-c-1.7.3/debian/gbp.conf --- xml-security-c-1.7.3/debian/gbp.conf 2016-11-08 21:30:39.000000000 +0100 +++ xml-security-c-1.7.3/debian/gbp.conf 2018-08-02 11:57:00.000000000 +0200 @@ -1,9 +1,11 @@ -[import-orig] +[DEFAULT] +debian-branch = stretch pristine-tar = True [dch] multimaint-merge = True id-length = 7 +full = True [pq] patch-numbers = False diff -Nru xml-security-c-1.7.3/debian/patches/Default-KeyInfo-resolver-doesn-t-check-for-empty-element-.patch xml-security-c-1.7.3/debian/patches/Default-KeyInfo-resolver-doesn-t-check-for-empty-element-.patch --- xml-security-c-1.7.3/debian/patches/Default-KeyInfo-resolver-doesn-t-check-for-empty-element-.patch 1970-01-01 01:00:00.000000000 +0100 +++ xml-security-c-1.7.3/debian/patches/Default-KeyInfo-resolver-doesn-t-check-for-empty-element-.patch 2018-08-03 11:25:06.000000000 +0200 @@ -0,0 +1,215 @@ +From: Scott Cantor <scan...@apache.org> +Date: Wed, 1 Aug 2018 13:02:21 +0000 +Subject: Default KeyInfo resolver doesn't check for empty element content + +The Apache Santuario XML Security for C++ library contained a +number of code paths at risk of dereferencing null pointers when +processing various kinds of malformed KeyInfo hints typically found +in signed or encrypted XML. The usual effect is a crash, and in the +case of the Shibboleth SP software, a crash in the shibd daemon. + +This is a combination of two upstream commits with some unrelated +whitespace changes removed. Quite much of it is still indentation +change because of the added conditionals. Best viewed with tabstop=4, +for example with 'LESS=Rx4 git show --ignore-space-changes'. + +Thanks: Scott Cantor +Upstream bug: + https://issues.apache.org/jira/projects/SANTUARIO/issues/SANTUARIO-491 +CVE: not assigned yet +Closes: #905332 +--- + xsec/dsig/DSIGKeyInfoValue.hpp | 8 +-- + xsec/enc/XSECKeyInfoResolverDefault.cpp | 108 +++++++++++++++++++------------- + 2 files changed, 69 insertions(+), 47 deletions(-) + +diff --git a/xsec/dsig/DSIGKeyInfoValue.hpp b/xsec/dsig/DSIGKeyInfoValue.hpp +index f652679..d6da5d5 100644 +--- a/xsec/dsig/DSIGKeyInfoValue.hpp ++++ b/xsec/dsig/DSIGKeyInfoValue.hpp +@@ -117,7 +117,7 @@ public: + * @returns a pointer to the DSA P string value. + */ + +- const XMLCh * getDSAP(void) const {return mp_PTextNode->getNodeValue();} ++ const XMLCh * getDSAP() const {return mp_PTextNode ? mp_PTextNode->getNodeValue() : NULL;} + + /** + * \brief Get Q value +@@ -125,7 +125,7 @@ public: + * @returns a pointer to the DSA Q string value. + */ + +- const XMLCh * getDSAQ(void) const {return mp_QTextNode->getNodeValue();} ++ const XMLCh * getDSAQ() const {return mp_QTextNode ? mp_QTextNode->getNodeValue() : NULL;} + + /** + * \brief Get G value +@@ -133,7 +133,7 @@ public: + * @returns a pointer to the DSA G string value. + */ + +- const XMLCh * getDSAG(void) const {return mp_GTextNode->getNodeValue();} ++ const XMLCh * getDSAG() const {return mp_GTextNode ? mp_GTextNode->getNodeValue() : NULL;} + + /** + * \brief Get Y value +@@ -141,7 +141,7 @@ public: + * @returns a pointer to the DSA Y string value. + */ + +- const XMLCh * getDSAY(void) const {return mp_YTextNode->getNodeValue();} ++ const XMLCh * getDSAY() const {return mp_YTextNode ? mp_YTextNode->getNodeValue() : NULL;} + + /** + * \brief Get Modulus +diff --git a/xsec/enc/XSECKeyInfoResolverDefault.cpp b/xsec/enc/XSECKeyInfoResolverDefault.cpp +index 52cdfe3..c4c81cb 100644 +--- a/xsec/enc/XSECKeyInfoResolverDefault.cpp ++++ b/xsec/enc/XSECKeyInfoResolverDefault.cpp +@@ -79,13 +79,11 @@ XSECCryptoKey * XSECKeyInfoResolverDefault::resolveKey(DSIGKeyInfoList * lst) { + case (DSIGKeyInfo::KEYINFO_X509) : + { + ret = NULL; +- const XMLCh * x509Str; +- XSECCryptoX509 * x509 = XSECPlatformUtils::g_cryptoProvider->X509(); +- Janitor<XSECCryptoX509> j_x509(x509); +- +- x509Str = ((DSIGKeyInfoX509 *) lst->item(i))->getCertificateItem(0); ++ const XMLCh* x509Str = ((const DSIGKeyInfoX509 *) lst->item(i))->getCertificateItem(0); + +- if (x509Str != 0) { ++ if (x509Str) { ++ XSECCryptoX509 * x509 = XSECPlatformUtils::g_cryptoProvider->X509(); ++ Janitor<XSECCryptoX509> j_x509(x509); + + // The crypto interface classes work UTF-8 + safeBuffer transX509; +@@ -104,66 +102,90 @@ XSECCryptoKey * XSECKeyInfoResolverDefault::resolveKey(DSIGKeyInfoList * lst) { + case (DSIGKeyInfo::KEYINFO_VALUE_DSA) : + { + +- XSECCryptoKeyDSA * dsa = XSECPlatformUtils::g_cryptoProvider->keyDSA(); +- Janitor<XSECCryptoKeyDSA> j_dsa(dsa); +- +- safeBuffer value; +- +- value << (*mp_formatter << ((DSIGKeyInfoValue *) lst->item(i))->getDSAP()); +- dsa->loadPBase64BigNums(value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); +- value << (*mp_formatter << ((DSIGKeyInfoValue *) lst->item(i))->getDSAQ()); +- dsa->loadQBase64BigNums(value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); +- value << (*mp_formatter << ((DSIGKeyInfoValue *) lst->item(i))->getDSAG()); +- dsa->loadGBase64BigNums(value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); +- value << (*mp_formatter << ((DSIGKeyInfoValue *) lst->item(i))->getDSAY()); +- dsa->loadYBase64BigNums(value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); +- +- j_dsa.release(); +- return dsa; ++ const DSIGKeyInfoValue* dsaval = (const DSIGKeyInfoValue *) lst->item(i); ++ if (dsaval->getDSAP() || dsaval->getDSAQ() || dsaval->getDSAG() || dsaval->getDSAY()) { ++ ++ XSECCryptoKeyDSA * dsa = XSECPlatformUtils::g_cryptoProvider->keyDSA(); ++ Janitor<XSECCryptoKeyDSA> j_dsa(dsa); ++ ++ safeBuffer value; ++ ++ if (dsaval->getDSAP()) { ++ value << (*mp_formatter << dsaval->getDSAP()); ++ dsa->loadPBase64BigNums(value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); ++ } ++ if (dsaval->getDSAQ()) { ++ value << (*mp_formatter << dsaval->getDSAQ()); ++ dsa->loadQBase64BigNums(value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); ++ } ++ if (dsaval->getDSAG()) { ++ value << (*mp_formatter << dsaval->getDSAG()); ++ dsa->loadGBase64BigNums(value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); ++ } ++ if (dsaval->getDSAY()) { ++ value << (*mp_formatter << dsaval->getDSAY()); ++ dsa->loadYBase64BigNums(value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); ++ } ++ ++ j_dsa.release(); ++ return dsa; ++ } + } + break; + + case (DSIGKeyInfo::KEYINFO_VALUE_RSA) : + { ++ const DSIGKeyInfoValue* rsaval = (const DSIGKeyInfoValue *) lst->item(i); ++ if (rsaval->getRSAModulus() && rsaval->getRSAExponent()) { + +- XSECCryptoKeyRSA * rsa = XSECPlatformUtils::g_cryptoProvider->keyRSA(); +- Janitor<XSECCryptoKeyRSA> j_rsa(rsa); ++ XSECCryptoKeyRSA* rsa = XSECPlatformUtils::g_cryptoProvider->keyRSA(); ++ Janitor<XSECCryptoKeyRSA> j_rsa(rsa); + +- safeBuffer value; ++ safeBuffer value; + +- value << (*mp_formatter << ((DSIGKeyInfoValue *) lst->item(i))->getRSAModulus()); +- rsa->loadPublicModulusBase64BigNums(value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); +- value << (*mp_formatter << ((DSIGKeyInfoValue *) lst->item(i))->getRSAExponent()); +- rsa->loadPublicExponentBase64BigNums(value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); ++ value << (*mp_formatter << rsaval->getRSAModulus()); ++ rsa->loadPublicModulusBase64BigNums(value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); ++ value << (*mp_formatter << rsaval->getRSAExponent()); ++ rsa->loadPublicExponentBase64BigNums(value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); + +- j_rsa.release(); +- return rsa; ++ j_rsa.release(); ++ return rsa; ++ } + + } + break; + + case (DSIGKeyInfo::KEYINFO_VALUE_EC) : + { ++ const DSIGKeyInfoValue* ecval = (const DSIGKeyInfoValue *) lst->item(i); ++ if (ecval->getECPublicKey() && ecval->getECNamedCurve()) { + +- XSECCryptoKeyEC* ec = XSECPlatformUtils::g_cryptoProvider->keyEC(); +- Janitor<XSECCryptoKeyEC> j_ec(ec); ++ XSECCryptoKeyEC* ec = XSECPlatformUtils::g_cryptoProvider->keyEC(); ++ Janitor<XSECCryptoKeyEC> j_ec(ec); + +- safeBuffer value; +- value << (*mp_formatter << ((DSIGKeyInfoValue *) lst->item(i))->getECPublicKey()); +- XSECAutoPtrChar curve(((DSIGKeyInfoValue *) lst->item(i))->getECNamedCurve()); +- if (curve.get()) { +- ec->loadPublicKeyBase64(curve.get(), value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); +- j_ec.release(); +- return ec; ++ safeBuffer value; ++ ++ value << (*mp_formatter << ecval->getECPublicKey()); ++ XSECAutoPtrChar curve(ecval->getECNamedCurve()); ++ if (curve.get()) { ++ ec->loadPublicKeyBase64(curve.get(), value.rawCharBuffer(), (unsigned int) strlen(value.rawCharBuffer())); ++ j_ec.release(); ++ return ec; ++ } + } + } + break; + + case (DSIGKeyInfo::KEYINFO_DERENCODED) : + { +- safeBuffer value; +- value << (*mp_formatter << ((DSIGKeyInfoDEREncoded *) lst->item(i))->getData()); +- return XSECPlatformUtils::g_cryptoProvider->keyDER(value.rawCharBuffer(), (unsigned int)strlen(value.rawCharBuffer()), true); ++ const DSIGKeyInfoDEREncoded* derval = (const DSIGKeyInfoDEREncoded *) lst->item(i); ++ if (derval->getData()) { ++ ++ safeBuffer value; ++ ++ value << (*mp_formatter << derval->getData()); ++ return XSECPlatformUtils::g_cryptoProvider->keyDER(value.rawCharBuffer(), (unsigned int)strlen(value.rawCharBuffer()), true); ++ } + } + break; + diff -Nru xml-security-c-1.7.3/debian/patches/series xml-security-c-1.7.3/debian/patches/series --- xml-security-c-1.7.3/debian/patches/series 2016-11-08 21:30:39.000000000 +0100 +++ xml-security-c-1.7.3/debian/patches/series 2018-08-03 11:32:47.000000000 +0200 @@ -21,3 +21,4 @@ Use-pkg-config-for-Xerces-OpenSSL-and-NSS-and-provid.patch We-do-not-use-pthreads-threadtest.cpp-is-Windows-onl.patch Only-add-found-packages-to-the-pkg-config-dependenci.patch +Default-KeyInfo-resolver-doesn-t-check-for-empty-element-.patch
I tested the resulting package, it fixed the bug and didn't cause any breakage for me. There is a header file change affecting inline function bodies, but according to codesearch.debian.net those functions aren't used outside of xml-security-c, so there's no need to rebuild anything in the archive after this update. The DSA should probably include a corresponding warning, though. Dear Security Team, please let me know how to proceed. (Do you need the Cc, or was the security tag enough to get you in the loop?) And jessie is handled by the LTS team now, isn't it? -- Regards, Feri