1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 /* -*- mode: c; indent-tabs-mode: nil -*- */ 6 /* 7 * lib/gssapi/krb5/lucid_context.c 8 * 9 * Copyright 2004, 2008 by the Massachusetts Institute of Technology. 10 * All Rights Reserved. 11 * 12 * Export of this software from the United States of America may 13 * require a specific license from the United States Government. 14 * It is the responsibility of any person or organization contemplating 15 * export to obtain such a license before exporting. 16 * 17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 18 * distribute this software and its documentation for any purpose and 19 * without fee is hereby granted, provided that the above copyright 20 * notice appear in all copies and that both that copyright notice and 21 * this permission notice appear in supporting documentation, and that 22 * the name of M.I.T. not be used in advertising or publicity pertaining 23 * to distribution of the software without specific, written prior 24 * permission. Furthermore if you modify this software you must label 25 * your software as modified software and not distribute it in such a 26 * fashion that it might be confused with the original M.I.T. software. 27 * M.I.T. makes no representations about the suitability of 28 * this software for any purpose. It is provided "as is" without express 29 * or implied warranty. 30 * 31 */ 32 33 /* 34 * lucid_context.c - Externalize a "lucid" security 35 * context from a krb5_gss_ctx_id_rec structure. 36 */ 37 #include "gssapiP_krb5.h" 38 #include "gssapi_krb5.h" 39 #include "mechglueP.h" /* SUNW17PACresync */ 40 41 /* 42 * Local routine prototypes 43 */ 44 static void 45 free_external_lucid_ctx_v1( 46 gss_krb5_lucid_context_v1_t *ctx); 47 48 static void 49 free_lucid_key_data( 50 gss_krb5_lucid_key_t *key); 51 52 static krb5_error_code 53 copy_keyblock_to_lucid_key( 54 krb5_keyblock *k5key, 55 gss_krb5_lucid_key_t *lkey); 56 57 static krb5_error_code 58 make_external_lucid_ctx_v1( 59 krb5_gss_ctx_id_rec * gctx, 60 int version, 61 void **out_ptr); 62 63 64 /* 65 * Exported routines 66 */ 67 68 OM_uint32 KRB5_CALLCONV 69 gss_krb5int_export_lucid_sec_context( 70 OM_uint32 *minor_status, 71 gss_ctx_id_t context_handle, 72 const gss_OID desired_object, 73 gss_buffer_set_t *data_set) 74 { 75 krb5_error_code kret = 0; 76 OM_uint32 retval; 77 krb5_gss_ctx_id_t ctx = (krb5_gss_ctx_id_t)context_handle; 78 void *lctx = NULL; 79 int version = 0; 80 gss_buffer_desc rep; 81 82 /* Assume failure */ 83 retval = GSS_S_FAILURE; 84 *minor_status = 0; 85 *data_set = GSS_C_NO_BUFFER_SET; 86 87 retval = generic_gss_oid_decompose(minor_status, 88 GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID, 89 GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH, 90 desired_object, 91 &version); 92 if (GSS_ERROR(retval)) 93 return retval; 94 95 /* Externalize a structure of the right version */ 96 switch (version) { 97 case 1: 98 kret = make_external_lucid_ctx_v1((krb5_pointer)ctx, 99 version, &lctx); 100 break; 101 default: 102 kret = (OM_uint32) KG_LUCID_VERSION; 103 break; 104 } 105 106 if (kret) 107 goto error_out; 108 109 /* Success! Record the context and return the buffer */ 110 if (! kg_save_lucidctx_id((void *)lctx)) { 111 kret = G_VALIDATE_FAILED; 112 goto error_out; 113 } 114 115 rep.value = &lctx; 116 rep.length = sizeof(lctx); 117 118 retval = generic_gss_add_buffer_set_member(minor_status, &rep, data_set); 119 if (GSS_ERROR(retval)) 120 goto error_out; 121 122 error_out: 123 if (*minor_status == 0) 124 *minor_status = (OM_uint32) kret; 125 return(retval); 126 } 127 128 /* 129 * Frees the storage associated with an 130 * exported lucid context structure. 131 */ 132 OM_uint32 133 gss_krb5int_free_lucid_sec_context( 134 OM_uint32 *minor_status, 135 const gss_OID desired_mech, 136 const gss_OID desired_object, 137 gss_buffer_t value) 138 { 139 OM_uint32 retval; 140 krb5_error_code kret = 0; 141 int version; 142 void *kctx; 143 144 /* Assume failure */ 145 retval = GSS_S_FAILURE; 146 *minor_status = 0; 147 148 kctx = value->value; 149 if (!kctx) { 150 kret = EINVAL; 151 goto error_out; 152 } 153 154 /* Verify pointer is valid lucid context */ 155 if (! kg_validate_lucidctx_id(kctx)) { 156 kret = G_VALIDATE_FAILED; 157 goto error_out; 158 } 159 160 /* Determine version and call correct free routine */ 161 version = ((gss_krb5_lucid_context_version_t *)kctx)->version; 162 switch (version) { 163 case 1: 164 (void)kg_delete_lucidctx_id(kctx); 165 free_external_lucid_ctx_v1((gss_krb5_lucid_context_v1_t*) kctx); 166 break; 167 default: 168 kret = EINVAL; 169 break; 170 } 171 172 if (kret) 173 goto error_out; 174 175 /* Success! */ 176 *minor_status = 0; 177 retval = GSS_S_COMPLETE; 178 179 return (retval); 180 181 error_out: 182 if (*minor_status == 0) 183 *minor_status = (OM_uint32) kret; 184 return(retval); 185 } 186 187 /* 188 * Local routines 189 */ 190 191 static krb5_error_code 192 make_external_lucid_ctx_v1( 193 krb5_gss_ctx_id_rec * gctx, 194 int version, 195 void **out_ptr) 196 { 197 gss_krb5_lucid_context_v1_t *lctx = NULL; 198 unsigned int bufsize = sizeof(gss_krb5_lucid_context_v1_t); 199 krb5_error_code retval; 200 201 /* Allocate the structure */ 202 if ((lctx = xmalloc(bufsize)) == NULL) { 203 retval = ENOMEM; 204 goto error_out; 205 } 206 207 memset(lctx, 0, bufsize); 208 209 lctx->version = 1; 210 lctx->initiate = gctx->initiate ? 1 : 0; 211 lctx->endtime = gctx->krb_times.endtime; 212 lctx->send_seq = gctx->seq_send; 213 lctx->recv_seq = gctx->seq_recv; 214 lctx->protocol = gctx->proto; 215 /* gctx->proto == 0 ==> rfc1964-style key information 216 gctx->proto == 1 ==> cfx-style (draft-ietf-krb-wg-gssapi-cfx-07) keys */ 217 if (gctx->proto == 0) { 218 lctx->rfc1964_kd.sign_alg = gctx->signalg; 219 lctx->rfc1964_kd.seal_alg = gctx->sealalg; 220 /* Copy key */ 221 if ((retval = copy_keyblock_to_lucid_key(gctx->seq, 222 &lctx->rfc1964_kd.ctx_key))) 223 goto error_out; 224 } 225 else if (gctx->proto == 1) { 226 /* Copy keys */ 227 /* (subkey is always present, either a copy of the kerberos 228 session key or a subkey) */ 229 if ((retval = copy_keyblock_to_lucid_key(gctx->subkey, 230 &lctx->cfx_kd.ctx_key))) 231 goto error_out; 232 if (gctx->have_acceptor_subkey) { 233 if ((retval = copy_keyblock_to_lucid_key(gctx->acceptor_subkey, 234 &lctx->cfx_kd.acceptor_subkey))) 235 goto error_out; 236 lctx->cfx_kd.have_acceptor_subkey = 1; 237 } 238 } 239 else { 240 return EINVAL; /* XXX better error code? */ 241 } 242 243 /* Success! */ 244 *out_ptr = lctx; 245 return 0; 246 247 error_out: 248 if (lctx) { 249 free_external_lucid_ctx_v1(lctx); 250 } 251 return retval; 252 253 } 254 255 /* Copy the contents of a krb5_keyblock to a gss_krb5_lucid_key_t structure */ 256 static krb5_error_code 257 copy_keyblock_to_lucid_key( 258 krb5_keyblock *k5key, 259 gss_krb5_lucid_key_t *lkey) 260 { 261 if (!k5key || !k5key->contents || k5key->length == 0) 262 return EINVAL; 263 264 memset(lkey, 0, sizeof(gss_krb5_lucid_key_t)); 265 266 /* Allocate storage for the key data */ 267 if ((lkey->data = xmalloc(k5key->length)) == NULL) { 268 return ENOMEM; 269 } 270 memcpy(lkey->data, k5key->contents, k5key->length); 271 lkey->length = k5key->length; 272 lkey->type = k5key->enctype; 273 274 return 0; 275 } 276 277 278 /* Free any storage associated with a gss_krb5_lucid_key_t structure */ 279 static void 280 free_lucid_key_data( 281 gss_krb5_lucid_key_t *key) 282 { 283 if (key) { 284 if (key->data && key->length) { 285 memset(key->data, 0, key->length); 286 xfree(key->data); 287 memset(key, 0, sizeof(gss_krb5_lucid_key_t)); 288 } 289 } 290 } 291 /* Free any storage associated with a gss_krb5_lucid_context_v1 structure */ 292 static void 293 free_external_lucid_ctx_v1( 294 gss_krb5_lucid_context_v1_t *ctx) 295 { 296 if (ctx) { 297 if (ctx->protocol == 0) { 298 free_lucid_key_data(&ctx->rfc1964_kd.ctx_key); 299 } 300 if (ctx->protocol == 1) { 301 free_lucid_key_data(&ctx->cfx_kd.ctx_key); 302 if (ctx->cfx_kd.have_acceptor_subkey) 303 free_lucid_key_data(&ctx->cfx_kd.acceptor_subkey); 304 } 305 xfree(ctx); 306 ctx = NULL; 307 } 308 } 309