Add new kadmin/ktutil --keep* and --enctypes opts

- Add --keepold/keepallold/pruneall options to various kadmin/ktutil
   commands.  Default behavior to "prune old keys".

 - When setting keys for a service, we need to specify enctypes for it:

    - Always use kadm5_randkey_principal_3() instead of the older
      kadm5_randkey_principal().

    - Add krb5_string_to_keysalts2(), like MIT's krb5_string_to_keysalts(),
      but with a context, and simpler.

    - Add --enctypes options to various kadmin/ktutil commands.

    - Add [libdefaults] supported_enctypes param with enctype[:salttype]
      list.

    - Add [realms] realm supported_enctypes param with enctype[:salttype]
      list.

      Default to aes128-cts-hmac-sha1-96:normal.
This commit is contained in:
Nicolas Williams
2019-01-01 17:25:06 -06:00
committed by Nico Williams
parent 7b76d6719f
commit d8394c65b7
18 changed files with 574 additions and 142 deletions

View File

@@ -36,17 +36,23 @@
RCSID("$Id$");
static krb5_error_code
change_entry (krb5_keytab keytab,
krb5_principal principal, krb5_kvno kvno,
const char *realm, const char *admin_server, int server_port)
change_entry(krb5_keytab keytab,
krb5_principal principal,
krb5_kvno kvno,
int keep,
size_t nkstuple,
krb5_key_salt_tuple *kstuple,
const char *realm,
const char *admin_server,
int server_port)
{
krb5_error_code ret;
kadm5_config_params conf;
void *kadm_handle;
char *client_name;
krb5_keyblock *keys;
size_t i;
int num_keys;
int i;
ret = krb5_unparse_name (context, principal, &client_name);
if (ret) {
@@ -96,14 +102,15 @@ change_entry (krb5_keytab keytab,
free (client_name);
return ret;
}
ret = kadm5_randkey_principal (kadm_handle, principal, &keys, &num_keys);
kadm5_destroy (kadm_handle);
ret = kadm5_randkey_principal_3(kadm_handle, principal, keep, nkstuple,
kstuple, &keys, &num_keys);
kadm5_destroy(kadm_handle);
if (ret) {
krb5_warn(context, ret, "kadm5_randkey_principal: %s:", client_name);
krb5_warn(context, ret, "kadm5_randkey_principal_3: %s:", client_name);
free (client_name);
return ret;
}
free (client_name);
free(client_name);
for (i = 0; i < num_keys; ++i) {
krb5_keytab_entry new_entry;
@@ -131,16 +138,51 @@ struct change_set {
};
int
kt_change (struct change_options *opt, int argc, char **argv)
kt_change(struct change_options *opt, int argc, char **argv)
{
krb5_error_code ret;
krb5_keytab keytab;
krb5_kt_cursor cursor;
krb5_keytab_entry entry;
int i, j, max;
krb5_key_salt_tuple *kstuple = NULL;
const char *enctype;
size_t i, j, max, nkstuple;
int keep = 0;
struct change_set *changeset;
int errors = 0;
i = 0;
if (opt->keepold_flag) {
keep = 1;
i++;
}
if (opt->keepallold_flag) {
keep = 2;
i++;
}
if (opt->pruneall_flag) {
keep = 0;
i++;
}
if (i > 1) {
fprintf(stderr, "use only one of --keepold, --keepallold, or --pruneall\n");
return EINVAL;
}
enctype = opt->enctype_string;
if (enctype == NULL || enctype[0] == '\0')
enctype = krb5_config_get_string(context, NULL, "libdefaults",
"supported_enctypes", NULL);
if (enctype == NULL || enctype[0] == '\0')
enctype = "aes128-cts-hmac-sha1-96";
ret = krb5_string_to_keysalts2(context, enctype, &nkstuple, &kstuple);
if (ret) {
fprintf(stderr, "enctype(s) unknown\n");
return ret;
}
/* XXX Parameterize keytab name */
if((keytab = ktutil_open_keytab()) == NULL)
return 1;
@@ -232,11 +274,12 @@ kt_change (struct change_options *opt, int argc, char **argv)
free(client_name);
}
}
ret = change_entry (keytab,
changeset[i].principal, changeset[i].kvno,
opt->realm_string,
opt->admin_server_string,
opt->server_port_integer);
ret = change_entry(keytab,
changeset[i].principal, changeset[i].kvno,
keep, nkstuple, kstuple,
opt->realm_string,
opt->admin_server_string,
opt->server_port_integer);
if (ret != 0)
errors = 1;
}
@@ -247,6 +290,7 @@ kt_change (struct change_options *opt, int argc, char **argv)
free (changeset);
out:
free(kstuple);
krb5_kt_close(context, keytab);
return errors;
}

