1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
4 * lib/krb5/krb/auth_con.c
6 * Copyright 2010 by the Massachusetts Institute of Technology.
9 * Export of this software from the United States of America may
10 * require a specific license from the United States Government.
11 * It is the responsibility of any person or organization contemplating
12 * export to obtain such a license before exporting.
14 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
15 * distribute this software and its documentation for any purpose and
16 * without fee is hereby granted, provided that the above copyright
17 * notice appear in all copies and that both that copyright notice and
18 * this permission notice appear in supporting documentation, and that
19 * the name of M.I.T. not be used in advertising or publicity pertaining
20 * to distribution of the software without specific, written prior
21 * permission. Furthermore if you modify this software you must label
22 * your software as modified software and not distribute it in such a
23 * fashion that it might be confused with the original M.I.T. software.
24 * M.I.T. makes no representations about the suitability of
25 * this software for any purpose. It is provided "as is" without express
26 * or implied warranty.
31 #include "int-proto.h"
34 static krb5_boolean chk_heimdal_seqnum(krb5_ui_4, krb5_ui_4);
36 krb5_error_code KRB5_CALLCONV
37 krb5_auth_con_init(krb5_context context, krb5_auth_context *auth_context)
40 (krb5_auth_context)calloc(1, sizeof(struct _krb5_auth_context));
44 /* Default flags, do time not seq */
45 (*auth_context)->auth_context_flags =
46 KRB5_AUTH_CONTEXT_DO_TIME | KRB5_AUTH_CONN_INITIALIZED;
48 (*auth_context)->req_cksumtype = context->default_ap_req_sumtype;
49 (*auth_context)->safe_cksumtype = context->default_safe_sumtype;
50 (*auth_context)->checksum_func = NULL;
51 (*auth_context)->checksum_func_data = NULL;
52 (*auth_context)->negotiated_etype = ENCTYPE_NULL;
53 (*auth_context)->magic = KV5M_AUTH_CONTEXT;
57 krb5_error_code KRB5_CALLCONV
58 krb5_auth_con_free(krb5_context context, krb5_auth_context auth_context)
60 if (auth_context == NULL)
62 if (auth_context->local_addr)
63 krb5_free_address(context, auth_context->local_addr);
64 if (auth_context->remote_addr)
65 krb5_free_address(context, auth_context->remote_addr);
66 if (auth_context->local_port)
67 krb5_free_address(context, auth_context->local_port);
68 if (auth_context->remote_port)
69 krb5_free_address(context, auth_context->remote_port);
70 if (auth_context->authentp)
71 krb5_free_authenticator(context, auth_context->authentp);
72 if (auth_context->key)
73 krb5_k_free_key(context, auth_context->key);
74 if (auth_context->send_subkey)
75 krb5_k_free_key(context, auth_context->send_subkey);
76 if (auth_context->recv_subkey)
77 krb5_k_free_key(context, auth_context->recv_subkey);
78 if (auth_context->rcache)
79 krb5_rc_close(context, auth_context->rcache);
80 if (auth_context->permitted_etypes)
81 free(auth_context->permitted_etypes);
82 if (auth_context->ad_context)
83 krb5_authdata_context_free(context, auth_context->ad_context);
89 krb5_auth_con_setaddrs(krb5_context context, krb5_auth_context auth_context, krb5_address *local_addr, krb5_address *remote_addr)
91 krb5_error_code retval;
93 /* Free old addresses */
94 if (auth_context->local_addr)
95 (void) krb5_free_address(context, auth_context->local_addr);
96 if (auth_context->remote_addr)
97 (void) krb5_free_address(context, auth_context->remote_addr);
101 retval = krb5_copy_addr(context,
103 &auth_context->local_addr);
105 auth_context->local_addr = NULL;
107 if (!retval && remote_addr)
108 retval = krb5_copy_addr(context,
110 &auth_context->remote_addr);
112 auth_context->remote_addr = NULL;
117 krb5_error_code KRB5_CALLCONV
118 krb5_auth_con_getaddrs(krb5_context context, krb5_auth_context auth_context, krb5_address **local_addr, krb5_address **remote_addr)
120 krb5_error_code retval;
123 if (local_addr && auth_context->local_addr) {
124 retval = krb5_copy_addr(context,
125 auth_context->local_addr,
128 if (!retval && (remote_addr) && auth_context->remote_addr) {
129 retval = krb5_copy_addr(context,
130 auth_context->remote_addr,
136 krb5_error_code KRB5_CALLCONV
137 krb5_auth_con_setports(krb5_context context, krb5_auth_context auth_context, krb5_address *local_port, krb5_address *remote_port)
139 krb5_error_code retval;
141 /* Free old addresses */
142 if (auth_context->local_port)
143 (void) krb5_free_address(context, auth_context->local_port);
144 if (auth_context->remote_port)
145 (void) krb5_free_address(context, auth_context->remote_port);
149 retval = krb5_copy_addr(context,
151 &auth_context->local_port);
153 auth_context->local_port = NULL;
155 if (!retval && remote_port)
156 retval = krb5_copy_addr(context,
158 &auth_context->remote_port);
160 auth_context->remote_port = NULL;
167 * This function overloads the keyblock field. It is only useful prior to
168 * a krb5_rd_req_decode() call for user to user authentication where the
169 * server has the key and needs to use it to decrypt the incoming request.
170 * Once decrypted this key is no longer necessary and is then overwritten
171 * with the session key sent by the client.
173 krb5_error_code KRB5_CALLCONV
174 krb5_auth_con_setuseruserkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock *keyblock)
176 if (auth_context->key)
177 krb5_k_free_key(context, auth_context->key);
178 return(krb5_k_create_key(context, keyblock, &(auth_context->key)));
181 krb5_error_code KRB5_CALLCONV
182 krb5_auth_con_getkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
184 if (auth_context->key)
185 return krb5_k_key_keyblock(context, auth_context->key, keyblock);
190 krb5_error_code KRB5_CALLCONV
191 krb5_auth_con_getkey_k(krb5_context context, krb5_auth_context auth_context,
194 krb5_k_reference_key(context, auth_context->key);
195 *key = auth_context->key;
199 krb5_error_code KRB5_CALLCONV
200 krb5_auth_con_getlocalsubkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
202 return krb5_auth_con_getsendsubkey(context, auth_context, keyblock);
205 krb5_error_code KRB5_CALLCONV
206 krb5_auth_con_getremotesubkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
208 return krb5_auth_con_getrecvsubkey(context, auth_context, keyblock);
211 krb5_error_code KRB5_CALLCONV
212 krb5_auth_con_setsendsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock *keyblock)
214 if (ac->send_subkey != NULL)
215 krb5_k_free_key(ctx, ac->send_subkey);
216 ac->send_subkey = NULL;
218 return krb5_k_create_key(ctx, keyblock, &ac->send_subkey);
223 krb5_error_code KRB5_CALLCONV
224 krb5_auth_con_setsendsubkey_k(krb5_context ctx, krb5_auth_context ac,
227 krb5_k_free_key(ctx, ac->send_subkey);
228 ac->send_subkey = key;
229 krb5_k_reference_key(ctx, key);
233 krb5_error_code KRB5_CALLCONV
234 krb5_auth_con_setrecvsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock *keyblock)
236 if (ac->recv_subkey != NULL)
237 krb5_k_free_key(ctx, ac->recv_subkey);
238 ac->recv_subkey = NULL;
239 if (keyblock != NULL)
240 return krb5_k_create_key(ctx, keyblock, &ac->recv_subkey);
245 krb5_error_code KRB5_CALLCONV
246 krb5_auth_con_setrecvsubkey_k(krb5_context ctx, krb5_auth_context ac,
249 krb5_k_free_key(ctx, ac->recv_subkey);
250 ac->recv_subkey = key;
251 krb5_k_reference_key(ctx, key);
255 krb5_error_code KRB5_CALLCONV
256 krb5_auth_con_getsendsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock **keyblock)
258 if (ac->send_subkey != NULL)
259 return krb5_k_key_keyblock(ctx, ac->send_subkey, keyblock);
264 krb5_error_code KRB5_CALLCONV
265 krb5_auth_con_getsendsubkey_k(krb5_context ctx, krb5_auth_context ac,
268 krb5_k_reference_key(ctx, ac->send_subkey);
269 *key = ac->send_subkey;
273 krb5_error_code KRB5_CALLCONV
274 krb5_auth_con_getrecvsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock **keyblock)
276 if (ac->recv_subkey != NULL)
277 return krb5_k_key_keyblock(ctx, ac->recv_subkey, keyblock);
282 krb5_error_code KRB5_CALLCONV
283 krb5_auth_con_getrecvsubkey_k(krb5_context ctx, krb5_auth_context ac,
286 krb5_k_reference_key(ctx, ac->recv_subkey);
287 *key = ac->recv_subkey;
291 krb5_error_code KRB5_CALLCONV
292 krb5_auth_con_set_req_cksumtype(krb5_context context, krb5_auth_context auth_context, krb5_cksumtype cksumtype)
294 auth_context->req_cksumtype = cksumtype;
299 krb5_auth_con_set_safe_cksumtype(krb5_context context, krb5_auth_context auth_context, krb5_cksumtype cksumtype)
301 auth_context->safe_cksumtype = cksumtype;
305 krb5_error_code KRB5_CALLCONV
306 krb5_auth_con_getlocalseqnumber(krb5_context context, krb5_auth_context auth_context, krb5_int32 *seqnumber)
308 *seqnumber = auth_context->local_seq_number;
312 krb5_error_code KRB5_CALLCONV
313 krb5_auth_con_getremoteseqnumber(krb5_context context, krb5_auth_context auth_context, krb5_int32 *seqnumber)
315 *seqnumber = auth_context->remote_seq_number;
319 krb5_error_code KRB5_CALLCONV
320 krb5_auth_con_initivector(krb5_context context, krb5_auth_context auth_context)
323 krb5_enctype enctype;
325 if (auth_context->key) {
328 enctype = krb5_k_key_enctype(context, auth_context->key);
329 if ((ret = krb5_c_block_size(context, enctype, &blocksize)))
331 if ((auth_context->i_vector = (krb5_pointer)calloc(1,blocksize))) {
336 return EINVAL; /* XXX need an error for no keyblock */
340 krb5_auth_con_setivector(krb5_context context, krb5_auth_context auth_context, krb5_pointer ivector)
342 auth_context->i_vector = ivector;
347 krb5_auth_con_getivector(krb5_context context, krb5_auth_context auth_context, krb5_pointer *ivector)
349 *ivector = auth_context->i_vector;
353 krb5_error_code KRB5_CALLCONV
354 krb5_auth_con_setflags(krb5_context context, krb5_auth_context auth_context, krb5_int32 flags)
356 auth_context->auth_context_flags = flags;
360 krb5_error_code KRB5_CALLCONV
361 krb5_auth_con_getflags(krb5_context context, krb5_auth_context auth_context, krb5_int32 *flags)
363 *flags = auth_context->auth_context_flags;
367 krb5_error_code KRB5_CALLCONV
368 krb5_auth_con_setrcache(krb5_context context, krb5_auth_context auth_context, krb5_rcache rcache)
370 auth_context->rcache = rcache;
375 krb5_auth_con_getrcache(krb5_context context, krb5_auth_context auth_context, krb5_rcache *rcache)
377 *rcache = auth_context->rcache;
382 krb5_auth_con_setpermetypes(krb5_context context,
383 krb5_auth_context auth_context,
384 const krb5_enctype *permetypes)
389 ret = krb5int_copy_etypes(permetypes, &newpe);
393 free(auth_context->permitted_etypes);
394 auth_context->permitted_etypes = newpe;
399 krb5_auth_con_getpermetypes(krb5_context context,
400 krb5_auth_context auth_context,
401 krb5_enctype **permetypes)
404 if (auth_context->permitted_etypes == NULL)
406 return krb5int_copy_etypes(auth_context->permitted_etypes, permetypes);
409 krb5_error_code KRB5_CALLCONV
410 krb5_auth_con_set_checksum_func( krb5_context context,
411 krb5_auth_context auth_context,
412 krb5_mk_req_checksum_func func,
415 auth_context->checksum_func = func;
416 auth_context->checksum_func_data = data;
420 krb5_error_code KRB5_CALLCONV
421 krb5_auth_con_get_checksum_func( krb5_context context,
422 krb5_auth_context auth_context,
423 krb5_mk_req_checksum_func *func,
426 *func = auth_context->checksum_func;
427 *data = auth_context->checksum_func_data;
432 * krb5int_auth_con_chkseqnum
434 * We use a somewhat complex heuristic for validating received
435 * sequence numbers. We must accommodate both our older
436 * implementation, which sends negative sequence numbers, and the
437 * broken Heimdal implementation (at least as of 0.5.2), which
438 * violates X.690 BER for integer encodings. The requirement of
439 * handling negative sequence numbers removes one of easier means of
440 * detecting a Heimdal implementation, so we resort to this mess
443 * X.690 BER (and consequently DER, which are the required encoding
444 * rules in RFC1510) encode all integer types as signed integers.
445 * This means that the MSB being set on the first octet of the
446 * contents of the encoding indicates a negative value. Heimdal does
447 * not prepend the required zero octet to unsigned integer encodings
448 * which would otherwise have the MSB of the first octet of their
451 * Our ASN.1 library implements a special decoder for sequence
452 * numbers, accepting both negative and positive 32-bit numbers but
453 * mapping them both into the space of positive unsigned 32-bit
454 * numbers in the obvious bit-pattern-preserving way. This maintains
455 * compatibility with our older implementations. This also means that
456 * encodings emitted by Heimdal are ambiguous.
458 * Heimdal counter value received uint32 value
460 * 0x00000080 0xFFFFFF80
461 * 0x000000FF 0xFFFFFFFF
462 * 0x00008000 0xFFFF8000
463 * 0x0000FFFF 0xFFFFFFFF
464 * 0x00800000 0xFF800000
465 * 0x00FFFFFF 0xFFFFFFFF
466 * 0xFF800000 0xFF800000
467 * 0xFFFFFFFF 0xFFFFFFFF
469 * We use two auth_context flags, SANE_SEQ and HEIMDAL_SEQ, which are
470 * only set after we can unambiguously determine the sanity of the
471 * sending implementation. Once one of these flags is set, we accept
472 * only the sequence numbers appropriate to the remote implementation
473 * type. We can make the determination in two different ways. The
474 * first is to note the receipt of a "negative" sequence number when a
475 * "positive" one was expected. The second is to note the receipt of
476 * a sequence number that wraps through "zero" in a weird way. The
477 * latter corresponds to the receipt of an initial sequence number in
478 * the ambiguous range.
480 * There are 2^7 + 2^15 + 2^23 + 2^23 = 16810112 total ambiguous
481 * initial Heimdal counter values, but we receive them as one of 2^23
482 * possible values. There is a ~1/256 chance of a Heimdal
483 * implementation sending an intial sequence number in the ambiguous
486 * We have to do special treatment when receiving sequence numbers
487 * between 0xFF800000..0xFFFFFFFF, or when wrapping through zero
488 * weirdly (due to ambiguous initial sequence number). If we are
489 * expecting a value corresponding to an ambiguous Heimdal counter
490 * value, and we receive an exact match, we can mark the remote end as
494 krb5int_auth_con_chkseqnum(
496 krb5_auth_context ac,
501 exp_seq = ac->remote_seq_number;
504 * If sender is known to be sane, accept _only_ exact matches.
506 if (ac->auth_context_flags & KRB5_AUTH_CONN_SANE_SEQ)
507 return in_seq == exp_seq;
510 * If sender is not known to be sane, first check the ambiguous
511 * range of received values, 0xFF800000..0xFFFFFFFF.
513 if ((in_seq & 0xFF800000) == 0xFF800000) {
515 * If expected sequence number is in the range
516 * 0xFF800000..0xFFFFFFFF, then we can't make any
517 * determinations about the sanity of the sending
520 if ((exp_seq & 0xFF800000) == 0xFF800000 && in_seq == exp_seq)
523 * If sender is not known for certain to be a broken Heimdal
524 * implementation, check for exact match.
526 if (!(ac->auth_context_flags & KRB5_AUTH_CONN_HEIMDAL_SEQ)
527 && in_seq == exp_seq)
530 * Now apply hairy algorithm for matching sequence numbers
531 * sent by broken Heimdal implementations. If it matches, we
532 * know for certain it's a broken Heimdal sender.
534 if (chk_heimdal_seqnum(exp_seq, in_seq)) {
535 ac->auth_context_flags |= KRB5_AUTH_CONN_HEIMDAL_SEQ;
542 * Received value not in the ambiguous range? If the _expected_
543 * value is in the range of ambiguous Hemidal counter values, and
544 * it matches the received value, sender is known to be sane.
546 if (in_seq == exp_seq) {
547 if (( exp_seq & 0xFFFFFF80) == 0x00000080
548 || (exp_seq & 0xFFFF8000) == 0x00008000
549 || (exp_seq & 0xFF800000) == 0x00800000)
550 ac->auth_context_flags |= KRB5_AUTH_CONN_SANE_SEQ;
555 * Magic wraparound for the case where the intial sequence number
556 * is in the ambiguous range. This means that the sender's
557 * counter is at a different count than ours, so we correct ours,
558 * and mark the sender as being a broken Heimdal implementation.
561 && !(ac->auth_context_flags & KRB5_AUTH_CONN_HEIMDAL_SEQ)) {
566 ac->auth_context_flags |= KRB5_AUTH_CONN_HEIMDAL_SEQ;
577 chk_heimdal_seqnum(krb5_ui_4 exp_seq, krb5_ui_4 in_seq)
579 if (( exp_seq & 0xFF800000) == 0x00800000
580 && (in_seq & 0xFF800000) == 0xFF800000
581 && (in_seq & 0x00FFFFFF) == exp_seq)
583 else if (( exp_seq & 0xFFFF8000) == 0x00008000
584 && (in_seq & 0xFFFF8000) == 0xFFFF8000
585 && (in_seq & 0x0000FFFF) == exp_seq)
587 else if (( exp_seq & 0xFFFFFF80) == 0x00000080
588 && (in_seq & 0xFFFFFF80) == 0xFFFFFF80
589 && (in_seq & 0x000000FF) == exp_seq)
596 krb5_auth_con_get_subkey_enctype(krb5_context context,
597 krb5_auth_context auth_context,
600 *etype = auth_context->negotiated_etype;
605 krb5_auth_con_get_authdata_context(krb5_context context,
606 krb5_auth_context auth_context,
607 krb5_authdata_context *ad_context)
609 *ad_context = auth_context->ad_context;
614 krb5_auth_con_set_authdata_context(krb5_context context,
615 krb5_auth_context auth_context,
616 krb5_authdata_context ad_context)
618 auth_context->ad_context = ad_context;