Add context extension to reset crypto state crypto_reset
authorSimo Sorce <simo@redhat.com>
Mon, 23 May 2016 14:46:13 +0000 (10:46 -0400)
committerSimo Sorce <simo@redhat.com>
Fri, 27 May 2016 18:43:41 +0000 (14:43 -0400)
This is need to account for the special handling described in MS-SPNG 3.3.5.1
It instructs sthat the NTLMSSP crypto state needs to be reset if MIC is
performed in the SPNEGO layer.

Signed-off-by: Simo Sorce <simo@redhat.com>
src/gss_sec_ctx.c
src/gssapi_ntlmssp.h
src/ntlm.h
src/ntlm_crypto.c

index 25983891c06c8fb7735f9a1fed810904ed5446d9..a926e2408621b1dd29617ffe53864f2292c0f47e 100644 (file)
@@ -1114,6 +1114,43 @@ uint32_t gssntlm_set_seq_num(uint32_t *minor_status,
     return GSSERRS(0, GSS_S_COMPLETE);
 }
 
+gss_OID_desc reset_crypto_oid = {
+    GSS_NTLMSSP_RESET_CRYPTO_OID_LENGTH,
+    discard_const(GSS_NTLMSSP_RESET_CRYPTO_OID_STRING)
+};
+
+uint32_t gssntlm_reset_crypto(uint32_t *minor_status,
+                              struct gssntlm_ctx *ctx,
+                              const gss_buffer_t value)
+{
+    uint32_t retmin;
+    uint32_t retmaj;
+
+    if (value->length != 4) {
+        return GSSERRS(ERR_BADARG, GSS_S_FAILURE);
+    }
+
+    /* reset crypto state */
+    if (ctx->neg_flags & (NTLMSSP_NEGOTIATE_SIGN |
+                            NTLMSSP_NEGOTIATE_SEAL)) {
+        uint32_t val;
+
+        memcpy(&val, value->value, value->length);
+
+        /* A val of 1 means we want to reset the verifier handle,
+         * which is the receive handle for NTLM, otherwise we reset
+         * the send handle. */
+        retmin = ntlm_reset_rc4_state(ctx->neg_flags, (val == 1),
+                                      &ctx->exported_session_key,
+                                      &ctx->crypto_state);
+        if (retmin) {
+            return GSSERRS(retmin, GSS_S_FAILURE);
+        }
+    }
+
+    return GSSERRS(0, GSS_S_COMPLETE);
+}
+
 uint32_t gssntlm_set_sec_context_option(uint32_t *minor_status,
                                         gss_ctx_id_t *context_handle,
                                         const gss_OID desired_object,
@@ -1135,6 +1172,8 @@ uint32_t gssntlm_set_sec_context_option(uint32_t *minor_status,
     /* set seq num */
     if (gss_oid_equal(desired_object, &set_seq_num_oid)) {
         return gssntlm_set_seq_num(minor_status, ctx, value);
+    } else if (gss_oid_equal(desired_object, &reset_crypto_oid)) {
+        return gssntlm_reset_crypto(minor_status, ctx, value);
     }
 
     return GSSERRS(ERR_BADARG, GSS_S_UNAVAILABLE);
index 2aae4348fce8d77c999c54787eebbed9d411b2cf..04dd76c10b33d59cb7aee616b7947c75cca3f2c2 100644 (file)
@@ -59,6 +59,15 @@ extern "C" {
 #define GSS_SPNEGO_REQUIRE_MIC_OID_STRING GSS_NTLMSSP_BASE_OID_STRING "\x02"
 #define GSS_SPNEGO_REQUIRE_MIC_OID_LENGTH GSS_NTLMSSP_BASE_OID_LENGTH + 1
 
+/* SPNEGO Reset Crypto OID
+ * MS-SPNG 3.3.5.1 warns hat the NTLM mechanism requires to reset the
+ * crypto engine when the SPNEGO layer uses a MechListMIC.
+ * This OID is queried by the SPNEGO mechanism after a MIC processing to
+ * cause the crypto engine to be reset.
+ */
+#define GSS_NTLMSSP_RESET_CRYPTO_OID_STRING GSS_NTLMSSP_BASE_OID_STRING "\x03"
+#define GSS_NTLMSSP_RESET_CRYPTO_OID_LENGTH GSS_NTLMSSP_BASE_OID_LENGTH + 1
+
 #define GSS_NTLMSSP_CS_DOMAIN "ntlmssp_domain"
 #define GSS_NTLMSSP_CS_NTHASH "ntlmssp_nthash"
 #define GSS_NTLMSSP_CS_PASSWORD "ntlmssp_password"
index 51204ec580f8e06b2e0b4c28ec8ec7b8838363bf..a62e407820b38f3ddeff3835542dcc7175cbb6c2 100644 (file)
@@ -341,6 +341,20 @@ int ntlm_signseal_keys(uint32_t flags, bool client,
                        struct ntlm_key *session_key,
                        struct ntlm_signseal_state *signseal_state);
 
+/**
+ * @brief   Resets the RC4 state for the send or receive handle
+ *
+ * @param flags                 Incoming challenge/authenticate flags
+ * @param recv                  Wheter to reset the send or recive buffer
+ * @param session_key           The session key
+ * @param signseal_state        Sign and seal keys and state
+ *
+ * @return 0 on success or error.
+ */
+int ntlm_reset_rc4_state(uint32_t flags, bool recv,
+                         struct ntlm_key *session_key,
+                         struct ntlm_signseal_state *state);
+
 /**
  * @brief   Verifies a NTLM v1 NT Response
  *
index 13e886e0af90665132022470c487e7464a01b451..be229e55e61c2935e71a795b88e7dec80c093a2e 100644 (file)
@@ -562,6 +562,34 @@ int ntlm_signseal_keys(uint32_t flags, bool client,
     }
 }
 
+int ntlm_reset_rc4_state(uint32_t flags, bool recv,
+                         struct ntlm_key *session_key,
+                         struct ntlm_signseal_state *state)
+{
+    struct ntlm_buffer rc4_key;
+    int ret;
+
+    if (!(flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
+        return no_ext_sec_handle(flags, session_key,
+                                 &state->send.seal_handle);
+    }
+
+    if (recv) {
+        RC4_FREE(&state->recv.seal_handle);
+        rc4_key.data = state->recv.seal_key.data;
+        rc4_key.length = state->recv.seal_key.length;
+        ret = RC4_INIT(&rc4_key, NTLM_CIPHER_DECRYPT,
+                       &state->recv.seal_handle);
+    } else {
+        RC4_FREE(&state->send.seal_handle);
+        rc4_key.data = state->send.seal_key.data;
+        rc4_key.length = state->send.seal_key.length;
+        ret = RC4_INIT(&rc4_key, NTLM_CIPHER_ENCRYPT,
+                       &state->send.seal_handle);
+    }
+    return ret;
+}
+
 static int ntlm_seal_regen(struct ntlm_signseal_handle *h)
 {
     struct ntlm_buffer payload;