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 H��gskolan 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 40static OM_uint32 41verify_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 152static OM_uint32 153verify_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; 199retry: 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 296OM_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 357OM_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