xref: /freebsd/crypto/heimdal/lib/gssapi/krb5/verify_mic.c (revision 39ee7a7a6bdd1557b1c3532abf60d139798ac88b)
1 /*
2  * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "gsskrb5_locl.h"
35 
36 #ifdef HEIM_WEAK_CRYPTO
37 
38 static OM_uint32
39 verify_mic_des
40            (OM_uint32 * minor_status,
41             const gsskrb5_ctx context_handle,
42 	    krb5_context context,
43             const gss_buffer_t message_buffer,
44             const gss_buffer_t token_buffer,
45             gss_qop_t * qop_state,
46 	    krb5_keyblock *key,
47 	    const char *type
48 	    )
49 {
50   u_char *p;
51   EVP_MD_CTX *md5;
52   u_char hash[16], *seq;
53   DES_key_schedule schedule;
54   EVP_CIPHER_CTX des_ctx;
55   DES_cblock zero;
56   DES_cblock deskey;
57   uint32_t seq_number;
58   OM_uint32 ret;
59   int cmp;
60 
61   p = token_buffer->value;
62   ret = _gsskrb5_verify_header (&p,
63 				   token_buffer->length,
64 				   type,
65 				   GSS_KRB5_MECHANISM);
66   if (ret)
67       return ret;
68 
69   if (memcmp(p, "\x00\x00", 2) != 0)
70       return GSS_S_BAD_SIG;
71   p += 2;
72   if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
73     return GSS_S_BAD_MIC;
74   p += 4;
75   p += 16;
76 
77   /* verify checksum */
78   md5 = EVP_MD_CTX_create();
79   EVP_DigestInit_ex(md5, EVP_md5(), NULL);
80   EVP_DigestUpdate(md5, p - 24, 8);
81   EVP_DigestUpdate(md5, message_buffer->value, message_buffer->length);
82   EVP_DigestFinal_ex(md5, hash, NULL);
83   EVP_MD_CTX_destroy(md5);
84 
85   memset (&zero, 0, sizeof(zero));
86   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
87 
88   DES_set_key_unchecked (&deskey, &schedule);
89   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
90 		 &schedule, &zero);
91   if (ct_memcmp (p - 8, hash, 8) != 0) {
92     memset (deskey, 0, sizeof(deskey));
93     memset (&schedule, 0, sizeof(schedule));
94     return GSS_S_BAD_MIC;
95   }
96 
97   /* verify sequence number */
98 
99   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
100 
101   p -= 16;
102 
103   EVP_CIPHER_CTX_init(&des_ctx);
104   EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, hash, 0);
105   EVP_Cipher(&des_ctx, p, p, 8);
106   EVP_CIPHER_CTX_cleanup(&des_ctx);
107 
108   memset (deskey, 0, sizeof(deskey));
109   memset (&schedule, 0, sizeof(schedule));
110 
111   seq = p;
112   _gsskrb5_decode_om_uint32(seq, &seq_number);
113 
114   if (context_handle->more_flags & LOCAL)
115       cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
116   else
117       cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
118 
119   if (cmp != 0) {
120     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
121     return GSS_S_BAD_MIC;
122   }
123 
124   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
125   if (ret) {
126       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
127       return ret;
128   }
129 
130   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
131 
132   return GSS_S_COMPLETE;
133 }
134 #endif
135 
136 static OM_uint32
137 verify_mic_des3
138            (OM_uint32 * minor_status,
139             const gsskrb5_ctx context_handle,
140 	    krb5_context context,
141             const gss_buffer_t message_buffer,
142             const gss_buffer_t token_buffer,
143             gss_qop_t * qop_state,
144 	    krb5_keyblock *key,
145 	    const char *type
146 	    )
147 {
148   u_char *p;
149   u_char *seq;
150   uint32_t seq_number;
151   OM_uint32 ret;
152   krb5_crypto crypto;
153   krb5_data seq_data;
154   int cmp, docompat;
155   Checksum csum;
156   char *tmp;
157   char ivec[8];
158 
159   p = token_buffer->value;
160   ret = _gsskrb5_verify_header (&p,
161 				   token_buffer->length,
162 				   type,
163 				   GSS_KRB5_MECHANISM);
164   if (ret)
165       return ret;
166 
167   if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */
168       return GSS_S_BAD_SIG;
169   p += 2;
170   if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
171     return GSS_S_BAD_MIC;
172   p += 4;
173 
174   ret = krb5_crypto_init(context, key,
175 			 ETYPE_DES3_CBC_NONE, &crypto);
176   if (ret){
177       *minor_status = ret;
178       return GSS_S_FAILURE;
179   }
180 
181   /* verify sequence number */
182   docompat = 0;
183 retry:
184   if (docompat)
185       memset(ivec, 0, 8);
186   else
187       memcpy(ivec, p + 8, 8);
188 
189   ret = krb5_decrypt_ivec (context,
190 			   crypto,
191 			   KRB5_KU_USAGE_SEQ,
192 			   p, 8, &seq_data, ivec);
193   if (ret) {
194       if (docompat++) {
195 	  krb5_crypto_destroy (context, crypto);
196 	  *minor_status = ret;
197 	  return GSS_S_FAILURE;
198       } else
199 	  goto retry;
200   }
201 
202   if (seq_data.length != 8) {
203       krb5_data_free (&seq_data);
204       if (docompat++) {
205 	  krb5_crypto_destroy (context, crypto);
206 	  return GSS_S_BAD_MIC;
207       } else
208 	  goto retry;
209   }
210 
211   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
212 
213   seq = seq_data.data;
214   _gsskrb5_decode_om_uint32(seq, &seq_number);
215 
216   if (context_handle->more_flags & LOCAL)
217       cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
218   else
219       cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
220 
221   krb5_data_free (&seq_data);
222   if (cmp != 0) {
223       krb5_crypto_destroy (context, crypto);
224       *minor_status = 0;
225       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
226       return GSS_S_BAD_MIC;
227   }
228 
229   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
230   if (ret) {
231       krb5_crypto_destroy (context, crypto);
232       *minor_status = 0;
233       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
234       return ret;
235   }
236 
237   /* verify checksum */
238 
239   tmp = malloc (message_buffer->length + 8);
240   if (tmp == NULL) {
241       krb5_crypto_destroy (context, crypto);
242       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
243       *minor_status = ENOMEM;
244       return GSS_S_FAILURE;
245   }
246 
247   memcpy (tmp, p - 8, 8);
248   memcpy (tmp + 8, message_buffer->value, message_buffer->length);
249 
250   csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
251   csum.checksum.length = 20;
252   csum.checksum.data   = p + 8;
253 
254   krb5_crypto_destroy (context, crypto);
255   ret = krb5_crypto_init(context, key,
256 			 ETYPE_DES3_CBC_SHA1, &crypto);
257   if (ret){
258       *minor_status = ret;
259       return GSS_S_FAILURE;
260   }
261 
262   ret = krb5_verify_checksum (context, crypto,
263 			      KRB5_KU_USAGE_SIGN,
264 			      tmp, message_buffer->length + 8,
265 			      &csum);
266   free (tmp);
267   if (ret) {
268       krb5_crypto_destroy (context, crypto);
269       *minor_status = ret;
270       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
271       return GSS_S_BAD_MIC;
272   }
273   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
274 
275   krb5_crypto_destroy (context, crypto);
276   return GSS_S_COMPLETE;
277 }
278 
279 OM_uint32
280 _gsskrb5_verify_mic_internal
281            (OM_uint32 * minor_status,
282             const gsskrb5_ctx ctx,
283 	    krb5_context context,
284             const gss_buffer_t message_buffer,
285             const gss_buffer_t token_buffer,
286             gss_qop_t * qop_state,
287 	    const char * type
288 	    )
289 {
290     krb5_keyblock *key;
291     OM_uint32 ret;
292     krb5_keytype keytype;
293 
294     if (ctx->more_flags & IS_CFX)
295         return _gssapi_verify_mic_cfx (minor_status, ctx,
296 				       context, message_buffer, token_buffer,
297 				       qop_state);
298 
299     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
300     ret = _gsskrb5i_get_token_key(ctx, context, &key);
301     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
302     if (ret) {
303 	*minor_status = ret;
304 	return GSS_S_FAILURE;
305     }
306     *minor_status = 0;
307     krb5_enctype_to_keytype (context, key->keytype, &keytype);
308     switch (keytype) {
309     case KEYTYPE_DES :
310 #ifdef HEIM_WEAK_CRYPTO
311 	ret = verify_mic_des (minor_status, ctx, context,
312 			      message_buffer, token_buffer, qop_state, key,
313 			      type);
314 #else
315       ret = GSS_S_FAILURE;
316 #endif
317 	break;
318     case KEYTYPE_DES3 :
319 	ret = verify_mic_des3 (minor_status, ctx, context,
320 			       message_buffer, token_buffer, qop_state, key,
321 			       type);
322 	break;
323     case KEYTYPE_ARCFOUR :
324     case KEYTYPE_ARCFOUR_56 :
325 	ret = _gssapi_verify_mic_arcfour (minor_status, ctx,
326 					  context,
327 					  message_buffer, token_buffer,
328 					  qop_state, key, type);
329 	break;
330     default :
331         abort();
332     }
333     krb5_free_keyblock (context, key);
334 
335     return ret;
336 }
337 
338 OM_uint32 GSSAPI_CALLCONV
339 _gsskrb5_verify_mic
340            (OM_uint32 * minor_status,
341             const gss_ctx_id_t context_handle,
342             const gss_buffer_t message_buffer,
343             const gss_buffer_t token_buffer,
344             gss_qop_t * qop_state
345 	    )
346 {
347     krb5_context context;
348     OM_uint32 ret;
349 
350     GSSAPI_KRB5_INIT (&context);
351 
352     if (qop_state != NULL)
353 	*qop_state = GSS_C_QOP_DEFAULT;
354 
355     ret = _gsskrb5_verify_mic_internal(minor_status,
356 				       (gsskrb5_ctx)context_handle,
357 				       context,
358 				       message_buffer, token_buffer,
359 				       qop_state, (void *)(intptr_t)"\x01\x01");
360 
361     return ret;
362 }
363