summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorGordon Ross <gwr@nexenta.com>2019-06-21 19:22:54 -0400
committerGordon Ross <gwr@nexenta.com>2019-11-18 11:07:56 -0500
commit686670eacbe137c7a9e6c85fef8763f8627a27b5 (patch)
tree63dccf1429c09029d41b0a412bf812ec1146f6d0 /usr/src
parent9fe633fd812f2df2354dc88fd3f7f50e94bd8eb3 (diff)
downloadillumos-joyent-686670eacbe137c7a9e6c85fef8763f8627a27b5.tar.gz
11855 Update SMB client to 3.02
Reviewed by: Matt Barden <matt.barden@nexenta.com> Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com> Reviewed by: Andy Fiddaman <andy@omniosce.org> Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/lib/libsmbfs/smb/ctx.c8
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile.c3
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c116
-rw-r--r--usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_sign_pkcs.c10
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c124
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c144
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c32
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h8
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h7
-rw-r--r--usr/src/uts/common/netsmb/smb_dev.h2
10 files changed, 392 insertions, 62 deletions
diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c
index 3aa67fd5f5..64122e3416 100644
--- a/usr/src/lib/libsmbfs/smb/ctx.c
+++ b/usr/src/lib/libsmbfs/smb/ctx.c
@@ -1411,10 +1411,16 @@ smb_cf_minauth_from_str(char *str)
return (-1);
}
-
+/*
+ * SMB 2.1 is the oldest SMB2 dialect implemented (we skipped SMB 2.002)
+ * so if we see a_protocol value of just "2" assume they meant 2.1
+ */
static struct nv
smbver_table[] = {
+ { "3.02", SMB2_DIALECT_0302 },
+ { "3.0", SMB2_DIALECT_0300 },
{ "2.1", SMB2_DIALECT_0210 },
+ { "2", SMB2_DIALECT_0210 },
{ "1", 1 },
{ NULL, 0 }
};
diff --git a/usr/src/lib/libsmbfs/smb/rcfile.c b/usr/src/lib/libsmbfs/smb/rcfile.c
index d7ee2d15af..da96b13c34 100644
--- a/usr/src/lib/libsmbfs/smb/rcfile.c
+++ b/usr/src/lib/libsmbfs/smb/rcfile.c
@@ -492,8 +492,7 @@ rc_parse(struct rcfile *rcp)
if (home_nsmbrc != 0 && (
strcmp(buf, "nbns") == 0 ||
strcmp(buf, "nbns_enable") == 0 ||
- strcmp(buf, "nbns_broadcast") == 0 ||
- strcmp(buf, "signing") == 0)) {
+ strcmp(buf, "nbns_broadcast") == 0)) {
fprintf(stderr, dgettext(TEXT_DOMAIN,
"option %s may not be set "
"in user .nsmbrc file\n"), buf);
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c b/usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
index 24bb8fccbc..44c6666313 100644
--- a/usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
@@ -23,22 +23,46 @@
#include <stdlib.h>
#include <strings.h>
+#include <sys/cmn_err.h>
#include <netsmb/smb_signing.h>
#include <security/cryptoki.h>
#include <security/pkcs11.h>
/*
+ * Common function to see if a mech is available.
+ */
+static int
+find_mech(smb_sign_mech_t *mech, ulong_t mid)
+{
+ CK_SESSION_HANDLE hdl;
+ CK_RV rv;
+
+ rv = SUNW_C_GetMechSession(mid, &hdl);
+ if (rv != CKR_OK) {
+ cmn_err(CE_NOTE, "PKCS#11: no mech 0x%x",
+ (unsigned int)mid);
+ return (-1);
+ }
+ (void) C_CloseSession(hdl);
+
+ mech->mechanism = mid;
+ mech->pParameter = NULL;
+ mech->ulParameterLen = 0;
+ return (0);
+}
+
+/*
* SMB1 signing helpers:
* (getmech, init, update, final)
*/
+/*
+ * Find out if we have this mech.
+ */
int
smb_md5_getmech(smb_sign_mech_t *mech)
{
- mech->mechanism = CKM_MD5;
- mech->pParameter = NULL;
- mech->ulParameterLen = 0;
- return (0);
+ return (find_mech(mech, CKM_MD5));
}
/*
@@ -93,13 +117,13 @@ smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
* (getmech, init, update, final)
*/
+/*
+ * Find out if we have this mech.
+ */
int
smb2_hmac_getmech(smb_sign_mech_t *mech)
{
- mech->mechanism = CKM_SHA256_HMAC;
- mech->pParameter = NULL;
- mech->ulParameterLen = 0;
- return (0);
+ return (find_mech(mech, CKM_SHA256_HMAC));
}
/*
@@ -161,3 +185,79 @@ smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
return (rv == CKR_OK ? 0 : -1);
}
+
+/*
+ * SMB3 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+/*
+ * Find out if we have this mech.
+ */
+int
+smb3_cmac_getmech(smb_sign_mech_t *mech)
+{
+ return (find_mech(mech, CKM_AES_CMAC));
+}
+
+/*
+ * Start PKCS#11 session, load the key.
+ */
+int
+smb3_cmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech,
+ uint8_t *key, size_t key_len)
+{
+ CK_OBJECT_HANDLE hkey = 0;
+ CK_RV rv;
+
+ rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
+ if (rv != CKR_OK)
+ return (-1);
+
+ rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism,
+ key, key_len, &hkey);
+ if (rv != CKR_OK) {
+ (void) C_CloseSession(*ctxp);
+ return (-1);
+ }
+
+ rv = C_SignInit(*ctxp, mech, hkey);
+ (void) C_DestroyObject(*ctxp, hkey);
+ if (rv != CKR_OK) {
+ (void) C_CloseSession(*ctxp);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb3_cmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
+{
+ CK_RV rv;
+
+ rv = C_SignUpdate(ctx, in, len);
+ if (rv != CKR_OK)
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * Note, the SMB2 signature is just the AES CMAC digest.
+ * (both are 16 bytes long)
+ */
+int
+smb3_cmac_final(smb_sign_ctx_t ctx, uint8_t *digest)
+{
+ CK_ULONG len = SMB2_SIG_SIZE;
+ CK_RV rv;
+
+ rv = C_SignFinal(ctx, digest, &len);
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
diff --git a/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_sign_pkcs.c b/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_sign_pkcs.c
index e018c6eb0c..f0eb05093c 100644
--- a/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_sign_pkcs.c
+++ b/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_sign_pkcs.c
@@ -215,13 +215,19 @@ smb3_cmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech,
rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism,
key, key_len, &hkey);
- if (rv != CKR_OK)
+ if (rv != CKR_OK) {
+ (void) C_CloseSession(*ctxp);
return (-1);
+ }
rv = C_SignInit(*ctxp, mech, hkey);
(void) C_DestroyObject(*ctxp, hkey);
+ if (rv != CKR_OK) {
+ (void) C_CloseSession(*ctxp);
+ return (-1);
+ }
- return (rv == CKR_OK ? 0 : -1);
+ return (0);
}
/*
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c b/usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c
index 2be033a8fc..4235c94a06 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c
@@ -29,23 +29,34 @@
#include <netsmb/smb_signing.h>
/*
- * SMB1 signing helpers:
- * (getmech, init, update, final)
+ * Common function to see if a mech is available.
*/
-
-int
-smb_md5_getmech(smb_sign_mech_t *mech)
+static int
+find_mech(smb_sign_mech_t *mech, crypto_mech_name_t name)
{
crypto_mech_type_t t;
- t = crypto_mech2id(SUN_CKM_MD5);
- if (t == CRYPTO_MECH_INVALID)
+ t = crypto_mech2id(name);
+ if (t == CRYPTO_MECH_INVALID) {
+ cmn_err(CE_NOTE, "nsmb: no kcf mech: %s", name);
return (-1);
+ }
mech->cm_type = t;
return (0);
}
/*
+ * SMB1 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb_md5_getmech(smb_sign_mech_t *mech)
+{
+ return (find_mech(mech, SUN_CKM_MD5));
+}
+
+/*
* Start the KCF session, load the key
*/
int
@@ -75,7 +86,12 @@ smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len)
rv = crypto_digest_update(ctx, &data, 0);
- return (rv == CRYPTO_SUCCESS ? 0 : -1);
+ if (rv != CRYPTO_SUCCESS) {
+ crypto_cancel_ctx(ctx);
+ return (-1);
+ }
+
+ return (0);
}
/*
@@ -106,13 +122,7 @@ smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
int
smb2_hmac_getmech(smb_sign_mech_t *mech)
{
- crypto_mech_type_t t;
-
- t = crypto_mech2id(SUN_CKM_SHA256_HMAC);
- if (t == CRYPTO_MECH_INVALID)
- return (-1);
- mech->cm_type = t;
- return (0);
+ return (find_mech(mech, SUN_CKM_SHA256_HMAC));
}
/*
@@ -152,7 +162,12 @@ smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
rv = crypto_mac_update(ctx, &data, 0);
- return (rv == CRYPTO_SUCCESS ? 0 : -1);
+ if (rv != CRYPTO_SUCCESS) {
+ crypto_cancel_ctx(ctx);
+ return (-1);
+ }
+
+ return (0);
}
/*
@@ -178,3 +193,80 @@ smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
return (rv == CRYPTO_SUCCESS ? 0 : -1);
}
+
+/*
+ * SMB3 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb3_cmac_getmech(smb_sign_mech_t *mech)
+{
+ return (find_mech(mech, SUN_CKM_AES_CMAC));
+}
+
+/*
+ * Start the KCF session, load the key
+ */
+int
+smb3_cmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech,
+ uint8_t *key, size_t key_len)
+{
+ crypto_key_t ckey;
+ int rv;
+
+ bzero(&ckey, sizeof (ckey));
+ ckey.ck_format = CRYPTO_KEY_RAW;
+ ckey.ck_data = key;
+ ckey.ck_length = key_len * 8; /* in bits */
+
+ rv = crypto_mac_init(mech, &ckey, NULL, ctxp, NULL);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb3_cmac_update(smb_sign_ctx_t ctx, uint8_t *in, 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 = (void *)in;
+ data.cd_raw.iov_len = len;
+
+ rv = crypto_mac_update(ctx, &data, 0);
+
+ if (rv != CRYPTO_SUCCESS) {
+ crypto_cancel_ctx(ctx);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Note, the SMB2 signature is just the AES CMAC digest.
+ * (both are 16 bytes long)
+ */
+int
+smb3_cmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
+{
+ crypto_data_t out;
+ int rv;
+
+ bzero(&out, sizeof (out));
+ out.cd_format = CRYPTO_DATA_RAW;
+ out.cd_length = SMB2_SIG_SIZE;
+ out.cd_raw.iov_len = SMB2_SIG_SIZE;
+ out.cd_raw.iov_base = (void *)digest16;
+
+ rv = crypto_mac_final(ctx, &out, 0);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c
index 46bf28c370..f7f20bdb5a 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c
@@ -54,10 +54,45 @@
#define SMB2_SIG_OFF 48
#define SMB2_SIG_LEN 16
+typedef struct smb_mac_ops {
+ int (*mac_init)(smb_sign_ctx_t *, smb_sign_mech_t *,
+ uint8_t *, size_t);
+ int (*mac_update)(smb_sign_ctx_t, uint8_t *, size_t);
+ int (*mac_final)(smb_sign_ctx_t, uint8_t *);
+} smb_mac_ops_t;
+
+static smb_mac_ops_t
+smb2_sign_ops = {
+ smb2_hmac_init,
+ smb2_hmac_update,
+ smb2_hmac_final
+};
+
+static struct smb_mac_ops
+smb3_sign_ops = {
+ smb3_cmac_init,
+ smb3_cmac_update,
+ smb3_cmac_final
+};
+
+/*
+ * 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 };
+
+int smb3_do_kdf(void *outbuf, size_t outbuf_len,
+ void *input, size_t input_len,
+ uint8_t *key, uint32_t key_len);
+
/*
* smb2_sign_init
*
- * Get the mechanism info and initilize SMB2 signing.
+ * Get the mechanism info and initilize SMB2 or SMB3 signing.
*/
int
smb2_sign_init(smb_vc_t *vcp)
@@ -68,31 +103,103 @@ smb2_sign_init(smb_vc_t *vcp)
ASSERT(vcp->vc_ssnkey != NULL);
ASSERT(vcp->vc_mackey == NULL);
- rc = smb2_hmac_getmech(&vcp->vc_signmech);
- if (rc != 0) {
- cmn_err(CE_NOTE, "smb2 can't get signing mechanism");
+ if (SMB_DIALECT(vcp) < SMB2_DIALECT_0300)
+ rc = smb2_hmac_getmech(&vcp->vc_signmech);
+ else
+ rc = smb3_cmac_getmech(&vcp->vc_signmech);
+ if (rc != 0)
return (EAUTH);
- }
/*
* Convert the session key to the MAC key.
*
* For SMB2, the signing key is just the first 16 bytes
* of the session key (truncated or padded with zeros).
- * [MS-SMB2] 3.2.5.3.1
- *
- * SMB3 would do KDF here.
+ * For SMB3, the signing key is a "KDF" hash of the
+ * session key. [MS-SMB2] 3.2.5.3.1
*/
vcp->vc_mackeylen = SMB2_SIG_LEN;
vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
- copysize = vcp->vc_ssnkeylen;
- if (copysize > vcp->vc_mackeylen)
- copysize = vcp->vc_mackeylen;
- bcopy(vcp->vc_ssnkey, vcp->vc_mackey, copysize);
+ if (SMB_DIALECT(vcp) < SMB2_DIALECT_0300) {
+ copysize = vcp->vc_ssnkeylen;
+ if (copysize > vcp->vc_mackeylen)
+ copysize = vcp->vc_mackeylen;
+ bcopy(vcp->vc_ssnkey, vcp->vc_mackey, copysize);
+
+ vcp->vc_sign_ops = &smb2_sign_ops;
+ } else {
+ rc = smb3_do_kdf(vcp->vc_mackey, vcp->vc_mackeylen,
+ sign_kdf_input, sizeof (sign_kdf_input),
+ vcp->vc_ssnkey, vcp->vc_ssnkeylen);
+ if (rc != 0)
+ return (EAUTH);
+ vcp->vc_sign_ops = &smb3_sign_ops;
+ }
return (0);
}
+/*
+ * 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, size_t outbuf_len,
+ void *input, size_t input_len,
+ uint8_t *key, uint32_t key_len)
+{
+ uint8_t digest32[SHA256_DIGEST_LENGTH];
+ smb_sign_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) */
+ if (key_len > SMB2_SIG_SIZE)
+ key_len = SMB2_SIG_SIZE;
+ rc = smb2_hmac_init(&hctx, &mech, key, key_len);
+ 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, outbuf_len);
+ return (0);
+}
/*
* Compute MAC signature of packet data, using the stored MAC key.
@@ -109,14 +216,17 @@ smb2_compute_MAC(struct smb_vc *vcp, mblk_t *mp, uchar_t *signature)
{
uint8_t tmp_hdr[SMB2_HDR_SIZE];
smb_sign_ctx_t ctx = 0;
+ smb_mac_ops_t *ops;
mblk_t *m = mp;
int size;
int rc;
if (vcp->vc_mackey == NULL)
return (-1);
+ if ((ops = vcp->vc_sign_ops) == NULL)
+ return (-1);
- rc = smb2_hmac_init(&ctx, &vcp->vc_signmech,
+ rc = ops->mac_init(&ctx, &vcp->vc_signmech,
vcp->vc_mackey, vcp->vc_mackeylen);
if (rc != 0)
return (rc);
@@ -131,7 +241,7 @@ smb2_compute_MAC(struct smb_vc *vcp, mblk_t *mp, uchar_t *signature)
size = SMB2_HDRLEN;
bcopy(m->b_rptr, tmp_hdr, size);
bzero(tmp_hdr + SMB2_SIG_OFF, SMB2_SIG_LEN);
- rc = smb2_hmac_update(ctx, tmp_hdr, size);
+ rc = ops->mac_update(ctx, tmp_hdr, size);
if (rc != 0)
return (rc);
@@ -140,7 +250,7 @@ smb2_compute_MAC(struct smb_vc *vcp, mblk_t *mp, uchar_t *signature)
* the data just after the SMB2 header.
*/
size = MBLKL(m) - SMB2_HDRLEN;
- rc = smb2_hmac_update(ctx, m->b_rptr + SMB2_HDRLEN, size);
+ rc = ops->mac_update(ctx, m->b_rptr + SMB2_HDRLEN, size);
if (rc != 0)
return (rc);
m = m->b_cont;
@@ -149,13 +259,13 @@ smb2_compute_MAC(struct smb_vc *vcp, mblk_t *mp, uchar_t *signature)
while (m != NULL) {
size = MBLKL(m);
if (size > 0) {
- rc = smb2_hmac_update(ctx, m->b_rptr, size);
+ rc = ops->mac_update(ctx, m->b_rptr, size);
if (rc != 0)
return (rc);
}
m = m->b_cont;
}
- rc = smb2_hmac_final(ctx, signature);
+ rc = ops->mac_final(ctx, signature);
return (rc);
}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c
index c3df18faa9..52d8661b7a 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c
@@ -50,9 +50,15 @@
#include <netsmb/smb_rq.h>
#include <netsmb/smb2_rq.h>
-#define NDIALECTS 1
-static const uint16_t smb2_dialects[1] = {
- SMB2_DIALECT_0210
+/*
+ * Supported dialects. Keep sorted by number because of how the
+ * vc_maxver check below may truncate this list.
+ */
+#define NDIALECTS 3
+static const uint16_t smb2_dialects[NDIALECTS] = {
+ SMB2_DIALECT_0210,
+ SMB2_DIALECT_0300,
+ SMB2_DIALECT_0302,
};
/* Optional capabilities we advertise (none yet). */
@@ -113,13 +119,13 @@ smb2_parse_smb1nego_resp(struct smb_rq *rqp)
md_get_uint16le(mdp, &sp->sv2_security_mode);
/* Get Dialect. */
- error = md_get_uint16le(mdp, &sp->sv2_dialect);
+ error = md_get_uint16le(mdp, &sp->sv_proto);
if (error != 0)
return (error);
/* What dialect did we get? */
- if (sp->sv2_dialect != SMB2_DIALECT_02ff) {
- SMBERROR("Unknown dialect 0x%x\n", sp->sv2_dialect);
+ if (sp->sv_proto != SMB2_DIALECT_02ff) {
+ SMBERROR("Unknown dialect 0x%x\n", sp->sv_proto);
return (EINVAL);
}
/* Set our (internal) SMB1 dialect also. */
@@ -148,6 +154,7 @@ smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
struct smb_rq *rqp = NULL;
struct mbchain *mbp = NULL;
struct mdchain *mdp = NULL;
+ uint16_t *ndialects_p;
uint16_t ndialects = NDIALECTS;
boolean_t will_sign = B_FALSE;
uint16_t length = 0;
@@ -174,15 +181,18 @@ smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
*/
smb_rq_getrequest(rqp, &mbp);
mb_put_uint16le(mbp, 36); /* Struct Size */
- mb_put_uint16le(mbp, ndialects); /* Dialect Count */
+ ndialects_p = mb_reserve(mbp, 2); /* Dialect Count */
mb_put_uint16le(mbp, security_mode);
mb_put_uint16le(mbp, 0); /* Reserved */
mb_put_uint32le(mbp, smb2_clnt_caps);
mb_put_mem(mbp, vcp->vc_cl_guid, 16, MB_MSYSTEM);
mb_put_uint64le(mbp, 0); /* Start Time */
for (i = 0; i < ndialects; i++) { /* Dialects */
+ if (smb2_dialects[i] > vcp->vc_maxver)
+ break;
mb_put_uint16le(mbp, smb2_dialects[i]);
}
+ *ndialects_p = htoles(i);
/*
* Do the OTW call.
@@ -209,7 +219,7 @@ smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
}
md_get_uint16le(mdp, &sp->sv2_security_mode);
- md_get_uint16le(mdp, &sp->sv2_dialect);
+ md_get_uint16le(mdp, &sp->sv_proto); /* dialect */
md_get_uint16le(mdp, NULL); /* reserved */
md_get_mem(mdp, sp->sv2_guid, 16, MB_MSYSTEM);
md_get_uint32le(mdp, &sp->sv2_capabilities);
@@ -254,7 +264,7 @@ smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
}
wk->wk_u_auth_rlen = sec_buf_len;
err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
- sec_buf_len, MB_MUSER);
+ sec_buf_len, MB_MUSER);
if (err) {
goto errout;
}
@@ -472,7 +482,7 @@ smb2_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
}
wk->wk_u_auth_rlen = sec_buf_len;
err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
- sec_buf_len, MB_MUSER);
+ sec_buf_len, MB_MUSER);
if (err != 0) {
ret = err;
goto out;
@@ -813,7 +823,7 @@ smb2_smb_ntcreate(
mb_put_uint16le(mbp, StructSize);
mb_put_uint8(mbp, 0); /* Security flags */
mb_put_uint8(mbp, SMB2_OPLOCK_LEVEL_NONE); /* Oplock level */
- mb_put_uint32le(mbp, impersonate); /* Impersonation Level */
+ mb_put_uint32le(mbp, impersonate); /* Impersonation Level */
mb_put_uint64le(mbp, cr_flags);
mb_put_uint64le(mbp, 0); /* Reserved */
mb_put_uint32le(mbp, req_acc);
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
index d0a8a1dca0..b88e32d781 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
@@ -70,7 +70,7 @@ typedef struct smb_cred {
#define SMBV_EXT_SEC 0x0080 /* conn to use extended security */
#define SMBV_SIGNING 0x0100 /* negotiated signing */
#define SMBV_SMB2 0x0200 /* VC using SMB 2 or 3 */
-#define SMBV_HAS_FILEIDS 0x0400 /* Use File IDs for hash and inode numbers */
+#define SMBV_HAS_FILEIDS 0x0400 /* Use File IDs for hash and inums */
#define SMBV_NO_WRITE_THRU 0x0800 /* Can't use ... */
/*
@@ -165,7 +165,7 @@ enum smbco_level {
* SMB1 Negotiated protocol parameters
*/
struct smb_sopt {
- int16_t sv_proto; /* protocol dialect */
+ uint16_t sv_proto; /* protocol dialect */
uchar_t sv_sm; /* security mode */
int16_t sv_tz; /* offset in min relative to UTC */
uint16_t sv_maxmux; /* max number of outstanding rq's */
@@ -178,13 +178,12 @@ struct smb_sopt {
/* SMB2+ fields */
uint32_t sv2_sessflags; /* final session setup reply flags */
- uint16_t sv2_dialect; /* dialect (non zero for SMB 2/3 */
uint32_t sv2_capabilities; /* capabilities */
uint32_t sv2_maxtransact; /* max transact size */
uint32_t sv2_maxread; /* max read size */
uint32_t sv2_maxwrite; /* max write size */
- uint8_t sv2_guid[16]; /* GUID */
uint16_t sv2_security_mode; /* security mode */
+ uint8_t sv2_guid[16]; /* GUID */
};
typedef struct smb_sopt smb_sopt_t;
@@ -226,6 +225,7 @@ typedef struct smb_vc {
uint8_t *vc_mackey; /* MAC key buffer */
uint8_t *vc_ssnkey; /* session key buffer */
smb_sign_mech_t vc_signmech;
+ struct smb_mac_ops *vc_sign_ops;
struct smb_tran_desc *vc_tdesc; /* transport ops. vector */
void *vc_tdata; /* transport control block */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h
index e1799e3383..81217d5182 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h
@@ -48,6 +48,8 @@ typedef CK_MECHANISM smb_sign_mech_t;
typedef CK_SESSION_HANDLE smb_sign_ctx_t;
#endif /* _KERNEL */
+struct smb_mac_ops;
+
/*
* SMB signing routines used in smb_signing.c
*/
@@ -66,6 +68,11 @@ int smb2_hmac_init(smb_sign_ctx_t *, smb_sign_mech_t *, uint8_t *, size_t);
int smb2_hmac_update(smb_sign_ctx_t, uint8_t *, size_t);
int smb2_hmac_final(smb_sign_ctx_t, uint8_t *);
+int smb3_cmac_getmech(smb_sign_mech_t *);
+int smb3_cmac_init(smb_sign_ctx_t *, smb_sign_mech_t *, uint8_t *, size_t);
+int smb3_cmac_update(smb_sign_ctx_t, uint8_t *, size_t);
+int smb3_cmac_final(smb_sign_ctx_t, uint8_t *);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/netsmb/smb_dev.h b/usr/src/uts/common/netsmb/smb_dev.h
index 817d214b3e..ceb22371b7 100644
--- a/usr/src/uts/common/netsmb/smb_dev.h
+++ b/usr/src/uts/common/netsmb/smb_dev.h
@@ -126,7 +126,7 @@
#define SMB2_DIALECT_0302 0x0302
/* Maximum supported dialect (for ssn_maxver) */
-#define SMB2_DIALECT_MAX SMB2_DIALECT_0210
+#define SMB2_DIALECT_MAX SMB2_DIALECT_0302
/*
* Option flags in smbioc_oshare.ioc_opt