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