CVE-2016-2110: auth/ntlmssp: implement gensec_ntlmssp_may_reset_crypto()
authorStefan Metzmacher <metze@samba.org>
Tue, 17 Dec 2013 10:49:31 +0000 (11:49 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 12 Apr 2016 17:25:23 +0000 (19:25 +0200)
[MS-SPNG] requires the NTLMSSP RC4 states to be reset after
the SPNEGO exchange with mechListMic verification (new_spnego).

The 'reset_full' parameter is needed to support the broken
behavior that windows only resets the RC4 states but not the
sequence numbers. Which means this functionality is completely
useless... But we want to work against all windows versions...

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11644

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: G√ľnther Deschner <gd@samba.org>
auth/ntlmssp/ntlmssp.c
auth/ntlmssp/ntlmssp.h
auth/ntlmssp/ntlmssp_sign.c

index 091fdab9e4a8cdd99b468104ad720e6a062106d7..4abab88627ad478c5f15ddd923af5d41297cf3db 100644 (file)
@@ -179,6 +179,30 @@ NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security,
        return NT_STATUS_OK;
 }
 
+static NTSTATUS gensec_ntlmssp_may_reset_crypto(struct gensec_security *gensec_security,
+                                               bool full_reset)
+{
+       struct gensec_ntlmssp_context *gensec_ntlmssp =
+               talloc_get_type_abort(gensec_security->private_data,
+                                     struct gensec_ntlmssp_context);
+       struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
+       NTSTATUS status;
+       bool reset_seqnums = full_reset;
+
+       if (!gensec_ntlmssp_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+               return NT_STATUS_OK;
+       }
+
+       status = ntlmssp_sign_reset(ntlmssp_state, reset_seqnums);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Could not reset NTLMSSP signing/sealing system (error was: %s)\n",
+                         nt_errstr(status)));
+               return status;
+       }
+
+       return NT_STATUS_OK;
+}
+
 static const char *gensec_ntlmssp_oids[] = {
        GENSEC_OID_NTLMSSP,
        NULL
@@ -193,6 +217,7 @@ static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
        .server_start   = gensec_ntlmssp_server_start,
        .magic          = gensec_ntlmssp_magic,
        .update         = gensec_ntlmssp_update,
+       .may_reset_crypto= gensec_ntlmssp_may_reset_crypto,
        .sig_size       = gensec_ntlmssp_sig_size,
        .sign_packet    = gensec_ntlmssp_sign_packet,
        .check_packet   = gensec_ntlmssp_check_packet,
index 8c254f36e83271e6a18ede0cd79baf2322077224..bb8807df4259703d4958167244e238f9bf732ea3 100644 (file)
@@ -130,6 +130,8 @@ NTSTATUS ntlmssp_unwrap(struct ntlmssp_state *ntlmssp_stae,
                        TALLOC_CTX *out_mem_ctx,
                        const DATA_BLOB *in,
                        DATA_BLOB *out);
+NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state,
+                           bool reset_seqnums);
 NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state);
 
 bool ntlmssp_blob_matches_magic(const DATA_BLOB *blob);
index 2f8c6de75d9c97f303ba0ffe6097b931abb5532a..a975725880358adfd6c695294c82731997dcc2ca 100644 (file)
@@ -503,20 +503,14 @@ NTSTATUS ntlmssp_unwrap(struct ntlmssp_state *ntlmssp_state,
 /**
    Initialise the state for NTLMSSP signing.
 */
-NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state)
+NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state,
+                           bool reset_seqnums)
 {
        DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n"));
        debug_ntlmssp_flags(ntlmssp_state->neg_flags);
 
-       if (ntlmssp_state->session_key.length < 8) {
-               DEBUG(3, ("NO session key, cannot intialise signing\n"));
-               return NT_STATUS_NO_USER_SESSION_KEY;
-       }
-
-       ntlmssp_state->crypt = talloc_zero(ntlmssp_state,
-                                          union ntlmssp_crypt_state);
        if (ntlmssp_state->crypt == NULL) {
-               return NT_STATUS_NO_MEMORY;
+               return NT_STATUS_INVALID_PARAMETER_MIX;
        }
 
        if (ntlmssp_state->force_wrap_seal &&
@@ -606,7 +600,9 @@ NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state)
                                &ntlmssp_state->crypt->ntlm2.sending.seal_state);
 
                /* SEND: seq num */
-               ntlmssp_state->crypt->ntlm2.sending.seq_num = 0;
+               if (reset_seqnums) {
+                       ntlmssp_state->crypt->ntlm2.sending.seq_num = 0;
+               }
 
                /* RECV: sign key */
                calc_ntlmv2_key(ntlmssp_state->crypt->ntlm2.receiving.sign_key,
@@ -626,7 +622,9 @@ NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state)
                                &ntlmssp_state->crypt->ntlm2.receiving.seal_state);
 
                /* RECV: seq num */
-               ntlmssp_state->crypt->ntlm2.receiving.seq_num = 0;
+               if (reset_seqnums) {
+                       ntlmssp_state->crypt->ntlm2.receiving.seq_num = 0;
+               }
        } else {
                uint8_t weak_session_key[8];
                DATA_BLOB seal_session_key = ntlmssp_state->session_key;
@@ -676,8 +674,26 @@ NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state)
                dump_arc4_state("NTLMv1 arc4 state:\n",
                                &ntlmssp_state->crypt->ntlm.seal_state);
 
-               ntlmssp_state->crypt->ntlm.seq_num = 0;
+               if (reset_seqnums) {
+                       ntlmssp_state->crypt->ntlm.seq_num = 0;
+               }
        }
 
        return NT_STATUS_OK;
 }
+
+NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state)
+{
+       if (ntlmssp_state->session_key.length < 8) {
+               DEBUG(3, ("NO session key, cannot intialise signing\n"));
+               return NT_STATUS_NO_USER_SESSION_KEY;
+       }
+
+       ntlmssp_state->crypt = talloc_zero(ntlmssp_state,
+                                          union ntlmssp_crypt_state);
+       if (ntlmssp_state->crypt == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       return ntlmssp_sign_reset(ntlmssp_state, true);
+}