The branch, master has been updated via 033ced60ac734161686bd3da685f2d7b056e17c8 (commit) via 8f482ae663611ee2109395e4d24418e4c4f57160 (commit) from 4c5854fc2d8569cdf27fc6af543ad4a25a6f7a0b (commit)
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 033ced60ac734161686bd3da685f2d7b056e17c8 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Sep 16 02:03:46 2009 +0200 libcli/auth: rewrite schannel sign/seal code to be more generic This prepares support for HMAC-SHA256/AES. metze commit 8f482ae663611ee2109395e4d24418e4c4f57160 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Sep 16 02:36:49 2009 +0200 lib/crypto: include aes.h into crypto.h metze ----------------------------------------------------------------------- Summary of changes: lib/crypto/crypto.h | 2 +- libcli/auth/schannel_proto.h | 21 +-- libcli/auth/schannel_sign.c | 297 ++++++++++++++++++++-------------------- source3/rpc_client/cli_pipe.c | 41 ++++--- source3/rpc_server/srv_pipe.c | 44 ++++--- source4/auth/gensec/schannel.c | 89 ++++++++----- 6 files changed, 264 insertions(+), 230 deletions(-) Changeset truncated at 500 lines: diff --git a/lib/crypto/crypto.h b/lib/crypto/crypto.h index 0a43cbe..b5ea9c7 100644 --- a/lib/crypto/crypto.h +++ b/lib/crypto/crypto.h @@ -24,5 +24,5 @@ #include "../lib/crypto/sha256.h" #include "../lib/crypto/hmacsha256.h" #include "../lib/crypto/arcfour.h" - +#include "../lib/crypto/aes.h" diff --git a/libcli/auth/schannel_proto.h b/libcli/auth/schannel_proto.h index d31707d..eee7199 100644 --- a/libcli/auth/schannel_proto.h +++ b/libcli/auth/schannel_proto.h @@ -23,20 +23,15 @@ #ifndef _LIBCLI_AUTH_SCHANNEL_PROTO_H__ #define _LIBCLI_AUTH_SCHANNEL_PROTO_H__ -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); -NTSTATUS schannel_check_packet(struct schannel_state *state, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const DATA_BLOB *sig); -NTSTATUS schannel_seal_packet(struct schannel_state *state, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - DATA_BLOB *sig); -NTSTATUS schannel_sign_packet(struct schannel_state *state, - TALLOC_CTX *mem_ctx, - const 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); + #endif diff --git a/libcli/auth/schannel_sign.c b/libcli/auth/schannel_sign.c index e60b410..0672f67 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; } diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index 393c726..186696f 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -676,6 +676,7 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p uint32 save_offset = prs_offset(current_pdu); struct schannel_state *schannel_auth = cli->auth->a_u.schannel_auth; + uint8_t *data; uint32 data_len; DATA_BLOB blob; NTSTATUS status; @@ -727,20 +728,24 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p dump_NL_AUTH_SIGNATURE(talloc_tos(), &blob); } + data = (uint8_t *)prs_data_p(current_pdu)+RPC_HEADER_LEN+RPC_HDR_RESP_LEN; + switch (cli->auth->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: - status = schannel_unseal_packet(schannel_auth, + status = netsec_incoming_packet(schannel_auth, talloc_tos(), - (uint8_t *)prs_data_p(current_pdu)+RPC_HEADER_LEN+RPC_HDR_RESP_LEN, + true, + data, data_len, &blob); break; case DCERPC_AUTH_LEVEL_INTEGRITY: - status = schannel_check_packet(schannel_auth, - talloc_tos(), - (uint8_t *)prs_data_p(current_pdu)+RPC_HEADER_LEN+RPC_HDR_RESP_LEN, - data_len, - &blob); + status = netsec_incoming_packet(schannel_auth, + talloc_tos(), + false, + data, + data_len, + &blob); break; default: status = NT_STATUS_INTERNAL_ERROR; @@ -1948,18 +1953,20 @@ static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, switch (cli->auth->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: - status = schannel_seal_packet(sas, - talloc_tos(), - (uint8_t *)data_p, - data_and_pad_len, - &blob); + status = netsec_outgoing_packet(sas, + talloc_tos(), + true, + (uint8_t *)data_p, -- Samba Shared Repository