gss: fix downlevel Windows interop regression
The recent changes to SPNEGO removed support for GSS_C_PEER_HAS_UPDATED_SPNEGO, through which the Kerberos mechanism could indicate to SPNEGO that the peer did not suffer from SPNEGO conformance bugs present in some versions of Windows.* This patch restores this workaround, documented in [MS-SPNG] Appendix A <7> Section 3.1.5.1. Whilst improving interoperability with these admittedly now unsupported versions of Windows, it does introduce a risk that Kerberos with pre-AES ciphers could be negotiated in lieu of a stronger and more preferred mechanism. Note: this patch inverts the mechanism interface from GSS_C_PEER_HAS_UPDATED_SPNEGO to GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO, so that new mechanisms (which did not ship with these older versions of Windows) are not required to implement it. * Windows 2000, Windows 2003, and Windows XP
This commit is contained in:
@@ -154,8 +154,8 @@ extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_spnego_mechanism_oid_desc;
|
||||
#define GSS_SPNEGO_MECHANISM (&__gss_spnego_mechanism_oid_desc)
|
||||
|
||||
/* From Luke Howard */
|
||||
extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_peer_has_updated_spnego_oid_desc;
|
||||
#define GSS_C_PEER_HAS_UPDATED_SPNEGO (&__gss_c_peer_has_updated_spnego_oid_desc)
|
||||
extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_inq_peer_has_buggy_spnego_oid_desc;
|
||||
#define GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO (&__gss_c_inq_peer_has_buggy_spnego_oid_desc)
|
||||
|
||||
extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ntlm_reset_crypto_oid_desc;
|
||||
#define GSS_C_NTLM_RESET_CRYPTO (&__gss_c_ntlm_reset_crypto_oid_desc)
|
||||
|
@@ -263,39 +263,31 @@ static OM_uint32 inquire_sec_context_authz_data
|
||||
return ret;
|
||||
}
|
||||
|
||||
static OM_uint32 inquire_sec_context_has_updated_spnego
|
||||
static OM_uint32 inquire_sec_context_has_buggy_spnego
|
||||
(OM_uint32 *minor_status,
|
||||
const gsskrb5_ctx context_handle,
|
||||
gss_buffer_set_t *data_set)
|
||||
{
|
||||
int is_updated = 0;
|
||||
uint8_t old_enctype;
|
||||
gss_buffer_desc buffer;
|
||||
|
||||
*minor_status = 0;
|
||||
*data_set = GSS_C_NO_BUFFER_SET;
|
||||
|
||||
/*
|
||||
* For Windows SPNEGO implementations, both the initiator and the
|
||||
* acceptor are assumed to have been updated if a "newer" [CLAR] or
|
||||
* different enctype is negotiated for use by the Kerberos GSS-API
|
||||
* mechanism.
|
||||
* For Windows SPNEGO implementations, the initiator or acceptor
|
||||
* are presumed to be "buggy" (Windows 2003 or earlier) if an
|
||||
* "older" (i.e. pre-AES per RFC 4121) encryption type was used.
|
||||
*/
|
||||
|
||||
HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
|
||||
is_updated = (context_handle->more_flags & IS_CFX);
|
||||
if (is_updated == 0) {
|
||||
krb5_keyblock *acceptor_subkey;
|
||||
|
||||
if (context_handle->more_flags & LOCAL)
|
||||
acceptor_subkey = context_handle->auth_context->remote_subkey;
|
||||
else
|
||||
acceptor_subkey = context_handle->auth_context->local_subkey;
|
||||
|
||||
if (acceptor_subkey != NULL)
|
||||
is_updated = (acceptor_subkey->keytype !=
|
||||
context_handle->auth_context->keyblock->keytype);
|
||||
}
|
||||
old_enctype = ((context_handle->more_flags & IS_CFX) == 0);
|
||||
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
|
||||
|
||||
return is_updated ? GSS_S_COMPLETE : GSS_S_FAILURE;
|
||||
buffer.value = &old_enctype;
|
||||
buffer.length = sizeof(old_enctype);
|
||||
|
||||
return gss_add_buffer_set_member(minor_status, &buffer, data_set);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -549,10 +541,10 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_sec_context_by_oid
|
||||
return inquire_sec_context_tkt_flags(minor_status,
|
||||
ctx,
|
||||
data_set);
|
||||
} else if (gss_oid_equal(desired_object, GSS_C_PEER_HAS_UPDATED_SPNEGO)) {
|
||||
return inquire_sec_context_has_updated_spnego(minor_status,
|
||||
ctx,
|
||||
data_set);
|
||||
} else if (gss_oid_equal(desired_object, GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO)) {
|
||||
return inquire_sec_context_has_buggy_spnego(minor_status,
|
||||
ctx,
|
||||
data_set);
|
||||
} else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SUBKEY_X)) {
|
||||
return inquire_sec_context_get_subkey(minor_status,
|
||||
ctx,
|
||||
|
@@ -168,7 +168,6 @@ EXPORTS
|
||||
__gss_krb5_mechanism_oid_desc DATA
|
||||
__gss_ntlm_mechanism_oid_desc DATA
|
||||
__gss_spnego_mechanism_oid_desc DATA
|
||||
__gss_c_peer_has_updated_spnego_oid_desc DATA
|
||||
__gss_c_ma_mech_concrete_oid_desc DATA
|
||||
__gss_c_ma_mech_pseudo_oid_desc DATA
|
||||
__gss_c_ma_mech_composite_oid_desc DATA
|
||||
|
@@ -142,8 +142,8 @@ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_ntlm_mechanism_oid_desc = { 10, rk_UNCONS
|
||||
/* GSS_SPNEGO_MECHANISM - 1.3.6.1.5.5.2 */
|
||||
gss_OID_desc GSSAPI_LIB_VARIABLE __gss_spnego_mechanism_oid_desc = { 6, rk_UNCONST("\x2b\x06\x01\x05\x05\x02") };
|
||||
|
||||
/* GSS_C_PEER_HAS_UPDATED_SPNEGO - 1.3.6.1.4.1.5322.19.5 */
|
||||
gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_peer_has_updated_spnego_oid_desc = { 9, rk_UNCONST("\x2b\x06\x01\x04\x01\xa9\x4a\x13\x05") };
|
||||
/* GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO - 1.3.6.1.4.1.5322.19.6 */
|
||||
gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_peer_has_buggy_spnego_oid_desc = { 9, rk_UNCONST("\x2b\x06\x01\x04\x01\xa9\x4a\x13\x06") };
|
||||
|
||||
/* GSS_C_NTLM_RESET_CRYPTO - 1.3.6.1.4.1.7165.655.1.3 */
|
||||
gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ntlm_reset_crypto_oid_desc = { 11, rk_UNCONST("\x2b\x06\x01\x04\x01\xb7\x7d\x85\x0f\x01\x03") };
|
||||
@@ -325,7 +325,7 @@ gss_OID _gss_ot_internal[] = {
|
||||
&__gss_krb5_mechanism_oid_desc,
|
||||
&__gss_ntlm_mechanism_oid_desc,
|
||||
&__gss_spnego_mechanism_oid_desc,
|
||||
&__gss_c_peer_has_updated_spnego_oid_desc,
|
||||
&__gss_c_inq_peer_has_buggy_spnego_oid_desc,
|
||||
&__gss_c_ntlm_reset_crypto_oid_desc,
|
||||
&__gss_negoex_mechanism_oid_desc,
|
||||
&__gss_c_ma_mech_concrete_oid_desc,
|
||||
|
@@ -66,7 +66,7 @@ oid base GSS_SPNEGO_MECHANISM 1.3.6.1.5.5.2
|
||||
|
||||
# /* From Luke Howard */
|
||||
|
||||
oid base GSS_C_PEER_HAS_UPDATED_SPNEGO 1.3.6.1.4.1.5322.19.5
|
||||
oid base GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO 1.3.6.1.4.1.5322.19.6
|
||||
oid base GSS_C_NTLM_RESET_CRYPTO 1.3.6.1.4.1.7165.655.1.3
|
||||
oid base GSS_NEGOEX_MECHANISM 1.3.6.1.4.1.311.2.2.30
|
||||
|
||||
|
@@ -152,38 +152,30 @@ OM_uint32 GSSAPI_CALLCONV _gss_spnego_internal_delete_sec_context
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns TRUE if the mechanism believes that a mechListMIC is required.
|
||||
* This is an internal interface for NTLM which requires a mechListMIC if
|
||||
* an internal MIC in the NTLM protocol was used. Note that only the Samba
|
||||
* NTLM mechanism supports this, it is not yet implemented in Heimdal's.
|
||||
*/
|
||||
|
||||
static int
|
||||
mech_require_mechlist_mic_p(gssspnego_ctx ctx)
|
||||
inq_context_by_oid_bool(gssspnego_ctx ctx, gss_OID oid)
|
||||
{
|
||||
OM_uint32 major, minor;
|
||||
gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
|
||||
uint8_t mech_require_mic = 0;
|
||||
uint8_t ret = 0;
|
||||
|
||||
major = gss_inquire_sec_context_by_oid(&minor, ctx->negotiated_ctx_id,
|
||||
GSS_C_INQ_REQUIRE_MECHLIST_MIC, &data_set);
|
||||
oid, &data_set);
|
||||
if (major != GSS_S_COMPLETE)
|
||||
return FALSE;
|
||||
|
||||
if (data_set != GSS_C_NO_BUFFER_SET &&
|
||||
data_set->count == 1 &&
|
||||
data_set->elements[0].length == 1)
|
||||
mech_require_mic = *((uint8_t *)data_set->elements[0].value);
|
||||
ret = *((uint8_t *)data_set->elements[0].value);
|
||||
|
||||
gss_release_buffer_set(&minor, &data_set);
|
||||
|
||||
return mech_require_mic == 1;
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns TRUE if it is safe to omit mechListMIC because the preferred
|
||||
* mechanism was selected, and the peer did not require it.
|
||||
* Returns TRUE if it is safe to omit mechListMIC.
|
||||
*/
|
||||
|
||||
int
|
||||
@@ -193,11 +185,16 @@ _gss_spnego_safe_omit_mechlist_mic(gssspnego_ctx ctx)
|
||||
|
||||
if (ctx->flags.peer_require_mic) {
|
||||
_gss_mg_log(10, "spnego: mechListMIC required by peer");
|
||||
} else if (mech_require_mechlist_mic_p(ctx)) {
|
||||
} else if (inq_context_by_oid_bool(ctx, GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO)) {
|
||||
/* [MS-SPNG] Appendix A <7> Section 3.1.5.1: may be old peer with buggy SPNEGO */
|
||||
safe_omit = TRUE;
|
||||
_gss_mg_log(10, "spnego: mechListMIC omitted for legacy interoperability");
|
||||
} else if (inq_context_by_oid_bool(ctx, GSS_C_INQ_REQUIRE_MECHLIST_MIC)) {
|
||||
/* [MS-SPNG] Appendix A <7> Section 3.1.5.1: allow NTLM to force MIC */
|
||||
_gss_mg_log(10, "spnego: mechListMIC required by mechanism");
|
||||
} else if (gss_oid_equal(ctx->selected_mech_type, ctx->preferred_mech_type)) {
|
||||
safe_omit = TRUE;
|
||||
_gss_mg_log(10, "spnego: mechListMIC may be omitted as preferred mechanism selected");
|
||||
_gss_mg_log(10, "spnego: mechListMIC omitted as preferred mechanism selected");
|
||||
} else {
|
||||
_gss_mg_log(10, "spnego: mechListMIC required by default");
|
||||
}
|
||||
|
@@ -171,7 +171,6 @@ HEIMDAL_GSS_2.0 {
|
||||
__gss_krb5_mechanism_oid_desc;
|
||||
__gss_ntlm_mechanism_oid_desc;
|
||||
__gss_spnego_mechanism_oid_desc;
|
||||
__gss_c_peer_has_updated_spnego_oid_desc;
|
||||
__gss_c_ma_mech_concrete_oid_desc;
|
||||
__gss_c_ma_mech_pseudo_oid_desc;
|
||||
__gss_c_ma_mech_composite_oid_desc;
|
||||
|
Reference in New Issue
Block a user