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 44380 : 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 44380 : *suffix = 0;
43 :
44 44380 : ret = der_get_oid(oid_enc->elements, oid_enc->length,
45 : &oid, NULL);
46 44380 : if (ret) {
47 0 : return 0;
48 : }
49 :
50 44380 : ret = der_get_oid(prefix_enc->elements, prefix_enc->length,
51 : &prefix, NULL);
52 44380 : if (ret) {
53 0 : der_free_oid(&oid);
54 0 : return 0;
55 : }
56 :
57 44380 : ret = 0;
58 :
59 44380 : if (oid.length - 1 == prefix.length) {
60 44380 : *suffix = oid.components[oid.length - 1];
61 44380 : oid.length--;
62 44380 : ret = (der_heim_oid_cmp(&oid, &prefix) == 0);
63 44380 : oid.length++;
64 : }
65 :
66 44380 : der_free_oid(&oid);
67 44380 : der_free_oid(&prefix);
68 :
69 44380 : 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 64218 : 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 64218 : krb5_keyblock *key = NULL;
112 64218 : krb5_storage *sp = NULL;
113 : krb5_data data;
114 64218 : OM_uint32 maj_stat = GSS_S_COMPLETE;
115 : krb5_error_code ret;
116 :
117 64218 : krb5_data_zero(&data);
118 :
119 64218 : sp = krb5_storage_emem();
120 64218 : 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 64218 : 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 64218 : case TOKEN_KEY:
135 64218 : ret = _gsskrb5i_get_token_key(context_handle, context, &key);
136 64218 : 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 64218 : if (ret)
144 0 : goto out;
145 64218 : 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 64218 : ret = krb5_store_keyblock(sp, *key);
152 64218 : if (ret)
153 0 : goto out;
154 :
155 64218 : ret = krb5_storage_to_data(sp, &data);
156 64218 : if (ret)
157 0 : goto out;
158 :
159 : {
160 : gss_buffer_desc value;
161 :
162 64218 : value.length = data.length;
163 64218 : value.value = data.data;
164 :
165 64218 : maj_stat = gss_add_buffer_set_member(minor_status,
166 : &value,
167 : data_set);
168 : }
169 :
170 64218 : out:
171 64218 : krb5_free_keyblock(context, key);
172 64218 : krb5_data_free(&data);
173 64218 : if (sp)
174 64218 : krb5_storage_free(sp);
175 64218 : if (ret) {
176 0 : *minor_status = ret;
177 0 : maj_stat = GSS_S_FAILURE;
178 : }
179 64218 : return maj_stat;
180 : }
181 :
182 114284 : 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 114284 : 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 114284 : ret = _gsskrb5i_get_token_key(context_handle, context, &key);
195 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
196 :
197 114284 : if (ret)
198 0 : goto out;
199 114284 : if (key == NULL) {
200 0 : ret = EINVAL;
201 0 : goto out;
202 : }
203 :
204 114284 : value.length = key->keyvalue.length;
205 114284 : value.value = key->keyvalue.data;
206 :
207 114284 : maj_stat = gss_add_buffer_set_member(minor_status,
208 : &value,
209 : data_set);
210 114284 : krb5_free_keyblock(context, key);
211 :
212 : /* MIT also returns the enctype encoded as an OID in data_set[1] */
213 :
214 114284 : out:
215 114284 : if (ret) {
216 0 : *minor_status = ret;
217 0 : maj_stat = GSS_S_FAILURE;
218 : }
219 114284 : return maj_stat;
220 : }
221 :
222 44380 : 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 44380 : *minor_status = 0;
234 44380 : *data_set = GSS_C_NO_BUFFER_SET;
235 :
236 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
237 44380 : 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 88760 : ret = krb5_ticket_get_authorization_data_type(context,
245 44380 : context_handle->ticket,
246 : ad_type,
247 : &data);
248 : HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
249 44380 : if (ret) {
250 7 : *minor_status = ret;
251 7 : return GSS_S_FAILURE;
252 : }
253 :
254 44373 : ad_data.value = data.data;
255 44373 : ad_data.length = data.length;
256 :
257 44373 : ret = gss_add_buffer_set_member(minor_status,
258 : &ad_data,
259 : data_set);
260 :
261 44373 : krb5_data_free(&data);
262 :
263 44373 : 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 : uint8_t old_enctype;
272 : 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 : HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
284 0 : old_enctype = ((context_handle->more_flags & IS_CFX) == 0);
285 : 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 : krb5_error_code ret;
306 0 : krb5_keyblock *key = NULL;
307 : int32_t number;
308 : int is_cfx;
309 : krb5_data data;
310 :
311 0 : *minor_status = 0;
312 :
313 : 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 : 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 : 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 : 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 : gss_buffer_desc value;
433 : unsigned char buf[4];
434 : OM_uint32 authtime;
435 :
436 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
437 0 : if (ctx->ticket == NULL) {
438 : 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 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
447 :
448 0 : _gsskrb5_encode_om_uint32(authtime, buf);
449 0 : value.length = sizeof(buf);
450 0 : value.value = buf;
451 :
452 0 : return gss_add_buffer_set_member(minor_status,
453 : &value,
454 : data_set);
455 : }
456 :
457 :
458 : static OM_uint32
459 0 : get_service_keyblock
460 : (OM_uint32 *minor_status,
461 : gsskrb5_ctx ctx,
462 : gss_buffer_set_t *data_set)
463 : {
464 0 : krb5_storage *sp = NULL;
465 : krb5_data data;
466 0 : OM_uint32 maj_stat = GSS_S_COMPLETE;
467 0 : krb5_error_code ret = EINVAL;
468 :
469 0 : sp = krb5_storage_emem();
470 0 : if (sp == NULL) {
471 0 : _gsskrb5_clear_status();
472 0 : *minor_status = ENOMEM;
473 0 : return GSS_S_FAILURE;
474 : }
475 :
476 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
477 0 : if (ctx->service_keyblock == NULL) {
478 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
479 0 : krb5_storage_free(sp);
480 0 : _gsskrb5_set_status(EINVAL, "No service keyblock on gssapi context");
481 0 : *minor_status = EINVAL;
482 0 : return GSS_S_FAILURE;
483 : }
484 :
485 0 : krb5_data_zero(&data);
486 :
487 0 : ret = krb5_store_keyblock(sp, *ctx->service_keyblock);
488 :
489 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
490 :
491 0 : if (ret)
492 0 : goto out;
493 :
494 0 : ret = krb5_storage_to_data(sp, &data);
495 0 : if (ret)
496 0 : goto out;
497 :
498 : {
499 : gss_buffer_desc value;
500 :
501 0 : value.length = data.length;
502 0 : value.value = data.data;
503 :
504 0 : maj_stat = gss_add_buffer_set_member(minor_status,
505 : &value,
506 : data_set);
507 : }
508 :
509 0 : out:
510 0 : krb5_data_free(&data);
511 0 : if (sp)
512 0 : krb5_storage_free(sp);
513 0 : if (ret) {
514 0 : *minor_status = ret;
515 0 : maj_stat = GSS_S_FAILURE;
516 : }
517 0 : return maj_stat;
518 : }
519 : /*
520 : *
521 : */
522 :
523 222882 : OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_sec_context_by_oid
524 : (OM_uint32 *minor_status,
525 : gss_const_ctx_id_t context_handle,
526 : const gss_OID desired_object,
527 : gss_buffer_set_t *data_set)
528 : {
529 : krb5_context context;
530 222882 : const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
531 : unsigned suffix;
532 :
533 222882 : if (ctx == NULL) {
534 0 : *minor_status = EINVAL;
535 0 : return GSS_S_NO_CONTEXT;
536 : }
537 :
538 222882 : GSSAPI_KRB5_INIT (&context);
539 :
540 222882 : if (gss_oid_equal(desired_object, GSS_KRB5_GET_TKT_FLAGS_X)) {
541 0 : return inquire_sec_context_tkt_flags(minor_status,
542 : ctx,
543 : data_set);
544 222882 : } else if (gss_oid_equal(desired_object, GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO)) {
545 0 : return inquire_sec_context_has_buggy_spnego(minor_status,
546 : ctx,
547 : data_set);
548 222882 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SUBKEY_X)) {
549 64218 : return inquire_sec_context_get_subkey(minor_status,
550 : ctx,
551 : context,
552 : TOKEN_KEY,
553 : data_set);
554 158664 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_INITIATOR_SUBKEY_X)) {
555 0 : return inquire_sec_context_get_subkey(minor_status,
556 : ctx,
557 : context,
558 : INITIATOR_KEY,
559 : data_set);
560 158664 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_ACCEPTOR_SUBKEY_X)) {
561 0 : return inquire_sec_context_get_subkey(minor_status,
562 : ctx,
563 : context,
564 : ACCEPTOR_KEY,
565 : data_set);
566 158664 : } else if (gss_oid_equal(desired_object, GSS_C_INQ_SSPI_SESSION_KEY)) {
567 114284 : return inquire_sec_context_get_sspi_session_key(minor_status,
568 : ctx,
569 : context,
570 : data_set);
571 44380 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_AUTHTIME_X)) {
572 0 : return get_authtime(minor_status, ctx, data_set);
573 44380 : } else if (oid_prefix_equal(desired_object,
574 : GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X,
575 : &suffix)) {
576 44380 : return inquire_sec_context_authz_data(minor_status,
577 : ctx,
578 : context,
579 : suffix,
580 : data_set);
581 0 : } else if (oid_prefix_equal(desired_object,
582 : GSS_KRB5_EXPORT_LUCID_CONTEXT_X,
583 : &suffix)) {
584 0 : if (suffix == 1)
585 0 : return export_lucid_sec_context_v1(minor_status,
586 : ctx,
587 : context,
588 : data_set);
589 0 : *minor_status = 0;
590 0 : return GSS_S_FAILURE;
591 0 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SERVICE_KEYBLOCK_X)) {
592 0 : return get_service_keyblock(minor_status, ctx, data_set);
593 : } else {
594 0 : *minor_status = 0;
595 0 : return GSS_S_FAILURE;
596 : }
597 : }
598 :
|