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