--- old/usr/src/cmd/smbsrv/smbd/server.xml	2020-04-15 01:43:35.447532227 +0000
+++ new/usr/src/cmd/smbsrv/smbd/server.xml	2020-04-15 01:43:35.453850461 +0000
@@ -24,7 +24,7 @@
 Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
 Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
 Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
-Copyright 2019 RackTop Systems.
+Copyright 2020 RackTop Systems.
 
 NOTE:  This service manifest is not editable; its contents will
 be overwritten by package or patch operations, including
@@ -234,6 +234,8 @@
 			value='' override='true'/>
 		<propval name='encrypt' type='astring'
 			value='disabled' override='true'/>
+		<propval name='encrypt_cipher' type='astring'
+			value='' override='true'/>
 		<propval name='initial_credits' type='integer'
 			value='20' override='true'/>
 		<propval name='maximum_credits' type='integer'
--- old/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com	2020-04-15 01:43:35.611964860 +0000
+++ new/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com	2020-04-15 01:43:35.617213671 +0000
@@ -25,6 +25,8 @@
 # Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
 #
 # Copyright (c) 2018, Joyent, Inc.
+#
+# Copyright 2020 RackTop Systems, Inc.
 
 LIBRARY =	libfksmbsrv.a
 VERS =		.1
@@ -36,6 +38,7 @@
 		fksmb_idmap.o \
 		fksmb_init.o \
 		fksmb_kdoor.o \
+		fksmb_preauth_pkcs.o \
 		fksmb_sign_pkcs.o \
 		fake_lookup.o \
 		fake_nblk.o \
@@ -161,6 +164,7 @@
 		smb2_tree_disconn.o \
 		smb2_write.o \
 	        \
+	        smb3_kdf.o \
 	        smb3_encrypt.o
 
 # Can't just link with -lsmb because of user vs kernel API
--- old/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_encrypt_pkcs.c	2020-04-15 01:43:35.761128407 +0000
+++ new/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_encrypt_pkcs.c	2020-04-15 01:43:35.766922157 +0000
@@ -11,6 +11,7 @@
 
 /*
  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 /*
@@ -33,7 +34,15 @@
 
 /* ARGSUSED */
 int
-smb3_encrypt_getmech(smb_crypto_mech_t *mech)
+smb3_aes_ccm_getmech(smb_crypto_mech_t *mech)
+{
+	cmn_err(CE_NOTE, "fksmbsrv does not support SMB3 Encryption");
+	return (-1);
+}
+
+/* ARGSUSED */
+int
+smb3_aes_gcm_getmech(smb_crypto_mech_t *mech)
 {
 	cmn_err(CE_NOTE, "fksmbsrv does not support SMB3 Encryption");
 	return (-1);
@@ -41,12 +50,19 @@
 
 /* ARGSUSED */
 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)
 {
 }
 
+/* ARGSUSED */
+void
+smb3_crypto_init_gcm_param(smb3_crypto_param_t *param,
+    uint8_t *nonce, size_t noncesize, uint8_t *auth, size_t authsize)
+{
+}
+
 /*
  * Start the KCF session, load the key
  */
--- /dev/null	2020-04-15 01:43:35.000000000 +0000
+++ new/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_preauth_pkcs.c	2020-04-15 01:43:35.939644252 +0000
@@ -0,0 +1,40 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2020 RackTop Systems, Inc.
+ */
+
+#include <smbsrv/smb2_kproto.h>
+#include <smbsrv/smb2.h>
+#include <sys/crypto/api.h>
+#include <smbsrv/smb_kproto.h>
+#include <smbsrv/smb_kcrypt.h>
+
+/*
+ * not implemented yet
+ */
+void
+smb31_preauth_init_mech(smb_session_t *s)
+{
+}
+
+void
+smb31_preauth_fini(smb_session_t *s)
+{
+}
+
+int
+smb31_preauth_sha512_calc(smb_request_t *sr, struct mbuf_chain *mbc,
+    uint8_t *hashval)
+{
+	return (0);
+}
--- old/usr/src/lib/smbsrv/libsmb/common/libsmb.h	2020-04-15 01:43:36.022666375 +0000
+++ new/usr/src/lib/smbsrv/libsmb/common/libsmb.h	2020-04-15 01:43:36.028724346 +0000
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 #ifndef	_LIBSMB_H
@@ -160,6 +161,7 @@
 	SMB_CI_ENCRYPT,
 	SMB_CI_MIN_PROTOCOL,
 	SMB_CI_BYPASS_TRAVERSE_CHECKING,
+	SMB_CI_ENCRYPT_CIPHER,
 
 	SMB_CI_MAX
 } smb_cfg_id_t;
@@ -221,6 +223,7 @@
 extern uint32_t smb_config_get_max_protocol(void);
 extern uint32_t smb_config_get_min_protocol(void);
 extern void smb_config_upgrade(void);
+extern uint16_t smb31_config_get_encrypt_cipher(void);
 
 extern smb_cfg_val_t smb_config_get_require(smb_cfg_id_t);
 
--- old/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c	2020-04-15 01:43:36.213503298 +0000
+++ new/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c	2020-04-15 01:43:36.219039645 +0000
@@ -21,6 +21,7 @@
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 /*
@@ -150,6 +151,7 @@
 	{SMB_CI_MIN_PROTOCOL, "min_protocol", SCF_TYPE_ASTRING, 0},
 	{SMB_CI_BYPASS_TRAVERSE_CHECKING,
 	    "bypass_traverse_checking", SCF_TYPE_BOOLEAN, 0},
+	{SMB_CI_ENCRYPT_CIPHER, "encrypt_cipher", SCF_TYPE_ASTRING, 0},
 
 	/* SMB_CI_MAX */
 };
@@ -165,6 +167,7 @@
  */
 static struct str_val
 smb_versions[] = {
+	{ "3.11",	SMB_VERS_3_11 },
 	{ "3.02",	SMB_VERS_3_02 },
 	{ "3.0",	SMB_VERS_3_0 },
 	{ "2.1",	SMB_VERS_2_1 },
@@ -173,6 +176,16 @@
 	{ NULL,		0 }
 };
 
+/*
+ * Supported encryption ciphers.
+ */
+static struct str_val
+smb31_encrypt_ciphers[] = {
+	{ "aes128-ccm",	SMB3_CIPHER_AES128_CCM },	/* SMB 3.x */
+	{ "aes128-gcm",	SMB3_CIPHER_AES128_GCM },	/* SMB 3.1.1 */
+	{ NULL,		0 }
+};
+
 static smb_cfg_param_t *smb_config_getent(smb_cfg_id_t);
 
 static boolean_t smb_is_base64(unsigned char c);
@@ -1224,7 +1237,7 @@
  * whole range that we implement). For that reason, this should usually be the
  * highest protocol version we implement.
  */
-uint32_t max_protocol_default = SMB_VERS_3_02;
+uint32_t max_protocol_default = SMB_VERS_3_11;
 
 uint32_t
 smb_config_get_max_protocol(void)
