Print this page
NEX-15724 SMB3 clients fail to connect using FQDN
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15724 SMB3 clients fail to connect using FQDN
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-10231 SMB logon fails in fksmbd
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-5273 SMB 3 Encryption
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5560 smb2 should use 64-bit server-global uids
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-3728 SMB1 signing should use KCF like SMB2/3
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-3610 CLONE NEX-3591 SMB3 signing
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-3080 SMB1 signing problem with Kerberos auth.
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-2869 SMB2 signing fails for multi-user clients like Citrix RDS
SMB-55 SMB2 signing (syslog noise)
SMB-55 SMB2 signing


   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  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 /*
  26  * These routines provide the SMB MAC signing for the SMB2 server.
  27  * The routines calculate the signature of a SMB message in an mbuf chain.
  28  *
  29  * The following table describes the client server
  30  * signing registry relationship
  31  *
  32  *              | Required      | Enabled     | Disabled
  33  * -------------+---------------+------------ +--------------
  34  * Required     | Signed        | Signed      | Fail
  35  * -------------+---------------+-------------+-----------------
  36  * Enabled      | Signed        | Signed      | Not Signed
  37  * -------------+---------------+-------------+----------------
  38  * Disabled     | Fail          | Not Signed  | Not Signed
  39  */
  40 
  41 #include <sys/uio.h>
  42 #include <smbsrv/smb_kproto.h>
  43 #include <smbsrv/smb_signing.h>
  44 #include <sys/isa_defs.h>
  45 #include <sys/byteorder.h>
  46 #include <sys/cmn_err.h>
  47 
  48 #define SMB2_SIG_OFFS   48
  49 #define SMB2_SIG_SIZE   16
  50 










  51 /*























  52  * Called during session destroy.
  53  */
  54 static void
  55 smb2_sign_fini(smb_session_t *s)
  56 {
  57         smb_sign_mech_t *mech;
  58 
  59         if ((mech = s->sign_mech) != NULL) {
  60                 kmem_free(mech, sizeof (*mech));
  61                 s->sign_mech = NULL;
  62         }
  63 }
  64 
  65 /*































































  66  * smb2_sign_begin

  67  *
  68  * Get the mechanism info.
  69  * Intializes MAC key based on the user session key and store it in
  70  * the signing structure.  This begins signing on this session.
  71  */
  72 int
  73 smb2_sign_begin(smb_request_t *sr, smb_token_t *token)
  74 {
  75         smb_session_t *s = sr->session;
  76         smb_user_t *u = sr->uid_user;
  77         struct smb_key *sign_key = &u->u_sign_key;
  78         smb_sign_mech_t *mech;
  79         int rc;
  80 


  81         /*
  82          * We should normally have a session key here because
  83          * our caller filters out Anonymous and Guest logons.
  84          * However, buggy clients could get us here without a
  85          * session key, in which case we'll fail later when a
  86          * request that requires signing can't be checked.

  87          */
  88         if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0)
  89                 return (0);

  90 
  91         /*
  92          * Session-level initialization (once per session)
  93          * Get mech handle, sign_fini function.
  94          */
  95         smb_rwx_rwenter(&s->s_lock, RW_WRITER);
  96         if (s->sign_mech == NULL) {
  97                 mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
  98                 rc = smb2_hmac_getmech(mech);
  99                 if (rc != 0) {
 100                         kmem_free(mech, sizeof (*mech));
 101                         smb_rwx_rwexit(&s->s_lock);
 102                         return (rc);
 103                 }
 104                 s->sign_mech = mech;
 105                 s->sign_fini = smb2_sign_fini;
 106         }
 107         smb_rwx_rwexit(&s->s_lock);
 108 
 109         /*
 110          * Compute and store the signing key, which lives in
 111          * the user structure.
 112          */
 113         sign_key->len = SMB2_SIG_SIZE;
 114 
 115         /*










 116          * For SMB2, the signing key is just the first 16 bytes
 117          * of the session key (truncated or padded with zeros).
 118          * [MS-SMB2] 3.2.5.3.1
 119          */

 120         bcopy(token->tkn_ssnkey.val, sign_key->key,
 121             MIN(token->tkn_ssnkey.len, sign_key->len));

 122 
 123         mutex_enter(&u->u_mutex);
 124         if (s->secmode & SMB2_NEGOTIATE_SIGNING_ENABLED)
 125                 u->u_sign_flags |= SMB_SIGNING_ENABLED;
 126         if (s->secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED)

 127                 u->u_sign_flags |=
 128                     SMB_SIGNING_ENABLED | SMB_SIGNING_CHECK;
 129         mutex_exit(&u->u_mutex);
 130 
 131         /*
 132          * If we just turned on signing, the current request
 133          * (an SMB2 session setup) will have come in without
 134          * SMB2_FLAGS_SIGNED (and not signed) but the response
 135          * is is supposed to be signed. [MS-SMB2] 3.3.5.5
 136          */
 137         if (u->u_sign_flags & SMB_SIGNING_ENABLED)
 138                 sr->smb2_hdr_flags |= SMB2_FLAGS_SIGNED;
 139 
 140         return (0);
 141 }
 142 
 143 /*
 144  * smb2_sign_calc
 145  *
 146  * Calculates MAC signature for the given buffer and returns
 147  * it in the mac_sign parameter.
 148  *
 149  * The signature is in the last 16 bytes of the SMB2 header.
 150  * The signature algorighm is to compute HMAC SHA256 over the
 151  * entire command, with the signature field set to zeros.
 152  *
 153  * Return 0 if  success else -1
 154  */

 155 static int
 156 smb2_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc,
 157     uint8_t *digest)
 158 {
 159         uint8_t tmp_hdr[SMB2_HDR_SIZE];
 160         smb_sign_ctx_t ctx = 0;
 161         smb_session_t *s = sr->session;
 162         smb_user_t *u = sr->uid_user;
 163         struct smb_key *sign_key = &u->u_sign_key;
 164         struct mbuf *mbuf;
 165         int offset, resid, tlen, rc;
 166 
 167         if (s->sign_mech == NULL || sign_key->len == 0)
 168                 return (-1);
 169 
 170         rc = smb2_hmac_init(&ctx, s->sign_mech, sign_key->key, sign_key->len);

 171         if (rc != 0)
 172                 return (rc);
 173 
 174         /*
 175          * Work with a copy of the SMB2 header so we can
 176          * clear the signature field without modifying
 177          * the original message.
 178          */
 179         tlen = SMB2_HDR_SIZE;
 180         offset = mbc->chain_offset;
 181         resid = mbc->max_bytes - offset;
 182         if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0)
 183                 return (-1);
 184         bzero(tmp_hdr + SMB2_SIG_OFFS, SMB2_SIG_SIZE);
 185         if ((rc = smb2_hmac_update(ctx, tmp_hdr, tlen)) != 0)

 186                 return (rc);
 187         offset += tlen;
 188         resid -= tlen;
 189 
 190         /*
 191          * Digest the rest of the SMB packet, starting at the data
 192          * just after the SMB header.
 193          *
 194          * Advance to the src mbuf where we start digesting.
 195          */
 196         mbuf = mbc->chain;
 197         while (mbuf != NULL && (offset >= mbuf->m_len)) {
 198                 offset -= mbuf->m_len;
 199                 mbuf = mbuf->m_next;
 200         }
 201 
 202         if (mbuf == NULL)
 203                 return (-1);
 204 
 205         /*
 206          * Digest the remainder of this mbuf, limited to the
 207          * residual count, and starting at the current offset.
 208          * (typically SMB2_HDR_SIZE)
 209          */
 210         tlen = mbuf->m_len - offset;
 211         if (tlen > resid)
 212                 tlen = resid;
 213         rc = smb2_hmac_update(ctx, (uint8_t *)mbuf->m_data + offset, tlen);

 214         if (rc != 0)
 215                 return (rc);
 216         resid -= tlen;
 217 
 218         /*
 219          * Digest any more mbufs in the chain.
 220          */
 221         while (resid > 0) {
 222                 mbuf = mbuf->m_next;
 223                 if (mbuf == NULL)
 224                         return (-1);
 225                 tlen = mbuf->m_len;
 226                 if (tlen > resid)
 227                         tlen = resid;
 228                 rc = smb2_hmac_update(ctx, (uint8_t *)mbuf->m_data, tlen);
 229                 if (rc != 0)
 230                         return (rc);
 231                 resid -= tlen;
 232         }
 233 
 234         /*

 235          * Note: digest is _always_ SMB2_SIG_SIZE,
 236          * even if the mech uses a longer one.


 237          */
 238         if ((rc = smb2_hmac_final(ctx, digest)) != 0)
 239                 return (rc);
 240 
 241         return (0);
 242 }
 243 
 244 /*
 245  * smb2_sign_check_request
 246  *
 247  * Calculates MAC signature for the request mbuf chain
 248  * using the next expected sequence number and compares
 249  * it to the given signature.
 250  *
 251  * Note it does not check the signature for secondary transactions
 252  * as their sequence number is the same as the original request.
 253  *
 254  * Return 0 if the signature verifies, otherwise, returns -1;
 255  *
 256  */
 257 int
 258 smb2_sign_check_request(smb_request_t *sr)
 259 {
 260         uint8_t req_sig[SMB2_SIG_SIZE];
 261         uint8_t vfy_sig[SMB2_SIG_SIZE];
 262         struct mbuf_chain *mbc = &sr->smb_data;

 263         smb_user_t *u = sr->uid_user;
 264         int sig_off;
 265 
 266         /*
 267          * Don't check commands with a zero session ID.
 268          * [MS-SMB2] 3.3.4.1.1
 269          */
 270         if (sr->smb_uid == 0 || u == NULL)
 271                 return (0);
 272 




 273         /* Get the request signature. */
 274         sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS;
 275         if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0)
 276                 return (-1);
 277 
 278         /*
 279          * Compute the correct signature and compare.

 280          */
 281         if (smb2_sign_calc(sr, mbc, vfy_sig) != 0)
 282                 return (-1);
 283         if (memcmp(vfy_sig, req_sig, SMB2_SIG_SIZE) != 0) {
 284                 cmn_err(CE_NOTE, "smb2_sign_check_request: bad signature");
 285                 return (-1);
 286         }
 287 
 288         return (0);
 289 }
 290 
 291 /*
 292  * smb2_sign_reply
 293  *
 294  * Calculates MAC signature for the given mbuf chain,
 295  * and write it to the signature field in the mbuf.
 296  *
 297  */
 298 void
 299 smb2_sign_reply(smb_request_t *sr)
 300 {
 301         uint8_t reply_sig[SMB2_SIG_SIZE];
 302         struct mbuf_chain tmp_mbc;

 303         smb_user_t *u = sr->uid_user;
 304         int hdr_off, msg_len;
 305 
 306         if (u == NULL)
 307                 return;


 308 
 309         msg_len = sr->reply.chain_offset - sr->smb2_reply_hdr;
 310         (void) MBC_SHADOW_CHAIN(&tmp_mbc, &sr->reply,
 311             sr->smb2_reply_hdr, msg_len);
 312 
 313         /*
 314          * Calculate the MAC signature for this reply.

 315          */
 316         if (smb2_sign_calc(sr, &tmp_mbc, reply_sig) != 0)
 317                 return;
 318 
 319         /*
 320          * Poke the signature into the response.
 321          */
 322         hdr_off = sr->smb2_reply_hdr + SMB2_SIG_OFFS;
 323         (void) smb_mbc_poke(&sr->reply, hdr_off, "#c",
 324             SMB2_SIG_SIZE, reply_sig);




























































 325 }


   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  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 /*
  26  * These routines provide the SMB MAC signing for the SMB2 server.
  27  * The routines calculate the signature of a SMB message in an mbuf chain.
  28  *
  29  * The following table describes the client server
  30  * signing registry relationship
  31  *
  32  *              | Required      | Enabled     | Disabled
  33  * -------------+---------------+------------ +--------------
  34  * Required     | Signed        | Signed      | Fail
  35  * -------------+---------------+-------------+-----------------
  36  * Enabled      | Signed        | Signed      | Not Signed
  37  * -------------+---------------+-------------+----------------
  38  * Disabled     | Fail          | Not Signed  | Not Signed
  39  */
  40 
  41 #include <sys/uio.h>
  42 #include <smbsrv/smb2_kproto.h>
  43 #include <smbsrv/smb_kcrypt.h>
  44 #include <sys/isa_defs.h>
  45 #include <sys/byteorder.h>
  46 #include <sys/cmn_err.h>
  47 
  48 #define SMB2_SIG_OFFS   48
  49 #define SMB2_SIG_SIZE   16
  50 
  51 typedef struct mac_ops {
  52         int (*mac_init)(smb_sign_ctx_t *, smb_crypto_mech_t *,
  53                         uint8_t *, size_t);
  54         int (*mac_update)(smb_sign_ctx_t, uint8_t *, size_t);
  55         int (*mac_final)(smb_sign_ctx_t, uint8_t *);
  56 } mac_ops_t;
  57 
  58 static int smb2_sign_calc_common(smb_request_t *, struct mbuf_chain *,
  59     uint8_t *, mac_ops_t *);
  60 
  61 /*
  62  * SMB2 wrapper functions
  63  */
  64 
  65 static mac_ops_t
  66 smb2_sign_ops = {
  67         smb2_hmac_init,
  68         smb2_hmac_update,
  69         smb2_hmac_final
  70 };
  71 
  72 static int
  73 smb2_sign_calc(smb_request_t *sr,
  74     struct mbuf_chain *mbc,
  75     uint8_t *digest16)
  76 {
  77         int rv;
  78 
  79         rv = smb2_sign_calc_common(sr, mbc, digest16, &smb2_sign_ops);
  80 
  81         return (rv);
  82 }
  83 
  84 /*
  85  * Called during session destroy.
  86  */
  87 static void
  88 smb2_sign_fini(smb_session_t *s)
  89 {
  90         smb_crypto_mech_t *mech;
  91 
  92         if ((mech = s->sign_mech) != NULL) {
  93                 kmem_free(mech, sizeof (*mech));
  94                 s->sign_mech = NULL;
  95         }
  96 }
  97 
  98 /*
  99  * SMB3 wrapper functions
 100  */
 101 
 102 static struct mac_ops
 103 smb3_sign_ops = {
 104         smb3_cmac_init,
 105         smb3_cmac_update,
 106         smb3_cmac_final
 107 };
 108 
 109 static int
 110 smb3_sign_calc(smb_request_t *sr,
 111     struct mbuf_chain *mbc,
 112     uint8_t *digest16)
 113 {
 114         int rv;
 115 
 116         rv = smb2_sign_calc_common(sr, mbc, digest16, &smb3_sign_ops);
 117 
 118         return (rv);
 119 }
 120 
 121 /*
 122  * Input to KDF for SigningKey.
 123  * See comment for smb3_do_kdf for content.
 124  */
 125 static uint8_t sign_kdf_input[29] = {
 126         0, 0, 0, 1, 'S', 'M', 'B', '2',
 127         'A', 'E', 'S', 'C', 'M', 'A', 'C', 0,
 128         0, 'S', 'm', 'b', 'S', 'i', 'g', 'n',
 129         0, 0, 0, 0, 0x80 };
 130 
 131 void
 132 smb2_sign_init_mech(smb_session_t *s)
 133 {
 134         smb_crypto_mech_t *mech;
 135         int (*get_mech)(smb_crypto_mech_t *);
 136         int (*sign_calc)(smb_request_t *, struct mbuf_chain *, uint8_t *);
 137         int rc;
 138 
 139         if (s->sign_mech != NULL)
 140                 return;
 141 
 142         if (s->dialect >= SMB_VERS_3_0) {
 143                 get_mech = smb3_cmac_getmech;
 144                 sign_calc = smb3_sign_calc;
 145         } else {
 146                 get_mech = smb2_hmac_getmech;
 147                 sign_calc = smb2_sign_calc;
 148         }
 149 
 150         mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
 151         rc = get_mech(mech);
 152         if (rc != 0) {
 153                 kmem_free(mech, sizeof (*mech));
 154                 return;
 155         }
 156         s->sign_mech = mech;
 157         s->sign_calc = sign_calc;
 158         s->sign_fini = smb2_sign_fini;
 159 }
 160 
 161 /*
 162  * smb2_sign_begin
 163  * Handles both SMB2 & SMB3
 164  *
 165  * Get the mechanism info.
 166  * Intializes MAC key based on the user session key and store it in
 167  * the signing structure.  This begins signing on this session.
 168  */
 169 void
 170 smb2_sign_begin(smb_request_t *sr, smb_token_t *token)
 171 {
 172         smb_session_t *s = sr->session;
 173         smb_user_t *u = sr->uid_user;
 174         struct smb_key *sign_key = &u->u_sign_key;


 175 
 176         sign_key->len = 0;
 177 
 178         /*
 179          * We should normally have a session key here because
 180          * our caller filters out Anonymous and Guest logons.
 181          * However, buggy clients could get us here without a
 182          * session key, in which case we'll fail later when a
 183          * request that requires signing can't be checked.
 184          * Also, don't bother initializing if we don't have a mechanism.
 185          */
 186         if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0 ||
 187             s->sign_mech == NULL)
 188                 return;
 189 
 190         /*


















 191          * Compute and store the signing key, which lives in
 192          * the user structure.
 193          */
 194         if (s->dialect >= SMB_VERS_3_0) {

 195                 /*
 196                  * For SMB3, the signing key is a "KDF" hash of the
 197                  * session key.
 198                  */
 199                 if (smb3_do_kdf(sign_key->key, sign_kdf_input,
 200                     sizeof (sign_kdf_input), token->tkn_ssnkey.val,
 201                     token->tkn_ssnkey.len) != 0)
 202                         return;
 203                 sign_key->len = SMB3_KEYLEN;
 204         } else {
 205                 /*
 206                  * For SMB2, the signing key is just the first 16 bytes
 207                  * of the session key (truncated or padded with zeros).
 208                  * [MS-SMB2] 3.2.5.3.1
 209                  */
 210                 sign_key->len = SMB2_KEYLEN;
 211                 bcopy(token->tkn_ssnkey.val, sign_key->key,
 212                     MIN(token->tkn_ssnkey.len, sign_key->len));
 213         }
 214 
 215         mutex_enter(&u->u_mutex);
 216         if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_ENABLED) != 0)
 217                 u->u_sign_flags |= SMB_SIGNING_ENABLED;
 218         if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0 ||
 219             (s->cli_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0)
 220                 u->u_sign_flags |=
 221                     SMB_SIGNING_ENABLED | SMB_SIGNING_CHECK;
 222         mutex_exit(&u->u_mutex);
 223 
 224         /*
 225          * If we just turned on signing, the current request
 226          * (an SMB2 session setup) will have come in without
 227          * SMB2_FLAGS_SIGNED (and not signed) but the response
 228          * is is supposed to be signed. [MS-SMB2] 3.3.5.5
 229          */
 230         if (u->u_sign_flags & SMB_SIGNING_ENABLED)
 231                 sr->smb2_hdr_flags |= SMB2_FLAGS_SIGNED;


 232 }
 233 
 234 /*
 235  * smb2_sign_calc_common
 236  *
 237  * Calculates MAC signature for the given buffer and returns
 238  * it in the mac_sign parameter.
 239  *
 240  * The signature algorithm is to compute HMAC SHA256 or AES_CMAC
 241  * over the entire command, with the signature field set to zeros.

 242  *
 243  * Return 0 if  success else -1
 244  */
 245 
 246 static int
 247 smb2_sign_calc_common(smb_request_t *sr, struct mbuf_chain *mbc,
 248     uint8_t *digest, mac_ops_t *ops)
 249 {
 250         uint8_t tmp_hdr[SMB2_HDR_SIZE];
 251         smb_sign_ctx_t ctx = 0;
 252         smb_session_t *s = sr->session;
 253         smb_user_t *u = sr->uid_user;
 254         struct smb_key *sign_key = &u->u_sign_key;
 255         struct mbuf *mbuf;
 256         int offset, resid, tlen, rc;
 257 
 258         if (s->sign_mech == NULL || sign_key->len == 0)
 259                 return (-1);
 260 
 261         /* smb2_hmac_init or smb3_cmac_init */
 262         rc = ops->mac_init(&ctx, s->sign_mech, sign_key->key, sign_key->len);
 263         if (rc != 0)
 264                 return (rc);
 265 
 266         /*
 267          * Work with a copy of the SMB2 header so we can
 268          * clear the signature field without modifying
 269          * the original message.
 270          */
 271         tlen = SMB2_HDR_SIZE;
 272         offset = mbc->chain_offset;
 273         resid = mbc->max_bytes - offset;
 274         if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0)
 275                 return (-1);
 276         bzero(tmp_hdr + SMB2_SIG_OFFS, SMB2_SIG_SIZE);
 277         /* smb2_hmac_update or smb3_cmac_update */
 278         if ((rc = ops->mac_update(ctx, tmp_hdr, tlen)) != 0)
 279                 return (rc);
 280         offset += tlen;
 281         resid -= tlen;
 282 
 283         /*
 284          * Digest the rest of the SMB packet, starting at the data
 285          * just after the SMB header.
 286          *
 287          * Advance to the src mbuf where we start digesting.
 288          */
 289         mbuf = mbc->chain;
 290         while (mbuf != NULL && (offset >= mbuf->m_len)) {
 291                 offset -= mbuf->m_len;
 292                 mbuf = mbuf->m_next;
 293         }
 294 
 295         if (mbuf == NULL)
 296                 return (-1);
 297 
 298         /*
 299          * Digest the remainder of this mbuf, limited to the
 300          * residual count, and starting at the current offset.
 301          * (typically SMB2_HDR_SIZE)
 302          */
 303         tlen = mbuf->m_len - offset;
 304         if (tlen > resid)
 305                 tlen = resid;
 306         /* smb2_hmac_update or smb3_cmac_update */
 307         rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data + offset, tlen);
 308         if (rc != 0)
 309                 return (rc);
 310         resid -= tlen;
 311 
 312         /*
 313          * Digest any more mbufs in the chain.
 314          */
 315         while (resid > 0) {
 316                 mbuf = mbuf->m_next;
 317                 if (mbuf == NULL)
 318                         return (-1);
 319                 tlen = mbuf->m_len;
 320                 if (tlen > resid)
 321                         tlen = resid;
 322                 rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data, tlen);
 323                 if (rc != 0)
 324                         return (rc);
 325                 resid -= tlen;
 326         }
 327 
 328         /*
 329          * smb2_hmac_final or smb3_cmac_final
 330          * Note: digest is _always_ SMB2_SIG_SIZE,
 331          * even if the mech uses a longer one.
 332          *
 333          * smb2_hmac_update or smb3_cmac_update
 334          */
 335         if ((rc = ops->mac_final(ctx, digest)) != 0)
 336                 return (rc);
 337 
 338         return (0);
 339 }
 340 
 341 /*
 342  * smb2_sign_check_request
 343  *
 344  * Calculates MAC signature for the request mbuf chain
 345  * using the next expected sequence number and compares
 346  * it to the given signature.
 347  *
 348  * Note it does not check the signature for secondary transactions
 349  * as their sequence number is the same as the original request.
 350  *
 351  * Return 0 if the signature verifies, otherwise, returns -1;
 352  *
 353  */
 354 int
 355 smb2_sign_check_request(smb_request_t *sr)
 356 {
 357         uint8_t req_sig[SMB2_SIG_SIZE];
 358         uint8_t vfy_sig[SMB2_SIG_SIZE];
 359         struct mbuf_chain *mbc = &sr->smb_data;
 360         smb_session_t *s = sr->session;
 361         smb_user_t *u = sr->uid_user;
 362         int sig_off;
 363 
 364         /*
 365          * Don't check commands with a zero session ID.
 366          * [MS-SMB2] 3.3.4.1.1
 367          */
 368         if (sr->smb2_ssnid == 0 || u == NULL)
 369                 return (0);
 370 
 371         /* In case _sign_begin failed. */
 372         if (s->sign_calc == NULL)
 373                 return (-1);
 374 
 375         /* Get the request signature. */
 376         sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS;
 377         if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0)
 378                 return (-1);
 379 
 380         /*
 381          * Compute the correct signature and compare.
 382          * smb2_sign_calc() or smb3_sign_calc()
 383          */
 384         if (s->sign_calc(sr, mbc, vfy_sig) != 0)
 385                 return (-1);
 386         if (memcmp(vfy_sig, req_sig, SMB2_SIG_SIZE) != 0) {
 387                 cmn_err(CE_NOTE, "smb2_sign_check_request: bad signature");
 388                 return (-1);
 389         }
 390 
 391         return (0);
 392 }
 393 
 394 /*
 395  * smb2_sign_reply
 396  *
 397  * Calculates MAC signature for the given mbuf chain,
 398  * and write it to the signature field in the mbuf.
 399  *
 400  */
 401 void
 402 smb2_sign_reply(smb_request_t *sr)
 403 {
 404         uint8_t reply_sig[SMB2_SIG_SIZE];
 405         struct mbuf_chain tmp_mbc;
 406         smb_session_t *s = sr->session;
 407         smb_user_t *u = sr->uid_user;
 408         int hdr_off, msg_len;
 409 
 410         if (u == NULL)
 411                 return;
 412         if (s->sign_calc == NULL)
 413                 return;
 414 
 415         msg_len = sr->reply.chain_offset - sr->smb2_reply_hdr;
 416         (void) MBC_SHADOW_CHAIN(&tmp_mbc, &sr->reply,
 417             sr->smb2_reply_hdr, msg_len);
 418 
 419         /*
 420          * Calculate the MAC signature for this reply.
 421          * smb2_sign_calc() or smb3_sign_calc()
 422          */
 423         if (s->sign_calc(sr, &tmp_mbc, reply_sig) != 0)
 424                 return;
 425 
 426         /*
 427          * Poke the signature into the response.
 428          */
 429         hdr_off = sr->smb2_reply_hdr + SMB2_SIG_OFFS;
 430         (void) smb_mbc_poke(&sr->reply, hdr_off, "#c",
 431             SMB2_SIG_SIZE, reply_sig);
 432 }
 433 
 434 /*
 435  * Derive SMB3 key as described in [MS-SMB2] 3.1.4.2
 436  * and [NIST SP800-108]
 437  *
 438  * r = 32, L = 128, PRF = HMAC-SHA256, key = (session key)
 439  *
 440  * Note that these describe pre-3.1.1 inputs.
 441  *
 442  * Session.SigningKey for binding a session:
 443  * - Session.SessionKey as K1
 444  * - label = SMB2AESCMAC (size 12)
 445  * - context = SmbSign (size 8)
 446  * Channel.SigningKey for for all other requests
 447  * - if SMB2_SESSION_FLAG_BINDING, GSS key (in Session.SessionKey?) as K1;
 448  * - otherwise, Session.SessionKey as K1
 449  * - label = SMB2AESCMAC (size 12)
 450  * - context = SmbSign (size 8)
 451  * Session.ApplicationKey for ... (not sure what yet)
 452  * - Session.SessionKey as K1
 453  * - label = SMB2APP (size 8)
 454  * - context = SmbRpc (size 7)
 455  * Session.EncryptionKey for encrypting server messages
 456  * - Session.SessionKey as K1
 457  * - label = "SMB2AESCCM" (size 11)
 458  * - context = "ServerOut" (size 10)
 459  * Session.DecryptionKey for decrypting client requests
 460  * - Session.SessionKey as K1
 461  * - label = "SMB2AESCCM" (size 11)
 462  * - context = "ServerIn " (size 10) (Note the space)
 463  */
 464 
 465 int
 466 smb3_do_kdf(void *outbuf, void *input, size_t input_len,
 467     uint8_t *key, uint32_t key_len)
 468 {
 469         uint8_t digest32[SHA256_DIGEST_LENGTH];
 470         smb_crypto_mech_t mech;
 471         smb_sign_ctx_t hctx = 0;
 472         int rc;
 473 
 474         bzero(&mech, sizeof (mech));
 475         if ((rc = smb2_hmac_getmech(&mech)) != 0)
 476                 return (rc);
 477 
 478         /* Limit the SessionKey input to its maximum size (16 bytes) */
 479         rc = smb2_hmac_init(&hctx, &mech, key, MIN(key_len, SMB2_KEYLEN));
 480         if (rc != 0)
 481                 return (rc);
 482 
 483         if ((rc = smb2_hmac_update(hctx, input, input_len)) != 0)
 484                 return (rc);
 485 
 486         if ((rc = smb2_hmac_final(hctx, digest32)) != 0)
 487                 return (rc);
 488 
 489         /* Output is first 16 bytes of digest. */
 490         bcopy(digest32, outbuf, SMB3_KEYLEN);
 491         return (0);
 492 }