]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
lib:crypto: Add samba_gnutls_sp800_108_derive_key()
authorJoseph Sutton <josephsutton@catalyst.net.nz>
Tue, 28 Nov 2023 22:36:57 +0000 (11:36 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 30 Nov 2023 00:02:33 +0000 (00:02 +0000)
Rename smb2_key_derivation() to samba_gnutls_sp800_108_derive_key() and
move it to GNUTLS_HELPERS.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
lib/crypto/gnutls_helpers.h
lib/crypto/gnutls_sp800_108.c [new file with mode: 0644]
lib/crypto/wscript
libcli/smb/smb2_signing.c
libcli/smb/smb2_signing.h
libcli/smb/smbXcli_base.c

index 4e6f4f3f8b1f2674db79f6ac9ca8175940260e81..c0b76047a0c35537d48cca910c1e0d22431c3c13 100644 (file)
@@ -187,4 +187,43 @@ samba_gnutls_aead_aes_256_cbc_hmac_sha512_decrypt(TALLOC_CTX *mem_ctx,
  */
 bool samba_gnutls_weak_crypto_allowed(void);
 
+/**
+ * @brief Derive a key using the NIST SP 800‐108 algorithm.
+ *
+ * The details of the algorithm can be found at
+ * https://csrc.nist.gov/pubs/sp/800/108/r1/final.
+ *
+ * @param KI            The key‐derivation key used as input.
+ *
+ * @param KI_len        The length of the key‐derivation key.
+ *
+ * @param Label         A label that identifies the purpose for the derived key.
+ *                      Ignored if FixedData is non‐NULL.
+ *
+ * @param Label_len     The length of the label.
+ *
+ * @param Context       Information related to the derived key. Ignored if
+ *                      FixedData is non‐NULL.
+ *
+ * @param Context_len   The length of the context data.
+ *
+ * @param algorithm     The HMAC algorithm to use.
+ *
+ * @param KO            A buffer to receive the derived key.
+ *
+ * @param KO_len        The length of the key to be derived.
+ *
+ * @return NT_STATUS_OK on success, an NT status error code otherwise.
+ */
+NTSTATUS samba_gnutls_sp800_108_derive_key(
+       const uint8_t *KI,
+       size_t KI_len,
+       const uint8_t *Label,
+       size_t Label_len,
+       const uint8_t *Context,
+       size_t Context_len,
+       const gnutls_mac_algorithm_t algorithm,
+       uint8_t *KO,
+       size_t KO_len);
+
 #endif /* _GNUTLS_HELPERS_H */
diff --git a/lib/crypto/gnutls_sp800_108.c b/lib/crypto/gnutls_sp800_108.c
new file mode 100644 (file)
index 0000000..225c9b2
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+   Unix SMB/CIFS implementation.
+   Wrapper for gnutls key derivation functions
+
+   Copyright (C) Stefan Metzmacher 2009
+   Copyright (C) Catalyst.Net Ltd 2023
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include "gnutls_helpers.h"
+
+/**
+ * @brief Derive a key using the NIST SP 800‐108 algorithm.
+ *
+ * The details of the algorithm can be found at
+ * https://csrc.nist.gov/pubs/sp/800/108/r1/final.
+ *
+ * @param KI            The key‐derivation key used as input.
+ *
+ * @param KI_len        The length of the key‐derivation key.
+ *
+ * @param Label         A label that identifies the purpose for the derived key.
+ *                      Ignored if FixedData is non‐NULL.
+ *
+ * @param Label_len     The length of the label.
+ *
+ * @param Context       Information related to the derived key. Ignored if
+ *                      FixedData is non‐NULL.
+ *
+ * @param Context_len   The length of the context data.
+ *
+ * @param algorithm     The HMAC algorithm to use.
+ *
+ * @param KO            A buffer to receive the derived key.
+ *
+ * @param KO_len        The length of the key to be derived.
+ *
+ * @return NT_STATUS_OK on success, an NT status error code otherwise.
+ */
+NTSTATUS samba_gnutls_sp800_108_derive_key(
+       const uint8_t *KI,
+       size_t KI_len,
+       const uint8_t *Label,
+       size_t Label_len,
+       const uint8_t *Context,
+       size_t Context_len,
+       const gnutls_mac_algorithm_t algorithm,
+       uint8_t *KO,
+       size_t KO_len)
+{
+       gnutls_hmac_hd_t hmac_hnd = NULL;
+       uint8_t buf[4];
+       static const uint8_t zero = 0;
+       const size_t digest_len = gnutls_hmac_get_len(algorithm);
+       uint8_t digest[digest_len];
+       uint32_t i = 1;
+       uint32_t L = KO_len * 8;
+       int rc;
+
+       if (KO_len > digest_len) {
+               DBG_ERR("KO_len[%zu] > digest_len[%zu]\n", KO_len, digest_len);
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       switch (KO_len) {
+       case 16:
+       case 32:
+               break;
+       default:
+               DBG_ERR("KO_len[%zu] not supported\n", KO_len);
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       /*
+        * a simplified version of
+        * "NIST Special Publication 800-108" section 5.1.
+        */
+       rc = gnutls_hmac_init(&hmac_hnd,
+                             algorithm,
+                             KI,
+                             KI_len);
+       if (rc < 0) {
+               return gnutls_error_to_ntstatus(rc,
+                                               NT_STATUS_HMAC_NOT_SUPPORTED);
+       }
+
+       RSIVAL(buf, 0, i);
+       rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
+       if (rc < 0) {
+               return gnutls_error_to_ntstatus(rc,
+                                               NT_STATUS_HMAC_NOT_SUPPORTED);
+       }
+       rc = gnutls_hmac(hmac_hnd, Label, Label_len);
+       if (rc < 0) {
+               gnutls_hmac_deinit(hmac_hnd, NULL);
+               return gnutls_error_to_ntstatus(rc,
+                                               NT_STATUS_HMAC_NOT_SUPPORTED);
+       }
+       rc = gnutls_hmac(hmac_hnd, &zero, 1);
+       if (rc < 0) {
+               gnutls_hmac_deinit(hmac_hnd, NULL);
+               return gnutls_error_to_ntstatus(rc,
+                                               NT_STATUS_HMAC_NOT_SUPPORTED);
+       }
+       rc = gnutls_hmac(hmac_hnd, Context, Context_len);
+       if (rc < 0) {
+               gnutls_hmac_deinit(hmac_hnd, NULL);
+               return gnutls_error_to_ntstatus(rc,
+                                               NT_STATUS_HMAC_NOT_SUPPORTED);
+       }
+       RSIVAL(buf, 0, L);
+       rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
+       if (rc < 0) {
+               gnutls_hmac_deinit(hmac_hnd, NULL);
+               return gnutls_error_to_ntstatus(rc,
+                                               NT_STATUS_HMAC_NOT_SUPPORTED);
+       }
+
+       gnutls_hmac_deinit(hmac_hnd, digest);
+
+       memcpy(KO, digest, KO_len);
+
+       ZERO_ARRAY(digest);
+
+       return NT_STATUS_OK;
+}
index c43f084f6d47d953b9907897aaad979108777b42..fc298ab83c940918392a2451746c114ae12b0045 100644 (file)
@@ -8,6 +8,7 @@ def build(bld):
                         gnutls_aead_aes_256_cbc_hmac_sha512.c
                         gnutls_arcfour_confounded_md5.c
                         gnutls_weak_crypto.c
+                        gnutls_sp800_108.c
                         ''',
                         deps="gnutls samba-errors")
 
index ab654e74f2bff22704b7a01a72aa86b5fe1059e6..87337874c40473daf24a9cbdb27b5fc53a732f7b 100644 (file)
@@ -258,11 +258,15 @@ static NTSTATUS smb2_signing_key_create(TALLOC_CTX *mem_ctx,
                return NT_STATUS_OK;
        }
 
-       status = smb2_key_derivation(key->blob.data, in_key_length,
-                                    d->label.data, d->label.length,
-                                    d->context.data, d->context.length,
-                                    GNUTLS_MAC_SHA256,
-                                    key->blob.data, out_key_length);
+       status = samba_gnutls_sp800_108_derive_key(key->blob.data,
+                                                  in_key_length,
+                                                  d->label.data,
+                                                  d->label.length,
+                                                  d->context.data,
+                                                  d->context.length,
+                                                  GNUTLS_MAC_SHA256,
+                                                  key->blob.data,
+                                                  out_key_length);
        if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(key);
                return status;
@@ -647,89 +651,6 @@ NTSTATUS smb2_signing_check_pdu(struct smb2_signing_key *signing_key,
        return NT_STATUS_OK;
 }
 
-NTSTATUS smb2_key_derivation(const uint8_t *KI, size_t KI_len,
-                            const uint8_t *Label, size_t Label_len,
-                            const uint8_t *Context, size_t Context_len,
-                            const gnutls_mac_algorithm_t algorithm,
-                            uint8_t *KO, size_t KO_len)
-{
-       gnutls_hmac_hd_t hmac_hnd = NULL;
-       uint8_t buf[4];
-       static const uint8_t zero = 0;
-       const size_t digest_len = gnutls_hmac_get_len(algorithm);
-       uint8_t digest[digest_len];
-       uint32_t i = 1;
-       uint32_t L = KO_len * 8;
-       int rc;
-
-       if (KO_len > digest_len) {
-               DBG_ERR("KO_len[%zu] > digest_len[%zu]\n", KO_len, digest_len);
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       switch (KO_len) {
-       case 16:
-       case 32:
-               break;
-       default:
-               DBG_ERR("KO_len[%zu] not supported\n", KO_len);
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       /*
-        * a simplified version of
-        * "NIST Special Publication 800-108" section 5.1.
-        */
-       rc = gnutls_hmac_init(&hmac_hnd,
-                             algorithm,
-                             KI,
-                             KI_len);
-       if (rc < 0) {
-               return gnutls_error_to_ntstatus(rc,
-                                               NT_STATUS_HMAC_NOT_SUPPORTED);
-       }
-
-       RSIVAL(buf, 0, i);
-       rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
-       if (rc < 0) {
-               return gnutls_error_to_ntstatus(rc,
-                                               NT_STATUS_HMAC_NOT_SUPPORTED);
-       }
-       rc = gnutls_hmac(hmac_hnd, Label, Label_len);
-       if (rc < 0) {
-               gnutls_hmac_deinit(hmac_hnd, NULL);
-               return gnutls_error_to_ntstatus(rc,
-                                               NT_STATUS_HMAC_NOT_SUPPORTED);
-       }
-       rc = gnutls_hmac(hmac_hnd, &zero, 1);
-       if (rc < 0) {
-               gnutls_hmac_deinit(hmac_hnd, NULL);
-               return gnutls_error_to_ntstatus(rc,
-                                               NT_STATUS_HMAC_NOT_SUPPORTED);
-       }
-       rc = gnutls_hmac(hmac_hnd, Context, Context_len);
-       if (rc < 0) {
-               gnutls_hmac_deinit(hmac_hnd, NULL);
-               return gnutls_error_to_ntstatus(rc,
-                                               NT_STATUS_HMAC_NOT_SUPPORTED);
-       }
-       RSIVAL(buf, 0, L);
-       rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
-       if (rc < 0) {
-               gnutls_hmac_deinit(hmac_hnd, NULL);
-               return gnutls_error_to_ntstatus(rc,
-                                               NT_STATUS_HMAC_NOT_SUPPORTED);
-       }
-
-       gnutls_hmac_deinit(hmac_hnd, digest);
-
-       memcpy(KO, digest, KO_len);
-
-       ZERO_ARRAY(digest);
-
-       return NT_STATUS_OK;
-}
-
 NTSTATUS smb2_signing_encrypt_pdu(struct smb2_signing_key *encryption_key,
                                  struct iovec *vector,
                                  int count)
index e298db11a9b6751e53c3f07c42a8f23580a76839..2b8eef9fc42c75ebb1b989bdfca9892f63761079 100644 (file)
@@ -92,12 +92,6 @@ NTSTATUS smb2_signing_check_pdu(struct smb2_signing_key *signing_key,
                                const struct iovec *vector,
                                int count);
 
-NTSTATUS smb2_key_derivation(const uint8_t *KI, size_t KI_len,
-                            const uint8_t *Label, size_t Label_len,
-                            const uint8_t *Context, size_t Context_len,
-                            const gnutls_mac_algorithm_t algorithm,
-                            uint8_t *KO, size_t KO_len);
-
 NTSTATUS smb2_signing_encrypt_pdu(struct smb2_signing_key *encryption_key,
                                  struct iovec *vector,
                                  int count);
index 9390f8634b0965ac6db6c2f77993de82fda39d1d..73b505fc7fdf1e5343c1d5dac94edf23fa09a5e3 100644 (file)
@@ -6669,12 +6669,16 @@ NTSTATUS smb2cli_session_set_channel_key(struct smbXcli_session *session,
        if (conn->protocol >= PROTOCOL_SMB3_00) {
                struct _derivation *d = &derivation.signing;
 
-               status = smb2_key_derivation(channel_key, sizeof(channel_key),
-                                            d->label.data, d->label.length,
-                                            d->context.data, d->context.length,
-                                            GNUTLS_MAC_SHA256,
-                                            session->smb2_channel.signing_key->blob.data,
-                                            session->smb2_channel.signing_key->blob.length);
+               status = samba_gnutls_sp800_108_derive_key(
+                       channel_key,
+                       sizeof(channel_key),
+                       d->label.data,
+                       d->label.length,
+                       d->context.data,
+                       d->context.length,
+                       GNUTLS_MAC_SHA256,
+                       session->smb2_channel.signing_key->blob.data,
+                       session->smb2_channel.signing_key->blob.length);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }