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
__dh_gss_context_time(void * ctx,OM_uint32 * minor,gss_ctx_id_t context,OM_uint32 * time_remaining)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
__dh_gss_delete_sec_context(void * ctx,OM_uint32 * minor,gss_ctx_id_t * context,gss_buffer_t token)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*/
__dh_gss_export_sec_context(void * ctx,OM_uint32 * minor,gss_ctx_id_t * context,gss_buffer_t token)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*/
__dh_gss_import_sec_context(void * ctx,OM_uint32 * minor,gss_buffer_t token,gss_ctx_id_t * context)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
__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 __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*/
__dh_gss_process_context_token(void * ctx,OM_uint32 * minor,gss_ctx_id_t context,gss_buffer_t token)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
__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 __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