158 lines
6.9 KiB
Diff
158 lines
6.9 KiB
Diff
|
From d741ddbee4b4a0b5ad66c776d305a153eeed7cbe Mon Sep 17 00:00:00 2001
|
||
|
From: Greg Hudson <ghudson@mit.edu>
|
||
|
Date: Mon, 26 Feb 2024 19:03:38 -0500
|
||
|
Subject: [PATCH] Use SoftHSMv2 for PKCS11 PKINIT tests
|
||
|
|
||
|
Instead of softpkcs11, use SoftHSMv2 to mock the PKCS11 token for
|
||
|
PKINIT tests. Use pkcs11-tool from OpenSC to initialize the token and
|
||
|
import a certificate and key. SoftHSM does not support PIN-less
|
||
|
tokens (see https://github.com/opendnssec/SoftHSMv2/issues/480) so
|
||
|
remove that test for now.
|
||
|
|
||
|
(cherry picked from commit 8ab61608236883fdc5c2d43f4bd1ff2094401d19)
|
||
|
---
|
||
|
.github/workflows/build.yml | 2 +-
|
||
|
src/tests/t_pkinit.py | 82 ++++++++++++++++++++-----------------
|
||
|
2 files changed, 45 insertions(+), 39 deletions(-)
|
||
|
|
||
|
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
|
||
|
index 68a4788adb..d7ae86b150 100644
|
||
|
--- a/.github/workflows/build.yml
|
||
|
+++ b/.github/workflows/build.yml
|
||
|
@@ -33,7 +33,7 @@ jobs:
|
||
|
if: startsWith(matrix.os, 'ubuntu')
|
||
|
run: |
|
||
|
sudo apt-get update -qq
|
||
|
- sudo apt-get install -y bison gettext keyutils ldap-utils libcmocka-dev libldap2-dev libkeyutils-dev libsasl2-dev libssl-dev python3-kdcproxy python3-pip slapd tcsh
|
||
|
+ sudo apt-get install -y bison gettext keyutils ldap-utils libcmocka-dev libldap2-dev libkeyutils-dev libsasl2-dev libssl-dev python3-kdcproxy python3-pip slapd tcsh softhsm2 opensc
|
||
|
pip3 install pyrad
|
||
|
- name: Build
|
||
|
env:
|
||
|
diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
|
||
|
index f8f2debc1b..4435746429 100755
|
||
|
--- a/src/tests/t_pkinit.py
|
||
|
+++ b/src/tests/t_pkinit.py
|
||
|
@@ -1,11 +1,10 @@
|
||
|
from k5test import *
|
||
|
+import re
|
||
|
|
||
|
# Skip this test if pkinit wasn't built.
|
||
|
if not pkinit_enabled:
|
||
|
skip_rest('PKINIT tests', 'PKINIT module not built')
|
||
|
|
||
|
-soft_pkcs11 = os.path.join(buildtop, 'tests', 'softpkcs11', 'softpkcs11.so')
|
||
|
-
|
||
|
# Construct a krb5.conf fragment configuring pkinit.
|
||
|
user_pem = os.path.join(pkinit_certs, 'user.pem')
|
||
|
privkey_pem = os.path.join(pkinit_certs, 'privkey.pem')
|
||
|
@@ -55,9 +54,6 @@ p12_upn2_identity = 'PKCS12:%s' % user_upn2_p12
|
||
|
p12_upn3_identity = 'PKCS12:%s' % user_upn3_p12
|
||
|
p12_generic_identity = 'PKCS12:%s' % generic_p12
|
||
|
p12_enc_identity = 'PKCS12:%s' % user_enc_p12
|
||
|
-p11_identity = 'PKCS11:' + soft_pkcs11
|
||
|
-p11_token_identity = ('PKCS11:module_name=' + soft_pkcs11 +
|
||
|
- ':slotid=1:token=SoftToken (token)')
|
||
|
|
||
|
# Start a realm with the test kdb module for the following UPN SAN tests.
|
||
|
realm = K5Realm(kdc_conf=alias_kdc_conf, create_kdb=False, pkinit=True)
|
||
|
@@ -389,53 +385,63 @@ realm.klist(realm.user_princ)
|
||
|
realm.kinit(realm.user_princ, flags=['-X', 'X509_user_identity=,'],
|
||
|
expected_code=1, expected_msg='Preauthentication failed while')
|
||
|
|
||
|
-softpkcs11rc = os.path.join(os.getcwd(), 'testdir', 'soft-pkcs11.rc')
|
||
|
-realm.env['SOFTPKCS11RC'] = softpkcs11rc
|
||
|
+softhsm2 = '/usr/lib/softhsm/libsofthsm2.so'
|
||
|
+if not os.path.exists(softhsm2):
|
||
|
+ skip_rest('PKCS11 tests', 'SoftHSMv2 required')
|
||
|
+pkcs11_tool = which('pkcs11-tool')
|
||
|
+if not pkcs11_tool:
|
||
|
+ skip_rest('PKCS11 tests', 'pkcs11-tool from OpenSC required')
|
||
|
+tool_cmd = [pkcs11_tool, '--module', softhsm2]
|
||
|
+
|
||
|
+# Prepare a SoftHSM token.
|
||
|
+softhsm2_conf = os.path.join(realm.testdir, 'softhsm2.conf')
|
||
|
+softhsm2_tokens = os.path.join(realm.testdir, 'tokens')
|
||
|
+os.mkdir(softhsm2_tokens)
|
||
|
+realm.env['SOFTHSM2_CONF'] = softhsm2_conf
|
||
|
+with open(softhsm2_conf, 'w') as f:
|
||
|
+ f.write('directories.tokendir = %s\n' % softhsm2_tokens)
|
||
|
+realm.run(tool_cmd + ['--init-token', '--label', 'user',
|
||
|
+ '--so-pin', 'sopin', '--init-pin', '--pin', 'userpin'])
|
||
|
+realm.run(tool_cmd + ['-w', user_pem, '-y', 'cert'])
|
||
|
+realm.run(tool_cmd + ['-w', privkey_pem, '-y', 'privkey',
|
||
|
+ '-l', '--pin', 'userpin'])
|
||
|
+
|
||
|
+# Extract the slot ID generated by SoftHSM.
|
||
|
+out = realm.run(tool_cmd + ['-L'])
|
||
|
+m = re.search(r'slot ID 0x([0-9a-f]+)\n', out)
|
||
|
+if not m:
|
||
|
+ fail('could not extract slot ID from SoftHSM token')
|
||
|
+slot_id = int(m.group(1), 16)
|
||
|
+
|
||
|
+p11_attr = 'X509_user_identity=PKCS11:' + softhsm2
|
||
|
+p11_token_identity = ('PKCS11:module_name=%s:slotid=%d:token=user' %
|
||
|
+ (softhsm2, slot_id))
|
||
|
|
||
|
-# PKINIT with PKCS11: identity, with no need for a PIN.
|
||
|
-mark('PKCS11 identity, no PIN')
|
||
|
-conf = open(softpkcs11rc, 'w')
|
||
|
-conf.write("%s\t%s\t%s\t%s\n" % ('user', 'user token', user_pem, privkey_pem))
|
||
|
-conf.close()
|
||
|
-# Expect to succeed without having to supply any more information.
|
||
|
-realm.kinit(realm.user_princ,
|
||
|
- flags=['-X', 'X509_user_identity=%s' % p11_identity])
|
||
|
+mark('PKCS11 identity, with PIN (prompter)')
|
||
|
+realm.kinit(realm.user_princ, flags=['-X', p11_attr], password='userpin')
|
||
|
realm.klist(realm.user_princ)
|
||
|
realm.run([kvno, realm.host_princ])
|
||
|
|
||
|
-# PKINIT with PKCS11: identity, with a PIN supplied by the prompter.
|
||
|
-mark('PKCS11 identity, with PIN (prompter)')
|
||
|
-os.remove(softpkcs11rc)
|
||
|
-conf = open(softpkcs11rc, 'w')
|
||
|
-conf.write("%s\t%s\t%s\t%s\n" % ('user', 'user token', user_pem,
|
||
|
- privkey_enc_pem))
|
||
|
-conf.close()
|
||
|
-# Expect failure if the responder does nothing, and there's no prompter
|
||
|
+mark('PKCS11 identity, unavailable PIN')
|
||
|
realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % p11_token_identity,
|
||
|
- '-X', 'X509_user_identity=%s' % p11_identity, realm.user_princ],
|
||
|
- expected_code=2)
|
||
|
-realm.kinit(realm.user_princ,
|
||
|
- flags=['-X', 'X509_user_identity=%s' % p11_identity],
|
||
|
- password='encrypted')
|
||
|
-realm.klist(realm.user_princ)
|
||
|
-realm.run([kvno, realm.host_princ])
|
||
|
+ '-X', p11_attr, realm.user_princ], expected_code=2)
|
||
|
|
||
|
-# Supply the wrong PIN.
|
||
|
mark('PKCS11 identity, wrong PIN')
|
||
|
expected_trace = ('PKINIT client has no configured identity; giving up',)
|
||
|
realm.kinit(realm.user_princ,
|
||
|
- flags=['-X', 'X509_user_identity=%s' % p11_identity],
|
||
|
+ flags=['-X', p11_attr],
|
||
|
password='wrong', expected_code=1, expected_trace=expected_trace)
|
||
|
|
||
|
# PKINIT with PKCS11: identity, with a PIN supplied by the responder.
|
||
|
-# Supply the response in raw form.
|
||
|
+# Supply the response in raw form. Expect the PIN_COUNT_LOW flag (1)
|
||
|
+# to be set due to the previous test.
|
||
|
mark('PKCS11 identity, with PIN (responder)')
|
||
|
-realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % p11_token_identity,
|
||
|
- '-r', 'pkinit={"%s": "encrypted"}' % p11_token_identity,
|
||
|
- '-X', 'X509_user_identity=%s' % p11_identity, realm.user_princ])
|
||
|
+realm.run(['./responder', '-x', 'pkinit={"%s": 1}' % p11_token_identity,
|
||
|
+ '-r', 'pkinit={"%s": "userpin"}' % p11_token_identity,
|
||
|
+ '-X', p11_attr, realm.user_princ])
|
||
|
# Supply the response through the convenience API.
|
||
|
-realm.run(['./responder', '-X', 'X509_user_identity=%s' % p11_identity,
|
||
|
- '-p', '%s=%s' % (p11_token_identity, 'encrypted'),
|
||
|
+realm.run(['./responder', '-X', p11_attr,
|
||
|
+ '-p', '%s=%s' % (p11_token_identity, 'userpin'),
|
||
|
realm.user_princ])
|
||
|
realm.klist(realm.user_princ)
|
||
|
realm.run([kvno, realm.host_princ])
|
||
|
--
|
||
|
2.47.1
|
||
|
|