Home | History | Annotate | Line # | Download | only in krb5
      1 /*	$NetBSD: verify_mic.c,v 1.7 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 #ifdef HEIM_WEAK_CRYPTO
     39 
     40 static OM_uint32
     41 verify_mic_des
     42            (OM_uint32 * minor_status,
     43             const gsskrb5_ctx context_handle,
     44 	    krb5_context context,
     45             const gss_buffer_t message_buffer,
     46             const gss_buffer_t token_buffer,
     47             gss_qop_t * qop_state,
     48 	    krb5_keyblock *key,
     49 	    const char *type
     50 	    )
     51 {
     52   u_char *p;
     53   EVP_MD_CTX *md5;
     54   u_char hash[16], *seq;
     55   DES_key_schedule schedule;
     56   EVP_CIPHER_CTX *des_ctx;
     57   DES_cblock zero;
     58   DES_cblock deskey;
     59   uint32_t seq_number;
     60   OM_uint32 ret;
     61   int cmp;
     62 
     63   p = token_buffer->value;
     64   ret = _gsskrb5_verify_header (&p,
     65 				   token_buffer->length,
     66 				   type,
     67 				   GSS_KRB5_MECHANISM);
     68   if (ret)
     69       return ret;
     70 
     71   if (memcmp(p, "\x00\x00", 2) != 0)
     72       return GSS_S_BAD_SIG;
     73   p += 2;
     74   if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
     75     return GSS_S_BAD_MIC;
     76   p += 4;
     77   p += 16;
     78 
     79   /* verify checksum */
     80   md5 = EVP_MD_CTX_create();
     81   EVP_DigestInit_ex(md5, EVP_md5(), NULL);
     82   EVP_DigestUpdate(md5, p - 24, 8);
     83   EVP_DigestUpdate(md5, message_buffer->value, message_buffer->length);
     84   EVP_DigestFinal_ex(md5, hash, NULL);
     85   EVP_MD_CTX_destroy(md5);
     86 
     87   memset (&zero, 0, sizeof(zero));
     88   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
     89 
     90   DES_set_key_unchecked (&deskey, &schedule);
     91   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
     92 		 &schedule, &zero);
     93   if (ct_memcmp (p - 8, hash, 8) != 0) {
     94     memset_s(deskey, sizeof(deskey), 0, sizeof(deskey));
     95     memset_s(&schedule, sizeof(schedule), 0, sizeof(schedule));
     96     return GSS_S_BAD_MIC;
     97   }
     98 
     99   /* verify sequence number */
    100 
    101   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
    102 
    103   p -= 16;
    104 
    105 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    106   EVP_CIPHER_CTX des_ctxs;
    107   des_ctx = &des_ctxs;
    108   EVP_CIPHER_CTX_init(des_ctx);
    109 #else
    110   des_ctx = EVP_CIPHER_CTX_new();
    111 #endif
    112   if (!EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data,
    113       hash, 0)) {
    114     *minor_status = EINVAL;
    115     return GSS_S_FAILURE;
    116   }
    117   EVP_Cipher(des_ctx, p, p, 8);
    118 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    119   EVP_CIPHER_CTX_cleanup(des_ctx);
    120 #else
    121   EVP_CIPHER_CTX_free(des_ctx);
    122 #endif
    123 
    124   memset_s(deskey, sizeof(deskey), 0, sizeof(deskey));
    125   memset_s(&schedule, sizeof(schedule), 0, sizeof(schedule));
    126 
    127   seq = p;
    128   _gsskrb5_decode_om_uint32(seq, &seq_number);
    129 
    130   if (context_handle->more_flags & LOCAL)
    131       cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
    132   else
    133       cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
    134 
    135   if (cmp != 0) {
    136     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    137     return GSS_S_BAD_MIC;
    138   }
    139 
    140   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
    141   if (ret) {
    142       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    143       return ret;
    144   }
    145 
    146   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    147 
    148   return GSS_S_COMPLETE;
    149 }
    150 #endif
    151 
    152 static OM_uint32
    153 verify_mic_des3
    154            (OM_uint32 * minor_status,
    155             const gsskrb5_ctx context_handle,
    156 	    krb5_context context,
    157             const gss_buffer_t message_buffer,
    158             const gss_buffer_t token_buffer,
    159             gss_qop_t * qop_state,
    160 	    krb5_keyblock *key,
    161 	    const char *type
    162 	    )
    163 {
    164   u_char *p;
    165   u_char *seq;
    166   uint32_t seq_number;
    167   OM_uint32 ret;
    168   krb5_crypto crypto;
    169   krb5_data seq_data;
    170   int cmp, docompat;
    171   Checksum csum;
    172   char *tmp;
    173   char ivec[8];
    174 
    175   p = token_buffer->value;
    176   ret = _gsskrb5_verify_header (&p,
    177 				   token_buffer->length,
    178 				   type,
    179 				   GSS_KRB5_MECHANISM);
    180   if (ret)
    181       return ret;
    182 
    183   if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */
    184       return GSS_S_BAD_SIG;
    185   p += 2;
    186   if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
    187     return GSS_S_BAD_MIC;
    188   p += 4;
    189 
    190   ret = krb5_crypto_init(context, key,
    191 			 ETYPE_DES3_CBC_NONE, &crypto);
    192   if (ret){
    193       *minor_status = ret;
    194       return GSS_S_FAILURE;
    195   }
    196 
    197   /* verify sequence number */
    198   docompat = 0;
    199 retry:
    200   if (docompat)
    201       memset(ivec, 0, 8);
    202   else
    203       memcpy(ivec, p + 8, 8);
    204 
    205   ret = krb5_decrypt_ivec (context,
    206 			   crypto,
    207 			   KRB5_KU_USAGE_SEQ,
    208 			   p, 8, &seq_data, ivec);
    209   if (ret) {
    210       if (docompat++) {
    211 	  krb5_crypto_destroy (context, crypto);
    212 	  *minor_status = ret;
    213 	  return GSS_S_FAILURE;
    214       } else
    215 	  goto retry;
    216   }
    217 
    218   if (seq_data.length != 8) {
    219       krb5_data_free (&seq_data);
    220       if (docompat++) {
    221 	  krb5_crypto_destroy (context, crypto);
    222 	  return GSS_S_BAD_MIC;
    223       } else
    224 	  goto retry;
    225   }
    226 
    227   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
    228 
    229   seq = seq_data.data;
    230   _gsskrb5_decode_om_uint32(seq, &seq_number);
    231 
    232   if (context_handle->more_flags & LOCAL)
    233       cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
    234   else
    235       cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
    236 
    237   krb5_data_free (&seq_data);
    238   if (cmp != 0) {
    239       krb5_crypto_destroy (context, crypto);
    240       *minor_status = 0;
    241       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    242       return GSS_S_BAD_MIC;
    243   }
    244 
    245   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
    246   if (ret) {
    247       krb5_crypto_destroy (context, crypto);
    248       *minor_status = 0;
    249       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    250       return ret;
    251   }
    252 
    253   /* verify checksum */
    254 
    255   tmp = malloc (message_buffer->length + 8);
    256   if (tmp == NULL) {
    257       krb5_crypto_destroy (context, crypto);
    258       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    259       *minor_status = ENOMEM;
    260       return GSS_S_FAILURE;
    261   }
    262 
    263   memcpy (tmp, p - 8, 8);
    264   memcpy (tmp + 8, message_buffer->value, message_buffer->length);
    265 
    266   csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
    267   csum.checksum.length = 20;
    268   csum.checksum.data   = p + 8;
    269 
    270   krb5_crypto_destroy (context, crypto);
    271   ret = krb5_crypto_init(context, key,
    272 			 ETYPE_DES3_CBC_SHA1, &crypto);
    273   if (ret) {
    274       free (tmp);
    275       *minor_status = ret;
    276       return GSS_S_FAILURE;
    277   }
    278 
    279   ret = krb5_verify_checksum (context, crypto,
    280 			      KRB5_KU_USAGE_SIGN,
    281 			      tmp, message_buffer->length + 8,
    282 			      &csum);
    283   free (tmp);
    284   if (ret) {
    285       krb5_crypto_destroy (context, crypto);
    286       *minor_status = ret;
    287       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    288       return GSS_S_BAD_MIC;
    289   }
    290   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    291 
    292   krb5_crypto_destroy (context, crypto);
    293   return GSS_S_COMPLETE;
    294 }
    295 
    296 OM_uint32
    297 _gsskrb5_verify_mic_internal
    298            (OM_uint32 * minor_status,
    299             const gsskrb5_ctx ctx,
    300 	    krb5_context context,
    301             const gss_buffer_t message_buffer,
    302             const gss_buffer_t token_buffer,
    303             gss_qop_t * qop_state,
    304 	    const char * type
    305 	    )
    306 {
    307     krb5_keyblock *key;
    308     OM_uint32 ret;
    309 
    310     if (ctx->more_flags & IS_CFX)
    311         return _gssapi_verify_mic_cfx (minor_status, ctx,
    312 				       context, message_buffer, token_buffer,
    313 				       qop_state);
    314 
    315     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
    316     ret = _gsskrb5i_get_token_key(ctx, context, &key);
    317     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    318     if (ret) {
    319 	*minor_status = ret;
    320 	return GSS_S_FAILURE;
    321     }
    322     *minor_status = 0;
    323 
    324     switch (key->keytype) {
    325     case KRB5_ENCTYPE_DES_CBC_CRC :
    326     case KRB5_ENCTYPE_DES_CBC_MD4 :
    327     case KRB5_ENCTYPE_DES_CBC_MD5 :
    328 #ifdef HEIM_WEAK_CRYPTO
    329 	ret = verify_mic_des (minor_status, ctx, context,
    330 			      message_buffer, token_buffer, qop_state, key,
    331 			      type);
    332 #else
    333       ret = GSS_S_FAILURE;
    334 #endif
    335 	break;
    336     case KRB5_ENCTYPE_DES3_CBC_MD5 :
    337     case KRB5_ENCTYPE_DES3_CBC_SHA1 :
    338 	ret = verify_mic_des3 (minor_status, ctx, context,
    339 			       message_buffer, token_buffer, qop_state, key,
    340 			       type);
    341 	break;
    342     case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5:
    343     case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56:
    344 	ret = _gssapi_verify_mic_arcfour (minor_status, ctx,
    345 					  context,
    346 					  message_buffer, token_buffer,
    347 					  qop_state, key, type);
    348 	break;
    349     default :
    350         abort();
    351     }
    352     krb5_free_keyblock (context, key);
    353 
    354     return ret;
    355 }
    356 
    357 OM_uint32 GSSAPI_CALLCONV
    358 _gsskrb5_verify_mic
    359            (OM_uint32 * minor_status,
    360             gss_const_ctx_id_t context_handle,
    361             const gss_buffer_t message_buffer,
    362             const gss_buffer_t token_buffer,
    363             gss_qop_t * qop_state
    364 	    )
    365 {
    366     krb5_context context;
    367     OM_uint32 ret;
    368 
    369     GSSAPI_KRB5_INIT (&context);
    370 
    371     if (qop_state != NULL)
    372 	*qop_state = GSS_C_QOP_DEFAULT;
    373 
    374     ret = _gsskrb5_verify_mic_internal(minor_status,
    375 				       (gsskrb5_ctx)context_handle,
    376 				       context,
    377 				       message_buffer, token_buffer,
    378 				       qop_state, (void *)(intptr_t)"\x01\x01");
    379 
    380     return ret;
    381 }
    382