xref: /freebsd/crypto/krb5/src/lib/kdb/kdb_cpw.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* lib/kdb/kdb_cpw.c */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright 1995, 2009, 2014 by the Massachusetts Institute of Technology.
5*7f2fe78bSCy Schubert  * All Rights Reserved.
6*7f2fe78bSCy Schubert  *
7*7f2fe78bSCy Schubert  * Export of this software from the United States of America may
8*7f2fe78bSCy Schubert  *   require a specific license from the United States Government.
9*7f2fe78bSCy Schubert  *   It is the responsibility of any person or organization contemplating
10*7f2fe78bSCy Schubert  *   export to obtain such a license before exporting.
11*7f2fe78bSCy Schubert  *
12*7f2fe78bSCy Schubert  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*7f2fe78bSCy Schubert  * distribute this software and its documentation for any purpose and
14*7f2fe78bSCy Schubert  * without fee is hereby granted, provided that the above copyright
15*7f2fe78bSCy Schubert  * notice appear in all copies and that both that copyright notice and
16*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation, and that
17*7f2fe78bSCy Schubert  * the name of M.I.T. not be used in advertising or publicity pertaining
18*7f2fe78bSCy Schubert  * to distribution of the software without specific, written prior
19*7f2fe78bSCy Schubert  * permission.  Furthermore if you modify this software you must label
20*7f2fe78bSCy Schubert  * your software as modified software and not distribute it in such a
21*7f2fe78bSCy Schubert  * fashion that it might be confused with the original M.I.T. software.
22*7f2fe78bSCy Schubert  * M.I.T. makes no representations about the suitability of
23*7f2fe78bSCy Schubert  * this software for any purpose.  It is provided "as is" without express
24*7f2fe78bSCy Schubert  * or implied warranty.
25*7f2fe78bSCy Schubert  */
26*7f2fe78bSCy Schubert /*
27*7f2fe78bSCy Schubert  * Copyright (C) 1998 by the FundsXpress, INC.
28*7f2fe78bSCy Schubert  *
29*7f2fe78bSCy Schubert  * All rights reserved.
30*7f2fe78bSCy Schubert  *
31*7f2fe78bSCy Schubert  * Export of this software from the United States of America may require
32*7f2fe78bSCy Schubert  * a specific license from the United States Government.  It is the
33*7f2fe78bSCy Schubert  * responsibility of any person or organization contemplating export to
34*7f2fe78bSCy Schubert  * obtain such a license before exporting.
35*7f2fe78bSCy Schubert  *
36*7f2fe78bSCy Schubert  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
37*7f2fe78bSCy Schubert  * distribute this software and its documentation for any purpose and
38*7f2fe78bSCy Schubert  * without fee is hereby granted, provided that the above copyright
39*7f2fe78bSCy Schubert  * notice appear in all copies and that both that copyright notice and
40*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation, and that
41*7f2fe78bSCy Schubert  * the name of FundsXpress. not be used in advertising or publicity pertaining
42*7f2fe78bSCy Schubert  * to distribution of the software without specific, written prior
43*7f2fe78bSCy Schubert  * permission.  FundsXpress makes no representations about the suitability of
44*7f2fe78bSCy Schubert  * this software for any purpose.  It is provided "as is" without express
45*7f2fe78bSCy Schubert  * or implied warranty.
46*7f2fe78bSCy Schubert  *
47*7f2fe78bSCy Schubert  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
48*7f2fe78bSCy Schubert  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
49*7f2fe78bSCy Schubert  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
50*7f2fe78bSCy Schubert  */
51*7f2fe78bSCy Schubert 
52*7f2fe78bSCy Schubert #include "k5-int.h"
53*7f2fe78bSCy Schubert #include "kdb.h"
54*7f2fe78bSCy Schubert #include <stdio.h>
55*7f2fe78bSCy Schubert #include <errno.h>
56*7f2fe78bSCy Schubert 
57*7f2fe78bSCy Schubert enum save { DISCARD_ALL, KEEP_LAST_KVNO, KEEP_ALL };
58*7f2fe78bSCy Schubert 
59*7f2fe78bSCy Schubert int
krb5_db_get_key_data_kvno(context,count,data)60*7f2fe78bSCy Schubert krb5_db_get_key_data_kvno(context, count, data)
61*7f2fe78bSCy Schubert     krb5_context          context;
62*7f2fe78bSCy Schubert     int                   count;
63*7f2fe78bSCy Schubert     krb5_key_data       * data;
64*7f2fe78bSCy Schubert {
65*7f2fe78bSCy Schubert     int i, kvno;
66*7f2fe78bSCy Schubert     /* Find last key version number */
67*7f2fe78bSCy Schubert     for (kvno = i = 0; i < count; i++) {
68*7f2fe78bSCy Schubert         if (kvno < data[i].key_data_kvno) {
69*7f2fe78bSCy Schubert             kvno = data[i].key_data_kvno;
70*7f2fe78bSCy Schubert         }
71*7f2fe78bSCy Schubert     }
72*7f2fe78bSCy Schubert     return(kvno);
73*7f2fe78bSCy Schubert }
74*7f2fe78bSCy Schubert 
75*7f2fe78bSCy Schubert static void
cleanup_key_data(context,count,data)76*7f2fe78bSCy Schubert cleanup_key_data(context, count, data)
77*7f2fe78bSCy Schubert     krb5_context          context;
78*7f2fe78bSCy Schubert     int                   count;
79*7f2fe78bSCy Schubert     krb5_key_data       * data;
80*7f2fe78bSCy Schubert {
81*7f2fe78bSCy Schubert     int i;
82*7f2fe78bSCy Schubert 
83*7f2fe78bSCy Schubert     /* If data is NULL, count is always 0 */
84*7f2fe78bSCy Schubert     if (data == NULL) return;
85*7f2fe78bSCy Schubert 
86*7f2fe78bSCy Schubert     for (i = 0; i < count; i++)
87*7f2fe78bSCy Schubert         krb5_dbe_free_key_data_contents(context, &data[i]);
88*7f2fe78bSCy Schubert     free(data);
89*7f2fe78bSCy Schubert }
90*7f2fe78bSCy Schubert 
91*7f2fe78bSCy Schubert /* Transfer key data from old_kd to new_kd, making sure that new_kd is
92*7f2fe78bSCy Schubert  * encrypted with mkey.  May steal from old_kd and zero it out. */
93*7f2fe78bSCy Schubert static krb5_error_code
preserve_one_old_key(krb5_context context,krb5_keyblock * mkey,krb5_db_entry * dbent,krb5_key_data * old_kd,krb5_key_data * new_kd)94*7f2fe78bSCy Schubert preserve_one_old_key(krb5_context context, krb5_keyblock *mkey,
95*7f2fe78bSCy Schubert                      krb5_db_entry *dbent, krb5_key_data *old_kd,
96*7f2fe78bSCy Schubert                      krb5_key_data *new_kd)
97*7f2fe78bSCy Schubert {
98*7f2fe78bSCy Schubert     krb5_error_code ret;
99*7f2fe78bSCy Schubert     krb5_keyblock kb;
100*7f2fe78bSCy Schubert     krb5_keysalt salt;
101*7f2fe78bSCy Schubert 
102*7f2fe78bSCy Schubert     memset(new_kd, 0, sizeof(*new_kd));
103*7f2fe78bSCy Schubert 
104*7f2fe78bSCy Schubert     ret = krb5_dbe_decrypt_key_data(context, mkey, old_kd, &kb, NULL);
105*7f2fe78bSCy Schubert     if (ret == 0) {
106*7f2fe78bSCy Schubert         /* old_kd is already encrypted in mkey, so just move it. */
107*7f2fe78bSCy Schubert         *new_kd = *old_kd;
108*7f2fe78bSCy Schubert         memset(old_kd, 0, sizeof(*old_kd));
109*7f2fe78bSCy Schubert         krb5_free_keyblock_contents(context, &kb);
110*7f2fe78bSCy Schubert         return 0;
111*7f2fe78bSCy Schubert     }
112*7f2fe78bSCy Schubert 
113*7f2fe78bSCy Schubert     /* Decrypt and re-encrypt old_kd using mkey. */
114*7f2fe78bSCy Schubert     ret = krb5_dbe_decrypt_key_data(context, NULL, old_kd, &kb, &salt);
115*7f2fe78bSCy Schubert     if (ret)
116*7f2fe78bSCy Schubert         return ret;
117*7f2fe78bSCy Schubert     ret = krb5_dbe_encrypt_key_data(context, mkey, &kb, &salt,
118*7f2fe78bSCy Schubert                                     old_kd->key_data_kvno, new_kd);
119*7f2fe78bSCy Schubert     krb5_free_keyblock_contents(context, &kb);
120*7f2fe78bSCy Schubert     krb5_free_data_contents(context, &salt.data);
121*7f2fe78bSCy Schubert     return ret;
122*7f2fe78bSCy Schubert }
123*7f2fe78bSCy Schubert 
124*7f2fe78bSCy Schubert /*
125*7f2fe78bSCy Schubert  * Add key_data to dbent, making sure that each entry is encrypted in mkey.  If
126*7f2fe78bSCy Schubert  * kvno is non-zero, preserve only keys of that kvno.  May steal some elements
127*7f2fe78bSCy Schubert  * from key_data and zero them out.
128*7f2fe78bSCy Schubert  */
129*7f2fe78bSCy Schubert static krb5_error_code
preserve_old_keys(krb5_context context,krb5_keyblock * mkey,krb5_db_entry * dbent,int kvno,int n_key_data,krb5_key_data * key_data)130*7f2fe78bSCy Schubert preserve_old_keys(krb5_context context, krb5_keyblock *mkey,
131*7f2fe78bSCy Schubert                   krb5_db_entry *dbent, int kvno, int n_key_data,
132*7f2fe78bSCy Schubert                   krb5_key_data *key_data)
133*7f2fe78bSCy Schubert {
134*7f2fe78bSCy Schubert     krb5_error_code ret;
135*7f2fe78bSCy Schubert     int i;
136*7f2fe78bSCy Schubert 
137*7f2fe78bSCy Schubert     for (i = 0; i < n_key_data; i++) {
138*7f2fe78bSCy Schubert         if (kvno != 0 && key_data[i].key_data_kvno != kvno)
139*7f2fe78bSCy Schubert             continue;
140*7f2fe78bSCy Schubert         ret = krb5_dbe_create_key_data(context, dbent);
141*7f2fe78bSCy Schubert         if (ret)
142*7f2fe78bSCy Schubert             return ret;
143*7f2fe78bSCy Schubert         ret = preserve_one_old_key(context, mkey, dbent, &key_data[i],
144*7f2fe78bSCy Schubert                                    &dbent->key_data[dbent->n_key_data - 1]);
145*7f2fe78bSCy Schubert         if (ret)
146*7f2fe78bSCy Schubert             return ret;
147*7f2fe78bSCy Schubert     }
148*7f2fe78bSCy Schubert     return 0;
149*7f2fe78bSCy Schubert }
150*7f2fe78bSCy Schubert 
151*7f2fe78bSCy Schubert static krb5_error_code
add_key_rnd(context,master_key,ks_tuple,ks_tuple_count,db_entry,kvno)152*7f2fe78bSCy Schubert add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno)
153*7f2fe78bSCy Schubert     krb5_context          context;
154*7f2fe78bSCy Schubert     krb5_keyblock       * master_key;
155*7f2fe78bSCy Schubert     krb5_key_salt_tuple * ks_tuple;
156*7f2fe78bSCy Schubert     int                   ks_tuple_count;
157*7f2fe78bSCy Schubert     krb5_db_entry       * db_entry;
158*7f2fe78bSCy Schubert     int                   kvno;
159*7f2fe78bSCy Schubert {
160*7f2fe78bSCy Schubert     krb5_keyblock         key;
161*7f2fe78bSCy Schubert     int                   i, j;
162*7f2fe78bSCy Schubert     krb5_error_code       retval;
163*7f2fe78bSCy Schubert     krb5_key_data        *kd_slot;
164*7f2fe78bSCy Schubert 
165*7f2fe78bSCy Schubert     for (i = 0; i < ks_tuple_count; i++) {
166*7f2fe78bSCy Schubert         krb5_boolean similar;
167*7f2fe78bSCy Schubert 
168*7f2fe78bSCy Schubert         similar = 0;
169*7f2fe78bSCy Schubert 
170*7f2fe78bSCy Schubert         /*
171*7f2fe78bSCy Schubert          * We could use krb5_keysalt_iterate to replace this loop, or use
172*7f2fe78bSCy Schubert          * krb5_keysalt_is_present for the loop below, but we want to avoid
173*7f2fe78bSCy Schubert          * circular library dependencies.
174*7f2fe78bSCy Schubert          */
175*7f2fe78bSCy Schubert         for (j = 0; j < i; j++) {
176*7f2fe78bSCy Schubert             if ((retval = krb5_c_enctype_compare(context,
177*7f2fe78bSCy Schubert                                                  ks_tuple[i].ks_enctype,
178*7f2fe78bSCy Schubert                                                  ks_tuple[j].ks_enctype,
179*7f2fe78bSCy Schubert                                                  &similar)))
180*7f2fe78bSCy Schubert                 return(retval);
181*7f2fe78bSCy Schubert 
182*7f2fe78bSCy Schubert             if (similar)
183*7f2fe78bSCy Schubert                 break;
184*7f2fe78bSCy Schubert         }
185*7f2fe78bSCy Schubert 
186*7f2fe78bSCy Schubert         if (similar)
187*7f2fe78bSCy Schubert             continue;
188*7f2fe78bSCy Schubert 
189*7f2fe78bSCy Schubert         if ((retval = krb5_dbe_create_key_data(context, db_entry)))
190*7f2fe78bSCy Schubert             return retval;
191*7f2fe78bSCy Schubert         kd_slot = &db_entry->key_data[db_entry->n_key_data - 1];
192*7f2fe78bSCy Schubert 
193*7f2fe78bSCy Schubert         /* there used to be code here to extract the old key, and derive
194*7f2fe78bSCy Schubert            a new key from it.  Now that there's a unified prng, that isn't
195*7f2fe78bSCy Schubert            necessary. */
196*7f2fe78bSCy Schubert 
197*7f2fe78bSCy Schubert         /* make new key */
198*7f2fe78bSCy Schubert         if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype,
199*7f2fe78bSCy Schubert                                              &key)))
200*7f2fe78bSCy Schubert             return retval;
201*7f2fe78bSCy Schubert 
202*7f2fe78bSCy Schubert         retval = krb5_dbe_encrypt_key_data(context, master_key, &key, NULL,
203*7f2fe78bSCy Schubert                                            kvno, kd_slot);
204*7f2fe78bSCy Schubert 
205*7f2fe78bSCy Schubert         krb5_free_keyblock_contents(context, &key);
206*7f2fe78bSCy Schubert         if( retval )
207*7f2fe78bSCy Schubert             return retval;
208*7f2fe78bSCy Schubert     }
209*7f2fe78bSCy Schubert 
210*7f2fe78bSCy Schubert     return 0;
211*7f2fe78bSCy Schubert }
212*7f2fe78bSCy Schubert 
213*7f2fe78bSCy Schubert /* Construct a random explicit salt. */
214*7f2fe78bSCy Schubert static krb5_error_code
make_random_salt(krb5_context context,krb5_keysalt * salt_out)215*7f2fe78bSCy Schubert make_random_salt(krb5_context context, krb5_keysalt *salt_out)
216*7f2fe78bSCy Schubert {
217*7f2fe78bSCy Schubert     krb5_error_code retval;
218*7f2fe78bSCy Schubert     unsigned char rndbuf[8];
219*7f2fe78bSCy Schubert     krb5_data salt, rnd = make_data(rndbuf, sizeof(rndbuf));
220*7f2fe78bSCy Schubert     unsigned int i;
221*7f2fe78bSCy Schubert 
222*7f2fe78bSCy Schubert     /*
223*7f2fe78bSCy Schubert      * Salts are limited by RFC 4120 to 7-bit ASCII.  For ease of examination
224*7f2fe78bSCy Schubert      * and to avoid certain folding issues for older enctypes, we use printable
225*7f2fe78bSCy Schubert      * characters with four fixed bits and four random bits, encoding 64
226*7f2fe78bSCy Schubert      * psuedo-random bits into 16 bytes.
227*7f2fe78bSCy Schubert      */
228*7f2fe78bSCy Schubert     retval = krb5_c_random_make_octets(context, &rnd);
229*7f2fe78bSCy Schubert     if (retval)
230*7f2fe78bSCy Schubert         return retval;
231*7f2fe78bSCy Schubert     retval = alloc_data(&salt, sizeof(rndbuf) * 2);
232*7f2fe78bSCy Schubert     if (retval)
233*7f2fe78bSCy Schubert         return retval;
234*7f2fe78bSCy Schubert     for (i = 0; i < sizeof(rndbuf); i++) {
235*7f2fe78bSCy Schubert         salt.data[i * 2] = 0x40 | (rndbuf[i] >> 4);
236*7f2fe78bSCy Schubert         salt.data[i * 2 + 1] = 0x40 | (rndbuf[i] & 0xf);
237*7f2fe78bSCy Schubert     }
238*7f2fe78bSCy Schubert 
239*7f2fe78bSCy Schubert     salt_out->type = KRB5_KDB_SALTTYPE_SPECIAL;
240*7f2fe78bSCy Schubert     salt_out->data = salt;
241*7f2fe78bSCy Schubert     return 0;
242*7f2fe78bSCy Schubert }
243*7f2fe78bSCy Schubert 
244*7f2fe78bSCy Schubert /*
245*7f2fe78bSCy Schubert  * Add key_data for a krb5_db_entry
246*7f2fe78bSCy Schubert  * If passwd is NULL the assumes that the caller wants a random password.
247*7f2fe78bSCy Schubert  */
248*7f2fe78bSCy Schubert static krb5_error_code
add_key_pwd(context,master_key,ks_tuple,ks_tuple_count,passwd,db_entry,kvno)249*7f2fe78bSCy Schubert add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
250*7f2fe78bSCy Schubert             db_entry, kvno)
251*7f2fe78bSCy Schubert     krb5_context          context;
252*7f2fe78bSCy Schubert     krb5_keyblock       * master_key;
253*7f2fe78bSCy Schubert     krb5_key_salt_tuple * ks_tuple;
254*7f2fe78bSCy Schubert     int                   ks_tuple_count;
255*7f2fe78bSCy Schubert     const char          * passwd;
256*7f2fe78bSCy Schubert     krb5_db_entry       * db_entry;
257*7f2fe78bSCy Schubert     int                   kvno;
258*7f2fe78bSCy Schubert {
259*7f2fe78bSCy Schubert     krb5_error_code       retval;
260*7f2fe78bSCy Schubert     krb5_keysalt          key_salt;
261*7f2fe78bSCy Schubert     krb5_keyblock         key;
262*7f2fe78bSCy Schubert     krb5_data             pwd;
263*7f2fe78bSCy Schubert     int                   i, j;
264*7f2fe78bSCy Schubert     krb5_key_data        *kd_slot;
265*7f2fe78bSCy Schubert 
266*7f2fe78bSCy Schubert     for (i = 0; i < ks_tuple_count; i++) {
267*7f2fe78bSCy Schubert         krb5_boolean similar;
268*7f2fe78bSCy Schubert 
269*7f2fe78bSCy Schubert         similar = 0;
270*7f2fe78bSCy Schubert 
271*7f2fe78bSCy Schubert         /*
272*7f2fe78bSCy Schubert          * We could use krb5_keysalt_iterate to replace this loop, or use
273*7f2fe78bSCy Schubert          * krb5_keysalt_is_present for the loop below, but we want to avoid
274*7f2fe78bSCy Schubert          * circular library dependencies.
275*7f2fe78bSCy Schubert          */
276*7f2fe78bSCy Schubert         for (j = 0; j < i; j++) {
277*7f2fe78bSCy Schubert             if ((retval = krb5_c_enctype_compare(context,
278*7f2fe78bSCy Schubert                                                  ks_tuple[i].ks_enctype,
279*7f2fe78bSCy Schubert                                                  ks_tuple[j].ks_enctype,
280*7f2fe78bSCy Schubert                                                  &similar)))
281*7f2fe78bSCy Schubert                 return(retval);
282*7f2fe78bSCy Schubert 
283*7f2fe78bSCy Schubert             if (similar &&
284*7f2fe78bSCy Schubert                 (ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype))
285*7f2fe78bSCy Schubert                 break;
286*7f2fe78bSCy Schubert         }
287*7f2fe78bSCy Schubert 
288*7f2fe78bSCy Schubert         if (j < i)
289*7f2fe78bSCy Schubert             continue;
290*7f2fe78bSCy Schubert 
291*7f2fe78bSCy Schubert         if ((retval = krb5_dbe_create_key_data(context, db_entry)))
292*7f2fe78bSCy Schubert             return(retval);
293*7f2fe78bSCy Schubert         kd_slot = &db_entry->key_data[db_entry->n_key_data - 1];
294*7f2fe78bSCy Schubert 
295*7f2fe78bSCy Schubert         /* Convert password string to key using appropriate salt */
296*7f2fe78bSCy Schubert         switch (key_salt.type = ks_tuple[i].ks_salttype) {
297*7f2fe78bSCy Schubert         case KRB5_KDB_SALTTYPE_ONLYREALM: {
298*7f2fe78bSCy Schubert             krb5_data * saltdata;
299*7f2fe78bSCy Schubert             if ((retval = krb5_copy_data(context, krb5_princ_realm(context,
300*7f2fe78bSCy Schubert                                                                    db_entry->princ), &saltdata)))
301*7f2fe78bSCy Schubert                 return(retval);
302*7f2fe78bSCy Schubert 
303*7f2fe78bSCy Schubert             key_salt.data = *saltdata;
304*7f2fe78bSCy Schubert             free(saltdata);
305*7f2fe78bSCy Schubert         }
306*7f2fe78bSCy Schubert             break;
307*7f2fe78bSCy Schubert         case KRB5_KDB_SALTTYPE_NOREALM:
308*7f2fe78bSCy Schubert             if ((retval=krb5_principal2salt_norealm(context, db_entry->princ,
309*7f2fe78bSCy Schubert                                                     &key_salt.data)))
310*7f2fe78bSCy Schubert                 return(retval);
311*7f2fe78bSCy Schubert             break;
312*7f2fe78bSCy Schubert         case KRB5_KDB_SALTTYPE_NORMAL:
313*7f2fe78bSCy Schubert             if ((retval = krb5_principal2salt(context, db_entry->princ,
314*7f2fe78bSCy Schubert                                               &key_salt.data)))
315*7f2fe78bSCy Schubert                 return(retval);
316*7f2fe78bSCy Schubert             break;
317*7f2fe78bSCy Schubert         case KRB5_KDB_SALTTYPE_SPECIAL:
318*7f2fe78bSCy Schubert             retval = make_random_salt(context, &key_salt);
319*7f2fe78bSCy Schubert             if (retval)
320*7f2fe78bSCy Schubert                 return retval;
321*7f2fe78bSCy Schubert             break;
322*7f2fe78bSCy Schubert         default:
323*7f2fe78bSCy Schubert             return(KRB5_KDB_BAD_SALTTYPE);
324*7f2fe78bSCy Schubert         }
325*7f2fe78bSCy Schubert 
326*7f2fe78bSCy Schubert         pwd = string2data((char *)passwd);
327*7f2fe78bSCy Schubert 
328*7f2fe78bSCy Schubert         retval = krb5_c_string_to_key_with_params(context,
329*7f2fe78bSCy Schubert                                                   ks_tuple[i].ks_enctype,
330*7f2fe78bSCy Schubert                                                   &pwd, &key_salt.data,
331*7f2fe78bSCy Schubert                                                   NULL, &key);
332*7f2fe78bSCy Schubert         if (retval) {
333*7f2fe78bSCy Schubert             free(key_salt.data.data);
334*7f2fe78bSCy Schubert             return retval;
335*7f2fe78bSCy Schubert         }
336*7f2fe78bSCy Schubert 
337*7f2fe78bSCy Schubert         retval = krb5_dbe_encrypt_key_data(context, master_key, &key,
338*7f2fe78bSCy Schubert                                            (const krb5_keysalt *)&key_salt,
339*7f2fe78bSCy Schubert                                            kvno, kd_slot);
340*7f2fe78bSCy Schubert         if (key_salt.data.data)
341*7f2fe78bSCy Schubert             free(key_salt.data.data);
342*7f2fe78bSCy Schubert         free(key.contents);
343*7f2fe78bSCy Schubert 
344*7f2fe78bSCy Schubert         if( retval )
345*7f2fe78bSCy Schubert             return retval;
346*7f2fe78bSCy Schubert     }
347*7f2fe78bSCy Schubert 
348*7f2fe78bSCy Schubert     return 0;
349*7f2fe78bSCy Schubert }
350*7f2fe78bSCy Schubert 
351*7f2fe78bSCy Schubert static krb5_error_code
rekey(krb5_context context,krb5_keyblock * mkey,krb5_key_salt_tuple * ks_tuple,int ks_tuple_count,const char * password,int new_kvno,enum save savekeys,krb5_db_entry * db_entry)352*7f2fe78bSCy Schubert rekey(krb5_context context, krb5_keyblock *mkey, krb5_key_salt_tuple *ks_tuple,
353*7f2fe78bSCy Schubert       int ks_tuple_count, const char *password, int new_kvno,
354*7f2fe78bSCy Schubert       enum save savekeys, krb5_db_entry *db_entry)
355*7f2fe78bSCy Schubert {
356*7f2fe78bSCy Schubert     krb5_error_code ret;
357*7f2fe78bSCy Schubert     krb5_key_data *key_data;
358*7f2fe78bSCy Schubert     int n_key_data, old_kvno, save_kvno;
359*7f2fe78bSCy Schubert 
360*7f2fe78bSCy Schubert     /* Save aside the old key data. */
361*7f2fe78bSCy Schubert     n_key_data = db_entry->n_key_data;
362*7f2fe78bSCy Schubert     key_data = db_entry->key_data;
363*7f2fe78bSCy Schubert     db_entry->n_key_data = 0;
364*7f2fe78bSCy Schubert     db_entry->key_data = NULL;
365*7f2fe78bSCy Schubert 
366*7f2fe78bSCy Schubert     /* Make sure the new kvno is greater than the old largest kvno. */
367*7f2fe78bSCy Schubert     old_kvno = krb5_db_get_key_data_kvno(context, n_key_data, key_data);
368*7f2fe78bSCy Schubert     if (new_kvno < old_kvno + 1)
369*7f2fe78bSCy Schubert         new_kvno = old_kvno + 1;
370*7f2fe78bSCy Schubert     /* Wrap from 65535 to 1; we can only store 16-bit kvno values in key_data,
371*7f2fe78bSCy Schubert      * and we assign special meaning to kvno 0. */
372*7f2fe78bSCy Schubert     if (new_kvno == (1 << 16))
373*7f2fe78bSCy Schubert         new_kvno = 1;
374*7f2fe78bSCy Schubert 
375*7f2fe78bSCy Schubert     /* Add new keys to the front of the list. */
376*7f2fe78bSCy Schubert     if (password != NULL) {
377*7f2fe78bSCy Schubert         ret = add_key_pwd(context, mkey, ks_tuple, ks_tuple_count, password,
378*7f2fe78bSCy Schubert                           db_entry, new_kvno);
379*7f2fe78bSCy Schubert     } else {
380*7f2fe78bSCy Schubert         ret = add_key_rnd(context, mkey, ks_tuple, ks_tuple_count, db_entry,
381*7f2fe78bSCy Schubert                           new_kvno);
382*7f2fe78bSCy Schubert     }
383*7f2fe78bSCy Schubert     if (ret) {
384*7f2fe78bSCy Schubert         cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
385*7f2fe78bSCy Schubert         db_entry->n_key_data = n_key_data;
386*7f2fe78bSCy Schubert         db_entry->key_data = key_data;
387*7f2fe78bSCy Schubert         return ret;
388*7f2fe78bSCy Schubert     }
389*7f2fe78bSCy Schubert 
390*7f2fe78bSCy Schubert     /* Possibly add some or all of the old keys to the back of the list.  May
391*7f2fe78bSCy Schubert      * steal from and zero out some of the old key data entries. */
392*7f2fe78bSCy Schubert     if (savekeys != DISCARD_ALL) {
393*7f2fe78bSCy Schubert         save_kvno = (savekeys == KEEP_LAST_KVNO) ? old_kvno : 0;
394*7f2fe78bSCy Schubert         ret = preserve_old_keys(context, mkey, db_entry, save_kvno, n_key_data,
395*7f2fe78bSCy Schubert                                 key_data);
396*7f2fe78bSCy Schubert     }
397*7f2fe78bSCy Schubert 
398*7f2fe78bSCy Schubert     /* Free any old key data entries not stolen and zeroed out above. */
399*7f2fe78bSCy Schubert     cleanup_key_data(context, n_key_data, key_data);
400*7f2fe78bSCy Schubert     return ret;
401*7f2fe78bSCy Schubert }
402*7f2fe78bSCy Schubert 
403*7f2fe78bSCy Schubert /*
404*7f2fe78bSCy Schubert  * Change random key for a krb5_db_entry
405*7f2fe78bSCy Schubert  * Assumes the max kvno
406*7f2fe78bSCy Schubert  *
407*7f2fe78bSCy Schubert  * As a side effect all old keys are nuked if keepold is false.
408*7f2fe78bSCy Schubert  */
409*7f2fe78bSCy Schubert krb5_error_code
krb5_dbe_crk(krb5_context context,krb5_keyblock * mkey,krb5_key_salt_tuple * ks_tuple,int ks_tuple_count,krb5_boolean keepold,krb5_db_entry * dbent)410*7f2fe78bSCy Schubert krb5_dbe_crk(krb5_context context, krb5_keyblock *mkey,
411*7f2fe78bSCy Schubert              krb5_key_salt_tuple *ks_tuple, int ks_tuple_count,
412*7f2fe78bSCy Schubert              krb5_boolean keepold, krb5_db_entry *dbent)
413*7f2fe78bSCy Schubert {
414*7f2fe78bSCy Schubert     return rekey(context, mkey, ks_tuple, ks_tuple_count, NULL, 0,
415*7f2fe78bSCy Schubert                  keepold ? KEEP_ALL : DISCARD_ALL, dbent);
416*7f2fe78bSCy Schubert }
417*7f2fe78bSCy Schubert 
418*7f2fe78bSCy Schubert /*
419*7f2fe78bSCy Schubert  * Add random key for a krb5_db_entry
420*7f2fe78bSCy Schubert  * Assumes the max kvno
421*7f2fe78bSCy Schubert  *
422*7f2fe78bSCy Schubert  * As a side effect all old keys older than the max kvno are nuked.
423*7f2fe78bSCy Schubert  */
424*7f2fe78bSCy Schubert krb5_error_code
krb5_dbe_ark(krb5_context context,krb5_keyblock * mkey,krb5_key_salt_tuple * ks_tuple,int ks_tuple_count,krb5_db_entry * dbent)425*7f2fe78bSCy Schubert krb5_dbe_ark(krb5_context context, krb5_keyblock *mkey,
426*7f2fe78bSCy Schubert              krb5_key_salt_tuple *ks_tuple, int ks_tuple_count,
427*7f2fe78bSCy Schubert              krb5_db_entry *dbent)
428*7f2fe78bSCy Schubert {
429*7f2fe78bSCy Schubert     return rekey(context, mkey, ks_tuple, ks_tuple_count, NULL, 0,
430*7f2fe78bSCy Schubert                  KEEP_LAST_KVNO, dbent);
431*7f2fe78bSCy Schubert }
432*7f2fe78bSCy Schubert 
433*7f2fe78bSCy Schubert /*
434*7f2fe78bSCy Schubert  * Change password for a krb5_db_entry
435*7f2fe78bSCy Schubert  * Assumes the max kvno
436*7f2fe78bSCy Schubert  *
437*7f2fe78bSCy Schubert  * As a side effect all old keys are nuked if keepold is false.
438*7f2fe78bSCy Schubert  */
439*7f2fe78bSCy Schubert krb5_error_code
krb5_dbe_def_cpw(krb5_context context,krb5_keyblock * mkey,krb5_key_salt_tuple * ks_tuple,int ks_tuple_count,char * password,int new_kvno,krb5_boolean keepold,krb5_db_entry * dbent)440*7f2fe78bSCy Schubert krb5_dbe_def_cpw(krb5_context context, krb5_keyblock *mkey,
441*7f2fe78bSCy Schubert                  krb5_key_salt_tuple *ks_tuple, int ks_tuple_count,
442*7f2fe78bSCy Schubert                  char *password, int new_kvno, krb5_boolean keepold,
443*7f2fe78bSCy Schubert                  krb5_db_entry *dbent)
444*7f2fe78bSCy Schubert {
445*7f2fe78bSCy Schubert     return rekey(context, mkey, ks_tuple, ks_tuple_count, password, new_kvno,
446*7f2fe78bSCy Schubert                  keepold ? KEEP_ALL : DISCARD_ALL, dbent);
447*7f2fe78bSCy Schubert }
448*7f2fe78bSCy Schubert 
449*7f2fe78bSCy Schubert /*
450*7f2fe78bSCy Schubert  * Add password for a krb5_db_entry
451*7f2fe78bSCy Schubert  * Assumes the max kvno
452*7f2fe78bSCy Schubert  *
453*7f2fe78bSCy Schubert  * As a side effect all old keys older than the max kvno are nuked.
454*7f2fe78bSCy Schubert  */
455*7f2fe78bSCy Schubert krb5_error_code
krb5_dbe_apw(krb5_context context,krb5_keyblock * mkey,krb5_key_salt_tuple * ks_tuple,int ks_tuple_count,char * password,krb5_db_entry * dbent)456*7f2fe78bSCy Schubert krb5_dbe_apw(krb5_context context, krb5_keyblock *mkey,
457*7f2fe78bSCy Schubert              krb5_key_salt_tuple *ks_tuple, int ks_tuple_count, char *password,
458*7f2fe78bSCy Schubert              krb5_db_entry *dbent)
459*7f2fe78bSCy Schubert {
460*7f2fe78bSCy Schubert     return rekey(context, mkey, ks_tuple, ks_tuple_count, password, 0,
461*7f2fe78bSCy Schubert                  KEEP_LAST_KVNO, dbent);
462*7f2fe78bSCy Schubert }
463