xref: /illumos-gate/usr/src/uts/common/gssapi/mechs/krb5/mech/k5unseal.c (revision 89a7715a55deca73d03076f5c24463717f0aaa91)
1 /*
2  * Copyright 2004 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;
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 	    token.length = tmsglen - conflen - plain[tmsglen-1];
281 	}
282 
283 	if (token.length) {
284 	    if ((token.value = (void *) xmalloc(token.length)) == NULL) {
285 		if (sealalg != 0xffff)
286 		    xfree_wrap(plain, tmsglen);
287 		*minor_status = ENOMEM;
288 		KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error2 ENOMEM\n");
289 		return(GSS_S_FAILURE);
290 	    }
291 	    (void) memcpy(token.value, plain+conflen, token.length);
292 	} else {
293 	    token.value = NULL;
294 	}
295     } else if (toktype == KG_TOK_SIGN_MSG) {
296 	KRB5_LOG0(KRB5_INFO, "kg_unseal_v1() toktype == KG_TOK_SIGN_MSG\n");
297 	token = *message_buffer;
298 	plain = token.value;
299 	plainlen = token.length;
300     } else {
301 	KRB5_LOG0(KRB5_INFO, "kg_unseal_v1() toktype == NULL\n");
302 	token.length = 0;
303 	token.value = NULL;
304 	plain = token.value;
305 	plainlen = token.length;
306     }
307 
308     /* compute the checksum of the message */
309 
310     /* initialize the the cksum */
311     switch (signalg) {
312     case SGN_ALG_DES_MAC_MD5:
313     case SGN_ALG_MD2_5:
314     case SGN_ALG_DES_MAC:
315     case SGN_ALG_3:
316 	md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
317 	break;
318     case SGN_ALG_HMAC_SHA1_DES3_KD:
319 	md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
320 	break;
321     case SGN_ALG_HMAC_MD5:
322 	md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
323 	break;
324     default:
325 	KRB5_LOG(KRB5_ERR, "kg_unseal_v1() end, error2 signalg=%d\n", signalg);
326 #ifndef	_KERNEL
327 	abort ();
328 #else
329 	*minor_status = 0;
330 	return(GSS_S_DEFECTIVE_TOKEN);
331 #endif /* _KERNEL */
332     }
333 
334     if (code = krb5_c_checksum_length(context, md5cksum.checksum_type,
335 		&sumlen))
336     {
337 	KRB5_LOG(KRB5_ERR, "kg_unseal_v1() end, krb5_c_checksum_length() error "
338 		"code=%d\n", code);
339 	return(code);
340     }
341     md5cksum.length = (size_t)sumlen;
342 
343     switch (signalg) {
344     case SGN_ALG_DES_MAC_MD5:
345     case SGN_ALG_3:
346 	/* compute the checksum of the message */
347 
348 	/* 8 = bytes of token body to be checksummed according to spec */
349 
350 	if (! (data_ptr = (void *)
351 	       xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
352 	    if (sealalg != 0xffff)
353 		xfree_wrap(plain, tmsglen);
354 	    if (toktype == KG_TOK_SEAL_MSG) {
355 		xfree_wrap(token.value, token.length);
356 		/* Solaris Kerberos: just to be safe since token.value is an
357 		 * output parameter.
358 		 */
359 		token.value = NULL;
360 		token.length = 0;
361 	    }
362 	    *minor_status = ENOMEM;
363 	    KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error3 ENOMEM\n");
364 	    return(GSS_S_FAILURE);
365 	}
366 
367 	(void) memcpy(data_ptr, ptr-2, 8);
368 
369 	if (ctx->big_endian)
370 	    (void) memcpy(data_ptr+8, token.value, token.length);
371 	else
372 	    (void) memcpy(data_ptr+8, plain, plainlen);
373 
374 	plaind.length = 8 + (ctx->big_endian ? token.length : plainlen);
375 	plaind.data = data_ptr;
376 	code = krb5_c_make_checksum(context, md5cksum.checksum_type,
377 				    ctx->seq, sign_usage,
378 				    &plaind, &md5cksum);
379 	xfree_wrap(data_ptr, 8 + (ctx->big_endian ? token.length : plainlen));
380 
381 	if (code) {
382 	    if (toktype == KG_TOK_SEAL_MSG) {
383 		xfree_wrap(token.value, token.length);
384 		/* Solaris Kerberos: just to be safe since token.value is an
385 		 * output parameter.
386 		 */
387 		token.value = NULL;
388 		token.length = 0;
389 	    }
390 	    *minor_status = code;
391 	    KRB5_LOG(KRB5_ERR, "kg_unseal_v1() end, krb5_c_make_checksum() "
392 		    "error code = %d\n", code);
393 	    return(GSS_S_FAILURE);
394 	}
395 
396 	if ((code = kg_encrypt(context, ctx->seq, KG_USAGE_SEAL,
397 			       (g_OID_equal(ctx->mech_used, gss_mech_krb5_old) ?
398 				ctx->seq->contents : NULL),
399 			       md5cksum.contents, md5cksum.contents, 16))) {
400 	    xfree_wrap(md5cksum.contents, md5cksum.length);
401 	    if (toktype == KG_TOK_SEAL_MSG) {
402 		xfree_wrap(token.value, token.length);
403 		/* Solaris Kerberos: just to be safe since token.value is an
404 		 * output parameter.
405 		 */
406 		token.value = NULL;
407 		token.length = 0;
408 	    }
409 	    *minor_status = code;
410 	    KRB5_LOG(KRB5_ERR, "kg_unseal_v1() end, kg_encrypt() error"
411 		    "code = %d\n", code);
412 	    return GSS_S_FAILURE;
413 	}
414 
415 	if (signalg == 0)
416 	    cksum.length = 8;
417 	else
418 	    cksum.length = 16;
419 	cksum.contents = md5cksum.contents + 16 - cksum.length;
420 
421 	code = memcmp(cksum.contents, ptr+14, cksum.length);
422 	break;
423 
424     case SGN_ALG_MD2_5:
425 	if (!ctx->seed_init &&
426 	    (code = kg_make_seed(context, ctx->subkey, ctx->seed))) {
427 	    xfree_wrap(md5cksum.contents, md5cksum.length);
428 	    if (sealalg != 0xffff)
429 		xfree_wrap(plain, tmsglen);
430 	    if (toktype == KG_TOK_SEAL_MSG) {
431 		xfree_wrap(token.value, token.length);
432 		/* Solaris Kerberos: just to be safe since token.value is an
433 		 * output parameter.
434 		 */
435 		token.value = NULL;
436 		token.length = 0;
437 	    }
438 	    *minor_status = code;
439 	    return GSS_S_FAILURE;
440 	}
441 
442 	if (! (data_ptr = (void *)
443 	       xmalloc(sizeof(ctx->seed) + 8 +
444 		       (ctx->big_endian ? token.length : plainlen)))) {
445 	    xfree_wrap(md5cksum.contents, md5cksum.length);
446 	    if (sealalg == 0)
447 		xfree_wrap(plain, tmsglen);
448 	    if (toktype == KG_TOK_SEAL_MSG) {
449 		xfree_wrap(token.value, token.length);
450 		/* Solaris Kerberos: just to be safe since token.value is an
451 		 * output parameter.
452 		 */
453 		token.value = NULL;
454 		token.length = 0;
455 	    }
456 	    *minor_status = ENOMEM;
457 	    return(GSS_S_FAILURE);
458 	}
459 	(void) memcpy(data_ptr, ptr-2, 8);
460 	(void) memcpy(data_ptr+8, ctx->seed, sizeof(ctx->seed));
461 	if (ctx->big_endian)
462 	    (void) memcpy(data_ptr+8+sizeof(ctx->seed),
463 			  token.value, token.length);
464 	else
465 	    (void) memcpy(data_ptr+8+sizeof(ctx->seed),
466 			  plain, plainlen);
467 	plaind.length = 8 + sizeof(ctx->seed) +
468 	    (ctx->big_endian ? token.length : plainlen);
469 	plaind.data = data_ptr;
470 	xfree_wrap(md5cksum.contents, md5cksum.length);
471 	code = krb5_c_make_checksum(context, md5cksum.checksum_type,
472 				    ctx->seq, KG_USAGE_SIGN,
473 				    &plaind, &md5cksum);
474 	xfree_wrap(data_ptr, 8 + sizeof(ctx->seed) +
475             (ctx->big_endian ? token.length : plainlen));
476 
477 	if (code) {
478 	    if (sealalg == 0)
479 		xfree_wrap(plain, tmsglen);
480 	    if (toktype == KG_TOK_SEAL_MSG) {
481 		xfree_wrap(token.value, token.length);
482 		/* Solaris Kerberos: just to be safe since token.value is an
483 		 * output parameter.
484 		 */
485 		token.value = NULL;
486 		token.length = 0;
487 	    }
488 	    *minor_status = code;
489 	    return(GSS_S_FAILURE);
490 	}
491 
492 	code = memcmp(md5cksum.contents, ptr+14, 8);
493 	/* Falls through to defective-token??  */
494 
495     default:
496 	*minor_status = 0;
497 	KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error SGN_ALG_MD2_5 "
498 		"GSS_S_DEFECTIVE_TOKEN\n");
499 	return(GSS_S_DEFECTIVE_TOKEN);
500 
501     case SGN_ALG_HMAC_SHA1_DES3_KD:
502     case SGN_ALG_HMAC_MD5:
503 	/* compute the checksum of the message */
504 
505 	/* 8 = bytes of token body to be checksummed according to spec */
506 
507 	if (! (data_ptr = (void *)
508 	       xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
509 	    if (sealalg != 0xffff)
510 		xfree_wrap(plain, tmsglen);
511 	    if (toktype == KG_TOK_SEAL_MSG) {
512 		xfree_wrap(token.value, token.length);
513 		/* Solaris Kerberos: just to be safe since token.value is an
514 		 * output parameter.
515 		 */
516 		token.value = NULL;
517 		token.length = 0;
518 	    }
519 	    *minor_status = ENOMEM;
520 	    return(GSS_S_FAILURE);
521 	}
522 
523 	(void) memcpy(data_ptr, ptr-2, 8);
524 
525 	if (ctx->big_endian) {
526 	    KRB5_LOG0(KRB5_INFO, "kg_unseal_v1() ctx->big_endian = 1\n");
527 	    (void) memcpy(data_ptr+8, token.value, token.length);
528 	}
529 	else {
530 	    KRB5_LOG0(KRB5_INFO, "kg_unseal_v1() ctx->big_endian = 0\n");
531 	    (void) memcpy(data_ptr+8, plain, plainlen);
532 	}
533 
534 	plaind.length = 8 + (ctx->big_endian ? token.length : plainlen);
535 	plaind.data = data_ptr;
536 
537 	code = krb5_c_make_checksum(context, md5cksum.checksum_type,
538 				    ctx->seq, sign_usage,
539 				    &plaind, &md5cksum);
540 
541 	xfree_wrap(data_ptr, 8 + (ctx->big_endian ? token.length : plainlen));
542 
543 	if (code) {
544 	    if (toktype == KG_TOK_SEAL_MSG) {
545 		xfree_wrap(token.value, token.length);
546 		/* Solaris Kerberos: just to be safe since token.value is an
547 		 * output parameter.
548 		 */
549 		token.value = NULL;
550 		token.length = 0;
551 	    }
552 	    *minor_status = code;
553 	    KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error "
554 		    "SGN_ALG_HMAC_SHA1_DES3_KD GSS_S_FAILURE\n");
555 	    return(GSS_S_FAILURE);
556 	}
557 
558 	/* compare the computed checksum against the transmitted checksum */
559 	code = memcmp(md5cksum.contents, ptr+14, cksum_len);
560 	KRB5_LOG(KRB5_INFO, "kg_unseal_v1() memcmp %d bytes", cksum_len);
561 	break;
562     }
563 
564     xfree_wrap(md5cksum.contents, md5cksum.length);
565     if (sealalg != 0xffff)
566 	xfree_wrap(plain, tmsglen);
567 
568     if (code) {
569 	if (toktype == KG_TOK_SEAL_MSG) {
570 	    xfree_wrap(token.value, token.length);
571 	    /* Solaris Kerberos: just to be safe since token.value is an
572 	     * output parameter.
573 	     */
574 	    token.value = NULL;
575 	    token.length = 0;
576 	}
577 	*minor_status = 0;
578 	KRB5_LOG0(KRB5_ERR, "kg_unseal_v1() end, error GSS_S_BAD_SIG\n");
579 	return(GSS_S_BAD_SIG);
580     }
581 
582     if (conf_state)
583 	*conf_state = (sealalg != 0xffff);
584 
585     if (qop_state)
586 	*qop_state = GSS_C_QOP_DEFAULT;
587 
588     if ((code = krb5_timeofday(context, &now))) {
589 	*minor_status = code;
590 
591 	KRB5_LOG(KRB5_ERR, "kg_unseal_v1() end, krb5_timeofday()"
592 		"error code = %d\n", code);
593 
594 	return(GSS_S_FAILURE);
595     }
596 
597     if (now > ctx->endtime) {
598 	*minor_status = 0;
599 
600 	KRB5_LOG1(KRB5_ERR, "kg_unseal_v1() end, error "
601 		"now %d > ctx->endtime %d\n", now, ctx->endtime);
602 
603 	return(GSS_S_CONTEXT_EXPIRED);
604     }
605 
606     /* do sequencing checks */
607     if ((ctx->initiate && direction != 0xff) ||
608 	(!ctx->initiate && direction != 0)) {
609 	if (toktype == KG_TOK_SEAL_MSG) {
610 	    xfree_wrap(token.value, token.length);
611 	    /* Solaris Kerberos: just to be safe since token.value is an
612 	     * output parameter.
613 	     */
614 	    token.value = NULL;
615 	    token.length = 0;
616 	}
617 	*minor_status = (OM_uint32) G_BAD_DIRECTION;
618 
619 	KRB5_LOG1(KRB5_ERR, "kg_unseal_v1() end, error GSS_S_BAD_SIG "
620 		"G_BAD_DIRECTION ctx->initiate = %d "
621 		"direction = %d\n", ctx->initiate, direction);
622 
623 	return(GSS_S_BAD_SIG);
624     }
625 
626     retval = g_order_check(&(ctx->seqstate), (gssint_uint64)seqnum);
627 
628     /* It got through unscathed, adjust the output message buffer. */
629     if (retval == 0 && toktype == KG_TOK_SEAL_MSG)
630 	*message_buffer = token;
631 
632     *minor_status = 0;
633     KRB5_LOG(KRB5_INFO, "kg_unseal_v1() end, retval = %d\n", retval);
634     return(retval);
635 }
636 
637 /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
638    conf_state is only valid if SEAL. */
639 
640 OM_uint32
641 kg_unseal(minor_status, context_handle, input_token_buffer,
642 	  message_buffer, conf_state, qop_state, toktype)
643     OM_uint32 *minor_status;
644     gss_ctx_id_t context_handle;
645     gss_buffer_t input_token_buffer;
646     gss_buffer_t message_buffer;
647     int *conf_state;
648     int *qop_state;
649     int toktype;
650 {
651     krb5_gss_ctx_id_rec *ctx;
652     unsigned char *ptr;
653     int bodysize;
654     int err;
655     int toktype2;
656 
657     KRB5_LOG0(KRB5_INFO, "kg_unseal() start \n");
658 
659     /* validate the context handle */
660     if (! kg_validate_ctx_id(context_handle)) {
661 	*minor_status = (OM_uint32) G_VALIDATE_FAILED;
662 
663 	KRB5_LOG0(KRB5_ERR, "kg_unseal() end, kg_validate_ctx_id() error "
664 		"G_VALIDATE_FAILED \n");
665 
666 	return(GSS_S_NO_CONTEXT);
667     }
668 
669     ctx = (krb5_gss_ctx_id_rec *) context_handle;
670 
671     if (! ctx->established) {
672 	*minor_status = KG_CTX_INCOMPLETE;
673 	KRB5_LOG0(KRB5_ERR, "kg_unseal() end, error ! ctx->established \n");
674 	return(GSS_S_NO_CONTEXT);
675     }
676 
677     /* parse the token, leave the data in message_buffer, setting conf_state */
678 
679     /* verify the header */
680     ptr = (unsigned char *) input_token_buffer->value;
681     if (ctx->proto)
682 	switch (toktype) {
683 	case KG_TOK_SIGN_MSG:
684             toktype2 = 0x0404;
685             break;
686 	case KG_TOK_SEAL_MSG:
687             toktype2 = 0x0504;
688             break;
689 	case KG_TOK_DEL_CTX:
690             toktype2 = 0x0405;
691             break;
692 	default:
693             toktype2 = toktype;
694             break;
695 	}
696     else
697         toktype2 = toktype;
698     err = g_verify_token_header(ctx->mech_used,
699 				(uint32_t *)&bodysize, &ptr, toktype2,
700 				input_token_buffer->length,
701 				!ctx->proto);
702     if (err) {
703 	*minor_status = err;
704 	return GSS_S_DEFECTIVE_TOKEN;
705     }
706 
707 
708 
709     if (ctx->proto == 0) {
710 	err = kg_unseal_v1(ctx->k5_context, minor_status, ctx, ptr, bodysize,
711 			    message_buffer, conf_state, qop_state,
712 			    toktype);
713 
714     } else {
715 	err = gss_krb5int_unseal_token_v3(ctx->k5_context, minor_status, ctx,
716                                            ptr, bodysize, message_buffer,
717                                            conf_state, qop_state, toktype);
718     }
719 
720     *minor_status = err;
721 
722     KRB5_LOG(KRB5_INFO, "kg_unseal() end, err = %d", err);
723 
724     return(err);
725 }
726