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 SMB 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 
  47 #define SMB_SIG_SIZE    8
  48 #define SMB_SIG_OFFS    14
  49 #define SMB_HDRLEN      32
  50 
  51 #ifdef _LITTLE_ENDIAN
  52 #define htolel(x)       ((uint32_t)(x))
  53 #else
  54 #define htolel(x)       BSWAP_32(x)
  55 #endif
  56 
  57 static int
  58 smb_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc,
  59     uint32_t seqnum, unsigned char *sig);
  60 
  61 #ifdef DEBUG
  62 uint32_t smb_sign_debug_search = 10;
  63 
  64 /*
  65  * Debug code to search +/- for the correct sequence number.
  66  * If found, correct sign->seqnum and return 0, else return -1
  67  */
  68 static int
  69 smb_sign_find_seqnum(
  70     smb_request_t *sr,
  71     struct mbuf_chain *mbc,
  72     unsigned char *mac_sig,
  73     unsigned char *sr_sig)
  74 {
  75         struct smb_sign *sign = &sr->session->signing;
  76         uint32_t i, t;
  77 
  78         for (i = 1; i < smb_sign_debug_search; i++) {
  79                 t = sr->sr_seqnum + i;
  80                 (void) smb_sign_calc(sr, mbc, t, mac_sig);
  81                 if (memcmp(mac_sig, sr_sig, SMB_SIG_SIZE) == 0) {
  82                         goto found;
  83                 }
  84                 t = sr->sr_seqnum - i;
  85                 (void) smb_sign_calc(sr, mbc, t, mac_sig);
  86                 if (memcmp(mac_sig, sr_sig, SMB_SIG_SIZE) == 0) {
  87                         goto found;
  88                 }
  89         }
  90         cmn_err(CE_WARN, "smb_sign_find_seqnum: failed after %d", i);
  91         return (-1);
  92 
  93 found:
  94         cmn_err(CE_WARN, "smb_sign_find_seqnum: found! %d <- %d",
  95             sign->seqnum, t);
  96         sign->seqnum = t;
  97         return (0);
  98 }
  99 #endif
 100 
 101 /*
 102  * Called during session destroy.
 103  */
 104 static void
 105 smb_sign_fini(smb_session_t *s)
 106 {
 107         smb_sign_mech_t *mech;
 108 
 109         if ((mech = s->sign_mech) != NULL) {
 110                 kmem_free(mech, sizeof (*mech));
 111                 s->sign_mech = NULL;
 112         }
 113 }
 114 
 115 /*
 116  * smb_sign_begin
 117  *
 118  * Intializes MAC key based on the user session key and
 119  * NTLM response and store it in the signing structure.
 120  * This is what begins SMB signing.
 121  */
 122 int
 123 smb_sign_begin(smb_request_t *sr, smb_token_t *token)
 124 {
 125         smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup;
 126         smb_session_t *session = sr->session;
 127         struct smb_sign *sign = &session->signing;
 128         smb_sign_mech_t *mech;
 129         int rc;
 130 
 131         /*
 132          * We should normally have a session key here because
 133          * our caller filters out Anonymous and Guest logons.
 134          * However, buggy clients could get us here without a
 135          * session key, in which case: just don't sign.
 136          */
 137         if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0)
 138                 return (0);
 139 
 140         /*
 141          * Session-level initialization (once per session)
 142          */
 143         smb_rwx_rwenter(&session->s_lock, RW_WRITER);
 144 
 145         /*
 146          * Signing may already have been setup by a prior logon,
 147          * in which case we're done here.
 148          */
 149         if (sign->mackey != NULL) {
 150                 smb_rwx_rwexit(&session->s_lock);
 151                 return (0);
 152         }
 153 
 154         /*
 155          * Get the mech handle
 156          */
 157         if (session->sign_mech == NULL) {
 158                 mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
 159                 rc = smb_md5_getmech(mech);
 160                 if (rc != 0) {
 161                         kmem_free(mech, sizeof (*mech));
 162                         smb_rwx_rwexit(&session->s_lock);
 163                         return (rc);
 164                 }
 165                 session->sign_mech = mech;
 166                 session->sign_fini = smb_sign_fini;
 167         }
 168 
 169         /*
 170          * Compute and store the signing (MAC) key.
 171          *
 172          * With extended security, the MAC key is the same as the
 173          * session key (and we'll have sinfo->ssi_ntpwlen == 0).
 174          * With non-extended security, it's the concatenation of
 175          * the session key and the "NT response" we received.
 176          */
 177         sign->mackey_len = token->tkn_ssnkey.len + sinfo->ssi_ntpwlen;
 178         sign->mackey = kmem_alloc(sign->mackey_len, KM_SLEEP);
 179         bcopy(token->tkn_ssnkey.val, sign->mackey, token->tkn_ssnkey.len);
 180         if (sinfo->ssi_ntpwlen > 0) {
 181                 bcopy(sinfo->ssi_ntpwd, sign->mackey + token->tkn_ssnkey.len,
 182                     sinfo->ssi_ntpwlen);
 183         }
 184 
 185         session->signing.seqnum = 0;
 186         sr->sr_seqnum = 2;
 187         sr->reply_seqnum = 1;
 188         sign->flags = 0;
 189 
 190         if (session->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
 191                 sign->flags |= SMB_SIGNING_ENABLED;
 192                 if (session->secmode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)
 193                         sign->flags |= SMB_SIGNING_CHECK;
 194         }
 195 
 196         smb_rwx_rwexit(&session->s_lock);
 197         return (0);
 198 }
 199 
 200 /*
 201  * smb_sign_calc
 202  *
 203  * Calculates MAC signature for the given buffer and returns
 204  * it in the mac_sign parameter.
 205  *
 206  * The sequence number is placed in the first four bytes of the signature
 207  * field of the signature and the other 4 bytes are zeroed.
 208  * The signature is the first 8 bytes of the MD5 result of the
 209  * concatenated MAC key and the SMB message.
 210  *
 211  * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8)
 212  *
 213  * where
 214  *
 215  *      MACKey = concat( UserSessionKey, NTLMResp )
 216  *
 217  * and
 218  *
 219  *      SMBMsg is the SMB message containing the sequence number.
 220  *
 221  * Return 0 if success
 222  *
 223  */
 224 static int
 225 smb_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc,
 226     uint32_t seqnum, unsigned char *mac_sign)
 227 {
 228         smb_session_t *s = sr->session;
 229         struct smb_sign *sign = &s->signing;
 230         smb_sign_ctx_t ctx = 0;
 231         uchar_t digest[MD5_DIGEST_LENGTH];
 232         uchar_t *hdrp;
 233         struct mbuf *mbuf = mbc->chain;
 234         int offset = mbc->chain_offset;
 235         int size;
 236         int rc;
 237 
 238         /*
 239          * This union is a little bit of trickery to:
 240          * (1) get the sequence number int aligned, and
 241          * (2) reduce the number of digest calls, at the
 242          * cost of a copying 32 bytes instead of 8.
 243          * Both sides of this union are 2+32 bytes.
 244          */
 245         union {
 246                 struct {
 247                         uint8_t skip[2]; /* not used - just alignment */
 248                         uint8_t raw[SMB_HDRLEN];  /* header length (32) */
 249                 } r;
 250                 struct {
 251                         uint8_t skip[2]; /* not used - just alignment */
 252                         uint8_t hdr[SMB_SIG_OFFS]; /* sig. offset (14) */
 253                         uint32_t sig[2]; /* MAC signature, aligned! */
 254                         uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
 255                 } s;
 256         } smbhdr;
 257 
 258         if (s->sign_mech == NULL || sign->mackey == NULL)
 259                 return (-1);
 260 
 261         if ((rc = smb_md5_init(&ctx, s->sign_mech)) != 0)
 262                 return (rc);
 263 
 264         /* Digest the MAC Key */
 265         rc = smb_md5_update(ctx, sign->mackey, sign->mackey_len);
 266         if (rc != 0)
 267                 return (rc);
 268 
 269         /*
 270          * Make an aligned copy of the SMB header,
 271          * fill in the sequence number, and digest.
 272          */
 273         hdrp = (unsigned char *)&smbhdr.r.raw;
 274         size = SMB_HDRLEN;
 275         if (smb_mbc_peek(mbc, offset, "#c", size, hdrp) != 0)
 276                 return (-1);
 277         smbhdr.s.sig[0] = htolel(seqnum);
 278         smbhdr.s.sig[1] = 0;
 279 
 280         rc = smb_md5_update(ctx, &smbhdr.r.raw, size);
 281         if (rc != 0)
 282                 return (rc);
 283 
 284         /*
 285          * Digest the rest of the SMB packet, starting at the data
 286          * just after the SMB header.
 287          */
 288         offset += size;
 289         while (mbuf != NULL && (offset >= mbuf->m_len)) {
 290                 offset -= mbuf->m_len;
 291                 mbuf = mbuf->m_next;
 292         }
 293         if (mbuf != NULL && (size = (mbuf->m_len - offset)) > 0) {
 294                 rc = smb_md5_update(ctx, &mbuf->m_data[offset], size);
 295                 if (rc != 0)
 296                         return (rc);
 297                 offset = 0;
 298                 mbuf = mbuf->m_next;
 299         }
 300         while (mbuf != NULL) {
 301                 rc = smb_md5_update(ctx, mbuf->m_data, mbuf->m_len);
 302                 if (rc != 0)
 303                         return (rc);
 304                 mbuf = mbuf->m_next;
 305         }
 306         rc = smb_md5_final(ctx, digest);
 307         if (rc == 0)
 308                 bcopy(digest, mac_sign, SMB_SIG_SIZE);
 309 
 310         return (rc);
 311 }
 312 
 313 
 314 /*
 315  * smb_sign_check_request
 316  *
 317  * Calculates MAC signature for the request mbuf chain
 318  * using the next expected sequence number and compares
 319  * it to the given signature.
 320  *
 321  * Note it does not check the signature for secondary transactions
 322  * as their sequence number is the same as the original request.
 323  *
 324  * Return 0 if the signature verifies, otherwise, returns -1;
 325  *
 326  */
 327 int
 328 smb_sign_check_request(smb_request_t *sr)
 329 {
 330         struct mbuf_chain mbc = sr->command;
 331         unsigned char mac_sig[SMB_SIG_SIZE];
 332 
 333         /*
 334          * Don't check secondary transactions - we dont know the sequence
 335          * number.
 336          */
 337         if (sr->smb_com == SMB_COM_TRANSACTION_SECONDARY ||
 338             sr->smb_com == SMB_COM_TRANSACTION2_SECONDARY ||
 339             sr->smb_com == SMB_COM_NT_TRANSACT_SECONDARY)
 340                 return (0);
 341 
 342         /* Reset the offset to begining of header */
 343         mbc.chain_offset = sr->orig_request_hdr;
 344 
 345         /* calculate mac signature */
 346         if (smb_sign_calc(sr, &mbc, sr->sr_seqnum, mac_sig) != 0)
 347                 return (-1);
 348 
 349         /* compare the signatures */
 350         if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) == 0) {
 351                 /* They match! OK, we're done. */
 352                 return (0);
 353         }
 354 
 355         DTRACE_PROBE2(smb__signature__mismatch, smb_request_t, sr,
 356             unsigned char *, mac_sig);
 357         cmn_err(CE_NOTE, "smb_sign_check_request: bad signature");
 358 
 359         /*
 360          * check nearby sequence numbers in debug mode
 361          */
 362 #ifdef  DEBUG
 363         if (smb_sign_debug) {
 364                 return (smb_sign_find_seqnum(sr, &mbc, mac_sig, sr->smb_sig));
 365         }
 366 #endif
 367         return (-1);
 368 }
 369 
 370 /*
 371  * smb_sign_check_secondary
 372  *
 373  * Calculates MAC signature for the secondary transaction mbuf chain
 374  * and compares it to the given signature.
 375  * Return 0 if the signature verifies, otherwise, returns -1;
 376  *
 377  */
 378 int
 379 smb_sign_check_secondary(smb_request_t *sr, unsigned int reply_seqnum)
 380 {
 381         struct mbuf_chain mbc = sr->command;
 382         unsigned char mac_sig[SMB_SIG_SIZE];
 383         int rtn = 0;
 384 
 385         /* Reset the offset to begining of header */
 386         mbc.chain_offset = sr->orig_request_hdr;
 387 
 388         /* calculate mac signature */
 389         if (smb_sign_calc(sr, &mbc, reply_seqnum - 1, mac_sig) != 0)
 390                 return (-1);
 391 
 392 
 393         /* compare the signatures */
 394         if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) {
 395                 cmn_err(CE_WARN, "SmbSignCheckSecond: bad signature");
 396                 rtn = -1;
 397         }
 398         /* Save the reply sequence number */
 399         sr->reply_seqnum = reply_seqnum;
 400 
 401         return (rtn);
 402 }
 403 
 404 /*
 405  * smb_sign_reply
 406  *
 407  * Calculates MAC signature for the given mbuf chain,
 408  * and write it to the signature field in the mbuf.
 409  *
 410  */
 411 void
 412 smb_sign_reply(smb_request_t *sr, struct mbuf_chain *reply)
 413 {
 414         struct mbuf_chain mbc;
 415         unsigned char mac[SMB_SIG_SIZE];
 416 
 417         if (reply)
 418                 mbc = *reply;
 419         else
 420                 mbc = sr->reply;
 421 
 422         /* Reset offset to start of reply */
 423         mbc.chain_offset = 0;
 424 
 425         /*
 426          * Calculate MAC signature
 427          */
 428         if (smb_sign_calc(sr, &mbc, sr->reply_seqnum, mac) != 0) {
 429                 cmn_err(CE_WARN, "smb_sign_reply: error in smb_sign_calc");
 430                 return;
 431         }
 432 
 433         /*
 434          * Put signature in the response
 435          */
 436         (void) smb_mbc_poke(&mbc, SMB_SIG_OFFS, "#c",
 437             SMB_SIG_SIZE, mac);
 438 }