1/*	$NetBSD$	*/
2
3/*
4 * Copyright (c) 2003 - 2006 Kungliga Tekniska H��gskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "gsskrb5_locl.h"
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
72static krb5_error_code
73arcfour_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
116static krb5_error_code
117arcfour_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
165OM_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    EVP_CIPHER_CTX 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    EVP_CIPHER_CTX_init(&rc4_key);
241    EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
242    EVP_Cipher(&rc4_key, p, p, 8);
243    EVP_CIPHER_CTX_cleanup(&rc4_key);
244
245    memset(k6_data, 0, sizeof(k6_data));
246
247    *minor_status = 0;
248    return GSS_S_COMPLETE;
249}
250
251
252OM_uint32
253_gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
254			   const gsskrb5_ctx context_handle,
255			   krb5_context context,
256			   const gss_buffer_t message_buffer,
257			   const gss_buffer_t token_buffer,
258			   gss_qop_t * qop_state,
259			   krb5_keyblock *key,
260			   char *type)
261{
262    krb5_error_code ret;
263    uint32_t seq_number;
264    OM_uint32 omret;
265    u_char SND_SEQ[8], cksum_data[8], *p;
266    char k6_data[16];
267    int cmp;
268
269    if (qop_state)
270	*qop_state = 0;
271
272    p = token_buffer->value;
273    omret = _gsskrb5_verify_header (&p,
274				       token_buffer->length,
275				       (u_char *)type,
276				       GSS_KRB5_MECHANISM);
277    if (omret)
278	return omret;
279
280    if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
281	return GSS_S_BAD_SIG;
282    p += 2;
283    if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
284	return GSS_S_BAD_MIC;
285    p += 4;
286
287    ret = arcfour_mic_cksum(context,
288			    key, KRB5_KU_USAGE_SIGN,
289			    cksum_data, sizeof(cksum_data),
290			    p - 8, 8,
291			    message_buffer->value, message_buffer->length,
292			    NULL, 0);
293    if (ret) {
294	*minor_status = ret;
295	return GSS_S_FAILURE;
296    }
297
298    ret = arcfour_mic_key(context, key,
299			  cksum_data, sizeof(cksum_data),
300			  k6_data, sizeof(k6_data));
301    if (ret) {
302	*minor_status = ret;
303	return GSS_S_FAILURE;
304    }
305
306    cmp = ct_memcmp(cksum_data, p + 8, 8);
307    if (cmp) {
308	*minor_status = 0;
309	return GSS_S_BAD_MIC;
310    }
311
312    {
313	EVP_CIPHER_CTX rc4_key;
314
315	EVP_CIPHER_CTX_init(&rc4_key);
316	EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, (void *)k6_data, NULL, 0);
317	EVP_Cipher(&rc4_key, SND_SEQ, p, 8);
318	EVP_CIPHER_CTX_cleanup(&rc4_key);
319
320	memset(k6_data, 0, sizeof(k6_data));
321    }
322
323    _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number);
324
325    if (context_handle->more_flags & LOCAL)
326	cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
327    else
328	cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
329
330    memset(SND_SEQ, 0, sizeof(SND_SEQ));
331    if (cmp != 0) {
332	*minor_status = 0;
333	return GSS_S_BAD_MIC;
334    }
335
336    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
337    omret = _gssapi_msg_order_check(context_handle->order, seq_number);
338    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
339    if (omret)
340	return omret;
341
342    *minor_status = 0;
343    return GSS_S_COMPLETE;
344}
345
346OM_uint32
347_gssapi_wrap_arcfour(OM_uint32 * minor_status,
348		     const gsskrb5_ctx context_handle,
349		     krb5_context context,
350		     int conf_req_flag,
351		     gss_qop_t qop_req,
352		     const gss_buffer_t input_message_buffer,
353		     int * conf_state,
354		     gss_buffer_t output_message_buffer,
355		     krb5_keyblock *key)
356{
357    u_char Klocaldata[16], k6_data[16], *p, *p0;
358    size_t len, total_len, datalen;
359    krb5_keyblock Klocal;
360    krb5_error_code ret;
361    int32_t seq_number;
362
363    if (conf_state)
364	*conf_state = 0;
365
366    datalen = input_message_buffer->length;
367
368    if (IS_DCE_STYLE(context_handle)) {
369	len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
370	_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
371	total_len += datalen;
372    } else {
373	datalen += 1; /* padding */
374	len = datalen + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
375	_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
376    }
377
378    output_message_buffer->length = total_len;
379    output_message_buffer->value  = malloc (total_len);
380    if (output_message_buffer->value == NULL) {
381	*minor_status = ENOMEM;
382	return GSS_S_FAILURE;
383    }
384
385    p0 = _gssapi_make_mech_header(output_message_buffer->value,
386				  len,
387				  GSS_KRB5_MECHANISM);
388    p = p0;
389
390    *p++ = 0x02; /* TOK_ID */
391    *p++ = 0x01;
392    *p++ = 0x11; /* SGN_ALG */
393    *p++ = 0x00;
394    if (conf_req_flag) {
395	*p++ = 0x10; /* SEAL_ALG */
396	*p++ = 0x00;
397    } else {
398	*p++ = 0xff; /* SEAL_ALG */
399	*p++ = 0xff;
400    }
401    *p++ = 0xff; /* Filler */
402    *p++ = 0xff;
403
404    p = NULL;
405
406    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
407    krb5_auth_con_getlocalseqnumber (context,
408				     context_handle->auth_context,
409				     &seq_number);
410
411    _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8);
412
413    krb5_auth_con_setlocalseqnumber (context,
414				     context_handle->auth_context,
415				     ++seq_number);
416    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
417
418    memset (p0 + 8 + 4,
419	    (context_handle->more_flags & LOCAL) ? 0 : 0xff,
420	    4);
421
422    krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
423
424    /* p points to data */
425    p = p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
426    memcpy(p, input_message_buffer->value, input_message_buffer->length);
427
428    if (!IS_DCE_STYLE(context_handle))
429	p[input_message_buffer->length] = 1; /* padding */
430
431    ret = arcfour_mic_cksum(context,
432			    key, KRB5_KU_USAGE_SEAL,
433			    p0 + 16, 8, /* SGN_CKSUM */
434			    p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
435			    p0 + 24, 8, /* Confounder */
436			    p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
437			    datalen);
438    if (ret) {
439	*minor_status = ret;
440	_gsskrb5_release_buffer(minor_status, output_message_buffer);
441	return GSS_S_FAILURE;
442    }
443
444    {
445	int i;
446
447	Klocal.keytype = key->keytype;
448	Klocal.keyvalue.data = Klocaldata;
449	Klocal.keyvalue.length = sizeof(Klocaldata);
450
451	for (i = 0; i < 16; i++)
452	    Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
453    }
454    ret = arcfour_mic_key(context, &Klocal,
455			  p0 + 8, 4, /* SND_SEQ */
456			  k6_data, sizeof(k6_data));
457    memset(Klocaldata, 0, sizeof(Klocaldata));
458    if (ret) {
459	_gsskrb5_release_buffer(minor_status, output_message_buffer);
460	*minor_status = ret;
461	return GSS_S_FAILURE;
462    }
463
464
465    if(conf_req_flag) {
466	EVP_CIPHER_CTX rc4_key;
467
468	EVP_CIPHER_CTX_init(&rc4_key);
469	EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
470	EVP_Cipher(&rc4_key, p0 + 24, p0 + 24, 8 + datalen);
471	EVP_CIPHER_CTX_cleanup(&rc4_key);
472    }
473    memset(k6_data, 0, sizeof(k6_data));
474
475    ret = arcfour_mic_key(context, key,
476			  p0 + 16, 8, /* SGN_CKSUM */
477			  k6_data, sizeof(k6_data));
478    if (ret) {
479	_gsskrb5_release_buffer(minor_status, output_message_buffer);
480	*minor_status = ret;
481	return GSS_S_FAILURE;
482    }
483
484    {
485	EVP_CIPHER_CTX rc4_key;
486
487	EVP_CIPHER_CTX_init(&rc4_key);
488	EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
489	EVP_Cipher(&rc4_key, p0 + 8, p0 + 8 /* SND_SEQ */, 8);
490	EVP_CIPHER_CTX_cleanup(&rc4_key);
491	memset(k6_data, 0, sizeof(k6_data));
492    }
493
494    if (conf_state)
495	*conf_state = conf_req_flag;
496
497    *minor_status = 0;
498    return GSS_S_COMPLETE;
499}
500
501OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
502				 const gsskrb5_ctx context_handle,
503				 krb5_context context,
504				 const gss_buffer_t input_message_buffer,
505				 gss_buffer_t output_message_buffer,
506				 int *conf_state,
507				 gss_qop_t *qop_state,
508				 krb5_keyblock *key)
509{
510    u_char Klocaldata[16];
511    krb5_keyblock Klocal;
512    krb5_error_code ret;
513    uint32_t seq_number;
514    size_t datalen;
515    OM_uint32 omret;
516    u_char k6_data[16], SND_SEQ[8], Confounder[8];
517    u_char cksum_data[8];
518    u_char *p, *p0;
519    int cmp;
520    int conf_flag;
521    size_t padlen = 0, len;
522
523    if (conf_state)
524	*conf_state = 0;
525    if (qop_state)
526	*qop_state = 0;
527
528    p0 = input_message_buffer->value;
529
530    if (IS_DCE_STYLE(context_handle)) {
531	len = GSS_ARCFOUR_WRAP_TOKEN_SIZE +
532	    GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE;
533	if (input_message_buffer->length < len)
534	    return GSS_S_BAD_MECH;
535    } else {
536	len = input_message_buffer->length;
537    }
538
539    omret = _gssapi_verify_mech_header(&p0,
540				       len,
541				       GSS_KRB5_MECHANISM);
542    if (omret)
543	return omret;
544
545    /* length of mech header */
546    len = (p0 - (u_char *)input_message_buffer->value) +
547	GSS_ARCFOUR_WRAP_TOKEN_SIZE;
548
549    if (len > input_message_buffer->length)
550	return GSS_S_BAD_MECH;
551
552    /* length of data */
553    datalen = input_message_buffer->length - len;
554
555    p = p0;
556
557    if (memcmp(p, "\x02\x01", 2) != 0)
558	return GSS_S_BAD_SIG;
559    p += 2;
560    if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
561	return GSS_S_BAD_SIG;
562    p += 2;
563
564    if (memcmp (p, "\x10\x00", 2) == 0)
565	conf_flag = 1;
566    else if (memcmp (p, "\xff\xff", 2) == 0)
567	conf_flag = 0;
568    else
569	return GSS_S_BAD_SIG;
570
571    p += 2;
572    if (memcmp (p, "\xff\xff", 2) != 0)
573	return GSS_S_BAD_MIC;
574    p = NULL;
575
576    ret = arcfour_mic_key(context, key,
577			  p0 + 16, 8, /* SGN_CKSUM */
578			  k6_data, sizeof(k6_data));
579    if (ret) {
580	*minor_status = ret;
581	return GSS_S_FAILURE;
582    }
583
584    {
585	EVP_CIPHER_CTX rc4_key;
586
587	EVP_CIPHER_CTX_init(&rc4_key);
588	EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
589	EVP_Cipher(&rc4_key, SND_SEQ, p0 + 8, 8);
590	EVP_CIPHER_CTX_cleanup(&rc4_key);
591	memset(k6_data, 0, sizeof(k6_data));
592    }
593
594    _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number);
595
596    if (context_handle->more_flags & LOCAL)
597	cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
598    else
599	cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
600
601    if (cmp != 0) {
602	*minor_status = 0;
603	return GSS_S_BAD_MIC;
604    }
605
606    {
607	int i;
608
609	Klocal.keytype = key->keytype;
610	Klocal.keyvalue.data = Klocaldata;
611	Klocal.keyvalue.length = sizeof(Klocaldata);
612
613	for (i = 0; i < 16; i++)
614	    Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
615    }
616    ret = arcfour_mic_key(context, &Klocal,
617			  SND_SEQ, 4,
618			  k6_data, sizeof(k6_data));
619    memset(Klocaldata, 0, sizeof(Klocaldata));
620    if (ret) {
621	*minor_status = ret;
622	return GSS_S_FAILURE;
623    }
624
625    output_message_buffer->value = malloc(datalen);
626    if (output_message_buffer->value == NULL) {
627	*minor_status = ENOMEM;
628	return GSS_S_FAILURE;
629    }
630    output_message_buffer->length = datalen;
631
632    if(conf_flag) {
633	EVP_CIPHER_CTX rc4_key;
634
635	EVP_CIPHER_CTX_init(&rc4_key);
636	EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
637	EVP_Cipher(&rc4_key, Confounder, p0 + 24, 8);
638	EVP_Cipher(&rc4_key, output_message_buffer->value, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, datalen);
639	EVP_CIPHER_CTX_cleanup(&rc4_key);
640    } else {
641	memcpy(Confounder, p0 + 24, 8); /* Confounder */
642	memcpy(output_message_buffer->value,
643	       p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
644	       datalen);
645    }
646    memset(k6_data, 0, sizeof(k6_data));
647
648    if (!IS_DCE_STYLE(context_handle)) {
649	ret = _gssapi_verify_pad(output_message_buffer, datalen, &padlen);
650	if (ret) {
651	    _gsskrb5_release_buffer(minor_status, output_message_buffer);
652	    *minor_status = 0;
653	    return ret;
654	}
655	output_message_buffer->length -= padlen;
656    }
657
658    ret = arcfour_mic_cksum(context,
659			    key, KRB5_KU_USAGE_SEAL,
660			    cksum_data, sizeof(cksum_data),
661			    p0, 8,
662			    Confounder, sizeof(Confounder),
663			    output_message_buffer->value,
664			    output_message_buffer->length + padlen);
665    if (ret) {
666	_gsskrb5_release_buffer(minor_status, output_message_buffer);
667	*minor_status = ret;
668	return GSS_S_FAILURE;
669    }
670
671    cmp = ct_memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */
672    if (cmp) {
673	_gsskrb5_release_buffer(minor_status, output_message_buffer);
674	*minor_status = 0;
675	return GSS_S_BAD_MIC;
676    }
677
678    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
679    omret = _gssapi_msg_order_check(context_handle->order, seq_number);
680    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
681    if (omret)
682	return omret;
683
684    if (conf_state)
685	*conf_state = conf_flag;
686
687    *minor_status = 0;
688    return GSS_S_COMPLETE;
689}
690
691static OM_uint32
692max_wrap_length_arcfour(const gsskrb5_ctx ctx,
693			krb5_crypto crypto,
694			size_t input_length,
695			OM_uint32 *max_input_size)
696{
697    /*
698     * if GSS_C_DCE_STYLE is in use:
699     *  - we only need to encapsulate the WRAP token
700     * However, since this is a fixed since, we just
701     */
702    if (IS_DCE_STYLE(ctx)) {
703	size_t len, total_len;
704
705	len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
706	_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
707
708	if (input_length < len)
709	    *max_input_size = 0;
710	else
711	    *max_input_size = input_length - len;
712
713    } else {
714	size_t extrasize = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
715	size_t blocksize = 8;
716	size_t len, total_len;
717
718	len = 8 + input_length + blocksize + extrasize;
719
720	_gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
721
722	total_len -= input_length; /* token length */
723	if (total_len < input_length) {
724	    *max_input_size = (input_length - total_len);
725	    (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
726	} else {
727	    *max_input_size = 0;
728	}
729    }
730
731    return GSS_S_COMPLETE;
732}
733
734OM_uint32
735_gssapi_wrap_size_arcfour(OM_uint32 *minor_status,
736			  const gsskrb5_ctx ctx,
737			  krb5_context context,
738			  int conf_req_flag,
739			  gss_qop_t qop_req,
740			  OM_uint32 req_output_size,
741			  OM_uint32 *max_input_size,
742			  krb5_keyblock *key)
743{
744    krb5_error_code ret;
745    krb5_crypto crypto;
746
747    ret = krb5_crypto_init(context, key, 0, &crypto);
748    if (ret != 0) {
749	*minor_status = ret;
750	return GSS_S_FAILURE;
751    }
752
753    ret = max_wrap_length_arcfour(ctx, crypto,
754				  req_output_size, max_input_size);
755    if (ret != 0) {
756	*minor_status = ret;
757	krb5_crypto_destroy(context, crypto);
758	return GSS_S_FAILURE;
759    }
760
761    krb5_crypto_destroy(context, crypto);
762
763    return GSS_S_COMPLETE;
764}
765