1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * Support for SMB2 "signing" (message integrity)
  29  */
  30 
  31 #include <sys/param.h>
  32 #include <sys/systm.h>
  33 #include <sys/conf.h>
  34 #include <sys/proc.h>
  35 #include <sys/fcntl.h>
  36 #include <sys/socket.h>
  37 #include <sys/md4.h>
  38 #include <sys/md5.h>
  39 #include <sys/des.h>
  40 #include <sys/kmem.h>
  41 #include <sys/cmn_err.h>
  42 #include <sys/stream.h>
  43 #include <sys/strsun.h>
  44 #include <sys/sdt.h>
  45 
  46 #include <netsmb/smb_osdep.h>
  47 #include <netsmb/smb2.h>
  48 #include <netsmb/smb_conn.h>
  49 #include <netsmb/smb_subr.h>
  50 #include <netsmb/smb_dev.h>
  51 #include <netsmb/smb_rq.h>
  52 #include <netsmb/smb_signing.h>
  53 
  54 #define SMB2_SIG_OFF    48
  55 #define SMB2_SIG_LEN    16
  56 
  57 /*
  58  * smb2_sign_init
  59  *
  60  * Get the mechanism info and initilize SMB2 signing.
  61  */
  62 int
  63 smb2_sign_init(smb_vc_t *vcp)
  64 {
  65         uint_t copysize;
  66         int rc;
  67 
  68         ASSERT(vcp->vc_ssnkey != NULL);
  69         ASSERT(vcp->vc_mackey == NULL);
  70 
  71         rc = smb2_hmac_getmech(&vcp->vc_signmech);
  72         if (rc != 0) {
  73                 cmn_err(CE_NOTE, "smb2 can't get signing mechanism");
  74                 return (EAUTH);
  75         }
  76 
  77         /*
  78          * Convert the session key to the MAC key.
  79          *
  80          * For SMB2, the signing key is just the first 16 bytes
  81          * of the session key (truncated or padded with zeros).
  82          * [MS-SMB2] 3.2.5.3.1
  83          *
  84          * SMB3 would do KDF here.
  85          */
  86         vcp->vc_mackeylen = SMB2_SIG_LEN;
  87         vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
  88         copysize = vcp->vc_ssnkeylen;
  89         if (copysize > vcp->vc_mackeylen)
  90                 copysize = vcp->vc_mackeylen;
  91         bcopy(vcp->vc_ssnkey, vcp->vc_mackey, copysize);
  92 
  93         return (0);
  94 }
  95 
  96 
  97 /*
  98  * Compute MAC signature of packet data, using the stored MAC key.
  99  *
 100  * The signature is in the last 16 bytes of the SMB2 header.
 101  * The signature algorighm is to compute HMAC SHA256 over the
 102  * entire command, with the signature field set to zeros.
 103  *
 104  * See similar code for the server side:
 105  * uts/common/fs/smbsrv/smb2_signing.c : smb2_sign_calc
 106  */
 107 static int
 108 smb2_compute_MAC(struct smb_vc *vcp, mblk_t *mp, uchar_t *signature)
 109 {
 110         uint8_t tmp_hdr[SMB2_HDR_SIZE];
 111         smb_sign_ctx_t ctx = 0;
 112         mblk_t *m = mp;
 113         int size;
 114         int rc;
 115 
 116         if (vcp->vc_mackey == NULL)
 117                 return (-1);
 118 
 119         rc = smb2_hmac_init(&ctx, &vcp->vc_signmech,
 120             vcp->vc_mackey, vcp->vc_mackeylen);
 121         if (rc != 0)
 122                 return (rc);
 123 
 124         /* Our caller should ensure mp has a contiguous header */
 125         ASSERT(m != NULL);
 126         ASSERT(MBLKL(m) >= SMB2_HDRLEN);
 127 
 128         /*
 129          * Copy of the SMB2 header, zero out the signature, and digest.
 130          */
 131         size = SMB2_HDRLEN;
 132         bcopy(m->b_rptr, tmp_hdr, size);
 133         bzero(tmp_hdr + SMB2_SIG_OFF, SMB2_SIG_LEN);
 134         rc = smb2_hmac_update(ctx, tmp_hdr, size);
 135         if (rc != 0)
 136                 return (rc);
 137 
 138         /*
 139          * Digest the rest of the SMB2 header packet, starting at
 140          * the data just after the SMB2 header.
 141          */
 142         size = MBLKL(m) - SMB2_HDRLEN;
 143         rc = smb2_hmac_update(ctx, m->b_rptr + SMB2_HDRLEN, size);
 144         if (rc != 0)
 145                 return (rc);
 146         m = m->b_cont;
 147 
 148         /* Digest rest of the SMB2 message. */
 149         while (m != NULL) {
 150                 size = MBLKL(m);
 151                 if (size > 0) {
 152                         rc = smb2_hmac_update(ctx, m->b_rptr, size);
 153                         if (rc != 0)
 154                                 return (rc);
 155                 }
 156                 m = m->b_cont;
 157         }
 158         rc = smb2_hmac_final(ctx, signature);
 159 
 160         return (rc);
 161 }
 162 
 163 /*
 164  * Sign a request with HMAC-MD5.
 165  */
 166 void
 167 smb2_rq_sign(struct smb_rq *rqp)
 168 {
 169         struct smb_vc *vcp = rqp->sr_vc;
 170         mblk_t *mp = rqp->sr_rq.mb_top;
 171         uint8_t *sigloc;
 172         int rc;
 173 
 174         /*
 175          * smb_rq_new() ensures this,
 176          * but just in case..
 177          */
 178         ASSERT(MBLKL(mp) >= SMB2_HDRLEN);
 179         sigloc = mp->b_rptr + SMB2_SIG_OFF;
 180 
 181         if (vcp->vc_mackey == NULL)
 182                 return;
 183 
 184         /*
 185          * This will compute the MAC and store it
 186          * directly into the message at sigloc.
 187          */
 188         rc = smb2_compute_MAC(vcp, mp, sigloc);
 189         if (rc != 0) {
 190                 SMBSDEBUG("Crypto error %d", rc);
 191                 bzero(sigloc, SMB2_SIG_LEN);
 192         }
 193 }
 194 
 195 /*
 196  * Verify reply signature.
 197  */
 198 int
 199 smb2_rq_verify(struct smb_rq *rqp)
 200 {
 201         struct smb_vc *vcp = rqp->sr_vc;
 202         mblk_t *mp = rqp->sr_rp.md_top;
 203         uint8_t sigbuf[SMB2_SIG_LEN];
 204         uint8_t *sigloc;
 205         int rc;
 206 
 207         /*
 208          * Note vc_mackey and vc_mackeylen gets filled in by
 209          * smb_usr_iod_work as the connection comes in.
 210          */
 211         if (vcp->vc_mackey == NULL) {
 212                 SMBSDEBUG("no mac key\n");
 213                 return (0);
 214         }
 215 
 216         /*
 217          * Let caller deal with empty reply or short messages by
 218          * returning zero.  Caller will fail later, in parsing.
 219          */
 220         if (mp == NULL) {
 221                 SMBSDEBUG("empty reply\n");
 222                 return (0);
 223         }
 224 
 225         /* smb2_iod_process ensures this */
 226         ASSERT(MBLKL(mp) >= SMB2_HDRLEN);
 227         sigloc = mp->b_rptr + SMB2_SIG_OFF;
 228 
 229         /*
 230          * Compute the expected signature in sigbuf.
 231          */
 232         rc = smb2_compute_MAC(vcp, mp, sigbuf);
 233         if (rc != 0) {
 234                 SMBSDEBUG("Crypto error %d", rc);
 235                 /*
 236                  * If we can't compute a MAC, then there's
 237                  * no point trying other seqno values.
 238                  */
 239                 return (EBADRPC);
 240         }
 241 
 242         /*
 243          * Compare the computed signature with the
 244          * one found in the message (at sigloc)
 245          */
 246         if (bcmp(sigbuf, sigloc, SMB2_SIG_LEN) == 0)
 247                 return (0);
 248 
 249         SMBERROR("BAD signature, Server=%s MID=0x%llx\n",
 250             vcp->vc_srvname, (long long)rqp->sr2_messageid);
 251 
 252         return (EBADRPC);
 253 }