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  * 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 }