Home | History | Annotate | Download | only in mech
      1 /*
      2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 
      7 /*
      8  * Copyright 2001 by the Massachusetts Institute of Technology.
      9  * Copyright 1993 by OpenVision Technologies, Inc.
     10  *
     11  * Permission to use, copy, modify, distribute, and sell this software
     12  * and its documentation for any purpose is hereby granted without fee,
     13  * provided that the above copyright notice appears in all copies and
     14  * that both that copyright notice and this permission notice appear in
     15  * supporting documentation, and that the name of OpenVision not be used
     16  * in advertising or publicity pertaining to distribution of the software
     17  * without specific, written prior permission. OpenVision makes no
     18  * representations about the suitability of this software for any
     19  * purpose.  It is provided "as is" without express or implied warranty.
     20  *
     21  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     22  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     23  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     24  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
     25  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
     26  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     27  * PERFORMANCE OF THIS SOFTWARE.
     28  */
     29 
     30 /*
     31  * Copyright (C) 1998 by the FundsXpress, INC.
     32  *
     33  * All rights reserved.
     34  *
     35  * Export of this software from the United States of America may require
     36  * a specific license from the United States Government.  It is the
     37  * responsibility of any person or organization contemplating export to
     38  * obtain such a license before exporting.
     39  *
     40  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
     41  * distribute this software and its documentation for any purpose and
     42  * without fee is hereby granted, provided that the above copyright
     43  * notice appear in all copies and that both that copyright notice and
     44  * this permission notice appear in supporting documentation, and that
     45  * the name of FundsXpress. not be used in advertising or publicity pertaining
     46  * to distribution of the software without specific, written prior
     47  * permission.  FundsXpress makes no representations about the suitability of
     48  * this software for any purpose.  It is provided "as is" without express
     49  * or implied warranty.
     50  *
     51  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
     52  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     53  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     54  */
     55 
     56 #include "gssapiP_krb5.h"
     57 #include "k5-int.h"
     58 
     59 /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
     60    conf_state is only valid if SEAL. */
     61 
     62 static OM_uint32
     63 kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer,
     64 	     conf_state, qop_state, toktype)
     65     krb5_context context;
     66     OM_uint32 *minor_status;
     67     krb5_gss_ctx_id_rec *ctx;
     68     unsigned char *ptr;
     69     int bodysize;
     70     gss_buffer_t message_buffer;
     71     int *conf_state;
     72     int *qop_state;
     73     int toktype;
     74 {
     75     krb5_error_code code;
     76     int conflen = 0;
     77     int signalg;
     78     int sealalg;
     79     gss_buffer_desc token;
     80     krb5_checksum cksum;
     81     krb5_checksum md5cksum;
     82     krb5_data plaind;
     83     char *data_ptr;
     84     krb5_timestamp now;
     85     unsigned char *plain;
     86     unsigned int cksum_len = 0;
     87     size_t plainlen;
     88     int direction;
     89     krb5_ui_4 seqnum;
     90     OM_uint32 retval;
     91     size_t sumlen, blocksize;
     92     int tmsglen;
     93     krb5_keyusage sign_usage = KG_USAGE_SIGN;
     94 
     95     KRB5_LOG0(KRB5_INFO, "kg_unseal_v1() start\n");
     96 
     97     /* Solaris Kerberos:  make sure this is initialized */
     98     *minor_status = 0;
     99 
    100     if (toktype == KG_TOK_SEAL_MSG) {
    101 	message_buffer->length = 0;
    102 	message_buffer->value = NULL;
    103     }
    104 
    105     /* get the sign and seal algorithms */
    106 
    107     signalg = ptr[0] + (ptr[1]<<8);
    108     sealalg = ptr[2] + (ptr[3]<<8);
    109 
    110     /* Sanity checks */
    111 
    112     if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) {
    113 	*minor_status = 0;
    114 	KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error GSS_S_DEFECTIVE_TOKEN\n");
    115 	return GSS_S_DEFECTIVE_TOKEN;
    116     }
    117 
    118     if ((toktype != KG_TOK_SEAL_MSG) &&
    119 	(sealalg != 0xffff)) {
    120 	*minor_status = 0;
    121 	KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error2 GSS_S_DEFECTIVE_TOKEN\n");
    122 	return GSS_S_DEFECTIVE_TOKEN;
    123     }
    124 
    125     /* in the current spec, there is only one valid seal algorithm per
    126        key type, so a simple comparison is ok */
    127 
    128     if ((toktype == KG_TOK_SEAL_MSG) &&
    129 	!((sealalg == 0xffff) ||
    130 	  (sealalg == ctx->sealalg))) {
    131 	*minor_status = 0;
    132 	KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error3 GSS_S_DEFECTIVE_TOKEN\n");
    133 	return GSS_S_DEFECTIVE_TOKEN;
    134     }
    135 
    136     /* there are several mappings of seal algorithms to sign algorithms,
    137        but few enough that we can try them all. */
    138 
    139     if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
    140 	(ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
    141 	(ctx->sealalg == SEAL_ALG_DES3KD &&
    142 	 signalg != SGN_ALG_HMAC_SHA1_DES3_KD)||
    143 	(ctx->sealalg == SEAL_ALG_MICROSOFT_RC4 &&
    144 	signalg != SGN_ALG_HMAC_MD5)) {
    145 	*minor_status = 0;
    146 	KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error4 GSS_S_DEFECTIVE_TOKEN\n");
    147 	return GSS_S_DEFECTIVE_TOKEN;
    148     }
    149 
    150     KRB5_LOG(KRB5_INFO, "kg_unseal_v1() signalg = %d\n", signalg);
    151 
    152     switch (signalg) {
    153     case SGN_ALG_DES_MAC_MD5:
    154     case SGN_ALG_MD2_5:
    155     case SGN_ALG_HMAC_MD5:
    156 	cksum_len = 8;
    157 	if (toktype != KG_TOK_SEAL_MSG)
    158 	  sign_usage = 15;
    159 	    break;
    160     case SGN_ALG_3:
    161 	cksum_len = 16;
    162 	break;
    163     case SGN_ALG_HMAC_SHA1_DES3_KD:
    164 	cksum_len = 20;
    165 	break;
    166     default:
    167 	*minor_status = 0;
    168 	KRB5_LOG(KRB5_ERR, "kg_unseal_v1() end, error signalg=%d\n", signalg);
    169 	return GSS_S_DEFECTIVE_TOKEN;
    170     }
    171 
    172 #ifdef _KERNEL
    173 	/*
    174 	 * Because the ARCFOUR code bypasses the standard
    175 	 * crypto interfaces, we must make sure the kernel
    176 	 * crypto framework mechanism types are properly
    177 	 * initialized here.
    178 	 */
    179 	context->kef_cipher_mt = get_cipher_mech_type(context,
    180 					ctx->seq);
    181 	context->kef_hash_mt = get_hash_mech_type(context,
    182 					ctx->seq);
    183 	if ((code = init_key_kef(context->kef_cipher_mt,
    184 				ctx->seq))) {
    185 		*minor_status = code;
    186 		return (GSS_S_FAILURE);
    187 	}
    188 	if ((code = init_key_kef(context->kef_cipher_mt,
    189 			ctx->enc))) {
    190 		*minor_status = code;
    191 		return (GSS_S_FAILURE);
    192 	}
    193 #endif /* _KERNEL */
    194 
    195     /* get the token parameters */
    196 
    197     if ((code = kg_get_seq_num(context, ctx->seq, ptr+14, ptr+6, &direction,
    198 			       &seqnum))) {
    199 	*minor_status = code;
    200 	return(GSS_S_BAD_SIG);
    201     }
    202 
    203     /* decode the message, if SEAL */
    204 
    205     if (toktype == KG_TOK_SEAL_MSG) {
    206 	tmsglen = bodysize-(14+cksum_len);
    207 	KRB5_LOG1(KRB5_INFO, "kg_unseal_v1() tmsglen = %d cksum_len = %d",
    208 		tmsglen, cksum_len);
    209 	KRB5_LOG0(KRB5_INFO, "kg_unseal_v1() toktype == KG_TOK_SEAL_MSG\n");
    210 
    211 	if (sealalg != 0xffff) {
    212 	    if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
    213 		*minor_status = ENOMEM;
    214 		KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error ENOMEM\n");
    215 		return(GSS_S_FAILURE);
    216 	    }
    217 	    if (ctx->enc->enctype == ENCTYPE_ARCFOUR_HMAC) {
    218 	      unsigned char bigend_seqnum[4];
    219 	      krb5_keyblock *enc_key;
    220 	      int i;
    221 	      bigend_seqnum[0] = (seqnum>>24) & 0xff;
    222 	      bigend_seqnum[1] = (seqnum>>16) & 0xff;
    223 	      bigend_seqnum[2] = (seqnum>>8) & 0xff;
    224 	      bigend_seqnum[3] = seqnum & 0xff;
    225 	      code = krb5_copy_keyblock (context, ctx->enc, &enc_key);
    226 	      if (code)
    227 		{
    228 		  xfree_wrap(plain, tmsglen);
    229 		  *minor_status = code;
    230 		  return(GSS_S_FAILURE);
    231 		}
    232 
    233 	      for (i = 0; i <= 15; i++)
    234 		((char *) enc_key->contents)[i] ^=0xf0;
    235 
    236 #ifndef _KERNEL
    237 		/*
    238 		 * The enc_key contents were modified, delete the
    239 		 * key object so it doesn't get used later.
    240 		 */
    241 		if (enc_key->hKey != CK_INVALID_HANDLE) {
    242 			(void)C_DestroyObject(krb_ctx_hSession(context),
    243 				enc_key->hKey);
    244 			enc_key->hKey = CK_INVALID_HANDLE;
    245 		}
    246 #endif
    247 		KRB5_LOG(KRB5_INFO, "kg_unseal_v1() enc_key->enctype = %d",
    248 			enc_key->enctype);
    249 
    250 		code = kg_arcfour_docrypt (context,
    251 				enc_key, 0,
    252 				&bigend_seqnum[0], 4,
    253 				ptr+14+cksum_len, tmsglen,
    254 				plain);
    255 		krb5_free_keyblock (context, enc_key);
    256             } else {
    257 		code = kg_decrypt(context, ctx->enc, KG_USAGE_SEAL, NULL,
    258 			ptr+14+cksum_len, plain, tmsglen);
    259 	    }
    260             if (code) {
    261                 xfree_wrap(plain, tmsglen);
    262 		*minor_status = code;
    263 		return(GSS_S_FAILURE);
    264 	    }
    265 	} else {
    266 	    plain = ptr+14+cksum_len;
    267 	}
    268 
    269 	plainlen = tmsglen;
    270 
    271 	if ((sealalg == 0xffff) && ctx->big_endian) {
    272 	    token.length = tmsglen;
    273 	} else {
    274 	    conflen = kg_confounder_size(context, ctx->enc);
    275 	    /*
    276 	     * Solaris Kerberos: we want to perform a sanity check on the
    277 	     * pad length, so we know it can not be more than the blocksize.
    278 	     */
    279 	    code = krb5_c_block_size(context, ctx->enc->enctype, &blocksize);
    280 	    if (code != 0) {
    281 		if (sealalg != 0xffff)
    282 		    xfree_wrap(plain, tmsglen);
    283 		*minor_status = code;
    284 		return(GSS_S_FAILURE);
    285 	    }
    286 	    if (plain[tmsglen-1] > blocksize) {
    287 		if (sealalg != 0xffff)
    288 		    xfree_wrap(plain, tmsglen);
    289 		*minor_status = KG_BAD_LENGTH;
    290 		return(GSS_S_FAILURE);
    291 	    }
    292 	    token.length = tmsglen - conflen - plain[tmsglen-1];
    293 	}
    294 
    295 	if (token.length) {
    296 	    if ((token.value = (void *) xmalloc(token.length)) == NULL) {
    297 		if (sealalg != 0xffff)
    298 		    xfree_wrap(plain, tmsglen);
    299 		*minor_status = ENOMEM;
    300 		KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error2 ENOMEM\n");
    301 		return(GSS_S_FAILURE);
    302 	    }
    303 	    (void) memcpy(token.value, plain+conflen, token.length);
    304 	} else {
    305 	    token.value = NULL;
    306 	}
    307     } else if (toktype == KG_TOK_SIGN_MSG) {
    308 	KRB5_LOG0(KRB5_INFO, "kg_unseal_v1() toktype == KG_TOK_SIGN_MSG\n");
    309 	token = *message_buffer;
    310 	plain = token.value;
    311 	plainlen = token.length;
    312     } else {
    313 	KRB5_LOG0(KRB5_INFO, "kg_unseal_v1() toktype == NULL\n");
    314 	token.length = 0;
    315 	token.value = NULL;
    316 	plain = token.value;
    317 	plainlen = token.length;
    318     }
    319 
    320     /* compute the checksum of the message */
    321 
    322     /* initialize the the cksum */
    323     switch (signalg) {
    324     case SGN_ALG_DES_MAC_MD5:
    325     case SGN_ALG_MD2_5:
    326     case SGN_ALG_DES_MAC:
    327     case SGN_ALG_3:
    328 	md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
    329 	break;
    330     case SGN_ALG_HMAC_MD5:
    331       md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
    332       break;
    333     case SGN_ALG_HMAC_SHA1_DES3_KD:
    334 	md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
    335 	break;
    336     default:
    337 	KRB5_LOG(KRB5_ERR, "kg_unseal_v1() end, error2 signalg=%d\n", signalg);
    338 #ifndef	_KERNEL
    339 	abort ();
    340 #else
    341 	*minor_status = 0;
    342 	return(GSS_S_DEFECTIVE_TOKEN);
    343 #endif /* _KERNEL */
    344     }
    345 
    346     code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
    347     if (code)
    348     {
    349 	KRB5_LOG(KRB5_ERR, "kg_unseal_v1() end, krb5_c_checksum_length() error "
    350 		"code=%d\n", code);
    351 	return(code);
    352     }
    353     md5cksum.length = (size_t)sumlen;
    354 
    355     switch (signalg) {
    356     case SGN_ALG_DES_MAC_MD5:
    357     case SGN_ALG_3:
    358 	/* compute the checksum of the message */
    359 
    360 	/* 8 = bytes of token body to be checksummed according to spec */
    361 
    362 	if (! (data_ptr = (void *)
    363 	       xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
    364 	    if (sealalg != 0xffff)
    365 		xfree_wrap(plain, tmsglen);
    366 	    if (toktype == KG_TOK_SEAL_MSG) {
    367 		xfree_wrap(token.value, token.length);
    368 		/* Solaris Kerberos: just to be safe since token.value is an
    369 		 * output parameter.
    370 		 */
    371 		token.value = NULL;
    372 		token.length = 0;
    373 	    }
    374 	    *minor_status = ENOMEM;
    375 	    KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error3 ENOMEM\n");
    376 	    return(GSS_S_FAILURE);
    377 	}
    378 
    379 	(void) memcpy(data_ptr, ptr-2, 8);
    380 
    381 	if (ctx->big_endian)
    382 	    (void) memcpy(data_ptr+8, token.value, token.length);
    383 	else
    384 	    (void) memcpy(data_ptr+8, plain, plainlen);
    385 
    386 	plaind.length = 8 + (ctx->big_endian ? token.length : plainlen);
    387 	plaind.data = data_ptr;
    388 	code = krb5_c_make_checksum(context, md5cksum.checksum_type,
    389 				    ctx->seq, sign_usage,
    390 				    &plaind, &md5cksum);
    391 	xfree_wrap(data_ptr, 8 + (ctx->big_endian ? token.length : plainlen));
    392 
    393 	if (code) {
    394 	    if (toktype == KG_TOK_SEAL_MSG) {
    395 		xfree_wrap(token.value, token.length);
    396 		/* Solaris Kerberos: just to be safe since token.value is an
    397 		 * output parameter.
    398 		 */
    399 		token.value = NULL;
    400 		token.length = 0;
    401 	    }
    402 	    *minor_status = code;
    403 	    KRB5_LOG(KRB5_ERR, "kg_unseal_v1() end, krb5_c_make_checksum() "
    404 		    "error code = %d\n", code);
    405 	    return(GSS_S_FAILURE);
    406 	}
    407 
    408 	if ((code = kg_encrypt(context, ctx->seq, KG_USAGE_SEAL,
    409 			       (g_OID_equal(ctx->mech_used, gss_mech_krb5_old) ?
    410 				ctx->seq->contents : NULL),
    411 			       md5cksum.contents, md5cksum.contents, 16))) {
    412 	    xfree_wrap(md5cksum.contents, md5cksum.length);
    413 	    if (toktype == KG_TOK_SEAL_MSG) {
    414 		xfree_wrap(token.value, token.length);
    415 		/* Solaris Kerberos: just to be safe since token.value is an
    416 		 * output parameter.
    417 		 */
    418 		token.value = NULL;
    419 		token.length = 0;
    420 	    }
    421 	    *minor_status = code;
    422 	    KRB5_LOG(KRB5_ERR, "kg_unseal_v1() end, kg_encrypt() error"
    423 		    "code = %d\n", code);
    424 	    return GSS_S_FAILURE;
    425 	}
    426 
    427 	if (signalg == 0)
    428 	    cksum.length = 8;
    429 	else
    430 	    cksum.length = 16;
    431 	cksum.contents = md5cksum.contents + 16 - cksum.length;
    432 
    433 	code = memcmp(cksum.contents, ptr+14, cksum.length);
    434 	break;
    435 
    436     case SGN_ALG_MD2_5:
    437 	if (!ctx->seed_init &&
    438 	    (code = kg_make_seed(context, ctx->subkey, ctx->seed))) {
    439 	    xfree_wrap(md5cksum.contents, md5cksum.length);
    440 	    if (sealalg != 0xffff)
    441 		xfree_wrap(plain, tmsglen);
    442 	    if (toktype == KG_TOK_SEAL_MSG) {
    443 		xfree_wrap(token.value, token.length);
    444 		/* Solaris Kerberos: just to be safe since token.value is an
    445 		 * output parameter.
    446 		 */
    447 		token.value = NULL;
    448 		token.length = 0;
    449 	    }
    450 	    *minor_status = code;
    451 	    return GSS_S_FAILURE;
    452 	}
    453 
    454 	if (! (data_ptr = (void *)
    455 	       xmalloc(sizeof(ctx->seed) + 8 +
    456 		       (ctx->big_endian ? token.length : plainlen)))) {
    457 	    xfree_wrap(md5cksum.contents, md5cksum.length);
    458 	    if (sealalg == 0)
    459 		xfree_wrap(plain, tmsglen);
    460 	    if (toktype == KG_TOK_SEAL_MSG) {
    461 		xfree_wrap(token.value, token.length);
    462 		/* Solaris Kerberos: just to be safe since token.value is an
    463 		 * output parameter.
    464 		 */
    465 		token.value = NULL;
    466 		token.length = 0;
    467 	    }
    468 	    *minor_status = ENOMEM;
    469 	    return(GSS_S_FAILURE);
    470 	}
    471 	(void) memcpy(data_ptr, ptr-2, 8);
    472 	(void) memcpy(data_ptr+8, ctx->seed, sizeof(ctx->seed));
    473 	if (ctx->big_endian)
    474 	    (void) memcpy(data_ptr+8+sizeof(ctx->seed),
    475 			  token.value, token.length);
    476 	else
    477 	    (void) memcpy(data_ptr+8+sizeof(ctx->seed),
    478 			  plain, plainlen);
    479 	plaind.length = 8 + sizeof(ctx->seed) +
    480 	    (ctx->big_endian ? token.length : plainlen);
    481 	plaind.data = data_ptr;
    482 	xfree_wrap(md5cksum.contents, md5cksum.length);
    483 	code = krb5_c_make_checksum(context, md5cksum.checksum_type,
    484 				    ctx->seq, KG_USAGE_SIGN,
    485 				    &plaind, &md5cksum);
    486 	xfree_wrap(data_ptr, 8 + sizeof(ctx->seed) +
    487             (ctx->big_endian ? token.length : plainlen));
    488 
    489 	if (code) {
    490 	    if (sealalg == 0)
    491 		xfree_wrap(plain, tmsglen);
    492 	    if (toktype == KG_TOK_SEAL_MSG) {
    493 		xfree_wrap(token.value, token.length);
    494 		/* Solaris Kerberos: just to be safe since token.value is an
    495 		 * output parameter.
    496 		 */
    497 		token.value = NULL;
    498 		token.length = 0;
    499 	    }
    500 	    *minor_status = code;
    501 	    return(GSS_S_FAILURE);
    502 	}
    503 
    504 	code = memcmp(md5cksum.contents, ptr+14, 8);
    505 	/* Falls through to defective-token??  */
    506 
    507     default:
    508 	*minor_status = 0;
    509 	KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error SGN_ALG_MD2_5 "
    510 		"GSS_S_DEFECTIVE_TOKEN\n");
    511 	return(GSS_S_DEFECTIVE_TOKEN);
    512 
    513     case SGN_ALG_HMAC_SHA1_DES3_KD:
    514     case SGN_ALG_HMAC_MD5:
    515 	/* compute the checksum of the message */
    516 
    517 	/* 8 = bytes of token body to be checksummed according to spec */
    518 
    519 	if (! (data_ptr = (void *)
    520 	       xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
    521 	    if (sealalg != 0xffff)
    522 		xfree_wrap(plain, tmsglen);
    523 	    if (toktype == KG_TOK_SEAL_MSG) {
    524 		xfree_wrap(token.value, token.length);
    525 		/* Solaris Kerberos: just to be safe since token.value is an
    526 		 * output parameter.
    527 		 */
    528 		token.value = NULL;
    529 		token.length = 0;
    530 	    }
    531 	    *minor_status = ENOMEM;
    532 	    return(GSS_S_FAILURE);
    533 	}
    534 
    535 	(void) memcpy(data_ptr, ptr-2, 8);
    536 
    537 	if (ctx->big_endian) {
    538 	    KRB5_LOG0(KRB5_INFO, "kg_unseal_v1() ctx->big_endian = 1\n");
    539 	    (void) memcpy(data_ptr+8, token.value, token.length);
    540 	}
    541 	else {
    542 	    KRB5_LOG0(KRB5_INFO, "kg_unseal_v1() ctx->big_endian = 0\n");
    543 	    (void) memcpy(data_ptr+8, plain, plainlen);
    544 	}
    545 
    546 	plaind.length = 8 + (ctx->big_endian ? token.length : plainlen);
    547 	plaind.data = data_ptr;
    548 
    549 	code = krb5_c_make_checksum(context, md5cksum.checksum_type,
    550 				    ctx->seq, sign_usage,
    551 				    &plaind, &md5cksum);
    552 
    553 	xfree_wrap(data_ptr, 8 + (ctx->big_endian ? token.length : plainlen));
    554 
    555 	if (code) {
    556 	    if (toktype == KG_TOK_SEAL_MSG) {
    557 		xfree_wrap(token.value, token.length);
    558 		/* Solaris Kerberos: just to be safe since token.value is an
    559 		 * output parameter.
    560 		 */
    561 		token.value = NULL;
    562 		token.length = 0;
    563 	    }
    564 	    *minor_status = code;
    565 	    KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error "
    566 		    "SGN_ALG_HMAC_SHA1_DES3_KD GSS_S_FAILURE\n");
    567 	    return(GSS_S_FAILURE);
    568 	}
    569 
    570 	/* compare the computed checksum against the transmitted checksum */
    571 	code = memcmp(md5cksum.contents, ptr+14, cksum_len);
    572 	KRB5_LOG(KRB5_INFO, "kg_unseal_v1() memcmp %d bytes", cksum_len);
    573 	break;
    574     }
    575 
    576     xfree_wrap(md5cksum.contents, md5cksum.length);
    577     if (sealalg != 0xffff)
    578 	xfree_wrap(plain, tmsglen);
    579 
    580     if (code) {
    581 	if (toktype == KG_TOK_SEAL_MSG) {
    582 	    xfree_wrap(token.value, token.length);
    583 	    /* Solaris Kerberos: just to be safe since token.value is an
    584 	     * output parameter.
    585 	     */
    586 	    token.value = NULL;
    587 	    token.length = 0;
    588 	}
    589 	*minor_status = 0;
    590 	KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error GSS_S_BAD_SIG\n");
    591 	return(GSS_S_BAD_SIG);
    592     }
    593 
    594     if (conf_state)
    595 	*conf_state = (sealalg != 0xffff);
    596 
    597     if (qop_state)
    598 	*qop_state = GSS_C_QOP_DEFAULT;
    599 
    600     if ((code = krb5_timeofday(context, &now))) {
    601 	*minor_status = code;
    602 
    603 	KRB5_LOG(KRB5_ERR, "kg_unseal_v1() end, krb5_timeofday()"
    604 		"error code = %d\n", code);
    605 
    606 	return(GSS_S_FAILURE);
    607     }
    608 
    609     if (now > ctx->endtime) {
    610 	*minor_status = 0;
    611 
    612 	KRB5_LOG1(KRB5_ERR, "kg_unseal_v1() end, error "
    613 		"now %d > ctx->endtime %d\n", now, ctx->endtime);
    614 
    615 	return(GSS_S_CONTEXT_EXPIRED);
    616     }
    617 
    618     /* do sequencing checks */
    619     if ((ctx->initiate && direction != 0xff) ||
    620 	(!ctx->initiate && direction != 0)) {
    621 	if (toktype == KG_TOK_SEAL_MSG) {
    622 	    xfree_wrap(token.value, token.length);
    623 	    /* Solaris Kerberos: just to be safe since token.value is an
    624 	     * output parameter.
    625 	     */
    626 	    token.value = NULL;
    627 	    token.length = 0;
    628 	}
    629 	*minor_status = (OM_uint32) G_BAD_DIRECTION;
    630 
    631 	KRB5_LOG1(KRB5_ERR, "kg_unseal_v1() end, error GSS_S_BAD_SIG "
    632 		"G_BAD_DIRECTION ctx->initiate = %d "
    633 		"direction = %d\n", ctx->initiate, direction);
    634 
    635 	return(GSS_S_BAD_SIG);
    636     }
    637 
    638     retval = g_order_check(&(ctx->seqstate), (gssint_uint64)seqnum);
    639 
    640     /* It got through unscathed, adjust the output message buffer. */
    641     if (retval == 0 && toktype == KG_TOK_SEAL_MSG)
    642 	*message_buffer = token;
    643 
    644     *minor_status = 0;
    645     KRB5_LOG(KRB5_INFO, "kg_unseal_v1() end, retval = %d\n", retval);
    646     return(retval);
    647 }
    648 
    649 /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
    650    conf_state is only valid if SEAL. */
    651 
    652 OM_uint32
    653 kg_unseal(minor_status, context_handle, input_token_buffer,
    654 	  message_buffer, conf_state, qop_state, toktype)
    655     OM_uint32 *minor_status;
    656     gss_ctx_id_t context_handle;
    657     gss_buffer_t input_token_buffer;
    658     gss_buffer_t message_buffer;
    659     int *conf_state;
    660     int *qop_state;
    661     int toktype;
    662 {
    663     krb5_gss_ctx_id_rec *ctx;
    664     unsigned char *ptr;
    665     int bodysize;
    666     int err;
    667     int toktype2;
    668 
    669     KRB5_LOG0(KRB5_INFO, "kg_unseal() start \n");
    670 
    671     /* validate the context handle */
    672     if (! kg_validate_ctx_id(context_handle)) {
    673 	*minor_status = (OM_uint32) G_VALIDATE_FAILED;
    674 
    675 	KRB5_LOG0(KRB5_ERR, "kg_unseal() end, kg_validate_ctx_id() error "
    676 		"G_VALIDATE_FAILED \n");
    677 
    678 	return(GSS_S_NO_CONTEXT);
    679     }
    680 
    681     ctx = (krb5_gss_ctx_id_rec *) context_handle;
    682 
    683     if (! ctx->established) {
    684 	*minor_status = KG_CTX_INCOMPLETE;
    685 	KRB5_LOG0(KRB5_ERR, "kg_unseal() end, error ! ctx->established \n");
    686 	return(GSS_S_NO_CONTEXT);
    687     }
    688 
    689     /* parse the token, leave the data in message_buffer, setting conf_state */
    690 
    691     /* verify the header */
    692     ptr = (unsigned char *) input_token_buffer->value;
    693     if (ctx->proto)
    694 	switch (toktype) {
    695 	case KG_TOK_SIGN_MSG:
    696 	    toktype2 = 0x0404;
    697 	    break;
    698 	case KG_TOK_SEAL_MSG:
    699 	    toktype2 = 0x0504;
    700 	    break;
    701 	case KG_TOK_DEL_CTX:
    702 	    toktype2 = 0x0405;
    703 	    break;
    704 	default:
    705 	    toktype2 = toktype;
    706 	    break;
    707 	}
    708     else
    709 	toktype2 = toktype;
    710     err = g_verify_token_header(ctx->mech_used,
    711 				(uint32_t *)&bodysize, &ptr, toktype2,
    712 				input_token_buffer->length,
    713 				!ctx->proto);
    714     if (err) {
    715 	*minor_status = err;
    716 	return GSS_S_DEFECTIVE_TOKEN;
    717     }
    718 
    719     if (ctx->proto == 0) {
    720 	err = kg_unseal_v1(ctx->k5_context, minor_status, ctx, ptr, bodysize,
    721 			    message_buffer, conf_state, qop_state,
    722 			    toktype);
    723 
    724     } else {
    725 	err = gss_krb5int_unseal_token_v3(&ctx->k5_context, minor_status, ctx,
    726                                            ptr, bodysize, message_buffer,
    727                                            conf_state, qop_state, toktype);
    728     }
    729 
    730     *minor_status = err;
    731 
    732     KRB5_LOG(KRB5_INFO, "kg_unseal() end, err = %d", err);
    733 
    734     return(err);
    735 }
    736