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