summaryrefslogtreecommitdiff
path: root/source3/libsmb/ntlmssp_sign.c
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2003-07-14 08:46:32 +0000
committerAndrew Bartlett <abartlet@samba.org>2003-07-14 08:46:32 +0000
commit456f51bcbe04ccbb37a27b6e115a851cc134adcd (patch)
treea68c7158940ad47fa856f894c6634a26669ef692 /source3/libsmb/ntlmssp_sign.c
parent379367dd7607514c17bc8ea8aa60212b1c6070a7 (diff)
downloadsamba-456f51bcbe04ccbb37a27b6e115a851cc134adcd.tar.gz
samba-456f51bcbe04ccbb37a27b6e115a851cc134adcd.tar.bz2
samba-456f51bcbe04ccbb37a27b6e115a851cc134adcd.zip
Jeremy requested that I get my NTLMSSP patch into CVS. He didn't request
the schannel code, but I've included that anyway. :-) This patch revives the client-side NTLMSSP support for RPC named pipes in Samba, and cleans up the client and server schannel code. The use of the new code is enabled by the 'sign', 'seal' and 'schannel' commands in rpcclient. The aim was to prove that our separate NTLMSSP client library actually implements NTLMSSP signing and sealing as per Microsoft's NTLMv1 implementation, in the hope that knowing this will assist us in correctly implementing NTLMSSP signing for SMB packets. (Still not yet functional) This patch replaces the NTLMSSP implementation in rpc_client/cli_pipe.c with calls to libsmb/ntlmssp.c. In the process, we have gained the ability to use the more secure NT password, and the ability to sign-only, instead of having to seal the pipe connection. (Previously we were limited to sealing, and could only use the LM-password derived key). Our new client-side NTLMSSP code also needed alteration to cope with our comparatively simple server-side implementation. A future step is to replace it with calls to the same NTLMSSP library. Also included in this patch is the schannel 'sign only' patch I submitted to the team earlier. While not enabled (and not functional, at this stage) the work in this patch makes the code paths *much* easier to follow. I have also included similar hooks in rpccleint to allow the use of schannel on *any* pipe. rpcclient now defaults to not using schannel (or any other extra per-pipe authenticiation) for any connection. The 'schannel' command enables schannel for all pipes until disabled. This code is also much more secure than the previous code, as changes to our cli_pipe routines ensure that the authentication footer cannot be removed by an attacker, and more error states are correctly handled. (The same needs to be done to our server) Andrew Bartlett (This used to be commit 5472ddc9eaf4e79c5b2e1c8ee8c7f190dc285f19)
Diffstat (limited to 'source3/libsmb/ntlmssp_sign.c')
-rw-r--r--source3/libsmb/ntlmssp_sign.c206
1 files changed, 169 insertions, 37 deletions
diff --git a/source3/libsmb/ntlmssp_sign.c b/source3/libsmb/ntlmssp_sign.c
index 86faf1f5e6..748c008963 100644
--- a/source3/libsmb/ntlmssp_sign.c
+++ b/source3/libsmb/ntlmssp_sign.c
@@ -79,13 +79,18 @@ static void calc_hash(unsigned char *hash, const char *k2, int k2l)
}
static void calc_ntlmv2_hash(unsigned char hash[16], char digest[16],
- const char encrypted_response[16],
+ DATA_BLOB session_key,
const char *constant)
{
struct MD5Context ctx3;
+ /* NOTE: This code is currently complate fantasy - it's
+ got more in common with reality than the previous code
+ (the LM session key is not the right thing to use) but
+ it still needs work */
+
MD5Init(&ctx3);
- MD5Update(&ctx3, encrypted_response, 5);
+ MD5Update(&ctx3, session_key.data, session_key.length);
MD5Update(&ctx3, constant, strlen(constant));
MD5Final(digest, &ctx3);
@@ -113,25 +118,28 @@ static NTSTATUS ntlmssp_make_packet_signiture(NTLMSSP_CLIENT_STATE *ntlmssp_stat
hmac_md5_update(data, length, &ctx);
hmac_md5_final(digest, &ctx);
- if (!msrpc_gen(sig, "Bd", digest, sizeof(digest), ntlmssp_state->ntlmssp_seq_num)) {
+ if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
+ , ntlmssp_state->ntlmssp_seq_num)) {
return NT_STATUS_NO_MEMORY;
}
switch (direction) {
case NTLMSSP_SEND:
- NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash, sig->data, sig->length);
+ NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash, sig->data+4, sig->length-4);
break;
case NTLMSSP_RECEIVE:
- NTLMSSPcalc_ap(ntlmssp_state->srv_sign_hash, sig->data, sig->length);
+ NTLMSSPcalc_ap(ntlmssp_state->srv_sign_hash, sig->data+4, sig->length-4);
break;
}
} else {
uint32 crc;
crc = crc32_calc_buffer(data, length);
- if (!msrpc_gen(sig, "ddd", 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+ if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
return NT_STATUS_NO_MEMORY;
}
- NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data, sig->length);
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
}
return NT_STATUS_OK;
}
@@ -140,8 +148,11 @@ NTSTATUS ntlmssp_client_sign_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
const uchar *data, size_t length,
DATA_BLOB *sig)
{
+ NTSTATUS nt_status = ntlmssp_make_packet_signiture(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+
+ /* increment counter on send */
ntlmssp_state->ntlmssp_seq_num++;
- return ntlmssp_make_packet_signiture(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+ return nt_status;
}
/**
@@ -151,8 +162,8 @@ NTSTATUS ntlmssp_client_sign_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
*/
NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
- const uchar *data, size_t length,
- const DATA_BLOB *sig)
+ const uchar *data, size_t length,
+ const DATA_BLOB *sig)
{
DATA_BLOB local_sig;
NTSTATUS nt_status;
@@ -170,9 +181,7 @@ NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
return nt_status;
}
- if (memcmp(sig->data, local_sig.data, MIN(sig->length, local_sig.length)) == 0) {
- return NT_STATUS_OK;
- } else {
+ if (memcmp(sig->data+sig->length - 8, local_sig.data+local_sig.length - 8, 8) != 0) {
DEBUG(5, ("BAD SIG: wanted signature of\n"));
dump_data(5, local_sig.data, local_sig.length);
@@ -182,6 +191,97 @@ NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
DEBUG(0, ("NTLMSSP packet check failed due to invalid signiture!\n"));
return NT_STATUS_ACCESS_DENIED;
}
+
+ /* increment counter on recieive */
+ ntlmssp_state->ntlmssp_seq_num++;
+
+ return NT_STATUS_OK;
+}
+
+
+/**
+ * Seal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_client_seal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ DEBUG(10,("ntlmssp_client_seal_data: seal\n"));
+ dump_data_pw("ntlmssp clear data\n", data, length);
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ HMACMD5Context ctx;
+ char seq_num[4];
+ uchar digest[16];
+ SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
+
+ hmac_md5_init_limK_to_64(ntlmssp_state->cli_sign_const, 16, &ctx);
+ hmac_md5_update(seq_num, 4, &ctx);
+ hmac_md5_update(data, length, &ctx);
+ hmac_md5_final(digest, &ctx);
+
+ if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
+ , ntlmssp_state->ntlmssp_seq_num)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dump_data_pw("ntlmssp client sealing hash:\n",
+ ntlmssp_state->cli_seal_hash,
+ sizeof(ntlmssp_state->cli_seal_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->cli_seal_hash, data, length);
+ dump_data_pw("ntlmssp client signing hash:\n",
+ ntlmssp_state->cli_sign_hash,
+ sizeof(ntlmssp_state->cli_sign_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash, sig->data+4, sig->length-4);
+ } else {
+ uint32 crc;
+ crc = crc32_calc_buffer(data, length);
+ if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* The order of these two operations matters - we must first seal the packet,
+ then seal the sequence number - this is becouse the ntlmssp_hash is not
+ constant, but is is rather updated with each iteration */
+
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
+ }
+ dump_data_pw("ntlmssp sealed data\n", data, length);
+
+ /* increment counter on send */
+ ntlmssp_state->ntlmssp_seq_num++;
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Unseal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_client_unseal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ DEBUG(10,("ntlmssp_client_unseal_data: seal\n"));
+ dump_data_pw("ntlmssp sealed data\n", data, length);
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ NTLMSSPcalc_ap(ntlmssp_state->srv_seal_hash, data, length);
+ } else {
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+ }
+ dump_data_pw("ntlmssp clear data\n", data, length);
+
+ return ntlmssp_client_check_packet(ntlmssp_state, data, length, sig);
}
/**
@@ -190,37 +290,69 @@ NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
NTSTATUS ntlmssp_client_sign_init(NTLMSSP_CLIENT_STATE *ntlmssp_state)
{
unsigned char p24[24];
- unsigned char lm_hash[16];
+ ZERO_STRUCT(p24);
+
+ DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n"));
+ debug_ntlmssp_flags(ntlmssp_state->neg_flags);
- if (!ntlmssp_state->lm_resp.data) {
- /* can't sign or check signitures yet */
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- E_deshash(ntlmssp_state->password, lm_hash);
-
- NTLMSSPOWFencrypt(lm_hash, ntlmssp_state->lm_resp.data, p24);
-
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
{
- calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash, ntlmssp_state->cli_sign_const, p24, CLI_SIGN);
- calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash, ntlmssp_state->cli_seal_const, p24, CLI_SEAL);
- calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash, ntlmssp_state->srv_sign_const, p24, SRV_SIGN);
- calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash, ntlmssp_state->srv_seal_const, p24, SRV_SEAL);
- }
- else
- {
- char k2[8];
- memcpy(k2, p24, 5);
- k2[5] = 0xe5;
- k2[6] = 0x38;
- k2[7] = 0xb0;
+
+ calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash,
+ ntlmssp_state->cli_sign_const,
+ ntlmssp_state->session_key, CLI_SIGN);
+ dump_data_pw("NTLMSSP client sign hash:\n",
+ ntlmssp_state->cli_sign_hash,
+ sizeof(ntlmssp_state->cli_sign_hash));
+
+ calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash,
+ ntlmssp_state->cli_seal_const,
+ ntlmssp_state->session_key, CLI_SEAL);
+ dump_data_pw("NTLMSSP client sesl hash:\n",
+ ntlmssp_state->cli_seal_hash,
+ sizeof(ntlmssp_state->cli_seal_hash));
+
+ calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash,
+ ntlmssp_state->srv_sign_const,
+ ntlmssp_state->session_key, SRV_SIGN);
+ dump_data_pw("NTLMSSP server sign hash:\n",
+ ntlmssp_state->srv_sign_hash,
+ sizeof(ntlmssp_state->srv_sign_hash));
+
+ calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash,
+ ntlmssp_state->srv_seal_const,
+ ntlmssp_state->session_key, SRV_SEAL);
+ dump_data_pw("NTLMSSP server seal hash:\n",
+ ntlmssp_state->cli_sign_hash,
+ sizeof(ntlmssp_state->cli_sign_hash));
+ }
+ else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
+ if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 8) {
+ /* can't sign or check signitures yet */
+ DEBUG(5, ("NTLMSSP Sign/Seal - cannot use LM KEY yet\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(5, ("NTLMSSP Sign/Seal - using LM KEY\n"));
+
+ calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 8);
+ dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ } else {
+ if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 16) {
+ /* can't sign or check signitures yet */
+ DEBUG(5, ("NTLMSSP Sign/Seal - cannot use NT KEY yet\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
- calc_hash(ntlmssp_state->ntlmssp_hash, k2, 8);
+ DEBUG(5, ("NTLMSSP Sign/Seal - using NT KEY\n"));
+
+ calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 16);
+ dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
}
ntlmssp_state->ntlmssp_seq_num = 0;
- ZERO_STRUCT(lm_hash);
return NT_STATUS_OK;
}