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