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