Skip to content

Commit

Permalink
test: simplify _can_decrypt_with_key
Browse files Browse the repository at this point in the history
there are some gpg 2.1 compatibility issues with how this was
written previously: namely that exporting secret keys needs to be
apparently requires a passphrase [0], which isis's python-gnupg
does not support [1].

this commit modifies the test to instead just assert that the file
decrypts with a key in the keyring, not the specific key.

[0] https://bitbucket.org/vinay.sajip/python-gnupg/commits/9e90361bfc2fc853953a64aca6a0b6bcb64981c8?at=default#Lgnupg.pyT1142
[1] https://github.com/isislovecruft/python-gnupg/blob/master/pretty_bad_protocol/gnupg.py#L423
  • Loading branch information
redshiftzero committed Feb 1, 2019
1 parent 6b579b8 commit ef5a79b
Showing 1 changed file with 13 additions and 39 deletions.
52 changes: 13 additions & 39 deletions securedrop/tests/test_integration.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
# -*- coding: utf-8 -*-

from distutils.version import StrictVersion
import pretty_bad_protocol as gnupg
import gzip
import os
import random
import re
import shutil
import tempfile
import zipfile

from base64 import b32encode
Expand Down Expand Up @@ -327,11 +324,10 @@ def assertion():

zf = zipfile.ZipFile(StringIO(resp.data), 'r')
data = zf.read(zf.namelist()[0])
_can_decrypt_with_key(journalist_app, data, config.JOURNALIST_KEY)
_can_decrypt_with_key(journalist_app, data)
_can_decrypt_with_key(
journalist_app,
data,
current_app.crypto_util.getkey(filesystem_id),
codename)

# Test deleting reply on the journalist interface
Expand Down Expand Up @@ -401,50 +397,28 @@ def assertion():
utils.async.wait_for_assertion(assertion)


def _can_decrypt_with_key(journalist_app, msg, key_fpr, passphrase=None):
def _can_decrypt_with_key(journalist_app, msg, passphrase=None):
"""
Test that the given GPG message can be decrypted with the given key
(identified by its fingerprint).
Test that the given GPG message can be decrypted.
"""
# GPG does not provide a way to specify which key to use to decrypt a
# message. Since the default keyring that we use has both the
# `config.JOURNALIST_KEY` and all of the reply keypairs, there's no way
# to use it to test whether a message is decryptable with a specific
# key.
gpg_tmp_dir = tempfile.mkdtemp()
# gpg 2.1+ requires gpg-agent, see #4013
gpg_agent_config = os.path.join(gpg_tmp_dir, 'gpg-agent.conf')
with open(gpg_agent_config, 'w+') as f:
f.write('allow-loopback-pinentry')

gpg_binary = gnupg.GPG(binary='gpg2', homedir=gpg_tmp_dir)
if StrictVersion(gpg_binary.binary_version) >= StrictVersion('2.1'):
gpg = gnupg.GPG(binary='gpg2',
homedir=gpg_tmp_dir,
options=['--pinentry-mode loopback'])
else:
gpg = gpg_binary

# Export the key of interest from the application's keyring
pubkey = journalist_app.crypto_util.gpg.export_keys(key_fpr)
seckey = journalist_app.crypto_util.gpg.export_keys(key_fpr, secret=True)
# Import it into our isolated temporary GPG directory
for key in (pubkey, seckey):
gpg.import_keys(key)

# Attempt decryption with the given key

# For gpg 2.1+, a non null passphrase _must_ be passed to decrypt()
using_gpg_2_1 = StrictVersion(
journalist_app.crypto_util.gpg.binary_version) >= StrictVersion('2.1')

if passphrase:
passphrase = journalist_app.crypto_util.hash_codename(
passphrase,
salt=journalist_app.crypto_util.scrypt_gpg_pepper)
decrypted_data = gpg.decrypt(msg, passphrase=passphrase)
elif using_gpg_2_1:
passphrase = 'dummy passphrase'

decrypted_data = journalist_app.crypto_util.gpg.decrypt(
msg, passphrase=passphrase)
assert decrypted_data.ok, \
"Could not decrypt msg with key, gpg says: {}" \
.format(decrypted_data.stderr)

# We have to clean up the temporary GPG dir
shutil.rmtree(gpg_tmp_dir)


def test_reply_normal(journalist_app,
source_app,
Expand Down

0 comments on commit ef5a79b

Please sign in to comment.