pull up r24469, r24530, r24533, r24534, r24535, r24537 from trunk
[krb5.git] / src / lib / krb5 / krb / auth_con.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
3 /*
4  * lib/krb5/krb/auth_con.c
5  *
6  * Copyright 2010 by the Massachusetts Institute of Technology.
7  * All Rights Reserved.
8  *
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.
13  *
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.
27  *
28  */
29
30 #include "k5-int.h"
31 #include "int-proto.h"
32 #include "auth_con.h"
33
34 static krb5_boolean chk_heimdal_seqnum(krb5_ui_4, krb5_ui_4);
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)calloc(1, sizeof(struct _krb5_auth_context));
41     if (!*auth_context)
42         return ENOMEM;
43
44     /* Default flags, do time not seq */
45     (*auth_context)->auth_context_flags =
46         KRB5_AUTH_CONTEXT_DO_TIME |  KRB5_AUTH_CONN_INITIALIZED;
47
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;
54     return 0;
55 }
56
57 krb5_error_code KRB5_CALLCONV
58 krb5_auth_con_free(krb5_context context, krb5_auth_context auth_context)
59 {
60     if (auth_context == NULL)
61         return 0;
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);
84     free(auth_context);
85     return 0;
86 }
87
88 krb5_error_code
89 krb5_auth_con_setaddrs(krb5_context context, krb5_auth_context auth_context, krb5_address *local_addr, krb5_address *remote_addr)
90 {
91     krb5_error_code     retval;
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     retval = 0;
100     if (local_addr)
101         retval = krb5_copy_addr(context,
102                                 local_addr,
103                                 &auth_context->local_addr);
104     else
105         auth_context->local_addr = NULL;
106
107     if (!retval && remote_addr)
108         retval = krb5_copy_addr(context,
109                                 remote_addr,
110                                 &auth_context->remote_addr);
111     else
112         auth_context->remote_addr = NULL;
113
114     return retval;
115 }
116
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)
119 {
120     krb5_error_code     retval;
121
122     retval = 0;
123     if (local_addr && auth_context->local_addr) {
124         retval = krb5_copy_addr(context,
125                                 auth_context->local_addr,
126                                 local_addr);
127     }
128     if (!retval && (remote_addr) && auth_context->remote_addr) {
129         retval = krb5_copy_addr(context,
130                                 auth_context->remote_addr,
131                                 remote_addr);
132     }
133     return retval;
134 }
135
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)
138 {
139     krb5_error_code     retval;
140
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);
146
147     retval = 0;
148     if (local_port)
149         retval = krb5_copy_addr(context,
150                                 local_port,
151                                 &auth_context->local_port);
152     else
153         auth_context->local_port = NULL;
154
155     if (!retval && remote_port)
156         retval = krb5_copy_addr(context,
157                                 remote_port,
158                                 &auth_context->remote_port);
159     else
160         auth_context->remote_port = NULL;
161
162     return retval;
163 }
164
165
166 /*
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.
172  */
173 krb5_error_code KRB5_CALLCONV
174 krb5_auth_con_setuseruserkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock *keyblock)
175 {
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)));
179 }
180
181 krb5_error_code KRB5_CALLCONV
182 krb5_auth_con_getkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
183 {
184     if (auth_context->key)
185         return krb5_k_key_keyblock(context, auth_context->key, keyblock);
186     *keyblock = NULL;
187     return 0;
188 }
189
190 krb5_error_code KRB5_CALLCONV
191 krb5_auth_con_getkey_k(krb5_context context, krb5_auth_context auth_context,
192                        krb5_key *key)
193 {
194     krb5_k_reference_key(context, auth_context->key);
195     *key = auth_context->key;
196     return 0;
197 }
198
199 krb5_error_code KRB5_CALLCONV
200 krb5_auth_con_getlocalsubkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
201 {
202     return krb5_auth_con_getsendsubkey(context, auth_context, keyblock);
203 }
204
205 krb5_error_code KRB5_CALLCONV
206 krb5_auth_con_getremotesubkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
207 {
208     return krb5_auth_con_getrecvsubkey(context, auth_context, keyblock);
209 }
210
211 krb5_error_code KRB5_CALLCONV
212 krb5_auth_con_setsendsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock *keyblock)
213 {
214     if (ac->send_subkey != NULL)
215         krb5_k_free_key(ctx, ac->send_subkey);
216     ac->send_subkey = NULL;
217     if (keyblock !=NULL)
218         return krb5_k_create_key(ctx, keyblock, &ac->send_subkey);
219     else
220         return 0;
221 }
222
223 krb5_error_code KRB5_CALLCONV
224 krb5_auth_con_setsendsubkey_k(krb5_context ctx, krb5_auth_context ac,
225                               krb5_key key)
226 {
227     krb5_k_free_key(ctx, ac->send_subkey);
228     ac->send_subkey = key;
229     krb5_k_reference_key(ctx, key);
230     return 0;
231 }
232
233 krb5_error_code KRB5_CALLCONV
234 krb5_auth_con_setrecvsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock *keyblock)
235 {
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);
241     else
242         return 0;
243 }
244
245 krb5_error_code KRB5_CALLCONV
246 krb5_auth_con_setrecvsubkey_k(krb5_context ctx, krb5_auth_context ac,
247                               krb5_key key)
248 {
249     krb5_k_free_key(ctx, ac->recv_subkey);
250     ac->recv_subkey = key;
251     krb5_k_reference_key(ctx, key);
252     return 0;
253 }
254
255 krb5_error_code KRB5_CALLCONV
256 krb5_auth_con_getsendsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock **keyblock)
257 {
258     if (ac->send_subkey != NULL)
259         return krb5_k_key_keyblock(ctx, ac->send_subkey, keyblock);
260     *keyblock = NULL;
261     return 0;
262 }
263
264 krb5_error_code KRB5_CALLCONV
265 krb5_auth_con_getsendsubkey_k(krb5_context ctx, krb5_auth_context ac,
266                               krb5_key *key)
267 {
268     krb5_k_reference_key(ctx, ac->send_subkey);
269     *key = ac->send_subkey;
270     return 0;
271 }
272
273 krb5_error_code KRB5_CALLCONV
274 krb5_auth_con_getrecvsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock **keyblock)
275 {
276     if (ac->recv_subkey != NULL)
277         return krb5_k_key_keyblock(ctx, ac->recv_subkey, keyblock);
278     *keyblock = NULL;
279     return 0;
280 }
281
282 krb5_error_code KRB5_CALLCONV
283 krb5_auth_con_getrecvsubkey_k(krb5_context ctx, krb5_auth_context ac,
284                               krb5_key *key)
285 {
286     krb5_k_reference_key(ctx, ac->recv_subkey);
287     *key = ac->recv_subkey;
288     return 0;
289 }
290
291 krb5_error_code KRB5_CALLCONV
292 krb5_auth_con_set_req_cksumtype(krb5_context context, krb5_auth_context auth_context, krb5_cksumtype cksumtype)
293 {
294     auth_context->req_cksumtype = cksumtype;
295     return 0;
296 }
297
298 krb5_error_code
299 krb5_auth_con_set_safe_cksumtype(krb5_context context, krb5_auth_context auth_context, krb5_cksumtype cksumtype)
300 {
301     auth_context->safe_cksumtype = cksumtype;
302     return 0;
303 }
304
305 krb5_error_code KRB5_CALLCONV
306 krb5_auth_con_getlocalseqnumber(krb5_context context, krb5_auth_context auth_context, krb5_int32 *seqnumber)
307 {
308     *seqnumber = auth_context->local_seq_number;
309     return 0;
310 }
311
312 krb5_error_code KRB5_CALLCONV
313 krb5_auth_con_getremoteseqnumber(krb5_context context, krb5_auth_context auth_context, krb5_int32 *seqnumber)
314 {
315     *seqnumber = auth_context->remote_seq_number;
316     return 0;
317 }
318
319 krb5_error_code KRB5_CALLCONV
320 krb5_auth_con_initivector(krb5_context context, krb5_auth_context auth_context)
321 {
322     krb5_error_code ret;
323     krb5_enctype enctype;
324
325     if (auth_context->key) {
326         size_t blocksize;
327
328         enctype = krb5_k_key_enctype(context, auth_context->key);
329         if ((ret = krb5_c_block_size(context, enctype, &blocksize)))
330             return(ret);
331         if ((auth_context->i_vector = (krb5_pointer)calloc(1,blocksize))) {
332             return 0;
333         }
334         return ENOMEM;
335     }
336     return EINVAL; /* XXX need an error for no keyblock */
337 }
338
339 krb5_error_code
340 krb5_auth_con_setivector(krb5_context context, krb5_auth_context auth_context, krb5_pointer ivector)
341 {
342     auth_context->i_vector = ivector;
343     return 0;
344 }
345
346 krb5_error_code
347 krb5_auth_con_getivector(krb5_context context, krb5_auth_context auth_context, krb5_pointer *ivector)
348 {
349     *ivector = auth_context->i_vector;
350     return 0;
351 }
352
353 krb5_error_code KRB5_CALLCONV
354 krb5_auth_con_setflags(krb5_context context, krb5_auth_context auth_context, krb5_int32 flags)
355 {
356     auth_context->auth_context_flags = flags;
357     return 0;
358 }
359
360 krb5_error_code KRB5_CALLCONV
361 krb5_auth_con_getflags(krb5_context context, krb5_auth_context auth_context, krb5_int32 *flags)
362 {
363     *flags = auth_context->auth_context_flags;
364     return 0;
365 }
366
367 krb5_error_code KRB5_CALLCONV
368 krb5_auth_con_setrcache(krb5_context context, krb5_auth_context auth_context, krb5_rcache rcache)
369 {
370     auth_context->rcache = rcache;
371     return 0;
372 }
373
374 krb5_error_code
375 krb5_auth_con_getrcache(krb5_context context, krb5_auth_context auth_context, krb5_rcache *rcache)
376 {
377     *rcache = auth_context->rcache;
378     return 0;
379 }
380
381 krb5_error_code
382 krb5_auth_con_setpermetypes(krb5_context context,
383                             krb5_auth_context auth_context,
384                             const krb5_enctype *permetypes)
385 {
386     krb5_enctype *newpe;
387     krb5_error_code ret;
388
389     ret = krb5int_copy_etypes(permetypes, &newpe);
390     if (ret != 0)
391         return ret;
392
393     free(auth_context->permitted_etypes);
394     auth_context->permitted_etypes = newpe;
395     return 0;
396 }
397
398 krb5_error_code
399 krb5_auth_con_getpermetypes(krb5_context context,
400                             krb5_auth_context auth_context,
401                             krb5_enctype **permetypes)
402 {
403     *permetypes = NULL;
404     if (auth_context->permitted_etypes == NULL)
405         return 0;
406     return krb5int_copy_etypes(auth_context->permitted_etypes, permetypes);
407 }
408
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,
413                                  void *data)
414 {
415     auth_context->checksum_func = func;
416     auth_context->checksum_func_data = data;
417     return 0;
418 }
419
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,
424                                  void **data)
425 {
426     *func = auth_context->checksum_func;
427     *data = auth_context->checksum_func_data;
428     return 0;
429 }
430
431 /*
432  * krb5int_auth_con_chkseqnum
433  *
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
441  * here.
442  *
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
449  * encodings set.
450  *
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.
457  *
458  * Heimdal counter value        received uint32 value
459  *
460  * 0x00000080                   0xFFFFFF80
461  * 0x000000FF                   0xFFFFFFFF
462  * 0x00008000                   0xFFFF8000
463  * 0x0000FFFF                   0xFFFFFFFF
464  * 0x00800000                   0xFF800000
465  * 0x00FFFFFF                   0xFFFFFFFF
466  * 0xFF800000                   0xFF800000
467  * 0xFFFFFFFF                   0xFFFFFFFF
468  *
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.
479  *
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
484  * range.
485  *
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
491  * sane.
492  */
493 krb5_boolean
494 krb5int_auth_con_chkseqnum(
495     krb5_context ctx,
496     krb5_auth_context ac,
497     krb5_ui_4 in_seq)
498 {
499     krb5_ui_4 exp_seq;
500
501     exp_seq = ac->remote_seq_number;
502
503     /*
504      * If sender is known to be sane, accept _only_ exact matches.
505      */
506     if (ac->auth_context_flags & KRB5_AUTH_CONN_SANE_SEQ)
507         return in_seq == exp_seq;
508
509     /*
510      * If sender is not known to be sane, first check the ambiguous
511      * range of received values, 0xFF800000..0xFFFFFFFF.
512      */
513     if ((in_seq & 0xFF800000) == 0xFF800000) {
514         /*
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
518          * implementation.
519          */
520         if ((exp_seq & 0xFF800000) == 0xFF800000 && in_seq == exp_seq)
521             return 1;
522         /*
523          * If sender is not known for certain to be a broken Heimdal
524          * implementation, check for exact match.
525          */
526         if (!(ac->auth_context_flags & KRB5_AUTH_CONN_HEIMDAL_SEQ)
527             && in_seq == exp_seq)
528             return 1;
529         /*
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.
533          */
534         if (chk_heimdal_seqnum(exp_seq, in_seq)) {
535             ac->auth_context_flags |= KRB5_AUTH_CONN_HEIMDAL_SEQ;
536             return 1;
537         }
538         return 0;
539     }
540
541     /*
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.
545      */
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;
551         return 1;
552     }
553
554     /*
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.
559      */
560     if (exp_seq == 0
561         && !(ac->auth_context_flags & KRB5_AUTH_CONN_HEIMDAL_SEQ)) {
562         switch (in_seq) {
563         case 0x100:
564         case 0x10000:
565         case 0x1000000:
566             ac->auth_context_flags |= KRB5_AUTH_CONN_HEIMDAL_SEQ;
567             exp_seq = in_seq;
568             return 1;
569         default:
570             return 0;
571         }
572     }
573     return 0;
574 }
575
576 static krb5_boolean
577 chk_heimdal_seqnum(krb5_ui_4 exp_seq, krb5_ui_4 in_seq)
578 {
579     if (( exp_seq & 0xFF800000) == 0x00800000
580         && (in_seq & 0xFF800000) == 0xFF800000
581         && (in_seq & 0x00FFFFFF) == exp_seq)
582         return 1;
583     else if ((  exp_seq & 0xFFFF8000) == 0x00008000
584              && (in_seq & 0xFFFF8000) == 0xFFFF8000
585              && (in_seq & 0x0000FFFF) == exp_seq)
586         return 1;
587     else if ((  exp_seq & 0xFFFFFF80) == 0x00000080
588              && (in_seq & 0xFFFFFF80) == 0xFFFFFF80
589              && (in_seq & 0x000000FF) == exp_seq)
590         return 1;
591     else
592         return 0;
593 }
594
595 krb5_error_code
596 krb5_auth_con_get_subkey_enctype(krb5_context context,
597                                  krb5_auth_context auth_context,
598                                  krb5_enctype *etype)
599 {
600     *etype = auth_context->negotiated_etype;
601     return 0;
602 }
603
604 krb5_error_code
605 krb5_auth_con_get_authdata_context(krb5_context context,
606                                    krb5_auth_context auth_context,
607                                    krb5_authdata_context *ad_context)
608 {
609     *ad_context = auth_context->ad_context;
610     return 0;
611 }
612
613 krb5_error_code
614 krb5_auth_con_set_authdata_context(krb5_context context,
615                                    krb5_auth_context auth_context,
616                                    krb5_authdata_context ad_context)
617 {
618     auth_context->ad_context = ad_context;
619     return 0;
620 }