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