Home | History | Annotate | Line # | Download | only in krb5
      1 /*	$NetBSD: unwrap.c,v 1.5 2023/06/19 21:41:43 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997 - 2004 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 #ifdef HEIM_WEAK_CRYPTO
     39 
     40 static OM_uint32
     41 unwrap_des
     42            (OM_uint32 * minor_status,
     43             const gsskrb5_ctx context_handle,
     44             const gss_buffer_t input_message_buffer,
     45             gss_buffer_t output_message_buffer,
     46             int * conf_state,
     47             gss_qop_t * qop_state,
     48 	    krb5_keyblock *key
     49            )
     50 {
     51   u_char *p, *seq;
     52   size_t len;
     53   EVP_MD_CTX *md5;
     54   u_char hash[16];
     55   EVP_CIPHER_CTX *des_ctx;
     56   DES_key_schedule schedule;
     57   DES_cblock deskey;
     58   DES_cblock zero;
     59   size_t i;
     60   uint32_t seq_number;
     61   size_t padlength;
     62   OM_uint32 ret;
     63   int cstate;
     64   int cmp;
     65   int token_len;
     66 
     67   if (IS_DCE_STYLE(context_handle)) {
     68      token_len = 22 + 8 + 15; /* 45 */
     69      if (input_message_buffer->length < token_len)
     70 	  return GSS_S_BAD_MECH;
     71   } else {
     72      token_len = input_message_buffer->length;
     73   }
     74 
     75   p = input_message_buffer->value;
     76   ret = _gsskrb5_verify_header (&p,
     77 				   token_len,
     78 				   "\x02\x01",
     79 				   GSS_KRB5_MECHANISM);
     80   if (ret)
     81       return ret;
     82 
     83   len = (p - (u_char *)input_message_buffer->value)
     84       + 22 + 8;
     85   if (input_message_buffer->length < len)
     86       return GSS_S_BAD_MECH;
     87 
     88   if (memcmp (p, "\x00\x00", 2) != 0)
     89     return GSS_S_BAD_SIG;
     90   p += 2;
     91   if (memcmp (p, "\x00\x00", 2) == 0) {
     92       cstate = 1;
     93   } else if (memcmp (p, "\xFF\xFF", 2) == 0) {
     94       cstate = 0;
     95   } else
     96       return GSS_S_BAD_MIC;
     97   p += 2;
     98   if(conf_state != NULL)
     99       *conf_state = cstate;
    100   if (memcmp (p, "\xff\xff", 2) != 0)
    101     return GSS_S_DEFECTIVE_TOKEN;
    102   p += 2;
    103   p += 16;
    104 
    105   len = p - (u_char *)input_message_buffer->value;
    106 
    107   if(cstate) {
    108       /* decrypt data */
    109       memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
    110       memset (&zero, 0, sizeof(zero));
    111 
    112       for (i = 0; i < sizeof(deskey); ++i)
    113 	  deskey[i] ^= 0xf0;
    114 
    115 
    116 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    117       EVP_CIPHER_CTX des_ctxs;
    118       des_ctx = &des_ctxs;
    119       EVP_CIPHER_CTX_init(des_ctx);
    120 #else
    121       des_ctx = EVP_CIPHER_CTX_new();
    122 #endif
    123       if (!EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, deskey, zero, 0)) {
    124 	*minor_status = EINVAL;
    125 	return GSS_S_FAILURE;
    126       }
    127       EVP_Cipher(des_ctx, p, p, input_message_buffer->length - len);
    128 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    129       EVP_CIPHER_CTX_cleanup(des_ctx);
    130 #else
    131       EVP_CIPHER_CTX_free(des_ctx);
    132 #endif
    133 
    134       memset (&schedule, 0, sizeof(schedule));
    135   }
    136 
    137   if (IS_DCE_STYLE(context_handle)) {
    138     padlength = 0;
    139   } else {
    140     /* check pad */
    141     ret = _gssapi_verify_pad(input_message_buffer,
    142 			     input_message_buffer->length - len - 8,
    143 			     &padlength);
    144     if (ret)
    145         return ret;
    146   }
    147 
    148   md5 = EVP_MD_CTX_create();
    149   EVP_DigestInit_ex(md5, EVP_md5(), NULL);
    150   EVP_DigestUpdate(md5, p - 24, 8);
    151   EVP_DigestUpdate(md5, p, input_message_buffer->length - len);
    152   EVP_DigestFinal_ex(md5, hash, NULL);
    153   EVP_MD_CTX_destroy(md5);
    154 
    155   memset (&zero, 0, sizeof(zero));
    156   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
    157   DES_set_key_unchecked (&deskey, &schedule);
    158   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
    159 		 &schedule, &zero);
    160   if (ct_memcmp (p - 8, hash, 8) != 0)
    161     return GSS_S_BAD_MIC;
    162 
    163   /* verify sequence number */
    164 
    165   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
    166 
    167   p -= 16;
    168 
    169 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    170   EVP_CIPHER_CTX des_ctxs;
    171   des_ctx = &des_ctxs;
    172   EVP_CIPHER_CTX_init(des_ctx);
    173 #else
    174   des_ctx = EVP_CIPHER_CTX_new();
    175 #endif
    176   if (!EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, hash,
    177       0)) {
    178     *minor_status = EINVAL;
    179     return GSS_S_FAILURE;
    180   }
    181   EVP_Cipher(des_ctx, p, p, 8);
    182 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    183   EVP_CIPHER_CTX_cleanup(des_ctx);
    184 #else
    185   EVP_CIPHER_CTX_free(des_ctx);
    186 #endif
    187 
    188   memset (deskey, 0, sizeof(deskey));
    189   memset (&schedule, 0, sizeof(schedule));
    190 
    191   seq = p;
    192   _gsskrb5_decode_om_uint32(seq, &seq_number);
    193 
    194   if (context_handle->more_flags & LOCAL)
    195       cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
    196   else
    197       cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
    198 
    199   if (cmp != 0) {
    200     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    201     return GSS_S_BAD_MIC;
    202   }
    203 
    204   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
    205   if (ret) {
    206     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    207     return ret;
    208   }
    209 
    210   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    211 
    212   /* copy out data */
    213 
    214   output_message_buffer->length = input_message_buffer->length
    215     - len - padlength - 8;
    216   output_message_buffer->value  = malloc(output_message_buffer->length);
    217   if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
    218       return GSS_S_FAILURE;
    219   if (output_message_buffer->value != NULL)
    220       memcpy (output_message_buffer->value,
    221 	      p + 24,
    222 	      output_message_buffer->length);
    223   return GSS_S_COMPLETE;
    224 }
    225 #endif
    226 
    227 static OM_uint32
    228 unwrap_des3
    229            (OM_uint32 * minor_status,
    230             const gsskrb5_ctx context_handle,
    231 	    krb5_context context,
    232             const gss_buffer_t input_message_buffer,
    233             gss_buffer_t output_message_buffer,
    234             int * conf_state,
    235             gss_qop_t * qop_state,
    236 	    krb5_keyblock *key
    237            )
    238 {
    239   u_char *p;
    240   size_t len;
    241   u_char *seq;
    242   krb5_data seq_data;
    243   u_char cksum[20];
    244   uint32_t seq_number;
    245   size_t padlength;
    246   OM_uint32 ret;
    247   int cstate;
    248   krb5_crypto crypto;
    249   Checksum csum;
    250   int cmp;
    251   int token_len;
    252 
    253   if (IS_DCE_STYLE(context_handle)) {
    254      token_len = 34 + 8 + 15; /* 57 */
    255      if (input_message_buffer->length < token_len)
    256 	  return GSS_S_BAD_MECH;
    257   } else {
    258      token_len = input_message_buffer->length;
    259   }
    260 
    261   p = input_message_buffer->value;
    262   ret = _gsskrb5_verify_header (&p,
    263 				   token_len,
    264 				   "\x02\x01",
    265 				   GSS_KRB5_MECHANISM);
    266   if (ret)
    267       return ret;
    268 
    269   len = (p - (u_char *)input_message_buffer->value)
    270       + 34 + 8;
    271   if (input_message_buffer->length < len)
    272       return GSS_S_BAD_MECH;
    273 
    274   if (ct_memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */
    275     return GSS_S_BAD_SIG;
    276   p += 2;
    277   if (ct_memcmp (p, "\x02\x00", 2) == 0) {
    278     cstate = 1;
    279   } else if (ct_memcmp (p, "\xff\xff", 2) == 0) {
    280     cstate = 0;
    281   } else
    282     return GSS_S_BAD_MIC;
    283   p += 2;
    284   if(conf_state != NULL)
    285     *conf_state = cstate;
    286   if (ct_memcmp (p, "\xff\xff", 2) != 0)
    287     return GSS_S_DEFECTIVE_TOKEN;
    288   p += 2;
    289   p += 28;
    290 
    291   len = p - (u_char *)input_message_buffer->value;
    292 
    293   if(cstate) {
    294       /* decrypt data */
    295       krb5_data tmp;
    296 
    297       ret = krb5_crypto_init(context, key,
    298 			     ETYPE_DES3_CBC_NONE, &crypto);
    299       if (ret) {
    300 	  *minor_status = ret;
    301 	  return GSS_S_FAILURE;
    302       }
    303       ret = krb5_decrypt(context, crypto, KRB5_KU_USAGE_SEAL,
    304 			 p, input_message_buffer->length - len, &tmp);
    305       krb5_crypto_destroy(context, crypto);
    306       if (ret) {
    307 	  *minor_status = ret;
    308 	  return GSS_S_FAILURE;
    309       }
    310       assert (tmp.length == input_message_buffer->length - len);
    311 
    312       memcpy (p, tmp.data, tmp.length);
    313       krb5_data_free(&tmp);
    314   }
    315 
    316   if (IS_DCE_STYLE(context_handle)) {
    317     padlength = 0;
    318   } else {
    319     /* check pad */
    320     ret = _gssapi_verify_pad(input_message_buffer,
    321 			     input_message_buffer->length - len - 8,
    322 			     &padlength);
    323     if (ret)
    324         return ret;
    325   }
    326 
    327   /* verify sequence number */
    328 
    329   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
    330 
    331   p -= 28;
    332 
    333   ret = krb5_crypto_init(context, key,
    334 			 ETYPE_DES3_CBC_NONE, &crypto);
    335   if (ret) {
    336       *minor_status = ret;
    337       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    338       return GSS_S_FAILURE;
    339   }
    340   {
    341       DES_cblock ivec;
    342 
    343       memcpy(&ivec, p + 8, 8);
    344       ret = krb5_decrypt_ivec (context,
    345 			       crypto,
    346 			       KRB5_KU_USAGE_SEQ,
    347 			       p, 8, &seq_data,
    348 			       &ivec);
    349   }
    350   krb5_crypto_destroy (context, crypto);
    351   if (ret) {
    352       *minor_status = ret;
    353       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    354       return GSS_S_FAILURE;
    355   }
    356   if (seq_data.length != 8) {
    357       krb5_data_free (&seq_data);
    358       *minor_status = 0;
    359       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    360       return GSS_S_BAD_MIC;
    361   }
    362 
    363   seq = seq_data.data;
    364   _gsskrb5_decode_om_uint32(seq, &seq_number);
    365 
    366   if (context_handle->more_flags & LOCAL)
    367       cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
    368   else
    369       cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
    370 
    371   krb5_data_free (&seq_data);
    372   if (cmp != 0) {
    373       *minor_status = 0;
    374       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    375       return GSS_S_BAD_MIC;
    376   }
    377 
    378   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
    379   if (ret) {
    380       *minor_status = 0;
    381       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    382       return ret;
    383   }
    384 
    385   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    386 
    387   /* verify checksum */
    388 
    389   memcpy (cksum, p + 8, 20);
    390 
    391   memcpy (p + 20, p - 8, 8);
    392 
    393   csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
    394   csum.checksum.length = 20;
    395   csum.checksum.data   = cksum;
    396 
    397   ret = krb5_crypto_init(context, key, 0, &crypto);
    398   if (ret) {
    399       *minor_status = ret;
    400       return GSS_S_FAILURE;
    401   }
    402 
    403   ret = krb5_verify_checksum (context, crypto,
    404 			      KRB5_KU_USAGE_SIGN,
    405 			      p + 20,
    406 			      input_message_buffer->length - len + 8,
    407 			      &csum);
    408   krb5_crypto_destroy (context, crypto);
    409   if (ret) {
    410       *minor_status = ret;
    411       return GSS_S_FAILURE;
    412   }
    413 
    414   /* copy out data */
    415 
    416   output_message_buffer->length = input_message_buffer->length
    417     - len - padlength - 8;
    418   output_message_buffer->value  = malloc(output_message_buffer->length);
    419   if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
    420       return GSS_S_FAILURE;
    421   if (output_message_buffer->value != NULL)
    422       memcpy (output_message_buffer->value,
    423 	      p + 36,
    424 	      output_message_buffer->length);
    425   return GSS_S_COMPLETE;
    426 }
    427 
    428 OM_uint32 GSSAPI_CALLCONV _gsskrb5_unwrap
    429            (OM_uint32 * minor_status,
    430             gss_const_ctx_id_t context_handle,
    431             const gss_buffer_t input_message_buffer,
    432             gss_buffer_t output_message_buffer,
    433             int * conf_state,
    434             gss_qop_t * qop_state
    435            )
    436 {
    437   krb5_keyblock *key;
    438   krb5_context context;
    439   OM_uint32 ret;
    440   gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle;
    441 
    442   output_message_buffer->value = NULL;
    443   output_message_buffer->length = 0;
    444   if (qop_state != NULL)
    445       *qop_state = GSS_C_QOP_DEFAULT;
    446 
    447   GSSAPI_KRB5_INIT (&context);
    448 
    449   if (ctx->more_flags & IS_CFX)
    450       return _gssapi_unwrap_cfx (minor_status, ctx, context,
    451 				 input_message_buffer, output_message_buffer,
    452 				 conf_state, qop_state);
    453 
    454   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
    455   ret = _gsskrb5i_get_token_key(ctx, context, &key);
    456   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    457   if (ret) {
    458       *minor_status = ret;
    459       return GSS_S_FAILURE;
    460   }
    461 
    462   *minor_status = 0;
    463 
    464   switch (key->keytype) {
    465   case KRB5_ENCTYPE_DES_CBC_CRC :
    466   case KRB5_ENCTYPE_DES_CBC_MD4 :
    467   case KRB5_ENCTYPE_DES_CBC_MD5 :
    468 #ifdef HEIM_WEAK_CRYPTO
    469       ret = unwrap_des (minor_status, ctx,
    470 			input_message_buffer, output_message_buffer,
    471 			conf_state, qop_state, key);
    472 #else
    473       ret = GSS_S_FAILURE;
    474 #endif
    475       break;
    476   case KRB5_ENCTYPE_DES3_CBC_MD5 :
    477   case KRB5_ENCTYPE_DES3_CBC_SHA1 :
    478       ret = unwrap_des3 (minor_status, ctx, context,
    479 			 input_message_buffer, output_message_buffer,
    480 			 conf_state, qop_state, key);
    481       break;
    482   case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5:
    483   case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56:
    484       ret = _gssapi_unwrap_arcfour (minor_status, ctx, context,
    485 				    input_message_buffer, output_message_buffer,
    486 				    conf_state, qop_state, key);
    487       break;
    488   default :
    489       abort();
    490       break;
    491   }
    492   krb5_free_keyblock (context, key);
    493   return ret;
    494 }
    495