summaryrefslogtreecommitdiff
path: root/libcli/auth/schannel_sign.c
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2009-09-16 02:03:46 +0200
committerStefan Metzmacher <metze@samba.org>2009-09-16 12:29:06 +0200
commit033ced60ac734161686bd3da685f2d7b056e17c8 (patch)
tree30986b71cee0e153c105ef1fed8b93d3a7322fab /libcli/auth/schannel_sign.c
parent8f482ae663611ee2109395e4d24418e4c4f57160 (diff)
downloadsamba-033ced60ac734161686bd3da685f2d7b056e17c8.tar.gz
samba-033ced60ac734161686bd3da685f2d7b056e17c8.tar.bz2
samba-033ced60ac734161686bd3da685f2d7b056e17c8.zip
libcli/auth: rewrite schannel sign/seal code to be more generic
This prepares support for HMAC-SHA256/AES. metze
Diffstat (limited to 'libcli/auth/schannel_sign.c')
-rw-r--r--libcli/auth/schannel_sign.c297
1 files changed, 148 insertions, 149 deletions
diff --git a/libcli/auth/schannel_sign.c b/libcli/auth/schannel_sign.c
index e60b4107bb..0672f67197 100644
--- a/libcli/auth/schannel_sign.c
+++ b/libcli/auth/schannel_sign.c
@@ -24,58 +24,89 @@
#include "../libcli/auth/schannel.h"
#include "../lib/crypto/crypto.h"
-#define NETSEC_SIGN_SIGNATURE { 0x77, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 }
-#define NETSEC_SEAL_SIGNATURE { 0x77, 0x00, 0x7a, 0x00, 0xff, 0xff, 0x00, 0x00 }
+static void netsec_offset_and_sizes(struct schannel_state *state,
+ bool do_seal,
+ uint32_t *_min_sig_size,
+ uint32_t *_used_sig_size,
+ uint32_t *_checksum_length,
+ uint32_t *_confounder_ofs)
+{
+ uint32_t min_sig_size = 24;
+ uint32_t used_sig_size = 32;
+ uint32_t checksum_length = 8;
+ uint32_t confounder_ofs = 24;
+
+ if (do_seal) {
+ min_sig_size += 8;
+ }
+
+ if (_min_sig_size) {
+ *_min_sig_size = min_sig_size;
+ }
+
+ if (_used_sig_size) {
+ *_used_sig_size = used_sig_size;
+ }
+
+ if (_checksum_length) {
+ *_checksum_length = checksum_length;
+ }
+
+ if (_confounder_ofs) {
+ *_confounder_ofs = confounder_ofs;
+ }
+}
/*******************************************************************
Encode or Decode the sequence number (which is symmetric)
********************************************************************/
-static void netsec_deal_with_seq_num(struct schannel_state *state,
- const uint8_t packet_digest[8],
- uint8_t seq_num[8])
+static void netsec_do_seq_num(struct schannel_state *state,
+ const uint8_t *checksum,
+ uint32_t checksum_length,
+ uint8_t seq_num[8])
{
static const uint8_t zeros[4];
uint8_t sequence_key[16];
uint8_t digest1[16];
hmac_md5(state->creds->session_key, zeros, sizeof(zeros), digest1);
- hmac_md5(digest1, packet_digest, 8, sequence_key);
+ hmac_md5(digest1, checksum, checksum_length, sequence_key);
arcfour_crypt(seq_num, sequence_key, 8);
state->seq_num++;
}
-
-/*******************************************************************
- Calculate the key with which to encode the data payload
- ********************************************************************/
-static void netsec_get_sealing_key(const uint8_t session_key[16],
- const uint8_t seq_num[8],
- uint8_t sealing_key[16])
+static void netsec_do_seal(struct schannel_state *state,
+ const uint8_t seq_num[8],
+ uint8_t confounder[8],
+ uint8_t *data, uint32_t length)
{
+ uint8_t sealing_key[16];
static const uint8_t zeros[4];
uint8_t digest2[16];
uint8_t sess_kf0[16];
int i;
for (i = 0; i < 16; i++) {
- sess_kf0[i] = session_key[i] ^ 0xf0;
+ sess_kf0[i] = state->creds->session_key[i] ^ 0xf0;
}
hmac_md5(sess_kf0, zeros, 4, digest2);
hmac_md5(digest2, seq_num, 8, sealing_key);
-}
+ arcfour_crypt(confounder, sealing_key, 8);
+ arcfour_crypt(data, sealing_key, length);
+}
/*******************************************************************
Create a digest over the entire packet (including the data), and
MD5 it with the session key.
********************************************************************/
-static void schannel_digest(const uint8_t sess_key[16],
- const uint8_t netsec_sig[8],
- const uint8_t *confounder,
- const uint8_t *data, size_t data_len,
- uint8_t digest_final[16])
+static void netsec_do_sign(struct schannel_state *state,
+ const uint8_t *confounder,
+ const uint8_t *data, size_t data_len,
+ uint8_t header[8],
+ uint8_t *checksum)
{
uint8_t packet_digest[16];
static const uint8_t zeros[4];
@@ -83,187 +114,155 @@ static void schannel_digest(const uint8_t sess_key[16],
MD5Init(&ctx);
MD5Update(&ctx, zeros, 4);
- MD5Update(&ctx, netsec_sig, 8);
if (confounder) {
+ SSVAL(header, 0, NL_SIGN_HMAC_MD5);
+ SSVAL(header, 2, NL_SEAL_RC4);
+ SSVAL(header, 4, 0xFFFF);
+ SSVAL(header, 6, 0x0000);
+
+ MD5Update(&ctx, header, 8);
MD5Update(&ctx, confounder, 8);
+ } else {
+ SSVAL(header, 0, NL_SIGN_HMAC_MD5);
+ SSVAL(header, 2, NL_SEAL_NONE);
+ SSVAL(header, 4, 0xFFFF);
+ SSVAL(header, 6, 0x0000);
+
+ MD5Update(&ctx, header, 8);
}
MD5Update(&ctx, data, data_len);
MD5Final(packet_digest, &ctx);
- hmac_md5(sess_key, packet_digest, sizeof(packet_digest), digest_final);
+ hmac_md5(state->creds->session_key,
+ packet_digest, sizeof(packet_digest),
+ checksum);
}
-
-/*
- unseal a packet
-*/
-NTSTATUS schannel_unseal_packet(struct schannel_state *state,
+NTSTATUS netsec_incoming_packet(struct schannel_state *state,
TALLOC_CTX *mem_ctx,
+ bool do_unseal,
uint8_t *data, size_t length,
const DATA_BLOB *sig)
{
- uint8_t digest_final[16];
- uint8_t confounder[8];
+ uint32_t min_sig_size = 0;
+ uint8_t header[8];
+ uint8_t checksum[32];
+ uint32_t checksum_length = sizeof(checksum_length);
+ uint8_t _confounder[8];
+ uint8_t *confounder = NULL;
+ uint32_t confounder_ofs = 0;
uint8_t seq_num[8];
- uint8_t sealing_key[16];
- static const uint8_t netsec_sig[8] = NETSEC_SEAL_SIGNATURE;
+ int ret;
+
+ netsec_offset_and_sizes(state,
+ do_unseal,
+ &min_sig_size,
+ NULL,
+ &checksum_length,
+ &confounder_ofs);
- if (sig->length != 32) {
+ if (sig->length < min_sig_size) {
return NT_STATUS_ACCESS_DENIED;
}
- memcpy(confounder, sig->data+24, 8);
+ if (do_unseal) {
+ confounder = _confounder;
+ memcpy(confounder, sig->data+confounder_ofs, 8);
+ } else {
+ confounder = NULL;
+ }
RSIVAL(seq_num, 0, state->seq_num);
SIVAL(seq_num, 4, state->initiator?0:0x80);
- netsec_get_sealing_key(state->creds->session_key, seq_num, sealing_key);
- arcfour_crypt(confounder, sealing_key, 8);
- arcfour_crypt(data, sealing_key, length);
-
- schannel_digest(state->creds->session_key,
- netsec_sig, confounder,
- data, length, digest_final);
-
- if (memcmp(digest_final, sig->data+16, 8) != 0) {
- dump_data_pw("calc digest:", digest_final, 8);
- dump_data_pw("wire digest:", sig->data+16, 8);
- return NT_STATUS_ACCESS_DENIED;
+ if (do_unseal) {
+ netsec_do_seal(state, seq_num,
+ confounder,
+ data, length);
}
- netsec_deal_with_seq_num(state, digest_final, seq_num);
-
- if (memcmp(seq_num, sig->data+8, 8) != 0) {
- dump_data_pw("calc seq num:", seq_num, 8);
- dump_data_pw("wire seq num:", sig->data+8, 8);
- return NT_STATUS_ACCESS_DENIED;
- }
-
- return NT_STATUS_OK;
-}
-
-/*
- check the signature on a packet
-*/
-NTSTATUS schannel_check_packet(struct schannel_state *state,
- TALLOC_CTX *mem_ctx,
- const uint8_t *data, size_t length,
- const DATA_BLOB *sig)
-{
- uint8_t digest_final[16];
- uint8_t seq_num[8];
- static const uint8_t netsec_sig[8] = NETSEC_SIGN_SIGNATURE;
+ netsec_do_sign(state, confounder,
+ data, length,
+ header, checksum);
- /* w2k sends just 24 bytes and skip the confounder */
- if (sig->length != 32 && sig->length != 24) {
+ ret = memcmp(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);
return NT_STATUS_ACCESS_DENIED;
}
- RSIVAL(seq_num, 0, state->seq_num);
- SIVAL(seq_num, 4, state->initiator?0:0x80);
-
- dump_data_pw("seq_num:\n", seq_num, 8);
- dump_data_pw("sess_key:\n", state->creds->session_key, 16);
+ netsec_do_seq_num(state, checksum, checksum_length, seq_num);
- schannel_digest(state->creds->session_key,
- netsec_sig, NULL,
- data, length, digest_final);
-
- netsec_deal_with_seq_num(state, digest_final, seq_num);
-
- if (memcmp(seq_num, sig->data+8, 8) != 0) {
+ ret = memcmp(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);
return NT_STATUS_ACCESS_DENIED;
}
- if (memcmp(digest_final, sig->data+16, 8) != 0) {
- dump_data_pw("calc digest:", digest_final, 8);
- dump_data_pw("wire digest:", sig->data+16, 8);
- return NT_STATUS_ACCESS_DENIED;
- }
-
return NT_STATUS_OK;
}
-
-/*
- seal a packet
-*/
-NTSTATUS schannel_seal_packet(struct schannel_state *state,
- TALLOC_CTX *mem_ctx,
- uint8_t *data, size_t length,
- DATA_BLOB *sig)
+NTSTATUS netsec_outgoing_packet(struct schannel_state *state,
+ TALLOC_CTX *mem_ctx,
+ bool do_seal,
+ uint8_t *data, size_t length,
+ DATA_BLOB *sig)
{
- uint8_t digest_final[16];
- uint8_t confounder[8];
+ uint32_t min_sig_size = 0;
+ uint32_t used_sig_size = 0;
+ uint8_t header[8];
+ uint8_t checksum[32];
+ uint32_t checksum_length = sizeof(checksum_length);
+ uint8_t _confounder[8];
+ uint8_t *confounder = NULL;
+ uint32_t confounder_ofs = 0;
uint8_t seq_num[8];
- uint8_t sealing_key[16];
- static const uint8_t netsec_sig[8] = NETSEC_SEAL_SIGNATURE;
- generate_random_buffer(confounder, 8);
+ netsec_offset_and_sizes(state,
+ do_seal,
+ &min_sig_size,
+ &used_sig_size,
+ &checksum_length,
+ &confounder_ofs);
RSIVAL(seq_num, 0, state->seq_num);
SIVAL(seq_num, 4, state->initiator?0x80:0);
- schannel_digest(state->creds->session_key,
- netsec_sig, confounder,
- data, length, digest_final);
-
- netsec_get_sealing_key(state->creds->session_key, seq_num, sealing_key);
- arcfour_crypt(confounder, sealing_key, 8);
- arcfour_crypt(data, sealing_key, length);
-
- netsec_deal_with_seq_num(state, digest_final, seq_num);
-
- (*sig) = data_blob_talloc(mem_ctx, NULL, 32);
-
- memcpy(sig->data, netsec_sig, 8);
- memcpy(sig->data+8, seq_num, 8);
- memcpy(sig->data+16, digest_final, 8);
- memcpy(sig->data+24, confounder, 8);
-
- dump_data_pw("signature:", sig->data+ 0, 8);
- dump_data_pw("seq_num :", sig->data+ 8, 8);
- dump_data_pw("digest :", sig->data+16, 8);
- dump_data_pw("confound :", sig->data+24, 8);
-
- return NT_STATUS_OK;
-}
-
-
-/*
- sign a packet
-*/
-NTSTATUS schannel_sign_packet(struct schannel_state *state,
- TALLOC_CTX *mem_ctx,
- const uint8_t *data, size_t length,
- DATA_BLOB *sig)
-{
- uint8_t digest_final[16];
- uint8_t seq_num[8];
- static const uint8_t netsec_sig[8] = NETSEC_SIGN_SIGNATURE;
+ if (do_seal) {
+ confounder = _confounder;
+ generate_random_buffer(confounder, 8);
+ } else {
+ confounder = NULL;
+ }
- RSIVAL(seq_num, 0, state->seq_num);
- SIVAL(seq_num, 4, state->initiator?0x80:0);
+ netsec_do_sign(state, confounder,
+ data, length,
+ header, checksum);
- schannel_digest(state->creds->session_key,
- netsec_sig, NULL,
- data, length, digest_final);
+ if (do_seal) {
+ netsec_do_seal(state, seq_num,
+ confounder,
+ data, length);
+ }
- netsec_deal_with_seq_num(state, digest_final, seq_num);
+ netsec_do_seq_num(state, checksum, checksum_length, seq_num);
- (*sig) = data_blob_talloc(mem_ctx, NULL, 32);
+ (*sig) = data_blob_talloc_zero(mem_ctx, used_sig_size);
- memcpy(sig->data, netsec_sig, 8);
+ memcpy(sig->data, header, 8);
memcpy(sig->data+8, seq_num, 8);
- memcpy(sig->data+16, digest_final, 8);
- memset(sig->data+24, 0, 8);
+ memcpy(sig->data+16, checksum, checksum_length);
+
+ if (confounder) {
+ memcpy(sig->data+confounder_ofs, confounder, 8);
+ }
dump_data_pw("signature:", sig->data+ 0, 8);
dump_data_pw("seq_num :", sig->data+ 8, 8);
- dump_data_pw("digest :", sig->data+16, 8);
- dump_data_pw("confound :", sig->data+24, 8);
+ dump_data_pw("digest :", sig->data+16, checksum_length);
+ dump_data_pw("confound :", sig->data+confounder_ofs, 8);
return NT_STATUS_OK;
}