summaryrefslogtreecommitdiff
path: root/source4/libcli/auth
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2004-09-11 15:11:36 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:58:39 -0500
commit909c9b681a0718b8701e05addbad08c0aec87113 (patch)
treed569f2f54075a0514fa6e4b591d383f47e8d631d /source4/libcli/auth
parent4490c816a90871cd93b1a709bae91e5176e4f599 (diff)
downloadsamba-909c9b681a0718b8701e05addbad08c0aec87113.tar.gz
samba-909c9b681a0718b8701e05addbad08c0aec87113.tar.bz2
samba-909c9b681a0718b8701e05addbad08c0aec87113.zip
r2284: Thanks to some great detective work by tridge, NTLM2 signing now works.
This means that 'require NTLMv2 session security' now works for RPC pipe signing. We don't yet have sealing, but it can't be much further. This is almost all tridge's code, munged into a form that can work with the GENSEC API. This commit also includes more lsakey fixes - that key is used for all DCE-RPC level authenticated connections, even over CIFS/ncacn_np. No doubt I missed something, but I'm going to get some sleep :-) Andrew Bartlett (This used to be commit a1fe175eec884280fb7e9ca8f528134cf4600beb)
Diffstat (limited to 'source4/libcli/auth')
-rw-r--r--source4/libcli/auth/gensec.c32
-rw-r--r--source4/libcli/auth/gensec.h17
-rw-r--r--source4/libcli/auth/gensec_ntlmssp.c41
-rw-r--r--source4/libcli/auth/ntlmssp.c6
-rw-r--r--source4/libcli/auth/ntlmssp.h7
-rw-r--r--source4/libcli/auth/ntlmssp_sign.c135
-rw-r--r--source4/libcli/auth/spnego.c62
7 files changed, 203 insertions, 97 deletions
diff --git a/source4/libcli/auth/gensec.c b/source4/libcli/auth/gensec.c
index 4b362b5305..a744f513dc 100644
--- a/source4/libcli/auth/gensec.c
+++ b/source4/libcli/auth/gensec.c
@@ -248,8 +248,6 @@ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
gensec_want_feature(gensec_security, GENSEC_WANT_SEAL);
}
- gensec_want_feature(gensec_security, GENSEC_WANT_SESSION_KEY);
-
return gensec_start_mech(gensec_security);
}
@@ -303,17 +301,23 @@ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
*/
NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig)
+ uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig)
{
if (!gensec_security->ops->unseal_packet) {
return NT_STATUS_NOT_IMPLEMENTED;
}
- return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, data, length, sig);
+ return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
+ data, length,
+ whole_pdu, pdu_length,
+ sig);
}
NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
const DATA_BLOB *sig)
{
if (!gensec_security->ops->check_packet) {
@@ -323,12 +327,13 @@ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
return NT_STATUS_INVALID_PARAMETER;
}
- return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, sig);
+ return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
}
NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
DATA_BLOB *sig)
{
if (!gensec_security->ops->seal_packet) {
@@ -338,12 +343,13 @@ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
return NT_STATUS_INVALID_PARAMETER;
}
- return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, sig);
+ return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
}
NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
DATA_BLOB *sig)
{
if (!gensec_security->ops->sign_packet) {
@@ -353,7 +359,19 @@ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
return NT_STATUS_INVALID_PARAMETER;
}
- return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, sig);
+ return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
+}
+
+size_t gensec_sig_size(struct gensec_security *gensec_security)
+{
+ if (!gensec_security->ops->sig_size) {
+ return 0;
+ }
+ if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
+ return 0;
+ }
+
+ return gensec_security->ops->sig_size(gensec_security);
}
NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
diff --git a/source4/libcli/auth/gensec.h b/source4/libcli/auth/gensec.h
index 73a5f6b463..00c1c0dd0a 100644
--- a/source4/libcli/auth/gensec.h
+++ b/source4/libcli/auth/gensec.h
@@ -60,13 +60,22 @@ struct gensec_security_ops {
NTSTATUS (*update)(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
const DATA_BLOB in, DATA_BLOB *out);
NTSTATUS (*seal_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig);
+ uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig);
NTSTATUS (*sign_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
- const uint8_t *data, size_t length, DATA_BLOB *sig);
+ const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig);
+ size_t (*sig_size)(struct gensec_security *gensec_security);
NTSTATUS (*check_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
- const uint8_t *data, size_t length, const DATA_BLOB *sig);
+ const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ const DATA_BLOB *sig);
NTSTATUS (*unseal_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig);
+ uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig);
NTSTATUS (*session_key)(struct gensec_security *gensec_security, DATA_BLOB *session_key);
NTSTATUS (*session_info)(struct gensec_security *gensec_security,
struct auth_session_info **session_info);
diff --git a/source4/libcli/auth/gensec_ntlmssp.c b/source4/libcli/auth/gensec_ntlmssp.c
index beee29a088..0c96a783f1 100644
--- a/source4/libcli/auth/gensec_ntlmssp.c
+++ b/source4/libcli/auth/gensec_ntlmssp.c
@@ -287,42 +287,52 @@ static NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_secur
wrappers for the ntlmssp_*() functions
*/
static NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig)
+ TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig)
{
struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_unseal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
+ return ntlmssp_unseal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig);
}
static NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const uint8_t *data, size_t length,
- const DATA_BLOB *sig)
+ TALLOC_CTX *mem_ctx,
+ const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ const DATA_BLOB *sig)
{
struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_check_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
+ return ntlmssp_check_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig);
}
static NTSTATUS gensec_ntlmssp_seal_packet(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- uint8_t *data, size_t length,
- DATA_BLOB *sig)
+ TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig)
{
struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_seal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
+ return ntlmssp_seal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig);
}
static NTSTATUS gensec_ntlmssp_sign_packet(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const uint8_t *data, size_t length,
- DATA_BLOB *sig)
+ TALLOC_CTX *mem_ctx,
+ const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig)
{
struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_sign_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
+ return ntlmssp_sign_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig);
+}
+
+static size_t gensec_ntlmssp_sig_size(struct gensec_security *gensec_security)
+{
+ return NTLMSSP_SIG_SIZE;
}
static NTSTATUS gensec_ntlmssp_session_key(struct gensec_security *gensec_security,
@@ -413,6 +423,7 @@ static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
.server_start = gensec_ntlmssp_server_start,
.update = gensec_ntlmssp_update,
.seal_packet = gensec_ntlmssp_seal_packet,
+ .sig_size = gensec_ntlmssp_sig_size,
.sign_packet = gensec_ntlmssp_sign_packet,
.check_packet = gensec_ntlmssp_check_packet,
.unseal_packet = gensec_ntlmssp_unseal_packet,
diff --git a/source4/libcli/auth/ntlmssp.c b/source4/libcli/auth/ntlmssp.c
index 4d2dd6b576..e6839e1fea 100644
--- a/source4/libcli/auth/ntlmssp.c
+++ b/source4/libcli/auth/ntlmssp.c
@@ -940,7 +940,7 @@ NTSTATUS ntlmssp_server_start(struct ntlmssp_state **ntlmssp_state)
(*ntlmssp_state)->neg_flags =
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_NTLM |
-/* NTLMSSP_NEGOTIATE_NTLM2 | */
+ NTLMSSP_NEGOTIATE_NTLM2 |
NTLMSSP_NEGOTIATE_KEY_EXCH;
return NT_STATUS_OK;
@@ -971,7 +971,7 @@ static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state,
}
if (ntlmssp_state->use_ntlmv2) {
-/* ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;*/
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
}
/* generate the ntlmssp negotiate packet */
@@ -1293,7 +1293,7 @@ NTSTATUS ntlmssp_client_start(struct ntlmssp_state **ntlmssp_state)
(*ntlmssp_state)->neg_flags =
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_NTLM |
-/* NTLMSSP_NEGOTIATE_NTLM2 |*/
+ NTLMSSP_NEGOTIATE_NTLM2 |
NTLMSSP_NEGOTIATE_KEY_EXCH |
NTLMSSP_REQUEST_TARGET;
diff --git a/source4/libcli/auth/ntlmssp.h b/source4/libcli/auth/ntlmssp.h
index 61285e472b..153669f7b4 100644
--- a/source4/libcli/auth/ntlmssp.h
+++ b/source4/libcli/auth/ntlmssp.h
@@ -71,6 +71,8 @@ enum ntlmssp_message_type
#define NTLMSSP_SIGN_VERSION 1
+#define NTLMSSP_SIG_SIZE 16
+
struct ntlmssp_state
{
TALLOC_CTX *mem_ctx;
@@ -162,8 +164,9 @@ struct ntlmssp_state
const char *(*get_domain)(void);
/* SMB Signing */
-
- uint32_t ntlmssp_seq_num;
+ uint32_t ntlm_seq_num;
+ uint32_t ntlm2_send_seq_num;
+ uint32_t ntlm2_recv_seq_num;
/* ntlmv2 */
DATA_BLOB send_sign_key;
diff --git a/source4/libcli/auth/ntlmssp_sign.c b/source4/libcli/auth/ntlmssp_sign.c
index ca3660eea7..2ab54124e3 100644
--- a/source4/libcli/auth/ntlmssp_sign.c
+++ b/source4/libcli/auth/ntlmssp_sign.c
@@ -64,31 +64,40 @@ enum ntlmssp_direction {
static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_state,
TALLOC_CTX *sig_mem_ctx,
const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
enum ntlmssp_direction direction,
- DATA_BLOB *sig)
+ DATA_BLOB *sig, BOOL encrypt_sig)
{
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
HMACMD5Context ctx;
uint8_t digest[16];
uint8_t seq_num[4];
- SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
+ *sig = data_blob_talloc(sig_mem_ctx, NULL, NTLMSSP_SIG_SIZE);
+ if (!sig->data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
switch (direction) {
case NTLMSSP_SEND:
+ SIVAL(seq_num, 0, ntlmssp_state->ntlm2_send_seq_num);
+ ntlmssp_state->ntlm2_send_seq_num++;
hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key.data,
ntlmssp_state->send_sign_key.length, &ctx);
break;
case NTLMSSP_RECEIVE:
+ SIVAL(seq_num, 0, ntlmssp_state->ntlm2_recv_seq_num);
+ ntlmssp_state->ntlm2_recv_seq_num++;
hmac_md5_init_limK_to_64(ntlmssp_state->recv_sign_key.data,
ntlmssp_state->recv_sign_key.length, &ctx);
break;
}
hmac_md5_update(seq_num, sizeof(seq_num), &ctx);
- hmac_md5_update(data, length, &ctx);
+ hmac_md5_update(whole_pdu, pdu_length, &ctx);
hmac_md5_final(digest, &ctx);
- if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+ if (encrypt_sig && ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
switch (direction) {
case NTLMSSP_SEND:
arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, digest, 8);
@@ -98,7 +107,7 @@ static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_stat
break;
}
}
- *sig = data_blob_talloc(sig_mem_ctx, NULL, 16);
+
SIVAL(sig->data, 0, NTLMSSP_SIGN_VERSION);
memcpy(sig->data + 4, digest, 8);
memcpy(sig->data + 12, seq_num, 4);
@@ -106,11 +115,14 @@ static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_stat
} else {
uint32_t crc;
crc = crc32_calc_buffer((const char *)data, length);
- if (!msrpc_gen(sig_mem_ctx, sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+ if (!msrpc_gen(sig_mem_ctx, sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlm_seq_num)) {
return NT_STATUS_NO_MEMORY;
}
-
- arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
+ ntlmssp_state->ntlm_seq_num++;
+
+ if (encrypt_sig) {
+ arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
+ }
}
dump_data_pw("calculated ntlmssp signature\n", sig->data, sig->length);
return NT_STATUS_OK;
@@ -119,26 +131,23 @@ static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_stat
NTSTATUS ntlmssp_sign_packet(struct ntlmssp_state *ntlmssp_state,
TALLOC_CTX *sig_mem_ctx,
const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
DATA_BLOB *sig)
{
- NTSTATUS nt_status;
-
if (!ntlmssp_state->session_key.length) {
DEBUG(3, ("NO session key, cannot check sign packet\n"));
return NT_STATUS_NO_USER_SESSION_KEY;
}
-
+
if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
DEBUG(3, ("NTLMSSP Signing not negotiated - cannot sign packet!\n"));
return NT_STATUS_INVALID_PARAMETER;
}
-
- nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx,
- data, length, NTLMSSP_SEND, sig);
-
- /* increment counter on send */
- ntlmssp_state->ntlmssp_seq_num++;
- return nt_status;
+
+ return ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx,
+ data, length,
+ whole_pdu, pdu_length,
+ NTLMSSP_SEND, sig, True);
}
/**
@@ -149,6 +158,7 @@ NTSTATUS ntlmssp_sign_packet(struct ntlmssp_state *ntlmssp_state,
NTSTATUS ntlmssp_check_packet(struct ntlmssp_state *ntlmssp_state,
TALLOC_CTX *sig_mem_ctx,
const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
const DATA_BLOB *sig)
{
DATA_BLOB local_sig;
@@ -164,17 +174,16 @@ NTSTATUS ntlmssp_check_packet(struct ntlmssp_state *ntlmssp_state,
(unsigned long)sig->length));
}
- nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx, data,
- length, NTLMSSP_RECEIVE, &local_sig);
+ nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx,
+ data, length,
+ whole_pdu, pdu_length,
+ NTLMSSP_RECEIVE, &local_sig, True);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status)));
return nt_status;
}
- /* increment counter on recv */
- ntlmssp_state->ntlmssp_seq_num++;
-
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
if (local_sig.length != sig->length ||
memcmp(local_sig.data,
@@ -216,8 +225,10 @@ NTSTATUS ntlmssp_check_packet(struct ntlmssp_state *ntlmssp_state,
NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state,
TALLOC_CTX *sig_mem_ctx,
uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
DATA_BLOB *sig)
{
+ NTSTATUS nt_status;
if (!ntlmssp_state->session_key.length) {
DEBUG(3, ("NO session key, cannot seal packet\n"));
return NT_STATUS_NO_USER_SESSION_KEY;
@@ -231,35 +242,20 @@ NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state,
DEBUG(10,("ntlmssp_seal_data: seal\n"));
dump_data_pw("ntlmssp clear data\n", data, length);
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
- HMACMD5Context ctx;
- uint8_t seq_num[4];
- uint8_t digest[16];
- SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
-
- hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key.data,
- ntlmssp_state->send_sign_key.length, &ctx);
- hmac_md5_update(seq_num, 4, &ctx);
- hmac_md5_update(data, length, &ctx);
- hmac_md5_final(digest, &ctx);
-
/* The order of these two operations matters - we must first seal the packet,
then seal the sequence number - this is becouse the send_seal_hash is not
constant, but is is rather updated with each iteration */
arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, data, length);
- if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
- arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, digest, 8);
- }
-
- *sig = data_blob_talloc(sig_mem_ctx, NULL, 16);
- SIVAL(sig->data, 0, NTLMSSP_SIGN_VERSION);
- memcpy(sig->data + 4, digest, 8);
- memcpy(sig->data + 12, seq_num, 4);
+ nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx,
+ data, length,
+ whole_pdu, pdu_length,
+ NTLMSSP_SEND, sig, True);
} else {
uint32_t crc;
crc = crc32_calc_buffer((const char *)data, length);
- if (!msrpc_gen(sig_mem_ctx, sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+ if (!msrpc_gen(sig_mem_ctx, sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlm_seq_num)) {
return NT_STATUS_NO_MEMORY;
}
@@ -270,14 +266,15 @@ NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state,
arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, data, length);
arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
+ /* increment counter on send */
+ ntlmssp_state->ntlm_seq_num++;
+ nt_status = NT_STATUS_OK;
}
dump_data_pw("ntlmssp signature\n", sig->data, sig->length);
dump_data_pw("ntlmssp sealed data\n", data, length);
- /* increment counter on send */
- ntlmssp_state->ntlmssp_seq_num++;
- return NT_STATUS_OK;
+ return nt_status;
}
/**
@@ -288,8 +285,11 @@ NTSTATUS ntlmssp_seal_packet(struct ntlmssp_state *ntlmssp_state,
NTSTATUS ntlmssp_unseal_packet(struct ntlmssp_state *ntlmssp_state,
TALLOC_CTX *sig_mem_ctx,
uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
DATA_BLOB *sig)
{
+ DATA_BLOB local_sig;
+ NTSTATUS nt_status;
if (!ntlmssp_state->session_key.length) {
DEBUG(3, ("NO session key, cannot unseal packet\n"));
return NT_STATUS_NO_USER_SESSION_KEY;
@@ -297,13 +297,46 @@ NTSTATUS ntlmssp_unseal_packet(struct ntlmssp_state *ntlmssp_state,
dump_data_pw("ntlmssp sealed data\n", data, length);
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+
+ /* We have to pass the data past the arcfour pad in
+ * the correct order, so we must encrypt the signature
+ * after we decrypt the main body. however, the
+ * signature is calculated over the encrypted data */
+
+ nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx,
+ data, length,
+ whole_pdu, pdu_length,
+ NTLMSSP_RECEIVE, &local_sig, False);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
arcfour_crypt_sbox(ntlmssp_state->recv_seal_hash, data, length);
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+ arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, local_sig.data + 4, 8);
+ }
+
+ if (local_sig.length != sig->length ||
+ memcmp(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);
+
+ DEBUG(5, ("BAD SIG: got signature of\n"));
+ dump_data(5, sig->data, sig->length);
+
+ DEBUG(0, ("NTLMSSP NTLM2 packet check failed due to invalid signature!\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ dump_data_pw("ntlmssp clear data\n", data, length);
+ return NT_STATUS_OK;
} else {
arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, data, length);
+ dump_data_pw("ntlmssp clear data\n", data, length);
+ return ntlmssp_check_packet(ntlmssp_state, sig_mem_ctx, data, length, whole_pdu, pdu_length, sig);
}
- dump_data_pw("ntlmssp clear data\n", data, length);
-
- return ntlmssp_check_packet(ntlmssp_state, sig_mem_ctx, data, length, sig);
}
/**
@@ -414,7 +447,9 @@ NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state)
sizeof(ntlmssp_state->ntlmssp_hash));
}
- ntlmssp_state->ntlmssp_seq_num = 0;
+ ntlmssp_state->ntlm_seq_num = 0;
+ ntlmssp_state->ntlm2_send_seq_num = 0;
+ ntlmssp_state->ntlm2_recv_seq_num = 0;
return NT_STATUS_OK;
}
diff --git a/source4/libcli/auth/spnego.c b/source4/libcli/auth/spnego.c
index de71814354..f3ead5069d 100644
--- a/source4/libcli/auth/spnego.c
+++ b/source4/libcli/auth/spnego.c
@@ -92,8 +92,10 @@ static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_securi
wrappers for the spnego_*() functions
*/
static NTSTATUS gensec_spnego_unseal_packet(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig)
+ TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig)
{
struct spnego_state *spnego_state = gensec_security->private_data;
@@ -103,13 +105,17 @@ static NTSTATUS gensec_spnego_unseal_packet(struct gensec_security *gensec_secur
}
return gensec_unseal_packet(spnego_state->sub_sec_security,
- mem_ctx, data, length, sig);
+ mem_ctx,
+ data, length,
+ whole_pdu, pdu_length,
+ sig);
}
static NTSTATUS gensec_spnego_check_packet(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const uint8_t *data, size_t length,
- const DATA_BLOB *sig)
+ TALLOC_CTX *mem_ctx,
+ const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ const DATA_BLOB *sig)
{
struct spnego_state *spnego_state = gensec_security->private_data;
@@ -120,13 +126,17 @@ static NTSTATUS gensec_spnego_check_packet(struct gensec_security *gensec_securi
}
return gensec_check_packet(spnego_state->sub_sec_security,
- mem_ctx, data, length, sig);
+ mem_ctx,
+ data, length,
+ whole_pdu, pdu_length,
+ sig);
}
static NTSTATUS gensec_spnego_seal_packet(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- uint8_t *data, size_t length,
- DATA_BLOB *sig)
+ TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig)
{
struct spnego_state *spnego_state = gensec_security->private_data;
@@ -137,13 +147,17 @@ static NTSTATUS gensec_spnego_seal_packet(struct gensec_security *gensec_securit
}
return gensec_seal_packet(spnego_state->sub_sec_security,
- mem_ctx, data, length, sig);
+ mem_ctx,
+ data, length,
+ whole_pdu, pdu_length,
+ sig);
}
static NTSTATUS gensec_spnego_sign_packet(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const uint8_t *data, size_t length,
- DATA_BLOB *sig)
+ TALLOC_CTX *mem_ctx,
+ const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig)
{
struct spnego_state *spnego_state = gensec_security->private_data;
@@ -153,11 +167,26 @@ static NTSTATUS gensec_spnego_sign_packet(struct gensec_security *gensec_securit
}
return gensec_sign_packet(spnego_state->sub_sec_security,
- mem_ctx, data, length, sig);
+ mem_ctx,
+ data, length,
+ whole_pdu, pdu_length,
+ sig);
+}
+
+static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security)
+{
+ struct spnego_state *spnego_state = gensec_security->private_data;
+
+ if (spnego_state->state_position != SPNEGO_DONE
+ && spnego_state->state_position != SPNEGO_FALLBACK) {
+ return 0;
+ }
+
+ return gensec_sig_size(spnego_state->sub_sec_security);
}
static NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_security,
- DATA_BLOB *session_key)
+ DATA_BLOB *session_key)
{
struct spnego_state *spnego_state = gensec_security->private_data;
if (!spnego_state->sub_sec_security) {
@@ -684,6 +713,7 @@ static const struct gensec_security_ops gensec_spnego_security_ops = {
.update = gensec_spnego_update,
.seal_packet = gensec_spnego_seal_packet,
.sign_packet = gensec_spnego_sign_packet,
+ .sig_size = gensec_spnego_sig_size,
.check_packet = gensec_spnego_check_packet,
.unseal_packet = gensec_spnego_unseal_packet,
.session_key = gensec_spnego_session_key,