1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

auth/ntlmssp: implement channel binding support

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

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
(cherry picked from commit f1d34a430d)
This commit is contained in:
Stefan Metzmacher 2020-02-11 16:07:05 +01:00 committed by Jule Anger
parent c41feb6c2a
commit 1219bf3830
4 changed files with 154 additions and 6 deletions

View File

@ -599,6 +599,8 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
SingleHost->Value.AvSingleHost.remaining = data_blob_null;
}
if (!(gensec_security->want_features & GENSEC_FEATURE_CB_OPTIONAL)
|| gensec_security->channel_bindings != NULL)
{
struct AV_PAIR *ChannelBindings = NULL;
@ -607,13 +609,12 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
count++;
*eol = *ChannelBindings;
/*
* gensec doesn't support channel bindings yet,
* but we want to match Windows on the wire
*/
ChannelBindings->AvId = MsvChannelBindings;
memset(ChannelBindings->Value.ChannelBindings, 0,
sizeof(ChannelBindings->Value.ChannelBindings));
nt_status = ntlmssp_hash_channel_bindings(gensec_security,
ChannelBindings->Value.ChannelBindings);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
}
service = gensec_get_target_service(gensec_security);

View File

@ -56,6 +56,8 @@ void debug_ntlmssp_flags(uint32_t neg_flags);
NTSTATUS ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
uint32_t neg_flags, const char *name);
const DATA_BLOB ntlmssp_version_blob(void);
NTSTATUS ntlmssp_hash_channel_bindings(struct gensec_security *gensec_security,
uint8_t cb_hash[16]);
/* The following definitions come from auth/ntlmssp_server.c */

View File

@ -386,6 +386,9 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
DATA_BLOB version_blob = data_blob_null;
const unsigned int mic_len = NTLMSSP_MIC_SIZE;
DATA_BLOB mic_blob = data_blob_null;
const uint8_t zero_channel_bindings[16] = { 0, };
const uint8_t *client_channel_bindings = zero_channel_bindings;
uint8_t server_channel_bindings[16] = { 0, };
const char *parse_string;
bool ok;
struct timeval endtime;
@ -523,6 +526,7 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
uint32_t i = 0;
uint32_t count = 0;
const struct AV_PAIR *flags = NULL;
const struct AV_PAIR *cb = NULL;
const struct AV_PAIR *eol = NULL;
uint32_t av_flags = 0;
@ -598,6 +602,12 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
ntlmssp_state->new_spnego = true;
}
cb = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
MsvChannelBindings);
if (cb != NULL) {
client_channel_bindings = cb->Value.ChannelBindings;
}
count = ntlmssp_state->server.av_pair_list.count;
if (v2_resp.Challenge.AvPairs.count < count) {
return NT_STATUS_INVALID_PARAMETER;
@ -700,6 +710,43 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
}
}
if (gensec_security->channel_bindings != NULL) {
nt_status = ntlmssp_hash_channel_bindings(gensec_security,
server_channel_bindings);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
ok = mem_equal_const_time(client_channel_bindings,
server_channel_bindings,
16);
if (!ok && gensec_security->want_features & GENSEC_FEATURE_CB_OPTIONAL) {
/*
* Unlike kerberos, explicit 16 zeros in
* MsvChannelBindings are not enough to
* pass the optional check.
*
* So we only let it through without explicit
* MsvChannelBindings.
*/
ok = (client_channel_bindings == zero_channel_bindings);
}
if (!ok) {
DBG_WARNING("Invalid channel bindings for "
"user=[%s] domain=[%s] workstation=[%s]\n",
ntlmssp_state->user,
ntlmssp_state->domain,
ntlmssp_state->client.netbios_name);
dump_data(DBGLVL_WARNING,
client_channel_bindings,
16);
dump_data(DBGLVL_WARNING,
server_channel_bindings,
16);
return NT_STATUS_BAD_BINDINGS;
}
}
nttime_to_timeval(&endtime, ntlmssp_state->server.challenge_endtime);
expired = timeval_expired(&endtime);
if (expired) {

View File

@ -22,9 +22,15 @@
*/
#include "includes.h"
#include "auth/gensec/gensec.h"
#include "auth/gensec/gensec_internal.h"
#include "../auth/ntlmssp/ntlmssp.h"
#include "../auth/ntlmssp/ntlmssp_private.h"
#include "lib/crypto/gnutls_helpers.h"
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
@ -218,3 +224,95 @@ const DATA_BLOB ntlmssp_version_blob(void)
return data_blob_const(version_buffer, ARRAY_SIZE(version_buffer));
}
NTSTATUS ntlmssp_hash_channel_bindings(struct gensec_security *gensec_security,
uint8_t cb_hash[16])
{
const struct gensec_channel_bindings *cb =
gensec_security->channel_bindings;
gnutls_hash_hd_t hash_hnd = NULL;
uint8_t uint32buf[4];
int rc;
if (cb == NULL) {
memset(cb_hash, 0, 16);
return NT_STATUS_OK;
}
GNUTLS_FIPS140_SET_LAX_MODE();
rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
if (rc < 0) {
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
SIVAL(uint32buf, 0, cb->initiator_addrtype);
rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf));
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
SIVAL(uint32buf, 0, cb->initiator_address.length);
rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf));
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
if (cb->initiator_address.length > 0) {
rc = gnutls_hash(hash_hnd,
cb->initiator_address.data,
cb->initiator_address.length);
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
}
SIVAL(uint32buf, 0, cb->acceptor_addrtype);
rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf));
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
SIVAL(uint32buf, 0, cb->acceptor_address.length);
rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf));
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
if (cb->acceptor_address.length > 0) {
rc = gnutls_hash(hash_hnd,
cb->acceptor_address.data,
cb->acceptor_address.length);
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
}
SIVAL(uint32buf, 0, cb->application_data.length);
rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf));
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
if (cb->application_data.length > 0) {
rc = gnutls_hash(hash_hnd,
cb->application_data.data,
cb->application_data.length);
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
}
gnutls_hash_deinit(hash_hnd, cb_hash);
GNUTLS_FIPS140_SET_STRICT_MODE();
return NT_STATUS_OK;
}