1178825Sdfr/*
2233294Sstas * Copyright (c) 1997 - 2004 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34233294Sstas#include "gsskrb5_locl.h"
35178825Sdfr
36233294Sstas#ifdef HEIM_WEAK_CRYPTO
37178825Sdfr
38178825Sdfrstatic OM_uint32
39178825Sdfrunwrap_des
40178825Sdfr           (OM_uint32 * minor_status,
41178825Sdfr            const gsskrb5_ctx context_handle,
42178825Sdfr            const gss_buffer_t input_message_buffer,
43178825Sdfr            gss_buffer_t output_message_buffer,
44178825Sdfr            int * conf_state,
45178825Sdfr            gss_qop_t * qop_state,
46178825Sdfr	    krb5_keyblock *key
47178825Sdfr           )
48178825Sdfr{
49178825Sdfr  u_char *p, *seq;
50178825Sdfr  size_t len;
51233294Sstas  EVP_MD_CTX *md5;
52178825Sdfr  u_char hash[16];
53233294Sstas  EVP_CIPHER_CTX des_ctx;
54178825Sdfr  DES_key_schedule schedule;
55178825Sdfr  DES_cblock deskey;
56178825Sdfr  DES_cblock zero;
57233294Sstas  size_t i;
58178825Sdfr  uint32_t seq_number;
59178825Sdfr  size_t padlength;
60178825Sdfr  OM_uint32 ret;
61178825Sdfr  int cstate;
62178825Sdfr  int cmp;
63233294Sstas  int token_len;
64178825Sdfr
65233294Sstas  if (IS_DCE_STYLE(context_handle)) {
66233294Sstas     token_len = 22 + 8 + 15; /* 45 */
67233294Sstas  } else {
68233294Sstas     token_len = input_message_buffer->length;
69233294Sstas  }
70233294Sstas
71178825Sdfr  p = input_message_buffer->value;
72178825Sdfr  ret = _gsskrb5_verify_header (&p,
73233294Sstas				   token_len,
74178825Sdfr				   "\x02\x01",
75178825Sdfr				   GSS_KRB5_MECHANISM);
76178825Sdfr  if (ret)
77178825Sdfr      return ret;
78178825Sdfr
79178825Sdfr  if (memcmp (p, "\x00\x00", 2) != 0)
80178825Sdfr    return GSS_S_BAD_SIG;
81178825Sdfr  p += 2;
82178825Sdfr  if (memcmp (p, "\x00\x00", 2) == 0) {
83178825Sdfr      cstate = 1;
84178825Sdfr  } else if (memcmp (p, "\xFF\xFF", 2) == 0) {
85178825Sdfr      cstate = 0;
86178825Sdfr  } else
87178825Sdfr      return GSS_S_BAD_MIC;
88178825Sdfr  p += 2;
89178825Sdfr  if(conf_state != NULL)
90178825Sdfr      *conf_state = cstate;
91178825Sdfr  if (memcmp (p, "\xff\xff", 2) != 0)
92178825Sdfr    return GSS_S_DEFECTIVE_TOKEN;
93178825Sdfr  p += 2;
94178825Sdfr  p += 16;
95178825Sdfr
96178825Sdfr  len = p - (u_char *)input_message_buffer->value;
97178825Sdfr
98178825Sdfr  if(cstate) {
99178825Sdfr      /* decrypt data */
100178825Sdfr      memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
101233294Sstas      memset (&zero, 0, sizeof(zero));
102178825Sdfr
103178825Sdfr      for (i = 0; i < sizeof(deskey); ++i)
104178825Sdfr	  deskey[i] ^= 0xf0;
105233294Sstas
106233294Sstas
107233294Sstas      EVP_CIPHER_CTX_init(&des_ctx);
108233294Sstas      EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, deskey, zero, 0);
109233294Sstas      EVP_Cipher(&des_ctx, p, p, input_message_buffer->length - len);
110233294Sstas      EVP_CIPHER_CTX_cleanup(&des_ctx);
111233294Sstas
112178825Sdfr      memset (&schedule, 0, sizeof(schedule));
113178825Sdfr  }
114178825Sdfr
115233294Sstas  if (IS_DCE_STYLE(context_handle)) {
116233294Sstas    padlength = 0;
117233294Sstas  } else {
118233294Sstas    /* check pad */
119233294Sstas    ret = _gssapi_verify_pad(input_message_buffer,
120233294Sstas			     input_message_buffer->length - len,
121233294Sstas			     &padlength);
122233294Sstas    if (ret)
123233294Sstas        return ret;
124233294Sstas  }
125178825Sdfr
126233294Sstas  md5 = EVP_MD_CTX_create();
127233294Sstas  EVP_DigestInit_ex(md5, EVP_md5(), NULL);
128233294Sstas  EVP_DigestUpdate(md5, p - 24, 8);
129233294Sstas  EVP_DigestUpdate(md5, p, input_message_buffer->length - len);
130233294Sstas  EVP_DigestFinal_ex(md5, hash, NULL);
131233294Sstas  EVP_MD_CTX_destroy(md5);
132233294Sstas
133178825Sdfr  memset (&zero, 0, sizeof(zero));
134178825Sdfr  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
135233294Sstas  DES_set_key_unchecked (&deskey, &schedule);
136178825Sdfr  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
137178825Sdfr		 &schedule, &zero);
138233294Sstas  if (ct_memcmp (p - 8, hash, 8) != 0)
139178825Sdfr    return GSS_S_BAD_MIC;
140178825Sdfr
141178825Sdfr  /* verify sequence number */
142233294Sstas
143178825Sdfr  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
144178825Sdfr
145178825Sdfr  p -= 16;
146178825Sdfr
147233294Sstas  EVP_CIPHER_CTX_init(&des_ctx);
148233294Sstas  EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, hash, 0);
149233294Sstas  EVP_Cipher(&des_ctx, p, p, 8);
150233294Sstas  EVP_CIPHER_CTX_cleanup(&des_ctx);
151233294Sstas
152178825Sdfr  memset (deskey, 0, sizeof(deskey));
153178825Sdfr  memset (&schedule, 0, sizeof(schedule));
154178825Sdfr
155178825Sdfr  seq = p;
156178825Sdfr  _gsskrb5_decode_om_uint32(seq, &seq_number);
157178825Sdfr
158178825Sdfr  if (context_handle->more_flags & LOCAL)
159233294Sstas      cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
160178825Sdfr  else
161233294Sstas      cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
162178825Sdfr
163178825Sdfr  if (cmp != 0) {
164178825Sdfr    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
165178825Sdfr    return GSS_S_BAD_MIC;
166178825Sdfr  }
167178825Sdfr
168178825Sdfr  ret = _gssapi_msg_order_check(context_handle->order, seq_number);
169178825Sdfr  if (ret) {
170178825Sdfr    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
171178825Sdfr    return ret;
172178825Sdfr  }
173178825Sdfr
174178825Sdfr  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
175178825Sdfr
176178825Sdfr  /* copy out data */
177178825Sdfr
178178825Sdfr  output_message_buffer->length = input_message_buffer->length
179178825Sdfr    - len - padlength - 8;
180178825Sdfr  output_message_buffer->value  = malloc(output_message_buffer->length);
181178825Sdfr  if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
182178825Sdfr      return GSS_S_FAILURE;
183178825Sdfr  memcpy (output_message_buffer->value,
184178825Sdfr	  p + 24,
185178825Sdfr	  output_message_buffer->length);
186178825Sdfr  return GSS_S_COMPLETE;
187178825Sdfr}
188233294Sstas#endif
189178825Sdfr
190178825Sdfrstatic OM_uint32
191178825Sdfrunwrap_des3
192178825Sdfr           (OM_uint32 * minor_status,
193178825Sdfr            const gsskrb5_ctx context_handle,
194178825Sdfr	    krb5_context context,
195178825Sdfr            const gss_buffer_t input_message_buffer,
196178825Sdfr            gss_buffer_t output_message_buffer,
197178825Sdfr            int * conf_state,
198178825Sdfr            gss_qop_t * qop_state,
199178825Sdfr	    krb5_keyblock *key
200178825Sdfr           )
201178825Sdfr{
202178825Sdfr  u_char *p;
203178825Sdfr  size_t len;
204178825Sdfr  u_char *seq;
205178825Sdfr  krb5_data seq_data;
206178825Sdfr  u_char cksum[20];
207178825Sdfr  uint32_t seq_number;
208178825Sdfr  size_t padlength;
209178825Sdfr  OM_uint32 ret;
210178825Sdfr  int cstate;
211178825Sdfr  krb5_crypto crypto;
212178825Sdfr  Checksum csum;
213178825Sdfr  int cmp;
214233294Sstas  int token_len;
215178825Sdfr
216233294Sstas  if (IS_DCE_STYLE(context_handle)) {
217233294Sstas     token_len = 34 + 8 + 15; /* 57 */
218233294Sstas  } else {
219233294Sstas     token_len = input_message_buffer->length;
220233294Sstas  }
221233294Sstas
222178825Sdfr  p = input_message_buffer->value;
223178825Sdfr  ret = _gsskrb5_verify_header (&p,
224233294Sstas				   token_len,
225178825Sdfr				   "\x02\x01",
226178825Sdfr				   GSS_KRB5_MECHANISM);
227178825Sdfr  if (ret)
228178825Sdfr      return ret;
229178825Sdfr
230178825Sdfr  if (memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */
231178825Sdfr    return GSS_S_BAD_SIG;
232178825Sdfr  p += 2;
233233294Sstas  if (ct_memcmp (p, "\x02\x00", 2) == 0) {
234178825Sdfr    cstate = 1;
235233294Sstas  } else if (ct_memcmp (p, "\xff\xff", 2) == 0) {
236178825Sdfr    cstate = 0;
237178825Sdfr  } else
238178825Sdfr    return GSS_S_BAD_MIC;
239178825Sdfr  p += 2;
240178825Sdfr  if(conf_state != NULL)
241178825Sdfr    *conf_state = cstate;
242233294Sstas  if (ct_memcmp (p, "\xff\xff", 2) != 0)
243178825Sdfr    return GSS_S_DEFECTIVE_TOKEN;
244178825Sdfr  p += 2;
245178825Sdfr  p += 28;
246178825Sdfr
247178825Sdfr  len = p - (u_char *)input_message_buffer->value;
248178825Sdfr
249178825Sdfr  if(cstate) {
250178825Sdfr      /* decrypt data */
251178825Sdfr      krb5_data tmp;
252178825Sdfr
253178825Sdfr      ret = krb5_crypto_init(context, key,
254178825Sdfr			     ETYPE_DES3_CBC_NONE, &crypto);
255178825Sdfr      if (ret) {
256178825Sdfr	  *minor_status = ret;
257178825Sdfr	  return GSS_S_FAILURE;
258178825Sdfr      }
259178825Sdfr      ret = krb5_decrypt(context, crypto, KRB5_KU_USAGE_SEAL,
260178825Sdfr			 p, input_message_buffer->length - len, &tmp);
261178825Sdfr      krb5_crypto_destroy(context, crypto);
262178825Sdfr      if (ret) {
263178825Sdfr	  *minor_status = ret;
264178825Sdfr	  return GSS_S_FAILURE;
265178825Sdfr      }
266178825Sdfr      assert (tmp.length == input_message_buffer->length - len);
267178825Sdfr
268178825Sdfr      memcpy (p, tmp.data, tmp.length);
269178825Sdfr      krb5_data_free(&tmp);
270178825Sdfr  }
271178825Sdfr
272233294Sstas  if (IS_DCE_STYLE(context_handle)) {
273233294Sstas    padlength = 0;
274233294Sstas  } else {
275233294Sstas    /* check pad */
276233294Sstas    ret = _gssapi_verify_pad(input_message_buffer,
277233294Sstas			     input_message_buffer->length - len,
278233294Sstas			     &padlength);
279233294Sstas    if (ret)
280233294Sstas        return ret;
281233294Sstas  }
282233294Sstas
283178825Sdfr  /* verify sequence number */
284233294Sstas
285178825Sdfr  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
286178825Sdfr
287178825Sdfr  p -= 28;
288178825Sdfr
289178825Sdfr  ret = krb5_crypto_init(context, key,
290178825Sdfr			 ETYPE_DES3_CBC_NONE, &crypto);
291178825Sdfr  if (ret) {
292178825Sdfr      *minor_status = ret;
293178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
294178825Sdfr      return GSS_S_FAILURE;
295178825Sdfr  }
296178825Sdfr  {
297178825Sdfr      DES_cblock ivec;
298178825Sdfr
299178825Sdfr      memcpy(&ivec, p + 8, 8);
300178825Sdfr      ret = krb5_decrypt_ivec (context,
301178825Sdfr			       crypto,
302178825Sdfr			       KRB5_KU_USAGE_SEQ,
303178825Sdfr			       p, 8, &seq_data,
304178825Sdfr			       &ivec);
305178825Sdfr  }
306178825Sdfr  krb5_crypto_destroy (context, crypto);
307178825Sdfr  if (ret) {
308178825Sdfr      *minor_status = ret;
309178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
310178825Sdfr      return GSS_S_FAILURE;
311178825Sdfr  }
312178825Sdfr  if (seq_data.length != 8) {
313178825Sdfr      krb5_data_free (&seq_data);
314178825Sdfr      *minor_status = 0;
315178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
316178825Sdfr      return GSS_S_BAD_MIC;
317178825Sdfr  }
318178825Sdfr
319178825Sdfr  seq = seq_data.data;
320178825Sdfr  _gsskrb5_decode_om_uint32(seq, &seq_number);
321178825Sdfr
322178825Sdfr  if (context_handle->more_flags & LOCAL)
323233294Sstas      cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
324178825Sdfr  else
325233294Sstas      cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
326233294Sstas
327178825Sdfr  krb5_data_free (&seq_data);
328178825Sdfr  if (cmp != 0) {
329178825Sdfr      *minor_status = 0;
330178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
331178825Sdfr      return GSS_S_BAD_MIC;
332178825Sdfr  }
333178825Sdfr
334178825Sdfr  ret = _gssapi_msg_order_check(context_handle->order, seq_number);
335178825Sdfr  if (ret) {
336178825Sdfr      *minor_status = 0;
337178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
338178825Sdfr      return ret;
339178825Sdfr  }
340178825Sdfr
341178825Sdfr  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
342178825Sdfr
343178825Sdfr  /* verify checksum */
344178825Sdfr
345178825Sdfr  memcpy (cksum, p + 8, 20);
346178825Sdfr
347178825Sdfr  memcpy (p + 20, p - 8, 8);
348178825Sdfr
349178825Sdfr  csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
350178825Sdfr  csum.checksum.length = 20;
351178825Sdfr  csum.checksum.data   = cksum;
352178825Sdfr
353178825Sdfr  ret = krb5_crypto_init(context, key, 0, &crypto);
354178825Sdfr  if (ret) {
355178825Sdfr      *minor_status = ret;
356178825Sdfr      return GSS_S_FAILURE;
357178825Sdfr  }
358178825Sdfr
359178825Sdfr  ret = krb5_verify_checksum (context, crypto,
360178825Sdfr			      KRB5_KU_USAGE_SIGN,
361178825Sdfr			      p + 20,
362178825Sdfr			      input_message_buffer->length - len + 8,
363178825Sdfr			      &csum);
364178825Sdfr  krb5_crypto_destroy (context, crypto);
365178825Sdfr  if (ret) {
366178825Sdfr      *minor_status = ret;
367178825Sdfr      return GSS_S_FAILURE;
368178825Sdfr  }
369178825Sdfr
370178825Sdfr  /* copy out data */
371178825Sdfr
372178825Sdfr  output_message_buffer->length = input_message_buffer->length
373178825Sdfr    - len - padlength - 8;
374178825Sdfr  output_message_buffer->value  = malloc(output_message_buffer->length);
375178825Sdfr  if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
376178825Sdfr      return GSS_S_FAILURE;
377178825Sdfr  memcpy (output_message_buffer->value,
378178825Sdfr	  p + 36,
379178825Sdfr	  output_message_buffer->length);
380178825Sdfr  return GSS_S_COMPLETE;
381178825Sdfr}
382178825Sdfr
383233294SstasOM_uint32 GSSAPI_CALLCONV _gsskrb5_unwrap
384178825Sdfr           (OM_uint32 * minor_status,
385178825Sdfr            const gss_ctx_id_t context_handle,
386178825Sdfr            const gss_buffer_t input_message_buffer,
387178825Sdfr            gss_buffer_t output_message_buffer,
388178825Sdfr            int * conf_state,
389178825Sdfr            gss_qop_t * qop_state
390178825Sdfr           )
391178825Sdfr{
392178825Sdfr  krb5_keyblock *key;
393178825Sdfr  krb5_context context;
394178825Sdfr  OM_uint32 ret;
395178825Sdfr  krb5_keytype keytype;
396178825Sdfr  gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle;
397178825Sdfr
398178825Sdfr  output_message_buffer->value = NULL;
399178825Sdfr  output_message_buffer->length = 0;
400233294Sstas  if (qop_state != NULL)
401233294Sstas      *qop_state = GSS_C_QOP_DEFAULT;
402178825Sdfr
403178825Sdfr  GSSAPI_KRB5_INIT (&context);
404178825Sdfr
405233294Sstas  if (ctx->more_flags & IS_CFX)
406233294Sstas      return _gssapi_unwrap_cfx (minor_status, ctx, context,
407233294Sstas				 input_message_buffer, output_message_buffer,
408233294Sstas				 conf_state, qop_state);
409233294Sstas
410178825Sdfr  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
411178825Sdfr  ret = _gsskrb5i_get_token_key(ctx, context, &key);
412178825Sdfr  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
413178825Sdfr  if (ret) {
414178825Sdfr      *minor_status = ret;
415178825Sdfr      return GSS_S_FAILURE;
416178825Sdfr  }
417178825Sdfr  krb5_enctype_to_keytype (context, key->keytype, &keytype);
418178825Sdfr
419178825Sdfr  *minor_status = 0;
420178825Sdfr
421178825Sdfr  switch (keytype) {
422178825Sdfr  case KEYTYPE_DES :
423233294Sstas#ifdef HEIM_WEAK_CRYPTO
424178825Sdfr      ret = unwrap_des (minor_status, ctx,
425178825Sdfr			input_message_buffer, output_message_buffer,
426178825Sdfr			conf_state, qop_state, key);
427233294Sstas#else
428233294Sstas      ret = GSS_S_FAILURE;
429233294Sstas#endif
430178825Sdfr      break;
431178825Sdfr  case KEYTYPE_DES3 :
432178825Sdfr      ret = unwrap_des3 (minor_status, ctx, context,
433178825Sdfr			 input_message_buffer, output_message_buffer,
434178825Sdfr			 conf_state, qop_state, key);
435178825Sdfr      break;
436178825Sdfr  case KEYTYPE_ARCFOUR:
437178825Sdfr  case KEYTYPE_ARCFOUR_56:
438178825Sdfr      ret = _gssapi_unwrap_arcfour (minor_status, ctx, context,
439178825Sdfr				    input_message_buffer, output_message_buffer,
440178825Sdfr				    conf_state, qop_state, key);
441178825Sdfr      break;
442178825Sdfr  default :
443233294Sstas      abort();
444178825Sdfr      break;
445178825Sdfr  }
446178825Sdfr  krb5_free_keyblock (context, key);
447178825Sdfr  return ret;
448178825Sdfr}
449