1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
5 static krb5_boolean chk_heimdal_seqnum(krb5_ui_4, krb5_ui_4);
8 actx_copy_addr(krb5_context context, const krb5_address *inad, krb5_address **outad)
12 if (!(tmpad = (krb5_address *)malloc(sizeof(*tmpad))))
15 if (!(tmpad->contents = (krb5_octet *)malloc(inad->length))) {
19 memcpy(tmpad->contents, inad->contents, inad->length);
24 krb5_error_code KRB5_CALLCONV
25 krb5_auth_con_init(krb5_context context, krb5_auth_context *auth_context)
28 (krb5_auth_context)calloc(1, sizeof(struct _krb5_auth_context));
32 /* Default flags, do time not seq */
33 (*auth_context)->auth_context_flags =
34 KRB5_AUTH_CONTEXT_DO_TIME | KRB5_AUTH_CONN_INITIALIZED;
36 (*auth_context)->req_cksumtype = context->default_ap_req_sumtype;
37 (*auth_context)->safe_cksumtype = context->default_safe_sumtype;
38 (*auth_context)->checksum_func = NULL;
39 (*auth_context)->checksum_func_data = NULL;
40 (*auth_context)->negotiated_etype = ENCTYPE_NULL;
41 (*auth_context)->magic = KV5M_AUTH_CONTEXT;
45 krb5_error_code KRB5_CALLCONV
46 krb5_auth_con_free(krb5_context context, krb5_auth_context auth_context)
48 if (auth_context == NULL)
50 if (auth_context->local_addr)
51 krb5_free_address(context, auth_context->local_addr);
52 if (auth_context->remote_addr)
53 krb5_free_address(context, auth_context->remote_addr);
54 if (auth_context->local_port)
55 krb5_free_address(context, auth_context->local_port);
56 if (auth_context->remote_port)
57 krb5_free_address(context, auth_context->remote_port);
58 if (auth_context->authentp)
59 krb5_free_authenticator(context, auth_context->authentp);
60 if (auth_context->key)
61 krb5_k_free_key(context, auth_context->key);
62 if (auth_context->send_subkey)
63 krb5_k_free_key(context, auth_context->send_subkey);
64 if (auth_context->recv_subkey)
65 krb5_k_free_key(context, auth_context->recv_subkey);
66 if (auth_context->rcache)
67 krb5_rc_close(context, auth_context->rcache);
68 if (auth_context->permitted_etypes)
69 free(auth_context->permitted_etypes);
70 if (auth_context->ad_context)
71 krb5_authdata_context_free(context, auth_context->ad_context);
77 krb5_auth_con_setaddrs(krb5_context context, krb5_auth_context auth_context, krb5_address *local_addr, krb5_address *remote_addr)
79 krb5_error_code retval;
81 /* Free old addresses */
82 if (auth_context->local_addr)
83 (void) krb5_free_address(context, auth_context->local_addr);
84 if (auth_context->remote_addr)
85 (void) krb5_free_address(context, auth_context->remote_addr);
89 retval = actx_copy_addr(context,
91 &auth_context->local_addr);
93 auth_context->local_addr = NULL;
95 if (!retval && remote_addr)
96 retval = actx_copy_addr(context,
98 &auth_context->remote_addr);
100 auth_context->remote_addr = NULL;
105 krb5_error_code KRB5_CALLCONV
106 krb5_auth_con_getaddrs(krb5_context context, krb5_auth_context auth_context, krb5_address **local_addr, krb5_address **remote_addr)
108 krb5_error_code retval;
111 if (local_addr && auth_context->local_addr) {
112 retval = actx_copy_addr(context,
113 auth_context->local_addr,
116 if (!retval && (remote_addr) && auth_context->remote_addr) {
117 retval = actx_copy_addr(context,
118 auth_context->remote_addr,
124 krb5_error_code KRB5_CALLCONV
125 krb5_auth_con_setports(krb5_context context, krb5_auth_context auth_context, krb5_address *local_port, krb5_address *remote_port)
127 krb5_error_code retval;
129 /* Free old addresses */
130 if (auth_context->local_port)
131 (void) krb5_free_address(context, auth_context->local_port);
132 if (auth_context->remote_port)
133 (void) krb5_free_address(context, auth_context->remote_port);
137 retval = actx_copy_addr(context,
139 &auth_context->local_port);
141 auth_context->local_port = NULL;
143 if (!retval && remote_port)
144 retval = actx_copy_addr(context,
146 &auth_context->remote_port);
148 auth_context->remote_port = NULL;
155 * This function overloads the keyblock field. It is only useful prior to
156 * a krb5_rd_req_decode() call for user to user authentication where the
157 * server has the key and needs to use it to decrypt the incoming request.
158 * Once decrypted this key is no longer necessary and is then overwritten
159 * with the session key sent by the client.
161 krb5_error_code KRB5_CALLCONV
162 krb5_auth_con_setuseruserkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock *keyblock)
164 if (auth_context->key)
165 krb5_k_free_key(context, auth_context->key);
166 return(krb5_k_create_key(context, keyblock, &(auth_context->key)));
169 krb5_error_code KRB5_CALLCONV
170 krb5_auth_con_getkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
172 if (auth_context->key)
173 return krb5_k_key_keyblock(context, auth_context->key, keyblock);
178 krb5_error_code KRB5_CALLCONV
179 krb5_auth_con_getkey_k(krb5_context context, krb5_auth_context auth_context,
182 krb5_k_reference_key(context, auth_context->key);
183 *key = auth_context->key;
187 krb5_error_code KRB5_CALLCONV
188 krb5_auth_con_getlocalsubkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
190 return krb5_auth_con_getsendsubkey(context, auth_context, keyblock);
193 krb5_error_code KRB5_CALLCONV
194 krb5_auth_con_getremotesubkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
196 return krb5_auth_con_getrecvsubkey(context, auth_context, keyblock);
199 krb5_error_code KRB5_CALLCONV
200 krb5_auth_con_setsendsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock *keyblock)
202 if (ac->send_subkey != NULL)
203 krb5_k_free_key(ctx, ac->send_subkey);
204 ac->send_subkey = NULL;
206 return krb5_k_create_key(ctx, keyblock, &ac->send_subkey);
211 krb5_error_code KRB5_CALLCONV
212 krb5_auth_con_setrecvsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock *keyblock)
214 if (ac->recv_subkey != NULL)
215 krb5_k_free_key(ctx, ac->recv_subkey);
216 ac->recv_subkey = NULL;
217 if (keyblock != NULL)
218 return krb5_k_create_key(ctx, keyblock, &ac->recv_subkey);
223 krb5_error_code KRB5_CALLCONV
224 krb5_auth_con_getsendsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock **keyblock)
226 if (ac->send_subkey != NULL)
227 return krb5_k_key_keyblock(ctx, ac->send_subkey, keyblock);
232 krb5_error_code KRB5_CALLCONV
233 krb5_auth_con_getsendsubkey_k(krb5_context ctx, krb5_auth_context ac,
236 krb5_k_reference_key(ctx, ac->send_subkey);
237 *key = ac->send_subkey;
241 krb5_error_code KRB5_CALLCONV
242 krb5_auth_con_getrecvsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock **keyblock)
244 if (ac->recv_subkey != NULL)
245 return krb5_k_key_keyblock(ctx, ac->recv_subkey, keyblock);
250 krb5_error_code KRB5_CALLCONV
251 krb5_auth_con_getrecvsubkey_k(krb5_context ctx, krb5_auth_context ac,
254 krb5_k_reference_key(ctx, ac->recv_subkey);
255 *key = ac->recv_subkey;
259 krb5_error_code KRB5_CALLCONV
260 krb5_auth_con_set_req_cksumtype(krb5_context context, krb5_auth_context auth_context, krb5_cksumtype cksumtype)
262 auth_context->req_cksumtype = cksumtype;
267 krb5_auth_con_set_safe_cksumtype(krb5_context context, krb5_auth_context auth_context, krb5_cksumtype cksumtype)
269 auth_context->safe_cksumtype = cksumtype;
273 krb5_error_code KRB5_CALLCONV
274 krb5_auth_con_getlocalseqnumber(krb5_context context, krb5_auth_context auth_context, krb5_int32 *seqnumber)
276 *seqnumber = auth_context->local_seq_number;
280 krb5_error_code KRB5_CALLCONV
281 krb5_auth_con_getauthenticator(krb5_context context, krb5_auth_context auth_context, krb5_authenticator **authenticator)
283 return (krb5_copy_authenticator(context, auth_context->authentp,
288 krb5_error_code KRB5_CALLCONV
289 krb5_auth_con_getremoteseqnumber(krb5_context context, krb5_auth_context auth_context, krb5_int32 *seqnumber)
291 *seqnumber = auth_context->remote_seq_number;
295 krb5_error_code KRB5_CALLCONV
296 krb5_auth_con_initivector(krb5_context context, krb5_auth_context auth_context)
299 krb5_enctype enctype;
301 if (auth_context->key) {
304 enctype = krb5_k_key_enctype(context, auth_context->key);
305 if ((ret = krb5_c_block_size(context, enctype, &blocksize)))
307 if ((auth_context->i_vector = (krb5_pointer)calloc(1,blocksize))) {
312 return EINVAL; /* XXX need an error for no keyblock */
316 krb5_auth_con_setivector(krb5_context context, krb5_auth_context auth_context, krb5_pointer ivector)
318 auth_context->i_vector = ivector;
323 krb5_auth_con_getivector(krb5_context context, krb5_auth_context auth_context, krb5_pointer *ivector)
325 *ivector = auth_context->i_vector;
329 krb5_error_code KRB5_CALLCONV
330 krb5_auth_con_setflags(krb5_context context, krb5_auth_context auth_context, krb5_int32 flags)
332 auth_context->auth_context_flags = flags;
336 krb5_error_code KRB5_CALLCONV
337 krb5_auth_con_getflags(krb5_context context, krb5_auth_context auth_context, krb5_int32 *flags)
339 *flags = auth_context->auth_context_flags;
343 krb5_error_code KRB5_CALLCONV
344 krb5_auth_con_setrcache(krb5_context context, krb5_auth_context auth_context, krb5_rcache rcache)
346 auth_context->rcache = rcache;
351 krb5_auth_con_getrcache(krb5_context context, krb5_auth_context auth_context, krb5_rcache *rcache)
353 *rcache = auth_context->rcache;
358 krb5_auth_con_setpermetypes(krb5_context context, krb5_auth_context auth_context, const krb5_enctype *permetypes)
360 krb5_enctype * newpe;
363 for (i=0; permetypes[i]; i++)
365 i++; /* include the zero */
367 if ((newpe = (krb5_enctype *) malloc(i*sizeof(krb5_enctype)))
371 if (auth_context->permitted_etypes)
372 free(auth_context->permitted_etypes);
374 auth_context->permitted_etypes = newpe;
376 memcpy(newpe, permetypes, i*sizeof(krb5_enctype));
382 krb5_auth_con_getpermetypes(krb5_context context, krb5_auth_context auth_context, krb5_enctype **permetypes)
384 krb5_enctype * newpe;
387 if (! auth_context->permitted_etypes) {
392 for (i=0; auth_context->permitted_etypes[i]; i++)
394 i++; /* include the zero */
396 if ((newpe = (krb5_enctype *) malloc(i*sizeof(krb5_enctype)))
402 memcpy(newpe, auth_context->permitted_etypes, i*sizeof(krb5_enctype));
407 krb5_error_code KRB5_CALLCONV
408 krb5_auth_con_set_checksum_func( krb5_context context,
409 krb5_auth_context auth_context,
410 krb5_mk_req_checksum_func func,
413 auth_context->checksum_func = func;
414 auth_context->checksum_func_data = data;
418 krb5_error_code KRB5_CALLCONV
419 krb5_auth_con_get_checksum_func( krb5_context context,
420 krb5_auth_context auth_context,
421 krb5_mk_req_checksum_func *func,
424 *func = auth_context->checksum_func;
425 *data = auth_context->checksum_func_data;
430 * krb5int_auth_con_chkseqnum
432 * We use a somewhat complex heuristic for validating received
433 * sequence numbers. We must accommodate both our older
434 * implementation, which sends negative sequence numbers, and the
435 * broken Heimdal implementation (at least as of 0.5.2), which
436 * violates X.690 BER for integer encodings. The requirement of
437 * handling negative sequence numbers removes one of easier means of
438 * detecting a Heimdal implementation, so we resort to this mess
441 * X.690 BER (and consequently DER, which are the required encoding
442 * rules in RFC1510) encode all integer types as signed integers.
443 * This means that the MSB being set on the first octet of the
444 * contents of the encoding indicates a negative value. Heimdal does
445 * not prepend the required zero octet to unsigned integer encodings
446 * which would otherwise have the MSB of the first octet of their
449 * Our ASN.1 library implements a special decoder for sequence
450 * numbers, accepting both negative and positive 32-bit numbers but
451 * mapping them both into the space of positive unsigned 32-bit
452 * numbers in the obvious bit-pattern-preserving way. This maintains
453 * compatibility with our older implementations. This also means that
454 * encodings emitted by Heimdal are ambiguous.
456 * Heimdal counter value received uint32 value
458 * 0x00000080 0xFFFFFF80
459 * 0x000000FF 0xFFFFFFFF
460 * 0x00008000 0xFFFF8000
461 * 0x0000FFFF 0xFFFFFFFF
462 * 0x00800000 0xFF800000
463 * 0x00FFFFFF 0xFFFFFFFF
464 * 0xFF800000 0xFF800000
465 * 0xFFFFFFFF 0xFFFFFFFF
467 * We use two auth_context flags, SANE_SEQ and HEIMDAL_SEQ, which are
468 * only set after we can unambiguously determine the sanity of the
469 * sending implementation. Once one of these flags is set, we accept
470 * only the sequence numbers appropriate to the remote implementation
471 * type. We can make the determination in two different ways. The
472 * first is to note the receipt of a "negative" sequence number when a
473 * "positive" one was expected. The second is to note the receipt of
474 * a sequence number that wraps through "zero" in a weird way. The
475 * latter corresponds to the receipt of an initial sequence number in
476 * the ambiguous range.
478 * There are 2^7 + 2^15 + 2^23 + 2^23 = 16810112 total ambiguous
479 * initial Heimdal counter values, but we receive them as one of 2^23
480 * possible values. There is a ~1/256 chance of a Heimdal
481 * implementation sending an intial sequence number in the ambiguous
484 * We have to do special treatment when receiving sequence numbers
485 * between 0xFF800000..0xFFFFFFFF, or when wrapping through zero
486 * weirdly (due to ambiguous initial sequence number). If we are
487 * expecting a value corresponding to an ambiguous Heimdal counter
488 * value, and we receive an exact match, we can mark the remote end as
492 krb5int_auth_con_chkseqnum(
494 krb5_auth_context ac,
499 exp_seq = ac->remote_seq_number;
502 * If sender is known to be sane, accept _only_ exact matches.
504 if (ac->auth_context_flags & KRB5_AUTH_CONN_SANE_SEQ)
505 return in_seq == exp_seq;
508 * If sender is not known to be sane, first check the ambiguous
509 * range of received values, 0xFF800000..0xFFFFFFFF.
511 if ((in_seq & 0xFF800000) == 0xFF800000) {
513 * If expected sequence number is in the range
514 * 0xFF800000..0xFFFFFFFF, then we can't make any
515 * determinations about the sanity of the sending
518 if ((exp_seq & 0xFF800000) == 0xFF800000 && in_seq == exp_seq)
521 * If sender is not known for certain to be a broken Heimdal
522 * implementation, check for exact match.
524 if (!(ac->auth_context_flags & KRB5_AUTH_CONN_HEIMDAL_SEQ)
525 && in_seq == exp_seq)
528 * Now apply hairy algorithm for matching sequence numbers
529 * sent by broken Heimdal implementations. If it matches, we
530 * know for certain it's a broken Heimdal sender.
532 if (chk_heimdal_seqnum(exp_seq, in_seq)) {
533 ac->auth_context_flags |= KRB5_AUTH_CONN_HEIMDAL_SEQ;
540 * Received value not in the ambiguous range? If the _expected_
541 * value is in the range of ambiguous Hemidal counter values, and
542 * it matches the received value, sender is known to be sane.
544 if (in_seq == exp_seq) {
545 if (( exp_seq & 0xFFFFFF80) == 0x00000080
546 || (exp_seq & 0xFFFF8000) == 0x00008000
547 || (exp_seq & 0xFF800000) == 0x00800000)
548 ac->auth_context_flags |= KRB5_AUTH_CONN_SANE_SEQ;
553 * Magic wraparound for the case where the intial sequence number
554 * is in the ambiguous range. This means that the sender's
555 * counter is at a different count than ours, so we correct ours,
556 * and mark the sender as being a broken Heimdal implementation.
559 && !(ac->auth_context_flags & KRB5_AUTH_CONN_HEIMDAL_SEQ)) {
564 ac->auth_context_flags |= KRB5_AUTH_CONN_HEIMDAL_SEQ;
575 chk_heimdal_seqnum(krb5_ui_4 exp_seq, krb5_ui_4 in_seq)
577 if (( exp_seq & 0xFF800000) == 0x00800000
578 && (in_seq & 0xFF800000) == 0xFF800000
579 && (in_seq & 0x00FFFFFF) == exp_seq)
581 else if (( exp_seq & 0xFFFF8000) == 0x00008000
582 && (in_seq & 0xFFFF8000) == 0xFFFF8000
583 && (in_seq & 0x0000FFFF) == exp_seq)
585 else if (( exp_seq & 0xFFFFFF80) == 0x00000080
586 && (in_seq & 0xFFFFFF80) == 0xFFFFFF80
587 && (in_seq & 0x000000FF) == exp_seq)
594 krb5_auth_con_get_subkey_enctype(krb5_context context,
595 krb5_auth_context auth_context,
598 *etype = auth_context->negotiated_etype;
602 krb5_error_code KRB5_CALLCONV
603 krb5_auth_con_get_authdata_context(krb5_context context,
604 krb5_auth_context auth_context,
605 krb5_authdata_context *ad_context)
607 *ad_context = auth_context->ad_context;
611 krb5_error_code KRB5_CALLCONV
612 krb5_auth_con_set_authdata_context(krb5_context context,
613 krb5_auth_context auth_context,
614 krb5_authdata_context ad_context)
616 auth_context->ad_context = ad_context;