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 "krb5/gsskrb5_locl.h"
35 
36 RCSID("$Id: verify_mic.c 19031 2006-11-13 18:02:57Z lha $");
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 	    char *type
48 	    )
49 {
50   u_char *p;
51   MD5_CTX md5;
52   u_char hash[16], *seq;
53   DES_key_schedule schedule;
54   DES_cblock zero;
55   DES_cblock deskey;
56   uint32_t seq_number;
57   OM_uint32 ret;
58   int cmp;
59 
60   p = token_buffer->value;
61   ret = _gsskrb5_verify_header (&p,
62 				   token_buffer->length,
63 				   type,
64 				   GSS_KRB5_MECHANISM);
65   if (ret)
66       return ret;
67 
68   if (memcmp(p, "\x00\x00", 2) != 0)
69       return GSS_S_BAD_SIG;
70   p += 2;
71   if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
72     return GSS_S_BAD_MIC;
73   p += 4;
74   p += 16;
75 
76   /* verify checksum */
77   MD5_Init (&md5);
78   MD5_Update (&md5, p - 24, 8);
79   MD5_Update (&md5, message_buffer->value,
80 	     message_buffer->length);
81   MD5_Final (hash, &md5);
82 
83   memset (&zero, 0, sizeof(zero));
84   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
85 
86   DES_set_key (&deskey, &schedule);
87   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
88 		 &schedule, &zero);
89   if (memcmp (p - 8, hash, 8) != 0) {
90     memset (deskey, 0, sizeof(deskey));
91     memset (&schedule, 0, sizeof(schedule));
92     return GSS_S_BAD_MIC;
93   }
94 
95   /* verify sequence number */
96 
97   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
98 
99   p -= 16;
100   DES_set_key (&deskey, &schedule);
101   DES_cbc_encrypt ((void *)p, (void *)p, 8,
102 		   &schedule, (DES_cblock *)hash, DES_DECRYPT);
103 
104   memset (deskey, 0, sizeof(deskey));
105   memset (&schedule, 0, sizeof(schedule));
106 
107   seq = p;
108   _gsskrb5_decode_om_uint32(seq, &seq_number);
109 
110   if (context_handle->more_flags & LOCAL)
111       cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
112   else
113       cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
114 
115   if (cmp != 0) {
116     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
117     return GSS_S_BAD_MIC;
118   }
119 
120   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
121   if (ret) {
122       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
123       return ret;
124   }
125 
126   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
127 
128   return GSS_S_COMPLETE;
129 }
130 
131 static OM_uint32
132 verify_mic_des3
133            (OM_uint32 * minor_status,
134             const gsskrb5_ctx context_handle,
135 	    krb5_context context,
136             const gss_buffer_t message_buffer,
137             const gss_buffer_t token_buffer,
138             gss_qop_t * qop_state,
139 	    krb5_keyblock *key,
140 	    char *type
141 	    )
142 {
143   u_char *p;
144   u_char *seq;
145   uint32_t seq_number;
146   OM_uint32 ret;
147   krb5_crypto crypto;
148   krb5_data seq_data;
149   int cmp, docompat;
150   Checksum csum;
151   char *tmp;
152   char ivec[8];
153 
154   p = token_buffer->value;
155   ret = _gsskrb5_verify_header (&p,
156 				   token_buffer->length,
157 				   type,
158 				   GSS_KRB5_MECHANISM);
159   if (ret)
160       return ret;
161 
162   if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */
163       return GSS_S_BAD_SIG;
164   p += 2;
165   if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
166     return GSS_S_BAD_MIC;
167   p += 4;
168 
169   ret = krb5_crypto_init(context, key,
170 			 ETYPE_DES3_CBC_NONE, &crypto);
171   if (ret){
172       *minor_status = ret;
173       return GSS_S_FAILURE;
174   }
175 
176   /* verify sequence number */
177   docompat = 0;
178 retry:
179   if (docompat)
180       memset(ivec, 0, 8);
181   else
182       memcpy(ivec, p + 8, 8);
183 
184   ret = krb5_decrypt_ivec (context,
185 			   crypto,
186 			   KRB5_KU_USAGE_SEQ,
187 			   p, 8, &seq_data, ivec);
188   if (ret) {
189       if (docompat++) {
190 	  krb5_crypto_destroy (context, crypto);
191 	  *minor_status = ret;
192 	  return GSS_S_FAILURE;
193       } else
194 	  goto retry;
195   }
196 
197   if (seq_data.length != 8) {
198       krb5_data_free (&seq_data);
199       if (docompat++) {
200 	  krb5_crypto_destroy (context, crypto);
201 	  return GSS_S_BAD_MIC;
202       } else
203 	  goto retry;
204   }
205 
206   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
207 
208   seq = seq_data.data;
209   _gsskrb5_decode_om_uint32(seq, &seq_number);
210 
211   if (context_handle->more_flags & LOCAL)
212       cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
213   else
214       cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
215 
216   krb5_data_free (&seq_data);
217   if (cmp != 0) {
218       krb5_crypto_destroy (context, crypto);
219       *minor_status = 0;
220       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
221       return GSS_S_BAD_MIC;
222   }
223 
224   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
225   if (ret) {
226       krb5_crypto_destroy (context, crypto);
227       *minor_status = 0;
228       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
229       return ret;
230   }
231 
232   /* verify checksum */
233 
234   tmp = malloc (message_buffer->length + 8);
235   if (tmp == NULL) {
236       krb5_crypto_destroy (context, crypto);
237       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
238       *minor_status = ENOMEM;
239       return GSS_S_FAILURE;
240   }
241 
242   memcpy (tmp, p - 8, 8);
243   memcpy (tmp + 8, message_buffer->value, message_buffer->length);
244 
245   csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
246   csum.checksum.length = 20;
247   csum.checksum.data   = p + 8;
248 
249   ret = krb5_verify_checksum (context, crypto,
250 			      KRB5_KU_USAGE_SIGN,
251 			      tmp, message_buffer->length + 8,
252 			      &csum);
253   free (tmp);
254   if (ret) {
255       krb5_crypto_destroy (context, crypto);
256       *minor_status = ret;
257       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
258       return GSS_S_BAD_MIC;
259   }
260   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
261 
262   krb5_crypto_destroy (context, crypto);
263   return GSS_S_COMPLETE;
264 }
265 
266 OM_uint32
267 _gsskrb5_verify_mic_internal
268            (OM_uint32 * minor_status,
269             const gsskrb5_ctx context_handle,
270 	    krb5_context context,
271             const gss_buffer_t message_buffer,
272             const gss_buffer_t token_buffer,
273             gss_qop_t * qop_state,
274 	    char * type
275 	    )
276 {
277     krb5_keyblock *key;
278     OM_uint32 ret;
279     krb5_keytype keytype;
280 
281     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
282     ret = _gsskrb5i_get_token_key(context_handle, context, &key);
283     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
284     if (ret) {
285 	*minor_status = ret;
286 	return GSS_S_FAILURE;
287     }
288     *minor_status = 0;
289     krb5_enctype_to_keytype (context, key->keytype, &keytype);
290     switch (keytype) {
291     case KEYTYPE_DES :
292 	ret = verify_mic_des (minor_status, context_handle, context,
293 			      message_buffer, token_buffer, qop_state, key,
294 			      type);
295 	break;
296     case KEYTYPE_DES3 :
297 	ret = verify_mic_des3 (minor_status, context_handle, context,
298 			       message_buffer, token_buffer, qop_state, key,
299 			       type);
300 	break;
301     case KEYTYPE_ARCFOUR :
302     case KEYTYPE_ARCFOUR_56 :
303 	ret = _gssapi_verify_mic_arcfour (minor_status, context_handle,
304 					  context,
305 					  message_buffer, token_buffer,
306 					  qop_state, key, type);
307 	break;
308     default :
309 	ret = _gssapi_verify_mic_cfx (minor_status, context_handle,
310 				      context,
311 				      message_buffer, token_buffer, qop_state,
312 				      key);
313 	break;
314     }
315     krb5_free_keyblock (context, key);
316 
317     return ret;
318 }
319 
320 OM_uint32
321 _gsskrb5_verify_mic
322            (OM_uint32 * minor_status,
323             const gss_ctx_id_t context_handle,
324             const gss_buffer_t message_buffer,
325             const gss_buffer_t token_buffer,
326             gss_qop_t * qop_state
327 	    )
328 {
329     krb5_context context;
330     OM_uint32 ret;
331 
332     GSSAPI_KRB5_INIT (&context);
333 
334     if (qop_state != NULL)
335 	*qop_state = GSS_C_QOP_DEFAULT;
336 
337     ret = _gsskrb5_verify_mic_internal(minor_status,
338 				       (gsskrb5_ctx)context_handle,
339 				       context,
340 				       message_buffer, token_buffer,
341 				       qop_state, "\x01\x01");
342 
343     return ret;
344 }
345