xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/gssapi/krb5/verify_mic.c (revision afab4e300d3a9fb07dd8c80daf53d0feb3345706)
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