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