1/*	$NetBSD: get_mic.c,v 1.6 2023/06/19 21:41:43 christos 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
117#if OPENSSL_VERSION_NUMBER < 0x10100000UL
118  EVP_CIPHER_CTX des_ctxs;
119  des_ctx = &des_ctxs;
120  EVP_CIPHER_CTX_init(des_ctx);
121#else
122  des_ctx = EVP_CIPHER_CTX_new();
123#endif
124  EVP_CIPHER_CTX_init(des_ctx);
125  if (!EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data,
126      p + 8, 1)) {
127      *minor_status = EINVAL;
128      return GSS_S_FAILURE;
129  }
130  EVP_Cipher(des_ctx, p, p, 8);
131#if OPENSSL_VERSION_NUMBER < 0x10100000UL
132  EVP_CIPHER_CTX_cleanup(des_ctx);
133#else
134  EVP_CIPHER_CTX_free(des_ctx);
135#endif
136
137  krb5_auth_con_setlocalseqnumber (context,
138			       ctx->auth_context,
139			       ++seq_number);
140  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
141
142  memset_s(deskey, sizeof(deskey), 0, sizeof(deskey));
143  memset_s(&schedule, sizeof(schedule), 0, sizeof(schedule));
144
145  *minor_status = 0;
146  return GSS_S_COMPLETE;
147}
148#endif
149
150static OM_uint32
151mic_des3
152           (OM_uint32 * minor_status,
153            const gsskrb5_ctx ctx,
154	    krb5_context context,
155            gss_qop_t qop_req,
156            const gss_buffer_t message_buffer,
157            gss_buffer_t message_token,
158	    krb5_keyblock *key
159           )
160{
161  u_char *p;
162  Checksum cksum;
163  u_char seq[8];
164
165  int32_t seq_number;
166  size_t len, total_len;
167
168  krb5_crypto crypto;
169  krb5_error_code kret;
170  krb5_data encdata;
171  char *tmp;
172  char ivec[8];
173
174  _gsskrb5_encap_length (36, &len, &total_len, GSS_KRB5_MECHANISM);
175
176  message_token->length = total_len;
177  message_token->value  = malloc (total_len);
178  if (message_token->value == NULL) {
179      message_token->length = 0;
180      *minor_status = ENOMEM;
181      return GSS_S_FAILURE;
182  }
183
184  p = _gsskrb5_make_header(message_token->value,
185			      len,
186			      "\x01\x01", /* TOK-ID */
187			      GSS_KRB5_MECHANISM);
188
189  memcpy (p, "\x04\x00", 2);	/* SGN_ALG = HMAC SHA1 DES3-KD */
190  p += 2;
191
192  memcpy (p, "\xff\xff\xff\xff", 4); /* filler */
193  p += 4;
194
195  /* this should be done in parts */
196
197  tmp = malloc (message_buffer->length + 8);
198  if (tmp == NULL) {
199      free (message_token->value);
200      message_token->value = NULL;
201      message_token->length = 0;
202      *minor_status = ENOMEM;
203      return GSS_S_FAILURE;
204  }
205  memcpy (tmp, p - 8, 8);
206  memcpy (tmp + 8, message_buffer->value, message_buffer->length);
207
208  kret = krb5_crypto_init(context, key, 0, &crypto);
209  if (kret) {
210      free (message_token->value);
211      message_token->value = NULL;
212      message_token->length = 0;
213      free (tmp);
214      *minor_status = kret;
215      return GSS_S_FAILURE;
216  }
217
218  kret = krb5_create_checksum (context,
219			       crypto,
220			       KRB5_KU_USAGE_SIGN,
221			       0,
222			       tmp,
223			       message_buffer->length + 8,
224			       &cksum);
225  free (tmp);
226  krb5_crypto_destroy (context, crypto);
227  if (kret) {
228      free (message_token->value);
229      message_token->value = NULL;
230      message_token->length = 0;
231      *minor_status = kret;
232      return GSS_S_FAILURE;
233  }
234
235  memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
236
237  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
238  /* sequence number */
239  krb5_auth_con_getlocalseqnumber (context,
240			       ctx->auth_context,
241			       &seq_number);
242
243  seq[0] = (seq_number >> 0)  & 0xFF;
244  seq[1] = (seq_number >> 8)  & 0xFF;
245  seq[2] = (seq_number >> 16) & 0xFF;
246  seq[3] = (seq_number >> 24) & 0xFF;
247  memset (seq + 4,
248	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
249	  4);
250
251  kret = krb5_crypto_init(context, key,
252			  ETYPE_DES3_CBC_NONE, &crypto);
253  if (kret) {
254      free (message_token->value);
255      message_token->value = NULL;
256      message_token->length = 0;
257      *minor_status = kret;
258      return GSS_S_FAILURE;
259  }
260
261  if (ctx->more_flags & COMPAT_OLD_DES3)
262      memset(ivec, 0, 8);
263  else
264      memcpy(ivec, p + 8, 8);
265
266  kret = krb5_encrypt_ivec (context,
267			    crypto,
268			    KRB5_KU_USAGE_SEQ,
269			    seq, 8, &encdata, ivec);
270  krb5_crypto_destroy (context, crypto);
271  if (kret) {
272      free (message_token->value);
273      message_token->value = NULL;
274      message_token->length = 0;
275      *minor_status = kret;
276      return GSS_S_FAILURE;
277  }
278
279  assert (encdata.length == 8);
280
281  memcpy (p, encdata.data, encdata.length);
282  krb5_data_free (&encdata);
283
284  krb5_auth_con_setlocalseqnumber (context,
285			       ctx->auth_context,
286			       ++seq_number);
287  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
288
289  free_Checksum (&cksum);
290  *minor_status = 0;
291  return GSS_S_COMPLETE;
292}
293
294OM_uint32 GSSAPI_CALLCONV _gsskrb5_get_mic
295           (OM_uint32 * minor_status,
296            gss_const_ctx_id_t context_handle,
297            gss_qop_t qop_req,
298            const gss_buffer_t message_buffer,
299            gss_buffer_t message_token
300           )
301{
302  krb5_context context;
303  const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
304  krb5_keyblock *key;
305  OM_uint32 ret;
306
307  GSSAPI_KRB5_INIT (&context);
308
309  if (ctx->more_flags & IS_CFX)
310      return _gssapi_mic_cfx (minor_status, ctx, context, qop_req,
311			      message_buffer, message_token);
312
313  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
314  ret = _gsskrb5i_get_token_key(ctx, context, &key);
315  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
316  if (ret) {
317      *minor_status = ret;
318      return GSS_S_FAILURE;
319  }
320
321  switch (key->keytype) {
322  case KRB5_ENCTYPE_DES_CBC_CRC :
323  case KRB5_ENCTYPE_DES_CBC_MD4 :
324  case KRB5_ENCTYPE_DES_CBC_MD5 :
325#ifdef HEIM_WEAK_CRYPTO
326      ret = mic_des (minor_status, ctx, context, qop_req,
327		     message_buffer, message_token, key);
328#else
329      ret = GSS_S_FAILURE;
330#endif
331      break;
332  case KRB5_ENCTYPE_DES3_CBC_MD5 :
333  case KRB5_ENCTYPE_DES3_CBC_SHA1 :
334      ret = mic_des3 (minor_status, ctx, context, qop_req,
335		      message_buffer, message_token, key);
336      break;
337  case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5:
338  case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56:
339      ret = _gssapi_get_mic_arcfour (minor_status, ctx, context, qop_req,
340				     message_buffer, message_token, key);
341      break;
342  default :
343      abort();
344      break;
345  }
346  krb5_free_keyblock (context, key);
347  return ret;
348}
349