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