aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--.travis.yml3
-rw-r--r--CMakeLists.txt18
-rw-r--r--CMakeOptions.txt2
-rw-r--r--appveyor.yml3
-rw-r--r--cmakeconfig.h.in3
-rw-r--r--epan/epan.c3
-rw-r--r--epan/secrets.c221
-rw-r--r--test/fixtures_ws.py2
-rw-r--r--test/keys/rsa-p-lt-q.p816
-rw-r--r--test/suite_decryption.py124
-rwxr-xr-xtools/debian-setup.sh51
11 files changed, 431 insertions, 15 deletions
diff --git a/.travis.yml b/.travis.yml
index c31ed16a96..ed47fbd7d0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -59,8 +59,9 @@ before_install:
- echo $TRAVIS_OS_NAME
# macos
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then ./tools/macos-setup-brew.sh; fi
+ - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install softhsm; fi
# linux
- - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ./tools/debian-setup.sh --install-optional -q; fi
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ./tools/debian-setup.sh --install-optional --install-test-deps -q; fi
- sudo gem install asciidoctor --no-ri --no-rdoc
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -y python3-pip; fi
- sudo pip3 install pytest pytest-xdist
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a228d3bbcf..e175bc6177 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -990,7 +990,7 @@ if(ENABLE_SMI)
set(PACKAGELIST ${PACKAGELIST} SMI)
endif()
-# GNU SSL/TLS support
+# Support for TLS decryption using RSA private keys.
if(ENABLE_GNUTLS)
set(PACKAGELIST ${PACKAGELIST} GNUTLS)
# Minimum version needed.
@@ -1167,6 +1167,22 @@ if(HAVE_LIBLUA)
set(HAVE_LUA_H 1)
set(HAVE_LUA 1)
endif()
+if(GNUTLS_FOUND AND NOT GNUTLS_VERSION VERSION_LESS "3.4.0")
+ # While all Linux and Windows builds have PKCS #11 support enabled,
+ # macos-setup.sh explicitly disables it using --without-p11-kit.
+ #
+ # Require at least GnuTLS 3.4.0 such that public keys can be calculated
+ # from PKCS #11 private keys.
+ include(CheckSymbolExists)
+ cmake_push_check_state()
+ if(WIN32)
+ set(CMAKE_REQUIRED_DEFINITIONS -Dssize_t=int)
+ endif()
+ set(CMAKE_REQUIRED_INCLUDES ${GNUTLS_INCLUDE_DIRS})
+ set(CMAKE_REQUIRED_LIBRARIES ${GNUTLS_LIBRARIES})
+ check_symbol_exists(gnutls_pkcs11_obj_list_import_url4 gnutls/pkcs11.h HAVE_GNUTLS_PKCS11)
+ cmake_pop_check_state()
+endif()
if(HAVE_LIBKERBEROS)
set(HAVE_KERBEROS 1)
endif()
diff --git a/CMakeOptions.txt b/CMakeOptions.txt
index 2cfe6419d4..f4d4ce1f31 100644
--- a/CMakeOptions.txt
+++ b/CMakeOptions.txt
@@ -69,7 +69,7 @@ option(ENABLE_SNAPPY "Build with Snappy compression support" ON)
option(ENABLE_NGHTTP2 "Build with HTTP/2 header decompression support" ON)
option(ENABLE_LUA "Build with Lua dissector support" ON)
option(ENABLE_SMI "Build with libsmi snmp support" ON)
-option(ENABLE_GNUTLS "Build with GNU TLS support" ON)
+option(ENABLE_GNUTLS "Build with RSA decryption support" ON)
if(WIN32)
option(ENABLE_WINSPARKLE "Enable WinSparkle support" ON)
endif()
diff --git a/appveyor.yml b/appveyor.yml
index c20b82735c..82059e4dc6 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -29,6 +29,9 @@ install:
# Py2 fails the test_tshark_unicode_display_filter test, so use Py3.
- set PATH=C:\Python37-x64;C:\Python37-x64\Scripts;%PATH%
- pip install pytest pytest-xdist
+ - ps: | # For pkcs11 tests.
+ Invoke-WebRequest -Uri https://github.com/disig/SoftHSM2-for-Windows/releases/download/v2.5.0/SoftHSM2-2.5.0.msi -OutFile $Env:WIRESHARK_BASE_DIR\SoftHSM2-2.5.0.msi
+ & msiexec /qn /i $Env:WIRESHARK_BASE_DIR\SoftHSM2-2.5.0.msi
# Note: the NSIS installer lacks debug dlls for Debug builds.
configuration: RelWithDebInfo
diff --git a/cmakeconfig.h.in b/cmakeconfig.h.in
index 5adaab7121..e5bc4a1937 100644
--- a/cmakeconfig.h.in
+++ b/cmakeconfig.h.in
@@ -112,6 +112,9 @@
/* Define to use GnuTLS library */
#cmakedefine HAVE_LIBGNUTLS 1
+/* Define to 1 if GnuTLS was built with pkcs11 support. */
+#cmakedefine HAVE_GNUTLS_PKCS11 1
+
/* Enable libnl support */
#cmakedefine HAVE_LIBNL 1
diff --git a/epan/epan.c b/epan/epan.c
index 0b3a969a18..e20a9cb28e 100644
--- a/epan/epan.c
+++ b/epan/epan.c
@@ -715,6 +715,9 @@ epan_get_compiled_version_info(GString *str)
g_string_append(str, ", ");
#ifdef HAVE_LIBGNUTLS
g_string_append(str, "with GnuTLS " LIBGNUTLS_VERSION);
+#ifdef HAVE_GNUTLS_PKCS11
+ g_string_append(str, " and PKCS #11 support");
+#endif /* HAVE_GNUTLS_PKCS11 */
#else
g_string_append(str, "without GnuTLS");
#endif /* HAVE_LIBGNUTLS */
diff --git a/epan/secrets.c b/epan/secrets.c
index bfbbad2b6e..a16913768c 100644
--- a/epan/secrets.c
+++ b/epan/secrets.c
@@ -51,6 +51,19 @@ static guint uat_num_rsa_privkeys;
static void register_rsa_uats(void);
#endif /* HAVE_LIBGNUTLS */
+#ifdef HAVE_GNUTLS_PKCS11
+/** PINs for PKCS #11 keys in rsa_privkeys. Must be cleared after rsa_privkeys. */
+static GSList *rsa_privkeys_pkcs11_pins;
+
+typedef struct {
+ char *library_path; /**< PKCS #11 library path. */
+} pkcs11_lib_record_t;
+
+static uat_t *pkcs11_libs_uat;
+static pkcs11_lib_record_t *uat_pkcs11_libs;
+static guint uat_num_pkcs11_libs;
+#endif /* HAVE_GNUTLS_PKCS11 */
+
void
secrets_init(void)
{
@@ -69,6 +82,10 @@ secrets_cleanup(void)
#ifdef HAVE_LIBGNUTLS
g_hash_table_destroy(rsa_privkeys);
rsa_privkeys = NULL;
+#ifdef HAVE_GNUTLS_PKCS11
+ g_slist_free_full(rsa_privkeys_pkcs11_pins, g_free);
+ rsa_privkeys_pkcs11_pins = NULL;
+#endif /* HAVE_GNUTLS_PKCS11 */
#endif /* HAVE_LIBGNUTLS */
}
@@ -125,6 +142,182 @@ rsa_privkey_add(const cert_key_id_t *key_id, gnutls_privkey_t pkey)
g_htonl(dw[1]), g_htonl(dw[2]), g_htonl(dw[3]), g_htonl(dw[4]));
}
+#ifdef HAVE_GNUTLS_PKCS11
+/** Provides a fixed PIN to the caller (or failure if the fixed PIN is NULL). */
+static int
+set_pin_callback(void *userdata, int attempt _U_,
+ const char *token_url _U_, const char *token_label _U_,
+ unsigned int flags, char *pin, size_t pin_max)
+{
+ const char *fixed_pin = (const char *)userdata;
+ size_t fixed_pin_len = fixed_pin ? strlen(fixed_pin) : 0;
+
+ /* Fail if the PIN was not provided, wrong or too long. */
+ if (!fixed_pin || (flags & GNUTLS_PIN_WRONG) || fixed_pin_len >= pin_max) {
+ return GNUTLS_E_PKCS11_PIN_ERROR;
+ }
+
+ memcpy(pin, fixed_pin, fixed_pin_len + 1);
+ return 0;
+}
+
+/**
+ * Load private RSA keys from a PKCS #11 token. Returns zero on success and a
+ * negative error code on failure.
+ */
+static int
+pkcs11_load_keys_from_token(const char *token_uri, const char *pin, char **err)
+{
+ gnutls_pkcs11_obj_t *list = NULL;
+ unsigned int nlist = 0;
+ int ret;
+ /* An empty/NULL PIN means that none is necessary. */
+ char *fixed_pin = pin && pin[0] ? g_strdup(pin) : NULL;
+ gboolean pin_in_use = FALSE;
+
+ /* Set PIN via a global callback since import_url can prompt for one. */
+ gnutls_pkcs11_set_pin_function(set_pin_callback, fixed_pin);
+
+ /* This might already result in callback for the PIN. */
+ ret = gnutls_pkcs11_obj_list_import_url4(&list, &nlist, token_uri,
+ GNUTLS_PKCS11_OBJ_FLAG_PRIVKEY|GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
+ if (ret < 0) {
+ *err = g_strdup_printf("Failed to iterate through objects for %s: %s", token_uri, gnutls_strerror(ret));
+ goto cleanup;
+ }
+
+ for (unsigned j = 0; j < nlist; j++) {
+ char *obj_uri = NULL;
+ gnutls_privkey_t privkey = NULL;
+ gnutls_pubkey_t pubkey = NULL;
+ cert_key_id_t key_id;
+ size_t size;
+
+ if (gnutls_pkcs11_obj_get_type(list[j]) != GNUTLS_PKCS11_OBJ_PRIVKEY) {
+ /* Should not happen since we requested private keys only. */
+ goto cont;
+ }
+
+ ret = gnutls_pkcs11_obj_export_url(list[j], GNUTLS_PKCS11_URL_GENERIC, &obj_uri);
+ if (ret < 0) {
+ /* Should not happen either if the object is valid. */
+ goto cont;
+ }
+
+ ret = gnutls_privkey_init(&privkey);
+ if (ret < 0) {
+ /* Out of memory? */
+ goto cont;
+ }
+
+ /* Set the PIN to be used during decryption. */
+ gnutls_privkey_set_pin_function(privkey, set_pin_callback, fixed_pin);
+
+ /* Can prompt for PIN. Can also invoke the token function set by
+ * gnutls_pkcs11_set_token_function (if not set, it will just fail
+ * immediately rather than retrying). */
+ ret = gnutls_privkey_import_url(privkey, obj_uri, 0);
+ if (ret < 0) {
+ /* Bad PIN or some other system error? */
+ g_debug("Failed to import private key %s: %s", obj_uri, gnutls_strerror(ret));
+ goto cont;
+ }
+
+ if (gnutls_privkey_get_pk_algorithm(privkey, NULL) != GNUTLS_PK_RSA) {
+ g_debug("Skipping private key %s, not RSA.", obj_uri);
+ goto cont;
+ }
+
+ ret = gnutls_pubkey_init(&pubkey);
+ if (ret < 0) {
+ /* Out of memory? */
+ goto cont;
+ }
+
+ /* This requires GnuTLS 3.4.0 and will fail on older versions. */
+ ret = gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0);
+ if (ret < 0) {
+ g_debug("Failed to import public key %s: %s", obj_uri, gnutls_strerror(ret));
+ goto cont;
+ }
+
+ size = sizeof(key_id);
+ ret = gnutls_pubkey_get_key_id(pubkey, GNUTLS_KEYID_USE_SHA1, key_id.key_id, &size);
+ if (ret < 0 || size != sizeof(key_id)) {
+ g_debug("Failed to calculate Key ID for %s: %s", obj_uri, gnutls_strerror(ret));
+ goto cont;
+ }
+
+ /* Remember the private key. */
+ rsa_privkey_add(&key_id, privkey);
+ privkey = NULL;
+ pin_in_use = TRUE;
+
+cont:
+ gnutls_privkey_deinit(privkey);
+ gnutls_pubkey_deinit(pubkey);
+ gnutls_free(obj_uri);
+ gnutls_pkcs11_obj_deinit(list[j]);
+ }
+ gnutls_free(list);
+ if (pin_in_use) {
+ /* Remember PINs such they can be freed later. */
+ rsa_privkeys_pkcs11_pins = g_slist_prepend(rsa_privkeys_pkcs11_pins, fixed_pin);
+ fixed_pin = NULL;
+ }
+ ret = 0;
+
+cleanup:
+ /* Forget about the PIN. */
+ gnutls_pkcs11_set_pin_function(NULL, NULL);
+ g_free(fixed_pin);
+ return ret;
+}
+
+/** Load all libraries specified in a UAT. */
+static void
+uat_pkcs11_libs_load_all(void)
+{
+ int ret;
+ GString *err = NULL;
+
+ for (guint i = 0; i < uat_num_pkcs11_libs; i++) {
+ const pkcs11_lib_record_t *rec = &uat_pkcs11_libs[i];
+ const char *libname = rec->library_path;
+ /* Note: should return success for already loaded libraries. */
+ ret = gnutls_pkcs11_add_provider(libname, NULL);
+ if (ret) {
+ if (!err) {
+ err = g_string_new("Error loading PKCS #11 libraries:");
+ }
+ g_string_append_printf(err, "\n%s: %s", libname, gnutls_strerror(ret));
+ }
+ }
+ if (err) {
+ report_failure("%s", err->str);
+ g_string_free(err, TRUE);
+ }
+}
+
+UAT_FILENAME_CB_DEF(pkcs11_libs_uats, library_path, pkcs11_lib_record_t)
+
+static void *
+uat_pkcs11_lib_copy_str_cb(void *dest, const void *source, size_t len _U_)
+{
+ pkcs11_lib_record_t *d = (pkcs11_lib_record_t *)dest;
+ const pkcs11_lib_record_t *s = (const pkcs11_lib_record_t *)source;
+ d->library_path = g_strdup(s->library_path);
+ return dest;
+}
+
+static void
+uat_pkcs11_lib_free_str_cb(void *record)
+{
+ pkcs11_lib_record_t *rec = (pkcs11_lib_record_t *)record;
+ g_free(rec->library_path);
+}
+#endif /* HAVE_GNUTLS_PKCS11 */
+
UAT_FILENAME_CB_DEF(rsa_privkeys_uats, uri, rsa_privkey_record_t)
UAT_CSTRING_CB_DEF(rsa_privkeys_uats, password, rsa_privkey_record_t)
@@ -202,6 +395,10 @@ uat_rsa_privkeys_post_update(void)
{
/* Clear previous keys. */
g_hash_table_remove_all(rsa_privkeys);
+#ifdef HAVE_GNUTLS_PKCS11
+ g_slist_free_full(rsa_privkeys_pkcs11_pins, g_free);
+ rsa_privkeys_pkcs11_pins = NULL;
+#endif /* HAVE_GNUTLS_PKCS11 */
GString *errors = NULL;
for (guint i = 0; i < uat_num_rsa_privkeys; i++) {
@@ -210,6 +407,9 @@ uat_rsa_privkeys_post_update(void)
char *err = NULL;
if (g_str_has_prefix(token_uri, "pkcs11:")) {
+#ifdef HAVE_GNUTLS_PKCS11
+ pkcs11_load_keys_from_token(token_uri, rec->password, &err);
+#endif /* HAVE_GNUTLS_PKCS11 */
} else {
load_rsa_keyfile(token_uri, rec->password, &err);
}
@@ -236,6 +436,27 @@ uat_rsa_privkeys_post_update(void)
static void
register_rsa_uats(void)
{
+#ifdef HAVE_GNUTLS_PKCS11
+ static uat_field_t uat_pkcs11_libs_fields[] = {
+ UAT_FLD_FILENAME_OTHER(pkcs11_libs_uats, library_path, "Library Path", NULL, "PKCS #11 provider library file"),
+ UAT_END_FIELDS
+ };
+ pkcs11_libs_uat = uat_new("PKCS #11 Provider Libraries",
+ sizeof(pkcs11_lib_record_t),
+ "pkcs11_libs", /* filename */
+ FALSE, /* from_profile */
+ &uat_pkcs11_libs, /* data_ptr */
+ &uat_num_pkcs11_libs, /* numitems_ptr */
+ 0, /* does not directly affect dissection */
+ NULL, /* Help section (currently a wiki page) */
+ uat_pkcs11_lib_copy_str_cb, /* copy_cb */
+ NULL, /* update_cb */
+ uat_pkcs11_lib_free_str_cb, /* free_cb */
+ uat_pkcs11_libs_load_all, /* post_update_cb */
+ NULL, /* reset_cb */
+ uat_pkcs11_libs_fields);
+#endif /* HAVE_GNUTLS_PKCS11 */
+
static uat_field_t uat_rsa_privkeys_fields[] = {
UAT_FLD_FILENAME_OTHER(rsa_privkeys_uats, uri, "Keyfile or Token URI", NULL, "RSA Key File or PKCS #11 URI for token"),
UAT_FLD_FILENAME_OTHER(rsa_privkeys_uats, password, "Password", NULL, "RSA Key File password or PKCS #11 Token PIN"),
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)
diff --git a/tools/debian-setup.sh b/tools/debian-setup.sh
index 678ddf8a2d..51b3bce8ab 100755
--- a/tools/debian-setup.sh
+++ b/tools/debian-setup.sh
@@ -18,6 +18,7 @@ then
printf "Usage: %s [--install-optional] [--install-deb-deps] [...other options...]\\n" "$0"
printf "\\t--install-optional: install optional software as well\\n"
printf "\\t--install-deb-deps: install packages required to build the .deb file\\n"
+ printf "\\t--install-test-deps: install packages required to run all tests\\n"
printf "\\t[other]: other options are passed as-is to apt\\n"
exit 1
fi
@@ -29,17 +30,24 @@ then
exit 1
fi
-for op
-do
- if [ "$op" = "--install-optional" ]
- then
- ADDITIONAL=1
- elif [ "$op" = "--install-deb-deps" ]
- then
- DEBDEPS=1
- else
- OPTIONS="$OPTIONS $op"
- fi
+ADDITIONAL=0
+DEBDEPS=0
+TESTDEPS=0
+for arg; do
+ case $arg in
+ --install-optional)
+ ADDITIONAL=1
+ ;;
+ --install-deb-deps)
+ DEBDEPS=1
+ ;;
+ --install-test-deps)
+ TESTDEPS=1
+ ;;
+ *)
+ OPTIONS="$OPTIONS $arg"
+ ;;
+ esac
done
BASIC_LIST="libglib2.0-dev \
@@ -83,6 +91,8 @@ DEBDEPS_LIST="debhelper \
libxml2-utils \
quilt"
+TESTDEPS_LIST=
+
# Adds package $2 to list variable $1 if the package is found.
# If $3 is given, then this version requirement must be satisfied.
add_package() {
@@ -122,7 +132,7 @@ echo "libssh-gcrypt-dev and libssh-dev are unavailable" >&2
add_package ADDITIONAL_LIST libgnutls28-dev ||
echo "libgnutls28-dev is unavailable" >&2
-# mmdbresolve
+# Debian >= jessie-backports, Ubuntu >= 16.04
add_package ADDITIONAL_LIST libmaxminddb-dev ||
echo "libmaxminddb-dev is unavailable" >&2
@@ -132,6 +142,18 @@ add_package DEBDEPS_LIST libsystemd-dev ||
add_package DEBDEPS_LIST libsystemd-journal-dev ||
echo "libsystemd-dev is unavailable"
+# softhsm2 2.0.0: Ubuntu 16.04
+# softhsm2 2.2.0: Debian >= jessie-backports, Ubuntu 18.04
+# softhsm2 >= 2.4.0: Debian >= buster, Ubuntu >= 18.10
+if ! add_package TESTDEPS_LIST softhsm2 '>= 2.3.0'; then
+ if add_package TESTDEPS_LIST softhsm2; then
+ # If SoftHSM 2.3.0 is unavailble, install p11tool.
+ TESTDEPS_LIST="$TESTDEPS_LIST gnutls-bin"
+ else
+ echo "softhsm2 is unavailable" >&2
+ fi
+fi
+
ACTUAL_LIST=$BASIC_LIST
# Now arrange for optional support libraries
@@ -145,6 +167,11 @@ then
ACTUAL_LIST="$ACTUAL_LIST $DEBDEPS_LIST"
fi
+if [ $TESTDEPS ]
+then
+ ACTUAL_LIST="$ACTUAL_LIST $TESTDEPS_LIST"
+fi
+
apt-get update || exit 2
# shellcheck disable=SC2086
apt-get install $ACTUAL_LIST $OPTIONS || exit 2