Fix some typos.
[heimdal.git] / lib / gssapi / krb5 / wrap.c
blob481e30375a44f8398049f77ff75ea05dce4ce7f9
1 /*
2 * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "gsskrb5_locl.h"
37 * Return initiator subkey, or if that doesn't exists, the subkey.
40 krb5_error_code
41 _gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,
42 krb5_context context,
43 krb5_keyblock **key)
45 krb5_error_code ret;
46 *key = NULL;
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);
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;
65 return ret;
68 krb5_error_code
69 _gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,
70 krb5_context context,
71 krb5_keyblock **key)
73 krb5_error_code ret;
74 *key = NULL;
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);
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;
89 return ret;
92 OM_uint32
93 _gsskrb5i_get_token_key(const gsskrb5_ctx ctx,
94 krb5_context context,
95 krb5_keyblock **key)
97 _gsskrb5i_get_acceptor_subkey(ctx, context, key);
98 if(*key == NULL) {
100 * Only use the initiator subkey or ticket session key if an
101 * acceptor subkey was not required.
103 if ((ctx->more_flags & ACCEPTOR_SUBKEY) == 0)
104 _gsskrb5i_get_initiator_subkey(ctx, context, key);
106 if (*key == NULL) {
107 krb5_set_error_message(context, 0, "No token key available");
108 return GSS_KRB5_S_KG_NO_SUBKEY;
110 return 0;
113 static OM_uint32
114 sub_wrap_size (
115 OM_uint32 req_output_size,
116 OM_uint32 * max_input_size,
117 int blocksize,
118 int extrasize
121 size_t len, total_len;
123 len = 8 + req_output_size + blocksize + extrasize;
125 _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
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;
134 return GSS_S_COMPLETE;
137 OM_uint32 GSSAPI_CALLCONV
138 _gsskrb5_wrap_size_limit (
139 OM_uint32 * minor_status,
140 gss_const_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
147 krb5_context context;
148 krb5_keyblock *key;
149 OM_uint32 ret;
150 const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
152 GSSAPI_KRB5_INIT (&context);
154 if (ctx->more_flags & IS_CFX)
155 return _gssapi_wrap_size_cfx(minor_status, ctx, context,
156 conf_req_flag, qop_req,
157 req_output_size, max_input_size);
159 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
160 ret = _gsskrb5i_get_token_key(ctx, context, &key);
161 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
162 if (ret) {
163 *minor_status = ret;
164 return GSS_S_FAILURE;
167 switch (key->keytype) {
168 case KRB5_ENCTYPE_DES_CBC_CRC :
169 case KRB5_ENCTYPE_DES_CBC_MD4 :
170 case KRB5_ENCTYPE_DES_CBC_MD5 :
171 #ifdef HEIM_WEAK_CRYPTO
172 ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
173 #else
174 ret = GSS_S_FAILURE;
175 #endif
176 break;
177 case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5:
178 case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56:
179 ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context,
180 conf_req_flag, qop_req,
181 req_output_size, max_input_size, key);
182 break;
183 case KRB5_ENCTYPE_DES3_CBC_MD5 :
184 case KRB5_ENCTYPE_DES3_CBC_SHA1 :
185 ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
186 break;
187 default :
188 abort();
189 break;
191 krb5_free_keyblock (context, key);
192 *minor_status = 0;
193 return ret;
196 #ifdef HEIM_WEAK_CRYPTO
198 static OM_uint32
199 wrap_des
200 (OM_uint32 * minor_status,
201 const gsskrb5_ctx ctx,
202 krb5_context context,
203 int conf_req_flag,
204 gss_qop_t qop_req,
205 const gss_buffer_t input_message_buffer,
206 int * conf_state,
207 gss_buffer_t output_message_buffer,
208 krb5_keyblock *key
211 u_char *p;
212 EVP_MD_CTX *md5;
213 u_char hash[16];
214 DES_key_schedule schedule;
215 EVP_CIPHER_CTX des_ctx;
216 DES_cblock deskey;
217 DES_cblock zero;
218 size_t i;
219 int32_t seq_number;
220 size_t len, total_len, padlength, datalen;
222 if (IS_DCE_STYLE(ctx)) {
223 padlength = 0;
224 datalen = input_message_buffer->length;
225 len = 22 + 8;
226 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
227 total_len += datalen;
228 datalen += 8;
229 } else {
230 padlength = 8 - (input_message_buffer->length % 8);
231 datalen = input_message_buffer->length + padlength + 8;
232 len = datalen + 22;
233 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
236 output_message_buffer->length = total_len;
237 output_message_buffer->value = malloc (total_len);
238 if (output_message_buffer->value == NULL) {
239 output_message_buffer->length = 0;
240 *minor_status = ENOMEM;
241 return GSS_S_FAILURE;
244 p = _gsskrb5_make_header(output_message_buffer->value,
245 len,
246 "\x02\x01", /* TOK_ID */
247 GSS_KRB5_MECHANISM);
249 /* SGN_ALG */
250 memcpy (p, "\x00\x00", 2);
251 p += 2;
252 /* SEAL_ALG */
253 if(conf_req_flag)
254 memcpy (p, "\x00\x00", 2);
255 else
256 memcpy (p, "\xff\xff", 2);
257 p += 2;
258 /* Filler */
259 memcpy (p, "\xff\xff", 2);
260 p += 2;
262 /* fill in later */
263 memset (p, 0, 16);
264 p += 16;
266 /* confounder + data + pad */
267 krb5_generate_random_block(p, 8);
268 memcpy (p + 8, input_message_buffer->value,
269 input_message_buffer->length);
270 memset (p + 8 + input_message_buffer->length, padlength, padlength);
272 /* checksum */
273 md5 = EVP_MD_CTX_create();
274 EVP_DigestInit_ex(md5, EVP_md5(), NULL);
275 EVP_DigestUpdate(md5, p - 24, 8);
276 EVP_DigestUpdate(md5, p, datalen);
277 EVP_DigestFinal_ex(md5, hash, NULL);
278 EVP_MD_CTX_destroy(md5);
280 memset (&zero, 0, sizeof(zero));
281 memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
282 DES_set_key_unchecked (&deskey, &schedule);
283 DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
284 &schedule, &zero);
285 memcpy (p - 8, hash, 8);
287 /* sequence number */
288 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
289 krb5_auth_con_getlocalseqnumber (context,
290 ctx->auth_context,
291 &seq_number);
293 p -= 16;
294 p[0] = (seq_number >> 0) & 0xFF;
295 p[1] = (seq_number >> 8) & 0xFF;
296 p[2] = (seq_number >> 16) & 0xFF;
297 p[3] = (seq_number >> 24) & 0xFF;
298 memset (p + 4,
299 (ctx->more_flags & LOCAL) ? 0 : 0xFF,
302 EVP_CIPHER_CTX_init(&des_ctx);
303 EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1);
304 EVP_Cipher(&des_ctx, p, p, 8);
305 EVP_CIPHER_CTX_cleanup(&des_ctx);
307 krb5_auth_con_setlocalseqnumber (context,
308 ctx->auth_context,
309 ++seq_number);
310 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
312 /* encrypt the data */
313 p += 16;
315 if(conf_req_flag) {
316 memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
318 for (i = 0; i < sizeof(deskey); ++i)
319 deskey[i] ^= 0xf0;
321 EVP_CIPHER_CTX_init(&des_ctx);
322 EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, deskey, zero, 1);
323 EVP_Cipher(&des_ctx, p, p, datalen);
324 EVP_CIPHER_CTX_cleanup(&des_ctx);
326 memset (deskey, 0, sizeof(deskey));
327 memset (&schedule, 0, sizeof(schedule));
329 if(conf_state != NULL)
330 *conf_state = conf_req_flag;
331 *minor_status = 0;
332 return GSS_S_COMPLETE;
335 #endif
337 static OM_uint32
338 wrap_des3
339 (OM_uint32 * minor_status,
340 const gsskrb5_ctx ctx,
341 krb5_context context,
342 int conf_req_flag,
343 gss_qop_t qop_req,
344 const gss_buffer_t input_message_buffer,
345 int * conf_state,
346 gss_buffer_t output_message_buffer,
347 krb5_keyblock *key
350 u_char *p;
351 u_char seq[8];
352 int32_t seq_number;
353 size_t len, total_len, padlength, datalen;
354 uint32_t ret;
355 krb5_crypto crypto;
356 Checksum cksum;
357 krb5_data encdata;
359 if (IS_DCE_STYLE(ctx)) {
360 padlength = 0;
361 datalen = input_message_buffer->length;
362 len = 34 + 8;
363 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
364 total_len += datalen;
365 datalen += 8;
366 } else {
367 padlength = 8 - (input_message_buffer->length % 8);
368 datalen = input_message_buffer->length + padlength + 8;
369 len = datalen + 34;
370 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
373 output_message_buffer->length = total_len;
374 output_message_buffer->value = malloc (total_len);
375 if (output_message_buffer->value == NULL) {
376 output_message_buffer->length = 0;
377 *minor_status = ENOMEM;
378 return GSS_S_FAILURE;
381 p = _gsskrb5_make_header(output_message_buffer->value,
382 len,
383 "\x02\x01", /* TOK_ID */
384 GSS_KRB5_MECHANISM);
386 /* SGN_ALG */
387 memcpy (p, "\x04\x00", 2); /* HMAC SHA1 DES3-KD */
388 p += 2;
389 /* SEAL_ALG */
390 if(conf_req_flag)
391 memcpy (p, "\x02\x00", 2); /* DES3-KD */
392 else
393 memcpy (p, "\xff\xff", 2);
394 p += 2;
395 /* Filler */
396 memcpy (p, "\xff\xff", 2);
397 p += 2;
399 /* calculate checksum (the above + confounder + data + pad) */
401 memcpy (p + 20, p - 8, 8);
402 krb5_generate_random_block(p + 28, 8);
403 memcpy (p + 28 + 8, input_message_buffer->value,
404 input_message_buffer->length);
405 memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
407 ret = krb5_crypto_init(context, key, 0, &crypto);
408 if (ret) {
409 free (output_message_buffer->value);
410 output_message_buffer->length = 0;
411 output_message_buffer->value = NULL;
412 *minor_status = ret;
413 return GSS_S_FAILURE;
416 ret = krb5_create_checksum (context,
417 crypto,
418 KRB5_KU_USAGE_SIGN,
420 p + 20,
421 datalen + 8,
422 &cksum);
423 krb5_crypto_destroy (context, crypto);
424 if (ret) {
425 free (output_message_buffer->value);
426 output_message_buffer->length = 0;
427 output_message_buffer->value = NULL;
428 *minor_status = ret;
429 return GSS_S_FAILURE;
432 /* zero out SND_SEQ + SGN_CKSUM in case */
433 memset (p, 0, 28);
435 memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
436 free_Checksum (&cksum);
438 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
439 /* sequence number */
440 krb5_auth_con_getlocalseqnumber (context,
441 ctx->auth_context,
442 &seq_number);
444 seq[0] = (seq_number >> 0) & 0xFF;
445 seq[1] = (seq_number >> 8) & 0xFF;
446 seq[2] = (seq_number >> 16) & 0xFF;
447 seq[3] = (seq_number >> 24) & 0xFF;
448 memset (seq + 4,
449 (ctx->more_flags & LOCAL) ? 0 : 0xFF,
453 ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE,
454 &crypto);
455 if (ret) {
456 free (output_message_buffer->value);
457 output_message_buffer->length = 0;
458 output_message_buffer->value = NULL;
459 *minor_status = ret;
460 return GSS_S_FAILURE;
464 DES_cblock ivec;
466 memcpy (&ivec, p + 8, 8);
467 ret = krb5_encrypt_ivec (context,
468 crypto,
469 KRB5_KU_USAGE_SEQ,
470 seq, 8, &encdata,
471 &ivec);
473 krb5_crypto_destroy (context, crypto);
474 if (ret) {
475 free (output_message_buffer->value);
476 output_message_buffer->length = 0;
477 output_message_buffer->value = NULL;
478 *minor_status = ret;
479 return GSS_S_FAILURE;
482 assert (encdata.length == 8);
484 memcpy (p, encdata.data, encdata.length);
485 krb5_data_free (&encdata);
487 krb5_auth_con_setlocalseqnumber (context,
488 ctx->auth_context,
489 ++seq_number);
490 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
492 /* encrypt the data */
493 p += 28;
495 if(conf_req_flag) {
496 krb5_data tmp;
498 ret = krb5_crypto_init(context, key,
499 ETYPE_DES3_CBC_NONE, &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;
507 ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL,
508 p, datalen, &tmp);
509 krb5_crypto_destroy(context, crypto);
510 if (ret) {
511 free (output_message_buffer->value);
512 output_message_buffer->length = 0;
513 output_message_buffer->value = NULL;
514 *minor_status = ret;
515 return GSS_S_FAILURE;
517 assert (tmp.length == datalen);
519 memcpy (p, tmp.data, datalen);
520 krb5_data_free(&tmp);
522 if(conf_state != NULL)
523 *conf_state = conf_req_flag;
524 *minor_status = 0;
525 return GSS_S_COMPLETE;
528 OM_uint32 GSSAPI_CALLCONV
529 _gsskrb5_wrap
530 (OM_uint32 * minor_status,
531 gss_const_ctx_id_t context_handle,
532 int conf_req_flag,
533 gss_qop_t qop_req,
534 const gss_buffer_t input_message_buffer,
535 int * conf_state,
536 gss_buffer_t output_message_buffer
539 krb5_context context;
540 krb5_keyblock *key;
541 OM_uint32 ret;
542 const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
544 output_message_buffer->value = NULL;
545 output_message_buffer->length = 0;
547 GSSAPI_KRB5_INIT (&context);
549 if (ctx->more_flags & IS_CFX)
550 return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
551 input_message_buffer, conf_state,
552 output_message_buffer);
554 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
555 ret = _gsskrb5i_get_token_key(ctx, context, &key);
556 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
557 if (ret) {
558 *minor_status = ret;
559 return GSS_S_FAILURE;
562 switch (key->keytype) {
563 case KRB5_ENCTYPE_DES_CBC_CRC :
564 case KRB5_ENCTYPE_DES_CBC_MD4 :
565 case KRB5_ENCTYPE_DES_CBC_MD5 :
566 #ifdef HEIM_WEAK_CRYPTO
567 ret = wrap_des (minor_status, ctx, context, conf_req_flag,
568 qop_req, input_message_buffer, conf_state,
569 output_message_buffer, key);
570 #else
571 ret = GSS_S_FAILURE;
572 #endif
573 break;
574 case KRB5_ENCTYPE_DES3_CBC_MD5 :
575 case KRB5_ENCTYPE_DES3_CBC_SHA1 :
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 KRB5_ENCTYPE_ARCFOUR_HMAC_MD5:
581 case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_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;
590 krb5_free_keyblock (context, key);
591 return ret;