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 44656 : oid_prefix_equal(gss_OID oid_enc, gss_OID prefix_enc, unsigned *suffix)
37 : {
38 : int ret;
39 : heim_oid oid;
40 : heim_oid prefix;
41 :
42 44656 : *suffix = 0;
43 :
44 44656 : ret = der_get_oid(oid_enc->elements, oid_enc->length,
45 : &oid, NULL);
46 44656 : if (ret) {
47 0 : return 0;
48 : }
49 :
50 44656 : ret = der_get_oid(prefix_enc->elements, prefix_enc->length,
51 : &prefix, NULL);
52 44656 : if (ret) {
53 0 : der_free_oid(&oid);
54 0 : return 0;
55 : }
56 :
57 44656 : ret = 0;
58 :
59 44656 : if (oid.length - 1 == prefix.length) {
60 44656 : *suffix = oid.components[oid.length - 1];
61 44656 : oid.length--;
62 44656 : ret = (der_heim_oid_cmp(&oid, &prefix) == 0);
63 44656 : oid.length++;
64 : }
65 :
66 44656 : der_free_oid(&oid);
67 44656 : der_free_oid(&prefix);
68 :
69 44656 : 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 : OM_uint32 tkt_flags;
78 : unsigned char buf[4];
79 : gss_buffer_desc value;
80 :
81 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
82 :
83 0 : if (context_handle->ticket == NULL) {
84 : 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 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
92 :
93 0 : _gsskrb5_encode_om_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 64598 : 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 64598 : krb5_keyblock *key = NULL;
112 64598 : krb5_storage *sp = NULL;
113 : krb5_data data;
114 64598 : OM_uint32 maj_stat = GSS_S_COMPLETE;
115 : krb5_error_code ret;
116 :
117 64598 : krb5_data_zero(&data);
118 :
119 64598 : sp = krb5_storage_emem();
120 64598 : if (sp == NULL) {
121 0 : _gsskrb5_clear_status();
122 0 : ret = ENOMEM;
123 0 : goto out;
124 : }
125 :
126 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
127 64598 : 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 64598 : case TOKEN_KEY:
135 64598 : ret = _gsskrb5i_get_token_key(context_handle, context, &key);
136 64598 : 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 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
143 64598 : if (ret)
144 0 : goto out;
145 64598 : 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 64598 : ret = krb5_store_keyblock(sp, *key);
152 64598 : krb5_free_keyblock (context, key);
153 64598 : if (ret)
154 0 : goto out;
155 :
156 64598 : ret = krb5_storage_to_data(sp, &data);
157 64598 : if (ret)
158 0 : goto out;
159 :
160 : {
161 : gss_buffer_desc value;
162 :
163 64598 : value.length = data.length;
164 64598 : value.value = data.data;
165 :
166 64598 : maj_stat = gss_add_buffer_set_member(minor_status,
167 : &value,
168 : data_set);
169 : }
170 :
171 64598 : out:
172 64598 : krb5_data_free(&data);
173 64598 : if (sp)
174 64598 : krb5_storage_free(sp);
175 64598 : if (ret) {
176 0 : *minor_status = ret;
177 0 : maj_stat = GSS_S_FAILURE;
178 : }
179 64598 : return maj_stat;
180 : }
181 :
182 116680 : 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 : krb5_keyblock *key;
189 116680 : OM_uint32 maj_stat = GSS_S_COMPLETE;
190 : krb5_error_code ret;
191 : gss_buffer_desc value;
192 :
193 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
194 116680 : ret = _gsskrb5i_get_token_key(context_handle, context, &key);
195 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
196 :
197 116680 : if (ret)
198 0 : goto out;
199 116680 : if (key == NULL) {
200 0 : ret = EINVAL;
201 0 : goto out;
202 : }
203 :
204 116680 : value.length = key->keyvalue.length;
205 116680 : value.value = key->keyvalue.data;
206 :
207 116680 : maj_stat = gss_add_buffer_set_member(minor_status,
208 : &value,
209 : data_set);
210 116680 : krb5_free_keyblock(context, key);
211 :
212 : /* MIT also returns the enctype encoded as an OID in data_set[1] */
213 :
214 116680 : out:
215 116680 : if (ret) {
216 0 : *minor_status = ret;
217 0 : maj_stat = GSS_S_FAILURE;
218 : }
219 116680 : return maj_stat;
220 : }
221 :
222 44656 : 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 : krb5_data data;
230 : gss_buffer_desc ad_data;
231 : OM_uint32 ret;
232 :
233 44656 : *minor_status = 0;
234 44656 : *data_set = GSS_C_NO_BUFFER_SET;
235 :
236 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
237 44656 : if (context_handle->ticket == NULL) {
238 : 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 88574 : ret = krb5_ticket_get_authorization_data_type(context,
245 43918 : context_handle->ticket,
246 : ad_type,
247 : &data);
248 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
249 44656 : if (ret) {
250 0 : *minor_status = ret;
251 0 : return GSS_S_FAILURE;
252 : }
253 :
254 44656 : ad_data.value = data.data;
255 44656 : ad_data.length = data.length;
256 :
257 44656 : ret = gss_add_buffer_set_member(minor_status,
258 : &ad_data,
259 : data_set);
260 :
261 44656 : krb5_data_free(&data);
262 :
263 43918 : return ret;
264 : }
265 :
266 0 : static OM_uint32 inquire_sec_context_has_updated_spnego
267 : (OM_uint32 *minor_status,
268 : const gsskrb5_ctx context_handle,
269 : gss_buffer_set_t *data_set)
270 : {
271 0 : int is_updated = 0;
272 :
273 0 : *minor_status = 0;
274 0 : *data_set = GSS_C_NO_BUFFER_SET;
275 :
276 : /*
277 : * For Windows SPNEGO implementations, both the initiator and the
278 : * acceptor are assumed to have been updated if a "newer" [CLAR] or
279 : * different enctype is negotiated for use by the Kerberos GSS-API
280 : * mechanism.
281 : */
282 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
283 0 : is_updated = (context_handle->more_flags & IS_CFX);
284 0 : if (is_updated == 0) {
285 : krb5_keyblock *acceptor_subkey;
286 :
287 0 : if (context_handle->more_flags & LOCAL)
288 0 : acceptor_subkey = context_handle->auth_context->remote_subkey;
289 : else
290 0 : acceptor_subkey = context_handle->auth_context->local_subkey;
291 :
292 0 : if (acceptor_subkey != NULL)
293 0 : is_updated = (acceptor_subkey->keytype !=
294 0 : context_handle->auth_context->keyblock->keytype);
295 : }
296 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
297 :
298 0 : return is_updated ? GSS_S_COMPLETE : GSS_S_FAILURE;
299 : }
300 :
301 : /*
302 : *
303 : */
304 :
305 : static OM_uint32
306 0 : export_lucid_sec_context_v1(OM_uint32 *minor_status,
307 : gsskrb5_ctx context_handle,
308 : krb5_context context,
309 : gss_buffer_set_t *data_set)
310 : {
311 0 : krb5_storage *sp = NULL;
312 0 : OM_uint32 major_status = GSS_S_COMPLETE;
313 : krb5_error_code ret;
314 0 : krb5_keyblock *key = NULL;
315 : int32_t number;
316 : int is_cfx;
317 : krb5_data data;
318 :
319 0 : *minor_status = 0;
320 :
321 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
322 :
323 0 : is_cfx = (context_handle->more_flags & IS_CFX);
324 :
325 0 : sp = krb5_storage_emem();
326 0 : if (sp == NULL) {
327 0 : _gsskrb5_clear_status();
328 0 : ret = ENOMEM;
329 0 : goto out;
330 : }
331 :
332 0 : ret = krb5_store_int32(sp, 1);
333 0 : if (ret) goto out;
334 0 : ret = krb5_store_int32(sp, (context_handle->more_flags & LOCAL) ? 1 : 0);
335 0 : if (ret) goto out;
336 0 : ret = krb5_store_int32(sp, context_handle->lifetime);
337 0 : if (ret) goto out;
338 0 : krb5_auth_con_getlocalseqnumber (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 : krb5_auth_con_getremoteseqnumber (context,
346 : context_handle->auth_context,
347 : &number);
348 0 : ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */
349 0 : if (ret) goto out;
350 0 : ret = krb5_store_uint32(sp, (uint32_t)number);
351 0 : if (ret) goto out;
352 0 : ret = krb5_store_int32(sp, (is_cfx) ? 1 : 0);
353 0 : if (ret) goto out;
354 :
355 0 : ret = _gsskrb5i_get_token_key(context_handle, context, &key);
356 0 : if (ret) goto out;
357 :
358 0 : if (is_cfx == 0) {
359 : int sign_alg, seal_alg;
360 :
361 0 : switch (key->keytype) {
362 0 : case ETYPE_DES_CBC_CRC:
363 : case ETYPE_DES_CBC_MD4:
364 : case ETYPE_DES_CBC_MD5:
365 0 : sign_alg = 0;
366 0 : seal_alg = 0;
367 0 : break;
368 0 : case ETYPE_DES3_CBC_MD5:
369 : case ETYPE_DES3_CBC_SHA1:
370 0 : sign_alg = 4;
371 0 : seal_alg = 2;
372 0 : break;
373 0 : case ETYPE_ARCFOUR_HMAC_MD5:
374 : case ETYPE_ARCFOUR_HMAC_MD5_56:
375 0 : sign_alg = 17;
376 0 : seal_alg = 16;
377 0 : break;
378 0 : default:
379 0 : sign_alg = -1;
380 0 : seal_alg = -1;
381 0 : break;
382 : }
383 0 : ret = krb5_store_int32(sp, sign_alg);
384 0 : if (ret) goto out;
385 0 : ret = krb5_store_int32(sp, seal_alg);
386 0 : if (ret) goto out;
387 : /* ctx_key */
388 0 : ret = krb5_store_keyblock(sp, *key);
389 0 : if (ret) goto out;
390 : } else {
391 0 : int subkey_p = (context_handle->more_flags & ACCEPTOR_SUBKEY) ? 1 : 0;
392 :
393 : /* have_acceptor_subkey */
394 0 : ret = krb5_store_int32(sp, subkey_p);
395 0 : if (ret) goto out;
396 : /* ctx_key */
397 0 : ret = krb5_store_keyblock(sp, *key);
398 0 : if (ret) goto out;
399 : /* acceptor_subkey */
400 0 : if (subkey_p) {
401 0 : ret = krb5_store_keyblock(sp, *key);
402 0 : if (ret) goto out;
403 : }
404 : }
405 0 : ret = krb5_storage_to_data(sp, &data);
406 0 : if (ret) goto out;
407 :
408 : {
409 : gss_buffer_desc ad_data;
410 :
411 0 : ad_data.value = data.data;
412 0 : ad_data.length = data.length;
413 :
414 0 : ret = gss_add_buffer_set_member(minor_status, &ad_data, data_set);
415 0 : krb5_data_free(&data);
416 0 : if (ret)
417 0 : goto out;
418 : }
419 :
420 0 : out:
421 0 : if (key)
422 0 : krb5_free_keyblock (context, key);
423 0 : if (sp)
424 0 : krb5_storage_free(sp);
425 0 : if (ret) {
426 0 : *minor_status = ret;
427 0 : major_status = GSS_S_FAILURE;
428 : }
429 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
430 0 : return major_status;
431 : }
432 :
433 : static OM_uint32
434 0 : get_authtime(OM_uint32 *minor_status,
435 : gsskrb5_ctx ctx,
436 : gss_buffer_set_t *data_set)
437 :
438 : {
439 : gss_buffer_desc value;
440 : unsigned char buf[4];
441 : OM_uint32 authtime;
442 :
443 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
444 0 : if (ctx->ticket == NULL) {
445 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
446 0 : _gsskrb5_set_status(EINVAL, "No ticket to obtain auth time from");
447 0 : *minor_status = EINVAL;
448 0 : return GSS_S_FAILURE;
449 : }
450 :
451 0 : authtime = ctx->ticket->ticket.authtime;
452 :
453 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
454 :
455 0 : _gsskrb5_encode_om_uint32(authtime, buf);
456 0 : value.length = sizeof(buf);
457 0 : value.value = buf;
458 :
459 0 : return gss_add_buffer_set_member(minor_status,
460 : &value,
461 : data_set);
462 : }
463 :
464 :
465 : static OM_uint32
466 0 : get_service_keyblock
467 : (OM_uint32 *minor_status,
468 : gsskrb5_ctx ctx,
469 : gss_buffer_set_t *data_set)
470 : {
471 0 : krb5_storage *sp = NULL;
472 : krb5_data data;
473 0 : OM_uint32 maj_stat = GSS_S_COMPLETE;
474 0 : krb5_error_code ret = EINVAL;
475 :
476 0 : sp = krb5_storage_emem();
477 0 : if (sp == NULL) {
478 0 : _gsskrb5_clear_status();
479 0 : *minor_status = ENOMEM;
480 0 : return GSS_S_FAILURE;
481 : }
482 :
483 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
484 0 : if (ctx->service_keyblock == NULL) {
485 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
486 0 : krb5_storage_free(sp);
487 0 : _gsskrb5_set_status(EINVAL, "No service keyblock on gssapi context");
488 0 : *minor_status = EINVAL;
489 0 : return GSS_S_FAILURE;
490 : }
491 :
492 0 : krb5_data_zero(&data);
493 :
494 0 : ret = krb5_store_keyblock(sp, *ctx->service_keyblock);
495 :
496 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
497 :
498 0 : if (ret)
499 0 : goto out;
500 :
501 0 : ret = krb5_storage_to_data(sp, &data);
502 0 : if (ret)
503 0 : goto out;
504 :
505 : {
506 : gss_buffer_desc value;
507 :
508 0 : value.length = data.length;
509 0 : value.value = data.data;
510 :
511 0 : maj_stat = gss_add_buffer_set_member(minor_status,
512 : &value,
513 : data_set);
514 : }
515 :
516 0 : out:
517 0 : krb5_data_free(&data);
518 0 : if (sp)
519 0 : krb5_storage_free(sp);
520 0 : if (ret) {
521 0 : *minor_status = ret;
522 0 : maj_stat = GSS_S_FAILURE;
523 : }
524 0 : return maj_stat;
525 : }
526 : /*
527 : *
528 : */
529 :
530 225934 : OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_sec_context_by_oid
531 : (OM_uint32 *minor_status,
532 : const gss_ctx_id_t context_handle,
533 : const gss_OID desired_object,
534 : gss_buffer_set_t *data_set)
535 : {
536 : krb5_context context;
537 225934 : const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
538 : unsigned suffix;
539 :
540 225934 : if (ctx == NULL) {
541 0 : *minor_status = EINVAL;
542 0 : return GSS_S_NO_CONTEXT;
543 : }
544 :
545 225934 : GSSAPI_KRB5_INIT (&context);
546 :
547 225934 : if (gss_oid_equal(desired_object, GSS_KRB5_GET_TKT_FLAGS_X)) {
548 0 : return inquire_sec_context_tkt_flags(minor_status,
549 : ctx,
550 : data_set);
551 225934 : } else if (gss_oid_equal(desired_object, GSS_C_PEER_HAS_UPDATED_SPNEGO)) {
552 0 : return inquire_sec_context_has_updated_spnego(minor_status,
553 : ctx,
554 : data_set);
555 225934 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SUBKEY_X)) {
556 64598 : return inquire_sec_context_get_subkey(minor_status,
557 : ctx,
558 : context,
559 : TOKEN_KEY,
560 : data_set);
561 161336 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_INITIATOR_SUBKEY_X)) {
562 0 : return inquire_sec_context_get_subkey(minor_status,
563 : ctx,
564 : context,
565 : INITIATOR_KEY,
566 : data_set);
567 161336 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_ACCEPTOR_SUBKEY_X)) {
568 0 : return inquire_sec_context_get_subkey(minor_status,
569 : ctx,
570 : context,
571 : ACCEPTOR_KEY,
572 : data_set);
573 161336 : } else if (gss_oid_equal(desired_object, GSS_C_INQ_SSPI_SESSION_KEY)) {
574 116680 : return inquire_sec_context_get_sspi_session_key(minor_status,
575 : ctx,
576 : context,
577 : data_set);
578 44656 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_AUTHTIME_X)) {
579 0 : return get_authtime(minor_status, ctx, data_set);
580 44656 : } else if (oid_prefix_equal(desired_object,
581 : GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X,
582 : &suffix)) {
583 44656 : return inquire_sec_context_authz_data(minor_status,
584 : ctx,
585 : context,
586 : suffix,
587 : data_set);
588 0 : } else if (oid_prefix_equal(desired_object,
589 : GSS_KRB5_EXPORT_LUCID_CONTEXT_X,
590 : &suffix)) {
591 0 : if (suffix == 1)
592 0 : return export_lucid_sec_context_v1(minor_status,
593 : ctx,
594 : context,
595 : data_set);
596 0 : *minor_status = 0;
597 0 : return GSS_S_FAILURE;
598 0 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SERVICE_KEYBLOCK_X)) {
599 0 : return get_service_keyblock(minor_status, ctx, data_set);
600 : } else {
601 0 : *minor_status = 0;
602 0 : return GSS_S_FAILURE;
603 : }
604 : }
605 :
|