Home | History | Annotate | Download | only in mech
      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