xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/gssapi/krb5/arcfour.c (revision afab4e300d3a9fb07dd8c80daf53d0feb3345706)
1*afab4e30Schristos /*	$NetBSD: arcfour.c,v 1.6 2023/06/19 21:41:43 christos Exp $	*/
2ca1c9b0cSelric 
3ca1c9b0cSelric /*
4ca1c9b0cSelric  * Copyright (c) 2003 - 2006 Kungliga Tekniska Högskolan
5ca1c9b0cSelric  * (Royal Institute of Technology, Stockholm, Sweden).
6ca1c9b0cSelric  * All rights reserved.
7ca1c9b0cSelric  *
8ca1c9b0cSelric  * Redistribution and use in source and binary forms, with or without
9ca1c9b0cSelric  * modification, are permitted provided that the following conditions
10ca1c9b0cSelric  * are met:
11ca1c9b0cSelric  *
12ca1c9b0cSelric  * 1. Redistributions of source code must retain the above copyright
13ca1c9b0cSelric  *    notice, this list of conditions and the following disclaimer.
14ca1c9b0cSelric  *
15ca1c9b0cSelric  * 2. Redistributions in binary form must reproduce the above copyright
16ca1c9b0cSelric  *    notice, this list of conditions and the following disclaimer in the
17ca1c9b0cSelric  *    documentation and/or other materials provided with the distribution.
18ca1c9b0cSelric  *
19ca1c9b0cSelric  * 3. Neither the name of the Institute nor the names of its contributors
20ca1c9b0cSelric  *    may be used to endorse or promote products derived from this software
21ca1c9b0cSelric  *    without specific prior written permission.
22ca1c9b0cSelric  *
23ca1c9b0cSelric  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ca1c9b0cSelric  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ca1c9b0cSelric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ca1c9b0cSelric  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ca1c9b0cSelric  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ca1c9b0cSelric  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ca1c9b0cSelric  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ca1c9b0cSelric  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ca1c9b0cSelric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ca1c9b0cSelric  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ca1c9b0cSelric  * SUCH DAMAGE.
34ca1c9b0cSelric  */
35ca1c9b0cSelric 
36ca1c9b0cSelric #include "gsskrb5_locl.h"
37ca1c9b0cSelric 
38ca1c9b0cSelric /*
39ca1c9b0cSelric  * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt
40ca1c9b0cSelric  *
41ca1c9b0cSelric  * The arcfour message have the following formats:
42ca1c9b0cSelric  *
43ca1c9b0cSelric  * MIC token
44ca1c9b0cSelric  * 	TOK_ID[2] = 01 01
45ca1c9b0cSelric  *	SGN_ALG[2] = 11 00
46ca1c9b0cSelric  *	Filler[4]
47ca1c9b0cSelric  *	SND_SEQ[8]
48ca1c9b0cSelric  *	SGN_CKSUM[8]
49ca1c9b0cSelric  *
50ca1c9b0cSelric  * WRAP token
51ca1c9b0cSelric  *	TOK_ID[2] = 02 01
52ca1c9b0cSelric  *	SGN_ALG[2];
53ca1c9b0cSelric  *	SEAL_ALG[2]
54ca1c9b0cSelric  *	Filler[2]
55ca1c9b0cSelric  *	SND_SEQ[2]
56ca1c9b0cSelric  *	SGN_CKSUM[8]
57ca1c9b0cSelric  *	Confounder[8]
58ca1c9b0cSelric  */
59ca1c9b0cSelric 
60ca1c9b0cSelric /*
61ca1c9b0cSelric  * WRAP in DCE-style have a fixed size header, the oid and length over
62ca1c9b0cSelric  * the WRAP header is a total of
63ca1c9b0cSelric  * GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE +
64ca1c9b0cSelric  * GSS_ARCFOUR_WRAP_TOKEN_SIZE byte (ie total of 45 bytes overhead,
65ca1c9b0cSelric  * remember the 2 bytes from APPL [0] SEQ).
66ca1c9b0cSelric  */
67ca1c9b0cSelric 
68ca1c9b0cSelric #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
69ca1c9b0cSelric #define GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE 13
70ca1c9b0cSelric 
71ca1c9b0cSelric 
72ca1c9b0cSelric static krb5_error_code
arcfour_mic_key(krb5_context context,krb5_keyblock * key,const void * cksum_data,size_t cksum_size,void * key6_data,size_t key6_size)73ca1c9b0cSelric arcfour_mic_key(krb5_context context, krb5_keyblock *key,
74b9d004c6Schristos 		const void *cksum_data, size_t cksum_size,
75ca1c9b0cSelric 		void *key6_data, size_t key6_size)
76ca1c9b0cSelric {
77ca1c9b0cSelric     krb5_error_code ret;
78ca1c9b0cSelric 
79ca1c9b0cSelric     Checksum cksum_k5;
80ca1c9b0cSelric     krb5_keyblock key5;
81ca1c9b0cSelric     char k5_data[16];
82ca1c9b0cSelric 
83ca1c9b0cSelric     Checksum cksum_k6;
84ca1c9b0cSelric 
85ca1c9b0cSelric     char T[4];
86ca1c9b0cSelric 
87ca1c9b0cSelric     memset(T, 0, 4);
88ca1c9b0cSelric     cksum_k5.checksum.data = k5_data;
89ca1c9b0cSelric     cksum_k5.checksum.length = sizeof(k5_data);
90ca1c9b0cSelric 
91b9d004c6Schristos     if (key->keytype == KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56) {
92ca1c9b0cSelric 	char L40[14] = "fortybits";
93ca1c9b0cSelric 
94ca1c9b0cSelric 	memcpy(L40 + 10, T, sizeof(T));
95ca1c9b0cSelric 	ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
96ca1c9b0cSelric 			L40, 14, 0, key, &cksum_k5);
97ca1c9b0cSelric 	memset(&k5_data[7], 0xAB, 9);
98ca1c9b0cSelric     } else {
99ca1c9b0cSelric 	ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
100ca1c9b0cSelric 			T, 4, 0, key, &cksum_k5);
101ca1c9b0cSelric     }
102ca1c9b0cSelric     if (ret)
103ca1c9b0cSelric 	return ret;
104ca1c9b0cSelric 
105b9d004c6Schristos     key5.keytype = KRB5_ENCTYPE_ARCFOUR_HMAC_MD5;
106ca1c9b0cSelric     key5.keyvalue = cksum_k5.checksum;
107ca1c9b0cSelric 
108ca1c9b0cSelric     cksum_k6.checksum.data = key6_data;
109ca1c9b0cSelric     cksum_k6.checksum.length = key6_size;
110ca1c9b0cSelric 
111ca1c9b0cSelric     return krb5_hmac(context, CKSUMTYPE_RSA_MD5,
112ca1c9b0cSelric 		     cksum_data, cksum_size, 0, &key5, &cksum_k6);
113ca1c9b0cSelric }
114ca1c9b0cSelric 
115ca1c9b0cSelric 
116ca1c9b0cSelric static krb5_error_code
arcfour_mic_cksum_iov(krb5_context context,krb5_keyblock * key,unsigned usage,u_char * sgn_cksum,size_t sgn_cksum_sz,const u_char * v1,size_t l1,const void * v2,size_t l2,const gss_iov_buffer_desc * iov,int iov_count,const gss_iov_buffer_desc * padding)117b9d004c6Schristos arcfour_mic_cksum_iov(krb5_context context,
118ca1c9b0cSelric 		      krb5_keyblock *key, unsigned usage,
119ca1c9b0cSelric 		      u_char *sgn_cksum, size_t sgn_cksum_sz,
120ca1c9b0cSelric 		      const u_char *v1, size_t l1,
121ca1c9b0cSelric 		      const void *v2, size_t l2,
122b9d004c6Schristos 		      const gss_iov_buffer_desc *iov,
123b9d004c6Schristos 		      int iov_count,
124b9d004c6Schristos 		      const gss_iov_buffer_desc *padding)
125ca1c9b0cSelric {
126ca1c9b0cSelric     Checksum CKSUM;
127ca1c9b0cSelric     u_char *ptr;
128ca1c9b0cSelric     size_t len;
129b9d004c6Schristos     size_t ofs = 0;
130b9d004c6Schristos     int i;
131ca1c9b0cSelric     krb5_crypto crypto;
132ca1c9b0cSelric     krb5_error_code ret;
133ca1c9b0cSelric 
134ca1c9b0cSelric     assert(sgn_cksum_sz == 8);
135ca1c9b0cSelric 
136b9d004c6Schristos     len = l1 + l2;
137b9d004c6Schristos 
138b9d004c6Schristos     for (i=0; i < iov_count; i++) {
139b9d004c6Schristos 	switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
140b9d004c6Schristos 	case GSS_IOV_BUFFER_TYPE_DATA:
141b9d004c6Schristos 	case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
142b9d004c6Schristos 	    break;
143b9d004c6Schristos 	default:
144b9d004c6Schristos 	    continue;
145b9d004c6Schristos 	}
146b9d004c6Schristos 
147b9d004c6Schristos 	len += iov[i].buffer.length;
148b9d004c6Schristos     }
149b9d004c6Schristos 
150b9d004c6Schristos     if (padding) {
151b9d004c6Schristos 	len += padding->buffer.length;
152b9d004c6Schristos     }
153ca1c9b0cSelric 
154ca1c9b0cSelric     ptr = malloc(len);
155ca1c9b0cSelric     if (ptr == NULL)
156ca1c9b0cSelric 	return ENOMEM;
157ca1c9b0cSelric 
158b9d004c6Schristos     memcpy(ptr + ofs, v1, l1);
159b9d004c6Schristos     ofs += l1;
160b9d004c6Schristos     memcpy(ptr + ofs, v2, l2);
161b9d004c6Schristos     ofs += l2;
162b9d004c6Schristos 
163b9d004c6Schristos     for (i=0; i < iov_count; i++) {
164b9d004c6Schristos 	switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
165b9d004c6Schristos 	case GSS_IOV_BUFFER_TYPE_DATA:
166b9d004c6Schristos 	case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
167b9d004c6Schristos 	    break;
168b9d004c6Schristos 	default:
169b9d004c6Schristos 	    continue;
170b9d004c6Schristos 	}
171b9d004c6Schristos 
172b9d004c6Schristos 	memcpy(ptr + ofs,
173b9d004c6Schristos 	       iov[i].buffer.value,
174b9d004c6Schristos 	       iov[i].buffer.length);
175b9d004c6Schristos 	ofs += iov[i].buffer.length;
176b9d004c6Schristos     }
177b9d004c6Schristos 
178b9d004c6Schristos     if (padding) {
179b9d004c6Schristos 	memcpy(ptr + ofs,
180b9d004c6Schristos 	       padding->buffer.value,
181b9d004c6Schristos 	       padding->buffer.length);
182*afab4e30Schristos 	/* ofs += padding->buffer.length; */
183b9d004c6Schristos     }
184ca1c9b0cSelric 
185ca1c9b0cSelric     ret = krb5_crypto_init(context, key, 0, &crypto);
186ca1c9b0cSelric     if (ret) {
187ca1c9b0cSelric 	free(ptr);
188ca1c9b0cSelric 	return ret;
189ca1c9b0cSelric     }
190ca1c9b0cSelric 
191ca1c9b0cSelric     ret = krb5_create_checksum(context,
192ca1c9b0cSelric 			       crypto,
193ca1c9b0cSelric 			       usage,
194ca1c9b0cSelric 			       0,
195ca1c9b0cSelric 			       ptr, len,
196ca1c9b0cSelric 			       &CKSUM);
197b9d004c6Schristos     memset(ptr, 0, len);
198ca1c9b0cSelric     free(ptr);
199ca1c9b0cSelric     if (ret == 0) {
200ca1c9b0cSelric 	memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz);
201ca1c9b0cSelric 	free_Checksum(&CKSUM);
202ca1c9b0cSelric     }
203ca1c9b0cSelric     krb5_crypto_destroy(context, crypto);
204ca1c9b0cSelric 
205ca1c9b0cSelric     return ret;
206ca1c9b0cSelric }
207ca1c9b0cSelric 
208b9d004c6Schristos static krb5_error_code
arcfour_mic_cksum(krb5_context context,krb5_keyblock * key,unsigned usage,u_char * sgn_cksum,size_t sgn_cksum_sz,const u_char * v1,size_t l1,const void * v2,size_t l2,const void * v3,size_t l3)209b9d004c6Schristos arcfour_mic_cksum(krb5_context context,
210b9d004c6Schristos 		  krb5_keyblock *key, unsigned usage,
211b9d004c6Schristos 		  u_char *sgn_cksum, size_t sgn_cksum_sz,
212b9d004c6Schristos 		  const u_char *v1, size_t l1,
213b9d004c6Schristos 		  const void *v2, size_t l2,
214b9d004c6Schristos 		  const void *v3, size_t l3)
215b9d004c6Schristos {
216b9d004c6Schristos     gss_iov_buffer_desc iov;
217b9d004c6Schristos 
218b9d004c6Schristos     iov.type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
219b9d004c6Schristos     iov.buffer.value = rk_UNCONST(v3);
220b9d004c6Schristos     iov.buffer.length = l3;
221b9d004c6Schristos 
222b9d004c6Schristos     return arcfour_mic_cksum_iov(context, key, usage,
223b9d004c6Schristos 				 sgn_cksum, sgn_cksum_sz,
224b9d004c6Schristos 				 v1, l1, v2, l2,
225b9d004c6Schristos 				 &iov, 1, NULL);
226b9d004c6Schristos }
227b9d004c6Schristos 
228ca1c9b0cSelric 
229ca1c9b0cSelric OM_uint32
_gssapi_get_mic_arcfour(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,krb5_context context,gss_qop_t qop_req,const gss_buffer_t message_buffer,gss_buffer_t message_token,krb5_keyblock * key)230ca1c9b0cSelric _gssapi_get_mic_arcfour(OM_uint32 * minor_status,
231ca1c9b0cSelric 			const gsskrb5_ctx context_handle,
232ca1c9b0cSelric 			krb5_context context,
233ca1c9b0cSelric 			gss_qop_t qop_req,
234ca1c9b0cSelric 			const gss_buffer_t message_buffer,
235ca1c9b0cSelric 			gss_buffer_t message_token,
236ca1c9b0cSelric 			krb5_keyblock *key)
237ca1c9b0cSelric {
238ca1c9b0cSelric     krb5_error_code ret;
239ca1c9b0cSelric     int32_t seq_number;
240ca1c9b0cSelric     size_t len, total_len;
241ca1c9b0cSelric     u_char k6_data[16], *p0, *p;
2426680b65dSchristos     EVP_CIPHER_CTX *rc4_key;
243ca1c9b0cSelric 
244ca1c9b0cSelric     _gsskrb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM);
245ca1c9b0cSelric 
246ca1c9b0cSelric     message_token->length = total_len;
247ca1c9b0cSelric     message_token->value  = malloc (total_len);
248ca1c9b0cSelric     if (message_token->value == NULL) {
249ca1c9b0cSelric 	*minor_status = ENOMEM;
250ca1c9b0cSelric 	return GSS_S_FAILURE;
251ca1c9b0cSelric     }
252ca1c9b0cSelric 
253ca1c9b0cSelric     p0 = _gssapi_make_mech_header(message_token->value,
254ca1c9b0cSelric 				  len,
255ca1c9b0cSelric 				  GSS_KRB5_MECHANISM);
256ca1c9b0cSelric     p = p0;
257ca1c9b0cSelric 
258ca1c9b0cSelric     *p++ = 0x01; /* TOK_ID */
259ca1c9b0cSelric     *p++ = 0x01;
260ca1c9b0cSelric     *p++ = 0x11; /* SGN_ALG */
261ca1c9b0cSelric     *p++ = 0x00;
262ca1c9b0cSelric     *p++ = 0xff; /* Filler */
263ca1c9b0cSelric     *p++ = 0xff;
264ca1c9b0cSelric     *p++ = 0xff;
265ca1c9b0cSelric     *p++ = 0xff;
266ca1c9b0cSelric 
267ca1c9b0cSelric     p = NULL;
268ca1c9b0cSelric 
269ca1c9b0cSelric     ret = arcfour_mic_cksum(context,
270ca1c9b0cSelric 			    key, KRB5_KU_USAGE_SIGN,
271ca1c9b0cSelric 			    p0 + 16, 8,  /* SGN_CKSUM */
272ca1c9b0cSelric 			    p0, 8, /* TOK_ID, SGN_ALG, Filer */
273ca1c9b0cSelric 			    message_buffer->value, message_buffer->length,
274ca1c9b0cSelric 			    NULL, 0);
275ca1c9b0cSelric     if (ret) {
276ca1c9b0cSelric 	_gsskrb5_release_buffer(minor_status, message_token);
277ca1c9b0cSelric 	*minor_status = ret;
278ca1c9b0cSelric 	return GSS_S_FAILURE;
279ca1c9b0cSelric     }
280ca1c9b0cSelric 
281ca1c9b0cSelric     ret = arcfour_mic_key(context, key,
282ca1c9b0cSelric 			  p0 + 16, 8, /* SGN_CKSUM */
283ca1c9b0cSelric 			  k6_data, sizeof(k6_data));
284ca1c9b0cSelric     if (ret) {
285ca1c9b0cSelric 	_gsskrb5_release_buffer(minor_status, message_token);
286ca1c9b0cSelric 	*minor_status = ret;
287ca1c9b0cSelric 	return GSS_S_FAILURE;
288ca1c9b0cSelric     }
289ca1c9b0cSelric 
290ca1c9b0cSelric     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
291ca1c9b0cSelric     krb5_auth_con_getlocalseqnumber (context,
292ca1c9b0cSelric 				     context_handle->auth_context,
293ca1c9b0cSelric 				     &seq_number);
294ca1c9b0cSelric     p = p0 + 8; /* SND_SEQ */
295ca1c9b0cSelric     _gsskrb5_encode_be_om_uint32(seq_number, p);
296ca1c9b0cSelric 
297ca1c9b0cSelric     krb5_auth_con_setlocalseqnumber (context,
298ca1c9b0cSelric 				     context_handle->auth_context,
299ca1c9b0cSelric 				     ++seq_number);
300ca1c9b0cSelric     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
301ca1c9b0cSelric 
302ca1c9b0cSelric     memset (p + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xff, 4);
303ca1c9b0cSelric 
3046680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
3056680b65dSchristos     EVP_CIPHER_CTX rc4_keys;
3066680b65dSchristos     rc4_key = &rc4_keys;
3076680b65dSchristos     EVP_CIPHER_CTX_init(rc4_key);
3086680b65dSchristos #else
3096680b65dSchristos     rc4_key = EVP_CIPHER_CTX_new();
3106680b65dSchristos #endif
3117b2118deSchristos     if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
3127b2118deSchristos 	*minor_status = EINVAL;
3137b2118deSchristos 	return GSS_S_FAILURE;
3147b2118deSchristos     }
3157b2118deSchristos 
3166680b65dSchristos     EVP_Cipher(rc4_key, p, p, 8);
3176680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
3186680b65dSchristos     EVP_CIPHER_CTX_cleanup(rc4_key);
3196680b65dSchristos #else
3206680b65dSchristos     EVP_CIPHER_CTX_free(rc4_key);
3216680b65dSchristos #endif
322ca1c9b0cSelric 
323241bea01Schristos     memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
324ca1c9b0cSelric 
325ca1c9b0cSelric     *minor_status = 0;
326ca1c9b0cSelric     return GSS_S_COMPLETE;
327ca1c9b0cSelric }
328ca1c9b0cSelric 
329ca1c9b0cSelric 
330ca1c9b0cSelric OM_uint32
_gssapi_verify_mic_arcfour(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,krb5_context context,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state,krb5_keyblock * key,const char * type)331ca1c9b0cSelric _gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
332ca1c9b0cSelric 			   const gsskrb5_ctx context_handle,
333ca1c9b0cSelric 			   krb5_context context,
334ca1c9b0cSelric 			   const gss_buffer_t message_buffer,
335ca1c9b0cSelric 			   const gss_buffer_t token_buffer,
336ca1c9b0cSelric 			   gss_qop_t * qop_state,
337ca1c9b0cSelric 			   krb5_keyblock *key,
3384f77a458Spettai 			   const char *type)
339ca1c9b0cSelric {
340ca1c9b0cSelric     krb5_error_code ret;
341ca1c9b0cSelric     uint32_t seq_number;
342ca1c9b0cSelric     OM_uint32 omret;
343ca1c9b0cSelric     u_char SND_SEQ[8], cksum_data[8], *p;
344ca1c9b0cSelric     char k6_data[16];
345ca1c9b0cSelric     int cmp;
346ca1c9b0cSelric 
347ca1c9b0cSelric     if (qop_state)
348ca1c9b0cSelric 	*qop_state = 0;
349ca1c9b0cSelric 
350ca1c9b0cSelric     p = token_buffer->value;
351ca1c9b0cSelric     omret = _gsskrb5_verify_header (&p,
352ca1c9b0cSelric 				       token_buffer->length,
3534f77a458Spettai 				       type,
354ca1c9b0cSelric 				       GSS_KRB5_MECHANISM);
355ca1c9b0cSelric     if (omret)
356ca1c9b0cSelric 	return omret;
357ca1c9b0cSelric 
358ca1c9b0cSelric     if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
359ca1c9b0cSelric 	return GSS_S_BAD_SIG;
360ca1c9b0cSelric     p += 2;
361ca1c9b0cSelric     if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
362ca1c9b0cSelric 	return GSS_S_BAD_MIC;
363ca1c9b0cSelric     p += 4;
364ca1c9b0cSelric 
365ca1c9b0cSelric     ret = arcfour_mic_cksum(context,
366ca1c9b0cSelric 			    key, KRB5_KU_USAGE_SIGN,
367ca1c9b0cSelric 			    cksum_data, sizeof(cksum_data),
368ca1c9b0cSelric 			    p - 8, 8,
369ca1c9b0cSelric 			    message_buffer->value, message_buffer->length,
370ca1c9b0cSelric 			    NULL, 0);
371ca1c9b0cSelric     if (ret) {
372ca1c9b0cSelric 	*minor_status = ret;
373ca1c9b0cSelric 	return GSS_S_FAILURE;
374ca1c9b0cSelric     }
375ca1c9b0cSelric 
376ca1c9b0cSelric     ret = arcfour_mic_key(context, key,
377ca1c9b0cSelric 			  cksum_data, sizeof(cksum_data),
378ca1c9b0cSelric 			  k6_data, sizeof(k6_data));
379ca1c9b0cSelric     if (ret) {
380ca1c9b0cSelric 	*minor_status = ret;
381ca1c9b0cSelric 	return GSS_S_FAILURE;
382ca1c9b0cSelric     }
383ca1c9b0cSelric 
384*afab4e30Schristos     cmp = (ct_memcmp(cksum_data, p + 8, 8) == 0);
385ca1c9b0cSelric     if (cmp) {
386ca1c9b0cSelric 	*minor_status = 0;
387ca1c9b0cSelric 	return GSS_S_BAD_MIC;
388ca1c9b0cSelric     }
389ca1c9b0cSelric 
390ca1c9b0cSelric     {
3916680b65dSchristos 	EVP_CIPHER_CTX *rc4_key;
3926680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
3936680b65dSchristos 	EVP_CIPHER_CTX rc4_keys;
3946680b65dSchristos 	rc4_key = &rc4_keys;
3956680b65dSchristos 	EVP_CIPHER_CTX_init(rc4_key);
3966680b65dSchristos #else
3976680b65dSchristos 	rc4_key = EVP_CIPHER_CTX_new();
3986680b65dSchristos #endif
399ca1c9b0cSelric 
4007b2118deSchristos 	if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, (void *)k6_data, NULL,
4017b2118deSchristos 	    0)) {
4027b2118deSchristos 	    *minor_status = EINVAL;
4037b2118deSchristos 	    return GSS_S_FAILURE;
4047b2118deSchristos 	}
4056680b65dSchristos 	EVP_Cipher(rc4_key, SND_SEQ, p, 8);
4066680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
4076680b65dSchristos 	EVP_CIPHER_CTX_cleanup(rc4_key);
4086680b65dSchristos #else
4096680b65dSchristos 	EVP_CIPHER_CTX_free(rc4_key);
4106680b65dSchristos #endif
411ca1c9b0cSelric 
412241bea01Schristos 	memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
413ca1c9b0cSelric     }
414ca1c9b0cSelric 
415ca1c9b0cSelric     _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number);
416ca1c9b0cSelric 
417ca1c9b0cSelric     if (context_handle->more_flags & LOCAL)
418*afab4e30Schristos 	cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0);
419ca1c9b0cSelric     else
420*afab4e30Schristos 	cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0);
421ca1c9b0cSelric 
422241bea01Schristos     memset_s(SND_SEQ, sizeof(SND_SEQ), 0, sizeof(SND_SEQ));
423ca1c9b0cSelric     if (cmp != 0) {
424ca1c9b0cSelric 	*minor_status = 0;
425ca1c9b0cSelric 	return GSS_S_BAD_MIC;
426ca1c9b0cSelric     }
427ca1c9b0cSelric 
428ca1c9b0cSelric     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
429ca1c9b0cSelric     omret = _gssapi_msg_order_check(context_handle->order, seq_number);
430ca1c9b0cSelric     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
431ca1c9b0cSelric     if (omret)
432ca1c9b0cSelric 	return omret;
433ca1c9b0cSelric 
434ca1c9b0cSelric     *minor_status = 0;
435ca1c9b0cSelric     return GSS_S_COMPLETE;
436ca1c9b0cSelric }
437ca1c9b0cSelric 
438ca1c9b0cSelric OM_uint32
_gssapi_wrap_arcfour(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,krb5_context context,int conf_req_flag,gss_qop_t qop_req,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer,krb5_keyblock * key)439ca1c9b0cSelric _gssapi_wrap_arcfour(OM_uint32 * minor_status,
440ca1c9b0cSelric 		     const gsskrb5_ctx context_handle,
441ca1c9b0cSelric 		     krb5_context context,
442ca1c9b0cSelric 		     int conf_req_flag,
443ca1c9b0cSelric 		     gss_qop_t qop_req,
444ca1c9b0cSelric 		     const gss_buffer_t input_message_buffer,
445ca1c9b0cSelric 		     int * conf_state,
446ca1c9b0cSelric 		     gss_buffer_t output_message_buffer,
447ca1c9b0cSelric 		     krb5_keyblock *key)
448ca1c9b0cSelric {
449ca1c9b0cSelric     u_char Klocaldata[16], k6_data[16], *p, *p0;
450ca1c9b0cSelric     size_t len, total_len, datalen;
451ca1c9b0cSelric     krb5_keyblock Klocal;
452ca1c9b0cSelric     krb5_error_code ret;
453ca1c9b0cSelric     int32_t seq_number;
454ca1c9b0cSelric 
455ca1c9b0cSelric     if (conf_state)
456ca1c9b0cSelric 	*conf_state = 0;
457ca1c9b0cSelric 
458ca1c9b0cSelric     datalen = input_message_buffer->length;
459ca1c9b0cSelric 
460ca1c9b0cSelric     if (IS_DCE_STYLE(context_handle)) {
461ca1c9b0cSelric 	len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
462ca1c9b0cSelric 	_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
463ca1c9b0cSelric 	total_len += datalen;
464ca1c9b0cSelric     } else {
465ca1c9b0cSelric 	datalen += 1; /* padding */
466ca1c9b0cSelric 	len = datalen + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
467ca1c9b0cSelric 	_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
468ca1c9b0cSelric     }
469ca1c9b0cSelric 
470ca1c9b0cSelric     output_message_buffer->length = total_len;
471ca1c9b0cSelric     output_message_buffer->value  = malloc (total_len);
472ca1c9b0cSelric     if (output_message_buffer->value == NULL) {
473ca1c9b0cSelric 	*minor_status = ENOMEM;
474ca1c9b0cSelric 	return GSS_S_FAILURE;
475ca1c9b0cSelric     }
476ca1c9b0cSelric 
477ca1c9b0cSelric     p0 = _gssapi_make_mech_header(output_message_buffer->value,
478ca1c9b0cSelric 				  len,
479ca1c9b0cSelric 				  GSS_KRB5_MECHANISM);
480ca1c9b0cSelric     p = p0;
481ca1c9b0cSelric 
482ca1c9b0cSelric     *p++ = 0x02; /* TOK_ID */
483ca1c9b0cSelric     *p++ = 0x01;
484ca1c9b0cSelric     *p++ = 0x11; /* SGN_ALG */
485ca1c9b0cSelric     *p++ = 0x00;
486ca1c9b0cSelric     if (conf_req_flag) {
487ca1c9b0cSelric 	*p++ = 0x10; /* SEAL_ALG */
488ca1c9b0cSelric 	*p++ = 0x00;
489ca1c9b0cSelric     } else {
490ca1c9b0cSelric 	*p++ = 0xff; /* SEAL_ALG */
491ca1c9b0cSelric 	*p++ = 0xff;
492ca1c9b0cSelric     }
493ca1c9b0cSelric     *p++ = 0xff; /* Filler */
494ca1c9b0cSelric     *p++ = 0xff;
495ca1c9b0cSelric 
496ca1c9b0cSelric     p = NULL;
497ca1c9b0cSelric 
498ca1c9b0cSelric     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
499ca1c9b0cSelric     krb5_auth_con_getlocalseqnumber (context,
500ca1c9b0cSelric 				     context_handle->auth_context,
501ca1c9b0cSelric 				     &seq_number);
502ca1c9b0cSelric 
503ca1c9b0cSelric     _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8);
504ca1c9b0cSelric 
505ca1c9b0cSelric     krb5_auth_con_setlocalseqnumber (context,
506ca1c9b0cSelric 				     context_handle->auth_context,
507ca1c9b0cSelric 				     ++seq_number);
508ca1c9b0cSelric     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
509ca1c9b0cSelric 
510ca1c9b0cSelric     memset (p0 + 8 + 4,
511ca1c9b0cSelric 	    (context_handle->more_flags & LOCAL) ? 0 : 0xff,
512ca1c9b0cSelric 	    4);
513ca1c9b0cSelric 
514ca1c9b0cSelric     krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
515ca1c9b0cSelric 
516ca1c9b0cSelric     /* p points to data */
517ca1c9b0cSelric     p = p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
518ca1c9b0cSelric     memcpy(p, input_message_buffer->value, input_message_buffer->length);
519ca1c9b0cSelric 
520ca1c9b0cSelric     if (!IS_DCE_STYLE(context_handle))
521ca1c9b0cSelric 	p[input_message_buffer->length] = 1; /* padding */
522ca1c9b0cSelric 
523ca1c9b0cSelric     ret = arcfour_mic_cksum(context,
524ca1c9b0cSelric 			    key, KRB5_KU_USAGE_SEAL,
525ca1c9b0cSelric 			    p0 + 16, 8, /* SGN_CKSUM */
526ca1c9b0cSelric 			    p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
527ca1c9b0cSelric 			    p0 + 24, 8, /* Confounder */
528ca1c9b0cSelric 			    p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
529ca1c9b0cSelric 			    datalen);
530ca1c9b0cSelric     if (ret) {
531ca1c9b0cSelric 	*minor_status = ret;
532ca1c9b0cSelric 	_gsskrb5_release_buffer(minor_status, output_message_buffer);
533ca1c9b0cSelric 	return GSS_S_FAILURE;
534ca1c9b0cSelric     }
535ca1c9b0cSelric 
536ca1c9b0cSelric     {
537ca1c9b0cSelric 	int i;
538ca1c9b0cSelric 
539ca1c9b0cSelric 	Klocal.keytype = key->keytype;
540ca1c9b0cSelric 	Klocal.keyvalue.data = Klocaldata;
541ca1c9b0cSelric 	Klocal.keyvalue.length = sizeof(Klocaldata);
542ca1c9b0cSelric 
543ca1c9b0cSelric 	for (i = 0; i < 16; i++)
544ca1c9b0cSelric 	    Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
545ca1c9b0cSelric     }
546ca1c9b0cSelric     ret = arcfour_mic_key(context, &Klocal,
547ca1c9b0cSelric 			  p0 + 8, 4, /* SND_SEQ */
548ca1c9b0cSelric 			  k6_data, sizeof(k6_data));
549241bea01Schristos     memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata));
550ca1c9b0cSelric     if (ret) {
551ca1c9b0cSelric 	_gsskrb5_release_buffer(minor_status, output_message_buffer);
552ca1c9b0cSelric 	*minor_status = ret;
553ca1c9b0cSelric 	return GSS_S_FAILURE;
554ca1c9b0cSelric     }
555ca1c9b0cSelric 
556ca1c9b0cSelric 
557ca1c9b0cSelric     if(conf_req_flag) {
5586680b65dSchristos 	EVP_CIPHER_CTX *rc4_key;
5596680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
5606680b65dSchristos 	EVP_CIPHER_CTX rc4_keys;
5616680b65dSchristos 	rc4_key = &rc4_keys;
5626680b65dSchristos 	EVP_CIPHER_CTX_init(rc4_key);
5636680b65dSchristos #else
5646680b65dSchristos 	rc4_key = EVP_CIPHER_CTX_new();
5656680b65dSchristos #endif
566ca1c9b0cSelric 
5676680b65dSchristos 	EVP_CIPHER_CTX_init(rc4_key);
5687b2118deSchristos 	if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
5697b2118deSchristos 	    *minor_status = EINVAL;
5707b2118deSchristos 	    return GSS_S_FAILURE;
5717b2118deSchristos 	}
5726680b65dSchristos 	EVP_Cipher(rc4_key, p0 + 24, p0 + 24, 8 + datalen);
5736680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
5746680b65dSchristos 	EVP_CIPHER_CTX_cleanup(rc4_key);
5756680b65dSchristos #else
5766680b65dSchristos 	EVP_CIPHER_CTX_free(rc4_key);
5776680b65dSchristos #endif
578ca1c9b0cSelric     }
579241bea01Schristos     memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
580ca1c9b0cSelric 
581ca1c9b0cSelric     ret = arcfour_mic_key(context, key,
582ca1c9b0cSelric 			  p0 + 16, 8, /* SGN_CKSUM */
583ca1c9b0cSelric 			  k6_data, sizeof(k6_data));
584ca1c9b0cSelric     if (ret) {
585ca1c9b0cSelric 	_gsskrb5_release_buffer(minor_status, output_message_buffer);
586ca1c9b0cSelric 	*minor_status = ret;
587ca1c9b0cSelric 	return GSS_S_FAILURE;
588ca1c9b0cSelric     }
589ca1c9b0cSelric 
590ca1c9b0cSelric     {
5916680b65dSchristos 	EVP_CIPHER_CTX *rc4_key;
5926680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
5936680b65dSchristos 	EVP_CIPHER_CTX rc4_keys;
5946680b65dSchristos 	rc4_key = &rc4_keys;
5956680b65dSchristos 	EVP_CIPHER_CTX_init(rc4_key);
5966680b65dSchristos #else
5976680b65dSchristos 	rc4_key = EVP_CIPHER_CTX_new();
5986680b65dSchristos #endif
599ca1c9b0cSelric 
6007b2118deSchristos 	if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
6017b2118deSchristos 	    *minor_status = EINVAL;
6027b2118deSchristos 	    return GSS_S_FAILURE;
6037b2118deSchristos 	}
6046680b65dSchristos 	EVP_Cipher(rc4_key, p0 + 8, p0 + 8 /* SND_SEQ */, 8);
6056680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
6066680b65dSchristos 	EVP_CIPHER_CTX_cleanup(rc4_key);
6076680b65dSchristos #else
6086680b65dSchristos 	EVP_CIPHER_CTX_free(rc4_key);
6096680b65dSchristos #endif
610241bea01Schristos 	memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
611ca1c9b0cSelric     }
612ca1c9b0cSelric 
613ca1c9b0cSelric     if (conf_state)
614ca1c9b0cSelric 	*conf_state = conf_req_flag;
615ca1c9b0cSelric 
616ca1c9b0cSelric     *minor_status = 0;
617ca1c9b0cSelric     return GSS_S_COMPLETE;
618ca1c9b0cSelric }
619ca1c9b0cSelric 
_gssapi_unwrap_arcfour(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,krb5_context context,const gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state,krb5_keyblock * key)620ca1c9b0cSelric OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
621ca1c9b0cSelric 				 const gsskrb5_ctx context_handle,
622ca1c9b0cSelric 				 krb5_context context,
623ca1c9b0cSelric 				 const gss_buffer_t input_message_buffer,
624ca1c9b0cSelric 				 gss_buffer_t output_message_buffer,
625ca1c9b0cSelric 				 int *conf_state,
626ca1c9b0cSelric 				 gss_qop_t *qop_state,
627ca1c9b0cSelric 				 krb5_keyblock *key)
628ca1c9b0cSelric {
629ca1c9b0cSelric     u_char Klocaldata[16];
630ca1c9b0cSelric     krb5_keyblock Klocal;
631ca1c9b0cSelric     krb5_error_code ret;
632ca1c9b0cSelric     uint32_t seq_number;
633ca1c9b0cSelric     size_t datalen;
634ca1c9b0cSelric     OM_uint32 omret;
635ca1c9b0cSelric     u_char k6_data[16], SND_SEQ[8], Confounder[8];
636ca1c9b0cSelric     u_char cksum_data[8];
637ca1c9b0cSelric     u_char *p, *p0;
638ca1c9b0cSelric     int cmp;
639ca1c9b0cSelric     int conf_flag;
640ca1c9b0cSelric     size_t padlen = 0, len;
641ca1c9b0cSelric 
642ca1c9b0cSelric     if (conf_state)
643ca1c9b0cSelric 	*conf_state = 0;
644ca1c9b0cSelric     if (qop_state)
645ca1c9b0cSelric 	*qop_state = 0;
646ca1c9b0cSelric 
647ca1c9b0cSelric     p0 = input_message_buffer->value;
648ca1c9b0cSelric 
649ca1c9b0cSelric     if (IS_DCE_STYLE(context_handle)) {
650ca1c9b0cSelric 	len = GSS_ARCFOUR_WRAP_TOKEN_SIZE +
651ca1c9b0cSelric 	    GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE;
652ca1c9b0cSelric 	if (input_message_buffer->length < len)
653ca1c9b0cSelric 	    return GSS_S_BAD_MECH;
654ca1c9b0cSelric     } else {
655ca1c9b0cSelric 	len = input_message_buffer->length;
656ca1c9b0cSelric     }
657ca1c9b0cSelric 
658ca1c9b0cSelric     omret = _gssapi_verify_mech_header(&p0,
659ca1c9b0cSelric 				       len,
660ca1c9b0cSelric 				       GSS_KRB5_MECHANISM);
661ca1c9b0cSelric     if (omret)
662ca1c9b0cSelric 	return omret;
663ca1c9b0cSelric 
664ca1c9b0cSelric     /* length of mech header */
665ca1c9b0cSelric     len = (p0 - (u_char *)input_message_buffer->value) +
666ca1c9b0cSelric 	GSS_ARCFOUR_WRAP_TOKEN_SIZE;
667ca1c9b0cSelric 
668ca1c9b0cSelric     if (len > input_message_buffer->length)
669ca1c9b0cSelric 	return GSS_S_BAD_MECH;
670ca1c9b0cSelric 
671ca1c9b0cSelric     /* length of data */
672ca1c9b0cSelric     datalen = input_message_buffer->length - len;
673ca1c9b0cSelric 
674ca1c9b0cSelric     p = p0;
675ca1c9b0cSelric 
676ca1c9b0cSelric     if (memcmp(p, "\x02\x01", 2) != 0)
677ca1c9b0cSelric 	return GSS_S_BAD_SIG;
678ca1c9b0cSelric     p += 2;
679ca1c9b0cSelric     if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
680ca1c9b0cSelric 	return GSS_S_BAD_SIG;
681ca1c9b0cSelric     p += 2;
682ca1c9b0cSelric 
683ca1c9b0cSelric     if (memcmp (p, "\x10\x00", 2) == 0)
684ca1c9b0cSelric 	conf_flag = 1;
685ca1c9b0cSelric     else if (memcmp (p, "\xff\xff", 2) == 0)
686ca1c9b0cSelric 	conf_flag = 0;
687ca1c9b0cSelric     else
688ca1c9b0cSelric 	return GSS_S_BAD_SIG;
689ca1c9b0cSelric 
690ca1c9b0cSelric     p += 2;
691ca1c9b0cSelric     if (memcmp (p, "\xff\xff", 2) != 0)
692ca1c9b0cSelric 	return GSS_S_BAD_MIC;
693ca1c9b0cSelric     p = NULL;
694ca1c9b0cSelric 
695ca1c9b0cSelric     ret = arcfour_mic_key(context, key,
696ca1c9b0cSelric 			  p0 + 16, 8, /* SGN_CKSUM */
697ca1c9b0cSelric 			  k6_data, sizeof(k6_data));
698ca1c9b0cSelric     if (ret) {
699ca1c9b0cSelric 	*minor_status = ret;
700ca1c9b0cSelric 	return GSS_S_FAILURE;
701ca1c9b0cSelric     }
702ca1c9b0cSelric 
703ca1c9b0cSelric     {
7046680b65dSchristos 	EVP_CIPHER_CTX *rc4_key;
7056680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
7066680b65dSchristos 	EVP_CIPHER_CTX rc4_keys;
7076680b65dSchristos 	rc4_key = &rc4_keys;
7086680b65dSchristos 	EVP_CIPHER_CTX_init(rc4_key);
7096680b65dSchristos #else
7106680b65dSchristos 	rc4_key = EVP_CIPHER_CTX_new();
7116680b65dSchristos #endif
712ca1c9b0cSelric 
7137b2118deSchristos 	if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
7147b2118deSchristos 	    *minor_status = EINVAL;
7157b2118deSchristos 	    return GSS_S_FAILURE;
7167b2118deSchristos 	}
7176680b65dSchristos 	EVP_Cipher(rc4_key, SND_SEQ, p0 + 8, 8);
7186680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
7196680b65dSchristos 	EVP_CIPHER_CTX_cleanup(rc4_key);
7206680b65dSchristos #else
7216680b65dSchristos 	EVP_CIPHER_CTX_free(rc4_key);
7226680b65dSchristos #endif
723241bea01Schristos 	memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
724ca1c9b0cSelric     }
725ca1c9b0cSelric 
726ca1c9b0cSelric     _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number);
727ca1c9b0cSelric 
728ca1c9b0cSelric     if (context_handle->more_flags & LOCAL)
729*afab4e30Schristos 	cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0);
730ca1c9b0cSelric     else
731*afab4e30Schristos 	cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0);
732ca1c9b0cSelric 
733ca1c9b0cSelric     if (cmp != 0) {
734ca1c9b0cSelric 	*minor_status = 0;
735ca1c9b0cSelric 	return GSS_S_BAD_MIC;
736ca1c9b0cSelric     }
737ca1c9b0cSelric 
738ca1c9b0cSelric     {
739ca1c9b0cSelric 	int i;
740ca1c9b0cSelric 
741ca1c9b0cSelric 	Klocal.keytype = key->keytype;
742ca1c9b0cSelric 	Klocal.keyvalue.data = Klocaldata;
743ca1c9b0cSelric 	Klocal.keyvalue.length = sizeof(Klocaldata);
744ca1c9b0cSelric 
745ca1c9b0cSelric 	for (i = 0; i < 16; i++)
746ca1c9b0cSelric 	    Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
747ca1c9b0cSelric     }
748ca1c9b0cSelric     ret = arcfour_mic_key(context, &Klocal,
749ca1c9b0cSelric 			  SND_SEQ, 4,
750ca1c9b0cSelric 			  k6_data, sizeof(k6_data));
751241bea01Schristos     memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata));
752ca1c9b0cSelric     if (ret) {
753ca1c9b0cSelric 	*minor_status = ret;
754ca1c9b0cSelric 	return GSS_S_FAILURE;
755ca1c9b0cSelric     }
756ca1c9b0cSelric 
757ca1c9b0cSelric     output_message_buffer->value = malloc(datalen);
758ca1c9b0cSelric     if (output_message_buffer->value == NULL) {
759ca1c9b0cSelric 	*minor_status = ENOMEM;
760ca1c9b0cSelric 	return GSS_S_FAILURE;
761ca1c9b0cSelric     }
762ca1c9b0cSelric     output_message_buffer->length = datalen;
763ca1c9b0cSelric 
764ca1c9b0cSelric     if(conf_flag) {
7656680b65dSchristos 	EVP_CIPHER_CTX *rc4_key;
7666680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
7676680b65dSchristos 	EVP_CIPHER_CTX rc4_keys;
7686680b65dSchristos 	rc4_key = &rc4_keys;
7696680b65dSchristos 	EVP_CIPHER_CTX_init(rc4_key);
7706680b65dSchristos #else
7716680b65dSchristos 	rc4_key = EVP_CIPHER_CTX_new();
7726680b65dSchristos #endif
7737b2118deSchristos 	if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
7747b2118deSchristos 	    *minor_status = EINVAL;
7757b2118deSchristos 	    return GSS_S_FAILURE;
7767b2118deSchristos 	}
7776680b65dSchristos 	EVP_Cipher(rc4_key, Confounder, p0 + 24, 8);
7786680b65dSchristos 	EVP_Cipher(rc4_key, output_message_buffer->value, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, datalen);
7796680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
7806680b65dSchristos 	EVP_CIPHER_CTX_cleanup(rc4_key);
7816680b65dSchristos #else
7826680b65dSchristos 	EVP_CIPHER_CTX_free(rc4_key);
7836680b65dSchristos #endif
784ca1c9b0cSelric     } else {
785ca1c9b0cSelric 	memcpy(Confounder, p0 + 24, 8); /* Confounder */
786ca1c9b0cSelric 	memcpy(output_message_buffer->value,
787ca1c9b0cSelric 	       p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
788ca1c9b0cSelric 	       datalen);
789ca1c9b0cSelric     }
790241bea01Schristos     memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
791ca1c9b0cSelric 
792ca1c9b0cSelric     if (!IS_DCE_STYLE(context_handle)) {
793ca1c9b0cSelric 	ret = _gssapi_verify_pad(output_message_buffer, datalen, &padlen);
794ca1c9b0cSelric 	if (ret) {
795ca1c9b0cSelric 	    _gsskrb5_release_buffer(minor_status, output_message_buffer);
796ca1c9b0cSelric 	    *minor_status = 0;
797ca1c9b0cSelric 	    return ret;
798ca1c9b0cSelric 	}
799ca1c9b0cSelric 	output_message_buffer->length -= padlen;
800ca1c9b0cSelric     }
801ca1c9b0cSelric 
802ca1c9b0cSelric     ret = arcfour_mic_cksum(context,
803ca1c9b0cSelric 			    key, KRB5_KU_USAGE_SEAL,
804ca1c9b0cSelric 			    cksum_data, sizeof(cksum_data),
805ca1c9b0cSelric 			    p0, 8,
806ca1c9b0cSelric 			    Confounder, sizeof(Confounder),
807ca1c9b0cSelric 			    output_message_buffer->value,
808ca1c9b0cSelric 			    output_message_buffer->length + padlen);
809ca1c9b0cSelric     if (ret) {
810ca1c9b0cSelric 	_gsskrb5_release_buffer(minor_status, output_message_buffer);
811ca1c9b0cSelric 	*minor_status = ret;
812ca1c9b0cSelric 	return GSS_S_FAILURE;
813ca1c9b0cSelric     }
814ca1c9b0cSelric 
815*afab4e30Schristos     cmp = (ct_memcmp(cksum_data, p0 + 16, 8) == 0); /* SGN_CKSUM */
816ca1c9b0cSelric     if (cmp) {
817ca1c9b0cSelric 	_gsskrb5_release_buffer(minor_status, output_message_buffer);
818ca1c9b0cSelric 	*minor_status = 0;
819ca1c9b0cSelric 	return GSS_S_BAD_MIC;
820ca1c9b0cSelric     }
821ca1c9b0cSelric 
822ca1c9b0cSelric     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
823ca1c9b0cSelric     omret = _gssapi_msg_order_check(context_handle->order, seq_number);
824ca1c9b0cSelric     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
825ca1c9b0cSelric     if (omret)
826ca1c9b0cSelric 	return omret;
827ca1c9b0cSelric 
828ca1c9b0cSelric     if (conf_state)
829ca1c9b0cSelric 	*conf_state = conf_flag;
830ca1c9b0cSelric 
831ca1c9b0cSelric     *minor_status = 0;
832ca1c9b0cSelric     return GSS_S_COMPLETE;
833ca1c9b0cSelric }
834ca1c9b0cSelric 
835ca1c9b0cSelric static OM_uint32
max_wrap_length_arcfour(const gsskrb5_ctx ctx,krb5_crypto crypto,size_t input_length,OM_uint32 * max_input_size)836ca1c9b0cSelric max_wrap_length_arcfour(const gsskrb5_ctx ctx,
837ca1c9b0cSelric 			krb5_crypto crypto,
838ca1c9b0cSelric 			size_t input_length,
839ca1c9b0cSelric 			OM_uint32 *max_input_size)
840ca1c9b0cSelric {
841ca1c9b0cSelric     /*
842ca1c9b0cSelric      * if GSS_C_DCE_STYLE is in use:
843ca1c9b0cSelric      *  - we only need to encapsulate the WRAP token
844ca1c9b0cSelric      * However, since this is a fixed since, we just
845ca1c9b0cSelric      */
846ca1c9b0cSelric     if (IS_DCE_STYLE(ctx)) {
847ca1c9b0cSelric 	size_t len, total_len;
848ca1c9b0cSelric 
849ca1c9b0cSelric 	len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
850ca1c9b0cSelric 	_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
851ca1c9b0cSelric 
852ca1c9b0cSelric 	if (input_length < len)
853ca1c9b0cSelric 	    *max_input_size = 0;
854ca1c9b0cSelric 	else
855ca1c9b0cSelric 	    *max_input_size = input_length - len;
856ca1c9b0cSelric 
857ca1c9b0cSelric     } else {
858ca1c9b0cSelric 	size_t extrasize = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
859ca1c9b0cSelric 	size_t blocksize = 8;
860ca1c9b0cSelric 	size_t len, total_len;
861ca1c9b0cSelric 
862ca1c9b0cSelric 	len = 8 + input_length + blocksize + extrasize;
863ca1c9b0cSelric 
864ca1c9b0cSelric 	_gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
865ca1c9b0cSelric 
866ca1c9b0cSelric 	total_len -= input_length; /* token length */
867ca1c9b0cSelric 	if (total_len < input_length) {
868ca1c9b0cSelric 	    *max_input_size = (input_length - total_len);
869ca1c9b0cSelric 	    (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
870ca1c9b0cSelric 	} else {
871ca1c9b0cSelric 	    *max_input_size = 0;
872ca1c9b0cSelric 	}
873ca1c9b0cSelric     }
874ca1c9b0cSelric 
875ca1c9b0cSelric     return GSS_S_COMPLETE;
876ca1c9b0cSelric }
877ca1c9b0cSelric 
878ca1c9b0cSelric OM_uint32
_gssapi_wrap_size_arcfour(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,OM_uint32 req_output_size,OM_uint32 * max_input_size,krb5_keyblock * key)879ca1c9b0cSelric _gssapi_wrap_size_arcfour(OM_uint32 *minor_status,
880ca1c9b0cSelric 			  const gsskrb5_ctx ctx,
881ca1c9b0cSelric 			  krb5_context context,
882ca1c9b0cSelric 			  int conf_req_flag,
883ca1c9b0cSelric 			  gss_qop_t qop_req,
884ca1c9b0cSelric 			  OM_uint32 req_output_size,
885ca1c9b0cSelric 			  OM_uint32 *max_input_size,
886ca1c9b0cSelric 			  krb5_keyblock *key)
887ca1c9b0cSelric {
888ca1c9b0cSelric     krb5_error_code ret;
889ca1c9b0cSelric     krb5_crypto crypto;
890ca1c9b0cSelric 
891ca1c9b0cSelric     ret = krb5_crypto_init(context, key, 0, &crypto);
892ca1c9b0cSelric     if (ret != 0) {
893ca1c9b0cSelric 	*minor_status = ret;
894ca1c9b0cSelric 	return GSS_S_FAILURE;
895ca1c9b0cSelric     }
896ca1c9b0cSelric 
897ca1c9b0cSelric     ret = max_wrap_length_arcfour(ctx, crypto,
898ca1c9b0cSelric 				  req_output_size, max_input_size);
899ca1c9b0cSelric     if (ret != 0) {
900ca1c9b0cSelric 	*minor_status = ret;
901ca1c9b0cSelric 	krb5_crypto_destroy(context, crypto);
902ca1c9b0cSelric 	return GSS_S_FAILURE;
903ca1c9b0cSelric     }
904ca1c9b0cSelric 
905ca1c9b0cSelric     krb5_crypto_destroy(context, crypto);
906ca1c9b0cSelric 
907ca1c9b0cSelric     return GSS_S_COMPLETE;
908ca1c9b0cSelric }
909b9d004c6Schristos 
910b9d004c6Schristos OM_uint32
_gssapi_wrap_iov_length_arcfour(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,int * conf_state,gss_iov_buffer_desc * iov,int iov_count)911b9d004c6Schristos _gssapi_wrap_iov_length_arcfour(OM_uint32 *minor_status,
912b9d004c6Schristos 				gsskrb5_ctx ctx,
913b9d004c6Schristos 				krb5_context context,
914b9d004c6Schristos 				int conf_req_flag,
915b9d004c6Schristos 				gss_qop_t qop_req,
916b9d004c6Schristos 				int *conf_state,
917b9d004c6Schristos 				gss_iov_buffer_desc *iov,
918b9d004c6Schristos 				int iov_count)
919b9d004c6Schristos {
920b9d004c6Schristos     OM_uint32 major_status;
921b9d004c6Schristos     size_t data_len = 0;
922b9d004c6Schristos     int i;
923b9d004c6Schristos     gss_iov_buffer_desc *header = NULL;
924b9d004c6Schristos     gss_iov_buffer_desc *padding = NULL;
925b9d004c6Schristos     gss_iov_buffer_desc *trailer = NULL;
926b9d004c6Schristos 
927b9d004c6Schristos     *minor_status = 0;
928b9d004c6Schristos 
929b9d004c6Schristos     for (i = 0; i < iov_count; i++) {
930b9d004c6Schristos 	switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
931b9d004c6Schristos 	case GSS_IOV_BUFFER_TYPE_EMPTY:
932b9d004c6Schristos 	    break;
933b9d004c6Schristos 	case GSS_IOV_BUFFER_TYPE_DATA:
934b9d004c6Schristos 	    data_len += iov[i].buffer.length;
935b9d004c6Schristos 	    break;
936b9d004c6Schristos 	case GSS_IOV_BUFFER_TYPE_HEADER:
937b9d004c6Schristos 	    if (header != NULL) {
938b9d004c6Schristos 		*minor_status = EINVAL;
939b9d004c6Schristos 		return GSS_S_FAILURE;
940b9d004c6Schristos 	    }
941b9d004c6Schristos 	    header = &iov[i];
942b9d004c6Schristos 	    break;
943b9d004c6Schristos 	case GSS_IOV_BUFFER_TYPE_TRAILER:
944b9d004c6Schristos 	    if (trailer != NULL) {
945b9d004c6Schristos 		*minor_status = EINVAL;
946b9d004c6Schristos 		return GSS_S_FAILURE;
947b9d004c6Schristos 	    }
948b9d004c6Schristos 	    trailer = &iov[i];
949b9d004c6Schristos 	    break;
950b9d004c6Schristos 	case GSS_IOV_BUFFER_TYPE_PADDING:
951b9d004c6Schristos 	    if (padding != NULL) {
952b9d004c6Schristos 		*minor_status = EINVAL;
953b9d004c6Schristos 		return GSS_S_FAILURE;
954b9d004c6Schristos 	    }
955b9d004c6Schristos 	    padding = &iov[i];
956b9d004c6Schristos 	    break;
957b9d004c6Schristos 	case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
958b9d004c6Schristos 	    break;
959b9d004c6Schristos 	default:
960b9d004c6Schristos 	    *minor_status = EINVAL;
961b9d004c6Schristos 	    return GSS_S_FAILURE;
962b9d004c6Schristos 	}
963b9d004c6Schristos     }
964b9d004c6Schristos 
965*afab4e30Schristos     if (header == NULL) {
966*afab4e30Schristos         *minor_status = EINVAL;
967*afab4e30Schristos         return GSS_S_FAILURE;
968*afab4e30Schristos     }
969*afab4e30Schristos 
970*afab4e30Schristos     major_status = _gk_verify_buffers(minor_status, ctx, header,
971*afab4e30Schristos 				      padding, trailer, FALSE);
972b9d004c6Schristos     if (major_status != GSS_S_COMPLETE) {
973b9d004c6Schristos 	    return major_status;
974b9d004c6Schristos     }
975b9d004c6Schristos 
976b9d004c6Schristos     if (IS_DCE_STYLE(ctx)) {
977b9d004c6Schristos 	size_t len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
978b9d004c6Schristos 	size_t total_len;
979b9d004c6Schristos 	_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
980b9d004c6Schristos 	header->buffer.length = total_len;
981b9d004c6Schristos     } else {
982b9d004c6Schristos 	size_t len;
983b9d004c6Schristos 	size_t total_len;
984b9d004c6Schristos 	if (padding) {
985b9d004c6Schristos 	    data_len += 1; /* padding */
986b9d004c6Schristos 	}
987b9d004c6Schristos 	len = data_len + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
988b9d004c6Schristos 	_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
989b9d004c6Schristos 	header->buffer.length = total_len - data_len;
990b9d004c6Schristos     }
991b9d004c6Schristos 
992b9d004c6Schristos     if (trailer) {
993b9d004c6Schristos 	trailer->buffer.length = 0;
994b9d004c6Schristos     }
995b9d004c6Schristos 
996b9d004c6Schristos     if (padding) {
997b9d004c6Schristos 	padding->buffer.length = 1;
998b9d004c6Schristos     }
999b9d004c6Schristos 
1000b9d004c6Schristos     return GSS_S_COMPLETE;
1001b9d004c6Schristos }
1002b9d004c6Schristos 
1003b9d004c6Schristos OM_uint32
_gssapi_wrap_iov_arcfour(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,int * conf_state,gss_iov_buffer_desc * iov,int iov_count,krb5_keyblock * key)1004b9d004c6Schristos _gssapi_wrap_iov_arcfour(OM_uint32 *minor_status,
1005b9d004c6Schristos 			 gsskrb5_ctx ctx,
1006b9d004c6Schristos 			 krb5_context context,
1007b9d004c6Schristos 			 int conf_req_flag,
1008b9d004c6Schristos 			 int *conf_state,
1009b9d004c6Schristos 			 gss_iov_buffer_desc *iov,
1010b9d004c6Schristos 			 int iov_count,
1011b9d004c6Schristos 			 krb5_keyblock *key)
1012b9d004c6Schristos {
1013b9d004c6Schristos     OM_uint32 major_status, junk;
1014b9d004c6Schristos     gss_iov_buffer_desc *header, *padding, *trailer;
1015b9d004c6Schristos     krb5_error_code kret;
1016b9d004c6Schristos     int32_t seq_number;
1017b9d004c6Schristos     u_char Klocaldata[16], k6_data[16], *p, *p0;
1018b9d004c6Schristos     size_t make_len = 0;
1019b9d004c6Schristos     size_t header_len = 0;
1020b9d004c6Schristos     size_t data_len = 0;
1021b9d004c6Schristos     krb5_keyblock Klocal;
1022b9d004c6Schristos     int i;
1023b9d004c6Schristos 
1024b9d004c6Schristos     header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
1025b9d004c6Schristos     padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
1026b9d004c6Schristos     trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
1027b9d004c6Schristos 
1028*afab4e30Schristos     major_status = _gk_verify_buffers(minor_status, ctx, header,
1029*afab4e30Schristos 				      padding, trailer, FALSE);
1030b9d004c6Schristos     if (major_status != GSS_S_COMPLETE) {
1031b9d004c6Schristos 	return major_status;
1032b9d004c6Schristos     }
1033b9d004c6Schristos 
1034b9d004c6Schristos     for (i = 0; i < iov_count; i++) {
1035b9d004c6Schristos 	switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
1036b9d004c6Schristos 	case GSS_IOV_BUFFER_TYPE_DATA:
1037b9d004c6Schristos 	    break;
1038b9d004c6Schristos 	default:
1039b9d004c6Schristos 	    continue;
1040b9d004c6Schristos 	}
1041b9d004c6Schristos 
1042b9d004c6Schristos 	data_len += iov[i].buffer.length;
1043b9d004c6Schristos     }
1044b9d004c6Schristos 
1045b9d004c6Schristos     if (padding) {
1046b9d004c6Schristos 	data_len += 1;
1047b9d004c6Schristos     }
1048b9d004c6Schristos 
1049b9d004c6Schristos     if (IS_DCE_STYLE(ctx)) {
1050b9d004c6Schristos 	size_t unwrapped_len;
1051b9d004c6Schristos 	unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
1052b9d004c6Schristos 	_gssapi_encap_length(unwrapped_len,
1053b9d004c6Schristos 			     &make_len,
1054b9d004c6Schristos 			     &header_len,
1055b9d004c6Schristos 			     GSS_KRB5_MECHANISM);
1056b9d004c6Schristos     } else {
1057b9d004c6Schristos 	size_t unwrapped_len;
1058b9d004c6Schristos 	unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + data_len;
1059b9d004c6Schristos 	_gssapi_encap_length(unwrapped_len,
1060b9d004c6Schristos 			     &make_len,
1061b9d004c6Schristos 			     &header_len,
1062b9d004c6Schristos 			     GSS_KRB5_MECHANISM);
1063b9d004c6Schristos 	header_len -= data_len;
1064b9d004c6Schristos     }
1065b9d004c6Schristos 
1066*afab4e30Schristos     if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
1067b9d004c6Schristos 	major_status = _gk_allocate_buffer(minor_status, header,
1068b9d004c6Schristos 					   header_len);
1069b9d004c6Schristos 	if (major_status != GSS_S_COMPLETE)
1070b9d004c6Schristos 	    goto failure;
1071b9d004c6Schristos     } else if (header->buffer.length < header_len) {
1072b9d004c6Schristos 	*minor_status = KRB5_BAD_MSIZE;
1073b9d004c6Schristos 	major_status = GSS_S_FAILURE;
1074b9d004c6Schristos 	goto failure;
1075b9d004c6Schristos     } else {
1076b9d004c6Schristos 	header->buffer.length = header_len;
1077b9d004c6Schristos     }
1078b9d004c6Schristos 
1079b9d004c6Schristos     if (padding) {
1080*afab4e30Schristos 	if (GSS_IOV_BUFFER_FLAGS(padding->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
1081b9d004c6Schristos 	    major_status = _gk_allocate_buffer(minor_status, padding, 1);
1082b9d004c6Schristos 	    if (major_status != GSS_S_COMPLETE)
1083b9d004c6Schristos 		goto failure;
1084b9d004c6Schristos 	} else if (padding->buffer.length < 1) {
1085b9d004c6Schristos 	    *minor_status = KRB5_BAD_MSIZE;
1086b9d004c6Schristos 	    major_status = GSS_S_FAILURE;
1087b9d004c6Schristos 	    goto failure;
1088b9d004c6Schristos 	} else {
1089b9d004c6Schristos 	    padding->buffer.length = 1;
1090b9d004c6Schristos 	}
1091b9d004c6Schristos 	memset(padding->buffer.value, 1, 1);
1092b9d004c6Schristos     }
1093b9d004c6Schristos 
1094b9d004c6Schristos     if (trailer) {
1095b9d004c6Schristos 	trailer->buffer.length = 0;
1096b9d004c6Schristos 	trailer->buffer.value = NULL;
1097b9d004c6Schristos     }
1098b9d004c6Schristos 
1099b9d004c6Schristos     p0 = _gssapi_make_mech_header(header->buffer.value,
1100b9d004c6Schristos 				  make_len,
1101b9d004c6Schristos 				  GSS_KRB5_MECHANISM);
1102b9d004c6Schristos     p = p0;
1103b9d004c6Schristos 
1104b9d004c6Schristos     *p++ = 0x02; /* TOK_ID */
1105b9d004c6Schristos     *p++ = 0x01;
1106b9d004c6Schristos     *p++ = 0x11; /* SGN_ALG */
1107b9d004c6Schristos     *p++ = 0x00;
1108b9d004c6Schristos     if (conf_req_flag) {
1109b9d004c6Schristos 	*p++ = 0x10; /* SEAL_ALG */
1110b9d004c6Schristos 	*p++ = 0x00;
1111b9d004c6Schristos     } else {
1112b9d004c6Schristos 	*p++ = 0xff; /* SEAL_ALG */
1113b9d004c6Schristos 	*p++ = 0xff;
1114b9d004c6Schristos     }
1115b9d004c6Schristos     *p++ = 0xff; /* Filler */
1116b9d004c6Schristos     *p++ = 0xff;
1117b9d004c6Schristos 
1118b9d004c6Schristos     p = NULL;
1119b9d004c6Schristos 
1120b9d004c6Schristos     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1121b9d004c6Schristos     krb5_auth_con_getlocalseqnumber(context,
1122b9d004c6Schristos 				    ctx->auth_context,
1123b9d004c6Schristos 				    &seq_number);
1124b9d004c6Schristos     _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8);
1125b9d004c6Schristos 
1126b9d004c6Schristos     krb5_auth_con_setlocalseqnumber(context,
1127b9d004c6Schristos 				    ctx->auth_context,
1128b9d004c6Schristos 				    ++seq_number);
1129b9d004c6Schristos     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1130b9d004c6Schristos 
1131b9d004c6Schristos     memset(p0 + 8 + 4,
1132b9d004c6Schristos            (ctx->more_flags & LOCAL) ? 0 : 0xff,
1133b9d004c6Schristos            4);
1134b9d004c6Schristos 
1135b9d004c6Schristos     krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
1136b9d004c6Schristos 
1137b9d004c6Schristos     /* Sign Data */
1138b9d004c6Schristos     kret = arcfour_mic_cksum_iov(context,
1139b9d004c6Schristos 				 key, KRB5_KU_USAGE_SEAL,
1140b9d004c6Schristos 				 p0 + 16, 8, /* SGN_CKSUM */
1141b9d004c6Schristos 				 p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
1142b9d004c6Schristos 				 p0 + 24, 8, /* Confounder */
1143b9d004c6Schristos 				 iov, iov_count, /* Data + SignOnly */
1144b9d004c6Schristos 				 padding); /* padding */
1145b9d004c6Schristos     if (kret) {
1146b9d004c6Schristos 	*minor_status = kret;
1147b9d004c6Schristos 	major_status = GSS_S_FAILURE;
1148b9d004c6Schristos 	goto failure;
1149b9d004c6Schristos     }
1150b9d004c6Schristos 
1151b9d004c6Schristos     Klocal.keytype = key->keytype;
1152b9d004c6Schristos     Klocal.keyvalue.data = Klocaldata;
1153b9d004c6Schristos     Klocal.keyvalue.length = sizeof(Klocaldata);
1154b9d004c6Schristos 
1155b9d004c6Schristos     for (i = 0; i < 16; i++) {
1156b9d004c6Schristos 	Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
1157b9d004c6Schristos     }
1158b9d004c6Schristos     kret = arcfour_mic_key(context, &Klocal,
1159b9d004c6Schristos 			   p0 + 8, 4, /* SND_SEQ */
1160b9d004c6Schristos 			   k6_data, sizeof(k6_data));
1161241bea01Schristos     memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata));
1162b9d004c6Schristos     if (kret) {
1163b9d004c6Schristos 	*minor_status = kret;
1164b9d004c6Schristos 	major_status = GSS_S_FAILURE;
1165b9d004c6Schristos 	goto failure;
1166b9d004c6Schristos     }
1167b9d004c6Schristos 
1168b9d004c6Schristos     if (conf_req_flag) {
11696680b65dSchristos 	EVP_CIPHER_CTX *rc4_key;
11706680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
11716680b65dSchristos 	EVP_CIPHER_CTX rc4_keys;
11726680b65dSchristos 	rc4_key = &rc4_keys;
11736680b65dSchristos 	EVP_CIPHER_CTX_init(rc4_key);
11746680b65dSchristos #else
11756680b65dSchristos 	rc4_key = EVP_CIPHER_CTX_new();
11766680b65dSchristos #endif
11777b2118deSchristos 	if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
11787b2118deSchristos 	    *minor_status = EINVAL;
11797b2118deSchristos 	    return GSS_S_FAILURE;
11807b2118deSchristos 	}
1181b9d004c6Schristos 
1182b9d004c6Schristos 	/* Confounder */
11836680b65dSchristos 	EVP_Cipher(rc4_key, p0 + 24, p0 + 24, 8);
1184b9d004c6Schristos 
1185b9d004c6Schristos 	/* Seal Data */
1186b9d004c6Schristos 	for (i=0; i < iov_count; i++) {
1187b9d004c6Schristos 	    switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
1188b9d004c6Schristos 	    case GSS_IOV_BUFFER_TYPE_DATA:
1189b9d004c6Schristos 		break;
1190b9d004c6Schristos 	    default:
1191b9d004c6Schristos 		continue;
1192b9d004c6Schristos 	    }
1193b9d004c6Schristos 
11946680b65dSchristos 	    EVP_Cipher(rc4_key, iov[i].buffer.value,
1195b9d004c6Schristos 		       iov[i].buffer.value, iov[i].buffer.length);
1196b9d004c6Schristos 	}
1197b9d004c6Schristos 
1198b9d004c6Schristos 	/* Padding */
1199b9d004c6Schristos 	if (padding) {
12006680b65dSchristos 	    EVP_Cipher(rc4_key, padding->buffer.value,
1201b9d004c6Schristos 		       padding->buffer.value, padding->buffer.length);
1202b9d004c6Schristos 	}
1203b9d004c6Schristos 
12046680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
12056680b65dSchristos 	EVP_CIPHER_CTX_cleanup(rc4_key);
12066680b65dSchristos #else
12076680b65dSchristos 	EVP_CIPHER_CTX_free(rc4_key);
12086680b65dSchristos #endif
1209b9d004c6Schristos     }
1210241bea01Schristos     memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
1211b9d004c6Schristos 
1212b9d004c6Schristos     kret = arcfour_mic_key(context, key,
1213b9d004c6Schristos 			   p0 + 16, 8, /* SGN_CKSUM */
1214b9d004c6Schristos 			   k6_data, sizeof(k6_data));
1215b9d004c6Schristos     if (kret) {
1216b9d004c6Schristos 	*minor_status = kret;
1217b9d004c6Schristos 	major_status = GSS_S_FAILURE;
1218b9d004c6Schristos         return major_status;
1219b9d004c6Schristos     }
1220b9d004c6Schristos 
1221b9d004c6Schristos     {
12226680b65dSchristos 	EVP_CIPHER_CTX *rc4_key;
12236680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
12246680b65dSchristos 	EVP_CIPHER_CTX rc4_keys;
12256680b65dSchristos 	rc4_key = &rc4_keys;
12266680b65dSchristos 	EVP_CIPHER_CTX_init(rc4_key);
12276680b65dSchristos #else
12286680b65dSchristos 	rc4_key = EVP_CIPHER_CTX_new();
12296680b65dSchristos #endif
12307b2118deSchristos 	if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
12317b2118deSchristos 	    *minor_status = EINVAL;
12327b2118deSchristos 	    return GSS_S_FAILURE;
12337b2118deSchristos 	}
12346680b65dSchristos 	EVP_Cipher(rc4_key, p0 + 8, p0 + 8, 8); /* SND_SEQ */
12356680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
12366680b65dSchristos 	EVP_CIPHER_CTX_cleanup(rc4_key);
12376680b65dSchristos #else
12386680b65dSchristos 	EVP_CIPHER_CTX_free(rc4_key);
12396680b65dSchristos #endif
1240b9d004c6Schristos 
1241241bea01Schristos 	memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
1242b9d004c6Schristos     }
1243b9d004c6Schristos 
1244b9d004c6Schristos     if (conf_state)
1245b9d004c6Schristos 	*conf_state = conf_req_flag;
1246b9d004c6Schristos 
1247b9d004c6Schristos     *minor_status = 0;
1248b9d004c6Schristos     return GSS_S_COMPLETE;
1249b9d004c6Schristos 
1250b9d004c6Schristos failure:
1251b9d004c6Schristos 
1252b9d004c6Schristos     gss_release_iov_buffer(&junk, iov, iov_count);
1253b9d004c6Schristos 
1254b9d004c6Schristos     return major_status;
1255b9d004c6Schristos }
1256b9d004c6Schristos 
1257b9d004c6Schristos OM_uint32
_gssapi_unwrap_iov_arcfour(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context,int * pconf_state,gss_qop_t * pqop_state,gss_iov_buffer_desc * iov,int iov_count,krb5_keyblock * key)1258b9d004c6Schristos _gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status,
1259b9d004c6Schristos 			   gsskrb5_ctx ctx,
1260b9d004c6Schristos 			   krb5_context context,
1261b9d004c6Schristos 			   int *pconf_state,
1262b9d004c6Schristos 			   gss_qop_t *pqop_state,
1263b9d004c6Schristos 			   gss_iov_buffer_desc *iov,
1264b9d004c6Schristos 			   int iov_count,
1265b9d004c6Schristos 			   krb5_keyblock *key)
1266b9d004c6Schristos {
1267b9d004c6Schristos     OM_uint32 major_status;
1268b9d004c6Schristos     gss_iov_buffer_desc *header, *padding, *trailer;
1269b9d004c6Schristos     krb5_keyblock Klocal;
1270b9d004c6Schristos     uint8_t Klocaldata[16];
1271b9d004c6Schristos     uint8_t k6_data[16], snd_seq[8], Confounder[8];
1272b9d004c6Schristos     uint8_t cksum_data[8];
1273b9d004c6Schristos     uint8_t *_p = NULL;
1274b9d004c6Schristos     const uint8_t *p, *p0;
1275b9d004c6Schristos     size_t verify_len = 0;
1276b9d004c6Schristos     uint32_t seq_number;
1277b9d004c6Schristos     size_t hlen = 0;
1278b9d004c6Schristos     int conf_state;
1279b9d004c6Schristos     int cmp;
1280b9d004c6Schristos     size_t i;
1281b9d004c6Schristos     krb5_error_code kret;
1282b9d004c6Schristos     OM_uint32 ret;
1283b9d004c6Schristos 
1284b9d004c6Schristos     if (pconf_state != NULL) {
1285b9d004c6Schristos 	*pconf_state = 0;
1286b9d004c6Schristos     }
1287b9d004c6Schristos     if (pqop_state != NULL) {
1288b9d004c6Schristos 	*pqop_state = 0;
1289b9d004c6Schristos     }
1290b9d004c6Schristos 
1291b9d004c6Schristos     header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
1292b9d004c6Schristos     padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
1293b9d004c6Schristos     trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
1294b9d004c6Schristos 
1295b9d004c6Schristos     /* Check if the packet is correct */
1296b9d004c6Schristos     major_status = _gk_verify_buffers(minor_status,
1297b9d004c6Schristos 				      ctx,
1298b9d004c6Schristos 				      header,
1299b9d004c6Schristos 				      padding,
1300*afab4e30Schristos 				      trailer,
1301*afab4e30Schristos 				      FALSE); /* behaves as stream cipher */
1302b9d004c6Schristos     if (major_status != GSS_S_COMPLETE) {
1303b9d004c6Schristos 	return major_status;
1304b9d004c6Schristos     }
1305b9d004c6Schristos 
1306b9d004c6Schristos     if (padding != NULL && padding->buffer.length != 1) {
1307b9d004c6Schristos 	*minor_status = EINVAL;
1308b9d004c6Schristos 	return GSS_S_FAILURE;
1309b9d004c6Schristos     }
1310b9d004c6Schristos 
1311b9d004c6Schristos     verify_len = header->buffer.length;
1312*afab4e30Schristos 
1313*afab4e30Schristos     if (!IS_DCE_STYLE(context)) {
1314*afab4e30Schristos 	for (i = 0; i < iov_count; i++) {
1315*afab4e30Schristos 	    /* length in header also includes data and padding */
1316*afab4e30Schristos 	    if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA)
1317*afab4e30Schristos 		verify_len += iov[i].buffer.length;
1318b9d004c6Schristos 	}
1319*afab4e30Schristos 
1320*afab4e30Schristos 	if (padding)
1321*afab4e30Schristos 	    verify_len += padding->buffer.length;
1322*afab4e30Schristos     }
1323*afab4e30Schristos 
1324b9d004c6Schristos     _p = header->buffer.value;
1325b9d004c6Schristos 
1326b9d004c6Schristos     ret = _gssapi_verify_mech_header(&_p,
1327b9d004c6Schristos 				     verify_len,
1328b9d004c6Schristos 				     GSS_KRB5_MECHANISM);
1329b9d004c6Schristos     if (ret) {
1330b9d004c6Schristos 	return ret;
1331b9d004c6Schristos     }
1332b9d004c6Schristos     p0 = _p;
1333b9d004c6Schristos 
1334b9d004c6Schristos     /* length of mech header */
1335b9d004c6Schristos     hlen = (p0 - (uint8_t *)header->buffer.value);
1336b9d004c6Schristos     hlen += GSS_ARCFOUR_WRAP_TOKEN_SIZE;
1337b9d004c6Schristos 
1338b9d004c6Schristos     if (hlen > header->buffer.length) {
1339b9d004c6Schristos 	return GSS_S_BAD_MECH;
1340b9d004c6Schristos     }
1341b9d004c6Schristos 
1342b9d004c6Schristos     p = p0;
1343b9d004c6Schristos 
1344b9d004c6Schristos     if (memcmp(p, "\x02\x01", 2) != 0)
1345b9d004c6Schristos 	return GSS_S_BAD_SIG;
1346b9d004c6Schristos     p += 2;
1347b9d004c6Schristos     if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
1348b9d004c6Schristos 	return GSS_S_BAD_SIG;
1349b9d004c6Schristos     p += 2;
1350b9d004c6Schristos 
1351b9d004c6Schristos     if (memcmp (p, "\x10\x00", 2) == 0)
1352b9d004c6Schristos 	conf_state = 1;
1353b9d004c6Schristos     else if (memcmp (p, "\xff\xff", 2) == 0)
1354b9d004c6Schristos 	conf_state = 0;
1355b9d004c6Schristos     else
1356b9d004c6Schristos 	return GSS_S_BAD_SIG;
1357b9d004c6Schristos 
1358b9d004c6Schristos     p += 2;
1359b9d004c6Schristos     if (memcmp (p, "\xff\xff", 2) != 0)
1360b9d004c6Schristos 	return GSS_S_BAD_MIC;
1361b9d004c6Schristos     p = NULL;
1362b9d004c6Schristos 
1363b9d004c6Schristos     kret = arcfour_mic_key(context,
1364b9d004c6Schristos 			   key,
1365b9d004c6Schristos 			   p0 + 16, /* SGN_CKSUM */
1366b9d004c6Schristos 			   8,       /* SGN_CKSUM_LEN */
1367b9d004c6Schristos 			   k6_data,
1368b9d004c6Schristos 			   sizeof(k6_data));
1369b9d004c6Schristos     if (kret) {
1370b9d004c6Schristos 	*minor_status = kret;
1371b9d004c6Schristos 	return GSS_S_FAILURE;
1372b9d004c6Schristos     }
1373b9d004c6Schristos 
1374b9d004c6Schristos     {
13756680b65dSchristos 	EVP_CIPHER_CTX *rc4_key;
13766680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
13776680b65dSchristos 	EVP_CIPHER_CTX rc4_keys;
13786680b65dSchristos 	rc4_key = &rc4_keys;
13796680b65dSchristos 	EVP_CIPHER_CTX_init(rc4_key);
13806680b65dSchristos #else
13816680b65dSchristos 	rc4_key = EVP_CIPHER_CTX_new();
13826680b65dSchristos #endif
1383b9d004c6Schristos 
13846680b65dSchristos 	EVP_CIPHER_CTX_init(rc4_key);
13857b2118deSchristos 	if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
13867b2118deSchristos 	    *minor_status = EINVAL;
13877b2118deSchristos 	    return GSS_S_FAILURE;
13887b2118deSchristos 	}
13896680b65dSchristos 	EVP_Cipher(rc4_key, snd_seq, p0 + 8, 8); /* SND_SEQ */
13906680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
13916680b65dSchristos 	EVP_CIPHER_CTX_cleanup(rc4_key);
13926680b65dSchristos #else
13936680b65dSchristos 	EVP_CIPHER_CTX_free(rc4_key);
13946680b65dSchristos #endif
1395b9d004c6Schristos 
1396241bea01Schristos 	memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
1397b9d004c6Schristos     }
1398b9d004c6Schristos 
1399b9d004c6Schristos     _gsskrb5_decode_be_om_uint32(snd_seq, &seq_number);
1400b9d004c6Schristos 
1401b9d004c6Schristos     if (ctx->more_flags & LOCAL) {
1402*afab4e30Schristos 	cmp = (ct_memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4) != 0);
1403b9d004c6Schristos     } else {
1404*afab4e30Schristos 	cmp = (ct_memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4) != 0);
1405b9d004c6Schristos     }
1406b9d004c6Schristos     if (cmp != 0) {
1407b9d004c6Schristos 	*minor_status = 0;
1408b9d004c6Schristos 	return GSS_S_BAD_MIC;
1409b9d004c6Schristos     }
1410b9d004c6Schristos 
1411b9d004c6Schristos     /* keyblock */
1412b9d004c6Schristos     Klocal.keytype = key->keytype;
1413b9d004c6Schristos     Klocal.keyvalue.data = Klocaldata;
1414b9d004c6Schristos     Klocal.keyvalue.length = sizeof(Klocaldata);
1415b9d004c6Schristos 
1416b9d004c6Schristos     for (i = 0; i < 16; i++) {
1417b9d004c6Schristos 	Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
1418b9d004c6Schristos     }
1419b9d004c6Schristos 
1420b9d004c6Schristos     kret = arcfour_mic_key(context,
1421b9d004c6Schristos 			   &Klocal,
1422b9d004c6Schristos 			   snd_seq,
1423b9d004c6Schristos 			   4,
1424b9d004c6Schristos 			   k6_data, sizeof(k6_data));
1425241bea01Schristos     memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata));
1426b9d004c6Schristos     if (kret) {
1427b9d004c6Schristos 	*minor_status = kret;
1428b9d004c6Schristos 	return GSS_S_FAILURE;
1429b9d004c6Schristos     }
1430b9d004c6Schristos 
1431b9d004c6Schristos     if (conf_state == 1) {
14326680b65dSchristos 	EVP_CIPHER_CTX *rc4_key;
14336680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
14346680b65dSchristos 	EVP_CIPHER_CTX rc4_keys;
14356680b65dSchristos 	rc4_key = &rc4_keys;
14366680b65dSchristos 	EVP_CIPHER_CTX_init(rc4_key);
14376680b65dSchristos #else
14386680b65dSchristos 	rc4_key = EVP_CIPHER_CTX_new();
14396680b65dSchristos #endif
1440b9d004c6Schristos 
14417b2118deSchristos 	if (!EVP_CipherInit_ex(rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1)) {
14427b2118deSchristos 	    *minor_status = EINVAL;
14437b2118deSchristos 	    return GSS_S_FAILURE;
14447b2118deSchristos 	}
1445b9d004c6Schristos 
1446b9d004c6Schristos 	/* Confounder */
14476680b65dSchristos 	EVP_Cipher(rc4_key, Confounder, p0 + 24, 8);
1448b9d004c6Schristos 
1449b9d004c6Schristos 	/* Data */
1450b9d004c6Schristos 	for (i = 0; i < iov_count; i++) {
1451b9d004c6Schristos 	    switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
1452b9d004c6Schristos 	    case GSS_IOV_BUFFER_TYPE_DATA:
1453b9d004c6Schristos 		break;
1454b9d004c6Schristos 	    default:
1455b9d004c6Schristos 		continue;
1456b9d004c6Schristos 	    }
1457b9d004c6Schristos 
14586680b65dSchristos 	    EVP_Cipher(rc4_key, iov[i].buffer.value,
1459b9d004c6Schristos 		       iov[i].buffer.value, iov[i].buffer.length);
1460b9d004c6Schristos 	}
1461b9d004c6Schristos 
1462b9d004c6Schristos 	/* Padding */
1463b9d004c6Schristos 	if (padding) {
14646680b65dSchristos 	    EVP_Cipher(rc4_key, padding->buffer.value,
1465b9d004c6Schristos 		       padding->buffer.value, padding->buffer.length);
1466b9d004c6Schristos 	}
1467b9d004c6Schristos 
14686680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
14696680b65dSchristos 	EVP_CIPHER_CTX_cleanup(rc4_key);
14706680b65dSchristos #else
14716680b65dSchristos 	EVP_CIPHER_CTX_free(rc4_key);
14726680b65dSchristos #endif
1473b9d004c6Schristos     } else {
1474b9d004c6Schristos 	/* Confounder */
1475b9d004c6Schristos 	memcpy(Confounder, p0 + 24, 8);
1476b9d004c6Schristos     }
1477241bea01Schristos     memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data));
1478b9d004c6Schristos 
1479b9d004c6Schristos     /* Prepare the buffer for signing */
1480b9d004c6Schristos     kret = arcfour_mic_cksum_iov(context,
1481b9d004c6Schristos 				 key, KRB5_KU_USAGE_SEAL,
1482b9d004c6Schristos 				 cksum_data, sizeof(cksum_data),
1483b9d004c6Schristos 				 p0, 8,
1484b9d004c6Schristos 				 Confounder, sizeof(Confounder),
1485b9d004c6Schristos 				 iov, iov_count,
1486b9d004c6Schristos 				 padding);
1487b9d004c6Schristos     if (kret) {
1488b9d004c6Schristos 	*minor_status = kret;
1489b9d004c6Schristos 	return GSS_S_FAILURE;
1490b9d004c6Schristos     }
1491b9d004c6Schristos 
1492b9d004c6Schristos     cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */
1493b9d004c6Schristos     if (cmp != 0) {
1494b9d004c6Schristos 	*minor_status = 0;
1495b9d004c6Schristos 	return GSS_S_BAD_MIC;
1496b9d004c6Schristos     }
1497b9d004c6Schristos 
1498b9d004c6Schristos     if (padding) {
1499b9d004c6Schristos 	size_t plen;
1500b9d004c6Schristos 
1501b9d004c6Schristos 	ret = _gssapi_verify_pad(&padding->buffer, 1, &plen);
1502b9d004c6Schristos 	if (ret) {
1503b9d004c6Schristos 	    *minor_status = 0;
1504b9d004c6Schristos 	    return ret;
1505b9d004c6Schristos 	}
1506b9d004c6Schristos     }
1507b9d004c6Schristos 
1508b9d004c6Schristos     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1509b9d004c6Schristos     ret = _gssapi_msg_order_check(ctx->order, seq_number);
1510b9d004c6Schristos     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1511b9d004c6Schristos     if (ret != 0) {
1512b9d004c6Schristos 	return ret;
1513b9d004c6Schristos     }
1514b9d004c6Schristos 
1515b9d004c6Schristos     if (pconf_state) {
1516b9d004c6Schristos 	*pconf_state = conf_state;
1517b9d004c6Schristos     }
1518b9d004c6Schristos 
1519b9d004c6Schristos     *minor_status = 0;
1520b9d004c6Schristos     return GSS_S_COMPLETE;
1521b9d004c6Schristos }
1522