1/*	$NetBSD: wrap.c,v 1.5 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/*
39 * Return initiator subkey, or if that doesn't exists, the subkey.
40 */
41
42krb5_error_code
43_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,
44			       krb5_context context,
45			       krb5_keyblock **key)
46{
47    krb5_error_code ret;
48    *key = NULL;
49
50    if (ctx->more_flags & LOCAL) {
51	ret = krb5_auth_con_getlocalsubkey(context,
52				     ctx->auth_context,
53				     key);
54    } else {
55	ret = krb5_auth_con_getremotesubkey(context,
56				      ctx->auth_context,
57				      key);
58    }
59    if (ret == 0 && *key == NULL)
60	ret = krb5_auth_con_getkey(context,
61				   ctx->auth_context,
62				   key);
63    if (ret == 0 && *key == NULL) {
64	krb5_set_error_message(context, 0, "No initiator subkey available");
65	return GSS_KRB5_S_KG_NO_SUBKEY;
66    }
67    return ret;
68}
69
70krb5_error_code
71_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,
72			      krb5_context context,
73			      krb5_keyblock **key)
74{
75    krb5_error_code ret;
76    *key = NULL;
77
78    if (ctx->more_flags & LOCAL) {
79	ret = krb5_auth_con_getremotesubkey(context,
80				      ctx->auth_context,
81				      key);
82    } else {
83	ret = krb5_auth_con_getlocalsubkey(context,
84				     ctx->auth_context,
85				     key);
86    }
87    if (ret == 0 && *key == NULL) {
88	krb5_set_error_message(context, 0, "No acceptor subkey available");
89	return GSS_KRB5_S_KG_NO_SUBKEY;
90    }
91    return ret;
92}
93
94OM_uint32
95_gsskrb5i_get_token_key(const gsskrb5_ctx ctx,
96			krb5_context context,
97			krb5_keyblock **key)
98{
99    _gsskrb5i_get_acceptor_subkey(ctx, context, key);
100    if(*key == NULL) {
101	/*
102	 * Only use the initiator subkey or ticket session key if an
103	 * acceptor subkey was not required.
104	 */
105	if ((ctx->more_flags & ACCEPTOR_SUBKEY) == 0)
106	    _gsskrb5i_get_initiator_subkey(ctx, context, key);
107    }
108    if (*key == NULL) {
109	krb5_set_error_message(context, 0, "No token key available");
110	return GSS_KRB5_S_KG_NO_SUBKEY;
111    }
112    return 0;
113}
114
115static OM_uint32
116sub_wrap_size (
117            OM_uint32 req_output_size,
118            OM_uint32 * max_input_size,
119	    int blocksize,
120	    int extrasize
121           )
122{
123    size_t len, total_len;
124
125    len = 8 + req_output_size + blocksize + extrasize;
126
127    _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
128
129    total_len -= req_output_size; /* token length */
130    if (total_len < req_output_size) {
131        *max_input_size = (req_output_size - total_len);
132        (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
133    } else {
134        *max_input_size = 0;
135    }
136    return GSS_S_COMPLETE;
137}
138
139OM_uint32 GSSAPI_CALLCONV
140_gsskrb5_wrap_size_limit (
141            OM_uint32 * minor_status,
142            gss_const_ctx_id_t context_handle,
143            int conf_req_flag,
144            gss_qop_t qop_req,
145            OM_uint32 req_output_size,
146            OM_uint32 * max_input_size
147           )
148{
149  krb5_context context;
150  krb5_keyblock *key;
151  OM_uint32 ret;
152  const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
153
154  GSSAPI_KRB5_INIT (&context);
155
156  if (ctx->more_flags & IS_CFX)
157      return _gssapi_wrap_size_cfx(minor_status, ctx, context,
158				   conf_req_flag, qop_req,
159				   req_output_size, max_input_size);
160
161  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
162  ret = _gsskrb5i_get_token_key(ctx, context, &key);
163  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
164  if (ret) {
165      *minor_status = ret;
166      return GSS_S_FAILURE;
167  }
168
169  switch (key->keytype) {
170  case KRB5_ENCTYPE_DES_CBC_CRC :
171  case KRB5_ENCTYPE_DES_CBC_MD4 :
172  case KRB5_ENCTYPE_DES_CBC_MD5 :
173#ifdef HEIM_WEAK_CRYPTO
174      ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
175#else
176      ret = GSS_S_FAILURE;
177#endif
178      break;
179  case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5:
180  case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56:
181      ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context,
182				      conf_req_flag, qop_req,
183				      req_output_size, max_input_size, key);
184      break;
185  case KRB5_ENCTYPE_DES3_CBC_MD5 :
186  case KRB5_ENCTYPE_DES3_CBC_SHA1 :
187      ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
188      break;
189  default :
190      abort();
191      break;
192  }
193  krb5_free_keyblock (context, key);
194  *minor_status = 0;
195  return ret;
196}
197
198#ifdef HEIM_WEAK_CRYPTO
199
200static OM_uint32
201wrap_des
202           (OM_uint32 * minor_status,
203            const gsskrb5_ctx ctx,
204	    krb5_context context,
205            int conf_req_flag,
206            gss_qop_t qop_req,
207            const gss_buffer_t input_message_buffer,
208            int * conf_state,
209            gss_buffer_t output_message_buffer,
210	    krb5_keyblock *key
211           )
212{
213  u_char *p;
214  EVP_MD_CTX *md5;
215  u_char hash[16];
216  DES_key_schedule schedule;
217  EVP_CIPHER_CTX *des_ctx;
218  DES_cblock deskey;
219  DES_cblock zero;
220  size_t i;
221  int32_t seq_number;
222  size_t len, total_len, padlength, datalen;
223
224  if (IS_DCE_STYLE(ctx)) {
225    padlength = 0;
226    datalen = input_message_buffer->length;
227    len = 22 + 8;
228    _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
229    total_len += datalen;
230    datalen += 8;
231  } else {
232    padlength = 8 - (input_message_buffer->length % 8);
233    datalen = input_message_buffer->length + padlength + 8;
234    len = datalen + 22;
235    _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
236  }
237
238  output_message_buffer->length = total_len;
239  output_message_buffer->value  = malloc (total_len);
240  if (output_message_buffer->value == NULL) {
241    output_message_buffer->length = 0;
242    *minor_status = ENOMEM;
243    return GSS_S_FAILURE;
244  }
245
246  p = _gsskrb5_make_header(output_message_buffer->value,
247			      len,
248			      "\x02\x01", /* TOK_ID */
249			      GSS_KRB5_MECHANISM);
250
251  /* SGN_ALG */
252  memcpy (p, "\x00\x00", 2);
253  p += 2;
254  /* SEAL_ALG */
255  if(conf_req_flag)
256      memcpy (p, "\x00\x00", 2);
257  else
258      memcpy (p, "\xff\xff", 2);
259  p += 2;
260  /* Filler */
261  memcpy (p, "\xff\xff", 2);
262  p += 2;
263
264  /* fill in later */
265  memset (p, 0, 16);
266  p += 16;
267
268  /* confounder + data + pad */
269  krb5_generate_random_block(p, 8);
270  memcpy (p + 8, input_message_buffer->value,
271	  input_message_buffer->length);
272  memset (p + 8 + input_message_buffer->length, padlength, padlength);
273
274  /* checksum */
275  md5 = EVP_MD_CTX_create();
276  EVP_DigestInit_ex(md5, EVP_md5(), NULL);
277  EVP_DigestUpdate(md5, p - 24, 8);
278  EVP_DigestUpdate(md5, p, datalen);
279  EVP_DigestFinal_ex(md5, hash, NULL);
280  EVP_MD_CTX_destroy(md5);
281
282  memset (&zero, 0, sizeof(zero));
283  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
284  DES_set_key_unchecked (&deskey, &schedule);
285  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
286		 &schedule, &zero);
287  memcpy (p - 8, hash, 8);
288
289  /* sequence number */
290  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
291  krb5_auth_con_getlocalseqnumber (context,
292				   ctx->auth_context,
293				   &seq_number);
294
295  p -= 16;
296  p[0] = (seq_number >> 0)  & 0xFF;
297  p[1] = (seq_number >> 8)  & 0xFF;
298  p[2] = (seq_number >> 16) & 0xFF;
299  p[3] = (seq_number >> 24) & 0xFF;
300  memset (p + 4,
301	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
302	  4);
303
304#if OPENSSL_VERSION_NUMBER < 0x10100000UL
305  EVP_CIPHER_CTX des_ctxs;
306  des_ctx = &des_ctxs;
307  EVP_CIPHER_CTX_init(des_ctx);
308#else
309  des_ctx = EVP_CIPHER_CTX_new();
310#endif
311  if (!EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data,
312      p + 8, 1)) {
313    *minor_status = EINVAL;
314    return GSS_S_FAILURE;
315  }
316  EVP_Cipher(des_ctx, p, p, 8);
317#if OPENSSL_VERSION_NUMBER < 0x10100000UL
318  EVP_CIPHER_CTX_cleanup(des_ctx);
319#else
320  EVP_CIPHER_CTX_free(des_ctx);
321#endif
322
323  krb5_auth_con_setlocalseqnumber (context,
324			       ctx->auth_context,
325			       ++seq_number);
326  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
327
328  /* encrypt the data */
329  p += 16;
330
331  if(conf_req_flag) {
332      memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
333
334      for (i = 0; i < sizeof(deskey); ++i)
335	  deskey[i] ^= 0xf0;
336
337#if OPENSSL_VERSION_NUMBER < 0x10100000UL
338      EVP_CIPHER_CTX des_ctxs;
339      des_ctx = &des_ctxs;
340      EVP_CIPHER_CTX_init(des_ctx);
341#else
342      des_ctx = EVP_CIPHER_CTX_new();
343#endif
344      if (!EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, deskey, zero, 1)) {
345	*minor_status = EINVAL;
346	return GSS_S_FAILURE;
347      }
348      EVP_Cipher(des_ctx, p, p, datalen);
349#if OPENSSL_VERSION_NUMBER < 0x10100000UL
350      EVP_CIPHER_CTX_cleanup(des_ctx);
351#else
352      EVP_CIPHER_CTX_free(des_ctx);
353#endif
354  }
355  memset (deskey, 0, sizeof(deskey));
356  memset (&schedule, 0, sizeof(schedule));
357
358  if(conf_state != NULL)
359      *conf_state = conf_req_flag;
360  *minor_status = 0;
361  return GSS_S_COMPLETE;
362}
363
364#endif
365
366static OM_uint32
367wrap_des3
368           (OM_uint32 * minor_status,
369            const gsskrb5_ctx ctx,
370	    krb5_context context,
371            int conf_req_flag,
372            gss_qop_t qop_req,
373            const gss_buffer_t input_message_buffer,
374            int * conf_state,
375            gss_buffer_t output_message_buffer,
376	    krb5_keyblock *key
377           )
378{
379  u_char *p;
380  u_char seq[8];
381  int32_t seq_number;
382  size_t len, total_len, padlength, datalen;
383  uint32_t ret;
384  krb5_crypto crypto;
385  Checksum cksum;
386  krb5_data encdata;
387
388  if (IS_DCE_STYLE(ctx)) {
389    padlength = 0;
390    datalen = input_message_buffer->length;
391    len = 34 + 8;
392    _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
393    total_len += datalen;
394    datalen += 8;
395  } else {
396    padlength = 8 - (input_message_buffer->length % 8);
397    datalen = input_message_buffer->length + padlength + 8;
398    len = datalen + 34;
399    _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
400  }
401
402  output_message_buffer->length = total_len;
403  output_message_buffer->value  = malloc (total_len);
404  if (output_message_buffer->value == NULL) {
405    output_message_buffer->length = 0;
406    *minor_status = ENOMEM;
407    return GSS_S_FAILURE;
408  }
409
410  p = _gsskrb5_make_header(output_message_buffer->value,
411			      len,
412			      "\x02\x01", /* TOK_ID */
413			      GSS_KRB5_MECHANISM);
414
415  /* SGN_ALG */
416  memcpy (p, "\x04\x00", 2);	/* HMAC SHA1 DES3-KD */
417  p += 2;
418  /* SEAL_ALG */
419  if(conf_req_flag)
420      memcpy (p, "\x02\x00", 2); /* DES3-KD */
421  else
422      memcpy (p, "\xff\xff", 2);
423  p += 2;
424  /* Filler */
425  memcpy (p, "\xff\xff", 2);
426  p += 2;
427
428  /* calculate checksum (the above + confounder + data + pad) */
429
430  memcpy (p + 20, p - 8, 8);
431  krb5_generate_random_block(p + 28, 8);
432  memcpy (p + 28 + 8, input_message_buffer->value,
433	  input_message_buffer->length);
434  memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
435
436  ret = krb5_crypto_init(context, key, 0, &crypto);
437  if (ret) {
438      free (output_message_buffer->value);
439      output_message_buffer->length = 0;
440      output_message_buffer->value = NULL;
441      *minor_status = ret;
442      return GSS_S_FAILURE;
443  }
444
445  ret = krb5_create_checksum (context,
446			      crypto,
447			      KRB5_KU_USAGE_SIGN,
448			      0,
449			      p + 20,
450			      datalen + 8,
451			      &cksum);
452  krb5_crypto_destroy (context, crypto);
453  if (ret) {
454      free (output_message_buffer->value);
455      output_message_buffer->length = 0;
456      output_message_buffer->value = NULL;
457      *minor_status = ret;
458      return GSS_S_FAILURE;
459  }
460
461  /* zero out SND_SEQ + SGN_CKSUM in case */
462  memset (p, 0, 28);
463
464  memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
465  free_Checksum (&cksum);
466
467  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
468  /* sequence number */
469  krb5_auth_con_getlocalseqnumber (context,
470			       ctx->auth_context,
471			       &seq_number);
472
473  seq[0] = (seq_number >> 0)  & 0xFF;
474  seq[1] = (seq_number >> 8)  & 0xFF;
475  seq[2] = (seq_number >> 16) & 0xFF;
476  seq[3] = (seq_number >> 24) & 0xFF;
477  memset (seq + 4,
478	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
479	  4);
480
481
482  ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE,
483			 &crypto);
484  if (ret) {
485      free (output_message_buffer->value);
486      output_message_buffer->length = 0;
487      output_message_buffer->value = NULL;
488      *minor_status = ret;
489      return GSS_S_FAILURE;
490  }
491
492  {
493      DES_cblock ivec;
494
495      memcpy (&ivec, p + 8, 8);
496      ret = krb5_encrypt_ivec (context,
497			       crypto,
498			       KRB5_KU_USAGE_SEQ,
499			       seq, 8, &encdata,
500			       &ivec);
501  }
502  krb5_crypto_destroy (context, crypto);
503  if (ret) {
504      free (output_message_buffer->value);
505      output_message_buffer->length = 0;
506      output_message_buffer->value = NULL;
507      *minor_status = ret;
508      return GSS_S_FAILURE;
509  }
510
511  assert (encdata.length == 8);
512
513  memcpy (p, encdata.data, encdata.length);
514  krb5_data_free (&encdata);
515
516  krb5_auth_con_setlocalseqnumber (context,
517			       ctx->auth_context,
518			       ++seq_number);
519  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
520
521  /* encrypt the data */
522  p += 28;
523
524  if(conf_req_flag) {
525      krb5_data tmp;
526
527      ret = krb5_crypto_init(context, key,
528			     ETYPE_DES3_CBC_NONE, &crypto);
529      if (ret) {
530	  free (output_message_buffer->value);
531	  output_message_buffer->length = 0;
532	  output_message_buffer->value = NULL;
533	  *minor_status = ret;
534	  return GSS_S_FAILURE;
535      }
536      ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL,
537			 p, datalen, &tmp);
538      krb5_crypto_destroy(context, crypto);
539      if (ret) {
540	  free (output_message_buffer->value);
541	  output_message_buffer->length = 0;
542	  output_message_buffer->value = NULL;
543	  *minor_status = ret;
544	  return GSS_S_FAILURE;
545      }
546      assert (tmp.length == datalen);
547
548      memcpy (p, tmp.data, datalen);
549      krb5_data_free(&tmp);
550  }
551  if(conf_state != NULL)
552      *conf_state = conf_req_flag;
553  *minor_status = 0;
554  return GSS_S_COMPLETE;
555}
556
557OM_uint32 GSSAPI_CALLCONV
558_gsskrb5_wrap
559           (OM_uint32 * minor_status,
560            gss_const_ctx_id_t context_handle,
561            int conf_req_flag,
562            gss_qop_t qop_req,
563            const gss_buffer_t input_message_buffer,
564            int * conf_state,
565            gss_buffer_t output_message_buffer
566           )
567{
568  krb5_context context;
569  krb5_keyblock *key;
570  OM_uint32 ret;
571  const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
572
573  output_message_buffer->value = NULL;
574  output_message_buffer->length = 0;
575
576  GSSAPI_KRB5_INIT (&context);
577
578  if (ctx->more_flags & IS_CFX)
579      return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
580			       input_message_buffer, conf_state,
581			       output_message_buffer);
582
583  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
584  ret = _gsskrb5i_get_token_key(ctx, context, &key);
585  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
586  if (ret) {
587      *minor_status = ret;
588      return GSS_S_FAILURE;
589  }
590
591  switch (key->keytype) {
592  case KRB5_ENCTYPE_DES_CBC_CRC :
593  case KRB5_ENCTYPE_DES_CBC_MD4 :
594  case KRB5_ENCTYPE_DES_CBC_MD5 :
595#ifdef HEIM_WEAK_CRYPTO
596      ret = wrap_des (minor_status, ctx, context, conf_req_flag,
597		      qop_req, input_message_buffer, conf_state,
598		      output_message_buffer, key);
599#else
600      ret = GSS_S_FAILURE;
601#endif
602      break;
603  case KRB5_ENCTYPE_DES3_CBC_MD5 :
604  case KRB5_ENCTYPE_DES3_CBC_SHA1 :
605      ret = wrap_des3 (minor_status, ctx, context, conf_req_flag,
606		       qop_req, input_message_buffer, conf_state,
607		       output_message_buffer, key);
608      break;
609  case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5:
610  case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56:
611      ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag,
612				  qop_req, input_message_buffer, conf_state,
613				  output_message_buffer, key);
614      break;
615  default :
616      abort();
617      break;
618  }
619  krb5_free_keyblock (context, key);
620  return ret;
621}
622