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

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbsrv/smb2_signing.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb2_signing.c
↓ open down ↓ 12 lines elided ↑ open up ↑
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23      - * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
       23 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  24   24   */
  25   25  /*
  26   26   * These routines provide the SMB MAC signing for the SMB2 server.
  27   27   * The routines calculate the signature of a SMB message in an mbuf chain.
  28   28   *
  29   29   * The following table describes the client server
  30   30   * signing registry relationship
  31   31   *
  32   32   *              | Required      | Enabled     | Disabled
  33   33   * -------------+---------------+------------ +--------------
  34   34   * Required     | Signed        | Signed      | Fail
  35   35   * -------------+---------------+-------------+-----------------
  36   36   * Enabled      | Signed        | Signed      | Not Signed
  37   37   * -------------+---------------+-------------+----------------
  38   38   * Disabled     | Fail          | Not Signed  | Not Signed
  39   39   */
  40   40  
  41   41  #include <sys/uio.h>
  42      -#include <smbsrv/smb_kproto.h>
  43      -#include <smbsrv/smb_signing.h>
       42 +#include <smbsrv/smb2_kproto.h>
       43 +#include <smbsrv/smb_kcrypt.h>
  44   44  #include <sys/isa_defs.h>
  45   45  #include <sys/byteorder.h>
  46   46  #include <sys/cmn_err.h>
  47   47  
  48   48  #define SMB2_SIG_OFFS   48
  49   49  #define SMB2_SIG_SIZE   16
  50   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 +
  51   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 +/*
  52   85   * Called during session destroy.
  53   86   */
  54   87  static void
  55   88  smb2_sign_fini(smb_session_t *s)
  56   89  {
  57      -        smb_sign_mech_t *mech;
       90 +        smb_crypto_mech_t *mech;
  58   91  
  59   92          if ((mech = s->sign_mech) != NULL) {
  60   93                  kmem_free(mech, sizeof (*mech));
  61   94                  s->sign_mech = NULL;
  62   95          }
  63   96  }
  64   97  
  65   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 +/*
  66  162   * smb2_sign_begin
      163 + * Handles both SMB2 & SMB3
  67  164   *
  68  165   * Get the mechanism info.
  69  166   * Intializes MAC key based on the user session key and store it in
  70  167   * the signing structure.  This begins signing on this session.
  71  168   */
  72      -int
      169 +void
  73  170  smb2_sign_begin(smb_request_t *sr, smb_token_t *token)
  74  171  {
  75  172          smb_session_t *s = sr->session;
  76  173          smb_user_t *u = sr->uid_user;
  77  174          struct smb_key *sign_key = &u->u_sign_key;
  78      -        smb_sign_mech_t *mech;
  79      -        int rc;
  80  175  
      176 +        sign_key->len = 0;
      177 +
  81  178          /*
  82  179           * We should normally have a session key here because
  83  180           * our caller filters out Anonymous and Guest logons.
  84  181           * However, buggy clients could get us here without a
  85  182           * session key, in which case we'll fail later when a
  86  183           * request that requires signing can't be checked.
      184 +         * Also, don't bother initializing if we don't have a mechanism.
  87  185           */
  88      -        if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0)
  89      -                return (0);
      186 +        if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0 ||
      187 +            s->sign_mech == NULL)
      188 +                return;
  90  189  
  91  190          /*
  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  191           * Compute and store the signing key, which lives in
 111  192           * the user structure.
 112  193           */
 113      -        sign_key->len = SMB2_SIG_SIZE;
      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 +        }
 114  214  
 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  215          mutex_enter(&u->u_mutex);
 124      -        if (s->secmode & SMB2_NEGOTIATE_SIGNING_ENABLED)
      216 +        if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_ENABLED) != 0)
 125  217                  u->u_sign_flags |= SMB_SIGNING_ENABLED;
 126      -        if (s->secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED)
      218 +        if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0 ||
      219 +            (s->cli_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0)
 127  220                  u->u_sign_flags |=
 128  221                      SMB_SIGNING_ENABLED | SMB_SIGNING_CHECK;
 129  222          mutex_exit(&u->u_mutex);
 130  223  
 131  224          /*
 132  225           * If we just turned on signing, the current request
 133  226           * (an SMB2 session setup) will have come in without
 134  227           * SMB2_FLAGS_SIGNED (and not signed) but the response
 135  228           * is is supposed to be signed. [MS-SMB2] 3.3.5.5
 136  229           */
 137  230          if (u->u_sign_flags & SMB_SIGNING_ENABLED)
 138  231                  sr->smb2_hdr_flags |= SMB2_FLAGS_SIGNED;
 139      -
 140      -        return (0);
 141  232  }
 142  233  
 143  234  /*
 144      - * smb2_sign_calc
      235 + * smb2_sign_calc_common
 145  236   *
 146  237   * Calculates MAC signature for the given buffer and returns
 147  238   * it in the mac_sign parameter.
 148  239   *
 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.
      240 + * The signature algorithm is to compute HMAC SHA256 or AES_CMAC
      241 + * over the entire command, with the signature field set to zeros.
 152  242   *
 153  243   * Return 0 if  success else -1
 154  244   */
      245 +
 155  246  static int
 156      -smb2_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc,
 157      -    uint8_t *digest)
      247 +smb2_sign_calc_common(smb_request_t *sr, struct mbuf_chain *mbc,
      248 +    uint8_t *digest, mac_ops_t *ops)
 158  249  {
 159  250          uint8_t tmp_hdr[SMB2_HDR_SIZE];
 160  251          smb_sign_ctx_t ctx = 0;
 161  252          smb_session_t *s = sr->session;
 162  253          smb_user_t *u = sr->uid_user;
 163  254          struct smb_key *sign_key = &u->u_sign_key;
 164  255          struct mbuf *mbuf;
 165  256          int offset, resid, tlen, rc;
 166  257  
 167  258          if (s->sign_mech == NULL || sign_key->len == 0)
 168  259                  return (-1);
 169  260  
 170      -        rc = smb2_hmac_init(&ctx, s->sign_mech, sign_key->key, sign_key->len);
      261 +        /* smb2_hmac_init or smb3_cmac_init */
      262 +        rc = ops->mac_init(&ctx, s->sign_mech, sign_key->key, sign_key->len);
 171  263          if (rc != 0)
 172  264                  return (rc);
 173  265  
 174  266          /*
 175  267           * Work with a copy of the SMB2 header so we can
 176  268           * clear the signature field without modifying
 177  269           * the original message.
 178  270           */
 179  271          tlen = SMB2_HDR_SIZE;
 180  272          offset = mbc->chain_offset;
 181  273          resid = mbc->max_bytes - offset;
 182  274          if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0)
 183  275                  return (-1);
 184  276          bzero(tmp_hdr + SMB2_SIG_OFFS, SMB2_SIG_SIZE);
 185      -        if ((rc = smb2_hmac_update(ctx, tmp_hdr, tlen)) != 0)
      277 +        /* smb2_hmac_update or smb3_cmac_update */
      278 +        if ((rc = ops->mac_update(ctx, tmp_hdr, tlen)) != 0)
 186  279                  return (rc);
 187  280          offset += tlen;
 188  281          resid -= tlen;
 189  282  
 190  283          /*
 191  284           * Digest the rest of the SMB packet, starting at the data
 192  285           * just after the SMB header.
 193  286           *
 194  287           * Advance to the src mbuf where we start digesting.
 195  288           */