@@ -1263,6 +1276,34 @@
 }
 
 /*
+ * Only SMB 3.x supports encryption.
+ * SMB 3.0.2 uses AES128-CCM only.
+ * SMB 3.1.1 - AES128-CCM or AES128-GCM.
+ */
+uint16_t
+smb31_config_get_encrypt_cipher(void)
+{
+	uint32_t max_proto = smb_config_get_max_protocol();
+	uint16_t cipher = SMB3_CIPHER_AES128_GCM; /* by default AES128-GCM */
+	char str[12];
+	int i;
+
+	if (max_proto < SMB_VERS_3_11)
+		return (SMB3_CIPHER_NONE);
+
+	/* SMB 3.1.1 */
+	if (smb_config_getstr(SMB_CI_ENCRYPT_CIPHER, str, sizeof (str))
+	    == SMBD_SMF_OK) {
+		for (i = 0; smb31_encrypt_ciphers[i].str != NULL; i++) {
+			if (strcmp(str, smb31_encrypt_ciphers[i].str) == 0)
+				cipher = smb31_encrypt_ciphers[i].val;
+		}
+	}
+
+	return (cipher);
+}
+
+/*
  * If smb2_enable is present and max_protocol is empty,
  * set max_protocol.  Delete smb2_enable.
  */
--- old/usr/src/lib/smbsrv/libsmb/common/smb_info.c	2020-04-15 01:43:36.389845368 +0000
+++ new/usr/src/lib/smbsrv/libsmb/common/smb_info.c	2020-04-15 01:43:36.396788151 +0000
@@ -21,6 +21,7 @@
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 #include <sys/types.h>
@@ -160,6 +161,7 @@
 	kcfg->skc_min_protocol = smb_config_get_min_protocol();
 	kcfg->skc_secmode = smb_config_get_secmode();
 	kcfg->skc_encrypt = smb_config_get_require(SMB_CI_ENCRYPT);
+	kcfg->skc_encrypt_cipher = smb31_config_get_encrypt_cipher();
 
 	(void) smb_getdomainname(kcfg->skc_nbdomain,
 	    sizeof (kcfg->skc_nbdomain));
--- old/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c	2020-04-15 01:43:36.546433140 +0000
+++ new/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c	2020-04-15 01:43:36.551260520 +0000
@@ -22,6 +22,7 @@
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  * Copyright 2017 Joyent, Inc.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 #include <sys/types.h>
@@ -96,6 +97,7 @@
 	ioc.initial_credits = cfg->skc_initial_credits;
 	ioc.maximum_credits = cfg->skc_maximum_credits;
 	ioc.encrypt = cfg->skc_encrypt;
+	ioc.encrypt_cipher = cfg->skc_encrypt_cipher;
 
 	(void) memcpy(ioc.machine_uuid, cfg->skc_machine_uuid, sizeof (uuid_t));
 	(void) memcpy(ioc.negtok, cfg->skc_negtok, sizeof (ioc.negtok));
--- old/usr/src/man/man4/smb.4	2020-04-15 01:43:36.718362041 +0000
+++ new/usr/src/man/man4/smb.4	2020-04-15 01:43:36.723396594 +0000
@@ -1,6 +1,7 @@
 '\" te
 .\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved.
 .\" Copyright 2017, Nexenta Systems, Inc. All Rights Reserved.
+.\" Copyright 2020, RackTop Systems, Inc. All Rights Reserved.
 .\" The contents of this file are subject to the terms of the
 .\" Common Development and Distribution License (the "License").
 .\" You may not use this file except in compliance with the License.
@@ -150,6 +151,40 @@
 .RE
 
 .sp
+.ne 2
+.na
+\fB\fBencrypt_cipher\fR\fR
+.ad
+.sp .6
+.RS 4n
+Specifies SMB 3.1.1 Encryption Cipher. This property is only used when
+encryption is On (see \fBencrypt\fR property) and negotiated SMB dialect
+is 3.1.1 or higher (see \fBmax_protocol\fR property). Otherwise it is ignored.
+If the property is not set the default encryption algorith is AES-128-GCM.
+.sp
+The property can be set to one of these values:
+.sp
+.ne 2
+.na
+\fBaes128-ccm\fR
+.ad
+.RS 13n
+AES-128-CCM. This is the only cipher used for SMB 3.0.2 dialect. It is
+deprecated by AES-128-GCM cipher.
+.RE
+
+.sp
+.ne 2
+.na
+\fBaes128-gcm\fR
+.ad
+.RS 13n
+AES-128-GCM. This is default cipher for SMB 3.1.1 dialect.
+.RE
+
+.RE
+
+.sp
 .ne 2
 .na
 \fB\fBipv6_enable\fR\fR
--- old/usr/src/uts/common/Makefile.files	2020-04-15 01:43:37.009030372 +0000
+++ new/usr/src/uts/common/Makefile.files	2020-04-15 01:43:37.014243523 +0000
@@ -28,6 +28,7 @@
 # Copyright 2020 Joyent, Inc.
 # Copyright 2016 OmniTI Computer Consulting, Inc.  All rights reserved.
 # Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
+# Copyright 2020 RackTop Systems, Inc.
 #
 
 #
@@ -1244,7 +1245,9 @@
 		smb2_write.o \
 		\
 		smb3_encrypt.o \
-		smb3_encrypt_kcf.o
+		smb3_encrypt_kcf.o \
+		smb3_kdf.o \
+		smb31_preauth.o
 
 PCFS_OBJS +=	pc_alloc.o	pc_dir.o	pc_node.o	pc_subr.o \
 		pc_vfsops.o	pc_vnops.o
--- old/usr/src/uts/common/fs/smbsrv/smb2_dispatch.c	2020-04-15 01:43:37.180497394 +0000
+++ new/usr/src/uts/common/fs/smbsrv/smb2_dispatch.c	2020-04-15 01:43:37.185676756 +0000
@@ -11,7 +11,7 @@
 
 /*
  * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
- * Copyright 2019 RackTop Systems.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 
@@ -973,6 +973,16 @@
 	 */
 	(void) smb2_encode_header(sr, B_TRUE);
 
+	/*
+	 * Cannot move this into smb2_session_setup() - encoded header required.
+	 */
+	if (session->dialect >= SMB_VERS_3_11 &&
+	    sr->smb2_cmd_code == SMB2_SESSION_SETUP &&
+	    sr->smb2_status == NT_STATUS_MORE_PROCESSING_REQUIRED) {
+		(void) smb31_preauth_sha512_calc(sr, &sr->reply,
+		    session->smb31_preauth_hashval);
+	}
+
 	/* Don't sign if we're going to encrypt */
 	if (sr->tform_ssn == NULL &&
 	    (sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) != 0)
@@ -1109,8 +1119,8 @@
 		disconnect = B_TRUE;
 		goto cleanup;
 	}
