r8302: import mini HEIMDAL into the tree
[samba.git] / source4 / heimdal / lib / gssapi / verify_mic.c
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 "gssapi_locl.h"
35
36 RCSID("$Id: verify_mic.c,v 1.32 2005/04/27 17:51:04 lha Exp $");
37
38 static OM_uint32
39 verify_mic_des
40            (OM_uint32 * minor_status,
41             const gss_ctx_id_t context_handle,
42             const gss_buffer_t message_buffer,
43             const gss_buffer_t token_buffer,
44             gss_qop_t * qop_state,
45             krb5_keyblock *key,
46             char *type
47             )
48 {
49   u_char *p;
50   MD5_CTX md5;
51   u_char hash[16], *seq;
52   DES_key_schedule schedule;
53   DES_cblock zero;
54   DES_cblock deskey;
55   int32_t seq_number;
56   OM_uint32 ret;
57   int cmp;
58
59   p = token_buffer->value;
60   ret = gssapi_krb5_verify_header (&p,
61                                    token_buffer->length,
62                                    type,
63                                    GSS_KRB5_MECHANISM);
64   if (ret)
65       return ret;
66
67   if (memcmp(p, "\x00\x00", 2) != 0)
68       return GSS_S_BAD_SIG;
69   p += 2;
70   if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
71     return GSS_S_BAD_MIC;
72   p += 4;
73   p += 16;
74
75   /* verify checksum */
76   MD5_Init (&md5);
77   MD5_Update (&md5, p - 24, 8);
78   MD5_Update (&md5, message_buffer->value,
79              message_buffer->length);
80   MD5_Final (hash, &md5);
81
82   memset (&zero, 0, sizeof(zero));
83   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
84
85   DES_set_key (&deskey, &schedule);
86   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
87                  &schedule, &zero);
88   if (memcmp (p - 8, hash, 8) != 0) {
89     memset (deskey, 0, sizeof(deskey));
90     memset (&schedule, 0, sizeof(schedule));
91     return GSS_S_BAD_MIC;
92   }
93
94   /* verify sequence number */
95   
96   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
97
98   p -= 16;
99   DES_set_key (&deskey, &schedule);
100   DES_cbc_encrypt ((void *)p, (void *)p, 8,
101                    &schedule, (DES_cblock *)hash, DES_DECRYPT);
102
103   memset (deskey, 0, sizeof(deskey));
104   memset (&schedule, 0, sizeof(schedule));
105
106   seq = p;
107   gssapi_decode_om_uint32(seq, &seq_number);
108
109   if (context_handle->more_flags & LOCAL)
110       cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
111   else
112       cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
113
114   if (cmp != 0) {
115     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
116     return GSS_S_BAD_MIC;
117   }
118
119   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
120   if (ret) {
121       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
122       return ret;
123   }
124
125   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
126
127   return GSS_S_COMPLETE;
128 }
129
130 static OM_uint32
131 verify_mic_des3
132            (OM_uint32 * minor_status,
133             const gss_ctx_id_t context_handle,
134             const gss_buffer_t message_buffer,
135             const gss_buffer_t token_buffer,
136             gss_qop_t * qop_state,
137             krb5_keyblock *key,
138             char *type
139             )
140 {
141   u_char *p;
142   u_char *seq;
143   int32_t seq_number;
144   OM_uint32 ret;
145   krb5_crypto crypto;
146   krb5_data seq_data;
147   int cmp, docompat;
148   Checksum csum;
149   char *tmp;
150   char ivec[8];
151   
152   p = token_buffer->value;
153   ret = gssapi_krb5_verify_header (&p,
154                                    token_buffer->length,
155                                    type,
156                                    GSS_KRB5_MECHANISM);
157   if (ret)
158       return ret;
159
160   if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */
161       return GSS_S_BAD_SIG;
162   p += 2;
163   if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
164     return GSS_S_BAD_MIC;
165   p += 4;
166
167   ret = krb5_crypto_init(gssapi_krb5_context, key,
168                          ETYPE_DES3_CBC_NONE, &crypto);
169   if (ret){
170       gssapi_krb5_set_error_string ();
171       *minor_status = ret;
172       return GSS_S_FAILURE;
173   }
174
175   /* verify sequence number */
176   docompat = 0;
177 retry:
178   if (docompat)
179       memset(ivec, 0, 8);
180   else
181       memcpy(ivec, p + 8, 8);
182
183   ret = krb5_decrypt_ivec (gssapi_krb5_context,
184                            crypto,
185                            KRB5_KU_USAGE_SEQ,
186                            p, 8, &seq_data, ivec);
187   if (ret) {
188       if (docompat++) {
189           gssapi_krb5_set_error_string ();
190           krb5_crypto_destroy (gssapi_krb5_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 (gssapi_krb5_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   gssapi_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 (gssapi_krb5_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 (gssapi_krb5_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 (gssapi_krb5_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 (gssapi_krb5_context, crypto,
250                               KRB5_KU_USAGE_SIGN,
251                               tmp, message_buffer->length + 8,
252                               &csum);
253   free (tmp);
254   if (ret) {
255       gssapi_krb5_set_error_string ();
256       krb5_crypto_destroy (gssapi_krb5_context, crypto);
257       *minor_status = ret;
258       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
259       return GSS_S_BAD_MIC;
260   }
261   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
262
263   krb5_crypto_destroy (gssapi_krb5_context, crypto);
264   return GSS_S_COMPLETE;
265 }
266
267 OM_uint32
268 gss_verify_mic_internal
269            (OM_uint32 * minor_status,
270             const gss_ctx_id_t context_handle,
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     ret = gss_krb5_get_subkey(context_handle, &key);
282     if (ret) {
283         gssapi_krb5_set_error_string ();
284         *minor_status = ret;
285         return GSS_S_FAILURE;
286     }
287     *minor_status = 0;
288     krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
289     switch (keytype) {
290     case KEYTYPE_DES :
291         ret = verify_mic_des (minor_status, context_handle,
292                               message_buffer, token_buffer, qop_state, key,
293                               type);
294         break;
295     case KEYTYPE_DES3 :
296         ret = verify_mic_des3 (minor_status, context_handle,
297                                message_buffer, token_buffer, qop_state, key,
298                                type);
299         break;
300     case KEYTYPE_ARCFOUR :
301     case KEYTYPE_ARCFOUR_56 :
302         ret = _gssapi_verify_mic_arcfour (minor_status, context_handle,
303                                           message_buffer, token_buffer,
304                                           qop_state, key, type);
305         break;
306     default :
307         ret = _gssapi_verify_mic_cfx (minor_status, context_handle,
308                                       message_buffer, token_buffer, qop_state,
309                                       key);
310         break;
311     }
312     krb5_free_keyblock (gssapi_krb5_context, key);
313     
314     return ret;
315 }
316
317 OM_uint32
318 gss_verify_mic
319            (OM_uint32 * minor_status,
320             const gss_ctx_id_t context_handle,
321             const gss_buffer_t message_buffer,
322             const gss_buffer_t token_buffer,
323             gss_qop_t * qop_state
324             )
325 {
326     OM_uint32 ret;
327
328     if (qop_state != NULL)
329         *qop_state = GSS_C_QOP_DEFAULT;
330
331     ret = gss_verify_mic_internal(minor_status, context_handle, 
332                                   message_buffer, token_buffer,
333                                   qop_state, "\x01\x01");
334
335     return ret;
336 }