From: Stefan Metzmacher Date: Thu, 11 Mar 2021 10:04:14 +0000 (+0100) Subject: libcli/smb: prepare support for SMB2_SIGNING_CAPABILITIES negotiation X-Git-Tag: samba-4.15.0rc1~19 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3706b27a3bc17e6e876c322c2e1701e494eee938;p=thirdparty%2Fsamba.git libcli/smb: prepare support for SMB2_SIGNING_CAPABILITIES negotiation For now client_sign_algos->num_algos will always be 0, but that'll change in the next commits. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- diff --git a/libcli/smb/smb2_negotiate_context.h b/libcli/smb/smb2_negotiate_context.h index 5d0180b0d3b..47ed6c94e8c 100644 --- a/libcli/smb/smb2_negotiate_context.h +++ b/libcli/smb/smb2_negotiate_context.h @@ -56,6 +56,12 @@ struct smb2_negotiate_context *smb2_negotiate_context_find(const struct smb2_neg uint16_t type); #define WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK 31 +struct smb3_signing_capabilities { +#define SMB3_SIGNING_CAPABILITIES_MAX_ALGOS 2 + uint16_t num_algos; + uint16_t algos[SMB3_SIGNING_CAPABILITIES_MAX_ALGOS]; +}; + struct smb3_encryption_capabilities { #define SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS 4 uint16_t num_algos; @@ -63,9 +69,11 @@ struct smb3_encryption_capabilities { }; struct smb311_capabilities { + struct smb3_signing_capabilities signing; struct smb3_encryption_capabilities encryption; }; +const char *smb3_signing_algorithm_name(uint16_t algo); const char *smb3_encryption_algorithm_name(uint16_t algo); struct smb311_capabilities smb311_capabilities_parse(const char *role, diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index 50cf86e1a6c..c2d70ee016d 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -337,9 +337,12 @@ struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx, int ret; if (smb3_capabilities != NULL) { + const struct smb3_signing_capabilities *sign_algos = + &smb3_capabilities->signing; const struct smb3_encryption_capabilities *ciphers = &smb3_capabilities->encryption; + SMB_ASSERT(sign_algos->num_algos <= SMB3_SIGNING_CAPABILITIES_MAX_ALGOS); SMB_ASSERT(ciphers->num_algos <= SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS); } @@ -4844,6 +4847,8 @@ static struct tevent_req *smbXcli_negprot_smb2_subreq(struct smbXcli_negprot_sta } if (state->conn->max_protocol >= PROTOCOL_SMB3_11) { + const struct smb3_signing_capabilities *client_sign_algos = + &state->conn->smb2.client.smb3_capabilities.signing; const struct smb3_encryption_capabilities *client_ciphers = &state->conn->smb2.client.smb3_capabilities.encryption; NTSTATUS status; @@ -4887,6 +4892,25 @@ static struct tevent_req *smbXcli_negprot_smb2_subreq(struct smbXcli_negprot_sta } } + if (client_sign_algos->num_algos > 0) { + size_t ofs = 0; + SSVAL(p, ofs, client_sign_algos->num_algos); + ofs += 2; + + for (i = 0; i < client_sign_algos->num_algos; i++) { + size_t next_ofs = ofs + 2; + SMB_ASSERT(next_ofs < ARRAY_SIZE(p)); + SSVAL(p, ofs, client_sign_algos->algos[i]); + ofs = next_ofs; + } + + status = smb2_negotiate_context_add( + state, &c, SMB2_SIGNING_CAPABILITIES, p, ofs); + if (!NT_STATUS_IS_OK(status)) { + return NULL; + } + } + ok = convert_string_talloc(state, CH_UNIX, CH_UTF16, state->conn->remote_name, strlen(state->conn->remote_name), @@ -4968,6 +4992,7 @@ static void smbXcli_negprot_smb2_done(struct tevent_req *subreq) uint16_t salt_length; uint16_t hash_selected; gnutls_hash_hd_t hash_hnd = NULL; + struct smb2_negotiate_context *sign_algo = NULL; struct smb2_negotiate_context *cipher = NULL; struct iovec sent_iov[3] = {{0}, {0}, {0}}; static const struct smb2cli_req_expected_response expected[] = { @@ -5174,6 +5199,65 @@ static void smbXcli_negprot_smb2_done(struct tevent_req *subreq) return; } + sign_algo = smb2_negotiate_context_find(&c, SMB2_SIGNING_CAPABILITIES); + if (sign_algo != NULL) { + const struct smb3_signing_capabilities *client_sign_algos = + &state->conn->smb2.client.smb3_capabilities.signing; + bool found_selected = false; + uint16_t sign_algo_count; + uint16_t sign_algo_selected; + + if (client_sign_algos->num_algos == 0) { + /* + * We didn't ask for SMB2_ENCRYPTION_CAPABILITIES + */ + tevent_req_nterror(req, + NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + if (sign_algo->data.length < 2) { + tevent_req_nterror(req, + NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + sign_algo_count = SVAL(sign_algo->data.data, 0); + if (sign_algo_count != 1) { + tevent_req_nterror(req, + NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + if (sign_algo->data.length < (2 + 2 * sign_algo_count)) { + tevent_req_nterror(req, + NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + sign_algo_selected = SVAL(sign_algo->data.data, 2); + + for (i = 0; i < client_sign_algos->num_algos; i++) { + if (client_sign_algos->algos[i] == sign_algo_selected) { + /* + * We found a match + */ + found_selected = true; + break; + } + } + + if (!found_selected) { + /* + * The server send a sign_algo we didn't offer. + */ + tevent_req_nterror(req, + NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + conn->smb2.server.sign_algo = sign_algo_selected; + } + cipher = smb2_negotiate_context_find(&c, SMB2_ENCRYPTION_CAPABILITIES); if (cipher != NULL) { const struct smb3_encryption_capabilities *client_ciphers = diff --git a/libcli/smb/util.c b/libcli/smb/util.c index e62865a84a8..362486375a9 100644 --- a/libcli/smb/util.c +++ b/libcli/smb/util.c @@ -465,6 +465,27 @@ enum smb_encryption_setting smb_encryption_setting_translate(const char *str) return encryption_state; } +static const struct enum_list enum_smb3_signing_algorithms[] = { + {SMB2_SIGNING_AES128_CMAC, "aes-128-cmac"}, + {SMB2_SIGNING_HMAC_SHA256, "hmac-sha-256"}, + {-1, NULL} +}; + +const char *smb3_signing_algorithm_name(uint16_t algo) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(enum_smb3_signing_algorithms); i++) { + if (enum_smb3_signing_algorithms[i].value != algo) { + continue; + } + + return enum_smb3_signing_algorithms[i].name; + } + + return NULL; +} + static const struct enum_list enum_smb3_encryption_algorithms[] = { {SMB2_ENCRYPTION_AES128_GCM, "aes-128-gcm"}, {SMB2_ENCRYPTION_AES128_CCM, "aes-128-ccm"}, @@ -512,17 +533,63 @@ static int32_t parse_enum_val(const struct enum_list *e, struct smb311_capabilities smb311_capabilities_parse(const char *role, const char * const *encryption_algos) { + const char * const *signing_algos = NULL; struct smb311_capabilities c = { + .signing = { + .num_algos = 0, + }, .encryption = { .num_algos = 0, }, }; + char sign_param[64] = { 0, }; char enc_param[64] = { 0, }; size_t ai; + snprintf(sign_param, sizeof(sign_param), + "%s smb3 signing algorithms", role); snprintf(enc_param, sizeof(enc_param), "%s smb3 encryption algorithms", role); + for (ai = 0; signing_algos != NULL && signing_algos[ai] != NULL; ai++) { + const char *algoname = signing_algos[ai]; + int32_t v32; + uint16_t algo; + size_t di; + bool ignore = false; + + if (c.signing.num_algos >= SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS) { + DBG_ERR("WARNING: Ignoring trailing value '%s' for parameter '%s'\n", + algoname, sign_param); + continue; + } + + v32 = parse_enum_val(enum_smb3_signing_algorithms, + sign_param, algoname); + if (v32 == INT32_MAX) { + continue; + } + algo = v32; + + for (di = 0; di < c.signing.num_algos; di++) { + if (algo != c.signing.algos[di]) { + continue; + } + + ignore = true; + break; + } + + if (ignore) { + DBG_ERR("WARNING: Ignoring duplicate value '%s' for parameter '%s'\n", + algoname, sign_param); + continue; + } + + c.signing.algos[c.signing.num_algos] = algo; + c.signing.num_algos += 1; + } + for (ai = 0; encryption_algos != NULL && encryption_algos[ai] != NULL; ai++) { const char *algoname = encryption_algos[ai]; int32_t v32;