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