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