Branch data Line data Source code
1 : : /* krb5/context.c --- Implementation of Kerberos 5 GSS Context functions.
2 : : * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Simon Josefsson
3 : : *
4 : : * This file is part of the Generic Security Service (GSS).
5 : : *
6 : : * GSS is free software; you can redistribute it and/or modify it
7 : : * under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 3 of the License, or
9 : : * (at your option) any later version.
10 : : *
11 : : * GSS is distributed in the hope that it will be useful, but WITHOUT
12 : : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 : : * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 : : * License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with GSS; if not, see http://www.gnu.org/licenses or write to
18 : : * the Free Software Foundation, Inc., 51 Franklin Street, Fifth
19 : : * Floor, Boston, MA 02110-1301, USA.
20 : : *
21 : : */
22 : :
23 : : /* Get specification. */
24 : : #include "k5internal.h"
25 : :
26 : : /* Get checksum (un)packers. */
27 : : #include "checksum.h"
28 : :
29 : : #define TOK_LEN 2
30 : : #define TOK_AP_REQ "\x01\x00"
31 : : #define TOK_AP_REP "\x02\x00"
32 : :
33 : : /* Request part of gss_krb5_init_sec_context. Assumes that
34 : : context_handle is valid, and has krb5 specific structure, and that
35 : : output_token is valid and cleared. */
36 : : static OM_uint32
37 : 3 : init_request (OM_uint32 * minor_status,
38 : : const gss_cred_id_t initiator_cred_handle,
39 : : gss_ctx_id_t * context_handle,
40 : : const gss_name_t target_name,
41 : : const gss_OID mech_type,
42 : : OM_uint32 req_flags,
43 : : OM_uint32 time_req,
44 : : const gss_channel_bindings_t input_chan_bindings,
45 : : const gss_buffer_t input_token,
46 : : gss_OID * actual_mech_type,
47 : : gss_buffer_t output_token,
48 : : OM_uint32 * ret_flags, OM_uint32 * time_rec)
49 : : {
50 : 3 : gss_ctx_id_t ctx = *context_handle;
51 : 3 : _gss_krb5_ctx_t k5 = ctx->krb5;
52 : : char *cksum, *der;
53 : : size_t cksumlen, derlen;
54 : : int rc;
55 : : OM_uint32 maj_stat;
56 : : Shishi_tkts_hint hint;
57 : :
58 : : /* Get service ticket. */
59 : 3 : maj_stat = gss_krb5_canonicalize_name (minor_status, target_name,
60 : : GSS_C_NO_OID, &k5->peerptr);
61 [ - + ]: 3 : if (GSS_ERROR (maj_stat))
62 : 0 : return maj_stat;
63 : :
64 : 3 : memset (&hint, 0, sizeof (hint));
65 : 3 : hint.server = k5->peerptr->value;
66 : 3 : hint.endtime = time_req;
67 : :
68 : 3 : k5->tkt = shishi_tkts_get (shishi_tkts_default (k5->sh), &hint);
69 [ - + ]: 3 : if (!k5->tkt)
70 : : {
71 [ # # ]: 0 : if (minor_status)
72 : 0 : *minor_status = GSS_KRB5_S_KG_CCACHE_NOMATCH;
73 : 0 : return GSS_S_NO_CRED;
74 : : }
75 : :
76 : : /* Create Authenticator checksum field. */
77 : 3 : maj_stat = _gss_krb5_checksum_pack (minor_status, initiator_cred_handle,
78 : : context_handle,
79 : : input_chan_bindings, req_flags,
80 : : &cksum, &cksumlen);
81 [ - + ]: 3 : if (GSS_ERROR (maj_stat))
82 : 0 : return maj_stat;
83 : :
84 : : /* Create AP-REQ in output_token. */
85 : 3 : rc = shishi_ap_tktoptionsraw (k5->sh, &k5->ap, k5->tkt,
86 : : SHISHI_APOPTIONS_MUTUAL_REQUIRED,
87 : : 0x8003, cksum, cksumlen);
88 : 3 : free (cksum);
89 [ - + ]: 3 : if (rc != SHISHI_OK)
90 : 0 : return GSS_S_FAILURE;
91 : :
92 : 3 : rc = shishi_authenticator_seqnumber_get (k5->sh,
93 : : shishi_ap_authenticator (k5->ap),
94 : : &k5->initseqnr);
95 [ - + ]: 3 : if (rc != SHISHI_OK)
96 : 0 : return GSS_S_FAILURE;
97 : :
98 : 3 : rc = shishi_ap_req_der (k5->ap, &der, &derlen);
99 [ - + ]: 3 : if (rc != SHISHI_OK)
100 : 0 : return GSS_S_FAILURE;
101 : :
102 : 3 : rc = _gss_encapsulate_token_prefix (TOK_AP_REQ, TOK_LEN,
103 : : der, derlen,
104 : 3 : GSS_KRB5->elements,
105 : 3 : GSS_KRB5->length,
106 : : &output_token->value,
107 : : &output_token->length);
108 : 3 : free (der);
109 [ - + ]: 3 : if (rc != 0)
110 : 0 : return GSS_S_FAILURE;
111 : :
112 [ + + ]: 3 : if (req_flags & GSS_C_MUTUAL_FLAG)
113 : 2 : return GSS_S_CONTINUE_NEEDED;
114 : :
115 : 3 : return GSS_S_COMPLETE;
116 : : }
117 : :
118 : : /* Reply part of gss_krb5_init_sec_context. Assumes that
119 : : context_handle is valid, and has krb5 specific structure, and that
120 : : output_token is valid and cleared. */
121 : : static OM_uint32
122 : 2 : init_reply (OM_uint32 * minor_status,
123 : : const gss_cred_id_t initiator_cred_handle,
124 : : gss_ctx_id_t * context_handle,
125 : : const gss_name_t target_name,
126 : : const gss_OID mech_type,
127 : : OM_uint32 req_flags,
128 : : OM_uint32 time_req,
129 : : const gss_channel_bindings_t input_chan_bindings,
130 : : const gss_buffer_t input_token,
131 : : gss_OID * actual_mech_type,
132 : : gss_buffer_t output_token,
133 : : OM_uint32 * ret_flags, OM_uint32 * time_rec)
134 : : {
135 : 2 : gss_ctx_id_t ctx = *context_handle;
136 : 2 : _gss_krb5_ctx_t k5 = ctx->krb5;
137 : : OM_uint32 tmp_min_stat;
138 : : gss_buffer_desc data;
139 : : int rc;
140 : :
141 [ - + ]: 2 : if (gss_decapsulate_token (input_token, GSS_KRB5, &data) != GSS_S_COMPLETE)
142 : 0 : return GSS_S_DEFECTIVE_TOKEN;
143 : :
144 [ - + ]: 2 : if (data.length < TOK_LEN)
145 : : {
146 : 0 : gss_release_buffer (&tmp_min_stat, &data);
147 : 0 : return GSS_S_DEFECTIVE_TOKEN;
148 : : }
149 : :
150 [ - + ]: 2 : if (memcmp (data.value, TOK_AP_REP, TOK_LEN) != 0)
151 : : {
152 : 0 : gss_release_buffer (&tmp_min_stat, &data);
153 : 0 : return GSS_S_DEFECTIVE_TOKEN;
154 : : }
155 : :
156 : 2 : rc = shishi_ap_rep_der_set (k5->ap, (char *) data.value + TOK_LEN,
157 : : data.length - TOK_LEN);
158 : 2 : gss_release_buffer (&tmp_min_stat, &data);
159 [ - + ]: 2 : if (rc != SHISHI_OK)
160 : 0 : return GSS_S_DEFECTIVE_TOKEN;
161 : :
162 : 2 : rc = shishi_ap_rep_verify (k5->ap);
163 [ - + ]: 2 : if (rc != SHISHI_OK)
164 : 0 : return GSS_S_DEFECTIVE_TOKEN;
165 : :
166 : 2 : rc = shishi_encapreppart_seqnumber_get (k5->sh,
167 : : shishi_ap_encapreppart (k5->ap),
168 : : &k5->acceptseqnr);
169 [ - + ]: 2 : if (rc != SHISHI_OK)
170 : : {
171 : : /* A strict 1964 implementation would return
172 : : GSS_S_DEFECTIVE_TOKEN here. gssapi-cfx permit absent
173 : : sequence number, though. */
174 : 0 : k5->acceptseqnr = 0;
175 : : }
176 : :
177 : 2 : return GSS_S_COMPLETE;
178 : : }
179 : :
180 : : /* Initiates the establishment of a krb5 security context between the
181 : : application and a remote peer. Assumes that context_handle and
182 : : output_token are valid and cleared. */
183 : : OM_uint32
184 : 5 : gss_krb5_init_sec_context (OM_uint32 * minor_status,
185 : : const gss_cred_id_t initiator_cred_handle,
186 : : gss_ctx_id_t * context_handle,
187 : : const gss_name_t target_name,
188 : : const gss_OID mech_type,
189 : : OM_uint32 req_flags,
190 : : OM_uint32 time_req,
191 : : const gss_channel_bindings_t input_chan_bindings,
192 : : const gss_buffer_t input_token,
193 : : gss_OID * actual_mech_type,
194 : : gss_buffer_t output_token,
195 : : OM_uint32 * ret_flags, OM_uint32 * time_rec)
196 : : {
197 : 5 : gss_ctx_id_t ctx = *context_handle;
198 : 5 : _gss_krb5_ctx_t k5 = ctx->krb5;
199 : : OM_uint32 maj_stat;
200 : : int rc;
201 : :
202 [ + - ]: 5 : if (minor_status)
203 : 5 : *minor_status = 0;
204 : :
205 [ - + ]: 5 : if (initiator_cred_handle)
206 : : {
207 : : /* We only support the default initiator. See k5internal.h for
208 : : adding a Shishi_tkt to the credential structure. I'm not sure
209 : : what the use would be -- user-to-user authentication perhaps?
210 : : Later: if you have tickets for foo@BAR and bar@FOO, it may be
211 : : useful to call gss_acquire_cred first to chose which one to
212 : : initiate the context with. Not many applications need this. */
213 : 0 : return GSS_S_NO_CRED;
214 : : }
215 : :
216 [ + + ]: 5 : if (k5 == NULL)
217 : : {
218 : 3 : k5 = ctx->krb5 = calloc (sizeof (*k5), 1);
219 [ - + ]: 3 : if (!k5)
220 : : {
221 [ # # ]: 0 : if (minor_status)
222 : 0 : *minor_status = ENOMEM;
223 : 0 : return GSS_S_FAILURE;
224 : : }
225 : :
226 : 3 : rc = shishi_init (&k5->sh);
227 [ - + ]: 3 : if (rc != SHISHI_OK)
228 : 0 : return GSS_S_FAILURE;
229 : : }
230 : :
231 [ + + ]: 5 : if (!k5->reqdone)
232 : : {
233 : 3 : maj_stat = init_request (minor_status,
234 : : initiator_cred_handle,
235 : : context_handle,
236 : : target_name,
237 : : mech_type,
238 : : req_flags,
239 : : time_req,
240 : : input_chan_bindings,
241 : : input_token,
242 : : actual_mech_type,
243 : : output_token, ret_flags, time_rec);
244 [ - + ]: 3 : if (GSS_ERROR (maj_stat))
245 : 0 : return maj_stat;
246 : :
247 : 3 : k5->flags = req_flags & ( /* GSS_C_DELEG_FLAG | */
248 : : GSS_C_MUTUAL_FLAG |
249 : : GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG |
250 : : GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);
251 : : /* PROT_READY is not mentioned in 1964/gssapi-cfx but we support
252 : : it anyway. */
253 : 3 : k5->flags |= GSS_C_PROT_READY_FLAG;
254 : :
255 [ + + ]: 3 : if (ret_flags)
256 : 1 : *ret_flags = k5->flags;
257 : :
258 : 3 : k5->key = shishi_ap_key (k5->ap);
259 : 3 : k5->reqdone = 1;
260 : : }
261 [ + - ][ + - ]: 4 : else if (k5->reqdone && k5->flags & GSS_C_MUTUAL_FLAG && !k5->repdone)
[ + - ]
262 : : {
263 : 2 : maj_stat = init_reply (minor_status,
264 : : initiator_cred_handle,
265 : : context_handle,
266 : : target_name,
267 : : mech_type,
268 : : req_flags,
269 : : time_req,
270 : : input_chan_bindings,
271 : : input_token,
272 : : actual_mech_type,
273 : : output_token, ret_flags, time_rec);
274 [ - + ]: 2 : if (GSS_ERROR (maj_stat))
275 : 0 : return maj_stat;
276 : :
277 [ + + ]: 2 : if (ret_flags)
278 : 1 : *ret_flags = k5->flags;
279 : :
280 : 2 : k5->repdone = 1;
281 : : }
282 : : else
283 : 0 : maj_stat = GSS_S_FAILURE;
284 : :
285 [ + + ]: 5 : if (time_rec)
286 : 1 : *time_rec = gss_krb5_tktlifetime (k5->tkt);
287 : :
288 : 5 : return maj_stat;
289 : : }
290 : :
291 : : /* Allows a remotely initiated security context between the
292 : : application and a remote peer to be established, using krb5.
293 : : Assumes context_handle is valid. */
294 : : OM_uint32
295 : 3 : gss_krb5_accept_sec_context (OM_uint32 * minor_status,
296 : : gss_ctx_id_t * context_handle,
297 : : const gss_cred_id_t acceptor_cred_handle,
298 : : const gss_buffer_t input_token_buffer,
299 : : const gss_channel_bindings_t input_chan_bindings,
300 : : gss_name_t * src_name,
301 : : gss_OID * mech_type,
302 : : gss_buffer_t output_token,
303 : : OM_uint32 * ret_flags,
304 : : OM_uint32 * time_rec,
305 : : gss_cred_id_t * delegated_cred_handle)
306 : : {
307 : : gss_buffer_desc in;
308 : : gss_ctx_id_t cx;
309 : : _gss_krb5_ctx_t cxk5;
310 : : _gss_krb5_cred_t crk5;
311 : : OM_uint32 tmp_min_stat;
312 : : int rc;
313 : :
314 [ + - ]: 3 : if (minor_status)
315 : 3 : *minor_status = 0;
316 : :
317 [ + - ]: 3 : if (ret_flags)
318 : 3 : *ret_flags = 0;
319 : :
320 [ - + ]: 3 : if (!acceptor_cred_handle)
321 : : /* XXX support GSS_C_NO_CREDENTIAL: acquire_cred() default server */
322 : 0 : return GSS_S_NO_CRED;
323 : :
324 [ - + ]: 3 : if (*context_handle)
325 : 0 : return GSS_S_FAILURE;
326 : :
327 : 3 : crk5 = acceptor_cred_handle->krb5;
328 : :
329 : 3 : cx = calloc (sizeof (*cx), 1);
330 [ - + ]: 3 : if (!cx)
331 : : {
332 [ # # ]: 0 : if (minor_status)
333 : 0 : *minor_status = ENOMEM;
334 : 0 : return GSS_S_FAILURE;
335 : : }
336 : :
337 : 3 : cxk5 = calloc (sizeof (*cxk5), 1);
338 [ - + ]: 3 : if (!cxk5)
339 : : {
340 : 0 : free (cx);
341 [ # # ]: 0 : if (minor_status)
342 : 0 : *minor_status = ENOMEM;
343 : 0 : return GSS_S_FAILURE;
344 : : }
345 : :
346 : 3 : cx->mech = GSS_KRB5;
347 : 3 : cx->krb5 = cxk5;
348 : : /* XXX cx->peer?? */
349 : 3 : *context_handle = cx;
350 : :
351 : 3 : cxk5->sh = crk5->sh;
352 : 3 : cxk5->key = crk5->key;
353 : 3 : cxk5->acceptor = 1;
354 : :
355 : 3 : rc = shishi_ap (cxk5->sh, &cxk5->ap);
356 [ - + ]: 3 : if (rc != SHISHI_OK)
357 : 0 : return GSS_S_FAILURE;
358 : :
359 : 3 : rc = gss_decapsulate_token (input_token_buffer, GSS_KRB5, &in);
360 [ - + ]: 3 : if (rc != GSS_S_COMPLETE)
361 : 0 : return GSS_S_BAD_MIC;
362 : :
363 [ - + ]: 3 : if (in.length < TOK_LEN)
364 : : {
365 : 0 : gss_release_buffer (&tmp_min_stat, &in);
366 : 0 : return GSS_S_BAD_MIC;
367 : : }
368 : :
369 [ - + ]: 3 : if (memcmp (in.value, TOK_AP_REQ, TOK_LEN) != 0)
370 : : {
371 : 0 : gss_release_buffer (&tmp_min_stat, &in);
372 : 0 : return GSS_S_BAD_MIC;
373 : : }
374 : :
375 : 3 : rc = shishi_ap_req_der_set (cxk5->ap, (char *) in.value + TOK_LEN,
376 : : in.length - TOK_LEN);
377 : 3 : gss_release_buffer (&tmp_min_stat, &in);
378 [ - + ]: 3 : if (rc != SHISHI_OK)
379 : 0 : return GSS_S_FAILURE;
380 : :
381 : 3 : rc = shishi_ap_req_process (cxk5->ap, crk5->key);
382 [ - + ]: 3 : if (rc != SHISHI_OK)
383 : : {
384 [ # # ]: 0 : if (minor_status)
385 : 0 : *minor_status = GSS_KRB5_S_G_VALIDATE_FAILED;
386 : 0 : return GSS_S_FAILURE;
387 : : }
388 : :
389 : 3 : rc = shishi_authenticator_seqnumber_get (cxk5->sh,
390 : : shishi_ap_authenticator (cxk5->ap),
391 : : &cxk5->initseqnr);
392 [ - + ]: 3 : if (rc != SHISHI_OK)
393 : 0 : return GSS_S_FAILURE;
394 : :
395 : 3 : rc = _gss_krb5_checksum_parse (minor_status,
396 : : context_handle, input_chan_bindings);
397 [ - + ]: 3 : if (rc != GSS_S_COMPLETE)
398 : 0 : return GSS_S_FAILURE;
399 : :
400 : 3 : cxk5->tkt = shishi_ap_tkt (cxk5->ap);
401 : 3 : cxk5->key = shishi_ap_key (cxk5->ap);
402 : :
403 [ + - ]: 3 : if (shishi_apreq_mutual_required_p (crk5->sh, shishi_ap_req (cxk5->ap)))
404 : : {
405 : : Shishi_asn1 aprep;
406 : : char *der;
407 : : size_t len;
408 : :
409 : 3 : rc = shishi_ap_rep_asn1 (cxk5->ap, &aprep);
410 [ - + ]: 3 : if (rc != SHISHI_OK)
411 : : {
412 : 0 : printf ("Error creating AP-REP: %s\n", shishi_strerror (rc));
413 : 0 : return GSS_S_FAILURE;
414 : : }
415 : :
416 : 3 : rc = shishi_encapreppart_seqnumber_get (cxk5->sh,
417 : : shishi_ap_encapreppart
418 : : (cxk5->ap), &cxk5->acceptseqnr);
419 [ - + ]: 3 : if (rc != SHISHI_OK)
420 : : {
421 : : /* A strict 1964 implementation would return
422 : : GSS_S_DEFECTIVE_TOKEN here. gssapi-cfx permit absent
423 : : sequence number, though. */
424 : 0 : cxk5->acceptseqnr = 0;
425 : : }
426 : :
427 : 3 : rc = shishi_asn1_to_der (crk5->sh, aprep, &der, &len);
428 [ - + ]: 3 : if (rc != SHISHI_OK)
429 : : {
430 : 0 : printf ("Error der encoding aprep: %s\n", shishi_strerror (rc));
431 : 0 : return GSS_S_FAILURE;
432 : : }
433 : :
434 : 3 : rc = _gss_encapsulate_token_prefix (TOK_AP_REP, TOK_LEN,
435 : : der, len,
436 : 3 : GSS_KRB5->elements,
437 : 3 : GSS_KRB5->length,
438 : : &output_token->value,
439 : : &output_token->length);
440 [ - + ]: 3 : if (rc != 0)
441 : 0 : return GSS_S_FAILURE;
442 : :
443 [ + - ]: 3 : if (ret_flags)
444 : 3 : *ret_flags = GSS_C_MUTUAL_FLAG;
445 : : }
446 : : else
447 : : {
448 : 0 : output_token->value = NULL;
449 : 0 : output_token->length = 0;
450 : : }
451 : :
452 [ + - ]: 3 : if (src_name)
453 : : {
454 : : gss_name_t p;
455 : :
456 : 3 : p = malloc (sizeof (*p));
457 [ - + ]: 3 : if (!p)
458 : : {
459 [ # # ]: 0 : if (minor_status)
460 : 0 : *minor_status = ENOMEM;
461 : 0 : return GSS_S_FAILURE;
462 : : }
463 : :
464 : 3 : rc = shishi_encticketpart_client (cxk5->sh,
465 : : shishi_tkt_encticketpart (cxk5->tkt),
466 : : &p->value, &p->length);
467 [ - + ]: 3 : if (rc != SHISHI_OK)
468 : 0 : return GSS_S_FAILURE;
469 : :
470 : 3 : p->type = GSS_KRB5_NT_PRINCIPAL_NAME;
471 : :
472 : 3 : *src_name = p;
473 : : }
474 : :
475 : : /* PROT_READY is not mentioned in 1964/gssapi-cfx but we support
476 : : it anyway. */
477 [ + - ]: 3 : if (ret_flags)
478 : 3 : *ret_flags |= GSS_C_PROT_READY_FLAG;
479 : :
480 [ + - ]: 3 : if (minor_status)
481 : 3 : *minor_status = 0;
482 : 3 : return GSS_S_COMPLETE;
483 : : }
484 : :
485 : : /* Delete a krb5 security context. Assumes context_handle is valid.
486 : : Should only delete krb5 specific part of context. */
487 : : OM_uint32
488 : 6 : gss_krb5_delete_sec_context (OM_uint32 * minor_status,
489 : : gss_ctx_id_t * context_handle,
490 : : gss_buffer_t output_token)
491 : : {
492 : 6 : _gss_krb5_ctx_t k5 = (*context_handle)->krb5;
493 : :
494 [ + + ]: 6 : if (k5->peerptr != GSS_C_NO_NAME)
495 : 3 : gss_release_name (NULL, &k5->peerptr);
496 : :
497 [ + - ]: 6 : if (k5->ap)
498 : 6 : shishi_ap_done (k5->ap);
499 : :
500 [ + + ]: 6 : if (!k5->acceptor)
501 : 3 : shishi_done (k5->sh);
502 : 6 : free (k5);
503 : :
504 [ - + ]: 6 : if (minor_status)
505 : 0 : *minor_status = 0;
506 : 6 : return GSS_S_COMPLETE;
507 : : }
508 : :
509 : : /* Determines the number of seconds for which the specified krb5
510 : : context will remain valid. Assumes context_handle is valid. */
511 : : OM_uint32
512 : 0 : gss_krb5_context_time (OM_uint32 * minor_status,
513 : : const gss_ctx_id_t context_handle,
514 : : OM_uint32 * time_rec)
515 : : {
516 : 0 : _gss_krb5_ctx_t k5 = context_handle->krb5;
517 : :
518 [ # # ]: 0 : if (time_rec)
519 : : {
520 : 0 : *time_rec = gss_krb5_tktlifetime (k5->tkt);
521 : :
522 [ # # ]: 0 : if (*time_rec == 0)
523 : : {
524 [ # # ]: 0 : if (minor_status)
525 : 0 : *minor_status = 0;
526 : 0 : return GSS_S_CONTEXT_EXPIRED;
527 : : }
528 : : }
529 : :
530 [ # # ]: 0 : if (minor_status)
531 : 0 : *minor_status = 0;
532 : 0 : return GSS_S_COMPLETE;
533 : : }
|