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
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,gss_const_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 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
200 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)201 wrap_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
366 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)367 wrap_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
557 OM_uint32 GSSAPI_CALLCONV
_gsskrb5_wrap(OM_uint32 * minor_status,gss_const_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)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