From: Stefan Metzmacher Date: Wed, 11 Nov 2020 12:00:34 +0000 (+0100) Subject: libcli/smb: split out smb2_signing_calc_signature() from smb2_signing_check_pdu() X-Git-Tag: tevent-0.11.0~1514 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2a4ba7b6cdfe417fa05479517b755a2f67416def;p=thirdparty%2Fsamba.git libcli/smb: split out smb2_signing_calc_signature() from smb2_signing_check_pdu() We only need one function to calculate the signature of an SMB2 packet. And that only need the logic based on a gnutls_mac_algorithm_t once. The next step will convert smb2_signing_sign_pdu() to also use smb2_signing_calc_signature(). Doing that in a separate commit should make sure we don't introduce a symetric bug. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14512 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- diff --git a/libcli/smb/smb2_constants.h b/libcli/smb/smb2_constants.h index ea1a21c84e8..64d5ec697cb 100644 --- a/libcli/smb/smb2_constants.h +++ b/libcli/smb/smb2_constants.h @@ -137,6 +137,10 @@ /* Values for the SMB2_PREAUTH_INTEGRITY_CAPABILITIES Context (>= 0x310) */ #define SMB2_PREAUTH_INTEGRITY_SHA512 0x0001 +#define SMB2_SIGNING_INVALID_ALGO 0xffff /* only used internally */ +#define SMB2_SIGNING_HMAC_SHA256 0x0000 /* default <= 0x210 */ +#define SMB2_SIGNING_AES128_CMAC 0x0001 /* default >= 0x224 */ + /* Values for the SMB2_ENCRYPTION_CAPABILITIES Context (>= 0x310) */ #define SMB2_ENCRYPTION_AES128_CCM 0x0001 /* only in dialect >= 0x224 */ #define SMB2_ENCRYPTION_AES128_GCM 0x0002 /* only in dialect >= 0x310 */ diff --git a/libcli/smb/smb2_signing.c b/libcli/smb/smb2_signing.c index 5927a1331ac..6da289dc434 100644 --- a/libcli/smb/smb2_signing.c +++ b/libcli/smb/smb2_signing.c @@ -62,6 +62,105 @@ bool smb2_signing_key_valid(const struct smb2_signing_key *key) return true; } +static NTSTATUS smb2_signing_calc_signature(struct smb2_signing_key *signing_key, + uint16_t sign_algo_id, + const struct iovec *vector, + int count, + uint8_t signature[16]) +{ + const uint8_t *hdr = (uint8_t *)vector[0].iov_base; + static const uint8_t zero_sig[16] = { 0, }; + gnutls_mac_algorithm_t hmac_algo = GNUTLS_MAC_UNKNOWN; + int i; + + SMB_ASSERT(count >= 2); + SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY); + + switch (sign_algo_id) { + case SMB2_SIGNING_AES128_CMAC: +#ifdef HAVE_GNUTLS_AES_CMAC + hmac_algo = GNUTLS_MAC_AES_CMAC_128; + break; +#else /* NOT HAVE_GNUTLS_AES_CMAC */ + { + struct aes_cmac_128_context ctx; + uint8_t key[AES_BLOCK_SIZE] = {0}; + + memcpy(key, + signing_key->blob.data, + MIN(signing_key->blob.length, 16)); + + aes_cmac_128_init(&ctx, key); + aes_cmac_128_update(&ctx, hdr, SMB2_HDR_SIGNATURE); + aes_cmac_128_update(&ctx, zero_sig, 16); + for (i=1; i < count; i++) { + aes_cmac_128_update(&ctx, + (const uint8_t *)vector[i].iov_base, + vector[i].iov_len); + } + aes_cmac_128_final(&ctx, signature); + + ZERO_ARRAY(key); + + return NT_STATUS_OK; + } break; +#endif + case SMB2_SIGNING_HMAC_SHA256: + hmac_algo = GNUTLS_MAC_SHA256; + break; + + default: + return NT_STATUS_HMAC_NOT_SUPPORTED; + } + + if (hmac_algo != GNUTLS_MAC_UNKNOWN) { + uint8_t digest[gnutls_hash_get_len(hmac_algo)]; + gnutls_datum_t key = { + .data = signing_key->blob.data, + .size = MIN(signing_key->blob.length, 16), + }; + int rc; + + if (signing_key->hmac_hnd == NULL) { + rc = gnutls_hmac_init(&signing_key->hmac_hnd, + hmac_algo, + key.data, + key.size); + if (rc < 0) { + return gnutls_error_to_ntstatus(rc, + NT_STATUS_HMAC_NOT_SUPPORTED); + } + } + + rc = gnutls_hmac(signing_key->hmac_hnd, hdr, SMB2_HDR_SIGNATURE); + if (rc < 0) { + return gnutls_error_to_ntstatus(rc, + NT_STATUS_HMAC_NOT_SUPPORTED); + } + rc = gnutls_hmac(signing_key->hmac_hnd, zero_sig, 16); + if (rc < 0) { + return gnutls_error_to_ntstatus(rc, + NT_STATUS_HMAC_NOT_SUPPORTED); + } + + for (i = 1; i < count; i++) { + rc = gnutls_hmac(signing_key->hmac_hnd, + vector[i].iov_base, + vector[i].iov_len); + if (rc < 0) { + return gnutls_error_to_ntstatus(rc, + NT_STATUS_HMAC_NOT_SUPPORTED); + } + } + gnutls_hmac_output(signing_key->hmac_hnd, digest); + memcpy(signature, digest, 16); + ZERO_ARRAY(digest); + return NT_STATUS_OK; + } + + return NT_STATUS_HMAC_NOT_SUPPORTED; +} + NTSTATUS smb2_signing_sign_pdu(struct smb2_signing_key *signing_key, enum protocol_types protocol, struct iovec *vector, @@ -182,12 +281,12 @@ NTSTATUS smb2_signing_check_pdu(struct smb2_signing_key *signing_key, const struct iovec *vector, int count) { + uint16_t sign_algo_id; const uint8_t *hdr; const uint8_t *sig; uint64_t session_id; uint8_t res[16]; - static const uint8_t zero_sig[16] = { 0, }; - int i; + NTSTATUS status; SMB_ASSERT(count >= 2); SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY); @@ -211,100 +310,25 @@ NTSTATUS smb2_signing_check_pdu(struct smb2_signing_key *signing_key, sig = hdr+SMB2_HDR_SIGNATURE; if (protocol >= PROTOCOL_SMB2_24) { -#ifdef HAVE_GNUTLS_AES_CMAC - gnutls_datum_t key = { - .data = signing_key->blob.data, - .size = MIN(signing_key->blob.length, 16), - }; - int rc; - - if (signing_key->hmac_hnd == NULL) { - rc = gnutls_hmac_init(&signing_key->hmac_hnd, - GNUTLS_MAC_AES_CMAC_128, - key.data, - key.size); - if (rc < 0) { - return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); - } - } - - rc = gnutls_hmac(signing_key->hmac_hnd, hdr, SMB2_HDR_SIGNATURE); - if (rc < 0) { - return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); - } - - rc = gnutls_hmac(signing_key->hmac_hnd, zero_sig, 16); - if (rc < 0) { - return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); - } - - for (i = 1; i < count; i++) { - rc = gnutls_hmac(signing_key->hmac_hnd, - vector[i].iov_base, - vector[i].iov_len); - if (rc < 0) { - return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); - } - } - gnutls_hmac_output(signing_key->hmac_hnd, res); -#else /* NOT HAVE_GNUTLS_AES_CMAC */ - struct aes_cmac_128_context ctx; - uint8_t key[AES_BLOCK_SIZE] = {0}; - - memcpy(key, - signing_key->blob.data, - MIN(signing_key->blob.length, 16)); - - aes_cmac_128_init(&ctx, key); - aes_cmac_128_update(&ctx, hdr, SMB2_HDR_SIGNATURE); - aes_cmac_128_update(&ctx, zero_sig, 16); - for (i=1; i < count; i++) { - aes_cmac_128_update(&ctx, - (const uint8_t *)vector[i].iov_base, - vector[i].iov_len); - } - aes_cmac_128_final(&ctx, res); - - ZERO_ARRAY(key); -#endif + sign_algo_id = SMB2_SIGNING_AES128_CMAC; } else { - uint8_t digest[gnutls_hash_get_len(GNUTLS_MAC_SHA256)]; - int rc; - - if (signing_key->hmac_hnd == NULL) { - rc = gnutls_hmac_init(&signing_key->hmac_hnd, - GNUTLS_MAC_SHA256, - signing_key->blob.data, - MIN(signing_key->blob.length, 16)); - if (rc < 0) { - return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); - } - } - - rc = gnutls_hmac(signing_key->hmac_hnd, hdr, SMB2_HDR_SIGNATURE); - if (rc < 0) { - return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); - } - rc = gnutls_hmac(signing_key->hmac_hnd, zero_sig, 16); - if (rc < 0) { - return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); - } + sign_algo_id = SMB2_SIGNING_HMAC_SHA256; + } - for (i = 1; i < count; i++) { - rc = gnutls_hmac(signing_key->hmac_hnd, - vector[i].iov_base, - vector[i].iov_len); - if (rc < 0) { - return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); - } - } - gnutls_hmac_output(signing_key->hmac_hnd, digest); - memcpy(res, digest, 16); - ZERO_ARRAY(digest); + status = smb2_signing_calc_signature(signing_key, + sign_algo_id, + vector, + count, + res); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("smb2_signing_calc_signature(sign_algo_id=%u) - %s\n", + (unsigned)sign_algo_id, nt_errstr(status)); + return status; } if (memcmp_const_time(res, sig, 16) != 0) { - DEBUG(0,("Bad SMB2 signature for message\n")); + DEBUG(0,("Bad SMB2 (sign_algo_id=%u) signature for message\n", + (unsigned)sign_algo_id)); dump_data(0, sig, 16); dump_data(0, res, 16); return NT_STATUS_ACCESS_DENIED;