remove gcc34
[dragonfly.git] / crypto / heimdal-0.6.3 / lib / gssapi / arcfour.c
1 /*
2  * Copyright (c) 2003 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors 
18  *    may be used to endorse or promote products derived from this software 
19  *    without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31  * SUCH DAMAGE. 
32  */
33
34 #include "gssapi_locl.h"
35
36 /*
37  * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt
38  */
39
40 RCSID("$Id: arcfour.c,v 1.12.2.3 2003/09/19 15:15:11 lha Exp $");
41
42 static krb5_error_code
43 arcfour_mic_key(krb5_context context, krb5_keyblock *key,
44                 void *cksum_data, size_t cksum_size,
45                 void *key6_data, size_t key6_size)
46 {
47     krb5_error_code ret;
48     
49     Checksum cksum_k5;
50     krb5_keyblock key5;
51     char k5_data[16];
52     
53     Checksum cksum_k6;
54     
55     char T[4];
56
57     memset(T, 0, 4);
58     cksum_k5.checksum.data = k5_data;
59     cksum_k5.checksum.length = sizeof(k5_data);
60
61     if (key->keytype == KEYTYPE_ARCFOUR_56) {
62         char L40[14] = "fortybits";
63
64         memcpy(L40 + 10, T, sizeof(T));
65         ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
66                         L40, 14, 0, key, &cksum_k5);
67         memset(&k5_data[7], 0xAB, 9);
68     } else {
69         ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
70                         T, 4, 0, key, &cksum_k5);
71     }
72     if (ret)
73         return ret;
74
75     key5.keytype = KEYTYPE_ARCFOUR;
76     key5.keyvalue = cksum_k5.checksum;
77
78     cksum_k6.checksum.data = key6_data;
79     cksum_k6.checksum.length = key6_size;
80
81     return krb5_hmac(context, CKSUMTYPE_RSA_MD5,
82                      cksum_data, cksum_size, 0, &key5, &cksum_k6);
83 }
84
85
86 static krb5_error_code
87 arcfour_mic_cksum(krb5_keyblock *key, unsigned usage,
88                   u_char *sgn_cksum, size_t sgn_cksum_sz,
89                   const char *v1, size_t l1,
90                   const void *v2, size_t l2,
91                   const void *v3, size_t l3)
92 {
93     Checksum CKSUM;
94     u_char *ptr;
95     size_t len;
96     krb5_crypto crypto;
97     krb5_error_code ret;
98     
99     assert(sgn_cksum_sz == 8);
100
101     len = l1 + l2 + l3;
102
103     ptr = malloc(len);
104     if (ptr == NULL)
105         return ENOMEM;
106
107     memcpy(ptr, v1, l1);
108     memcpy(ptr + l1, v2, l2);
109     memcpy(ptr + l1 + l2, v3, l3);
110     
111     ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
112     if (ret) {
113         free(ptr);
114         return ret;
115     }
116     
117     ret = krb5_create_checksum(gssapi_krb5_context,
118                                crypto,
119                                usage,
120                                0,
121                                ptr, len,
122                                &CKSUM);
123     free(ptr);
124     if (ret == 0) {
125         memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz);
126         free_Checksum(&CKSUM);
127     }
128     krb5_crypto_destroy(gssapi_krb5_context, crypto);
129
130     return ret;
131 }
132
133
134 OM_uint32
135 _gssapi_get_mic_arcfour(OM_uint32 * minor_status,
136                         const gss_ctx_id_t context_handle,
137                         gss_qop_t qop_req,
138                         const gss_buffer_t message_buffer,
139                         gss_buffer_t message_token,
140                         krb5_keyblock *key)
141 {
142     krb5_error_code ret;
143     int32_t seq_number;
144     size_t len, total_len;
145     u_char k6_data[16], *p0, *p;
146     RC4_KEY rc4_key;
147     
148     gssapi_krb5_encap_length (22, &len, &total_len);
149     
150     message_token->length = total_len;
151     message_token->value  = malloc (total_len);
152     if (message_token->value == NULL) {
153         *minor_status = ENOMEM;
154         return GSS_S_FAILURE;
155     }
156     
157     p0 = _gssapi_make_mech_header(message_token->value,
158                                   len);
159     p = p0;
160     
161     *p++ = 0x01; /* TOK_ID */
162     *p++ = 0x01;
163     *p++ = 0x11; /* SGN_ALG */
164     *p++ = 0x00;
165     *p++ = 0xff; /* Filler */
166     *p++ = 0xff;
167     *p++ = 0xff;
168     *p++ = 0xff;
169
170     p = NULL;
171
172     ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN,
173                             p0 + 16, 8,  /* SGN_CKSUM */
174                             p0, 8, /* TOK_ID, SGN_ALG, Filer */
175                             message_buffer->value, message_buffer->length,
176                             NULL, 0);
177     if (ret) {
178         gss_release_buffer(minor_status, message_token);
179         *minor_status = ret;
180         return GSS_S_FAILURE;
181     }
182
183     ret = arcfour_mic_key(gssapi_krb5_context, key,
184                           p0 + 16, 8, /* SGN_CKSUM */
185                           k6_data, sizeof(k6_data));
186     if (ret) {
187         gss_release_buffer(minor_status, message_token);
188         *minor_status = ret;
189         return GSS_S_FAILURE;
190     }
191
192     krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
193                                      context_handle->auth_context,
194                                      &seq_number);
195     p = p0 + 8; /* SND_SEQ */
196     gssapi_encode_be_om_uint32(seq_number, p);
197     
198     krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
199                                      context_handle->auth_context,
200                                      ++seq_number);
201     
202     memset (p + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xff, 4);
203
204     RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
205     RC4 (&rc4_key, 8, p, p);
206         
207     memset(&rc4_key, 0, sizeof(rc4_key));
208     memset(k6_data, 0, sizeof(k6_data));
209     
210     *minor_status = 0;
211     return GSS_S_COMPLETE;
212 }
213
214
215 OM_uint32
216 _gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
217                            const gss_ctx_id_t context_handle,
218                            const gss_buffer_t message_buffer,
219                            const gss_buffer_t token_buffer,
220                            gss_qop_t * qop_state,
221                            krb5_keyblock *key,
222                            char *type)
223 {
224     krb5_error_code ret;
225     int32_t seq_number, seq_number2;
226     OM_uint32 omret;
227     char cksum_data[8], k6_data[16], SND_SEQ[8];
228     u_char *p;
229     int cmp;
230     
231     if (qop_state)
232         *qop_state = 0;
233
234     p = token_buffer->value;
235     omret = gssapi_krb5_verify_header (&p,
236                                        token_buffer->length,
237                                        type);
238     if (omret)
239         return omret;
240     
241     if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
242         return GSS_S_BAD_SIG;
243     p += 2;
244     if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
245         return GSS_S_BAD_MIC;
246     p += 4;
247
248     ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN,
249                             cksum_data, sizeof(cksum_data),
250                             p - 8, 8,
251                             message_buffer->value, message_buffer->length,
252                             NULL, 0);
253     if (ret) {
254         *minor_status = ret;
255         return GSS_S_FAILURE;
256     }
257
258     ret = arcfour_mic_key(gssapi_krb5_context, key,
259                           cksum_data, sizeof(cksum_data),
260                           k6_data, sizeof(k6_data));
261     if (ret) {
262         *minor_status = ret;
263         return GSS_S_FAILURE;
264     }
265
266     cmp = memcmp(cksum_data, p + 8, 8);
267     if (cmp) {
268         *minor_status = 0;
269         return GSS_S_BAD_MIC;
270     }
271
272     {
273         RC4_KEY rc4_key;
274         
275         RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
276         RC4 (&rc4_key, 8, p, SND_SEQ);
277         
278         memset(&rc4_key, 0, sizeof(rc4_key));
279         memset(k6_data, 0, sizeof(k6_data));
280     }
281
282     gssapi_decode_be_om_uint32(SND_SEQ, &seq_number);
283
284     if (context_handle->more_flags & LOCAL)
285         cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
286     else
287         cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
288
289     memset(SND_SEQ, 0, sizeof(SND_SEQ));
290     if (cmp != 0) {
291         *minor_status = 0;
292         return GSS_S_BAD_MIC;
293     }
294     
295     krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
296                                       context_handle->auth_context,
297                                       &seq_number2);
298
299     if (seq_number != seq_number2) {
300         *minor_status = 0;
301         return GSS_S_UNSEQ_TOKEN;
302     }
303
304     krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
305                                       context_handle->auth_context,
306                                       ++seq_number2);
307
308     *minor_status = 0;
309     return GSS_S_COMPLETE;
310 }
311
312 OM_uint32
313 _gssapi_wrap_arcfour(OM_uint32 * minor_status,
314                      const gss_ctx_id_t context_handle,
315                      int conf_req_flag,
316                      gss_qop_t qop_req,
317                      const gss_buffer_t input_message_buffer,
318                      int * conf_state,
319                      gss_buffer_t output_message_buffer,
320                      krb5_keyblock *key)
321 {
322     u_char Klocaldata[16], k6_data[16], *p, *p0;
323     size_t len, total_len, datalen;
324     krb5_keyblock Klocal;
325     krb5_error_code ret;
326     int32_t seq_number;
327
328     if (conf_state)
329         *conf_state = 0;
330
331     datalen = input_message_buffer->length + 1 /* padding */;
332     len = datalen + 30;
333     gssapi_krb5_encap_length (len, &len, &total_len);
334
335     output_message_buffer->length = total_len;
336     output_message_buffer->value  = malloc (total_len);
337     if (output_message_buffer->value == NULL) {
338         *minor_status = ENOMEM;
339         return GSS_S_FAILURE;
340     }
341     
342     p0 = _gssapi_make_mech_header(output_message_buffer->value,
343                                   len);
344     p = p0;
345
346     *p++ = 0x02; /* TOK_ID */
347     *p++ = 0x01;
348     *p++ = 0x11; /* SGN_ALG */
349     *p++ = 0x00;
350     if (conf_req_flag) {
351         *p++ = 0x10; /* SEAL_ALG */
352         *p++ = 0x00;
353     } else {
354         *p++ = 0xff; /* SEAL_ALG */
355         *p++ = 0xff;
356     }
357     *p++ = 0xff; /* Filler */
358     *p++ = 0xff;
359
360     p = NULL;
361
362     krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
363                                      context_handle->auth_context,
364                                      &seq_number);
365
366     gssapi_encode_be_om_uint32(seq_number, p0 + 8);
367
368     krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
369                                      context_handle->auth_context,
370                                      ++seq_number);
371
372     memset (p0 + 8 + 4,
373             (context_handle->more_flags & LOCAL) ? 0 : 0xff,
374             4);
375
376     krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
377     
378     /* p points to data */
379     p = p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
380     memcpy(p, input_message_buffer->value, input_message_buffer->length);
381     p[input_message_buffer->length] = 1; /* PADDING */
382
383     ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL,
384                             p0 + 16, 8, /* SGN_CKSUM */ 
385                             p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
386                             p0 + 24, 8, /* Confounder */
387                             p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, 
388                             datalen);
389     if (ret) {
390         *minor_status = ret;
391         gss_release_buffer(minor_status, output_message_buffer);
392         return GSS_S_FAILURE;
393     }
394
395     {
396         int i;
397
398         Klocal.keytype = key->keytype;
399         Klocal.keyvalue.data = Klocaldata;
400         Klocal.keyvalue.length = sizeof(Klocaldata);
401
402         for (i = 0; i < 16; i++)
403             Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
404     }
405     ret = arcfour_mic_key(gssapi_krb5_context, &Klocal,
406                           p0 + 8, 4, /* SND_SEQ */
407                           k6_data, sizeof(k6_data));
408     memset(Klocaldata, 0, sizeof(Klocaldata));
409     if (ret) {
410         gss_release_buffer(minor_status, output_message_buffer);
411         *minor_status = ret;
412         return GSS_S_FAILURE;
413     }
414
415
416     if(conf_req_flag) {
417         RC4_KEY rc4_key;
418
419         RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
420         /* XXX ? */
421         RC4 (&rc4_key, 8 + datalen, p0 + 24, p0 + 24); /* Confounder + data */
422         memset(&rc4_key, 0, sizeof(rc4_key));
423     }
424     memset(k6_data, 0, sizeof(k6_data));
425
426     ret = arcfour_mic_key(gssapi_krb5_context, key,
427                           p0 + 16, 8, /* SGN_CKSUM */
428                           k6_data, sizeof(k6_data));
429     if (ret) {
430         gss_release_buffer(minor_status, output_message_buffer);
431         *minor_status = ret;
432         return GSS_S_FAILURE;
433     }
434
435     {
436         RC4_KEY rc4_key;
437         
438         RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
439         RC4 (&rc4_key, 8, p0 + 8, p0 + 8); /* SND_SEQ */
440         memset(&rc4_key, 0, sizeof(rc4_key));
441         memset(k6_data, 0, sizeof(k6_data));
442     }
443
444     if (conf_state)
445         *conf_state = conf_req_flag;
446
447     *minor_status = 0;
448     return GSS_S_COMPLETE;
449 }
450
451 OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
452                                  const gss_ctx_id_t context_handle,
453                                  const gss_buffer_t input_message_buffer,
454                                  gss_buffer_t output_message_buffer,
455                                  int *conf_state,
456                                  gss_qop_t *qop_state,
457                                  krb5_keyblock *key)
458 {
459     u_char Klocaldata[16];
460     krb5_keyblock Klocal;
461     krb5_error_code ret;
462     int32_t seq_number, seq_number2;
463     size_t datalen;
464     OM_uint32 omret;
465     char k6_data[16], SND_SEQ[8], Confounder[8];
466     char cksum_data[8];
467     u_char *p, *p0;
468     int cmp;
469     int conf_flag;
470     size_t padlen;
471     
472     if (conf_state)
473         *conf_state = 0;
474     if (qop_state)
475         *qop_state = 0;
476
477     p0 = input_message_buffer->value;
478     omret = _gssapi_verify_mech_header(&p0,
479                                        input_message_buffer->length);
480     if (omret)
481         return omret;
482     p = p0;
483
484     datalen = input_message_buffer->length -
485         (p - ((u_char *)input_message_buffer->value)) - 
486         GSS_ARCFOUR_WRAP_TOKEN_SIZE;
487
488     if (memcmp(p, "\x02\x01", 2) != 0)
489         return GSS_S_BAD_SIG;
490     p += 2;
491     if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
492         return GSS_S_BAD_SIG;
493     p += 2;
494
495     if (memcmp (p, "\x10\x00", 2) == 0)
496         conf_flag = 1;
497     else if (memcmp (p, "\xff\xff", 2) == 0)
498         conf_flag = 0;
499     else
500         return GSS_S_BAD_SIG;
501
502     p += 2;
503     if (memcmp (p, "\xff\xff", 2) != 0)
504         return GSS_S_BAD_MIC;
505     p = NULL;
506
507     ret = arcfour_mic_key(gssapi_krb5_context, key,
508                           p0 + 16, 8, /* SGN_CKSUM */
509                           k6_data, sizeof(k6_data));
510     if (ret) {
511         *minor_status = ret;
512         return GSS_S_FAILURE;
513     }
514
515     {
516         RC4_KEY rc4_key;
517         
518         RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
519         RC4 (&rc4_key, 8, p0 + 8, SND_SEQ); /* SND_SEQ */
520         memset(&rc4_key, 0, sizeof(rc4_key));
521         memset(k6_data, 0, sizeof(k6_data));
522     }
523
524     gssapi_decode_be_om_uint32(SND_SEQ, &seq_number);
525
526     if (context_handle->more_flags & LOCAL)
527         cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
528     else
529         cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
530
531     if (cmp != 0) {
532         *minor_status = 0;
533         return GSS_S_BAD_MIC;
534     }
535
536     {
537         int i;
538
539         Klocal.keytype = key->keytype;
540         Klocal.keyvalue.data = Klocaldata;
541         Klocal.keyvalue.length = sizeof(Klocaldata);
542
543         for (i = 0; i < 16; i++)
544             Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
545     }
546     ret = arcfour_mic_key(gssapi_krb5_context, &Klocal,
547                           SND_SEQ, 4,
548                           k6_data, sizeof(k6_data));
549     memset(Klocaldata, 0, sizeof(Klocaldata));
550     if (ret) {
551         *minor_status = ret;
552         return GSS_S_FAILURE;
553     }
554
555     output_message_buffer->value = malloc(datalen);
556     if (output_message_buffer->value == NULL) {
557         *minor_status = ENOMEM;
558         return GSS_S_FAILURE;
559     }
560     output_message_buffer->length = datalen;
561
562     if(conf_flag) {
563         RC4_KEY rc4_key;
564
565         RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
566         RC4 (&rc4_key, 8, p0 + 24, Confounder); /* Confounder */
567         RC4 (&rc4_key, datalen, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
568              output_message_buffer->value);
569         memset(&rc4_key, 0, sizeof(rc4_key));
570     } else {
571         memcpy(Confounder, p0 + 24, 8); /* Confounder */
572         memcpy(output_message_buffer->value, 
573                p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
574                datalen);
575     }
576     memset(k6_data, 0, sizeof(k6_data));
577
578     ret = _gssapi_verify_pad(output_message_buffer, datalen, &padlen);
579     if (ret) {
580         gss_release_buffer(minor_status, output_message_buffer);
581         *minor_status = 0;
582         return ret;
583     }
584     output_message_buffer->length -= padlen;
585
586     ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL,
587                             cksum_data, sizeof(cksum_data),
588                             p0, 8, 
589                             Confounder, sizeof(Confounder),
590                             output_message_buffer->value, 
591                             output_message_buffer->length + padlen);
592     if (ret) {
593         gss_release_buffer(minor_status, output_message_buffer);
594         *minor_status = ret;
595         return GSS_S_FAILURE;
596     }
597
598     cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */
599     if (cmp) {
600         gss_release_buffer(minor_status, output_message_buffer);
601         *minor_status = 0;
602         return GSS_S_BAD_MIC;
603     }
604
605     krb5_auth_getremoteseqnumber (gssapi_krb5_context,
606                                   context_handle->auth_context,
607                                   &seq_number2);
608
609     if (seq_number != seq_number2) {
610         *minor_status = 0;
611         return GSS_S_UNSEQ_TOKEN;
612     }
613
614     krb5_auth_con_setremoteseqnumber (gssapi_krb5_context,
615                                       context_handle->auth_context,
616                                       ++seq_number2);
617
618     if (conf_state)
619         *conf_state = conf_flag;
620
621     *minor_status = 0;
622     return GSS_S_COMPLETE;
623 }