↓ open down ↓ 7 lines elided ↑ open up ↑
 203  296                  return (-1);
 204  297  
 205  298          /*
 206  299           * Digest the remainder of this mbuf, limited to the
 207  300           * residual count, and starting at the current offset.
 208  301           * (typically SMB2_HDR_SIZE)
 209  302           */
 210  303          tlen = mbuf->m_len - offset;
 211  304          if (tlen > resid)
 212  305                  tlen = resid;
 213      -        rc = smb2_hmac_update(ctx, (uint8_t *)mbuf->m_data + offset, tlen);
      306 +        /* smb2_hmac_update or smb3_cmac_update */
      307 +        rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data + offset, tlen);
 214  308          if (rc != 0)
 215  309                  return (rc);
 216  310          resid -= tlen;
 217  311  
 218  312          /*
 219  313           * Digest any more mbufs in the chain.
 220  314           */
 221  315          while (resid > 0) {
 222  316                  mbuf = mbuf->m_next;
 223  317                  if (mbuf == NULL)
 224  318                          return (-1);
 225  319                  tlen = mbuf->m_len;
 226  320                  if (tlen > resid)
 227  321                          tlen = resid;
 228      -                rc = smb2_hmac_update(ctx, (uint8_t *)mbuf->m_data, tlen);
      322 +                rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data, tlen);
 229  323                  if (rc != 0)
 230  324                          return (rc);
 231  325                  resid -= tlen;
 232  326          }
 233  327  
 234  328          /*
      329 +         * smb2_hmac_final or smb3_cmac_final
 235  330           * Note: digest is _always_ SMB2_SIG_SIZE,
 236  331           * even if the mech uses a longer one.
      332 +         *
      333 +         * smb2_hmac_update or smb3_cmac_update
 237  334           */
 238      -        if ((rc = smb2_hmac_final(ctx, digest)) != 0)
      335 +        if ((rc = ops->mac_final(ctx, digest)) != 0)
 239  336                  return (rc);
 240  337  
 241  338          return (0);
 242  339  }
 243  340  
 244  341  /*
 245  342   * smb2_sign_check_request
 246  343   *
 247  344   * Calculates MAC signature for the request mbuf chain
 248  345   * using the next expected sequence number and compares
↓ open down ↓ 4 lines elided ↑ open up ↑
 253  350   *
 254  351   * Return 0 if the signature verifies, otherwise, returns -1;
 255  352   *
 256  353   */
 257  354  int
 258  355  smb2_sign_check_request(smb_request_t *sr)
 259  356  {
 260  357          uint8_t req_sig[SMB2_SIG_SIZE];
 261  358          uint8_t vfy_sig[SMB2_SIG_SIZE];
 262  359          struct mbuf_chain *mbc = &sr->smb_data;
      360 +        smb_session_t *s = sr->session;
 263  361          smb_user_t *u = sr->uid_user;
 264  362          int sig_off;
 265  363  
 266  364          /*
 267  365           * Don't check commands with a zero session ID.
 268  366           * [MS-SMB2] 3.3.4.1.1
 269  367           */
 270      -        if (sr->smb_uid == 0 || u == NULL)
      368 +        if (sr->smb2_ssnid == 0 || u == NULL)
 271  369                  return (0);
 272  370  
      371 +        /* In case _sign_begin failed. */
      372 +        if (s->sign_calc == NULL)
      373 +                return (-1);
      374 +
 273  375          /* Get the request signature. */
 274  376          sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS;
 275  377          if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0)
 276  378                  return (-1);
 277  379  
 278  380          /*
 279  381           * Compute the correct signature and compare.
      382 +         * smb2_sign_calc() or smb3_sign_calc()
 280  383           */
 281      -        if (smb2_sign_calc(sr, mbc, vfy_sig) != 0)
      384 +        if (s->sign_calc(sr, mbc, vfy_sig) != 0)
 282  385                  return (-1);
 283  386          if (memcmp(vfy_sig, req_sig, SMB2_SIG_SIZE) != 0) {
 284  387                  cmn_err(CE_NOTE, "smb2_sign_check_request: bad signature");
 285  388                  return (-1);
 286  389          }
 287  390  
 288  391          return (0);
 289  392  }
 290  393  
 291  394  /*
↓ open down ↓ 1 lines elided ↑ open up ↑
 293  396   *
 294  397   * Calculates MAC signature for the given mbuf chain,
 295  398   * and write it to the signature field in the mbuf.
 296  399   *
 297  400   */
 298  401  void
 299  402  smb2_sign_reply(smb_request_t *sr)
 300  403  {
 301  404          uint8_t reply_sig[SMB2_SIG_SIZE];
 302  405          struct mbuf_chain tmp_mbc;
      406 +        smb_session_t *s = sr->session;
 303  407          smb_user_t *u = sr->uid_user;
 304  408          int hdr_off, msg_len;
 305  409  
 306  410          if (u == NULL)
 307  411                  return;
      412 +        if (s->sign_calc == NULL)
      413 +                return;
 308  414  
 309  415          msg_len = sr->reply.chain_offset - sr->smb2_reply_hdr;
 310  416          (void) MBC_SHADOW_CHAIN(&tmp_mbc, &sr->reply,
 311  417              sr->smb2_reply_hdr, msg_len);
 312  418  
 313  419          /*
 314  420           * Calculate the MAC signature for this reply.
      421 +         * smb2_sign_calc() or smb3_sign_calc()
 315  422           */
 316      -        if (smb2_sign_calc(sr, &tmp_mbc, reply_sig) != 0)
      423 +        if (s->sign_calc(sr, &tmp_mbc, reply_sig) != 0)
 317  424                  return;
 318  425  
 319  426          /*
 320  427           * Poke the signature into the response.
 321  428           */
 322  429          hdr_off = sr->smb2_reply_hdr + SMB2_SIG_OFFS;
 323  430          (void) smb_mbc_poke(&sr->reply, hdr_off, "#c",
 324  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);
 325  492  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX