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