1 /*	$NetBSD: wrap.c,v 1.1.1.2 2014/04/24 12:45:29 pettai 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 
42 krb5_error_code
_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,krb5_context context,krb5_keyblock ** key)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 
70 krb5_error_code
_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,krb5_context context,krb5_keyblock ** key)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 
94 OM_uint32
_gsskrb5i_get_token_key(const gsskrb5_ctx ctx,krb5_context context,krb5_keyblock ** key)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 
115 static OM_uint32
sub_wrap_size(OM_uint32 req_output_size,OM_uint32 * max_input_size,int blocksize,int extrasize)116 sub_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 
139 OM_uint32 GSSAPI_CALLCONV
_gsskrb5_wrap_size_limit(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,OM_uint32 req_output_size,OM_uint32 * max_input_size)140 _gsskrb5_wrap_size_limit (
141             OM_uint32 * minor_status,
142             const gss_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   krb5_keytype keytype;
153   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
154 
155   GSSAPI_KRB5_INIT (&context);
156 
157   if (ctx->more_flags & IS_CFX)
158       return _gssapi_wrap_size_cfx(minor_status, ctx, context,
159 				   conf_req_flag, qop_req,
160 				   req_output_size, max_input_size);
161 
162   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
163   ret = _gsskrb5i_get_token_key(ctx, context, &key);
164   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
165   if (ret) {
166       *minor_status = ret;
167       return GSS_S_FAILURE;
168   }
169   krb5_enctype_to_keytype (context, key->keytype, &keytype);
170 
171   switch (keytype) {
172   case KEYTYPE_DES :
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 ENCTYPE_ARCFOUR_HMAC_MD5:
180   case 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 KEYTYPE_DES3 :
186       ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
187       break;
188   default :
189       abort();
190       break;
191   }
192   krb5_free_keyblock (context, key);
193   *minor_status = 0;
194   return ret;
195 }
196 
197 #ifdef HEIM_WEAK_CRYPTO
198 
199 static OM_uint32
wrap_des(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer,krb5_keyblock * key)200 wrap_des
201            (OM_uint32 * minor_status,
202             const gsskrb5_ctx ctx,
203 	    krb5_context context,
204             int conf_req_flag,
205             gss_qop_t qop_req,
206             const gss_buffer_t input_message_buffer,
207             int * conf_state,
208             gss_buffer_t output_message_buffer,
209 	    krb5_keyblock *key
210            )
211 {
212   u_char *p;
213   EVP_MD_CTX *md5;
214   u_char hash[16];
215   DES_key_schedule schedule;
216   EVP_CIPHER_CTX des_ctx;
217   DES_cblock deskey;
218   DES_cblock zero;
219   size_t i;
220   int32_t seq_number;
221   size_t len, total_len, padlength, datalen;
222 
223   if (IS_DCE_STYLE(ctx)) {
224     padlength = 0;
225     datalen = input_message_buffer->length;
226     len = 22 + 8;
227     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
228     total_len += datalen;
229     datalen += 8;
230   } else {
231     padlength = 8 - (input_message_buffer->length % 8);
232     datalen = input_message_buffer->length + padlength + 8;
233     len = datalen + 22;
234     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
235   }
236 
237   output_message_buffer->length = total_len;
238   output_message_buffer->value  = malloc (total_len);
239   if (output_message_buffer->value == NULL) {
240     output_message_buffer->length = 0;
241     *minor_status = ENOMEM;
242     return GSS_S_FAILURE;
243   }
244 
245   p = _gsskrb5_make_header(output_message_buffer->value,
246 			      len,
247 			      "\x02\x01", /* TOK_ID */
248 			      GSS_KRB5_MECHANISM);
249 
250   /* SGN_ALG */
251   memcpy (p, "\x00\x00", 2);
252   p += 2;
253   /* SEAL_ALG */
254   if(conf_req_flag)
255       memcpy (p, "\x00\x00", 2);
256   else
257       memcpy (p, "\xff\xff", 2);
258   p += 2;
259   /* Filler */
260   memcpy (p, "\xff\xff", 2);
261   p += 2;
262 
263   /* fill in later */
264   memset (p, 0, 16);
265   p += 16;
266 
267   /* confounder + data + pad */
268   krb5_generate_random_block(p, 8);
269   memcpy (p + 8, input_message_buffer->value,
270 	  input_message_buffer->length);
271   memset (p + 8 + input_message_buffer->length, padlength, padlength);
272 
273   /* checksum */
274   md5 = EVP_MD_CTX_create();
275   EVP_DigestInit_ex(md5, EVP_md5(), NULL);
276   EVP_DigestUpdate(md5, p - 24, 8);
277   EVP_DigestUpdate(md5, p, datalen);
278   EVP_DigestFinal_ex(md5, hash, NULL);
279   EVP_MD_CTX_destroy(md5);
280 
281   memset (&zero, 0, sizeof(zero));
282   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
283   DES_set_key_unchecked (&deskey, &schedule);
284   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
285 		 &schedule, &zero);
286   memcpy (p - 8, hash, 8);
287 
288   /* sequence number */
289   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
290   krb5_auth_con_getlocalseqnumber (context,
291 				   ctx->auth_context,
292 				   &seq_number);
293 
294   p -= 16;
295   p[0] = (seq_number >> 0)  & 0xFF;
296   p[1] = (seq_number >> 8)  & 0xFF;
297   p[2] = (seq_number >> 16) & 0xFF;
298   p[3] = (seq_number >> 24) & 0xFF;
299   memset (p + 4,
300 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
301 	  4);
302 
303   EVP_CIPHER_CTX_init(&des_ctx);
304   EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1);
305   EVP_Cipher(&des_ctx, p, p, 8);
306   EVP_CIPHER_CTX_cleanup(&des_ctx);
307 
308   krb5_auth_con_setlocalseqnumber (context,
309 			       ctx->auth_context,
310 			       ++seq_number);
311   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
312 
313   /* encrypt the data */
314   p += 16;
315 
316   if(conf_req_flag) {
317       memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
318 
319       for (i = 0; i < sizeof(deskey); ++i)
320 	  deskey[i] ^= 0xf0;
321 
322       EVP_CIPHER_CTX_init(&des_ctx);
323       EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, deskey, zero, 1);
324       EVP_Cipher(&des_ctx, p, p, datalen);
325       EVP_CIPHER_CTX_cleanup(&des_ctx);
326   }
327   memset (deskey, 0, sizeof(deskey));
328   memset (&schedule, 0, sizeof(schedule));
329 
330   if(conf_state != NULL)
331       *conf_state = conf_req_flag;
332   *minor_status = 0;
333   return GSS_S_COMPLETE;
334 }
335 
336 #endif
337 
338 static OM_uint32
wrap_des3(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer,krb5_keyblock * key)339 wrap_des3
340            (OM_uint32 * minor_status,
341             const gsskrb5_ctx ctx,
342 	    krb5_context context,
343             int conf_req_flag,
344             gss_qop_t qop_req,
345             const gss_buffer_t input_message_buffer,
346             int * conf_state,
347             gss_buffer_t output_message_buffer,
348 	    krb5_keyblock *key
349            )
350 {
351   u_char *p;
352   u_char seq[8];
353   int32_t seq_number;
354   size_t len, total_len, padlength, datalen;
355   uint32_t ret;
356   krb5_crypto crypto;
357   Checksum cksum;
358   krb5_data encdata;
359 
360   if (IS_DCE_STYLE(ctx)) {
361     padlength = 0;
362     datalen = input_message_buffer->length;
363     len = 34 + 8;
364     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
365     total_len += datalen;
366     datalen += 8;
367   } else {
368     padlength = 8 - (input_message_buffer->length % 8);
369     datalen = input_message_buffer->length + padlength + 8;
370     len = datalen + 34;
371     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
372   }
373 
374   output_message_buffer->length = total_len;
375   output_message_buffer->value  = malloc (total_len);
376   if (output_message_buffer->value == NULL) {
377     output_message_buffer->length = 0;
378     *minor_status = ENOMEM;
379     return GSS_S_FAILURE;
380   }
381 
382   p = _gsskrb5_make_header(output_message_buffer->value,
383 			      len,
384 			      "\x02\x01", /* TOK_ID */
385 			      GSS_KRB5_MECHANISM);
386 
387   /* SGN_ALG */
388   memcpy (p, "\x04\x00", 2);	/* HMAC SHA1 DES3-KD */
389   p += 2;
390   /* SEAL_ALG */
391   if(conf_req_flag)
392       memcpy (p, "\x02\x00", 2); /* DES3-KD */
393   else
394       memcpy (p, "\xff\xff", 2);
395   p += 2;
396   /* Filler */
397   memcpy (p, "\xff\xff", 2);
398   p += 2;
399 
400   /* calculate checksum (the above + confounder + data + pad) */
401 
402   memcpy (p + 20, p - 8, 8);
403   krb5_generate_random_block(p + 28, 8);
404   memcpy (p + 28 + 8, input_message_buffer->value,
405 	  input_message_buffer->length);
406   memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
407 
408   ret = krb5_crypto_init(context, key, 0, &crypto);
409   if (ret) {
410       free (output_message_buffer->value);
411       output_message_buffer->length = 0;
412       output_message_buffer->value = NULL;
413       *minor_status = ret;
414       return GSS_S_FAILURE;
415   }
416 
417   ret = krb5_create_checksum (context,
418 			      crypto,
419 			      KRB5_KU_USAGE_SIGN,
420 			      0,
421 			      p + 20,
422 			      datalen + 8,
423 			      &cksum);
424   krb5_crypto_destroy (context, crypto);
425   if (ret) {
426       free (output_message_buffer->value);
427       output_message_buffer->length = 0;
428       output_message_buffer->value = NULL;
429       *minor_status = ret;
430       return GSS_S_FAILURE;
431   }
432 
433   /* zero out SND_SEQ + SGN_CKSUM in case */
434   memset (p, 0, 28);
435 
436   memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
437   free_Checksum (&cksum);
438 
439   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
440   /* sequence number */
441   krb5_auth_con_getlocalseqnumber (context,
442 			       ctx->auth_context,
443 			       &seq_number);
444 
445   seq[0] = (seq_number >> 0)  & 0xFF;
446   seq[1] = (seq_number >> 8)  & 0xFF;
447   seq[2] = (seq_number >> 16) & 0xFF;
448   seq[3] = (seq_number >> 24) & 0xFF;
449   memset (seq + 4,
450 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
451 	  4);
452 
453 
454   ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE,
455 			 &crypto);
456   if (ret) {
457       free (output_message_buffer->value);
458       output_message_buffer->length = 0;
459       output_message_buffer->value = NULL;
460       *minor_status = ret;
461       return GSS_S_FAILURE;
462   }
463 
464   {
465       DES_cblock ivec;
466 
467       memcpy (&ivec, p + 8, 8);
468       ret = krb5_encrypt_ivec (context,
469 			       crypto,
470 			       KRB5_KU_USAGE_SEQ,
471 			       seq, 8, &encdata,
472 			       &ivec);
473   }
474   krb5_crypto_destroy (context, crypto);
475   if (ret) {
476       free (output_message_buffer->value);
477       output_message_buffer->length = 0;
478       output_message_buffer->value = NULL;
479       *minor_status = ret;
480       return GSS_S_FAILURE;
481   }
482 
483   assert (encdata.length == 8);
484 
485   memcpy (p, encdata.data, encdata.length);
486   krb5_data_free (&encdata);
487 
488   krb5_auth_con_setlocalseqnumber (context,
489 			       ctx->auth_context,
490 			       ++seq_number);
491   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
492 
493   /* encrypt the data */
494   p += 28;
495 
496   if(conf_req_flag) {
497       krb5_data tmp;
498 
499       ret = krb5_crypto_init(context, key,
500 			     ETYPE_DES3_CBC_NONE, &crypto);
501       if (ret) {
502 	  free (output_message_buffer->value);
503 	  output_message_buffer->length = 0;
504 	  output_message_buffer->value = NULL;
505 	  *minor_status = ret;
506 	  return GSS_S_FAILURE;
507       }
508       ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL,
509 			 p, datalen, &tmp);
510       krb5_crypto_destroy(context, crypto);
511       if (ret) {
512 	  free (output_message_buffer->value);
513 	  output_message_buffer->length = 0;
514 	  output_message_buffer->value = NULL;
515 	  *minor_status = ret;
516 	  return GSS_S_FAILURE;
517       }
518       assert (tmp.length == datalen);
519 
520       memcpy (p, tmp.data, datalen);
521       krb5_data_free(&tmp);
522   }
523   if(conf_state != NULL)
524       *conf_state = conf_req_flag;
525   *minor_status = 0;
526   return GSS_S_COMPLETE;
527 }
528 
529 OM_uint32 GSSAPI_CALLCONV
_gsskrb5_wrap(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer)530 _gsskrb5_wrap
531            (OM_uint32 * minor_status,
532             const gss_ctx_id_t context_handle,
533             int conf_req_flag,
534             gss_qop_t qop_req,
535             const gss_buffer_t input_message_buffer,
536             int * conf_state,
537             gss_buffer_t output_message_buffer
538            )
539 {
540   krb5_context context;
541   krb5_keyblock *key;
542   OM_uint32 ret;
543   krb5_keytype keytype;
544   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
545 
546   output_message_buffer->value = NULL;
547   output_message_buffer->length = 0;
548 
549   GSSAPI_KRB5_INIT (&context);
550 
551   if (ctx->more_flags & IS_CFX)
552       return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
553 			       input_message_buffer, conf_state,
554 			       output_message_buffer);
555 
556   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
557   ret = _gsskrb5i_get_token_key(ctx, context, &key);
558   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
559   if (ret) {
560       *minor_status = ret;
561       return GSS_S_FAILURE;
562   }
563   krb5_enctype_to_keytype (context, key->keytype, &keytype);
564 
565   switch (keytype) {
566   case KEYTYPE_DES :
567 #ifdef HEIM_WEAK_CRYPTO
568       ret = wrap_des (minor_status, ctx, context, conf_req_flag,
569 		      qop_req, input_message_buffer, conf_state,
570 		      output_message_buffer, key);
571 #else
572       ret = GSS_S_FAILURE;
573 #endif
574       break;
575   case KEYTYPE_DES3 :
576       ret = wrap_des3 (minor_status, ctx, context, conf_req_flag,
577 		       qop_req, input_message_buffer, conf_state,
578 		       output_message_buffer, key);
579       break;
580   case KEYTYPE_ARCFOUR:
581   case KEYTYPE_ARCFOUR_56:
582       ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag,
583 				  qop_req, input_message_buffer, conf_state,
584 				  output_message_buffer, key);
585       break;
586   default :
587       abort();
588       break;
589   }
590   krb5_free_keyblock (context, key);
591   return ret;
592 }
593