]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
libcli/smb: prepare support for SMB2_SIGNING_CAPABILITIES negotiation
authorStefan Metzmacher <metze@samba.org>
Thu, 11 Mar 2021 10:04:14 +0000 (11:04 +0100)
committerStefan Metzmacher <metze@samba.org>
Thu, 15 Jul 2021 00:06:31 +0000 (00:06 +0000)
For now client_sign_algos->num_algos will always be 0,
but that'll change in the next commits.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
libcli/smb/smb2_negotiate_context.h
libcli/smb/smbXcli_base.c
libcli/smb/util.c

index 5d0180b0d3b245e5e4988f65700e9d62858765ec..47ed6c94e8c90f136db0fe29fd19b2ee0523f707 100644 (file)
@@ -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,
index 50cf86e1a6c7ce3891818e937b421accabe30c3d..c2d70ee016d1d28020b47f5be9b5e9c8952ff2e8 100644 (file)
@@ -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 =
index e62865a84a8dc83baf884f495301173658e45787..362486375a965e122029c27694f2c885b2098589 100644 (file)
@@ -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;