xref: /onnv-gate/usr/src/lib/gss_mechs/mech_dh/backend/mech/context.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/note.h>
30*0Sstevel@tonic-gate #include "dh_gssapi.h"
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate /*
33*0Sstevel@tonic-gate  * This module contains the implementation of the gssapi context support
34*0Sstevel@tonic-gate  * routines for the Diffie-Hellman mechanism.
35*0Sstevel@tonic-gate  *
36*0Sstevel@tonic-gate  * The GSS routines that are supported by this module are:
37*0Sstevel@tonic-gate  *	gss_context_time
38*0Sstevel@tonic-gate  *	gss_delete_sec_context
39*0Sstevel@tonic-gate  *	gss_inquire_context
40*0Sstevel@tonic-gate  *	gss_wrap_size_limit
41*0Sstevel@tonic-gate  *
42*0Sstevel@tonic-gate  * The following routines are not supported for the Diffie-Hellman
43*0Sstevel@tonic-gate  * Mechanism at this time.
44*0Sstevel@tonic-gate  *	gss_export_sec_context
45*0Sstevel@tonic-gate  *	gss_import_sec_context
46*0Sstevel@tonic-gate  *
47*0Sstevel@tonic-gate  * The following routine is not supported since it is obsolete in version 2
48*0Sstevel@tonic-gate  * of the GSS-API.
49*0Sstevel@tonic-gate  *	gss_process_context_token.
50*0Sstevel@tonic-gate  *
51*0Sstevel@tonic-gate  * Note that support for gss_init_sec_context and gss_accept_sec_context is
52*0Sstevel@tonic-gate  * found in context_establish.c
53*0Sstevel@tonic-gate  */
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate OM_uint32
__dh_gss_context_time(void * ctx,OM_uint32 * minor,gss_ctx_id_t context,OM_uint32 * time_remaining)56*0Sstevel@tonic-gate __dh_gss_context_time(void *ctx, /* Mechanism context (not used) */
57*0Sstevel@tonic-gate 		    OM_uint32 * minor, /* GSS minor status */
58*0Sstevel@tonic-gate 		    gss_ctx_id_t context, /* GSS context handle */
59*0Sstevel@tonic-gate 		    OM_uint32* time_remaining /* Time remaining */)
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate {
62*0Sstevel@tonic-gate _NOTE(ARGUNUSED(ctx))
63*0Sstevel@tonic-gate 	/* Context is a dh context */
64*0Sstevel@tonic-gate 	dh_gss_context_t cntx = (dh_gss_context_t)context;
65*0Sstevel@tonic-gate 	time_t now = time(0);
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate 	if (minor == 0)
68*0Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 	if (time_remaining == 0)
71*0Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	/* Validate context */
74*0Sstevel@tonic-gate 	if ((*minor = __dh_validate_context(cntx)) != DH_SUCCESS)
75*0Sstevel@tonic-gate 		return (GSS_S_NO_CONTEXT);
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 	/* See if it is always valid */
78*0Sstevel@tonic-gate 	if (cntx->expire == (time_t)GSS_C_INDEFINITE) {
79*0Sstevel@tonic-gate 		*time_remaining = GSS_C_INDEFINITE;
80*0Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
81*0Sstevel@tonic-gate 	}
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 	/* Calculate the remainning time */
84*0Sstevel@tonic-gate 	*time_remaining = (now < cntx->expire) ? cntx->expire - now : 0;
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	/* Return expired if there is no time left */
87*0Sstevel@tonic-gate 	return (*time_remaining ? GSS_S_COMPLETE : GSS_S_CONTEXT_EXPIRED);
88*0Sstevel@tonic-gate }
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate /*
91*0Sstevel@tonic-gate  * Delete a Diffie-Hellman context that is pointed to by context.
92*0Sstevel@tonic-gate  * On a successfull return *context will be NULL.
93*0Sstevel@tonic-gate  */
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate OM_uint32
__dh_gss_delete_sec_context(void * ctx,OM_uint32 * minor,gss_ctx_id_t * context,gss_buffer_t token)96*0Sstevel@tonic-gate __dh_gss_delete_sec_context(void *ctx, /* Mechanism context */
97*0Sstevel@tonic-gate 			    OM_uint32 *minor, /* Mechanism status */
98*0Sstevel@tonic-gate 			    gss_ctx_id_t *context, /* GSS context */
99*0Sstevel@tonic-gate 			    gss_buffer_t token /* GSS token */)
100*0Sstevel@tonic-gate {
101*0Sstevel@tonic-gate _NOTE(ARGUNUSED(ctx))
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 	dh_gss_context_t cntx;
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 	if (context == 0)
106*0Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ |
107*0Sstevel@tonic-gate 			GSS_S_CALL_INACCESSIBLE_WRITE);
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	/* context is a Diffie-Hellman context */
110*0Sstevel@tonic-gate 	cntx = (dh_gss_context_t)*context;
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 	if (minor == 0)
113*0Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	/*
116*0Sstevel@tonic-gate 	 * If token then set the length to zero value to zero to indicate
117*0Sstevel@tonic-gate 	 * We indicat a null token since we don't need to send a token to
118*0Sstevel@tonic-gate 	 * the other side.
119*0Sstevel@tonic-gate 	 */
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate 	if (token) {
122*0Sstevel@tonic-gate 		token->length = 0;
123*0Sstevel@tonic-gate 		token->value = NULL;
124*0Sstevel@tonic-gate 	}
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	/* Deleting a null context is OK */
127*0Sstevel@tonic-gate 	if (cntx == NULL)
128*0Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	/* Validate the context */
131*0Sstevel@tonic-gate 	if ((*minor = __dh_validate_context(cntx)) != DH_SUCCESS)
132*0Sstevel@tonic-gate 		return (GSS_S_NO_CONTEXT);
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 	/* Zero out the session keys! */
135*0Sstevel@tonic-gate 	memset(cntx->keys, 0, cntx->no_keys * sizeof (des_block));
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	/* Unregister the context */
138*0Sstevel@tonic-gate 	*minor = __dh_remove_context(cntx);
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	/* Free storage */
141*0Sstevel@tonic-gate 	__dh_destroy_seq_hist(cntx);
142*0Sstevel@tonic-gate 	free(cntx->remote);
143*0Sstevel@tonic-gate 	free(cntx->local);
144*0Sstevel@tonic-gate 	Free(cntx->keys);
145*0Sstevel@tonic-gate 	Free(cntx);
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	/* Set context to NULL */
148*0Sstevel@tonic-gate 	*context = NULL;
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
151*0Sstevel@tonic-gate }
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate /*
155*0Sstevel@tonic-gate  * Diffie-Hellman mechanism currently does not support exporting and importing
156*0Sstevel@tonic-gate  * gss contexts.
157*0Sstevel@tonic-gate  */
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate OM_uint32
160*0Sstevel@tonic-gate /*ARGSUSED*/
__dh_gss_export_sec_context(void * ctx,OM_uint32 * minor,gss_ctx_id_t * context,gss_buffer_t token)161*0Sstevel@tonic-gate __dh_gss_export_sec_context(void *ctx, OM_uint32 *minor,
162*0Sstevel@tonic-gate 			    gss_ctx_id_t *context, gss_buffer_t token)
163*0Sstevel@tonic-gate {
164*0Sstevel@tonic-gate 	return (GSS_S_UNAVAILABLE);
165*0Sstevel@tonic-gate }
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate OM_uint32
168*0Sstevel@tonic-gate /*ARGSUSED*/
__dh_gss_import_sec_context(void * ctx,OM_uint32 * minor,gss_buffer_t token,gss_ctx_id_t * context)169*0Sstevel@tonic-gate __dh_gss_import_sec_context(void * ctx, OM_uint32 *minor,
170*0Sstevel@tonic-gate 			    gss_buffer_t token, gss_ctx_id_t *context)
171*0Sstevel@tonic-gate {
172*0Sstevel@tonic-gate 	return (GSS_S_UNAVAILABLE);
173*0Sstevel@tonic-gate }
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate /*
176*0Sstevel@tonic-gate  * Get the state of a Diffie-Hellman context
177*0Sstevel@tonic-gate  */
178*0Sstevel@tonic-gate 
179*0Sstevel@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)180*0Sstevel@tonic-gate __dh_gss_inquire_context(void *ctx, /* Mechanism context */
181*0Sstevel@tonic-gate 			OM_uint32 *minor, /* Mechanism status */
182*0Sstevel@tonic-gate 			gss_ctx_id_t context, /* GSS context */
183*0Sstevel@tonic-gate 			gss_name_t *initiator, /* Name of initiator */
184*0Sstevel@tonic-gate 			gss_name_t *acceptor, /* Name of acceptor */
185*0Sstevel@tonic-gate 			OM_uint32 *time_rec, /* Amount of time left */
186*0Sstevel@tonic-gate 			gss_OID *mech, /* return OID of mechanism */
187*0Sstevel@tonic-gate 			OM_uint32 *flags_rec, /* flags set on context */
188*0Sstevel@tonic-gate 			int *local, /* True if we're the initiator */
189*0Sstevel@tonic-gate 			int *open /* True if the context is established */)
190*0Sstevel@tonic-gate {
191*0Sstevel@tonic-gate 	dh_gss_context_t cntx;
192*0Sstevel@tonic-gate 	OM_uint32 stat = GSS_S_COMPLETE;
193*0Sstevel@tonic-gate 	OM_uint32 t;
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	/* context is a Diffie-Hellman */
196*0Sstevel@tonic-gate 	cntx = (dh_gss_context_t)context;
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 	/* Validate the context */
199*0Sstevel@tonic-gate 	if ((*minor = __dh_validate_context(cntx)) != DH_SUCCESS)
200*0Sstevel@tonic-gate 		return (GSS_S_NO_CONTEXT);
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	/* If the caller wants the mechanism OID set *mech to if we can */
203*0Sstevel@tonic-gate 	if (mech) {
204*0Sstevel@tonic-gate 		if (ctx == 0) {
205*0Sstevel@tonic-gate 			*mech = GSS_C_NO_OID;
206*0Sstevel@tonic-gate 			return (GSS_S_CALL_INACCESSIBLE_READ);
207*0Sstevel@tonic-gate 		}
208*0Sstevel@tonic-gate 		else
209*0Sstevel@tonic-gate 			*mech = ((dh_context_t)ctx)->mech;
210*0Sstevel@tonic-gate 	}
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	/* set t to be the time left on the context */
213*0Sstevel@tonic-gate 	if (cntx->expire == GSS_C_INDEFINITE)
214*0Sstevel@tonic-gate 		t = GSS_C_INDEFINITE;
215*0Sstevel@tonic-gate 	else {
216*0Sstevel@tonic-gate 		time_t now = time(0);
217*0Sstevel@tonic-gate 		t = now > cntx->expire ? 0 : (OM_uint32)(cntx->expire - now);
218*0Sstevel@tonic-gate 	}
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	/* If the caller wants the initiator set *initiator to it. */
221*0Sstevel@tonic-gate 	if (initiator) {
222*0Sstevel@tonic-gate 		dh_principal p = cntx->initiate ? cntx->local : cntx->remote;
223*0Sstevel@tonic-gate 		*initiator = (gss_name_t)strdup(p);
224*0Sstevel@tonic-gate 	}
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	/* If the callers wants the acceptor set *acceptor to it. */
227*0Sstevel@tonic-gate 	if (acceptor) {
228*0Sstevel@tonic-gate 		dh_principal p = cntx->initiate ? cntx->remote : cntx->local;
229*0Sstevel@tonic-gate 		*acceptor = (gss_name_t)strdup(p);
230*0Sstevel@tonic-gate 	}
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 	/* If the caller wants the time remaining set *time_rec to t */
233*0Sstevel@tonic-gate 	if (time_rec)
234*0Sstevel@tonic-gate 		*time_rec = t;
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	/* Return the flags in flags_rec if set */
238*0Sstevel@tonic-gate 	if (flags_rec)
239*0Sstevel@tonic-gate 		*flags_rec = cntx->flags;
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	/* ditto for local */
242*0Sstevel@tonic-gate 	if (local)
243*0Sstevel@tonic-gate 		*local = cntx->initiate;
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	/* ditto for open */
246*0Sstevel@tonic-gate 	if (open)
247*0Sstevel@tonic-gate 		*open = (cntx->state == ESTABLISHED);
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	/* return GSS_S_CONTEXT_EXPIRED if no time is left on the context */
251*0Sstevel@tonic-gate 	return ((t == 0 ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE) | stat);
252*0Sstevel@tonic-gate }
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate /*
255*0Sstevel@tonic-gate  * __dh_gss_process_context_token.
256*0Sstevel@tonic-gate  * This routine is not implemented. It is depricated in version 2.
257*0Sstevel@tonic-gate  */
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate OM_uint32
260*0Sstevel@tonic-gate /*ARGSUSED*/
__dh_gss_process_context_token(void * ctx,OM_uint32 * minor,gss_ctx_id_t context,gss_buffer_t token)261*0Sstevel@tonic-gate __dh_gss_process_context_token(void *ctx, OM_uint32 *minor,
262*0Sstevel@tonic-gate     gss_ctx_id_t context, gss_buffer_t token)
263*0Sstevel@tonic-gate {
264*0Sstevel@tonic-gate 	return (GSS_S_UNAVAILABLE);
265*0Sstevel@tonic-gate }
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate /*
268*0Sstevel@tonic-gate  * This implements the gss_wrap_size_limit entry point for Diffie-Hellman
269*0Sstevel@tonic-gate  * mechanism. See RFC 2078 for details. The idea here is for a context,
270*0Sstevel@tonic-gate  * qop, whether confidentiality is specified, and an output size, return
271*0Sstevel@tonic-gate  * the maximum input size that will fit in the given output size. Typically
272*0Sstevel@tonic-gate  * the output size would be the MTU of the higher level protocol using the
273*0Sstevel@tonic-gate  * GSS-API.
274*0Sstevel@tonic-gate  */
275*0Sstevel@tonic-gate 
276*0Sstevel@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)277*0Sstevel@tonic-gate __dh_gss_wrap_size_limit(void *ctx, /* Mechanism context (not used) */
278*0Sstevel@tonic-gate 			OM_uint32 *minor, /* Mechanism status */
279*0Sstevel@tonic-gate 			gss_ctx_id_t context, /* GSS context handle */
280*0Sstevel@tonic-gate 			int conf_req, /* True if confidentiality is wanted */
281*0Sstevel@tonic-gate 			gss_qop_t qop_req, /* Requested QOP */
282*0Sstevel@tonic-gate 			OM_uint32 output_size, /* The maximum ouput size */
283*0Sstevel@tonic-gate 			OM_uint32 *input_size /* Input size returned */)
284*0Sstevel@tonic-gate {
285*0Sstevel@tonic-gate _NOTE(ARGUNUSED(ctx))
286*0Sstevel@tonic-gate 	OM_uint32 major, stat = GSS_S_COMPLETE;
287*0Sstevel@tonic-gate 	unsigned int msgsize, sigsize, pad = 1, size;
288*0Sstevel@tonic-gate 	dh_token_desc token;
289*0Sstevel@tonic-gate 	dh_wrap_t wrap = &token.ver.dh_version_u.body.dh_token_body_desc_u.seal;
290*0Sstevel@tonic-gate 	OM_uint32 left;
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 	if (input_size == 0)
293*0Sstevel@tonic-gate 		stat = GSS_S_CALL_INACCESSIBLE_WRITE;
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 	/* We check for valid unexpired context by calling gss_context_time. */
296*0Sstevel@tonic-gate 	if ((major = stat | __dh_gss_context_time(ctx, minor, context, &left))
297*0Sstevel@tonic-gate 	    != GSS_S_COMPLETE)
298*0Sstevel@tonic-gate 		return (major | stat);
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	/* Find the signature size for this qop. */
301*0Sstevel@tonic-gate 	if ((*minor = __get_sig_size(qop_req, &sigsize)) != DH_SUCCESS)
302*0Sstevel@tonic-gate 		return (GSS_S_BAD_QOP | stat);
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	/* Just return if we can't give the caller what he ask for. */
305*0Sstevel@tonic-gate 	if (stat)
306*0Sstevel@tonic-gate 		return (stat);
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	/*
309*0Sstevel@tonic-gate 	 * If we requested confidentiality, get the cipher pad for the
310*0Sstevel@tonic-gate 	 * requested qop. Since we can't support privacy the cipher pad
311*0Sstevel@tonic-gate 	 * is always 1.
312*0Sstevel@tonic-gate 	 */
313*0Sstevel@tonic-gate 	if (conf_req)
314*0Sstevel@tonic-gate 		pad = 1;
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	/*
317*0Sstevel@tonic-gate 	 * Set up an empty wrap token to calculate header and signature
318*0Sstevel@tonic-gate 	 * overhead.
319*0Sstevel@tonic-gate 	 */
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	token.ver.verno = DH_PROTO_VERSION;
322*0Sstevel@tonic-gate 	token.ver.dh_version_u.body.type = DH_WRAP;
323*0Sstevel@tonic-gate 	wrap->mic.qop = qop_req;
324*0Sstevel@tonic-gate 	wrap->mic.seqnum = 0;
325*0Sstevel@tonic-gate 	wrap->mic.client_flag = 0;
326*0Sstevel@tonic-gate 	wrap->body.body_len = 0;
327*0Sstevel@tonic-gate 	wrap->body.body_val = 0;
328*0Sstevel@tonic-gate 	token.verifier.dh_signature_len = sigsize;
329*0Sstevel@tonic-gate 	token.verifier.dh_signature_val = 0;
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 	/* This is the size of an empy wrap token */
332*0Sstevel@tonic-gate 	size =  xdr_sizeof((xdrproc_t)xdr_dh_token_desc, (void *)&token);
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 	/* This is the amount of space left to put our message. */
335*0Sstevel@tonic-gate 	msgsize = (output_size > size) ? output_size - size : 0;
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	/* XDR needs to pad to a four byte boundry */
338*0Sstevel@tonic-gate 	msgsize = (msgsize / 4) * 4;
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	/* We need to pad to pad bytes for encryption (=1 if conf_req = 0) */
341*0Sstevel@tonic-gate 	msgsize = (msgsize / pad) * pad;
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	/*
344*0Sstevel@tonic-gate 	 * The serialization of the inner message includes
345*0Sstevel@tonic-gate 	 * the original length.
346*0Sstevel@tonic-gate 	 */
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 	msgsize = (msgsize > sizeof (uint_t)) ? msgsize - sizeof (uint_t) : 0;
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	/*
351*0Sstevel@tonic-gate 	 * We now have the space for the inner wrap message, which is also
352*0Sstevel@tonic-gate 	 * XDR encoded and is padded to a four byte boundry.
353*0Sstevel@tonic-gate 	 */
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	msgsize = (msgsize / 4) * 4;
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 	*input_size = msgsize;
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
360*0Sstevel@tonic-gate }
361