2 * Copyright (c) 2010 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
7 * Portions Copyright (c) 2010 PADL Software Pty Ltd. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the Institute nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include "mech_locl.h"
39 #include <crypto-headers.h>
42 get_option_def(int def
, gss_const_OID mech
, gss_mo_desc
*mo
, gss_buffer_t value
)
48 _gss_mo_get_option_1(gss_const_OID mech
, gss_mo_desc
*mo
, gss_buffer_t value
)
50 return get_option_def(1, mech
, mo
, value
);
54 _gss_mo_get_option_0(gss_const_OID mech
, gss_mo_desc
*mo
, gss_buffer_t value
)
56 return get_option_def(0, mech
, mo
, value
);
60 _gss_mo_get_ctx_as_string(gss_const_OID mech
, gss_mo_desc
*mo
, gss_buffer_t value
)
63 value
->value
= strdup((char *)mo
->ctx
);
64 if (value
->value
== NULL
)
66 value
->length
= strlen((char *)mo
->ctx
);
68 return GSS_S_COMPLETE
;
71 GSSAPI_LIB_FUNCTION
int GSSAPI_LIB_CALL
72 gss_mo_set(gss_const_OID mech
, gss_const_OID option
,
73 int enable
, gss_buffer_t value
)
75 gssapi_mech_interface m
;
78 if ((m
= __gss_get_mechanism(mech
)) == NULL
)
79 return GSS_S_BAD_MECH
;
81 for (n
= 0; n
< m
->gm_mo_num
; n
++)
82 if (gss_oid_equal(option
, m
->gm_mo
[n
].option
) && m
->gm_mo
[n
].set
)
83 return m
->gm_mo
[n
].set(mech
, &m
->gm_mo
[n
], enable
, value
);
85 return GSS_S_UNAVAILABLE
;
88 GSSAPI_LIB_FUNCTION
int GSSAPI_LIB_CALL
89 gss_mo_get(gss_const_OID mech
, gss_const_OID option
, gss_buffer_t value
)
91 gssapi_mech_interface m
;
94 _mg_buffer_zero(value
);
96 if ((m
= __gss_get_mechanism(mech
)) == NULL
)
97 return GSS_S_BAD_MECH
;
99 for (n
= 0; n
< m
->gm_mo_num
; n
++)
100 if (gss_oid_equal(option
, m
->gm_mo
[n
].option
) && m
->gm_mo
[n
].get
)
101 return m
->gm_mo
[n
].get(mech
, &m
->gm_mo
[n
], value
);
103 return GSS_S_UNAVAILABLE
;
107 add_all_mo(gssapi_mech_interface m
, gss_OID_set
*options
, OM_uint32 mask
)
112 for (n
= 0; n
< m
->gm_mo_num
; n
++)
113 if ((m
->gm_mo
[n
].flags
& mask
) == mask
)
114 gss_add_oid_set_member(&minor
, m
->gm_mo
[n
].option
, options
);
117 GSSAPI_LIB_FUNCTION
void GSSAPI_LIB_CALL
118 gss_mo_list(gss_const_OID mech
, gss_OID_set
*options
)
120 gssapi_mech_interface m
;
121 OM_uint32 major
, minor
;
126 *options
= GSS_C_NO_OID_SET
;
128 if ((m
= __gss_get_mechanism(mech
)) == NULL
)
131 major
= gss_create_empty_oid_set(&minor
, options
);
132 if (major
!= GSS_S_COMPLETE
)
135 add_all_mo(m
, options
, 0);
138 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
139 gss_mo_name(gss_const_OID mech
, gss_const_OID option
, gss_buffer_t name
)
141 gssapi_mech_interface m
;
145 return GSS_S_BAD_NAME
;
147 if ((m
= __gss_get_mechanism(mech
)) == NULL
)
148 return GSS_S_BAD_MECH
;
150 for (n
= 0; n
< m
->gm_mo_num
; n
++) {
151 if (gss_oid_equal(option
, m
->gm_mo
[n
].option
)) {
153 * If there is no name, its because its a GSS_C_MA and
154 * there is already a table for that.
156 if (m
->gm_mo
[n
].name
) {
157 name
->value
= strdup(m
->gm_mo
[n
].name
);
158 if (name
->value
== NULL
)
159 return GSS_S_BAD_NAME
;
160 name
->length
= strlen(m
->gm_mo
[n
].name
);
161 return GSS_S_COMPLETE
;
164 return gss_display_mech_attr(&junk
, option
,
169 return GSS_S_BAD_NAME
;
173 * Helper function to allow NULL name
177 mo_value(const gss_const_OID mech
, gss_const_OID option
, gss_buffer_t name
)
180 return GSS_S_COMPLETE
;
182 return gss_mo_get(mech
, option
, name
);
185 /* code derived from draft-ietf-cat-sasl-gssapi-01 */
186 static char basis_32
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
189 make_sasl_name(OM_uint32
*minor
, const gss_OID mech
, char sasl_name
[16])
193 u_char hdr
[2], hash
[20], *h
= hash
;
195 if (mech
->length
> 127)
196 return GSS_S_BAD_MECH
;
199 hdr
[1] = mech
->length
;
201 ctx
= EVP_MD_CTX_create();
202 EVP_DigestInit_ex(ctx
, EVP_sha1(), NULL
);
203 EVP_DigestUpdate(ctx
, hdr
, 2);
204 EVP_DigestUpdate(ctx
, mech
->elements
, mech
->length
);
205 EVP_DigestFinal_ex(ctx
, hash
, NULL
);
207 memcpy(p
, "GS2-", 4);
210 *p
++ = basis_32
[(h
[0] >> 3)];
211 *p
++ = basis_32
[((h
[0] & 7) << 2) | (h
[1] >> 6)];
212 *p
++ = basis_32
[(h
[1] & 0x3f) >> 1];
213 *p
++ = basis_32
[((h
[1] & 1) << 4) | (h
[2] >> 4)];
214 *p
++ = basis_32
[((h
[2] & 0xf) << 1) | (h
[3] >> 7)];
215 *p
++ = basis_32
[(h
[3] & 0x7f) >> 2];
216 *p
++ = basis_32
[((h
[3] & 3) << 3) | (h
[4] >> 5)];
217 *p
++ = basis_32
[(h
[4] & 0x1f)];
218 *p
++ = basis_32
[(h
[5] >> 3)];
219 *p
++ = basis_32
[((h
[5] & 7) << 2) | (h
[6] >> 6)];
220 *p
++ = basis_32
[(h
[6] & 0x3f) >> 1];
224 return GSS_S_COMPLETE
;
228 * gss_inquire_saslname_for_mech() wrapper that uses MIT SPI
231 inquire_saslname_for_mech_compat(OM_uint32
*minor
,
232 const gss_OID desired_mech
,
233 gss_buffer_t sasl_mech_name
,
234 gss_buffer_t mech_name
,
235 gss_buffer_t mech_description
)
237 struct gss_mech_compat_desc_struct
*gmc
;
238 gssapi_mech_interface m
;
241 m
= __gss_get_mechanism(desired_mech
);
243 return GSS_S_BAD_MECH
;
247 if (gmc
!= NULL
&& gmc
->gmc_inquire_saslname_for_mech
!= NULL
) {
248 major
= gmc
->gmc_inquire_saslname_for_mech(minor
,
254 major
= GSS_S_UNAVAILABLE
;
261 * Returns different protocol names and description of the mechanism.
263 * @param minor_status minor status code
264 * @param desired_mech mech list query
265 * @param sasl_mech_name SASL GS2 protocol name
266 * @param mech_name gssapi protocol name
267 * @param mech_description description of gssapi mech
269 * @return returns GSS_S_COMPLETE or a error code.
274 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
275 gss_inquire_saslname_for_mech(OM_uint32
*minor_status
,
276 const gss_OID desired_mech
,
277 gss_buffer_t sasl_mech_name
,
278 gss_buffer_t mech_name
,
279 gss_buffer_t mech_description
)
283 _mg_buffer_zero(sasl_mech_name
);
284 _mg_buffer_zero(mech_name
);
285 _mg_buffer_zero(mech_description
);
290 if (desired_mech
== NULL
)
291 return GSS_S_BAD_MECH
;
293 major
= mo_value(desired_mech
, GSS_C_MA_SASL_MECH_NAME
, sasl_mech_name
);
294 if (major
== GSS_S_COMPLETE
) {
296 major
= mo_value(desired_mech
, GSS_C_MA_MECH_NAME
, mech_name
);
297 if (GSS_ERROR(major
))
300 major
= mo_value(desired_mech
, GSS_C_MA_MECH_DESCRIPTION
, mech_description
);
301 if (GSS_ERROR(major
))
305 if (GSS_ERROR(major
)) {
306 /* API-as-SPI compatibility */
307 major
= inquire_saslname_for_mech_compat(minor_status
,
314 if (GSS_ERROR(major
)) {
315 /* Algorithmically dervied SASL mechanism name */
317 gss_buffer_desc tmp
= { sizeof(buf
) - 1, buf
};
319 major
= make_sasl_name(minor_status
, desired_mech
, buf
);
320 if (GSS_ERROR(major
))
323 major
= _gss_copy_buffer(minor_status
, &tmp
, sasl_mech_name
);
324 if (GSS_ERROR(major
))
332 * Find a mech for a sasl name
334 * @param minor_status minor status code
335 * @param sasl_mech_name
338 * @return returns GSS_S_COMPLETE or an error code.
341 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
342 gss_inquire_mech_for_saslname(OM_uint32
*minor_status
,
343 const gss_buffer_t sasl_mech_name
,
346 struct _gss_mech_switch
*m
;
347 gss_buffer_desc name
;
348 OM_uint32 major
, junk
;
355 HEIM_SLIST_FOREACH(m
, &_gss_mechs
, gm_link
) {
356 struct gss_mech_compat_desc_struct
*gmc
;
359 major
= mo_value(&m
->gm_mech_oid
, GSS_C_MA_SASL_MECH_NAME
, &name
);
360 if (major
== GSS_S_COMPLETE
&&
361 name
.length
== sasl_mech_name
->length
&&
362 memcmp(name
.value
, sasl_mech_name
->value
, name
.length
) == 0) {
363 gss_release_buffer(&junk
, &name
);
364 *mech_type
= &m
->gm_mech_oid
;
365 return GSS_S_COMPLETE
;
367 gss_release_buffer(&junk
, &name
);
369 if (GSS_ERROR(major
)) {
370 /* API-as-SPI compatibility */
371 gmc
= m
->gm_mech
.gm_compat
;
372 if (gmc
&& gmc
->gmc_inquire_mech_for_saslname
) {
373 major
= gmc
->gmc_inquire_mech_for_saslname(minor_status
,
376 if (major
== GSS_S_COMPLETE
)
377 return GSS_S_COMPLETE
;
381 if (GSS_ERROR(major
)) {
382 /* Algorithmically dervied SASL mechanism name */
383 if (sasl_mech_name
->length
== 16 &&
384 make_sasl_name(minor_status
, &m
->gm_mech_oid
, buf
) == GSS_S_COMPLETE
&&
385 memcmp(buf
, sasl_mech_name
->value
, 16) == 0) {
386 *mech_type
= &m
->gm_mech_oid
;
387 return GSS_S_COMPLETE
;
392 return GSS_S_BAD_MECH
;
396 * Test mechanism against indicated attributes using both Heimdal and
400 test_mech_attrs(gssapi_mech_interface mi
,
401 gss_const_OID_set mech_attrs
,
402 gss_const_OID_set against_attrs
,
408 if (against_attrs
== GSS_C_NO_OID_SET
)
411 for (n
= 0; n
< against_attrs
->count
; n
++) {
412 for (m
= 0; m
< mi
->gm_mo_num
; m
++) {
413 eq
= gss_oid_equal(mi
->gm_mo
[m
].option
,
414 &against_attrs
->elements
[n
]);
418 if (mech_attrs
!= GSS_C_NO_OID_SET
) {
419 for (m
= 0; m
< mech_attrs
->count
; m
++) {
420 eq
= gss_oid_equal(&mech_attrs
->elements
[m
],
421 &against_attrs
->elements
[n
]);
434 * Return set of mechanism that fullfill the criteria
436 * @param minor_status minor status code
437 * @param desired_mech_attrs
438 * @param except_mech_attrs
439 * @param critical_mech_attrs
440 * @param mechs returned mechs, free with gss_release_oid_set().
442 * @return returns GSS_S_COMPLETE or an error code.
445 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
446 gss_indicate_mechs_by_attrs(OM_uint32
* minor_status
,
447 gss_const_OID_set desired_mech_attrs
,
448 gss_const_OID_set except_mech_attrs
,
449 gss_const_OID_set critical_mech_attrs
,
452 struct _gss_mech_switch
*ms
;
453 gss_OID_set mech_attrs
= GSS_C_NO_OID_SET
;
454 gss_OID_set known_mech_attrs
= GSS_C_NO_OID_SET
;
457 major
= gss_create_empty_oid_set(minor_status
, mechs
);
458 if (GSS_ERROR(major
))
463 HEIM_SLIST_FOREACH(ms
, &_gss_mechs
, gm_link
) {
464 gssapi_mech_interface mi
= &ms
->gm_mech
;
465 struct gss_mech_compat_desc_struct
*gmc
= mi
->gm_compat
;
468 if (gmc
&& gmc
->gmc_inquire_attrs_for_mech
) {
469 major
= gmc
->gmc_inquire_attrs_for_mech(minor_status
,
473 if (GSS_ERROR(major
))
478 * Test mechanism supports all of desired_mech_attrs;
479 * none of except_mech_attrs;
480 * and knows of all critical_mech_attrs.
482 if (test_mech_attrs(mi
, mech_attrs
, desired_mech_attrs
, 0) &&
483 test_mech_attrs(mi
, mech_attrs
, except_mech_attrs
, 1) &&
484 test_mech_attrs(mi
, known_mech_attrs
, critical_mech_attrs
, 0)) {
485 major
= gss_add_oid_set_member(minor_status
, &mi
->gm_mech_oid
, mechs
);
488 gss_release_oid_set(&tmp
, &mech_attrs
);
489 gss_release_oid_set(&tmp
, &known_mech_attrs
);
491 if (GSS_ERROR(major
))
499 * List support attributes for a mech and/or all mechanisms.
501 * @param minor_status minor status code
502 * @param mech given together with mech_attr will return the list of
503 * attributes for mechanism, can optionally be GSS_C_NO_OID.
504 * @param mech_attr see mech parameter, can optionally be NULL,
505 * release with gss_release_oid_set().
506 * @param known_mech_attrs all attributes for mechanisms supported,
507 * release with gss_release_oid_set().
512 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
513 gss_inquire_attrs_for_mech(OM_uint32
* minor_status
,
515 gss_OID_set
*mech_attr
,
516 gss_OID_set
*known_mech_attrs
)
518 OM_uint32 major
, junk
;
520 if (known_mech_attrs
)
521 *known_mech_attrs
= GSS_C_NO_OID_SET
;
523 if (mech_attr
&& mech
) {
524 gssapi_mech_interface m
;
525 struct gss_mech_compat_desc_struct
*gmc
;
527 if ((m
= __gss_get_mechanism(mech
)) == NULL
) {
529 return GSS_S_BAD_MECH
;
534 if (gmc
&& gmc
->gmc_inquire_attrs_for_mech
) {
535 major
= gmc
->gmc_inquire_attrs_for_mech(minor_status
,
540 major
= gss_create_empty_oid_set(minor_status
, mech_attr
);
541 if (major
== GSS_S_COMPLETE
)
542 add_all_mo(m
, mech_attr
, GSS_MO_MA
);
544 if (GSS_ERROR(major
))
548 if (known_mech_attrs
) {
549 struct _gss_mech_switch
*m
;
551 if (*known_mech_attrs
== GSS_C_NO_OID_SET
) {
552 major
= gss_create_empty_oid_set(minor_status
, known_mech_attrs
);
553 if (GSS_ERROR(major
)) {
555 gss_release_oid_set(&junk
, mech_attr
);
562 HEIM_SLIST_FOREACH(m
, &_gss_mechs
, gm_link
)
563 add_all_mo(&m
->gm_mech
, known_mech_attrs
, GSS_MO_MA
);
567 return GSS_S_COMPLETE
;
571 * Return names and descriptions of mech attributes
573 * @param minor_status minor status code
579 * @return returns GSS_S_COMPLETE or an error code.
582 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
583 gss_display_mech_attr(OM_uint32
* minor_status
,
584 gss_const_OID mech_attr
,
586 gss_buffer_t short_desc
,
587 gss_buffer_t long_desc
)
589 struct _gss_oid_name_table
*ma
= NULL
;
593 _mg_buffer_zero(name
);
594 _mg_buffer_zero(short_desc
);
595 _mg_buffer_zero(long_desc
);
600 for (n
= 0; ma
== NULL
&& _gss_ont_ma
[n
].oid
; n
++)
601 if (gss_oid_equal(mech_attr
, _gss_ont_ma
[n
].oid
))
602 ma
= &_gss_ont_ma
[n
];
605 return GSS_S_BAD_MECH_ATTR
;
609 bd
.value
= rk_UNCONST(ma
->name
);
610 bd
.length
= strlen(ma
->name
);
611 major
= _gss_copy_buffer(minor_status
, &bd
, name
);
612 if (major
!= GSS_S_COMPLETE
)
618 bd
.value
= rk_UNCONST(ma
->short_desc
);
619 bd
.length
= strlen(ma
->short_desc
);
620 major
= _gss_copy_buffer(minor_status
, &bd
, short_desc
);
621 if (major
!= GSS_S_COMPLETE
)
627 bd
.value
= rk_UNCONST(ma
->long_desc
);
628 bd
.length
= strlen(ma
->long_desc
);
629 major
= _gss_copy_buffer(minor_status
, &bd
, long_desc
);
630 if (major
!= GSS_S_COMPLETE
)
634 return GSS_S_COMPLETE
;