1 1.3 pettai /* $NetBSD: keys.c,v 1.6 2023/06/19 21:41:43 christos Exp $ */ 2 1.1 elric 3 1.1 elric /* 4 1.4 christos * Copyright (c) 1997 - 2011 Kungliga Tekniska Hgskolan 5 1.1 elric * (Royal Institute of Technology, Stockholm, Sweden). 6 1.1 elric * All rights reserved. 7 1.1 elric * 8 1.1 elric * Redistribution and use in source and binary forms, with or without 9 1.1 elric * modification, are permitted provided that the following conditions 10 1.1 elric * are met: 11 1.1 elric * 12 1.1 elric * 1. Redistributions of source code must retain the above copyright 13 1.1 elric * notice, this list of conditions and the following disclaimer. 14 1.1 elric * 15 1.1 elric * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 elric * notice, this list of conditions and the following disclaimer in the 17 1.1 elric * documentation and/or other materials provided with the distribution. 18 1.1 elric * 19 1.1 elric * 3. Neither the name of the Institute nor the names of its contributors 20 1.1 elric * may be used to endorse or promote products derived from this software 21 1.1 elric * without specific prior written permission. 22 1.1 elric * 23 1.1 elric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 1.1 elric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.1 elric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.1 elric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 1.1 elric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 1.1 elric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 1.1 elric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.1 elric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 1.1 elric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 1.1 elric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 1.1 elric * SUCH DAMAGE. 34 1.1 elric */ 35 1.1 elric 36 1.1 elric #include "hdb_locl.h" 37 1.1 elric 38 1.4 christos struct hx509_certs_data; 39 1.4 christos struct krb5_pk_identity; 40 1.4 christos struct krb5_pk_cert; 41 1.4 christos struct ContentInfo; 42 1.4 christos struct AlgorithmIdentifier; 43 1.4 christos struct _krb5_krb_auth_data; 44 1.4 christos typedef struct krb5_pk_init_ctx_data *krb5_pk_init_ctx; 45 1.4 christos struct krb5_dh_moduli; 46 1.4 christos struct _krb5_key_data; 47 1.4 christos struct _krb5_encryption_type; 48 1.4 christos struct _krb5_key_type; 49 1.4 christos #include <krb5/pkinit_asn1.h> 50 1.4 christos #include <krb5/krb5-private.h> 51 1.4 christos #include <krb5/base64.h> 52 1.4 christos 53 1.1 elric /* 54 1.1 elric * free all the memory used by (len, keys) 55 1.1 elric */ 56 1.1 elric 57 1.1 elric void 58 1.4 christos hdb_free_keys(krb5_context context, int len, Key *keys) 59 1.1 elric { 60 1.4 christos size_t i; 61 1.1 elric 62 1.1 elric for (i = 0; i < len; i++) { 63 1.1 elric free(keys[i].mkvno); 64 1.1 elric keys[i].mkvno = NULL; 65 1.1 elric if (keys[i].salt != NULL) { 66 1.1 elric free_Salt(keys[i].salt); 67 1.1 elric free(keys[i].salt); 68 1.1 elric keys[i].salt = NULL; 69 1.1 elric } 70 1.1 elric krb5_free_keyblock_contents(context, &keys[i].key); 71 1.1 elric } 72 1.1 elric free (keys); 73 1.1 elric } 74 1.1 elric 75 1.1 elric /* 76 1.1 elric * for each entry in `default_keys' try to parse it as a sequence 77 1.1 elric * of etype:salttype:salt, syntax of this if something like: 78 1.1 elric * [(des|des3|etype):](pw-salt|afs3)[:string], if etype is omitted it 79 1.1 elric * means all etypes, and if string is omitted is means the default 80 1.1 elric * string (for that principal). Additional special values: 81 1.1 elric * v5 == pw-salt, and 82 1.1 elric * v4 == des:pw-salt: 83 1.1 elric * afs or afs3 == des:afs3-salt 84 1.1 elric */ 85 1.1 elric 86 1.1 elric static const krb5_enctype des_etypes[] = { 87 1.4 christos KRB5_ENCTYPE_DES_CBC_MD5, 88 1.4 christos KRB5_ENCTYPE_DES_CBC_MD4, 89 1.4 christos KRB5_ENCTYPE_DES_CBC_CRC 90 1.1 elric }; 91 1.1 elric 92 1.1 elric static const krb5_enctype all_etypes[] = { 93 1.4 christos KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, 94 1.4 christos KRB5_ENCTYPE_DES3_CBC_SHA1, 95 1.4 christos KRB5_ENCTYPE_ARCFOUR_HMAC_MD5 96 1.1 elric }; 97 1.1 elric 98 1.1 elric static krb5_error_code 99 1.1 elric parse_key_set(krb5_context context, const char *key, 100 1.1 elric krb5_enctype **ret_enctypes, size_t *ret_num_enctypes, 101 1.1 elric krb5_salt *salt, krb5_principal principal) 102 1.1 elric { 103 1.1 elric const char *p; 104 1.1 elric char buf[3][256]; 105 1.1 elric int num_buf = 0; 106 1.1 elric int i, num_enctypes = 0; 107 1.1 elric krb5_enctype e; 108 1.1 elric const krb5_enctype *enctypes = NULL; 109 1.1 elric krb5_error_code ret; 110 1.1 elric 111 1.1 elric p = key; 112 1.1 elric 113 1.1 elric *ret_enctypes = NULL; 114 1.1 elric *ret_num_enctypes = 0; 115 1.1 elric 116 1.1 elric /* split p in a list of :-separated strings */ 117 1.1 elric for(num_buf = 0; num_buf < 3; num_buf++) 118 1.1 elric if(strsep_copy(&p, ":", buf[num_buf], sizeof(buf[num_buf])) == -1) 119 1.1 elric break; 120 1.1 elric 121 1.1 elric salt->saltvalue.data = NULL; 122 1.1 elric salt->saltvalue.length = 0; 123 1.1 elric 124 1.1 elric for(i = 0; i < num_buf; i++) { 125 1.1 elric if(enctypes == NULL && num_buf > 1) { 126 1.1 elric /* this might be a etype specifier */ 127 1.1 elric /* XXX there should be a string_to_etypes handling 128 1.1 elric special cases like `des' and `all' */ 129 1.1 elric if(strcmp(buf[i], "des") == 0) { 130 1.1 elric enctypes = des_etypes; 131 1.1 elric num_enctypes = sizeof(des_etypes)/sizeof(des_etypes[0]); 132 1.1 elric } else if(strcmp(buf[i], "des3") == 0) { 133 1.4 christos e = KRB5_ENCTYPE_DES3_CBC_SHA1; 134 1.1 elric enctypes = &e; 135 1.1 elric num_enctypes = 1; 136 1.1 elric } else { 137 1.1 elric ret = krb5_string_to_enctype(context, buf[i], &e); 138 1.1 elric if (ret == 0) { 139 1.1 elric enctypes = &e; 140 1.1 elric num_enctypes = 1; 141 1.1 elric } else 142 1.1 elric return ret; 143 1.1 elric } 144 1.1 elric continue; 145 1.1 elric } 146 1.1 elric if(salt->salttype == 0) { 147 1.1 elric /* interpret string as a salt specifier, if no etype 148 1.1 elric is set, this sets default values */ 149 1.1 elric /* XXX should perhaps use string_to_salttype, but that 150 1.1 elric interface sucks */ 151 1.1 elric if(strcmp(buf[i], "pw-salt") == 0) { 152 1.1 elric if(enctypes == NULL) { 153 1.1 elric enctypes = all_etypes; 154 1.1 elric num_enctypes = sizeof(all_etypes)/sizeof(all_etypes[0]); 155 1.1 elric } 156 1.1 elric salt->salttype = KRB5_PW_SALT; 157 1.1 elric } else if(strcmp(buf[i], "afs3-salt") == 0) { 158 1.1 elric if(enctypes == NULL) { 159 1.1 elric enctypes = des_etypes; 160 1.1 elric num_enctypes = sizeof(des_etypes)/sizeof(des_etypes[0]); 161 1.1 elric } 162 1.1 elric salt->salttype = KRB5_AFS3_SALT; 163 1.1 elric } 164 1.1 elric continue; 165 1.1 elric } 166 1.1 elric 167 1.4 christos if (salt->saltvalue.data != NULL) 168 1.4 christos free(salt->saltvalue.data); 169 1.4 christos /* if there is a final string, use it as the string to 170 1.4 christos salt with, this is mostly useful with null salt for 171 1.4 christos v4 compat, and a cell name for afs compat */ 172 1.4 christos salt->saltvalue.data = strdup(buf[i]); 173 1.4 christos if (salt->saltvalue.data == NULL) 174 1.4 christos return krb5_enomem(context); 175 1.4 christos salt->saltvalue.length = strlen(buf[i]); 176 1.1 elric } 177 1.1 elric 178 1.1 elric if(enctypes == NULL || salt->salttype == 0) { 179 1.4 christos krb5_free_salt(context, *salt); 180 1.1 elric krb5_set_error_message(context, EINVAL, "bad value for default_keys `%s'", key); 181 1.1 elric return EINVAL; 182 1.1 elric } 183 1.1 elric 184 1.1 elric /* if no salt was specified make up default salt */ 185 1.1 elric if(salt->saltvalue.data == NULL) { 186 1.4 christos if(salt->salttype == KRB5_PW_SALT) { 187 1.1 elric ret = krb5_get_pw_salt(context, principal, salt); 188 1.4 christos if (ret) 189 1.4 christos return ret; 190 1.4 christos } else if(salt->salttype == KRB5_AFS3_SALT) { 191 1.1 elric krb5_const_realm realm = krb5_principal_get_realm(context, principal); 192 1.1 elric salt->saltvalue.data = strdup(realm); 193 1.1 elric if(salt->saltvalue.data == NULL) { 194 1.1 elric krb5_set_error_message(context, ENOMEM, 195 1.1 elric "out of memory while " 196 1.1 elric "parsing salt specifiers"); 197 1.1 elric return ENOMEM; 198 1.1 elric } 199 1.1 elric strlwr(salt->saltvalue.data); 200 1.1 elric salt->saltvalue.length = strlen(realm); 201 1.1 elric } 202 1.1 elric } 203 1.1 elric 204 1.1 elric *ret_enctypes = malloc(sizeof(enctypes[0]) * num_enctypes); 205 1.1 elric if (*ret_enctypes == NULL) { 206 1.1 elric krb5_free_salt(context, *salt); 207 1.1 elric krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 208 1.1 elric return ENOMEM; 209 1.1 elric } 210 1.1 elric memcpy(*ret_enctypes, enctypes, sizeof(enctypes[0]) * num_enctypes); 211 1.1 elric *ret_num_enctypes = num_enctypes; 212 1.1 elric 213 1.1 elric return 0; 214 1.1 elric } 215 1.1 elric 216 1.4 christos /** 217 1.4 christos * This function prunes an HDB entry's keys that are too old to have been used 218 1.4 christos * to mint still valid tickets (based on the entry's maximum ticket lifetime). 219 1.4 christos * 220 1.4 christos * @param context Context 221 1.4 christos * @param entry HDB entry 222 1.4 christos */ 223 1.4 christos krb5_error_code 224 1.4 christos hdb_prune_keys(krb5_context context, hdb_entry *entry) 225 1.4 christos { 226 1.4 christos HDB_extension *ext; 227 1.4 christos HDB_Ext_KeySet *keys; 228 1.4 christos size_t nelem; 229 1.4 christos 230 1.4 christos ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); 231 1.4 christos if (ext == NULL) 232 1.4 christos return 0; 233 1.4 christos keys = &ext->data.u.hist_keys; 234 1.4 christos nelem = keys->len; 235 1.4 christos 236 1.4 christos /* Optionally drop key history for keys older than now - max_life */ 237 1.4 christos if (entry->max_life != NULL && nelem > 0 238 1.4 christos && krb5_config_get_bool_default(context, NULL, FALSE, 239 1.4 christos "kadmin", "prune-key-history", NULL)) { 240 1.4 christos hdb_keyset *elem; 241 1.4 christos time_t ceiling = time(NULL) - *entry->max_life; 242 1.4 christos time_t keep_time = 0; 243 1.4 christos size_t i; 244 1.4 christos 245 1.4 christos /* 246 1.4 christos * Compute most recent key timestamp that predates the current time 247 1.4 christos * by at least the entry's maximum ticket lifetime. 248 1.4 christos */ 249 1.4 christos for (i = 0; i < nelem; ++i) { 250 1.4 christos elem = &keys->val[i]; 251 1.4 christos if (elem->set_time && *elem->set_time < ceiling 252 1.4 christos && (keep_time == 0 || *elem->set_time > keep_time)) 253 1.4 christos keep_time = *elem->set_time; 254 1.4 christos } 255 1.4 christos 256 1.4 christos /* Drop obsolete entries */ 257 1.4 christos if (keep_time) { 258 1.4 christos for (i = 0; i < nelem; /* see below */) { 259 1.4 christos elem = &keys->val[i]; 260 1.4 christos if (elem->set_time && *elem->set_time < keep_time) { 261 1.4 christos remove_HDB_Ext_KeySet(keys, i); 262 1.4 christos /* 263 1.4 christos * Removing the i'th element shifts the tail down, continue 264 1.4 christos * at same index with reduced upper bound. 265 1.4 christos */ 266 1.4 christos --nelem; 267 1.4 christos continue; 268 1.4 christos } 269 1.4 christos ++i; 270 1.4 christos } 271 1.4 christos } 272 1.4 christos } 273 1.4 christos 274 1.4 christos return 0; 275 1.4 christos } 276 1.4 christos 277 1.4 christos /** 278 1.4 christos * This function adds an HDB entry's current keyset to the entry's key 279 1.4 christos * history. The current keyset is left alone; the caller is responsible 280 1.4 christos * for freeing it. 281 1.4 christos * 282 1.4 christos * @param context Context 283 1.4 christos * @param entry HDB entry 284 1.4 christos */ 285 1.4 christos krb5_error_code 286 1.4 christos hdb_add_current_keys_to_history(krb5_context context, hdb_entry *entry) 287 1.4 christos { 288 1.4 christos krb5_boolean replace = FALSE; 289 1.4 christos krb5_error_code ret; 290 1.4 christos HDB_extension *ext; 291 1.4 christos HDB_Ext_KeySet *keys; 292 1.4 christos hdb_keyset newkeyset; 293 1.4 christos time_t newtime; 294 1.4 christos 295 1.4 christos if (entry->keys.len == 0) 296 1.4 christos return 0; /* nothing to do */ 297 1.4 christos 298 1.4 christos ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); 299 1.4 christos if (ext == NULL) { 300 1.4 christos replace = TRUE; 301 1.4 christos ext = calloc(1, sizeof (*ext)); 302 1.4 christos if (ext == NULL) 303 1.4 christos return krb5_enomem(context); 304 1.4 christos 305 1.4 christos ext->data.element = choice_HDB_extension_data_hist_keys; 306 1.4 christos } 307 1.4 christos keys = &ext->data.u.hist_keys; 308 1.4 christos 309 1.4 christos ext->mandatory = FALSE; 310 1.4 christos 311 1.4 christos /* 312 1.4 christos * Copy in newest old keyset 313 1.4 christos */ 314 1.4 christos ret = hdb_entry_get_pw_change_time(entry, &newtime); 315 1.4 christos if (ret) 316 1.4 christos goto out; 317 1.4 christos 318 1.4 christos memset(&newkeyset, 0, sizeof(newkeyset)); 319 1.4 christos newkeyset.keys = entry->keys; 320 1.4 christos newkeyset.kvno = entry->kvno; 321 1.4 christos newkeyset.set_time = &newtime; 322 1.4 christos 323 1.4 christos ret = add_HDB_Ext_KeySet(keys, &newkeyset); 324 1.4 christos if (ret) 325 1.4 christos goto out; 326 1.4 christos 327 1.4 christos if (replace) { 328 1.4 christos /* hdb_replace_extension() deep-copies ext; what a waste */ 329 1.4 christos ret = hdb_replace_extension(context, entry, ext); 330 1.4 christos if (ret) 331 1.4 christos goto out; 332 1.4 christos } 333 1.4 christos 334 1.4 christos ret = hdb_prune_keys(context, entry); 335 1.4 christos if (ret) 336 1.4 christos goto out; 337 1.4 christos 338 1.4 christos out: 339 1.4 christos if (replace && ext) { 340 1.4 christos free_HDB_extension(ext); 341 1.4 christos free(ext); 342 1.4 christos } 343 1.4 christos return ret; 344 1.4 christos } 345 1.4 christos 346 1.4 christos /** 347 1.4 christos * This function adds a key to an HDB entry's key history. 348 1.4 christos * 349 1.4 christos * @param context Context 350 1.4 christos * @param entry HDB entry 351 1.4 christos * @param kvno Key version number of the key to add to the history 352 1.4 christos * @param key The Key to add 353 1.4 christos */ 354 1.4 christos krb5_error_code 355 1.4 christos hdb_add_history_key(krb5_context context, hdb_entry *entry, krb5_kvno kvno, Key *key) 356 1.4 christos { 357 1.4 christos size_t i; 358 1.4 christos hdb_keyset keyset; 359 1.4 christos HDB_Ext_KeySet *hist_keys; 360 1.4 christos HDB_extension ext; 361 1.4 christos HDB_extension *extp; 362 1.4 christos krb5_error_code ret; 363 1.4 christos 364 1.4 christos memset(&keyset, 0, sizeof (keyset)); 365 1.4 christos memset(&ext, 0, sizeof (ext)); 366 1.4 christos 367 1.4 christos extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); 368 1.4 christos if (extp == NULL) { 369 1.4 christos ext.data.element = choice_HDB_extension_data_hist_keys; 370 1.4 christos extp = &ext; 371 1.4 christos } 372 1.4 christos 373 1.4 christos extp->mandatory = FALSE; 374 1.4 christos hist_keys = &extp->data.u.hist_keys; 375 1.4 christos 376 1.4 christos for (i = 0; i < hist_keys->len; i++) { 377 1.4 christos if (hist_keys->val[i].kvno == kvno) { 378 1.4 christos ret = add_Keys(&hist_keys->val[i].keys, key); 379 1.4 christos goto out; 380 1.4 christos } 381 1.4 christos } 382 1.4 christos 383 1.4 christos keyset.kvno = kvno; 384 1.4 christos ret = add_Keys(&keyset.keys, key); 385 1.4 christos if (ret) 386 1.4 christos goto out; 387 1.4 christos ret = add_HDB_Ext_KeySet(hist_keys, &keyset); 388 1.4 christos if (ret) 389 1.4 christos goto out; 390 1.4 christos if (extp == &ext) { 391 1.4 christos ret = hdb_replace_extension(context, entry, &ext); 392 1.4 christos if (ret) 393 1.4 christos goto out; 394 1.4 christos } 395 1.4 christos 396 1.4 christos out: 397 1.4 christos free_hdb_keyset(&keyset); 398 1.4 christos free_HDB_extension(&ext); 399 1.4 christos return ret; 400 1.4 christos } 401 1.4 christos 402 1.4 christos 403 1.4 christos /** 404 1.4 christos * This function changes an hdb_entry's kvno, swapping the current key 405 1.4 christos * set with a historical keyset. If no historical keys are found then 406 1.4 christos * an error is returned (the caller can still set entry->kvno directly). 407 1.4 christos * 408 1.4 christos * @param context krb5_context 409 1.4 christos * @param new_kvno New kvno for the entry 410 1.4 christos * @param entry hdb_entry to modify 411 1.4 christos */ 412 1.4 christos krb5_error_code 413 1.4 christos hdb_change_kvno(krb5_context context, krb5_kvno new_kvno, hdb_entry *entry) 414 1.4 christos { 415 1.4 christos HDB_extension ext; 416 1.4 christos HDB_extension *extp; 417 1.4 christos hdb_keyset keyset; 418 1.4 christos HDB_Ext_KeySet *hist_keys; 419 1.4 christos size_t i; 420 1.4 christos int found = 0; 421 1.4 christos krb5_error_code ret; 422 1.4 christos 423 1.4 christos if (entry->kvno == new_kvno) 424 1.4 christos return 0; 425 1.4 christos 426 1.4 christos extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); 427 1.4 christos if (extp == NULL) { 428 1.4 christos memset(&ext, 0, sizeof (ext)); 429 1.4 christos ext.data.element = choice_HDB_extension_data_hist_keys; 430 1.4 christos extp = &ext; 431 1.4 christos } 432 1.4 christos 433 1.4 christos memset(&keyset, 0, sizeof (keyset)); 434 1.4 christos hist_keys = &extp->data.u.hist_keys; 435 1.4 christos for (i = 0; i < hist_keys->len; i++) { 436 1.4 christos if (hist_keys->val[i].kvno == new_kvno) { 437 1.4 christos found = 1; 438 1.4 christos ret = copy_hdb_keyset(&hist_keys->val[i], &keyset); 439 1.4 christos if (ret) 440 1.4 christos goto out; 441 1.4 christos ret = remove_HDB_Ext_KeySet(hist_keys, i); 442 1.4 christos if (ret) 443 1.4 christos goto out; 444 1.4 christos break; 445 1.4 christos } 446 1.4 christos } 447 1.4 christos 448 1.4 christos if (!found) 449 1.4 christos return HDB_ERR_KVNO_NOT_FOUND; 450 1.4 christos 451 1.4 christos ret = hdb_add_current_keys_to_history(context, entry); 452 1.4 christos if (ret) 453 1.4 christos goto out; 454 1.4 christos 455 1.4 christos /* Note: we do nothing with keyset.set_time */ 456 1.4 christos entry->kvno = new_kvno; 457 1.4 christos entry->keys = keyset.keys; /* shortcut */ 458 1.4 christos memset(&keyset.keys, 0, sizeof (keyset.keys)); 459 1.4 christos 460 1.4 christos out: 461 1.4 christos free_hdb_keyset(&keyset); 462 1.4 christos return ret; 463 1.4 christos } 464 1.4 christos 465 1.4 christos 466 1.1 elric static krb5_error_code 467 1.1 elric add_enctype_to_key_set(Key **key_set, size_t *nkeyset, 468 1.1 elric krb5_enctype enctype, krb5_salt *salt) 469 1.1 elric { 470 1.1 elric krb5_error_code ret; 471 1.1 elric Key key, *tmp; 472 1.1 elric 473 1.1 elric memset(&key, 0, sizeof(key)); 474 1.1 elric 475 1.1 elric tmp = realloc(*key_set, (*nkeyset + 1) * sizeof((*key_set)[0])); 476 1.1 elric if (tmp == NULL) 477 1.1 elric return ENOMEM; 478 1.1 elric 479 1.1 elric *key_set = tmp; 480 1.1 elric 481 1.1 elric key.key.keytype = enctype; 482 1.1 elric key.key.keyvalue.length = 0; 483 1.1 elric key.key.keyvalue.data = NULL; 484 1.1 elric 485 1.1 elric if (salt) { 486 1.1 elric key.salt = calloc(1, sizeof(*key.salt)); 487 1.1 elric if (key.salt == NULL) { 488 1.1 elric free_Key(&key); 489 1.1 elric return ENOMEM; 490 1.1 elric } 491 1.2 pettai 492 1.1 elric key.salt->type = salt->salttype; 493 1.1 elric krb5_data_zero (&key.salt->salt); 494 1.2 pettai 495 1.1 elric ret = krb5_data_copy(&key.salt->salt, 496 1.1 elric salt->saltvalue.data, 497 1.1 elric salt->saltvalue.length); 498 1.1 elric if (ret) { 499 1.1 elric free_Key(&key); 500 1.1 elric return ret; 501 1.1 elric } 502 1.1 elric } else 503 1.1 elric key.salt = NULL; 504 1.1 elric 505 1.1 elric (*key_set)[*nkeyset] = key; 506 1.1 elric 507 1.1 elric *nkeyset += 1; 508 1.1 elric 509 1.1 elric return 0; 510 1.1 elric } 511 1.1 elric 512 1.1 elric 513 1.4 christos static 514 1.4 christos krb5_error_code 515 1.4 christos ks_tuple2str(krb5_context context, int n_ks_tuple, 516 1.4 christos krb5_key_salt_tuple *ks_tuple, char ***ks_tuple_strs) 517 1.4 christos { 518 1.4 christos size_t i; 519 1.4 christos char **ksnames; 520 1.4 christos krb5_error_code rc = KRB5_PROG_ETYPE_NOSUPP; 521 1.4 christos 522 1.4 christos *ks_tuple_strs = NULL; 523 1.4 christos if (n_ks_tuple < 1) 524 1.4 christos return 0; 525 1.4 christos 526 1.4 christos if ((ksnames = calloc(n_ks_tuple + 1, sizeof (*ksnames))) == NULL) 527 1.4 christos return (errno); 528 1.4 christos 529 1.4 christos for (i = 0; i < n_ks_tuple; i++) { 530 1.4 christos char *ename, *sname; 531 1.4 christos 532 1.4 christos if (krb5_enctype_to_string(context, ks_tuple[i].ks_enctype, &ename)) 533 1.4 christos goto out; 534 1.4 christos if (krb5_salttype_to_string(context, ks_tuple[i].ks_enctype, 535 1.4 christos ks_tuple[i].ks_salttype, &sname)) { 536 1.4 christos free(ename); 537 1.4 christos goto out; 538 1.4 christos } 539 1.4 christos 540 1.4 christos if (asprintf(&ksnames[i], "%s:%s", ename, sname) == -1) { 541 1.4 christos rc = errno; 542 1.4 christos free(ename); 543 1.4 christos free(sname); 544 1.4 christos goto out; 545 1.4 christos } 546 1.4 christos free(ename); 547 1.4 christos free(sname); 548 1.4 christos } 549 1.4 christos 550 1.4 christos ksnames[i] = NULL; 551 1.4 christos *ks_tuple_strs = ksnames; 552 1.4 christos return 0; 553 1.4 christos 554 1.4 christos out: 555 1.4 christos for (i = 0; i < n_ks_tuple; i++) 556 1.4 christos free(ksnames[i]); 557 1.4 christos free(ksnames); 558 1.4 christos return (rc); 559 1.4 christos } 560 1.4 christos 561 1.4 christos /* 562 1.4 christos * 563 1.4 christos */ 564 1.4 christos 565 1.4 christos static char ** 566 1.4 christos glob_rules_keys(krb5_context context, krb5_const_principal principal) 567 1.4 christos { 568 1.4 christos const krb5_config_binding *list; 569 1.4 christos krb5_principal pattern; 570 1.4 christos krb5_error_code ret; 571 1.4 christos 572 1.4 christos list = krb5_config_get_list(context, NULL, "kadmin", 573 1.4 christos "default_key_rules", NULL); 574 1.4 christos if (list == NULL) 575 1.4 christos return NULL; 576 1.4 christos 577 1.4 christos while (list) { 578 1.4 christos if (list->type == krb5_config_string) { 579 1.4 christos ret = krb5_parse_name(context, list->name, &pattern); 580 1.4 christos if (ret == 0) { 581 1.4 christos ret = krb5_principal_match(context, principal, pattern); 582 1.4 christos krb5_free_principal(context, pattern); 583 1.4 christos if (ret) { 584 1.4 christos return krb5_config_get_strings(context, list, 585 1.4 christos list->name, NULL); 586 1.4 christos } 587 1.4 christos } 588 1.4 christos } 589 1.4 christos list = list->next; 590 1.4 christos } 591 1.4 christos return NULL; 592 1.4 christos } 593 1.4 christos 594 1.4 christos /* 595 1.4 christos * NIST guidance in Section 5.1 of [SP800-132] requires that a portion 596 1.4 christos * of the salt of at least 128 bits shall be randomly generated. 597 1.4 christos */ 598 1.4 christos static krb5_error_code 599 1.4 christos add_random_to_salt(krb5_context context, krb5_salt *in, krb5_salt *out) 600 1.4 christos { 601 1.4 christos krb5_error_code ret; 602 1.4 christos char *p; 603 1.4 christos unsigned char random[16]; 604 1.4 christos char *s; 605 1.4 christos int slen; 606 1.4 christos 607 1.4 christos krb5_generate_random_block(random, sizeof(random)); 608 1.4 christos 609 1.4 christos slen = rk_base64_encode(random, sizeof(random), &s); 610 1.4 christos if (slen < 0) 611 1.4 christos return ENOMEM; 612 1.4 christos 613 1.4 christos ret = krb5_data_alloc(&out->saltvalue, slen + in->saltvalue.length); 614 1.4 christos if (ret) { 615 1.4 christos free(s); 616 1.4 christos return ret; 617 1.4 christos } 618 1.4 christos 619 1.4 christos p = out->saltvalue.data; 620 1.4 christos memcpy(p, s, slen); 621 1.4 christos memcpy(&p[slen], in->saltvalue.data, in->saltvalue.length); 622 1.4 christos 623 1.4 christos out->salttype = in->salttype; 624 1.4 christos free(s); 625 1.4 christos 626 1.4 christos return 0; 627 1.4 christos } 628 1.4 christos 629 1.1 elric /* 630 1.1 elric * Generate the `key_set' from the [kadmin]default_keys statement. If 631 1.1 elric * `no_salt' is set, salt is not important (and will not be set) since 632 1.1 elric * it's random keys that is going to be created. 633 1.1 elric */ 634 1.1 elric 635 1.1 elric krb5_error_code 636 1.1 elric hdb_generate_key_set(krb5_context context, krb5_principal principal, 637 1.4 christos krb5_key_salt_tuple *ks_tuple, int n_ks_tuple, 638 1.1 elric Key **ret_key_set, size_t *nkeyset, int no_salt) 639 1.1 elric { 640 1.4 christos char **ktypes = NULL; 641 1.4 christos char **kp; 642 1.1 elric krb5_error_code ret; 643 1.1 elric Key *k, *key_set; 644 1.2 pettai size_t i, j; 645 1.4 christos char **ks_tuple_strs; 646 1.4 christos char **config_ktypes = NULL; 647 1.2 pettai static const char *default_keytypes[] = { 648 1.1 elric "aes256-cts-hmac-sha1-96:pw-salt", 649 1.1 elric "des3-cbc-sha1:pw-salt", 650 1.1 elric "arcfour-hmac-md5:pw-salt", 651 1.1 elric NULL 652 1.1 elric }; 653 1.1 elric 654 1.4 christos if ((ret = ks_tuple2str(context, n_ks_tuple, ks_tuple, &ks_tuple_strs))) 655 1.4 christos return ret; 656 1.4 christos 657 1.4 christos ktypes = ks_tuple_strs; 658 1.4 christos if (ktypes == NULL) { 659 1.4 christos ktypes = glob_rules_keys(context, principal); 660 1.4 christos } 661 1.4 christos if (ktypes == NULL) { 662 1.4 christos config_ktypes = krb5_config_get_strings(context, NULL, "kadmin", 663 1.4 christos "default_keys", NULL); 664 1.4 christos ktypes = config_ktypes; 665 1.4 christos } 666 1.1 elric if (ktypes == NULL) 667 1.2 pettai ktypes = (char **)(intptr_t)default_keytypes; 668 1.1 elric 669 1.1 elric *ret_key_set = key_set = NULL; 670 1.1 elric *nkeyset = 0; 671 1.1 elric 672 1.1 elric for(kp = ktypes; kp && *kp; kp++) { 673 1.1 elric const char *p; 674 1.1 elric krb5_salt salt; 675 1.1 elric krb5_enctype *enctypes; 676 1.1 elric size_t num_enctypes; 677 1.1 elric 678 1.1 elric p = *kp; 679 1.1 elric /* check alias */ 680 1.1 elric if(strcmp(p, "v5") == 0) 681 1.1 elric p = "pw-salt"; 682 1.1 elric else if(strcmp(p, "v4") == 0) 683 1.1 elric p = "des:pw-salt:"; 684 1.1 elric else if(strcmp(p, "afs") == 0 || strcmp(p, "afs3") == 0) 685 1.1 elric p = "des:afs3-salt"; 686 1.1 elric else if (strcmp(p, "arcfour-hmac-md5") == 0) 687 1.1 elric p = "arcfour-hmac-md5:pw-salt"; 688 1.2 pettai 689 1.1 elric memset(&salt, 0, sizeof(salt)); 690 1.1 elric 691 1.1 elric ret = parse_key_set(context, p, 692 1.1 elric &enctypes, &num_enctypes, &salt, principal); 693 1.1 elric if (ret) { 694 1.1 elric krb5_warn(context, ret, "bad value for default_keys `%s'", *kp); 695 1.1 elric ret = 0; 696 1.4 christos krb5_free_salt(context, salt); 697 1.1 elric continue; 698 1.1 elric } 699 1.1 elric 700 1.1 elric for (i = 0; i < num_enctypes; i++) { 701 1.4 christos krb5_salt *saltp = no_salt ? NULL : &salt; 702 1.4 christos krb5_salt rsalt; 703 1.4 christos 704 1.1 elric /* find duplicates */ 705 1.1 elric for (j = 0; j < *nkeyset; j++) { 706 1.1 elric 707 1.1 elric k = &key_set[j]; 708 1.1 elric 709 1.1 elric if (k->key.keytype == enctypes[i]) { 710 1.1 elric if (no_salt) 711 1.1 elric break; 712 1.1 elric if (k->salt == NULL && salt.salttype == KRB5_PW_SALT) 713 1.1 elric break; 714 1.1 elric if (k->salt->type == salt.salttype && 715 1.1 elric k->salt->salt.length == salt.saltvalue.length && 716 1.1 elric memcmp(k->salt->salt.data, salt.saltvalue.data, 717 1.1 elric salt.saltvalue.length) == 0) 718 1.1 elric break; 719 1.1 elric } 720 1.1 elric } 721 1.1 elric /* not a duplicate, lets add it */ 722 1.4 christos if (j < *nkeyset) 723 1.4 christos continue; 724 1.4 christos 725 1.4 christos memset(&rsalt, 0, sizeof(rsalt)); 726 1.4 christos 727 1.4 christos /* prepend salt with randomness if required */ 728 1.4 christos if (!no_salt && 729 1.4 christos _krb5_enctype_requires_random_salt(context, enctypes[i])) { 730 1.4 christos saltp = &rsalt; 731 1.4 christos ret = add_random_to_salt(context, &salt, &rsalt); 732 1.4 christos } 733 1.4 christos 734 1.4 christos if (ret == 0) 735 1.1 elric ret = add_enctype_to_key_set(&key_set, nkeyset, enctypes[i], 736 1.4 christos saltp); 737 1.4 christos krb5_free_salt(context, rsalt); 738 1.4 christos 739 1.4 christos if (ret) { 740 1.4 christos free(enctypes); 741 1.4 christos krb5_free_salt(context, salt); 742 1.4 christos goto out; 743 1.1 elric } 744 1.1 elric } 745 1.1 elric free(enctypes); 746 1.1 elric krb5_free_salt(context, salt); 747 1.1 elric } 748 1.1 elric 749 1.1 elric *ret_key_set = key_set; 750 1.1 elric 751 1.1 elric out: 752 1.4 christos if (config_ktypes != NULL) 753 1.4 christos krb5_config_free_strings(config_ktypes); 754 1.4 christos 755 1.4 christos for(kp = ks_tuple_strs; kp && *kp; kp++) 756 1.4 christos free(*kp); 757 1.4 christos free(ks_tuple_strs); 758 1.1 elric 759 1.1 elric if (ret) { 760 1.1 elric krb5_warn(context, ret, 761 1.1 elric "failed to parse the [kadmin]default_keys values"); 762 1.1 elric 763 1.1 elric for (i = 0; i < *nkeyset; i++) 764 1.1 elric free_Key(&key_set[i]); 765 1.1 elric free(key_set); 766 1.1 elric } else if (*nkeyset == 0) { 767 1.1 elric krb5_warnx(context, 768 1.1 elric "failed to parse any of the [kadmin]default_keys values"); 769 1.1 elric ret = EINVAL; /* XXX */ 770 1.1 elric } 771 1.1 elric 772 1.1 elric return ret; 773 1.1 elric } 774 1.1 elric 775 1.1 elric 776 1.1 elric krb5_error_code 777 1.5 christos hdb_generate_key_set_password_with_ks_tuple(krb5_context context, 778 1.5 christos krb5_principal principal, 779 1.5 christos const char *password, 780 1.5 christos krb5_key_salt_tuple *ks_tuple, 781 1.5 christos int n_ks_tuple, 782 1.5 christos Key **keys, size_t *num_keys) 783 1.1 elric { 784 1.1 elric krb5_error_code ret; 785 1.2 pettai size_t i; 786 1.1 elric 787 1.4 christos ret = hdb_generate_key_set(context, principal, ks_tuple, n_ks_tuple, 788 1.1 elric keys, num_keys, 0); 789 1.1 elric if (ret) 790 1.1 elric return ret; 791 1.1 elric 792 1.1 elric for (i = 0; i < (*num_keys); i++) { 793 1.1 elric krb5_salt salt; 794 1.4 christos Key *key = &(*keys)[i]; 795 1.1 elric 796 1.4 christos salt.salttype = key->salt->type; 797 1.4 christos salt.saltvalue.length = key->salt->salt.length; 798 1.4 christos salt.saltvalue.data = key->salt->salt.data; 799 1.1 elric 800 1.1 elric ret = krb5_string_to_key_salt (context, 801 1.4 christos key->key.keytype, 802 1.1 elric password, 803 1.1 elric salt, 804 1.4 christos &key->key); 805 1.1 elric if(ret) 806 1.1 elric break; 807 1.1 elric } 808 1.1 elric 809 1.1 elric if(ret) { 810 1.1 elric hdb_free_keys (context, *num_keys, *keys); 811 1.1 elric return ret; 812 1.1 elric } 813 1.1 elric return ret; 814 1.1 elric } 815 1.5 christos 816 1.5 christos 817 1.5 christos krb5_error_code 818 1.5 christos hdb_generate_key_set_password(krb5_context context, 819 1.5 christos krb5_principal principal, 820 1.5 christos const char *password, 821 1.5 christos Key **keys, size_t *num_keys) 822 1.5 christos { 823 1.5 christos 824 1.5 christos return hdb_generate_key_set_password_with_ks_tuple(context, principal, 825 1.5 christos password, NULL, 0, 826 1.5 christos keys, num_keys); 827 1.5 christos } 828