krb5 commit: Use SoftHSMv2 for PKCS11 PKINIT tests

ghudson at mit.edu ghudson at mit.edu
Mon Mar 18 21:20:06 EDT 2024


https://github.com/krb5/krb5/commit/8ab61608236883fdc5c2d43f4bd1ff2094401d19
commit 8ab61608236883fdc5c2d43f4bd1ff2094401d19
Author: Greg Hudson <ghudson at mit.edu>
Date:   Mon Feb 26 19:03:38 2024 -0500

    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.

 .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 5ed42a4c3..350ed3de5 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 yasm
+                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 yasm softhsm2 opensc
                 pip3 install pyrad
             - name: Build
               env:
diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
index f8f2debc1..443574642 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])


More information about the cvs-krb5 mailing list