From fed54956a9c1a01423ecc3388ae791656e79990c Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 17 Feb 2022 15:35:42 +1300 Subject: [PATCH] auth: Use constant-time memcmp when comparing sensitive buffers This helps to avoid timing attacks. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15010 Signed-off-by: Joseph Sutton --- auth/gensec/schannel.c | 4 ++-- auth/ntlmssp/ntlmssp_ndr.c | 2 +- auth/ntlmssp/ntlmssp_server.c | 4 ++-- auth/ntlmssp/ntlmssp_sign.c | 4 ++-- auth/ntlmssp/ntlmssp_util.c | 2 +- lib/util/data_blob.c | 24 +++++++++++++++++++ lib/util/data_blob.h | 6 +++++ libcli/auth/credentials.c | 19 +++++++-------- libcli/auth/netlogon_creds_cli.c | 10 ++++---- libcli/auth/ntlm_check.c | 8 +++---- libcli/smb/smbXcli_base.c | 6 ++--- libcli/smb/smb_signing.c | 4 ++-- source3/librpc/crypto/gse_krb5.c | 4 ++-- source3/passdb/machine_account_secrets.c | 12 +++++----- source3/rpc_client/cli_netlogon.c | 12 +++++----- source3/rpc_server/netlogon/srv_netlog_nt.c | 4 ++-- source3/rpc_server/samr/srv_samr_chgpasswd.c | 18 +++++++------- source3/winbindd/winbindd_dual_srv.c | 12 +++++----- source3/winbindd/winbindd_pam.c | 8 +++---- source4/auth/ntlm/auth_sam.c | 4 ++-- .../dsdb/samdb/ldb_modules/password_hash.c | 10 ++++---- source4/libcli/raw/smb_signing.c | 2 +- .../rpc_server/backupkey/dcesrv_backupkey.c | 6 ++--- source4/rpc_server/netlogon/dcerpc_netlogon.c | 4 ++-- source4/rpc_server/samr/samr_password.c | 6 ++--- 25 files changed, 112 insertions(+), 83 deletions(-) diff --git a/auth/gensec/schannel.c b/auth/gensec/schannel.c index 6ebbe8f3179..2fbfb019124 100644 --- a/auth/gensec/schannel.c +++ b/auth/gensec/schannel.c @@ -649,7 +649,7 @@ static NTSTATUS netsec_incoming_packet(struct schannel_state *state, return NT_STATUS_ACCESS_DENIED; } - ret = memcmp(checksum, sig->data+16, checksum_length); + ret = memcmp_const_time(checksum, sig->data+16, checksum_length); if (ret != 0) { dump_data_pw("calc digest:", checksum, checksum_length); dump_data_pw("wire digest:", sig->data+16, checksum_length); @@ -665,7 +665,7 @@ static NTSTATUS netsec_incoming_packet(struct schannel_state *state, ZERO_ARRAY(checksum); - ret = memcmp(seq_num, sig->data+8, 8); + ret = memcmp_const_time(seq_num, sig->data+8, 8); if (ret != 0) { dump_data_pw("calc seq num:", seq_num, 8); dump_data_pw("wire seq num:", sig->data+8, 8); diff --git a/auth/ntlmssp/ntlmssp_ndr.c b/auth/ntlmssp/ntlmssp_ndr.c index c8b16ccd413..6de00427bbd 100644 --- a/auth/ntlmssp/ntlmssp_ndr.c +++ b/auth/ntlmssp/ntlmssp_ndr.c @@ -31,7 +31,7 @@ do { \ if (!NDR_ERR_CODE_IS_SUCCESS(__ndr_err)) { \ return ndr_map_error2ntstatus(__ndr_err); \ } \ - if (memcmp(r->Signature, "NTLMSSP\0", 8)) {\ + if (memcmp_const_time(r->Signature, "NTLMSSP\0", 8)) { \ return NT_STATUS_INVALID_PARAMETER; \ } \ return NT_STATUS_OK; \ diff --git a/auth/ntlmssp/ntlmssp_server.c b/auth/ntlmssp/ntlmssp_server.c index e077c2f7379..55688602881 100644 --- a/auth/ntlmssp/ntlmssp_server.c +++ b/auth/ntlmssp/ntlmssp_server.c @@ -1095,8 +1095,8 @@ static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security, } gnutls_hmac_deinit(hmac_hnd, mic_buffer); - cmp = memcmp(request.data + NTLMSSP_MIC_OFFSET, - mic_buffer, NTLMSSP_MIC_SIZE); + cmp = memcmp_const_time(request.data + NTLMSSP_MIC_OFFSET, + mic_buffer, NTLMSSP_MIC_SIZE); if (cmp != 0) { DEBUG(1,("%s: invalid NTLMSSP_MIC for " "user=[%s] domain=[%s] workstation=[%s]\n", diff --git a/auth/ntlmssp/ntlmssp_sign.c b/auth/ntlmssp/ntlmssp_sign.c index 89f1aa04f7a..b831308aa2c 100644 --- a/auth/ntlmssp/ntlmssp_sign.c +++ b/auth/ntlmssp/ntlmssp_sign.c @@ -291,7 +291,7 @@ NTSTATUS ntlmssp_check_packet(struct ntlmssp_state *ntlmssp_state, if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { if (local_sig.length != sig->length || - memcmp(local_sig.data, sig->data, sig->length) != 0) { + memcmp_const_time(local_sig.data, sig->data, sig->length) != 0) { DEBUG(5, ("BAD SIG NTLM2: wanted signature of\n")); dump_data(5, local_sig.data, local_sig.length); @@ -304,7 +304,7 @@ NTSTATUS ntlmssp_check_packet(struct ntlmssp_state *ntlmssp_state, } } else { if (local_sig.length != sig->length || - memcmp(local_sig.data + 8, sig->data + 8, sig->length - 8) != 0) { + memcmp_const_time(local_sig.data + 8, sig->data + 8, sig->length - 8) != 0) { DEBUG(5, ("BAD SIG NTLM1: wanted signature of\n")); dump_data(5, local_sig.data, local_sig.length); diff --git a/auth/ntlmssp/ntlmssp_util.c b/auth/ntlmssp/ntlmssp_util.c index 6f3b474fd71..1aeba343e9f 100644 --- a/auth/ntlmssp/ntlmssp_util.c +++ b/auth/ntlmssp/ntlmssp_util.c @@ -177,7 +177,7 @@ NTSTATUS ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, /* Does this blob looks like it could be NTLMSSP? */ bool ntlmssp_blob_matches_magic(const DATA_BLOB *blob) { - if (blob->length > 8 && memcmp("NTLMSSP\0", blob->data, 8) == 0) { + if (blob->length > 8 && memcmp_const_time("NTLMSSP\0", blob->data, 8) == 0) { return true; } else { return false; diff --git a/lib/util/data_blob.c b/lib/util/data_blob.c index 77b077f7ef9..2416d4da00a 100644 --- a/lib/util/data_blob.c +++ b/lib/util/data_blob.c @@ -21,6 +21,7 @@ #include "replace.h" #include "attr.h" #include "data_blob.h" +#include "lib/util/samba_util.h" const DATA_BLOB data_blob_null = { NULL, 0 }; @@ -129,6 +130,29 @@ _PUBLIC_ int data_blob_cmp(const DATA_BLOB *d1, const DATA_BLOB *d2) return ret; } +/** +check if two data blobs are equal, where the time taken should not depend on the +contents of either blob. +**/ +_PUBLIC_ int data_blob_cmp_const_time(const DATA_BLOB *d1, const DATA_BLOB *d2) +{ + int ret; + if (d1->data == NULL && d2->data != NULL) { + return -1; + } + if (d1->data != NULL && d2->data == NULL) { + return 1; + } + if (d1->data == d2->data) { + return d1->length - d2->length; + } + ret = memcmp_const_time(d1->data, d2->data, MIN(d1->length, d2->length)); + if (ret == 0) { + return d1->length - d2->length; + } + return ret; +} + /** print the data_blob as hex string **/ diff --git a/lib/util/data_blob.h b/lib/util/data_blob.h index 7a0dc3b0014..0f3eae16592 100644 --- a/lib/util/data_blob.h +++ b/lib/util/data_blob.h @@ -86,6 +86,12 @@ check if two data blobs are equal **/ _PUBLIC_ int data_blob_cmp(const DATA_BLOB *d1, const DATA_BLOB *d2); +/** +check if two data blobs are equal, where the time taken should not depend on the +contents of either blob. +**/ +_PUBLIC_ int data_blob_cmp_const_time(const DATA_BLOB *d1, const DATA_BLOB *d2); + /** print the data_blob as hex string **/ diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c index 23339d98bfa..56b8111efa1 100644 --- a/libcli/auth/credentials.c +++ b/libcli/auth/credentials.c @@ -42,15 +42,14 @@ bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge) * of the following steps. */ - if (challenge->data[1] == challenge->data[0] && - challenge->data[2] == challenge->data[0] && - challenge->data[3] == challenge->data[0] && - challenge->data[4] == challenge->data[0]) - { - return false; - } + uint8_t result = 0; - return true; + result |= (challenge->data[1] ^ challenge->data[0]); + result |= (challenge->data[2] ^ challenge->data[0]); + result |= (challenge->data[3] ^ challenge->data[0]); + result |= (challenge->data[4] ^ challenge->data[0]); + + return result != 0; } void netlogon_creds_random_challenge(struct netr_Credential *challenge) @@ -659,7 +658,7 @@ bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds, const struct netr_Credential *received_credentials) { if (!received_credentials || - memcmp(received_credentials->data, creds->server.data, 8) != 0) { + memcmp_const_time(received_credentials->data, creds->server.data, 8) != 0) { DEBUG(2,("credentials check failed\n")); return false; } @@ -678,7 +677,7 @@ next comes the server specific functions static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds, const struct netr_Credential *received_credentials) { - if (memcmp(received_credentials->data, creds->client.data, 8) != 0) { + if (memcmp_const_time(received_credentials->data, creds->client.data, 8) != 0) { DEBUG(2,("credentials check failed\n")); dump_data_pw("client creds", creds->client.data, 8); dump_data_pw("calc creds", received_credentials->data, 8); diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c index e92a042c012..369e3d94d3f 100644 --- a/libcli/auth/netlogon_creds_cli.c +++ b/libcli/auth/netlogon_creds_cli.c @@ -652,7 +652,7 @@ bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context, return false; } - cmp = data_blob_cmp(&blob1, &blob2); + cmp = data_blob_cmp_const_time(&blob1, &blob2); TALLOC_FREE(frame); @@ -3227,8 +3227,8 @@ static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq return; } - cmp = memcmp(state->new_owf_password.hash, - zero.hash, sizeof(zero.hash)); + cmp = memcmp_const_time(state->new_owf_password.hash, + zero.hash, sizeof(zero.hash)); if (cmp != 0) { status = netlogon_creds_des_decrypt(&state->tmp_creds, &state->new_owf_password); @@ -3237,8 +3237,8 @@ static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq return; } } - cmp = memcmp(state->old_owf_password.hash, - zero.hash, sizeof(zero.hash)); + cmp = memcmp_const_time(state->old_owf_password.hash, + zero.hash, sizeof(zero.hash)); if (cmp != 0) { status = netlogon_creds_des_decrypt(&state->tmp_creds, &state->old_owf_password); diff --git a/libcli/auth/ntlm_check.c b/libcli/auth/ntlm_check.c index 846e0c07cd5..d71bdb3b1a4 100644 --- a/libcli/auth/ntlm_check.c +++ b/libcli/auth/ntlm_check.c @@ -71,7 +71,7 @@ static bool smb_pwd_check_ntlmv1(TALLOC_CTX *mem_ctx, DEBUGADD(100,("Value from encryption was |\n")); dump_data(100, p24, 24); #endif - ok = (memcmp(p24, nt_response->data, 24) == 0); + ok = (memcmp_const_time(p24, nt_response->data, 24) == 0); if (!ok) { return false; } @@ -157,7 +157,7 @@ static bool smb_pwd_check_ntlmv2(TALLOC_CTX *mem_ctx, #endif data_blob_clear_free(&client_key_data); - ok = (memcmp(value_from_encryption, ntv2_response->data, 16) == 0); + ok = (memcmp_const_time(value_from_encryption, ntv2_response->data, 16) == 0); if (!ok) { return false; } @@ -271,7 +271,7 @@ NTSTATUS hash_password_check(TALLOC_CTX *mem_ctx, } if (client_nt && stored_nt) { - if (memcmp(client_nt->hash, stored_nt->hash, sizeof(stored_nt->hash)) == 0) { + if (memcmp_const_time(client_nt->hash, stored_nt->hash, sizeof(stored_nt->hash)) == 0) { return NT_STATUS_OK; } else { DEBUG(3,("hash_password_check: Interactive logon: NT password check failed for user %s\n", @@ -289,7 +289,7 @@ NTSTATUS hash_password_check(TALLOC_CTX *mem_ctx, return NT_STATUS_NOT_FOUND; } - if (memcmp(client_lanman->hash, stored_lanman->hash, sizeof(stored_lanman->hash)) == 0) { + if (memcmp_const_time(client_lanman->hash, stored_lanman->hash, sizeof(stored_lanman->hash)) == 0) { return NT_STATUS_OK; } else { DEBUG(3,("hash_password_check: Interactive logon: LANMAN password check failed for user %s\n", diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index 0f3e4fa3f90..13f51bb6344 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -3998,9 +3998,9 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn, if (signing_key) { int cmp; - cmp = memcmp(inhdr+SMB2_HDR_SIGNATURE, - state->smb2.hdr+SMB2_HDR_SIGNATURE, - 16); + cmp = memcmp_const_time(inhdr+SMB2_HDR_SIGNATURE, + state->smb2.hdr+SMB2_HDR_SIGNATURE, + 16); if (cmp == 0) { state->smb2.signing_skipped = true; signing_key = NULL; diff --git a/libcli/smb/smb_signing.c b/libcli/smb/smb_signing.c index f01865c9bc5..ee9b854275a 100644 --- a/libcli/smb/smb_signing.c +++ b/libcli/smb/smb_signing.c @@ -339,7 +339,7 @@ bool smb1_signing_check_pdu(struct smb1_signing_state *si, } reply_sent_mac = &inhdr[HDR_SS_FIELD]; - good = (memcmp(reply_sent_mac, calc_md5_mac, 8) == 0); + good = (memcmp_const_time(reply_sent_mac, calc_md5_mac, 8) == 0); if (!good) { int i; @@ -354,7 +354,7 @@ bool smb1_signing_check_pdu(struct smb1_signing_state *si, for (i = -sign_range; i < sign_range; i++) { smb1_signing_md5(&si->mac_key, inhdr, len, seqnum+i, calc_md5_mac); - if (memcmp(reply_sent_mac, calc_md5_mac, 8) == 0) { + if (memcmp_const_time(reply_sent_mac, calc_md5_mac, 8) == 0) { DBG_ERR("out of seq. seq num %u matches. " "We were expecting seq %u\n", (unsigned int)seqnum+i, diff --git a/source3/librpc/crypto/gse_krb5.c b/source3/librpc/crypto/gse_krb5.c index 83741c914a3..13547047165 100644 --- a/source3/librpc/crypto/gse_krb5.c +++ b/source3/librpc/crypto/gse_krb5.c @@ -240,8 +240,8 @@ static krb5_error_code fill_mem_keytab_from_secrets(krb5_context krbctx, * check if keytab is up to date */ if ((ct->length == KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry))) && - (memcmp(KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry)), - ct->data, ct->length) == 0)) { + (memcmp_const_time(KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry)), + ct->data, ct->length) == 0)) { /* keytab is already up to date, return */ smb_krb5_kt_free_entry(krbctx, &kt_entry); goto out; diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c index f98f0c98674..c238fa1a9de 100644 --- a/source3/passdb/machine_account_secrets.c +++ b/source3/passdb/machine_account_secrets.c @@ -1873,9 +1873,9 @@ static NTSTATUS secrets_check_password_change(const struct secrets_domain_info1 return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT; } - cmp = memcmp(sn->password->nt_hash.hash, - cn->password->nt_hash.hash, - 16); + cmp = memcmp_const_time(sn->password->nt_hash.hash, + cn->password->nt_hash.hash, + 16); if (cmp != 0) { DBG_ERR("next password.nt_hash differs for %s.\n", domain); @@ -1883,9 +1883,9 @@ static NTSTATUS secrets_check_password_change(const struct secrets_domain_info1 return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT; } - cmp = memcmp(stored->password->nt_hash.hash, - cookie->password->nt_hash.hash, - 16); + cmp = memcmp_const_time(stored->password->nt_hash.hash, + cookie->password->nt_hash.hash, + 16); if (cmp != 0) { DBG_ERR("password.nt_hash differs for %s.\n", domain); diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c index 50dae9d7f3e..9551621ce8a 100644 --- a/source3/rpc_client/cli_netlogon.c +++ b/source3/rpc_client/cli_netlogon.c @@ -325,9 +325,9 @@ again: status = netlogon_creds_cli_get(creds_ctx, frame, &creds); if (NT_STATUS_IS_OK(status)) { - int cmp = memcmp(found_session_key, - creds->session_key, - sizeof(found_session_key)); + int cmp = memcmp_const_time(found_session_key, + creds->session_key, + sizeof(found_session_key)); found_existing_creds = (cmp != 0); memcpy(found_session_key, @@ -356,9 +356,9 @@ again: status = netlogon_creds_cli_get(creds_ctx, frame, &creds); if (NT_STATUS_IS_OK(status)) { - int cmp = memcmp(found_session_key, - creds->session_key, - sizeof(found_session_key)); + int cmp = memcmp_const_time(found_session_key, + creds->session_key, + sizeof(found_session_key)); found_existing_creds = (cmp != 0); memcpy(found_session_key, creds->session_key, diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 5906464a9f3..b1f4d9c2b04 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1577,7 +1577,7 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p, confounder_len = 512 - new_password.length; enc_blob = data_blob_const(r->in.new_password->data, confounder_len); dec_blob = data_blob_const(password_buf.data, confounder_len); - if (confounder_len > 0 && data_blob_cmp(&dec_blob, &enc_blob) == 0) { + if (confounder_len > 0 && data_blob_cmp_const_time(&dec_blob, &enc_blob) == 0) { DBG_WARNING("Confounder buffer not encrypted Length[%zu]\n", confounder_len); TALLOC_FREE(creds); @@ -1592,7 +1592,7 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p, new_password.length); dec_blob = data_blob_const(password_buf.data + confounder_len, new_password.length); - if (data_blob_cmp(&dec_blob, &enc_blob) == 0) { + if (data_blob_cmp_const_time(&dec_blob, &enc_blob) == 0) { DBG_WARNING("Password buffer not encrypted Length[%zu]\n", new_password.length); TALLOC_FREE(creds); diff --git a/source3/rpc_server/samr/srv_samr_chgpasswd.c b/source3/rpc_server/samr/srv_samr_chgpasswd.c index e326745169e..5ff3edb5eb7 100644 --- a/source3/rpc_server/samr/srv_samr_chgpasswd.c +++ b/source3/rpc_server/samr/srv_samr_chgpasswd.c @@ -817,7 +817,7 @@ static NTSTATUS check_oem_password(const char *user, NTSTATUS status = NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER; return gnutls_error_to_ntstatus(rc, status); } - if (memcmp(verifier, old_nt_hash_encrypted, 16)) { + if (memcmp_const_time(verifier, old_nt_hash_encrypted, 16)) { DEBUG(0, ("check_oem_password: old nt " "password doesn't match.\n")); return NT_STATUS_WRONG_PASSWORD; @@ -848,7 +848,7 @@ static NTSTATUS check_oem_password(const char *user, NTSTATUS status = NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER; return gnutls_error_to_ntstatus(rc, status); } - if (memcmp(verifier, old_lm_hash_encrypted, 16)) { + if (memcmp_const_time(verifier, old_lm_hash_encrypted, 16)) { DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); return NT_STATUS_WRONG_PASSWORD; } @@ -872,7 +872,7 @@ static NTSTATUS check_oem_password(const char *user, NTSTATUS status = NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER; return gnutls_error_to_ntstatus(rc, status); } - if (memcmp(verifier, old_lm_hash_encrypted, 16)) { + if (memcmp_const_time(verifier, old_lm_hash_encrypted, 16)) { DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); return NT_STATUS_WRONG_PASSWORD; } @@ -915,8 +915,8 @@ static bool password_in_history(uint8_t nt_pw[NT_HASH_LEN], * New format: zero salt and then plain nt hash. * Directly compare the hashes. */ - if (memcmp(nt_pw, old_nt_pw_salted_md5_hash, - SALTED_MD5_HASH_LEN) == 0) + if (memcmp_const_time(nt_pw, old_nt_pw_salted_md5_hash, + SALTED_MD5_HASH_LEN) == 0) { return true; } @@ -945,9 +945,9 @@ static bool password_in_history(uint8_t nt_pw[NT_HASH_LEN], } gnutls_hash_deinit(hash_hnd, new_nt_pw_salted_md5_hash); - if (memcmp(new_nt_pw_salted_md5_hash, - old_nt_pw_salted_md5_hash, - SALTED_MD5_HASH_LEN) == 0) { + if (memcmp_const_time(new_nt_pw_salted_md5_hash, + old_nt_pw_salted_md5_hash, + SALTED_MD5_HASH_LEN) == 0) { return true; } } @@ -986,7 +986,7 @@ static bool check_passwd_history(struct samu *sampass, const char *plaintext) E_md4hash(plaintext, new_nt_p16); - if (!memcmp(nt_pw, new_nt_p16, NT_HASH_LEN)) { + if (!memcmp_const_time(nt_pw, new_nt_p16, NT_HASH_LEN)) { DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n", pdb_get_username(sampass) )); return True; diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c index 3daa8468ddc..d710e61dc94 100644 --- a/source3/winbindd/winbindd_dual_srv.c +++ b/source3/winbindd/winbindd_dual_srv.c @@ -1476,12 +1476,12 @@ reconnect: } } - cmp_new = memcmp(new_owf_password.hash, - cur_nt_hash->hash, - sizeof(cur_nt_hash->hash)); - cmp_old = memcmp(old_owf_password.hash, - cur_nt_hash->hash, - sizeof(cur_nt_hash->hash)); + cmp_new = memcmp_const_time(new_owf_password.hash, + cur_nt_hash->hash, + sizeof(cur_nt_hash->hash)); + cmp_old = memcmp_const_time(old_owf_password.hash, + cur_nt_hash->hash, + sizeof(cur_nt_hash->hash)); if (cmp_new != 0 && cmp_old != 0) { DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match " "any password known to dcname[%s]\n", diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index c2fcc399ab8..9b5dd732097 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -1117,12 +1117,12 @@ static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain, } gnutls_hash_deinit(hash_hnd, salted_hash); - password_good = (memcmp(cached_nt_pass, salted_hash, - NT_HASH_LEN) == 0); + password_good = (memcmp_const_time(cached_nt_pass, salted_hash, + NT_HASH_LEN) == 0); } else { /* Old cached cred - direct store of nt_hash (bad bad bad !). */ - password_good = (memcmp(cached_nt_pass, new_nt_pass, - NT_HASH_LEN) == 0); + password_good = (memcmp_const_time(cached_nt_pass, new_nt_pass, + NT_HASH_LEN) == 0); } if (password_good) { diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c index cf0656ae0da..d897f084482 100644 --- a/source4/auth/ntlm/auth_sam.c +++ b/source4/auth/ntlm/auth_sam.c @@ -368,12 +368,12 @@ static NTSTATUS authsam_password_check_and_record(struct auth4_context *auth_con */ E_md4hash("", zero_string_hash.hash); - if (memcmp(nt_history_pwd->hash, zero_string_hash.hash, 16) == 0) { + if (memcmp_const_time(nt_history_pwd->hash, zero_string_hash.hash, 16) == 0) { continue; } E_deshash("", zero_string_des_hash.hash); - if (!lm_history_pwd || memcmp(lm_history_pwd->hash, zero_string_des_hash.hash, 16) == 0) { + if (!lm_history_pwd || memcmp_const_time(lm_history_pwd->hash, zero_string_des_hash.hash, 16) == 0) { lm_history_pwd = NULL; } diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index 3978d82a79a..0d51a75c69c 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -602,7 +602,7 @@ static int password_hash_bypass(struct ldb_module *module, struct ldb_request *r "supplementalCredentialsBlob length differ"); } - if (memcmp(sce->values[0].data, blob.data, blob.length) != 0) { + if (memcmp_const_time(sce->values[0].data, blob.data, blob.length) != 0) { return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, "supplementalCredentialsBlob memcmp differ"); } @@ -2831,7 +2831,7 @@ static int check_password_restrictions(struct setup_password_fields_io *io, WERR /* The password modify through the NT hash is encouraged and has no problems at all */ if (io->og.nt_hash) { - if (!io->o.nt_hash || memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) { + if (!io->o.nt_hash || memcmp_const_time(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) { return make_error_and_update_badPwdCount(io, werror); } @@ -2844,7 +2844,7 @@ static int check_password_restrictions(struct setup_password_fields_io *io, WERR * (as the SAMR operations request it). */ if (io->og.lm_hash) { if ((!io->o.lm_hash && !nt_hash_checked) - || (io->o.lm_hash && memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0)) { + || (io->o.lm_hash && memcmp_const_time(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0)) { return make_error_and_update_badPwdCount(io, werror); } } @@ -2933,7 +2933,7 @@ static int check_password_restrictions(struct setup_password_fields_io *io, WERR /* checks the NT hash password history */ for (i = 0; i < io->o.nt_history_len; i++) { - ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16); + ret = memcmp_const_time(io->n.nt_hash, io->o.nt_history[i].hash, 16); if (ret == 0) { ret = LDB_ERR_CONSTRAINT_VIOLATION; *werror = WERR_PASSWORD_RESTRICTION; @@ -2953,7 +2953,7 @@ static int check_password_restrictions(struct setup_password_fields_io *io, WERR /* checks the LM hash password history */ for (i = 0; i < io->o.lm_history_len; i++) { - ret = memcmp(io->n.lm_hash, io->o.lm_history[i].hash, 16); + ret = memcmp_const_time(io->n.lm_hash, io->o.lm_history[i].hash, 16); if (ret == 0) { ret = LDB_ERR_CONSTRAINT_VIOLATION; *werror = WERR_PASSWORD_RESTRICTION; diff --git a/source4/libcli/raw/smb_signing.c b/source4/libcli/raw/smb_signing.c index 40734cb7205..cd781506897 100644 --- a/source4/libcli/raw/smb_signing.c +++ b/source4/libcli/raw/smb_signing.c @@ -198,7 +198,7 @@ bool check_signed_incoming_message(struct smb_request_buffer *in, DATA_BLOB *mac gnutls_hash_deinit(hash_hnd, calc_md5_mac); - ok = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0); + ok = (memcmp_const_time(server_sent_mac, calc_md5_mac, 8) == 0); if (i == 0) { if (!ok) { diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c index 181f95a5918..5fbd36323e4 100644 --- a/source4/rpc_server/backupkey/dcesrv_backupkey.c +++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c @@ -451,7 +451,7 @@ static WERROR get_and_verify_access_check(TALLOC_CTX *sub_ctx, * point to the same area */ - if (memcmp(hash, uncrypted_accesscheckv2.hash, hash_size) != 0) { + if (memcmp_const_time(hash, uncrypted_accesscheckv2.hash, hash_size) != 0) { DEBUG(2, ("Wrong hash value in the access check in backup key remote protocol\n")); return WERR_INVALID_DATA; } @@ -486,7 +486,7 @@ static WERROR get_and_verify_access_check(TALLOC_CTX *sub_ctx, * point to the same area */ - if (memcmp(hash, uncrypted_accesscheckv3.hash, hash_size) != 0) { + if (memcmp_const_time(hash, uncrypted_accesscheckv3.hash, hash_size) != 0) { DEBUG(2, ("Wrong hash value in the access check in backup key remote protocol\n")); return WERR_INVALID_DATA; } @@ -1547,7 +1547,7 @@ static WERROR bkrp_server_wrap_decrypt_data(struct dcesrv_call_state *dce_call, dump_data_pw("mac: \n", mac, sizeof(mac)); dump_data_pw("rc4payload.mac: \n", rc4payload.mac, sizeof(rc4payload.mac)); - if (memcmp(mac, rc4payload.mac, sizeof(mac)) != 0) { + if (memcmp_const_time(mac, rc4payload.mac, sizeof(mac)) != 0) { return WERR_INVALID_ACCESS; } diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index cfd6d148b0a..326f32d51e8 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -897,7 +897,7 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal confounder_len = 512 - new_password.length; enc_blob = data_blob_const(r->in.new_password->data, confounder_len); dec_blob = data_blob_const(password_buf.data, confounder_len); - if (confounder_len > 0 && data_blob_cmp(&dec_blob, &enc_blob) == 0) { + if (confounder_len > 0 && data_blob_cmp_const_time(&dec_blob, &enc_blob) == 0) { DBG_WARNING("Confounder buffer not encrypted Length[%zu]\n", confounder_len); return NT_STATUS_WRONG_PASSWORD; @@ -911,7 +911,7 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal new_password.length); dec_blob = data_blob_const(password_buf.data + confounder_len, new_password.length); - if (data_blob_cmp(&dec_blob, &enc_blob) == 0) { + if (data_blob_cmp_const_time(&dec_blob, &enc_blob) == 0) { DBG_WARNING("Password buffer not encrypted Length[%zu]\n", new_password.length); return NT_STATUS_WRONG_PASSWORD; diff --git a/source4/rpc_server/samr/samr_password.c b/source4/rpc_server/samr/samr_password.c index c0fbaacd4d8..36eb92c13c2 100644 --- a/source4/rpc_server/samr/samr_password.c +++ b/source4/rpc_server/samr/samr_password.c @@ -250,7 +250,7 @@ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER); goto failed; } - if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) { + if (memcmp_const_time(lm_verifier.hash, r->in.hash->hash, 16) != 0) { authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx)); status = NT_STATUS_WRONG_PASSWORD; goto failed; @@ -450,7 +450,7 @@ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER); goto failed; } - if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) { + if (memcmp_const_time(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } @@ -473,7 +473,7 @@ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER); goto failed; } - if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) { + if (memcmp_const_time(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } -- 2.35.0