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