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