Blob Blame History Raw
From a7e899281f24aadec536f3cb0adf7340683c27cb Mon Sep 17 00:00:00 2001
From: Simo Sorce <simo@redhat.com>
Date: Wed, 30 Mar 2016 13:00:19 -0400
Subject: [PATCH] Add SPNEGO special case for NTLMSSP+MechListMIC

MS-SPNG section 3.3.5.1 documents an odd behavior the SPNEGO layer
needs to implement specifically for the NTLMSSP mechanism.  This is
required for compatibility with Windows services.

ticket: 8423 (new)
---
 src/lib/gssapi/spnego/spnego_mech.c | 48 +++++++++++++++++++++++++++++++++----
 1 file changed, 43 insertions(+), 5 deletions(-)

diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index bb754d9..b76f7d6 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -520,6 +520,45 @@ mech_requires_mechlistMIC(spnego_gss_ctx_id_t sc)
 	return result;
 }
 
+/* iso(1) org(3) dod(6) internet(1) private(4) enterprises(1) Microsoft(311)
+ * security(2) mechanisms(2) NTLM(10) */
+static const gss_OID_desc gss_mech_ntlmssp_oid =
+	{ 10, "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a" };
+
+/* iso(1) org(3) dod(6) internet(1) private(4) enterprises(1) samba(7165)
+ * gssntlmssp(655) controls(1) ntlmssp_reset_crypto(3) */
+static const gss_OID_desc ntlmssp_reset_crypto_oid =
+	{ 11, "\x2B\x06\x01\x04\x01\xB7\x7D\x85\x0F\x01\x03" };
+
+/*
+ * MS-SPNG section 3.3.5.1 warns that the NTLM mechanism requires special
+ * handling of the crypto state to interop with Windows.  If the mechanism for
+ * sc is SPNEGO, invoke a mechanism-specific operation on the context to reset
+ * the RC4 state after producing or verifying a MIC.  Ignore a result of
+ * GSS_S_UNAVAILABLE for compatibility with older versions of the mechanism
+ * that do not support this functionality.
+ */
+static OM_uint32
+ntlmssp_reset_crypto_state(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+			   OM_uint32 verify)
+{
+	OM_uint32 major, minor;
+	gss_buffer_desc value;
+
+	if (!g_OID_equal(sc->internal_mech, &gss_mech_ntlmssp_oid))
+		return GSS_S_COMPLETE;
+
+	value.length = sizeof(verify);
+	value.value = &verify;
+	major = gss_set_sec_context_option(&minor, &sc->ctx_handle,
+					   (gss_OID)&ntlmssp_reset_crypto_oid,
+					   &value);
+	if (major == GSS_S_UNAVAILABLE)
+		return GSS_S_COMPLETE;
+	*minor_status = minor;
+	return major;
+}
+
 /*
  * Both initiator and acceptor call here to verify and/or create mechListMIC,
  * and to consistency-check the MIC state.  handle_mic is invoked only if the
@@ -601,6 +640,8 @@ process_mic(OM_uint32 *minor_status, gss_buffer_t mic_in,
 		ret = gss_verify_mic(minor_status, sc->ctx_handle,
 				     &sc->DER_mechTypes,
 				     mic_in, &qop_state);
+		if (ret == GSS_S_COMPLETE)
+			ret = ntlmssp_reset_crypto_state(minor_status, sc, 1);
 		if (ret != GSS_S_COMPLETE) {
 			*negState = REJECT;
 			*tokflag = ERROR_TOKEN_SEND;
@@ -615,6 +656,8 @@ process_mic(OM_uint32 *minor_status, gss_buffer_t mic_in,
 				  GSS_C_QOP_DEFAULT,
 				  &sc->DER_mechTypes,
 				  &tmpmic);
+		if (ret == GSS_S_COMPLETE)
+			ret = ntlmssp_reset_crypto_state(minor_status, sc, 0);
 		if (ret != GSS_S_COMPLETE) {
 			gss_release_buffer(&tmpmin, &tmpmic);
 			*tokflag = NO_TOKEN_SEND;
@@ -820,11 +863,6 @@ init_ctx_nego(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
 	return ret;
 }
 
-/* iso(1) org(3) dod(6) internet(1) private(4) enterprise(1) Microsoft(311)
- * security(2) mechanisms(2) NTLM(10) */
-static const gss_OID_desc gss_mech_ntlmssp_oid =
-	{ 10, "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a" };
-
 /*
  * Handle acceptor's counter-proposal of an alternative mechanism.
  */
-- 
2.8.1