Bug#854782: unblock: python-bottle-cork/0.12.0-2
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
Please unblock package python-bottle-cork
Recently a vulnerability in the package has been discovered (due to very weak
hashing of passwords), reported in the BTS as #854390.
Upstream has provided a fix in their repository, which I have now backported
and uploaded.
>From a Debian repository perspective, python-bottle-cork is a leaf package
with a very small popcon (i'm not entirely sure, how many of the 5 installments
are actually mine), so the impact should be small enough.
unblock python-bottle-cork/0.12.0-2
-- System Information:
Debian Release: 9.0
APT prefers unstable
APT policy: (500, 'unstable'), (500, 'testing'), (1, 'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386
Kernel: Linux 4.9.0-1-amd64 (SMP w/4 CPU cores)
Locale: LANG=en_US.utf8, LC_CTYPE=en_US.utf8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
diff -Nru python-bottle-cork-0.12.0/debian/changelog python-bottle-cork-0.12.0/debian/changelog
--- python-bottle-cork-0.12.0/debian/changelog 2016-08-31 21:13:24.000000000 +0200
+++ python-bottle-cork-0.12.0/debian/changelog 2017-02-10 10:04:27.000000000 +0100
@@ -1,3 +1,10 @@
+python-bottle-cork (0.12.0-2) unstable; urgency=medium
+
+ * Backported fix for weak hashing defaults (Closes: #854390)
+ * Thanks: Federico Ceratto
+
+ -- IOhannes m zmölnig (Debian/GNU) <umlaeute@debian.org> Fri, 10 Feb 2017 10:04:27 +0100
+
python-bottle-cork (0.12.0-1) unstable; urgency=medium
* Initial package (Closes: #836163)
diff -Nru python-bottle-cork-0.12.0/debian/.git-dpm python-bottle-cork-0.12.0/debian/.git-dpm
--- python-bottle-cork-0.12.0/debian/.git-dpm 2016-08-31 21:13:24.000000000 +0200
+++ python-bottle-cork-0.12.0/debian/.git-dpm 2017-02-10 10:04:27.000000000 +0100
@@ -1,6 +1,6 @@
# see git-dpm(1) from git-dpm package
-9f5b7a899774140f053c15ed7fd0b3c9d9b02bf8
-9f5b7a899774140f053c15ed7fd0b3c9d9b02bf8
+5cc4bf91c713ec506ced30483ce277456d55a609
+5cc4bf91c713ec506ced30483ce277456d55a609
a9a0d14d2806481a276a7cc79f3dacf05a1e5fd6
a9a0d14d2806481a276a7cc79f3dacf05a1e5fd6
python-bottle-cork_0.12.0.orig.tar.gz
diff -Nru python-bottle-cork-0.12.0/debian/patches/0002-Backported-fix-for-weak-hashing-defaults.patch python-bottle-cork-0.12.0/debian/patches/0002-Backported-fix-for-weak-hashing-defaults.patch
--- python-bottle-cork-0.12.0/debian/patches/0002-Backported-fix-for-weak-hashing-defaults.patch 1970-01-01 01:00:00.000000000 +0100
+++ python-bottle-cork-0.12.0/debian/patches/0002-Backported-fix-for-weak-hashing-defaults.patch 2017-02-10 10:04:27.000000000 +0100
@@ -0,0 +1,164 @@
+From 5cc4bf91c713ec506ced30483ce277456d55a609 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig=20=28Debian/GNU=29?=
+ <umlaeute@debian.org>
+Date: Thu, 9 Feb 2017 22:51:53 +0100
+Subject: Backported fix for weak hashing defaults
+
+upstream: ebb2777d6eaeff0cfa95f9b1d8b83ed9d87a493b
+Closes: #854390
+---
+ cork/cork.py | 73 ++++++++++++++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 56 insertions(+), 17 deletions(-)
+
+diff --git a/cork/cork.py b/cork/cork.py
+index d8b2320..e8b6358 100644
+--- a/cork/cork.py
++++ b/cork/cork.py
+@@ -69,7 +69,8 @@ class BaseCork(object):
+
+ def __init__(self, directory=None, backend=None, email_sender=None,
+ initialize=False, session_domain=None, smtp_server=None,
+- smtp_url='localhost', session_key_name=None):
++ smtp_url='localhost', session_key_name=None,
++ preferred_hashing_algorithm=None, pbkdf2_iterations=None):
+ """Auth/Authorization/Accounting class
+
+ :param directory: configuration directory
+@@ -79,13 +80,24 @@ class BaseCork(object):
+ :param roles_fname: roles filename (without .json), defaults to 'roles'
+ :type roles_fname: str.
+ """
++ if preferred_hashing_algorithm not in ("PBKDF2sha1", "PBKDF2sha256", "scrypt"):
++ raise Exception("preferred_hashing_algorithm must be 'PBKDF2sha256', 'PBKDF2sha1' or 'scrypt'")
++
++ if preferred_hashing_algorithm.startswith("PBKDF2") and not pbkdf2_iterations:
++ raise Exception("pbkdf2_iterations must be set")
++ elif preferred_hashing_algorithm == 'scrypt' and not scrypt_available:
++ raise Exception("scrypt.hash required."
++ " Please install the scrypt library.")
++
+ if smtp_server:
+ smtp_url = smtp_server
+ self.mailer = Mailer(email_sender, smtp_url)
+ self.password_reset_timeout = 3600 * 24
+ self.session_domain = session_domain
+ self.session_key_name = session_key_name or 'beaker.session'
+- self.preferred_hashing_algorithm = 'PBKDF2'
++ self.saltlength = { 'PBKDF2':32, 'scrypt':32, 'argon2':57 }
++ self.preferred_hashing_algorithm = preferred_hashing_algorithm
++ self.pbkdf2_iterations = pbkdf2_iterations
+
+ # Setup JsonBackend by default for backward compatibility.
+ if backend is None:
+@@ -612,16 +624,18 @@ class BaseCork(object):
+ if algo is None:
+ algo = self.preferred_hashing_algorithm
+
+- if algo == 'PBKDF2':
+- return self._hash_pbkdf2(username, pwd, salt=salt)
++ if algo == 'PBKDF2sha1':
++ return self._hash_pbkdf2_sha1(username, pwd, salt=salt)
++
++ if algo == 'PBKDF2sha256':
++ return self._hash_pbkdf2_sha256(username, pwd, salt=salt)
+
+ if algo == 'scrypt':
+ return self._hash_scrypt(username, pwd, salt=salt)
+
+ raise RuntimeError("Unknown hashing algorithm requested: %s" % algo)
+
+- @staticmethod
+- def _hash_scrypt(username, pwd, salt=None):
++ def _hash_scrypt(self, username, pwd, salt=None):
+ """Hash username and password, generating salt value if required
+ Use scrypt.
+
+@@ -632,9 +646,15 @@ class BaseCork(object):
+ " Please install the scrypt library.")
+
+ if salt is None:
+- salt = os.urandom(32)
++ salt = os.urandom(self.saltlength['scrypt'])
+
+- assert len(salt) == 32, "Incorrect salt length"
++ assert len(salt) == self.saltlength['scrypt'], "Incorrect salt length"
++
++ username = username.encode('utf-8')
++ assert isinstance(username, bytes)
++
++ pwd = pwd.encode('utf-8')
++ assert isinstance(pwd, bytes)
+
+ cleartext = "%s\0%s" % (username, pwd)
+ h = scrypt.hash(cleartext, salt)
+@@ -643,18 +663,33 @@ class BaseCork(object):
+ hashed = b's' + salt + h
+ return b64encode(hashed)
+
+- @staticmethod
+- def _hash_pbkdf2(username, pwd, salt=None):
++ def _hash_pbkdf2_sha1(self, username, pwd, salt=None):
++ """Hash username and password, generating salt value if required
++ Use PBKDF2 wih sha1
++
++ :returns: base-64 encoded str.
++ """
++ return self.__hash_pbkdf2('sha1', b'p', username, pwd, salt)
++
++ def _hash_pbkdf2_sha256(self, username, pwd, salt=None):
++ """Hash username and password, generating salt value if required
++ Use PBKDF2 wih sha256
++
++ :returns: base-64 encoded str.
++ """
++ return self.__hash_pbkdf2('sha256', b'k', username, pwd, salt)
++
++ def __hash_pbkdf2(self, algo, prefix, username, pwd, salt):
+ """Hash username and password, generating salt value if required
+ Use PBKDF2 from Beaker
+
+ :returns: base-64 encoded str.
+ """
+ if salt is None:
+- salt = os.urandom(32)
++ salt = os.urandom(self.saltlength['PBKDF2'])
+
+ assert isinstance(salt, bytes)
+- assert len(salt) == 32, "Incorrect salt length"
++ assert len(salt) == self.saltlength['PBKDF2'], "Incorrect salt length"
+
+ username = username.encode('utf-8')
+ assert isinstance(username, bytes)
+@@ -663,14 +698,14 @@ class BaseCork(object):
+ assert isinstance(pwd, bytes)
+
+ cleartext = username + b'\0' + pwd
+- h = hashlib.pbkdf2_hmac('sha1', cleartext, salt, 10, dklen=32)
++ h = hashlib.pbkdf2_hmac(algo, cleartext, salt, self.pbkdf2_iterations, dklen=32)
+
+ # 'p' for PBKDF2
+- hashed = b'p' + salt + h
++ hashed = prefix + salt + h
+ return b64encode(hashed)
+
+ def _verify_password(self, username, pwd, salted_hash):
+- """Verity username/password pair against a salted hash
++ """Verify username/password pair against a salted hash
+
+ :returns: bool
+ """
+@@ -682,8 +717,12 @@ class BaseCork(object):
+
+ salt = decoded[1:33]
+
+- if hash_type == 'p': # PBKDF2
+- h = self._hash_pbkdf2(username, pwd, salt)
++ if hash_type == 'p': # PBKDF2 with sha1
++ h = self._hash_pbkdf2_sha1(username, pwd, salt)
++ return salted_hash == h
++
++ if hash_type == 'k': # PBKDF2 with sha256
++ h = self._hash_pbkdf2_sha256(username, pwd, salt)
+ return salted_hash == h
+
+ if hash_type == 's': # scrypt
diff -Nru python-bottle-cork-0.12.0/debian/patches/series python-bottle-cork-0.12.0/debian/patches/series
--- python-bottle-cork-0.12.0/debian/patches/series 2016-08-31 21:13:24.000000000 +0200
+++ python-bottle-cork-0.12.0/debian/patches/series 2017-02-10 10:04:27.000000000 +0100
@@ -1 +1,2 @@
0001-Serve-local-jquery.js.patch
+0002-Backported-fix-for-weak-hashing-defaults.patch
Reply to: