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