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