-	sr->smb2_hdr_flags |=  (SMB2_FLAGS_SERVER_TO_REDIR |
-				SMB2_FLAGS_ASYNC_COMMAND);
+	sr->smb2_hdr_flags |= (SMB2_FLAGS_SERVER_TO_REDIR |
+	    SMB2_FLAGS_ASYNC_COMMAND);
 	sr->smb2_async_id = SMB2_ASYNCID(sr);
 
 	/*
--- old/usr/src/uts/common/fs/smbsrv/smb2_negotiate.c	2020-04-15 01:43:37.348454016 +0000
+++ new/usr/src/uts/common/fs/smbsrv/smb2_negotiate.c	2020-04-15 01:43:37.353469573 +0000
@@ -11,7 +11,7 @@
 
 /*
  * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
- * Copyright 2019 RackTop Systems.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 /*
@@ -20,6 +20,7 @@
 
 #include <smbsrv/smb2_kproto.h>
 #include <smbsrv/smb2.h>
+#include <sys/random.h>
 
 /*
  * Note from [MS-SMB2] Sec. 2.2.3:  Windows servers return
@@ -85,6 +86,7 @@
 	0x210,	/* SMB 2.1 */
 	0x300,	/* SMB 3.0 */
 	0x302,	/* SMB 3.02 */
+	0x311,	/* SMB 3.11 */
 };
 static uint16_t smb2_nversions =
     sizeof (smb2_versions) / sizeof (smb2_versions[0]);
@@ -210,6 +212,275 @@
  * Return value is 0 for success, and anything else will
  * terminate the reader thread (drop the connection).
  */
+typedef struct smb31_preauth_integrity_caps_ctx {
+	uint16_t	hash_count;
+	uint16_t	salt_len;
+	char		*salt;
+} smb31_preauth_integrity_caps_ctx_t;
+
+typedef struct smb31_encryption_caps_ctx {
+	uint16_t	cipher_count;
+} smb31_encrypt_caps_ctx_t;
+
+enum smb3_neg_ctx_type {
+	SMB31_PREAUTH_INTEGRITY_CAPS = 1,
+	SMB31_ENCRYPTION_CAPS = 2
+};
+
+typedef struct smb3_negotiate_context {
+	uint16_t	type;
+	uint16_t	datalen;
+	uint32_t	_resrvd;
+	char		data[];
+} smb3_neg_ctx_t;
+
+typedef struct smb3_negotiate_context_info {
+	uint32_t	offset;
+	uint16_t	count;
+	uint16_t	_resrvd;
+} smb3_neg_ctx_info_t;
+
+#define	NEG_CTX_INFO_OFFSET	(SMB2_HDR_SIZE + 28)
+#define	STATUS_SMB_NO_PREAUTH_INEGRITY_HASH_OVERLAP	(0xC05D0000)
+
+#define	STATUS_PREAUTH_HASH_OVERLAP \
+    STATUS_SMB_NO_PREAUTH_INEGRITY_HASH_OVERLAP
+
+/*
+ * This function should be called only for dialect >= 0x311
+ * Negotiate context list should contain exactly one
+ * smb31_preauth_INTEGRITY_CAPS context.
+ * Otherwise STATUS_INVALID_PARAMETER.
+ * It should contain at least 1 hash algorith what server does support.
+ * Otehrwise STATUS_SMB_NO_PREAUTH_INEGRITY_HASH_OVERLAP.
+ */
+static uint32_t
+smb31_decode_neg_ctxs(smb_request_t *sr, smb_session_t *s)
+{
+	uint32_t status = 0;
+	int found_preauth_ctx = 0;
+	boolean_t preauth_sha512_enabled = B_FALSE;
+	boolean_t encrypt_ccm_enabled = B_FALSE;
+	boolean_t encrypt_gcm_enabled = B_FALSE;
+	uint16_t cipher = sr->sr_server->sv_cfg.skc_encrypt_cipher;
+	smb3_neg_ctx_info_t	neg_ctx_info;
+	int cnt, i;
+	int rc;
+
+	sr->command.chain_offset = NEG_CTX_INFO_OFFSET;
+
+	rc = smb_mbc_decodef(&sr->command, "lw2.",
+	    &neg_ctx_info.offset,	/* l */
+	    &neg_ctx_info.count);	/* w */
+	if (rc != 0) {
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto errout;
+	}
+
+	/*
+	 * There should be exactly 1 SMB31_PREAUTH_INTEGRITY_CAPS negotiate ctx.
+	 * SMB31_ENCRYPTION_CAPS is optional one.
+	 */
+	cnt = neg_ctx_info.count;
+	if (cnt < 1) {
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto errout;
+	}
+
+	sr->command.chain_offset = neg_ctx_info.offset;
+
+	/*
+	 * Parse negotiate contexts.
+	 */
+	for (i = 0; i < cnt; i++) {
+		smb3_neg_ctx_t neg_ctx;
+
+		sr->command.chain_offset =
+		    P2ROUNDUP(sr->command.chain_offset, 8);
+
+		rc = smb_mbc_decodef(
+		    &sr->command, "ww4.",
+		    &neg_ctx.type,	/* w */
+		    &neg_ctx.datalen);	/* w */
+		if (rc != 0) {
+			status = NT_STATUS_INVALID_PARAMETER;
+			goto errout;
+		}
+
+		if (neg_ctx.type == SMB31_PREAUTH_INTEGRITY_CAPS) {
+			smb31_preauth_integrity_caps_ctx_t pic_ctx;
+
+			if (found_preauth_ctx++ != 0) {
+				status = NT_STATUS_INVALID_PARAMETER;
+				goto errout;
+			}
+
+			rc = smb_mbc_decodef(
+			    &sr->command, "ww",
+			    &pic_ctx.hash_count,	/* w */
+			    &pic_ctx.salt_len);		/* w */
+			if (rc != 0) {
+				status = NT_STATUS_INVALID_PARAMETER;
+				goto errout;
+			}
+
+			/*
+			 * In SMB 0x311 there should be exactly 1 preauth
+			 * negotiate context, and there should be exactly 1
+			 * hash value in the list - SHA512.
+			 */
+			if (pic_ctx.hash_count != 1) {
+				status = NT_STATUS_INVALID_PARAMETER;
+				goto errout;
+			}
+
+			for (int k = 0; k < pic_ctx.hash_count; k++) {
+				uint16_t hash_id;
+
+				rc = smb_mbc_decodef(
+				    &sr->command, "w",
+				    &hash_id);	  /* w */
+
+				switch (hash_id) {
+				case SMB3_HASH_SHA512:
+					preauth_sha512_enabled = B_TRUE;
+					break;
+				default:
+					;
+				}
+			}
+
+			rc = smb_mbc_decodef(
+			    &sr->command, "#.",
+			    pic_ctx.salt_len);
+
+		} else if (neg_ctx.type == SMB31_ENCRYPTION_CAPS) {
+			smb31_encrypt_caps_ctx_t enc_ctx;
+
+			rc = smb_mbc_decodef(
+			    &sr->command, "w",
+			    &enc_ctx.cipher_count);	/* w */
+			if (rc != 0) {
+				status = NT_STATUS_INVALID_PARAMETER;
+				goto errout;
+			}
+
+			for (int k = 0; k < enc_ctx.cipher_count; k++) {
+				uint16_t cipher_id;
+
+				rc = smb_mbc_decodef(
+				    &sr->command, "w",
+				    &cipher_id);	/* w */
+
+				switch (cipher_id) {
+				case SMB3_CIPHER_AES128_CCM:
+					encrypt_ccm_enabled = B_TRUE;
+					break;
+				case SMB3_CIPHER_AES128_GCM:
+					encrypt_gcm_enabled = B_TRUE;
+					break;
+				default:
+					;
+				}
+			}
+		} else {
+			/* Skip unsupported context */
+			ASSERT0(smb_mbc_decodef(
+			    &sr->command, "#.",
+			    neg_ctx.datalen));
+		}
+	}
+
+	/* Not found mandatory SMB31_PREAUTH_INTEGRITY_CAPS ctx */
+	if (!found_preauth_ctx)
+		status = NT_STATUS_INVALID_PARAMETER;
+
+	if (!preauth_sha512_enabled) {
+		status = STATUS_PREAUTH_HASH_OVERLAP;
+		goto errout;
+	}
+
+	s->smb31_preauth_hashid = SMB3_HASH_SHA512;
+
+	switch (cipher) {
+	case SMB3_CIPHER_AES128_GCM:
+		if (encrypt_gcm_enabled) {
+			s->smb31_enc_cipherid = cipher;
+			break;
+		}
+		/* FALLTHROUGH */
+	case SMB3_CIPHER_AES128_CCM:
+		if (encrypt_ccm_enabled) {
+			s->smb31_enc_cipherid = cipher;
+			break;
+		}
+		/* FALLTHROUGH */
+	default:
+		s->smb31_enc_cipherid = 0;
+	}
+
+errout:
+	return (status);
+}
+
+#define	SMB31_PREAUTH_CTX_SALT_LEN	32
+
+static int
+smb31_encode_neg_ctxs(smb_request_t *sr, smb_session_t *s)
+{
+	uint8_t salt[SMB31_PREAUTH_CTX_SALT_LEN];
+	uint16_t salt_len = SMB31_PREAUTH_CTX_SALT_LEN;
+	uint32_t preauth_ctx_len = 6 + salt_len;
+	uint32_t enc_ctx_len = 4;
+	uint32_t neg_ctx_off = SMB2_HDR_SIZE + 64 +
+	    P2ROUNDUP(sr->sr_cfg->skc_negtok_len, 8);
+	uint32_t rc;
+
+	sr->reply.chain_offset = P2ROUNDUP(sr->reply.chain_offset, 8);
+
+	ASSERT3S(neg_ctx_off, ==, sr->reply.chain_offset);
+
+	(void) random_get_pseudo_bytes(salt, sizeof (salt));
+
+	rc = smb_mbc_encodef(
+	    &sr->reply, "ww4.",
+	    SMB31_PREAUTH_INTEGRITY_CAPS,
+	    preauth_ctx_len
+	    /* 4. */); /* reserverd */
+
+	ASSERT0(rc);
+	rc = smb_mbc_encodef(
+	    &sr->reply, "www#c",
+	    1,				/* hash algo count */
+	    salt_len,			/* salt length */
+	    s->smb31_preauth_hashid,	/* hash id */
+	    salt_len,			/* salt length */
+	    salt);
+
+	/* aligned on 8-bytes boundary */
+	if (rc != 0 || s->smb31_enc_cipherid == 0) {
+		cmn_err(CE_NOTE, "Encryption is not supported");
+		return (rc);
+	}
+
+	if (sr->reply.chain_offset % 8 != 0) {
+		sr->reply.chain_offset = P2ROUNDUP(sr->reply.chain_offset, 8);
+	}
+
+	rc = smb_mbc_encodef(
+	    &sr->reply, "ww4.",
+	    SMB31_ENCRYPTION_CAPS,
+	    enc_ctx_len
+	    /* 4. */); /* reserverd */
+
+	rc = smb_mbc_encodef(
+	    &sr->reply, "ww",
+	    1,				/* cipher count */
+	    s->smb31_enc_cipherid);	/* encrypt. cipher id */
+
+	return (rc);
+}
+
 int
 smb2_newrq_negotiate(smb_request_t *sr)
 {
@@ -263,8 +534,8 @@
 	    version_cnt <= SMB2_NEGOTIATE_MAX_DIALECTS &&
 	    smb_mbc_decodef(&sr->command, "#w", version_cnt,
 	    cl_versions) != 0) {
-	    /* decode error; force an error below */
-	    version_cnt = 0;
+		/* decode error; force an error below */
+		version_cnt = 0;
 	}
 
 	DTRACE_SMB2_START(op__Negotiate, smb_request_t *, sr);
