1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  *	context_establish.c
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
26*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
27*7c478bd9Sstevel@tonic-gate  *
28*7c478bd9Sstevel@tonic-gate  */
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #include <string.h>
31*7c478bd9Sstevel@tonic-gate #include "dh_gssapi.h"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate /*
34*7c478bd9Sstevel@tonic-gate  * The following 2 routines convert a gss_channel_binding to a DH
35*7c478bd9Sstevel@tonic-gate  * channel_binding and vis versa.  We can no longer assume a simple
36*7c478bd9Sstevel@tonic-gate  * cast because a GSS buffer_t uses a size_t for the length field wich
37*7c478bd9Sstevel@tonic-gate  * is 64 bits in a 64 bit process. The xdr encoding always assumes the
38*7c478bd9Sstevel@tonic-gate  * length to be 32 bits :<.
39*7c478bd9Sstevel@tonic-gate  */
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate static dh_channel_binding_t
GSS2DH_channel_binding(dh_channel_binding_t dh_binding,gss_channel_bindings_t gss_binding)42*7c478bd9Sstevel@tonic-gate GSS2DH_channel_binding(dh_channel_binding_t dh_binding,
43*7c478bd9Sstevel@tonic-gate 		    gss_channel_bindings_t gss_binding)
44*7c478bd9Sstevel@tonic-gate {
45*7c478bd9Sstevel@tonic-gate 	if (gss_binding == GSS_C_NO_CHANNEL_BINDINGS)
46*7c478bd9Sstevel@tonic-gate 		return (NULL);
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate 	dh_binding->initiator_addrtype = gss_binding->initiator_addrtype;
49*7c478bd9Sstevel@tonic-gate 	dh_binding->initiator_address.dh_buffer_desc_len =
50*7c478bd9Sstevel@tonic-gate 		(uint32_t)gss_binding->initiator_address.length;
51*7c478bd9Sstevel@tonic-gate 	if (gss_binding->initiator_address.length !=
52*7c478bd9Sstevel@tonic-gate 		dh_binding->initiator_address.dh_buffer_desc_len)
53*7c478bd9Sstevel@tonic-gate 		return (NULL);
54*7c478bd9Sstevel@tonic-gate 	dh_binding->initiator_address.dh_buffer_desc_val =
55*7c478bd9Sstevel@tonic-gate 		gss_binding->initiator_address.value;
56*7c478bd9Sstevel@tonic-gate 	dh_binding->acceptor_addrtype = gss_binding->acceptor_addrtype;
57*7c478bd9Sstevel@tonic-gate 	dh_binding->acceptor_address.dh_buffer_desc_len =
58*7c478bd9Sstevel@tonic-gate 		(uint32_t)gss_binding->acceptor_address.length;
59*7c478bd9Sstevel@tonic-gate 	dh_binding->acceptor_address.dh_buffer_desc_val =
60*7c478bd9Sstevel@tonic-gate 		gss_binding->acceptor_address.value;
61*7c478bd9Sstevel@tonic-gate 	dh_binding->application_data.dh_buffer_desc_len =
62*7c478bd9Sstevel@tonic-gate 		(uint32_t)gss_binding->application_data.length;
63*7c478bd9Sstevel@tonic-gate 	dh_binding->application_data.dh_buffer_desc_val =
64*7c478bd9Sstevel@tonic-gate 		gss_binding->application_data.value;
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate 	return (dh_binding);
67*7c478bd9Sstevel@tonic-gate }
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate static gss_channel_bindings_t
DH2GSS_channel_binding(gss_channel_bindings_t gss_binding,dh_channel_binding_t dh_binding)70*7c478bd9Sstevel@tonic-gate DH2GSS_channel_binding(gss_channel_bindings_t gss_binding,
71*7c478bd9Sstevel@tonic-gate 		    dh_channel_binding_t dh_binding)
72*7c478bd9Sstevel@tonic-gate {
73*7c478bd9Sstevel@tonic-gate 	if (dh_binding == NULL)
74*7c478bd9Sstevel@tonic-gate 		return (GSS_C_NO_CHANNEL_BINDINGS);
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate 	gss_binding->initiator_addrtype = dh_binding->initiator_addrtype;
77*7c478bd9Sstevel@tonic-gate 	gss_binding->initiator_address.length =
78*7c478bd9Sstevel@tonic-gate 		dh_binding->initiator_address.dh_buffer_desc_len;
79*7c478bd9Sstevel@tonic-gate 	gss_binding->initiator_address.value =
80*7c478bd9Sstevel@tonic-gate 		dh_binding->initiator_address.dh_buffer_desc_val;
81*7c478bd9Sstevel@tonic-gate 	gss_binding->acceptor_addrtype = dh_binding->acceptor_addrtype;
82*7c478bd9Sstevel@tonic-gate 	gss_binding->acceptor_address.length =
83*7c478bd9Sstevel@tonic-gate 		dh_binding->acceptor_address.dh_buffer_desc_len;
84*7c478bd9Sstevel@tonic-gate 	gss_binding->acceptor_address.value =
85*7c478bd9Sstevel@tonic-gate 		dh_binding->acceptor_address.dh_buffer_desc_val;
86*7c478bd9Sstevel@tonic-gate 	gss_binding->application_data.length =
87*7c478bd9Sstevel@tonic-gate 		dh_binding->application_data.dh_buffer_desc_len;
88*7c478bd9Sstevel@tonic-gate 	gss_binding->application_data.value =
89*7c478bd9Sstevel@tonic-gate 		dh_binding->application_data.dh_buffer_desc_val;
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate 	return (gss_binding);
92*7c478bd9Sstevel@tonic-gate }
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate /*
95*7c478bd9Sstevel@tonic-gate  * Routine to compare that two gss_buffers are the same.
96*7c478bd9Sstevel@tonic-gate  */
97*7c478bd9Sstevel@tonic-gate static bool_t
gss_buffer_cmp(gss_buffer_t b1,gss_buffer_t b2)98*7c478bd9Sstevel@tonic-gate gss_buffer_cmp(gss_buffer_t b1, gss_buffer_t b2)
99*7c478bd9Sstevel@tonic-gate {
100*7c478bd9Sstevel@tonic-gate 	if (b1->length != b2->length)
101*7c478bd9Sstevel@tonic-gate 		return (FALSE);
102*7c478bd9Sstevel@tonic-gate 	if (b1->length == 0)
103*7c478bd9Sstevel@tonic-gate 		return (TRUE);
104*7c478bd9Sstevel@tonic-gate 	if (b1->value == b2->value)
105*7c478bd9Sstevel@tonic-gate 		return (TRUE);
106*7c478bd9Sstevel@tonic-gate 	if (b1->value == 0 || b2->value == 0)
107*7c478bd9Sstevel@tonic-gate 		return (FALSE);
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	return (memcmp(b1->value, b2->value, b1->length) == 0);
110*7c478bd9Sstevel@tonic-gate }
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate /*
113*7c478bd9Sstevel@tonic-gate  * Compare if two channel bindings are the same. If the local binding is
114*7c478bd9Sstevel@tonic-gate  * NULL then we always return TRUE. This indicates that the local host
115*7c478bd9Sstevel@tonic-gate  * does not care about any bindings.
116*7c478bd9Sstevel@tonic-gate  */
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate static bool_t
gss_chanbind_cmp(gss_channel_bindings_t local,gss_channel_bindings_t remote)119*7c478bd9Sstevel@tonic-gate gss_chanbind_cmp(gss_channel_bindings_t local, gss_channel_bindings_t remote)
120*7c478bd9Sstevel@tonic-gate {
121*7c478bd9Sstevel@tonic-gate 	if (local == NULL)
122*7c478bd9Sstevel@tonic-gate 		return (TRUE); /* local doesn't care so we won't either */
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	if (remote == NULL)
125*7c478bd9Sstevel@tonic-gate 		return (FALSE);
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	if (local->initiator_addrtype != remote->initiator_addrtype)
128*7c478bd9Sstevel@tonic-gate 		return (FALSE);
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	if (local->initiator_addrtype != GSS_C_AF_NULLADDR)
131*7c478bd9Sstevel@tonic-gate 		if (gss_buffer_cmp(&local->initiator_address,
132*7c478bd9Sstevel@tonic-gate 				    &remote->initiator_address) == FALSE)
133*7c478bd9Sstevel@tonic-gate 			return (FALSE);
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	if (local->acceptor_addrtype != remote->acceptor_addrtype)
136*7c478bd9Sstevel@tonic-gate 		return (FALSE);
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	if (local->acceptor_addrtype != GSS_C_AF_NULLADDR)
139*7c478bd9Sstevel@tonic-gate 		if (gss_buffer_cmp(&local->acceptor_address,
140*7c478bd9Sstevel@tonic-gate 				    &remote->acceptor_address) == FALSE)
141*7c478bd9Sstevel@tonic-gate 			return (FALSE);
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	return (gss_buffer_cmp(&local->application_data,
144*7c478bd9Sstevel@tonic-gate 				&remote->application_data));
145*7c478bd9Sstevel@tonic-gate }
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate /*
148*7c478bd9Sstevel@tonic-gate  * Generate an accept token for a context and channel binding puting the
149*7c478bd9Sstevel@tonic-gate  * generated token output.
150*7c478bd9Sstevel@tonic-gate  */
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate static
153*7c478bd9Sstevel@tonic-gate OM_uint32
gen_accept_token(dh_gss_context_t ctx,gss_channel_bindings_t channel,gss_buffer_t output)154*7c478bd9Sstevel@tonic-gate gen_accept_token(dh_gss_context_t ctx, /* Diffie-Hellman context */
155*7c478bd9Sstevel@tonic-gate 		gss_channel_bindings_t channel, /* channel bindings */
156*7c478bd9Sstevel@tonic-gate 		gss_buffer_t output /* The accept token */)
157*7c478bd9Sstevel@tonic-gate {
158*7c478bd9Sstevel@tonic-gate 	dh_token_desc token;
159*7c478bd9Sstevel@tonic-gate 	/* Grap a pointer to the context_t part of the token */
160*7c478bd9Sstevel@tonic-gate 	dh_cntx_t accept = &token.ver.dh_version_u.
161*7c478bd9Sstevel@tonic-gate 				body.dh_token_body_desc_u.accept_context.cntx;
162*7c478bd9Sstevel@tonic-gate 	dh_key_set keys;
163*7c478bd9Sstevel@tonic-gate 	dh_channel_binding_desc dh_binding;
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	/* Set the version number from the context. */
166*7c478bd9Sstevel@tonic-gate 	token.ver.verno = ctx->proto_version;
167*7c478bd9Sstevel@tonic-gate 	/* Set the token type to be an ACCEPT token. */
168*7c478bd9Sstevel@tonic-gate 	token.ver.dh_version_u.body.type = DH_ACCEPT_CNTX;
169*7c478bd9Sstevel@tonic-gate 	/* Set our self as the remote for the other end. */
170*7c478bd9Sstevel@tonic-gate 	accept->remote = ctx->local;
171*7c478bd9Sstevel@tonic-gate 	/* The remote side to us is the local side at the other end. */
172*7c478bd9Sstevel@tonic-gate 	accept->local = ctx->remote;
173*7c478bd9Sstevel@tonic-gate 	/* Our context flags */
174*7c478bd9Sstevel@tonic-gate 	accept->flags = ctx->flags;
175*7c478bd9Sstevel@tonic-gate 	/* When we will expire */
176*7c478bd9Sstevel@tonic-gate 	accept->expire = ctx->expire;
177*7c478bd9Sstevel@tonic-gate 	/* Our channel bindings */
178*7c478bd9Sstevel@tonic-gate 	accept->channel = GSS2DH_channel_binding(&dh_binding, channel);
179*7c478bd9Sstevel@tonic-gate 	/* Package the context session keys into a key_set */
180*7c478bd9Sstevel@tonic-gate 	keys.dh_key_set_len = ctx->no_keys;
181*7c478bd9Sstevel@tonic-gate 	keys.dh_key_set_val = ctx->keys;
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	/* Build the token */
184*7c478bd9Sstevel@tonic-gate 	return (__make_token(output, NULL, &token, &keys));
185*7c478bd9Sstevel@tonic-gate }
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate /*
188*7c478bd9Sstevel@tonic-gate  * Check if a credential is valid for the requested usage. Note that
189*7c478bd9Sstevel@tonic-gate  * Diffie-Hellman only supports credentials based on the callers net
190*7c478bd9Sstevel@tonic-gate  * name. netname will point to the users rpc netname. It is up to the
191*7c478bd9Sstevel@tonic-gate  * caller to free the netname.
192*7c478bd9Sstevel@tonic-gate  */
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate static OM_uint32
validate_cred(dh_context_t cntx,OM_uint32 * minor,dh_cred_id_t cred,gss_cred_usage_t usage,dh_principal * netname)195*7c478bd9Sstevel@tonic-gate validate_cred(dh_context_t cntx, /* Diffie-Hellman mechanism context */
196*7c478bd9Sstevel@tonic-gate 	    OM_uint32 *minor,	 /* Mechanism status */
197*7c478bd9Sstevel@tonic-gate 	    dh_cred_id_t cred, /* Diffie-Hellman credential */
198*7c478bd9Sstevel@tonic-gate 	    gss_cred_usage_t usage, /* Cred usage */
199*7c478bd9Sstevel@tonic-gate 	    dh_principal *netname /* Cred owner */)
200*7c478bd9Sstevel@tonic-gate {
201*7c478bd9Sstevel@tonic-gate 	/* Set minor status */
202*7c478bd9Sstevel@tonic-gate 	*minor = DH_SUCCESS;
203*7c478bd9Sstevel@tonic-gate 	*netname = NULL;
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 	/*
206*7c478bd9Sstevel@tonic-gate 	 * See if the users creditial is available, i.e.,
207*7c478bd9Sstevel@tonic-gate 	 * the user is "key logged" in.
208*7c478bd9Sstevel@tonic-gate 	 */
209*7c478bd9Sstevel@tonic-gate 	if (!cntx->keyopts->key_secretkey_is_set()) {
210*7c478bd9Sstevel@tonic-gate 		*minor = DH_NO_SECRET;
211*7c478bd9Sstevel@tonic-gate 		return (GSS_S_NO_CRED);
212*7c478bd9Sstevel@tonic-gate 	}
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	/*
216*7c478bd9Sstevel@tonic-gate 	 * Get the netname.
217*7c478bd9Sstevel@tonic-gate 	 */
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	if ((*netname = cntx->keyopts->get_principal()) == NULL) {
220*7c478bd9Sstevel@tonic-gate 		*minor = DH_NO_PRINCIPAL;
221*7c478bd9Sstevel@tonic-gate 		return (GSS_S_NO_CRED);
222*7c478bd9Sstevel@tonic-gate 	}
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	/*
225*7c478bd9Sstevel@tonic-gate 	 * Check if the supplied cred is valid for the requested usage.
226*7c478bd9Sstevel@tonic-gate 	 * The default cred never expires and has a usage of GSS_C_BOTH.
227*7c478bd9Sstevel@tonic-gate 	 */
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	if ((gss_cred_id_t)cred != GSS_C_NO_CREDENTIAL) {
230*7c478bd9Sstevel@tonic-gate 		if ((cred->usage != usage &&
231*7c478bd9Sstevel@tonic-gate 		    cred->usage != GSS_C_BOTH) ||
232*7c478bd9Sstevel@tonic-gate 		    strcmp(*netname, cred->principal) != 0) {
233*7c478bd9Sstevel@tonic-gate 			free(*netname);
234*7c478bd9Sstevel@tonic-gate 			return (GSS_S_NO_CRED);
235*7c478bd9Sstevel@tonic-gate 		}
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 		/* See if the cred is still valid */
238*7c478bd9Sstevel@tonic-gate 		if (cred->expire != GSS_C_INDEFINITE &&
239*7c478bd9Sstevel@tonic-gate 		    time(0) > cred->expire) {
240*7c478bd9Sstevel@tonic-gate 			free(*netname);
241*7c478bd9Sstevel@tonic-gate 			return (GSS_S_CREDENTIALS_EXPIRED);
242*7c478bd9Sstevel@tonic-gate 		}
243*7c478bd9Sstevel@tonic-gate 	}
244*7c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
245*7c478bd9Sstevel@tonic-gate }
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate /*
249*7c478bd9Sstevel@tonic-gate  * establish_session_keys: This routine decrypts the session keys supplied
250*7c478bd9Sstevel@tonic-gate  * and uses those keys to verifiy the signature over the input token
251*7c478bd9Sstevel@tonic-gate  * match the signature in the token.
252*7c478bd9Sstevel@tonic-gate  */
253*7c478bd9Sstevel@tonic-gate static OM_uint32
establish_session_keys(dh_context_t dhctx,const char * remote,dh_key_set_t keys,dh_signature_t sig,dh_token_t token)254*7c478bd9Sstevel@tonic-gate establish_session_keys(dh_context_t dhctx, const char *remote,
255*7c478bd9Sstevel@tonic-gate 		    dh_key_set_t keys, dh_signature_t sig, dh_token_t token)
256*7c478bd9Sstevel@tonic-gate {
257*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat;
258*7c478bd9Sstevel@tonic-gate 	int i, j;
259*7c478bd9Sstevel@tonic-gate 	des_block *saved_keys;
260*7c478bd9Sstevel@tonic-gate 	char *saved_sig;
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 	/*
263*7c478bd9Sstevel@tonic-gate 	 * The following variable is used by the keyopts key_decryptsessions
264*7c478bd9Sstevel@tonic-gate 	 * entry point. If this variable is non zero and the underling
265*7c478bd9Sstevel@tonic-gate 	 * mechanism uses a cache of public keys, then get the public key
266*7c478bd9Sstevel@tonic-gate 	 * for the remote out of that cache. When key_decrptsessions return
267*7c478bd9Sstevel@tonic-gate 	 * this variable will be set to non zero if the key did come
268*7c478bd9Sstevel@tonic-gate 	 * out of the cache, otherwise it will be set to zero.
269*7c478bd9Sstevel@tonic-gate 	 */
270*7c478bd9Sstevel@tonic-gate 	int key_was_from_cache = 1;
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 	/* Save the keyset so if we fail we can try again */
273*7c478bd9Sstevel@tonic-gate 	if ((saved_keys = New(des_block, keys->dh_key_set_len)) == NULL)
274*7c478bd9Sstevel@tonic-gate 		return (DH_NOMEM_FAILURE);
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < keys->dh_key_set_len; i++)
277*7c478bd9Sstevel@tonic-gate 		saved_keys[i] = keys->dh_key_set_val[i];
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 	/* Save the unencrypted signature as well for retry attempt */
280*7c478bd9Sstevel@tonic-gate 	if ((saved_sig = New(char, sig->dh_signature_len)) == NULL) {
281*7c478bd9Sstevel@tonic-gate 		Free(saved_keys);
282*7c478bd9Sstevel@tonic-gate 		return (DH_NOMEM_FAILURE);
283*7c478bd9Sstevel@tonic-gate 	}
284*7c478bd9Sstevel@tonic-gate 	memcpy(saved_sig, sig->dh_signature_val, sig->dh_signature_len);
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	/*
287*7c478bd9Sstevel@tonic-gate 	 * We will try to decrypt the session keys up to two times.
288*7c478bd9Sstevel@tonic-gate 	 * The first time will let the underlying mechanism use a
289*7c478bd9Sstevel@tonic-gate 	 * public key cache, if the set of session keys fail to
290*7c478bd9Sstevel@tonic-gate 	 * validate the signature that is reported in the deserialized
291*7c478bd9Sstevel@tonic-gate 	 * token, and those session keys were decrypted by a key
292*7c478bd9Sstevel@tonic-gate 	 * derived from a public key cache, then we will try again but
293*7c478bd9Sstevel@tonic-gate 	 * this time will advise the underlying mechanism not to use
294*7c478bd9Sstevel@tonic-gate 	 * its cache.
295*7c478bd9Sstevel@tonic-gate 	 */
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	for (i = 0; key_was_from_cache && i < 2; i++) {
298*7c478bd9Sstevel@tonic-gate 		/*
299*7c478bd9Sstevel@tonic-gate 		 * Decrypt the session keys using the mechanism specific
300*7c478bd9Sstevel@tonic-gate 		 * routine and if this is the second time, don't use
301*7c478bd9Sstevel@tonic-gate 		 * the cache.
302*7c478bd9Sstevel@tonic-gate 		 */
303*7c478bd9Sstevel@tonic-gate 		if (i == 1)
304*7c478bd9Sstevel@tonic-gate 			key_was_from_cache = 0;
305*7c478bd9Sstevel@tonic-gate 		if (dhctx->keyopts->key_decryptsessions(remote,
306*7c478bd9Sstevel@tonic-gate 							keys->dh_key_set_val,
307*7c478bd9Sstevel@tonic-gate 							keys->dh_key_set_len,
308*7c478bd9Sstevel@tonic-gate 							&key_was_from_cache)) {
309*7c478bd9Sstevel@tonic-gate 			Free(saved_keys);
310*7c478bd9Sstevel@tonic-gate 			Free(saved_sig);
311*7c478bd9Sstevel@tonic-gate 			return (DH_SESSION_CIPHER_FAILURE);
312*7c478bd9Sstevel@tonic-gate 		}
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate #ifdef DH_DEBUG
315*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "Received session keys %s the cache:\n",
316*7c478bd9Sstevel@tonic-gate 			key_was_form_cache ? "using" : "not using");
317*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < keys->dh_key_set_len; i++)
318*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%08.8x%08.8x ",
319*7c478bd9Sstevel@tonic-gate 				keys->dh_key_set_val[i].key.high,
320*7c478bd9Sstevel@tonic-gate 				keys->dh_key_set_val[i].key.low);
321*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "\n");
322*7c478bd9Sstevel@tonic-gate #endif
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 		/*
325*7c478bd9Sstevel@tonic-gate 		 * Now verify that the extracted signature from the
326*7c478bd9Sstevel@tonic-gate 		 * deserialized token is the same as our calculation
327*7c478bd9Sstevel@tonic-gate 		 * of the signature.
328*7c478bd9Sstevel@tonic-gate 		 */
329*7c478bd9Sstevel@tonic-gate 		if ((stat = __verify_sig(token, DH_MECH_QOP, keys, sig)) ==
330*7c478bd9Sstevel@tonic-gate 		    DH_SUCCESS) {
331*7c478bd9Sstevel@tonic-gate 			Free(saved_keys);
332*7c478bd9Sstevel@tonic-gate 			Free(saved_sig);
333*7c478bd9Sstevel@tonic-gate 			return (DH_SUCCESS);
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 		}
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 		/* Restore the keys and signature for retry */
338*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < keys->dh_key_set_len; j++)
339*7c478bd9Sstevel@tonic-gate 			keys->dh_key_set_val[j] = saved_keys[j];
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 		memcpy(sig->dh_signature_val, saved_sig, sig->dh_signature_len);
342*7c478bd9Sstevel@tonic-gate 	}
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	Free(saved_keys);
345*7c478bd9Sstevel@tonic-gate 	Free(saved_sig);
346*7c478bd9Sstevel@tonic-gate 	return (stat);
347*7c478bd9Sstevel@tonic-gate }
348*7c478bd9Sstevel@tonic-gate /*
349*7c478bd9Sstevel@tonic-gate  * This is the Diffie-Hellman mechanism entry point for the
350*7c478bd9Sstevel@tonic-gate  * gss_accept_sec context. See RFC 2078 for details. This
351*7c478bd9Sstevel@tonic-gate  * routine accepts a context establish token from the initator
352*7c478bd9Sstevel@tonic-gate  * and optionally produces a token to send back to the initator to
353*7c478bd9Sstevel@tonic-gate  * establish a GSS security context. The established context will
354*7c478bd9Sstevel@tonic-gate  * be return via the *gss_ctx paramater.
355*7c478bd9Sstevel@tonic-gate  */
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate OM_uint32
__dh_gss_accept_sec_context(void * ctx,OM_uint32 * minor,gss_ctx_id_t * gss_ctx,gss_cred_id_t cred,gss_buffer_t input,gss_channel_bindings_t channel,gss_name_t * principal,gss_OID * mech,gss_buffer_t output,OM_uint32 * flags,OM_uint32 * expire,gss_cred_id_t * del_cred)358*7c478bd9Sstevel@tonic-gate __dh_gss_accept_sec_context(void *ctx, /* Per mechanism context */
359*7c478bd9Sstevel@tonic-gate 			    OM_uint32 *minor, /* Mechanism status */
360*7c478bd9Sstevel@tonic-gate 			    gss_ctx_id_t *gss_ctx, /* GSS context */
361*7c478bd9Sstevel@tonic-gate 			    gss_cred_id_t cred, /* GSS credential */
362*7c478bd9Sstevel@tonic-gate 			    gss_buffer_t input, /* Input from initiator */
363*7c478bd9Sstevel@tonic-gate 				/* Local channel bindings  */
364*7c478bd9Sstevel@tonic-gate 			    gss_channel_bindings_t  channel,
365*7c478bd9Sstevel@tonic-gate 			    gss_name_t *principal, /* Initiator name */
366*7c478bd9Sstevel@tonic-gate 			    gss_OID* mech, /* Returned mechanism */
367*7c478bd9Sstevel@tonic-gate 			    gss_buffer_t output, /* Token to send initiator */
368*7c478bd9Sstevel@tonic-gate 			    OM_uint32 *flags, /* flags of context */
369*7c478bd9Sstevel@tonic-gate 			    OM_uint32 *expire, /* Time left on context */
370*7c478bd9Sstevel@tonic-gate 			    gss_cred_id_t *del_cred /* Delegated credential */)
371*7c478bd9Sstevel@tonic-gate {
372*7c478bd9Sstevel@tonic-gate 	dh_token_desc token;
373*7c478bd9Sstevel@tonic-gate 	/* ctx is a Diffie-Hellman mechanism context */
374*7c478bd9Sstevel@tonic-gate 	dh_context_t dhctx = (dh_context_t)ctx;
375*7c478bd9Sstevel@tonic-gate 	dh_gss_context_t g_cntx = NULL;
376*7c478bd9Sstevel@tonic-gate 	dh_principal netname = NULL;
377*7c478bd9Sstevel@tonic-gate 	dh_init_context_t clnt;
378*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat;
379*7c478bd9Sstevel@tonic-gate 	int i;
380*7c478bd9Sstevel@tonic-gate 	dh_signature sig;
381*7c478bd9Sstevel@tonic-gate 	struct gss_channel_bindings_struct dh_binding_desc;
382*7c478bd9Sstevel@tonic-gate 	gss_channel_bindings_t dh_binding;
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	/* Check for required parameters */
385*7c478bd9Sstevel@tonic-gate 	if (input == NULL)
386*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ);
387*7c478bd9Sstevel@tonic-gate 	if (minor == NULL || output == NULL || gss_ctx == NULL)
388*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	/* Give outputs sane values if present */
391*7c478bd9Sstevel@tonic-gate 	*minor = 0;
392*7c478bd9Sstevel@tonic-gate 	if (principal)
393*7c478bd9Sstevel@tonic-gate 		*principal = NULL;
394*7c478bd9Sstevel@tonic-gate 	if (mech)
395*7c478bd9Sstevel@tonic-gate 		*mech = GSS_C_NO_OID;
396*7c478bd9Sstevel@tonic-gate 	if (flags)
397*7c478bd9Sstevel@tonic-gate 		*flags  = 0;
398*7c478bd9Sstevel@tonic-gate 	if (expire)
399*7c478bd9Sstevel@tonic-gate 		*expire = 0;
400*7c478bd9Sstevel@tonic-gate 	if (del_cred)
401*7c478bd9Sstevel@tonic-gate 		*del_cred = GSS_C_NO_CREDENTIAL;
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	output->length = 0;
404*7c478bd9Sstevel@tonic-gate 	output->value = 0;
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	/*
407*7c478bd9Sstevel@tonic-gate 	 * Diffie-Hellman never returns GSS_S_CONTINUE_NEEDED from a
408*7c478bd9Sstevel@tonic-gate 	 * gss_accept_sec_context so the only context read should be
409*7c478bd9Sstevel@tonic-gate 	 * GSS_C_NO_CONTEXT.
410*7c478bd9Sstevel@tonic-gate 	 */
411*7c478bd9Sstevel@tonic-gate 	if (*gss_ctx != GSS_C_NO_CONTEXT)
412*7c478bd9Sstevel@tonic-gate 		return (GSS_S_NO_CONTEXT);
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 	/* Valdidate the local credentinal and retrieve then principal name */
415*7c478bd9Sstevel@tonic-gate 	stat = validate_cred(dhctx, minor,
416*7c478bd9Sstevel@tonic-gate 			    (dh_cred_id_t)cred, GSS_C_ACCEPT, &netname);
417*7c478bd9Sstevel@tonic-gate 	if (stat != GSS_S_COMPLETE)
418*7c478bd9Sstevel@tonic-gate 		return (stat);
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	/*
421*7c478bd9Sstevel@tonic-gate 	 * Deserialize the input into token, extracting the signature
422*7c478bd9Sstevel@tonic-gate 	 * into sig. Where sig is our calculation of the MD5 check sum
423*7c478bd9Sstevel@tonic-gate 	 * over the input token up to the signature.
424*7c478bd9Sstevel@tonic-gate 	 */
425*7c478bd9Sstevel@tonic-gate 	memset(&sig, 0, sizeof (sig));
426*7c478bd9Sstevel@tonic-gate 	if (*minor = __get_ap_token(input, dhctx->mech, &token, &sig)) {
427*7c478bd9Sstevel@tonic-gate 		free(netname);
428*7c478bd9Sstevel@tonic-gate 		__free_signature(&sig);
429*7c478bd9Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
430*7c478bd9Sstevel@tonic-gate 	}
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	/* set clnt to point to the init context part of token */
433*7c478bd9Sstevel@tonic-gate 	clnt = &token.ver.dh_version_u.body.dh_token_body_desc_u.init_context;
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	/* Check that this context is really for us */
436*7c478bd9Sstevel@tonic-gate 	if (strcmp(clnt->cntx.local, netname) != 0) {
437*7c478bd9Sstevel@tonic-gate 		free(netname);
438*7c478bd9Sstevel@tonic-gate 		*minor = DH_NOT_LOCAL;
439*7c478bd9Sstevel@tonic-gate 		stat = GSS_S_DEFECTIVE_TOKEN;
440*7c478bd9Sstevel@tonic-gate 		goto cleanup;
441*7c478bd9Sstevel@tonic-gate 	}
442*7c478bd9Sstevel@tonic-gate 	free(netname);
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	/*
445*7c478bd9Sstevel@tonic-gate 	 * See if this is a DH protocol version that we can handle.
446*7c478bd9Sstevel@tonic-gate 	 * Currently we can handle the one and only DH_PROTO_VERSION.
447*7c478bd9Sstevel@tonic-gate 	 */
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	if (token.ver.verno != DH_PROTO_VERSION) {
450*7c478bd9Sstevel@tonic-gate 		*minor = DH_PROTO_MISMATCH;
451*7c478bd9Sstevel@tonic-gate 		stat = GSS_S_DEFECTIVE_TOKEN;
452*7c478bd9Sstevel@tonic-gate 		goto cleanup;
453*7c478bd9Sstevel@tonic-gate 	}
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	/* Decrypt the session keys and verify the signature */
456*7c478bd9Sstevel@tonic-gate 	if ((*minor = establish_session_keys(dhctx, clnt->cntx.remote,
457*7c478bd9Sstevel@tonic-gate 					    &clnt->keys,
458*7c478bd9Sstevel@tonic-gate 					    &sig, &token)) != DH_SUCCESS) {
459*7c478bd9Sstevel@tonic-gate 		stat = GSS_S_BAD_SIG;
460*7c478bd9Sstevel@tonic-gate 		goto cleanup;
461*7c478bd9Sstevel@tonic-gate 	}
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	/* Check that the channel bindings are the same */
464*7c478bd9Sstevel@tonic-gate 	dh_binding = DH2GSS_channel_binding(&dh_binding_desc,
465*7c478bd9Sstevel@tonic-gate 					    clnt->cntx.channel);
466*7c478bd9Sstevel@tonic-gate 	if (!gss_chanbind_cmp(channel, dh_binding)) {
467*7c478bd9Sstevel@tonic-gate 		stat = GSS_S_BAD_BINDINGS;
468*7c478bd9Sstevel@tonic-gate 		goto cleanup;
469*7c478bd9Sstevel@tonic-gate 	}
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 	/* Everything is OK, so allocate the context */
472*7c478bd9Sstevel@tonic-gate 	if ((g_cntx = New(dh_gss_context_desc, 1)) == NULL) {
473*7c478bd9Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
474*7c478bd9Sstevel@tonic-gate 		stat = GSS_S_FAILURE;
475*7c478bd9Sstevel@tonic-gate 		goto cleanup;
476*7c478bd9Sstevel@tonic-gate 	}
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	/*
479*7c478bd9Sstevel@tonic-gate 	 * The context is now established for us, though we may still
480*7c478bd9Sstevel@tonic-gate 	 * need to send a token if the initiator requested mutual
481*7c478bd9Sstevel@tonic-gate 	 * authentications.
482*7c478bd9Sstevel@tonic-gate 	 */
483*7c478bd9Sstevel@tonic-gate 	g_cntx->state = ESTABLISHED;
484*7c478bd9Sstevel@tonic-gate 	/* We're not the initiator */
485*7c478bd9Sstevel@tonic-gate 	g_cntx->initiate = 0;
486*7c478bd9Sstevel@tonic-gate 	/* Set the protocol version from the token */
487*7c478bd9Sstevel@tonic-gate 	g_cntx->proto_version = token.ver.verno;
488*7c478bd9Sstevel@tonic-gate 	/* Initialize the sequence history */
489*7c478bd9Sstevel@tonic-gate 	__dh_init_seq_hist(g_cntx);
490*7c478bd9Sstevel@tonic-gate 	/* Set debug to false */
491*7c478bd9Sstevel@tonic-gate 	g_cntx->debug = 0;
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	/* Set who the initiator is */
494*7c478bd9Sstevel@tonic-gate 	if ((g_cntx->remote = strdup(clnt->cntx.remote)) == NULL) {
495*7c478bd9Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
496*7c478bd9Sstevel@tonic-gate 		stat = GSS_S_FAILURE;
497*7c478bd9Sstevel@tonic-gate 		goto cleanup;
498*7c478bd9Sstevel@tonic-gate 	}
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 	/* Set who we are */
501*7c478bd9Sstevel@tonic-gate 	if ((g_cntx->local = strdup(clnt->cntx.local)) == NULL) {
502*7c478bd9Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
503*7c478bd9Sstevel@tonic-gate 		stat = GSS_S_FAILURE;
504*7c478bd9Sstevel@tonic-gate 		goto cleanup;
505*7c478bd9Sstevel@tonic-gate 	}
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	/* Stash a copy of the session keys for the context */
508*7c478bd9Sstevel@tonic-gate 	g_cntx->no_keys = clnt->keys.dh_key_set_len;
509*7c478bd9Sstevel@tonic-gate 	if ((g_cntx->keys = New(des_block, g_cntx->no_keys)) == NULL) {
510*7c478bd9Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
511*7c478bd9Sstevel@tonic-gate 		stat = GSS_S_FAILURE;
512*7c478bd9Sstevel@tonic-gate 		goto cleanup;
513*7c478bd9Sstevel@tonic-gate 	}
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < g_cntx->no_keys; i++)
516*7c478bd9Sstevel@tonic-gate 		g_cntx->keys[i] = clnt->keys.dh_key_set_val[i];
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	/* Set the flags and expire time */
519*7c478bd9Sstevel@tonic-gate 	g_cntx->flags = clnt->cntx.flags;
520*7c478bd9Sstevel@tonic-gate 	g_cntx->expire = clnt->cntx.expire;
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	/* Create output token if needed */
523*7c478bd9Sstevel@tonic-gate 	if (g_cntx->flags & GSS_C_MUTUAL_FLAG) {
524*7c478bd9Sstevel@tonic-gate 		if (*minor = gen_accept_token(g_cntx, channel, output)) {
525*7c478bd9Sstevel@tonic-gate 			stat = GSS_S_FAILURE;
526*7c478bd9Sstevel@tonic-gate 			goto cleanup;
527*7c478bd9Sstevel@tonic-gate 		}
528*7c478bd9Sstevel@tonic-gate 	}
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	/* This is now a valid context */
531*7c478bd9Sstevel@tonic-gate 	if ((*minor = __dh_install_context(g_cntx)) != DH_SUCCESS) {
532*7c478bd9Sstevel@tonic-gate 		stat = GSS_S_FAILURE;
533*7c478bd9Sstevel@tonic-gate 		goto cleanup;
534*7c478bd9Sstevel@tonic-gate 	}
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	/* Return the GSS context to the caller */
537*7c478bd9Sstevel@tonic-gate 	*gss_ctx = (gss_ctx_id_t)g_cntx;
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 	/* Return the remote principal if requested */
540*7c478bd9Sstevel@tonic-gate 	if (principal)
541*7c478bd9Sstevel@tonic-gate 		*principal = (gss_name_t)strdup(g_cntx->remote);
542*7c478bd9Sstevel@tonic-gate 	/* Return the flags if requested */
543*7c478bd9Sstevel@tonic-gate 	if (flags)
544*7c478bd9Sstevel@tonic-gate 		*flags = g_cntx->flags;
545*7c478bd9Sstevel@tonic-gate 	/* Return the expire time if requested */
546*7c478bd9Sstevel@tonic-gate 	if (expire)
547*7c478bd9Sstevel@tonic-gate 		*expire = g_cntx->expire;
548*7c478bd9Sstevel@tonic-gate 	/* Return the mechanism if requested */
549*7c478bd9Sstevel@tonic-gate 	if (mech)
550*7c478bd9Sstevel@tonic-gate 		*mech = dhctx->mech;
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	/* Release storage of the signature */
553*7c478bd9Sstevel@tonic-gate 	__free_signature(&sig);
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	/* Tear down the deserialize token */
556*7c478bd9Sstevel@tonic-gate 	xdr_free(xdr_dh_token_desc, (char *)&token);
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 	/* We're done */
559*7c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate cleanup:
562*7c478bd9Sstevel@tonic-gate 	/* Destroy incomplete context */
563*7c478bd9Sstevel@tonic-gate 	if (g_cntx) {
564*7c478bd9Sstevel@tonic-gate 		__dh_destroy_seq_hist(g_cntx);
565*7c478bd9Sstevel@tonic-gate 		(void) __dh_remove_context(g_cntx);
566*7c478bd9Sstevel@tonic-gate 		free(g_cntx->remote);
567*7c478bd9Sstevel@tonic-gate 		free(g_cntx->local);
568*7c478bd9Sstevel@tonic-gate 		Free(g_cntx->keys);
569*7c478bd9Sstevel@tonic-gate 		Free(g_cntx);
570*7c478bd9Sstevel@tonic-gate 	}
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	/* Release the signature and the deserialized token. */
573*7c478bd9Sstevel@tonic-gate 	__free_signature(&sig);
574*7c478bd9Sstevel@tonic-gate 	xdr_free(xdr_dh_token_desc, (char *)&token);
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	return (stat);
577*7c478bd9Sstevel@tonic-gate }
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate /*
581*7c478bd9Sstevel@tonic-gate  * gen_init_token: create a token to pass to the other side
582*7c478bd9Sstevel@tonic-gate  * to create a GSS context.
583*7c478bd9Sstevel@tonic-gate  */
584*7c478bd9Sstevel@tonic-gate static
585*7c478bd9Sstevel@tonic-gate OM_uint32
gen_init_token(dh_gss_context_t cntx,dh_context_t dhctx,gss_channel_bindings_t channel,gss_buffer_t result)586*7c478bd9Sstevel@tonic-gate gen_init_token(dh_gss_context_t cntx, /* Diffie-Hellman GSS context */
587*7c478bd9Sstevel@tonic-gate 	    dh_context_t dhctx,    /* Diffie-Hellman mechanism context */
588*7c478bd9Sstevel@tonic-gate 	    gss_channel_bindings_t channel, /* local channel bindings */
589*7c478bd9Sstevel@tonic-gate 	    gss_buffer_t result /* The serialized token to send */)
590*7c478bd9Sstevel@tonic-gate {
591*7c478bd9Sstevel@tonic-gate 	dh_token_desc token;	/* Unserialed token */
592*7c478bd9Sstevel@tonic-gate 	dh_init_context_t remote;  /* init_context in token */
593*7c478bd9Sstevel@tonic-gate 	dh_key_set keys, ukeys;	/* encrypted and unencrypted keys */
594*7c478bd9Sstevel@tonic-gate 	int i, stat;
595*7c478bd9Sstevel@tonic-gate 	dh_channel_binding_desc dh_binding;
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 	/* Create key_set for session keys */
598*7c478bd9Sstevel@tonic-gate 	if ((keys.dh_key_set_val = New(des_block, cntx->no_keys)) == NULL)
599*7c478bd9Sstevel@tonic-gate 		return (DH_NOMEM_FAILURE);
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 	keys.dh_key_set_len = cntx->no_keys;
602*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < cntx->no_keys; i++)
603*7c478bd9Sstevel@tonic-gate 		keys.dh_key_set_val[i] = cntx->keys[i];
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 	/* Initialize token from GSS context */
606*7c478bd9Sstevel@tonic-gate 	memset(&token, 0, sizeof (token));
607*7c478bd9Sstevel@tonic-gate 	token.ver.verno = cntx->proto_version;
608*7c478bd9Sstevel@tonic-gate 	token.ver.dh_version_u.body.type = DH_INIT_CNTX;
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	/* Set remote to init_context part of token */
611*7c478bd9Sstevel@tonic-gate 	remote = &token.ver.dh_version_u.body.dh_token_body_desc_u.init_context;
612*7c478bd9Sstevel@tonic-gate 	/* We're the remote to the other side */
613*7c478bd9Sstevel@tonic-gate 	remote->cntx.remote = cntx->local;
614*7c478bd9Sstevel@tonic-gate 	/* And they are the local */
615*7c478bd9Sstevel@tonic-gate 	remote->cntx.local = cntx->remote;
616*7c478bd9Sstevel@tonic-gate 	/* Set our flags */
617*7c478bd9Sstevel@tonic-gate 	remote->cntx.flags = cntx->flags;
618*7c478bd9Sstevel@tonic-gate 	/* Set the expire time */
619*7c478bd9Sstevel@tonic-gate 	remote->cntx.expire = cntx->expire;
620*7c478bd9Sstevel@tonic-gate 	/* hand of our channel bindings */
621*7c478bd9Sstevel@tonic-gate 	remote->cntx.channel = GSS2DH_channel_binding(&dh_binding, channel);
622*7c478bd9Sstevel@tonic-gate 	/* set the tokens keys */
623*7c478bd9Sstevel@tonic-gate 	remote->keys = keys;
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	/* Encrypt the keys for the other side */
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate 	if (dhctx->keyopts->key_encryptsessions(cntx->remote,
629*7c478bd9Sstevel@tonic-gate 						keys.dh_key_set_val,
630*7c478bd9Sstevel@tonic-gate 						cntx->no_keys)) {
631*7c478bd9Sstevel@tonic-gate 		Free(keys.dh_key_set_val);
632*7c478bd9Sstevel@tonic-gate 		return (DH_SESSION_CIPHER_FAILURE);
633*7c478bd9Sstevel@tonic-gate 	}
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 	/* Package up our session keys */
636*7c478bd9Sstevel@tonic-gate 	ukeys.dh_key_set_len = cntx->no_keys;
637*7c478bd9Sstevel@tonic-gate 	ukeys.dh_key_set_val = cntx->keys;
638*7c478bd9Sstevel@tonic-gate 	/*
639*7c478bd9Sstevel@tonic-gate 	 * Make an APPLICATION 0 token and place it in result.
640*7c478bd9Sstevel@tonic-gate 	 * Note that the unecrypted ukeys key_set is used to sign
641*7c478bd9Sstevel@tonic-gate 	 * the token.
642*7c478bd9Sstevel@tonic-gate 	 */
643*7c478bd9Sstevel@tonic-gate 	stat =  __make_ap_token(result, dhctx->mech, &token, &ukeys);
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 	/* We're don with the encrypted session keys */
646*7c478bd9Sstevel@tonic-gate 	Free(keys.dh_key_set_val);
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate 	/* Return our status */
649*7c478bd9Sstevel@tonic-gate 	return (stat);
650*7c478bd9Sstevel@tonic-gate }
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate /*
653*7c478bd9Sstevel@tonic-gate  * create_context: Builds the initial Diffie-Hellman GSS context.
654*7c478bd9Sstevel@tonic-gate  * It should always be the case that *gss_ctx == GSS_C_NO_CONTEXT
655*7c478bd9Sstevel@tonic-gate  * on entering this routine. Given the inputs we created a Diffie-Hellman
656*7c478bd9Sstevel@tonic-gate  * context from them. This routine will call gen_init_token above to
657*7c478bd9Sstevel@tonic-gate  * generate the output token to pass to the other side.
658*7c478bd9Sstevel@tonic-gate  */
659*7c478bd9Sstevel@tonic-gate static
660*7c478bd9Sstevel@tonic-gate OM_uint32
create_context(OM_uint32 * minor,dh_context_t cntx,dh_gss_context_t * gss_ctx,dh_principal netname,dh_principal target,gss_channel_bindings_t channel,OM_uint32 flags_req,OM_uint32 time_req,OM_uint32 * flags_rec,OM_uint32 * time_rec,gss_buffer_t results)661*7c478bd9Sstevel@tonic-gate create_context(OM_uint32 *minor, /* Diffie-Hellman specific status */
662*7c478bd9Sstevel@tonic-gate 	    dh_context_t cntx, /* Diffie-Hellman mech context */
663*7c478bd9Sstevel@tonic-gate 	    dh_gss_context_t *gss_ctx, /* DH GSS context */
664*7c478bd9Sstevel@tonic-gate 	    dh_principal netname, /* Local principal */
665*7c478bd9Sstevel@tonic-gate 	    dh_principal target, /* Remote principal */
666*7c478bd9Sstevel@tonic-gate 	    gss_channel_bindings_t channel, /* Channel bindings */
667*7c478bd9Sstevel@tonic-gate 	    OM_uint32 flags_req, /* Flags to set on context */
668*7c478bd9Sstevel@tonic-gate 	    OM_uint32 time_req, /* Time to live for context */
669*7c478bd9Sstevel@tonic-gate 	    OM_uint32 *flags_rec, /* Flags that were actually set */
670*7c478bd9Sstevel@tonic-gate 	    OM_uint32 *time_rec, /* Time actually received */
671*7c478bd9Sstevel@tonic-gate 	    gss_buffer_t results /* Output token for the other side */)
672*7c478bd9Sstevel@tonic-gate {
673*7c478bd9Sstevel@tonic-gate 	dh_gss_context_t dh_gss_ctx; /* The Diffie-Hellman context to create */
674*7c478bd9Sstevel@tonic-gate 	time_t now = time(0);	/* Used to set the expire time */
675*7c478bd9Sstevel@tonic-gate 	OM_uint32 expire;	/* Time left on the context */
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	/* Create the Diffie-Hellman context */
678*7c478bd9Sstevel@tonic-gate 	if ((*gss_ctx = dh_gss_ctx = New(dh_gss_context_desc, 1)) == NULL) {
679*7c478bd9Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
680*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
681*7c478bd9Sstevel@tonic-gate 	}
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	/* We're not established yet */
684*7c478bd9Sstevel@tonic-gate 	dh_gss_ctx->state = INCOMPLETE;
685*7c478bd9Sstevel@tonic-gate 	/* We're the initiator */
686*7c478bd9Sstevel@tonic-gate 	dh_gss_ctx->initiate = 1;
687*7c478bd9Sstevel@tonic-gate 	/* Set the protocol version for the context */
688*7c478bd9Sstevel@tonic-gate 	dh_gss_ctx->proto_version = DH_PROTO_VERSION;
689*7c478bd9Sstevel@tonic-gate 	/* Initialize the sequence and replay history */
690*7c478bd9Sstevel@tonic-gate 	__dh_init_seq_hist(dh_gss_ctx);
691*7c478bd9Sstevel@tonic-gate 	/* Turn off debugging */
692*7c478bd9Sstevel@tonic-gate 	dh_gss_ctx->debug = 0;
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	dh_gss_ctx->local = NULL;
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 	/* Remember who we want to talk to. */
697*7c478bd9Sstevel@tonic-gate 	if ((dh_gss_ctx->remote = strdup(target)) == NULL) {
698*7c478bd9Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
699*7c478bd9Sstevel@tonic-gate 		goto cleanup;
700*7c478bd9Sstevel@tonic-gate 	}
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate 	/* Rember who we are. */
703*7c478bd9Sstevel@tonic-gate 	if ((dh_gss_ctx->local = strdup(netname)) == NULL) {
704*7c478bd9Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
705*7c478bd9Sstevel@tonic-gate 		goto cleanup;
706*7c478bd9Sstevel@tonic-gate 	}
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	/* Set up the session key */
709*7c478bd9Sstevel@tonic-gate 	dh_gss_ctx->no_keys = 3;
710*7c478bd9Sstevel@tonic-gate 	dh_gss_ctx->keys = New(des_block, 3);
711*7c478bd9Sstevel@tonic-gate 	if (dh_gss_ctx->keys == NULL) {
712*7c478bd9Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
713*7c478bd9Sstevel@tonic-gate 		goto cleanup;
714*7c478bd9Sstevel@tonic-gate 	}
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	/* Call the mechanism specific key generator */
717*7c478bd9Sstevel@tonic-gate 	if (cntx->keyopts->key_gendeskeys(dh_gss_ctx->keys, 3)) {
718*7c478bd9Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
719*7c478bd9Sstevel@tonic-gate 		goto cleanup;
720*7c478bd9Sstevel@tonic-gate 	}
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate #ifdef DH_DEBUG
723*7c478bd9Sstevel@tonic-gate 	{
724*7c478bd9Sstevel@tonic-gate 		int i;
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "Generated session keys:\n");
727*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < dh_gss_ctx->no_keys; i++)
728*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%08.8x%08.8x ",
729*7c478bd9Sstevel@tonic-gate 				dh_gss_ctx->keys[i].key.high,
730*7c478bd9Sstevel@tonic-gate 				dh_gss_ctx->keys[i].key.low);
731*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "\n");
732*7c478bd9Sstevel@tonic-gate 	}
733*7c478bd9Sstevel@tonic-gate #endif
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 	/*
736*7c478bd9Sstevel@tonic-gate 	 *  We don't support currently support
737*7c478bd9Sstevel@tonic-gate 	 *  GSS_C_ANON_FLAG and GSS_C_DELEG_FLAG and GSS_C_CONF_FLAG
738*7c478bd9Sstevel@tonic-gate 	 */
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	dh_gss_ctx->flags = (flags_req &
741*7c478bd9Sstevel@tonic-gate 	    (GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG |
742*7c478bd9Sstevel@tonic-gate 		    GSS_C_SEQUENCE_FLAG | GSS_C_REPLAY_FLAG));
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 	/* This mechanism does integrity */
745*7c478bd9Sstevel@tonic-gate 	dh_gss_ctx->flags |=  GSS_C_INTEG_FLAG;
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate 	/* Return flags to the caller if they care */
748*7c478bd9Sstevel@tonic-gate 	if (flags_rec)
749*7c478bd9Sstevel@tonic-gate 		*flags_rec = dh_gss_ctx->flags;
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate 	/* Set expire, 0 is the default, which means indefinite */
752*7c478bd9Sstevel@tonic-gate 	expire = time_req ? time_req : GSS_C_INDEFINITE;
753*7c478bd9Sstevel@tonic-gate 	/* Actually set the expire time for the context */
754*7c478bd9Sstevel@tonic-gate 	dh_gss_ctx->expire = expire == GSS_C_INDEFINITE ?
755*7c478bd9Sstevel@tonic-gate 		expire : expire + now;
756*7c478bd9Sstevel@tonic-gate 	/* Tell the call the time given to the context if they care */
757*7c478bd9Sstevel@tonic-gate 	if (time_rec)
758*7c478bd9Sstevel@tonic-gate 		*time_rec = expire;
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 	/* Gennerate the output token to send to the other side */
761*7c478bd9Sstevel@tonic-gate 	*minor = gen_init_token(dh_gss_ctx, cntx,
762*7c478bd9Sstevel@tonic-gate 				channel, results);
763*7c478bd9Sstevel@tonic-gate 	if (*minor != DH_SUCCESS)
764*7c478bd9Sstevel@tonic-gate 		goto cleanup;
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate 	/* Recored this context as valid */
767*7c478bd9Sstevel@tonic-gate 	if ((*minor = __dh_install_context(dh_gss_ctx)) != DH_SUCCESS)
768*7c478bd9Sstevel@tonic-gate 		goto cleanup;
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 	/* If we ask for mutal authentication return continue needed */
771*7c478bd9Sstevel@tonic-gate 	dh_gss_ctx->state = dh_gss_ctx->flags & GSS_C_MUTUAL_FLAG ?
772*7c478bd9Sstevel@tonic-gate 		INCOMPLETE : ESTABLISHED;
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 	return (dh_gss_ctx->state == ESTABLISHED ?
775*7c478bd9Sstevel@tonic-gate 		GSS_S_COMPLETE : GSS_S_CONTINUE_NEEDED);
776*7c478bd9Sstevel@tonic-gate cleanup:
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 	__dh_destroy_seq_hist(dh_gss_ctx);
779*7c478bd9Sstevel@tonic-gate 	free(dh_gss_ctx->remote);
780*7c478bd9Sstevel@tonic-gate 	free(dh_gss_ctx->local);
781*7c478bd9Sstevel@tonic-gate 	Free(dh_gss_ctx->keys);
782*7c478bd9Sstevel@tonic-gate 	Free(dh_gss_ctx);
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 	/*
785*7c478bd9Sstevel@tonic-gate 	 * Let the caller of gss_init_sec_context know that they don't
786*7c478bd9Sstevel@tonic-gate 	 * have a context.
787*7c478bd9Sstevel@tonic-gate 	 */
788*7c478bd9Sstevel@tonic-gate 	*gss_ctx = (dh_gss_context_t)GSS_C_NO_CONTEXT;
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 	return (GSS_S_FAILURE);
791*7c478bd9Sstevel@tonic-gate }
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate /*
794*7c478bd9Sstevel@tonic-gate  * continue_context: Proccess the token from the otherside in the case
795*7c478bd9Sstevel@tonic-gate  * of mutual authentication.
796*7c478bd9Sstevel@tonic-gate  */
797*7c478bd9Sstevel@tonic-gate static
798*7c478bd9Sstevel@tonic-gate OM_uint32
continue_context(OM_uint32 * minor,gss_buffer_t token,dh_gss_context_t dh_gss_ctx,gss_channel_bindings_t channel)799*7c478bd9Sstevel@tonic-gate continue_context(OM_uint32 *minor, gss_buffer_t token,
800*7c478bd9Sstevel@tonic-gate     dh_gss_context_t dh_gss_ctx, gss_channel_bindings_t channel)
801*7c478bd9Sstevel@tonic-gate {
802*7c478bd9Sstevel@tonic-gate 	dh_key_set keys;
803*7c478bd9Sstevel@tonic-gate 	dh_token_desc tok;
804*7c478bd9Sstevel@tonic-gate 	dh_cntx_t remote_ctx;
805*7c478bd9Sstevel@tonic-gate 	struct gss_channel_bindings_struct remote_chan_desc;
806*7c478bd9Sstevel@tonic-gate 	gss_channel_bindings_t remote_chan;
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 	/* Set minor to sane state */
809*7c478bd9Sstevel@tonic-gate 	*minor = DH_SUCCESS;
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate 	/* This should never happen */
812*7c478bd9Sstevel@tonic-gate 	if (token == NULL || token->length == 0)
813*7c478bd9Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate 	/* Package the session keys for __get_token) */
816*7c478bd9Sstevel@tonic-gate 	keys.dh_key_set_len = dh_gss_ctx->no_keys;
817*7c478bd9Sstevel@tonic-gate 	keys.dh_key_set_val = dh_gss_ctx->keys;
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 	/* Deserialize the input token into tok using the session keys */
820*7c478bd9Sstevel@tonic-gate 	if (*minor = __get_token(token, NULL, &tok, &keys))
821*7c478bd9Sstevel@tonic-gate 		return (*minor == DH_VERIFIER_MISMATCH ?
822*7c478bd9Sstevel@tonic-gate 			GSS_S_BAD_SIG : GSS_S_DEFECTIVE_TOKEN);
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 	/*
825*7c478bd9Sstevel@tonic-gate 	 * See if this is a Diffie-Hellman protocol version that we
826*7c478bd9Sstevel@tonic-gate 	 * can handle. Currently we can only handle the protocol version that
827*7c478bd9Sstevel@tonic-gate 	 * we initiated.
828*7c478bd9Sstevel@tonic-gate 	 */
829*7c478bd9Sstevel@tonic-gate 	if (tok.ver.verno != dh_gss_ctx->proto_version) {
830*7c478bd9Sstevel@tonic-gate 		*minor = DH_PROTO_MISMATCH;
831*7c478bd9Sstevel@tonic-gate 		xdr_free(xdr_dh_token_desc, (char *)&tok);
832*7c478bd9Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
833*7c478bd9Sstevel@tonic-gate 	}
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 	/* Make sure this is the right type of token */
836*7c478bd9Sstevel@tonic-gate 	if (tok.ver.dh_version_u.body.type != DH_ACCEPT_CNTX) {
837*7c478bd9Sstevel@tonic-gate 		xdr_free(xdr_dh_token_desc, (char *)&tok);
838*7c478bd9Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
839*7c478bd9Sstevel@tonic-gate 	}
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate 	/* Grab a pointer to the context part of the token */
842*7c478bd9Sstevel@tonic-gate 	remote_ctx = &tok.ver.dh_version_u.
843*7c478bd9Sstevel@tonic-gate 			body.dh_token_body_desc_u.accept_context.cntx;
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 	/* Make sure this is from the remote and for us */
846*7c478bd9Sstevel@tonic-gate 	if (strcmp(remote_ctx->remote, dh_gss_ctx->remote) ||
847*7c478bd9Sstevel@tonic-gate 	    strcmp(remote_ctx->local, dh_gss_ctx->local)) {
848*7c478bd9Sstevel@tonic-gate 		xdr_free(xdr_dh_token_desc, (char *)&tok);
849*7c478bd9Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
850*7c478bd9Sstevel@tonic-gate 	}
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate 	/* Make sure if the optional channel_bindings are the same */
853*7c478bd9Sstevel@tonic-gate 	remote_chan = DH2GSS_channel_binding(&remote_chan_desc,
854*7c478bd9Sstevel@tonic-gate 					    remote_ctx->channel);
855*7c478bd9Sstevel@tonic-gate 	if (!gss_chanbind_cmp(channel, remote_chan)) {
856*7c478bd9Sstevel@tonic-gate 		xdr_free(xdr_dh_token_desc, (char *)&tok);
857*7c478bd9Sstevel@tonic-gate 		return (GSS_S_BAD_BINDINGS);
858*7c478bd9Sstevel@tonic-gate 	}
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 	/* Update the context flags with what the remote will accept */
861*7c478bd9Sstevel@tonic-gate 	dh_gss_ctx->flags = remote_ctx->flags;
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 	/* We now have an established context */
864*7c478bd9Sstevel@tonic-gate 	dh_gss_ctx->state = ESTABLISHED;
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	/* Release the deserialized token, tok */
867*7c478bd9Sstevel@tonic-gate 	xdr_free(xdr_dh_token_desc, (char *)&tok);
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
870*7c478bd9Sstevel@tonic-gate }
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate /*
873*7c478bd9Sstevel@tonic-gate  * This is the Diffie-Hellman mechanism entry point for the
874*7c478bd9Sstevel@tonic-gate  * gss_int_sec context. See RFC 2078 for details. This
875*7c478bd9Sstevel@tonic-gate  * routine creates a new context or continues a previously created
876*7c478bd9Sstevel@tonic-gate  * context if mutual authentication had been requested on the orignal
877*7c478bd9Sstevel@tonic-gate  * context. The first call to this routine should set *context to
878*7c478bd9Sstevel@tonic-gate  * GSS_C_NO_CONTEXT and input_token to GSS_C_NO_BUFFER or input_token->length
879*7c478bd9Sstevel@tonic-gate  * to zero. To continue a context in the case of mutual authentication
880*7c478bd9Sstevel@tonic-gate  * gss_ctx should point to the initial context and input_token should point
881*7c478bd9Sstevel@tonic-gate  * to the token received from the remote. The established context will
882*7c478bd9Sstevel@tonic-gate  * be return via the *context paramater in all cases.
883*7c478bd9Sstevel@tonic-gate  */
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate OM_uint32
__dh_gss_init_sec_context(void * ctx,OM_uint32 * minor,gss_cred_id_t cred,gss_ctx_id_t * context,gss_name_t target,gss_OID mech,OM_uint32 req_flags,OM_uint32 time_req,gss_channel_bindings_t channel,gss_buffer_t input_token,gss_OID * mech_rec,gss_buffer_t output_token,OM_uint32 * flags_rec,OM_uint32 * time_rec)887*7c478bd9Sstevel@tonic-gate __dh_gss_init_sec_context(void *ctx, /* Per Mechananism context */
888*7c478bd9Sstevel@tonic-gate 			OM_uint32 *minor, /* Mech status */
889*7c478bd9Sstevel@tonic-gate 			gss_cred_id_t cred, /* Local credentials */
890*7c478bd9Sstevel@tonic-gate 			gss_ctx_id_t *context, /* The context to create */
891*7c478bd9Sstevel@tonic-gate 			gss_name_t target, /* The server to talk to */
892*7c478bd9Sstevel@tonic-gate 			gss_OID mech, /* The mechanism to use */
893*7c478bd9Sstevel@tonic-gate 			OM_uint32 req_flags, /* Requested context flags */
894*7c478bd9Sstevel@tonic-gate 			OM_uint32 time_req, /* Requested life time */
895*7c478bd9Sstevel@tonic-gate 			gss_channel_bindings_t channel, /* Local bindings */
896*7c478bd9Sstevel@tonic-gate 			gss_buffer_t input_token, /* Token from remote */
897*7c478bd9Sstevel@tonic-gate 			gss_OID *mech_rec, /* Optional mech to return */
898*7c478bd9Sstevel@tonic-gate 			gss_buffer_t output_token, /* Token for remote */
899*7c478bd9Sstevel@tonic-gate 			OM_uint32 *flags_rec, /* Actual flags received */
900*7c478bd9Sstevel@tonic-gate 			OM_uint32 *time_rec /* Actual life time received */)
901*7c478bd9Sstevel@tonic-gate {
902*7c478bd9Sstevel@tonic-gate 	dh_context_t cntx = (dh_context_t)ctx;
903*7c478bd9Sstevel@tonic-gate 	dh_gss_context_t dh_gss_ctx = (dh_gss_context_t)*context;
904*7c478bd9Sstevel@tonic-gate 	dh_principal netname;
905*7c478bd9Sstevel@tonic-gate 	dh_cred_id_t dh_cred = (dh_cred_id_t)cred;
906*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat;
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 	/* We need these */
909*7c478bd9Sstevel@tonic-gate 	if (minor == 0 || output_token == 0)
910*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 	/* Set to sane state */
913*7c478bd9Sstevel@tonic-gate 	*minor = DH_SUCCESS;
914*7c478bd9Sstevel@tonic-gate 	output_token->length = 0;
915*7c478bd9Sstevel@tonic-gate 	output_token->value = NULL;
916*7c478bd9Sstevel@tonic-gate 	if (mech_rec)
917*7c478bd9Sstevel@tonic-gate 		*mech_rec = cntx->mech;   /* Note this should not be duped. */
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate 	/* Check that were the right mechanism */
920*7c478bd9Sstevel@tonic-gate 	if ((mech != GSS_C_NULL_OID) &&
921*7c478bd9Sstevel@tonic-gate 	    (!__OID_equal(mech, cntx->mech))) {
922*7c478bd9Sstevel@tonic-gate 		return (GSS_S_BAD_MECH);
923*7c478bd9Sstevel@tonic-gate 	}
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 	/* Validate the cred and obtain our netname in the process. */
926*7c478bd9Sstevel@tonic-gate 	stat = validate_cred(cntx, minor, dh_cred, GSS_C_INITIATE, &netname);
927*7c478bd9Sstevel@tonic-gate 	if (stat != GSS_S_COMPLETE)
928*7c478bd9Sstevel@tonic-gate 		return (stat);
929*7c478bd9Sstevel@tonic-gate 
930*7c478bd9Sstevel@tonic-gate 	/* validate target name */
931*7c478bd9Sstevel@tonic-gate 	/*
932*7c478bd9Sstevel@tonic-gate 	 * we could check that the target is in the proper form and
933*7c478bd9Sstevel@tonic-gate 	 * possibly do a lookup up on the host part.
934*7c478bd9Sstevel@tonic-gate 	 */
935*7c478bd9Sstevel@tonic-gate 
936*7c478bd9Sstevel@tonic-gate 	/* checks for new context */
937*7c478bd9Sstevel@tonic-gate 	if (dh_gss_ctx == (dh_gss_context_t)GSS_C_NO_CONTEXT) {
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 		if (input_token != GSS_C_NO_BUFFER &&
940*7c478bd9Sstevel@tonic-gate 			input_token->length != 0)
941*7c478bd9Sstevel@tonic-gate 			return (GSS_S_DEFECTIVE_TOKEN);
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate 		/* Create a new context */
944*7c478bd9Sstevel@tonic-gate 		stat =  create_context(minor, cntx, &dh_gss_ctx, netname,
945*7c478bd9Sstevel@tonic-gate 				    (dh_principal)target, channel, req_flags,
946*7c478bd9Sstevel@tonic-gate 				    time_req, flags_rec, time_rec,
947*7c478bd9Sstevel@tonic-gate 				    output_token);
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 		/* Set the GSS context to the Diffie-Hellman context */
950*7c478bd9Sstevel@tonic-gate 		*context = (gss_ctx_id_t)dh_gss_ctx;
951*7c478bd9Sstevel@tonic-gate 
952*7c478bd9Sstevel@tonic-gate 	} else {
953*7c478bd9Sstevel@tonic-gate 
954*7c478bd9Sstevel@tonic-gate 		/* Validate the context */
955*7c478bd9Sstevel@tonic-gate 		if ((*minor = __dh_validate_context(dh_gss_ctx)) != DH_SUCCESS)
956*7c478bd9Sstevel@tonic-gate 			return (GSS_S_NO_CONTEXT);
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 		/* Authenticate the server */
959*7c478bd9Sstevel@tonic-gate 		stat = continue_context(minor,
960*7c478bd9Sstevel@tonic-gate 					input_token, dh_gss_ctx, channel);
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate 	}
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 	free(netname);
965*7c478bd9Sstevel@tonic-gate 	return (stat);
966*7c478bd9Sstevel@tonic-gate }
967