From: Joseph Sutton Date: Tue, 28 Nov 2023 22:36:57 +0000 (+1300) Subject: lib:crypto: Add samba_gnutls_sp800_108_derive_key() X-Git-Tag: talloc-2.4.2~453 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=04b6dc8d0bb98f79a4b791c7b9dbc324799628ad;p=thirdparty%2Fsamba.git lib:crypto: Add samba_gnutls_sp800_108_derive_key() Rename smb2_key_derivation() to samba_gnutls_sp800_108_derive_key() and move it to GNUTLS_HELPERS. Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett --- diff --git a/lib/crypto/gnutls_helpers.h b/lib/crypto/gnutls_helpers.h index 4e6f4f3f8b1..c0b76047a0c 100644 --- a/lib/crypto/gnutls_helpers.h +++ b/lib/crypto/gnutls_helpers.h @@ -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 index 00000000000..225c9b2c448 --- /dev/null +++ b/lib/crypto/gnutls_sp800_108.c @@ -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 . + +*/ + +#include "includes.h" +#include +#include +#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; +} diff --git a/lib/crypto/wscript b/lib/crypto/wscript index c43f084f6d4..fc298ab83c9 100644 --- a/lib/crypto/wscript +++ b/lib/crypto/wscript @@ -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") diff --git a/libcli/smb/smb2_signing.c b/libcli/smb/smb2_signing.c index ab654e74f2b..87337874c40 100644 --- a/libcli/smb/smb2_signing.c +++ b/libcli/smb/smb2_signing.c @@ -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) diff --git a/libcli/smb/smb2_signing.h b/libcli/smb/smb2_signing.h index e298db11a9b..2b8eef9fc42 100644 --- a/libcli/smb/smb2_signing.h +++ b/libcli/smb/smb2_signing.h @@ -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); diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index 9390f8634b0..73b505fc7fd 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -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; }