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_data krbtgt_princ_entries[] = {
79 { 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME },
82 krb5_principal_data krbtgt_princ = {
84 {0, 0, 0}, /* krb5_data realm */
85 (krb5_data *) NULL, /* krb5_data *data */
87 KRB5_NT_SRV_INST /* int type */
89 krb5_keyblock krbtgt_keyblock, * key;
90 krb5_pointer krbtgt_seed;
91 krb5_encrypt_block krbtgt_eblock;
92 krb5_db_entry krbtgt_entry;
94 int max_kvno, one, i, j;
95 krb5_error_code retval;
97 krbtgt_princ.data = krbtgt_princ_entries;
98 krb5_princ_set_realm_length(context, &krbtgt_princ,
99 db_entry->princ->realm.length);
100 krb5_princ_set_realm_data(context, &krbtgt_princ,
101 db_entry->princ->realm.data);
102 krb5_princ_component(context, &krbtgt_princ, 1)->length =
103 db_entry->princ->realm.length;
104 krb5_princ_component(context, &krbtgt_princ, 1)->data =
105 db_entry->princ->realm.data;
107 /* Get tgt from database */
108 if (retval = krb5_db_get_principal(context, &krbtgt_princ, &krbtgt_entry,
111 if ((one > 1) || (more)) {
112 krb5_db_free_principal(context, &krbtgt_entry, one);
113 return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
116 return KRB5_KDB_NOENTRY;
119 for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) {
120 if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) {
121 max_kvno = krbtgt_entry.key_data[j].key_data_kvno;
125 for (i = 0; i < ks_tuple_count; i++) {
126 if (retval = krb5_dbe_create_key_data(context, db_entry))
127 goto add_key_rnd_err;
129 for (j = 0; j < krbtgt_entry.n_key_data; j++) {
130 if ((krbtgt_entry.key_data[j].key_data_kvno == max_kvno) &&
131 (krbtgt_entry.key_data[j].key_data_type[0] ==
132 ks_tuple[i].ks_keytype)) {
137 if (j == krbtgt_entry.n_key_data) {
138 retval = KRB5_KDB_BAD_KEYTYPE;
139 goto add_key_rnd_err;
143 if (retval = krb5_dbekd_decrypt_key_data(context, master_eblock,
144 &krbtgt_entry.key_data[j],
145 &krbtgt_keyblock, NULL)) {
146 goto add_key_rnd_err;
150 krb5_use_keytype(context, &krbtgt_eblock, ks_tuple[i].ks_keytype);
151 if (retval = krb5_process_key(context,&krbtgt_eblock,&krbtgt_keyblock)){
152 goto add_key_rnd_err;
155 /* Init random generator */
156 if (retval = krb5_init_random_key(context, &krbtgt_eblock,
157 &krbtgt_keyblock, &krbtgt_seed)) {
158 krb5_finish_key(context, &krbtgt_eblock);
159 goto add_key_rnd_err;
162 if (retval = krb5_random_key(context,&krbtgt_eblock,krbtgt_seed,&key)) {
163 krb5_finish_random_key(context, &krbtgt_eblock, &krbtgt_seed);
164 krb5_finish_key(context, &krbtgt_eblock);
165 goto add_key_rnd_err;
168 krb5_finish_random_key(context, &krbtgt_eblock, &krbtgt_seed);
169 krb5_finish_key(context, &krbtgt_eblock);
171 if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock,
173 db_entry->key_data)) {
174 krb5_free_keyblock(context, key);
175 goto add_key_rnd_err;
178 /* Finish random key */
179 krb5_free_keyblock(context, key);
183 krb5_db_free_principal(context, &krbtgt_entry, one);
188 * Change random key for a krb5_db_entry
189 * Assumes the max kvno
191 * As a side effect all old keys are nuked.
194 krb5_dbe_crk(context, master_eblock, ks_tuple, ks_tuple_count, db_entry)
195 krb5_context context;
196 krb5_encrypt_block * master_eblock;
197 krb5_key_salt_tuple * ks_tuple;
199 krb5_db_entry * db_entry;
202 krb5_key_data * key_data;
203 krb5_error_code retval;
206 /* First save the old keydata */
207 kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
208 key_data_count = db_entry->n_key_data;
209 key_data = db_entry->key_data;
210 db_entry->key_data = NULL;
211 db_entry->n_key_data = 0;
213 if (retval = add_key_rnd(context, master_eblock, ks_tuple,
214 ks_tuple_count, db_entry, kvno)) {
215 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
216 db_entry->n_key_data = key_data_count;
217 db_entry->key_data = key_data;
219 cleanup_key_data(context, key_data_count, key_data);
225 * Add random key for a krb5_db_entry
226 * Assumes the max kvno
228 * As a side effect all old keys older than the max kvno are nuked.
231 krb5_dbe_ark(context, master_eblock, ks_tuple, ks_tuple_count, db_entry)
232 krb5_context context;
233 krb5_encrypt_block * master_eblock;
234 krb5_key_salt_tuple * ks_tuple;
236 krb5_db_entry * db_entry;
239 krb5_key_data * key_data;
240 krb5_error_code retval;
244 /* First save the old keydata */
245 kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
246 key_data_count = db_entry->n_key_data;
247 key_data = db_entry->key_data;
248 db_entry->key_data = NULL;
249 db_entry->n_key_data = 0;
251 if (retval = add_key_rnd(context, master_eblock, ks_tuple,
252 ks_tuple_count, db_entry, kvno)) {
253 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
254 db_entry->n_key_data = key_data_count;
255 db_entry->key_data = key_data;
257 /* Copy keys with key_data_kvno = kvno */
258 for (i = 0; i < key_data_count; i++) {
259 if (key_data[i].key_data_kvno = kvno) {
260 if (retval = krb5_dbe_create_key_data(context, db_entry)) {
261 cleanup_key_data(context, db_entry->n_key_data,
265 /* We should decrypt/re-encrypt the data to use the same mkvno*/
266 db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
267 memset(&key_data[i], 0, sizeof(krb5_key_data));
270 cleanup_key_data(context, key_data_count, key_data);
276 * Add key_data for a krb5_db_entry
277 * If passwd is NULL the assumes that the caller wants a random password.
279 static krb5_error_code
280 add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, passwd,
282 krb5_context context;
283 krb5_encrypt_block * master_eblock;
284 krb5_key_salt_tuple * ks_tuple;
287 krb5_db_entry * db_entry;
290 krb5_error_code retval;
291 krb5_encrypt_block key_eblock;
292 krb5_keysalt key_salt;
297 for (i = 0; i < ks_tuple_count; i++) {
298 krb5_use_keytype(context, &key_eblock, ks_tuple[i].ks_keytype);
299 if (retval = krb5_dbe_create_key_data(context, db_entry))
302 /* Convert password string to key using appropriate salt */
303 switch (key_salt.type = ks_tuple[i].ks_salttype) {
304 case KRB5_KDB_SALTTYPE_ONLYREALM: {
305 krb5_data * saltdata;
306 if (retval = krb5_copy_data(context, krb5_princ_realm(context,
307 db_entry->princ), &saltdata))
310 key_salt.data = *saltdata;
311 krb5_xfree(saltdata);
313 case KRB5_KDB_SALTTYPE_NOREALM:
314 if (retval=krb5_principal2salt_norealm(context, db_entry->princ,
318 case KRB5_KDB_SALTTYPE_NORMAL:
319 if (retval = krb5_principal2salt(context, db_entry->princ,
323 case KRB5_KDB_SALTTYPE_V4:
324 key_salt.data.length = 0;
325 key_salt.data.data = 0;
328 return(KRB5_KDB_BAD_SALTTYPE);
332 pwd.length = strlen(passwd);
333 if (retval = krb5_string_to_key(context, &key_eblock,
334 ks_tuple[i].ks_keytype, &key,
335 &pwd, &key_salt.data))
338 if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock, &key,
339 key_salt.type ? (const krb5_keysalt *)&key_salt : NULL,
340 kvno + 1, &db_entry->key_data[i])) {
341 krb5_xfree(key.contents);
344 krb5_xfree(key.contents);
350 * Change password for a krb5_db_entry
351 * Assumes the max kvno
353 * As a side effect all old keys are nuked.
356 krb5_dbe_cpw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry)
357 krb5_context context;
358 krb5_encrypt_block * master_eblock;
359 krb5_key_salt_tuple * ks_tuple;
362 krb5_db_entry * db_entry;
365 krb5_key_data * key_data;
366 krb5_error_code retval;
369 /* First save the old keydata */
370 kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
371 key_data_count = db_entry->n_key_data;
372 key_data = db_entry->key_data;
373 db_entry->key_data = NULL;
374 db_entry->n_key_data = 0;
376 if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count,
377 passwd, db_entry, kvno)) {
378 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
379 db_entry->n_key_data = key_data_count;
380 db_entry->key_data = key_data;
382 cleanup_key_data(context, key_data_count, key_data);
388 * Add password for a krb5_db_entry
389 * Assumes the max kvno
391 * As a side effect all old keys older than the max kvno are nuked.
394 krb5_dbe_apw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry)
395 krb5_context context;
396 krb5_encrypt_block * master_eblock;
397 krb5_key_salt_tuple * ks_tuple;
400 krb5_db_entry * db_entry;
403 krb5_key_data * key_data;
404 krb5_error_code retval;
408 /* First save the old keydata */
409 kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
410 key_data_count = db_entry->n_key_data;
411 key_data = db_entry->key_data;
412 db_entry->key_data = NULL;
413 db_entry->n_key_data = 0;
415 if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count,
416 passwd, db_entry, kvno)) {
417 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
418 db_entry->n_key_data = key_data_count;
419 db_entry->key_data = key_data;
421 /* Copy keys with key_data_kvno = kvno */
422 for (i = 0; i < key_data_count; i++) {
423 if (key_data[i].key_data_kvno = kvno) {
424 if (retval = krb5_dbe_create_key_data(context, db_entry)) {
425 cleanup_key_data(context, db_entry->n_key_data,
429 /* We should decrypt/re-encrypt the data to use the same mkvno*/
430 db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
431 memset(&key_data[i], 0, sizeof(krb5_key_data));
434 cleanup_key_data(context, key_data_count, key_data);