xref: /freebsd/crypto/heimdal/lib/gssapi/krb5/cfx.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1c19800e8SDoug Rabson /*
2c19800e8SDoug Rabson  * Copyright (c) 2003, PADL Software Pty Ltd.
3c19800e8SDoug Rabson  * All rights reserved.
4c19800e8SDoug Rabson  *
5c19800e8SDoug Rabson  * Redistribution and use in source and binary forms, with or without
6c19800e8SDoug Rabson  * modification, are permitted provided that the following conditions
7c19800e8SDoug Rabson  * are met:
8c19800e8SDoug Rabson  *
9c19800e8SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
10c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
11c19800e8SDoug Rabson  *
12c19800e8SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
13c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
14c19800e8SDoug Rabson  *    documentation and/or other materials provided with the distribution.
15c19800e8SDoug Rabson  *
16c19800e8SDoug Rabson  * 3. Neither the name of PADL Software nor the names of its contributors
17c19800e8SDoug Rabson  *    may be used to endorse or promote products derived from this software
18c19800e8SDoug Rabson  *    without specific prior written permission.
19c19800e8SDoug Rabson  *
20c19800e8SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21c19800e8SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22c19800e8SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23c19800e8SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
24c19800e8SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25c19800e8SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26c19800e8SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27c19800e8SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28c19800e8SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29c19800e8SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30c19800e8SDoug Rabson  * SUCH DAMAGE.
31c19800e8SDoug Rabson  */
32c19800e8SDoug Rabson 
33*ae771770SStanislav Sedov #include "gsskrb5_locl.h"
34c19800e8SDoug Rabson 
35c19800e8SDoug Rabson /*
36*ae771770SStanislav Sedov  * Implementation of RFC 4121
37c19800e8SDoug Rabson  */
38c19800e8SDoug Rabson 
39c19800e8SDoug Rabson #define CFXSentByAcceptor	(1 << 0)
40c19800e8SDoug Rabson #define CFXSealed		(1 << 1)
41c19800e8SDoug Rabson #define CFXAcceptorSubkey	(1 << 2)
42c19800e8SDoug Rabson 
43c19800e8SDoug Rabson krb5_error_code
_gsskrb5cfx_wrap_length_cfx(krb5_context context,krb5_crypto crypto,int conf_req_flag,int dce_style,size_t input_length,size_t * output_length,size_t * cksumsize,uint16_t * padlength)44c19800e8SDoug Rabson _gsskrb5cfx_wrap_length_cfx(krb5_context context,
45c19800e8SDoug Rabson 			    krb5_crypto crypto,
46c19800e8SDoug Rabson 			    int conf_req_flag,
47*ae771770SStanislav Sedov 			    int dce_style,
48c19800e8SDoug Rabson 			    size_t input_length,
49c19800e8SDoug Rabson 			    size_t *output_length,
50c19800e8SDoug Rabson 			    size_t *cksumsize,
51c19800e8SDoug Rabson 			    uint16_t *padlength)
52c19800e8SDoug Rabson {
53c19800e8SDoug Rabson     krb5_error_code ret;
54c19800e8SDoug Rabson     krb5_cksumtype type;
55c19800e8SDoug Rabson 
56c19800e8SDoug Rabson     /* 16-byte header is always first */
57c19800e8SDoug Rabson     *output_length = sizeof(gss_cfx_wrap_token_desc);
58c19800e8SDoug Rabson     *padlength = 0;
59c19800e8SDoug Rabson 
60c19800e8SDoug Rabson     ret = krb5_crypto_get_checksum_type(context, crypto, &type);
61c19800e8SDoug Rabson     if (ret)
62c19800e8SDoug Rabson 	return ret;
63c19800e8SDoug Rabson 
64c19800e8SDoug Rabson     ret = krb5_checksumsize(context, type, cksumsize);
65c19800e8SDoug Rabson     if (ret)
66c19800e8SDoug Rabson 	return ret;
67c19800e8SDoug Rabson 
68c19800e8SDoug Rabson     if (conf_req_flag) {
69c19800e8SDoug Rabson 	size_t padsize;
70c19800e8SDoug Rabson 
71c19800e8SDoug Rabson 	/* Header is concatenated with data before encryption */
72c19800e8SDoug Rabson 	input_length += sizeof(gss_cfx_wrap_token_desc);
73c19800e8SDoug Rabson 
74*ae771770SStanislav Sedov 	if (dce_style) {
75*ae771770SStanislav Sedov 		ret = krb5_crypto_getblocksize(context, crypto, &padsize);
76*ae771770SStanislav Sedov 	} else {
77c19800e8SDoug Rabson 		ret = krb5_crypto_getpadsize(context, crypto, &padsize);
78*ae771770SStanislav Sedov 	}
79c19800e8SDoug Rabson 	if (ret) {
80c19800e8SDoug Rabson 	    return ret;
81c19800e8SDoug Rabson 	}
82c19800e8SDoug Rabson 	if (padsize > 1) {
83c19800e8SDoug Rabson 	    /* XXX check this */
84c19800e8SDoug Rabson 	    *padlength = padsize - (input_length % padsize);
85c19800e8SDoug Rabson 
86c19800e8SDoug Rabson 	    /* We add the pad ourselves (noted here for completeness only) */
87c19800e8SDoug Rabson 	    input_length += *padlength;
88c19800e8SDoug Rabson 	}
89c19800e8SDoug Rabson 
90c19800e8SDoug Rabson 	*output_length += krb5_get_wrapped_length(context,
91c19800e8SDoug Rabson 						  crypto, input_length);
92c19800e8SDoug Rabson     } else {
93c19800e8SDoug Rabson 	/* Checksum is concatenated with data */
94c19800e8SDoug Rabson 	*output_length += input_length + *cksumsize;
95c19800e8SDoug Rabson     }
96c19800e8SDoug Rabson 
97c19800e8SDoug Rabson     assert(*output_length > input_length);
98c19800e8SDoug Rabson 
99c19800e8SDoug Rabson     return 0;
100c19800e8SDoug Rabson }
101c19800e8SDoug Rabson 
102*ae771770SStanislav Sedov OM_uint32
_gssapi_wrap_size_cfx(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)103*ae771770SStanislav Sedov _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
104*ae771770SStanislav Sedov 		      const gsskrb5_ctx ctx,
105*ae771770SStanislav Sedov 		      krb5_context context,
106c19800e8SDoug Rabson 		      int conf_req_flag,
107*ae771770SStanislav Sedov 		      gss_qop_t qop_req,
108*ae771770SStanislav Sedov 		      OM_uint32 req_output_size,
109*ae771770SStanislav Sedov 		      OM_uint32 *max_input_size)
110c19800e8SDoug Rabson {
111c19800e8SDoug Rabson     krb5_error_code ret;
112c19800e8SDoug Rabson 
113*ae771770SStanislav Sedov     *max_input_size = 0;
114c19800e8SDoug Rabson 
115c19800e8SDoug Rabson     /* 16-byte header is always first */
116*ae771770SStanislav Sedov     if (req_output_size < 16)
117c19800e8SDoug Rabson 	return 0;
118*ae771770SStanislav Sedov     req_output_size -= 16;
119c19800e8SDoug Rabson 
120c19800e8SDoug Rabson     if (conf_req_flag) {
121c19800e8SDoug Rabson 	size_t wrapped_size, sz;
122c19800e8SDoug Rabson 
123*ae771770SStanislav Sedov 	wrapped_size = req_output_size + 1;
124c19800e8SDoug Rabson 	do {
125c19800e8SDoug Rabson 	    wrapped_size--;
126c19800e8SDoug Rabson 	    sz = krb5_get_wrapped_length(context,
127*ae771770SStanislav Sedov 					 ctx->crypto, wrapped_size);
128*ae771770SStanislav Sedov 	} while (wrapped_size && sz > req_output_size);
129*ae771770SStanislav Sedov 	if (wrapped_size == 0)
130c19800e8SDoug Rabson 	    return 0;
131c19800e8SDoug Rabson 
132c19800e8SDoug Rabson 	/* inner header */
133*ae771770SStanislav Sedov 	if (wrapped_size < 16)
134c19800e8SDoug Rabson 	    return 0;
135*ae771770SStanislav Sedov 
136c19800e8SDoug Rabson 	wrapped_size -= 16;
137c19800e8SDoug Rabson 
138*ae771770SStanislav Sedov 	*max_input_size = wrapped_size;
139c19800e8SDoug Rabson     } else {
140c19800e8SDoug Rabson 	krb5_cksumtype type;
141c19800e8SDoug Rabson 	size_t cksumsize;
142c19800e8SDoug Rabson 
143*ae771770SStanislav Sedov 	ret = krb5_crypto_get_checksum_type(context, ctx->crypto, &type);
144c19800e8SDoug Rabson 	if (ret)
145c19800e8SDoug Rabson 	    return ret;
146c19800e8SDoug Rabson 
147c19800e8SDoug Rabson 	ret = krb5_checksumsize(context, type, &cksumsize);
148c19800e8SDoug Rabson 	if (ret)
149c19800e8SDoug Rabson 	    return ret;
150c19800e8SDoug Rabson 
151*ae771770SStanislav Sedov 	if (req_output_size < cksumsize)
152c19800e8SDoug Rabson 	    return 0;
153c19800e8SDoug Rabson 
154c19800e8SDoug Rabson 	/* Checksum is concatenated with data */
155*ae771770SStanislav Sedov 	*max_input_size = req_output_size - cksumsize;
156c19800e8SDoug Rabson     }
157c19800e8SDoug Rabson 
158c19800e8SDoug Rabson     return 0;
159c19800e8SDoug Rabson }
160c19800e8SDoug Rabson 
161c19800e8SDoug Rabson /*
162c19800e8SDoug Rabson  * Rotate "rrc" bytes to the front or back
163c19800e8SDoug Rabson  */
164c19800e8SDoug Rabson 
165c19800e8SDoug Rabson static krb5_error_code
rrc_rotate(void * data,size_t len,uint16_t rrc,krb5_boolean unrotate)166c19800e8SDoug Rabson rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate)
167c19800e8SDoug Rabson {
168c19800e8SDoug Rabson     u_char *tmp, buf[256];
169c19800e8SDoug Rabson     size_t left;
170c19800e8SDoug Rabson 
171c19800e8SDoug Rabson     if (len == 0)
172c19800e8SDoug Rabson 	return 0;
173c19800e8SDoug Rabson 
174c19800e8SDoug Rabson     rrc %= len;
175c19800e8SDoug Rabson 
176c19800e8SDoug Rabson     if (rrc == 0)
177c19800e8SDoug Rabson 	return 0;
178c19800e8SDoug Rabson 
179c19800e8SDoug Rabson     left = len - rrc;
180c19800e8SDoug Rabson 
181c19800e8SDoug Rabson     if (rrc <= sizeof(buf)) {
182c19800e8SDoug Rabson 	tmp = buf;
183c19800e8SDoug Rabson     } else {
184c19800e8SDoug Rabson 	tmp = malloc(rrc);
185c19800e8SDoug Rabson 	if (tmp == NULL)
186c19800e8SDoug Rabson 	    return ENOMEM;
187c19800e8SDoug Rabson     }
188c19800e8SDoug Rabson 
189c19800e8SDoug Rabson     if (unrotate) {
190c19800e8SDoug Rabson 	memcpy(tmp, data, rrc);
191c19800e8SDoug Rabson 	memmove(data, (u_char *)data + rrc, left);
192c19800e8SDoug Rabson 	memcpy((u_char *)data + left, tmp, rrc);
193c19800e8SDoug Rabson     } else {
194c19800e8SDoug Rabson 	memcpy(tmp, (u_char *)data + left, rrc);
195c19800e8SDoug Rabson 	memmove((u_char *)data + rrc, data, left);
196c19800e8SDoug Rabson 	memcpy(data, tmp, rrc);
197c19800e8SDoug Rabson     }
198c19800e8SDoug Rabson 
199c19800e8SDoug Rabson     if (rrc > sizeof(buf))
200c19800e8SDoug Rabson 	free(tmp);
201c19800e8SDoug Rabson 
202c19800e8SDoug Rabson     return 0;
203c19800e8SDoug Rabson }
204c19800e8SDoug Rabson 
205*ae771770SStanislav Sedov gss_iov_buffer_desc *
_gk_find_buffer(gss_iov_buffer_desc * iov,int iov_count,OM_uint32 type)206*ae771770SStanislav Sedov _gk_find_buffer(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
207*ae771770SStanislav Sedov {
208*ae771770SStanislav Sedov     int i;
209*ae771770SStanislav Sedov 
210*ae771770SStanislav Sedov     for (i = 0; i < iov_count; i++)
211*ae771770SStanislav Sedov 	if (type == GSS_IOV_BUFFER_TYPE(iov[i].type))
212*ae771770SStanislav Sedov 	    return &iov[i];
213*ae771770SStanislav Sedov     return NULL;
214*ae771770SStanislav Sedov }
215*ae771770SStanislav Sedov 
216*ae771770SStanislav Sedov OM_uint32
_gk_allocate_buffer(OM_uint32 * minor_status,gss_iov_buffer_desc * buffer,size_t size)217*ae771770SStanislav Sedov _gk_allocate_buffer(OM_uint32 *minor_status, gss_iov_buffer_desc *buffer, size_t size)
218*ae771770SStanislav Sedov {
219*ae771770SStanislav Sedov     if (buffer->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
220*ae771770SStanislav Sedov 	if (buffer->buffer.length == size)
221*ae771770SStanislav Sedov 	    return GSS_S_COMPLETE;
222*ae771770SStanislav Sedov 	free(buffer->buffer.value);
223*ae771770SStanislav Sedov     }
224*ae771770SStanislav Sedov 
225*ae771770SStanislav Sedov     buffer->buffer.value = malloc(size);
226*ae771770SStanislav Sedov     buffer->buffer.length = size;
227*ae771770SStanislav Sedov     if (buffer->buffer.value == NULL) {
228*ae771770SStanislav Sedov 	*minor_status = ENOMEM;
229*ae771770SStanislav Sedov 	return GSS_S_FAILURE;
230*ae771770SStanislav Sedov     }
231*ae771770SStanislav Sedov     buffer->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
232*ae771770SStanislav Sedov 
233*ae771770SStanislav Sedov     return GSS_S_COMPLETE;
234*ae771770SStanislav Sedov }
235*ae771770SStanislav Sedov 
236*ae771770SStanislav Sedov 
237*ae771770SStanislav Sedov OM_uint32
_gk_verify_buffers(OM_uint32 * minor_status,const gsskrb5_ctx ctx,const gss_iov_buffer_desc * header,const gss_iov_buffer_desc * padding,const gss_iov_buffer_desc * trailer)238*ae771770SStanislav Sedov _gk_verify_buffers(OM_uint32 *minor_status,
239*ae771770SStanislav Sedov 		   const gsskrb5_ctx ctx,
240*ae771770SStanislav Sedov 		   const gss_iov_buffer_desc *header,
241*ae771770SStanislav Sedov 		   const gss_iov_buffer_desc *padding,
242*ae771770SStanislav Sedov 		   const gss_iov_buffer_desc *trailer)
243*ae771770SStanislav Sedov {
244*ae771770SStanislav Sedov     if (header == NULL) {
245*ae771770SStanislav Sedov 	*minor_status = EINVAL;
246*ae771770SStanislav Sedov 	return GSS_S_FAILURE;
247*ae771770SStanislav Sedov     }
248*ae771770SStanislav Sedov 
249*ae771770SStanislav Sedov     if (IS_DCE_STYLE(ctx)) {
250*ae771770SStanislav Sedov 	/*
251*ae771770SStanislav Sedov 	 * In DCE style mode we reject having a padding or trailer buffer
252*ae771770SStanislav Sedov 	 */
253*ae771770SStanislav Sedov 	if (padding) {
254*ae771770SStanislav Sedov 	    *minor_status = EINVAL;
255*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
256*ae771770SStanislav Sedov 	}
257*ae771770SStanislav Sedov 	if (trailer) {
258*ae771770SStanislav Sedov 	    *minor_status = EINVAL;
259*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
260*ae771770SStanislav Sedov 	}
261*ae771770SStanislav Sedov     } else {
262*ae771770SStanislav Sedov 	/*
263*ae771770SStanislav Sedov 	 * In non-DCE style mode we require having a padding buffer
264*ae771770SStanislav Sedov 	 */
265*ae771770SStanislav Sedov 	if (padding == NULL) {
266*ae771770SStanislav Sedov 	    *minor_status = EINVAL;
267*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
268*ae771770SStanislav Sedov 	}
269*ae771770SStanislav Sedov     }
270*ae771770SStanislav Sedov 
271*ae771770SStanislav Sedov     *minor_status = 0;
272*ae771770SStanislav Sedov     return GSS_S_COMPLETE;
273*ae771770SStanislav Sedov }
274*ae771770SStanislav Sedov 
275*ae771770SStanislav Sedov #if 0
276*ae771770SStanislav Sedov OM_uint32
277*ae771770SStanislav Sedov _gssapi_wrap_cfx_iov(OM_uint32 *minor_status,
278*ae771770SStanislav Sedov 		     gsskrb5_ctx ctx,
279*ae771770SStanislav Sedov 		     krb5_context context,
280*ae771770SStanislav Sedov 		     int conf_req_flag,
281*ae771770SStanislav Sedov 		     int *conf_state,
282*ae771770SStanislav Sedov 		     gss_iov_buffer_desc *iov,
283*ae771770SStanislav Sedov 		     int iov_count)
284*ae771770SStanislav Sedov {
285*ae771770SStanislav Sedov     OM_uint32 major_status, junk;
286*ae771770SStanislav Sedov     gss_iov_buffer_desc *header, *trailer, *padding;
287*ae771770SStanislav Sedov     size_t gsshsize, k5hsize;
288*ae771770SStanislav Sedov     size_t gsstsize, k5tsize;
289*ae771770SStanislav Sedov     size_t rrc = 0, ec = 0;
290*ae771770SStanislav Sedov     int i;
291*ae771770SStanislav Sedov     gss_cfx_wrap_token token;
292*ae771770SStanislav Sedov     krb5_error_code ret;
293*ae771770SStanislav Sedov     int32_t seq_number;
294*ae771770SStanislav Sedov     unsigned usage;
295*ae771770SStanislav Sedov     krb5_crypto_iov *data = NULL;
296*ae771770SStanislav Sedov 
297*ae771770SStanislav Sedov     header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
298*ae771770SStanislav Sedov     if (header == NULL) {
299*ae771770SStanislav Sedov 	*minor_status = EINVAL;
300*ae771770SStanislav Sedov 	return GSS_S_FAILURE;
301*ae771770SStanislav Sedov     }
302*ae771770SStanislav Sedov 
303*ae771770SStanislav Sedov     padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
304*ae771770SStanislav Sedov     if (padding != NULL) {
305*ae771770SStanislav Sedov 	padding->buffer.length = 0;
306*ae771770SStanislav Sedov     }
307*ae771770SStanislav Sedov 
308*ae771770SStanislav Sedov     trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
309*ae771770SStanislav Sedov 
310*ae771770SStanislav Sedov     major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
311*ae771770SStanislav Sedov     if (major_status != GSS_S_COMPLETE) {
312*ae771770SStanislav Sedov 	    return major_status;
313*ae771770SStanislav Sedov     }
314*ae771770SStanislav Sedov 
315*ae771770SStanislav Sedov     if (conf_req_flag) {
316*ae771770SStanislav Sedov 	size_t k5psize = 0;
317*ae771770SStanislav Sedov 	size_t k5pbase = 0;
318*ae771770SStanislav Sedov 	size_t k5bsize = 0;
319*ae771770SStanislav Sedov 	size_t size = 0;
320*ae771770SStanislav Sedov 
321*ae771770SStanislav Sedov 	for (i = 0; i < iov_count; i++) {
322*ae771770SStanislav Sedov 	    switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
323*ae771770SStanislav Sedov 	    case GSS_IOV_BUFFER_TYPE_DATA:
324*ae771770SStanislav Sedov 		size += iov[i].buffer.length;
325*ae771770SStanislav Sedov 		break;
326*ae771770SStanislav Sedov 	    default:
327*ae771770SStanislav Sedov 		break;
328*ae771770SStanislav Sedov 	    }
329*ae771770SStanislav Sedov 	}
330*ae771770SStanislav Sedov 
331*ae771770SStanislav Sedov 	size += sizeof(gss_cfx_wrap_token_desc);
332*ae771770SStanislav Sedov 
333*ae771770SStanislav Sedov 	*minor_status = krb5_crypto_length(context, ctx->crypto,
334*ae771770SStanislav Sedov 					   KRB5_CRYPTO_TYPE_HEADER,
335*ae771770SStanislav Sedov 					   &k5hsize);
336*ae771770SStanislav Sedov 	if (*minor_status)
337*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
338*ae771770SStanislav Sedov 
339*ae771770SStanislav Sedov 	*minor_status = krb5_crypto_length(context, ctx->crypto,
340*ae771770SStanislav Sedov 					   KRB5_CRYPTO_TYPE_TRAILER,
341*ae771770SStanislav Sedov 					   &k5tsize);
342*ae771770SStanislav Sedov 	if (*minor_status)
343*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
344*ae771770SStanislav Sedov 
345*ae771770SStanislav Sedov 	*minor_status = krb5_crypto_length(context, ctx->crypto,
346*ae771770SStanislav Sedov 					   KRB5_CRYPTO_TYPE_PADDING,
347*ae771770SStanislav Sedov 					   &k5pbase);
348*ae771770SStanislav Sedov 	if (*minor_status)
349*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
350*ae771770SStanislav Sedov 
351*ae771770SStanislav Sedov 	if (k5pbase > 1) {
352*ae771770SStanislav Sedov 	    k5psize = k5pbase - (size % k5pbase);
353*ae771770SStanislav Sedov 	} else {
354*ae771770SStanislav Sedov 	    k5psize = 0;
355*ae771770SStanislav Sedov 	}
356*ae771770SStanislav Sedov 
357*ae771770SStanislav Sedov 	if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
358*ae771770SStanislav Sedov 	    *minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
359*ae771770SStanislav Sedov 						     &k5bsize);
360*ae771770SStanislav Sedov 	    if (*minor_status)
361*ae771770SStanislav Sedov 		return GSS_S_FAILURE;
362*ae771770SStanislav Sedov 	    ec = k5bsize;
363*ae771770SStanislav Sedov 	} else {
364*ae771770SStanislav Sedov 	    ec = k5psize;
365*ae771770SStanislav Sedov 	}
366*ae771770SStanislav Sedov 
367*ae771770SStanislav Sedov 	gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
368*ae771770SStanislav Sedov 	gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize;
369*ae771770SStanislav Sedov     } else {
370*ae771770SStanislav Sedov 	if (IS_DCE_STYLE(ctx)) {
371*ae771770SStanislav Sedov 	    *minor_status = EINVAL;
372*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
373*ae771770SStanislav Sedov 	}
374*ae771770SStanislav Sedov 
375*ae771770SStanislav Sedov 	k5hsize = 0;
376*ae771770SStanislav Sedov 	*minor_status = krb5_crypto_length(context, ctx->crypto,
377*ae771770SStanislav Sedov 					   KRB5_CRYPTO_TYPE_CHECKSUM,
378*ae771770SStanislav Sedov 					   &k5tsize);
379*ae771770SStanislav Sedov 	if (*minor_status)
380*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
381*ae771770SStanislav Sedov 
382*ae771770SStanislav Sedov 	gsshsize = sizeof(gss_cfx_wrap_token_desc);
383*ae771770SStanislav Sedov 	gsstsize = k5tsize;
384*ae771770SStanislav Sedov     }
385*ae771770SStanislav Sedov 
386*ae771770SStanislav Sedov     /*
387*ae771770SStanislav Sedov      *
388*ae771770SStanislav Sedov      */
389*ae771770SStanislav Sedov 
390*ae771770SStanislav Sedov     if (trailer == NULL) {
391*ae771770SStanislav Sedov 	rrc = gsstsize;
392*ae771770SStanislav Sedov 	if (IS_DCE_STYLE(ctx))
393*ae771770SStanislav Sedov 	    rrc -= ec;
394*ae771770SStanislav Sedov 	gsshsize += gsstsize;
395*ae771770SStanislav Sedov 	gsstsize = 0;
396*ae771770SStanislav Sedov     } else if (GSS_IOV_BUFFER_FLAGS(trailer->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
397*ae771770SStanislav Sedov 	major_status = _gk_allocate_buffer(minor_status, trailer, gsstsize);
398*ae771770SStanislav Sedov 	if (major_status)
399*ae771770SStanislav Sedov 	    goto failure;
400*ae771770SStanislav Sedov     } else if (trailer->buffer.length < gsstsize) {
401*ae771770SStanislav Sedov 	*minor_status = KRB5_BAD_MSIZE;
402*ae771770SStanislav Sedov 	major_status = GSS_S_FAILURE;
403*ae771770SStanislav Sedov 	goto failure;
404*ae771770SStanislav Sedov     } else
405*ae771770SStanislav Sedov 	trailer->buffer.length = gsstsize;
406*ae771770SStanislav Sedov 
407*ae771770SStanislav Sedov     /*
408*ae771770SStanislav Sedov      *
409*ae771770SStanislav Sedov      */
410*ae771770SStanislav Sedov 
411*ae771770SStanislav Sedov     if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
412*ae771770SStanislav Sedov 	major_status = _gk_allocate_buffer(minor_status, header, gsshsize);
413*ae771770SStanislav Sedov 	if (major_status != GSS_S_COMPLETE)
414*ae771770SStanislav Sedov 	    goto failure;
415*ae771770SStanislav Sedov     } else if (header->buffer.length < gsshsize) {
416*ae771770SStanislav Sedov 	*minor_status = KRB5_BAD_MSIZE;
417*ae771770SStanislav Sedov 	major_status = GSS_S_FAILURE;
418*ae771770SStanislav Sedov 	goto failure;
419*ae771770SStanislav Sedov     } else
420*ae771770SStanislav Sedov 	header->buffer.length = gsshsize;
421*ae771770SStanislav Sedov 
422*ae771770SStanislav Sedov     token = (gss_cfx_wrap_token)header->buffer.value;
423*ae771770SStanislav Sedov 
424*ae771770SStanislav Sedov     token->TOK_ID[0] = 0x05;
425*ae771770SStanislav Sedov     token->TOK_ID[1] = 0x04;
426*ae771770SStanislav Sedov     token->Flags     = 0;
427*ae771770SStanislav Sedov     token->Filler    = 0xFF;
428*ae771770SStanislav Sedov 
429*ae771770SStanislav Sedov     if ((ctx->more_flags & LOCAL) == 0)
430*ae771770SStanislav Sedov 	token->Flags |= CFXSentByAcceptor;
431*ae771770SStanislav Sedov 
432*ae771770SStanislav Sedov     if (ctx->more_flags & ACCEPTOR_SUBKEY)
433*ae771770SStanislav Sedov 	token->Flags |= CFXAcceptorSubkey;
434*ae771770SStanislav Sedov 
435*ae771770SStanislav Sedov     if (ctx->more_flags & LOCAL)
436*ae771770SStanislav Sedov 	usage = KRB5_KU_USAGE_INITIATOR_SEAL;
437*ae771770SStanislav Sedov     else
438*ae771770SStanislav Sedov 	usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
439*ae771770SStanislav Sedov 
440*ae771770SStanislav Sedov     if (conf_req_flag) {
441*ae771770SStanislav Sedov 	/*
442*ae771770SStanislav Sedov 	 * In Wrap tokens with confidentiality, the EC field is
443*ae771770SStanislav Sedov 	 * used to encode the size (in bytes) of the random filler.
444*ae771770SStanislav Sedov 	 */
445*ae771770SStanislav Sedov 	token->Flags |= CFXSealed;
446*ae771770SStanislav Sedov 	token->EC[0] = (ec >> 8) & 0xFF;
447*ae771770SStanislav Sedov 	token->EC[1] = (ec >> 0) & 0xFF;
448*ae771770SStanislav Sedov 
449*ae771770SStanislav Sedov     } else {
450*ae771770SStanislav Sedov 	/*
451*ae771770SStanislav Sedov 	 * In Wrap tokens without confidentiality, the EC field is
452*ae771770SStanislav Sedov 	 * used to encode the size (in bytes) of the trailing
453*ae771770SStanislav Sedov 	 * checksum.
454*ae771770SStanislav Sedov 	 *
455*ae771770SStanislav Sedov 	 * This is not used in the checksum calcuation itself,
456*ae771770SStanislav Sedov 	 * because the checksum length could potentially vary
457*ae771770SStanislav Sedov 	 * depending on the data length.
458*ae771770SStanislav Sedov 	 */
459*ae771770SStanislav Sedov 	token->EC[0] = 0;
460*ae771770SStanislav Sedov 	token->EC[1] = 0;
461*ae771770SStanislav Sedov     }
462*ae771770SStanislav Sedov 
463*ae771770SStanislav Sedov     /*
464*ae771770SStanislav Sedov      * In Wrap tokens that provide for confidentiality, the RRC
465*ae771770SStanislav Sedov      * field in the header contains the hex value 00 00 before
466*ae771770SStanislav Sedov      * encryption.
467*ae771770SStanislav Sedov      *
468*ae771770SStanislav Sedov      * In Wrap tokens that do not provide for confidentiality,
469*ae771770SStanislav Sedov      * both the EC and RRC fields in the appended checksum
470*ae771770SStanislav Sedov      * contain the hex value 00 00 for the purpose of calculating
471*ae771770SStanislav Sedov      * the checksum.
472*ae771770SStanislav Sedov      */
473*ae771770SStanislav Sedov     token->RRC[0] = 0;
474*ae771770SStanislav Sedov     token->RRC[1] = 0;
475*ae771770SStanislav Sedov 
476*ae771770SStanislav Sedov     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
477*ae771770SStanislav Sedov     krb5_auth_con_getlocalseqnumber(context,
478*ae771770SStanislav Sedov 				    ctx->auth_context,
479*ae771770SStanislav Sedov 				    &seq_number);
480*ae771770SStanislav Sedov     _gsskrb5_encode_be_om_uint32(0,          &token->SND_SEQ[0]);
481*ae771770SStanislav Sedov     _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
482*ae771770SStanislav Sedov     krb5_auth_con_setlocalseqnumber(context,
483*ae771770SStanislav Sedov 				    ctx->auth_context,
484*ae771770SStanislav Sedov 				    ++seq_number);
485*ae771770SStanislav Sedov     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
486*ae771770SStanislav Sedov 
487*ae771770SStanislav Sedov     data = calloc(iov_count + 3, sizeof(data[0]));
488*ae771770SStanislav Sedov     if (data == NULL) {
489*ae771770SStanislav Sedov 	*minor_status = ENOMEM;
490*ae771770SStanislav Sedov 	major_status = GSS_S_FAILURE;
491*ae771770SStanislav Sedov 	goto failure;
492*ae771770SStanislav Sedov     }
493*ae771770SStanislav Sedov 
494*ae771770SStanislav Sedov     if (conf_req_flag) {
495*ae771770SStanislav Sedov 	/*
496*ae771770SStanislav Sedov 	  plain packet:
497*ae771770SStanislav Sedov 
498*ae771770SStanislav Sedov 	  {"header" | encrypt(plaintext-data | ec-padding | E"header")}
499*ae771770SStanislav Sedov 
500*ae771770SStanislav Sedov 	  Expanded, this is with with RRC = 0:
501*ae771770SStanislav Sedov 
502*ae771770SStanislav Sedov 	  {"header" | krb5-header | plaintext-data | ec-padding | E"header" | krb5-trailer }
503*ae771770SStanislav Sedov 
504*ae771770SStanislav Sedov 	  In DCE-RPC mode == no trailer: RRC = gss "trailer" == length(ec-padding | E"header" | krb5-trailer)
505*ae771770SStanislav Sedov 
506*ae771770SStanislav Sedov 	  {"header" | ec-padding | E"header" | krb5-trailer | krb5-header | plaintext-data  }
507*ae771770SStanislav Sedov 	 */
508*ae771770SStanislav Sedov 
509*ae771770SStanislav Sedov 	i = 0;
510*ae771770SStanislav Sedov 	data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
511*ae771770SStanislav Sedov 	data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
512*ae771770SStanislav Sedov 	data[i].data.length = k5hsize;
513*ae771770SStanislav Sedov 
514*ae771770SStanislav Sedov 	for (i = 1; i < iov_count + 1; i++) {
515*ae771770SStanislav Sedov 	    switch (GSS_IOV_BUFFER_TYPE(iov[i - 1].type)) {
516*ae771770SStanislav Sedov 	    case GSS_IOV_BUFFER_TYPE_DATA:
517*ae771770SStanislav Sedov 		data[i].flags = KRB5_CRYPTO_TYPE_DATA;
518*ae771770SStanislav Sedov 		break;
519*ae771770SStanislav Sedov 	    case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
520*ae771770SStanislav Sedov 		data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
521*ae771770SStanislav Sedov 		break;
522*ae771770SStanislav Sedov 	    default:
523*ae771770SStanislav Sedov 		data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
524*ae771770SStanislav Sedov 		break;
525*ae771770SStanislav Sedov 	    }
526*ae771770SStanislav Sedov 	    data[i].data.length = iov[i - 1].buffer.length;
527*ae771770SStanislav Sedov 	    data[i].data.data = iov[i - 1].buffer.value;
528*ae771770SStanislav Sedov 	}
529*ae771770SStanislav Sedov 
530*ae771770SStanislav Sedov 	/*
531*ae771770SStanislav Sedov 	 * Any necessary padding is added here to ensure that the
532*ae771770SStanislav Sedov 	 * encrypted token header is always at the end of the
533*ae771770SStanislav Sedov 	 * ciphertext.
534*ae771770SStanislav Sedov 	 */
535*ae771770SStanislav Sedov 
536*ae771770SStanislav Sedov 	/* encrypted CFX header in trailer (or after the header if in
537*ae771770SStanislav Sedov 	   DCE mode). Copy in header into E"header"
538*ae771770SStanislav Sedov 	*/
539*ae771770SStanislav Sedov 	data[i].flags = KRB5_CRYPTO_TYPE_DATA;
540*ae771770SStanislav Sedov 	if (trailer)
541*ae771770SStanislav Sedov 	    data[i].data.data = trailer->buffer.value;
542*ae771770SStanislav Sedov 	else
543*ae771770SStanislav Sedov 	    data[i].data.data = ((uint8_t *)header->buffer.value) + sizeof(*token);
544*ae771770SStanislav Sedov 
545*ae771770SStanislav Sedov 	data[i].data.length = ec + sizeof(*token);
546*ae771770SStanislav Sedov 	memset(data[i].data.data, 0xFF, ec);
547*ae771770SStanislav Sedov 	memcpy(((uint8_t *)data[i].data.data) + ec, token, sizeof(*token));
548*ae771770SStanislav Sedov 	i++;
549*ae771770SStanislav Sedov 
550*ae771770SStanislav Sedov 	/* Kerberos trailer comes after the gss trailer */
551*ae771770SStanislav Sedov 	data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
552*ae771770SStanislav Sedov 	data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
553*ae771770SStanislav Sedov 	data[i].data.length = k5tsize;
554*ae771770SStanislav Sedov 	i++;
555*ae771770SStanislav Sedov 
556*ae771770SStanislav Sedov 	ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
557*ae771770SStanislav Sedov 	if (ret != 0) {
558*ae771770SStanislav Sedov 	    *minor_status = ret;
559*ae771770SStanislav Sedov 	    major_status = GSS_S_FAILURE;
560*ae771770SStanislav Sedov 	    goto failure;
561*ae771770SStanislav Sedov 	}
562*ae771770SStanislav Sedov 
563*ae771770SStanislav Sedov 	if (rrc) {
564*ae771770SStanislav Sedov 	    token->RRC[0] = (rrc >> 8) & 0xFF;
565*ae771770SStanislav Sedov 	    token->RRC[1] = (rrc >> 0) & 0xFF;
566*ae771770SStanislav Sedov 	}
567*ae771770SStanislav Sedov 
568*ae771770SStanislav Sedov     } else {
569*ae771770SStanislav Sedov 	/*
570*ae771770SStanislav Sedov 	  plain packet:
571*ae771770SStanislav Sedov 
572*ae771770SStanislav Sedov 	  {data | "header" | gss-trailer (krb5 checksum)
573*ae771770SStanislav Sedov 
574*ae771770SStanislav Sedov 	  don't do RRC != 0
575*ae771770SStanislav Sedov 
576*ae771770SStanislav Sedov 	 */
577*ae771770SStanislav Sedov 
578*ae771770SStanislav Sedov 	for (i = 0; i < iov_count; i++) {
579*ae771770SStanislav Sedov 	    switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
580*ae771770SStanislav Sedov 	    case GSS_IOV_BUFFER_TYPE_DATA:
581*ae771770SStanislav Sedov 		data[i].flags = KRB5_CRYPTO_TYPE_DATA;
582*ae771770SStanislav Sedov 		break;
583*ae771770SStanislav Sedov 	    case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
584*ae771770SStanislav Sedov 		data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
585*ae771770SStanislav Sedov 		break;
586*ae771770SStanislav Sedov 	    default:
587*ae771770SStanislav Sedov 		data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
588*ae771770SStanislav Sedov 		break;
589*ae771770SStanislav Sedov 	    }
590*ae771770SStanislav Sedov 	    data[i].data.length = iov[i].buffer.length;
591*ae771770SStanislav Sedov 	    data[i].data.data = iov[i].buffer.value;
592*ae771770SStanislav Sedov 	}
593*ae771770SStanislav Sedov 
594*ae771770SStanislav Sedov 	data[i].flags = KRB5_CRYPTO_TYPE_DATA;
595*ae771770SStanislav Sedov 	data[i].data.data = header->buffer.value;
596*ae771770SStanislav Sedov 	data[i].data.length = sizeof(gss_cfx_wrap_token_desc);
597*ae771770SStanislav Sedov 	i++;
598*ae771770SStanislav Sedov 
599*ae771770SStanislav Sedov 	data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
600*ae771770SStanislav Sedov 	if (trailer) {
601*ae771770SStanislav Sedov 		data[i].data.data = trailer->buffer.value;
602*ae771770SStanislav Sedov 	} else {
603*ae771770SStanislav Sedov 		data[i].data.data = (uint8_t *)header->buffer.value +
604*ae771770SStanislav Sedov 				     sizeof(gss_cfx_wrap_token_desc);
605*ae771770SStanislav Sedov 	}
606*ae771770SStanislav Sedov 	data[i].data.length = k5tsize;
607*ae771770SStanislav Sedov 	i++;
608*ae771770SStanislav Sedov 
609*ae771770SStanislav Sedov 	ret = krb5_create_checksum_iov(context, ctx->crypto, usage, data, i, NULL);
610*ae771770SStanislav Sedov 	if (ret) {
611*ae771770SStanislav Sedov 	    *minor_status = ret;
612*ae771770SStanislav Sedov 	    major_status = GSS_S_FAILURE;
613*ae771770SStanislav Sedov 	    goto failure;
614*ae771770SStanislav Sedov 	}
615*ae771770SStanislav Sedov 
616*ae771770SStanislav Sedov 	if (rrc) {
617*ae771770SStanislav Sedov 	    token->RRC[0] = (rrc >> 8) & 0xFF;
618*ae771770SStanislav Sedov 	    token->RRC[1] = (rrc >> 0) & 0xFF;
619*ae771770SStanislav Sedov 	}
620*ae771770SStanislav Sedov 
621*ae771770SStanislav Sedov 	token->EC[0] =  (k5tsize >> 8) & 0xFF;
622*ae771770SStanislav Sedov 	token->EC[1] =  (k5tsize >> 0) & 0xFF;
623*ae771770SStanislav Sedov     }
624*ae771770SStanislav Sedov 
625*ae771770SStanislav Sedov     if (conf_state != NULL)
626*ae771770SStanislav Sedov 	*conf_state = conf_req_flag;
627*ae771770SStanislav Sedov 
628*ae771770SStanislav Sedov     free(data);
629*ae771770SStanislav Sedov 
630*ae771770SStanislav Sedov     *minor_status = 0;
631*ae771770SStanislav Sedov     return GSS_S_COMPLETE;
632*ae771770SStanislav Sedov 
633*ae771770SStanislav Sedov  failure:
634*ae771770SStanislav Sedov     if (data)
635*ae771770SStanislav Sedov 	free(data);
636*ae771770SStanislav Sedov 
637*ae771770SStanislav Sedov     gss_release_iov_buffer(&junk, iov, iov_count);
638*ae771770SStanislav Sedov 
639*ae771770SStanislav Sedov     return major_status;
640*ae771770SStanislav Sedov }
641*ae771770SStanislav Sedov #endif
642*ae771770SStanislav Sedov 
643*ae771770SStanislav Sedov /* This is slowpath */
644*ae771770SStanislav Sedov static OM_uint32
unrotate_iov(OM_uint32 * minor_status,size_t rrc,gss_iov_buffer_desc * iov,int iov_count)645*ae771770SStanislav Sedov unrotate_iov(OM_uint32 *minor_status, size_t rrc, gss_iov_buffer_desc *iov, int iov_count)
646*ae771770SStanislav Sedov {
647*ae771770SStanislav Sedov     uint8_t *p, *q;
648*ae771770SStanislav Sedov     size_t len = 0, skip;
649*ae771770SStanislav Sedov     int i;
650*ae771770SStanislav Sedov 
651*ae771770SStanislav Sedov     for (i = 0; i < iov_count; i++)
652*ae771770SStanislav Sedov 	if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
653*ae771770SStanislav Sedov 	    GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
654*ae771770SStanislav Sedov 	    GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
655*ae771770SStanislav Sedov 	    len += iov[i].buffer.length;
656*ae771770SStanislav Sedov 
657*ae771770SStanislav Sedov     p = malloc(len);
658*ae771770SStanislav Sedov     if (p == NULL) {
659*ae771770SStanislav Sedov 	*minor_status = ENOMEM;
660*ae771770SStanislav Sedov 	return GSS_S_FAILURE;
661*ae771770SStanislav Sedov     }
662*ae771770SStanislav Sedov     q = p;
663*ae771770SStanislav Sedov 
664*ae771770SStanislav Sedov     /* copy up */
665*ae771770SStanislav Sedov 
666*ae771770SStanislav Sedov     for (i = 0; i < iov_count; i++) {
667*ae771770SStanislav Sedov 	if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
668*ae771770SStanislav Sedov 	    GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
669*ae771770SStanislav Sedov 	    GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
670*ae771770SStanislav Sedov 	{
671*ae771770SStanislav Sedov 	    memcpy(q, iov[i].buffer.value, iov[i].buffer.length);
672*ae771770SStanislav Sedov 	    q += iov[i].buffer.length;
673*ae771770SStanislav Sedov 	}
674*ae771770SStanislav Sedov     }
675*ae771770SStanislav Sedov     assert((size_t)(q - p) == len);
676*ae771770SStanislav Sedov 
677*ae771770SStanislav Sedov     /* unrotate first part */
678*ae771770SStanislav Sedov     q = p + rrc;
679*ae771770SStanislav Sedov     skip = rrc;
680*ae771770SStanislav Sedov     for (i = 0; i < iov_count; i++) {
681*ae771770SStanislav Sedov 	if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
682*ae771770SStanislav Sedov 	    GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
683*ae771770SStanislav Sedov 	    GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
684*ae771770SStanislav Sedov 	{
685*ae771770SStanislav Sedov 	    if (iov[i].buffer.length <= skip) {
686*ae771770SStanislav Sedov 		skip -= iov[i].buffer.length;
687*ae771770SStanislav Sedov 	    } else {
688*ae771770SStanislav Sedov 		memcpy(((uint8_t *)iov[i].buffer.value) + skip, q, iov[i].buffer.length - skip);
689*ae771770SStanislav Sedov 		q += iov[i].buffer.length - skip;
690*ae771770SStanislav Sedov 		skip = 0;
691*ae771770SStanislav Sedov 	    }
692*ae771770SStanislav Sedov 	}
693*ae771770SStanislav Sedov     }
694*ae771770SStanislav Sedov     /* copy trailer */
695*ae771770SStanislav Sedov     q = p;
696*ae771770SStanislav Sedov     skip = rrc;
697*ae771770SStanislav Sedov     for (i = 0; i < iov_count; i++) {
698*ae771770SStanislav Sedov 	if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
699*ae771770SStanislav Sedov 	    GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
700*ae771770SStanislav Sedov 	    GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
701*ae771770SStanislav Sedov 	{
702*ae771770SStanislav Sedov 	    memcpy(q, iov[i].buffer.value, min(iov[i].buffer.length, skip));
703*ae771770SStanislav Sedov 	    if (iov[i].buffer.length > skip)
704*ae771770SStanislav Sedov 		break;
705*ae771770SStanislav Sedov 	    skip -= iov[i].buffer.length;
706*ae771770SStanislav Sedov 	    q += iov[i].buffer.length;
707*ae771770SStanislav Sedov 	}
708*ae771770SStanislav Sedov     }
709*ae771770SStanislav Sedov     return GSS_S_COMPLETE;
710*ae771770SStanislav Sedov }
711*ae771770SStanislav Sedov 
712*ae771770SStanislav Sedov #if 0
713*ae771770SStanislav Sedov 
714*ae771770SStanislav Sedov OM_uint32
715*ae771770SStanislav Sedov _gssapi_unwrap_cfx_iov(OM_uint32 *minor_status,
716*ae771770SStanislav Sedov 		       gsskrb5_ctx ctx,
717*ae771770SStanislav Sedov 		       krb5_context context,
718*ae771770SStanislav Sedov 		       int *conf_state,
719*ae771770SStanislav Sedov 		       gss_qop_t *qop_state,
720*ae771770SStanislav Sedov 		       gss_iov_buffer_desc *iov,
721*ae771770SStanislav Sedov 		       int iov_count)
722*ae771770SStanislav Sedov {
723*ae771770SStanislav Sedov     OM_uint32 seq_number_lo, seq_number_hi, major_status, junk;
724*ae771770SStanislav Sedov     gss_iov_buffer_desc *header, *trailer, *padding;
725*ae771770SStanislav Sedov     gss_cfx_wrap_token token, ttoken;
726*ae771770SStanislav Sedov     u_char token_flags;
727*ae771770SStanislav Sedov     krb5_error_code ret;
728*ae771770SStanislav Sedov     unsigned usage;
729*ae771770SStanislav Sedov     uint16_t ec, rrc;
730*ae771770SStanislav Sedov     krb5_crypto_iov *data = NULL;
731*ae771770SStanislav Sedov     int i, j;
732*ae771770SStanislav Sedov 
733*ae771770SStanislav Sedov     *minor_status = 0;
734*ae771770SStanislav Sedov 
735*ae771770SStanislav Sedov     header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
736*ae771770SStanislav Sedov     if (header == NULL) {
737*ae771770SStanislav Sedov 	*minor_status = EINVAL;
738*ae771770SStanislav Sedov 	return GSS_S_FAILURE;
739*ae771770SStanislav Sedov     }
740*ae771770SStanislav Sedov 
741*ae771770SStanislav Sedov     if (header->buffer.length < sizeof(*token)) /* we check exact below */
742*ae771770SStanislav Sedov 	return GSS_S_DEFECTIVE_TOKEN;
743*ae771770SStanislav Sedov 
744*ae771770SStanislav Sedov     padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
745*ae771770SStanislav Sedov     if (padding != NULL && padding->buffer.length != 0) {
746*ae771770SStanislav Sedov 	*minor_status = EINVAL;
747*ae771770SStanislav Sedov 	return GSS_S_FAILURE;
748*ae771770SStanislav Sedov     }
749*ae771770SStanislav Sedov 
750*ae771770SStanislav Sedov     trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
751*ae771770SStanislav Sedov 
752*ae771770SStanislav Sedov     major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
753*ae771770SStanislav Sedov     if (major_status != GSS_S_COMPLETE) {
754*ae771770SStanislav Sedov 	    return major_status;
755*ae771770SStanislav Sedov     }
756*ae771770SStanislav Sedov 
757*ae771770SStanislav Sedov     token = (gss_cfx_wrap_token)header->buffer.value;
758*ae771770SStanislav Sedov 
759*ae771770SStanislav Sedov     if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04)
760*ae771770SStanislav Sedov 	return GSS_S_DEFECTIVE_TOKEN;
761*ae771770SStanislav Sedov 
762*ae771770SStanislav Sedov     /* Ignore unknown flags */
763*ae771770SStanislav Sedov     token_flags = token->Flags &
764*ae771770SStanislav Sedov 	(CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
765*ae771770SStanislav Sedov 
766*ae771770SStanislav Sedov     if (token_flags & CFXSentByAcceptor) {
767*ae771770SStanislav Sedov 	if ((ctx->more_flags & LOCAL) == 0)
768*ae771770SStanislav Sedov 	    return GSS_S_DEFECTIVE_TOKEN;
769*ae771770SStanislav Sedov     }
770*ae771770SStanislav Sedov 
771*ae771770SStanislav Sedov     if (ctx->more_flags & ACCEPTOR_SUBKEY) {
772*ae771770SStanislav Sedov 	if ((token_flags & CFXAcceptorSubkey) == 0)
773*ae771770SStanislav Sedov 	    return GSS_S_DEFECTIVE_TOKEN;
774*ae771770SStanislav Sedov     } else {
775*ae771770SStanislav Sedov 	if (token_flags & CFXAcceptorSubkey)
776*ae771770SStanislav Sedov 	    return GSS_S_DEFECTIVE_TOKEN;
777*ae771770SStanislav Sedov     }
778*ae771770SStanislav Sedov 
779*ae771770SStanislav Sedov     if (token->Filler != 0xFF)
780*ae771770SStanislav Sedov 	return GSS_S_DEFECTIVE_TOKEN;
781*ae771770SStanislav Sedov 
782*ae771770SStanislav Sedov     if (conf_state != NULL)
783*ae771770SStanislav Sedov 	*conf_state = (token_flags & CFXSealed) ? 1 : 0;
784*ae771770SStanislav Sedov 
785*ae771770SStanislav Sedov     ec  = (token->EC[0]  << 8) | token->EC[1];
786*ae771770SStanislav Sedov     rrc = (token->RRC[0] << 8) | token->RRC[1];
787*ae771770SStanislav Sedov 
788*ae771770SStanislav Sedov     /*
789*ae771770SStanislav Sedov      * Check sequence number
790*ae771770SStanislav Sedov      */
791*ae771770SStanislav Sedov     _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
792*ae771770SStanislav Sedov     _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
793*ae771770SStanislav Sedov     if (seq_number_hi) {
794*ae771770SStanislav Sedov 	/* no support for 64-bit sequence numbers */
795*ae771770SStanislav Sedov 	*minor_status = ERANGE;
796*ae771770SStanislav Sedov 	return GSS_S_UNSEQ_TOKEN;
797*ae771770SStanislav Sedov     }
798*ae771770SStanislav Sedov 
799*ae771770SStanislav Sedov     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
800*ae771770SStanislav Sedov     ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
801*ae771770SStanislav Sedov     if (ret != 0) {
802*ae771770SStanislav Sedov 	*minor_status = 0;
803*ae771770SStanislav Sedov 	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
804*ae771770SStanislav Sedov 	return ret;
805*ae771770SStanislav Sedov     }
806*ae771770SStanislav Sedov     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
807*ae771770SStanislav Sedov 
808*ae771770SStanislav Sedov     /*
809*ae771770SStanislav Sedov      * Decrypt and/or verify checksum
810*ae771770SStanislav Sedov      */
811*ae771770SStanislav Sedov 
812*ae771770SStanislav Sedov     if (ctx->more_flags & LOCAL) {
813*ae771770SStanislav Sedov 	usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
814*ae771770SStanislav Sedov     } else {
815*ae771770SStanislav Sedov 	usage = KRB5_KU_USAGE_INITIATOR_SEAL;
816*ae771770SStanislav Sedov     }
817*ae771770SStanislav Sedov 
818*ae771770SStanislav Sedov     data = calloc(iov_count + 3, sizeof(data[0]));
819*ae771770SStanislav Sedov     if (data == NULL) {
820*ae771770SStanislav Sedov 	*minor_status = ENOMEM;
821*ae771770SStanislav Sedov 	major_status = GSS_S_FAILURE;
822*ae771770SStanislav Sedov 	goto failure;
823*ae771770SStanislav Sedov     }
824*ae771770SStanislav Sedov 
825*ae771770SStanislav Sedov     if (token_flags & CFXSealed) {
826*ae771770SStanislav Sedov 	size_t k5tsize, k5hsize;
827*ae771770SStanislav Sedov 
828*ae771770SStanislav Sedov 	krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &k5hsize);
829*ae771770SStanislav Sedov 	krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5tsize);
830*ae771770SStanislav Sedov 
831*ae771770SStanislav Sedov 	/* Rotate by RRC; bogus to do this in-place XXX */
832*ae771770SStanislav Sedov 	/* Check RRC */
833*ae771770SStanislav Sedov 
834*ae771770SStanislav Sedov 	if (trailer == NULL) {
835*ae771770SStanislav Sedov 	    size_t gsstsize = k5tsize + sizeof(*token);
836*ae771770SStanislav Sedov 	    size_t gsshsize = k5hsize + sizeof(*token);
837*ae771770SStanislav Sedov 
838*ae771770SStanislav Sedov 	    if (rrc != gsstsize) {
839*ae771770SStanislav Sedov 		major_status = GSS_S_DEFECTIVE_TOKEN;
840*ae771770SStanislav Sedov 		goto failure;
841*ae771770SStanislav Sedov 	    }
842*ae771770SStanislav Sedov 
843*ae771770SStanislav Sedov 	    if (IS_DCE_STYLE(ctx))
844*ae771770SStanislav Sedov 		gsstsize += ec;
845*ae771770SStanislav Sedov 
846*ae771770SStanislav Sedov 	    gsshsize += gsstsize;
847*ae771770SStanislav Sedov 
848*ae771770SStanislav Sedov 	    if (header->buffer.length != gsshsize) {
849*ae771770SStanislav Sedov 		major_status = GSS_S_DEFECTIVE_TOKEN;
850*ae771770SStanislav Sedov 		goto failure;
851*ae771770SStanislav Sedov 	    }
852*ae771770SStanislav Sedov 	} else if (trailer->buffer.length != sizeof(*token) + k5tsize) {
853*ae771770SStanislav Sedov 	    major_status = GSS_S_DEFECTIVE_TOKEN;
854*ae771770SStanislav Sedov 	    goto failure;
855*ae771770SStanislav Sedov 	} else if (header->buffer.length != sizeof(*token) + k5hsize) {
856*ae771770SStanislav Sedov 	    major_status = GSS_S_DEFECTIVE_TOKEN;
857*ae771770SStanislav Sedov 	    goto failure;
858*ae771770SStanislav Sedov 	} else if (rrc != 0) {
859*ae771770SStanislav Sedov 	    /* go though slowpath */
860*ae771770SStanislav Sedov 	    major_status = unrotate_iov(minor_status, rrc, iov, iov_count);
861*ae771770SStanislav Sedov 	    if (major_status)
862*ae771770SStanislav Sedov 		goto failure;
863*ae771770SStanislav Sedov 	}
864*ae771770SStanislav Sedov 
865*ae771770SStanislav Sedov 	i = 0;
866*ae771770SStanislav Sedov 	data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
867*ae771770SStanislav Sedov 	data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
868*ae771770SStanislav Sedov 	data[i].data.length = k5hsize;
869*ae771770SStanislav Sedov 	i++;
870*ae771770SStanislav Sedov 
871*ae771770SStanislav Sedov 	for (j = 0; j < iov_count; i++, j++) {
872*ae771770SStanislav Sedov 	    switch (GSS_IOV_BUFFER_TYPE(iov[j].type)) {
873*ae771770SStanislav Sedov 	    case GSS_IOV_BUFFER_TYPE_DATA:
874*ae771770SStanislav Sedov 		data[i].flags = KRB5_CRYPTO_TYPE_DATA;
875*ae771770SStanislav Sedov 		break;
876*ae771770SStanislav Sedov 	    case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
877*ae771770SStanislav Sedov 		data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
878*ae771770SStanislav Sedov 		break;
879*ae771770SStanislav Sedov 	    default:
880*ae771770SStanislav Sedov 		data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
881*ae771770SStanislav Sedov 		break;
882*ae771770SStanislav Sedov 	    }
883*ae771770SStanislav Sedov 	    data[i].data.length = iov[j].buffer.length;
884*ae771770SStanislav Sedov 	    data[i].data.data = iov[j].buffer.value;
885*ae771770SStanislav Sedov 	}
886*ae771770SStanislav Sedov 
887*ae771770SStanislav Sedov 	/* encrypted CFX header in trailer (or after the header if in
888*ae771770SStanislav Sedov 	   DCE mode). Copy in header into E"header"
889*ae771770SStanislav Sedov 	*/
890*ae771770SStanislav Sedov 	data[i].flags = KRB5_CRYPTO_TYPE_DATA;
891*ae771770SStanislav Sedov 	if (trailer) {
892*ae771770SStanislav Sedov 	    data[i].data.data = trailer->buffer.value;
893*ae771770SStanislav Sedov 	} else {
894*ae771770SStanislav Sedov 	    data[i].data.data = ((uint8_t *)header->buffer.value) +
895*ae771770SStanislav Sedov 		header->buffer.length - k5hsize - k5tsize - ec- sizeof(*token);
896*ae771770SStanislav Sedov 	}
897*ae771770SStanislav Sedov 
898*ae771770SStanislav Sedov 	data[i].data.length = ec + sizeof(*token);
899*ae771770SStanislav Sedov 	ttoken = (gss_cfx_wrap_token)(((uint8_t *)data[i].data.data) + ec);
900*ae771770SStanislav Sedov 	i++;
901*ae771770SStanislav Sedov 
902*ae771770SStanislav Sedov 	/* Kerberos trailer comes after the gss trailer */
903*ae771770SStanislav Sedov 	data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
904*ae771770SStanislav Sedov 	data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
905*ae771770SStanislav Sedov 	data[i].data.length = k5tsize;
906*ae771770SStanislav Sedov 	i++;
907*ae771770SStanislav Sedov 
908*ae771770SStanislav Sedov 	ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
909*ae771770SStanislav Sedov 	if (ret != 0) {
910*ae771770SStanislav Sedov 	    *minor_status = ret;
911*ae771770SStanislav Sedov 	    major_status = GSS_S_FAILURE;
912*ae771770SStanislav Sedov 	    goto failure;
913*ae771770SStanislav Sedov 	}
914*ae771770SStanislav Sedov 
915*ae771770SStanislav Sedov 	ttoken->RRC[0] = token->RRC[0];
916*ae771770SStanislav Sedov 	ttoken->RRC[1] = token->RRC[1];
917*ae771770SStanislav Sedov 
918*ae771770SStanislav Sedov 	/* Check the integrity of the header */
919*ae771770SStanislav Sedov 	if (ct_memcmp(ttoken, token, sizeof(*token)) != 0) {
920*ae771770SStanislav Sedov 	    major_status = GSS_S_BAD_MIC;
921*ae771770SStanislav Sedov 	    goto failure;
922*ae771770SStanislav Sedov 	}
923*ae771770SStanislav Sedov     } else {
924*ae771770SStanislav Sedov 	size_t gsstsize = ec;
925*ae771770SStanislav Sedov 	size_t gsshsize = sizeof(*token);
926*ae771770SStanislav Sedov 
927*ae771770SStanislav Sedov 	if (trailer == NULL) {
928*ae771770SStanislav Sedov 	    /* Check RRC */
929*ae771770SStanislav Sedov 	    if (rrc != gsstsize) {
930*ae771770SStanislav Sedov 	       *minor_status = EINVAL;
931*ae771770SStanislav Sedov 	       major_status = GSS_S_FAILURE;
932*ae771770SStanislav Sedov 	       goto failure;
933*ae771770SStanislav Sedov 	    }
934*ae771770SStanislav Sedov 
935*ae771770SStanislav Sedov 	    gsshsize += gsstsize;
936*ae771770SStanislav Sedov 	    gsstsize = 0;
937*ae771770SStanislav Sedov 	} else if (trailer->buffer.length != gsstsize) {
938*ae771770SStanislav Sedov 	    major_status = GSS_S_DEFECTIVE_TOKEN;
939*ae771770SStanislav Sedov 	    goto failure;
940*ae771770SStanislav Sedov 	} else if (rrc != 0) {
941*ae771770SStanislav Sedov 	    /* Check RRC */
942*ae771770SStanislav Sedov 	    *minor_status = EINVAL;
943*ae771770SStanislav Sedov 	    major_status = GSS_S_FAILURE;
944*ae771770SStanislav Sedov 	    goto failure;
945*ae771770SStanislav Sedov 	}
946*ae771770SStanislav Sedov 
947*ae771770SStanislav Sedov 	if (header->buffer.length != gsshsize) {
948*ae771770SStanislav Sedov 	    major_status = GSS_S_DEFECTIVE_TOKEN;
949*ae771770SStanislav Sedov 	    goto failure;
950*ae771770SStanislav Sedov 	}
951*ae771770SStanislav Sedov 
952*ae771770SStanislav Sedov 	for (i = 0; i < iov_count; i++) {
953*ae771770SStanislav Sedov 	    switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
954*ae771770SStanislav Sedov 	    case GSS_IOV_BUFFER_TYPE_DATA:
955*ae771770SStanislav Sedov 		data[i].flags = KRB5_CRYPTO_TYPE_DATA;
956*ae771770SStanislav Sedov 		break;
957*ae771770SStanislav Sedov 	    case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
958*ae771770SStanislav Sedov 		data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
959*ae771770SStanislav Sedov 		break;
960*ae771770SStanislav Sedov 	    default:
961*ae771770SStanislav Sedov 		data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
962*ae771770SStanislav Sedov 		break;
963*ae771770SStanislav Sedov 	    }
964*ae771770SStanislav Sedov 	    data[i].data.length = iov[i].buffer.length;
965*ae771770SStanislav Sedov 	    data[i].data.data = iov[i].buffer.value;
966*ae771770SStanislav Sedov 	}
967*ae771770SStanislav Sedov 
968*ae771770SStanislav Sedov 	data[i].flags = KRB5_CRYPTO_TYPE_DATA;
969*ae771770SStanislav Sedov 	data[i].data.data = header->buffer.value;
970*ae771770SStanislav Sedov 	data[i].data.length = sizeof(*token);
971*ae771770SStanislav Sedov 	i++;
972*ae771770SStanislav Sedov 
973*ae771770SStanislav Sedov 	data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
974*ae771770SStanislav Sedov 	if (trailer) {
975*ae771770SStanislav Sedov 		data[i].data.data = trailer->buffer.value;
976*ae771770SStanislav Sedov 	} else {
977*ae771770SStanislav Sedov 		data[i].data.data = (uint8_t *)header->buffer.value +
978*ae771770SStanislav Sedov 				     sizeof(*token);
979*ae771770SStanislav Sedov 	}
980*ae771770SStanislav Sedov 	data[i].data.length = ec;
981*ae771770SStanislav Sedov 	i++;
982*ae771770SStanislav Sedov 
983*ae771770SStanislav Sedov 	token = (gss_cfx_wrap_token)header->buffer.value;
984*ae771770SStanislav Sedov 	token->EC[0]  = 0;
985*ae771770SStanislav Sedov 	token->EC[1]  = 0;
986*ae771770SStanislav Sedov 	token->RRC[0] = 0;
987*ae771770SStanislav Sedov 	token->RRC[1] = 0;
988*ae771770SStanislav Sedov 
989*ae771770SStanislav Sedov 	ret = krb5_verify_checksum_iov(context, ctx->crypto, usage, data, i, NULL);
990*ae771770SStanislav Sedov 	if (ret) {
991*ae771770SStanislav Sedov 	    *minor_status = ret;
992*ae771770SStanislav Sedov 	    major_status = GSS_S_FAILURE;
993*ae771770SStanislav Sedov 	    goto failure;
994*ae771770SStanislav Sedov 	}
995*ae771770SStanislav Sedov     }
996*ae771770SStanislav Sedov 
997*ae771770SStanislav Sedov     if (qop_state != NULL) {
998*ae771770SStanislav Sedov 	*qop_state = GSS_C_QOP_DEFAULT;
999*ae771770SStanislav Sedov     }
1000*ae771770SStanislav Sedov 
1001*ae771770SStanislav Sedov     free(data);
1002*ae771770SStanislav Sedov 
1003*ae771770SStanislav Sedov     *minor_status = 0;
1004*ae771770SStanislav Sedov     return GSS_S_COMPLETE;
1005*ae771770SStanislav Sedov 
1006*ae771770SStanislav Sedov  failure:
1007*ae771770SStanislav Sedov     if (data)
1008*ae771770SStanislav Sedov 	free(data);
1009*ae771770SStanislav Sedov 
1010*ae771770SStanislav Sedov     gss_release_iov_buffer(&junk, iov, iov_count);
1011*ae771770SStanislav Sedov 
1012*ae771770SStanislav Sedov     return major_status;
1013*ae771770SStanislav Sedov }
1014*ae771770SStanislav Sedov #endif
1015*ae771770SStanislav Sedov 
1016*ae771770SStanislav Sedov OM_uint32
_gssapi_wrap_iov_length_cfx(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)1017*ae771770SStanislav Sedov _gssapi_wrap_iov_length_cfx(OM_uint32 *minor_status,
1018*ae771770SStanislav Sedov 			    gsskrb5_ctx ctx,
1019c19800e8SDoug Rabson 			    krb5_context context,
1020c19800e8SDoug Rabson 			    int conf_req_flag,
1021c19800e8SDoug Rabson 			    gss_qop_t qop_req,
1022*ae771770SStanislav Sedov 			    int *conf_state,
1023*ae771770SStanislav Sedov 			    gss_iov_buffer_desc *iov,
1024*ae771770SStanislav Sedov 			    int iov_count)
1025*ae771770SStanislav Sedov {
1026*ae771770SStanislav Sedov     OM_uint32 major_status;
1027*ae771770SStanislav Sedov     size_t size;
1028*ae771770SStanislav Sedov     int i;
1029*ae771770SStanislav Sedov     gss_iov_buffer_desc *header = NULL;
1030*ae771770SStanislav Sedov     gss_iov_buffer_desc *padding = NULL;
1031*ae771770SStanislav Sedov     gss_iov_buffer_desc *trailer = NULL;
1032*ae771770SStanislav Sedov     size_t gsshsize = 0;
1033*ae771770SStanislav Sedov     size_t gsstsize = 0;
1034*ae771770SStanislav Sedov     size_t k5hsize = 0;
1035*ae771770SStanislav Sedov     size_t k5tsize = 0;
1036*ae771770SStanislav Sedov 
1037*ae771770SStanislav Sedov     GSSAPI_KRB5_INIT (&context);
1038*ae771770SStanislav Sedov     *minor_status = 0;
1039*ae771770SStanislav Sedov 
1040*ae771770SStanislav Sedov     for (size = 0, i = 0; i < iov_count; i++) {
1041*ae771770SStanislav Sedov 	switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
1042*ae771770SStanislav Sedov 	case GSS_IOV_BUFFER_TYPE_EMPTY:
1043*ae771770SStanislav Sedov 	    break;
1044*ae771770SStanislav Sedov 	case GSS_IOV_BUFFER_TYPE_DATA:
1045*ae771770SStanislav Sedov 	    size += iov[i].buffer.length;
1046*ae771770SStanislav Sedov 	    break;
1047*ae771770SStanislav Sedov 	case GSS_IOV_BUFFER_TYPE_HEADER:
1048*ae771770SStanislav Sedov 	    if (header != NULL) {
1049*ae771770SStanislav Sedov 		*minor_status = 0;
1050*ae771770SStanislav Sedov 		return GSS_S_FAILURE;
1051*ae771770SStanislav Sedov 	    }
1052*ae771770SStanislav Sedov 	    header = &iov[i];
1053*ae771770SStanislav Sedov 	    break;
1054*ae771770SStanislav Sedov 	case GSS_IOV_BUFFER_TYPE_TRAILER:
1055*ae771770SStanislav Sedov 	    if (trailer != NULL) {
1056*ae771770SStanislav Sedov 		*minor_status = 0;
1057*ae771770SStanislav Sedov 		return GSS_S_FAILURE;
1058*ae771770SStanislav Sedov 	    }
1059*ae771770SStanislav Sedov 	    trailer = &iov[i];
1060*ae771770SStanislav Sedov 	    break;
1061*ae771770SStanislav Sedov 	case GSS_IOV_BUFFER_TYPE_PADDING:
1062*ae771770SStanislav Sedov 	    if (padding != NULL) {
1063*ae771770SStanislav Sedov 		*minor_status = 0;
1064*ae771770SStanislav Sedov 		return GSS_S_FAILURE;
1065*ae771770SStanislav Sedov 	    }
1066*ae771770SStanislav Sedov 	    padding = &iov[i];
1067*ae771770SStanislav Sedov 	    break;
1068*ae771770SStanislav Sedov 	case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
1069*ae771770SStanislav Sedov 	    break;
1070*ae771770SStanislav Sedov 	default:
1071*ae771770SStanislav Sedov 	    *minor_status = EINVAL;
1072*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
1073*ae771770SStanislav Sedov 	}
1074*ae771770SStanislav Sedov     }
1075*ae771770SStanislav Sedov 
1076*ae771770SStanislav Sedov     major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
1077*ae771770SStanislav Sedov     if (major_status != GSS_S_COMPLETE) {
1078*ae771770SStanislav Sedov 	    return major_status;
1079*ae771770SStanislav Sedov     }
1080*ae771770SStanislav Sedov 
1081*ae771770SStanislav Sedov     if (conf_req_flag) {
1082*ae771770SStanislav Sedov 	size_t k5psize = 0;
1083*ae771770SStanislav Sedov 	size_t k5pbase = 0;
1084*ae771770SStanislav Sedov 	size_t k5bsize = 0;
1085*ae771770SStanislav Sedov 	size_t ec = 0;
1086*ae771770SStanislav Sedov 
1087*ae771770SStanislav Sedov 	size += sizeof(gss_cfx_wrap_token_desc);
1088*ae771770SStanislav Sedov 
1089*ae771770SStanislav Sedov 	*minor_status = krb5_crypto_length(context, ctx->crypto,
1090*ae771770SStanislav Sedov 					   KRB5_CRYPTO_TYPE_HEADER,
1091*ae771770SStanislav Sedov 					   &k5hsize);
1092*ae771770SStanislav Sedov 	if (*minor_status)
1093*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
1094*ae771770SStanislav Sedov 
1095*ae771770SStanislav Sedov 	*minor_status = krb5_crypto_length(context, ctx->crypto,
1096*ae771770SStanislav Sedov 					   KRB5_CRYPTO_TYPE_TRAILER,
1097*ae771770SStanislav Sedov 					   &k5tsize);
1098*ae771770SStanislav Sedov 	if (*minor_status)
1099*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
1100*ae771770SStanislav Sedov 
1101*ae771770SStanislav Sedov 	*minor_status = krb5_crypto_length(context, ctx->crypto,
1102*ae771770SStanislav Sedov 					   KRB5_CRYPTO_TYPE_PADDING,
1103*ae771770SStanislav Sedov 					   &k5pbase);
1104*ae771770SStanislav Sedov 	if (*minor_status)
1105*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
1106*ae771770SStanislav Sedov 
1107*ae771770SStanislav Sedov 	if (k5pbase > 1) {
1108*ae771770SStanislav Sedov 	    k5psize = k5pbase - (size % k5pbase);
1109*ae771770SStanislav Sedov 	} else {
1110*ae771770SStanislav Sedov 	    k5psize = 0;
1111*ae771770SStanislav Sedov 	}
1112*ae771770SStanislav Sedov 
1113*ae771770SStanislav Sedov 	if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
1114*ae771770SStanislav Sedov 	    *minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
1115*ae771770SStanislav Sedov 						     &k5bsize);
1116*ae771770SStanislav Sedov 	    if (*minor_status)
1117*ae771770SStanislav Sedov 		return GSS_S_FAILURE;
1118*ae771770SStanislav Sedov 
1119*ae771770SStanislav Sedov 	    ec = k5bsize;
1120*ae771770SStanislav Sedov 	} else {
1121*ae771770SStanislav Sedov 	    ec = k5psize;
1122*ae771770SStanislav Sedov 	}
1123*ae771770SStanislav Sedov 
1124*ae771770SStanislav Sedov 	gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
1125*ae771770SStanislav Sedov 	gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize;
1126*ae771770SStanislav Sedov     } else {
1127*ae771770SStanislav Sedov 	*minor_status = krb5_crypto_length(context, ctx->crypto,
1128*ae771770SStanislav Sedov 					   KRB5_CRYPTO_TYPE_CHECKSUM,
1129*ae771770SStanislav Sedov 					   &k5tsize);
1130*ae771770SStanislav Sedov 	if (*minor_status)
1131*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
1132*ae771770SStanislav Sedov 
1133*ae771770SStanislav Sedov 	gsshsize = sizeof(gss_cfx_wrap_token_desc);
1134*ae771770SStanislav Sedov 	gsstsize = k5tsize;
1135*ae771770SStanislav Sedov     }
1136*ae771770SStanislav Sedov 
1137*ae771770SStanislav Sedov     if (trailer != NULL) {
1138*ae771770SStanislav Sedov 	trailer->buffer.length = gsstsize;
1139*ae771770SStanislav Sedov     } else {
1140*ae771770SStanislav Sedov 	gsshsize += gsstsize;
1141*ae771770SStanislav Sedov     }
1142*ae771770SStanislav Sedov 
1143*ae771770SStanislav Sedov     header->buffer.length = gsshsize;
1144*ae771770SStanislav Sedov 
1145*ae771770SStanislav Sedov     if (padding) {
1146*ae771770SStanislav Sedov 	/* padding is done via EC and is contained in the header or trailer */
1147*ae771770SStanislav Sedov 	padding->buffer.length = 0;
1148*ae771770SStanislav Sedov     }
1149*ae771770SStanislav Sedov 
1150*ae771770SStanislav Sedov     if (conf_state) {
1151*ae771770SStanislav Sedov 	*conf_state = conf_req_flag;
1152*ae771770SStanislav Sedov     }
1153*ae771770SStanislav Sedov 
1154*ae771770SStanislav Sedov     return GSS_S_COMPLETE;
1155*ae771770SStanislav Sedov }
1156*ae771770SStanislav Sedov 
1157*ae771770SStanislav Sedov 
1158*ae771770SStanislav Sedov 
1159*ae771770SStanislav Sedov 
_gssapi_wrap_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer)1160*ae771770SStanislav Sedov OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
1161*ae771770SStanislav Sedov 			   const gsskrb5_ctx ctx,
1162*ae771770SStanislav Sedov 			   krb5_context context,
1163*ae771770SStanislav Sedov 			   int conf_req_flag,
1164c19800e8SDoug Rabson 			   const gss_buffer_t input_message_buffer,
1165c19800e8SDoug Rabson 			   int *conf_state,
1166*ae771770SStanislav Sedov 			   gss_buffer_t output_message_buffer)
1167c19800e8SDoug Rabson {
1168c19800e8SDoug Rabson     gss_cfx_wrap_token token;
1169c19800e8SDoug Rabson     krb5_error_code ret;
1170c19800e8SDoug Rabson     unsigned usage;
1171c19800e8SDoug Rabson     krb5_data cipher;
1172c19800e8SDoug Rabson     size_t wrapped_len, cksumsize;
1173c19800e8SDoug Rabson     uint16_t padlength, rrc = 0;
1174c19800e8SDoug Rabson     int32_t seq_number;
1175c19800e8SDoug Rabson     u_char *p;
1176c19800e8SDoug Rabson 
1177c19800e8SDoug Rabson     ret = _gsskrb5cfx_wrap_length_cfx(context,
1178*ae771770SStanislav Sedov 				      ctx->crypto, conf_req_flag,
1179*ae771770SStanislav Sedov 				      IS_DCE_STYLE(ctx),
1180c19800e8SDoug Rabson 				      input_message_buffer->length,
1181c19800e8SDoug Rabson 				      &wrapped_len, &cksumsize, &padlength);
1182c19800e8SDoug Rabson     if (ret != 0) {
1183c19800e8SDoug Rabson 	*minor_status = ret;
1184c19800e8SDoug Rabson 	return GSS_S_FAILURE;
1185c19800e8SDoug Rabson     }
1186c19800e8SDoug Rabson 
1187c19800e8SDoug Rabson     /* Always rotate encrypted token (if any) and checksum to header */
1188c19800e8SDoug Rabson     rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize;
1189c19800e8SDoug Rabson 
1190c19800e8SDoug Rabson     output_message_buffer->length = wrapped_len;
1191c19800e8SDoug Rabson     output_message_buffer->value = malloc(output_message_buffer->length);
1192c19800e8SDoug Rabson     if (output_message_buffer->value == NULL) {
1193c19800e8SDoug Rabson 	*minor_status = ENOMEM;
1194c19800e8SDoug Rabson 	return GSS_S_FAILURE;
1195c19800e8SDoug Rabson     }
1196c19800e8SDoug Rabson 
1197c19800e8SDoug Rabson     p = output_message_buffer->value;
1198c19800e8SDoug Rabson     token = (gss_cfx_wrap_token)p;
1199c19800e8SDoug Rabson     token->TOK_ID[0] = 0x05;
1200c19800e8SDoug Rabson     token->TOK_ID[1] = 0x04;
1201c19800e8SDoug Rabson     token->Flags     = 0;
1202c19800e8SDoug Rabson     token->Filler    = 0xFF;
1203*ae771770SStanislav Sedov     if ((ctx->more_flags & LOCAL) == 0)
1204c19800e8SDoug Rabson 	token->Flags |= CFXSentByAcceptor;
1205*ae771770SStanislav Sedov     if (ctx->more_flags & ACCEPTOR_SUBKEY)
1206c19800e8SDoug Rabson 	token->Flags |= CFXAcceptorSubkey;
1207c19800e8SDoug Rabson     if (conf_req_flag) {
1208c19800e8SDoug Rabson 	/*
1209c19800e8SDoug Rabson 	 * In Wrap tokens with confidentiality, the EC field is
1210c19800e8SDoug Rabson 	 * used to encode the size (in bytes) of the random filler.
1211c19800e8SDoug Rabson 	 */
1212c19800e8SDoug Rabson 	token->Flags |= CFXSealed;
1213c19800e8SDoug Rabson 	token->EC[0] = (padlength >> 8) & 0xFF;
1214c19800e8SDoug Rabson 	token->EC[1] = (padlength >> 0) & 0xFF;
1215c19800e8SDoug Rabson     } else {
1216c19800e8SDoug Rabson 	/*
1217c19800e8SDoug Rabson 	 * In Wrap tokens without confidentiality, the EC field is
1218c19800e8SDoug Rabson 	 * used to encode the size (in bytes) of the trailing
1219c19800e8SDoug Rabson 	 * checksum.
1220c19800e8SDoug Rabson 	 *
1221c19800e8SDoug Rabson 	 * This is not used in the checksum calcuation itself,
1222c19800e8SDoug Rabson 	 * because the checksum length could potentially vary
1223c19800e8SDoug Rabson 	 * depending on the data length.
1224c19800e8SDoug Rabson 	 */
1225c19800e8SDoug Rabson 	token->EC[0] = 0;
1226c19800e8SDoug Rabson 	token->EC[1] = 0;
1227c19800e8SDoug Rabson     }
1228c19800e8SDoug Rabson 
1229c19800e8SDoug Rabson     /*
1230c19800e8SDoug Rabson      * In Wrap tokens that provide for confidentiality, the RRC
1231c19800e8SDoug Rabson      * field in the header contains the hex value 00 00 before
1232c19800e8SDoug Rabson      * encryption.
1233c19800e8SDoug Rabson      *
1234c19800e8SDoug Rabson      * In Wrap tokens that do not provide for confidentiality,
1235c19800e8SDoug Rabson      * both the EC and RRC fields in the appended checksum
1236c19800e8SDoug Rabson      * contain the hex value 00 00 for the purpose of calculating
1237c19800e8SDoug Rabson      * the checksum.
1238c19800e8SDoug Rabson      */
1239c19800e8SDoug Rabson     token->RRC[0] = 0;
1240c19800e8SDoug Rabson     token->RRC[1] = 0;
1241c19800e8SDoug Rabson 
1242*ae771770SStanislav Sedov     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1243c19800e8SDoug Rabson     krb5_auth_con_getlocalseqnumber(context,
1244*ae771770SStanislav Sedov 				    ctx->auth_context,
1245c19800e8SDoug Rabson 				    &seq_number);
1246c19800e8SDoug Rabson     _gsskrb5_encode_be_om_uint32(0,          &token->SND_SEQ[0]);
1247c19800e8SDoug Rabson     _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
1248c19800e8SDoug Rabson     krb5_auth_con_setlocalseqnumber(context,
1249*ae771770SStanislav Sedov 				    ctx->auth_context,
1250c19800e8SDoug Rabson 				    ++seq_number);
1251*ae771770SStanislav Sedov     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1252c19800e8SDoug Rabson 
1253c19800e8SDoug Rabson     /*
1254c19800e8SDoug Rabson      * If confidentiality is requested, the token header is
1255c19800e8SDoug Rabson      * appended to the plaintext before encryption; the resulting
1256c19800e8SDoug Rabson      * token is {"header" | encrypt(plaintext | pad | "header")}.
1257c19800e8SDoug Rabson      *
1258c19800e8SDoug Rabson      * If no confidentiality is requested, the checksum is
1259c19800e8SDoug Rabson      * calculated over the plaintext concatenated with the
1260c19800e8SDoug Rabson      * token header.
1261c19800e8SDoug Rabson      */
1262*ae771770SStanislav Sedov     if (ctx->more_flags & LOCAL) {
1263c19800e8SDoug Rabson 	usage = KRB5_KU_USAGE_INITIATOR_SEAL;
1264c19800e8SDoug Rabson     } else {
1265c19800e8SDoug Rabson 	usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
1266c19800e8SDoug Rabson     }
1267c19800e8SDoug Rabson 
1268c19800e8SDoug Rabson     if (conf_req_flag) {
1269c19800e8SDoug Rabson 	/*
1270c19800e8SDoug Rabson 	 * Any necessary padding is added here to ensure that the
1271c19800e8SDoug Rabson 	 * encrypted token header is always at the end of the
1272c19800e8SDoug Rabson 	 * ciphertext.
1273c19800e8SDoug Rabson 	 *
1274c19800e8SDoug Rabson 	 * The specification does not require that the padding
1275c19800e8SDoug Rabson 	 * bytes are initialized.
1276c19800e8SDoug Rabson 	 */
1277c19800e8SDoug Rabson 	p += sizeof(*token);
1278c19800e8SDoug Rabson 	memcpy(p, input_message_buffer->value, input_message_buffer->length);
1279c19800e8SDoug Rabson 	memset(p + input_message_buffer->length, 0xFF, padlength);
1280c19800e8SDoug Rabson 	memcpy(p + input_message_buffer->length + padlength,
1281c19800e8SDoug Rabson 	       token, sizeof(*token));
1282c19800e8SDoug Rabson 
1283*ae771770SStanislav Sedov 	ret = krb5_encrypt(context, ctx->crypto,
1284c19800e8SDoug Rabson 			   usage, p,
1285c19800e8SDoug Rabson 			   input_message_buffer->length + padlength +
1286c19800e8SDoug Rabson 				sizeof(*token),
1287c19800e8SDoug Rabson 			   &cipher);
1288c19800e8SDoug Rabson 	if (ret != 0) {
1289c19800e8SDoug Rabson 	    *minor_status = ret;
1290c19800e8SDoug Rabson 	    _gsskrb5_release_buffer(minor_status, output_message_buffer);
1291c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
1292c19800e8SDoug Rabson 	}
1293c19800e8SDoug Rabson 	assert(sizeof(*token) + cipher.length == wrapped_len);
1294c19800e8SDoug Rabson 	token->RRC[0] = (rrc >> 8) & 0xFF;
1295c19800e8SDoug Rabson 	token->RRC[1] = (rrc >> 0) & 0xFF;
1296c19800e8SDoug Rabson 
1297*ae771770SStanislav Sedov 	/*
1298*ae771770SStanislav Sedov 	 * this is really ugly, but needed against windows
1299*ae771770SStanislav Sedov 	 * for DCERPC, as windows rotates by EC+RRC.
1300*ae771770SStanislav Sedov 	 */
1301*ae771770SStanislav Sedov 	if (IS_DCE_STYLE(ctx)) {
1302*ae771770SStanislav Sedov 		ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE);
1303*ae771770SStanislav Sedov 	} else {
1304c19800e8SDoug Rabson 		ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);
1305*ae771770SStanislav Sedov 	}
1306c19800e8SDoug Rabson 	if (ret != 0) {
1307c19800e8SDoug Rabson 	    *minor_status = ret;
1308c19800e8SDoug Rabson 	    _gsskrb5_release_buffer(minor_status, output_message_buffer);
1309c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
1310c19800e8SDoug Rabson 	}
1311c19800e8SDoug Rabson 	memcpy(p, cipher.data, cipher.length);
1312c19800e8SDoug Rabson 	krb5_data_free(&cipher);
1313c19800e8SDoug Rabson     } else {
1314c19800e8SDoug Rabson 	char *buf;
1315c19800e8SDoug Rabson 	Checksum cksum;
1316c19800e8SDoug Rabson 
1317c19800e8SDoug Rabson 	buf = malloc(input_message_buffer->length + sizeof(*token));
1318c19800e8SDoug Rabson 	if (buf == NULL) {
1319c19800e8SDoug Rabson 	    *minor_status = ENOMEM;
1320c19800e8SDoug Rabson 	    _gsskrb5_release_buffer(minor_status, output_message_buffer);
1321c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
1322c19800e8SDoug Rabson 	}
1323c19800e8SDoug Rabson 	memcpy(buf, input_message_buffer->value, input_message_buffer->length);
1324c19800e8SDoug Rabson 	memcpy(buf + input_message_buffer->length, token, sizeof(*token));
1325c19800e8SDoug Rabson 
1326*ae771770SStanislav Sedov 	ret = krb5_create_checksum(context, ctx->crypto,
1327c19800e8SDoug Rabson 				   usage, 0, buf,
1328c19800e8SDoug Rabson 				   input_message_buffer->length +
1329c19800e8SDoug Rabson 					sizeof(*token),
1330c19800e8SDoug Rabson 				   &cksum);
1331c19800e8SDoug Rabson 	if (ret != 0) {
1332c19800e8SDoug Rabson 	    *minor_status = ret;
1333c19800e8SDoug Rabson 	    _gsskrb5_release_buffer(minor_status, output_message_buffer);
1334c19800e8SDoug Rabson 	    free(buf);
1335c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
1336c19800e8SDoug Rabson 	}
1337c19800e8SDoug Rabson 
1338c19800e8SDoug Rabson 	free(buf);
1339c19800e8SDoug Rabson 
1340c19800e8SDoug Rabson 	assert(cksum.checksum.length == cksumsize);
1341c19800e8SDoug Rabson 	token->EC[0] =  (cksum.checksum.length >> 8) & 0xFF;
1342c19800e8SDoug Rabson 	token->EC[1] =  (cksum.checksum.length >> 0) & 0xFF;
1343c19800e8SDoug Rabson 	token->RRC[0] = (rrc >> 8) & 0xFF;
1344c19800e8SDoug Rabson 	token->RRC[1] = (rrc >> 0) & 0xFF;
1345c19800e8SDoug Rabson 
1346c19800e8SDoug Rabson 	p += sizeof(*token);
1347c19800e8SDoug Rabson 	memcpy(p, input_message_buffer->value, input_message_buffer->length);
1348c19800e8SDoug Rabson 	memcpy(p + input_message_buffer->length,
1349c19800e8SDoug Rabson 	       cksum.checksum.data, cksum.checksum.length);
1350c19800e8SDoug Rabson 
1351c19800e8SDoug Rabson 	ret = rrc_rotate(p,
1352c19800e8SDoug Rabson 	    input_message_buffer->length + cksum.checksum.length, rrc, FALSE);
1353c19800e8SDoug Rabson 	if (ret != 0) {
1354c19800e8SDoug Rabson 	    *minor_status = ret;
1355c19800e8SDoug Rabson 	    _gsskrb5_release_buffer(minor_status, output_message_buffer);
1356c19800e8SDoug Rabson 	    free_Checksum(&cksum);
1357c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
1358c19800e8SDoug Rabson 	}
1359c19800e8SDoug Rabson 	free_Checksum(&cksum);
1360c19800e8SDoug Rabson     }
1361c19800e8SDoug Rabson 
1362c19800e8SDoug Rabson     if (conf_state != NULL) {
1363c19800e8SDoug Rabson 	*conf_state = conf_req_flag;
1364c19800e8SDoug Rabson     }
1365c19800e8SDoug Rabson 
1366c19800e8SDoug Rabson     *minor_status = 0;
1367c19800e8SDoug Rabson     return GSS_S_COMPLETE;
1368c19800e8SDoug Rabson }
1369c19800e8SDoug Rabson 
_gssapi_unwrap_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,const gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state)1370c19800e8SDoug Rabson OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
1371*ae771770SStanislav Sedov 			     const gsskrb5_ctx ctx,
1372c19800e8SDoug Rabson 			     krb5_context context,
1373c19800e8SDoug Rabson 			     const gss_buffer_t input_message_buffer,
1374c19800e8SDoug Rabson 			     gss_buffer_t output_message_buffer,
1375c19800e8SDoug Rabson 			     int *conf_state,
1376*ae771770SStanislav Sedov 			     gss_qop_t *qop_state)
1377c19800e8SDoug Rabson {
1378c19800e8SDoug Rabson     gss_cfx_wrap_token token;
1379c19800e8SDoug Rabson     u_char token_flags;
1380c19800e8SDoug Rabson     krb5_error_code ret;
1381c19800e8SDoug Rabson     unsigned usage;
1382c19800e8SDoug Rabson     krb5_data data;
1383c19800e8SDoug Rabson     uint16_t ec, rrc;
1384c19800e8SDoug Rabson     OM_uint32 seq_number_lo, seq_number_hi;
1385c19800e8SDoug Rabson     size_t len;
1386c19800e8SDoug Rabson     u_char *p;
1387c19800e8SDoug Rabson 
1388c19800e8SDoug Rabson     *minor_status = 0;
1389c19800e8SDoug Rabson 
1390c19800e8SDoug Rabson     if (input_message_buffer->length < sizeof(*token)) {
1391c19800e8SDoug Rabson 	return GSS_S_DEFECTIVE_TOKEN;
1392c19800e8SDoug Rabson     }
1393c19800e8SDoug Rabson 
1394c19800e8SDoug Rabson     p = input_message_buffer->value;
1395c19800e8SDoug Rabson 
1396c19800e8SDoug Rabson     token = (gss_cfx_wrap_token)p;
1397c19800e8SDoug Rabson 
1398c19800e8SDoug Rabson     if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) {
1399c19800e8SDoug Rabson 	return GSS_S_DEFECTIVE_TOKEN;
1400c19800e8SDoug Rabson     }
1401c19800e8SDoug Rabson 
1402c19800e8SDoug Rabson     /* Ignore unknown flags */
1403c19800e8SDoug Rabson     token_flags = token->Flags &
1404c19800e8SDoug Rabson 	(CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
1405c19800e8SDoug Rabson 
1406c19800e8SDoug Rabson     if (token_flags & CFXSentByAcceptor) {
1407*ae771770SStanislav Sedov 	if ((ctx->more_flags & LOCAL) == 0)
1408c19800e8SDoug Rabson 	    return GSS_S_DEFECTIVE_TOKEN;
1409c19800e8SDoug Rabson     }
1410c19800e8SDoug Rabson 
1411*ae771770SStanislav Sedov     if (ctx->more_flags & ACCEPTOR_SUBKEY) {
1412c19800e8SDoug Rabson 	if ((token_flags & CFXAcceptorSubkey) == 0)
1413c19800e8SDoug Rabson 	    return GSS_S_DEFECTIVE_TOKEN;
1414c19800e8SDoug Rabson     } else {
1415c19800e8SDoug Rabson 	if (token_flags & CFXAcceptorSubkey)
1416c19800e8SDoug Rabson 	    return GSS_S_DEFECTIVE_TOKEN;
1417c19800e8SDoug Rabson     }
1418c19800e8SDoug Rabson 
1419c19800e8SDoug Rabson     if (token->Filler != 0xFF) {
1420c19800e8SDoug Rabson 	return GSS_S_DEFECTIVE_TOKEN;
1421c19800e8SDoug Rabson     }
1422c19800e8SDoug Rabson 
1423c19800e8SDoug Rabson     if (conf_state != NULL) {
1424c19800e8SDoug Rabson 	*conf_state = (token_flags & CFXSealed) ? 1 : 0;
1425c19800e8SDoug Rabson     }
1426c19800e8SDoug Rabson 
1427c19800e8SDoug Rabson     ec  = (token->EC[0]  << 8) | token->EC[1];
1428c19800e8SDoug Rabson     rrc = (token->RRC[0] << 8) | token->RRC[1];
1429c19800e8SDoug Rabson 
1430c19800e8SDoug Rabson     /*
1431c19800e8SDoug Rabson      * Check sequence number
1432c19800e8SDoug Rabson      */
1433c19800e8SDoug Rabson     _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
1434c19800e8SDoug Rabson     _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
1435c19800e8SDoug Rabson     if (seq_number_hi) {
1436c19800e8SDoug Rabson 	/* no support for 64-bit sequence numbers */
1437c19800e8SDoug Rabson 	*minor_status = ERANGE;
1438c19800e8SDoug Rabson 	return GSS_S_UNSEQ_TOKEN;
1439c19800e8SDoug Rabson     }
1440c19800e8SDoug Rabson 
1441*ae771770SStanislav Sedov     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1442*ae771770SStanislav Sedov     ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
1443c19800e8SDoug Rabson     if (ret != 0) {
1444c19800e8SDoug Rabson 	*minor_status = 0;
1445*ae771770SStanislav Sedov 	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1446c19800e8SDoug Rabson 	_gsskrb5_release_buffer(minor_status, output_message_buffer);
1447c19800e8SDoug Rabson 	return ret;
1448c19800e8SDoug Rabson     }
1449*ae771770SStanislav Sedov     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1450c19800e8SDoug Rabson 
1451c19800e8SDoug Rabson     /*
1452c19800e8SDoug Rabson      * Decrypt and/or verify checksum
1453c19800e8SDoug Rabson      */
1454c19800e8SDoug Rabson 
1455*ae771770SStanislav Sedov     if (ctx->more_flags & LOCAL) {
1456c19800e8SDoug Rabson 	usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
1457c19800e8SDoug Rabson     } else {
1458c19800e8SDoug Rabson 	usage = KRB5_KU_USAGE_INITIATOR_SEAL;
1459c19800e8SDoug Rabson     }
1460c19800e8SDoug Rabson 
1461c19800e8SDoug Rabson     p += sizeof(*token);
1462c19800e8SDoug Rabson     len = input_message_buffer->length;
1463c19800e8SDoug Rabson     len -= (p - (u_char *)input_message_buffer->value);
1464c19800e8SDoug Rabson 
1465*ae771770SStanislav Sedov     if (token_flags & CFXSealed) {
1466*ae771770SStanislav Sedov 	/*
1467*ae771770SStanislav Sedov 	 * this is really ugly, but needed against windows
1468*ae771770SStanislav Sedov 	 * for DCERPC, as windows rotates by EC+RRC.
1469*ae771770SStanislav Sedov 	 */
1470*ae771770SStanislav Sedov 	if (IS_DCE_STYLE(ctx)) {
1471*ae771770SStanislav Sedov 		*minor_status = rrc_rotate(p, len, rrc+ec, TRUE);
1472*ae771770SStanislav Sedov 	} else {
1473c19800e8SDoug Rabson 		*minor_status = rrc_rotate(p, len, rrc, TRUE);
1474*ae771770SStanislav Sedov 	}
1475c19800e8SDoug Rabson 	if (*minor_status != 0) {
1476c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
1477c19800e8SDoug Rabson 	}
1478c19800e8SDoug Rabson 
1479*ae771770SStanislav Sedov 	ret = krb5_decrypt(context, ctx->crypto, usage,
1480c19800e8SDoug Rabson 	    p, len, &data);
1481c19800e8SDoug Rabson 	if (ret != 0) {
1482c19800e8SDoug Rabson 	    *minor_status = ret;
1483c19800e8SDoug Rabson 	    return GSS_S_BAD_MIC;
1484c19800e8SDoug Rabson 	}
1485c19800e8SDoug Rabson 
1486c19800e8SDoug Rabson 	/* Check that there is room for the pad and token header */
1487c19800e8SDoug Rabson 	if (data.length < ec + sizeof(*token)) {
1488c19800e8SDoug Rabson 	    krb5_data_free(&data);
1489c19800e8SDoug Rabson 	    return GSS_S_DEFECTIVE_TOKEN;
1490c19800e8SDoug Rabson 	}
1491c19800e8SDoug Rabson 	p = data.data;
1492c19800e8SDoug Rabson 	p += data.length - sizeof(*token);
1493c19800e8SDoug Rabson 
1494c19800e8SDoug Rabson 	/* RRC is unprotected; don't modify input buffer */
1495c19800e8SDoug Rabson 	((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0];
1496c19800e8SDoug Rabson 	((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1];
1497c19800e8SDoug Rabson 
1498c19800e8SDoug Rabson 	/* Check the integrity of the header */
1499*ae771770SStanislav Sedov 	if (ct_memcmp(p, token, sizeof(*token)) != 0) {
1500c19800e8SDoug Rabson 	    krb5_data_free(&data);
1501c19800e8SDoug Rabson 	    return GSS_S_BAD_MIC;
1502c19800e8SDoug Rabson 	}
1503c19800e8SDoug Rabson 
1504c19800e8SDoug Rabson 	output_message_buffer->value = data.data;
1505c19800e8SDoug Rabson 	output_message_buffer->length = data.length - ec - sizeof(*token);
1506c19800e8SDoug Rabson     } else {
1507c19800e8SDoug Rabson 	Checksum cksum;
1508c19800e8SDoug Rabson 
1509*ae771770SStanislav Sedov 	/* Rotate by RRC; bogus to do this in-place XXX */
1510*ae771770SStanislav Sedov 	*minor_status = rrc_rotate(p, len, rrc, TRUE);
1511*ae771770SStanislav Sedov 	if (*minor_status != 0) {
1512*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
1513*ae771770SStanislav Sedov 	}
1514*ae771770SStanislav Sedov 
1515c19800e8SDoug Rabson 	/* Determine checksum type */
1516c19800e8SDoug Rabson 	ret = krb5_crypto_get_checksum_type(context,
1517*ae771770SStanislav Sedov 					    ctx->crypto,
1518*ae771770SStanislav Sedov 					    &cksum.cksumtype);
1519c19800e8SDoug Rabson 	if (ret != 0) {
1520c19800e8SDoug Rabson 	    *minor_status = ret;
1521c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
1522c19800e8SDoug Rabson 	}
1523c19800e8SDoug Rabson 
1524c19800e8SDoug Rabson 	cksum.checksum.length = ec;
1525c19800e8SDoug Rabson 
1526c19800e8SDoug Rabson 	/* Check we have at least as much data as the checksum */
1527c19800e8SDoug Rabson 	if (len < cksum.checksum.length) {
1528c19800e8SDoug Rabson 	    *minor_status = ERANGE;
1529c19800e8SDoug Rabson 	    return GSS_S_BAD_MIC;
1530c19800e8SDoug Rabson 	}
1531c19800e8SDoug Rabson 
1532c19800e8SDoug Rabson 	/* Length now is of the plaintext only, no checksum */
1533c19800e8SDoug Rabson 	len -= cksum.checksum.length;
1534c19800e8SDoug Rabson 	cksum.checksum.data = p + len;
1535c19800e8SDoug Rabson 
1536c19800e8SDoug Rabson 	output_message_buffer->length = len; /* for later */
1537c19800e8SDoug Rabson 	output_message_buffer->value = malloc(len + sizeof(*token));
1538c19800e8SDoug Rabson 	if (output_message_buffer->value == NULL) {
1539c19800e8SDoug Rabson 	    *minor_status = ENOMEM;
1540c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
1541c19800e8SDoug Rabson 	}
1542c19800e8SDoug Rabson 
1543c19800e8SDoug Rabson 	/* Checksum is over (plaintext-data | "header") */
1544c19800e8SDoug Rabson 	memcpy(output_message_buffer->value, p, len);
1545c19800e8SDoug Rabson 	memcpy((u_char *)output_message_buffer->value + len,
1546c19800e8SDoug Rabson 	       token, sizeof(*token));
1547c19800e8SDoug Rabson 
1548c19800e8SDoug Rabson 	/* EC is not included in checksum calculation */
1549c19800e8SDoug Rabson 	token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value +
1550c19800e8SDoug Rabson 				     len);
1551c19800e8SDoug Rabson 	token->EC[0]  = 0;
1552c19800e8SDoug Rabson 	token->EC[1]  = 0;
1553c19800e8SDoug Rabson 	token->RRC[0] = 0;
1554c19800e8SDoug Rabson 	token->RRC[1] = 0;
1555c19800e8SDoug Rabson 
1556*ae771770SStanislav Sedov 	ret = krb5_verify_checksum(context, ctx->crypto,
1557c19800e8SDoug Rabson 				   usage,
1558c19800e8SDoug Rabson 				   output_message_buffer->value,
1559c19800e8SDoug Rabson 				   len + sizeof(*token),
1560c19800e8SDoug Rabson 				   &cksum);
1561c19800e8SDoug Rabson 	if (ret != 0) {
1562c19800e8SDoug Rabson 	    *minor_status = ret;
1563c19800e8SDoug Rabson 	    _gsskrb5_release_buffer(minor_status, output_message_buffer);
1564c19800e8SDoug Rabson 	    return GSS_S_BAD_MIC;
1565c19800e8SDoug Rabson 	}
1566c19800e8SDoug Rabson     }
1567c19800e8SDoug Rabson 
1568c19800e8SDoug Rabson     if (qop_state != NULL) {
1569c19800e8SDoug Rabson 	*qop_state = GSS_C_QOP_DEFAULT;
1570c19800e8SDoug Rabson     }
1571c19800e8SDoug Rabson 
1572c19800e8SDoug Rabson     *minor_status = 0;
1573c19800e8SDoug Rabson     return GSS_S_COMPLETE;
1574c19800e8SDoug Rabson }
1575c19800e8SDoug Rabson 
_gssapi_mic_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,gss_qop_t qop_req,const gss_buffer_t message_buffer,gss_buffer_t message_token)1576c19800e8SDoug Rabson OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
1577*ae771770SStanislav Sedov 			  const gsskrb5_ctx ctx,
1578c19800e8SDoug Rabson 			  krb5_context context,
1579c19800e8SDoug Rabson 			  gss_qop_t qop_req,
1580c19800e8SDoug Rabson 			  const gss_buffer_t message_buffer,
1581*ae771770SStanislav Sedov 			  gss_buffer_t message_token)
1582c19800e8SDoug Rabson {
1583c19800e8SDoug Rabson     gss_cfx_mic_token token;
1584c19800e8SDoug Rabson     krb5_error_code ret;
1585c19800e8SDoug Rabson     unsigned usage;
1586c19800e8SDoug Rabson     Checksum cksum;
1587c19800e8SDoug Rabson     u_char *buf;
1588c19800e8SDoug Rabson     size_t len;
1589c19800e8SDoug Rabson     int32_t seq_number;
1590c19800e8SDoug Rabson 
1591c19800e8SDoug Rabson     len = message_buffer->length + sizeof(*token);
1592c19800e8SDoug Rabson     buf = malloc(len);
1593c19800e8SDoug Rabson     if (buf == NULL) {
1594c19800e8SDoug Rabson 	*minor_status = ENOMEM;
1595c19800e8SDoug Rabson 	return GSS_S_FAILURE;
1596c19800e8SDoug Rabson     }
1597c19800e8SDoug Rabson 
1598c19800e8SDoug Rabson     memcpy(buf, message_buffer->value, message_buffer->length);
1599c19800e8SDoug Rabson 
1600c19800e8SDoug Rabson     token = (gss_cfx_mic_token)(buf + message_buffer->length);
1601c19800e8SDoug Rabson     token->TOK_ID[0] = 0x04;
1602c19800e8SDoug Rabson     token->TOK_ID[1] = 0x04;
1603c19800e8SDoug Rabson     token->Flags = 0;
1604*ae771770SStanislav Sedov     if ((ctx->more_flags & LOCAL) == 0)
1605c19800e8SDoug Rabson 	token->Flags |= CFXSentByAcceptor;
1606*ae771770SStanislav Sedov     if (ctx->more_flags & ACCEPTOR_SUBKEY)
1607c19800e8SDoug Rabson 	token->Flags |= CFXAcceptorSubkey;
1608c19800e8SDoug Rabson     memset(token->Filler, 0xFF, 5);
1609c19800e8SDoug Rabson 
1610*ae771770SStanislav Sedov     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1611c19800e8SDoug Rabson     krb5_auth_con_getlocalseqnumber(context,
1612*ae771770SStanislav Sedov 				    ctx->auth_context,
1613c19800e8SDoug Rabson 				    &seq_number);
1614c19800e8SDoug Rabson     _gsskrb5_encode_be_om_uint32(0,          &token->SND_SEQ[0]);
1615c19800e8SDoug Rabson     _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
1616c19800e8SDoug Rabson     krb5_auth_con_setlocalseqnumber(context,
1617*ae771770SStanislav Sedov 				    ctx->auth_context,
1618c19800e8SDoug Rabson 				    ++seq_number);
1619*ae771770SStanislav Sedov     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1620c19800e8SDoug Rabson 
1621*ae771770SStanislav Sedov     if (ctx->more_flags & LOCAL) {
1622c19800e8SDoug Rabson 	usage = KRB5_KU_USAGE_INITIATOR_SIGN;
1623c19800e8SDoug Rabson     } else {
1624c19800e8SDoug Rabson 	usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
1625c19800e8SDoug Rabson     }
1626c19800e8SDoug Rabson 
1627*ae771770SStanislav Sedov     ret = krb5_create_checksum(context, ctx->crypto,
1628c19800e8SDoug Rabson 	usage, 0, buf, len, &cksum);
1629c19800e8SDoug Rabson     if (ret != 0) {
1630c19800e8SDoug Rabson 	*minor_status = ret;
1631c19800e8SDoug Rabson 	free(buf);
1632c19800e8SDoug Rabson 	return GSS_S_FAILURE;
1633c19800e8SDoug Rabson     }
1634c19800e8SDoug Rabson 
1635c19800e8SDoug Rabson     /* Determine MIC length */
1636c19800e8SDoug Rabson     message_token->length = sizeof(*token) + cksum.checksum.length;
1637c19800e8SDoug Rabson     message_token->value = malloc(message_token->length);
1638c19800e8SDoug Rabson     if (message_token->value == NULL) {
1639c19800e8SDoug Rabson 	*minor_status = ENOMEM;
1640c19800e8SDoug Rabson 	free_Checksum(&cksum);
1641c19800e8SDoug Rabson 	free(buf);
1642c19800e8SDoug Rabson 	return GSS_S_FAILURE;
1643c19800e8SDoug Rabson     }
1644c19800e8SDoug Rabson 
1645c19800e8SDoug Rabson     /* Token is { "header" | get_mic("header" | plaintext-data) } */
1646c19800e8SDoug Rabson     memcpy(message_token->value, token, sizeof(*token));
1647c19800e8SDoug Rabson     memcpy((u_char *)message_token->value + sizeof(*token),
1648c19800e8SDoug Rabson 	   cksum.checksum.data, cksum.checksum.length);
1649c19800e8SDoug Rabson 
1650c19800e8SDoug Rabson     free_Checksum(&cksum);
1651c19800e8SDoug Rabson     free(buf);
1652c19800e8SDoug Rabson 
1653c19800e8SDoug Rabson     *minor_status = 0;
1654c19800e8SDoug Rabson     return GSS_S_COMPLETE;
1655c19800e8SDoug Rabson }
1656c19800e8SDoug Rabson 
_gssapi_verify_mic_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state)1657c19800e8SDoug Rabson OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
1658*ae771770SStanislav Sedov 				 const gsskrb5_ctx ctx,
1659c19800e8SDoug Rabson 				 krb5_context context,
1660c19800e8SDoug Rabson 				 const gss_buffer_t message_buffer,
1661c19800e8SDoug Rabson 				 const gss_buffer_t token_buffer,
1662*ae771770SStanislav Sedov 				 gss_qop_t *qop_state)
1663c19800e8SDoug Rabson {
1664c19800e8SDoug Rabson     gss_cfx_mic_token token;
1665c19800e8SDoug Rabson     u_char token_flags;
1666c19800e8SDoug Rabson     krb5_error_code ret;
1667c19800e8SDoug Rabson     unsigned usage;
1668c19800e8SDoug Rabson     OM_uint32 seq_number_lo, seq_number_hi;
1669c19800e8SDoug Rabson     u_char *buf, *p;
1670c19800e8SDoug Rabson     Checksum cksum;
1671c19800e8SDoug Rabson 
1672c19800e8SDoug Rabson     *minor_status = 0;
1673c19800e8SDoug Rabson 
1674c19800e8SDoug Rabson     if (token_buffer->length < sizeof(*token)) {
1675c19800e8SDoug Rabson 	return GSS_S_DEFECTIVE_TOKEN;
1676c19800e8SDoug Rabson     }
1677c19800e8SDoug Rabson 
1678c19800e8SDoug Rabson     p = token_buffer->value;
1679c19800e8SDoug Rabson 
1680c19800e8SDoug Rabson     token = (gss_cfx_mic_token)p;
1681c19800e8SDoug Rabson 
1682c19800e8SDoug Rabson     if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) {
1683c19800e8SDoug Rabson 	return GSS_S_DEFECTIVE_TOKEN;
1684c19800e8SDoug Rabson     }
1685c19800e8SDoug Rabson 
1686c19800e8SDoug Rabson     /* Ignore unknown flags */
1687c19800e8SDoug Rabson     token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey);
1688c19800e8SDoug Rabson 
1689c19800e8SDoug Rabson     if (token_flags & CFXSentByAcceptor) {
1690*ae771770SStanislav Sedov 	if ((ctx->more_flags & LOCAL) == 0)
1691c19800e8SDoug Rabson 	    return GSS_S_DEFECTIVE_TOKEN;
1692c19800e8SDoug Rabson     }
1693*ae771770SStanislav Sedov     if (ctx->more_flags & ACCEPTOR_SUBKEY) {
1694c19800e8SDoug Rabson 	if ((token_flags & CFXAcceptorSubkey) == 0)
1695c19800e8SDoug Rabson 	    return GSS_S_DEFECTIVE_TOKEN;
1696c19800e8SDoug Rabson     } else {
1697c19800e8SDoug Rabson 	if (token_flags & CFXAcceptorSubkey)
1698c19800e8SDoug Rabson 	    return GSS_S_DEFECTIVE_TOKEN;
1699c19800e8SDoug Rabson     }
1700c19800e8SDoug Rabson 
1701*ae771770SStanislav Sedov     if (ct_memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) {
1702c19800e8SDoug Rabson 	return GSS_S_DEFECTIVE_TOKEN;
1703c19800e8SDoug Rabson     }
1704c19800e8SDoug Rabson 
1705c19800e8SDoug Rabson     /*
1706c19800e8SDoug Rabson      * Check sequence number
1707c19800e8SDoug Rabson      */
1708c19800e8SDoug Rabson     _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
1709c19800e8SDoug Rabson     _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
1710c19800e8SDoug Rabson     if (seq_number_hi) {
1711c19800e8SDoug Rabson 	*minor_status = ERANGE;
1712c19800e8SDoug Rabson 	return GSS_S_UNSEQ_TOKEN;
1713c19800e8SDoug Rabson     }
1714c19800e8SDoug Rabson 
1715*ae771770SStanislav Sedov     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1716*ae771770SStanislav Sedov     ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
1717c19800e8SDoug Rabson     if (ret != 0) {
1718c19800e8SDoug Rabson 	*minor_status = 0;
1719*ae771770SStanislav Sedov 	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1720c19800e8SDoug Rabson 	return ret;
1721c19800e8SDoug Rabson     }
1722*ae771770SStanislav Sedov     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1723c19800e8SDoug Rabson 
1724c19800e8SDoug Rabson     /*
1725c19800e8SDoug Rabson      * Verify checksum
1726c19800e8SDoug Rabson      */
1727*ae771770SStanislav Sedov     ret = krb5_crypto_get_checksum_type(context, ctx->crypto,
1728c19800e8SDoug Rabson 					&cksum.cksumtype);
1729c19800e8SDoug Rabson     if (ret != 0) {
1730c19800e8SDoug Rabson 	*minor_status = ret;
1731c19800e8SDoug Rabson 	return GSS_S_FAILURE;
1732c19800e8SDoug Rabson     }
1733c19800e8SDoug Rabson 
1734c19800e8SDoug Rabson     cksum.checksum.data = p + sizeof(*token);
1735c19800e8SDoug Rabson     cksum.checksum.length = token_buffer->length - sizeof(*token);
1736c19800e8SDoug Rabson 
1737*ae771770SStanislav Sedov     if (ctx->more_flags & LOCAL) {
1738c19800e8SDoug Rabson 	usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
1739c19800e8SDoug Rabson     } else {
1740c19800e8SDoug Rabson 	usage = KRB5_KU_USAGE_INITIATOR_SIGN;
1741c19800e8SDoug Rabson     }
1742c19800e8SDoug Rabson 
1743c19800e8SDoug Rabson     buf = malloc(message_buffer->length + sizeof(*token));
1744c19800e8SDoug Rabson     if (buf == NULL) {
1745c19800e8SDoug Rabson 	*minor_status = ENOMEM;
1746c19800e8SDoug Rabson 	return GSS_S_FAILURE;
1747c19800e8SDoug Rabson     }
1748c19800e8SDoug Rabson     memcpy(buf, message_buffer->value, message_buffer->length);
1749c19800e8SDoug Rabson     memcpy(buf + message_buffer->length, token, sizeof(*token));
1750c19800e8SDoug Rabson 
1751*ae771770SStanislav Sedov     ret = krb5_verify_checksum(context, ctx->crypto,
1752c19800e8SDoug Rabson 			       usage,
1753c19800e8SDoug Rabson 			       buf,
1754c19800e8SDoug Rabson 			       sizeof(*token) + message_buffer->length,
1755c19800e8SDoug Rabson 			       &cksum);
1756c19800e8SDoug Rabson     if (ret != 0) {
1757c19800e8SDoug Rabson 	*minor_status = ret;
1758c19800e8SDoug Rabson 	free(buf);
1759c19800e8SDoug Rabson 	return GSS_S_BAD_MIC;
1760c19800e8SDoug Rabson     }
1761c19800e8SDoug Rabson 
1762c19800e8SDoug Rabson     free(buf);
1763c19800e8SDoug Rabson 
1764c19800e8SDoug Rabson     if (qop_state != NULL) {
1765c19800e8SDoug Rabson 	*qop_state = GSS_C_QOP_DEFAULT;
1766c19800e8SDoug Rabson     }
1767c19800e8SDoug Rabson 
1768c19800e8SDoug Rabson     return GSS_S_COMPLETE;
1769c19800e8SDoug Rabson }
1770