root/source4/heimdal/lib/gssapi/krb5/cfx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _gsskrb5cfx_wrap_length_cfx
  2. _gsskrb5cfx_max_wrap_length_cfx
  3. _gssapi_wrap_size_cfx
  4. rrc_rotate
  5. _gssapi_wrap_cfx
  6. _gssapi_unwrap_cfx
  7. _gssapi_mic_cfx
  8. _gssapi_verify_mic_cfx

   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 "krb5/gsskrb5_locl.h"
  34 
  35 RCSID("$Id$");
  36 
  37 /*
  38  * Implementation of draft-ietf-krb-wg-gssapi-cfx-06.txt
  39  */
  40 
  41 #define CFXSentByAcceptor       (1 << 0)
  42 #define CFXSealed               (1 << 1)
  43 #define CFXAcceptorSubkey       (1 << 2)
  44 
  45 krb5_error_code
  46 _gsskrb5cfx_wrap_length_cfx(const gsskrb5_ctx context_handle,
     /* [<][>][^][v][top][bottom][index][help] */
  47                             krb5_context context,
  48                             krb5_crypto crypto,
  49                             int conf_req_flag,
  50                             size_t input_length,
  51                             size_t *output_length,
  52                             size_t *cksumsize,
  53                             uint16_t *padlength)
  54 {
  55     krb5_error_code ret;
  56     krb5_cksumtype type;
  57 
  58     /* 16-byte header is always first */
  59     *output_length = sizeof(gss_cfx_wrap_token_desc);
  60     *padlength = 0;
  61 
  62     ret = krb5_crypto_get_checksum_type(context, crypto, &type);
  63     if (ret)
  64         return ret;
  65 
  66     ret = krb5_checksumsize(context, type, cksumsize);
  67     if (ret)
  68         return ret;
  69 
  70     if (conf_req_flag) {
  71         size_t padsize;
  72 
  73         /* Header is concatenated with data before encryption */
  74         input_length += sizeof(gss_cfx_wrap_token_desc);
  75 
  76         if (IS_DCE_STYLE(context_handle)) {
  77                 ret = krb5_crypto_getblocksize(context, crypto, &padsize);
  78         } else {
  79                 ret = krb5_crypto_getpadsize(context, crypto, &padsize);
  80         }
  81         if (ret) {
  82             return ret;
  83         }
  84         if (padsize > 1) {
  85             /* XXX check this */
  86             *padlength = padsize - (input_length % padsize);
  87 
  88             /* We add the pad ourselves (noted here for completeness only) */
  89             input_length += *padlength;
  90         }
  91 
  92         *output_length += krb5_get_wrapped_length(context,
  93                                                   crypto, input_length);
  94     } else {
  95         /* Checksum is concatenated with data */
  96         *output_length += input_length + *cksumsize;
  97     }
  98 
  99     assert(*output_length > input_length);
 100 
 101     return 0;
 102 }
 103 
 104 krb5_error_code
 105 _gsskrb5cfx_max_wrap_length_cfx(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 106                                 krb5_crypto crypto,
 107                                 int conf_req_flag,
 108                                 size_t input_length,
 109                                 OM_uint32 *output_length)
 110 {
 111     krb5_error_code ret;
 112 
 113     *output_length = 0;
 114 
 115     /* 16-byte header is always first */
 116     if (input_length < 16)
 117         return 0;
 118     input_length -= 16;
 119 
 120     if (conf_req_flag) {
 121         size_t wrapped_size, sz;
 122 
 123         wrapped_size = input_length + 1;
 124         do {
 125             wrapped_size--;
 126             sz = krb5_get_wrapped_length(context,
 127                                          crypto, wrapped_size);
 128         } while (wrapped_size && sz > input_length);
 129         if (wrapped_size == 0) {
 130             *output_length = 0;
 131             return 0;
 132         }
 133 
 134         /* inner header */
 135         if (wrapped_size < 16) {
 136             *output_length = 0;
 137             return 0;
 138         }
 139         wrapped_size -= 16;
 140 
 141         *output_length = wrapped_size;
 142     } else {
 143         krb5_cksumtype type;
 144         size_t cksumsize;
 145 
 146         ret = krb5_crypto_get_checksum_type(context, crypto, &type);
 147         if (ret)
 148             return ret;
 149 
 150         ret = krb5_checksumsize(context, type, &cksumsize);
 151         if (ret)
 152             return ret;
 153 
 154         if (input_length < cksumsize)
 155             return 0;
 156 
 157         /* Checksum is concatenated with data */
 158         *output_length = input_length - cksumsize;
 159     }
 160 
 161     return 0;
 162 }
 163 
 164 
 165 OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
     /* [<][>][^][v][top][bottom][index][help] */
 166                                 const gsskrb5_ctx context_handle,
 167                                 krb5_context context,
 168                                 int conf_req_flag,
 169                                 gss_qop_t qop_req,
 170                                 OM_uint32 req_output_size,
 171                                 OM_uint32 *max_input_size,
 172                                 krb5_keyblock *key)
 173 {
 174     krb5_error_code ret;
 175     krb5_crypto crypto;
 176 
 177     ret = krb5_crypto_init(context, key, 0, &crypto);
 178     if (ret != 0) {
 179         *minor_status = ret;
 180         return GSS_S_FAILURE;
 181     }
 182 
 183     ret = _gsskrb5cfx_max_wrap_length_cfx(context, crypto, conf_req_flag,
 184                                           req_output_size, max_input_size);
 185     if (ret != 0) {
 186         *minor_status = ret;
 187         krb5_crypto_destroy(context, crypto);
 188         return GSS_S_FAILURE;
 189     }
 190 
 191     krb5_crypto_destroy(context, crypto);
 192 
 193     return GSS_S_COMPLETE;
 194 }
 195 
 196 /*
 197  * Rotate "rrc" bytes to the front or back
 198  */
 199 
 200 static krb5_error_code
 201 rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate)
     /* [<][>][^][v][top][bottom][index][help] */
 202 {
 203     u_char *tmp, buf[256];
 204     size_t left;
 205 
 206     if (len == 0)
 207         return 0;
 208 
 209     rrc %= len;
 210 
 211     if (rrc == 0)
 212         return 0;
 213 
 214     left = len - rrc;
 215 
 216     if (rrc <= sizeof(buf)) {
 217         tmp = buf;
 218     } else {
 219         tmp = malloc(rrc);
 220         if (tmp == NULL)
 221             return ENOMEM;
 222     }
 223 
 224     if (unrotate) {
 225         memcpy(tmp, data, rrc);
 226         memmove(data, (u_char *)data + rrc, left);
 227         memcpy((u_char *)data + left, tmp, rrc);
 228     } else {
 229         memcpy(tmp, (u_char *)data + left, rrc);
 230         memmove((u_char *)data + rrc, data, left);
 231         memcpy(data, tmp, rrc);
 232     }
 233 
 234     if (rrc > sizeof(buf))
 235         free(tmp);
 236 
 237     return 0;
 238 }
 239 
 240 OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
     /* [<][>][^][v][top][bottom][index][help] */
 241                            const gsskrb5_ctx context_handle,
 242                            krb5_context context,
 243                            int conf_req_flag,
 244                            gss_qop_t qop_req,
 245                            const gss_buffer_t input_message_buffer,
 246                            int *conf_state,
 247                            gss_buffer_t output_message_buffer,
 248                            krb5_keyblock *key)
 249 {
 250     krb5_crypto crypto;
 251     gss_cfx_wrap_token token;
 252     krb5_error_code ret;
 253     unsigned usage;
 254     krb5_data cipher;
 255     size_t wrapped_len, cksumsize;
 256     uint16_t padlength, rrc = 0;
 257     int32_t seq_number;
 258     u_char *p;
 259 
 260     ret = krb5_crypto_init(context, key, 0, &crypto);
 261     if (ret != 0) {
 262         *minor_status = ret;
 263         return GSS_S_FAILURE;
 264     }
 265 
 266     ret = _gsskrb5cfx_wrap_length_cfx(context_handle, context,
 267                                       crypto, conf_req_flag,
 268                                       input_message_buffer->length,
 269                                       &wrapped_len, &cksumsize, &padlength);
 270     if (ret != 0) {
 271         *minor_status = ret;
 272         krb5_crypto_destroy(context, crypto);
 273         return GSS_S_FAILURE;
 274     }
 275 
 276     /* Always rotate encrypted token (if any) and checksum to header */
 277     rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize;
 278 
 279     output_message_buffer->length = wrapped_len;
 280     output_message_buffer->value = malloc(output_message_buffer->length);
 281     if (output_message_buffer->value == NULL) {
 282         *minor_status = ENOMEM;
 283         krb5_crypto_destroy(context, crypto);
 284         return GSS_S_FAILURE;
 285     }
 286 
 287     p = output_message_buffer->value;
 288     token = (gss_cfx_wrap_token)p;
 289     token->TOK_ID[0] = 0x05;
 290     token->TOK_ID[1] = 0x04;
 291     token->Flags     = 0;
 292     token->Filler    = 0xFF;
 293     if ((context_handle->more_flags & LOCAL) == 0)
 294         token->Flags |= CFXSentByAcceptor;
 295     if (context_handle->more_flags & ACCEPTOR_SUBKEY)
 296         token->Flags |= CFXAcceptorSubkey;
 297     if (conf_req_flag) {
 298         /*
 299          * In Wrap tokens with confidentiality, the EC field is
 300          * used to encode the size (in bytes) of the random filler.
 301          */
 302         token->Flags |= CFXSealed;
 303         token->EC[0] = (padlength >> 8) & 0xFF;
 304         token->EC[1] = (padlength >> 0) & 0xFF;
 305     } else {
 306         /*
 307          * In Wrap tokens without confidentiality, the EC field is
 308          * used to encode the size (in bytes) of the trailing
 309          * checksum.
 310          *
 311          * This is not used in the checksum calcuation itself,
 312          * because the checksum length could potentially vary
 313          * depending on the data length.
 314          */
 315         token->EC[0] = 0;
 316         token->EC[1] = 0;
 317     }
 318 
 319     /*
 320      * In Wrap tokens that provide for confidentiality, the RRC
 321      * field in the header contains the hex value 00 00 before
 322      * encryption.
 323      *
 324      * In Wrap tokens that do not provide for confidentiality,
 325      * both the EC and RRC fields in the appended checksum
 326      * contain the hex value 00 00 for the purpose of calculating
 327      * the checksum.
 328      */
 329     token->RRC[0] = 0;
 330     token->RRC[1] = 0;
 331 
 332     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 333     krb5_auth_con_getlocalseqnumber(context,
 334                                     context_handle->auth_context,
 335                                     &seq_number);
 336     _gsskrb5_encode_be_om_uint32(0,          &token->SND_SEQ[0]);
 337     _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
 338     krb5_auth_con_setlocalseqnumber(context,
 339                                     context_handle->auth_context,
 340                                     ++seq_number);
 341     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 342 
 343     /*
 344      * If confidentiality is requested, the token header is
 345      * appended to the plaintext before encryption; the resulting
 346      * token is {"header" | encrypt(plaintext | pad | "header")}.
 347      *
 348      * If no confidentiality is requested, the checksum is
 349      * calculated over the plaintext concatenated with the
 350      * token header.
 351      */
 352     if (context_handle->more_flags & LOCAL) {
 353         usage = KRB5_KU_USAGE_INITIATOR_SEAL;
 354     } else {
 355         usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
 356     }
 357 
 358     if (conf_req_flag) {
 359         /*
 360          * Any necessary padding is added here to ensure that the
 361          * encrypted token header is always at the end of the
 362          * ciphertext.
 363          *
 364          * The specification does not require that the padding
 365          * bytes are initialized.
 366          */
 367         p += sizeof(*token);
 368         memcpy(p, input_message_buffer->value, input_message_buffer->length);
 369         memset(p + input_message_buffer->length, 0xFF, padlength);
 370         memcpy(p + input_message_buffer->length + padlength,
 371                token, sizeof(*token));
 372 
 373         ret = krb5_encrypt(context, crypto,
 374                            usage, p,
 375                            input_message_buffer->length + padlength +
 376                                 sizeof(*token),
 377                            &cipher);
 378         if (ret != 0) {
 379             *minor_status = ret;
 380             krb5_crypto_destroy(context, crypto);
 381             _gsskrb5_release_buffer(minor_status, output_message_buffer);
 382             return GSS_S_FAILURE;
 383         }
 384         assert(sizeof(*token) + cipher.length == wrapped_len);
 385         token->RRC[0] = (rrc >> 8) & 0xFF;
 386         token->RRC[1] = (rrc >> 0) & 0xFF;
 387 
 388         /*
 389          * this is really ugly, but needed against windows
 390          * for DCERPC, as windows rotates by EC+RRC.
 391          */
 392         if (IS_DCE_STYLE(context_handle)) {
 393                 ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE);
 394         } else {
 395                 ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);
 396         }
 397         if (ret != 0) {
 398             *minor_status = ret;
 399             krb5_crypto_destroy(context, crypto);
 400             _gsskrb5_release_buffer(minor_status, output_message_buffer);
 401             return GSS_S_FAILURE;
 402         }
 403         memcpy(p, cipher.data, cipher.length);
 404         krb5_data_free(&cipher);
 405     } else {
 406         char *buf;
 407         Checksum cksum;
 408 
 409         buf = malloc(input_message_buffer->length + sizeof(*token));
 410         if (buf == NULL) {
 411             *minor_status = ENOMEM;
 412             krb5_crypto_destroy(context, crypto);
 413             _gsskrb5_release_buffer(minor_status, output_message_buffer);
 414             return GSS_S_FAILURE;
 415         }
 416         memcpy(buf, input_message_buffer->value, input_message_buffer->length);
 417         memcpy(buf + input_message_buffer->length, token, sizeof(*token));
 418 
 419         ret = krb5_create_checksum(context, crypto,
 420                                    usage, 0, buf,
 421                                    input_message_buffer->length +
 422                                         sizeof(*token),
 423                                    &cksum);
 424         if (ret != 0) {
 425             *minor_status = ret;
 426             krb5_crypto_destroy(context, crypto);
 427             _gsskrb5_release_buffer(minor_status, output_message_buffer);
 428             free(buf);
 429             return GSS_S_FAILURE;
 430         }
 431 
 432         free(buf);
 433 
 434         assert(cksum.checksum.length == cksumsize);
 435         token->EC[0] =  (cksum.checksum.length >> 8) & 0xFF;
 436         token->EC[1] =  (cksum.checksum.length >> 0) & 0xFF;
 437         token->RRC[0] = (rrc >> 8) & 0xFF;
 438         token->RRC[1] = (rrc >> 0) & 0xFF;
 439 
 440         p += sizeof(*token);
 441         memcpy(p, input_message_buffer->value, input_message_buffer->length);
 442         memcpy(p + input_message_buffer->length,
 443                cksum.checksum.data, cksum.checksum.length);
 444 
 445         ret = rrc_rotate(p,
 446             input_message_buffer->length + cksum.checksum.length, rrc, FALSE);
 447         if (ret != 0) {
 448             *minor_status = ret;
 449             krb5_crypto_destroy(context, crypto);
 450             _gsskrb5_release_buffer(minor_status, output_message_buffer);
 451             free_Checksum(&cksum);
 452             return GSS_S_FAILURE;
 453         }
 454         free_Checksum(&cksum);
 455     }
 456 
 457     krb5_crypto_destroy(context, crypto);
 458 
 459     if (conf_state != NULL) {
 460         *conf_state = conf_req_flag;
 461     }
 462 
 463     *minor_status = 0;
 464     return GSS_S_COMPLETE;
 465 }
 466 
 467 OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
     /* [<][>][^][v][top][bottom][index][help] */
 468                              const gsskrb5_ctx context_handle,
 469                              krb5_context context,
 470                              const gss_buffer_t input_message_buffer,
 471                              gss_buffer_t output_message_buffer,
 472                              int *conf_state,
 473                              gss_qop_t *qop_state,
 474                              krb5_keyblock *key)
 475 {
 476     krb5_crypto crypto;
 477     gss_cfx_wrap_token token;
 478     u_char token_flags;
 479     krb5_error_code ret;
 480     unsigned usage;
 481     krb5_data data;
 482     uint16_t ec, rrc;
 483     OM_uint32 seq_number_lo, seq_number_hi;
 484     size_t len;
 485     u_char *p;
 486 
 487     *minor_status = 0;
 488 
 489     if (input_message_buffer->length < sizeof(*token)) {
 490         return GSS_S_DEFECTIVE_TOKEN;
 491     }
 492 
 493     p = input_message_buffer->value;
 494 
 495     token = (gss_cfx_wrap_token)p;
 496 
 497     if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) {
 498         return GSS_S_DEFECTIVE_TOKEN;
 499     }
 500 
 501     /* Ignore unknown flags */
 502     token_flags = token->Flags &
 503         (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
 504 
 505     if (token_flags & CFXSentByAcceptor) {
 506         if ((context_handle->more_flags & LOCAL) == 0)
 507             return GSS_S_DEFECTIVE_TOKEN;
 508     }
 509 
 510     if (context_handle->more_flags & ACCEPTOR_SUBKEY) {
 511         if ((token_flags & CFXAcceptorSubkey) == 0)
 512             return GSS_S_DEFECTIVE_TOKEN;
 513     } else {
 514         if (token_flags & CFXAcceptorSubkey)
 515             return GSS_S_DEFECTIVE_TOKEN;
 516     }
 517 
 518     if (token->Filler != 0xFF) {
 519         return GSS_S_DEFECTIVE_TOKEN;
 520     }
 521 
 522     if (conf_state != NULL) {
 523         *conf_state = (token_flags & CFXSealed) ? 1 : 0;
 524     }
 525 
 526     ec  = (token->EC[0]  << 8) | token->EC[1];
 527     rrc = (token->RRC[0] << 8) | token->RRC[1];
 528 
 529     /*
 530      * Check sequence number
 531      */
 532     _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
 533     _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
 534     if (seq_number_hi) {
 535         /* no support for 64-bit sequence numbers */
 536         *minor_status = ERANGE;
 537         return GSS_S_UNSEQ_TOKEN;
 538     }
 539 
 540     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 541     ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo);
 542     if (ret != 0) {
 543         *minor_status = 0;
 544         HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 545         _gsskrb5_release_buffer(minor_status, output_message_buffer);
 546         return ret;
 547     }
 548     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 549 
 550     /*
 551      * Decrypt and/or verify checksum
 552      */
 553     ret = krb5_crypto_init(context, key, 0, &crypto);
 554     if (ret != 0) {
 555         *minor_status = ret;
 556         return GSS_S_FAILURE;
 557     }
 558 
 559     if (context_handle->more_flags & LOCAL) {
 560         usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
 561     } else {
 562         usage = KRB5_KU_USAGE_INITIATOR_SEAL;
 563     }
 564 
 565     p += sizeof(*token);
 566     len = input_message_buffer->length;
 567     len -= (p - (u_char *)input_message_buffer->value);
 568 
 569     if (token_flags & CFXSealed) {
 570         /*
 571          * this is really ugly, but needed against windows
 572          * for DCERPC, as windows rotates by EC+RRC.
 573          */
 574         if (IS_DCE_STYLE(context_handle)) {
 575                 *minor_status = rrc_rotate(p, len, rrc+ec, TRUE);
 576         } else {
 577                 *minor_status = rrc_rotate(p, len, rrc, TRUE);
 578         }
 579         if (*minor_status != 0) {
 580             krb5_crypto_destroy(context, crypto);
 581             return GSS_S_FAILURE;
 582         }
 583 
 584         ret = krb5_decrypt(context, crypto, usage,
 585             p, len, &data);
 586         if (ret != 0) {
 587             *minor_status = ret;
 588             krb5_crypto_destroy(context, crypto);
 589             return GSS_S_BAD_MIC;
 590         }
 591 
 592         /* Check that there is room for the pad and token header */
 593         if (data.length < ec + sizeof(*token)) {
 594             krb5_crypto_destroy(context, crypto);
 595             krb5_data_free(&data);
 596             return GSS_S_DEFECTIVE_TOKEN;
 597         }
 598         p = data.data;
 599         p += data.length - sizeof(*token);
 600 
 601         /* RRC is unprotected; don't modify input buffer */
 602         ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0];
 603         ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1];
 604 
 605         /* Check the integrity of the header */
 606         if (memcmp(p, token, sizeof(*token)) != 0) {
 607             krb5_crypto_destroy(context, crypto);
 608             krb5_data_free(&data);
 609             return GSS_S_BAD_MIC;
 610         }
 611 
 612         output_message_buffer->value = data.data;
 613         output_message_buffer->length = data.length - ec - sizeof(*token);
 614     } else {
 615         Checksum cksum;
 616 
 617         /* Rotate by RRC; bogus to do this in-place XXX */
 618         *minor_status = rrc_rotate(p, len, rrc, TRUE);
 619         if (*minor_status != 0) {
 620             krb5_crypto_destroy(context, crypto);
 621             return GSS_S_FAILURE;
 622         }
 623 
 624         /* Determine checksum type */
 625         ret = krb5_crypto_get_checksum_type(context,
 626                                             crypto, &cksum.cksumtype);
 627         if (ret != 0) {
 628             *minor_status = ret;
 629             krb5_crypto_destroy(context, crypto);
 630             return GSS_S_FAILURE;
 631         }
 632 
 633         cksum.checksum.length = ec;
 634 
 635         /* Check we have at least as much data as the checksum */
 636         if (len < cksum.checksum.length) {
 637             *minor_status = ERANGE;
 638             krb5_crypto_destroy(context, crypto);
 639             return GSS_S_BAD_MIC;
 640         }
 641 
 642         /* Length now is of the plaintext only, no checksum */
 643         len -= cksum.checksum.length;
 644         cksum.checksum.data = p + len;
 645 
 646         output_message_buffer->length = len; /* for later */
 647         output_message_buffer->value = malloc(len + sizeof(*token));
 648         if (output_message_buffer->value == NULL) {
 649             *minor_status = ENOMEM;
 650             krb5_crypto_destroy(context, crypto);
 651             return GSS_S_FAILURE;
 652         }
 653 
 654         /* Checksum is over (plaintext-data | "header") */
 655         memcpy(output_message_buffer->value, p, len);
 656         memcpy((u_char *)output_message_buffer->value + len,
 657                token, sizeof(*token));
 658 
 659         /* EC is not included in checksum calculation */
 660         token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value +
 661                                      len);
 662         token->EC[0]  = 0;
 663         token->EC[1]  = 0;
 664         token->RRC[0] = 0;
 665         token->RRC[1] = 0;
 666 
 667         ret = krb5_verify_checksum(context, crypto,
 668                                    usage,
 669                                    output_message_buffer->value,
 670                                    len + sizeof(*token),
 671                                    &cksum);
 672         if (ret != 0) {
 673             *minor_status = ret;
 674             krb5_crypto_destroy(context, crypto);
 675             _gsskrb5_release_buffer(minor_status, output_message_buffer);
 676             return GSS_S_BAD_MIC;
 677         }
 678     }
 679 
 680     krb5_crypto_destroy(context, crypto);
 681 
 682     if (qop_state != NULL) {
 683         *qop_state = GSS_C_QOP_DEFAULT;
 684     }
 685 
 686     *minor_status = 0;
 687     return GSS_S_COMPLETE;
 688 }
 689 
 690 OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
     /* [<][>][^][v][top][bottom][index][help] */
 691                           const gsskrb5_ctx context_handle,
 692                           krb5_context context,
 693                           gss_qop_t qop_req,
 694                           const gss_buffer_t message_buffer,
 695                           gss_buffer_t message_token,
 696                           krb5_keyblock *key)
 697 {
 698     krb5_crypto crypto;
 699     gss_cfx_mic_token token;
 700     krb5_error_code ret;
 701     unsigned usage;
 702     Checksum cksum;
 703     u_char *buf;
 704     size_t len;
 705     int32_t seq_number;
 706 
 707     ret = krb5_crypto_init(context, key, 0, &crypto);
 708     if (ret != 0) {
 709         *minor_status = ret;
 710         return GSS_S_FAILURE;
 711     }
 712 
 713     len = message_buffer->length + sizeof(*token);
 714     buf = malloc(len);
 715     if (buf == NULL) {
 716         *minor_status = ENOMEM;
 717         krb5_crypto_destroy(context, crypto);
 718         return GSS_S_FAILURE;
 719     }
 720 
 721     memcpy(buf, message_buffer->value, message_buffer->length);
 722 
 723     token = (gss_cfx_mic_token)(buf + message_buffer->length);
 724     token->TOK_ID[0] = 0x04;
 725     token->TOK_ID[1] = 0x04;
 726     token->Flags = 0;
 727     if ((context_handle->more_flags & LOCAL) == 0)
 728         token->Flags |= CFXSentByAcceptor;
 729     if (context_handle->more_flags & ACCEPTOR_SUBKEY)
 730         token->Flags |= CFXAcceptorSubkey;
 731     memset(token->Filler, 0xFF, 5);
 732 
 733     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 734     krb5_auth_con_getlocalseqnumber(context,
 735                                     context_handle->auth_context,
 736                                     &seq_number);
 737     _gsskrb5_encode_be_om_uint32(0,          &token->SND_SEQ[0]);
 738     _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
 739     krb5_auth_con_setlocalseqnumber(context,
 740                                     context_handle->auth_context,
 741                                     ++seq_number);
 742     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 743 
 744     if (context_handle->more_flags & LOCAL) {
 745         usage = KRB5_KU_USAGE_INITIATOR_SIGN;
 746     } else {
 747         usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
 748     }
 749 
 750     ret = krb5_create_checksum(context, crypto,
 751         usage, 0, buf, len, &cksum);
 752     if (ret != 0) {
 753         *minor_status = ret;
 754         krb5_crypto_destroy(context, crypto);
 755         free(buf);
 756         return GSS_S_FAILURE;
 757     }
 758     krb5_crypto_destroy(context, crypto);
 759 
 760     /* Determine MIC length */
 761     message_token->length = sizeof(*token) + cksum.checksum.length;
 762     message_token->value = malloc(message_token->length);
 763     if (message_token->value == NULL) {
 764         *minor_status = ENOMEM;
 765         free_Checksum(&cksum);
 766         free(buf);
 767         return GSS_S_FAILURE;
 768     }
 769 
 770     /* Token is { "header" | get_mic("header" | plaintext-data) } */
 771     memcpy(message_token->value, token, sizeof(*token));
 772     memcpy((u_char *)message_token->value + sizeof(*token),
 773            cksum.checksum.data, cksum.checksum.length);
 774 
 775     free_Checksum(&cksum);
 776     free(buf);
 777 
 778     *minor_status = 0;
 779     return GSS_S_COMPLETE;
 780 }
 781 
 782 OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
     /* [<][>][^][v][top][bottom][index][help] */
 783                                  const gsskrb5_ctx context_handle,
 784                                  krb5_context context,
 785                                  const gss_buffer_t message_buffer,
 786                                  const gss_buffer_t token_buffer,
 787                                  gss_qop_t *qop_state,
 788                                  krb5_keyblock *key)
 789 {
 790     krb5_crypto crypto;
 791     gss_cfx_mic_token token;
 792     u_char token_flags;
 793     krb5_error_code ret;
 794     unsigned usage;
 795     OM_uint32 seq_number_lo, seq_number_hi;
 796     u_char *buf, *p;
 797     Checksum cksum;
 798 
 799     *minor_status = 0;
 800 
 801     if (token_buffer->length < sizeof(*token)) {
 802         return GSS_S_DEFECTIVE_TOKEN;
 803     }
 804 
 805     p = token_buffer->value;
 806 
 807     token = (gss_cfx_mic_token)p;
 808 
 809     if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) {
 810         return GSS_S_DEFECTIVE_TOKEN;
 811     }
 812 
 813     /* Ignore unknown flags */
 814     token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey);
 815 
 816     if (token_flags & CFXSentByAcceptor) {
 817         if ((context_handle->more_flags & LOCAL) == 0)
 818             return GSS_S_DEFECTIVE_TOKEN;
 819     }
 820     if (context_handle->more_flags & ACCEPTOR_SUBKEY) {
 821         if ((token_flags & CFXAcceptorSubkey) == 0)
 822             return GSS_S_DEFECTIVE_TOKEN;
 823     } else {
 824         if (token_flags & CFXAcceptorSubkey)
 825             return GSS_S_DEFECTIVE_TOKEN;
 826     }
 827 
 828     if (memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) {
 829         return GSS_S_DEFECTIVE_TOKEN;
 830     }
 831 
 832     /*
 833      * Check sequence number
 834      */
 835     _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
 836     _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
 837     if (seq_number_hi) {
 838         *minor_status = ERANGE;
 839         return GSS_S_UNSEQ_TOKEN;
 840     }
 841 
 842     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 843     ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo);
 844     if (ret != 0) {
 845         *minor_status = 0;
 846         HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 847         return ret;
 848     }
 849     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 850 
 851     /*
 852      * Verify checksum
 853      */
 854     ret = krb5_crypto_init(context, key, 0, &crypto);
 855     if (ret != 0) {
 856         *minor_status = ret;
 857         return GSS_S_FAILURE;
 858     }
 859 
 860     ret = krb5_crypto_get_checksum_type(context, crypto,
 861                                         &cksum.cksumtype);
 862     if (ret != 0) {
 863         *minor_status = ret;
 864         krb5_crypto_destroy(context, crypto);
 865         return GSS_S_FAILURE;
 866     }
 867 
 868     cksum.checksum.data = p + sizeof(*token);
 869     cksum.checksum.length = token_buffer->length - sizeof(*token);
 870 
 871     if (context_handle->more_flags & LOCAL) {
 872         usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
 873     } else {
 874         usage = KRB5_KU_USAGE_INITIATOR_SIGN;
 875     }
 876 
 877     buf = malloc(message_buffer->length + sizeof(*token));
 878     if (buf == NULL) {
 879         *minor_status = ENOMEM;
 880         krb5_crypto_destroy(context, crypto);
 881         return GSS_S_FAILURE;
 882     }
 883     memcpy(buf, message_buffer->value, message_buffer->length);
 884     memcpy(buf + message_buffer->length, token, sizeof(*token));
 885 
 886     ret = krb5_verify_checksum(context, crypto,
 887                                usage,
 888                                buf,
 889                                sizeof(*token) + message_buffer->length,
 890                                &cksum);
 891     krb5_crypto_destroy(context, crypto);
 892     if (ret != 0) {
 893         *minor_status = ret;
 894         free(buf);
 895         return GSS_S_BAD_MIC;
 896     }
 897 
 898     free(buf);
 899 
 900     if (qop_state != NULL) {
 901         *qop_state = GSS_C_QOP_DEFAULT;
 902     }
 903 
 904     return GSS_S_COMPLETE;
 905 }

/* [<][>][^][v][top][bottom][index][help] */