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