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