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