1/*	$NetBSD: get_mic.c,v 1.1.1.1 2011/04/13 18:14:45 elric Exp $	*/
2
3/*
4 * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "gsskrb5_locl.h"
37
38#ifdef HEIM_WEAK_CRYPTO
39
40static OM_uint32
41mic_des
42           (OM_uint32 * minor_status,
43            const gsskrb5_ctx ctx,
44	    krb5_context context,
45            gss_qop_t qop_req,
46            const gss_buffer_t message_buffer,
47            gss_buffer_t message_token,
48	    krb5_keyblock *key
49           )
50{
51  u_char *p;
52  EVP_MD_CTX *md5;
53  u_char hash[16];
54  DES_key_schedule schedule;
55  EVP_CIPHER_CTX des_ctx;
56  DES_cblock deskey;
57  DES_cblock zero;
58  int32_t seq_number;
59  size_t len, total_len;
60
61  _gsskrb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM);
62
63  message_token->length = total_len;
64  message_token->value  = malloc (total_len);
65  if (message_token->value == NULL) {
66    message_token->length = 0;
67    *minor_status = ENOMEM;
68    return GSS_S_FAILURE;
69  }
70
71  p = _gsskrb5_make_header(message_token->value,
72			      len,
73			      "\x01\x01", /* TOK_ID */
74			      GSS_KRB5_MECHANISM);
75
76  memcpy (p, "\x00\x00", 2);	/* SGN_ALG = DES MAC MD5 */
77  p += 2;
78
79  memcpy (p, "\xff\xff\xff\xff", 4); /* Filler */
80  p += 4;
81
82  /* Fill in later (SND-SEQ) */
83  memset (p, 0, 16);
84  p += 16;
85
86  /* checksum */
87  md5 = EVP_MD_CTX_create();
88  EVP_DigestInit_ex(md5, EVP_md5(), NULL);
89  EVP_DigestUpdate(md5, p - 24, 8);
90  EVP_DigestUpdate(md5, message_buffer->value, message_buffer->length);
91  EVP_DigestFinal_ex(md5, hash, NULL);
92  EVP_MD_CTX_destroy(md5);
93
94  memset (&zero, 0, sizeof(zero));
95  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
96  DES_set_key_unchecked (&deskey, &schedule);
97  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
98		 &schedule, &zero);
99  memcpy (p - 8, hash, 8);	/* SGN_CKSUM */
100
101  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
102  /* sequence number */
103  krb5_auth_con_getlocalseqnumber (context,
104				   ctx->auth_context,
105				   &seq_number);
106
107  p -= 16;			/* SND_SEQ */
108  p[0] = (seq_number >> 0)  & 0xFF;
109  p[1] = (seq_number >> 8)  & 0xFF;
110  p[2] = (seq_number >> 16) & 0xFF;
111  p[3] = (seq_number >> 24) & 0xFF;
112  memset (p + 4,
113	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
114	  4);
115
116  EVP_CIPHER_CTX_init(&des_ctx);
117  EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1);
118  EVP_Cipher(&des_ctx, p, p, 8);
119  EVP_CIPHER_CTX_cleanup(&des_ctx);
120
121  krb5_auth_con_setlocalseqnumber (context,
122			       ctx->auth_context,
123			       ++seq_number);
124  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
125
126  memset (deskey, 0, sizeof(deskey));
127  memset (&schedule, 0, sizeof(schedule));
128
129  *minor_status = 0;
130  return GSS_S_COMPLETE;
131}
132#endif
133
134static OM_uint32
135mic_des3
136           (OM_uint32 * minor_status,
137            const gsskrb5_ctx ctx,
138	    krb5_context context,
139            gss_qop_t qop_req,
140            const gss_buffer_t message_buffer,
141            gss_buffer_t message_token,
142	    krb5_keyblock *key
143           )
144{
145  u_char *p;
146  Checksum cksum;
147  u_char seq[8];
148
149  int32_t seq_number;
150  size_t len, total_len;
151
152  krb5_crypto crypto;
153  krb5_error_code kret;
154  krb5_data encdata;
155  char *tmp;
156  char ivec[8];
157
158  _gsskrb5_encap_length (36, &len, &total_len, GSS_KRB5_MECHANISM);
159
160  message_token->length = total_len;
161  message_token->value  = malloc (total_len);
162  if (message_token->value == NULL) {
163      message_token->length = 0;
164      *minor_status = ENOMEM;
165      return GSS_S_FAILURE;
166  }
167
168  p = _gsskrb5_make_header(message_token->value,
169			      len,
170			      "\x01\x01", /* TOK-ID */
171			      GSS_KRB5_MECHANISM);
172
173  memcpy (p, "\x04\x00", 2);	/* SGN_ALG = HMAC SHA1 DES3-KD */
174  p += 2;
175
176  memcpy (p, "\xff\xff\xff\xff", 4); /* filler */
177  p += 4;
178
179  /* this should be done in parts */
180
181  tmp = malloc (message_buffer->length + 8);
182  if (tmp == NULL) {
183      free (message_token->value);
184      message_token->value = NULL;
185      message_token->length = 0;
186      *minor_status = ENOMEM;
187      return GSS_S_FAILURE;
188  }
189  memcpy (tmp, p - 8, 8);
190  memcpy (tmp + 8, message_buffer->value, message_buffer->length);
191
192  kret = krb5_crypto_init(context, key, 0, &crypto);
193  if (kret) {
194      free (message_token->value);
195      message_token->value = NULL;
196      message_token->length = 0;
197      free (tmp);
198      *minor_status = kret;
199      return GSS_S_FAILURE;
200  }
201
202  kret = krb5_create_checksum (context,
203			       crypto,
204			       KRB5_KU_USAGE_SIGN,
205			       0,
206			       tmp,
207			       message_buffer->length + 8,
208			       &cksum);
209  free (tmp);
210  krb5_crypto_destroy (context, crypto);
211  if (kret) {
212      free (message_token->value);
213      message_token->value = NULL;
214      message_token->length = 0;
215      *minor_status = kret;
216      return GSS_S_FAILURE;
217  }
218
219  memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
220
221  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
222  /* sequence number */
223  krb5_auth_con_getlocalseqnumber (context,
224			       ctx->auth_context,
225			       &seq_number);
226
227  seq[0] = (seq_number >> 0)  & 0xFF;
228  seq[1] = (seq_number >> 8)  & 0xFF;
229  seq[2] = (seq_number >> 16) & 0xFF;
230  seq[3] = (seq_number >> 24) & 0xFF;
231  memset (seq + 4,
232	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
233	  4);
234
235  kret = krb5_crypto_init(context, key,
236			  ETYPE_DES3_CBC_NONE, &crypto);
237  if (kret) {
238      free (message_token->value);
239      message_token->value = NULL;
240      message_token->length = 0;
241      *minor_status = kret;
242      return GSS_S_FAILURE;
243  }
244
245  if (ctx->more_flags & COMPAT_OLD_DES3)
246      memset(ivec, 0, 8);
247  else
248      memcpy(ivec, p + 8, 8);
249
250  kret = krb5_encrypt_ivec (context,
251			    crypto,
252			    KRB5_KU_USAGE_SEQ,
253			    seq, 8, &encdata, ivec);
254  krb5_crypto_destroy (context, crypto);
255  if (kret) {
256      free (message_token->value);
257      message_token->value = NULL;
258      message_token->length = 0;
259      *minor_status = kret;
260      return GSS_S_FAILURE;
261  }
262
263  assert (encdata.length == 8);
264
265  memcpy (p, encdata.data, encdata.length);
266  krb5_data_free (&encdata);
267
268  krb5_auth_con_setlocalseqnumber (context,
269			       ctx->auth_context,
270			       ++seq_number);
271  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
272
273  free_Checksum (&cksum);
274  *minor_status = 0;
275  return GSS_S_COMPLETE;
276}
277
278OM_uint32 GSSAPI_CALLCONV _gsskrb5_get_mic
279           (OM_uint32 * minor_status,
280            const gss_ctx_id_t context_handle,
281            gss_qop_t qop_req,
282            const gss_buffer_t message_buffer,
283            gss_buffer_t message_token
284           )
285{
286  krb5_context context;
287  const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
288  krb5_keyblock *key;
289  OM_uint32 ret;
290  krb5_keytype keytype;
291
292  GSSAPI_KRB5_INIT (&context);
293
294  if (ctx->more_flags & IS_CFX)
295      return _gssapi_mic_cfx (minor_status, ctx, context, qop_req,
296			      message_buffer, message_token);
297
298  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
299  ret = _gsskrb5i_get_token_key(ctx, context, &key);
300  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
301  if (ret) {
302      *minor_status = ret;
303      return GSS_S_FAILURE;
304  }
305  krb5_enctype_to_keytype (context, key->keytype, &keytype);
306
307  switch (keytype) {
308  case KEYTYPE_DES :
309#ifdef HEIM_WEAK_CRYPTO
310      ret = mic_des (minor_status, ctx, context, qop_req,
311		     message_buffer, message_token, key);
312#else
313      ret = GSS_S_FAILURE;
314#endif
315      break;
316  case KEYTYPE_DES3 :
317      ret = mic_des3 (minor_status, ctx, context, qop_req,
318		      message_buffer, message_token, key);
319      break;
320  case KEYTYPE_ARCFOUR:
321  case KEYTYPE_ARCFOUR_56:
322      ret = _gssapi_get_mic_arcfour (minor_status, ctx, context, qop_req,
323				     message_buffer, message_token, key);
324      break;
325  default :
326      abort();
327      break;
328  }
329  krb5_free_keyblock (context, key);
330  return ret;
331}
332