Print this page
12513 SMB 3.1.1 support for server
@@ -9,10 +9,11 @@
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
*/
/*
* Helper functions for SMB3 encryption using the
* Kernel Cryptographic Framework (KCF)
@@ -26,40 +27,67 @@
#include <smbsrv/smb_kcrypt.h>
#include <smbsrv/smb2_kproto.h>
#include <sys/cmn_err.h>
/*
- * SMB3 encryption helpers:
- * (getmech, init, update, final)
+ * Common function to see if a mech is available.
*/
-
-int
-smb3_encrypt_getmech(smb_crypto_mech_t *mech)
+static int
+find_mech(smb_crypto_mech_t *mech, crypto_mech_name_t name)
{
crypto_mech_type_t t;
- t = crypto_mech2id(SUN_CKM_AES_CCM);
+ t = crypto_mech2id(name);
if (t == CRYPTO_MECH_INVALID) {
- cmn_err(CE_NOTE, "smb: no kcf mech: %s", SUN_CKM_AES_CCM);
+ cmn_err(CE_NOTE, "smb: no kcf mech: %s", name);
return (-1);
}
mech->cm_type = t;
-
return (0);
}
+/*
+ * SMB3 encryption helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb3_aes_ccm_getmech(smb_crypto_mech_t *mech)
+{
+ return (find_mech(mech, SUN_CKM_AES_CCM));
+}
+
+int
+smb3_aes_gcm_getmech(smb_crypto_mech_t *mech)
+{
+ return (find_mech(mech, SUN_CKM_AES_GCM));
+}
+
void
-smb3_crypto_init_param(smb3_crypto_param_t *param,
+smb3_crypto_init_ccm_param(smb3_crypto_param_t *param,
uint8_t *nonce, size_t noncesize, uint8_t *auth, size_t authsize,
size_t datasize)
{
- param->ulMACSize = SMB2_SIG_SIZE;
- param->ulNonceSize = noncesize;
- param->nonce = nonce;
- param->ulDataSize = datasize;
- param->ulAuthDataSize = authsize;
- param->authData = auth;
+ param->ccm.ulMACSize = SMB2_SIG_SIZE;
+ param->ccm.ulNonceSize = noncesize;
+ param->ccm.nonce = nonce;
+ param->ccm.ulDataSize = datasize;
+ param->ccm.ulAuthDataSize = authsize;
+ param->ccm.authData = auth;
+}
+
+void
+smb3_crypto_init_gcm_param(smb3_crypto_param_t *param,
+ uint8_t *nonce, size_t noncesize, uint8_t *auth, size_t authsize)
+{
+ ASSERT3U(noncesize, ==, 12);
+ param->gcm.pIv = nonce;
+ param->gcm.ulIvLen = noncesize; /* should be 12 bytes */
+ /* tform hdr size - (protcolo id + signing) == 32 bytes */
+ param->gcm.ulTagBits = SMB2_SIG_SIZE << 3; /* convert bytes to bits */
+ param->gcm.pAAD = auth; /* auth data */
+ param->gcm.ulAADLen = authsize; /* auth data len */
}
/*
* Start the KCF session, load the key
*/
@@ -197,11 +225,26 @@
if (rv != CRYPTO_SUCCESS) {
cmn_err(CE_WARN, "crypto_encrypt_final failed: 0x%x", rv);
return (-1);
}
+ /*
+ * For some reason AES module processes ccm_encrypt_final and
+ * gcm_encrypt_final differently.
+ * For GCM it restores original offset (which is 0) and updates
+ * cd_length to size of residual data + mac len.
+ * For CCM it does nothing, what means offset is updated and cd_length
+ * is decreased by size of residual data + mac len.
+ */
+ if (out.cd_offset == 0) {
+ /* GCM */
+ outlen = out.cd_length - SMB2_SIG_SIZE;
+ } else {
+ /* CCM */
outlen = out.cd_offset - SMB2_SIG_SIZE;
+ }
+
if (outlen > 0)
bcopy(buf, ctxp->output.cd_raw.iov_base +
ctxp->output.cd_offset, outlen);
bcopy(buf + outlen, digest16, SMB2_SIG_SIZE);