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