4 * Copyright 1995 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. M.I.T. makes no representations about the suitability of
20 * this software for any purpose. It is provided "as is" without express
21 * or implied warranty.
31 get_key_data_kvno(context, count, data)
37 /* Find last key version number */
38 for (kvno = i = 0; i < count; i++) {
39 if (kvno < data[i].key_data_kvno) {
40 kvno = data[i].key_data_kvno;
47 cleanup_key_data(context, count, data)
54 for (i = 0; i < count; i++) {
55 for (j = 0; j < data[i].key_data_ver; j++) {
56 if (data[i].key_data_length[j]) {
57 free(data[i].key_data_contents[j]);
64 * Currently we can only generate random keys for preinitialized
65 * krb5_encrypt_block with a seed. This is bogus but currently
66 * necessary to insure that we don't generate two keys with the
69 static krb5_error_code
70 add_key_rnd(context, master_eblock, ks_tuple, ks_tuple_count, db_entry, kvno)
72 krb5_encrypt_block * master_eblock;
73 krb5_key_salt_tuple * ks_tuple;
75 krb5_db_entry * db_entry;
78 krb5_principal krbtgt_princ;
79 krb5_keyblock krbtgt_keyblock, * key;
80 krb5_pointer krbtgt_seed;
81 krb5_encrypt_block krbtgt_eblock;
82 krb5_db_entry krbtgt_entry;
83 krb5_boolean more, found;
84 int max_kvno, one, i, j;
85 krb5_error_code retval;
87 memset(&krbtgt_keyblock, 0, sizeof(krbtgt_keyblock));
88 retval = krb5_build_principal_ext(context, &krbtgt_princ,
89 db_entry->princ->realm.length,
90 db_entry->princ->realm.data,
93 db_entry->princ->realm.length,
94 db_entry->princ->realm.data,
99 /* Get tgt from database */
100 retval = krb5_db_get_principal(context, krbtgt_princ, &krbtgt_entry,
102 krb5_free_principal(context, krbtgt_princ); /* don't need it anymore */
105 if ((one > 1) || (more)) {
106 krb5_db_free_principal(context, &krbtgt_entry, one);
107 return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
110 return KRB5_KDB_NOENTRY;
113 for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) {
114 if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) {
115 max_kvno = krbtgt_entry.key_data[j].key_data_kvno;
119 for (i = 0; i < ks_tuple_count; i++) {
121 * We could use krb5_keysalt_iterate to replace this loop, or use
122 * krb5_keysalt_is_present for the loop below, but we want to avoid
123 * circular library dependencies.
126 for (j = 0; j < i; j++) {
127 if (ks_tuple[j].ks_keytype == ks_tuple[i].ks_keytype) {
134 if (retval = krb5_dbe_create_key_data(context, db_entry))
135 goto add_key_rnd_err;
137 for (j = 0; j < krbtgt_entry.n_key_data; j++) {
138 if ((krbtgt_entry.key_data[j].key_data_kvno == max_kvno) &&
139 (krbtgt_entry.key_data[j].key_data_type[0] ==
140 ks_tuple[i].ks_keytype)) {
145 if (j == krbtgt_entry.n_key_data) {
146 retval = KRB5_KDB_BAD_KEYTYPE;
147 goto add_key_rnd_err;
151 if (retval = krb5_dbekd_decrypt_key_data(context, master_eblock,
152 &krbtgt_entry.key_data[j],
153 &krbtgt_keyblock, NULL)) {
154 goto add_key_rnd_err;
158 krb5_use_keytype(context, &krbtgt_eblock, ks_tuple[i].ks_keytype);
159 if (retval = krb5_process_key(context,&krbtgt_eblock,&krbtgt_keyblock)){
160 goto add_key_rnd_err;
163 /* Init random generator */
164 if (retval = krb5_init_random_key(context, &krbtgt_eblock,
165 &krbtgt_keyblock, &krbtgt_seed)) {
166 krb5_finish_key(context, &krbtgt_eblock);
167 goto add_key_rnd_err;
170 if (retval = krb5_random_key(context,&krbtgt_eblock,krbtgt_seed,&key)) {
171 krb5_finish_random_key(context, &krbtgt_eblock, &krbtgt_seed);
172 krb5_finish_key(context, &krbtgt_eblock);
173 goto add_key_rnd_err;
176 krb5_finish_random_key(context, &krbtgt_eblock, &krbtgt_seed);
177 krb5_finish_key(context, &krbtgt_eblock);
179 if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock,
181 &db_entry->key_data[db_entry->n_key_data-1])) {
182 krb5_free_keyblock(context, key);
183 goto add_key_rnd_err;
186 /* Finish random key */
187 krb5_free_keyblock(context, key);
191 krb5_db_free_principal(context, &krbtgt_entry, one);
192 if (krbtgt_keyblock.contents && krbtgt_keyblock.length) {
193 memset(krbtgt_keyblock.contents, 0, krbtgt_keyblock.length);
194 krb5_xfree(krbtgt_keyblock.contents);
200 * Change random key for a krb5_db_entry
201 * Assumes the max kvno
203 * As a side effect all old keys are nuked.
206 krb5_dbe_crk(context, master_eblock, ks_tuple, ks_tuple_count, db_entry)
207 krb5_context context;
208 krb5_encrypt_block * master_eblock;
209 krb5_key_salt_tuple * ks_tuple;
211 krb5_db_entry * db_entry;
214 krb5_key_data * key_data;
215 krb5_error_code retval;
218 /* First save the old keydata */
219 kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
220 key_data_count = db_entry->n_key_data;
221 key_data = db_entry->key_data;
222 db_entry->key_data = NULL;
223 db_entry->n_key_data = 0;
225 if (retval = add_key_rnd(context, master_eblock, ks_tuple,
226 ks_tuple_count, db_entry, kvno)) {
227 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
228 db_entry->n_key_data = key_data_count;
229 db_entry->key_data = key_data;
231 cleanup_key_data(context, key_data_count, key_data);
237 * Add random key for a krb5_db_entry
238 * Assumes the max kvno
240 * As a side effect all old keys older than the max kvno are nuked.
243 krb5_dbe_ark(context, master_eblock, ks_tuple, ks_tuple_count, db_entry)
244 krb5_context context;
245 krb5_encrypt_block * master_eblock;
246 krb5_key_salt_tuple * ks_tuple;
248 krb5_db_entry * db_entry;
251 krb5_key_data * key_data;
252 krb5_error_code retval;
256 /* First save the old keydata */
257 kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
258 key_data_count = db_entry->n_key_data;
259 key_data = db_entry->key_data;
260 db_entry->key_data = NULL;
261 db_entry->n_key_data = 0;
263 if (retval = add_key_rnd(context, master_eblock, ks_tuple,
264 ks_tuple_count, db_entry, kvno)) {
265 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
266 db_entry->n_key_data = key_data_count;
267 db_entry->key_data = key_data;
269 /* Copy keys with key_data_kvno = kvno */
270 for (i = 0; i < key_data_count; i++) {
271 if (key_data[i].key_data_kvno = kvno) {
272 if (retval = krb5_dbe_create_key_data(context, db_entry)) {
273 cleanup_key_data(context, db_entry->n_key_data,
277 /* We should decrypt/re-encrypt the data to use the same mkvno*/
278 db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
279 memset(&key_data[i], 0, sizeof(krb5_key_data));
282 cleanup_key_data(context, key_data_count, key_data);
288 * Add key_data for a krb5_db_entry
289 * If passwd is NULL the assumes that the caller wants a random password.
291 static krb5_error_code
292 add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, passwd,
294 krb5_context context;
295 krb5_encrypt_block * master_eblock;
296 krb5_key_salt_tuple * ks_tuple;
299 krb5_db_entry * db_entry;
302 krb5_error_code retval;
303 krb5_encrypt_block key_eblock;
304 krb5_keysalt key_salt;
310 for (i = 0; i < ks_tuple_count; i++) {
312 * We could use krb5_keysalt_iterate to replace this loop, or use
313 * krb5_keysalt_is_present for the loop below, but we want to avoid
314 * circular library dependencies.
317 for (j = 0; j < i; j++) {
318 if ((ks_tuple[j].ks_keytype == ks_tuple[i].ks_keytype) &&
319 (ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype)) {
326 krb5_use_keytype(context, &key_eblock, ks_tuple[i].ks_keytype);
327 if (retval = krb5_dbe_create_key_data(context, db_entry))
330 /* Convert password string to key using appropriate salt */
331 switch (key_salt.type = ks_tuple[i].ks_salttype) {
332 case KRB5_KDB_SALTTYPE_ONLYREALM: {
333 krb5_data * saltdata;
334 if (retval = krb5_copy_data(context, krb5_princ_realm(context,
335 db_entry->princ), &saltdata))
338 key_salt.data = *saltdata;
339 krb5_xfree(saltdata);
342 case KRB5_KDB_SALTTYPE_NOREALM:
343 if (retval=krb5_principal2salt_norealm(context, db_entry->princ,
347 case KRB5_KDB_SALTTYPE_NORMAL:
348 if (retval = krb5_principal2salt(context, db_entry->princ,
352 case KRB5_KDB_SALTTYPE_V4:
353 key_salt.data.length = 0;
354 key_salt.data.data = 0;
357 return(KRB5_KDB_BAD_SALTTYPE);
361 pwd.length = strlen(passwd);
362 if (retval = krb5_string_to_key(context, &key_eblock,
363 ks_tuple[i].ks_keytype, &key,
364 &pwd, &key_salt.data))
367 if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock, &key,
368 (const krb5_keysalt *)&key_salt,
369 kvno + 1, &db_entry->key_data[db_entry->n_key_data-1])) {
370 krb5_xfree(key.contents);
373 krb5_xfree(key.contents);
379 * Change password for a krb5_db_entry
380 * Assumes the max kvno
382 * As a side effect all old keys are nuked.
385 krb5_dbe_cpw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry)
386 krb5_context context;
387 krb5_encrypt_block * master_eblock;
388 krb5_key_salt_tuple * ks_tuple;
391 krb5_db_entry * db_entry;
394 krb5_key_data * key_data;
395 krb5_error_code retval;
398 /* First save the old keydata */
399 kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
400 key_data_count = db_entry->n_key_data;
401 key_data = db_entry->key_data;
402 db_entry->key_data = NULL;
403 db_entry->n_key_data = 0;
405 if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count,
406 passwd, db_entry, kvno)) {
407 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
408 db_entry->n_key_data = key_data_count;
409 db_entry->key_data = key_data;
411 cleanup_key_data(context, key_data_count, key_data);
417 * Add password for a krb5_db_entry
418 * Assumes the max kvno
420 * As a side effect all old keys older than the max kvno are nuked.
423 krb5_dbe_apw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry)
424 krb5_context context;
425 krb5_encrypt_block * master_eblock;
426 krb5_key_salt_tuple * ks_tuple;
429 krb5_db_entry * db_entry;
432 krb5_key_data * key_data;
433 krb5_error_code retval;
437 /* First save the old keydata */
438 kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
439 key_data_count = db_entry->n_key_data;
440 key_data = db_entry->key_data;
441 db_entry->key_data = NULL;
442 db_entry->n_key_data = 0;
444 if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count,
445 passwd, db_entry, kvno)) {
446 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
447 db_entry->n_key_data = key_data_count;
448 db_entry->key_data = key_data;
450 /* Copy keys with key_data_kvno = kvno */
451 for (i = 0; i < key_data_count; i++) {
452 if (key_data[i].key_data_kvno = kvno) {
453 if (retval = krb5_dbe_create_key_data(context, db_entry)) {
454 cleanup_key_data(context, db_entry->n_key_data,
458 /* We should decrypt/re-encrypt the data to use the same mkvno*/
459 db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
460 memset(&key_data[i], 0, sizeof(krb5_key_data));
463 cleanup_key_data(context, key_data_count, key_data);