1178825Sdfr/*
2233294Sstas * Copyright (c) 1997 - 2003 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
39178825Sdfrmic_des
40178825Sdfr           (OM_uint32 * minor_status,
41178825Sdfr            const gsskrb5_ctx ctx,
42178825Sdfr	    krb5_context context,
43178825Sdfr            gss_qop_t qop_req,
44178825Sdfr            const gss_buffer_t message_buffer,
45178825Sdfr            gss_buffer_t message_token,
46178825Sdfr	    krb5_keyblock *key
47178825Sdfr           )
48178825Sdfr{
49178825Sdfr  u_char *p;
50233294Sstas  EVP_MD_CTX *md5;
51178825Sdfr  u_char hash[16];
52178825Sdfr  DES_key_schedule schedule;
53233294Sstas  EVP_CIPHER_CTX des_ctx;
54178825Sdfr  DES_cblock deskey;
55178825Sdfr  DES_cblock zero;
56178825Sdfr  int32_t seq_number;
57178825Sdfr  size_t len, total_len;
58178825Sdfr
59178825Sdfr  _gsskrb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM);
60178825Sdfr
61178825Sdfr  message_token->length = total_len;
62178825Sdfr  message_token->value  = malloc (total_len);
63178825Sdfr  if (message_token->value == NULL) {
64178825Sdfr    message_token->length = 0;
65178825Sdfr    *minor_status = ENOMEM;
66178825Sdfr    return GSS_S_FAILURE;
67178825Sdfr  }
68178825Sdfr
69178825Sdfr  p = _gsskrb5_make_header(message_token->value,
70178825Sdfr			      len,
71178825Sdfr			      "\x01\x01", /* TOK_ID */
72233294Sstas			      GSS_KRB5_MECHANISM);
73178825Sdfr
74178825Sdfr  memcpy (p, "\x00\x00", 2);	/* SGN_ALG = DES MAC MD5 */
75178825Sdfr  p += 2;
76178825Sdfr
77178825Sdfr  memcpy (p, "\xff\xff\xff\xff", 4); /* Filler */
78178825Sdfr  p += 4;
79178825Sdfr
80178825Sdfr  /* Fill in later (SND-SEQ) */
81178825Sdfr  memset (p, 0, 16);
82178825Sdfr  p += 16;
83178825Sdfr
84178825Sdfr  /* checksum */
85233294Sstas  md5 = EVP_MD_CTX_create();
86233294Sstas  EVP_DigestInit_ex(md5, EVP_md5(), NULL);
87233294Sstas  EVP_DigestUpdate(md5, p - 24, 8);
88233294Sstas  EVP_DigestUpdate(md5, message_buffer->value, message_buffer->length);
89233294Sstas  EVP_DigestFinal_ex(md5, hash, NULL);
90233294Sstas  EVP_MD_CTX_destroy(md5);
91178825Sdfr
92178825Sdfr  memset (&zero, 0, sizeof(zero));
93178825Sdfr  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
94233294Sstas  DES_set_key_unchecked (&deskey, &schedule);
95178825Sdfr  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
96178825Sdfr		 &schedule, &zero);
97178825Sdfr  memcpy (p - 8, hash, 8);	/* SGN_CKSUM */
98178825Sdfr
99178825Sdfr  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
100178825Sdfr  /* sequence number */
101178825Sdfr  krb5_auth_con_getlocalseqnumber (context,
102178825Sdfr				   ctx->auth_context,
103178825Sdfr				   &seq_number);
104178825Sdfr
105178825Sdfr  p -= 16;			/* SND_SEQ */
106178825Sdfr  p[0] = (seq_number >> 0)  & 0xFF;
107178825Sdfr  p[1] = (seq_number >> 8)  & 0xFF;
108178825Sdfr  p[2] = (seq_number >> 16) & 0xFF;
109178825Sdfr  p[3] = (seq_number >> 24) & 0xFF;
110178825Sdfr  memset (p + 4,
111178825Sdfr	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
112178825Sdfr	  4);
113178825Sdfr
114233294Sstas  EVP_CIPHER_CTX_init(&des_ctx);
115233294Sstas  EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1);
116233294Sstas  EVP_Cipher(&des_ctx, p, p, 8);
117233294Sstas  EVP_CIPHER_CTX_cleanup(&des_ctx);
118178825Sdfr
119178825Sdfr  krb5_auth_con_setlocalseqnumber (context,
120178825Sdfr			       ctx->auth_context,
121178825Sdfr			       ++seq_number);
122178825Sdfr  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
123233294Sstas
124178825Sdfr  memset (deskey, 0, sizeof(deskey));
125178825Sdfr  memset (&schedule, 0, sizeof(schedule));
126233294Sstas
127178825Sdfr  *minor_status = 0;
128178825Sdfr  return GSS_S_COMPLETE;
129178825Sdfr}
130233294Sstas#endif
131178825Sdfr
132178825Sdfrstatic OM_uint32
133178825Sdfrmic_des3
134178825Sdfr           (OM_uint32 * minor_status,
135178825Sdfr            const gsskrb5_ctx ctx,
136178825Sdfr	    krb5_context context,
137178825Sdfr            gss_qop_t qop_req,
138178825Sdfr            const gss_buffer_t message_buffer,
139178825Sdfr            gss_buffer_t message_token,
140178825Sdfr	    krb5_keyblock *key
141178825Sdfr           )
142178825Sdfr{
143178825Sdfr  u_char *p;
144178825Sdfr  Checksum cksum;
145178825Sdfr  u_char seq[8];
146178825Sdfr
147178825Sdfr  int32_t seq_number;
148178825Sdfr  size_t len, total_len;
149178825Sdfr
150178825Sdfr  krb5_crypto crypto;
151178825Sdfr  krb5_error_code kret;
152178825Sdfr  krb5_data encdata;
153178825Sdfr  char *tmp;
154178825Sdfr  char ivec[8];
155178825Sdfr
156178825Sdfr  _gsskrb5_encap_length (36, &len, &total_len, GSS_KRB5_MECHANISM);
157178825Sdfr
158178825Sdfr  message_token->length = total_len;
159178825Sdfr  message_token->value  = malloc (total_len);
160178825Sdfr  if (message_token->value == NULL) {
161178825Sdfr      message_token->length = 0;
162178825Sdfr      *minor_status = ENOMEM;
163178825Sdfr      return GSS_S_FAILURE;
164178825Sdfr  }
165178825Sdfr
166178825Sdfr  p = _gsskrb5_make_header(message_token->value,
167178825Sdfr			      len,
168178825Sdfr			      "\x01\x01", /* TOK-ID */
169178825Sdfr			      GSS_KRB5_MECHANISM);
170178825Sdfr
171178825Sdfr  memcpy (p, "\x04\x00", 2);	/* SGN_ALG = HMAC SHA1 DES3-KD */
172178825Sdfr  p += 2;
173178825Sdfr
174178825Sdfr  memcpy (p, "\xff\xff\xff\xff", 4); /* filler */
175178825Sdfr  p += 4;
176178825Sdfr
177178825Sdfr  /* this should be done in parts */
178178825Sdfr
179178825Sdfr  tmp = malloc (message_buffer->length + 8);
180178825Sdfr  if (tmp == NULL) {
181178825Sdfr      free (message_token->value);
182178825Sdfr      message_token->value = NULL;
183178825Sdfr      message_token->length = 0;
184178825Sdfr      *minor_status = ENOMEM;
185178825Sdfr      return GSS_S_FAILURE;
186178825Sdfr  }
187178825Sdfr  memcpy (tmp, p - 8, 8);
188178825Sdfr  memcpy (tmp + 8, message_buffer->value, message_buffer->length);
189178825Sdfr
190178825Sdfr  kret = krb5_crypto_init(context, key, 0, &crypto);
191178825Sdfr  if (kret) {
192178825Sdfr      free (message_token->value);
193178825Sdfr      message_token->value = NULL;
194178825Sdfr      message_token->length = 0;
195178825Sdfr      free (tmp);
196178825Sdfr      *minor_status = kret;
197178825Sdfr      return GSS_S_FAILURE;
198178825Sdfr  }
199178825Sdfr
200178825Sdfr  kret = krb5_create_checksum (context,
201178825Sdfr			       crypto,
202178825Sdfr			       KRB5_KU_USAGE_SIGN,
203178825Sdfr			       0,
204178825Sdfr			       tmp,
205178825Sdfr			       message_buffer->length + 8,
206178825Sdfr			       &cksum);
207178825Sdfr  free (tmp);
208178825Sdfr  krb5_crypto_destroy (context, crypto);
209178825Sdfr  if (kret) {
210178825Sdfr      free (message_token->value);
211178825Sdfr      message_token->value = NULL;
212178825Sdfr      message_token->length = 0;
213178825Sdfr      *minor_status = kret;
214178825Sdfr      return GSS_S_FAILURE;
215178825Sdfr  }
216178825Sdfr
217178825Sdfr  memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
218178825Sdfr
219178825Sdfr  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
220178825Sdfr  /* sequence number */
221178825Sdfr  krb5_auth_con_getlocalseqnumber (context,
222178825Sdfr			       ctx->auth_context,
223178825Sdfr			       &seq_number);
224178825Sdfr
225178825Sdfr  seq[0] = (seq_number >> 0)  & 0xFF;
226178825Sdfr  seq[1] = (seq_number >> 8)  & 0xFF;
227178825Sdfr  seq[2] = (seq_number >> 16) & 0xFF;
228178825Sdfr  seq[3] = (seq_number >> 24) & 0xFF;
229178825Sdfr  memset (seq + 4,
230178825Sdfr	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
231178825Sdfr	  4);
232178825Sdfr
233178825Sdfr  kret = krb5_crypto_init(context, key,
234178825Sdfr			  ETYPE_DES3_CBC_NONE, &crypto);
235178825Sdfr  if (kret) {
236178825Sdfr      free (message_token->value);
237178825Sdfr      message_token->value = NULL;
238178825Sdfr      message_token->length = 0;
239178825Sdfr      *minor_status = kret;
240178825Sdfr      return GSS_S_FAILURE;
241178825Sdfr  }
242178825Sdfr
243178825Sdfr  if (ctx->more_flags & COMPAT_OLD_DES3)
244178825Sdfr      memset(ivec, 0, 8);
245178825Sdfr  else
246178825Sdfr      memcpy(ivec, p + 8, 8);
247178825Sdfr
248178825Sdfr  kret = krb5_encrypt_ivec (context,
249178825Sdfr			    crypto,
250178825Sdfr			    KRB5_KU_USAGE_SEQ,
251178825Sdfr			    seq, 8, &encdata, ivec);
252178825Sdfr  krb5_crypto_destroy (context, crypto);
253178825Sdfr  if (kret) {
254178825Sdfr      free (message_token->value);
255178825Sdfr      message_token->value = NULL;
256178825Sdfr      message_token->length = 0;
257178825Sdfr      *minor_status = kret;
258178825Sdfr      return GSS_S_FAILURE;
259178825Sdfr  }
260233294Sstas
261178825Sdfr  assert (encdata.length == 8);
262178825Sdfr
263178825Sdfr  memcpy (p, encdata.data, encdata.length);
264178825Sdfr  krb5_data_free (&encdata);
265178825Sdfr
266178825Sdfr  krb5_auth_con_setlocalseqnumber (context,
267178825Sdfr			       ctx->auth_context,
268178825Sdfr			       ++seq_number);
269178825Sdfr  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
270233294Sstas
271178825Sdfr  free_Checksum (&cksum);
272178825Sdfr  *minor_status = 0;
273178825Sdfr  return GSS_S_COMPLETE;
274178825Sdfr}
275178825Sdfr
276233294SstasOM_uint32 GSSAPI_CALLCONV _gsskrb5_get_mic
277178825Sdfr           (OM_uint32 * minor_status,
278178825Sdfr            const gss_ctx_id_t context_handle,
279178825Sdfr            gss_qop_t qop_req,
280178825Sdfr            const gss_buffer_t message_buffer,
281178825Sdfr            gss_buffer_t message_token
282178825Sdfr           )
283178825Sdfr{
284178825Sdfr  krb5_context context;
285178825Sdfr  const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
286178825Sdfr  krb5_keyblock *key;
287178825Sdfr  OM_uint32 ret;
288178825Sdfr  krb5_keytype keytype;
289178825Sdfr
290178825Sdfr  GSSAPI_KRB5_INIT (&context);
291178825Sdfr
292233294Sstas  if (ctx->more_flags & IS_CFX)
293233294Sstas      return _gssapi_mic_cfx (minor_status, ctx, context, qop_req,
294233294Sstas			      message_buffer, message_token);
295233294Sstas
296178825Sdfr  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
297178825Sdfr  ret = _gsskrb5i_get_token_key(ctx, context, &key);
298178825Sdfr  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
299178825Sdfr  if (ret) {
300178825Sdfr      *minor_status = ret;
301178825Sdfr      return GSS_S_FAILURE;
302178825Sdfr  }
303178825Sdfr  krb5_enctype_to_keytype (context, key->keytype, &keytype);
304178825Sdfr
305178825Sdfr  switch (keytype) {
306178825Sdfr  case KEYTYPE_DES :
307233294Sstas#ifdef HEIM_WEAK_CRYPTO
308178825Sdfr      ret = mic_des (minor_status, ctx, context, qop_req,
309178825Sdfr		     message_buffer, message_token, key);
310233294Sstas#else
311233294Sstas      ret = GSS_S_FAILURE;
312233294Sstas#endif
313178825Sdfr      break;
314178825Sdfr  case KEYTYPE_DES3 :
315178825Sdfr      ret = mic_des3 (minor_status, ctx, context, qop_req,
316178825Sdfr		      message_buffer, message_token, key);
317178825Sdfr      break;
318178825Sdfr  case KEYTYPE_ARCFOUR:
319178825Sdfr  case KEYTYPE_ARCFOUR_56:
320178825Sdfr      ret = _gssapi_get_mic_arcfour (minor_status, ctx, context, qop_req,
321178825Sdfr				     message_buffer, message_token, key);
322178825Sdfr      break;
323178825Sdfr  default :
324233294Sstas      abort();
325178825Sdfr      break;
326178825Sdfr  }
327178825Sdfr  krb5_free_keyblock (context, key);
328178825Sdfr  return ret;
329178825Sdfr}
330