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