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