Implement gss_wrap_iov, gss_unwrap_iov for CFX type encryption types.
[heimdal.git] / lib / gssapi / krb5 / wrap.c
blob9627cc20b02f1387ba36500eb931a35e0efe210a
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
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
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;
153 GSSAPI_KRB5_INIT (&context);
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);
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;
167 krb5_enctype_to_keytype (context, key->keytype, &keytype);
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;
186 krb5_free_keyblock (context, key);
187 *minor_status = 0;
188 return ret;
191 static OM_uint32
192 wrap_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
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;
214 padlength = 8 - (input_message_buffer->length % 8);
215 datalen = input_message_buffer->length + padlength + 8;
216 len = datalen + 22;
217 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
219 output_message_buffer->length = total_len;
220 output_message_buffer->value = malloc (total_len);
221 if (output_message_buffer->value == NULL) {
222 output_message_buffer->length = 0;
223 *minor_status = ENOMEM;
224 return GSS_S_FAILURE;
227 p = _gsskrb5_make_header(output_message_buffer->value,
228 len,
229 "\x02\x01", /* TOK_ID */
230 GSS_KRB5_MECHANISM);
232 /* SGN_ALG */
233 memcpy (p, "\x00\x00", 2);
234 p += 2;
235 /* SEAL_ALG */
236 if(conf_req_flag)
237 memcpy (p, "\x00\x00", 2);
238 else
239 memcpy (p, "\xff\xff", 2);
240 p += 2;
241 /* Filler */
242 memcpy (p, "\xff\xff", 2);
243 p += 2;
245 /* fill in later */
246 memset (p, 0, 16);
247 p += 16;
249 /* confounder + data + pad */
250 krb5_generate_random_block(p, 8);
251 memcpy (p + 8, input_message_buffer->value,
252 input_message_buffer->length);
253 memset (p + 8 + input_message_buffer->length, padlength, padlength);
255 /* checksum */
256 MD5_Init (&md5);
257 MD5_Update (&md5, p - 24, 8);
258 MD5_Update (&md5, p, datalen);
259 MD5_Final (hash, &md5);
261 memset (&zero, 0, sizeof(zero));
262 memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
263 DES_set_key_unchecked (&deskey, &schedule);
264 DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
265 &schedule, &zero);
266 memcpy (p - 8, hash, 8);
268 /* sequence number */
269 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
270 krb5_auth_con_getlocalseqnumber (context,
271 ctx->auth_context,
272 &seq_number);
274 p -= 16;
275 p[0] = (seq_number >> 0) & 0xFF;
276 p[1] = (seq_number >> 8) & 0xFF;
277 p[2] = (seq_number >> 16) & 0xFF;
278 p[3] = (seq_number >> 24) & 0xFF;
279 memset (p + 4,
280 (ctx->more_flags & LOCAL) ? 0 : 0xFF,
283 DES_set_key_unchecked (&deskey, &schedule);
284 DES_cbc_encrypt ((void *)p, (void *)p, 8,
285 &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT);
287 krb5_auth_con_setlocalseqnumber (context,
288 ctx->auth_context,
289 ++seq_number);
290 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
292 /* encrypt the data */
293 p += 16;
295 if(conf_req_flag) {
296 memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
298 for (i = 0; i < sizeof(deskey); ++i)
299 deskey[i] ^= 0xf0;
300 DES_set_key_unchecked (&deskey, &schedule);
301 memset (&zero, 0, sizeof(zero));
302 DES_cbc_encrypt ((void *)p,
303 (void *)p,
304 datalen,
305 &schedule,
306 &zero,
307 DES_ENCRYPT);
309 memset (deskey, 0, sizeof(deskey));
310 memset (&schedule, 0, sizeof(schedule));
312 if(conf_state != NULL)
313 *conf_state = conf_req_flag;
314 *minor_status = 0;
315 return GSS_S_COMPLETE;
318 static OM_uint32
319 wrap_des3
320 (OM_uint32 * minor_status,
321 const gsskrb5_ctx ctx,
322 krb5_context context,
323 int conf_req_flag,
324 gss_qop_t qop_req,
325 const gss_buffer_t input_message_buffer,
326 int * conf_state,
327 gss_buffer_t output_message_buffer,
328 krb5_keyblock *key
331 u_char *p;
332 u_char seq[8];
333 int32_t seq_number;
334 size_t len, total_len, padlength, datalen;
335 uint32_t ret;
336 krb5_crypto crypto;
337 Checksum cksum;
338 krb5_data encdata;
340 padlength = 8 - (input_message_buffer->length % 8);
341 datalen = input_message_buffer->length + padlength + 8;
342 len = datalen + 34;
343 _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
345 output_message_buffer->length = total_len;
346 output_message_buffer->value = malloc (total_len);
347 if (output_message_buffer->value == NULL) {
348 output_message_buffer->length = 0;
349 *minor_status = ENOMEM;
350 return GSS_S_FAILURE;
353 p = _gsskrb5_make_header(output_message_buffer->value,
354 len,
355 "\x02\x01", /* TOK_ID */
356 GSS_KRB5_MECHANISM);
358 /* SGN_ALG */
359 memcpy (p, "\x04\x00", 2); /* HMAC SHA1 DES3-KD */
360 p += 2;
361 /* SEAL_ALG */
362 if(conf_req_flag)
363 memcpy (p, "\x02\x00", 2); /* DES3-KD */
364 else
365 memcpy (p, "\xff\xff", 2);
366 p += 2;
367 /* Filler */
368 memcpy (p, "\xff\xff", 2);
369 p += 2;
371 /* calculate checksum (the above + confounder + data + pad) */
373 memcpy (p + 20, p - 8, 8);
374 krb5_generate_random_block(p + 28, 8);
375 memcpy (p + 28 + 8, input_message_buffer->value,
376 input_message_buffer->length);
377 memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
379 ret = krb5_crypto_init(context, key, 0, &crypto);
380 if (ret) {
381 free (output_message_buffer->value);
382 output_message_buffer->length = 0;
383 output_message_buffer->value = NULL;
384 *minor_status = ret;
385 return GSS_S_FAILURE;
388 ret = krb5_create_checksum (context,
389 crypto,
390 KRB5_KU_USAGE_SIGN,
392 p + 20,
393 datalen + 8,
394 &cksum);
395 krb5_crypto_destroy (context, crypto);
396 if (ret) {
397 free (output_message_buffer->value);
398 output_message_buffer->length = 0;
399 output_message_buffer->value = NULL;
400 *minor_status = ret;
401 return GSS_S_FAILURE;
404 /* zero out SND_SEQ + SGN_CKSUM in case */
405 memset (p, 0, 28);
407 memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
408 free_Checksum (&cksum);
410 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
411 /* sequence number */
412 krb5_auth_con_getlocalseqnumber (context,
413 ctx->auth_context,
414 &seq_number);
416 seq[0] = (seq_number >> 0) & 0xFF;
417 seq[1] = (seq_number >> 8) & 0xFF;
418 seq[2] = (seq_number >> 16) & 0xFF;
419 seq[3] = (seq_number >> 24) & 0xFF;
420 memset (seq + 4,
421 (ctx->more_flags & LOCAL) ? 0 : 0xFF,
425 ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE,
426 &crypto);
427 if (ret) {
428 free (output_message_buffer->value);
429 output_message_buffer->length = 0;
430 output_message_buffer->value = NULL;
431 *minor_status = ret;
432 return GSS_S_FAILURE;
436 DES_cblock ivec;
438 memcpy (&ivec, p + 8, 8);
439 ret = krb5_encrypt_ivec (context,
440 crypto,
441 KRB5_KU_USAGE_SEQ,
442 seq, 8, &encdata,
443 &ivec);
445 krb5_crypto_destroy (context, crypto);
446 if (ret) {
447 free (output_message_buffer->value);
448 output_message_buffer->length = 0;
449 output_message_buffer->value = NULL;
450 *minor_status = ret;
451 return GSS_S_FAILURE;
454 assert (encdata.length == 8);
456 memcpy (p, encdata.data, encdata.length);
457 krb5_data_free (&encdata);
459 krb5_auth_con_setlocalseqnumber (context,
460 ctx->auth_context,
461 ++seq_number);
462 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
464 /* encrypt the data */
465 p += 28;
467 if(conf_req_flag) {
468 krb5_data tmp;
470 ret = krb5_crypto_init(context, key,
471 ETYPE_DES3_CBC_NONE, &crypto);
472 if (ret) {
473 free (output_message_buffer->value);
474 output_message_buffer->length = 0;
475 output_message_buffer->value = NULL;
476 *minor_status = ret;
477 return GSS_S_FAILURE;
479 ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL,
480 p, datalen, &tmp);
481 krb5_crypto_destroy(context, crypto);
482 if (ret) {
483 free (output_message_buffer->value);
484 output_message_buffer->length = 0;
485 output_message_buffer->value = NULL;
486 *minor_status = ret;
487 return GSS_S_FAILURE;
489 assert (tmp.length == datalen);
491 memcpy (p, tmp.data, datalen);
492 krb5_data_free(&tmp);
494 if(conf_state != NULL)
495 *conf_state = conf_req_flag;
496 *minor_status = 0;
497 return GSS_S_COMPLETE;
500 OM_uint32 _gsskrb5_wrap
501 (OM_uint32 * minor_status,
502 const gss_ctx_id_t context_handle,
503 int conf_req_flag,
504 gss_qop_t qop_req,
505 const gss_buffer_t input_message_buffer,
506 int * conf_state,
507 gss_buffer_t output_message_buffer
510 krb5_context context;
511 krb5_keyblock *key;
512 OM_uint32 ret;
513 krb5_keytype keytype;
514 const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
516 output_message_buffer->value = NULL;
517 output_message_buffer->length = 0;
519 GSSAPI_KRB5_INIT (&context);
521 if (ctx->more_flags & IS_CFX)
522 return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
523 input_message_buffer, conf_state,
524 output_message_buffer);
526 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
527 ret = _gsskrb5i_get_token_key(ctx, context, &key);
528 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
529 if (ret) {
530 *minor_status = ret;
531 return GSS_S_FAILURE;
533 krb5_enctype_to_keytype (context, key->keytype, &keytype);
535 switch (keytype) {
536 case KEYTYPE_DES :
537 ret = wrap_des (minor_status, ctx, context, conf_req_flag,
538 qop_req, input_message_buffer, conf_state,
539 output_message_buffer, key);
540 break;
541 case KEYTYPE_DES3 :
542 ret = wrap_des3 (minor_status, ctx, context, conf_req_flag,
543 qop_req, input_message_buffer, conf_state,
544 output_message_buffer, key);
545 break;
546 case KEYTYPE_ARCFOUR:
547 case KEYTYPE_ARCFOUR_56:
548 ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag,
549 qop_req, input_message_buffer, conf_state,
550 output_message_buffer, key);
551 break;
552 default :
553 abort();
554 break;
556 krb5_free_keyblock (context, key);
557 return ret;