aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2018-12-12 14:34:00 +0100
committerPeter Wu <peter@lekensteyn.nl>2018-12-29 10:40:16 +0000
commitac58eafa3223ef40b9b60765b0b3d118f338fffc (patch)
tree8403b9749b31cd0f3a1baab3f5dac1072980f1ae /test
parent53d8e6dcf8c639a13f8c52a11df829b854c1b9ac (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')
-rw-r--r--test/fixtures_ws.py2
-rw-r--r--test/keys/rsa-p-lt-q.p816
-rw-r--r--test/suite_decryption.py124
3 files changed, 142 insertions, 0 deletions
diff --git a/test/fixtures_ws.py b/test/fixtures_ws.py
index cfadaf0ab8..6fd5d791d1 100644
--- a/test/fixtures_ws.py
+++ b/test/fixtures_ws.py
@@ -145,12 +145,14 @@ def features(cmd_tshark, make_env):
tshark_v = ''
gcry_m = re.search(r'with +Gcrypt +([0-9]+\.[0-9]+)', tshark_v)
return types.SimpleNamespace(
+ have_x64='Compiled (64-bit)' in tshark_v,
have_lua='with Lua' in tshark_v,
have_nghttp2='with nghttp2' in tshark_v,
have_kerberos='with MIT Kerberos' in tshark_v or 'with Heimdal Kerberos' in tshark_v,
have_libgcrypt16=gcry_m and float(gcry_m.group(1)) >= 1.6,
have_libgcrypt17=gcry_m and float(gcry_m.group(1)) >= 1.7,
have_gnutls='with GnuTLS' in tshark_v,
+ have_pkcs11='and PKCS #11 support' in tshark_v,
)
diff --git a/test/keys/rsa-p-lt-q.p8 b/test/keys/rsa-p-lt-q.p8
new file mode 100644
index 0000000000..d9fca7ee08
--- /dev/null
+++ b/test/keys/rsa-p-lt-q.p8
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOE/58jJArmp9xd6
+M42ttJk+tbzG5U47pHfj9wFVMoPPUP5/9Mfl9PGBm7GdnGxW//9wQrphEjrqrwya
+st6OBO5yb1DotLAl8FecN6eJxSTMPPS108A2D52kXdZohFgn8OjDhi3wR09L42vC
+1w7hPJOHIIuzPbywLauhqB7H/OazAgMBAAECgYEAgEnza0oBAVmqX3a8Ef9TEszC
+mWf2hd42SApQTjQF90iGaszZz1hLb5lP4ZNQ2eubFhMMDjbnOSMc2+Ln6RWd/Fb1
+Oy8mYkXYwPH+a2PHwa0yQ6IWuqRgZ09EijO+DxRlk8pn5hBj7YC8gU9hIce/PAkx
+z50FS6yEPT3U7xouJ9ECQQDm2BAoJasJBOKpYTHbPN4fhZ9m5DV65+nvu9ZgbxeR
+FfrBbYRva9KX9q/E03sSPkoEEHV21KYCMYz2g0FipqqXAkEA+cvGNz2upzwX8Ty5
+WKR323NHEVSMerEbbAQikamcCYnR5vdeJ2w3OMYNWTOQrNE9+Rk3gfaMCxwqER1l
+eW/0RQJAIzPLsvObk3KFRiMmQTKVBOWRm1UtuqJnEEHqvSXzyBI7/QdAbOVaZgYe
+Y7uERxHso5YG86oV7ruzrVvyuqKD3QJAH4do7XALq3AaVYiknFumBTz3q2hQkuvn
+2iprcpdF6q5KoCx45eDy12eoJ6oqiKWgfOCB8RV9d6mGZcKgHEPVQQJALFi49VGr
+qyX5SCcfS6c+XgX/VuJGS6eFxhpXHolAG3O1FmbQMKJ618bOGt8jYjGYR0bM5Kgd
+sDXwcu06rODBIA==
+-----END PRIVATE KEY-----
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)