krb5 commit: Add ktutil addent option to fetch salt from KDC
Greg Hudson
ghudson at mit.edu
Thu Oct 4 16:56:11 EDT 2018
https://github.com/krb5/krb5/commit/eb5d2c9afa4eba05f44e66d0e843b94be74d53e7
commit eb5d2c9afa4eba05f44e66d0e843b94be74d53e7
Author: Greg Hudson <ghudson at mit.edu>
Date: Thu Sep 27 18:32:24 2018 -0400
Add ktutil addent option to fetch salt from KDC
Add a -f flag to ktutil addent. If specified, the enctype need not be
specified (although it can be) and ktutil will request etype-info from
the KDC to produce the string-to-key parameters.
ticket: 8587
doc/admin/admin_commands/ktutil.rst | 11 +++-
src/kadmin/ktutil/ktutil.c | 19 +++++---
src/kadmin/ktutil/ktutil.h | 1 +
src/kadmin/ktutil/ktutil_funcs.c | 87 ++++++++++++++++++++++++++++-------
src/tests/t_keytab.py | 43 +++++++++++++++++
5 files changed, 134 insertions(+), 27 deletions(-)
diff --git a/doc/admin/admin_commands/ktutil.rst b/doc/admin/admin_commands/ktutil.rst
index 2eb19de..9f8e53e 100644
--- a/doc/admin/admin_commands/ktutil.rst
+++ b/doc/admin/admin_commands/ktutil.rst
@@ -87,9 +87,14 @@ add_entry
~~~~~~~~~
**add_entry** {**-key**\|\ **-password**} **-p** *principal*
- **-k** *kvno* **-e** *enctype* [**-s** *salt*]
-
-Add *principal* to keylist using key or password.
+ **-k** *kvno* [**-e** *enctype*] [**-f**\|\ **-s** *salt*]
+
+Add *principal* to keylist using key or password. If the **-f** flag
+is specified, salt information will be fetched from the KDC; in this
+case the **-e** flag may be omitted, or it may be supplied to force a
+particular enctype. If the **-f** flag is not specified, the **-e**
+flag must be specified, and the default salt will be used unless
+overridden with the **-s** option.
Alias: **addent**
diff --git a/src/kadmin/ktutil/ktutil.c b/src/kadmin/ktutil/ktutil.c
index 198cb13..196f207 100644
--- a/src/kadmin/ktutil/ktutil.c
+++ b/src/kadmin/ktutil/ktutil.c
@@ -140,7 +140,7 @@ void ktutil_add_entry(argc, argv)
char *princ = NULL;
char *enctype = NULL;
krb5_kvno kvno = 0;
- int use_pass = 0, use_key = 0, use_kvno = 0, i;
+ int use_pass = 0, use_key = 0, use_kvno = 0, fetch = 0, i;
char *salt = NULL;
for (i = 1; i < argc; i++) {
@@ -169,18 +169,23 @@ void ktutil_add_entry(argc, argv)
salt = argv[++i];
continue;
}
+ if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-f", 2))
+ fetch++;
}
- if (!((argc == 8 && princ && use_kvno && enctype) ||
- (argc == 10 && princ && use_kvno && enctype && salt)) ||
- use_pass + use_key != 1) {
+ if (princ == NULL || use_pass + use_key != 1 || !use_kvno ||
+ (fetch && salt != NULL)) {
fprintf(stderr, _("usage: %s (-key | -password) -p principal "
- "-k kvno -e enctype [-s salt]\n"), argv[0]);
+ "-k kvno [-e enctype] [-f|-s salt]\n"), argv[0]);
+ return;
+ }
+ if (!fetch && enctype == NULL) {
+ fprintf(stderr, _("enctype must be specified if not using -f\n"));
return;
}
- retval = ktutil_add(kcontext, &ktlist, princ, kvno, enctype, use_pass,
- salt);
+ retval = ktutil_add(kcontext, &ktlist, princ, fetch, kvno, enctype,
+ use_pass, salt);
if (retval)
com_err(argv[0], retval, _("while adding new entry"));
}
diff --git a/src/kadmin/ktutil/ktutil.h b/src/kadmin/ktutil/ktutil.h
index 8bf4915..ddb754b 100644
--- a/src/kadmin/ktutil/ktutil.h
+++ b/src/kadmin/ktutil/ktutil.h
@@ -36,6 +36,7 @@ krb5_error_code ktutil_delete (krb5_context, krb5_kt_list *, int);
krb5_error_code ktutil_add (krb5_context,
krb5_kt_list *,
char *,
+ int,
krb5_kvno,
char *,
int,
diff --git a/src/kadmin/ktutil/ktutil_funcs.c b/src/kadmin/ktutil/ktutil_funcs.c
index 5843e24..2daf814 100644
--- a/src/kadmin/ktutil/ktutil_funcs.c
+++ b/src/kadmin/ktutil/ktutil_funcs.c
@@ -82,16 +82,68 @@ krb5_error_code ktutil_delete(context, list, idx)
}
/*
+ * Determine the enctype, salt, and s2kparams for princ based on the presence
+ * of the -f flag (fetch), the optionally specified salt string, and the
+ * optionally specified enctype. If the fetch flag is used, salt_str must not
+ * be given; if the fetch flag is not used, the enctype must be given.
+ */
+static krb5_error_code
+get_etype_info(krb5_context context, krb5_principal princ, int fetch,
+ char *salt_str, krb5_enctype *enctype_inout,
+ krb5_data *salt_out, krb5_data *s2kparams_out)
+{
+ krb5_error_code retval;
+ krb5_enctype enctype;
+ krb5_get_init_creds_opt *opt = NULL;
+ krb5_data salt;
+
+ *salt_out = empty_data();
+ *s2kparams_out = empty_data();
+
+ if (!fetch) {
+ /* Use the specified enctype and either the specified or default salt.
+ * Do not produce s2kparams. */
+ assert(*enctype_inout != ENCTYPE_NULL);
+ if (salt_str != NULL) {
+ salt = string2data(salt_str);
+ return krb5int_copy_data_contents(context, &salt, salt_out);
+ } else {
+ return krb5_principal2salt(context, princ, salt_out);
+ }
+ }
+
+ /* Get etype-info from the KDC. */
+ assert(salt_str == NULL);
+ if (*enctype_inout != ENCTYPE_NULL) {
+ retval = krb5_get_init_creds_opt_alloc(context, &opt);
+ if (retval)
+ return retval;
+ krb5_get_init_creds_opt_set_etype_list(opt, enctype_inout, 1);
+ }
+ retval = krb5_get_etype_info(context, princ, opt, &enctype, salt_out,
+ s2kparams_out);
+ krb5_get_init_creds_opt_free(context, opt);
+ if (retval)
+ return retval;
+ if (enctype == ENCTYPE_NULL)
+ return KRB5KDC_ERR_ETYPE_NOSUPP;
+
+ *enctype_inout = enctype;
+ return 0;
+}
+
+/*
* Create a new keytab entry and add it to the keytab list.
* Based on the value of use_pass, either prompt the user for a
* password or key. If the keytab list is NULL, allocate a new
* one first.
*/
-krb5_error_code ktutil_add(context, list, princ_str, kvno,
+krb5_error_code ktutil_add(context, list, princ_str, fetch, kvno,
enctype_str, use_pass, salt_str)
krb5_context context;
krb5_kt_list *list;
char *princ_str;
+ int fetch;
krb5_kvno kvno;
char *enctype_str;
int use_pass;
@@ -100,10 +152,10 @@ krb5_error_code ktutil_add(context, list, princ_str, kvno,
krb5_keytab_entry *entry;
krb5_kt_list lp = NULL, prev = NULL;
krb5_principal princ;
- krb5_enctype enctype;
+ krb5_enctype enctype = ENCTYPE_NULL;
krb5_timestamp now;
krb5_error_code retval;
- krb5_data password, salt, defsalt = empty_data();
+ krb5_data password, salt = empty_data(), params = empty_data(), *s2kparams;
krb5_keyblock key;
char buf[BUFSIZ];
char promptstr[1024];
@@ -119,9 +171,11 @@ krb5_error_code ktutil_add(context, list, princ_str, kvno,
retval = krb5_unparse_name(context, princ, &princ_str);
if (retval)
return retval;
- retval = krb5_string_to_enctype(enctype_str, &enctype);
- if (retval)
- return KRB5_BAD_ENCTYPE;
+ if (enctype_str != NULL) {
+ retval = krb5_string_to_enctype(enctype_str, &enctype);
+ if (retval)
+ return KRB5_BAD_ENCTYPE;
+ }
retval = krb5_timeofday(context, &now);
if (retval)
return retval;
@@ -166,16 +220,14 @@ krb5_error_code ktutil_add(context, list, princ_str, kvno,
&password.length);
if (retval)
goto cleanup;
- if (salt_str != NULL) {
- salt = string2data(salt_str);
- } else {
- retval = krb5_principal2salt(context, princ, &defsalt);
- if (retval)
- goto cleanup;
- salt = defsalt;
- }
- retval = krb5_c_string_to_key(context, enctype, &password,
- &salt, &key);
+
+ retval = get_etype_info(context, princ, fetch, salt_str,
+ &enctype, &salt, ¶ms);
+ if (retval)
+ goto cleanup;
+ s2kparams = (params.length > 0) ? ¶ms : NULL;
+ retval = krb5_c_string_to_key_with_params(context, enctype, &password,
+ &salt, s2kparams, &key);
if (retval)
goto cleanup;
memset(password.data, 0, password.length);
@@ -225,7 +277,8 @@ cleanup:
if (prev)
prev->next = NULL;
ktutil_free_kt_list(context, lp);
- krb5_free_data_contents(context, &defsalt);
+ krb5_free_data_contents(context, &salt);
+ krb5_free_data_contents(context, ¶ms);
return retval;
}
diff --git a/src/tests/t_keytab.py b/src/tests/t_keytab.py
index 950517d..72e09da 100755
--- a/src/tests/t_keytab.py
+++ b/src/tests/t_keytab.py
@@ -148,4 +148,47 @@ out = realm.run([klist, '-k'], expected_code=1, expected_msg=msg)
msg = 'FILE:testdir/xyz%s' % uidstr
out = realm.run([klist, '-ki'], expected_code=1, expected_msg=msg)
+conf = {'libdefaults': {'allow_weak_crypto': 'true'}}
+realm = K5Realm(create_user=False, create_host=False, krb5_conf=conf)
+
+realm.run([kadminl, 'ank', '-pw', 'pw', 'default'])
+realm.run([kadminl, 'ank', '-e', 'aes256-cts:special', '-pw', 'pw', 'exp'])
+realm.run([kadminl, 'ank', '-e', 'aes256-cts:special', '-pw', 'pw', '+preauth',
+ 'pexp'])
+realm.run([kadminl, 'ank', '-e', 'des-cbc-crc:afs3', '-pw', 'pw', 'afs'])
+realm.run([kadminl, 'ank', '-e', 'des-cbc-crc:afs3', '-pw', 'pw', '+preauth',
+ 'pafs'])
+
+# Extract one of the explicit salt values from the database.
+out = realm.run([kdb5_util, 'tabdump', 'keyinfo'])
+salt_dict = {f[0]: f[5] for f in [l.split('\t') for l in out.splitlines()]}
+exp_salt = bytes.fromhex(salt_dict['exp at KRBTEST.COM']).decode('ascii')
+
+# Create a keytab using ktutil addent with the specified options and
+# password "pw". Test that we can use it to get initial tickets.
+# Remove the keytab afterwards.
+def test_addent(realm, princ, opts):
+ realm.run([ktutil], input=('addent -password -p %s -k 1 %s\npw\nwkt %s\n' %
+ (princ, opts, realm.keytab)))
+ realm.kinit(princ, flags=['-k'])
+ os.remove(realm.keytab)
+
+mark('ktutil addent')
+
+# Test with default salt.
+test_addent(realm, 'default', '-e aes128-cts')
+test_addent(realm, 'default', '-e aes256-cts')
+
+# Test with a salt specified to ktutil addent.
+test_addent(realm, 'exp', '-e aes256-cts -s %s' % exp_salt)
+
+# Test etype-info fetching.
+test_addent(realm, 'default', '-f')
+test_addent(realm, 'default', '-f -e aes128-cts')
+test_addent(realm, 'exp', '-f')
+test_addent(realm, 'pexp', '-f')
+test_addent(realm, 'afs', '-f')
+test_addent(realm, 'pafs', '-f')
+
+success('Keytab-related tests')
success('Keytab-related tests')
More information about the cvs-krb5
mailing list