From d258fb4d0dcd04899dede7f17c8658251c9cd5e7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?G=C3=BCnther=20Deschner?= Date: Fri, 11 Sep 2009 02:52:25 +0200 Subject: [PATCH] s3-schannel: use NL_AUTH_SIGNATURE for schannel sign & seal (client & server). Guenther --- source3/include/includes.h | 1 + source3/include/proto.h | 4 +- source3/rpc_client/cli_pipe.c | 39 ++++++++++---- source3/rpc_parse/parse_prs.c | 118 ++++++++++++++++++++---------------------- source3/rpc_server/srv_pipe.c | 39 +++++++++++--- 5 files changed, 118 insertions(+), 83 deletions(-) diff --git a/source3/include/includes.h b/source3/include/includes.h index 92a37053ce7..31dfc005458 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -653,6 +653,7 @@ struct smb_iconv_convenience *lp_iconv_convenience(void *lp_ctx); #include "privileges.h" #include "rpc_misc.h" #include "rpc_dce.h" +#include "../librpc/gen_ndr/schannel.h" #include "mapping.h" #include "passdb.h" #include "rpc_secdes.h" diff --git a/source3/include/proto.h b/source3/include/proto.h index 9de77f9227b..c51d4ee728e 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -5691,11 +5691,11 @@ bool prs_unistr(const char *name, prs_struct *ps, int depth, UNISTR *str); bool prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_buf_size); void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level, enum schannel_direction direction, - RPC_AUTH_SCHANNEL_CHK * verf, + struct NL_AUTH_SIGNATURE *verf, char *data, size_t data_len); bool schannel_decode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level, enum schannel_direction direction, - RPC_AUTH_SCHANNEL_CHK * verf, char *data, size_t data_len); + struct NL_AUTH_SIGNATURE *verf, char *data, size_t data_len); bool prs_init_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx); bool prs_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx); diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index 16fe9daca18..0c3fc946d4f 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -670,12 +670,14 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p uint8 *p_ss_padding_len) { RPC_HDR_AUTH auth_info; - RPC_AUTH_SCHANNEL_CHK schannel_chk; + struct NL_AUTH_SIGNATURE schannel_chk; uint32 auth_len = prhdr->auth_len; uint32 save_offset = prs_offset(current_pdu); struct schannel_auth_struct *schannel_auth = cli->auth->a_u.schannel_auth; uint32 data_len; + enum ndr_err_code ndr_err; + DATA_BLOB blob; if (cli->auth->auth_level == PIPE_AUTH_LEVEL_NONE || cli->auth->auth_level == PIPE_AUTH_LEVEL_CONNECT) { @@ -718,10 +720,17 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p return NT_STATUS_BUFFER_TOO_SMALL; } - if(!smb_io_rpc_auth_schannel_chk("", RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN, - &schannel_chk, current_pdu, 0)) { + blob = data_blob_const(prs_data_p(current_pdu) + prs_offset(current_pdu), data_len); + + ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), NULL, &schannel_chk, + (ndr_pull_flags_fn_t)ndr_pull_NL_AUTH_SIGNATURE); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(0,("cli_pipe_verify_schannel: failed to unmarshal RPC_AUTH_SCHANNEL_CHK.\n")); - return NT_STATUS_BUFFER_TOO_SMALL; + return ndr_map_error2ntstatus(ndr_err); + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(NL_AUTH_SIGNATURE, &schannel_chk); } if (!schannel_decode(schannel_auth, @@ -1905,10 +1914,12 @@ static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, prs_struct *outgoing_pdu) { RPC_HDR_AUTH auth_info; - RPC_AUTH_SCHANNEL_CHK verf; + struct NL_AUTH_SIGNATURE verf; struct schannel_auth_struct *sas = cli->auth->a_u.schannel_auth; char *data_p = prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN; size_t data_and_pad_len = prs_offset(outgoing_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN; + enum ndr_err_code ndr_err; + DATA_BLOB blob; if (!sas) { return NT_STATUS_INVALID_PARAMETER; @@ -1949,12 +1960,20 @@ static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, return NT_STATUS_INVALID_PARAMETER; } + ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), NULL, &verf, + (ndr_push_flags_fn_t)ndr_push_NL_AUTH_SIGNATURE); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(NL_AUTH_SIGNATURE, &verf); + } + /* Finally marshall the blob. */ - smb_io_rpc_auth_schannel_chk("", - RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN, - &verf, - outgoing_pdu, - 0); + if (!prs_copy_data_in(outgoing_pdu, (const char *)blob.data, blob.length)) { + return NT_STATUS_NO_MEMORY; + } return NT_STATUS_OK; } diff --git a/source3/rpc_parse/parse_prs.c b/source3/rpc_parse/parse_prs.c index 621ccf4bc90..d428c3aa9ea 100644 --- a/source3/rpc_parse/parse_prs.c +++ b/source3/rpc_parse/parse_prs.c @@ -21,6 +21,7 @@ */ #include "includes.h" +#include "../librpc/gen_ndr/ndr_schannel.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_PARSE @@ -1071,24 +1072,31 @@ bool prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_ static void schannel_digest(struct schannel_auth_struct *a, enum pipe_auth_level auth_level, - RPC_AUTH_SCHANNEL_CHK * verf, + struct NL_AUTH_SIGNATURE *verf, char *data, size_t data_len, uchar digest_final[16]) { uchar whole_packet_digest[16]; uchar zeros[4]; struct MD5Context ctx3; + uint8_t sig[8]; ZERO_STRUCT(zeros); + ZERO_STRUCT(sig); + + SSVAL(sig,0,verf->SignatureAlgorithm); + SSVAL(sig,2,verf->SealAlgorithm); + SSVAL(sig,4,verf->Pad); + SSVAL(sig,8,verf->Flags); /* verfiy the signature on the packet by MD5 over various bits */ MD5Init(&ctx3); /* use our sequence number, which ensures the packet is not out of order */ MD5Update(&ctx3, zeros, sizeof(zeros)); - MD5Update(&ctx3, verf->sig, sizeof(verf->sig)); + MD5Update(&ctx3, sig, 8); if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { - MD5Update(&ctx3, verf->confounder, sizeof(verf->confounder)); + MD5Update(&ctx3, verf->Confounder, sizeof(verf->Confounder)); } MD5Update(&ctx3, (const unsigned char *)data, data_len); MD5Final(whole_packet_digest, &ctx3); @@ -1104,7 +1112,7 @@ static void schannel_digest(struct schannel_auth_struct *a, ********************************************************************/ static void schannel_get_sealing_key(struct schannel_auth_struct *a, - RPC_AUTH_SCHANNEL_CHK *verf, + struct NL_AUTH_SIGNATURE *verf, uchar sealing_key[16]) { uchar zeros[4]; @@ -1125,7 +1133,7 @@ static void schannel_get_sealing_key(struct schannel_auth_struct *a, dump_data_pw("digest2:\n", digest2, sizeof(digest2)); /* MD5 of the above result, plus 8 bytes of sequence number */ - hmac_md5(digest2, verf->seq_num, sizeof(verf->seq_num), sealing_key); + hmac_md5(digest2, verf->SequenceNumber, sizeof(verf->SequenceNumber), sealing_key); dump_data_pw("sealing_key:\n", sealing_key, 16); } @@ -1134,7 +1142,7 @@ static void schannel_get_sealing_key(struct schannel_auth_struct *a, ********************************************************************/ static void schannel_deal_with_seq_num(struct schannel_auth_struct *a, - RPC_AUTH_SCHANNEL_CHK *verf) + struct NL_AUTH_SIGNATURE *verf) { uchar zeros[4]; uchar sequence_key[16]; @@ -1145,33 +1153,13 @@ static void schannel_deal_with_seq_num(struct schannel_auth_struct *a, hmac_md5(a->sess_key, zeros, sizeof(zeros), digest1); dump_data_pw("(sequence key) digest1:\n", digest1, sizeof(digest1)); - hmac_md5(digest1, verf->packet_digest, 8, sequence_key); + hmac_md5(digest1, verf->Checksum, 8, sequence_key); dump_data_pw("sequence_key:\n", sequence_key, sizeof(sequence_key)); - dump_data_pw("seq_num (before):\n", verf->seq_num, sizeof(verf->seq_num)); - arcfour_crypt(verf->seq_num, sequence_key, 8); - dump_data_pw("seq_num (after):\n", verf->seq_num, sizeof(verf->seq_num)); -} - -/******************************************************************* -creates an RPC_AUTH_SCHANNEL_CHK structure. -********************************************************************/ - -static bool init_rpc_auth_schannel_chk(RPC_AUTH_SCHANNEL_CHK * chk, - const uchar sig[8], - const uchar packet_digest[8], - const uchar seq_num[8], const uchar confounder[8]) -{ - if (chk == NULL) - return False; - - memcpy(chk->sig, sig, sizeof(chk->sig)); - memcpy(chk->packet_digest, packet_digest, sizeof(chk->packet_digest)); - memcpy(chk->seq_num, seq_num, sizeof(chk->seq_num)); - memcpy(chk->confounder, confounder, sizeof(chk->confounder)); - - return True; + dump_data_pw("seq_num (before):\n", verf->SequenceNumber, sizeof(verf->SequenceNumber)); + arcfour_crypt(verf->SequenceNumber, sequence_key, 8); + dump_data_pw("seq_num (after):\n", verf->SequenceNumber, sizeof(verf->SequenceNumber)); } /******************************************************************* @@ -1183,7 +1171,7 @@ static bool init_rpc_auth_schannel_chk(RPC_AUTH_SCHANNEL_CHK * chk, void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level, enum schannel_direction direction, - RPC_AUTH_SCHANNEL_CHK * verf, + struct NL_AUTH_SIGNATURE *verf, char *data, size_t data_len) { uchar digest_final[16]; @@ -1191,18 +1179,8 @@ void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_l uchar seq_num[8]; static const uchar nullbytes[8] = { 0, }; - static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE; - static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE; - const uchar *schannel_sig = NULL; - DEBUG(10,("SCHANNEL: schannel_encode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len)); - if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { - schannel_sig = schannel_seal_sig; - } else { - schannel_sig = schannel_sign_sig; - } - /* fill the 'confounder' with random data */ generate_random_buffer(confounder, sizeof(confounder)); @@ -1219,14 +1197,25 @@ void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_l break; } - dump_data_pw("verf->seq_num:\n", seq_num, sizeof(verf->seq_num)); + dump_data_pw("verf->SequenceNumber:\n", verf->SequenceNumber, sizeof(verf->SequenceNumber)); + + if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { + verf->SealAlgorithm = NL_SEAL_RC4; + } else { + verf->SealAlgorithm = NL_SEAL_NONE; + } + + verf->SignatureAlgorithm = NL_SIGN_HMAC_MD5; + verf->Pad = 0xffff; + verf->Flags = 0x0000; + + memcpy(verf->SequenceNumber, seq_num, sizeof(verf->SequenceNumber)); + memcpy(verf->Checksum, nullbytes, sizeof(verf->Checksum)); + memcpy(verf->Confounder, confounder, sizeof(verf->Confounder)); - init_rpc_auth_schannel_chk(verf, schannel_sig, nullbytes, - seq_num, confounder); - /* produce a digest of the packet to prove it's legit (before we seal it) */ schannel_digest(a, auth_level, verf, data, data_len, digest_final); - memcpy(verf->packet_digest, digest_final, sizeof(verf->packet_digest)); + memcpy(verf->Checksum, digest_final, sizeof(verf->Checksum)); if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { uchar sealing_key[16]; @@ -1235,10 +1224,10 @@ void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_l schannel_get_sealing_key(a, verf, sealing_key); /* encode the verification data */ - dump_data_pw("verf->confounder:\n", verf->confounder, sizeof(verf->confounder)); - arcfour_crypt(verf->confounder, sealing_key, 8); + dump_data_pw("verf->Confounder:\n", verf->Confounder, sizeof(verf->Confounder)); + arcfour_crypt(verf->Confounder, sealing_key, 8); - dump_data_pw("verf->confounder_enc:\n", verf->confounder, sizeof(verf->confounder)); + dump_data_pw("verf->Confounder_enc:\n", verf->Confounder, sizeof(verf->Confounder)); /* encode the packet payload */ dump_data_pw("data:\n", (const unsigned char *)data, data_len); @@ -1262,7 +1251,7 @@ void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_l bool schannel_decode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level, enum schannel_direction direction, - RPC_AUTH_SCHANNEL_CHK * verf, char *data, size_t data_len) + struct NL_AUTH_SIGNATURE *verf, char *data, size_t data_len) { uchar digest_final[16]; @@ -1302,24 +1291,27 @@ bool schannel_decode(struct schannel_auth_struct *a, enum pipe_auth_level auth_l is used in the sealing stuff... */ schannel_deal_with_seq_num(a, verf); - if (memcmp(verf->seq_num, seq_num, sizeof(seq_num))) { + if (memcmp(verf->SequenceNumber, seq_num, sizeof(seq_num))) { /* don't even bother with the below if the sequence number is out */ /* The sequence number is MD5'ed with a key based on the whole-packet digest, as supplied by the client. We check that it's a valid checksum after the decode, below */ DEBUG(2, ("schannel_decode: FAILED: packet sequence number:\n")); - dump_data(2, verf->seq_num, sizeof(verf->seq_num)); + dump_data(2, verf->SequenceNumber, sizeof(verf->SequenceNumber)); DEBUG(2, ("should be:\n")); dump_data(2, seq_num, sizeof(seq_num)); return False; } - if (memcmp(verf->sig, schannel_sig, sizeof(verf->sig))) { + if (memcmp(&verf->SignatureAlgorithm, &schannel_sig[0], 2) || + memcmp(&verf->SealAlgorithm, &schannel_sig[2], 2) || + memcmp(&verf->Pad, &schannel_sig[4], 2) || + memcmp(&verf->Flags, &schannel_sig[6], 2)) { /* Validate that the other end sent the expected header */ DEBUG(2, ("schannel_decode: FAILED: packet header:\n")); - dump_data(2, verf->sig, sizeof(verf->sig)); + dump_data(2, (const uint8_t *)verf, sizeof(schannel_sig)); DEBUG(2, ("should be:\n")); dump_data(2, schannel_sig, sizeof(schannel_sig)); return False; @@ -1332,12 +1324,12 @@ bool schannel_decode(struct schannel_auth_struct *a, enum pipe_auth_level auth_l schannel_get_sealing_key(a, verf, sealing_key); /* extract the verification data */ - dump_data_pw("verf->confounder:\n", verf->confounder, - sizeof(verf->confounder)); - arcfour_crypt(verf->confounder, sealing_key, 8); + dump_data_pw("verf->Confounder:\n", verf->Confounder, + sizeof(verf->Confounder)); + arcfour_crypt(verf->Confounder, sealing_key, 8); - dump_data_pw("verf->confounder_dec:\n", verf->confounder, - sizeof(verf->confounder)); + dump_data_pw("verf->Confounder_dec:\n", verf->Confounder, + sizeof(verf->Confounder)); /* extract the packet payload */ dump_data_pw("data :\n", (const unsigned char *)data, data_len); @@ -1350,13 +1342,13 @@ bool schannel_decode(struct schannel_auth_struct *a, enum pipe_auth_level auth_l dump_data_pw("Calculated digest:\n", digest_final, sizeof(digest_final)); - dump_data_pw("verf->packet_digest:\n", verf->packet_digest, - sizeof(verf->packet_digest)); + dump_data_pw("verf->Checksum:\n", verf->Checksum, + sizeof(verf->Checksum)); /* compare - if the client got the same result as us, then it must know the session key */ - return (memcmp(digest_final, verf->packet_digest, - sizeof(verf->packet_digest)) == 0); + return (memcmp(digest_final, verf->Checksum, + sizeof(verf->Checksum)) == 0); } /******************************************************************* diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index 5df87e3b0be..7be0a0d2d2d 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -407,7 +407,9 @@ static bool create_next_pdu_schannel(pipes_struct *p) * Schannel processing. */ RPC_HDR_AUTH auth_info; - RPC_AUTH_SCHANNEL_CHK verf; + struct NL_AUTH_SIGNATURE verf; + DATA_BLOB blob; + enum ndr_err_code ndr_err; /* Check it's the type of reply we were expecting to decode */ @@ -429,10 +431,22 @@ static bool create_next_pdu_schannel(pipes_struct *p) prs_data_p(&p->out_data.frag) + data_pos, data_len + ss_padding_len); - if (!smb_io_rpc_auth_schannel_chk("", RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN, - &verf, &p->out_data.frag, 0)) { + /* Finally marshall the blob. */ + + ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), NULL, &verf, + (ndr_push_flags_fn_t)ndr_push_NL_AUTH_SIGNATURE); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { prs_mem_free(&p->out_data.frag); - return False; + return false; + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(NL_AUTH_SIGNATURE, &verf); + } + + if (!prs_copy_data_in(&p->out_data.frag, (const char *)blob.data, blob.length)) { + prs_mem_free(&p->out_data.frag); + return false; } p->auth.a_u.schannel_auth->seq_num++; @@ -2135,7 +2149,9 @@ bool api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss uint32 auth_len; uint32 save_offset = prs_offset(rpc_in); RPC_HDR_AUTH auth_info; - RPC_AUTH_SCHANNEL_CHK schannel_chk; + struct NL_AUTH_SIGNATURE schannel_chk; + enum ndr_err_code ndr_err; + DATA_BLOB blob; auth_len = p->hdr.auth_len; @@ -2183,9 +2199,16 @@ bool api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss return False; } - if(!smb_io_rpc_auth_schannel_chk("", RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN, &schannel_chk, rpc_in, 0)) { - DEBUG(0,("failed to unmarshal RPC_AUTH_SCHANNEL_CHK.\n")); - return False; + blob = data_blob_const(prs_data_p(rpc_in) + prs_offset(rpc_in), data_len); + + ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), NULL, &schannel_chk, + (ndr_pull_flags_fn_t)ndr_pull_NL_AUTH_SIGNATURE); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return false; + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(NL_AUTH_SIGNATURE, &schannel_chk); } if (!schannel_decode(p->auth.a_u.schannel_auth, -- 2.11.4.GIT