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