gss: add mechanism-force-mechListMIC hook to SPNEGO

NTLM erroneously requires a mechListMIC at the SPNEGO layer if an internal MIC
in the NTLM protocol was used. Add a private interface between SPNEGO and the
Samba NTLM mechanism to allow the mechanism to signal that a mechListMIC is
required even if it otherwise would not be.

This interface is the same as that supported by MIT.

Note that only the Samba NTLM mechanism currently implements this feature, it
is not implemented by the Heimdal NTLM mechanism (which does not support NTLM
authenticate message MICs).
This commit is contained in:
Luke Howard
2020-02-04 16:39:34 +11:00
parent 5d1a33f780
commit 921d528d8b
4 changed files with 48 additions and 8 deletions

View File

@@ -138,6 +138,9 @@ extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_inq_negoex_key_oid_desc;
extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_inq_negoex_verify_key_oid_desc;
#define GSS_C_INQ_NEGOEX_VERIFY_KEY (&__gss_c_inq_negoex_verify_key_oid_desc)
extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_inq_require_mechlist_mic_oid_desc;
#define GSS_C_INQ_REQUIRE_MECHLIST_MIC (&__gss_c_inq_require_mechlist_mic_oid_desc)
/*
* "Standard" mechs
*/

View File

@@ -130,6 +130,9 @@ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_negoex_key_oid_desc = { 11, rk_UNCO
/* GSS_C_INQ_NEGOEX_VERIFY_KEY - 1.2.840.113554.1.2.2.5.17 */
gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_negoex_verify_key_oid_desc = { 11, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x11") };
/* GSS_C_INQ_REQUIRE_MECHLIST_MIC - 1.3.6.1.4.1.7165.655.1.2 */
gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_require_mechlist_mic_oid_desc = { 11, rk_UNCONST("\x2b\x06\x01\x04\x01\xb7\x7d\x85\x0f\x01\x02") };
/* GSS_KRB5_MECHANISM - 1.2.840.113554.1.2.2 */
gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_mechanism_oid_desc = { 9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
@@ -318,6 +321,7 @@ gss_OID _gss_ot_internal[] = {
&__gss_c_inq_sspi_session_key_oid_desc,
&__gss_c_inq_negoex_key_oid_desc,
&__gss_c_inq_negoex_verify_key_oid_desc,
&__gss_c_inq_require_mechlist_mic_oid_desc,
&__gss_krb5_mechanism_oid_desc,
&__gss_ntlm_mechanism_oid_desc,
&__gss_spnego_mechanism_oid_desc,

View File

@@ -54,6 +54,7 @@ oid base GSS_C_INQ_WIN2K_PAC_X 1.2.752.43.13.3.128
oid base GSS_C_INQ_SSPI_SESSION_KEY 1.2.840.113554.1.2.2.5.5
oid base GSS_C_INQ_NEGOEX_KEY 1.2.840.113554.1.2.2.5.16
oid base GSS_C_INQ_NEGOEX_VERIFY_KEY 1.2.840.113554.1.2.2.5.17
oid base GSS_C_INQ_REQUIRE_MECHLIST_MIC 1.3.6.1.4.1.7165.655.1.2
#/*
# * "Standard" mechs

View File

@@ -152,6 +152,35 @@ 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)
{
OM_uint32 major, minor;
gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
uint8_t mech_require_mic = 0;
major = gss_inquire_sec_context_by_oid(&minor, ctx->negotiated_ctx_id,
GSS_C_INQ_REQUIRE_MECHLIST_MIC, &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);
gss_release_buffer_set(&minor, &data_set);
return mech_require_mic == 1;
}
/*
* Returns TRUE if it is safe to omit mechListMIC because the preferred
* mechanism was selected, and the peer did not require it.
@@ -160,15 +189,18 @@ OM_uint32 GSSAPI_CALLCONV _gss_spnego_internal_delete_sec_context
int
_gss_spnego_safe_omit_mechlist_mic(gssspnego_ctx ctx)
{
int safe_omit = 0;
int safe_omit = FALSE;
if (ctx->flags.peer_require_mic == FALSE)
safe_omit = gss_oid_equal(ctx->selected_mech_type, ctx->preferred_mech_type);
if (safe_omit)
_gss_mg_log(10, "spnego: safe to omit mechListMIC, as preferred mechanism selected");
else
_gss_mg_log(10, "spnego: mechListMIC required");
if (ctx->flags.peer_require_mic) {
_gss_mg_log(10, "spnego: mechListMIC required by peer");
} else if (mech_require_mechlist_mic_p(ctx)) {
_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");
} else {
_gss_mg_log(10, "spnego: mechListMIC required by default");
}
return safe_omit;
}