Home | History | Annotate | Line # | Download | only in krb5
      1 /*	$NetBSD: wrap.c,v 1.5 2023/06/19 21:41:43 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997 - 2003 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * 3. Neither the name of the Institute nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include "gsskrb5_locl.h"
     37 
     38 /*
     39  * Return initiator subkey, or if that doesn't exists, the subkey.
     40  */
     41 
     42 krb5_error_code
     43 _gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,
     44 			       krb5_context context,
     45 			       krb5_keyblock **key)
     46 {
     47     krb5_error_code ret;
     48     *key = NULL;
     49 
     50     if (ctx->more_flags & LOCAL) {
     51 	ret = krb5_auth_con_getlocalsubkey(context,
     52 				     ctx->auth_context,
     53 				     key);
     54     } else {
     55 	ret = krb5_auth_con_getremotesubkey(context,
     56 				      ctx->auth_context,
     57 				      key);
     58     }
     59     if (ret == 0 && *key == NULL)
     60 	ret = krb5_auth_con_getkey(context,
     61 				   ctx->auth_context,
     62 				   key);
     63     if (ret == 0 && *key == NULL) {
     64 	krb5_set_error_message(context, 0, "No initiator subkey available");
     65 	return GSS_KRB5_S_KG_NO_SUBKEY;
     66     }
     67     return ret;
     68 }
     69 
     70 krb5_error_code
     71 _gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,
     72 			      krb5_context context,
     73 			      krb5_keyblock **key)
     74 {
     75     krb5_error_code ret;
     76     *key = NULL;
     77 
     78     if (ctx->more_flags & LOCAL) {
     79 	ret = krb5_auth_con_getremotesubkey(context,
     80 				      ctx->auth_context,
     81 				      key);
     82     } else {
     83 	ret = krb5_auth_con_getlocalsubkey(context,
     84 				     ctx->auth_context,
     85 				     key);
     86     }
     87     if (ret == 0 && *key == NULL) {
     88 	krb5_set_error_message(context, 0, "No acceptor subkey available");
     89 	return GSS_KRB5_S_KG_NO_SUBKEY;
     90     }
     91     return ret;
     92 }
     93 
     94 OM_uint32
     95 _gsskrb5i_get_token_key(const gsskrb5_ctx ctx,
     96 			krb5_context context,
     97 			krb5_keyblock **key)
     98 {
     99     _gsskrb5i_get_acceptor_subkey(ctx, context, key);
    100     if(*key == NULL) {
    101 	/*
    102 	 * Only use the initiator subkey or ticket session key if an
    103 	 * acceptor subkey was not required.
    104 	 */
    105 	if ((ctx->more_flags & ACCEPTOR_SUBKEY) == 0)
    106 	    _gsskrb5i_get_initiator_subkey(ctx, context, key);
    107     }
    108     if (*key == NULL) {
    109 	krb5_set_error_message(context, 0, "No token key available");
    110 	return GSS_KRB5_S_KG_NO_SUBKEY;
    111     }
    112     return 0;
    113 }
    114 
    115 static OM_uint32
    116 sub_wrap_size (
    117             OM_uint32 req_output_size,
    118             OM_uint32 * max_input_size,
    119 	    int blocksize,
    120 	    int extrasize
    121            )
    122 {
    123     size_t len, total_len;
    124 
    125     len = 8 + req_output_size + blocksize + extrasize;
    126 
    127     _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
    128 
    129     total_len -= req_output_size; /* token length */
    130     if (total_len < req_output_size) {
    131         *max_input_size = (req_output_size - total_len);
    132         (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
    133     } else {
    134         *max_input_size = 0;
    135     }
    136     return GSS_S_COMPLETE;
    137 }
    138 
    139 OM_uint32 GSSAPI_CALLCONV
    140 _gsskrb5_wrap_size_limit (
    141             OM_uint32 * minor_status,
    142             gss_const_ctx_id_t context_handle,
    143             int conf_req_flag,
    144             gss_qop_t qop_req,
    145             OM_uint32 req_output_size,
    146             OM_uint32 * max_input_size
    147            )
    148 {
    149   krb5_context context;
    150   krb5_keyblock *key;
    151   OM_uint32 ret;
    152   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
    153 
    154   GSSAPI_KRB5_INIT (&context);
    155 
    156   if (ctx->more_flags & IS_CFX)
    157       return _gssapi_wrap_size_cfx(minor_status, ctx, context,
    158 				   conf_req_flag, qop_req,
    159 				   req_output_size, max_input_size);
    160 
    161   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
    162   ret = _gsskrb5i_get_token_key(ctx, context, &key);
    163   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    164   if (ret) {
    165       *minor_status = ret;
    166       return GSS_S_FAILURE;
    167   }
    168 
    169   switch (key->keytype) {
    170   case KRB5_ENCTYPE_DES_CBC_CRC :
    171   case KRB5_ENCTYPE_DES_CBC_MD4 :
    172   case KRB5_ENCTYPE_DES_CBC_MD5 :
    173 #ifdef HEIM_WEAK_CRYPTO
    174       ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
    175 #else
    176       ret = GSS_S_FAILURE;
    177 #endif
    178       break;
    179   case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5:
    180   case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56:
    181       ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context,
    182 				      conf_req_flag, qop_req,
    183 				      req_output_size, max_input_size, key);
    184       break;
    185   case KRB5_ENCTYPE_DES3_CBC_MD5 :
    186   case KRB5_ENCTYPE_DES3_CBC_SHA1 :
    187       ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
    188       break;
    189   default :
    190       abort();
    191       break;
    192   }
    193   krb5_free_keyblock (context, key);
    194   *minor_status = 0;
    195   return ret;
    196 }
    197 
    198 #ifdef HEIM_WEAK_CRYPTO
    199 
    200 static OM_uint32
    201 wrap_des
    202            (OM_uint32 * minor_status,
    203             const gsskrb5_ctx ctx,
    204 	    krb5_context context,
    205             int conf_req_flag,
    206             gss_qop_t qop_req,
    207             const gss_buffer_t input_message_buffer,
    208             int * conf_state,
    209             gss_buffer_t output_message_buffer,
    210 	    krb5_keyblock *key
    211            )
    212 {
    213   u_char *p;
    214   EVP_MD_CTX *md5;
    215   u_char hash[16];
    216   DES_key_schedule schedule;
    217   EVP_CIPHER_CTX *des_ctx;
    218   DES_cblock deskey;
    219   DES_cblock zero;
    220   size_t i;
    221   int32_t seq_number;
    222   size_t len, total_len, padlength, datalen;
    223 
    224   if (IS_DCE_STYLE(ctx)) {
    225     padlength = 0;
    226     datalen = input_message_buffer->length;
    227     len = 22 + 8;
    228     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
    229     total_len += datalen;
    230     datalen += 8;
    231   } else {
    232     padlength = 8 - (input_message_buffer->length % 8);
    233     datalen = input_message_buffer->length + padlength + 8;
    234     len = datalen + 22;
    235     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
    236   }
    237 
    238   output_message_buffer->length = total_len;
    239   output_message_buffer->value  = malloc (total_len);
    240   if (output_message_buffer->value == NULL) {
    241     output_message_buffer->length = 0;
    242     *minor_status = ENOMEM;
    243     return GSS_S_FAILURE;
    244   }
    245 
    246   p = _gsskrb5_make_header(output_message_buffer->value,
    247 			      len,
    248 			      "\x02\x01", /* TOK_ID */
    249 			      GSS_KRB5_MECHANISM);
    250 
    251   /* SGN_ALG */
    252   memcpy (p, "\x00\x00", 2);
    253   p += 2;
    254   /* SEAL_ALG */
    255   if(conf_req_flag)
    256       memcpy (p, "\x00\x00", 2);
    257   else
    258       memcpy (p, "\xff\xff", 2);
    259   p += 2;
    260   /* Filler */
    261   memcpy (p, "\xff\xff", 2);
    262   p += 2;
    263 
    264   /* fill in later */
    265   memset (p, 0, 16);
    266   p += 16;
    267 
    268   /* confounder + data + pad */
    269   krb5_generate_random_block(p, 8);
    270   memcpy (p + 8, input_message_buffer->value,
    271 	  input_message_buffer->length);
    272   memset (p + 8 + input_message_buffer->length, padlength, padlength);
    273 
    274   /* checksum */
    275   md5 = EVP_MD_CTX_create();
    276   EVP_DigestInit_ex(md5, EVP_md5(), NULL);
    277   EVP_DigestUpdate(md5, p - 24, 8);
    278   EVP_DigestUpdate(md5, p, datalen);
    279   EVP_DigestFinal_ex(md5, hash, NULL);
    280   EVP_MD_CTX_destroy(md5);
    281 
    282   memset (&zero, 0, sizeof(zero));
    283   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
    284   DES_set_key_unchecked (&deskey, &schedule);
    285   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
    286 		 &schedule, &zero);
    287   memcpy (p - 8, hash, 8);
    288 
    289   /* sequence number */
    290   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
    291   krb5_auth_con_getlocalseqnumber (context,
    292 				   ctx->auth_context,
    293 				   &seq_number);
    294 
    295   p -= 16;
    296   p[0] = (seq_number >> 0)  & 0xFF;
    297   p[1] = (seq_number >> 8)  & 0xFF;
    298   p[2] = (seq_number >> 16) & 0xFF;
    299   p[3] = (seq_number >> 24) & 0xFF;
    300   memset (p + 4,
    301 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
    302 	  4);
    303 
    304 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    305   EVP_CIPHER_CTX des_ctxs;
    306   des_ctx = &des_ctxs;
    307   EVP_CIPHER_CTX_init(des_ctx);
    308 #else
    309   des_ctx = EVP_CIPHER_CTX_new();
    310 #endif
    311   if (!EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data,
    312       p + 8, 1)) {
    313     *minor_status = EINVAL;
    314     return GSS_S_FAILURE;
    315   }
    316   EVP_Cipher(des_ctx, p, p, 8);
    317 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    318   EVP_CIPHER_CTX_cleanup(des_ctx);
    319 #else
    320   EVP_CIPHER_CTX_free(des_ctx);
    321 #endif
    322 
    323   krb5_auth_con_setlocalseqnumber (context,
    324 			       ctx->auth_context,
    325 			       ++seq_number);
    326   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    327 
    328   /* encrypt the data */
    329   p += 16;
    330 
    331   if(conf_req_flag) {
    332       memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
    333 
    334       for (i = 0; i < sizeof(deskey); ++i)
    335 	  deskey[i] ^= 0xf0;
    336 
    337 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    338       EVP_CIPHER_CTX des_ctxs;
    339       des_ctx = &des_ctxs;
    340       EVP_CIPHER_CTX_init(des_ctx);
    341 #else
    342       des_ctx = EVP_CIPHER_CTX_new();
    343 #endif
    344       if (!EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, deskey, zero, 1)) {
    345 	*minor_status = EINVAL;
    346 	return GSS_S_FAILURE;
    347       }
    348       EVP_Cipher(des_ctx, p, p, datalen);
    349 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    350       EVP_CIPHER_CTX_cleanup(des_ctx);
    351 #else
    352       EVP_CIPHER_CTX_free(des_ctx);
    353 #endif
    354   }
    355   memset (deskey, 0, sizeof(deskey));
    356   memset (&schedule, 0, sizeof(schedule));
    357 
    358   if(conf_state != NULL)
    359       *conf_state = conf_req_flag;
    360   *minor_status = 0;
    361   return GSS_S_COMPLETE;
    362 }
    363 
    364 #endif
    365 
    366 static OM_uint32
    367 wrap_des3
    368            (OM_uint32 * minor_status,
    369             const gsskrb5_ctx ctx,
    370 	    krb5_context context,
    371             int conf_req_flag,
    372             gss_qop_t qop_req,
    373             const gss_buffer_t input_message_buffer,
    374             int * conf_state,
    375             gss_buffer_t output_message_buffer,
    376 	    krb5_keyblock *key
    377            )
    378 {
    379   u_char *p;
    380   u_char seq[8];
    381   int32_t seq_number;
    382   size_t len, total_len, padlength, datalen;
    383   uint32_t ret;
    384   krb5_crypto crypto;
    385   Checksum cksum;
    386   krb5_data encdata;
    387 
    388   if (IS_DCE_STYLE(ctx)) {
    389     padlength = 0;
    390     datalen = input_message_buffer->length;
    391     len = 34 + 8;
    392     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
    393     total_len += datalen;
    394     datalen += 8;
    395   } else {
    396     padlength = 8 - (input_message_buffer->length % 8);
    397     datalen = input_message_buffer->length + padlength + 8;
    398     len = datalen + 34;
    399     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
    400   }
    401 
    402   output_message_buffer->length = total_len;
    403   output_message_buffer->value  = malloc (total_len);
    404   if (output_message_buffer->value == NULL) {
    405     output_message_buffer->length = 0;
    406     *minor_status = ENOMEM;
    407     return GSS_S_FAILURE;
    408   }
    409 
    410   p = _gsskrb5_make_header(output_message_buffer->value,
    411 			      len,
    412 			      "\x02\x01", /* TOK_ID */
    413 			      GSS_KRB5_MECHANISM);
    414 
    415   /* SGN_ALG */
    416   memcpy (p, "\x04\x00", 2);	/* HMAC SHA1 DES3-KD */
    417   p += 2;
    418   /* SEAL_ALG */
    419   if(conf_req_flag)
    420       memcpy (p, "\x02\x00", 2); /* DES3-KD */
    421   else
    422       memcpy (p, "\xff\xff", 2);
    423   p += 2;
    424   /* Filler */
    425   memcpy (p, "\xff\xff", 2);
    426   p += 2;
    427 
    428   /* calculate checksum (the above + confounder + data + pad) */
    429 
    430   memcpy (p + 20, p - 8, 8);
    431   krb5_generate_random_block(p + 28, 8);
    432   memcpy (p + 28 + 8, input_message_buffer->value,
    433 	  input_message_buffer->length);
    434   memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
    435 
    436   ret = krb5_crypto_init(context, key, 0, &crypto);
    437   if (ret) {
    438       free (output_message_buffer->value);
    439       output_message_buffer->length = 0;
    440       output_message_buffer->value = NULL;
    441       *minor_status = ret;
    442       return GSS_S_FAILURE;
    443   }
    444 
    445   ret = krb5_create_checksum (context,
    446 			      crypto,
    447 			      KRB5_KU_USAGE_SIGN,
    448 			      0,
    449 			      p + 20,
    450 			      datalen + 8,
    451 			      &cksum);
    452   krb5_crypto_destroy (context, crypto);
    453   if (ret) {
    454       free (output_message_buffer->value);
    455       output_message_buffer->length = 0;
    456       output_message_buffer->value = NULL;
    457       *minor_status = ret;
    458       return GSS_S_FAILURE;
    459   }
    460 
    461   /* zero out SND_SEQ + SGN_CKSUM in case */
    462   memset (p, 0, 28);
    463 
    464   memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
    465   free_Checksum (&cksum);
    466 
    467   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
    468   /* sequence number */
    469   krb5_auth_con_getlocalseqnumber (context,
    470 			       ctx->auth_context,
    471 			       &seq_number);
    472 
    473   seq[0] = (seq_number >> 0)  & 0xFF;
    474   seq[1] = (seq_number >> 8)  & 0xFF;
    475   seq[2] = (seq_number >> 16) & 0xFF;
    476   seq[3] = (seq_number >> 24) & 0xFF;
    477   memset (seq + 4,
    478 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
    479 	  4);
    480 
    481 
    482   ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE,
    483 			 &crypto);
    484   if (ret) {
    485       free (output_message_buffer->value);
    486       output_message_buffer->length = 0;
    487       output_message_buffer->value = NULL;
    488       *minor_status = ret;
    489       return GSS_S_FAILURE;
    490   }
    491 
    492   {
    493       DES_cblock ivec;
    494 
    495       memcpy (&ivec, p + 8, 8);
    496       ret = krb5_encrypt_ivec (context,
    497 			       crypto,
    498 			       KRB5_KU_USAGE_SEQ,
    499 			       seq, 8, &encdata,
    500 			       &ivec);
    501   }
    502   krb5_crypto_destroy (context, crypto);
    503   if (ret) {
    504       free (output_message_buffer->value);
    505       output_message_buffer->length = 0;
    506       output_message_buffer->value = NULL;
    507       *minor_status = ret;
    508       return GSS_S_FAILURE;
    509   }
    510 
    511   assert (encdata.length == 8);
    512 
    513   memcpy (p, encdata.data, encdata.length);
    514   krb5_data_free (&encdata);
    515 
    516   krb5_auth_con_setlocalseqnumber (context,
    517 			       ctx->auth_context,
    518 			       ++seq_number);
    519   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    520 
    521   /* encrypt the data */
    522   p += 28;
    523 
    524   if(conf_req_flag) {
    525       krb5_data tmp;
    526 
    527       ret = krb5_crypto_init(context, key,
    528 			     ETYPE_DES3_CBC_NONE, &crypto);
    529       if (ret) {
    530 	  free (output_message_buffer->value);
    531 	  output_message_buffer->length = 0;
    532 	  output_message_buffer->value = NULL;
    533 	  *minor_status = ret;
    534 	  return GSS_S_FAILURE;
    535       }
    536       ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL,
    537 			 p, datalen, &tmp);
    538       krb5_crypto_destroy(context, crypto);
    539       if (ret) {
    540 	  free (output_message_buffer->value);
    541 	  output_message_buffer->length = 0;
    542 	  output_message_buffer->value = NULL;
    543 	  *minor_status = ret;
    544 	  return GSS_S_FAILURE;
    545       }
    546       assert (tmp.length == datalen);
    547 
    548       memcpy (p, tmp.data, datalen);
    549       krb5_data_free(&tmp);
    550   }
    551   if(conf_state != NULL)
    552       *conf_state = conf_req_flag;
    553   *minor_status = 0;
    554   return GSS_S_COMPLETE;
    555 }
    556 
    557 OM_uint32 GSSAPI_CALLCONV
    558 _gsskrb5_wrap
    559            (OM_uint32 * minor_status,
    560             gss_const_ctx_id_t context_handle,
    561             int conf_req_flag,
    562             gss_qop_t qop_req,
    563             const gss_buffer_t input_message_buffer,
    564             int * conf_state,
    565             gss_buffer_t output_message_buffer
    566            )
    567 {
    568   krb5_context context;
    569   krb5_keyblock *key;
    570   OM_uint32 ret;
    571   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
    572 
    573   output_message_buffer->value = NULL;
    574   output_message_buffer->length = 0;
    575 
    576   GSSAPI_KRB5_INIT (&context);
    577 
    578   if (ctx->more_flags & IS_CFX)
    579       return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
    580 			       input_message_buffer, conf_state,
    581 			       output_message_buffer);
    582 
    583   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
    584   ret = _gsskrb5i_get_token_key(ctx, context, &key);
    585   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    586   if (ret) {
    587       *minor_status = ret;
    588       return GSS_S_FAILURE;
    589   }
    590 
    591   switch (key->keytype) {
    592   case KRB5_ENCTYPE_DES_CBC_CRC :
    593   case KRB5_ENCTYPE_DES_CBC_MD4 :
    594   case KRB5_ENCTYPE_DES_CBC_MD5 :
    595 #ifdef HEIM_WEAK_CRYPTO
    596       ret = wrap_des (minor_status, ctx, context, conf_req_flag,
    597 		      qop_req, input_message_buffer, conf_state,
    598 		      output_message_buffer, key);
    599 #else
    600       ret = GSS_S_FAILURE;
    601 #endif
    602       break;
    603   case KRB5_ENCTYPE_DES3_CBC_MD5 :
    604   case KRB5_ENCTYPE_DES3_CBC_SHA1 :
    605       ret = wrap_des3 (minor_status, ctx, context, conf_req_flag,
    606 		       qop_req, input_message_buffer, conf_state,
    607 		       output_message_buffer, key);
    608       break;
    609   case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5:
    610   case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56:
    611       ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag,
    612 				  qop_req, input_message_buffer, conf_state,
    613 				  output_message_buffer, key);
    614       break;
    615   default :
    616       abort();
    617       break;
    618   }
    619   krb5_free_keyblock (context, key);
    620   return ret;
    621 }
    622