Merge from vendor branch HEIMDAL:
[dragonfly.git] / crypto / heimdal-0.6.3 / lib / gssapi / unwrap.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: unwrap.c,v 1.22.2.1 2003/09/18 22:05:22 lha Exp $");
37
38 OM_uint32
39 gss_krb5_get_remotekey(const gss_ctx_id_t context_handle,
40                        krb5_keyblock **key)
41 {
42     krb5_keyblock *skey;
43
44     krb5_auth_con_getremotesubkey(gssapi_krb5_context,
45                                   context_handle->auth_context, 
46                                   &skey);
47     if(skey == NULL)
48         krb5_auth_con_getlocalsubkey(gssapi_krb5_context,
49                                      context_handle->auth_context, 
50                                      &skey);
51     if(skey == NULL)
52         krb5_auth_con_getkey(gssapi_krb5_context,
53                              context_handle->auth_context, 
54                              &skey);
55     if(skey == NULL)
56         return GSS_KRB5_S_KG_NO_SUBKEY; /* XXX */
57     *key = skey;
58     return 0;
59 }
60
61 static OM_uint32
62 unwrap_des
63            (OM_uint32 * minor_status,
64             const gss_ctx_id_t context_handle,
65             const gss_buffer_t input_message_buffer,
66             gss_buffer_t output_message_buffer,
67             int * conf_state,
68             gss_qop_t * qop_state,
69             krb5_keyblock *key
70            )
71 {
72   u_char *p, *pad;
73   size_t len;
74   MD5_CTX md5;
75   u_char hash[16], seq_data[8];
76   des_key_schedule schedule;
77   des_cblock deskey;
78   des_cblock zero;
79   int i;
80   int32_t seq_number;
81   size_t padlength;
82   OM_uint32 ret;
83   int cstate;
84
85   p = input_message_buffer->value;
86   ret = gssapi_krb5_verify_header (&p,
87                                    input_message_buffer->length,
88                                    "\x02\x01");
89   if (ret)
90       return ret;
91
92   if (memcmp (p, "\x00\x00", 2) != 0)
93     return GSS_S_BAD_SIG;
94   p += 2;
95   if (memcmp (p, "\x00\x00", 2) == 0) {
96       cstate = 1;
97   } else if (memcmp (p, "\xFF\xFF", 2) == 0) {
98       cstate = 0;
99   } else
100       return GSS_S_BAD_MIC;
101   p += 2;
102   if(conf_state != NULL)
103       *conf_state = cstate;
104   if (memcmp (p, "\xff\xff", 2) != 0)
105     return GSS_S_DEFECTIVE_TOKEN;
106   p += 2;
107   p += 16;
108
109   len = p - (u_char *)input_message_buffer->value;
110
111   if(cstate) {
112       /* decrypt data */
113       memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
114
115       for (i = 0; i < sizeof(deskey); ++i)
116           deskey[i] ^= 0xf0;
117       des_set_key (&deskey, schedule);
118       memset (&zero, 0, sizeof(zero));
119       des_cbc_encrypt ((void *)p,
120                        (void *)p,
121                        input_message_buffer->length - len,
122                        schedule,
123                        &zero,
124                        DES_DECRYPT);
125       
126       memset (deskey, 0, sizeof(deskey));
127       memset (schedule, 0, sizeof(schedule));
128   }
129   /* check pad */
130
131   pad = (u_char *)input_message_buffer->value + input_message_buffer->length - 1;
132   padlength = *pad;
133
134   for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
135     ;
136   if (i != 0)
137     return GSS_S_BAD_MIC;
138
139   MD5_Init (&md5);
140   MD5_Update (&md5, p - 24, 8);
141   MD5_Update (&md5, p, input_message_buffer->length - len);
142   MD5_Final (hash, &md5);
143
144   memset (&zero, 0, sizeof(zero));
145   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
146   des_set_key (&deskey, schedule);
147   des_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
148                  schedule, &zero);
149   if (memcmp (p - 8, hash, 8) != 0)
150     return GSS_S_BAD_MIC;
151
152   /* verify sequence number */
153   
154   krb5_auth_getremoteseqnumber (gssapi_krb5_context,
155                                 context_handle->auth_context,
156                                 &seq_number);
157   seq_data[0] = (seq_number >> 0)  & 0xFF;
158   seq_data[1] = (seq_number >> 8)  & 0xFF;
159   seq_data[2] = (seq_number >> 16) & 0xFF;
160   seq_data[3] = (seq_number >> 24) & 0xFF;
161   memset (seq_data + 4,
162           (context_handle->more_flags & LOCAL) ? 0xFF : 0,
163           4);
164
165   p -= 16;
166   des_set_key (&deskey, schedule);
167   des_cbc_encrypt ((void *)p, (void *)p, 8,
168                    schedule, (des_cblock *)hash, DES_DECRYPT);
169
170   memset (deskey, 0, sizeof(deskey));
171   memset (schedule, 0, sizeof(schedule));
172
173   if (memcmp (p, seq_data, 8) != 0) {
174     return GSS_S_BAD_MIC;
175   }
176
177   krb5_auth_con_setremoteseqnumber (gssapi_krb5_context,
178                                 context_handle->auth_context,
179                                 ++seq_number);
180
181   /* copy out data */
182
183   output_message_buffer->length = input_message_buffer->length
184     - len - padlength - 8;
185   output_message_buffer->value  = malloc(output_message_buffer->length);
186   if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
187       return GSS_S_FAILURE;
188   memcpy (output_message_buffer->value,
189           p + 24,
190           output_message_buffer->length);
191   return GSS_S_COMPLETE;
192 }
193
194 static OM_uint32
195 unwrap_des3
196            (OM_uint32 * minor_status,
197             const gss_ctx_id_t context_handle,
198             const gss_buffer_t input_message_buffer,
199             gss_buffer_t output_message_buffer,
200             int * conf_state,
201             gss_qop_t * qop_state,
202             krb5_keyblock *key
203            )
204 {
205   u_char *p, *pad;
206   size_t len;
207   u_char seq[8];
208   krb5_data seq_data;
209   u_char cksum[20];
210   int i;
211   int32_t seq_number;
212   size_t padlength;
213   OM_uint32 ret;
214   int cstate;
215   krb5_crypto crypto;
216   Checksum csum;
217   int cmp;
218
219   p = input_message_buffer->value;
220   ret = gssapi_krb5_verify_header (&p,
221                                    input_message_buffer->length,
222                                    "\x02\x01");
223   if (ret)
224       return ret;
225
226   if (memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */
227     return GSS_S_BAD_SIG;
228   p += 2;
229   if (memcmp (p, "\x02\x00", 2) == 0) {
230     cstate = 1;
231   } else if (memcmp (p, "\xff\xff", 2) == 0) {
232     cstate = 0;
233   } else
234     return GSS_S_BAD_MIC;
235   p += 2;
236   if(conf_state != NULL)
237     *conf_state = cstate;
238   if (memcmp (p, "\xff\xff", 2) != 0)
239     return GSS_S_DEFECTIVE_TOKEN;
240   p += 2;
241   p += 28;
242
243   len = p - (u_char *)input_message_buffer->value;
244
245   if(cstate) {
246       /* decrypt data */
247       krb5_data tmp;
248
249       ret = krb5_crypto_init(gssapi_krb5_context, key,
250                              ETYPE_DES3_CBC_NONE, &crypto);
251       if (ret) {
252           gssapi_krb5_set_error_string ();
253           *minor_status = ret;
254           return GSS_S_FAILURE;
255       }
256       ret = krb5_decrypt(gssapi_krb5_context, crypto, KRB5_KU_USAGE_SEAL,
257                          p, input_message_buffer->length - len, &tmp);
258       krb5_crypto_destroy(gssapi_krb5_context, crypto);
259       if (ret) {
260           gssapi_krb5_set_error_string ();
261           *minor_status = ret;
262           return GSS_S_FAILURE;
263       }
264       assert (tmp.length == input_message_buffer->length - len);
265
266       memcpy (p, tmp.data, tmp.length);
267       krb5_data_free(&tmp);
268   }
269   /* check pad */
270
271   pad = (u_char *)input_message_buffer->value + input_message_buffer->length - 1;
272   padlength = *pad;
273
274   for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
275     ;
276   if (i != 0)
277     return GSS_S_BAD_MIC;
278
279   /* verify sequence number */
280   
281   krb5_auth_getremoteseqnumber (gssapi_krb5_context,
282                                 context_handle->auth_context,
283                                 &seq_number);
284   seq[0] = (seq_number >> 0)  & 0xFF;
285   seq[1] = (seq_number >> 8)  & 0xFF;
286   seq[2] = (seq_number >> 16) & 0xFF;
287   seq[3] = (seq_number >> 24) & 0xFF;
288   memset (seq + 4,
289           (context_handle->more_flags & LOCAL) ? 0xFF : 0,
290           4);
291
292   p -= 28;
293
294   ret = krb5_crypto_init(gssapi_krb5_context, key,
295                          ETYPE_DES3_CBC_NONE, &crypto);
296   if (ret) {
297       gssapi_krb5_set_error_string ();
298       *minor_status = ret;
299       return GSS_S_FAILURE;
300   }
301   {
302       des_cblock ivec;
303
304       memcpy(&ivec, p + 8, 8);
305       ret = krb5_decrypt_ivec (gssapi_krb5_context,
306                                crypto,
307                                KRB5_KU_USAGE_SEQ,
308                                p, 8, &seq_data,
309                                &ivec);
310   }
311   krb5_crypto_destroy (gssapi_krb5_context, crypto);
312   if (ret) {
313       gssapi_krb5_set_error_string ();
314       *minor_status = ret;
315       return GSS_S_FAILURE;
316   }
317   if (seq_data.length != 8) {
318       krb5_data_free (&seq_data);
319       return GSS_S_BAD_MIC;
320   }
321
322   cmp = memcmp (seq, seq_data.data, seq_data.length);
323   krb5_data_free (&seq_data);
324   if (cmp != 0) {
325       return GSS_S_BAD_MIC;
326   }
327
328   krb5_auth_con_setremoteseqnumber (gssapi_krb5_context,
329                                 context_handle->auth_context,
330                                 ++seq_number);
331
332   /* verify checksum */
333
334   memcpy (cksum, p + 8, 20);
335
336   memcpy (p + 20, p - 8, 8);
337
338   csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
339   csum.checksum.length = 20;
340   csum.checksum.data   = cksum;
341
342   ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
343   if (ret) {
344       gssapi_krb5_set_error_string ();
345       *minor_status = ret;
346       return GSS_S_FAILURE;
347   }
348
349   ret = krb5_verify_checksum (gssapi_krb5_context, crypto,
350                               KRB5_KU_USAGE_SIGN,
351                               p + 20,
352                               input_message_buffer->length - len + 8,
353                               &csum);
354   krb5_crypto_destroy (gssapi_krb5_context, crypto);
355   if (ret) {
356       gssapi_krb5_set_error_string ();
357       *minor_status = ret;
358       return GSS_S_FAILURE;
359   }
360
361   /* copy out data */
362
363   output_message_buffer->length = input_message_buffer->length
364     - len - padlength - 8;
365   output_message_buffer->value  = malloc(output_message_buffer->length);
366   if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
367       return GSS_S_FAILURE;
368   memcpy (output_message_buffer->value,
369           p + 36,
370           output_message_buffer->length);
371   return GSS_S_COMPLETE;
372 }
373
374 OM_uint32 gss_unwrap
375            (OM_uint32 * minor_status,
376             const gss_ctx_id_t context_handle,
377             const gss_buffer_t input_message_buffer,
378             gss_buffer_t output_message_buffer,
379             int * conf_state,
380             gss_qop_t * qop_state
381            )
382 {
383   krb5_keyblock *key;
384   OM_uint32 ret;
385   krb5_keytype keytype;
386
387   if (qop_state != NULL)
388       *qop_state = GSS_C_QOP_DEFAULT;
389   ret = gss_krb5_get_remotekey(context_handle, &key);
390   if (ret) {
391       gssapi_krb5_set_error_string ();
392       *minor_status = ret;
393       return GSS_S_FAILURE;
394   }
395   krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
396
397   *minor_status = 0;
398
399   switch (keytype) {
400   case KEYTYPE_DES :
401       ret = unwrap_des (minor_status, context_handle,
402                         input_message_buffer, output_message_buffer,
403                         conf_state, qop_state, key);
404       break;
405   case KEYTYPE_DES3 :
406       ret = unwrap_des3 (minor_status, context_handle,
407                          input_message_buffer, output_message_buffer,
408                          conf_state, qop_state, key);
409       break;
410   case KEYTYPE_ARCFOUR:
411       ret = _gssapi_unwrap_arcfour (minor_status, context_handle,
412                                     input_message_buffer, output_message_buffer,
413                                     conf_state, qop_state, key);
414       break;
415   default :
416       *minor_status = KRB5_PROG_ETYPE_NOSUPP;
417       ret = GSS_S_FAILURE;
418       break;
419   }
420   krb5_free_keyblock (gssapi_krb5_context, key);
421   return ret;
422 }