From 7bd502dcdb44c7d0f8a56b2ba489ae8cf2b886bd Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 6 Dec 2018 18:11:14 +0100 Subject: auth:ntlmssp: Use GnuTLS RC4 for ntlmssp signing BUG: https://bugzilla.samba.org/show_bug.cgi?id=14031 Signed-off-by: Andreas Schneider Reviewed-by: Andrew Bartlett --- auth/ntlmssp/ntlmssp_private.h | 5 +- auth/ntlmssp/ntlmssp_sign.c | 212 +++++++++++++++++++++++++++++++++-------- 2 files changed, 174 insertions(+), 43 deletions(-) (limited to 'auth') diff --git a/auth/ntlmssp/ntlmssp_private.h b/auth/ntlmssp/ntlmssp_private.h index 95ec6374f51..4d84e3347b6 100644 --- a/auth/ntlmssp/ntlmssp_private.h +++ b/auth/ntlmssp/ntlmssp_private.h @@ -20,14 +20,15 @@ /* For structures internal to the NTLMSSP implementation that should not be exposed */ -#include "../lib/crypto/arcfour.h" +#include +#include struct auth_session_info; struct ntlmssp_crypt_direction { uint32_t seq_num; uint8_t sign_key[16]; - struct arcfour_state seal_state; + gnutls_cipher_hd_t seal_state; }; union ntlmssp_crypt_state { diff --git a/auth/ntlmssp/ntlmssp_sign.c b/auth/ntlmssp/ntlmssp_sign.c index 8ba2e246b34..89f1aa04f7a 100644 --- a/auth/ntlmssp/ntlmssp_sign.c +++ b/auth/ntlmssp/ntlmssp_sign.c @@ -47,9 +47,9 @@ */ static void dump_arc4_state(const char *description, - struct arcfour_state *state) + gnutls_cipher_hd_t *state) { - dump_data_pw(description, state->sbox, sizeof(state->sbox)); + DBG_DEBUG("%s\n", description); } static NTSTATUS calc_ntlmv2_key(uint8_t subkey[16], @@ -90,13 +90,13 @@ static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_stat enum ntlmssp_direction direction, DATA_BLOB *sig, bool encrypt_sig) { - NTSTATUS status; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + int rc; if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { gnutls_hmac_hd_t hmac_hnd = NULL; uint8_t digest[16]; uint8_t seq_num[4]; - int rc; *sig = data_blob_talloc(sig_mem_ctx, NULL, NTLMSSP_SIG_SIZE); if (!sig->data) { @@ -158,14 +158,24 @@ static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_stat if (encrypt_sig && (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) { switch (direction) { case NTLMSSP_SEND: - arcfour_crypt_sbox(&ntlmssp_state->crypt->ntlm2.sending.seal_state, - digest, 8); + rc = gnutls_cipher_encrypt(ntlmssp_state->crypt->ntlm2.sending.seal_state, + digest, + 8); break; case NTLMSSP_RECEIVE: - arcfour_crypt_sbox(&ntlmssp_state->crypt->ntlm2.receiving.seal_state, - digest, 8); + rc = gnutls_cipher_encrypt(ntlmssp_state->crypt->ntlm2.receiving.seal_state, + digest, + 8); break; } + if (rc < 0) { + DBG_ERR("gnutls_cipher_encrypt for NTLMv2 EXCH " + "%s packet signature failed: %s\n", + direction == NTLMSSP_SEND ? + "send" : "receive", + gnutls_strerror(rc)); + return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); + } } SIVAL(sig->data, 0, NTLMSSP_SIGN_VERSION); @@ -194,8 +204,15 @@ static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_stat dump_arc4_state("ntlmssp hash: \n", &ntlmssp_state->crypt->ntlm.seal_state); - arcfour_crypt_sbox(&ntlmssp_state->crypt->ntlm.seal_state, - sig->data+4, sig->length-4); + rc = gnutls_cipher_encrypt(ntlmssp_state->crypt->ntlm.seal_state, + sig->data + 4, + sig->length - 4); + if (rc < 0) { + DBG_ERR("gnutls_cipher_encrypt for NTLM packet " + "signature failed: %s\n", + gnutls_strerror(rc)); + return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); + } } return NT_STATUS_OK; @@ -317,6 +334,8 @@ NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state, const uint8_t *whole_pdu, size_t pdu_length, DATA_BLOB *sig) { + int rc; + if (!(ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL)) { DEBUG(3, ("NTLMSSP Sealing not negotiated - cannot seal packet!\n")); return NT_STATUS_INVALID_PARAMETER; @@ -353,11 +372,25 @@ NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state, return nt_status; } - arcfour_crypt_sbox(&ntlmssp_state->crypt->ntlm2.sending.seal_state, - data, length); + rc = gnutls_cipher_encrypt(ntlmssp_state->crypt->ntlm2.sending.seal_state, + data, + length); + if (rc < 0) { + DBG_ERR("gnutls_cipher_encrypt ntlmv2 sealing the data " + "failed: %s\n", + gnutls_strerror(rc)); + return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); + } if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { - arcfour_crypt_sbox(&ntlmssp_state->crypt->ntlm2.sending.seal_state, - sig->data+4, 8); + rc = gnutls_cipher_encrypt(ntlmssp_state->crypt->ntlm2.sending.seal_state, + sig->data + 4, + 8); + if (rc < 0) { + DBG_ERR("gnutls_cipher_encrypt ntlmv2 sealing " + "the EXCH signature data failed: %s\n", + gnutls_strerror(rc)); + return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); + } } } else { NTSTATUS status; @@ -381,17 +414,30 @@ NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state, * is not constant, but is is rather updated with * each iteration */ - dump_arc4_state("ntlmv1 arc4 state:\n", &ntlmssp_state->crypt->ntlm.seal_state); - arcfour_crypt_sbox(&ntlmssp_state->crypt->ntlm.seal_state, - data, length); + rc = gnutls_cipher_encrypt(ntlmssp_state->crypt->ntlm.seal_state, + data, + length); + if (rc < 0) { + DBG_ERR("gnutls_cipher_encrypt ntlmv1 sealing data" + "failed: %s\n", + gnutls_strerror(rc)); + return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); + } dump_arc4_state("ntlmv1 arc4 state:\n", &ntlmssp_state->crypt->ntlm.seal_state); - arcfour_crypt_sbox(&ntlmssp_state->crypt->ntlm.seal_state, - sig->data+4, sig->length-4); + rc = gnutls_cipher_encrypt(ntlmssp_state->crypt->ntlm.seal_state, + sig->data + 4, + sig->length - 4); + if (rc < 0) { + DBG_ERR("gnutls_cipher_encrypt ntlmv1 sealing signing " + "data failed: %s\n", + gnutls_strerror(rc)); + return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); + } ntlmssp_state->crypt->ntlm.seq_num++; } @@ -412,6 +458,8 @@ NTSTATUS ntlmssp_unseal_packet(struct ntlmssp_state *ntlmssp_state, const DATA_BLOB *sig) { NTSTATUS status; + int rc; + if (!ntlmssp_state->session_key.length) { DEBUG(3, ("NO session key, cannot unseal packet\n")); return NT_STATUS_NO_USER_SESSION_KEY; @@ -422,14 +470,29 @@ NTSTATUS ntlmssp_unseal_packet(struct ntlmssp_state *ntlmssp_state, if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { /* First unseal the data. */ - arcfour_crypt_sbox(&ntlmssp_state->crypt->ntlm2.receiving.seal_state, - data, length); + rc = gnutls_cipher_decrypt(ntlmssp_state->crypt->ntlm2.receiving.seal_state, + data, + length); + if (rc < 0) { + DBG_ERR("gnutls_cipher_decrypt ntlmv2 unsealing the " + "data failed: %s\n", + gnutls_strerror(rc)); + return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); + } dump_data_pw("ntlmv2 clear data\n", data, length); } else { - arcfour_crypt_sbox(&ntlmssp_state->crypt->ntlm.seal_state, - data, length); + rc = gnutls_cipher_decrypt(ntlmssp_state->crypt->ntlm.seal_state, + data, + length); + if (rc < 0) { + DBG_ERR("gnutls_cipher_decrypt ntlmv1 unsealing the " + "data failed: %s\n", + gnutls_strerror(rc)); + return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); + } dump_data_pw("ntlmv1 clear data\n", data, length); } + status = ntlmssp_check_packet(ntlmssp_state, data, length, whole_pdu, pdu_length, @@ -555,6 +618,8 @@ NTSTATUS ntlmssp_unwrap(struct ntlmssp_state *ntlmssp_state, NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state, bool reset_seqnums) { + int rc; + DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n")); debug_ntlmssp_flags(ntlmssp_state->neg_flags); @@ -584,12 +649,16 @@ NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state, const char *send_seal_const; const char *recv_sign_const; const char *recv_seal_const; - uint8_t send_seal_key[16]; - DATA_BLOB send_seal_blob = data_blob_const(send_seal_key, - sizeof(send_seal_key)); - uint8_t recv_seal_key[16]; - DATA_BLOB recv_seal_blob = data_blob_const(recv_seal_key, - sizeof(recv_seal_key)); + uint8_t send_seal_key[16] = {0}; + gnutls_datum_t send_seal_blob = { + .data = send_seal_key, + .size = sizeof(send_seal_key), + }; + uint8_t recv_seal_key[16] = {0}; + gnutls_datum_t recv_seal_blob = { + .data = recv_seal_key, + .size = sizeof(recv_seal_key), + }; NTSTATUS status; switch (ntlmssp_state->role) { @@ -648,10 +717,22 @@ NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state, if (!NT_STATUS_IS_OK(status)) { return status; } - dump_data_pw("NTLMSSP send seal key:\n", send_seal_key, 16); + dump_data_pw("NTLMSSP send seal key:\n", + send_seal_key, + sizeof(send_seal_key)); - arcfour_init(&ntlmssp_state->crypt->ntlm2.sending.seal_state, - &send_seal_blob); + if (ntlmssp_state->crypt->ntlm2.sending.seal_state != NULL) { + gnutls_cipher_deinit(ntlmssp_state->crypt->ntlm2.sending.seal_state); + } + rc = gnutls_cipher_init(&ntlmssp_state->crypt->ntlm2.sending.seal_state, + GNUTLS_CIPHER_ARCFOUR_128, + &send_seal_blob, + NULL); + if (rc < 0) { + DBG_ERR("gnutls_cipher_init failed: %s\n", + gnutls_strerror(rc)); + return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); + } dump_arc4_state("NTLMSSP send seal arc4 state:\n", &ntlmssp_state->crypt->ntlm2.sending.seal_state); @@ -677,10 +758,22 @@ NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state, if (!NT_STATUS_IS_OK(status)) { return status; } - dump_data_pw("NTLMSSP recv seal key:\n", recv_seal_key, 16); + dump_data_pw("NTLMSSP recv seal key:\n", + recv_seal_key, + sizeof(recv_seal_key)); - arcfour_init(&ntlmssp_state->crypt->ntlm2.receiving.seal_state, - &recv_seal_blob); + if (ntlmssp_state->crypt->ntlm2.receiving.seal_state != NULL) { + gnutls_cipher_deinit(ntlmssp_state->crypt->ntlm2.receiving.seal_state); + } + rc = gnutls_cipher_init(&ntlmssp_state->crypt->ntlm2.receiving.seal_state, + GNUTLS_CIPHER_ARCFOUR_128, + &recv_seal_blob, + NULL); + if (rc < 0) { + DBG_ERR("gnutls_cipher_init failed: %s\n", + gnutls_strerror(rc)); + return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); + } dump_arc4_state("NTLMSSP recv seal arc4 state:\n", &ntlmssp_state->crypt->ntlm2.receiving.seal_state); @@ -690,8 +783,10 @@ NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state, ntlmssp_state->crypt->ntlm2.receiving.seq_num = 0; } } else { - uint8_t weak_session_key[8]; - DATA_BLOB seal_session_key = ntlmssp_state->session_key; + gnutls_datum_t seal_session_key = { + .data = ntlmssp_state->session_key.data, + .size = ntlmssp_state->session_key.length, + }; bool do_weak = false; DEBUG(5, ("NTLMSSP Sign/Seal - using NTLM1\n")); @@ -709,14 +804,19 @@ NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state, * Nothing to weaken. * We certainly don't want to 'extend' the length... */ - if (seal_session_key.length < 16) { + if (ntlmssp_state->session_key.length < 16) { /* TODO: is this really correct? */ do_weak = false; } if (do_weak) { + uint8_t weak_session_key[8]; + memcpy(weak_session_key, seal_session_key.data, 8); - seal_session_key = data_blob_const(weak_session_key, 8); + seal_session_key = (gnutls_datum_t) { + .data = weak_session_key, + .size = sizeof(weak_session_key), + }; /* * LM key doesn't support 128 bit crypto, so this is @@ -732,8 +832,18 @@ NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state, } } - arcfour_init(&ntlmssp_state->crypt->ntlm.seal_state, - &seal_session_key); + if (ntlmssp_state->crypt->ntlm.seal_state != NULL) { + gnutls_cipher_deinit(ntlmssp_state->crypt->ntlm.seal_state); + } + rc = gnutls_cipher_init(&ntlmssp_state->crypt->ntlm.seal_state, + GNUTLS_CIPHER_ARCFOUR_128, + &seal_session_key, + NULL); + if (rc < 0) { + DBG_ERR("gnutls_cipher_init failed: %s\n", + gnutls_strerror(rc)); + return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); + } dump_arc4_state("NTLMv1 arc4 state:\n", &ntlmssp_state->crypt->ntlm.seal_state); @@ -746,6 +856,24 @@ NTSTATUS ntlmssp_sign_reset(struct ntlmssp_state *ntlmssp_state, return NT_STATUS_OK; } +static int ntlmssp_crypt_free_gnutls_cipher_state(union ntlmssp_crypt_state *c) +{ + if (c->ntlm2.sending.seal_state != NULL) { + gnutls_cipher_deinit(c->ntlm2.sending.seal_state); + c->ntlm2.sending.seal_state = NULL; + } + if (c->ntlm2.receiving.seal_state != NULL) { + gnutls_cipher_deinit(c->ntlm2.receiving.seal_state); + c->ntlm2.receiving.seal_state = NULL; + } + if (c->ntlm.seal_state != NULL) { + gnutls_cipher_deinit(c->ntlm.seal_state); + c->ntlm.seal_state = NULL; + } + + return 0; +} + NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state) { if (ntlmssp_state->session_key.length < 8) { @@ -758,6 +886,8 @@ NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state) if (ntlmssp_state->crypt == NULL) { return NT_STATUS_NO_MEMORY; } + talloc_set_destructor(ntlmssp_state->crypt, + ntlmssp_crypt_free_gnutls_cipher_state); return ntlmssp_sign_reset(ntlmssp_state, true); } -- cgit v1.2.1