diff options
author | Peter Wu <peter@lekensteyn.nl> | 2018-12-12 14:34:00 +0100 |
---|---|---|
committer | Peter Wu <peter@lekensteyn.nl> | 2018-12-29 10:40:16 +0000 |
commit | ac58eafa3223ef40b9b60765b0b3d118f338fffc (patch) | |
tree | 8403b9749b31cd0f3a1baab3f5dac1072980f1ae /test/suite_decryption.py | |
parent | 53d8e6dcf8c639a13f8c52a11df829b854c1b9ac (diff) |
Add support for RSA decryption using PKCS #11 tokens
Add support for loading RSA private key files from PKCS #11 tokens,
identified by PKCS #11 URIs. Add a new 'pkcs11_libs' UAT which can
dynamically load PKCS #11 provider libraries that are not found by
p11-kit.
The configuration GUI will need additional code to discover available
PKCS #11 tokens and will be added later.
This feature requires GnuTLS 3.4 with PKCS #11 support, so Windows,
macOS via Homebrew, Ubuntu 16.04, Debian Stretch. Not supported: RHEL7.
Currently macOS via official packages disables PKCS #11 support, so that
will also not work.
Change-Id: I20646bfd69c6bd13c8c2d27cb65c164a4b0b7a66
Reviewed-on: https://code.wireshark.org/review/30855
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Diffstat (limited to 'test/suite_decryption.py')
-rw-r--r-- | test/suite_decryption.py | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/test/suite_decryption.py b/test/suite_decryption.py index aad2b2dde0..1cbdaf33bb 100644 --- a/test/suite_decryption.py +++ b/test/suite_decryption.py @@ -10,7 +10,12 @@ '''Decryption tests''' import os.path +import shutil +import subprocess import subprocesstest +import sys +import sysconfig +import types import unittest import fixtures @@ -862,3 +867,122 @@ class case_decrypt_knxip(subprocesstest.SubprocessTestCase): self.assertTrue(self.grepOutput('^IA 1[.]1[.]4 SeqNr 12345$')) self.assertTrue(self.grepOutput('^IA 2[.]1[.]0 key B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF$')) self.assertTrue(self.grepOutput('^IA 2[.]1[.]0 SeqNr 1234$')) + + +@fixtures.fixture(scope='session') +def softhsm_paths(features): + if sys.platform == 'win32': + search_path = os.getenv('PATH') + r';C:\SoftHSM2\bin' + else: + search_path = None + softhsm_tool = shutil.which('softhsm2-util', path=search_path) + if not softhsm_tool: + # Note: do not fallback to SoftHSMv1. While available on Ubuntu 14.04 + # (and 16.04), it is built with botan < 1.11.10 which causes a crash due + # to a conflict with the GMP library that is also used by GnuTLS/nettle. + # See https://github.com/randombit/botan/issues/1090 + fixtures.skip('SoftHSM is not found') + # Find provider library path. + bindir = os.path.dirname(softhsm_tool) + libdir = os.path.join(os.path.dirname(bindir), 'lib') + if sys.platform == 'win32': + libdirs = [libdir, bindir] + if features.have_x64: + name = 'softhsm2-x64.dll' + else: + name = 'softhsm2.dll' + else: + # Debian/Ubuntu-specific paths + madir = sysconfig.get_config_var('multiarchsubdir') + libdir64_sub = os.path.join(libdir + '64', 'softhsm') + libdir_sub = os.path.join(libdir, 'softhsm') + libdirs = [os.path.join(libdir + madir, 'softhsm')] if madir else [] + libdirs += [libdir_sub, libdir64_sub] + name = 'libsofthsm2.so' + for libdir in libdirs: + provider = os.path.join(libdir, name) + if os.path.exists(provider): + break + else: + # Even if p11-kit can automatically locate it, do not rely on it. + fixtures.skip('SoftHSM provider library not detected') + # Now check whether the import tool is usable. SoftHSM < 2.3.0 did not + # set CKA_DECRYPT when using softhsm2-tool --import and therefore cannot be + # used to import keys for decryption. Use GnuTLS p11tool as workaround. + softhsm_version = subprocess.check_output([softhsm_tool, '--version'], + universal_newlines=True).strip() + use_p11tool = softhsm_version in ('2.0.0', '2.1.0', '2.2.0') + if use_p11tool and not shutil.which('p11tool'): + fixtures.skip('SoftHSM available, but GnuTLS p11tool is unavailable') + return use_p11tool, softhsm_tool, provider + + +@fixtures.fixture +def softhsm(softhsm_paths, home_path, base_env): + '''Creates a temporary SoftHSM token store (and set it in the environment), + returns a function to populate that token store and the path to the PKCS #11 + provider library.''' + use_p11tool, softhsm_tool, provider = softhsm_paths + conf_path = os.path.join(home_path, 'softhsm-test.conf') + db_path = os.path.join(home_path, 'softhsm-test-tokens') + os.makedirs(db_path) + with open(conf_path, 'w') as f: + f.write('directories.tokendir = %s\n' % db_path) + f.write('objectstore.backend = file\n') + # Avoid syslog spam + f.write('log.level = ERROR\n') + base_env['SOFTHSM2_CONF'] = conf_path + + tool_env = base_env.copy() + if sys.platform == 'win32': + # Ensure that softhsm2-util can find the library. + tool_env['PATH'] += ';%s' % os.path.dirname(provider) + + # Initialize tokens store. + token_name = 'Wireshark-Test-Tokens' + pin = 'Secret' + subprocess.check_call([softhsm_tool, '--init-token', '--slot', '0', + '--label', token_name, '--so-pin', 'Supersecret', '--pin', pin], + env=tool_env) + if use_p11tool: + tool_env['GNUTLS_PIN'] = pin + + # Arbitrary IDs and labels. + ids = iter(range(0xab12, 0xffff)) + def import_key(keyfile): + '''Returns a PKCS #11 URI to identify the imported key.''' + label = os.path.basename(keyfile) + obj_id = '%x' % next(ids) + if not use_p11tool: + tool_args = [softhsm_tool, '--import', keyfile, '--label', label, + '--id', obj_id, '--pin', pin, '--token', token_name] + else: + # Fallback for SoftHSM < 2.3.0 + tool_args = ['p11tool', '--provider', provider, '--batch', + '--login', '--write', 'pkcs11:token=%s' % token_name, + '--load-privkey', keyfile, '--label', label, '--id', obj_id] + subprocess.check_call(tool_args, env=tool_env) + id_str = '%{}{}%{}{}'.format(*obj_id) + return 'pkcs11:token=%s;id=%s;type=private' % (token_name, id_str) + + return types.SimpleNamespace(import_key=import_key, provider=provider, pin=pin) + + +@fixtures.mark_usefixtures('test_env') +@fixtures.uses_fixtures +class case_decrypt_pkcs11(subprocesstest.SubprocessTestCase): + def test_tls_pkcs11(self, cmd_tshark, dirs, capture_file, features, softhsm): + '''Check that a RSA key in a PKCS #11 token enables decryption.''' + if not features.have_pkcs11: + self.skipTest('Requires GnuTLS with PKCS #11 support.') + key_file = os.path.join(dirs.key_dir, 'rsa-p-lt-q.p8') + key_uri = softhsm.import_key(key_file) + proc = self.assertRun((cmd_tshark, + '-r', capture_file('rsa-p-lt-q.pcap'), + '-o', 'uat:pkcs11_libs:"{}"'.format(softhsm.provider.replace('\\', '\\x5c')), + '-o', 'uat:rsa_keys:"{}","{}"'.format(key_uri, softhsm.pin), + '-Tfields', + '-e', 'http.request.uri', + '-Y', 'http', + )) + self.assertIn('/', proc.stdout_str) |