/* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* -*- mode: c; indent-tabs-mode: nil -*- */ /* * lib/gssapi/krb5/lucid_context.c * * Copyright 2004, 2008 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ /* * lucid_context.c - Externalize a "lucid" security * context from a krb5_gss_ctx_id_rec structure. */ #include "gssapiP_krb5.h" #include "gssapi_krb5.h" #include "mechglueP.h" /* SUNW17PACresync */ /* * Local routine prototypes */ static void free_external_lucid_ctx_v1( gss_krb5_lucid_context_v1_t *ctx); static void free_lucid_key_data( gss_krb5_lucid_key_t *key); static krb5_error_code copy_keyblock_to_lucid_key( krb5_keyblock *k5key, gss_krb5_lucid_key_t *lkey); static krb5_error_code make_external_lucid_ctx_v1( krb5_gss_ctx_id_rec * gctx, int version, void **out_ptr); /* * Exported routines */ OM_uint32 KRB5_CALLCONV gss_krb5int_export_lucid_sec_context( OM_uint32 *minor_status, gss_ctx_id_t context_handle, const gss_OID desired_object, gss_buffer_set_t *data_set) { krb5_error_code kret = 0; OM_uint32 retval; krb5_gss_ctx_id_t ctx = (krb5_gss_ctx_id_t)context_handle; void *lctx = NULL; int version = 0; gss_buffer_desc rep; /* Assume failure */ retval = GSS_S_FAILURE; *minor_status = 0; *data_set = GSS_C_NO_BUFFER_SET; retval = generic_gss_oid_decompose(minor_status, GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID, GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH, desired_object, &version); if (GSS_ERROR(retval)) return retval; /* Externalize a structure of the right version */ switch (version) { case 1: kret = make_external_lucid_ctx_v1((krb5_pointer)ctx, version, &lctx); break; default: kret = (OM_uint32) KG_LUCID_VERSION; break; } if (kret) goto error_out; /* Success! Record the context and return the buffer */ if (! kg_save_lucidctx_id((void *)lctx)) { kret = G_VALIDATE_FAILED; goto error_out; } rep.value = &lctx; rep.length = sizeof(lctx); retval = generic_gss_add_buffer_set_member(minor_status, &rep, data_set); if (GSS_ERROR(retval)) goto error_out; error_out: if (*minor_status == 0) *minor_status = (OM_uint32) kret; return(retval); } /* * Frees the storage associated with an * exported lucid context structure. */ OM_uint32 gss_krb5int_free_lucid_sec_context( OM_uint32 *minor_status, const gss_OID desired_mech, const gss_OID desired_object, gss_buffer_t value) { OM_uint32 retval; krb5_error_code kret = 0; int version; void *kctx; /* Assume failure */ retval = GSS_S_FAILURE; *minor_status = 0; kctx = value->value; if (!kctx) { kret = EINVAL; goto error_out; } /* Verify pointer is valid lucid context */ if (! kg_validate_lucidctx_id(kctx)) { kret = G_VALIDATE_FAILED; goto error_out; } /* Determine version and call correct free routine */ version = ((gss_krb5_lucid_context_version_t *)kctx)->version; switch (version) { case 1: (void)kg_delete_lucidctx_id(kctx); free_external_lucid_ctx_v1((gss_krb5_lucid_context_v1_t*) kctx); break; default: kret = EINVAL; break; } if (kret) goto error_out; /* Success! */ *minor_status = 0; retval = GSS_S_COMPLETE; return (retval); error_out: if (*minor_status == 0) *minor_status = (OM_uint32) kret; return(retval); } /* * Local routines */ static krb5_error_code make_external_lucid_ctx_v1( krb5_gss_ctx_id_rec * gctx, int version, void **out_ptr) { gss_krb5_lucid_context_v1_t *lctx = NULL; unsigned int bufsize = sizeof(gss_krb5_lucid_context_v1_t); krb5_error_code retval; /* Allocate the structure */ if ((lctx = xmalloc(bufsize)) == NULL) { retval = ENOMEM; goto error_out; } memset(lctx, 0, bufsize); lctx->version = 1; lctx->initiate = gctx->initiate ? 1 : 0; lctx->endtime = gctx->krb_times.endtime; lctx->send_seq = gctx->seq_send; lctx->recv_seq = gctx->seq_recv; lctx->protocol = gctx->proto; /* gctx->proto == 0 ==> rfc1964-style key information gctx->proto == 1 ==> cfx-style (draft-ietf-krb-wg-gssapi-cfx-07) keys */ if (gctx->proto == 0) { lctx->rfc1964_kd.sign_alg = gctx->signalg; lctx->rfc1964_kd.seal_alg = gctx->sealalg; /* Copy key */ if ((retval = copy_keyblock_to_lucid_key(gctx->seq, &lctx->rfc1964_kd.ctx_key))) goto error_out; } else if (gctx->proto == 1) { /* Copy keys */ /* (subkey is always present, either a copy of the kerberos session key or a subkey) */ if ((retval = copy_keyblock_to_lucid_key(gctx->subkey, &lctx->cfx_kd.ctx_key))) goto error_out; if (gctx->have_acceptor_subkey) { if ((retval = copy_keyblock_to_lucid_key(gctx->acceptor_subkey, &lctx->cfx_kd.acceptor_subkey))) goto error_out; lctx->cfx_kd.have_acceptor_subkey = 1; } } else { return EINVAL; /* XXX better error code? */ } /* Success! */ *out_ptr = lctx; return 0; error_out: if (lctx) { free_external_lucid_ctx_v1(lctx); } return retval; } /* Copy the contents of a krb5_keyblock to a gss_krb5_lucid_key_t structure */ static krb5_error_code copy_keyblock_to_lucid_key( krb5_keyblock *k5key, gss_krb5_lucid_key_t *lkey) { if (!k5key || !k5key->contents || k5key->length == 0) return EINVAL; memset(lkey, 0, sizeof(gss_krb5_lucid_key_t)); /* Allocate storage for the key data */ if ((lkey->data = xmalloc(k5key->length)) == NULL) { return ENOMEM; } memcpy(lkey->data, k5key->contents, k5key->length); lkey->length = k5key->length; lkey->type = k5key->enctype; return 0; } /* Free any storage associated with a gss_krb5_lucid_key_t structure */ static void free_lucid_key_data( gss_krb5_lucid_key_t *key) { if (key) { if (key->data && key->length) { memset(key->data, 0, key->length); xfree(key->data); memset(key, 0, sizeof(gss_krb5_lucid_key_t)); } } } /* Free any storage associated with a gss_krb5_lucid_context_v1 structure */ static void free_external_lucid_ctx_v1( gss_krb5_lucid_context_v1_t *ctx) { if (ctx) { if (ctx->protocol == 0) { free_lucid_key_data(&ctx->rfc1964_kd.ctx_key); } if (ctx->protocol == 1) { free_lucid_key_data(&ctx->cfx_kd.ctx_key); if (ctx->cfx_kd.have_acceptor_subkey) free_lucid_key_data(&ctx->cfx_kd.acceptor_subkey); } xfree(ctx); ctx = NULL; } }