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