1from k5test import * 2 3for realm in multipass_realms(create_user=False): 4 # Test kinit with a keytab. 5 realm.kinit(realm.host_princ, flags=['-k']) 6 7realm = K5Realm(get_creds=False, start_kadmind=True) 8 9# Test kinit with a partial keytab. 10mark('partial keytab') 11pkeytab = realm.keytab + '.partial' 12realm.run([ktutil], input=('rkt %s\ndelent 1\nwkt %s\n' % 13 (realm.keytab, pkeytab))) 14realm.kinit(realm.host_princ, flags=['-k', '-t', pkeytab]) 15 16# Test kinit with no keys for client in keytab. 17mark('no keys for client') 18realm.kinit(realm.user_princ, flags=['-k'], expected_code=1, 19 expected_msg='no suitable keys') 20 21# Test kinit and klist with client keytab defaults. 22mark('client keytab') 23realm.extract_keytab(realm.user_princ, realm.client_keytab); 24realm.run([kinit, '-k', '-i']) 25realm.klist(realm.user_princ) 26realm.run([kdestroy]) 27realm.kinit(realm.user_princ, flags=['-k', '-i']) 28realm.klist(realm.user_princ) 29out = realm.run([klist, '-k', '-i']) 30if realm.client_keytab not in out or realm.user_princ not in out: 31 fail('Expected output not seen from klist -k -i') 32 33# Test implicit request for keytab (-i or -t without -k) 34mark('implicit -k') 35realm.run([kdestroy]) 36realm.kinit(realm.host_princ, flags=['-t', realm.keytab], 37 expected_msg='keytab specified, forcing -k') 38realm.klist(realm.host_princ) 39realm.run([kdestroy]) 40realm.kinit(realm.user_princ, flags=['-i'], 41 expected_msg='keytab specified, forcing -k') 42realm.klist(realm.user_princ) 43 44# Test extracting keys with multiple key versions present. 45mark('multi-kvno extract') 46os.remove(realm.keytab) 47realm.run([kadminl, 'cpw', '-randkey', '-keepold', realm.host_princ]) 48out = realm.run([kadminl, 'ktadd', '-norandkey', realm.host_princ]) 49if 'with kvno 1,' not in out or 'with kvno 2,' not in out: 50 fail('Expected output not seen from kadmin.local ktadd -norandkey') 51out = realm.run([klist, '-k', '-e']) 52if ' 1 host/' not in out or ' 2 host/' not in out: 53 fail('Expected output not seen from klist -k -e') 54 55# Test again using kadmin over the network. 56mark('multi-kvno extract (via kadmin)') 57realm.prep_kadmin() 58os.remove(realm.keytab) 59out = realm.run_kadmin(['ktadd', '-norandkey', realm.host_princ]) 60if 'with kvno 1,' not in out or 'with kvno 2,' not in out: 61 fail('Expected output not seen from kadmin.local ktadd -norandkey') 62out = realm.run([klist, '-k', '-e']) 63if ' 1 host/' not in out or ' 2 host/' not in out: 64 fail('Expected output not seen from klist -k -e') 65 66# Test handling of kvno values beyond 255. Use kadmin over the 67# network since we used to have an 8-bit limit on kvno marshalling. 68 69# Test one key rotation, verifying that the expected new kvno appears 70# in the keytab and in the principal entry. 71def test_key_rotate(realm, princ, expected_kvno): 72 realm.run_kadmin(['ktadd', '-k', realm.keytab, princ]) 73 realm.run([kadminl, 'ktrem', princ, 'old']) 74 realm.kinit(princ, flags=['-k']) 75 msg = '%d %s' % (expected_kvno, princ) 76 out = realm.run([klist, '-k'], expected_msg=msg) 77 msg = 'Key: vno %d,' % expected_kvno 78 out = realm.run_kadmin(['getprinc', princ], expected_msg=msg) 79 80mark('key rotation across boundaries') 81princ = 'foo/bar@%s' % realm.realm 82realm.addprinc(princ) 83os.remove(realm.keytab) 84realm.run([kadminl, 'modprinc', '-kvno', '253', princ]) 85test_key_rotate(realm, princ, 254) 86test_key_rotate(realm, princ, 255) 87test_key_rotate(realm, princ, 256) 88test_key_rotate(realm, princ, 257) 89realm.run([kadminl, 'modprinc', '-kvno', '32766', princ]) 90test_key_rotate(realm, princ, 32767) 91test_key_rotate(realm, princ, 32768) 92test_key_rotate(realm, princ, 32769) 93realm.run([kadminl, 'modprinc', '-kvno', '65534', princ]) 94test_key_rotate(realm, princ, 65535) 95test_key_rotate(realm, princ, 1) 96test_key_rotate(realm, princ, 2) 97 98mark('32-bit kvno') 99 100# Test that klist -k can read a keytab entry without a 32-bit kvno and 101# reports the 8-bit key version. 102record = b'\x00\x01' # principal component count 103record += b'\x00\x0bKRBTEST.COM' # realm 104record += b'\x00\x04user' # principal component 105record += b'\x00\x00\x00\x01' # name type (NT-PRINCIPAL) 106record += b'\x54\xf7\x4d\x35' # timestamp 107record += b'\x02' # key version 108record += b'\x00\x12' # enctype 109record += b'\x00\x20' # key length 110record += b'\x00' * 32 # key bytes 111f = open(realm.keytab, 'wb') 112f.write(b'\x05\x02\x00\x00\x00' + bytes([len(record)])) 113f.write(record) 114f.close() 115msg = ' 2 %s' % realm.user_princ 116out = realm.run([klist, '-k'], expected_msg=msg) 117 118# Make sure zero-fill isn't treated as a 32-bit kvno. 119f = open(realm.keytab, 'wb') 120f.write(b'\x05\x02\x00\x00\x00' + bytes([len(record) + 4])) 121f.write(record) 122f.write(b'\x00\x00\x00\x00') 123f.close() 124msg = ' 2 %s' % realm.user_princ 125out = realm.run([klist, '-k'], expected_msg=msg) 126 127# Make sure a hand-crafted 32-bit kvno is recognized. 128f = open(realm.keytab, 'wb') 129f.write(b'\x05\x02\x00\x00\x00' + bytes([len(record) + 4])) 130f.write(record) 131f.write(b'\x00\x00\x00\x03') 132f.close() 133msg = ' 3 %s' % realm.user_princ 134out = realm.run([klist, '-k'], expected_msg=msg) 135 136# Test parameter expansion in profile variables 137mark('parameter expansion') 138realm.stop() 139conf = {'libdefaults': { 140 'default_keytab_name': 'testdir/%{null}abc%{uid}', 141 'default_client_keytab_name': 'testdir/%{null}xyz%{uid}'}} 142realm = K5Realm(krb5_conf=conf, create_kdb=False) 143del realm.env['KRB5_KTNAME'] 144del realm.env['KRB5_CLIENT_KTNAME'] 145uidstr = str(os.getuid()) 146msg = 'FILE:testdir/abc%s' % uidstr 147out = realm.run([klist, '-k'], expected_code=1, expected_msg=msg) 148msg = 'FILE:testdir/xyz%s' % uidstr 149out = realm.run([klist, '-ki'], expected_code=1, expected_msg=msg) 150 151conf = {'libdefaults': {'allow_weak_crypto': 'true'}} 152realm = K5Realm(create_user=False, create_host=False, krb5_conf=conf) 153 154realm.run([kadminl, 'ank', '-pw', 'pw', 'default']) 155realm.run([kadminl, 'ank', '-e', 'aes256-cts:special', '-pw', 'pw', 'exp']) 156realm.run([kadminl, 'ank', '-e', 'aes256-cts:special', '-pw', 'pw', '+preauth', 157 'pexp']) 158 159# Extract one of the explicit salt values from the database. 160out = realm.run([kdb5_util, 'tabdump', 'keyinfo']) 161salt_dict = {f[0]: f[5] for f in [l.split('\t') for l in out.splitlines()]} 162exp_salt = bytes.fromhex(salt_dict['exp@KRBTEST.COM']).decode('ascii') 163 164# Create a keytab using ktutil addent with the specified options and 165# password "pw". Test that we can use it to get initial tickets. 166# Remove the keytab afterwards. 167def test_addent(realm, princ, opts): 168 realm.run([ktutil], input=('addent -password -p %s -k 1 %s\npw\nwkt %s\n' % 169 (princ, opts, realm.keytab))) 170 realm.kinit(princ, flags=['-k']) 171 os.remove(realm.keytab) 172 173mark('ktutil addent') 174 175# Test with default salt. 176test_addent(realm, 'default', '-e aes128-cts') 177test_addent(realm, 'default', '-e aes256-cts') 178 179# Test with a salt specified to ktutil addent. 180test_addent(realm, 'exp', '-e aes256-cts -s %s' % exp_salt) 181 182# Test etype-info fetching. 183test_addent(realm, 'default', '-f') 184test_addent(realm, 'default', '-f -e aes128-cts') 185test_addent(realm, 'exp', '-f') 186test_addent(realm, 'pexp', '-f') 187 188# Regression test for #8914: INT32_MIN length can cause backwards seek 189mark('invalid record length') 190f = open(realm.keytab, 'wb') 191f.write(b'\x05\x02\x80\x00\x00\x00') 192f.close() 193msg = 'Bad format in keytab while scanning keytab' 194realm.run([klist, '-k'], expected_code=1, expected_msg=msg) 195 196success('Keytab-related tests') 197