6 * Provide an interface to assemble and disassemble krb5_cred
14 #include <stddef.h> /* NULL */
15 #include <stdlib.h> /* malloc */
16 #include <errno.h> /* ENOMEM */
18 /*-------------------- encrypt_credencpart --------------------*/
21 * encrypt the enc_part of krb5_cred
23 static krb5_error_code
24 encrypt_credencpart(context, pcredpart, pkeyblock, pencdata)
26 krb5_cred_enc_part * pcredpart;
27 krb5_keyblock * pkeyblock;
28 krb5_enc_data * pencdata;
30 krb5_error_code retval;
31 krb5_encrypt_block eblock;
34 if (pkeyblock && !valid_enctype(pkeyblock->enctype))
35 return KRB5_PROG_ETYPE_NOSUPP;
37 /* start by encoding to-be-encrypted part of the message */
38 if ((retval = encode_krb5_enc_cred_part(pcredpart, &scratch)))
42 * If the keyblock is NULL, just copy the data from the encoded
43 * data to the ciphertext area.
45 if (pkeyblock == NULL) {
46 pencdata->ciphertext.data = scratch->data;
47 pencdata->ciphertext.length = scratch->length;
52 /* put together an eblock for this encryption */
55 pencdata->enctype = pkeyblock->enctype;
57 krb5_use_enctype(context, &eblock, pkeyblock->enctype);
58 pencdata->ciphertext.length = krb5_encrypt_size(scratch->length,
61 /* add padding area, and zero it */
62 if (!(scratch->data = (char *)realloc(scratch->data,
63 pencdata->ciphertext.length))) {
64 /* may destroy scratch->data */
69 memset(scratch->data + scratch->length, 0,
70 pencdata->ciphertext.length - scratch->length);
71 if (!(pencdata->ciphertext.data =
72 (char *)malloc(pencdata->ciphertext.length))) {
77 /* do any necessary key pre-processing */
78 if ((retval = krb5_process_key(context, &eblock, pkeyblock))) {
82 /* call the encryption routine */
83 if ((retval = krb5_encrypt(context, (krb5_pointer)scratch->data,
84 (krb5_pointer)pencdata->ciphertext.data,
85 scratch->length, &eblock, 0))) {
86 krb5_finish_key(context, &eblock);
90 retval = krb5_finish_key(context, &eblock);
94 memset(pencdata->ciphertext.data, 0, pencdata->ciphertext.length);
95 free(pencdata->ciphertext.data);
96 pencdata->ciphertext.length = 0;
97 pencdata->ciphertext.data = 0;
101 memset(scratch->data, 0, scratch->length);
102 krb5_free_data(context, scratch);
107 /*----------------------- krb5_mk_ncred_basic -----------------------*/
109 static krb5_error_code
110 krb5_mk_ncred_basic(context, ppcreds, nppcreds, keyblock,
111 replaydata, local_addr, remote_addr, pcred)
112 krb5_context context;
113 krb5_creds FAR * FAR * ppcreds;
115 krb5_keyblock FAR * keyblock;
116 krb5_replay_data FAR * replaydata;
117 krb5_address FAR * local_addr;
118 krb5_address FAR * remote_addr;
119 krb5_cred FAR * pcred;
121 krb5_cred_enc_part credenc;
122 krb5_error_code retval;
126 credenc.magic = KV5M_CRED_ENC_PART;
128 credenc.s_address = 0;
129 credenc.r_address = 0;
130 if (local_addr) krb5_copy_addr(context, local_addr, &credenc.s_address);
131 if (remote_addr) krb5_copy_addr(context, remote_addr, &credenc.r_address);
133 credenc.nonce = replaydata->seq;
134 credenc.usec = replaydata->usec;
135 credenc.timestamp = replaydata->timestamp;
137 /* Get memory for creds and initialize it */
138 size = sizeof(krb5_cred_info FAR *) * (nppcreds + 1);
139 credenc.ticket_info = (krb5_cred_info FAR * FAR *) malloc(size);
140 if (credenc.ticket_info == NULL)
142 memset(credenc.ticket_info, 0, size);
145 * For each credential in the list, initialize a cred info
146 * structure and copy the ticket into the ticket list.
148 for (i = 0; i < nppcreds; i++) {
149 credenc.ticket_info[i] = malloc(sizeof(krb5_cred_info));
150 if (credenc.ticket_info[i] == NULL) {
154 credenc.ticket_info[i+1] = NULL;
156 credenc.ticket_info[i]->magic = KV5M_CRED_INFO;
157 credenc.ticket_info[i]->times = ppcreds[i]->times;
158 credenc.ticket_info[i]->flags = ppcreds[i]->ticket_flags;
160 if ((retval = decode_krb5_ticket(&ppcreds[i]->ticket,
161 &pcred->tickets[i])))
164 if ((retval = krb5_copy_keyblock(context, &ppcreds[i]->keyblock,
165 &credenc.ticket_info[i]->session)))
168 if ((retval = krb5_copy_principal(context, ppcreds[i]->client,
169 &credenc.ticket_info[i]->client)))
172 if ((retval = krb5_copy_principal(context, ppcreds[i]->server,
173 &credenc.ticket_info[i]->server)))
176 if ((retval = krb5_copy_addresses(context, ppcreds[i]->addresses,
177 &credenc.ticket_info[i]->caddrs)))
182 * NULL terminate the lists.
184 pcred->tickets[i] = NULL;
186 /* encrypt the credential encrypted part */
187 retval = encrypt_credencpart(context, &credenc, keyblock,
191 krb5_free_cred_enc_part(context, &credenc);
195 /*----------------------- krb5_mk_ncred -----------------------*/
198 * This functions takes as input an array of krb5_credentials, and
199 * outputs an encoded KRB_CRED message suitable for krb5_rd_cred
201 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
202 krb5_mk_ncred(context, auth_context, ppcreds, ppdata, outdata)
204 krb5_context context;
205 krb5_auth_context auth_context;
206 krb5_creds FAR * FAR * ppcreds;
207 krb5_data FAR * FAR * ppdata;
208 krb5_replay_data FAR * outdata;
210 krb5_address FAR * premote_fulladdr = NULL;
211 krb5_address FAR * plocal_fulladdr = NULL;
212 krb5_address remote_fulladdr;
213 krb5_address local_fulladdr;
214 krb5_error_code retval;
215 krb5_keyblock FAR * keyblock;
216 krb5_replay_data replaydata;
217 krb5_cred FAR * pcred;
220 local_fulladdr.contents = 0;
221 remote_fulladdr.contents = 0;
222 memset(&replaydata, 0, sizeof(krb5_replay_data));
224 if (ppcreds == NULL) {
225 return KRB5KRB_AP_ERR_BADADDR;
229 * Allocate memory for a NULL terminated list of tickets.
231 for (ncred = 0; ppcreds[ncred]; ncred++);
233 if ((pcred = (krb5_cred *)malloc(sizeof(krb5_cred))) == NULL)
235 memset(pcred, 0, sizeof(krb5_cred));
238 = (krb5_ticket FAR * FAR *)malloc(sizeof(krb5_ticket FAR *) * (ncred + 1))) == NULL) {
242 memset(pcred->tickets, 0, sizeof(krb5_ticket FAR *) * (ncred +1));
245 if ((keyblock = auth_context->local_subkey) == NULL)
246 if ((keyblock = auth_context->remote_subkey) == NULL)
247 keyblock = auth_context->keyblock;
249 /* Get replay info */
250 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
251 (auth_context->rcache == NULL))
252 return KRB5_RC_REQUIRED;
254 if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
255 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
257 /* Need a better error */
258 return KRB5_RC_REQUIRED;
260 if ((retval = krb5_us_timeofday(context, &replaydata.timestamp,
263 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) {
264 outdata->timestamp = replaydata.timestamp;
265 outdata->usec = replaydata.usec;
267 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
268 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
269 replaydata.seq = auth_context->local_seq_number;
270 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
271 auth_context->local_seq_number++;
273 outdata->seq = replaydata.seq;
277 if (auth_context->local_addr) {
278 if (auth_context->local_port) {
279 if ((retval = krb5_make_fulladdr(context, auth_context->local_addr,
280 auth_context->local_port,
283 plocal_fulladdr = &local_fulladdr;
285 plocal_fulladdr = auth_context->local_addr;
289 if (auth_context->remote_addr) {
290 if (auth_context->remote_port) {
291 if ((retval = krb5_make_fulladdr(context,auth_context->remote_addr,
292 auth_context->remote_port,
295 premote_fulladdr = &remote_fulladdr;
297 premote_fulladdr = auth_context->remote_addr;
301 /* Setup creds structure */
302 if ((retval = krb5_mk_ncred_basic(context, ppcreds, ncred, keyblock,
303 &replaydata, plocal_fulladdr,
304 premote_fulladdr, pcred))) {
308 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
309 krb5_donot_replay replay;
311 if ((retval = krb5_gen_replay_name(context, auth_context->local_addr,
312 "_forw", &replay.client)))
315 replay.server = ""; /* XXX */
316 replay.cusec = replaydata.usec;
317 replay.ctime = replaydata.timestamp;
318 if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
319 /* should we really error out here? XXX */
320 krb5_xfree(replay.client);
323 krb5_xfree(replay.client);
326 /* Encode creds structure */
327 retval = encode_krb5_cred(pcred, ppdata);
330 if (local_fulladdr.contents)
331 free(local_fulladdr.contents);
332 if (remote_fulladdr.contents)
333 free(remote_fulladdr.contents);
334 krb5_free_cred(context, pcred);
337 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
338 || (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
339 auth_context->local_seq_number--;
344 /*----------------------- krb5_mk_1cred -----------------------*/
347 * A convenience function that calls krb5_mk_ncred.
349 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
350 krb5_mk_1cred(context, auth_context, pcreds, ppdata, outdata)
351 krb5_context context;
352 krb5_auth_context auth_context;
353 krb5_creds FAR * pcreds;
354 krb5_data FAR * FAR * ppdata;
355 krb5_replay_data FAR * outdata;
357 krb5_error_code retval;
358 krb5_creds FAR * FAR *ppcreds;
360 if ((ppcreds = (krb5_creds FAR * FAR *)malloc(sizeof(*ppcreds) * 2)) == NULL) {
367 retval = krb5_mk_ncred(context, auth_context, ppcreds,