Line data Source code
1 : /*
2 : * Copyright (c) 2004, PADL Software Pty Ltd.
3 : * All rights reserved.
4 : *
5 : * Redistribution and use in source and binary forms, with or without
6 : * modification, are permitted provided that the following conditions
7 : * are met:
8 : *
9 : * 1. Redistributions of source code must retain the above copyright
10 : * notice, this list of conditions and the following disclaimer.
11 : *
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : *
16 : * 3. Neither the name of PADL Software nor the names of its contributors
17 : * may be used to endorse or promote products derived from this software
18 : * without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
24 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 : * SUCH DAMAGE.
31 : */
32 :
33 : #include "gsskrb5_locl.h"
34 :
35 : static int
36 52132 : oid_prefix_equal(gss_OID oid_enc, gss_OID prefix_enc, unsigned *suffix)
37 : {
38 881 : int ret;
39 881 : heim_oid oid;
40 881 : heim_oid prefix;
41 :
42 52132 : *suffix = 0;
43 :
44 52132 : ret = der_get_oid(oid_enc->elements, oid_enc->length,
45 : &oid, NULL);
46 52132 : if (ret) {
47 0 : return 0;
48 : }
49 :
50 52132 : ret = der_get_oid(prefix_enc->elements, prefix_enc->length,
51 : &prefix, NULL);
52 52132 : if (ret) {
53 0 : der_free_oid(&oid);
54 0 : return 0;
55 : }
56 :
57 52132 : ret = 0;
58 :
59 52132 : if (oid.length - 1 == prefix.length) {
60 52132 : *suffix = oid.components[oid.length - 1];
61 52132 : oid.length--;
62 52132 : ret = (der_heim_oid_cmp(&oid, &prefix) == 0);
63 52132 : oid.length++;
64 : }
65 :
66 52132 : der_free_oid(&oid);
67 52132 : der_free_oid(&prefix);
68 :
69 52132 : return ret;
70 : }
71 :
72 0 : static OM_uint32 inquire_sec_context_tkt_flags
73 : (OM_uint32 *minor_status,
74 : const gsskrb5_ctx context_handle,
75 : gss_buffer_set_t *data_set)
76 : {
77 0 : OM_uint32 tkt_flags;
78 0 : unsigned char buf[4];
79 0 : gss_buffer_desc value;
80 :
81 0 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
82 :
83 0 : if (context_handle->ticket == NULL) {
84 0 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
85 0 : _gsskrb5_set_status(EINVAL, "No ticket from which to obtain flags");
86 0 : *minor_status = EINVAL;
87 0 : return GSS_S_BAD_MECH;
88 : }
89 :
90 0 : tkt_flags = TicketFlags2int(context_handle->ticket->ticket.flags);
91 0 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
92 :
93 0 : _gss_mg_encode_le_uint32(tkt_flags, buf);
94 0 : value.length = sizeof(buf);
95 0 : value.value = buf;
96 :
97 0 : return gss_add_buffer_set_member(minor_status,
98 : &value,
99 : data_set);
100 : }
101 :
102 : enum keytype { ACCEPTOR_KEY, INITIATOR_KEY, TOKEN_KEY };
103 :
104 72500 : static OM_uint32 inquire_sec_context_get_subkey
105 : (OM_uint32 *minor_status,
106 : const gsskrb5_ctx context_handle,
107 : krb5_context context,
108 : enum keytype keytype,
109 : gss_buffer_set_t *data_set)
110 : {
111 72500 : krb5_keyblock *key = NULL;
112 72500 : krb5_storage *sp = NULL;
113 978 : krb5_data data;
114 72500 : OM_uint32 maj_stat = GSS_S_COMPLETE;
115 978 : krb5_error_code ret;
116 :
117 72500 : krb5_data_zero(&data);
118 :
119 72500 : sp = krb5_storage_emem();
120 72500 : if (sp == NULL) {
121 0 : _gsskrb5_clear_status();
122 0 : ret = ENOMEM;
123 0 : goto out;
124 : }
125 :
126 978 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
127 72500 : switch(keytype) {
128 0 : case ACCEPTOR_KEY:
129 0 : ret = _gsskrb5i_get_acceptor_subkey(context_handle, context, &key);
130 0 : break;
131 0 : case INITIATOR_KEY:
132 0 : ret = _gsskrb5i_get_initiator_subkey(context_handle, context, &key);
133 0 : break;
134 72500 : case TOKEN_KEY:
135 72500 : ret = _gsskrb5i_get_token_key(context_handle, context, &key);
136 72500 : break;
137 0 : default:
138 0 : _gsskrb5_set_status(EINVAL, "%d is not a valid subkey type", keytype);
139 0 : ret = EINVAL;
140 0 : break;
141 : }
142 978 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
143 72500 : if (ret)
144 0 : goto out;
145 72500 : if (key == NULL) {
146 0 : _gsskrb5_set_status(EINVAL, "have no subkey of type %d", keytype);
147 0 : ret = EINVAL;
148 0 : goto out;
149 : }
150 :
151 72500 : ret = krb5_store_keyblock(sp, *key);
152 72500 : if (ret)
153 0 : goto out;
154 :
155 72500 : ret = krb5_storage_to_data(sp, &data);
156 72500 : if (ret)
157 0 : goto out;
158 :
159 : {
160 978 : gss_buffer_desc value;
161 :
162 72500 : value.length = data.length;
163 72500 : value.value = data.data;
164 :
165 72500 : maj_stat = gss_add_buffer_set_member(minor_status,
166 : &value,
167 : data_set);
168 : }
169 :
170 72500 : out:
171 72500 : krb5_free_keyblock(context, key);
172 72500 : krb5_data_free(&data);
173 72500 : if (sp)
174 72500 : krb5_storage_free(sp);
175 72500 : if (ret) {
176 0 : *minor_status = ret;
177 0 : maj_stat = GSS_S_FAILURE;
178 : }
179 72500 : return maj_stat;
180 : }
181 :
182 135584 : static OM_uint32 inquire_sec_context_get_sspi_session_key
183 : (OM_uint32 *minor_status,
184 : const gsskrb5_ctx context_handle,
185 : krb5_context context,
186 : gss_buffer_set_t *data_set)
187 : {
188 2510 : krb5_keyblock *key;
189 135584 : OM_uint32 maj_stat = GSS_S_COMPLETE;
190 2510 : krb5_error_code ret;
191 2510 : gss_buffer_desc value;
192 :
193 2510 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
194 135584 : ret = _gsskrb5i_get_token_key(context_handle, context, &key);
195 2510 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
196 :
197 135584 : if (ret)
198 0 : goto out;
199 135584 : if (key == NULL) {
200 0 : ret = EINVAL;
201 0 : goto out;
202 : }
203 :
204 135584 : value.length = key->keyvalue.length;
205 135584 : value.value = key->keyvalue.data;
206 :
207 135584 : maj_stat = gss_add_buffer_set_member(minor_status,
208 : &value,
209 : data_set);
210 135584 : krb5_free_keyblock(context, key);
211 :
212 : /* MIT also returns the enctype encoded as an OID in data_set[1] */
213 :
214 135584 : out:
215 135584 : if (ret) {
216 0 : *minor_status = ret;
217 0 : maj_stat = GSS_S_FAILURE;
218 : }
219 135584 : return maj_stat;
220 : }
221 :
222 52132 : static OM_uint32 inquire_sec_context_authz_data
223 : (OM_uint32 *minor_status,
224 : const gsskrb5_ctx context_handle,
225 : krb5_context context,
226 : unsigned ad_type,
227 : gss_buffer_set_t *data_set)
228 : {
229 881 : krb5_data data;
230 881 : gss_buffer_desc ad_data;
231 881 : OM_uint32 ret;
232 :
233 52132 : *minor_status = 0;
234 52132 : *data_set = GSS_C_NO_BUFFER_SET;
235 :
236 881 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
237 52132 : if (context_handle->ticket == NULL) {
238 0 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
239 0 : *minor_status = EINVAL;
240 0 : _gsskrb5_set_status(EINVAL, "No ticket to obtain authz data from");
241 0 : return GSS_S_NO_CONTEXT;
242 : }
243 :
244 103383 : ret = krb5_ticket_get_authorization_data_type(context,
245 51251 : context_handle->ticket,
246 : ad_type,
247 : &data);
248 881 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
249 52132 : if (ret) {
250 8 : *minor_status = ret;
251 8 : return GSS_S_FAILURE;
252 : }
253 :
254 52124 : ad_data.value = data.data;
255 52124 : ad_data.length = data.length;
256 :
257 52124 : ret = gss_add_buffer_set_member(minor_status,
258 : &ad_data,
259 : data_set);
260 :
261 52124 : krb5_data_free(&data);
262 :
263 52124 : return ret;
264 : }
265 :
266 0 : static OM_uint32 inquire_sec_context_has_buggy_spnego
267 : (OM_uint32 *minor_status,
268 : const gsskrb5_ctx context_handle,
269 : gss_buffer_set_t *data_set)
270 : {
271 0 : uint8_t old_enctype;
272 0 : gss_buffer_desc buffer;
273 :
274 0 : *minor_status = 0;
275 0 : *data_set = GSS_C_NO_BUFFER_SET;
276 :
277 : /*
278 : * For Windows SPNEGO implementations, the initiator or acceptor
279 : * are presumed to be "buggy" (Windows 2003 or earlier) if an
280 : * "older" (i.e. pre-AES per RFC 4121) encryption type was used.
281 : */
282 :
283 0 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
284 0 : old_enctype = ((context_handle->more_flags & IS_CFX) == 0);
285 0 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
286 :
287 0 : buffer.value = &old_enctype;
288 0 : buffer.length = sizeof(old_enctype);
289 :
290 0 : return gss_add_buffer_set_member(minor_status, &buffer, data_set);
291 : }
292 :
293 : /*
294 : *
295 : */
296 :
297 : static OM_uint32
298 0 : export_lucid_sec_context_v1(OM_uint32 *minor_status,
299 : gsskrb5_ctx context_handle,
300 : krb5_context context,
301 : gss_buffer_set_t *data_set)
302 : {
303 0 : krb5_storage *sp = NULL;
304 0 : OM_uint32 major_status = GSS_S_COMPLETE;
305 0 : krb5_error_code ret;
306 0 : krb5_keyblock *key = NULL;
307 0 : int32_t number;
308 0 : int is_cfx;
309 0 : krb5_data data;
310 :
311 0 : *minor_status = 0;
312 :
313 0 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
314 :
315 0 : is_cfx = (context_handle->more_flags & IS_CFX);
316 :
317 0 : sp = krb5_storage_emem();
318 0 : if (sp == NULL) {
319 0 : _gsskrb5_clear_status();
320 0 : ret = ENOMEM;
321 0 : goto out;
322 : }
323 :
324 0 : ret = krb5_store_int32(sp, 1);
325 0 : if (ret) goto out;
326 0 : ret = krb5_store_int32(sp, (context_handle->more_flags & LOCAL) ? 1 : 0);
327 0 : if (ret) goto out;
328 : /* XXX need krb5_store_int64() */
329 0 : ret = krb5_store_int32(sp, context_handle->endtime);
330 0 : if (ret) goto out;
331 0 : krb5_auth_con_getlocalseqnumber (context,
332 : context_handle->auth_context,
333 : &number);
334 0 : ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */
335 0 : if (ret) goto out;
336 0 : ret = krb5_store_uint32(sp, (uint32_t)number);
337 0 : if (ret) goto out;
338 0 : krb5_auth_con_getremoteseqnumber (context,
339 : context_handle->auth_context,
340 : &number);
341 0 : ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */
342 0 : if (ret) goto out;
343 0 : ret = krb5_store_uint32(sp, (uint32_t)number);
344 0 : if (ret) goto out;
345 0 : ret = krb5_store_int32(sp, (is_cfx) ? 1 : 0);
346 0 : if (ret) goto out;
347 :
348 0 : ret = _gsskrb5i_get_token_key(context_handle, context, &key);
349 0 : if (ret) goto out;
350 :
351 0 : if (is_cfx == 0) {
352 0 : int sign_alg, seal_alg;
353 :
354 0 : switch (key->keytype) {
355 0 : case ETYPE_DES_CBC_CRC:
356 : case ETYPE_DES_CBC_MD4:
357 : case ETYPE_DES_CBC_MD5:
358 0 : sign_alg = 0;
359 0 : seal_alg = 0;
360 0 : break;
361 0 : case ETYPE_DES3_CBC_MD5:
362 : case ETYPE_DES3_CBC_SHA1:
363 0 : sign_alg = 4;
364 0 : seal_alg = 2;
365 0 : break;
366 0 : case ETYPE_ARCFOUR_HMAC_MD5:
367 : case ETYPE_ARCFOUR_HMAC_MD5_56:
368 0 : sign_alg = 17;
369 0 : seal_alg = 16;
370 0 : break;
371 0 : default:
372 0 : sign_alg = -1;
373 0 : seal_alg = -1;
374 0 : break;
375 : }
376 0 : ret = krb5_store_int32(sp, sign_alg);
377 0 : if (ret) goto out;
378 0 : ret = krb5_store_int32(sp, seal_alg);
379 0 : if (ret) goto out;
380 : /* ctx_key */
381 0 : ret = krb5_store_keyblock(sp, *key);
382 0 : if (ret) goto out;
383 : } else {
384 0 : int subkey_p = (context_handle->more_flags & ACCEPTOR_SUBKEY) ? 1 : 0;
385 :
386 : /* have_acceptor_subkey */
387 0 : ret = krb5_store_int32(sp, subkey_p);
388 0 : if (ret) goto out;
389 : /* ctx_key */
390 0 : ret = krb5_store_keyblock(sp, *key);
391 0 : if (ret) goto out;
392 : /* acceptor_subkey */
393 0 : if (subkey_p) {
394 0 : ret = krb5_store_keyblock(sp, *key);
395 0 : if (ret) goto out;
396 : }
397 : }
398 0 : ret = krb5_storage_to_data(sp, &data);
399 0 : if (ret) goto out;
400 :
401 : {
402 0 : gss_buffer_desc ad_data;
403 :
404 0 : ad_data.value = data.data;
405 0 : ad_data.length = data.length;
406 :
407 0 : ret = gss_add_buffer_set_member(minor_status, &ad_data, data_set);
408 0 : krb5_data_free(&data);
409 0 : if (ret)
410 0 : goto out;
411 : }
412 :
413 0 : out:
414 0 : if (key)
415 0 : krb5_free_keyblock (context, key);
416 0 : if (sp)
417 0 : krb5_storage_free(sp);
418 0 : if (ret) {
419 0 : *minor_status = ret;
420 0 : major_status = GSS_S_FAILURE;
421 : }
422 0 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
423 0 : return major_status;
424 : }
425 :
426 : static OM_uint32
427 0 : get_authtime(OM_uint32 *minor_status,
428 : gsskrb5_ctx ctx,
429 : gss_buffer_set_t *data_set)
430 :
431 : {
432 0 : gss_buffer_desc value;
433 0 : unsigned char buf[SIZEOF_TIME_T];
434 0 : time_t authtime;
435 :
436 0 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
437 0 : if (ctx->ticket == NULL) {
438 0 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
439 0 : _gsskrb5_set_status(EINVAL, "No ticket to obtain auth time from");
440 0 : *minor_status = EINVAL;
441 0 : return GSS_S_FAILURE;
442 : }
443 :
444 0 : authtime = ctx->ticket->ticket.authtime;
445 :
446 0 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
447 :
448 : #if SIZEOF_TIME_T == 8
449 0 : _gss_mg_encode_le_uint64(authtime, buf);
450 : #elif SIZEOF_TIME_T == 4
451 : _gss_mg_encode_le_uint32(authtime, buf);
452 : #else
453 : #error set SIZEOF_TIME_T for your platform
454 : #endif
455 0 : value.length = sizeof(buf);
456 0 : value.value = buf;
457 :
458 0 : return gss_add_buffer_set_member(minor_status,
459 : &value,
460 : data_set);
461 : }
462 :
463 :
464 : static OM_uint32
465 0 : get_service_keyblock
466 : (OM_uint32 *minor_status,
467 : gsskrb5_ctx ctx,
468 : gss_buffer_set_t *data_set)
469 : {
470 0 : krb5_storage *sp = NULL;
471 0 : krb5_data data;
472 0 : OM_uint32 maj_stat = GSS_S_COMPLETE;
473 0 : krb5_error_code ret = EINVAL;
474 :
475 0 : sp = krb5_storage_emem();
476 0 : if (sp == NULL) {
477 0 : _gsskrb5_clear_status();
478 0 : *minor_status = ENOMEM;
479 0 : return GSS_S_FAILURE;
480 : }
481 :
482 0 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
483 0 : if (ctx->service_keyblock == NULL) {
484 0 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
485 0 : krb5_storage_free(sp);
486 0 : _gsskrb5_set_status(EINVAL, "No service keyblock on gssapi context");
487 0 : *minor_status = EINVAL;
488 0 : return GSS_S_FAILURE;
489 : }
490 :
491 0 : krb5_data_zero(&data);
492 :
493 0 : ret = krb5_store_keyblock(sp, *ctx->service_keyblock);
494 :
495 0 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
496 :
497 0 : if (ret)
498 0 : goto out;
499 :
500 0 : ret = krb5_storage_to_data(sp, &data);
501 0 : if (ret)
502 0 : goto out;
503 :
504 : {
505 0 : gss_buffer_desc value;
506 :
507 0 : value.length = data.length;
508 0 : value.value = data.data;
509 :
510 0 : maj_stat = gss_add_buffer_set_member(minor_status,
511 : &value,
512 : data_set);
513 : }
514 :
515 0 : out:
516 0 : krb5_data_free(&data);
517 0 : if (sp)
518 0 : krb5_storage_free(sp);
519 0 : if (ret) {
520 0 : *minor_status = ret;
521 0 : maj_stat = GSS_S_FAILURE;
522 : }
523 0 : return maj_stat;
524 : }
525 : /*
526 : *
527 : */
528 :
529 260216 : OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_sec_context_by_oid
530 : (OM_uint32 *minor_status,
531 : gss_const_ctx_id_t context_handle,
532 : const gss_OID desired_object,
533 : gss_buffer_set_t *data_set)
534 : {
535 4369 : krb5_context context;
536 260216 : const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
537 4369 : unsigned suffix;
538 :
539 260216 : if (ctx == NULL) {
540 0 : *minor_status = EINVAL;
541 0 : return GSS_S_NO_CONTEXT;
542 : }
543 :
544 260216 : GSSAPI_KRB5_INIT (&context);
545 :
546 260216 : if (gss_oid_equal(desired_object, GSS_KRB5_GET_TKT_FLAGS_X)) {
547 0 : return inquire_sec_context_tkt_flags(minor_status,
548 : ctx,
549 : data_set);
550 260216 : } else if (gss_oid_equal(desired_object, GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO)) {
551 0 : return inquire_sec_context_has_buggy_spnego(minor_status,
552 : ctx,
553 : data_set);
554 260216 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SUBKEY_X)) {
555 72500 : return inquire_sec_context_get_subkey(minor_status,
556 : ctx,
557 : context,
558 : TOKEN_KEY,
559 : data_set);
560 187716 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_INITIATOR_SUBKEY_X)) {
561 0 : return inquire_sec_context_get_subkey(minor_status,
562 : ctx,
563 : context,
564 : INITIATOR_KEY,
565 : data_set);
566 187716 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_ACCEPTOR_SUBKEY_X)) {
567 0 : return inquire_sec_context_get_subkey(minor_status,
568 : ctx,
569 : context,
570 : ACCEPTOR_KEY,
571 : data_set);
572 187716 : } else if (gss_oid_equal(desired_object, GSS_C_INQ_SSPI_SESSION_KEY)) {
573 135584 : return inquire_sec_context_get_sspi_session_key(minor_status,
574 : ctx,
575 : context,
576 : data_set);
577 52132 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_AUTHTIME_X)) {
578 0 : return get_authtime(minor_status, ctx, data_set);
579 52132 : } else if (oid_prefix_equal(desired_object,
580 : GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X,
581 : &suffix)) {
582 52132 : return inquire_sec_context_authz_data(minor_status,
583 : ctx,
584 : context,
585 : suffix,
586 : data_set);
587 0 : } else if (oid_prefix_equal(desired_object,
588 : GSS_KRB5_EXPORT_LUCID_CONTEXT_X,
589 : &suffix)) {
590 0 : if (suffix == 1)
591 0 : return export_lucid_sec_context_v1(minor_status,
592 : ctx,
593 : context,
594 : data_set);
595 0 : *minor_status = 0;
596 0 : return GSS_S_FAILURE;
597 0 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SERVICE_KEYBLOCK_X)) {
598 0 : return get_service_keyblock(minor_status, ctx, data_set);
599 : } else {
600 0 : *minor_status = 0;
601 0 : return GSS_S_FAILURE;
602 : }
603 : }
604 :
|