Print this page
NEX-19225 SMB client 2.1 hits redzone panic
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)
        
@@ -19,10 +19,11 @@
  * CDDL HEADER END
  */
 
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
  * Support for SMB "signing" (message integrity)
  */
@@ -35,12 +36,10 @@
 #include <sys/socket.h>
 #include <sys/md4.h>
 #include <sys/md5.h>
 #include <sys/des.h>
 #include <sys/kmem.h>
-#include <sys/crypto/api.h>
-#include <sys/crypto/common.h>
 #include <sys/cmn_err.h>
 #include <sys/stream.h>
 #include <sys/strsun.h>
 #include <sys/sdt.h>
 
@@ -48,30 +47,53 @@
 #include <netsmb/smb.h>
 #include <netsmb/smb_conn.h>
 #include <netsmb/smb_subr.h>
 #include <netsmb/smb_dev.h>
 #include <netsmb/smb_rq.h>
+#include <netsmb/smb_signing.h>
 
 #ifdef DEBUG
 /*
  * Set this to a small number to debug sequence numbers
  * that seem to get out of step.
  */
 int nsmb_signing_fudge = 0;
 #endif
 
-/* Mechanism definitions */
-static  crypto_mechanism_t crypto_mech_md5 = { CRYPTO_MECH_INVALID };
-
-void
-smb_crypto_mech_init(void)
+/*
+ * This is called just after session setup completes,
+ * at the top of smb_iod_vc_work().  Initialize signing.
+ */
+int
+smb_sign_init(smb_vc_t *vcp)
 {
-        crypto_mech_md5.cm_type = crypto_mech2id(SUN_CKM_MD5);
-}
+        int rc;
 
+        ASSERT(vcp->vc_ssnkey != NULL);
+        ASSERT(vcp->vc_mackey == NULL);
 
+        rc = smb_md5_getmech(&vcp->vc_signmech);
+        if (rc != 0) {
+                cmn_err(CE_NOTE, "smb can't get signing mechanism");
+                return (EAUTH);
+        }
 
+        /*
+         * Convert the session key to the MAC key.
+         * SMB1 uses the whole session key.
+         */
+        vcp->vc_mackeylen = vcp->vc_ssnkeylen;
+        vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
+        bcopy(vcp->vc_ssnkey, vcp->vc_mackey, vcp->vc_mackeylen);
+
+        /* The initial sequence number is two. */
+        vcp->vc_next_seq = 2;
+
+        return (0);
+}
+
+
 #define SMBSIGLEN       8       /* SMB signature length */
 #define SMBSIGOFF       14      /* SMB signature offset */
 
 /*
  * Compute HMAC-MD5 of packet data, using the stored MAC key.
@@ -81,16 +103,16 @@
  */
 static int
 smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
         uint32_t seqno, uchar_t *signature)
 {
-        crypto_context_t crypto_ctx;
-        crypto_data_t key;
-        crypto_data_t data;
-        crypto_data_t digest;
-        uchar_t mac[16];
-        int status;
+        uchar_t digest[MD5_DIGEST_LENGTH];
+        smb_sign_ctx_t ctx = 0;
+        mblk_t *m = mp;
+        int size;
+        int rc;
+
         /*
          * This union is a little bit of trickery to:
          * (1) get the sequence number int aligned, and
          * (2) reduce the number of digest calls, at the
          * cost of a copying 32 bytes instead of 8.
@@ -107,82 +129,68 @@
                         uint32_t sig[2]; /* MAC signature, aligned! */
                         uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
                 } s;
         } smbhdr;
 
-        ASSERT(mp != NULL);
-        ASSERT(MBLKL(mp) >= SMB_HDRLEN);
-        ASSERT(vcp->vc_mackey != NULL);
+        if (vcp->vc_mackey == NULL)
+                return (-1);
 
+        if ((rc = smb_md5_init(&ctx, &vcp->vc_signmech)) != 0)
+                return (rc);
+
+        /* Digest the MAC Key */
+        rc = smb_md5_update(ctx, vcp->vc_mackey, vcp->vc_mackeylen);
+        if (rc != 0)
+                return (rc);
+
+        /* Our caller should ensure mp has a contiguous header */
+        ASSERT(m != NULL);
+        ASSERT(MBLKL(m) >= SMB_HDRLEN);
+
         /*
-         * Make an aligned copy of the SMB header
-         * and fill in the sequence number.
+         * Make an aligned copy of the SMB header,
+         * fill in the sequence number, and digest.
          */
-        bcopy(mp->b_rptr, smbhdr.r.raw, SMB_HDRLEN);
+        size = SMB_HDRLEN;
+        bcopy(m->b_rptr, smbhdr.r.raw, size);
         smbhdr.s.sig[0] = htolel(seqno);
         smbhdr.s.sig[1] = 0;
 
+        rc = smb_md5_update(ctx, &smbhdr.r.raw, size);
+        if (rc != 0)
+                return (rc);
+
         /*
-         * Compute the MAC: MD5(concat(Key, message))
+         * Digest the rest of the SMB header packet, starting at
+         * the data just after the SMB header.
          */
-        if (crypto_mech_md5.cm_type == CRYPTO_MECH_INVALID) {
-                SMBSDEBUG("crypto_mech_md5 invalid\n");
-                return (CRYPTO_MECHANISM_INVALID);
-        }
-        status = crypto_digest_init(&crypto_mech_md5, &crypto_ctx, 0);
-        if (status != CRYPTO_SUCCESS)
-                return (status);
+        size = MBLKL(m) - SMB_HDRLEN;
+        rc = smb_md5_update(ctx, m->b_rptr + SMB_HDRLEN, size);
+        if (rc != 0)
+                return (rc);
+        m = m->b_cont;
 
-        /* Digest the MAC Key */
-        key.cd_format = CRYPTO_DATA_RAW;
-        key.cd_offset = 0;
-        key.cd_length = vcp->vc_mackeylen;
-        key.cd_miscdata = 0;
-        key.cd_raw.iov_base = (char *)vcp->vc_mackey;
-        key.cd_raw.iov_len = vcp->vc_mackeylen;
-        status = crypto_digest_update(crypto_ctx, &key, 0);
-        if (status != CRYPTO_SUCCESS)
-                return (status);
-
-        /* Digest the (copied) SMB header */
-        data.cd_format = CRYPTO_DATA_RAW;
-        data.cd_offset = 0;
-        data.cd_length = SMB_HDRLEN;
-        data.cd_miscdata = 0;
-        data.cd_raw.iov_base = (char *)smbhdr.r.raw;
-        data.cd_raw.iov_len = SMB_HDRLEN;
-        status = crypto_digest_update(crypto_ctx, &data, 0);
-        if (status != CRYPTO_SUCCESS)
-                return (status);
-
         /* Digest rest of the SMB message. */
-        data.cd_format = CRYPTO_DATA_MBLK;
-        data.cd_offset = SMB_HDRLEN;
-        data.cd_length = msgdsize(mp) - SMB_HDRLEN;
-        data.cd_miscdata = 0;
-        data.cd_mp = mp;
-        status = crypto_digest_update(crypto_ctx, &data, 0);
-        if (status != CRYPTO_SUCCESS)
-                return (status);
+        while (m != NULL) {
+                size = MBLKL(m);
+                if (size > 0) {
+                        rc = smb_md5_update(ctx, m->b_rptr, size);
+                        if (rc != 0)
+                                return (rc);
+                }
+                m = m->b_cont;
+        }
+        rc = smb_md5_final(ctx, digest);
+        if (rc != 0)
+                return (rc);
 
-        /* Final */
-        digest.cd_format = CRYPTO_DATA_RAW;
-        digest.cd_offset = 0;
-        digest.cd_length = sizeof (mac);
-        digest.cd_miscdata = 0;
-        digest.cd_raw.iov_base = (char *)mac;
-        digest.cd_raw.iov_len = sizeof (mac);
-        status = crypto_digest_final(crypto_ctx, &digest, 0);
-        if (status != CRYPTO_SUCCESS)
-                return (status);
-
         /*
          * Finally, store the signature.
          * (first 8 bytes of the mac)
          */
-        if (signature)
-                bcopy(mac, signature, SMBSIGLEN);
+        if (signature != NULL)
+                bcopy(digest, signature, SMBSIGLEN);
 
         return (0);
 }
 
 /*
@@ -195,17 +203,14 @@
         mblk_t *mp = rqp->sr_rq.mb_top;
         uint8_t *sigloc;
         int status;
 
         /*
-         * Our mblk allocation ensures this,
-         * but just in case...
+         * smb_rq_new() ensures this,
+         * but just in case..
          */
-        if (MBLKL(mp) < SMB_HDRLEN) {
-                if (!pullupmsg(mp, SMB_HDRLEN))
-                        return;
-        }
+        ASSERT(MBLKL(mp) >= SMB_HDRLEN);
         sigloc = mp->b_rptr + SMBSIGOFF;
 
         if (vcp->vc_mackey == NULL) {
                 /*
                  * Signing is required, but we have no key yet
@@ -219,11 +224,11 @@
         /*
          * This will compute the MAC and store it
          * directly into the message at sigloc.
          */
         status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc);
-        if (status != CRYPTO_SUCCESS) {
+        if (status != 0) {
                 SMBSDEBUG("Crypto error %d", status);
                 bzero(sigloc, SMBSIGLEN);
         }
 }
 
@@ -254,22 +259,20 @@
          */
         if (mp == NULL) {
                 SMBSDEBUG("empty reply\n");
                 return (0);
         }
-        if (MBLKL(mp) < SMB_HDRLEN) {
-                if (!pullupmsg(mp, SMB_HDRLEN))
-                        return (0);
-        }
+
+        ASSERT(MBLKL(mp) >= SMB_HDRLEN);
         sigloc = mp->b_rptr + SMBSIGOFF;
 
         /*
          * Compute the expected signature in sigbuf.
          */
         rsn = rqp->sr_rseqno;
         status = smb_compute_MAC(vcp, mp, rsn, sigbuf);
-        if (status != CRYPTO_SUCCESS) {
+        if (status != 0) {
                 SMBSDEBUG("Crypto error %d", status);
                 /*
                  * If we can't compute a MAC, then there's
                  * no point trying other seqno values.
                  */