• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/heimdal/lib/gssapi/krb5/
1/*
2 * Copyright (c) 1997 - 2003 Kungliga Tekniska H��gskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "gsskrb5_locl.h"
35
36/*
37 * Return initiator subkey, or if that doesn't exists, the subkey.
38 */
39
40krb5_error_code
41_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,
42			       krb5_context context,
43			       krb5_keyblock **key)
44{
45    krb5_error_code ret;
46    *key = NULL;
47
48    if (ctx->more_flags & LOCAL) {
49	ret = krb5_auth_con_getlocalsubkey(context,
50				     ctx->auth_context,
51				     key);
52    } else {
53	ret = krb5_auth_con_getremotesubkey(context,
54				      ctx->auth_context,
55				      key);
56    }
57    if (ret == 0 && *key == NULL)
58	ret = krb5_auth_con_getkey(context,
59				   ctx->auth_context,
60				   key);
61    if (ret == 0 && *key == NULL) {
62	krb5_set_error_message(context, 0, "No initiator subkey available");
63	return GSS_KRB5_S_KG_NO_SUBKEY;
64    }
65    return ret;
66}
67
68krb5_error_code
69_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,
70			      krb5_context context,
71			      krb5_keyblock **key)
72{
73    krb5_error_code ret;
74    *key = NULL;
75
76    if (ctx->more_flags & LOCAL) {
77	ret = krb5_auth_con_getremotesubkey(context,
78				      ctx->auth_context,
79				      key);
80    } else {
81	ret = krb5_auth_con_getlocalsubkey(context,
82				     ctx->auth_context,
83				     key);
84    }
85    if (ret == 0 && *key == NULL) {
86	krb5_set_error_message(context, 0, "No acceptor subkey available");
87	return GSS_KRB5_S_KG_NO_SUBKEY;
88    }
89    return ret;
90}
91
92OM_uint32
93_gsskrb5i_get_token_key(const gsskrb5_ctx ctx,
94			krb5_context context,
95			krb5_keyblock **key)
96{
97    _gsskrb5i_get_acceptor_subkey(ctx, context, key);
98    if(*key == NULL) {
99	/*
100	 * Only use the initiator subkey or ticket session key if an
101	 * acceptor subkey was not required.
102	 */
103	if ((ctx->more_flags & ACCEPTOR_SUBKEY) == 0)
104	    _gsskrb5i_get_initiator_subkey(ctx, context, key);
105    }
106    if (*key == NULL) {
107	krb5_set_error_message(context, 0, "No token key available");
108	return GSS_KRB5_S_KG_NO_SUBKEY;
109    }
110    return 0;
111}
112
113static OM_uint32
114sub_wrap_size (
115            OM_uint32 req_output_size,
116            OM_uint32 * max_input_size,
117	    int blocksize,
118	    int extrasize
119           )
120{
121    size_t len, total_len;
122
123    len = 8 + req_output_size + blocksize + extrasize;
124
125    _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
126
127    total_len -= req_output_size; /* token length */
128    if (total_len < req_output_size) {
129        *max_input_size = (req_output_size - total_len);
130        (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
131    } else {
132        *max_input_size = 0;
133    }
134    return GSS_S_COMPLETE;
135}
136
137OM_uint32
138_gsskrb5_wrap_size_limit (
139            OM_uint32 * minor_status,
140            const gss_ctx_id_t context_handle,
141            int conf_req_flag,
142            gss_qop_t qop_req,
143            OM_uint32 req_output_size,
144            OM_uint32 * max_input_size
145           )
146{
147  krb5_context context;
148  krb5_keyblock *key;
149  OM_uint32 ret;
150  krb5_keytype keytype;
151  const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
152
153  GSSAPI_KRB5_INIT (&context);
154
155  if (ctx->more_flags & IS_CFX)
156      return _gssapi_wrap_size_cfx(minor_status, ctx, context,
157				   conf_req_flag, qop_req,
158				   req_output_size, max_input_size);
159
160  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
161  ret = _gsskrb5i_get_token_key(ctx, context, &key);
162  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
163  if (ret) {
164      *minor_status = ret;
165      return GSS_S_FAILURE;
166  }
167  krb5_enctype_to_keytype (context, key->keytype, &keytype);
168
169  switch (keytype) {
170  case KEYTYPE_DES :
171      ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
172      break;
173  case KEYTYPE_ARCFOUR:
174  case KEYTYPE_ARCFOUR_56:
175      ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context,
176				      conf_req_flag, qop_req,
177				      req_output_size, max_input_size, key);
178      break;
179  case KEYTYPE_DES3 :
180      ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
181      break;
182  default :
183      abort();
184      break;
185  }
186  krb5_free_keyblock (context, key);
187  *minor_status = 0;
188  return ret;
189}
190
191static OM_uint32
192wrap_des
193           (OM_uint32 * minor_status,
194            const gsskrb5_ctx ctx,
195	    krb5_context context,
196            int conf_req_flag,
197            gss_qop_t qop_req,
198            const gss_buffer_t input_message_buffer,
199            int * conf_state,
200            gss_buffer_t output_message_buffer,
201	    krb5_keyblock *key
202           )
203{
204  u_char *p;
205  MD5_CTX md5;
206  u_char hash[16];
207  DES_key_schedule schedule;
208  DES_cblock deskey;
209  DES_cblock zero;
210  int i;
211  int32_t seq_number;
212  size_t len, total_len, padlength, datalen;
213
214  if (IS_DCE_STYLE(ctx)) {
215    padlength = 0;
216    datalen = input_message_buffer->length;
217    len = 22 + 8;
218    _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
219    total_len += datalen;
220    datalen += 8;
221  } else {
222    padlength = 8 - (input_message_buffer->length % 8);
223    datalen = input_message_buffer->length + padlength + 8;
224    len = datalen + 22;
225    _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
226  }
227
228  output_message_buffer->length = total_len;
229  output_message_buffer->value  = malloc (total_len);
230  if (output_message_buffer->value == NULL) {
231    output_message_buffer->length = 0;
232    *minor_status = ENOMEM;
233    return GSS_S_FAILURE;
234  }
235
236  p = _gsskrb5_make_header(output_message_buffer->value,
237			      len,
238			      "\x02\x01", /* TOK_ID */
239			      GSS_KRB5_MECHANISM);
240
241  /* SGN_ALG */
242  memcpy (p, "\x00\x00", 2);
243  p += 2;
244  /* SEAL_ALG */
245  if(conf_req_flag)
246      memcpy (p, "\x00\x00", 2);
247  else
248      memcpy (p, "\xff\xff", 2);
249  p += 2;
250  /* Filler */
251  memcpy (p, "\xff\xff", 2);
252  p += 2;
253
254  /* fill in later */
255  memset (p, 0, 16);
256  p += 16;
257
258  /* confounder + data + pad */
259  krb5_generate_random_block(p, 8);
260  memcpy (p + 8, input_message_buffer->value,
261	  input_message_buffer->length);
262  memset (p + 8 + input_message_buffer->length, padlength, padlength);
263
264  /* checksum */
265  MD5_Init (&md5);
266  MD5_Update (&md5, p - 24, 8);
267  MD5_Update (&md5, p, datalen);
268  MD5_Final (hash, &md5);
269
270  memset (&zero, 0, sizeof(zero));
271  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
272  DES_set_key_unchecked (&deskey, &schedule);
273  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
274		 &schedule, &zero);
275  memcpy (p - 8, hash, 8);
276
277  /* sequence number */
278  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
279  krb5_auth_con_getlocalseqnumber (context,
280				   ctx->auth_context,
281				   &seq_number);
282
283  p -= 16;
284  p[0] = (seq_number >> 0)  & 0xFF;
285  p[1] = (seq_number >> 8)  & 0xFF;
286  p[2] = (seq_number >> 16) & 0xFF;
287  p[3] = (seq_number >> 24) & 0xFF;
288  memset (p + 4,
289	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
290	  4);
291
292  DES_set_key_unchecked (&deskey, &schedule);
293  DES_cbc_encrypt ((void *)p, (void *)p, 8,
294		   &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT);
295
296  krb5_auth_con_setlocalseqnumber (context,
297			       ctx->auth_context,
298			       ++seq_number);
299  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
300
301  /* encrypt the data */
302  p += 16;
303
304  if(conf_req_flag) {
305      memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
306
307      for (i = 0; i < sizeof(deskey); ++i)
308	  deskey[i] ^= 0xf0;
309      DES_set_key_unchecked (&deskey, &schedule);
310      memset (&zero, 0, sizeof(zero));
311      DES_cbc_encrypt ((void *)p,
312		       (void *)p,
313		       datalen,
314		       &schedule,
315		       &zero,
316		       DES_ENCRYPT);
317  }
318  memset (deskey, 0, sizeof(deskey));
319  memset (&schedule, 0, sizeof(schedule));
320
321  if(conf_state != NULL)
322      *conf_state = conf_req_flag;
323  *minor_status = 0;
324  return GSS_S_COMPLETE;
325}
326
327static OM_uint32
328wrap_des3
329           (OM_uint32 * minor_status,
330            const gsskrb5_ctx ctx,
331	    krb5_context context,
332            int conf_req_flag,
333            gss_qop_t qop_req,
334            const gss_buffer_t input_message_buffer,
335            int * conf_state,
336            gss_buffer_t output_message_buffer,
337	    krb5_keyblock *key
338           )
339{
340  u_char *p;
341  u_char seq[8];
342  int32_t seq_number;
343  size_t len, total_len, padlength, datalen;
344  uint32_t ret;
345  krb5_crypto crypto;
346  Checksum cksum;
347  krb5_data encdata;
348
349  if (IS_DCE_STYLE(ctx)) {
350    padlength = 0;
351    datalen = input_message_buffer->length;
352    len = 34 + 8;
353    _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
354    total_len += datalen;
355    datalen += 8;
356  } else {
357    padlength = 8 - (input_message_buffer->length % 8);
358    datalen = input_message_buffer->length + padlength + 8;
359    len = datalen + 34;
360    _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
361  }
362
363  output_message_buffer->length = total_len;
364  output_message_buffer->value  = malloc (total_len);
365  if (output_message_buffer->value == NULL) {
366    output_message_buffer->length = 0;
367    *minor_status = ENOMEM;
368    return GSS_S_FAILURE;
369  }
370
371  p = _gsskrb5_make_header(output_message_buffer->value,
372			      len,
373			      "\x02\x01", /* TOK_ID */
374			      GSS_KRB5_MECHANISM);
375
376  /* SGN_ALG */
377  memcpy (p, "\x04\x00", 2);	/* HMAC SHA1 DES3-KD */
378  p += 2;
379  /* SEAL_ALG */
380  if(conf_req_flag)
381      memcpy (p, "\x02\x00", 2); /* DES3-KD */
382  else
383      memcpy (p, "\xff\xff", 2);
384  p += 2;
385  /* Filler */
386  memcpy (p, "\xff\xff", 2);
387  p += 2;
388
389  /* calculate checksum (the above + confounder + data + pad) */
390
391  memcpy (p + 20, p - 8, 8);
392  krb5_generate_random_block(p + 28, 8);
393  memcpy (p + 28 + 8, input_message_buffer->value,
394	  input_message_buffer->length);
395  memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
396
397  ret = krb5_crypto_init(context, key, 0, &crypto);
398  if (ret) {
399      free (output_message_buffer->value);
400      output_message_buffer->length = 0;
401      output_message_buffer->value = NULL;
402      *minor_status = ret;
403      return GSS_S_FAILURE;
404  }
405
406  ret = krb5_create_checksum (context,
407			      crypto,
408			      KRB5_KU_USAGE_SIGN,
409			      0,
410			      p + 20,
411			      datalen + 8,
412			      &cksum);
413  krb5_crypto_destroy (context, crypto);
414  if (ret) {
415      free (output_message_buffer->value);
416      output_message_buffer->length = 0;
417      output_message_buffer->value = NULL;
418      *minor_status = ret;
419      return GSS_S_FAILURE;
420  }
421
422  /* zero out SND_SEQ + SGN_CKSUM in case */
423  memset (p, 0, 28);
424
425  memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
426  free_Checksum (&cksum);
427
428  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
429  /* sequence number */
430  krb5_auth_con_getlocalseqnumber (context,
431			       ctx->auth_context,
432			       &seq_number);
433
434  seq[0] = (seq_number >> 0)  & 0xFF;
435  seq[1] = (seq_number >> 8)  & 0xFF;
436  seq[2] = (seq_number >> 16) & 0xFF;
437  seq[3] = (seq_number >> 24) & 0xFF;
438  memset (seq + 4,
439	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
440	  4);
441
442
443  ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE,
444			 &crypto);
445  if (ret) {
446      free (output_message_buffer->value);
447      output_message_buffer->length = 0;
448      output_message_buffer->value = NULL;
449      *minor_status = ret;
450      return GSS_S_FAILURE;
451  }
452
453  {
454      DES_cblock ivec;
455
456      memcpy (&ivec, p + 8, 8);
457      ret = krb5_encrypt_ivec (context,
458			       crypto,
459			       KRB5_KU_USAGE_SEQ,
460			       seq, 8, &encdata,
461			       &ivec);
462  }
463  krb5_crypto_destroy (context, crypto);
464  if (ret) {
465      free (output_message_buffer->value);
466      output_message_buffer->length = 0;
467      output_message_buffer->value = NULL;
468      *minor_status = ret;
469      return GSS_S_FAILURE;
470  }
471
472  assert (encdata.length == 8);
473
474  memcpy (p, encdata.data, encdata.length);
475  krb5_data_free (&encdata);
476
477  krb5_auth_con_setlocalseqnumber (context,
478			       ctx->auth_context,
479			       ++seq_number);
480  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
481
482  /* encrypt the data */
483  p += 28;
484
485  if(conf_req_flag) {
486      krb5_data tmp;
487
488      ret = krb5_crypto_init(context, key,
489			     ETYPE_DES3_CBC_NONE, &crypto);
490      if (ret) {
491	  free (output_message_buffer->value);
492	  output_message_buffer->length = 0;
493	  output_message_buffer->value = NULL;
494	  *minor_status = ret;
495	  return GSS_S_FAILURE;
496      }
497      ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL,
498			 p, datalen, &tmp);
499      krb5_crypto_destroy(context, crypto);
500      if (ret) {
501	  free (output_message_buffer->value);
502	  output_message_buffer->length = 0;
503	  output_message_buffer->value = NULL;
504	  *minor_status = ret;
505	  return GSS_S_FAILURE;
506      }
507      assert (tmp.length == datalen);
508
509      memcpy (p, tmp.data, datalen);
510      krb5_data_free(&tmp);
511  }
512  if(conf_state != NULL)
513      *conf_state = conf_req_flag;
514  *minor_status = 0;
515  return GSS_S_COMPLETE;
516}
517
518OM_uint32 _gsskrb5_wrap
519           (OM_uint32 * minor_status,
520            const gss_ctx_id_t context_handle,
521            int conf_req_flag,
522            gss_qop_t qop_req,
523            const gss_buffer_t input_message_buffer,
524            int * conf_state,
525            gss_buffer_t output_message_buffer
526           )
527{
528  krb5_context context;
529  krb5_keyblock *key;
530  OM_uint32 ret;
531  krb5_keytype keytype;
532  const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
533
534  output_message_buffer->value = NULL;
535  output_message_buffer->length = 0;
536
537  GSSAPI_KRB5_INIT (&context);
538
539  if (ctx->more_flags & IS_CFX)
540      return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
541			       input_message_buffer, conf_state,
542			       output_message_buffer);
543
544  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
545  ret = _gsskrb5i_get_token_key(ctx, context, &key);
546  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
547  if (ret) {
548      *minor_status = ret;
549      return GSS_S_FAILURE;
550  }
551  krb5_enctype_to_keytype (context, key->keytype, &keytype);
552
553  switch (keytype) {
554  case KEYTYPE_DES :
555      ret = wrap_des (minor_status, ctx, context, conf_req_flag,
556		      qop_req, input_message_buffer, conf_state,
557		      output_message_buffer, key);
558      break;
559  case KEYTYPE_DES3 :
560      ret = wrap_des3 (minor_status, ctx, context, conf_req_flag,
561		       qop_req, input_message_buffer, conf_state,
562		       output_message_buffer, key);
563      break;
564  case KEYTYPE_ARCFOUR:
565  case KEYTYPE_ARCFOUR_56:
566      ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag,
567				  qop_req, input_message_buffer, conf_state,
568				  output_message_buffer, key);
569      break;
570  default :
571      abort();
572      break;
573  }
574  krb5_free_keyblock (context, key);
575  return ret;
576}
577