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:
parent
c41feb6c2a
commit
1219bf3830
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user