15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 22*10966SJordan.Brown@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw /* 275331Samw * These routines provide the SMB MAC signing for the SMB server. 285331Samw * The routines calculate the signature of a SMB message in an mbuf chain. 295331Samw * 307348SJose.Borrego@Sun.COM * The following table describes the client server 317348SJose.Borrego@Sun.COM * signing registry relationship 327348SJose.Borrego@Sun.COM * 337348SJose.Borrego@Sun.COM * | Required | Enabled | Disabled 347348SJose.Borrego@Sun.COM * -------------+---------------+------------ +-------------- 357348SJose.Borrego@Sun.COM * Required | Signed | Signed | Fail 367348SJose.Borrego@Sun.COM * -------------+---------------+-------------+----------------- 377348SJose.Borrego@Sun.COM * Enabled | Signed | Signed | Not Signed 387348SJose.Borrego@Sun.COM * -------------+---------------+-------------+---------------- 397348SJose.Borrego@Sun.COM * Disabled | Fail | Not Signed | Not Signed 405331Samw */ 415331Samw 425331Samw #include <sys/uio.h> 43*10966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h> 445331Samw #include <smbsrv/msgbuf.h> 455331Samw #include <sys/crypto/api.h> 465331Samw 476600Sas200622 #define SMBAUTH_SESSION_KEY_SZ 16 485331Samw #define SMB_SIG_SIZE 8 495331Samw #define SMB_SIG_OFFS 14 505331Samw 517348SJose.Borrego@Sun.COM int 527348SJose.Borrego@Sun.COM smb_sign_calc(struct mbuf_chain *mbc, 537348SJose.Borrego@Sun.COM struct smb_sign *sign, 547348SJose.Borrego@Sun.COM uint32_t seqnum, 557348SJose.Borrego@Sun.COM unsigned char *mac_sign); 567348SJose.Borrego@Sun.COM 577348SJose.Borrego@Sun.COM #ifdef DEBUG 587348SJose.Borrego@Sun.COM void smb_sign_find_seqnum( 597348SJose.Borrego@Sun.COM struct smb_sign *sign, 607348SJose.Borrego@Sun.COM struct mbuf_chain *command, 617348SJose.Borrego@Sun.COM unsigned char *mac_sig, 627348SJose.Borrego@Sun.COM unsigned char *sr_sig, 637348SJose.Borrego@Sun.COM boolean_t *found); 647348SJose.Borrego@Sun.COM 657348SJose.Borrego@Sun.COM #define SMB_CHECK_SEQNUM(sign, command, mac_sig, sr_sig, found) \ 667348SJose.Borrego@Sun.COM { \ 677348SJose.Borrego@Sun.COM if (smb_sign_debug) \ 687348SJose.Borrego@Sun.COM smb_sign_find_seqnum(sign, command, mac_sig, sr_sig, found); \ 697348SJose.Borrego@Sun.COM } 707348SJose.Borrego@Sun.COM #else 717348SJose.Borrego@Sun.COM #define SMB_CHECK_SEQNUM(sign, command, mac_sig, sr_sig, found) \ 727348SJose.Borrego@Sun.COM { } 737348SJose.Borrego@Sun.COM #endif 747348SJose.Borrego@Sun.COM 757348SJose.Borrego@Sun.COM #ifdef DEBUG 767348SJose.Borrego@Sun.COM void 777348SJose.Borrego@Sun.COM smb_sign_find_seqnum( 787348SJose.Borrego@Sun.COM struct smb_sign *sign, 797348SJose.Borrego@Sun.COM struct mbuf_chain *command, 807348SJose.Borrego@Sun.COM unsigned char *mac_sig, 817348SJose.Borrego@Sun.COM unsigned char *sr_sig, 827348SJose.Borrego@Sun.COM boolean_t *found) 837348SJose.Borrego@Sun.COM { 847348SJose.Borrego@Sun.COM int start_seqnum; 857348SJose.Borrego@Sun.COM int i; 867348SJose.Borrego@Sun.COM 877348SJose.Borrego@Sun.COM /* Debug code to hunt for the sequence number */ 887348SJose.Borrego@Sun.COM *found = B_FALSE; 897348SJose.Borrego@Sun.COM start_seqnum = (int)sign->seqnum - 6; 907348SJose.Borrego@Sun.COM if (start_seqnum < 0) 917348SJose.Borrego@Sun.COM start_seqnum = 0; 927348SJose.Borrego@Sun.COM for (i = start_seqnum; i <= start_seqnum + 6; i++) { 937639SNick.Todd@Sun.COM (void) smb_sign_calc(command, sign, i, mac_sig); 947348SJose.Borrego@Sun.COM if (memcmp(mac_sig, sr_sig, SMB_SIG_SIZE) == 0) { 957348SJose.Borrego@Sun.COM sign->seqnum = i; 967348SJose.Borrego@Sun.COM *found = B_TRUE; 977348SJose.Borrego@Sun.COM break; 987348SJose.Borrego@Sun.COM } 997348SJose.Borrego@Sun.COM cmn_err(CE_WARN, "smb_sign_find_seqnum: seqnum%d mismatch", i); 1007348SJose.Borrego@Sun.COM } 1017348SJose.Borrego@Sun.COM cmn_err(CE_WARN, "smb_sign_find_seqnum: found=%d", *found); 1027348SJose.Borrego@Sun.COM } 1037348SJose.Borrego@Sun.COM #endif 1045331Samw /* This holds the MD5 mechanism */ 1055331Samw static crypto_mechanism_t crypto_mech = {CRYPTO_MECHANISM_INVALID, 0, 0}; 1065331Samw 1075331Samw /* 1085331Samw * smb_sign_init 1095331Samw * 1105331Samw * Intializes MAC key based on the user session key and 1115331Samw * NTLM response and store it in the signing structure. 1125331Samw */ 1135331Samw void 1146139Sjb150015 smb_sign_init(smb_request_t *sr, smb_session_key_t *session_key, 1155331Samw char *resp, int resp_len) 1165331Samw { 1176139Sjb150015 struct smb_sign *sign = &sr->session->signing; 1185331Samw 1195331Samw /* 1205331Samw * Initialise the crypto mechanism to MD5 if it not 1215331Samw * already initialised. 1225331Samw */ 1235331Samw if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) { 1245331Samw crypto_mech.cm_type = crypto_mech2id(SUN_CKM_MD5); 1255331Samw if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) { 1265331Samw /* 1275331Samw * There is no MD5 crypto mechanism 1285331Samw * so turn off signing 1295331Samw */ 1306139Sjb150015 sr->sr_cfg->skc_signing_enable = 0; 1316139Sjb150015 sr->session->secmode &= 1325331Samw (~NEGOTIATE_SECURITY_SIGNATURES_ENABLED); 1335331Samw cmn_err(CE_WARN, 1345331Samw "SmbSignInit: signing disabled (no MD5)"); 1355331Samw return; 1365331Samw } 1375331Samw } 1385331Samw 1395331Samw /* MAC key = concat (SessKey, NTLMResponse) */ 1405331Samw 1415331Samw bcopy(session_key, sign->mackey, sizeof (smb_session_key_t)); 1425331Samw bcopy(resp, &(sign->mackey[sizeof (smb_session_key_t)]), 1435331Samw resp_len); 1445331Samw sign->mackey_len = sizeof (smb_session_key_t) + resp_len; 1455331Samw 1466139Sjb150015 sr->reply_seqnum = 1; 1475331Samw sign->seqnum = 2; 1485331Samw sign->flags = SMB_SIGNING_ENABLED; 1495331Samw 1505331Samw } 1515331Samw 1525331Samw /* 1535331Samw * smb_sign_calc 1545331Samw * 1555331Samw * Calculates MAC signature for the given buffer and returns 1565331Samw * it in the mac_sign parameter. 1575331Samw * 1585331Samw * The sequence number is placed in the first four bytes of the signature 1595331Samw * field of the signature and the other 4 bytes are zeroed. 1605331Samw * The signature is the first 8 bytes of the MD5 result of the 1615331Samw * concatenated MAC key and the SMB message. 1625331Samw * 1635331Samw * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8) 1645331Samw * 1655331Samw * where 1665331Samw * 1675331Samw * MACKey = concat( UserSessionKey, NTLMResp ) 1685331Samw * 1695331Samw * and 1705331Samw * 1715331Samw * SMBMsg is the SMB message containing the sequence number. 1725331Samw * 1735331Samw * Return 0 if success else -1 1745331Samw * 1755331Samw */ 1767348SJose.Borrego@Sun.COM int 1775331Samw smb_sign_calc(struct mbuf_chain *mbc, 1785331Samw struct smb_sign *sign, 1795331Samw uint32_t seqnum, 1805331Samw unsigned char *mac_sign) 1815331Samw { 1825331Samw uint32_t seq_buf[2] = {0, 0}; 1835331Samw unsigned char mac[16]; 1845331Samw struct mbuf *mbuf = mbc->chain; 1855331Samw int offset = mbc->chain_offset; 1865331Samw int size; 1875331Samw int status; 1885331Samw 1895331Samw crypto_data_t data; 1905331Samw crypto_data_t digest; 1915331Samw crypto_context_t crypto_ctx; 1925331Samw 1935331Samw data.cd_format = CRYPTO_DATA_RAW; 1945331Samw data.cd_offset = 0; 1955331Samw data.cd_length = (size_t)-1; 1965331Samw data.cd_miscdata = 0; 1975331Samw 1985331Samw digest.cd_format = CRYPTO_DATA_RAW; 1995331Samw digest.cd_offset = 0; 2005331Samw digest.cd_length = (size_t)-1; 2015331Samw digest.cd_miscdata = 0; 2025331Samw digest.cd_raw.iov_base = (char *)mac; 2035331Samw digest.cd_raw.iov_len = sizeof (mac); 2045331Samw 2055331Samw status = crypto_digest_init(&crypto_mech, &crypto_ctx, 0); 2066600Sas200622 if (status != CRYPTO_SUCCESS) 2076600Sas200622 goto error; 2085331Samw 2095331Samw /* 2105331Samw * Put the sequence number into the first 4 bytes 2115331Samw * of the signature field in little endian format. 2125331Samw * We are using a buffer to represent the signature 2135331Samw * rather than modifying the SMB message. 2145331Samw */ 2155331Samw #ifdef __sparc 2165331Samw { 2175331Samw uint32_t temp; 2185331Samw ((uint8_t *)&temp)[0] = ((uint8_t *)&seqnum)[3]; 2195331Samw ((uint8_t *)&temp)[1] = ((uint8_t *)&seqnum)[2]; 2205331Samw ((uint8_t *)&temp)[2] = ((uint8_t *)&seqnum)[1]; 2215331Samw ((uint8_t *)&temp)[3] = ((uint8_t *)&seqnum)[0]; 2225331Samw 2235331Samw seq_buf[0] = temp; 2245331Samw } 2255331Samw #else 2265331Samw seq_buf[0] = seqnum; 2275331Samw #endif 2285331Samw 2295331Samw /* Digest the MACKey */ 2305331Samw data.cd_raw.iov_base = (char *)sign->mackey; 2315331Samw data.cd_raw.iov_len = sign->mackey_len; 2326600Sas200622 data.cd_length = sign->mackey_len; 2336600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 2346600Sas200622 if (status != CRYPTO_SUCCESS) 2356600Sas200622 goto error; 2365331Samw 2375331Samw /* Find start of data in chain */ 2385331Samw while (offset >= mbuf->m_len) { 2395331Samw offset -= mbuf->m_len; 2405331Samw mbuf = mbuf->m_next; 2415331Samw } 2425331Samw 2435331Samw /* Digest the SMB packet up to the signature field */ 2445331Samw size = SMB_SIG_OFFS; 2455331Samw while (size >= mbuf->m_len - offset) { 2465331Samw data.cd_raw.iov_base = &mbuf->m_data[offset]; 2475331Samw data.cd_raw.iov_len = mbuf->m_len - offset; 2486600Sas200622 data.cd_length = mbuf->m_len - offset; 2496600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 2506600Sas200622 if (status != CRYPTO_SUCCESS) 2516600Sas200622 goto error; 2525331Samw 2535331Samw size -= mbuf->m_len - offset; 2545331Samw mbuf = mbuf->m_next; 2555331Samw offset = 0; 2565331Samw } 2575331Samw if (size > 0) { 2585331Samw data.cd_raw.iov_base = &mbuf->m_data[offset]; 2595331Samw data.cd_raw.iov_len = size; 2606600Sas200622 data.cd_length = size; 2616600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 2626600Sas200622 if (status != CRYPTO_SUCCESS) 2636600Sas200622 goto error; 2645331Samw offset += size; 2655331Samw } 2665331Samw 2675331Samw /* 2685331Samw * Digest in the seq_buf instead of the signature 2695331Samw * which has the sequence number 2705331Samw */ 2715331Samw 2725331Samw data.cd_raw.iov_base = (char *)seq_buf; 2735331Samw data.cd_raw.iov_len = SMB_SIG_SIZE; 2746600Sas200622 data.cd_length = SMB_SIG_SIZE; 2756600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 2766600Sas200622 if (status != CRYPTO_SUCCESS) 2776600Sas200622 goto error; 2785331Samw 2795331Samw /* Find the end of the signature field */ 2805331Samw offset += SMB_SIG_SIZE; 2815331Samw while (offset >= mbuf->m_len) { 2825331Samw offset -= mbuf->m_len; 2835331Samw mbuf = mbuf->m_next; 2845331Samw } 2855331Samw /* Digest the rest of the SMB packet */ 2865331Samw while (mbuf) { 2875331Samw data.cd_raw.iov_base = &mbuf->m_data[offset]; 2885331Samw data.cd_raw.iov_len = mbuf->m_len - offset; 2896600Sas200622 data.cd_length = mbuf->m_len - offset; 2906600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 2916600Sas200622 if (status != CRYPTO_SUCCESS) 2926600Sas200622 goto error; 2935331Samw mbuf = mbuf->m_next; 2945331Samw offset = 0; 2955331Samw } 2966600Sas200622 digest.cd_length = SMBAUTH_SESSION_KEY_SZ; 2976600Sas200622 status = crypto_digest_final(crypto_ctx, &digest, 0); 2986600Sas200622 if (status != CRYPTO_SUCCESS) 2996600Sas200622 goto error; 3005331Samw bcopy(mac, mac_sign, SMB_SIG_SIZE); 3015331Samw return (0); 3025331Samw error: 3035331Samw cmn_err(CE_WARN, "SmbSignCalc: crypto error %d", status); 3045331Samw return (-1); 3055331Samw 3065331Samw } 3075331Samw 3085331Samw 3095331Samw /* 3105331Samw * smb_sign_check_request 3115331Samw * 3125331Samw * Calculates MAC signature for the request mbuf chain 3135331Samw * using the next expected sequence number and compares 3145331Samw * it to the given signature. 3155331Samw * 3165331Samw * Note it does not check the signature for secondary transactions 3175331Samw * as their sequence number is the same as the original request. 3185331Samw * 3195331Samw * Return 0 if the signature verifies, otherwise, returns -1; 3205331Samw * 3215331Samw */ 3225331Samw int 3236139Sjb150015 smb_sign_check_request(smb_request_t *sr) 3245331Samw { 3256139Sjb150015 struct mbuf_chain command = sr->command; 3265331Samw unsigned char mac_sig[SMB_SIG_SIZE]; 3276139Sjb150015 struct smb_sign *sign = &sr->session->signing; 3285331Samw int rtn = 0; 3297348SJose.Borrego@Sun.COM boolean_t found = B_TRUE; 3305331Samw /* 3315331Samw * Don't check secondary transactions - we dont know the sequence 3325331Samw * number. 3335331Samw */ 3346139Sjb150015 if (sr->smb_com == SMB_COM_TRANSACTION_SECONDARY || 3356139Sjb150015 sr->smb_com == SMB_COM_TRANSACTION2_SECONDARY || 3366139Sjb150015 sr->smb_com == SMB_COM_NT_TRANSACT_SECONDARY) 3375331Samw return (0); 3385331Samw 3397348SJose.Borrego@Sun.COM /* Reset the offset to begining of header */ 3407348SJose.Borrego@Sun.COM command.chain_offset = sr->orig_request_hdr; 3415331Samw 3427348SJose.Borrego@Sun.COM /* calculate mac signature */ 3437348SJose.Borrego@Sun.COM if (smb_sign_calc(&command, sign, sign->seqnum, mac_sig) != 0) 3447348SJose.Borrego@Sun.COM return (-1); 3455331Samw 3467348SJose.Borrego@Sun.COM /* compare the signatures */ 3477348SJose.Borrego@Sun.COM if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) { 3487348SJose.Borrego@Sun.COM DTRACE_PROBE2(smb__signing__req, smb_request_t, sr, 3497348SJose.Borrego@Sun.COM smb_sign_t *, sr->smb_sig); 3507348SJose.Borrego@Sun.COM cmn_err(CE_NOTE, "message signing: bad signature"); 3517348SJose.Borrego@Sun.COM /* 3527348SJose.Borrego@Sun.COM * check nearby sequence numbers in debug mode 3537348SJose.Borrego@Sun.COM */ 3547348SJose.Borrego@Sun.COM SMB_CHECK_SEQNUM(sign, &command, mac_sig, sr->smb_sig, &found); 3557348SJose.Borrego@Sun.COM if (found == B_FALSE) 3565331Samw rtn = -1; 3575331Samw } 3585331Samw /* 3597348SJose.Borrego@Sun.COM * Increment the sequence number for the reply, save the reply 3605331Samw * and set it for the next expect command. 3617348SJose.Borrego@Sun.COM * There is no reply for NT Cancel so just increment it for the 3625331Samw * next expected command. 3635331Samw */ 3645331Samw sign->seqnum++; 3655331Samw 3666139Sjb150015 if (sr->smb_com == SMB_COM_NT_CANCEL) 3676139Sjb150015 sr->reply_seqnum = 0; 3685331Samw else 3696139Sjb150015 sr->reply_seqnum = sign->seqnum++; 3705331Samw 3715331Samw return (rtn); 3725331Samw } 3735331Samw 3745331Samw /* 3755331Samw * smb_sign_check_secondary 3765331Samw * 3775331Samw * Calculates MAC signature for the secondary transaction mbuf chain 3785331Samw * and compares it to the given signature. 3795331Samw * Return 0 if the signature verifies, otherwise, returns -1; 3805331Samw * 3815331Samw */ 3825331Samw int 3836139Sjb150015 smb_sign_check_secondary(smb_request_t *sr, unsigned int reply_seqnum) 3845331Samw { 3856139Sjb150015 struct mbuf_chain command = sr->command; 3865331Samw unsigned char mac_sig[SMB_SIG_SIZE]; 3876139Sjb150015 struct smb_sign *sign = &sr->session->signing; 3885331Samw int rtn = 0; 3895331Samw 3907348SJose.Borrego@Sun.COM /* Reset the offset to begining of header */ 3917348SJose.Borrego@Sun.COM command.chain_offset = sr->orig_request_hdr; 3925331Samw 3937348SJose.Borrego@Sun.COM /* calculate mac signature */ 3947348SJose.Borrego@Sun.COM if (smb_sign_calc(&command, sign, reply_seqnum - 1, 3957348SJose.Borrego@Sun.COM mac_sig) != 0) 3967348SJose.Borrego@Sun.COM return (-1); 3975331Samw 3985331Samw 3997348SJose.Borrego@Sun.COM /* compare the signatures */ 4007348SJose.Borrego@Sun.COM if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) { 4017348SJose.Borrego@Sun.COM cmn_err(CE_WARN, "SmbSignCheckSecond: bad signature"); 4027348SJose.Borrego@Sun.COM rtn = -1; 4035331Samw } 4045331Samw /* Save the reply sequence number */ 4056139Sjb150015 sr->reply_seqnum = reply_seqnum; 4065331Samw 4075331Samw return (rtn); 4085331Samw } 4095331Samw 4105331Samw 4115331Samw 4125331Samw 4135331Samw /* 4145331Samw * smb_sign_reply 4155331Samw * 4165331Samw * Calculates MAC signature for the given mbuf chain, 4175331Samw * and write it to the signature field in the mbuf. 4185331Samw * 4195331Samw */ 4205331Samw void 4216139Sjb150015 smb_sign_reply(smb_request_t *sr, struct mbuf_chain *reply) 4225331Samw { 4235331Samw struct mbuf_chain resp; 4246139Sjb150015 struct smb_sign *sign = &sr->session->signing; 4255331Samw unsigned char signature[SMB_SIG_SIZE]; 4265331Samw struct mbuf *mbuf; 4275331Samw int size = SMB_SIG_SIZE; 4285331Samw unsigned char *sig_ptr = signature; 4295331Samw int offset = 0; 4305331Samw 4315331Samw if (reply) 4325331Samw resp = *reply; 4335331Samw else 4346139Sjb150015 resp = sr->reply; 4355331Samw 4365331Samw /* Reset offset to start of reply */ 4375331Samw resp.chain_offset = 0; 4385331Samw mbuf = resp.chain; 4395331Samw 4405331Samw /* 4415331Samw * Calculate MAC signature 4425331Samw */ 4436139Sjb150015 if (smb_sign_calc(&resp, sign, sr->reply_seqnum, signature) != 0) 4445331Samw return; 4455331Samw 4465331Samw /* 4475331Samw * Put signature in the response 4485331Samw * 4495331Samw * First find start of signature in chain (offset + signature offset) 4505331Samw */ 4515331Samw offset += SMB_SIG_OFFS; 4525331Samw while (offset >= mbuf->m_len) { 4535331Samw offset -= mbuf->m_len; 4545331Samw mbuf = mbuf->m_next; 4555331Samw } 4565331Samw 4575331Samw while (size >= mbuf->m_len - offset) { 4585331Samw (void) memcpy(&mbuf->m_data[offset], 4595331Samw sig_ptr, mbuf->m_len - offset); 4605331Samw offset = 0; 4615331Samw sig_ptr += mbuf->m_len - offset; 4625331Samw size -= mbuf->m_len - offset; 4635331Samw mbuf = mbuf->m_next; 4645331Samw } 4655331Samw if (size > 0) { 4665331Samw (void) memcpy(&mbuf->m_data[offset], sig_ptr, size); 4675331Samw } 4685331Samw } 469