#!/usr/bin/python from k5test import * # Skip this test if pkinit wasn't built. if not os.path.exists(os.path.join(plugins, 'preauth', 'pkinit.so')): success('Warning: not testing pkinit because it is not built') exit(0) # Check if soft-pkcs11.so is available. try: import ctypes lib = ctypes.LibraryLoader(ctypes.CDLL).LoadLibrary('soft-pkcs11.so') del lib have_soft_pkcs11 = True except: have_soft_pkcs11 = False # Construct a krb5.conf fragment configuring pkinit. certs = os.path.join(srctop, 'tests', 'dejagnu', 'pkinit-certs') ca_pem = os.path.join(certs, 'ca.pem') kdc_pem = os.path.join(certs, 'kdc.pem') user_pem = os.path.join(certs, 'user.pem') privkey_pem = os.path.join(certs, 'privkey.pem') privkey_enc_pem = os.path.join(certs, 'privkey-enc.pem') user_p12 = os.path.join(certs, 'user.p12') user_enc_p12 = os.path.join(certs, 'user-enc.p12') path = os.path.join(os.getcwd(), 'testdir', 'tmp-pkinit-certs') path_enc = os.path.join(os.getcwd(), 'testdir', 'tmp-pkinit-certs-enc') pkinit_krb5_conf = {'realms': {'$realm': { 'pkinit_anchors': 'FILE:%s' % ca_pem}}} pkinit_kdc_conf = {'realms': {'$realm': { 'default_principal_flags': '+preauth', 'pkinit_eku_checking': 'none', 'pkinit_identity': 'FILE:%s,%s' % (kdc_pem, privkey_pem)}}} restrictive_kdc_conf = {'realms': {'$realm': { 'restrict_anonymous_to_tgt': 'true' }}} file_identity = 'FILE:%s,%s' % (user_pem, privkey_pem) file_enc_identity = 'FILE:%s,%s' % (user_pem, privkey_enc_pem) dir_identity = 'DIR:%s' % path dir_enc_identity = 'DIR:%s' % path_enc dir_file_identity = 'FILE:%s,%s' % (os.path.join(path, 'user.crt'), os.path.join(path, 'user.key')) dir_file_enc_identity = 'FILE:%s,%s' % (os.path.join(path_enc, 'user.crt'), os.path.join(path_enc, 'user.key')) p12_identity = 'PKCS12:%s' % user_p12 p12_enc_identity = 'PKCS12:%s' % user_enc_p12 p11_identity = 'PKCS11:soft-pkcs11.so' p11_token_identity = ('PKCS11:module_name=soft-pkcs11.so:' 'slotid=1:token=SoftToken (token)') realm = K5Realm(krb5_conf=pkinit_krb5_conf, kdc_conf=pkinit_kdc_conf, get_creds=False) # Sanity check - password-based preauth should still work. realm.run(['./responder', '-r', 'password=%s' % password('user'), 'user@%s' % realm.realm]) realm.kinit('user@%s' % realm.realm, password=password('user')) realm.klist('user@%s' % realm.realm) realm.run([kvno, realm.host_princ]) # Test anonymous PKINIT. out = realm.kinit('@%s' % realm.realm, flags=['-n'], expected_code=1) if 'not found in Kerberos database' not in out: fail('Wrong error for anonymous PKINIT without anonymous enabled') realm.addprinc('WELLKNOWN/ANONYMOUS') realm.kinit('@%s' % realm.realm, flags=['-n']) realm.klist('WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS') realm.run([kvno, realm.host_princ]) # Test anonymous kadmin. f = open(os.path.join(realm.testdir, 'acl'), 'a') f.write('WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS a *') f.close() realm.start_kadmind() out = realm.run([kadmin, '-n', '-q', 'addprinc -pw test testadd']) if 'created.' not in out: fail('Could not create principal with anonymous kadmin') out = realm.run([kadmin, '-n', '-q', 'getprinc testadd']) if "Operation requires ``get'' privilege" not in out: fail('Anonymous kadmin has too much privilege') realm.stop_kadmind() # Test with anonymous restricted; FAST should work but kvno should fail. r_env = realm.special_env('restrict', True, kdc_conf=restrictive_kdc_conf) realm.stop_kdc() realm.start_kdc(env=r_env) realm.kinit('@%s' % realm.realm, flags=['-n']) realm.kinit('@%s' % realm.realm, flags=['-n', '-T', realm.ccache]) out = realm.run([kvno, realm.host_princ], expected_code=1) if 'KDC policy rejects request' not in out: fail('Wrong error for restricted anonymous PKINIT') # Go back to a normal KDC and disable anonymous PKINIT. realm.stop_kdc() realm.start_kdc() realm.run_kadminl('delprinc -force WELLKNOWN/ANONYMOUS') # Run the basic test - PKINIT with FILE: identity, with no password on the key. realm.run(['./responder', '-x', 'pkinit=', '-X', 'X509_user_identity=%s' % file_identity, 'user@%s' % realm.realm]) realm.kinit('user@%s' % realm.realm, flags=['-X', 'X509_user_identity=%s' % file_identity]) realm.klist('user@%s' % realm.realm) realm.run([kvno, realm.host_princ]) # Run the basic test - PKINIT with FILE: identity, with a password on the key, # supplied by the prompter. # Expect failure if the responder does nothing, and we have no prompter. realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % file_enc_identity, '-X', 'X509_user_identity=%s' % file_enc_identity, 'user@%s' % realm.realm], expected_code=2) realm.kinit('user@%s' % realm.realm, flags=['-X', 'X509_user_identity=%s' % file_enc_identity], password='encrypted') realm.klist('user@%s' % realm.realm) realm.run([kvno, realm.host_princ]) # Run the basic test - PKINIT with FILE: identity, with a password on the key, # supplied by the responder. # Supply the response in raw form. realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % file_enc_identity, '-r', 'pkinit={"%s": "encrypted"}' % file_enc_identity, '-X', 'X509_user_identity=%s' % file_enc_identity, 'user@%s' % realm.realm]) # Supply the response through the convenience API. realm.run(['./responder', '-X', 'X509_user_identity=%s' % file_enc_identity, '-p', '%s=%s' % (file_enc_identity, 'encrypted'), 'user@%s' % realm.realm]) realm.klist('user@%s' % realm.realm) realm.run([kvno, realm.host_princ]) # PKINIT with DIR: identity, with no password on the key. os.mkdir(path) os.mkdir(path_enc) shutil.copy(privkey_pem, os.path.join(path, 'user.key')) shutil.copy(privkey_enc_pem, os.path.join(path_enc, 'user.key')) shutil.copy(user_pem, os.path.join(path, 'user.crt')) shutil.copy(user_pem, os.path.join(path_enc, 'user.crt')) realm.run(['./responder', '-x', 'pkinit=', '-X', 'X509_user_identity=%s' % dir_identity, 'user@%s' % realm.realm]) realm.kinit('user@%s' % realm.realm, flags=['-X', 'X509_user_identity=%s' % dir_identity]) realm.klist('user@%s' % realm.realm) realm.run([kvno, realm.host_princ]) # PKINIT with DIR: identity, with a password on the key, supplied by the # prompter. # Expect failure if the responder does nothing, and we have no prompter. realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % dir_file_enc_identity, '-X', 'X509_user_identity=%s' % dir_enc_identity, 'user@%s' % realm.realm], expected_code=2) realm.kinit('user@%s' % realm.realm, flags=['-X', 'X509_user_identity=%s' % dir_enc_identity], password='encrypted') realm.klist('user@%s' % realm.realm) realm.run([kvno, realm.host_princ]) # PKINIT with DIR: identity, with a password on the key, supplied by the # responder. # Supply the response in raw form. realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % dir_file_enc_identity, '-r', 'pkinit={"%s": "encrypted"}' % dir_file_enc_identity, '-X', 'X509_user_identity=%s' % dir_enc_identity, 'user@%s' % realm.realm]) # Supply the response through the convenience API. realm.run(['./responder', '-X', 'X509_user_identity=%s' % dir_enc_identity, '-p', '%s=%s' % (dir_file_enc_identity, 'encrypted'), 'user@%s' % realm.realm]) realm.klist('user@%s' % realm.realm) realm.run([kvno, realm.host_princ]) # PKINIT with PKCS12: identity, with no password on the bundle. realm.run(['./responder', '-x', 'pkinit=', '-X', 'X509_user_identity=%s' % p12_identity, 'user@%s' % realm.realm]) realm.kinit('user@%s' % realm.realm, flags=['-X', 'X509_user_identity=%s' % p12_identity]) realm.klist('user@%s' % realm.realm) realm.run([kvno, realm.host_princ]) # PKINIT with PKCS12: identity, with a password on the bundle, supplied by the # prompter. # Expect failure if the responder does nothing, and we have no prompter. realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % p12_enc_identity, '-X', 'X509_user_identity=%s' % p12_enc_identity, 'user@%s' % realm.realm], expected_code=2) realm.kinit('user@%s' % realm.realm, flags=['-X', 'X509_user_identity=%s' % p12_enc_identity], password='encrypted') realm.klist('user@%s' % realm.realm) realm.run([kvno, realm.host_princ]) # PKINIT with PKCS12: identity, with a password on the bundle, supplied by the # responder. # Supply the response in raw form. realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % p12_enc_identity, '-r', 'pkinit={"%s": "encrypted"}' % p12_enc_identity, '-X', 'X509_user_identity=%s' % p12_enc_identity, 'user@%s' % realm.realm]) # Supply the response through the convenience API. realm.run(['./responder', '-X', 'X509_user_identity=%s' % p12_enc_identity, '-p', '%s=%s' % (p12_enc_identity, 'encrypted'), 'user@%s' % realm.realm]) realm.klist('user@%s' % realm.realm) realm.run([kvno, realm.host_princ]) if have_soft_pkcs11: softpkcs11rc = os.path.join(os.getcwd(), 'testdir', 'soft-pkcs11.rc') realm.env['SOFTPKCS11RC'] = softpkcs11rc # PKINIT with PKCS11: identity, with no need for a 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.run(['./responder', '-x', 'pkinit=', '-X', 'X509_user_identity=%s' % p11_identity, 'user@%s' % realm.realm]) realm.kinit('user@%s' % realm.realm, flags=['-X', 'X509_user_identity=%s' % p11_identity]) realm.klist('user@%s' % realm.realm) realm.run([kvno, realm.host_princ]) # PKINIT with PKCS11: identity, with a PIN supplied by the 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 realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % p11_token_identity, '-X', 'X509_user_identity=%s' % p11_identity, 'user@%s' % realm.realm], expected_code=2) realm.kinit('user@%s' % realm.realm, flags=['-X', 'X509_user_identity=%s' % p11_identity], password='encrypted') realm.klist('user@%s' % realm.realm) realm.run([kvno, realm.host_princ]) # PKINIT with PKCS11: identity, with a PIN supplied by the responder. # Supply the response in raw form. realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % p11_token_identity, '-r', 'pkinit={"%s": "encrypted"}' % p11_token_identity, '-X', 'X509_user_identity=%s' % p11_identity, 'user@%s' % realm.realm]) # Supply the response through the convenience API. realm.run(['./responder', '-X', 'X509_user_identity=%s' % p11_identity, '-p', '%s=%s' % (p11_token_identity, 'encrypted'), 'user@%s' % realm.realm]) realm.klist('user@%s' % realm.realm) realm.run([kvno, realm.host_princ]) else: output('soft-pkcs11.so not found: skipping tests with PKCS11 identities\n') success('Authenticated PKINIT')