View File

@@ -82,45 +82,84 @@ open_kadmin_connection(char *principal,
return kadm_handle;
}
static int
parse_enctypes(struct get_options *opt,
size_t *nks,
krb5_key_salt_tuple **ks)
{
const char *str;
char *s = NULL;
char *tmp;
size_t i;
int ret;
*nks = 0;
*ks = NULL;
if (opt->enctypes_strings.num_strings == 0) {
str = krb5_config_get_string(context, NULL, "libdefaults",
"supported_enctypes", NULL);
if (str == NULL)
str = "aes128-cts-hmac-sha1-96";
return krb5_string_to_keysalts2(context, str, nks, ks);
}
for (i = 0; i < opt->enctypes_strings.num_strings; i++) {
if (asprintf(&tmp, "%s%s%s", i ? s : "", i ? "," : "",
opt->enctypes_strings.strings[i]) == -1) {
free(s);
return krb5_enomem(context);
}
s = tmp;
}
ret = krb5_string_to_keysalts2(context, s, nks, ks);
free(s);
return ret;
}
int
kt_get(struct get_options *opt, int argc, char **argv)
{
krb5_error_code ret = 0;
krb5_keytab keytab;
void *kadm_handle = NULL;
krb5_enctype *etypes = NULL;
size_t netypes = 0;
krb5_key_salt_tuple *ks = NULL;
size_t nks;
size_t i;
int a, j;
int a, j, keep;
unsigned int failed = 0;
if((keytab = ktutil_open_keytab()) == NULL)
i = 0;
keep = 0;
if (opt->keepallold_flag) {
keep = 2;
i++;
}
if (opt->keepold_flag) {
keep = 1;
i++;
}
if (opt->pruneall_flag) {
keep = 0;
i++;
}
if (i > 1) {
fprintf(stderr, "use only one of --keepold, --keepallold, or --pruneall\n");
return EINVAL;
}
if ((ret = parse_enctypes(opt, &nks, &ks))) {
fprintf(stderr, "invalid enctype(s)\n");
return ret;
}
if((keytab = ktutil_open_keytab()) == NULL) {
free(ks);
return 1;
}
if(opt->realm_string)
krb5_set_default_realm(context, opt->realm_string);
if (opt->enctypes_strings.num_strings != 0) {
etypes = malloc (opt->enctypes_strings.num_strings * sizeof(*etypes));
if (etypes == NULL) {
krb5_warnx(context, "malloc failed");
goto out;
}
netypes = opt->enctypes_strings.num_strings;
for(i = 0; i < netypes; i++) {
ret = krb5_string_to_enctype(context,
opt->enctypes_strings.strings[i],
&etypes[i]);
if(ret) {
krb5_warnx(context, "unrecognized enctype: %s",
opt->enctypes_strings.strings[i]);
goto out;
}
}
}
for(a = 0; a < argc; a++){
krb5_principal princ_ent;
kadm5_principal_ent_rec princ;
@@ -167,7 +206,8 @@ kt_get(struct get_options *opt, int argc, char **argv)
failed++;
continue;
}
ret = kadm5_randkey_principal(kadm_handle, princ_ent, &keys, &n_keys);
ret = kadm5_randkey_principal_3(kadm_handle, princ_ent, keep, nks, ks,
&keys, &n_keys);
if (ret) {
krb5_warn(context, ret, "kadm5_randkey_principal(%s)", argv[a]);
krb5_free_principal(context, princ_ent);
@@ -203,37 +243,22 @@ kt_get(struct get_options *opt, int argc, char **argv)
continue;
}
for(j = 0; j < n_keys; j++) {
int do_add = TRUE;
if (netypes) {
size_t k;
do_add = FALSE;
for (k = 0; k < netypes; ++k)
if (keys[j].keytype == etypes[k]) {
do_add = TRUE;
break;
}
}
if (do_add) {
entry.principal = princ_ent;
entry.vno = princ.kvno;
entry.keyblock = keys[j];
entry.timestamp = time (NULL);
ret = krb5_kt_add_entry(context, keytab, &entry);
if (ret)
krb5_warn(context, ret, "krb5_kt_add_entry");
}
entry.principal = princ_ent;
entry.vno = princ.kvno;
entry.keyblock = keys[j];
entry.timestamp = time (NULL);
ret = krb5_kt_add_entry(context, keytab, &entry);
if (ret)
krb5_warn(context, ret, "krb5_kt_add_entry");
krb5_free_keyblock_contents(context, &keys[j]);
}
kadm5_free_principal_ent(kadm_handle, &princ);
krb5_free_principal(context, princ_ent);
}
out:
free(etypes);
if (kadm_handle)
kadm5_destroy(kadm_handle);
krb5_kt_close(context, keytab);
free(ks);
return ret != 0 || failed > 0;
}

