Print this page
12513 SMB 3.1.1 support for server
@@ -9,10 +9,11 @@
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
*/
/*
* Routines for smb3 encryption.
*/
@@ -22,27 +23,12 @@
#include <sys/random.h>
#include <sys/cmn_err.h>
#define SMB3_NONCE_OFFS 20
#define SMB3_SIG_OFFS 4
-#define SMB3_NONCE_SIZE 11 /* 12 for gcm later */
-
-/*
- * Inputs to KDF for EncryptionKey and DecryptionKey.
- * See comment for smb3_do_kdf for content.
- */
-static uint8_t encrypt_kdf_input[30] = {
- 0, 0, 0, 1, 'S', 'M', 'B', '2',
- 'A', 'E', 'S', 'C', 'C', 'M', 0, 0,
- 'S', 'e', 'r', 'v', 'e', 'r', 'O',
- 'u', 't', 0, 0, 0, 0, 0x80 };
-
-static uint8_t decrypt_kdf_input[30] = {
- 0, 0, 0, 1, 'S', 'M', 'B', '2',
- 'A', 'E', 'S', 'C', 'C', 'M', 0, 0,
- 'S', 'e', 'r', 'v', 'e', 'r', 'I',
- 'n', ' ', 0, 0, 0, 0, 0x80 };
+#define SMB3_AES128_CCM_NONCE_SIZE 11
+#define SMB3_AES128_GCM_NONCE_SIZE 12
/*
* Arbitrary value used to prevent nonce reuse via overflow. Currently
* 2^64 - 2^32 - 1. Assumes we can't have (or are unlikely to have)
* 2^32 concurrent messages when we hit this number.
@@ -98,12 +84,26 @@
int rc;
if (s->enc_mech != NULL)
return (0);
+ if (s->dialect < SMB_VERS_3_11)
+ s->smb31_enc_cipherid = SMB3_CIPHER_AES128_CCM;
+
mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
- rc = smb3_encrypt_getmech(mech);
+
+ switch (s->smb31_enc_cipherid) {
+ case SMB3_CIPHER_AES128_GCM:
+ rc = smb3_aes_gcm_getmech(mech);
+ break;
+ case SMB3_CIPHER_AES128_CCM:
+ rc = smb3_aes_ccm_getmech(mech);
+ break;
+ default:
+ return (-1);
+ }
+
if (rc != 0) {
kmem_free(mech, sizeof (*mech));
return (rc);
}
s->enc_mech = mech;
@@ -148,19 +148,35 @@
/*
* For SMB3, the encrypt/decrypt keys are derived from
* the session key using KDF in counter mode.
*/
- if (smb3_do_kdf(enc_key->key, encrypt_kdf_input,
- sizeof (encrypt_kdf_input), token->tkn_ssnkey.val,
- token->tkn_ssnkey.len) != 0)
+ if (s->dialect >= SMB_VERS_3_11) {
+ if (smb3_kdf(enc_key->key,
+ token->tkn_ssnkey.val, token->tkn_ssnkey.len,
+ (uint8_t *)"SMBS2CCipherKey", 16,
+ s->smb31_preauth_hashval, SHA512_DIGEST_LENGTH) != 0)
+ return;
+
+ if (smb3_kdf(dec_key->key,
+ token->tkn_ssnkey.val, token->tkn_ssnkey.len,
+ (uint8_t *)"SMBC2SCipherKey", 16,
+ s->smb31_preauth_hashval, SHA512_DIGEST_LENGTH) != 0)
+ return;
+ } else {
+ if (smb3_kdf(enc_key->key,
+ token->tkn_ssnkey.val, token->tkn_ssnkey.len,
+ (uint8_t *)"SMB2AESCCM", 11,
+ (uint8_t *)"ServerOut", 10) != 0)
return;
- if (smb3_do_kdf(dec_key->key, decrypt_kdf_input,
- sizeof (decrypt_kdf_input), token->tkn_ssnkey.val,
- token->tkn_ssnkey.len) != 0)
+ if (smb3_kdf(dec_key->key,
+ token->tkn_ssnkey.val, token->tkn_ssnkey.len,
+ (uint8_t *)"SMB2AESCCM", 11,
+ (uint8_t *)"ServerIn ", 10) != 0)
return;
+ }
smb3_encrypt_init_nonce(u);
enc_key->len = SMB3_KEYLEN;
dec_key->len = SMB3_KEYLEN;
@@ -182,10 +198,14 @@
struct smb_key *dec_key = &u->u_dec_key;
struct mbuf *mbuf;
int offset, resid, tlen, rc;
smb3_crypto_param_t param;
smb_crypto_mech_t mech;
+ boolean_t gcm = sr->session->smb31_enc_cipherid ==
+ SMB3_CIPHER_AES128_GCM;
+ size_t nonce_size = (gcm ? SMB3_AES128_GCM_NONCE_SIZE :
+ SMB3_AES128_CCM_NONCE_SIZE);
ASSERT(u != NULL);
if (s->enc_mech == NULL || dec_key->len != 16) {
return (-1);
}
@@ -208,11 +228,15 @@
/*
* The transform header, minus the PROTOCOL_ID and the
* SIGNATURE, is authenticated but not encrypted.
*/
- smb3_crypto_init_param(¶m, sr->nonce, SMB3_NONCE_SIZE,
+ if (gcm)
+ smb3_crypto_init_gcm_param(¶m, sr->nonce, nonce_size,
+ tmp_hdr, tlen);
+ else
+ smb3_crypto_init_ccm_param(¶m, sr->nonce, nonce_size,
tmp_hdr, tlen, sr->msgsize + SMB2_SIG_SIZE);
/*
* Unlike signing, which uses one global mech struct,
* encryption requires modifying the mech to add a
@@ -315,36 +339,44 @@
struct smb_key *enc_key = &u->u_enc_key;
struct mbuf *mbuf;
int resid, tlen, rc;
smb3_crypto_param_t param;
smb_crypto_mech_t mech;
+ boolean_t gcm = sr->session->smb31_enc_cipherid ==
+ SMB3_CIPHER_AES128_GCM;
+ size_t nonce_size = (gcm ? SMB3_AES128_GCM_NONCE_SIZE :
+ SMB3_AES128_CCM_NONCE_SIZE);
ASSERT(u != NULL);
if (s->enc_mech == NULL || enc_key->len != 16) {
return (-1);
}
- rc = smb3_encrypt_gen_nonce(u, sr->nonce, SMB3_NONCE_SIZE);
+ rc = smb3_encrypt_gen_nonce(u, sr->nonce, nonce_size);
if (rc != 0) {
cmn_err(CE_WARN, "ran out of nonces");
return (-1);
}
(void) smb_mbc_poke(out_mbc, SMB3_NONCE_OFFS, "#c",
- SMB3_NONCE_SIZE, sr->nonce);
+ nonce_size, sr->nonce);
resid = in_mbc->max_bytes;
/*
* The transform header, minus the PROTOCOL_ID and the
* SIGNATURE, is authenticated but not encrypted.
*/
- smb3_crypto_init_param(¶m,
- sr->nonce, SMB3_NONCE_SIZE,
- buf + SMB3_NONCE_OFFS, SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS,
- resid);
+ if (gcm)
+ smb3_crypto_init_gcm_param(¶m, sr->nonce, nonce_size,
+ buf + SMB3_NONCE_OFFS,
+ SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS);
+ else
+ smb3_crypto_init_ccm_param(¶m, sr->nonce, nonce_size,
+ buf + SMB3_NONCE_OFFS,
+ SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS, resid);
/*
* Unlike signing, which uses one global mech struct,
* encryption requires modifying the mech to add a
* per-use param struct. Thus, we need to make a copy.