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