@@ -309,6 +580,11 @@
 		status = NT_STATUS_NOT_SUPPORTED;
 		goto errout;
 	}
+	if (best_version >= 0x311) {
+		if ((status = smb31_decode_neg_ctxs(sr, s)) != 0)
+			goto errout;
+	}
+
 	s->dialect = best_version;
 
 	/* Allow normal SMB2 requests now. */
@@ -326,6 +602,12 @@
 		smb2sr_put_error(sr, sr->smb2_status);
 	(void) smb2_encode_header(sr, B_TRUE);
 
+	if (s->dialect >= SMB_VERS_3_11) {
+		ASSERT3U(s->smb31_preauth_hashid, !=, 0);
+		(void) smb31_preauth_sha512_calc(sr, &sr->reply,
+		    s->smb31_preauth_hashval);
+	}
+
 	smb2_send_reply(sr);
 
 	return (rc);
@@ -347,6 +629,8 @@
 	int rc;
 	uint32_t max_rwsize;
 	uint16_t secmode;
+	uint16_t neg_ctx_cnt = 0;
+	uint32_t neg_ctx_off = 0;
 
 	/*
 	 * Negotiation itself.  First the Security Mode.
@@ -379,6 +663,8 @@
 	 */
 	if (version != 0x2FF)
 		smb2_sign_init_mech(s);
+	if (version >= 0x311)
+		smb31_preauth_init_mech(s);
 
 	/*
 	 * [MS-SMB2] 3.3.5.4 Receiving an SMB2 NEGOTIATE Request
@@ -404,6 +690,17 @@
 		if ((s->srv_cap & SMB2_CAP_ENCRYPTION) != 0 &&
 		    smb3_encrypt_init_mech(s) != 0) {
 			s->srv_cap &= ~SMB2_CAP_ENCRYPTION;
+			s->smb31_enc_cipherid = 0;
+		}
+
+		if (s->dialect >= SMB_VERS_3_11) {
+			neg_ctx_cnt = s->smb31_enc_cipherid == 0 ? 1 : 2;
+			neg_ctx_off = SMB2_HDR_SIZE + 64 +
+			    P2ROUNDUP(sr->sr_cfg->skc_negtok_len, 8);
+
+			ASSERT3U(s->smb31_preauth_hashid, !=, 0);
+			(void) smb31_preauth_sha512_calc(sr, &sr->command,
+			    s->smb31_preauth_hashval);
 		}
 	}
 
@@ -421,7 +718,7 @@
 	    65,	/* StructSize */	/* w */
 	    s->srv_secmode,		/* w */
 	    version,			/* w */