View File

@@ -54,7 +54,7 @@ command = {
short = "e"
type = "string"
argument = "enctype"
help = "encryption type"
help = "encryption type(s)"
}
option = {
long = "password"
@@ -75,6 +75,21 @@ command = {
type = "flag"
help = "generate random key"
}
option = {
long = "keepold"
type = "flag"
help = "keep old keys/password needed to decrypt extant tickets (default)"
}
option = {
long = "keepallold"
type = "flag"
help = "keep all old keys/password"
}
option = {
long = "pruneall"
type = "flag"
help = "delete all old keys"
}
option = {
long = "hex"
short = "H"
@@ -94,6 +109,28 @@ command = {
argument = "realm"
help = "realm to use"
}
option = {
long = "enctype"
short = "e"
type = "string"
argument = "enctype"
help = "encryption type(s)"
}
option = {
long = "keepold"
type = "flag"
help = "keep old keys/password needed to decrypt extant tickets (default)"
}
option = {
long = "keepallold"
type = "flag"
help = "keep all old keys/password"
}
option = {
long = "pruneall"
type = "flag"
help = "delete all old keys"
}
option = {
long = "admin-server"
short = "a"
@@ -136,6 +173,21 @@ command = {
help = "encryption types to use"
argument = "enctype"
}
option = {
long = "keepold"
type = "flag"
help = "keep old keys/password needed to decrypt extant tickets (default)"
}
option = {
long = "keepallold"
type = "flag"
help = "keep all old keys/password"
}
option = {
long = "pruneall"
type = "flag"
help = "delete all old keys"
}
option = {
long = "realm"
short = "r"

View File

@@ -62,6 +62,7 @@ can be one of the following:
.Bl -tag -width srvconvert
.It add Oo Fl p Ar principal Oc Oo Fl Fl principal= Ns Ar principal Oc \
Oo Fl V Ar kvno Oc Oo Fl Fl kvno= Ns Ar kvno Oc Oo Fl e Ar enctype Oc \
Oo Fl Fl keepold | Fl Fl keepallold | Fl Fl pruneall Oc \
Oo Fl Fl enctype= Ns Ar enctype Oc Oo Fl w Ar password Oc \
Oo Fl Fl password= Ns Ar password Oc Oo Fl r Oc Oo Fl Fl random Oc \
Oo Fl s Oc Oo Fl Fl no-salt Oc Oo Fl H Oc Op Fl Fl hex
@@ -72,6 +73,8 @@ the keytab, you should consider the
.Ar get
command, which talks to the kadmin server.
.It change Oo Fl r Ar realm Oc Oo Fl Fl realm= Ns Ar realm Oc \
Oo Fl Fl keepold | Fl Fl keepallold | Fl Fl pruneall Oc \
Oo Fl Fl enctype= Ns Ar enctype Oc \
Oo Fl Fl a Ar host Oc Oo Fl Fl admin-server= Ns Ar host Oc \
Oo Fl Fl s Ar port Oc Op Fl Fl server-port= Ns Ar port
Update one or several keys to new versions. By default, use the admin
@@ -86,6 +89,7 @@ to
.Ar keytab-dest .
.It get Oo Fl p Ar admin principal Oc \
Oo Fl Fl principal= Ns Ar admin principal Oc Oo Fl e Ar enctype Oc \
Oo Fl Fl keepold | Fl Fl keepallold | Fl Fl pruneall Oc \
Oo Fl Fl enctypes= Ns Ar enctype Oc Oo Fl r Ar realm Oc \
Oo Fl Fl realm= Ns Ar realm Oc Oo Fl a Ar admin server Oc \
Oo Fl Fl admin-server= Ns Ar admin server Oc Oo Fl s Ar server port Oc \