1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 #include <k5-int.h>
9 #include <auth_con.h>
10 
11 static krb5_boolean chk_heimdal_seqnum(krb5_ui_4, krb5_ui_4);
12 
13 /*ARGSUSED*/
14 static krb5_error_code
15 actx_copy_addr(krb5_context context, const krb5_address *inad,
16 	krb5_address	**outad)
17 {
18     krb5_address *tmpad;
19 
20     if (!(tmpad = (krb5_address *)MALLOC(sizeof(*tmpad))))
21 	return ENOMEM;
22 #ifdef HAVE_C_STRUCTURE_ASSIGNMENT
23     *tmpad = *inad;
24 #else
25     (void) memcpy(tmpad, inad, sizeof(krb5_address));
26 #endif
27     if (!(tmpad->contents = (krb5_octet *)MALLOC(inad->length))) {
28 	krb5_xfree(tmpad);
29 	return ENOMEM;
30     }
31     (void) memcpy((char *)tmpad->contents, (char *)inad->contents, inad->length);
32     *outad = tmpad;
33     return 0;
34 }
35 
36 krb5_error_code KRB5_CALLCONV
37 krb5_auth_con_init(krb5_context context, krb5_auth_context *auth_context)
38 {
39     *auth_context =
40             (krb5_auth_context)MALLOC(sizeof(struct _krb5_auth_context));
41     if (!*auth_context)
42 	    return ENOMEM;
43 
44     (void) memset(*auth_context, 0, sizeof(struct _krb5_auth_context));
45 
46     /* Default flags, do time not seq */
47     (*auth_context)->auth_context_flags =
48 	    KRB5_AUTH_CONTEXT_DO_TIME |  KRB5_AUTH_CONN_INITIALIZED;
49 
50     (*auth_context)->req_cksumtype = context->default_ap_req_sumtype;
51     (*auth_context)->safe_cksumtype = context->default_safe_sumtype;
52     (*auth_context) -> checksum_func = NULL;
53     (*auth_context)->checksum_func_data = NULL;
54     (*auth_context)->magic = KV5M_AUTH_CONTEXT;
55     return 0;
56 }
57 
58 krb5_error_code KRB5_CALLCONV
59 krb5_auth_con_free(krb5_context context, krb5_auth_context auth_context)
60 {
61     if (auth_context->local_addr)
62 	krb5_free_address(context, auth_context->local_addr);
63     if (auth_context->remote_addr)
64 	krb5_free_address(context, auth_context->remote_addr);
65     if (auth_context->local_port)
66 	krb5_free_address(context, auth_context->local_port);
67     if (auth_context->remote_port)
68 	krb5_free_address(context, auth_context->remote_port);
69     if (auth_context->authentp)
70 	krb5_free_authenticator(context, auth_context->authentp);
71     if (auth_context->keyblock)
72 	krb5_free_keyblock(context, auth_context->keyblock);
73     if (auth_context->send_subkey)
74 	krb5_free_keyblock(context, auth_context->send_subkey);
75     if (auth_context->recv_subkey)
76 	krb5_free_keyblock(context, auth_context->recv_subkey);
77     if (auth_context->rcache)
78 	(void) krb5_rc_close(context, auth_context->rcache);
79     if (auth_context->permitted_etypes)
80 	krb5_xfree(auth_context->permitted_etypes);
81     FREE(auth_context, sizeof(krb5_auth_context));
82     return 0;
83 }
84 
85 krb5_error_code KRB5_CALLCONV
86 krb5_auth_con_setaddrs(krb5_context context,
87 	krb5_auth_context auth_context,
88 	krb5_address *local_addr,
89 	krb5_address *remote_addr)
90 {
91     krb5_error_code	retval = 0;
92 
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);
98 
99     if (local_addr)
100 	retval = actx_copy_addr(context,
101 				local_addr,
102 				&auth_context->local_addr);
103     else
104 	auth_context->local_addr = NULL;
105 
106     if (!retval && remote_addr)
107 	retval = actx_copy_addr(context,
108 				remote_addr,
109 				&auth_context->remote_addr);
110     else
111 	auth_context->remote_addr = NULL;
112 
113     return retval;
114 }
115 
116 krb5_error_code
117 krb5_auth_con_getaddrs(krb5_context context,
118 	krb5_auth_context auth_context,
119 	krb5_address **local_addr,
120 	krb5_address **remote_addr)
121 {
122     krb5_error_code	retval;
123 
124     retval = 0;
125     if (local_addr && auth_context->local_addr) {
126 	retval = actx_copy_addr(context,
127 				auth_context->local_addr,
128 				local_addr);
129     }
130     if (!retval && (remote_addr) && auth_context->remote_addr) {
131 	retval = actx_copy_addr(context,
132 				auth_context->remote_addr,
133 				remote_addr);
134     }
135     return retval;
136 }
137 
138 krb5_error_code
139 krb5_auth_con_setports(
140     krb5_context      	  context,
141     krb5_auth_context     auth_context,
142     krb5_address      	* local_port,
143     krb5_address      	* remote_port)
144 {
145     krb5_error_code	retval;
146 
147     /* Free old addresses */
148     if (auth_context->local_port)
149 	(void) krb5_free_address(context, auth_context->local_port);
150     if (auth_context->remote_port)
151 	(void) krb5_free_address(context, auth_context->remote_port);
152 
153     retval = 0;
154     if (local_port)
155 	retval = actx_copy_addr(context,
156 				local_port,
157 				&auth_context->local_port);
158     else
159 	auth_context->local_port = NULL;
160 
161     if (!retval && remote_port)
162 	retval = actx_copy_addr(context,
163 				remote_port,
164 				&auth_context->remote_port);
165     else
166 	auth_context->remote_port = NULL;
167 
168     return retval;
169 }
170 
171 
172 /*
173  * This function overloads the keyblock field. It is only useful prior to
174  * a krb5_rd_req_decode() call for user to user authentication where the
175  * server has the key and needs to use it to decrypt the incoming request.
176  * Once decrypted this key is no longer necessary and is then overwritten
177  * with the session key sent by the client.
178  */
179 krb5_error_code KRB5_CALLCONV
180 krb5_auth_con_setuseruserkey(
181     krb5_context      	  context,
182     krb5_auth_context 	  auth_context,
183     krb5_keyblock       * keyblock)
184 {
185     if (auth_context->keyblock)
186 	krb5_free_keyblock(context, auth_context->keyblock);
187     return(krb5_copy_keyblock(context, keyblock, &(auth_context->keyblock)));
188 }
189 
190 krb5_error_code KRB5_CALLCONV
191 krb5_auth_con_getkey(
192     krb5_context      	  context,
193     krb5_auth_context 	  auth_context,
194     krb5_keyblock      ** keyblock)
195 {
196     if (auth_context->keyblock)
197     	return krb5_copy_keyblock(context, auth_context->keyblock, keyblock);
198     *keyblock = NULL;
199     return 0;
200 }
201 
202 krb5_error_code KRB5_CALLCONV
203 krb5_auth_con_getlocalsubkey(
204     krb5_context      	  context,
205     krb5_auth_context 	  auth_context,
206     krb5_keyblock * * keyblock)
207 {
208     return krb5_auth_con_getsendsubkey(context, auth_context, keyblock);
209 }
210 
211 krb5_error_code KRB5_CALLCONV
212 krb5_auth_con_getremotesubkey(
213     krb5_context      	  context,
214     krb5_auth_context 	  auth_context,
215     krb5_keyblock 	**keyblock)
216 {
217     return krb5_auth_con_getrecvsubkey(context, auth_context, keyblock);
218 }
219 
220 krb5_error_code KRB5_CALLCONV
221 krb5_auth_con_setsendsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock *keyblock)
222 {
223     if (ac->send_subkey != NULL)
224 	krb5_free_keyblock(ctx, ac->send_subkey);
225     ac->send_subkey = NULL;
226     if (keyblock !=NULL)
227 	return krb5_copy_keyblock(ctx, keyblock, &ac->send_subkey);
228     else
229         return 0;
230 }
231 
232 krb5_error_code KRB5_CALLCONV
233 krb5_auth_con_setrecvsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock *keyblock)
234 {
235     if (ac->recv_subkey != NULL)
236 	krb5_free_keyblock(ctx, ac->recv_subkey);
237     ac->recv_subkey = NULL;
238     if (keyblock != NULL)
239 	return krb5_copy_keyblock(ctx, keyblock, &ac->recv_subkey);
240     else
241         return 0;
242 }
243 
244 krb5_error_code KRB5_CALLCONV
245 krb5_auth_con_getsendsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock **keyblock)
246 {
247     if (ac->send_subkey != NULL)
248 	return krb5_copy_keyblock(ctx, ac->send_subkey, keyblock);
249     *keyblock = NULL;
250     return 0;
251 }
252 
253 krb5_error_code KRB5_CALLCONV
254 krb5_auth_con_getrecvsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock **keyblock)
255 {
256     if (ac->recv_subkey != NULL)
257 	return krb5_copy_keyblock(ctx, ac->recv_subkey, keyblock);
258     *keyblock = NULL;
259     return 0;
260 }
261 
262 /*ARGSUSED*/
263 krb5_error_code KRB5_CALLCONV
264 krb5_auth_con_set_req_cksumtype(
265     krb5_context      	  context,
266     krb5_auth_context 	  auth_context,
267     krb5_cksumtype	  cksumtype)
268 {
269     auth_context->req_cksumtype = cksumtype;
270     return 0;
271 }
272 
273 /*ARGSUSED*/
274 krb5_error_code
275 krb5_auth_con_set_safe_cksumtype(
276     krb5_context      	  context,
277     krb5_auth_context 	  auth_context,
278     krb5_cksumtype	  cksumtype)
279 {
280     auth_context->safe_cksumtype = cksumtype;
281     return 0;
282 }
283 
284 /*ARGSUSED*/
285 krb5_error_code KRB5_CALLCONV
286 krb5_auth_con_getlocalseqnumber(
287     krb5_context      	  context,
288     krb5_auth_context 	  auth_context,
289     krb5_int32	  	* seqnumber)
290 {
291     *seqnumber = auth_context->local_seq_number;
292     return 0;
293 }
294 
295 krb5_error_code KRB5_CALLCONV
296 krb5_auth_con_getauthenticator(
297     krb5_context      	  context,
298     krb5_auth_context 	  auth_context,
299     krb5_authenticator 	**authenticator)
300 {
301     return (krb5_copy_authenticator(context, auth_context->authentp,
302 				    authenticator));
303 }
304 
305 /*ARGSUSED*/
306 krb5_error_code KRB5_CALLCONV
307 krb5_auth_con_getremoteseqnumber(
308     krb5_context      	  context,
309     krb5_auth_context 	  auth_context,
310     krb5_int32	    	* seqnumber)
311 {
312     *seqnumber = auth_context->remote_seq_number;
313     return 0;
314 }
315 
316 krb5_error_code
317 krb5_auth_con_initivector(
318     krb5_context      	  context,
319     krb5_auth_context 	  auth_context)
320 {
321     krb5_error_code ret;
322 
323     if (auth_context->keyblock) {
324 	size_t blocksize;
325 
326 	if ((ret = krb5_c_block_size(context, auth_context->keyblock->enctype,
327 				    &blocksize)))
328 	    return(ret);
329 	if ((auth_context->i_vector = (krb5_pointer)MALLOC(blocksize))) {
330 	    memset(auth_context->i_vector, 0, blocksize);
331 	    return 0;
332 	}
333 	return ENOMEM;
334     }
335     return EINVAL; /* XXX need an error for no keyblock */
336 }
337 
338 /*ARGSUSED*/
339 krb5_error_code
340 krb5_auth_con_setivector(
341     krb5_context      	  context,
342     krb5_auth_context 	  auth_context,
343     krb5_pointer	  ivector)
344 {
345     auth_context->i_vector = ivector;
346     return 0;
347 }
348 
349 /*ARGSUSED*/
350 krb5_error_code
351 krb5_auth_con_getivector(
352     krb5_context      	  context,
353     krb5_auth_context 	  auth_context,
354     krb5_pointer	* ivector)
355 {
356     *ivector = auth_context->i_vector;
357     return 0;
358 }
359 
360 /*ARGSUSED*/
361 krb5_error_code KRB5_CALLCONV
362 krb5_auth_con_setflags(
363     krb5_context      	  context,
364     krb5_auth_context 	  auth_context,
365     krb5_int32		  flags)
366 {
367     auth_context->auth_context_flags = flags;
368     return 0;
369 }
370 
371 /*ARGSUSED*/
372 krb5_error_code KRB5_CALLCONV
373 krb5_auth_con_getflags(
374     krb5_context      	  context,
375     krb5_auth_context 	  auth_context,
376     krb5_int32	    	* flags)
377 {
378     *flags = auth_context->auth_context_flags;
379     return 0;
380 }
381 
382 /*ARGSUSED*/
383 krb5_error_code KRB5_CALLCONV
384 krb5_auth_con_setrcache(
385     krb5_context      	  context,
386     krb5_auth_context 	  auth_context,
387     krb5_rcache		  rcache)
388 {
389     auth_context->rcache = rcache;
390     return 0;
391 }
392 
393 /*ARGSUSED*/
394 krb5_error_code
395 krb5_auth_con_getrcache(
396     krb5_context      	  context,
397     krb5_auth_context 	  auth_context,
398     krb5_rcache		* rcache)
399 {
400     *rcache = auth_context->rcache;
401     return 0;
402 }
403 
404 /*ARGSUSED*/
405 krb5_error_code
406 krb5_auth_con_setpermetypes(
407     krb5_context      	  context,
408     krb5_auth_context 	  auth_context,
409     const krb5_enctype	* permetypes)
410 {
411     krb5_enctype	* newpe;
412     int i;
413 
414     for (i=0; permetypes[i]; i++)
415 	;
416     i++; /* include the zero */
417 
418     if ((newpe = (krb5_enctype *) MALLOC(i*sizeof(krb5_enctype)))
419 	== NULL)
420 	return(ENOMEM);
421 
422     if (auth_context->permitted_etypes)
423 	krb5_xfree(auth_context->permitted_etypes);
424 
425     auth_context->permitted_etypes = newpe;
426 
427     (void) memcpy(newpe, permetypes, i*sizeof(krb5_enctype));
428 
429     return 0;
430 }
431 
432 /*ARGSUSED*/
433 krb5_error_code
434 krb5_auth_con_getpermetypes(
435     krb5_context      	  context,
436     krb5_auth_context 	  auth_context,
437     krb5_enctype       ** permetypes)
438 {
439     krb5_enctype	* newpe;
440     int i;
441 
442     if (! auth_context->permitted_etypes) {
443 	*permetypes = NULL;
444 	return(0);
445     }
446 
447     for (i=0; auth_context->permitted_etypes[i]; i++)
448 	;
449     i++; /* include the zero */
450 
451     if ((newpe = (krb5_enctype *) MALLOC(i*sizeof(krb5_enctype)))
452 	== NULL)
453 	return(ENOMEM);
454 
455     *permetypes = newpe;
456 
457     memcpy(newpe, auth_context->permitted_etypes, i*sizeof(krb5_enctype));
458 
459     return(0);
460 }
461 
462 krb5_error_code KRB5_CALLCONV
463 krb5_auth_con_set_checksum_func( krb5_context context,
464                                  krb5_auth_context  auth_context,
465                                  krb5_mk_req_checksum_func func,
466                                  void *data)
467 {
468   auth_context->checksum_func = func;
469   auth_context->checksum_func_data = data;
470   return 0;
471 }
472 
473 static krb5_boolean
474 chk_heimdal_seqnum(krb5_ui_4 exp_seq, krb5_ui_4 in_seq)
475 {
476     if (( exp_seq & 0xFF800000) == 0x00800000
477 	&& (in_seq & 0xFF800000) == 0xFF800000
478 	&& (in_seq & 0x00FFFFFF) == exp_seq)
479 	return 1;
480     else if ((	exp_seq & 0xFFFF8000) == 0x00008000
481 		&& (in_seq & 0xFFFF8000) == 0xFFFF8000
482 		&& (in_seq & 0x0000FFFF) == exp_seq)
483 	return 1;
484     else if ((	exp_seq & 0xFFFFFF80) == 0x00000080
485              && (in_seq & 0xFFFFFF80) == 0xFFFFFF80
486              && (in_seq & 0x000000FF) == exp_seq)
487 	return 1;
488     else
489         return 0;
490 }
491 
492 
493 krb5_error_code KRB5_CALLCONV
494 krb5_auth_con_get_checksum_func( krb5_context context,
495                                  krb5_auth_context auth_context,
496                                  krb5_mk_req_checksum_func *func,
497                                  void **data)
498 {
499   *func = auth_context->checksum_func;
500   *data = auth_context->checksum_func_data;
501   return 0;
502 }
503 
504 
505 /*
506  * krb5int_auth_con_chkseqnum
507  *
508  * We use a somewhat complex heuristic for validating received
509  * sequence numbers.  We must accommodate both our older
510  * implementation, which sends negative sequence numbers, and the
511  * broken Heimdal implementation (at least as of 0.5.2), which
512  * violates X.690 BER for integer encodings.  The requirement of
513  * handling negative sequence numbers removes one of easier means of
514  * detecting a Heimdal implementation, so we resort to this mess
515  * here.
516  *
517  * X.690 BER (and consequently DER, which are the required encoding
518  * rules in RFC1510) encode all integer types as signed integers.
519  * This means that the MSB being set on the first octet of the
520  * contents of the encoding indicates a negative value.	 Heimdal does
521  * not prepend the required zero octet to unsigned integer encodings
522  * which would otherwise have the MSB of the first octet of their
523  * encodings set.
524  *
525  * Our ASN.1 library implements a special decoder for sequence
526  * numbers, accepting both negative and positive 32-bit numbers but
527  * mapping them both into the space of positive unsigned 32-bit
528  * numbers in the obvious bit-pattern-preserving way.  This maintains
529  * compatibility with our older implementations.  This also means that
530  * encodings emitted by Heimdal are ambiguous.
531  *
532  * Heimdal counter value	received uint32 value
533  *
534  * 0x00000080			0xFFFFFF80
535  * 0x000000FF			0xFFFFFFFF
536  * 0x00008000			0xFFFF8000
537  * 0x0000FFFF			0xFFFFFFFF
538  * 0x00800000			0xFF800000
539  * 0x00FFFFFF			0xFFFFFFFF
540  * 0xFF800000			0xFF800000
541  * 0xFFFFFFFF			0xFFFFFFFF
542  *
543  * We use two auth_context flags, SANE_SEQ and HEIMDAL_SEQ, which are
544  * only set after we can unambiguously determine the sanity of the
545  * sending implementation.  Once one of these flags is set, we accept
546  * only the sequence numbers appropriate to the remote implementation
547  * type.  We can make the determination in two different ways.	The
548  * first is to note the receipt of a "negative" sequence number when a
549  * "positive" one was expected.	 The second is to note the receipt of
550  * a sequence number that wraps through "zero" in a weird way.	The
551  * latter corresponds to the receipt of an initial sequence number in
552  * the ambiguous range.
553  *
554  * There are 2^7 + 2^15 + 2^23 + 2^23 = 16810112 total ambiguous
555  * initial Heimdal counter values, but we receive them as one of 2^23
556  * possible values.  There is a ~1/256 chance of a Heimdal
557  * implementation sending an intial sequence number in the ambiguous
558  * range.
559  *
560  * We have to do special treatment when receiving sequence numbers
561  * between 0xFF800000..0xFFFFFFFF, or when wrapping through zero
562  * weirdly (due to ambiguous initial sequence number).	If we are
563  * expecting a value corresponding to an ambiguous Heimdal counter
564  * value, and we receive an exact match, we can mark the remote end as
565  * sane.
566  */
567 krb5_boolean
568 krb5int_auth_con_chkseqnum(
569     krb5_context ctx,
570     krb5_auth_context ac,
571     krb5_ui_4 in_seq)
572 {
573     krb5_ui_4 exp_seq;
574 
575     exp_seq = ac->remote_seq_number;
576 
577     /*
578      * If sender is known to be sane, accept _only_ exact matches.
579      */
580     if (ac->auth_context_flags & KRB5_AUTH_CONN_SANE_SEQ)
581 	return in_seq == exp_seq;
582     /*
583      * If sender is not known to be sane, first check the ambiguous
584      * range of received values, 0xFF800000..0xFFFFFFFF.
585      */
586     if ((in_seq & 0xFF800000) == 0xFF800000) {
587 	/*
588          * If expected sequence number is in the range
589 	 * 0xFF800000..0xFFFFFFFF, then we can't make any
590 	 * determinations about the sanity of the sending
591 	 * implementation.
592 	 */
593 	if ((exp_seq & 0xFF800000) == 0xFF800000 && in_seq == exp_seq)
594             return 1;
595 	/*
596          * If sender is not known for certain to be a broken Heimdal
597 	 * implementation, check for exact match.
598 	 */
599 	if (!(ac->auth_context_flags & KRB5_AUTH_CONN_HEIMDAL_SEQ)
600             && in_seq == exp_seq)
601             return 1;
602 	/*
603          * Now apply hairy algorithm for matching sequence numbers
604 	 * sent by broken Heimdal implementations.  If it matches, we
605 	 * know for certain it's a broken Heimdal sender.
606 	 */
607 	if (chk_heimdal_seqnum(exp_seq, in_seq)) {
608             ac->auth_context_flags |= KRB5_AUTH_CONN_HEIMDAL_SEQ;
609             return 1;
610 	}
611         return 0;
612     }
613 
614     /*
615      * Received value not in the ambiguous range?  If the _expected_
616      * value is in the range of ambiguous Hemidal counter values, and
617      * it matches the received value, sender is known to be sane.
618      */
619     if (in_seq == exp_seq) {
620 	if ((	exp_seq & 0xFFFFFF80) == 0x00000080
621             || (exp_seq & 0xFFFF8000) == 0x00008000
622             || (exp_seq & 0xFF800000) == 0x00800000)
623             ac->auth_context_flags |= KRB5_AUTH_CONN_SANE_SEQ;
624 	return 1;
625     }
626 
627     /*
628      * Magic wraparound for the case where the intial sequence number
629      * is in the ambiguous range.  This means that the sender's
630      * counter is at a different count than ours, so we correct ours,
631      * and mark the sender as being a broken Heimdal implementation.
632      */
633     if (exp_seq == 0
634 	&& !(ac->auth_context_flags & KRB5_AUTH_CONN_HEIMDAL_SEQ)) {
635 	switch (in_seq) {
636 	case 0x100:
637 	case 0x10000:
638 	case 0x1000000:
639             ac->auth_context_flags |= KRB5_AUTH_CONN_HEIMDAL_SEQ;
640             exp_seq = in_seq;
641             return 1;
642 	default:
643             return 0;
644 	}
645     }
646     return 0;
647 }
648 
649