1 /* $NetBSD: set_keys.c,v 1.2 2017/01/28 21:31:49 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "kadm5_locl.h" 37 38 __RCSID("$NetBSD: set_keys.c,v 1.2 2017/01/28 21:31:49 christos Exp $"); 39 40 /* 41 * Set the keys of `ent' to the string-to-key of `password' 42 */ 43 44 kadm5_ret_t 45 _kadm5_set_keys(kadm5_server_context *context, 46 hdb_entry *ent, 47 int n_ks_tuple, 48 krb5_key_salt_tuple *ks_tuple, 49 const char *password) 50 { 51 Key *keys; 52 size_t num_keys; 53 kadm5_ret_t ret; 54 55 ret = hdb_generate_key_set_password(context->context, 56 ent->principal, 57 password, 58 ks_tuple, n_ks_tuple, 59 &keys, &num_keys); 60 if (ret) 61 return ret; 62 63 _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val); 64 ent->keys.val = keys; 65 ent->keys.len = num_keys; 66 67 hdb_entry_set_pw_change_time(context->context, ent, 0); 68 69 if (krb5_config_get_bool_default(context->context, NULL, FALSE, 70 "kadmin", "save-password", NULL)) 71 { 72 ret = hdb_entry_set_password(context->context, context->db, 73 ent, password); 74 if (ret) 75 return ret; 76 } 77 78 return 0; 79 } 80 81 static void 82 setup_Key(Key *k, Salt *s, krb5_key_data *kd, size_t kd_offset) 83 { 84 memset(k, 0, sizeof (*k)); /* sets mkvno and salt */ 85 k->key.keytype = kd[kd_offset].key_data_type[0]; 86 k->key.keyvalue.length = kd[kd_offset].key_data_length[0]; 87 k->key.keyvalue.data = kd[kd_offset].key_data_contents[0]; 88 89 if(kd[kd_offset].key_data_ver == 2) { 90 memset(s, 0, sizeof (*s)); 91 s->type = kd[kd_offset].key_data_type[1]; 92 s->salt.length = kd[kd_offset].key_data_length[1]; 93 s->salt.data = kd[kd_offset].key_data_contents[1]; 94 k->salt = s; 95 } 96 } 97 98 /* 99 * Set the keys of `ent' to (`n_key_data', `key_data') 100 */ 101 102 kadm5_ret_t 103 _kadm5_set_keys2(kadm5_server_context *context, 104 hdb_entry *ent, 105 int16_t n_key_data, 106 krb5_key_data *key_data) 107 { 108 krb5_error_code ret; 109 size_t i, k; 110 HDB_extension ext; 111 HDB_extension *extp = NULL; 112 HDB_Ext_KeySet *hist_keys = &ext.data.u.hist_keys; 113 Key key; 114 Salt salt; 115 Keys keys; 116 hdb_keyset hkset; 117 krb5_kvno kvno = -1; 118 int one_key_set = 1; 119 int replace_hist_keys = 0; 120 121 if (n_key_data == 0) { 122 /* Clear all keys! */ 123 ret = hdb_clear_extension(context->context, ent, 124 choice_HDB_extension_data_hist_keys); 125 if (ret) 126 return ret; 127 free_Keys(&ent->keys); 128 return 0; 129 } 130 131 memset(&keys, 0, sizeof (keys)); 132 memset(&hkset, 0, sizeof (hkset)); /* set set_time */ 133 memset(&ext, 0, sizeof (ext)); 134 ext.mandatory = FALSE; 135 ext.data.element = choice_HDB_extension_data_hist_keys; 136 memset(hist_keys, 0, sizeof (*hist_keys)); 137 138 for (i = 0; i < n_key_data; i++) { 139 if (kvno != -1 && kvno != key_data[i].key_data_kvno) { 140 one_key_set = 0; 141 break; 142 } 143 kvno = key_data[i].key_data_kvno; 144 } 145 if (one_key_set) { 146 /* 147 * If we're updating KADM5_KEY_DATA with a single keyset then we 148 * assume we must be setting the principal's kvno as well! 149 * 150 * Just have to be careful about old clients that might have 151 * sent 0 as the kvno... This may seem ugly, but it's the price 152 * of backwards compatibility with pre-multi-kvno kadmin clients 153 * (besides, who's to say that updating KADM5_KEY_DATA requires 154 * updating the entry's kvno?) 155 * 156 * Note that we do nothing special for the case where multiple 157 * keysets are given but the entry's kvno is not set and not in 158 * the given set of keysets. If this happens we'll just update 159 * the key history only and leave the current keyset alone. 160 */ 161 if (kvno == 0) { 162 /* Force kvno to 1 if it was 0; (ank would do this anyways) */ 163 if (ent->kvno == 0) 164 ent->kvno = 1; 165 /* Below we need key_data[*].kvno to be reasonable */ 166 for (i = 0; i < n_key_data; i++) 167 key_data[i].key_data_kvno = ent->kvno; 168 } else { 169 /* 170 * Or force the entry's kvno to match the one from the new, 171 * singular keyset 172 */ 173 ent->kvno = kvno; 174 } 175 } 176 177 for (i = 0; i < n_key_data; i++) { 178 if (key_data[i].key_data_kvno == ent->kvno) { 179 /* A current key; add to current key set */ 180 setup_Key(&key, &salt, key_data, i); 181 ret = add_Keys(&keys, &key); 182 continue; 183 } 184 185 /* 186 * This kvno is historical. Build an hdb_keyset for keys of 187 * this enctype and add them to the new key history. 188 */ 189 for (k = 0; k < hist_keys->len; k++) { 190 if (hist_keys->val[k].kvno == key_data[i].key_data_kvno) 191 break; 192 } 193 if (hist_keys->len > k && 194 hist_keys->val[k].kvno == key_data[i].key_data_kvno) 195 /* We've added all keys of this kvno already (see below) */ 196 continue; 197 198 memset(&hkset, 0, sizeof (hkset)); /* set set_time */ 199 hkset.kvno = key_data[i].key_data_kvno; 200 for (k = 0; k < n_key_data; k++) { 201 /* Find all keys of this kvno and add them to the new keyset */ 202 if (key_data[k].key_data_kvno != hkset.kvno) 203 continue; 204 205 setup_Key(&key, &salt, key_data, k); 206 ret = add_Keys(&hkset.keys, &key); 207 if (ret) { 208 free_hdb_keyset(&hkset); 209 goto out; 210 } 211 } 212 ret = add_HDB_Ext_KeySet(hist_keys, &hkset); 213 free_hdb_keyset(&hkset); 214 if (ret) 215 goto out; 216 replace_hist_keys = 1; 217 } 218 219 if (replace_hist_keys) 220 /* No key history given -> leave it alone */ 221 extp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); 222 if (extp != NULL) { 223 HDB_Ext_KeySet *old_hist_keys; 224 225 /* 226 * Try to keep the very useful set_time values from the old hist 227 * keys. kadm5 loses this info, so this heuristic is the best we 228 * can do. 229 */ 230 old_hist_keys = &extp->data.u.hist_keys; 231 for (i = 0; i < old_hist_keys->len; i++) { 232 if (old_hist_keys->val[i].set_time == NULL) 233 continue; 234 for (k = 0; k < hist_keys->len; k++) { 235 if (hist_keys->val[k].kvno != old_hist_keys->val[k].kvno) 236 continue; 237 hist_keys->val[k].set_time = old_hist_keys->val[k].set_time; 238 old_hist_keys->val[k].set_time = NULL; 239 } 240 } 241 } 242 243 if (replace_hist_keys) { 244 /* If hist keys not given in key_data then don't blow away hist_keys */ 245 ret = hdb_replace_extension(context->context, ent, &ext); 246 if (ret) 247 goto out; 248 } 249 250 /* 251 * A structure copy is more efficient here than this would be: 252 * 253 * copy_Keys(&keys, &ent->keys); 254 * free_Keys(&keys); 255 * 256 * Of course, the above hdb_replace_extension() is not at all efficient... 257 */ 258 free_HDB_extension(&ext); 259 free_Keys(&ent->keys); 260 free_hdb_keyset(&hkset); 261 ent->keys = keys; 262 hdb_entry_set_pw_change_time(context->context, ent, 0); 263 hdb_entry_clear_password(context->context, ent); 264 265 return 0; 266 267 out: 268 free_Keys(&keys); 269 free_HDB_extension(&ext); 270 return ret; 271 } 272 273 /* 274 * Set the keys of `ent' to `n_keys, keys' 275 */ 276 277 kadm5_ret_t 278 _kadm5_set_keys3(kadm5_server_context *context, 279 hdb_entry *ent, 280 int n_keys, 281 krb5_keyblock *keyblocks) 282 { 283 krb5_error_code ret; 284 int i; 285 unsigned len; 286 Key *keys; 287 288 len = n_keys; 289 keys = malloc (len * sizeof(*keys)); 290 if (keys == NULL && len != 0) 291 return ENOMEM; 292 293 _kadm5_init_keys (keys, len); 294 295 for(i = 0; i < n_keys; i++) { 296 keys[i].mkvno = NULL; 297 ret = krb5_copy_keyblock_contents (context->context, 298 &keyblocks[i], 299 &keys[i].key); 300 if(ret) 301 goto out; 302 keys[i].salt = NULL; 303 } 304 _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val); 305 ent->keys.len = len; 306 ent->keys.val = keys; 307 308 hdb_entry_set_pw_change_time(context->context, ent, 0); 309 hdb_entry_clear_password(context->context, ent); 310 311 return 0; 312 out: 313 _kadm5_free_keys (context->context, len, keys); 314 return ret; 315 } 316 317 /* 318 * 319 */ 320 321 static int 322 is_des_key_p(int keytype) 323 { 324 return keytype == ETYPE_DES_CBC_CRC || 325 keytype == ETYPE_DES_CBC_MD4 || 326 keytype == ETYPE_DES_CBC_MD5; 327 } 328 329 330 /* 331 * Set the keys of `ent' to random keys and return them in `n_keys' 332 * and `new_keys'. 333 */ 334 335 kadm5_ret_t 336 _kadm5_set_keys_randomly (kadm5_server_context *context, 337 hdb_entry *ent, 338 int n_ks_tuple, 339 krb5_key_salt_tuple *ks_tuple, 340 krb5_keyblock **new_keys, 341 int *n_keys) 342 { 343 krb5_keyblock *kblock = NULL; 344 kadm5_ret_t ret = 0; 345 int des_keyblock; 346 size_t i, num_keys; 347 Key *keys; 348 349 ret = hdb_generate_key_set(context->context, ent->principal, 350 ks_tuple, n_ks_tuple, &keys, &num_keys, 1); 351 if (ret) 352 return ret; 353 354 kblock = malloc(num_keys * sizeof(kblock[0])); 355 if (kblock == NULL) { 356 ret = ENOMEM; 357 _kadm5_free_keys (context->context, num_keys, keys); 358 return ret; 359 } 360 memset(kblock, 0, num_keys * sizeof(kblock[0])); 361 362 des_keyblock = -1; 363 for (i = 0; i < num_keys; i++) { 364 365 /* 366 * To make sure all des keys are the the same we generate only 367 * the first one and then copy key to all other des keys. 368 */ 369 370 if (des_keyblock != -1 && is_des_key_p(keys[i].key.keytype)) { 371 ret = krb5_copy_keyblock_contents (context->context, 372 &kblock[des_keyblock], 373 &kblock[i]); 374 if (ret) 375 goto out; 376 kblock[i].keytype = keys[i].key.keytype; 377 } else { 378 ret = krb5_generate_random_keyblock (context->context, 379 keys[i].key.keytype, 380 &kblock[i]); 381 if (ret) 382 goto out; 383 384 if (is_des_key_p(keys[i].key.keytype)) 385 des_keyblock = i; 386 } 387 388 ret = krb5_copy_keyblock_contents (context->context, 389 &kblock[i], 390 &keys[i].key); 391 if (ret) 392 goto out; 393 } 394 395 out: 396 if(ret) { 397 for (i = 0; i < num_keys; ++i) 398 krb5_free_keyblock_contents (context->context, &kblock[i]); 399 free(kblock); 400 _kadm5_free_keys (context->context, num_keys, keys); 401 return ret; 402 } 403 404 _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val); 405 ent->keys.val = keys; 406 ent->keys.len = num_keys; 407 if (n_keys && new_keys) { 408 *new_keys = kblock; 409 *n_keys = num_keys; 410 } else { 411 free(kblock); 412 } 413 414 hdb_entry_set_pw_change_time(context->context, ent, 0); 415 hdb_entry_clear_password(context->context, ent); 416 417 return 0; 418 } 419