From dbc3788405b1d57c20946a98e40ca27c8ebac302 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: May 27 2018 14:05:50 +0000 Subject: Use GnuPG 2 for symmentric encryption The /usr/bin/gpg command is old, legacy GnuPG 1.4 version. The recommended version is GnuPG 2 provided by /usr/bin/gpg2. For simple symmentric encryption, gpg2 is a drop-in replacement for gpg. Fixes: https://pagure.io/freeipa/issue/7560 Signed-off-by: Christian Heimes Reviewed-By: Rob Crittenden --- diff --git a/freeipa.spec.in b/freeipa.spec.in index 8ef3d16..4382e33 100755 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -758,6 +758,7 @@ Provides: python2-ipaplatform = %{version}-%{release} Requires: %{name}-common = %{version}-%{release} Requires: python2-gssapi >= 1.2.0-5 Requires: gnupg +Requires: gnupg2 Requires: keyutils Requires: python2 >= 2.7.9 Requires: python2-cryptography >= 1.6 @@ -811,6 +812,7 @@ Provides: python3-ipaplatform = %{version}-%{release} Requires: %{name}-common = %{version}-%{release} Requires: python3-gssapi >= 1.2.0 Requires: gnupg +Requires: gnupg2 Requires: keyutils Requires: python3-cryptography >= 1.6 Requires: python3-netaddr >= %{python_netaddr_version} diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py index fdb80d9..cade978 100644 --- a/ipaplatform/base/paths.py +++ b/ipaplatform/base/paths.py @@ -168,6 +168,7 @@ class BasePathNamespace(object): FIREFOX = "/usr/bin/firefox" GETCERT = "/usr/bin/getcert" GPG = "/usr/bin/gpg" + GPG2 = "/usr/bin/gpg2" GPG_AGENT = "/usr/bin/gpg-agent" IPA_GETCERT = "/usr/bin/ipa-getcert" KADMIN_LOCAL = '/usr/sbin/kadmin.local' diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index 39f0bb6..96707e9 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -786,6 +786,26 @@ def _ensure_nonempty_string(string, message): raise ValueError(message) +def gpg_command(extra_args, password=None, workdir=None): + tempdir = tempfile.mkdtemp('', 'ipa-', workdir) + args = [ + paths.GPG_AGENT, + '--batch', + '--homedir', tempdir, + '--daemon', paths.GPG2, + '--batch', + '--homedir', tempdir, + '--passphrase-fd', '0', + '--yes', + '--no-tty', + ] + args.extend(extra_args) + try: + ipautil.run(args, stdin=password, skip_output=True) + finally: + shutil.rmtree(tempdir, ignore_errors=True) + + # uses gpg to compress and encrypt a file def encrypt_file(source, dest, password, workdir=None): _ensure_nonempty_string(source, 'Missing Source File') @@ -795,32 +815,11 @@ def encrypt_file(source, dest, password, workdir=None): _ensure_nonempty_string(dest, 'Missing Destination File') _ensure_nonempty_string(password, 'Missing Password') - # create a tempdir so that we can clean up with easily - tempdir = tempfile.mkdtemp('', 'ipa-', workdir) - gpgdir = os.path.join(tempdir, ".gnupg") - - try: - try: - # give gpg a fake dir so that we can leater remove all - # the cruft when we clean up the tempdir - os.mkdir(gpgdir) - args = [paths.GPG_AGENT, - '--batch', - '--homedir', gpgdir, - '--daemon', paths.GPG, - '--batch', - '--homedir', gpgdir, - '--passphrase-fd', '0', - '--yes', - '--no-tty', - '-o', dest, - '-c', source] - ipautil.run(args, password, skip_output=True) - except: - raise - finally: - # job done, clean up - shutil.rmtree(tempdir, ignore_errors=True) + extra_args = [ + '-o', dest, + '-c', source, + ] + gpg_command(extra_args, password, workdir) def decrypt_file(source, dest, password, workdir=None): @@ -831,32 +830,12 @@ def decrypt_file(source, dest, password, workdir=None): _ensure_nonempty_string(dest, 'Missing Destination File') _ensure_nonempty_string(password, 'Missing Password') - # create a tempdir so that we can clean up with easily - tempdir = tempfile.mkdtemp('', 'ipa-', workdir) - gpgdir = os.path.join(tempdir, ".gnupg") + extra_args = [ + '-o', dest, + '-d', source, + ] - try: - try: - # give gpg a fake dir so that we can leater remove all - # the cruft when we clean up the tempdir - os.mkdir(gpgdir) - args = [paths.GPG_AGENT, - '--batch', - '--homedir', gpgdir, - '--daemon', paths.GPG, - '--batch', - '--homedir', gpgdir, - '--passphrase-fd', '0', - '--yes', - '--no-tty', - '-o', dest, - '-d', source] - ipautil.run(args, password, skip_output=True) - except: - raise - finally: - # job done, clean up - shutil.rmtree(tempdir, ignore_errors=True) + gpg_command(extra_args, password, workdir) def expand_replica_info(filename, password): diff --git a/ipatests/test_ipaserver/test_install/test_installutils.py b/ipatests/test_ipaserver/test_install/test_installutils.py index 757c3ed..7331aa2 100644 --- a/ipatests/test_ipaserver/test_install/test_installutils.py +++ b/ipatests/test_ipaserver/test_install/test_installutils.py @@ -8,6 +8,7 @@ import tempfile import pytest +from ipapython import ipautil from ipaserver.install import installutils EXAMPLE_CONFIG = [ @@ -21,6 +22,8 @@ WHITESPACE_CONFIG = [ ] + + @pytest.fixture def tempdir(request): tempdir = tempfile.mkdtemp() @@ -173,3 +176,25 @@ def test_directivesetter(tempdir): 'dict2 "value2"\n', ] + + +def test_gpg_encrypt(tempdir): + src = os.path.join(tempdir, "data.txt") + encrypted = os.path.join(tempdir, "data.gpg") + decrypted = os.path.join(tempdir, "data.out") + passwd = 'Secret123' + payload = 'Dummy text\n' + + with open(src, 'w') as f: + f.write(payload) + + installutils.encrypt_file(src, encrypted, password=passwd) + assert os.path.isfile(encrypted) + + installutils.decrypt_file(encrypted, decrypted, password=passwd) + assert os.path.isfile(decrypted) + with open(decrypted) as f: + assert f.read() == payload + + with pytest.raises(ipautil.CalledProcessError): + installutils.decrypt_file(encrypted, decrypted, password='invalid')