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