Restructure Makefiles to accomodate multiple archs
[dragonfly.git] / crypto / heimdal-0.6.3 / 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.18.2.4 2003/09/18 22:05:34 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_data[8];
52   des_key_schedule schedule;
53   des_cblock zero;
54   des_cblock deskey;
55   int32_t seq_number;
56   OM_uint32 ret;
57
58   p = token_buffer->value;
59   ret = gssapi_krb5_verify_header (&p,
60                                    token_buffer->length,
61                                    type);
62   if (ret)
63       return ret;
64
65   if (memcmp(p, "\x00\x00", 2) != 0)
66       return GSS_S_BAD_SIG;
67   p += 2;
68   if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
69     return GSS_S_BAD_MIC;
70   p += 4;
71   p += 16;
72
73   /* verify checksum */
74   MD5_Init (&md5);
75   MD5_Update (&md5, p - 24, 8);
76   MD5_Update (&md5, message_buffer->value,
77              message_buffer->length);
78   MD5_Final (hash, &md5);
79
80   memset (&zero, 0, sizeof(zero));
81   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
82
83   des_set_key (&deskey, schedule);
84   des_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
85                  schedule, &zero);
86   if (memcmp (p - 8, hash, 8) != 0) {
87     memset (deskey, 0, sizeof(deskey));
88     memset (schedule, 0, sizeof(schedule));
89     return GSS_S_BAD_MIC;
90   }
91
92   /* verify sequence number */
93   
94   krb5_auth_getremoteseqnumber (gssapi_krb5_context,
95                                 context_handle->auth_context,
96                                 &seq_number);
97   seq_data[0] = (seq_number >> 0)  & 0xFF;
98   seq_data[1] = (seq_number >> 8)  & 0xFF;
99   seq_data[2] = (seq_number >> 16) & 0xFF;
100   seq_data[3] = (seq_number >> 24) & 0xFF;
101   memset (seq_data + 4,
102           (context_handle->more_flags & LOCAL) ? 0xFF : 0,
103           4);
104
105   p -= 16;
106   des_set_key (&deskey, schedule);
107   des_cbc_encrypt ((void *)p, (void *)p, 8,
108                    schedule, (des_cblock *)hash, DES_DECRYPT);
109
110   memset (deskey, 0, sizeof(deskey));
111   memset (schedule, 0, sizeof(schedule));
112
113   if (memcmp (p, seq_data, 8) != 0) {
114     return GSS_S_BAD_MIC;
115   }
116
117   krb5_auth_con_setremoteseqnumber (gssapi_krb5_context,
118                                 context_handle->auth_context,
119                                 ++seq_number);
120
121   return GSS_S_COMPLETE;
122 }
123
124 static OM_uint32
125 verify_mic_des3
126            (OM_uint32 * minor_status,
127             const gss_ctx_id_t context_handle,
128             const gss_buffer_t message_buffer,
129             const gss_buffer_t token_buffer,
130             gss_qop_t * qop_state,
131             krb5_keyblock *key,
132             char *type
133             )
134 {
135   u_char *p;
136   u_char seq[8];
137   int32_t seq_number;
138   OM_uint32 ret;
139   krb5_crypto crypto;
140   krb5_data seq_data;
141   int cmp, docompat;
142   Checksum csum;
143   char *tmp;
144   char ivec[8];
145   
146   p = token_buffer->value;
147   ret = gssapi_krb5_verify_header (&p,
148                                    token_buffer->length,
149                                    type);
150   if (ret)
151       return ret;
152
153   if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */
154       return GSS_S_BAD_SIG;
155   p += 2;
156   if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
157     return GSS_S_BAD_MIC;
158   p += 4;
159
160   ret = krb5_crypto_init(gssapi_krb5_context, key,
161                          ETYPE_DES3_CBC_NONE, &crypto);
162   if (ret){
163       gssapi_krb5_set_error_string ();
164       *minor_status = ret;
165       return GSS_S_FAILURE;
166   }
167
168   /* verify sequence number */
169   docompat = 0;
170 retry:
171   if (docompat)
172       memset(ivec, 0, 8);
173   else
174       memcpy(ivec, p + 8, 8);
175
176   ret = krb5_decrypt_ivec (gssapi_krb5_context,
177                            crypto,
178                            KRB5_KU_USAGE_SEQ,
179                            p, 8, &seq_data, ivec);
180   if (ret) {
181       if (docompat++) {
182           gssapi_krb5_set_error_string ();
183           krb5_crypto_destroy (gssapi_krb5_context, crypto);
184           *minor_status = ret;
185           return GSS_S_FAILURE;
186       } else
187           goto retry;
188   }
189
190   if (seq_data.length != 8) {
191       krb5_data_free (&seq_data);
192       if (docompat++) {
193           krb5_crypto_destroy (gssapi_krb5_context, crypto);
194           return GSS_S_BAD_MIC;
195       } else
196           goto retry;
197   }
198
199   krb5_auth_getremoteseqnumber (gssapi_krb5_context,
200                                 context_handle->auth_context,
201                                 &seq_number);
202   seq[0] = (seq_number >> 0)  & 0xFF;
203   seq[1] = (seq_number >> 8)  & 0xFF;
204   seq[2] = (seq_number >> 16) & 0xFF;
205   seq[3] = (seq_number >> 24) & 0xFF;
206   memset (seq + 4,
207           (context_handle->more_flags & LOCAL) ? 0xFF : 0,
208           4);
209   cmp = memcmp (seq, seq_data.data, seq_data.length);
210   krb5_data_free (&seq_data);
211   if (cmp != 0) {
212       if (docompat++) {
213           krb5_crypto_destroy (gssapi_krb5_context, crypto);
214           return GSS_S_BAD_MIC;
215       } else
216           goto retry;
217   }
218
219   /* verify checksum */
220
221   tmp = malloc (message_buffer->length + 8);
222   if (tmp == NULL) {
223       krb5_crypto_destroy (gssapi_krb5_context, crypto);
224       *minor_status = ENOMEM;
225       return GSS_S_FAILURE;
226   }
227
228   memcpy (tmp, p - 8, 8);
229   memcpy (tmp + 8, message_buffer->value, message_buffer->length);
230
231   csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
232   csum.checksum.length = 20;
233   csum.checksum.data   = p + 8;
234
235   ret = krb5_verify_checksum (gssapi_krb5_context, crypto,
236                               KRB5_KU_USAGE_SIGN,
237                               tmp, message_buffer->length + 8,
238                               &csum);
239   free (tmp);
240   if (ret) {
241       gssapi_krb5_set_error_string ();
242       krb5_crypto_destroy (gssapi_krb5_context, crypto);
243       *minor_status = ret;
244       return GSS_S_BAD_MIC;
245   }
246
247   krb5_auth_con_setremoteseqnumber (gssapi_krb5_context,
248                                 context_handle->auth_context,
249                                 ++seq_number);
250
251   krb5_crypto_destroy (gssapi_krb5_context, crypto);
252   return GSS_S_COMPLETE;
253 }
254
255 OM_uint32
256 gss_verify_mic_internal
257            (OM_uint32 * minor_status,
258             const gss_ctx_id_t context_handle,
259             const gss_buffer_t message_buffer,
260             const gss_buffer_t token_buffer,
261             gss_qop_t * qop_state,
262             char * type
263             )
264 {
265     krb5_keyblock *key;
266     OM_uint32 ret;
267     krb5_keytype keytype;
268
269     ret = gss_krb5_get_remotekey(context_handle, &key);
270     if (ret) {
271         gssapi_krb5_set_error_string ();
272         *minor_status = ret;
273         return GSS_S_FAILURE;
274     }
275     *minor_status = 0;
276     krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
277     switch (keytype) {
278     case KEYTYPE_DES :
279         ret = verify_mic_des (minor_status, context_handle,
280                               message_buffer, token_buffer, qop_state, key,
281                               type);
282         break;
283     case KEYTYPE_DES3 :
284         ret = verify_mic_des3 (minor_status, context_handle,
285                                message_buffer, token_buffer, qop_state, key,
286                                type);
287         break;
288     case KEYTYPE_ARCFOUR :
289         ret = _gssapi_verify_mic_arcfour (minor_status, context_handle,
290                                           message_buffer, token_buffer,
291                                           qop_state, key, type);
292         break;
293     default :
294         *minor_status = KRB5_PROG_ETYPE_NOSUPP;
295         ret = GSS_S_FAILURE;
296         break;
297     }
298     krb5_free_keyblock (gssapi_krb5_context, key);
299     
300     return ret;
301 }
302
303 OM_uint32
304 gss_verify_mic
305            (OM_uint32 * minor_status,
306             const gss_ctx_id_t context_handle,
307             const gss_buffer_t message_buffer,
308             const gss_buffer_t token_buffer,
309             gss_qop_t * qop_state
310             )
311 {
312     OM_uint32 ret;
313
314     if (qop_state != NULL)
315         *qop_state = GSS_C_QOP_DEFAULT;
316
317     ret = gss_verify_mic_internal(minor_status, context_handle, 
318                                   message_buffer, token_buffer,
319                                   qop_state, "\x01\x01");
320
321     return ret;
322 }