From 6306a2a8697c94f968a02d66204f7d357aa0e7f6 Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Thu, 10 Jan 2019 16:34:54 -0500 Subject: [PATCH] Mark deprecated enctypes when used Preface ETYPE_DEPRECATED enctypes with "DEPRECATED:" in klist output, KDC logs, and kadmin interactions. Also complain in krb5kdc when the stash file has a deprecated enctype or a deprecated enctype is requested with -k. ticket: 8773 (new) (cherry picked from commit 8d8e68283b599e680f9fe45eff8af397e827bd6c) --- src/clients/klist/klist.c | 14 ++++++++++---- src/kadmin/cli/kadmin.c | 6 +++++- src/kdc/kdc_util.c | 9 +++++++++ src/kdc/main.c | 19 +++++++++++++++++++ src/tests/gssapi/t_enctypes.py | 15 +++++++++------ src/tests/t_keyrollover.py | 8 +++++--- src/tests/t_sesskeynego.py | 4 ++-- 7 files changed, 59 insertions(+), 16 deletions(-) diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c index 70adb54e8..8c307151a 100644 --- a/src/clients/klist/klist.c +++ b/src/clients/klist/klist.c @@ -571,11 +571,17 @@ static char * etype_string(krb5_enctype enctype) { static char buf[100]; - krb5_error_code ret; + char *bp = buf; + size_t deplen, buflen = sizeof(buf); - ret = krb5_enctype_to_name(enctype, FALSE, buf, sizeof(buf)); - if (ret) - snprintf(buf, sizeof(buf), "etype %d", enctype); + if (krb5int_c_deprecated_enctype(enctype)) { + deplen = strlcpy(bp, "DEPRECATED:", buflen); + buflen -= deplen; + bp += deplen; + } + + if (krb5_enctype_to_name(enctype, FALSE, bp, buflen)) + snprintf(bp, buflen, "etype %d", enctype); return buf; } diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c index ed581ee79..cc74921bf 100644 --- a/src/kadmin/cli/kadmin.c +++ b/src/kadmin/cli/kadmin.c @@ -1451,12 +1451,16 @@ kadmin_getprinc(int argc, char *argv[]) for (i = 0; i < dprinc.n_key_data; i++) { krb5_key_data *key_data = &dprinc.key_data[i]; char enctype[BUFSIZ], salttype[BUFSIZ]; + char *deprecated = ""; if (krb5_enctype_to_name(key_data->key_data_type[0], FALSE, enctype, sizeof(enctype))) snprintf(enctype, sizeof(enctype), _(""), key_data->key_data_type[0]); - printf("Key: vno %d, %s", key_data->key_data_kvno, enctype); + if (krb5int_c_deprecated_enctype(key_data->key_data_type[0])) + deprecated = "DEPRECATED:"; + printf("Key: vno %d, %s%s", key_data->key_data_kvno, deprecated, + enctype); if (key_data->key_data_ver > 1 && key_data->key_data_type[1] != KRB5_KDB_SALTTYPE_NORMAL) { if (krb5_salttype_to_string(key_data->key_data_type[1], diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c index f5c581c82..96c88edc1 100644 --- a/src/kdc/kdc_util.c +++ b/src/kdc/kdc_util.c @@ -1048,11 +1048,20 @@ static krb5_error_code enctype_name(krb5_enctype ktype, char *buf, size_t buflen) { char *name; + size_t len; if (buflen == 0) return EINVAL; *buf = '\0'; /* ensure these are always valid C-strings */ + if (krb5int_c_deprecated_enctype(ktype)) { + len = strlcpy(buf, "DEPRECATED:", buflen); + if (len >= buflen) + return ENOMEM; + buflen -= len; + buf += len; + } + /* rfc4556 recommends that clients wishing to indicate support for these * pkinit algorithms include them in the etype field of the AS-REQ. */ if (ktype == ENCTYPE_DSA_SHA1_CMS) diff --git a/src/kdc/main.c b/src/kdc/main.c index 663fd6303..60092a0df 100644 --- a/src/kdc/main.c +++ b/src/kdc/main.c @@ -210,12 +210,23 @@ init_realm(kdc_realm_t * rdp, krb5_pointer aprof, char *realm, char *svalue = NULL; const char *hierarchy[4]; krb5_kvno mkvno = IGNORE_VNO; + char ename[32]; memset(rdp, 0, sizeof(kdc_realm_t)); if (!realm) { kret = EINVAL; goto whoops; } + + if (def_enctype != ENCTYPE_UNKNOWN && + krb5int_c_deprecated_enctype(def_enctype)) { + if (krb5_enctype_to_name(def_enctype, FALSE, ename, sizeof(ename))) + ename[0] = '\0'; + fprintf(stderr, + _("Requested master password enctype %s in %s is DEPRECATED!"), + ename, realm); + } + hierarchy[0] = KRB5_CONF_REALMS; hierarchy[1] = realm; hierarchy[3] = NULL; @@ -370,6 +381,14 @@ init_realm(kdc_realm_t * rdp, krb5_pointer aprof, char *realm, goto whoops; } + if (krb5int_c_deprecated_enctype(rdp->realm_mkey.enctype)) { + if (krb5_enctype_to_name(rdp->realm_mkey.enctype, FALSE, ename, + sizeof(ename))) + ename[0] = '\0'; + fprintf(stderr, _("Stash file %s uses DEPRECATED enctype %s!"), + rdp->realm_stash, ename); + } + if ((kret = krb5_db_fetch_mkey_list(rdp->realm_context, rdp->realm_mprinc, &rdp->realm_mkey))) { kdc_err(rdp->realm_context, kret, diff --git a/src/tests/gssapi/t_enctypes.py b/src/tests/gssapi/t_enctypes.py index 5d9f80e04..ca3d32d21 100755 --- a/src/tests/gssapi/t_enctypes.py +++ b/src/tests/gssapi/t_enctypes.py @@ -9,8 +9,11 @@ from k5test import * aes256 = 'aes256-cts-hmac-sha1-96' aes128 = 'aes128-cts-hmac-sha1-96' des3 = 'des3-cbc-sha1' +d_des3 = 'DEPRECATED:des3-cbc-sha1' des3raw = 'des3-cbc-raw' +d_des3raw = 'DEPRECATED:des3-cbc-raw' rc4 = 'arcfour-hmac' +d_rc4 = 'DEPRECATED:arcfour-hmac' # These tests make assumptions about the default enctype lists, so set # them explicitly rather than relying on the library defaults. @@ -92,7 +95,7 @@ test_err('acc aes128', None, 'aes128-cts', # no acceptor subkey will be generated because we can't upgrade to a # CFX enctype. test('init des3', 'des3', None, - tktenc=aes256, tktsession=des3, + tktenc=aes256, tktsession=d_des3, proto='rfc1964', isubkey=des3raw, asubkey=None) # Force the ticket session key to be rc4, so we can test some subkey @@ -103,7 +106,7 @@ realm.run([kadminl, 'setstr', realm.host_princ, 'session_enctypes', 'rc4']) # [aes256 aes128 des3] and the acceptor should upgrade to an aes256 # subkey. test('upgrade noargs', None, None, - tktenc=aes256, tktsession=rc4, + tktenc=aes256, tktsession=d_rc4, proto='cfx', isubkey=rc4, asubkey=aes256) # If the initiator won't permit rc4 as a session key, it won't be able @@ -113,14 +116,14 @@ test_err('upgrade init aes', 'aes', None, 'no support for encryption type') # If the initiator permits rc4 but prefers aes128, it will send an # upgrade list of [aes128] and the acceptor will upgrade to aes128. test('upgrade init aes128+rc4', 'aes128-cts rc4', None, - tktenc=aes256, tktsession=rc4, + tktenc=aes256, tktsession=d_rc4, proto='cfx', isubkey=rc4, asubkey=aes128) # If the initiator permits rc4 but prefers des3, it will send an # upgrade list of [des3], but the acceptor won't generate a subkey # because des3 isn't a CFX enctype. test('upgrade init des3+rc4', 'des3 rc4', None, - tktenc=aes256, tktsession=rc4, + tktenc=aes256, tktsession=d_rc4, proto='rfc1964', isubkey=rc4, asubkey=None) # If the acceptor permits only aes128, subkey negotiation will fail @@ -134,14 +137,14 @@ test_err('upgrade acc aes128', None, 'aes128-cts', # If the acceptor permits rc4 but prefers aes128, it will negotiate an # upgrade to aes128. test('upgrade acc aes128 rc4', None, 'aes128-cts rc4', - tktenc=aes256, tktsession=rc4, + tktenc=aes256, tktsession=d_rc4, proto='cfx', isubkey=rc4, asubkey=aes128) # In this test, the initiator and acceptor each prefer an AES enctype # to rc4, but they can't agree on which one, so no subkey is # generated. test('upgrade mismatch', 'aes128-cts rc4', 'aes256-cts rc4', - tktenc=aes256, tktsession=rc4, + tktenc=aes256, tktsession=d_rc4, proto='rfc1964', isubkey=rc4, asubkey=None) success('gss_krb5_set_allowable_enctypes tests') diff --git a/src/tests/t_keyrollover.py b/src/tests/t_keyrollover.py index 7c8d828f0..4af6804f2 100755 --- a/src/tests/t_keyrollover.py +++ b/src/tests/t_keyrollover.py @@ -22,8 +22,9 @@ realm.run([kvno, princ1]) realm.run([kadminl, 'purgekeys', realm.krbtgt_princ]) # Make sure an old TGT fails after purging old TGS key. realm.run([kvno, princ2], expected_code=1) -msg = 'krbtgt/%s@%s\n\tEtype (skey, tkt): des-cbc-crc, des-cbc-crc' % \ - (realm.realm, realm.realm) +ddes = "DEPRECATED:des-cbc-crc" +msg = 'krbtgt/%s@%s\n\tEtype (skey, tkt): %s, %s' % \ + (realm.realm, realm.realm, ddes, ddes) realm.run([klist, '-e'], expected_msg=msg) # Check that new key actually works. @@ -48,7 +49,8 @@ realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e', 'aes256-cts', realm.krbtgt_princ]) realm.run([kadminl, 'modprinc', '-kvno', '1', realm.krbtgt_princ]) out = realm.run([kadminl, 'getprinc', realm.krbtgt_princ]) -if 'vno 1, aes256' not in out or 'vno 1, des3' not in out: +if 'vno 1, aes256-cts' not in out or \ + 'vno 1, DEPRECATED:des3-cbc-sha1' not in out: fail('keyrollover: setup for TGS enctype test failed') # Now present the DES3 ticket to the KDC and make sure it's rejected. realm.run([kvno, realm.host_princ], expected_code=1) diff --git a/src/tests/t_sesskeynego.py b/src/tests/t_sesskeynego.py index 448092387..da02f224a 100755 --- a/src/tests/t_sesskeynego.py +++ b/src/tests/t_sesskeynego.py @@ -62,11 +62,11 @@ test_kvno(realm, 'aes128-cts-hmac-sha1-96', 'aes256-cts-hmac-sha1-96') # 3b: Negotiate rc4-hmac session key when principal only has aes256 long-term. realm.run([kadminl, 'setstr', 'server', 'session_enctypes', 'rc4-hmac,aes128-cts,aes256-cts']) -test_kvno(realm, 'arcfour-hmac', 'aes256-cts-hmac-sha1-96') +test_kvno(realm, 'DEPRECATED:arcfour-hmac', 'aes256-cts-hmac-sha1-96') # 3c: Test des-cbc-crc default assumption. realm.run([kadminl, 'delstr', 'server', 'session_enctypes']) -test_kvno(realm, 'des-cbc-crc', 'aes256-cts-hmac-sha1-96') +test_kvno(realm, 'DEPRECATED:des-cbc-crc', 'aes256-cts-hmac-sha1-96') realm.stop() # Last go: test that we can disable the des-cbc-crc assumption