-	    0, /* reserved */		/* w */
+	    neg_ctx_cnt,		/* w */
 	    UUID_LEN,			/* # */
 	    &s->s_cfg.skc_machine_uuid, /* c */
 	    s->srv_cap,			/* l */
@@ -432,10 +729,16 @@
 	    &boot_tv,			/* T */
 	    128, /* SecBufOff */	/* w */
 	    sr->sr_cfg->skc_negtok_len,	/* w */
-	    0,	/* reserved */		/* l */
+	    neg_ctx_off,		/* l */
 	    sr->sr_cfg->skc_negtok_len,	/* # */
 	    sr->sr_cfg->skc_negtok);	/* c */
 
+
+
+	if (neg_ctx_cnt) {
+		rc = smb31_encode_neg_ctxs(sr, s);
+	}
+
 	/* smb2_send_reply(sr); in caller */
 
 	(void) ksocket_setsockopt(s->sock, SOL_SOCKET,
--- old/usr/src/uts/common/fs/smbsrv/smb2_session_setup.c	2020-04-15 01:43:37.505217095 +0000
+++ new/usr/src/uts/common/fs/smbsrv/smb2_session_setup.c	2020-04-15 01:43:37.510540723 +0000
@@ -11,6 +11,7 @@
 
 /*
  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 /*
@@ -30,6 +31,7 @@
 smb2_session_setup(smb_request_t *sr)
 {
 	smb_arg_sessionsetup_t	*sinfo;
+	smb_session_t *s = sr->session;
 	uint16_t StructureSize;
 	uint8_t  Flags;
 	uint8_t  SecurityMode;
@@ -80,6 +82,12 @@
 	if (rc)
 		return (SDRC_ERROR);
 
+	if (s->dialect >= SMB_VERS_3_11) {
+		ASSERT3U(s->smb31_preauth_hashid, !=, 0);
+		(void) smb31_preauth_sha512_calc(sr, &sr->command,
+		    s->smb31_preauth_hashval);
+	}
+
 	/*
 	 * Decoded everything.  Dtrace probe,
 	 * then no more early returns.
--- old/usr/src/uts/common/fs/smbsrv/smb2_signing.c	2020-04-15 01:43:37.651612998 +0000
+++ new/usr/src/uts/common/fs/smbsrv/smb2_signing.c	2020-04-15 01:43:37.656416789 +0000
@@ -21,6 +21,7 @@
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 /*
  * These routines provide the SMB MAC signing for the SMB2 server.
@@ -118,16 +119,6 @@
 	return (rv);
 }
 
-/*
- * Input to KDF for SigningKey.
- * See comment for smb3_do_kdf for content.
- */
-static uint8_t sign_kdf_input[29] = {
-	0, 0, 0, 1, 'S', 'M', 'B', '2',
-	'A', 'E', 'S', 'C', 'M', 'A', 'C', 0,
-	0, 'S', 'm', 'b', 'S', 'i', 'g', 'n',
-	0, 0, 0, 0, 0x80 };
-
 void
 smb2_sign_init_mech(smb_session_t *s)
 {
@@ -196,10 +187,21 @@
 		 * For SMB3, the signing key is a "KDF" hash of the
 		 * session key.
 		 */
-		if (smb3_do_kdf(sign_key->key, sign_kdf_input,
-		    sizeof (sign_kdf_input), token->tkn_ssnkey.val,
-		    token->tkn_ssnkey.len) != 0)
-			return;
+		if (s->dialect >= SMB_VERS_3_11) {
+			if (smb3_kdf(sign_key->key,
+			    token->tkn_ssnkey.val, token->tkn_ssnkey.len,
+			    (uint8_t *)"SMBSigningKey", 14,
+			    s->smb31_preauth_hashval, SHA512_DIGEST_LENGTH)
+			    != 0)
+				return;
+		} else {
+			if (smb3_kdf(sign_key->key,
+			    token->tkn_ssnkey.val, token->tkn_ssnkey.len,
+			    (uint8_t *)"SMB2AESCMAC", 12,
+			    (uint8_t *)"SmbSign", 8)
+			    != 0)
+				return;
+		}
 		sign_key->len = SMB3_KEYLEN;
 	} else {
 		/*
@@ -430,63 +432,3 @@
 	(void) smb_mbc_poke(&sr->reply, hdr_off, "#c",
 	    SMB2_SIG_SIZE, reply_sig);
 }
-
-/*
- * Derive SMB3 key as described in [MS-SMB2] 3.1.4.2
- * and [NIST SP800-108]
- *
- * r = 32, L = 128, PRF = HMAC-SHA256, key = (session key)
- *
- * Note that these describe pre-3.1.1 inputs.
- *
- * Session.SigningKey for binding a session:
- * - Session.SessionKey as K1
- * - label = SMB2AESCMAC (size 12)
- * - context = SmbSign (size 8)
- * Channel.SigningKey for for all other requests
- * - if SMB2_SESSION_FLAG_BINDING, GSS key (in Session.SessionKey?) as K1;
- * - otherwise, Session.SessionKey as K1
- * - label = SMB2AESCMAC (size 12)
- * - context = SmbSign (size 8)
- * Session.ApplicationKey for ... (not sure what yet)
- * - Session.SessionKey as K1
- * - label = SMB2APP (size 8)
- * - context = SmbRpc (size 7)
- * Session.EncryptionKey for encrypting server messages
- * - Session.SessionKey as K1
- * - label = "SMB2AESCCM" (size 11)
- * - context = "ServerOut" (size 10)
- * Session.DecryptionKey for decrypting client requests
- * - Session.SessionKey as K1
- * - label = "SMB2AESCCM" (size 11)
- * - context = "ServerIn " (size 10) (Note the space)
- */
-
-int
-smb3_do_kdf(void *outbuf, void *input, size_t input_len,
-    uint8_t *key, uint32_t key_len)
-{
-	uint8_t digest32[SHA256_DIGEST_LENGTH];
-	smb_crypto_mech_t mech;
-	smb_sign_ctx_t hctx = 0;
-	int rc;
-
-	bzero(&mech, sizeof (mech));
-	if ((rc = smb2_hmac_getmech(&mech)) != 0)
-		return (rc);
-
-	/* Limit the SessionKey input to its maximum size (16 bytes) */
-	rc = smb2_hmac_init(&hctx, &mech, key, MIN(key_len, SMB2_KEYLEN));
-	if (rc != 0)
-		return (rc);
-
-	if ((rc = smb2_hmac_update(hctx, input, input_len)) != 0)
-		return (rc);
-
-	if ((rc = smb2_hmac_final(hctx, digest32)) != 0)
-		return (rc);
-
-	/* Output is first 16 bytes of digest. */
-	bcopy(digest32, outbuf, SMB3_KEYLEN);
-	return (0);
-}
--- /dev/null	2020-04-15 01:43:37.000000000 +0000
+++ new/usr/src/uts/common/fs/smbsrv/smb31_preauth.c	2020-04-15 01:43:37.806839164 +0000
@@ -0,0 +1,169 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2020 RackTop Systems, Inc.
+ */
+
+#include <smbsrv/smb2_kproto.h>
+#include <smbsrv/smb2.h>
+#include <sys/crypto/api.h>
+#include <smbsrv/smb_kproto.h>
+#include <smbsrv/smb_kcrypt.h>
+
+/*
+ * SMB 3.1.1 Preauth Integrity
+ */
+int
+smb3_sha512_getmech(smb_crypto_mech_t *mech)
+{
+	crypto_mech_type_t t;
+
+	t = crypto_mech2id(SUN_CKM_SHA512);
+	if (t == CRYPTO_MECH_INVALID) {
+		cmn_err(CE_NOTE, "smb: no kcf mech: %s", SUN_CKM_SHA512);
+		return (-1);
+	}
+	mech->cm_type = t;
+	return (0);
+}
+
+/*
+ * (called from smb2_negotiate_common)
+ */
+void
+smb31_preauth_init_mech(smb_session_t *s)
+{
+	smb_crypto_mech_t *mech;
+	int rc;
+
+	ASSERT3S(s->dialect, >=, SMB_VERS_3_11);
+
+	if (s->preauth_mech != NULL)
+		return;
+
+	mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
+	rc = smb3_sha512_getmech(mech);
+	if (rc != 0) {
+		kmem_free(mech, sizeof (*mech));
+		return;
+	}
+	s->preauth_mech = mech;
+}
+
+void
+smb31_preauth_fini(smb_session_t *s)
+{
+	smb_crypto_mech_t *mech;
+
+	if ((mech = s->preauth_mech) != NULL) {
+		kmem_free(mech, sizeof (*mech));
+		s->preauth_mech = NULL;
+	}
+}
+
+/*
+ * Start the KCF session, load the key
+ */
+int
+smb_sha512_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech)
+{
+	int rv;
+
+	rv = crypto_digest_init(mech, ctxp, NULL);
+
+	return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb_sha512_update(smb_sign_ctx_t ctx, void *buf, size_t len)
+{
+	crypto_data_t data;
+	int rv;
+
+	bzero(&data, sizeof (data));
+	data.cd_format = CRYPTO_DATA_RAW;
+	data.cd_length = len;
+	data.cd_raw.iov_base = buf;
+	data.cd_raw.iov_len = len;
+
+	rv = crypto_digest_update(ctx, &data, 0);
+
+	if (rv != CRYPTO_SUCCESS) {
+		crypto_cancel_ctx(ctx);
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * Get the final digest.
+ */
+int
+smb_sha512_final(smb_sign_ctx_t ctx, uint8_t *digest)
+{
+	crypto_data_t out;
+	int rv;
+
+	bzero(&out, sizeof (out));
+	out.cd_format = CRYPTO_DATA_RAW;
+	out.cd_length = SHA512_DIGEST_LENGTH;
+	out.cd_raw.iov_len = SHA512_DIGEST_LENGTH;
+	out.cd_raw.iov_base = (void *)digest;
+
+	rv = crypto_digest_final(ctx, &out, 0);
+
+	return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+int
+smb31_preauth_sha512_calc(smb_request_t *sr, struct mbuf_chain *mbc,
+    uint8_t *hashval)
+{
+	smb_session_t *s = sr->session;
+	smb_sign_ctx_t ctx = 0;
+	struct mbuf *mbuf = mbc->chain;
+	int rc;
+
+	if (s->preauth_mech == NULL)
+		return (-1);
+
+	if ((rc = smb_sha512_init(&ctx, s->preauth_mech)) != 0)
+		return (rc);
+
+	/* Digest current hashval */
+	rc = smb_sha512_update(ctx, hashval, SHA512_DIGEST_LENGTH);
+	if (rc != 0)
+		return (rc);
+
+	while (mbuf != NULL) {
+		rc = smb_sha512_update(ctx, mbuf->m_data, mbuf->m_len);
+		if (rc != 0)
+			return (rc);
+		mbuf = mbuf->m_next;
+	}
+
+	rc = smb_sha512_final(ctx, hashval);
+	return (rc);
+}
--- old/usr/src/uts/common/fs/smbsrv/smb3_encrypt.c	2020-04-15 01:43:37.867336193 +0000
+++ new/usr/src/uts/common/fs/smbsrv/smb3_encrypt.c	2020-04-15 01:43:37.872234784 +0000
@@ -11,6 +11,7 @@
 
 /*
  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 /*
@@ -24,23 +25,8 @@
 
 #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
@@ -100,8 +86,22 @@
 	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);
@@ -150,15 +150,31 @@
 	 * 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)
-		return;
-
-	if (smb3_do_kdf(dec_key->key, decrypt_kdf_input,
-	    sizeof (decrypt_kdf_input), token->tkn_ssnkey.val,
-	    token->tkn_ssnkey.len) != 0)
-		return;
+	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_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);
 
@@ -184,6 +200,10 @@
 	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) {
@@ -210,8 +230,12 @@
 	 * The transform header, minus the PROTOCOL_ID and the
 	 * SIGNATURE, is authenticated but not encrypted.
 	 */
-	smb3_crypto_init_param(&param, sr->nonce, SMB3_NONCE_SIZE,
-	    tmp_hdr, tlen, sr->msgsize + SMB2_SIG_SIZE);
+	if (gcm)
+		smb3_crypto_init_gcm_param(&param, sr->nonce, nonce_size,
+		    tmp_hdr, tlen);
+	else
+		smb3_crypto_init_ccm_param(&param, sr->nonce, nonce_size,
+		    tmp_hdr, tlen, sr->msgsize + SMB2_SIG_SIZE);
 
 	/*
 	 * Unlike signing, which uses one global mech struct,
@@ -317,13 +341,17 @@
 	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");
@@ -331,7 +359,7 @@
 	}
 
 	(void) smb_mbc_poke(out_mbc, SMB3_NONCE_OFFS, "#c",
-	    SMB3_NONCE_SIZE, sr->nonce);
+	    nonce_size, sr->nonce);
 
 	resid = in_mbc->max_bytes;
 
@@ -339,10 +367,14 @@
 	 * The transform header, minus the PROTOCOL_ID and the
 	 * SIGNATURE, is authenticated but not encrypted.
 	 */
-	smb3_crypto_init_param(&param,
-	    sr->nonce, SMB3_NONCE_SIZE,
-	    buf + SMB3_NONCE_OFFS, SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS,
-	    resid);
+	if (gcm)
+		smb3_crypto_init_gcm_param(&param, sr->nonce, nonce_size,
+		    buf + SMB3_NONCE_OFFS,
+		    SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS);
+	else
+		smb3_crypto_init_ccm_param(&param, sr->nonce, nonce_size,
+		    buf + SMB3_NONCE_OFFS,
+		    SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS, resid);
 
 	/*
 	 * Unlike signing, which uses one global mech struct,
--- old/usr/src/uts/common/fs/smbsrv/smb3_encrypt_kcf.c	2020-04-15 01:43:38.016275107 +0000
+++ new/usr/src/uts/common/fs/smbsrv/smb3_encrypt_kcf.c	2020-04-15 01:43:38.021128061 +0000
@@ -11,6 +11,7 @@
 
 /*
  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 /*
@@ -28,36 +29,63 @@
 #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 */
 }
 
 /*
@@ -199,7 +227,22 @@
 		return (-1);
 	}
 
-	outlen = out.cd_offset - SMB2_SIG_SIZE;
+	/*
+	 * 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);
--- /dev/null	2020-04-15 01:43:38.000000000 +0000
+++ new/usr/src/uts/common/fs/smbsrv/smb3_kdf.c	2020-04-15 01:43:38.162405066 +0000
@@ -0,0 +1,136 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
+ */
+
+#include <smbsrv/smb_kcrypt.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+
+/*
+ * Derive SMB3 key as described in [MS-SMB2] 3.1.4.2
+ * and [NIST SP800-108]
+ *
+ * r = 32, L = 128, PRF = HMAC-SHA256, key = (session key)
+ */
+
+/*
+ * SMB 3.0.2 KDF Input
+ *
+ * Session.SigningKey for binding a session:
+ * - Session.SessionKey as K1
+ * - label = "SMB2AESCMAC" (size 12)
+ * - context = "SmbSign" (size 8)
+ * Channel.SigningKey for for all other requests
+ * - if SMB2_SESSION_FLAG_BINDING, GSS key (in Session.SessionKey?) as K1;
+ * - otherwise, Session.SessionKey as K1
+ * - label = "SMB2AESCMAC" (size 12)
+ * - context = "SmbSign" (size 8)
+ * Session.ApplicationKey for ... (not sure what yet)
+ * - Session.SessionKey as K1
+ * - label = "SMB2APP" (size 8)
+ * - context = "SmbRpc" (size 7)
+ * Session.EncryptionKey for encrypting server messages
+ * - Session.SessionKey as K1
+ * - label = "SMB2AESCCM" (size 11)
+ * - context = "ServerOut" (size 10)
+ * Session.DecryptionKey for decrypting client requests
+ * - Session.SessionKey as K1
+ * - label = "SMB2AESCCM" (size 11)
+ * - context = "ServerIn " (size 10) (Note the space)
+ */
+
+/*
+ * SMB 3.1.1 KDF Input
+ *
+ * Session.SigningKey for binding a session:
+ * - Session.SessionKey as K1
+ * - label = "SMBSigningKey" (size 14)
+ * - context = preauth hashval
+ * Channel.SigningKey for for all other requests
+ * - if SMB2_SESSION_FLAG_BINDING, GSS key (in Session.SessionKey?) as K1;
+ * - otherwise, Session.SessionKey as K1
+ * - label = "SMBSigningKey" (size 14)
+ * - context = preauth hashval
+ * Session.EncryptionKey for encrypting server messages
+ * - Session.SessionKey as K1
+ * - label = "SMBS2CCipherKey" (size 16)
+ * - context = preauth hashval
+ * Session.DecryptionKey for decrypting client requests
+ * - Session.SessionKey as K1
+ * - label = "SMBC2SCipherKey" (size 16)
+ * - context = preauth hashval
+ */
+
+/*
+ * SMB3KDF(Ki, Label, Context)
+ * counter || Lebel || 0x00 || Context || L
+ */
+int
+smb3_kdf(uint8_t *outbuf,
+    uint8_t *key, size_t key_len,
+    uint8_t *label, size_t label_len,
+    uint8_t *context, size_t context_len)
+{
+	static uint8_t L[4] = { 0, 0, 0, 0x80 };
+	uint8_t digest32[SHA256_DIGEST_LENGTH];
+	uint8_t kdfbuf[89] = { 0, 0, 0, 1 }; /* initialized by counter */
+	smb_crypto_mech_t mech;
+	smb_sign_ctx_t hctx = 0;
+	int pos = 4;	/* skip counter */
+	int rc;
+
+	bcopy(label, &kdfbuf[pos], label_len);
+	pos += label_len;
+
+	kdfbuf[pos] = 0;
+	pos++;
+
+	bcopy(context, &kdfbuf[pos], context_len);
+	pos += context_len;
+
+	bcopy(L, &kdfbuf[pos], 4);
+	pos += 4;
+
+	bzero(&mech, sizeof (mech));
+	if ((rc = smb2_hmac_getmech(&mech)) != 0)
+		return (rc);
+
+	/* Limit the SessionKey input to its maximum size (16 bytes) */
+	rc = smb2_hmac_init(&hctx, &mech, key, MIN(key_len, SMB2_KEYLEN));
+	if (rc != 0)
+		return (rc);
+
+	if ((rc = smb2_hmac_update(hctx, kdfbuf, pos)) != 0)
+		return (rc);
+
+	if ((rc = smb2_hmac_final(hctx, digest32)) != 0)
+		return (rc);
+
+	/* Output is first 16 bytes of digest. */
+	bcopy(digest32, outbuf, SMB3_KEYLEN);
+	return (0);
+}
--- old/usr/src/uts/common/fs/smbsrv/smb_server.c	2020-04-15 01:43:38.221575078 +0000
+++ new/usr/src/uts/common/fs/smbsrv/smb_server.c	2020-04-15 01:43:38.226460519 +0000
@@ -22,6 +22,7 @@
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2017 by Delphix. All rights reserved.
  * Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 /*
@@ -2078,6 +2079,7 @@
 	sv->sv_cfg.skc_max_protocol = ioc->max_protocol;
 	sv->sv_cfg.skc_min_protocol = ioc->min_protocol;
 	sv->sv_cfg.skc_encrypt = ioc->encrypt;
+	sv->sv_cfg.skc_encrypt_cipher = ioc->encrypt_cipher;
 	sv->sv_cfg.skc_execflags = ioc->exec_flags;
 	sv->sv_cfg.skc_negtok_len = ioc->negtok_len;
 	sv->sv_cfg.skc_version = ioc->version;
--- old/usr/src/uts/common/fs/smbsrv/smb_session.c	2020-04-15 01:43:38.398912014 +0000
+++ new/usr/src/uts/common/fs/smbsrv/smb_session.c	2020-04-15 01:43:38.403932420 +0000
@@ -21,6 +21,7 @@
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 #include <sys/atomic.h>
@@ -857,6 +858,9 @@
 		    session->signing.mackey_len);
 	}
 
+	if (session->preauth_mech != NULL)
+		smb31_preauth_fini(session);
+
 	session->s_magic = 0;
 
 	smb_rwx_destroy(&session->s_lock);
--- old/usr/src/uts/common/smbsrv/smb2_kproto.h	2020-04-15 01:43:38.573539843 +0000
+++ new/usr/src/uts/common/smbsrv/smb2_kproto.h	2020-04-15 01:43:38.578520292 +0000
@@ -11,6 +11,7 @@
 
 /*
  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 #ifndef _SMB2_KPROTO_H_
@@ -63,6 +64,10 @@
 int smb2_sign_check_request(smb_request_t *);
 void smb2_sign_reply(smb_request_t *);
 void smb2_sign_init_mech(smb_session_t *);
+void smb31_preauth_init_mech(smb_session_t *);
+void smb31_preauth_fini(smb_session_t *s);
+int smb31_preauth_sha512_calc(smb_request_t *, struct mbuf_chain *,
+    uint8_t *);
 
 int smb3_encrypt_sr(smb_request_t *, struct mbuf_chain *, struct mbuf_chain *);
 int smb3_decrypt_sr(smb_request_t *);
--- old/usr/src/uts/common/smbsrv/smb_ioctl.h	2020-04-15 01:43:38.717616563 +0000
+++ new/usr/src/uts/common/smbsrv/smb_ioctl.h	2020-04-15 01:43:38.722610709 +0000
@@ -22,6 +22,7 @@
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  * Copyright 2017 Joyent, Inc.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 #ifndef _SMB_IOCTL_H_
@@ -177,6 +178,7 @@
 	uint32_t	exec_flags;
 	uint32_t	negtok_len;
 	smb_version_t	version;
+	uint16_t	encrypt_cipher;
 	uint16_t	initial_credits;
 	uint16_t	maximum_credits;
 	/* SMB negotiate protocol response. */
--- old/usr/src/uts/common/smbsrv/smb_kcrypt.h	2020-04-15 01:43:38.863082222 +0000
+++ new/usr/src/uts/common/smbsrv/smb_kcrypt.h	2020-04-15 01:43:38.867896603 +0000
@@ -11,6 +11,7 @@
 
 /*
  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 #ifndef _SMB_KCRYPT_H_
@@ -36,6 +37,7 @@
 
 #define	MD5_DIGEST_LENGTH	16	/* MD5 digest length in bytes */
 #define	SHA256_DIGEST_LENGTH	32	/* SHA256 digest length in bytes */
+#define	SHA512_DIGEST_LENGTH	64	/* SHA512 digest length in bytes */
 #define	SMB2_SIG_SIZE		16
 #define	SMB2_KEYLEN		16
 #define	SMB3_KEYLEN		16	/* AES-128 keys */
@@ -49,7 +51,12 @@
 	crypto_data_t output;
 	size_t len;
 } smb3_enc_ctx_t;
-typedef CK_AES_CCM_PARAMS	smb3_crypto_param_t;
+
+typedef union {
+	CK_AES_CCM_PARAMS	ccm;
+	CK_AES_GCM_PARAMS	gcm;
+} smb3_crypto_param_t;
+
 #else	/* _KERNEL */
 /* PKCS11 variant */
 typedef CK_MECHANISM		smb_crypto_mech_t;
@@ -93,11 +100,16 @@
 int smb3_cmac_update(smb_sign_ctx_t, uint8_t *, size_t);
 int smb3_cmac_final(smb_sign_ctx_t, uint8_t *);
 
-int smb3_do_kdf(void *, void *, size_t, uint8_t *, uint32_t);
-
-int smb3_encrypt_getmech(smb_crypto_mech_t *);
-void smb3_crypto_init_param(smb3_crypto_param_t *, uint8_t *, size_t,
+int smb3_kdf(uint8_t *outbuf, uint8_t *key, size_t key_len,
+    uint8_t *label, size_t label_len,
+    uint8_t *context, size_t context_len);
+
+int smb3_aes_ccm_getmech(smb_crypto_mech_t *);
+int smb3_aes_gcm_getmech(smb_crypto_mech_t *);
+void smb3_crypto_init_ccm_param(smb3_crypto_param_t *, uint8_t *, size_t,
     uint8_t *, size_t, size_t);
+void smb3_crypto_init_gcm_param(smb3_crypto_param_t *, uint8_t *, size_t,
+    uint8_t *, size_t);
 
 int smb3_encrypt_init(smb3_enc_ctx_t *, smb_crypto_mech_t *,
     smb3_crypto_param_t *, uint8_t *, size_t, uint8_t *, size_t);
--- old/usr/src/uts/common/smbsrv/smb_ktypes.h	2020-04-15 01:43:39.020557644 +0000
+++ new/usr/src/uts/common/smbsrv/smb_ktypes.h	2020-04-15 01:43:39.026291652 +0000
@@ -21,6 +21,7 @@
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 /*
@@ -888,6 +889,7 @@
     ASSERT(((p) != NULL) && ((p)->s_magic == SMB_SESSION_MAGIC))
 
 #define	SMB_CHALLENGE_SZ	8
+#define	SMB3_PREAUTH_HASHVAL_SZ	64
 
 typedef enum {
 	SMB_SESSION_STATE_INITIALIZED = 0,
@@ -938,6 +940,7 @@
 	struct smb_sign		signing;	/* SMB1 */
 	void			*sign_mech;	/* mechanism info */
 	void			*enc_mech;
+	void			*preauth_mech;
 
 	/* SMB2/SMB3 signing support */
 	int			(*sign_calc)(struct smb_request *,
@@ -976,6 +979,12 @@
 	uint16_t		smb_max_mpx;
 	smb_srqueue_t		*s_srqueue;
 	uint64_t		start_time;
+
+	uint16_t		smb31_enc_cipherid;
+	uint16_t		smb31_preauth_hashid;
+	uint8_t			smb31_preauth_hashval[SMB3_PREAUTH_HASHVAL_SZ];
+	uint8_t			smb31_preauth_salt[32];
+
 	unsigned char		MAC_key[44];
 	char			ip_addr_str[INET6_ADDRSTRLEN];
 	uint8_t			clnt_uuid[16];
--- old/usr/src/uts/common/smbsrv/smbinfo.h	2020-04-15 01:43:39.202815661 +0000
+++ new/usr/src/uts/common/smbsrv/smbinfo.h	2020-04-15 01:43:39.208155365 +0000
@@ -21,6 +21,7 @@
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 #ifndef	_SMBSRV_SMBINFO_H
@@ -157,6 +158,7 @@
 	uint32_t skc_max_protocol;	/* SMB_VERS_... */
 	uint32_t skc_min_protocol;	/* SMB_VERS_... */
 	smb_cfg_val_t skc_encrypt; /* EncryptData and RejectUnencryptedAccess */
+	uint16_t skc_encrypt_cipher;	/* 3.1.1 encryption cipher */
 	uint32_t skc_execflags;
 	uint32_t skc_negtok_len;
 	smb_version_t skc_version;
@@ -231,6 +233,13 @@
 #define	SMB_VERS_2_1		0x210	/* "2.1" */
 #define	SMB_VERS_3_0		0x300	/* "3.0" */
 #define	SMB_VERS_3_02		0x302	/* "3.02" */
+#define	SMB_VERS_3_11		0x311	/* "3.11" */
+
+#define	SMB3_HASH_SHA512	1
+
+#define	SMB3_CIPHER_NONE	0
+#define	SMB3_CIPHER_AES128_CCM	1
+#define	SMB3_CIPHER_AES128_GCM	2
 
 #ifdef __cplusplus
 }
