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