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