1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/rd_cred.c - definition of krb5_rd_cred() */
4 * Copyright 1994-2009 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. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
31 #include <stddef.h> /* NULL */
32 #include <stdlib.h> /* malloc */
33 #include <errno.h> /* ENOMEM */
35 /*-------------------- decrypt_credencdata --------------------*/
38 * decrypt the enc_part of a krb5_cred
40 static krb5_error_code
41 decrypt_credencdata(krb5_context context, krb5_cred *pcred,
42 krb5_key pkey, krb5_cred_enc_part *pcredenc)
44 krb5_cred_enc_part * ppart = NULL;
45 krb5_error_code retval = 0;
48 scratch.length = pcred->enc_part.ciphertext.length;
49 if (!(scratch.data = (char *)malloc(scratch.length)))
53 if ((retval = krb5_k_decrypt(context, pkey,
54 KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0,
55 &pcred->enc_part, &scratch)))
58 memcpy(scratch.data, pcred->enc_part.ciphertext.data, scratch.length);
61 /* now decode the decrypted stuff */
62 if ((retval = decode_krb5_enc_cred_part(&scratch, &ppart)))
69 memset(ppart, 0, sizeof(*ppart));
72 memset(scratch.data, 0, scratch.length);
77 /*----------------------- krb5_rd_cred_basic -----------------------*/
79 static krb5_error_code
80 krb5_rd_cred_basic(krb5_context context, krb5_data *pcreddata,
81 krb5_key pkey, krb5_replay_data *replaydata,
82 krb5_creds ***pppcreds)
84 krb5_error_code retval = 0;
85 krb5_cred * pcred = NULL;
86 krb5_int32 ncreds = 0;
88 krb5_cred_enc_part encpart;
90 /* decode cred message */
91 if ((retval = decode_krb5_cred(pcreddata, &pcred)))
94 memset(&encpart, 0, sizeof(encpart));
96 if ((retval = decrypt_credencdata(context, pcred, pkey, &encpart)))
100 replaydata->timestamp = encpart.timestamp;
101 replaydata->usec = encpart.usec;
102 replaydata->seq = encpart.nonce;
105 * Allocate the list of creds. The memory is allocated so that
106 * krb5_free_tgt_creds can be used to free the list.
108 for (ncreds = 0; pcred->tickets[ncreds]; ncreds++);
111 (krb5_creds **)malloc((size_t)(sizeof(krb5_creds *) *
112 (ncreds + 1)))) == NULL) {
116 (*pppcreds)[0] = NULL;
119 * For each credential, create a strcture in the list of
120 * credentials and copy the information.
123 krb5_cred_info * pinfo;
127 if ((pcur = (krb5_creds *)calloc(1, sizeof(krb5_creds))) == NULL) {
132 (*pppcreds)[i] = pcur;
133 (*pppcreds)[i+1] = 0;
134 pinfo = encpart.ticket_info[i++];
136 if ((retval = krb5_copy_principal(context, pinfo->client,
140 if ((retval = krb5_copy_principal(context, pinfo->server,
144 if ((retval = krb5_copy_keyblock_contents(context, pinfo->session,
148 if ((retval = krb5_copy_addresses(context, pinfo->caddrs,
152 if ((retval = encode_krb5_ticket(pcred->tickets[i - 1], &pdata)))
155 pcur->ticket = *pdata;
159 pcur->is_skey = FALSE;
160 pcur->magic = KV5M_CREDS;
161 pcur->times = pinfo->times;
162 pcur->ticket_flags = pinfo->flags;
163 pcur->authdata = NULL; /* not used */
164 memset(&pcur->second_ticket, 0, sizeof(pcur->second_ticket));
168 * NULL terminate the list
170 (*pppcreds)[i] = NULL;
174 krb5_free_tgt_creds(context, *pppcreds);
177 krb5_free_cred(context, pcred);
178 krb5_free_cred_enc_part(context, &encpart);
183 /*----------------------- krb5_rd_cred -----------------------*/
186 * This functions takes as input an KRB_CRED message, validates it, and
187 * outputs the array of the forwarded credentials and replay cache information
189 krb5_error_code KRB5_CALLCONV
190 krb5_rd_cred(krb5_context context, krb5_auth_context auth_context,
191 krb5_data *pcreddata, krb5_creds ***pppcreds,
192 krb5_replay_data *outdata)
194 krb5_error_code retval = 0;
195 krb5_replay_data replaydata;
197 if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
198 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
200 /* Need a better error */
201 return KRB5_RC_REQUIRED;
203 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
204 (auth_context->rcache == NULL))
205 return KRB5_RC_REQUIRED;
208 * If decrypting with the subsession key fails, perhaps the
209 * credentials are stored in the session key so try decrypting with that.
211 if (auth_context->recv_subkey == NULL ||
212 (retval = krb5_rd_cred_basic(context, pcreddata,
213 auth_context->recv_subkey,
214 &replaydata, pppcreds))) {
215 retval = krb5_rd_cred_basic(context, pcreddata,
217 &replaydata, pppcreds);
222 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
223 krb5_donot_replay replay;
225 if ((retval = krb5_check_clockskew(context, replaydata.timestamp)))
228 if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr,
229 "_forw", &replay.client)))
232 replay.server = ""; /* XXX */
233 replay.msghash = NULL;
234 replay.cusec = replaydata.usec;
235 replay.ctime = replaydata.timestamp;
236 if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
243 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
244 if (auth_context->remote_seq_number != replaydata.seq) {
245 retval = KRB5KRB_AP_ERR_BADORDER;
248 auth_context->remote_seq_number++;
251 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
252 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
253 outdata->timestamp = replaydata.timestamp;
254 outdata->usec = replaydata.usec;
255 outdata->seq = replaydata.seq;
260 krb5_free_tgt_creds(context, *pppcreds);