1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 2001, 2007 by the Massachusetts Institute of Technology.
4 * Copyright 1993 by OpenVision Technologies, Inc.
6 * Permission to use, copy, modify, distribute, and sell this software
7 * and its documentation for any purpose is hereby granted without fee,
8 * provided that the above copyright notice appears in all copies and
9 * that both that copyright notice and this permission notice appear in
10 * supporting documentation, and that the name of OpenVision not be used
11 * in advertising or publicity pertaining to distribution of the software
12 * without specific, written prior permission. OpenVision makes no
13 * representations about the suitability of this software for any
14 * purpose. It is provided "as is" without express or implied warranty.
16 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
20 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
21 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
26 * Copyright (C) 1998 by the FundsXpress, INC.
28 * All rights reserved.
30 * Export of this software from the United States of America may require
31 * a specific license from the United States Government. It is the
32 * responsibility of any person or organization contemplating export to
33 * obtain such a license before exporting.
35 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
36 * distribute this software and its documentation for any purpose and
37 * without fee is hereby granted, provided that the above copyright
38 * notice appear in all copies and that both that copyright notice and
39 * this permission notice appear in supporting documentation, and that
40 * the name of FundsXpress. not be used in advertising or publicity pertaining
41 * to distribution of the software without specific, written prior
42 * permission. FundsXpress makes no representations about the suitability of
43 * this software for any purpose. It is provided "as is" without express
44 * or implied warranty.
46 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
48 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
51 #include "gssapiP_krb5.h"
57 /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
58 conf_state is only valid if SEAL. */
61 kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer,
62 conf_state, qop_state, toktype)
64 OM_uint32 *minor_status;
65 krb5_gss_ctx_id_rec *ctx;
68 gss_buffer_t message_buffer;
77 gss_buffer_desc token;
79 krb5_checksum md5cksum;
83 unsigned int cksum_len = 0;
89 krb5_keyusage sign_usage = KG_USAGE_SIGN;
91 if (toktype == KG_TOK_SEAL_MSG) {
92 message_buffer->length = 0;
93 message_buffer->value = NULL;
96 /* get the sign and seal algorithms */
98 signalg = ptr[0] + (ptr[1]<<8);
99 sealalg = ptr[2] + (ptr[3]<<8);
103 if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) {
105 return GSS_S_DEFECTIVE_TOKEN;
108 if ((toktype != KG_TOK_SEAL_MSG) &&
109 (sealalg != 0xffff)) {
111 return GSS_S_DEFECTIVE_TOKEN;
114 /* in the current spec, there is only one valid seal algorithm per
115 key type, so a simple comparison is ok */
117 if ((toktype == KG_TOK_SEAL_MSG) &&
118 !((sealalg == 0xffff) ||
119 (sealalg == ctx->sealalg))) {
121 return GSS_S_DEFECTIVE_TOKEN;
124 /* there are several mappings of seal algorithms to sign algorithms,
125 but few enough that we can try them all. */
127 if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
128 (ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
129 (ctx->sealalg == SEAL_ALG_DES3KD &&
130 signalg != SGN_ALG_HMAC_SHA1_DES3_KD)||
131 (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4 &&
132 signalg != SGN_ALG_HMAC_MD5)) {
134 return GSS_S_DEFECTIVE_TOKEN;
138 case SGN_ALG_DES_MAC_MD5:
140 case SGN_ALG_HMAC_MD5:
142 if (toktype != KG_TOK_SEAL_MSG)
148 case SGN_ALG_HMAC_SHA1_DES3_KD:
153 return GSS_S_DEFECTIVE_TOKEN;
156 /* get the token parameters */
158 if ((code = kg_get_seq_num(context, ctx->seq, ptr+14, ptr+6, &direction,
160 *minor_status = code;
161 return(GSS_S_BAD_SIG);
164 /* decode the message, if SEAL */
166 if (toktype == KG_TOK_SEAL_MSG) {
167 size_t tmsglen = bodysize-(14+cksum_len);
168 if (sealalg != 0xffff) {
169 if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
170 *minor_status = ENOMEM;
171 return(GSS_S_FAILURE);
173 if (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) {
174 unsigned char bigend_seqnum[4];
175 krb5_keyblock *enc_key;
177 store_32_be(seqnum, bigend_seqnum);
178 code = krb5_k_key_keyblock(context, ctx->enc, &enc_key);
182 *minor_status = code;
183 return(GSS_S_FAILURE);
186 assert (enc_key->length == 16);
187 for (i = 0; i <= 15; i++)
188 ((char *) enc_key->contents)[i] ^=0xf0;
189 code = kg_arcfour_docrypt (enc_key, 0,
190 &bigend_seqnum[0], 4,
191 ptr+14+cksum_len, tmsglen,
193 krb5_free_keyblock (context, enc_key);
195 code = kg_decrypt(context, ctx->enc, KG_USAGE_SEAL, NULL,
196 ptr+14+cksum_len, plain, tmsglen);
200 *minor_status = code;
201 return(GSS_S_FAILURE);
204 plain = ptr+14+cksum_len;
209 if ((sealalg == 0xffff) && ctx->big_endian) {
210 token.length = tmsglen;
212 conflen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
213 token.length = tmsglen - conflen - plain[tmsglen-1];
217 if ((token.value = (void *) gssalloc_malloc(token.length)) == NULL) {
218 if (sealalg != 0xffff)
220 *minor_status = ENOMEM;
221 return(GSS_S_FAILURE);
223 memcpy(token.value, plain+conflen, token.length);
227 } else if (toktype == KG_TOK_SIGN_MSG) {
228 token = *message_buffer;
230 plainlen = token.length;
235 plainlen = token.length;
238 /* compute the checksum of the message */
240 /* initialize the the cksum */
242 case SGN_ALG_DES_MAC_MD5:
244 case SGN_ALG_DES_MAC:
246 md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
248 case SGN_ALG_HMAC_MD5:
249 md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
251 case SGN_ALG_HMAC_SHA1_DES3_KD:
252 md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
258 code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
261 md5cksum.length = sumlen;
264 case SGN_ALG_DES_MAC_MD5:
266 /* compute the checksum of the message */
268 /* 8 = bytes of token body to be checksummed according to spec */
270 if (! (data_ptr = (void *)
271 xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
272 if (sealalg != 0xffff)
274 if (toktype == KG_TOK_SEAL_MSG)
275 gssalloc_free(token.value);
276 *minor_status = ENOMEM;
277 return(GSS_S_FAILURE);
280 (void) memcpy(data_ptr, ptr-2, 8);
283 (void) memcpy(data_ptr+8, token.value, token.length);
285 (void) memcpy(data_ptr+8, plain, plainlen);
287 plaind.length = 8 + (ctx->big_endian ? token.length : plainlen);
288 plaind.data = data_ptr;
289 code = krb5_k_make_checksum(context, md5cksum.checksum_type,
290 ctx->seq, sign_usage,
295 if (toktype == KG_TOK_SEAL_MSG)
296 gssalloc_free(token.value);
297 *minor_status = code;
298 return(GSS_S_FAILURE);
301 code = kg_encrypt_inplace(context, ctx->seq, KG_USAGE_SEAL,
302 (g_OID_equal(ctx->mech_used,
304 ctx->seq->keyblock.contents : NULL),
305 md5cksum.contents, 16);
307 krb5_free_checksum_contents(context, &md5cksum);
308 if (toktype == KG_TOK_SEAL_MSG)
309 gssalloc_free(token.value);
310 *minor_status = code;
311 return GSS_S_FAILURE;
318 cksum.contents = md5cksum.contents + 16 - cksum.length;
320 code = memcmp(cksum.contents, ptr+14, cksum.length);
324 if (!ctx->seed_init &&
325 (code = kg_make_seed(context, ctx->subkey, ctx->seed))) {
326 krb5_free_checksum_contents(context, &md5cksum);
327 if (sealalg != 0xffff)
329 if (toktype == KG_TOK_SEAL_MSG)
330 gssalloc_free(token.value);
331 *minor_status = code;
332 return GSS_S_FAILURE;
335 if (! (data_ptr = (void *)
336 xmalloc(sizeof(ctx->seed) + 8 +
337 (ctx->big_endian ? token.length : plainlen)))) {
338 krb5_free_checksum_contents(context, &md5cksum);
341 if (toktype == KG_TOK_SEAL_MSG)
342 gssalloc_free(token.value);
343 *minor_status = ENOMEM;
344 return(GSS_S_FAILURE);
346 (void) memcpy(data_ptr, ptr-2, 8);
347 (void) memcpy(data_ptr+8, ctx->seed, sizeof(ctx->seed));
349 (void) memcpy(data_ptr+8+sizeof(ctx->seed),
350 token.value, token.length);
352 (void) memcpy(data_ptr+8+sizeof(ctx->seed),
354 plaind.length = 8 + sizeof(ctx->seed) +
355 (ctx->big_endian ? token.length : plainlen);
356 plaind.data = data_ptr;
357 krb5_free_checksum_contents(context, &md5cksum);
358 code = krb5_k_make_checksum(context, md5cksum.checksum_type,
359 ctx->seq, sign_usage,
366 if (toktype == KG_TOK_SEAL_MSG)
367 gssalloc_free(token.value);
368 *minor_status = code;
369 return(GSS_S_FAILURE);
372 code = memcmp(md5cksum.contents, ptr+14, 8);
373 /* Falls through to defective-token?? */
377 return(GSS_S_DEFECTIVE_TOKEN);
379 case SGN_ALG_HMAC_SHA1_DES3_KD:
380 case SGN_ALG_HMAC_MD5:
381 /* compute the checksum of the message */
383 /* 8 = bytes of token body to be checksummed according to spec */
385 if (! (data_ptr = (void *)
386 xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
387 if (sealalg != 0xffff)
389 if (toktype == KG_TOK_SEAL_MSG)
390 gssalloc_free(token.value);
391 *minor_status = ENOMEM;
392 return(GSS_S_FAILURE);
395 (void) memcpy(data_ptr, ptr-2, 8);
398 (void) memcpy(data_ptr+8, token.value, token.length);
400 (void) memcpy(data_ptr+8, plain, plainlen);
402 plaind.length = 8 + (ctx->big_endian ? token.length : plainlen);
403 plaind.data = data_ptr;
404 code = krb5_k_make_checksum(context, md5cksum.checksum_type,
405 ctx->seq, sign_usage,
410 if (toktype == KG_TOK_SEAL_MSG)
411 gssalloc_free(token.value);
412 *minor_status = code;
413 return(GSS_S_FAILURE);
416 code = memcmp(md5cksum.contents, ptr+14, cksum_len);
420 krb5_free_checksum_contents(context, &md5cksum);
421 if (sealalg != 0xffff)
424 /* compare the computed checksum against the transmitted checksum */
427 if (toktype == KG_TOK_SEAL_MSG)
428 gssalloc_free(token.value);
430 return(GSS_S_BAD_SIG);
434 /* it got through unscathed. Make sure the context is unexpired */
436 if (toktype == KG_TOK_SEAL_MSG)
437 *message_buffer = token;
440 *conf_state = (sealalg != 0xffff);
443 *qop_state = GSS_C_QOP_DEFAULT;
445 /* do sequencing checks */
447 if ((ctx->initiate && direction != 0xff) ||
448 (!ctx->initiate && direction != 0)) {
449 if (toktype == KG_TOK_SEAL_MSG) {
450 gssalloc_free(token.value);
451 message_buffer->value = NULL;
452 message_buffer->length = 0;
454 *minor_status = (OM_uint32)G_BAD_DIRECTION;
455 return(GSS_S_BAD_SIG);
458 retval = g_order_check(&(ctx->seqstate), (gssint_uint64)seqnum);
460 /* success or ordering violation */
466 /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
467 conf_state is only valid if SEAL. */
470 kg_unseal(minor_status, context_handle, input_token_buffer,
471 message_buffer, conf_state, qop_state, toktype)
472 OM_uint32 *minor_status;
473 gss_ctx_id_t context_handle;
474 gss_buffer_t input_token_buffer;
475 gss_buffer_t message_buffer;
477 gss_qop_t *qop_state;
480 krb5_gss_ctx_id_rec *ctx;
482 unsigned int bodysize;
488 ctx = (krb5_gss_ctx_id_rec *) context_handle;
490 if (! ctx->established) {
491 *minor_status = KG_CTX_INCOMPLETE;
492 return(GSS_S_NO_CONTEXT);
495 /* parse the token, leave the data in message_buffer, setting conf_state */
497 /* verify the header */
499 ptr = (unsigned char *) input_token_buffer->value;
502 err = g_verify_token_header(ctx->mech_used,
504 input_token_buffer->length,
508 return GSS_S_DEFECTIVE_TOKEN;
512 *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
513 return GSS_S_DEFECTIVE_TOKEN;
516 toktype2 = load_16_be(ptr);
522 case KG2_TOK_MIC_MSG:
523 case KG2_TOK_WRAP_MSG:
524 case KG2_TOK_DEL_CTX:
525 ret = gss_krb5int_unseal_token_v3(&ctx->k5_context, minor_status, ctx,
526 ptr, bodysize, message_buffer,
527 conf_state, qop_state, toktype);
530 case KG_TOK_WRAP_MSG:
532 ret = kg_unseal_v1(ctx->k5_context, minor_status, ctx, ptr, bodysize,
533 message_buffer, conf_state, qop_state,
537 *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
538 ret = GSS_S_DEFECTIVE_TOKEN;
543 save_error_info (*minor_status, ctx->k5_context);
548 OM_uint32 KRB5_CALLCONV
549 krb5_gss_unwrap(minor_status, context_handle,
550 input_message_buffer, output_message_buffer,
551 conf_state, qop_state)
552 OM_uint32 *minor_status;
553 gss_ctx_id_t context_handle;
554 gss_buffer_t input_message_buffer;
555 gss_buffer_t output_message_buffer;
557 gss_qop_t *qop_state;
561 rstat = kg_unseal(minor_status, context_handle,
562 input_message_buffer, output_message_buffer,
563 conf_state, qop_state, KG_TOK_WRAP_MSG);
567 OM_uint32 KRB5_CALLCONV
568 krb5_gss_verify_mic(minor_status, context_handle,
569 message_buffer, token_buffer,
571 OM_uint32 *minor_status;
572 gss_ctx_id_t context_handle;
573 gss_buffer_t message_buffer;
574 gss_buffer_t token_buffer;
575 gss_qop_t *qop_state;
579 rstat = kg_unseal(minor_status, context_handle,
580 token_buffer, message_buffer,
581 NULL, qop_state, KG_TOK_MIC_MSG);