17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*48bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <sys/note.h>
297c478bd9Sstevel@tonic-gate #include "dh_gssapi.h"
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * This module contains the implementation of the gssapi context support
337c478bd9Sstevel@tonic-gate  * routines for the Diffie-Hellman mechanism.
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * The GSS routines that are supported by this module are:
367c478bd9Sstevel@tonic-gate  *	gss_context_time
377c478bd9Sstevel@tonic-gate  *	gss_delete_sec_context
387c478bd9Sstevel@tonic-gate  *	gss_inquire_context
397c478bd9Sstevel@tonic-gate  *	gss_wrap_size_limit
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * The following routines are not supported for the Diffie-Hellman
427c478bd9Sstevel@tonic-gate  * Mechanism at this time.
437c478bd9Sstevel@tonic-gate  *	gss_export_sec_context
447c478bd9Sstevel@tonic-gate  *	gss_import_sec_context
457c478bd9Sstevel@tonic-gate  *
467c478bd9Sstevel@tonic-gate  * The following routine is not supported since it is obsolete in version 2
477c478bd9Sstevel@tonic-gate  * of the GSS-API.
487c478bd9Sstevel@tonic-gate  *	gss_process_context_token.
497c478bd9Sstevel@tonic-gate  *
507c478bd9Sstevel@tonic-gate  * Note that support for gss_init_sec_context and gss_accept_sec_context is
517c478bd9Sstevel@tonic-gate  * found in context_establish.c
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate OM_uint32
__dh_gss_context_time(void * ctx,OM_uint32 * minor,gss_ctx_id_t context,OM_uint32 * time_remaining)557c478bd9Sstevel@tonic-gate __dh_gss_context_time(void *ctx, /* Mechanism context (not used) */
567c478bd9Sstevel@tonic-gate 		    OM_uint32 * minor, /* GSS minor status */
577c478bd9Sstevel@tonic-gate 		    gss_ctx_id_t context, /* GSS context handle */
587c478bd9Sstevel@tonic-gate 		    OM_uint32* time_remaining /* Time remaining */)
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(ctx))
627c478bd9Sstevel@tonic-gate 	/* Context is a dh context */
637c478bd9Sstevel@tonic-gate 	dh_gss_context_t cntx = (dh_gss_context_t)context;
647c478bd9Sstevel@tonic-gate 	time_t now = time(0);
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	if (minor == 0)
677c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	if (time_remaining == 0)
707c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	/* Validate context */
737c478bd9Sstevel@tonic-gate 	if ((*minor = __dh_validate_context(cntx)) != DH_SUCCESS)
747c478bd9Sstevel@tonic-gate 		return (GSS_S_NO_CONTEXT);
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	/* See if it is always valid */
777c478bd9Sstevel@tonic-gate 	if (cntx->expire == (time_t)GSS_C_INDEFINITE) {
787c478bd9Sstevel@tonic-gate 		*time_remaining = GSS_C_INDEFINITE;
797c478bd9Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
807c478bd9Sstevel@tonic-gate 	}
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	/* Calculate the remainning time */
837c478bd9Sstevel@tonic-gate 	*time_remaining = (now < cntx->expire) ? cntx->expire - now : 0;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	/* Return expired if there is no time left */
867c478bd9Sstevel@tonic-gate 	return (*time_remaining ? GSS_S_COMPLETE : GSS_S_CONTEXT_EXPIRED);
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate  * Delete a Diffie-Hellman context that is pointed to by context.
917c478bd9Sstevel@tonic-gate  * On a successfull return *context will be NULL.
927c478bd9Sstevel@tonic-gate  */
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate OM_uint32
__dh_gss_delete_sec_context(void * ctx,OM_uint32 * minor,gss_ctx_id_t * context,gss_buffer_t token)957c478bd9Sstevel@tonic-gate __dh_gss_delete_sec_context(void *ctx, /* Mechanism context */
967c478bd9Sstevel@tonic-gate 			    OM_uint32 *minor, /* Mechanism status */
977c478bd9Sstevel@tonic-gate 			    gss_ctx_id_t *context, /* GSS context */
987c478bd9Sstevel@tonic-gate 			    gss_buffer_t token /* GSS token */)
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(ctx))
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	dh_gss_context_t cntx;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	if (context == 0)
1057c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ |
1067c478bd9Sstevel@tonic-gate 			GSS_S_CALL_INACCESSIBLE_WRITE);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	/* context is a Diffie-Hellman context */
1097c478bd9Sstevel@tonic-gate 	cntx = (dh_gss_context_t)*context;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	if (minor == 0)
1127c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	/*
1157c478bd9Sstevel@tonic-gate 	 * If token then set the length to zero value to zero to indicate
1167c478bd9Sstevel@tonic-gate 	 * We indicat a null token since we don't need to send a token to
1177c478bd9Sstevel@tonic-gate 	 * the other side.
1187c478bd9Sstevel@tonic-gate 	 */
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	if (token) {
1217c478bd9Sstevel@tonic-gate 		token->length = 0;
1227c478bd9Sstevel@tonic-gate 		token->value = NULL;
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	/* Deleting a null context is OK */
1267c478bd9Sstevel@tonic-gate 	if (cntx == NULL)
1277c478bd9Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	/* Validate the context */
1307c478bd9Sstevel@tonic-gate 	if ((*minor = __dh_validate_context(cntx)) != DH_SUCCESS)
1317c478bd9Sstevel@tonic-gate 		return (GSS_S_NO_CONTEXT);
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	/* Zero out the session keys! */
1347c478bd9Sstevel@tonic-gate 	memset(cntx->keys, 0, cntx->no_keys * sizeof (des_block));
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	/* Unregister the context */
1377c478bd9Sstevel@tonic-gate 	*minor = __dh_remove_context(cntx);
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	/* Free storage */
1407c478bd9Sstevel@tonic-gate 	__dh_destroy_seq_hist(cntx);
1417c478bd9Sstevel@tonic-gate 	free(cntx->remote);
1427c478bd9Sstevel@tonic-gate 	free(cntx->local);
1437c478bd9Sstevel@tonic-gate 	Free(cntx->keys);
1447c478bd9Sstevel@tonic-gate 	Free(cntx);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	/* Set context to NULL */
1477c478bd9Sstevel@tonic-gate 	*context = NULL;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate  * Diffie-Hellman mechanism currently does not support exporting and importing
1557c478bd9Sstevel@tonic-gate  * gss contexts.
1567c478bd9Sstevel@tonic-gate  */
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate OM_uint32
1597c478bd9Sstevel@tonic-gate /*ARGSUSED*/
__dh_gss_export_sec_context(void * ctx,OM_uint32 * minor,gss_ctx_id_t * context,gss_buffer_t token)1607c478bd9Sstevel@tonic-gate __dh_gss_export_sec_context(void *ctx, OM_uint32 *minor,
1617c478bd9Sstevel@tonic-gate 			    gss_ctx_id_t *context, gss_buffer_t token)
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate 	return (GSS_S_UNAVAILABLE);
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate OM_uint32
1677c478bd9Sstevel@tonic-gate /*ARGSUSED*/
__dh_gss_import_sec_context(void * ctx,OM_uint32 * minor,gss_buffer_t token,gss_ctx_id_t * context)1687c478bd9Sstevel@tonic-gate __dh_gss_import_sec_context(void * ctx, OM_uint32 *minor,
1697c478bd9Sstevel@tonic-gate 			    gss_buffer_t token, gss_ctx_id_t *context)
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate 	return (GSS_S_UNAVAILABLE);
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate  * Get the state of a Diffie-Hellman context
1767c478bd9Sstevel@tonic-gate  */
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate OM_uint32
__dh_gss_inquire_context(void * ctx,OM_uint32 * minor,gss_ctx_id_t context,gss_name_t * initiator,gss_name_t * acceptor,OM_uint32 * time_rec,gss_OID * mech,OM_uint32 * flags_rec,int * local,int * open)1797c478bd9Sstevel@tonic-gate __dh_gss_inquire_context(void *ctx, /* Mechanism context */
1807c478bd9Sstevel@tonic-gate 			OM_uint32 *minor, /* Mechanism status */
1817c478bd9Sstevel@tonic-gate 			gss_ctx_id_t context, /* GSS context */
1827c478bd9Sstevel@tonic-gate 			gss_name_t *initiator, /* Name of initiator */
1837c478bd9Sstevel@tonic-gate 			gss_name_t *acceptor, /* Name of acceptor */
1847c478bd9Sstevel@tonic-gate 			OM_uint32 *time_rec, /* Amount of time left */
1857c478bd9Sstevel@tonic-gate 			gss_OID *mech, /* return OID of mechanism */
1867c478bd9Sstevel@tonic-gate 			OM_uint32 *flags_rec, /* flags set on context */
1877c478bd9Sstevel@tonic-gate 			int *local, /* True if we're the initiator */
1887c478bd9Sstevel@tonic-gate 			int *open /* True if the context is established */)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	dh_gss_context_t cntx;
1917c478bd9Sstevel@tonic-gate 	OM_uint32 stat = GSS_S_COMPLETE;
1927c478bd9Sstevel@tonic-gate 	OM_uint32 t;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	/* context is a Diffie-Hellman */
1957c478bd9Sstevel@tonic-gate 	cntx = (dh_gss_context_t)context;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	/* Validate the context */
1987c478bd9Sstevel@tonic-gate 	if ((*minor = __dh_validate_context(cntx)) != DH_SUCCESS)
1997c478bd9Sstevel@tonic-gate 		return (GSS_S_NO_CONTEXT);
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	/* If the caller wants the mechanism OID set *mech to if we can */
2027c478bd9Sstevel@tonic-gate 	if (mech) {
2037c478bd9Sstevel@tonic-gate 		if (ctx == 0) {
2047c478bd9Sstevel@tonic-gate 			*mech = GSS_C_NO_OID;
2057c478bd9Sstevel@tonic-gate 			return (GSS_S_CALL_INACCESSIBLE_READ);
2067c478bd9Sstevel@tonic-gate 		}
2077c478bd9Sstevel@tonic-gate 		else
2087c478bd9Sstevel@tonic-gate 			*mech = ((dh_context_t)ctx)->mech;
2097c478bd9Sstevel@tonic-gate 	}
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	/* set t to be the time left on the context */
2127c478bd9Sstevel@tonic-gate 	if (cntx->expire == GSS_C_INDEFINITE)
2137c478bd9Sstevel@tonic-gate 		t = GSS_C_INDEFINITE;
2147c478bd9Sstevel@tonic-gate 	else {
2157c478bd9Sstevel@tonic-gate 		time_t now = time(0);
2167c478bd9Sstevel@tonic-gate 		t = now > cntx->expire ? 0 : (OM_uint32)(cntx->expire - now);
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/* If the caller wants the initiator set *initiator to it. */
2207c478bd9Sstevel@tonic-gate 	if (initiator) {
2217c478bd9Sstevel@tonic-gate 		dh_principal p = cntx->initiate ? cntx->local : cntx->remote;
2227c478bd9Sstevel@tonic-gate 		*initiator = (gss_name_t)strdup(p);
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	/* If the callers wants the acceptor set *acceptor to it. */
2267c478bd9Sstevel@tonic-gate 	if (acceptor) {
2277c478bd9Sstevel@tonic-gate 		dh_principal p = cntx->initiate ? cntx->remote : cntx->local;
2287c478bd9Sstevel@tonic-gate 		*acceptor = (gss_name_t)strdup(p);
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	/* If the caller wants the time remaining set *time_rec to t */
2327c478bd9Sstevel@tonic-gate 	if (time_rec)
2337c478bd9Sstevel@tonic-gate 		*time_rec = t;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	/* Return the flags in flags_rec if set */
2377c478bd9Sstevel@tonic-gate 	if (flags_rec)
2387c478bd9Sstevel@tonic-gate 		*flags_rec = cntx->flags;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	/* ditto for local */
2417c478bd9Sstevel@tonic-gate 	if (local)
2427c478bd9Sstevel@tonic-gate 		*local = cntx->initiate;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	/* ditto for open */
2457c478bd9Sstevel@tonic-gate 	if (open)
2467c478bd9Sstevel@tonic-gate 		*open = (cntx->state == ESTABLISHED);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	/* return GSS_S_CONTEXT_EXPIRED if no time is left on the context */
2507c478bd9Sstevel@tonic-gate 	return ((t == 0 ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE) | stat);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate  * __dh_gss_process_context_token.
2557c478bd9Sstevel@tonic-gate  * This routine is not implemented. It is depricated in version 2.
2567c478bd9Sstevel@tonic-gate  */
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate OM_uint32
2597c478bd9Sstevel@tonic-gate /*ARGSUSED*/
__dh_gss_process_context_token(void * ctx,OM_uint32 * minor,gss_ctx_id_t context,gss_buffer_t token)2607c478bd9Sstevel@tonic-gate __dh_gss_process_context_token(void *ctx, OM_uint32 *minor,
2617c478bd9Sstevel@tonic-gate     gss_ctx_id_t context, gss_buffer_t token)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	return (GSS_S_UNAVAILABLE);
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate /*
2677c478bd9Sstevel@tonic-gate  * This implements the gss_wrap_size_limit entry point for Diffie-Hellman
2687c478bd9Sstevel@tonic-gate  * mechanism. See RFC 2078 for details. The idea here is for a context,
2697c478bd9Sstevel@tonic-gate  * qop, whether confidentiality is specified, and an output size, return
2707c478bd9Sstevel@tonic-gate  * the maximum input size that will fit in the given output size. Typically
2717c478bd9Sstevel@tonic-gate  * the output size would be the MTU of the higher level protocol using the
2727c478bd9Sstevel@tonic-gate  * GSS-API.
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate OM_uint32
__dh_gss_wrap_size_limit(void * ctx,OM_uint32 * minor,gss_ctx_id_t context,int conf_req,gss_qop_t qop_req,OM_uint32 output_size,OM_uint32 * input_size)2767c478bd9Sstevel@tonic-gate __dh_gss_wrap_size_limit(void *ctx, /* Mechanism context (not used) */
2777c478bd9Sstevel@tonic-gate 			OM_uint32 *minor, /* Mechanism status */
2787c478bd9Sstevel@tonic-gate 			gss_ctx_id_t context, /* GSS context handle */
2797c478bd9Sstevel@tonic-gate 			int conf_req, /* True if confidentiality is wanted */
2807c478bd9Sstevel@tonic-gate 			gss_qop_t qop_req, /* Requested QOP */
2817c478bd9Sstevel@tonic-gate 			OM_uint32 output_size, /* The maximum ouput size */
2827c478bd9Sstevel@tonic-gate 			OM_uint32 *input_size /* Input size returned */)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(ctx))
2857c478bd9Sstevel@tonic-gate 	OM_uint32 major, stat = GSS_S_COMPLETE;
2867c478bd9Sstevel@tonic-gate 	unsigned int msgsize, sigsize, pad = 1, size;
2877c478bd9Sstevel@tonic-gate 	dh_token_desc token;
2887c478bd9Sstevel@tonic-gate 	dh_wrap_t wrap = &token.ver.dh_version_u.body.dh_token_body_desc_u.seal;
2897c478bd9Sstevel@tonic-gate 	OM_uint32 left;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	if (input_size == 0)
2927c478bd9Sstevel@tonic-gate 		stat = GSS_S_CALL_INACCESSIBLE_WRITE;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	/* We check for valid unexpired context by calling gss_context_time. */
2957c478bd9Sstevel@tonic-gate 	if ((major = stat | __dh_gss_context_time(ctx, minor, context, &left))
2967c478bd9Sstevel@tonic-gate 	    != GSS_S_COMPLETE)
2977c478bd9Sstevel@tonic-gate 		return (major | stat);
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	/* Find the signature size for this qop. */
3007c478bd9Sstevel@tonic-gate 	if ((*minor = __get_sig_size(qop_req, &sigsize)) != DH_SUCCESS)
3017c478bd9Sstevel@tonic-gate 		return (GSS_S_BAD_QOP | stat);
3027c478bd9Sstevel@tonic-gate 
303*48bbca81SDaniel Hoffman 	/* Just return if we can't give the caller what it asked for. */
3047c478bd9Sstevel@tonic-gate 	if (stat)
3057c478bd9Sstevel@tonic-gate 		return (stat);
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	/*
3087c478bd9Sstevel@tonic-gate 	 * If we requested confidentiality, get the cipher pad for the
3097c478bd9Sstevel@tonic-gate 	 * requested qop. Since we can't support privacy the cipher pad
3107c478bd9Sstevel@tonic-gate 	 * is always 1.
3117c478bd9Sstevel@tonic-gate 	 */
3127c478bd9Sstevel@tonic-gate 	if (conf_req)
3137c478bd9Sstevel@tonic-gate 		pad = 1;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/*
3167c478bd9Sstevel@tonic-gate 	 * Set up an empty wrap token to calculate header and signature
3177c478bd9Sstevel@tonic-gate 	 * overhead.
3187c478bd9Sstevel@tonic-gate 	 */
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	token.ver.verno = DH_PROTO_VERSION;
3217c478bd9Sstevel@tonic-gate 	token.ver.dh_version_u.body.type = DH_WRAP;
3227c478bd9Sstevel@tonic-gate 	wrap->mic.qop = qop_req;
3237c478bd9Sstevel@tonic-gate 	wrap->mic.seqnum = 0;
3247c478bd9Sstevel@tonic-gate 	wrap->mic.client_flag = 0;
3257c478bd9Sstevel@tonic-gate 	wrap->body.body_len = 0;
3267c478bd9Sstevel@tonic-gate 	wrap->body.body_val = 0;
3277c478bd9Sstevel@tonic-gate 	token.verifier.dh_signature_len = sigsize;
3287c478bd9Sstevel@tonic-gate 	token.verifier.dh_signature_val = 0;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	/* This is the size of an empy wrap token */
3317c478bd9Sstevel@tonic-gate 	size =  xdr_sizeof((xdrproc_t)xdr_dh_token_desc, (void *)&token);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	/* This is the amount of space left to put our message. */
3347c478bd9Sstevel@tonic-gate 	msgsize = (output_size > size) ? output_size - size : 0;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	/* XDR needs to pad to a four byte boundry */
3377c478bd9Sstevel@tonic-gate 	msgsize = (msgsize / 4) * 4;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/* We need to pad to pad bytes for encryption (=1 if conf_req = 0) */
3407c478bd9Sstevel@tonic-gate 	msgsize = (msgsize / pad) * pad;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	/*
3437c478bd9Sstevel@tonic-gate 	 * The serialization of the inner message includes
3447c478bd9Sstevel@tonic-gate 	 * the original length.
3457c478bd9Sstevel@tonic-gate 	 */
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	msgsize = (msgsize > sizeof (uint_t)) ? msgsize - sizeof (uint_t) : 0;
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	/*
3507c478bd9Sstevel@tonic-gate 	 * We now have the space for the inner wrap message, which is also
3517c478bd9Sstevel@tonic-gate 	 * XDR encoded and is padded to a four byte boundry.
3527c478bd9Sstevel@tonic-gate 	 */
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	msgsize = (msgsize / 4) * 4;
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	*input_size = msgsize;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
3597c478bd9Sstevel@tonic-gate }
360