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