Protect certbot-auto against automated downgrades (#6448)

With current code, the certbot-auto self-upgrade process can make it actually to downgrade itself, because the comparison done is an equality test between local certbot-auto version and the remote one. This is a flaw for attackers, that could make certbot-auto break itself by falsely advertising it about an old version as the latest one available.

A function is added to make a more advanced comparison between version. Certbot-auto will upgrade itself only if the local version is strictly inferior to the latest one available. For instance, a version 0.28.0 will not upgrade itself if the latest one available on internet is 0.27.1. Similarly, non-official versions like 0.28.0.dev0 will never trigger a self-upgrade, to help development workflows.

This implementation relies only on the Python distribution installed by certbot-auto (supporting 2.7+) and basic shell operations, to be compatible with any UNIX-based system.

* Check version with protection again downgrade

* Create a stable version of letsencrypt-auto to use correctly self-upgrade functionality

* Update letsencrypt-auto-source/letsencrypt-auto.template
This commit is contained in:
Adrien Ferrand
2018-11-19 14:28:59 -08:00
committed by Brad Warren
parent 4e1c22779e
commit 78cf8ec4de
3 changed files with 84 additions and 3 deletions
+14 -1
View File
@@ -27,6 +27,19 @@ def tests_dir():
return dirname(abspath(__file__))
def copy_stable(src, dst):
"""
Copy letsencrypt-auto, and replace its current version to its equivalent stable one.
This is needed to test correctly the self-upgrade functionality.
"""
copy(src, dst)
with open(dst, 'r') as file:
filedata = file.read()
filedata = re.sub(r'LE_AUTO_VERSION="(.*)\.dev0"', r'LE_AUTO_VERSION="\1"', filedata)
with open(dst, 'w') as file:
file.write(filedata)
sys.path.insert(0, dirname(tests_dir()))
from build import build as build_le_auto
@@ -343,7 +356,7 @@ class AutoTests(TestCase):
'v99.9.9/letsencrypt-auto': build_le_auto(version='99.9.9'),
'v99.9.9/letsencrypt-auto.sig': signed('something else')}
with serving(resources) as base_url:
copy(LE_AUTO_PATH, le_auto_path)
copy_stable(LE_AUTO_PATH, le_auto_path)
try:
out, err = run_le_auto(le_auto_path, venv_dir, base_url)
except CalledProcessError as exc: