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,28 ****
--- 19,29 ----
* 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,46 ****
#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>
--- 36,45 ----
*** 48,77 ****
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_dev.h>
#include <netsmb/smb_rq.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)
{
! crypto_mech_md5.cm_type = crypto_mech2id(SUN_CKM_MD5);
! }
#define SMBSIGLEN 8 /* SMB signature length */
#define SMBSIGOFF 14 /* SMB signature offset */
/*
* Compute HMAC-MD5 of packet data, using the stored MAC key.
--- 47,99 ----
#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
! /*
! * 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)
{
! 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,96 ****
*/
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;
/*
* 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.
--- 103,118 ----
*/
static int
smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
uint32_t seqno, uchar_t *signature)
{
! 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,188 ****
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);
/*
! * Make an aligned copy of the SMB header
! * and fill in the sequence number.
*/
! bcopy(mp->b_rptr, smbhdr.r.raw, SMB_HDRLEN);
smbhdr.s.sig[0] = htolel(seqno);
smbhdr.s.sig[1] = 0;
/*
! * Compute the MAC: MD5(concat(Key, message))
*/
! 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);
- /* 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);
- /* 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);
return (0);
}
/*
--- 129,196 ----
uint32_t sig[2]; /* MAC signature, aligned! */
uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
} s;
} smbhdr;
! 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,
! * fill in the sequence number, and digest.
*/
! 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);
+
/*
! * Digest the rest of the SMB header packet, starting at
! * the data just after the SMB header.
*/
! 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 rest of the SMB message. */
! 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);
/*
* Finally, store the signature.
* (first 8 bytes of the mac)
*/
! if (signature != NULL)
! bcopy(digest, signature, SMBSIGLEN);
return (0);
}
/*
*** 195,211 ****
mblk_t *mp = rqp->sr_rq.mb_top;
uint8_t *sigloc;
int status;
/*
! * Our mblk allocation ensures this,
! * but just in case...
*/
! if (MBLKL(mp) < SMB_HDRLEN) {
! if (!pullupmsg(mp, SMB_HDRLEN))
! return;
! }
sigloc = mp->b_rptr + SMBSIGOFF;
if (vcp->vc_mackey == NULL) {
/*
* Signing is required, but we have no key yet
--- 203,216 ----
mblk_t *mp = rqp->sr_rq.mb_top;
uint8_t *sigloc;
int status;
/*
! * smb_rq_new() ensures this,
! * but just in case..
*/
! 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,229 ****
/*
* 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) {
SMBSDEBUG("Crypto error %d", status);
bzero(sigloc, SMBSIGLEN);
}
}
--- 224,234 ----
/*
* 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 != 0) {
SMBSDEBUG("Crypto error %d", status);
bzero(sigloc, SMBSIGLEN);
}
}
*** 254,275 ****
*/
if (mp == NULL) {
SMBSDEBUG("empty reply\n");
return (0);
}
! if (MBLKL(mp) < SMB_HDRLEN) {
! if (!pullupmsg(mp, SMB_HDRLEN))
! return (0);
! }
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) {
SMBSDEBUG("Crypto error %d", status);
/*
* If we can't compute a MAC, then there's
* no point trying other seqno values.
*/
--- 259,278 ----
*/
if (mp == NULL) {
SMBSDEBUG("empty reply\n");
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 != 0) {
SMBSDEBUG("Crypto error %d", status);
/*
* If we can't compute a MAC, then there's
* no point trying other seqno values.
*/