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
40 static OM_uint32
verify_mic_des(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,krb5_context context,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state,krb5_keyblock * key,const char * type)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
verify_mic_des3(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,krb5_context context,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state,krb5_keyblock * key,const char * type)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
_gsskrb5_verify_mic_internal(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state,const char * type)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
_gsskrb5_verify_mic(OM_uint32 * minor_status,gss_const_ctx_id_t context_handle,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state)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