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
gss_krb5int_export_lucid_sec_context(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_OID desired_object,gss_buffer_set_t * data_set)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 if (ctx->terminated || !ctx->established) {
79 *minor_status = KG_CTX_INCOMPLETE;
80 return GSS_S_NO_CONTEXT;
81 }
82
83 retval = generic_gss_oid_decompose(minor_status,
84 GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID,
85 GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH,
86 desired_object,
87 &version);
88 if (GSS_ERROR(retval))
89 return retval;
90
91 /* Externalize a structure of the right version */
92 switch (version) {
93 case 1:
94 kret = make_external_lucid_ctx_v1((krb5_pointer)ctx,
95 version, &lctx);
96 break;
97 default:
98 kret = (OM_uint32) KG_LUCID_VERSION;
99 break;
100 }
101
102 if (kret)
103 goto error_out;
104
105 rep.value = &lctx;
106 rep.length = sizeof(lctx);
107
108 retval = generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
109 if (GSS_ERROR(retval))
110 goto error_out;
111
112 error_out:
113 if (*minor_status == 0)
114 *minor_status = (OM_uint32) kret;
115 return(retval);
116 }
117
118 /*
119 * Frees the storage associated with an
120 * exported lucid context structure.
121 */
122 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)123 gss_krb5int_free_lucid_sec_context(
124 OM_uint32 *minor_status,
125 const gss_OID desired_mech,
126 const gss_OID desired_object,
127 gss_buffer_t value)
128 {
129 OM_uint32 retval;
130 krb5_error_code kret = 0;
131 int version;
132 void *kctx;
133
134 /* Assume failure */
135 retval = GSS_S_FAILURE;
136 *minor_status = 0;
137
138 kctx = value->value;
139 if (!kctx) {
140 kret = EINVAL;
141 goto error_out;
142 }
143
144 /* Determine version and call correct free routine */
145 version = ((gss_krb5_lucid_context_version_t *)kctx)->version;
146 switch (version) {
147 case 1:
148 free_external_lucid_ctx_v1((gss_krb5_lucid_context_v1_t*) kctx);
149 break;
150 default:
151 kret = EINVAL;
152 break;
153 }
154
155 if (kret)
156 goto error_out;
157
158 /* Success! */
159 *minor_status = 0;
160 retval = GSS_S_COMPLETE;
161
162 return (retval);
163
164 error_out:
165 if (*minor_status == 0)
166 *minor_status = (OM_uint32) kret;
167 return(retval);
168 }
169
170 /*
171 * Local routines
172 */
173
174 static krb5_error_code
make_external_lucid_ctx_v1(krb5_gss_ctx_id_rec * gctx,int version,void ** out_ptr)175 make_external_lucid_ctx_v1(
176 krb5_gss_ctx_id_rec * gctx,
177 int version,
178 void **out_ptr)
179 {
180 gss_krb5_lucid_context_v1_t *lctx = NULL;
181 unsigned int bufsize = sizeof(gss_krb5_lucid_context_v1_t);
182 krb5_error_code retval;
183
184 /* Allocate the structure */
185 if ((lctx = xmalloc(bufsize)) == NULL) {
186 retval = ENOMEM;
187 goto error_out;
188 }
189
190 memset(lctx, 0, bufsize);
191
192 lctx->version = 1;
193 lctx->initiate = gctx->initiate ? 1 : 0;
194 lctx->endtime = gctx->krb_times.endtime;
195 lctx->send_seq = gctx->seq_send;
196 lctx->recv_seq = gctx->seq_recv;
197 lctx->protocol = gctx->proto;
198 /* gctx->proto == 0 ==> rfc1964-style key information
199 gctx->proto == 1 ==> cfx-style (draft-ietf-krb-wg-gssapi-cfx-07) keys */
200 if (gctx->proto == 0) {
201 lctx->rfc1964_kd.sign_alg = gctx->signalg;
202 lctx->rfc1964_kd.seal_alg = gctx->sealalg;
203 /* Copy key */
204 if ((retval = copy_keyblock_to_lucid_key(&gctx->seq->keyblock,
205 &lctx->rfc1964_kd.ctx_key)))
206 goto error_out;
207 }
208 else if (gctx->proto == 1) {
209 /* Copy keys */
210 /* (subkey is always present, either a copy of the kerberos
211 session key or a subkey) */
212 if ((retval = copy_keyblock_to_lucid_key(&gctx->subkey->keyblock,
213 &lctx->cfx_kd.ctx_key)))
214 goto error_out;
215 if (gctx->have_acceptor_subkey) {
216 if ((retval = copy_keyblock_to_lucid_key(&gctx->acceptor_subkey->keyblock,
217 &lctx->cfx_kd.acceptor_subkey)))
218 goto error_out;
219 lctx->cfx_kd.have_acceptor_subkey = 1;
220 }
221 }
222 else {
223 xfree(lctx);
224 return EINVAL; /* XXX better error code? */
225 }
226
227 /* Success! */
228 *out_ptr = lctx;
229 return 0;
230
231 error_out:
232 if (lctx) {
233 free_external_lucid_ctx_v1(lctx);
234 }
235 return retval;
236
237 }
238
239 /* Copy the contents of a krb5_keyblock to a gss_krb5_lucid_key_t structure */
240 static krb5_error_code
copy_keyblock_to_lucid_key(krb5_keyblock * k5key,gss_krb5_lucid_key_t * lkey)241 copy_keyblock_to_lucid_key(
242 krb5_keyblock *k5key,
243 gss_krb5_lucid_key_t *lkey)
244 {
245 if (!k5key || !k5key->contents || k5key->length == 0)
246 return EINVAL;
247
248 memset(lkey, 0, sizeof(gss_krb5_lucid_key_t));
249
250 /* Allocate storage for the key data */
251 if ((lkey->data = xmalloc(k5key->length)) == NULL) {
252 return ENOMEM;
253 }
254 memcpy(lkey->data, k5key->contents, k5key->length);
255 lkey->length = k5key->length;
256 lkey->type = k5key->enctype;
257
258 return 0;
259 }
260
261
262 /* Free any storage associated with a gss_krb5_lucid_key_t structure */
263 static void
free_lucid_key_data(gss_krb5_lucid_key_t * key)264 free_lucid_key_data(
265 gss_krb5_lucid_key_t *key)
266 {
267 if (key) {
268 if (key->data && key->length) {
269 zap(key->data, key->length);
270 xfree(key->data);
271 zap(key, sizeof(gss_krb5_lucid_key_t));
272 }
273 }
274 }
275 /* Free any storage associated with a gss_krb5_lucid_context_v1 structure */
276 static void
free_external_lucid_ctx_v1(gss_krb5_lucid_context_v1_t * ctx)277 free_external_lucid_ctx_v1(
278 gss_krb5_lucid_context_v1_t *ctx)
279 {
280 if (ctx) {
281 if (ctx->protocol == 0) {
282 free_lucid_key_data(&ctx->rfc1964_kd.ctx_key);
283 }
284 if (ctx->protocol == 1) {
285 free_lucid_key_data(&ctx->cfx_kd.ctx_key);
286 if (ctx->cfx_kd.have_acceptor_subkey)
287 free_lucid_key_data(&ctx->cfx_kd.acceptor_subkey);
288 }
289 xfree(ctx);
290 ctx = NULL;
291 }
292 }
293