]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/heimdal/lib/gssapi/krb5/arcfour.c
heimdal: Fix multiple security vulnerabilities
[FreeBSD/FreeBSD.git] / crypto / heimdal / lib / gssapi / krb5 / arcfour.c
1 /*
2  * Copyright (c) 2003 - 2006 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 "gsskrb5_locl.h"
35
36 /*
37  * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt
38  *
39  * The arcfour message have the following formats:
40  *
41  * MIC token
42  *      TOK_ID[2] = 01 01
43  *      SGN_ALG[2] = 11 00
44  *      Filler[4]
45  *      SND_SEQ[8]
46  *      SGN_CKSUM[8]
47  *
48  * WRAP token
49  *      TOK_ID[2] = 02 01
50  *      SGN_ALG[2];
51  *      SEAL_ALG[2]
52  *      Filler[2]
53  *      SND_SEQ[2]
54  *      SGN_CKSUM[8]
55  *      Confounder[8]
56  */
57
58 /*
59  * WRAP in DCE-style have a fixed size header, the oid and length over
60  * the WRAP header is a total of
61  * GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE +
62  * GSS_ARCFOUR_WRAP_TOKEN_SIZE byte (ie total of 45 bytes overhead,
63  * remember the 2 bytes from APPL [0] SEQ).
64  */
65
66 #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
67 #define GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE 13
68
69
70 static krb5_error_code
71 arcfour_mic_key(krb5_context context, krb5_keyblock *key,
72                 void *cksum_data, size_t cksum_size,
73                 void *key6_data, size_t key6_size)
74 {
75     krb5_error_code ret;
76
77     Checksum cksum_k5;
78     krb5_keyblock key5;
79     char k5_data[16];
80
81     Checksum cksum_k6;
82
83     char T[4];
84
85     memset(T, 0, 4);
86     cksum_k5.checksum.data = k5_data;
87     cksum_k5.checksum.length = sizeof(k5_data);
88
89     if (key->keytype == ENCTYPE_ARCFOUR_HMAC_MD5_56) {
90         char L40[14] = "fortybits";
91
92         memcpy(L40 + 10, T, sizeof(T));
93         ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
94                         L40, 14, 0, key, &cksum_k5);
95         memset(&k5_data[7], 0xAB, 9);
96     } else {
97         ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
98                         T, 4, 0, key, &cksum_k5);
99     }
100     if (ret)
101         return ret;
102
103     key5.keytype = ENCTYPE_ARCFOUR_HMAC_MD5;
104     key5.keyvalue = cksum_k5.checksum;
105
106     cksum_k6.checksum.data = key6_data;
107     cksum_k6.checksum.length = key6_size;
108
109     return krb5_hmac(context, CKSUMTYPE_RSA_MD5,
110                      cksum_data, cksum_size, 0, &key5, &cksum_k6);
111 }
112
113
114 static krb5_error_code
115 arcfour_mic_cksum(krb5_context context,
116                   krb5_keyblock *key, unsigned usage,
117                   u_char *sgn_cksum, size_t sgn_cksum_sz,
118                   const u_char *v1, size_t l1,
119                   const void *v2, size_t l2,
120                   const void *v3, size_t l3)
121 {
122     Checksum CKSUM;
123     u_char *ptr;
124     size_t len;
125     krb5_crypto crypto;
126     krb5_error_code ret;
127
128     assert(sgn_cksum_sz == 8);
129
130     len = l1 + l2 + l3;
131
132     ptr = malloc(len);
133     if (ptr == NULL)
134         return ENOMEM;
135
136     memcpy(ptr, v1, l1);
137     memcpy(ptr + l1, v2, l2);
138     memcpy(ptr + l1 + l2, v3, l3);
139
140     ret = krb5_crypto_init(context, key, 0, &crypto);
141     if (ret) {
142         free(ptr);
143         return ret;
144     }
145
146     ret = krb5_create_checksum(context,
147                                crypto,
148                                usage,
149                                0,
150                                ptr, len,
151                                &CKSUM);
152     free(ptr);
153     if (ret == 0) {
154         memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz);
155         free_Checksum(&CKSUM);
156     }
157     krb5_crypto_destroy(context, crypto);
158
159     return ret;
160 }
161
162
163 OM_uint32
164 _gssapi_get_mic_arcfour(OM_uint32 * minor_status,
165                         const gsskrb5_ctx context_handle,
166                         krb5_context context,
167                         gss_qop_t qop_req,
168                         const gss_buffer_t message_buffer,
169                         gss_buffer_t message_token,
170                         krb5_keyblock *key)
171 {
172     krb5_error_code ret;
173     int32_t seq_number;
174     size_t len, total_len;
175     u_char k6_data[16], *p0, *p;
176     EVP_CIPHER_CTX *rc4_key;
177
178     _gsskrb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM);
179
180     message_token->length = total_len;
181     message_token->value  = malloc (total_len);
182     if (message_token->value == NULL) {
183         *minor_status = ENOMEM;
184         return GSS_S_FAILURE;
185     }
186
187     p0 = _gssapi_make_mech_header(message_token->value,
188                                   len,
189                                   GSS_KRB5_MECHANISM);
190     p = p0;
191
192     *p++ = 0x01; /* TOK_ID */
193     *p++ = 0x01;
194     *p++ = 0x11; /* SGN_ALG */
195     *p++ = 0x00;
196     *p++ = 0xff; /* Filler */
197     *p++ = 0xff;
198     *p++ = 0xff;
199     *p++ = 0xff;
200
201     p = NULL;
202
203     ret = arcfour_mic_cksum(context,
204                             key, KRB5_KU_USAGE_SIGN,
205                             p0 + 16, 8,  /* SGN_CKSUM */
206                             p0, 8, /* TOK_ID, SGN_ALG, Filer */
207                             message_buffer->value, message_buffer->length,
208                             NULL, 0);
209     if (ret) {
210         _gsskrb5_release_buffer(minor_status, message_token);
211         *minor_status = ret;
212         return GSS_S_FAILURE;
213     }
214
215     ret = arcfour_mic_key(context, key,
216                           p0 + 16, 8, /* SGN_CKSUM */
217                           k6_data, sizeof(k6_data));
218     if (ret) {
219         _gsskrb5_release_buffer(minor_status, message_token);
220         *minor_status = ret;
221         return GSS_S_FAILURE;
222     }
223
224     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
225     krb5_auth_con_getlocalseqnumber (context,
226                                      context_handle->auth_context,
227                                      &seq_number);
228     p = p0 + 8; /* SND_SEQ */
229     _gsskrb5_encode_be_om_uint32(seq_number, p);
230
231     krb5_auth_con_setlocalseqnumber (context,
232                                      context_handle->auth_context,
233                                      ++seq_number);
234     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
235
236     memset (p + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xff, 4);
237
238     rc4_key = EVP_CIPHER_CTX_new();
239     if (rc4_key == NULL) {
240         _gsskrb5_release_buffer(minor_status, message_token);
241         *minor_status = ENOMEM;
242         return GSS_S_FAILURE;
243     }
244
245     EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
246     EVP_Cipher(rc4_key, p, p, 8);
247     EVP_CIPHER_CTX_free(rc4_key);
248
249     memset(k6_data, 0, sizeof(k6_data));
250
251     *minor_status = 0;
252     return GSS_S_COMPLETE;
253 }
254
255
256 OM_uint32
257 _gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
258                            const gsskrb5_ctx context_handle,
259                            krb5_context context,
260                            const gss_buffer_t message_buffer,
261                            const gss_buffer_t token_buffer,
262                            gss_qop_t * qop_state,
263                            krb5_keyblock *key,
264                            const char *type)
265 {
266     krb5_error_code ret;
267     uint32_t seq_number;
268     OM_uint32 omret;
269     u_char SND_SEQ[8], cksum_data[8], *p;
270     char k6_data[16];
271     int cmp;
272
273     if (qop_state)
274         *qop_state = 0;
275
276     p = token_buffer->value;
277     omret = _gsskrb5_verify_header (&p,
278                                        token_buffer->length,
279                                        type,
280                                        GSS_KRB5_MECHANISM);
281     if (omret)
282         return omret;
283
284     if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
285         return GSS_S_BAD_SIG;
286     p += 2;
287     if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
288         return GSS_S_BAD_MIC;
289     p += 4;
290
291     ret = arcfour_mic_cksum(context,
292                             key, KRB5_KU_USAGE_SIGN,
293                             cksum_data, sizeof(cksum_data),
294                             p - 8, 8,
295                             message_buffer->value, message_buffer->length,
296                             NULL, 0);
297     if (ret) {
298         *minor_status = ret;
299         return GSS_S_FAILURE;
300     }
301
302     ret = arcfour_mic_key(context, key,
303                           cksum_data, sizeof(cksum_data),
304                           k6_data, sizeof(k6_data));
305     if (ret) {
306         *minor_status = ret;
307         return GSS_S_FAILURE;
308     }
309
310     cmp = (ct_memcmp(cksum_data, p + 8, 8) == 0);
311     if (cmp) {
312         *minor_status = 0;
313         return GSS_S_BAD_MIC;
314     }
315
316     {
317         EVP_CIPHER_CTX *rc4_key;
318
319         rc4_key = EVP_CIPHER_CTX_new();
320         if (rc4_key == NULL) {
321             *minor_status = ENOMEM;
322             return GSS_S_FAILURE;
323         }
324         EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, (void *)k6_data, NULL, 0);
325         EVP_Cipher(rc4_key, SND_SEQ, p, 8);
326         EVP_CIPHER_CTX_free(rc4_key);
327
328         memset(k6_data, 0, sizeof(k6_data));
329     }
330
331     _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number);
332
333     if (context_handle->more_flags & LOCAL)
334         cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0);
335     else
336         cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0);
337
338     memset(SND_SEQ, 0, sizeof(SND_SEQ));
339     if (cmp != 0) {
340         *minor_status = 0;
341         return GSS_S_BAD_MIC;
342     }
343
344     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
345     omret = _gssapi_msg_order_check(context_handle->order, seq_number);
346     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
347     if (omret)
348         return omret;
349
350     *minor_status = 0;
351     return GSS_S_COMPLETE;
352 }
353
354 OM_uint32
355 _gssapi_wrap_arcfour(OM_uint32 * minor_status,
356                      const gsskrb5_ctx context_handle,
357                      krb5_context context,
358                      int conf_req_flag,
359                      gss_qop_t qop_req,
360                      const gss_buffer_t input_message_buffer,
361                      int * conf_state,
362                      gss_buffer_t output_message_buffer,
363                      krb5_keyblock *key)
364 {
365     u_char Klocaldata[16], k6_data[16], *p, *p0;
366     size_t len, total_len, datalen;
367     krb5_keyblock Klocal;
368     krb5_error_code ret;
369     int32_t seq_number;
370
371     if (conf_state)
372         *conf_state = 0;
373
374     datalen = input_message_buffer->length;
375
376     if (IS_DCE_STYLE(context_handle)) {
377         len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
378         _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
379         total_len += datalen;
380     } else {
381         datalen += 1; /* padding */
382         len = datalen + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
383         _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
384     }
385
386     output_message_buffer->length = total_len;
387     output_message_buffer->value  = malloc (total_len);
388     if (output_message_buffer->value == NULL) {
389         *minor_status = ENOMEM;
390         return GSS_S_FAILURE;
391     }
392
393     p0 = _gssapi_make_mech_header(output_message_buffer->value,
394                                   len,
395                                   GSS_KRB5_MECHANISM);
396     p = p0;
397
398     *p++ = 0x02; /* TOK_ID */
399     *p++ = 0x01;
400     *p++ = 0x11; /* SGN_ALG */
401     *p++ = 0x00;
402     if (conf_req_flag) {
403         *p++ = 0x10; /* SEAL_ALG */
404         *p++ = 0x00;
405     } else {
406         *p++ = 0xff; /* SEAL_ALG */
407         *p++ = 0xff;
408     }
409     *p++ = 0xff; /* Filler */
410     *p++ = 0xff;
411
412     p = NULL;
413
414     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
415     krb5_auth_con_getlocalseqnumber (context,
416                                      context_handle->auth_context,
417                                      &seq_number);
418
419     _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8);
420
421     krb5_auth_con_setlocalseqnumber (context,
422                                      context_handle->auth_context,
423                                      ++seq_number);
424     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
425
426     memset (p0 + 8 + 4,
427             (context_handle->more_flags & LOCAL) ? 0 : 0xff,
428             4);
429
430     krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
431
432     /* p points to data */
433     p = p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
434     memcpy(p, input_message_buffer->value, input_message_buffer->length);
435
436     if (!IS_DCE_STYLE(context_handle))
437         p[input_message_buffer->length] = 1; /* padding */
438
439     ret = arcfour_mic_cksum(context,
440                             key, KRB5_KU_USAGE_SEAL,
441                             p0 + 16, 8, /* SGN_CKSUM */
442                             p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
443                             p0 + 24, 8, /* Confounder */
444                             p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
445                             datalen);
446     if (ret) {
447         *minor_status = ret;
448         _gsskrb5_release_buffer(minor_status, output_message_buffer);
449         return GSS_S_FAILURE;
450     }
451
452     {
453         int i;
454
455         Klocal.keytype = key->keytype;
456         Klocal.keyvalue.data = Klocaldata;
457         Klocal.keyvalue.length = sizeof(Klocaldata);
458
459         for (i = 0; i < 16; i++)
460             Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
461     }
462     ret = arcfour_mic_key(context, &Klocal,
463                           p0 + 8, 4, /* SND_SEQ */
464                           k6_data, sizeof(k6_data));
465     memset(Klocaldata, 0, sizeof(Klocaldata));
466     if (ret) {
467         _gsskrb5_release_buffer(minor_status, output_message_buffer);
468         *minor_status = ret;
469         return GSS_S_FAILURE;
470     }
471
472
473     if(conf_req_flag) {
474         EVP_CIPHER_CTX *rc4_key;
475
476         rc4_key = EVP_CIPHER_CTX_new();
477         if (rc4_key == NULL) {
478             _gsskrb5_release_buffer(minor_status, output_message_buffer);
479             *minor_status = ENOMEM;
480             return GSS_S_FAILURE;
481         }
482         EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
483         EVP_Cipher(rc4_key, p0 + 24, p0 + 24, 8 + datalen);
484         EVP_CIPHER_CTX_free(rc4_key);
485     }
486     memset(k6_data, 0, sizeof(k6_data));
487
488     ret = arcfour_mic_key(context, key,
489                           p0 + 16, 8, /* SGN_CKSUM */
490                           k6_data, sizeof(k6_data));
491     if (ret) {
492         _gsskrb5_release_buffer(minor_status, output_message_buffer);
493         *minor_status = ret;
494         return GSS_S_FAILURE;
495     }
496
497     {
498         EVP_CIPHER_CTX *rc4_key;
499
500         rc4_key = EVP_CIPHER_CTX_new();
501         if (rc4_key == NULL) {
502             _gsskrb5_release_buffer(minor_status, output_message_buffer);
503             *minor_status = ENOMEM;
504             return GSS_S_FAILURE;
505         }
506         EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
507         EVP_Cipher(rc4_key, p0 + 8, p0 + 8 /* SND_SEQ */, 8);
508         EVP_CIPHER_CTX_free(rc4_key);
509         memset(k6_data, 0, sizeof(k6_data));
510     }
511
512     if (conf_state)
513         *conf_state = conf_req_flag;
514
515     *minor_status = 0;
516     return GSS_S_COMPLETE;
517 }
518
519 OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
520                                  const gsskrb5_ctx context_handle,
521                                  krb5_context context,
522                                  const gss_buffer_t input_message_buffer,
523                                  gss_buffer_t output_message_buffer,
524                                  int *conf_state,
525                                  gss_qop_t *qop_state,
526                                  krb5_keyblock *key)
527 {
528     u_char Klocaldata[16];
529     krb5_keyblock Klocal;
530     krb5_error_code ret;
531     uint32_t seq_number;
532     size_t datalen;
533     OM_uint32 omret;
534     u_char k6_data[16], SND_SEQ[8], Confounder[8];
535     u_char cksum_data[8];
536     u_char *p, *p0;
537     int cmp;
538     int conf_flag;
539     size_t padlen = 0, len;
540
541     if (conf_state)
542         *conf_state = 0;
543     if (qop_state)
544         *qop_state = 0;
545
546     p0 = input_message_buffer->value;
547
548     if (IS_DCE_STYLE(context_handle)) {
549         len = GSS_ARCFOUR_WRAP_TOKEN_SIZE +
550             GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE;
551         if (input_message_buffer->length < len)
552             return GSS_S_BAD_MECH;
553     } else {
554         len = input_message_buffer->length;
555     }
556
557     omret = _gssapi_verify_mech_header(&p0,
558                                        len,
559                                        GSS_KRB5_MECHANISM);
560     if (omret)
561         return omret;
562
563     /* length of mech header */
564     len = (p0 - (u_char *)input_message_buffer->value) +
565         GSS_ARCFOUR_WRAP_TOKEN_SIZE;
566
567     if (len > input_message_buffer->length)
568         return GSS_S_BAD_MECH;
569
570     /* length of data */
571     datalen = input_message_buffer->length - len;
572
573     p = p0;
574
575     if (memcmp(p, "\x02\x01", 2) != 0)
576         return GSS_S_BAD_SIG;
577     p += 2;
578     if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
579         return GSS_S_BAD_SIG;
580     p += 2;
581
582     if (memcmp (p, "\x10\x00", 2) == 0)
583         conf_flag = 1;
584     else if (memcmp (p, "\xff\xff", 2) == 0)
585         conf_flag = 0;
586     else
587         return GSS_S_BAD_SIG;
588
589     p += 2;
590     if (memcmp (p, "\xff\xff", 2) != 0)
591         return GSS_S_BAD_MIC;
592     p = NULL;
593
594     ret = arcfour_mic_key(context, key,
595                           p0 + 16, 8, /* SGN_CKSUM */
596                           k6_data, sizeof(k6_data));
597     if (ret) {
598         *minor_status = ret;
599         return GSS_S_FAILURE;
600     }
601
602     {
603         EVP_CIPHER_CTX *rc4_key;
604
605         rc4_key = EVP_CIPHER_CTX_new();
606         if (rc4_key == NULL) {
607             *minor_status = ENOMEM;
608             return GSS_S_FAILURE;
609         }
610         EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
611         EVP_Cipher(rc4_key, SND_SEQ, p0 + 8, 8);
612         EVP_CIPHER_CTX_free(rc4_key);
613         memset(k6_data, 0, sizeof(k6_data));
614     }
615
616     _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number);
617
618     if (context_handle->more_flags & LOCAL)
619         cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0);
620     else
621         cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0);
622
623     if (cmp != 0) {
624         *minor_status = 0;
625         return GSS_S_BAD_MIC;
626     }
627
628     {
629         int i;
630
631         Klocal.keytype = key->keytype;
632         Klocal.keyvalue.data = Klocaldata;
633         Klocal.keyvalue.length = sizeof(Klocaldata);
634
635         for (i = 0; i < 16; i++)
636             Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
637     }
638     ret = arcfour_mic_key(context, &Klocal,
639                           SND_SEQ, 4,
640                           k6_data, sizeof(k6_data));
641     memset(Klocaldata, 0, sizeof(Klocaldata));
642     if (ret) {
643         *minor_status = ret;
644         return GSS_S_FAILURE;
645     }
646
647     output_message_buffer->value = malloc(datalen);
648     if (output_message_buffer->value == NULL) {
649         *minor_status = ENOMEM;
650         return GSS_S_FAILURE;
651     }
652     output_message_buffer->length = datalen;
653
654     if(conf_flag) {
655         EVP_CIPHER_CTX *rc4_key;
656
657         rc4_key = EVP_CIPHER_CTX_new();
658         if (rc4_key == NULL) {
659             _gsskrb5_release_buffer(minor_status, output_message_buffer);
660             *minor_status = ENOMEM;
661             return GSS_S_FAILURE;
662         }
663         EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
664         EVP_Cipher(rc4_key, Confounder, p0 + 24, 8);
665         EVP_Cipher(rc4_key, output_message_buffer->value, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, datalen);
666         EVP_CIPHER_CTX_free(rc4_key);
667     } else {
668         memcpy(Confounder, p0 + 24, 8); /* Confounder */
669         memcpy(output_message_buffer->value,
670                p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
671                datalen);
672     }
673     memset(k6_data, 0, sizeof(k6_data));
674
675     if (!IS_DCE_STYLE(context_handle)) {
676         ret = _gssapi_verify_pad(output_message_buffer, datalen, &padlen);
677         if (ret) {
678             _gsskrb5_release_buffer(minor_status, output_message_buffer);
679             *minor_status = 0;
680             return ret;
681         }
682         output_message_buffer->length -= padlen;
683     }
684
685     ret = arcfour_mic_cksum(context,
686                             key, KRB5_KU_USAGE_SEAL,
687                             cksum_data, sizeof(cksum_data),
688                             p0, 8,
689                             Confounder, sizeof(Confounder),
690                             output_message_buffer->value,
691                             output_message_buffer->length + padlen);
692     if (ret) {
693         _gsskrb5_release_buffer(minor_status, output_message_buffer);
694         *minor_status = ret;
695         return GSS_S_FAILURE;
696     }
697
698     cmp = (ct_memcmp(cksum_data, p0 + 16, 8) == 0); /* SGN_CKSUM */
699     if (cmp) {
700         _gsskrb5_release_buffer(minor_status, output_message_buffer);
701         *minor_status = 0;
702         return GSS_S_BAD_MIC;
703     }
704
705     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
706     omret = _gssapi_msg_order_check(context_handle->order, seq_number);
707     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
708     if (omret)
709         return omret;
710
711     if (conf_state)
712         *conf_state = conf_flag;
713
714     *minor_status = 0;
715     return GSS_S_COMPLETE;
716 }
717
718 static OM_uint32
719 max_wrap_length_arcfour(const gsskrb5_ctx ctx,
720                         krb5_crypto crypto,
721                         size_t input_length,
722                         OM_uint32 *max_input_size)
723 {
724     /*
725      * if GSS_C_DCE_STYLE is in use:
726      *  - we only need to encapsulate the WRAP token
727      * However, since this is a fixed since, we just
728      */
729     if (IS_DCE_STYLE(ctx)) {
730         size_t len, total_len;
731
732         len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
733         _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
734
735         if (input_length < len)
736             *max_input_size = 0;
737         else
738             *max_input_size = input_length - len;
739
740     } else {
741         size_t extrasize = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
742         size_t blocksize = 8;
743         size_t len, total_len;
744
745         len = 8 + input_length + blocksize + extrasize;
746
747         _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
748
749         total_len -= input_length; /* token length */
750         if (total_len < input_length) {
751             *max_input_size = (input_length - total_len);
752             (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
753         } else {
754             *max_input_size = 0;
755         }
756     }
757
758     return GSS_S_COMPLETE;
759 }
760
761 OM_uint32
762 _gssapi_wrap_size_arcfour(OM_uint32 *minor_status,
763                           const gsskrb5_ctx ctx,
764                           krb5_context context,
765                           int conf_req_flag,
766                           gss_qop_t qop_req,
767                           OM_uint32 req_output_size,
768                           OM_uint32 *max_input_size,
769                           krb5_keyblock *key)
770 {
771     krb5_error_code ret;
772     krb5_crypto crypto;
773
774     ret = krb5_crypto_init(context, key, 0, &crypto);
775     if (ret != 0) {
776         *minor_status = ret;
777         return GSS_S_FAILURE;
778     }
779
780     ret = max_wrap_length_arcfour(ctx, crypto,
781                                   req_output_size, max_input_size);
782     if (ret != 0) {
783         *minor_status = ret;
784         krb5_crypto_destroy(context, crypto);
785         return GSS_S_FAILURE;
786     }
787
788     krb5_crypto_destroy(context, crypto);
789
790     return GSS_S_COMPLETE;
791 }