summaryrefslogtreecommitdiffstats
path: root/debian/patches/0002-CVE-2022-26307-make-hash-encoding-match-decoding.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/0002-CVE-2022-26307-make-hash-encoding-match-decoding.patch')
-rw-r--r--debian/patches/0002-CVE-2022-26307-make-hash-encoding-match-decoding.patch183
1 files changed, 183 insertions, 0 deletions
diff --git a/debian/patches/0002-CVE-2022-26307-make-hash-encoding-match-decoding.patch b/debian/patches/0002-CVE-2022-26307-make-hash-encoding-match-decoding.patch
new file mode 100644
index 000000000..d56b5ea04
--- /dev/null
+++ b/debian/patches/0002-CVE-2022-26307-make-hash-encoding-match-decoding.patch
@@ -0,0 +1,183 @@
+From 780c42cdd8006dc60e281be2fe6566f101e909bc Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
+Date: Mon, 21 Mar 2022 20:58:34 +0000
+Subject: [PATCH 2/4] CVE-2022-26307 make hash encoding match decoding
+
+Seeing as old versions of the hash may be in the users config, add a
+StorageVersion field to the office config Passwords section which
+defaults to 0 to indicate the old hash is in use.
+
+Try the old varient when StorageVersion is 0. When a new encoded master
+password it set write StorageVersion of 1 to indicate a new hash is in
+use and use the new style when StorageVersion is 1.
+
+Change-Id: I3174c37a5891bfc849984e0ec5c2c392b9c6e7b1
+Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132080
+Tested-by: Jenkins
+Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
+(cherry picked from commit e890f54dbac57f3ab5acf4fbd31222095d3e8ab6)
+---
+ .../schema/org/openoffice/Office/Common.xcs | 6 +++
+ .../passwordcontainer/passwordcontainer.cxx | 45 +++++++++++++++++--
+ .../passwordcontainer/passwordcontainer.hxx | 6 +++
+ uui/source/iahndl-authentication.cxx | 5 ++-
+ 4 files changed, 57 insertions(+), 5 deletions(-)
+
+diff --git a/officecfg/registry/schema/org/openoffice/Office/Common.xcs b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
+index 9097c23c3c6a..922efc33cca7 100644
+--- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs
++++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
+@@ -942,6 +942,12 @@
+ </info>
+ <value>false</value>
+ </prop>
++ <prop oor:name="StorageVersion" oor:type="xs:int" oor:nillable="false">
++ <info>
++ <desc>Specifies what version of encoding scheme the password container uses.</desc>
++ </info>
++ <value>0</value>
++ </prop>
+ <prop oor:name="HasMaster" oor:type="xs:boolean" oor:nillable="false">
+ <info>
+ <desc>Specifies if there is a valid master password.</desc>
+diff --git a/svl/source/passwordcontainer/passwordcontainer.cxx b/svl/source/passwordcontainer/passwordcontainer.cxx
+index 51fb129cddb1..b674844f91d3 100644
+--- a/svl/source/passwordcontainer/passwordcontainer.cxx
++++ b/svl/source/passwordcontainer/passwordcontainer.cxx
+@@ -17,7 +17,6 @@
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+-
+ #include "passwordcontainer.hxx"
+
+ #include <cppuhelper/factory.hxx>
+@@ -259,6 +258,23 @@ bool StorageItem::useStorage()
+ return aResult;
+ }
+
++sal_Int32 StorageItem::getStorageVersion()
++{
++ Sequence<OUString> aNodeNames { "StorageVersion" };
++
++ Sequence< Any > aPropertyValues = ConfigItem::GetProperties( aNodeNames );
++
++ if( aPropertyValues.getLength() != aNodeNames.getLength() )
++ {
++ OSL_FAIL( "Problems during reading" );
++ return 0;
++ }
++
++ sal_Int32 nResult = 0;
++ aPropertyValues[0] >>= nResult;
++
++ return nResult;
++}
+
+ bool StorageItem::getEncodedMP( OUString& aResult )
+ {
+@@ -291,15 +307,17 @@ bool StorageItem::getEncodedMP( OUString& aResult )
+
+ void StorageItem::setEncodedMP( const OUString& aEncoded, bool bAcceptEmpty )
+ {
+- Sequence< OUString > sendNames(2);
+- Sequence< uno::Any > sendVals(2);
++ Sequence< OUString > sendNames(3);
++ Sequence< uno::Any > sendVals(3);
+
+ sendNames[0] = "HasMaster";
+ sendNames[1] = "Master";
++ sendNames[2] = "StorageVersion";
+
+ bool bHasMaster = ( !aEncoded.isEmpty() || bAcceptEmpty );
+ sendVals[0] <<= bHasMaster;
+ sendVals[1] <<= aEncoded;
++ sendVals[2] <<= nCurrentStorageVersion;
+
+ ConfigItem::SetModified();
+ ConfigItem::PutProperties( sendNames, sendVals );
+@@ -800,6 +818,18 @@ OUString PasswordContainer::RequestPasswordFromUser( PasswordRequestMode aRMode,
+ return aResult;
+ }
+
++// Mangle the key to match an old bug
++static OUString ReencodeAsOldHash(const OUString& rPass)
++{
++ OUStringBuffer aBuffer;
++ for (int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ++ind)
++ {
++ unsigned char i = static_cast<char>(rPass.copy(ind * 2, 2).toUInt32(16));
++ aBuffer.append(static_cast< sal_Unicode >('a' + (i >> 4)));
++ aBuffer.append(static_cast< sal_Unicode >('a' + (i & 15)));
++ }
++ return aBuffer.makeStringAndClear();
++}
+
+ OUString const & PasswordContainer::GetMasterPassword( const Reference< XInteractionHandler >& aHandler )
+ {
+@@ -838,6 +868,9 @@ OUString const & PasswordContainer::GetMasterPassword( const Reference< XInterac
+ }
+ else
+ {
++ if (m_pStorageFile->getStorageVersion() == 0)
++ aPass = ReencodeAsOldHash(aPass);
++
+ std::vector< OUString > aRM( DecodePasswords( aEncodedMP, aPass, aRMode ) );
+ if( aRM.empty() || aPass != aRM[0] )
+ {
+@@ -1042,6 +1075,12 @@ sal_Bool SAL_CALL PasswordContainer::authorizateWithMasterPassword( const uno::R
+
+ do {
+ aPass = RequestPasswordFromUser( aRMode, xTmpHandler );
++
++ if (!aPass.isEmpty() && m_pStorageFile->getStorageVersion() == 0)
++ {
++ aPass = ReencodeAsOldHash(aPass);
++ }
++
+ bResult = ( !aPass.isEmpty() && aPass == m_aMasterPasswd );
+ aRMode = PasswordRequestMode_PASSWORD_REENTER; // further questions with error notification
+ } while( !bResult && !aPass.isEmpty() );
+diff --git a/svl/source/passwordcontainer/passwordcontainer.hxx b/svl/source/passwordcontainer/passwordcontainer.hxx
+index 46ffec888602..bf43b5903602 100644
+--- a/svl/source/passwordcontainer/passwordcontainer.hxx
++++ b/svl/source/passwordcontainer/passwordcontainer.hxx
+@@ -168,6 +168,10 @@ public:
+ typedef ::std::pair< const OUString, ::std::vector< NamePassRecord > > PairUrlRecord;
+ typedef ::std::map< OUString, ::std::vector< NamePassRecord > > PassMap;
+
++// org.openoffice.Office.Common/Passwords/StorageVersion bump if details of
++// how password details are saved changes. Enables migration from previous
++// schemes.
++constexpr sal_Int32 nCurrentStorageVersion = 1;
+
+ class PasswordContainer;
+
+@@ -195,6 +195,8 @@
+ void remove( const OUString& url, const OUString& rec );
+ void clear();
+
++ sal_Int32 getStorageVersion();
++
+ bool getEncodedMP( OUString& aResult );
+ void setEncodedMP( const OUString& aResult, bool bAcceptEnmpty = false );
+ void setUseStorage( bool bUse );
+diff --git a/uui/source/iahndl-authentication.cxx b/uui/source/iahndl-authentication.cxx
+index ad975d3f9ae7..951f0b8a1c6b 100644
+--- a/uui/source/iahndl-authentication.cxx
++++ b/uui/source/iahndl-authentication.cxx
+@@ -436,8 +436,9 @@ executeMasterPasswordDialog(
+ OUStringBuffer aBuffer;
+ for (sal_uInt8 i : aKey)
+ {
+- aBuffer.append(static_cast< sal_Unicode >('a' + (i >> 4)));
+- aBuffer.append(static_cast< sal_Unicode >('a' + (i & 15)));
++ // match PasswordContainer::DecodePasswords aMasterPasswd.copy(index * 2, 2).toUInt32(16));
++ aBuffer.append(OUString::number(i >> 4, 16));
++ aBuffer.append(OUString::number(i & 15, 16));
+ }
+ rInfo.SetPassword(aBuffer.makeStringAndClear());
+ }
+--
+2.37.1
+