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 2011 Nexenta Systems, Inc. All rights reserved. 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. 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/msgbuf.h> 44 #include <sys/crypto/api.h> 45 46 #define SMBAUTH_SESSION_KEY_SZ 16 47 #define SMB_SIG_SIZE 8 48 #define SMB_SIG_OFFS 14 49 50 int 51 smb_sign_calc(struct mbuf_chain *mbc, 52 struct smb_sign *sign, 53 uint32_t seqnum, 54 unsigned char *mac_sign); 55 56 #ifdef DEBUG 57 void smb_sign_find_seqnum( 58 uint32_t seqnum, 59 struct smb_sign *sign, 60 struct mbuf_chain *command, 61 unsigned char *mac_sig, 62 unsigned char *sr_sig, 63 boolean_t *found); 64 #define SMB_CHECK_SEQNUM(seqnum, sign, command, mac_sig, sr_sig, found) \ 65 { \ 66 if (smb_sign_debug) \ 67 smb_sign_find_seqnum(seqnum, sign, \ 68 command, mac_sig, sr_sig, found); \ 69 } 70 #else 71 #define SMB_CHECK_SEQNUM(seqnum, sign, command, mac_sig, sr_sig, found) \ 72 { \ 73 *found = 0; \ 74 } 75 #endif 76 77 #ifdef DEBUG 78 void 79 smb_sign_find_seqnum( 80 uint32_t seqnum, 81 struct smb_sign *sign, 82 struct mbuf_chain *command, 83 unsigned char *mac_sig, 84 unsigned char *sr_sig, 85 boolean_t *found) 86 { 87 int start_seqnum; 88 int i; 89 90 /* Debug code to hunt for the sequence number */ 91 *found = B_FALSE; 92 start_seqnum = seqnum - 10; 93 if (start_seqnum < 0) 94 start_seqnum = 0; 95 for (i = start_seqnum; i <= start_seqnum + 20; i++) { 96 (void) smb_sign_calc(command, sign, i, mac_sig); 97 if (memcmp(mac_sig, sr_sig, SMB_SIG_SIZE) == 0) { 98 sign->seqnum = i; 99 *found = B_TRUE; 100 break; 101 } 102 cmn_err(CE_WARN, "smb_sign_find_seqnum: seqnum:%d mismatch", i); 103 } 104 cmn_err(CE_WARN, "smb_sign_find_seqnum: found=%d", *found); 105 } 106 #endif 107 108 /* This holds the MD5 mechanism */ 109 static crypto_mechanism_t crypto_mech = {CRYPTO_MECHANISM_INVALID, 0, 0}; 110 111 void 112 smb_sign_g_init(void) 113 { 114 /* 115 * Initialise the crypto mechanism to MD5 if it not 116 * already initialised. 117 */ 118 if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) { 119 crypto_mech.cm_type = crypto_mech2id(SUN_CKM_MD5); 120 } 121 } 122 123 /* 124 * smb_sign_init 125 * 126 * Intializes MAC key based on the user session key and 127 * NTLM response and store it in the signing structure. 128 */ 129 void 130 smb_sign_init(smb_request_t *sr, smb_session_key_t *session_key, 131 char *resp, int resp_len) 132 { 133 struct smb_sign *sign = &sr->session->signing; 134 135 if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) { 136 /* 137 * There is no MD5 crypto mechanism 138 * so turn off signing 139 */ 140 sr->sr_cfg->skc_signing_enable = 0; 141 sr->session->secmode &= 142 (~NEGOTIATE_SECURITY_SIGNATURES_ENABLED); 143 cmn_err(CE_WARN, 144 "SmbSignInit: signing disabled (no MD5)"); 145 return; 146 } 147 148 /* MAC key = concat (SessKey, NTLMResponse) */ 149 150 bcopy(session_key, sign->mackey, sizeof (smb_session_key_t)); 151 bcopy(resp, &(sign->mackey[sizeof (smb_session_key_t)]), 152 resp_len); 153 sign->mackey_len = sizeof (smb_session_key_t) + resp_len; 154 155 sr->session->signing.seqnum = 0; 156 sr->sr_seqnum = 2; 157 sr->reply_seqnum = 1; 158 sign->flags = SMB_SIGNING_ENABLED; 159 } 160 161 /* 162 * smb_sign_calc 163 * 164 * Calculates MAC signature for the given buffer and returns 165 * it in the mac_sign parameter. 166 * 167 * The sequence number is placed in the first four bytes of the signature 168 * field of the signature and the other 4 bytes are zeroed. 169 * The signature is the first 8 bytes of the MD5 result of the 170 * concatenated MAC key and the SMB message. 171 * 172 * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8) 173 * 174 * where 175 * 176 * MACKey = concat( UserSessionKey, NTLMResp ) 177 * 178 * and 179 * 180 * SMBMsg is the SMB message containing the sequence number. 181 * 182 * Return 0 if success else -1 183 * 184 */ 185 int 186 smb_sign_calc(struct mbuf_chain *mbc, 187 struct smb_sign *sign, 188 uint32_t seqnum, 189 unsigned char *mac_sign) 190 { 191 uint32_t seq_buf[2] = {0, 0}; 192 unsigned char mac[16]; 193 struct mbuf *mbuf = mbc->chain; 194 int offset = mbc->chain_offset; 195 int size; 196 int status; 197 198 crypto_data_t data; 199 crypto_data_t digest; 200 crypto_context_t crypto_ctx; 201 202 data.cd_format = CRYPTO_DATA_RAW; 203 data.cd_offset = 0; 204 data.cd_length = (size_t)-1; 205 data.cd_miscdata = 0; 206 207 digest.cd_format = CRYPTO_DATA_RAW; 208 digest.cd_offset = 0; 209 digest.cd_length = (size_t)-1; 210 digest.cd_miscdata = 0; 211 digest.cd_raw.iov_base = (char *)mac; 212 digest.cd_raw.iov_len = sizeof (mac); 213 214 status = crypto_digest_init(&crypto_mech, &crypto_ctx, 0); 215 if (status != CRYPTO_SUCCESS) 216 goto error; 217 218 /* 219 * Put the sequence number into the first 4 bytes 220 * of the signature field in little endian format. 221 * We are using a buffer to represent the signature 222 * rather than modifying the SMB message. 223 */ 224 #ifdef __sparc 225 { 226 uint32_t temp; 227 ((uint8_t *)&temp)[0] = ((uint8_t *)&seqnum)[3]; 228 ((uint8_t *)&temp)[1] = ((uint8_t *)&seqnum)[2]; 229 ((uint8_t *)&temp)[2] = ((uint8_t *)&seqnum)[1]; 230 ((uint8_t *)&temp)[3] = ((uint8_t *)&seqnum)[0]; 231 232 seq_buf[0] = temp; 233 } 234 #else 235 seq_buf[0] = seqnum; 236 #endif 237 238 /* Digest the MACKey */ 239 data.cd_raw.iov_base = (char *)sign->mackey; 240 data.cd_raw.iov_len = sign->mackey_len; 241 data.cd_length = sign->mackey_len; 242 status = crypto_digest_update(crypto_ctx, &data, 0); 243 if (status != CRYPTO_SUCCESS) 244 goto error; 245 246 /* Find start of data in chain */ 247 while (offset >= mbuf->m_len) { 248 offset -= mbuf->m_len; 249 mbuf = mbuf->m_next; 250 } 251 252 /* Digest the SMB packet up to the signature field */ 253 size = SMB_SIG_OFFS; 254 while (size >= mbuf->m_len - offset) { 255 data.cd_raw.iov_base = &mbuf->m_data[offset]; 256 data.cd_raw.iov_len = mbuf->m_len - offset; 257 data.cd_length = mbuf->m_len - offset; 258 status = crypto_digest_update(crypto_ctx, &data, 0); 259 if (status != CRYPTO_SUCCESS) 260 goto error; 261 262 size -= mbuf->m_len - offset; 263 mbuf = mbuf->m_next; 264 offset = 0; 265 } 266 if (size > 0) { 267 data.cd_raw.iov_base = &mbuf->m_data[offset]; 268 data.cd_raw.iov_len = size; 269 data.cd_length = size; 270 status = crypto_digest_update(crypto_ctx, &data, 0); 271 if (status != CRYPTO_SUCCESS) 272 goto error; 273 offset += size; 274 } 275 276 /* 277 * Digest in the seq_buf instead of the signature 278 * which has the sequence number 279 */ 280 281 data.cd_raw.iov_base = (char *)seq_buf; 282 data.cd_raw.iov_len = SMB_SIG_SIZE; 283 data.cd_length = SMB_SIG_SIZE; 284 status = crypto_digest_update(crypto_ctx, &data, 0); 285 if (status != CRYPTO_SUCCESS) 286 goto error; 287 288 /* Find the end of the signature field */ 289 offset += SMB_SIG_SIZE; 290 while (offset >= mbuf->m_len) { 291 offset -= mbuf->m_len; 292 mbuf = mbuf->m_next; 293 } 294 /* Digest the rest of the SMB packet */ 295 while (mbuf) { 296 data.cd_raw.iov_base = &mbuf->m_data[offset]; 297 data.cd_raw.iov_len = mbuf->m_len - offset; 298 data.cd_length = mbuf->m_len - offset; 299 status = crypto_digest_update(crypto_ctx, &data, 0); 300 if (status != CRYPTO_SUCCESS) 301 goto error; 302 mbuf = mbuf->m_next; 303 offset = 0; 304 } 305 digest.cd_length = SMBAUTH_SESSION_KEY_SZ; 306 status = crypto_digest_final(crypto_ctx, &digest, 0); 307 if (status != CRYPTO_SUCCESS) 308 goto error; 309 bcopy(mac, mac_sign, SMB_SIG_SIZE); 310 return (0); 311 error: 312 cmn_err(CE_WARN, "SmbSignCalc: crypto error %d", status); 313 return (-1); 314 315 } 316 317 318 /* 319 * smb_sign_check_request 320 * 321 * Calculates MAC signature for the request mbuf chain 322 * using the next expected sequence number and compares 323 * it to the given signature. 324 * 325 * Note it does not check the signature for secondary transactions 326 * as their sequence number is the same as the original request. 327 * 328 * Return 0 if the signature verifies, otherwise, returns -1; 329 * 330 */ 331 int 332 smb_sign_check_request(smb_request_t *sr) 333 { 334 struct mbuf_chain command = sr->command; 335 unsigned char mac_sig[SMB_SIG_SIZE]; 336 struct smb_sign *sign = &sr->session->signing; 337 int rtn = 0; 338 boolean_t found = B_TRUE; 339 340 /* 341 * Don't check secondary transactions - we dont know the sequence 342 * number. 343 */ 344 if (sr->smb_com == SMB_COM_TRANSACTION_SECONDARY || 345 sr->smb_com == SMB_COM_TRANSACTION2_SECONDARY || 346 sr->smb_com == SMB_COM_NT_TRANSACT_SECONDARY) 347 return (0); 348 349 /* Reset the offset to begining of header */ 350 command.chain_offset = sr->orig_request_hdr; 351 352 /* calculate mac signature */ 353 if (smb_sign_calc(&command, sign, sr->sr_seqnum, mac_sig) != 0) 354 return (-1); 355 356 /* compare the signatures */ 357 if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) { 358 DTRACE_PROBE2(smb__signing__req, smb_request_t, sr, 359 smb_sign_t *, sr->smb_sig); 360 cmn_err(CE_NOTE, "smb_sign_check_request: bad signature"); 361 /* 362 * check nearby sequence numbers in debug mode 363 */ 364 SMB_CHECK_SEQNUM(sr->sr_seqnum, sign, &command, 365 mac_sig, sr->smb_sig, &found); 366 if (found == B_FALSE) 367 rtn = -1; 368 } 369 return (rtn); 370 } 371 372 /* 373 * smb_sign_check_secondary 374 * 375 * Calculates MAC signature for the secondary transaction mbuf chain 376 * and compares it to the given signature. 377 * Return 0 if the signature verifies, otherwise, returns -1; 378 * 379 */ 380 int 381 smb_sign_check_secondary(smb_request_t *sr, unsigned int reply_seqnum) 382 { 383 struct mbuf_chain command = sr->command; 384 unsigned char mac_sig[SMB_SIG_SIZE]; 385 struct smb_sign *sign = &sr->session->signing; 386 int rtn = 0; 387 388 /* Reset the offset to begining of header */ 389 command.chain_offset = sr->orig_request_hdr; 390 391 /* calculate mac signature */ 392 if (smb_sign_calc(&command, sign, reply_seqnum - 1, 393 mac_sig) != 0) 394 return (-1); 395 396 397 /* compare the signatures */ 398 if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) { 399 cmn_err(CE_WARN, "SmbSignCheckSecond: bad signature"); 400 rtn = -1; 401 } 402 /* Save the reply sequence number */ 403 sr->reply_seqnum = reply_seqnum; 404 405 return (rtn); 406 } 407 408 /* 409 * smb_sign_reply 410 * 411 * Calculates MAC signature for the given mbuf chain, 412 * and write it to the signature field in the mbuf. 413 * 414 */ 415 void 416 smb_sign_reply(smb_request_t *sr, struct mbuf_chain *reply) 417 { 418 struct mbuf_chain resp; 419 struct smb_sign *sign = &sr->session->signing; 420 unsigned char signature[SMB_SIG_SIZE]; 421 struct mbuf *mbuf; 422 int size = SMB_SIG_SIZE; 423 unsigned char *sig_ptr = signature; 424 int offset = 0; 425 426 if (reply) 427 resp = *reply; 428 else 429 resp = sr->reply; 430 431 /* Reset offset to start of reply */ 432 resp.chain_offset = 0; 433 mbuf = resp.chain; 434 435 /* 436 * Calculate MAC signature 437 */ 438 if (smb_sign_calc(&resp, sign, sr->reply_seqnum, signature) != 0) { 439 cmn_err(CE_WARN, "smb_sign_reply: error in smb_sign_calc"); 440 return; 441 } 442 443 /* 444 * Put signature in the response 445 * 446 * First find start of signature in chain (offset + signature offset) 447 */ 448 offset += SMB_SIG_OFFS; 449 while (offset >= mbuf->m_len) { 450 offset -= mbuf->m_len; 451 mbuf = mbuf->m_next; 452 } 453 454 while (size >= mbuf->m_len - offset) { 455 (void) memcpy(&mbuf->m_data[offset], 456 sig_ptr, mbuf->m_len - offset); 457 offset = 0; 458 sig_ptr += mbuf->m_len - offset; 459 size -= mbuf->m_len - offset; 460 mbuf = mbuf->m_next; 461 } 462 if (size > 0) { 463 (void) memcpy(&mbuf->m_data[offset], sig_ptr, size); 464 } 465 } 466