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 2017 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 void 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; 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; 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; 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 } 198 199 /* 200 * smb_sign_calc 201 * 202 * Calculates MAC signature for the given buffer and returns 203 * it in the mac_sign parameter. 204 * 205 * The sequence number is placed in the first four bytes of the signature 206 * field of the signature and the other 4 bytes are zeroed. 207 * The signature is the first 8 bytes of the MD5 result of the 208 * concatenated MAC key and the SMB message. 209 * 210 * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8) 211 * 212 * where 213 * 214 * MACKey = concat( UserSessionKey, NTLMResp ) 215 * 216 * and 217 * 218 * SMBMsg is the SMB message containing the sequence number. 219 * 220 * Return 0 if success 221 * 222 */ 223 static int 224 smb_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc, 225 uint32_t seqnum, unsigned char *mac_sign) 226 { 227 smb_session_t *s = sr->session; 228 struct smb_sign *sign = &s->signing; 229 smb_sign_ctx_t ctx = 0; 230 uchar_t digest[MD5_DIGEST_LENGTH]; 231 uchar_t *hdrp; 232 struct mbuf *mbuf = mbc->chain; 233 int offset = mbc->chain_offset; 234 int size; 235 int rc; 236 237 /* 238 * This union is a little bit of trickery to: 239 * (1) get the sequence number int aligned, and 240 * (2) reduce the number of digest calls, at the 241 * cost of a copying 32 bytes instead of 8. 242 * Both sides of this union are 2+32 bytes. 243 */ 244 union { 245 struct { 246 uint8_t skip[2]; /* not used - just alignment */ 247 uint8_t raw[SMB_HDRLEN]; /* header length (32) */ 248 } r; 249 struct { 250 uint8_t skip[2]; /* not used - just alignment */ 251 uint8_t hdr[SMB_SIG_OFFS]; /* sig. offset (14) */ 252 uint32_t sig[2]; /* MAC signature, aligned! */ 253 uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */ 254 } s; 255 } smbhdr; 256 257 if (s->sign_mech == NULL || sign->mackey == NULL) 258 return (-1); 259 260 if ((rc = smb_md5_init(&ctx, s->sign_mech)) != 0) 261 return (rc); 262 263 /* Digest the MAC Key */ 264 rc = smb_md5_update(ctx, sign->mackey, sign->mackey_len); 265 if (rc != 0) 266 return (rc); 267 268 /* 269 * Make an aligned copy of the SMB header, 270 * fill in the sequence number, and digest. 271 */ 272 hdrp = (unsigned char *)&smbhdr.r.raw; 273 size = SMB_HDRLEN; 274 if (smb_mbc_peek(mbc, offset, "#c", size, hdrp) != 0) 275 return (-1); 276 smbhdr.s.sig[0] = htolel(seqnum); 277 smbhdr.s.sig[1] = 0; 278 279 rc = smb_md5_update(ctx, &smbhdr.r.raw, size); 280 if (rc != 0) 281 return (rc); 282 283 /* 284 * Digest the rest of the SMB packet, starting at the data 285 * just after the SMB header. 286 */ 287 offset += size; 288 while (mbuf != NULL && (offset >= mbuf->m_len)) { 289 offset -= mbuf->m_len; 290 mbuf = mbuf->m_next; 291 } 292 if (mbuf != NULL && (size = (mbuf->m_len - offset)) > 0) { 293 rc = smb_md5_update(ctx, &mbuf->m_data[offset], size); 294 if (rc != 0) 295 return (rc); 296 offset = 0; 297 mbuf = mbuf->m_next; 298 } 299 while (mbuf != NULL) { 300 rc = smb_md5_update(ctx, mbuf->m_data, mbuf->m_len); 301 if (rc != 0) 302 return (rc); 303 mbuf = mbuf->m_next; 304 } 305 rc = smb_md5_final(ctx, digest); 306 if (rc == 0) 307 bcopy(digest, mac_sign, SMB_SIG_SIZE); 308 309 return (rc); 310 } 311 312 313 /* 314 * smb_sign_check_request 315 * 316 * Calculates MAC signature for the request mbuf chain 317 * using the next expected sequence number and compares 318 * it to the given signature. 319 * 320 * Note it does not check the signature for secondary transactions 321 * as their sequence number is the same as the original request. 322 * 323 * Return 0 if the signature verifies, otherwise, returns -1; 324 * 325 */ 326 int 327 smb_sign_check_request(smb_request_t *sr) 328 { 329 struct mbuf_chain mbc = sr->command; 330 unsigned char mac_sig[SMB_SIG_SIZE]; 331 332 /* 333 * Don't check secondary transactions - we dont know the sequence 334 * number. 335 */ 336 if (sr->smb_com == SMB_COM_TRANSACTION_SECONDARY || 337 sr->smb_com == SMB_COM_TRANSACTION2_SECONDARY || 338 sr->smb_com == SMB_COM_NT_TRANSACT_SECONDARY) 339 return (0); 340 341 /* Reset the offset to begining of header */ 342 mbc.chain_offset = sr->orig_request_hdr; 343 344 /* calculate mac signature */ 345 if (smb_sign_calc(sr, &mbc, sr->sr_seqnum, mac_sig) != 0) 346 return (-1); 347 348 /* compare the signatures */ 349 if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) == 0) { 350 /* They match! OK, we're done. */ 351 return (0); 352 } 353 354 DTRACE_PROBE2(smb__signature__mismatch, smb_request_t, sr, 355 unsigned char *, mac_sig); 356 cmn_err(CE_NOTE, "smb_sign_check_request: bad signature"); 357 358 /* 359 * check nearby sequence numbers in debug mode 360 */ 361 #ifdef DEBUG 362 if (smb_sign_debug) { 363 return (smb_sign_find_seqnum(sr, &mbc, mac_sig, sr->smb_sig)); 364 } 365 #endif 366 return (-1); 367 } 368 369 /* 370 * smb_sign_check_secondary 371 * 372 * Calculates MAC signature for the secondary transaction mbuf chain 373 * and compares it to the given signature. 374 * Return 0 if the signature verifies, otherwise, returns -1; 375 * 376 */ 377 int 378 smb_sign_check_secondary(smb_request_t *sr, unsigned int reply_seqnum) 379 { 380 struct mbuf_chain mbc = sr->command; 381 unsigned char mac_sig[SMB_SIG_SIZE]; 382 int rtn = 0; 383 384 /* Reset the offset to begining of header */ 385 mbc.chain_offset = sr->orig_request_hdr; 386 387 /* calculate mac signature */ 388 if (smb_sign_calc(sr, &mbc, reply_seqnum - 1, mac_sig) != 0) 389 return (-1); 390 391 392 /* compare the signatures */ 393 if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) { 394 cmn_err(CE_WARN, "SmbSignCheckSecond: bad signature"); 395 rtn = -1; 396 } 397 /* Save the reply sequence number */ 398 sr->reply_seqnum = reply_seqnum; 399 400 return (rtn); 401 } 402 403 /* 404 * smb_sign_reply 405 * 406 * Calculates MAC signature for the given mbuf chain, 407 * and write it to the signature field in the mbuf. 408 * 409 */ 410 void 411 smb_sign_reply(smb_request_t *sr, struct mbuf_chain *reply) 412 { 413 struct mbuf_chain mbc; 414 unsigned char mac[SMB_SIG_SIZE]; 415 416 if (reply) 417 mbc = *reply; 418 else 419 mbc = sr->reply; 420 421 /* Reset offset to start of reply */ 422 mbc.chain_offset = 0; 423 424 /* 425 * Calculate MAC signature 426 */ 427 if (smb_sign_calc(sr, &mbc, sr->reply_seqnum, mac) != 0) { 428 cmn_err(CE_WARN, "smb_sign_reply: error in smb_sign_calc"); 429 return; 430 } 431 432 /* 433 * Put signature in the response 434 */ 435 (void) smb_mbc_poke(&mbc, SMB_SIG_OFFS, "#c", 436 SMB_SIG_SIZE, mac); 437 } 438