1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* kdc/fast_util.c */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert * Copyright (C) 2009, 2015 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 #include <k5-int.h>
28*7f2fe78bSCy Schubert
29*7f2fe78bSCy Schubert #include "kdc_util.h"
30*7f2fe78bSCy Schubert #include "extern.h"
31*7f2fe78bSCy Schubert
32*7f2fe78bSCy Schubert /* Let cookies be valid for ten minutes. */
33*7f2fe78bSCy Schubert #define COOKIE_LIFETIME 600
34*7f2fe78bSCy Schubert
armor_ap_request(struct kdc_request_state * state,krb5_fast_armor * armor)35*7f2fe78bSCy Schubert static krb5_error_code armor_ap_request
36*7f2fe78bSCy Schubert (struct kdc_request_state *state, krb5_fast_armor *armor)
37*7f2fe78bSCy Schubert {
38*7f2fe78bSCy Schubert krb5_error_code retval = 0;
39*7f2fe78bSCy Schubert krb5_auth_context authcontext = NULL;
40*7f2fe78bSCy Schubert krb5_ticket *ticket = NULL;
41*7f2fe78bSCy Schubert krb5_keyblock *subkey = NULL;
42*7f2fe78bSCy Schubert kdc_realm_t *realm = state->realm_data;
43*7f2fe78bSCy Schubert krb5_context context = realm->realm_context;
44*7f2fe78bSCy Schubert
45*7f2fe78bSCy Schubert assert(armor->armor_type == KRB5_FAST_ARMOR_AP_REQUEST);
46*7f2fe78bSCy Schubert krb5_clear_error_message(context);
47*7f2fe78bSCy Schubert retval = krb5_auth_con_init(context, &authcontext);
48*7f2fe78bSCy Schubert /*disable replay cache*/
49*7f2fe78bSCy Schubert if (retval == 0)
50*7f2fe78bSCy Schubert retval = krb5_auth_con_setflags(context, authcontext, 0);
51*7f2fe78bSCy Schubert if (retval == 0)
52*7f2fe78bSCy Schubert retval = krb5_rd_req(context, &authcontext, &armor->armor_value,
53*7f2fe78bSCy Schubert NULL /*server*/, realm->realm_keytab,
54*7f2fe78bSCy Schubert NULL, &ticket);
55*7f2fe78bSCy Schubert if (retval != 0) {
56*7f2fe78bSCy Schubert const char * errmsg = krb5_get_error_message(context, retval);
57*7f2fe78bSCy Schubert k5_setmsg(context, retval, _("%s while handling ap-request armor"),
58*7f2fe78bSCy Schubert errmsg);
59*7f2fe78bSCy Schubert krb5_free_error_message(context, errmsg);
60*7f2fe78bSCy Schubert }
61*7f2fe78bSCy Schubert if (retval == 0) {
62*7f2fe78bSCy Schubert if (!krb5_principal_compare_any_realm(context, realm->realm_tgsprinc,
63*7f2fe78bSCy Schubert ticket->server)) {
64*7f2fe78bSCy Schubert k5_setmsg(context, KRB5KDC_ERR_SERVER_NOMATCH,
65*7f2fe78bSCy Schubert _("ap-request armor for something other than the local "
66*7f2fe78bSCy Schubert "TGS"));
67*7f2fe78bSCy Schubert retval = KRB5KDC_ERR_SERVER_NOMATCH;
68*7f2fe78bSCy Schubert }
69*7f2fe78bSCy Schubert }
70*7f2fe78bSCy Schubert if (retval == 0) {
71*7f2fe78bSCy Schubert retval = krb5_auth_con_getrecvsubkey(context, authcontext, &subkey);
72*7f2fe78bSCy Schubert if (retval != 0 || subkey == NULL) {
73*7f2fe78bSCy Schubert k5_setmsg(context, KRB5KDC_ERR_POLICY,
74*7f2fe78bSCy Schubert _("ap-request armor without subkey"));
75*7f2fe78bSCy Schubert retval = KRB5KDC_ERR_POLICY;
76*7f2fe78bSCy Schubert }
77*7f2fe78bSCy Schubert }
78*7f2fe78bSCy Schubert if (retval == 0)
79*7f2fe78bSCy Schubert retval = krb5_c_fx_cf2_simple(context,
80*7f2fe78bSCy Schubert subkey, "subkeyarmor",
81*7f2fe78bSCy Schubert ticket->enc_part2->session, "ticketarmor",
82*7f2fe78bSCy Schubert &state->armor_key);
83*7f2fe78bSCy Schubert if (ticket)
84*7f2fe78bSCy Schubert krb5_free_ticket(context, ticket);
85*7f2fe78bSCy Schubert if (subkey)
86*7f2fe78bSCy Schubert krb5_free_keyblock(context, subkey);
87*7f2fe78bSCy Schubert if (authcontext)
88*7f2fe78bSCy Schubert krb5_auth_con_free(context, authcontext);
89*7f2fe78bSCy Schubert return retval;
90*7f2fe78bSCy Schubert }
91*7f2fe78bSCy Schubert
92*7f2fe78bSCy Schubert static krb5_error_code
encrypt_fast_reply(struct kdc_request_state * state,const krb5_fast_response * response,krb5_data ** fx_fast_reply)93*7f2fe78bSCy Schubert encrypt_fast_reply(struct kdc_request_state *state,
94*7f2fe78bSCy Schubert const krb5_fast_response *response,
95*7f2fe78bSCy Schubert krb5_data **fx_fast_reply)
96*7f2fe78bSCy Schubert {
97*7f2fe78bSCy Schubert krb5_context context = state->realm_data->realm_context;
98*7f2fe78bSCy Schubert krb5_error_code retval = 0;
99*7f2fe78bSCy Schubert krb5_enc_data encrypted_reply;
100*7f2fe78bSCy Schubert krb5_data *encoded_response = NULL;
101*7f2fe78bSCy Schubert
102*7f2fe78bSCy Schubert assert(state->armor_key);
103*7f2fe78bSCy Schubert retval = encode_krb5_fast_response(response, &encoded_response);
104*7f2fe78bSCy Schubert if (retval== 0)
105*7f2fe78bSCy Schubert retval = krb5_encrypt_helper(context, state->armor_key,
106*7f2fe78bSCy Schubert KRB5_KEYUSAGE_FAST_REP,
107*7f2fe78bSCy Schubert encoded_response, &encrypted_reply);
108*7f2fe78bSCy Schubert if (encoded_response)
109*7f2fe78bSCy Schubert krb5_free_data(context, encoded_response);
110*7f2fe78bSCy Schubert encoded_response = NULL;
111*7f2fe78bSCy Schubert if (retval == 0) {
112*7f2fe78bSCy Schubert retval = encode_krb5_pa_fx_fast_reply(&encrypted_reply,
113*7f2fe78bSCy Schubert fx_fast_reply);
114*7f2fe78bSCy Schubert krb5_free_data_contents(context, &encrypted_reply.ciphertext);
115*7f2fe78bSCy Schubert }
116*7f2fe78bSCy Schubert return retval;
117*7f2fe78bSCy Schubert }
118*7f2fe78bSCy Schubert
119*7f2fe78bSCy Schubert
120*7f2fe78bSCy Schubert /*
121*7f2fe78bSCy Schubert * This function will find the FAST padata and, if FAST is successfully
122*7f2fe78bSCy Schubert * processed, will free the outer request and update the pointer to point to
123*7f2fe78bSCy Schubert * the inner request. checksummed_data points to the data that is in the
124*7f2fe78bSCy Schubert * armored_fast_request checksum; either the pa-tgs-req or the kdc-req-body.
125*7f2fe78bSCy Schubert */
126*7f2fe78bSCy Schubert krb5_error_code
kdc_find_fast(krb5_kdc_req ** requestptr,krb5_data * checksummed_data,krb5_keyblock * tgs_subkey,krb5_keyblock * tgs_session,struct kdc_request_state * state,krb5_data ** inner_body_out)127*7f2fe78bSCy Schubert kdc_find_fast(krb5_kdc_req **requestptr,
128*7f2fe78bSCy Schubert krb5_data *checksummed_data,
129*7f2fe78bSCy Schubert krb5_keyblock *tgs_subkey,
130*7f2fe78bSCy Schubert krb5_keyblock *tgs_session,
131*7f2fe78bSCy Schubert struct kdc_request_state *state,
132*7f2fe78bSCy Schubert krb5_data **inner_body_out)
133*7f2fe78bSCy Schubert {
134*7f2fe78bSCy Schubert krb5_context context = state->realm_data->realm_context;
135*7f2fe78bSCy Schubert krb5_error_code retval = 0;
136*7f2fe78bSCy Schubert krb5_pa_data *fast_padata;
137*7f2fe78bSCy Schubert krb5_data scratch, plaintext, *inner_body = NULL;
138*7f2fe78bSCy Schubert krb5_fast_req * fast_req = NULL;
139*7f2fe78bSCy Schubert krb5_kdc_req *request = *requestptr;
140*7f2fe78bSCy Schubert krb5_fast_armored_req *fast_armored_req = NULL;
141*7f2fe78bSCy Schubert krb5_checksum *cksum;
142*7f2fe78bSCy Schubert krb5_boolean cksum_valid;
143*7f2fe78bSCy Schubert krb5_keyblock empty_keyblock;
144*7f2fe78bSCy Schubert
145*7f2fe78bSCy Schubert if (inner_body_out != NULL)
146*7f2fe78bSCy Schubert *inner_body_out = NULL;
147*7f2fe78bSCy Schubert scratch.data = NULL;
148*7f2fe78bSCy Schubert krb5_clear_error_message(context);
149*7f2fe78bSCy Schubert memset(&empty_keyblock, 0, sizeof(krb5_keyblock));
150*7f2fe78bSCy Schubert fast_padata = krb5int_find_pa_data(context, request->padata,
151*7f2fe78bSCy Schubert KRB5_PADATA_FX_FAST);
152*7f2fe78bSCy Schubert if (fast_padata != NULL){
153*7f2fe78bSCy Schubert scratch.length = fast_padata->length;
154*7f2fe78bSCy Schubert scratch.data = (char *) fast_padata->contents;
155*7f2fe78bSCy Schubert retval = decode_krb5_pa_fx_fast_request(&scratch, &fast_armored_req);
156*7f2fe78bSCy Schubert if (retval == 0 &&fast_armored_req->armor) {
157*7f2fe78bSCy Schubert switch (fast_armored_req->armor->armor_type) {
158*7f2fe78bSCy Schubert case KRB5_FAST_ARMOR_AP_REQUEST:
159*7f2fe78bSCy Schubert if (tgs_subkey) {
160*7f2fe78bSCy Schubert retval = KRB5KDC_ERR_PREAUTH_FAILED;
161*7f2fe78bSCy Schubert k5_setmsg(context, retval,
162*7f2fe78bSCy Schubert _("Ap-request armor not permitted with TGS"));
163*7f2fe78bSCy Schubert break;
164*7f2fe78bSCy Schubert }
165*7f2fe78bSCy Schubert retval = armor_ap_request(state, fast_armored_req->armor);
166*7f2fe78bSCy Schubert break;
167*7f2fe78bSCy Schubert default:
168*7f2fe78bSCy Schubert k5_setmsg(context, KRB5KDC_ERR_PREAUTH_FAILED,
169*7f2fe78bSCy Schubert _("Unknown FAST armor type %d"),
170*7f2fe78bSCy Schubert fast_armored_req->armor->armor_type);
171*7f2fe78bSCy Schubert retval = KRB5KDC_ERR_PREAUTH_FAILED;
172*7f2fe78bSCy Schubert }
173*7f2fe78bSCy Schubert }
174*7f2fe78bSCy Schubert if (retval == 0 && !state->armor_key) {
175*7f2fe78bSCy Schubert if (tgs_subkey)
176*7f2fe78bSCy Schubert retval = krb5_c_fx_cf2_simple(context,
177*7f2fe78bSCy Schubert tgs_subkey, "subkeyarmor",
178*7f2fe78bSCy Schubert tgs_session, "ticketarmor",
179*7f2fe78bSCy Schubert &state->armor_key);
180*7f2fe78bSCy Schubert else {
181*7f2fe78bSCy Schubert retval = KRB5KDC_ERR_PREAUTH_FAILED;
182*7f2fe78bSCy Schubert k5_setmsg(context, retval,
183*7f2fe78bSCy Schubert _("No armor key but FAST armored request present"));
184*7f2fe78bSCy Schubert }
185*7f2fe78bSCy Schubert }
186*7f2fe78bSCy Schubert if (retval == 0) {
187*7f2fe78bSCy Schubert plaintext.length = fast_armored_req->enc_part.ciphertext.length;
188*7f2fe78bSCy Schubert plaintext.data = k5alloc(plaintext.length, &retval);
189*7f2fe78bSCy Schubert }
190*7f2fe78bSCy Schubert if (retval == 0) {
191*7f2fe78bSCy Schubert retval = krb5_c_decrypt(context, state->armor_key,
192*7f2fe78bSCy Schubert KRB5_KEYUSAGE_FAST_ENC, NULL,
193*7f2fe78bSCy Schubert &fast_armored_req->enc_part,
194*7f2fe78bSCy Schubert &plaintext);
195*7f2fe78bSCy Schubert if (retval == 0)
196*7f2fe78bSCy Schubert retval = decode_krb5_fast_req(&plaintext, &fast_req);
197*7f2fe78bSCy Schubert if (retval == 0 && inner_body_out != NULL) {
198*7f2fe78bSCy Schubert retval = fetch_asn1_field((unsigned char *)plaintext.data,
199*7f2fe78bSCy Schubert 1, 2, &scratch);
200*7f2fe78bSCy Schubert if (retval == 0) {
201*7f2fe78bSCy Schubert retval = krb5_copy_data(context, &scratch, &inner_body);
202*7f2fe78bSCy Schubert }
203*7f2fe78bSCy Schubert }
204*7f2fe78bSCy Schubert if (plaintext.data)
205*7f2fe78bSCy Schubert free(plaintext.data);
206*7f2fe78bSCy Schubert }
207*7f2fe78bSCy Schubert cksum = &fast_armored_req->req_checksum;
208*7f2fe78bSCy Schubert if (retval == 0)
209*7f2fe78bSCy Schubert retval = krb5_c_verify_checksum(context, state->armor_key,
210*7f2fe78bSCy Schubert KRB5_KEYUSAGE_FAST_REQ_CHKSUM,
211*7f2fe78bSCy Schubert checksummed_data, cksum,
212*7f2fe78bSCy Schubert &cksum_valid);
213*7f2fe78bSCy Schubert if (retval == 0 && !cksum_valid) {
214*7f2fe78bSCy Schubert retval = KRB5KRB_AP_ERR_MODIFIED;
215*7f2fe78bSCy Schubert k5_setmsg(context, retval,
216*7f2fe78bSCy Schubert _("FAST req_checksum invalid; request modified"));
217*7f2fe78bSCy Schubert }
218*7f2fe78bSCy Schubert if (retval == 0) {
219*7f2fe78bSCy Schubert if (!krb5_c_is_keyed_cksum(cksum->checksum_type)) {
220*7f2fe78bSCy Schubert retval = KRB5KDC_ERR_POLICY;
221*7f2fe78bSCy Schubert k5_setmsg(context, retval,
222*7f2fe78bSCy Schubert _("Unkeyed checksum used in fast_req"));
223*7f2fe78bSCy Schubert }
224*7f2fe78bSCy Schubert }
225*7f2fe78bSCy Schubert if (retval == 0) {
226*7f2fe78bSCy Schubert if ((fast_req->fast_options & UNSUPPORTED_CRITICAL_FAST_OPTIONS) != 0)
227*7f2fe78bSCy Schubert retval = KRB5KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTION;
228*7f2fe78bSCy Schubert }
229*7f2fe78bSCy Schubert if (retval == 0) {
230*7f2fe78bSCy Schubert state->fast_options = fast_req->fast_options;
231*7f2fe78bSCy Schubert fast_req->req_body->msg_type = request->msg_type;
232*7f2fe78bSCy Schubert krb5_free_kdc_req(context, request);
233*7f2fe78bSCy Schubert *requestptr = fast_req->req_body;
234*7f2fe78bSCy Schubert fast_req->req_body = NULL;
235*7f2fe78bSCy Schubert }
236*7f2fe78bSCy Schubert }
237*7f2fe78bSCy Schubert if (retval == 0 && inner_body_out != NULL) {
238*7f2fe78bSCy Schubert *inner_body_out = inner_body;
239*7f2fe78bSCy Schubert inner_body = NULL;
240*7f2fe78bSCy Schubert }
241*7f2fe78bSCy Schubert krb5_free_data(context, inner_body);
242*7f2fe78bSCy Schubert if (fast_req)
243*7f2fe78bSCy Schubert krb5_free_fast_req(context, fast_req);
244*7f2fe78bSCy Schubert if (fast_armored_req)
245*7f2fe78bSCy Schubert krb5_free_fast_armored_req(context, fast_armored_req);
246*7f2fe78bSCy Schubert return retval;
247*7f2fe78bSCy Schubert }
248*7f2fe78bSCy Schubert
249*7f2fe78bSCy Schubert
250*7f2fe78bSCy Schubert krb5_error_code
kdc_make_rstate(kdc_realm_t * active_realm,struct kdc_request_state ** out)251*7f2fe78bSCy Schubert kdc_make_rstate(kdc_realm_t *active_realm, struct kdc_request_state **out)
252*7f2fe78bSCy Schubert {
253*7f2fe78bSCy Schubert struct kdc_request_state *state = malloc( sizeof(struct kdc_request_state));
254*7f2fe78bSCy Schubert if (state == NULL)
255*7f2fe78bSCy Schubert return ENOMEM;
256*7f2fe78bSCy Schubert memset( state, 0, sizeof(struct kdc_request_state));
257*7f2fe78bSCy Schubert state->realm_data = active_realm;
258*7f2fe78bSCy Schubert *out = state;
259*7f2fe78bSCy Schubert return 0;
260*7f2fe78bSCy Schubert }
261*7f2fe78bSCy Schubert
262*7f2fe78bSCy Schubert void
kdc_free_rstate(struct kdc_request_state * s)263*7f2fe78bSCy Schubert kdc_free_rstate (struct kdc_request_state *s)
264*7f2fe78bSCy Schubert {
265*7f2fe78bSCy Schubert if (s == NULL)
266*7f2fe78bSCy Schubert return;
267*7f2fe78bSCy Schubert if (s->armor_key)
268*7f2fe78bSCy Schubert krb5_free_keyblock(s->realm_data->realm_context, s->armor_key);
269*7f2fe78bSCy Schubert if (s->strengthen_key)
270*7f2fe78bSCy Schubert krb5_free_keyblock(s->realm_data->realm_context, s->strengthen_key);
271*7f2fe78bSCy Schubert k5_zapfree_pa_data(s->in_cookie_padata);
272*7f2fe78bSCy Schubert k5_zapfree_pa_data(s->out_cookie_padata);
273*7f2fe78bSCy Schubert free(s);
274*7f2fe78bSCy Schubert }
275*7f2fe78bSCy Schubert
276*7f2fe78bSCy Schubert krb5_error_code
kdc_fast_response_handle_padata(struct kdc_request_state * state,krb5_kdc_req * request,krb5_kdc_rep * rep,krb5_enctype enctype)277*7f2fe78bSCy Schubert kdc_fast_response_handle_padata(struct kdc_request_state *state,
278*7f2fe78bSCy Schubert krb5_kdc_req *request,
279*7f2fe78bSCy Schubert krb5_kdc_rep *rep, krb5_enctype enctype)
280*7f2fe78bSCy Schubert {
281*7f2fe78bSCy Schubert krb5_context context = state->realm_data->realm_context;
282*7f2fe78bSCy Schubert krb5_error_code retval = 0;
283*7f2fe78bSCy Schubert krb5_fast_finished finish;
284*7f2fe78bSCy Schubert krb5_fast_response fast_response;
285*7f2fe78bSCy Schubert krb5_data *encoded_ticket = NULL;
286*7f2fe78bSCy Schubert krb5_data *encrypted_reply = NULL;
287*7f2fe78bSCy Schubert krb5_pa_data *pa = NULL, **pa_array = NULL;
288*7f2fe78bSCy Schubert krb5_cksumtype cksumtype = CKSUMTYPE_RSA_MD5;
289*7f2fe78bSCy Schubert krb5_pa_data *empty_padata[] = {NULL};
290*7f2fe78bSCy Schubert krb5_keyblock *strengthen_key = NULL;
291*7f2fe78bSCy Schubert
292*7f2fe78bSCy Schubert if (!state->armor_key)
293*7f2fe78bSCy Schubert return 0;
294*7f2fe78bSCy Schubert memset(&finish, 0, sizeof(finish));
295*7f2fe78bSCy Schubert retval = krb5_init_keyblock(context, enctype, 0, &strengthen_key);
296*7f2fe78bSCy Schubert if (retval == 0)
297*7f2fe78bSCy Schubert retval = krb5_c_make_random_key(context, enctype, strengthen_key);
298*7f2fe78bSCy Schubert if (retval == 0) {
299*7f2fe78bSCy Schubert state->strengthen_key = strengthen_key;
300*7f2fe78bSCy Schubert strengthen_key = NULL;
301*7f2fe78bSCy Schubert }
302*7f2fe78bSCy Schubert
303*7f2fe78bSCy Schubert fast_response.padata = rep->padata;
304*7f2fe78bSCy Schubert if (fast_response.padata == NULL)
305*7f2fe78bSCy Schubert fast_response.padata = &empty_padata[0];
306*7f2fe78bSCy Schubert fast_response.strengthen_key = state->strengthen_key;
307*7f2fe78bSCy Schubert fast_response.nonce = request->nonce;
308*7f2fe78bSCy Schubert fast_response.finished = &finish;
309*7f2fe78bSCy Schubert finish.client = rep->client;
310*7f2fe78bSCy Schubert pa_array = calloc(3, sizeof(*pa_array));
311*7f2fe78bSCy Schubert if (pa_array == NULL)
312*7f2fe78bSCy Schubert retval = ENOMEM;
313*7f2fe78bSCy Schubert pa = calloc(1, sizeof(krb5_pa_data));
314*7f2fe78bSCy Schubert if (retval == 0 && pa == NULL)
315*7f2fe78bSCy Schubert retval = ENOMEM;
316*7f2fe78bSCy Schubert if (retval == 0)
317*7f2fe78bSCy Schubert retval = krb5_us_timeofday(context, &finish.timestamp, &finish.usec);
318*7f2fe78bSCy Schubert if (retval == 0)
319*7f2fe78bSCy Schubert retval = encode_krb5_ticket(rep->ticket, &encoded_ticket);
320*7f2fe78bSCy Schubert if (retval == 0)
321*7f2fe78bSCy Schubert retval = krb5int_c_mandatory_cksumtype(context,
322*7f2fe78bSCy Schubert state->armor_key->enctype,
323*7f2fe78bSCy Schubert &cksumtype);
324*7f2fe78bSCy Schubert if (retval == 0)
325*7f2fe78bSCy Schubert retval = krb5_c_make_checksum(context, cksumtype, state->armor_key,
326*7f2fe78bSCy Schubert KRB5_KEYUSAGE_FAST_FINISHED,
327*7f2fe78bSCy Schubert encoded_ticket, &finish.ticket_checksum);
328*7f2fe78bSCy Schubert if (retval == 0)
329*7f2fe78bSCy Schubert retval = encrypt_fast_reply(state, &fast_response, &encrypted_reply);
330*7f2fe78bSCy Schubert if (retval == 0) {
331*7f2fe78bSCy Schubert pa[0].pa_type = KRB5_PADATA_FX_FAST;
332*7f2fe78bSCy Schubert pa[0].length = encrypted_reply->length;
333*7f2fe78bSCy Schubert pa[0].contents = (unsigned char *) encrypted_reply->data;
334*7f2fe78bSCy Schubert pa_array[0] = &pa[0];
335*7f2fe78bSCy Schubert krb5_free_pa_data(context, rep->padata);
336*7f2fe78bSCy Schubert rep->padata = pa_array;
337*7f2fe78bSCy Schubert pa_array = NULL;
338*7f2fe78bSCy Schubert free(encrypted_reply);
339*7f2fe78bSCy Schubert encrypted_reply = NULL;
340*7f2fe78bSCy Schubert pa = NULL;
341*7f2fe78bSCy Schubert }
342*7f2fe78bSCy Schubert if (pa)
343*7f2fe78bSCy Schubert free(pa);
344*7f2fe78bSCy Schubert if (pa_array)
345*7f2fe78bSCy Schubert free(pa_array);
346*7f2fe78bSCy Schubert if (encrypted_reply)
347*7f2fe78bSCy Schubert krb5_free_data(context, encrypted_reply);
348*7f2fe78bSCy Schubert if (encoded_ticket)
349*7f2fe78bSCy Schubert krb5_free_data(context, encoded_ticket);
350*7f2fe78bSCy Schubert if (strengthen_key != NULL)
351*7f2fe78bSCy Schubert krb5_free_keyblock(context, strengthen_key);
352*7f2fe78bSCy Schubert if (finish.ticket_checksum.contents)
353*7f2fe78bSCy Schubert krb5_free_checksum_contents(context, &finish.ticket_checksum);
354*7f2fe78bSCy Schubert return retval;
355*7f2fe78bSCy Schubert }
356*7f2fe78bSCy Schubert
357*7f2fe78bSCy Schubert
358*7f2fe78bSCy Schubert /*
359*7f2fe78bSCy Schubert * We assume the caller is responsible for passing us an in_padata
360*7f2fe78bSCy Schubert * sufficient to include in a FAST error. In the FAST case we will
361*7f2fe78bSCy Schubert * set *fast_edata_out to the edata to be included in the error; in
362*7f2fe78bSCy Schubert * the non-FAST case we will set it to NULL.
363*7f2fe78bSCy Schubert */
364*7f2fe78bSCy Schubert krb5_error_code
kdc_fast_handle_error(krb5_context context,struct kdc_request_state * state,krb5_kdc_req * request,krb5_pa_data ** in_padata,krb5_error * err,krb5_data ** fast_edata_out)365*7f2fe78bSCy Schubert kdc_fast_handle_error(krb5_context context,
366*7f2fe78bSCy Schubert struct kdc_request_state *state,
367*7f2fe78bSCy Schubert krb5_kdc_req *request,
368*7f2fe78bSCy Schubert krb5_pa_data **in_padata, krb5_error *err,
369*7f2fe78bSCy Schubert krb5_data **fast_edata_out)
370*7f2fe78bSCy Schubert {
371*7f2fe78bSCy Schubert krb5_error_code retval = 0;
372*7f2fe78bSCy Schubert krb5_fast_response resp;
373*7f2fe78bSCy Schubert krb5_error fx_error;
374*7f2fe78bSCy Schubert krb5_data *encoded_fx_error = NULL, *encrypted_reply = NULL;
375*7f2fe78bSCy Schubert krb5_pa_data pa[1];
376*7f2fe78bSCy Schubert krb5_pa_data *outer_pa[3];
377*7f2fe78bSCy Schubert krb5_pa_data **inner_pa = NULL;
378*7f2fe78bSCy Schubert size_t size = 0;
379*7f2fe78bSCy Schubert
380*7f2fe78bSCy Schubert *fast_edata_out = NULL;
381*7f2fe78bSCy Schubert memset(outer_pa, 0, sizeof(outer_pa));
382*7f2fe78bSCy Schubert if (state->armor_key == NULL)
383*7f2fe78bSCy Schubert return 0;
384*7f2fe78bSCy Schubert fx_error = *err;
385*7f2fe78bSCy Schubert fx_error.e_data.data = NULL;
386*7f2fe78bSCy Schubert fx_error.e_data.length = 0;
387*7f2fe78bSCy Schubert for (size = 0; in_padata&&in_padata[size]; size++);
388*7f2fe78bSCy Schubert inner_pa = calloc(size + 2, sizeof(krb5_pa_data *));
389*7f2fe78bSCy Schubert if (inner_pa == NULL)
390*7f2fe78bSCy Schubert retval = ENOMEM;
391*7f2fe78bSCy Schubert if (retval == 0)
392*7f2fe78bSCy Schubert for (size=0; in_padata&&in_padata[size]; size++)
393*7f2fe78bSCy Schubert inner_pa[size] = in_padata[size];
394*7f2fe78bSCy Schubert if (retval == 0)
395*7f2fe78bSCy Schubert retval = encode_krb5_error(&fx_error, &encoded_fx_error);
396*7f2fe78bSCy Schubert if (retval == 0) {
397*7f2fe78bSCy Schubert pa[0].pa_type = KRB5_PADATA_FX_ERROR;
398*7f2fe78bSCy Schubert pa[0].length = encoded_fx_error->length;
399*7f2fe78bSCy Schubert pa[0].contents = (unsigned char *) encoded_fx_error->data;
400*7f2fe78bSCy Schubert inner_pa[size++] = &pa[0];
401*7f2fe78bSCy Schubert }
402*7f2fe78bSCy Schubert if (retval == 0) {
403*7f2fe78bSCy Schubert resp.padata = inner_pa;
404*7f2fe78bSCy Schubert resp.nonce = request->nonce;
405*7f2fe78bSCy Schubert resp.strengthen_key = NULL;
406*7f2fe78bSCy Schubert resp.finished = NULL;
407*7f2fe78bSCy Schubert }
408*7f2fe78bSCy Schubert if (retval == 0)
409*7f2fe78bSCy Schubert retval = encrypt_fast_reply(state, &resp, &encrypted_reply);
410*7f2fe78bSCy Schubert if (inner_pa)
411*7f2fe78bSCy Schubert free(inner_pa); /*contained storage from caller and our stack*/
412*7f2fe78bSCy Schubert if (retval == 0) {
413*7f2fe78bSCy Schubert pa[0].pa_type = KRB5_PADATA_FX_FAST;
414*7f2fe78bSCy Schubert pa[0].length = encrypted_reply->length;
415*7f2fe78bSCy Schubert pa[0].contents = (unsigned char *) encrypted_reply->data;
416*7f2fe78bSCy Schubert outer_pa[0] = &pa[0];
417*7f2fe78bSCy Schubert }
418*7f2fe78bSCy Schubert retval = encode_krb5_padata_sequence(outer_pa, fast_edata_out);
419*7f2fe78bSCy Schubert if (encrypted_reply)
420*7f2fe78bSCy Schubert krb5_free_data(context, encrypted_reply);
421*7f2fe78bSCy Schubert if (encoded_fx_error)
422*7f2fe78bSCy Schubert krb5_free_data(context, encoded_fx_error);
423*7f2fe78bSCy Schubert return retval;
424*7f2fe78bSCy Schubert }
425*7f2fe78bSCy Schubert
426*7f2fe78bSCy Schubert krb5_error_code
kdc_fast_handle_reply_key(struct kdc_request_state * state,krb5_keyblock * existing_key,krb5_keyblock ** out_key)427*7f2fe78bSCy Schubert kdc_fast_handle_reply_key(struct kdc_request_state *state,
428*7f2fe78bSCy Schubert krb5_keyblock *existing_key,
429*7f2fe78bSCy Schubert krb5_keyblock **out_key)
430*7f2fe78bSCy Schubert {
431*7f2fe78bSCy Schubert krb5_context context = state->realm_data->realm_context;
432*7f2fe78bSCy Schubert krb5_error_code retval = 0;
433*7f2fe78bSCy Schubert
434*7f2fe78bSCy Schubert if (state->armor_key)
435*7f2fe78bSCy Schubert retval = krb5_c_fx_cf2_simple(context,
436*7f2fe78bSCy Schubert state->strengthen_key, "strengthenkey",
437*7f2fe78bSCy Schubert existing_key, "replykey", out_key);
438*7f2fe78bSCy Schubert else
439*7f2fe78bSCy Schubert retval = krb5_copy_keyblock(context, existing_key, out_key);
440*7f2fe78bSCy Schubert return retval;
441*7f2fe78bSCy Schubert }
442*7f2fe78bSCy Schubert
443*7f2fe78bSCy Schubert krb5_boolean
kdc_fast_hide_client(struct kdc_request_state * state)444*7f2fe78bSCy Schubert kdc_fast_hide_client(struct kdc_request_state *state)
445*7f2fe78bSCy Schubert {
446*7f2fe78bSCy Schubert return (state->fast_options & KRB5_FAST_OPTION_HIDE_CLIENT_NAMES) != 0;
447*7f2fe78bSCy Schubert }
448*7f2fe78bSCy Schubert
449*7f2fe78bSCy Schubert /* Create a pa-data entry with the specified type and contents. */
450*7f2fe78bSCy Schubert static krb5_error_code
make_padata(krb5_preauthtype pa_type,const void * contents,size_t len,krb5_pa_data ** out)451*7f2fe78bSCy Schubert make_padata(krb5_preauthtype pa_type, const void *contents, size_t len,
452*7f2fe78bSCy Schubert krb5_pa_data **out)
453*7f2fe78bSCy Schubert {
454*7f2fe78bSCy Schubert if (k5_alloc_pa_data(pa_type, len, out) != 0)
455*7f2fe78bSCy Schubert return ENOMEM;
456*7f2fe78bSCy Schubert memcpy((*out)->contents, contents, len);
457*7f2fe78bSCy Schubert return 0;
458*7f2fe78bSCy Schubert }
459*7f2fe78bSCy Schubert
460*7f2fe78bSCy Schubert /*
461*7f2fe78bSCy Schubert * Derive the secure cookie encryption key from tgt_key and client_princ. The
462*7f2fe78bSCy Schubert * cookie key is derived with PRF+ using the concatenation of "COOKIE" and the
463*7f2fe78bSCy Schubert * unparsed client principal name as input.
464*7f2fe78bSCy Schubert */
465*7f2fe78bSCy Schubert static krb5_error_code
derive_cookie_key(krb5_context context,krb5_keyblock * tgt_key,krb5_const_principal client_princ,krb5_keyblock ** key_out)466*7f2fe78bSCy Schubert derive_cookie_key(krb5_context context, krb5_keyblock *tgt_key,
467*7f2fe78bSCy Schubert krb5_const_principal client_princ, krb5_keyblock **key_out)
468*7f2fe78bSCy Schubert {
469*7f2fe78bSCy Schubert krb5_error_code ret;
470*7f2fe78bSCy Schubert krb5_data d;
471*7f2fe78bSCy Schubert char *princstr = NULL, *derive_input = NULL;
472*7f2fe78bSCy Schubert
473*7f2fe78bSCy Schubert *key_out = NULL;
474*7f2fe78bSCy Schubert
475*7f2fe78bSCy Schubert /* Construct the input string and derive the cookie key. */
476*7f2fe78bSCy Schubert ret = krb5_unparse_name(context, client_princ, &princstr);
477*7f2fe78bSCy Schubert if (ret)
478*7f2fe78bSCy Schubert goto cleanup;
479*7f2fe78bSCy Schubert if (asprintf(&derive_input, "COOKIE%s", princstr) < 0) {
480*7f2fe78bSCy Schubert ret = ENOMEM;
481*7f2fe78bSCy Schubert goto cleanup;
482*7f2fe78bSCy Schubert }
483*7f2fe78bSCy Schubert d = string2data(derive_input);
484*7f2fe78bSCy Schubert ret = krb5_c_derive_prfplus(context, tgt_key, &d, ENCTYPE_NULL, key_out);
485*7f2fe78bSCy Schubert
486*7f2fe78bSCy Schubert cleanup:
487*7f2fe78bSCy Schubert krb5_free_unparsed_name(context, princstr);
488*7f2fe78bSCy Schubert free(derive_input);
489*7f2fe78bSCy Schubert return ret;
490*7f2fe78bSCy Schubert }
491*7f2fe78bSCy Schubert
492*7f2fe78bSCy Schubert /* Derive the cookie key for the specified kvno in tgt. tgt_key must be the
493*7f2fe78bSCy Schubert * decrypted first key data entry in tgt. */
494*7f2fe78bSCy Schubert static krb5_error_code
get_cookie_key(krb5_context context,krb5_db_entry * tgt,krb5_keyblock * tgt_key,krb5_kvno kvno,krb5_const_principal client_princ,krb5_keyblock ** key_out)495*7f2fe78bSCy Schubert get_cookie_key(krb5_context context, krb5_db_entry *tgt,
496*7f2fe78bSCy Schubert krb5_keyblock *tgt_key, krb5_kvno kvno,
497*7f2fe78bSCy Schubert krb5_const_principal client_princ, krb5_keyblock **key_out)
498*7f2fe78bSCy Schubert {
499*7f2fe78bSCy Schubert krb5_error_code ret;
500*7f2fe78bSCy Schubert krb5_keyblock storage, *key;
501*7f2fe78bSCy Schubert krb5_key_data *kd;
502*7f2fe78bSCy Schubert
503*7f2fe78bSCy Schubert *key_out = NULL;
504*7f2fe78bSCy Schubert memset(&storage, 0, sizeof(storage));
505*7f2fe78bSCy Schubert
506*7f2fe78bSCy Schubert if (kvno == current_kvno(tgt)) {
507*7f2fe78bSCy Schubert /* Use the already-decrypted first key. */
508*7f2fe78bSCy Schubert key = tgt_key;
509*7f2fe78bSCy Schubert } else {
510*7f2fe78bSCy Schubert /* The cookie used an older TGT key; find and decrypt it. */
511*7f2fe78bSCy Schubert ret = krb5_dbe_find_enctype(context, tgt, -1, -1, kvno, &kd);
512*7f2fe78bSCy Schubert if (ret)
513*7f2fe78bSCy Schubert return ret;
514*7f2fe78bSCy Schubert ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &storage, NULL);
515*7f2fe78bSCy Schubert if (ret)
516*7f2fe78bSCy Schubert return ret;
517*7f2fe78bSCy Schubert key = &storage;
518*7f2fe78bSCy Schubert }
519*7f2fe78bSCy Schubert
520*7f2fe78bSCy Schubert ret = derive_cookie_key(context, key, client_princ, key_out);
521*7f2fe78bSCy Schubert krb5_free_keyblock_contents(context, &storage);
522*7f2fe78bSCy Schubert return ret;
523*7f2fe78bSCy Schubert }
524*7f2fe78bSCy Schubert
525*7f2fe78bSCy Schubert /* Return true if there is any overlap between padata types in cpadata
526*7f2fe78bSCy Schubert * (from the cookie) and rpadata (from the request). */
527*7f2fe78bSCy Schubert static krb5_boolean
is_relevant(krb5_pa_data * const * cpadata,krb5_pa_data * const * rpadata)528*7f2fe78bSCy Schubert is_relevant(krb5_pa_data *const *cpadata, krb5_pa_data *const *rpadata)
529*7f2fe78bSCy Schubert {
530*7f2fe78bSCy Schubert krb5_pa_data *const *p;
531*7f2fe78bSCy Schubert
532*7f2fe78bSCy Schubert for (p = cpadata; p != NULL && *p != NULL; p++) {
533*7f2fe78bSCy Schubert if (krb5int_find_pa_data(NULL, rpadata, (*p)->pa_type) != NULL)
534*7f2fe78bSCy Schubert return TRUE;
535*7f2fe78bSCy Schubert }
536*7f2fe78bSCy Schubert return FALSE;
537*7f2fe78bSCy Schubert }
538*7f2fe78bSCy Schubert
539*7f2fe78bSCy Schubert /*
540*7f2fe78bSCy Schubert * Locate and decode the FAST cookie in req, storing its contents in state for
541*7f2fe78bSCy Schubert * later access by preauth modules. If the cookie is expired, return
542*7f2fe78bSCy Schubert * KRB5KDC_ERR_PREAUTH_EXPIRED if its contents are relevant to req, and ignore
543*7f2fe78bSCy Schubert * it if they aren't.
544*7f2fe78bSCy Schubert */
545*7f2fe78bSCy Schubert krb5_error_code
kdc_fast_read_cookie(krb5_context context,struct kdc_request_state * state,krb5_kdc_req * req,krb5_db_entry * local_tgt,krb5_keyblock * local_tgt_key)546*7f2fe78bSCy Schubert kdc_fast_read_cookie(krb5_context context, struct kdc_request_state *state,
547*7f2fe78bSCy Schubert krb5_kdc_req *req, krb5_db_entry *local_tgt,
548*7f2fe78bSCy Schubert krb5_keyblock *local_tgt_key)
549*7f2fe78bSCy Schubert {
550*7f2fe78bSCy Schubert krb5_error_code ret;
551*7f2fe78bSCy Schubert krb5_secure_cookie *cookie = NULL;
552*7f2fe78bSCy Schubert krb5_timestamp now;
553*7f2fe78bSCy Schubert krb5_keyblock *key = NULL;
554*7f2fe78bSCy Schubert krb5_enc_data enc;
555*7f2fe78bSCy Schubert krb5_pa_data *pa;
556*7f2fe78bSCy Schubert krb5_kvno kvno;
557*7f2fe78bSCy Schubert krb5_data plain = empty_data();
558*7f2fe78bSCy Schubert
559*7f2fe78bSCy Schubert pa = krb5int_find_pa_data(context, req->padata, KRB5_PADATA_FX_COOKIE);
560*7f2fe78bSCy Schubert if (pa == NULL)
561*7f2fe78bSCy Schubert return 0;
562*7f2fe78bSCy Schubert
563*7f2fe78bSCy Schubert /* If it's not an MIT version 1 cookie, ignore it. It may be an empty
564*7f2fe78bSCy Schubert * "MIT" cookie or a cookie generated by a different KDC implementation. */
565*7f2fe78bSCy Schubert if (pa->length <= 8 || memcmp(pa->contents, "MIT1", 4) != 0)
566*7f2fe78bSCy Schubert return 0;
567*7f2fe78bSCy Schubert
568*7f2fe78bSCy Schubert /* Extract the kvno and generate the corresponding cookie key. */
569*7f2fe78bSCy Schubert kvno = load_32_be(pa->contents + 4);
570*7f2fe78bSCy Schubert ret = get_cookie_key(context, local_tgt, local_tgt_key, kvno, req->client,
571*7f2fe78bSCy Schubert &key);
572*7f2fe78bSCy Schubert if (ret)
573*7f2fe78bSCy Schubert goto cleanup;
574*7f2fe78bSCy Schubert
575*7f2fe78bSCy Schubert /* Decrypt and decode the cookie. */
576*7f2fe78bSCy Schubert memset(&enc, 0, sizeof(enc));
577*7f2fe78bSCy Schubert enc.enctype = key->enctype;
578*7f2fe78bSCy Schubert enc.ciphertext = make_data(pa->contents + 8, pa->length - 8);
579*7f2fe78bSCy Schubert ret = alloc_data(&plain, pa->length - 8);
580*7f2fe78bSCy Schubert if (ret)
581*7f2fe78bSCy Schubert goto cleanup;
582*7f2fe78bSCy Schubert ret = krb5_c_decrypt(context, key, KRB5_KEYUSAGE_PA_FX_COOKIE, NULL, &enc,
583*7f2fe78bSCy Schubert &plain);
584*7f2fe78bSCy Schubert if (ret)
585*7f2fe78bSCy Schubert goto cleanup;
586*7f2fe78bSCy Schubert ret = decode_krb5_secure_cookie(&plain, &cookie);
587*7f2fe78bSCy Schubert if (ret)
588*7f2fe78bSCy Schubert goto cleanup;
589*7f2fe78bSCy Schubert
590*7f2fe78bSCy Schubert /* Check if the cookie is expired. */
591*7f2fe78bSCy Schubert ret = krb5_timeofday(context, &now);
592*7f2fe78bSCy Schubert if (ret)
593*7f2fe78bSCy Schubert goto cleanup;
594*7f2fe78bSCy Schubert if (ts2tt(now) > cookie->time + COOKIE_LIFETIME) {
595*7f2fe78bSCy Schubert /* Don't accept the cookie contents. Only return an error if the
596*7f2fe78bSCy Schubert * cookie is relevant to the request. */
597*7f2fe78bSCy Schubert if (is_relevant(cookie->data, req->padata))
598*7f2fe78bSCy Schubert ret = KRB5KDC_ERR_PREAUTH_EXPIRED;
599*7f2fe78bSCy Schubert goto cleanup;
600*7f2fe78bSCy Schubert }
601*7f2fe78bSCy Schubert
602*7f2fe78bSCy Schubert /* Steal the pa-data list pointer from the cookie and store it in state. */
603*7f2fe78bSCy Schubert state->in_cookie_padata = cookie->data;
604*7f2fe78bSCy Schubert cookie->data = NULL;
605*7f2fe78bSCy Schubert
606*7f2fe78bSCy Schubert cleanup:
607*7f2fe78bSCy Schubert zapfree(plain.data, plain.length);
608*7f2fe78bSCy Schubert krb5_free_keyblock(context, key);
609*7f2fe78bSCy Schubert k5_free_secure_cookie(context, cookie);
610*7f2fe78bSCy Schubert return 0;
611*7f2fe78bSCy Schubert }
612*7f2fe78bSCy Schubert
613*7f2fe78bSCy Schubert /* If state contains a cookie value for pa_type, set *out to the corresponding
614*7f2fe78bSCy Schubert * data and return true. Otherwise set *out to empty and return false. */
615*7f2fe78bSCy Schubert krb5_boolean
kdc_fast_search_cookie(struct kdc_request_state * state,krb5_preauthtype pa_type,krb5_data * out)616*7f2fe78bSCy Schubert kdc_fast_search_cookie(struct kdc_request_state *state,
617*7f2fe78bSCy Schubert krb5_preauthtype pa_type, krb5_data *out)
618*7f2fe78bSCy Schubert {
619*7f2fe78bSCy Schubert krb5_pa_data *pa;
620*7f2fe78bSCy Schubert
621*7f2fe78bSCy Schubert pa = krb5int_find_pa_data(NULL, state->in_cookie_padata, pa_type);
622*7f2fe78bSCy Schubert if (pa == NULL) {
623*7f2fe78bSCy Schubert *out = empty_data();
624*7f2fe78bSCy Schubert return FALSE;
625*7f2fe78bSCy Schubert } else {
626*7f2fe78bSCy Schubert *out = make_data(pa->contents, pa->length);
627*7f2fe78bSCy Schubert return TRUE;
628*7f2fe78bSCy Schubert }
629*7f2fe78bSCy Schubert }
630*7f2fe78bSCy Schubert
631*7f2fe78bSCy Schubert /* Set a cookie value in state for data, to be included in the outgoing
632*7f2fe78bSCy Schubert * cookie. Duplicate values are ignored. */
633*7f2fe78bSCy Schubert krb5_error_code
kdc_fast_set_cookie(struct kdc_request_state * state,krb5_preauthtype pa_type,const krb5_data * data)634*7f2fe78bSCy Schubert kdc_fast_set_cookie(struct kdc_request_state *state, krb5_preauthtype pa_type,
635*7f2fe78bSCy Schubert const krb5_data *data)
636*7f2fe78bSCy Schubert {
637*7f2fe78bSCy Schubert krb5_pa_data **list = state->out_cookie_padata;
638*7f2fe78bSCy Schubert size_t count;
639*7f2fe78bSCy Schubert
640*7f2fe78bSCy Schubert for (count = 0; list != NULL && list[count] != NULL; count++) {
641*7f2fe78bSCy Schubert if (list[count]->pa_type == pa_type)
642*7f2fe78bSCy Schubert return 0;
643*7f2fe78bSCy Schubert }
644*7f2fe78bSCy Schubert
645*7f2fe78bSCy Schubert list = realloc(list, (count + 2) * sizeof(*list));
646*7f2fe78bSCy Schubert if (list == NULL)
647*7f2fe78bSCy Schubert return ENOMEM;
648*7f2fe78bSCy Schubert state->out_cookie_padata = list;
649*7f2fe78bSCy Schubert list[count] = list[count + 1] = NULL;
650*7f2fe78bSCy Schubert return make_padata(pa_type, data->data, data->length, &list[count]);
651*7f2fe78bSCy Schubert }
652*7f2fe78bSCy Schubert
653*7f2fe78bSCy Schubert /* Construct a cookie pa-data item using the cookie values from state, or a
654*7f2fe78bSCy Schubert * trivial "MIT" cookie if no values are set. */
655*7f2fe78bSCy Schubert krb5_error_code
kdc_fast_make_cookie(krb5_context context,struct kdc_request_state * state,krb5_db_entry * local_tgt,krb5_keyblock * local_tgt_key,krb5_const_principal client_princ,krb5_pa_data ** cookie_out)656*7f2fe78bSCy Schubert kdc_fast_make_cookie(krb5_context context, struct kdc_request_state *state,
657*7f2fe78bSCy Schubert krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key,
658*7f2fe78bSCy Schubert krb5_const_principal client_princ,
659*7f2fe78bSCy Schubert krb5_pa_data **cookie_out)
660*7f2fe78bSCy Schubert {
661*7f2fe78bSCy Schubert krb5_error_code ret;
662*7f2fe78bSCy Schubert krb5_secure_cookie cookie;
663*7f2fe78bSCy Schubert krb5_pa_data **contents = state->out_cookie_padata, *pa;
664*7f2fe78bSCy Schubert krb5_keyblock *key = NULL;
665*7f2fe78bSCy Schubert krb5_timestamp now;
666*7f2fe78bSCy Schubert krb5_enc_data enc;
667*7f2fe78bSCy Schubert krb5_data *der_cookie = NULL;
668*7f2fe78bSCy Schubert size_t ctlen;
669*7f2fe78bSCy Schubert
670*7f2fe78bSCy Schubert *cookie_out = NULL;
671*7f2fe78bSCy Schubert memset(&enc, 0, sizeof(enc));
672*7f2fe78bSCy Schubert
673*7f2fe78bSCy Schubert /* Make a trivial cookie if there are no contents to marshal or we don't
674*7f2fe78bSCy Schubert * have a TGT entry to encrypt them. */
675*7f2fe78bSCy Schubert if (contents == NULL || *contents == NULL || local_tgt_key == NULL)
676*7f2fe78bSCy Schubert return make_padata(KRB5_PADATA_FX_COOKIE, "MIT", 3, cookie_out);
677*7f2fe78bSCy Schubert
678*7f2fe78bSCy Schubert ret = derive_cookie_key(context, local_tgt_key, client_princ, &key);
679*7f2fe78bSCy Schubert if (ret)
680*7f2fe78bSCy Schubert goto cleanup;
681*7f2fe78bSCy Schubert
682*7f2fe78bSCy Schubert /* Encode the cookie. */
683*7f2fe78bSCy Schubert ret = krb5_timeofday(context, &now);
684*7f2fe78bSCy Schubert if (ret)
685*7f2fe78bSCy Schubert goto cleanup;
686*7f2fe78bSCy Schubert cookie.time = ts2tt(now);
687*7f2fe78bSCy Schubert cookie.data = contents;
688*7f2fe78bSCy Schubert ret = encode_krb5_secure_cookie(&cookie, &der_cookie);
689*7f2fe78bSCy Schubert if (ret)
690*7f2fe78bSCy Schubert goto cleanup;
691*7f2fe78bSCy Schubert
692*7f2fe78bSCy Schubert /* Encrypt the cookie in key. */
693*7f2fe78bSCy Schubert ret = krb5_c_encrypt_length(context, key->enctype, der_cookie->length,
694*7f2fe78bSCy Schubert &ctlen);
695*7f2fe78bSCy Schubert if (ret)
696*7f2fe78bSCy Schubert goto cleanup;
697*7f2fe78bSCy Schubert ret = alloc_data(&enc.ciphertext, ctlen);
698*7f2fe78bSCy Schubert if (ret)
699*7f2fe78bSCy Schubert goto cleanup;
700*7f2fe78bSCy Schubert ret = krb5_c_encrypt(context, key, KRB5_KEYUSAGE_PA_FX_COOKIE, NULL,
701*7f2fe78bSCy Schubert der_cookie, &enc);
702*7f2fe78bSCy Schubert if (ret)
703*7f2fe78bSCy Schubert goto cleanup;
704*7f2fe78bSCy Schubert
705*7f2fe78bSCy Schubert /* Construct the cookie pa-data entry. */
706*7f2fe78bSCy Schubert ret = k5_alloc_pa_data(KRB5_PADATA_FX_COOKIE, 8 + enc.ciphertext.length,
707*7f2fe78bSCy Schubert &pa);
708*7f2fe78bSCy Schubert memcpy(pa->contents, "MIT1", 4);
709*7f2fe78bSCy Schubert store_32_be(current_kvno(local_tgt), pa->contents + 4);
710*7f2fe78bSCy Schubert memcpy(pa->contents + 8, enc.ciphertext.data, enc.ciphertext.length);
711*7f2fe78bSCy Schubert *cookie_out = pa;
712*7f2fe78bSCy Schubert
713*7f2fe78bSCy Schubert cleanup:
714*7f2fe78bSCy Schubert krb5_free_keyblock(context, key);
715*7f2fe78bSCy Schubert if (der_cookie != NULL) {
716*7f2fe78bSCy Schubert zapfree(der_cookie->data, der_cookie->length);
717*7f2fe78bSCy Schubert free(der_cookie);
718*7f2fe78bSCy Schubert }
719*7f2fe78bSCy Schubert krb5_free_data_contents(context, &enc.ciphertext);
720*7f2fe78bSCy Schubert return ret;
721*7f2fe78bSCy Schubert }
722