2 * Copyright (c) 2003 - 2004 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
34 #include "gssapi_locl.h"
36 RCSID("$Id: arcfour.c,v 1.17 2005/05/06 07:13:32 lha Exp $");
39 * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt
41 * The arcfour message have the following formats:
61 static krb5_error_code
62 arcfour_mic_key(krb5_context context, krb5_keyblock *key,
63 void *cksum_data, size_t cksum_size,
64 void *key6_data, size_t key6_size)
77 cksum_k5.checksum.data = k5_data;
78 cksum_k5.checksum.length = sizeof(k5_data);
80 if (key->keytype == KEYTYPE_ARCFOUR_56) {
81 char L40[14] = "fortybits";
83 memcpy(L40 + 10, T, sizeof(T));
84 ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
85 L40, 14, 0, key, &cksum_k5);
86 memset(&k5_data[7], 0xAB, 9);
88 ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
89 T, 4, 0, key, &cksum_k5);
94 key5.keytype = KEYTYPE_ARCFOUR;
95 key5.keyvalue = cksum_k5.checksum;
97 cksum_k6.checksum.data = key6_data;
98 cksum_k6.checksum.length = key6_size;
100 return krb5_hmac(context, CKSUMTYPE_RSA_MD5,
101 cksum_data, cksum_size, 0, &key5, &cksum_k6);
105 static krb5_error_code
106 arcfour_mic_cksum(krb5_keyblock *key, unsigned usage,
107 u_char *sgn_cksum, size_t sgn_cksum_sz,
108 const char *v1, size_t l1,
109 const void *v2, size_t l2,
110 const void *v3, size_t l3)
118 assert(sgn_cksum_sz == 8);
127 memcpy(ptr + l1, v2, l2);
128 memcpy(ptr + l1 + l2, v3, l3);
130 ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
136 ret = krb5_create_checksum(gssapi_krb5_context,
144 memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz);
145 free_Checksum(&CKSUM);
147 krb5_crypto_destroy(gssapi_krb5_context, crypto);
154 _gssapi_get_mic_arcfour(OM_uint32 * minor_status,
155 const gss_ctx_id_t context_handle,
157 const gss_buffer_t message_buffer,
158 gss_buffer_t message_token,
163 size_t len, total_len;
164 u_char k6_data[16], *p0, *p;
167 gssapi_krb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM);
169 message_token->length = total_len;
170 message_token->value = malloc (total_len);
171 if (message_token->value == NULL) {
172 *minor_status = ENOMEM;
173 return GSS_S_FAILURE;
176 p0 = _gssapi_make_mech_header(message_token->value,
181 *p++ = 0x01; /* TOK_ID */
183 *p++ = 0x11; /* SGN_ALG */
185 *p++ = 0xff; /* Filler */
192 ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN,
193 p0 + 16, 8, /* SGN_CKSUM */
194 p0, 8, /* TOK_ID, SGN_ALG, Filer */
195 message_buffer->value, message_buffer->length,
198 gss_release_buffer(minor_status, message_token);
200 return GSS_S_FAILURE;
203 ret = arcfour_mic_key(gssapi_krb5_context, key,
204 p0 + 16, 8, /* SGN_CKSUM */
205 k6_data, sizeof(k6_data));
207 gss_release_buffer(minor_status, message_token);
209 return GSS_S_FAILURE;
212 HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
213 krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
214 context_handle->auth_context,
216 p = p0 + 8; /* SND_SEQ */
217 gssapi_encode_be_om_uint32(seq_number, p);
219 krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
220 context_handle->auth_context,
222 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
224 memset (p + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xff, 4);
226 RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
227 RC4 (&rc4_key, 8, p, p);
229 memset(&rc4_key, 0, sizeof(rc4_key));
230 memset(k6_data, 0, sizeof(k6_data));
233 return GSS_S_COMPLETE;
238 _gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
239 const gss_ctx_id_t context_handle,
240 const gss_buffer_t message_buffer,
241 const gss_buffer_t token_buffer,
242 gss_qop_t * qop_state,
249 char cksum_data[8], k6_data[16], SND_SEQ[8];
256 p = token_buffer->value;
257 omret = gssapi_krb5_verify_header (&p,
258 token_buffer->length,
264 if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
265 return GSS_S_BAD_SIG;
267 if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
268 return GSS_S_BAD_MIC;
271 ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN,
272 cksum_data, sizeof(cksum_data),
274 message_buffer->value, message_buffer->length,
278 return GSS_S_FAILURE;
281 ret = arcfour_mic_key(gssapi_krb5_context, key,
282 cksum_data, sizeof(cksum_data),
283 k6_data, sizeof(k6_data));
286 return GSS_S_FAILURE;
289 cmp = memcmp(cksum_data, p + 8, 8);
292 return GSS_S_BAD_MIC;
298 RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
299 RC4 (&rc4_key, 8, p, SND_SEQ);
301 memset(&rc4_key, 0, sizeof(rc4_key));
302 memset(k6_data, 0, sizeof(k6_data));
305 gssapi_decode_be_om_uint32(SND_SEQ, &seq_number);
307 if (context_handle->more_flags & LOCAL)
308 cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
310 cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
312 memset(SND_SEQ, 0, sizeof(SND_SEQ));
315 return GSS_S_BAD_MIC;
318 HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
319 omret = _gssapi_msg_order_check(context_handle->order, seq_number);
320 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
325 return GSS_S_COMPLETE;
329 _gssapi_wrap_arcfour(OM_uint32 * minor_status,
330 const gss_ctx_id_t context_handle,
333 const gss_buffer_t input_message_buffer,
335 gss_buffer_t output_message_buffer,
338 u_char Klocaldata[16], k6_data[16], *p, *p0;
339 size_t len, total_len, datalen;
340 krb5_keyblock Klocal;
347 datalen = input_message_buffer->length;
348 len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
349 /* if GSS_C_DCE_STYLE is in use:
350 * - we only need to encapsulate the WRAP token
351 * - we should not add padding
353 if (!(context_handle->flags & GSS_C_DCE_STYLE)) {
354 datalen += 1 /* padding */;
357 _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
358 if (context_handle->flags & GSS_C_DCE_STYLE) {
359 total_len += datalen;
362 output_message_buffer->length = total_len;
363 output_message_buffer->value = malloc (total_len);
364 if (output_message_buffer->value == NULL) {
365 *minor_status = ENOMEM;
366 return GSS_S_FAILURE;
369 p0 = _gssapi_make_mech_header(output_message_buffer->value,
374 *p++ = 0x02; /* TOK_ID */
376 *p++ = 0x11; /* SGN_ALG */
379 *p++ = 0x10; /* SEAL_ALG */
382 *p++ = 0xff; /* SEAL_ALG */
385 *p++ = 0xff; /* Filler */
390 HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
391 krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
392 context_handle->auth_context,
395 gssapi_encode_be_om_uint32(seq_number, p0 + 8);
397 krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
398 context_handle->auth_context,
400 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
403 (context_handle->more_flags & LOCAL) ? 0 : 0xff,
406 krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
408 /* p points to data */
409 p = p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
410 memcpy(p, input_message_buffer->value, input_message_buffer->length);
411 /* only add padding when GSS_C_DCE_STYLE is not in use */
412 if (!(context_handle->flags & GSS_C_DCE_STYLE)) {
413 p[input_message_buffer->length] = 1; /* PADDING */
416 ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL,
417 p0 + 16, 8, /* SGN_CKSUM */
418 p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
419 p0 + 24, 8, /* Confounder */
420 p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
424 gss_release_buffer(minor_status, output_message_buffer);
425 return GSS_S_FAILURE;
431 Klocal.keytype = key->keytype;
432 Klocal.keyvalue.data = Klocaldata;
433 Klocal.keyvalue.length = sizeof(Klocaldata);
435 for (i = 0; i < 16; i++)
436 Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
438 ret = arcfour_mic_key(gssapi_krb5_context, &Klocal,
439 p0 + 8, 4, /* SND_SEQ */
440 k6_data, sizeof(k6_data));
441 memset(Klocaldata, 0, sizeof(Klocaldata));
443 gss_release_buffer(minor_status, output_message_buffer);
445 return GSS_S_FAILURE;
452 RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
454 RC4 (&rc4_key, 8 + datalen, p0 + 24, p0 + 24); /* Confounder + data */
455 memset(&rc4_key, 0, sizeof(rc4_key));
457 memset(k6_data, 0, sizeof(k6_data));
459 ret = arcfour_mic_key(gssapi_krb5_context, key,
460 p0 + 16, 8, /* SGN_CKSUM */
461 k6_data, sizeof(k6_data));
463 gss_release_buffer(minor_status, output_message_buffer);
465 return GSS_S_FAILURE;
471 RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
472 RC4 (&rc4_key, 8, p0 + 8, p0 + 8); /* SND_SEQ */
473 memset(&rc4_key, 0, sizeof(rc4_key));
474 memset(k6_data, 0, sizeof(k6_data));
478 *conf_state = conf_req_flag;
481 return GSS_S_COMPLETE;
484 OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
485 const gss_ctx_id_t context_handle,
486 const gss_buffer_t input_message_buffer,
487 gss_buffer_t output_message_buffer,
489 gss_qop_t *qop_state,
492 u_char Klocaldata[16];
493 krb5_keyblock Klocal;
498 char k6_data[16], SND_SEQ[8], Confounder[8];
510 p0 = input_message_buffer->value;
511 len = input_message_buffer->length;
512 /* if we have GSS_C_DCE_STYLE in use, we only need to decapsulate the WRAP token */
513 if (context_handle->flags & GSS_C_DCE_STYLE) {
514 if (input_message_buffer->length < (GSS_ARCFOUR_WRAP_TOKEN_OFFSET+GSS_ARCFOUR_WRAP_TOKEN_SIZE)) {
515 return GSS_S_BAD_MECH;
517 len = GSS_ARCFOUR_WRAP_TOKEN_OFFSET+GSS_ARCFOUR_WRAP_TOKEN_SIZE;
519 omret = _gssapi_verify_mech_header(&p0,
526 datalen = input_message_buffer->length -
527 (p - ((u_char *)input_message_buffer->value)) -
528 GSS_ARCFOUR_WRAP_TOKEN_SIZE;
530 if (memcmp(p, "\x02\x01", 2) != 0)
531 return GSS_S_BAD_SIG;
533 if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
534 return GSS_S_BAD_SIG;
537 if (memcmp (p, "\x10\x00", 2) == 0)
539 else if (memcmp (p, "\xff\xff", 2) == 0)
542 return GSS_S_BAD_SIG;
545 if (memcmp (p, "\xff\xff", 2) != 0)
546 return GSS_S_BAD_MIC;
549 ret = arcfour_mic_key(gssapi_krb5_context, key,
550 p0 + 16, 8, /* SGN_CKSUM */
551 k6_data, sizeof(k6_data));
554 return GSS_S_FAILURE;
560 RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
561 RC4 (&rc4_key, 8, p0 + 8, SND_SEQ); /* SND_SEQ */
562 memset(&rc4_key, 0, sizeof(rc4_key));
563 memset(k6_data, 0, sizeof(k6_data));
566 gssapi_decode_be_om_uint32(SND_SEQ, &seq_number);
568 if (context_handle->more_flags & LOCAL)
569 cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
571 cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
575 return GSS_S_BAD_MIC;
581 Klocal.keytype = key->keytype;
582 Klocal.keyvalue.data = Klocaldata;
583 Klocal.keyvalue.length = sizeof(Klocaldata);
585 for (i = 0; i < 16; i++)
586 Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
588 ret = arcfour_mic_key(gssapi_krb5_context, &Klocal,
590 k6_data, sizeof(k6_data));
591 memset(Klocaldata, 0, sizeof(Klocaldata));
594 return GSS_S_FAILURE;
597 output_message_buffer->value = malloc(datalen);
598 if (output_message_buffer->value == NULL) {
599 *minor_status = ENOMEM;
600 return GSS_S_FAILURE;
602 output_message_buffer->length = datalen;
607 RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
608 RC4 (&rc4_key, 8, p0 + 24, Confounder); /* Confounder */
609 RC4 (&rc4_key, datalen, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
610 output_message_buffer->value);
611 memset(&rc4_key, 0, sizeof(rc4_key));
613 memcpy(Confounder, p0 + 24, 8); /* Confounder */
614 memcpy(output_message_buffer->value,
615 p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
618 memset(k6_data, 0, sizeof(k6_data));
620 if (!(context_handle->flags & GSS_C_DCE_STYLE)) {
621 ret = _gssapi_verify_pad(output_message_buffer, datalen, &padlen);
623 gss_release_buffer(minor_status, output_message_buffer);
627 output_message_buffer->length -= padlen;
630 ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL,
631 cksum_data, sizeof(cksum_data),
633 Confounder, sizeof(Confounder),
634 output_message_buffer->value,
635 output_message_buffer->length + padlen);
637 gss_release_buffer(minor_status, output_message_buffer);
639 return GSS_S_FAILURE;
642 cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */
644 gss_release_buffer(minor_status, output_message_buffer);
646 return GSS_S_BAD_MIC;
649 HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
650 omret = _gssapi_msg_order_check(context_handle->order, seq_number);
651 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
656 *conf_state = conf_flag;
659 return GSS_S_COMPLETE;