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*12508Samw@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235331Samw */
245331Samw /*
255331Samw * These routines provide the SMB MAC signing for the SMB server.
265331Samw * The routines calculate the signature of a SMB message in an mbuf chain.
275331Samw *
287348SJose.Borrego@Sun.COM * The following table describes the client server
297348SJose.Borrego@Sun.COM * signing registry relationship
307348SJose.Borrego@Sun.COM *
317348SJose.Borrego@Sun.COM * | Required | Enabled | Disabled
327348SJose.Borrego@Sun.COM * -------------+---------------+------------ +--------------
337348SJose.Borrego@Sun.COM * Required | Signed | Signed | Fail
347348SJose.Borrego@Sun.COM * -------------+---------------+-------------+-----------------
357348SJose.Borrego@Sun.COM * Enabled | Signed | Signed | Not Signed
367348SJose.Borrego@Sun.COM * -------------+---------------+-------------+----------------
377348SJose.Borrego@Sun.COM * Disabled | Fail | Not Signed | Not Signed
385331Samw */
395331Samw
405331Samw #include <sys/uio.h>
4110966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
425331Samw #include <smbsrv/msgbuf.h>
435331Samw #include <sys/crypto/api.h>
445331Samw
456600Sas200622 #define SMBAUTH_SESSION_KEY_SZ 16
465331Samw #define SMB_SIG_SIZE 8
475331Samw #define SMB_SIG_OFFS 14
485331Samw
497348SJose.Borrego@Sun.COM int
507348SJose.Borrego@Sun.COM smb_sign_calc(struct mbuf_chain *mbc,
517348SJose.Borrego@Sun.COM struct smb_sign *sign,
527348SJose.Borrego@Sun.COM uint32_t seqnum,
537348SJose.Borrego@Sun.COM unsigned char *mac_sign);
547348SJose.Borrego@Sun.COM
557348SJose.Borrego@Sun.COM #ifdef DEBUG
567348SJose.Borrego@Sun.COM void smb_sign_find_seqnum(
57*12508Samw@Sun.COM uint32_t seqnum,
587348SJose.Borrego@Sun.COM struct smb_sign *sign,
597348SJose.Borrego@Sun.COM struct mbuf_chain *command,
607348SJose.Borrego@Sun.COM unsigned char *mac_sig,
617348SJose.Borrego@Sun.COM unsigned char *sr_sig,
627348SJose.Borrego@Sun.COM boolean_t *found);
63*12508Samw@Sun.COM #define SMB_CHECK_SEQNUM(seqnum, sign, command, mac_sig, sr_sig, found) \
647348SJose.Borrego@Sun.COM { \
657348SJose.Borrego@Sun.COM if (smb_sign_debug) \
66*12508Samw@Sun.COM smb_sign_find_seqnum(seqnum, sign, \
67*12508Samw@Sun.COM command, mac_sig, sr_sig, found); \
687348SJose.Borrego@Sun.COM }
697348SJose.Borrego@Sun.COM #else
70*12508Samw@Sun.COM #define SMB_CHECK_SEQNUM(seqnum, sign, command, mac_sig, sr_sig, found) \
71*12508Samw@Sun.COM { \
72*12508Samw@Sun.COM *found = 0; \
73*12508Samw@Sun.COM }
747348SJose.Borrego@Sun.COM #endif
757348SJose.Borrego@Sun.COM
767348SJose.Borrego@Sun.COM #ifdef DEBUG
777348SJose.Borrego@Sun.COM void
smb_sign_find_seqnum(uint32_t seqnum,struct smb_sign * sign,struct mbuf_chain * command,unsigned char * mac_sig,unsigned char * sr_sig,boolean_t * found)787348SJose.Borrego@Sun.COM smb_sign_find_seqnum(
79*12508Samw@Sun.COM uint32_t seqnum,
807348SJose.Borrego@Sun.COM struct smb_sign *sign,
817348SJose.Borrego@Sun.COM struct mbuf_chain *command,
827348SJose.Borrego@Sun.COM unsigned char *mac_sig,
837348SJose.Borrego@Sun.COM unsigned char *sr_sig,
847348SJose.Borrego@Sun.COM boolean_t *found)
857348SJose.Borrego@Sun.COM {
867348SJose.Borrego@Sun.COM int start_seqnum;
877348SJose.Borrego@Sun.COM int i;
887348SJose.Borrego@Sun.COM
897348SJose.Borrego@Sun.COM /* Debug code to hunt for the sequence number */
907348SJose.Borrego@Sun.COM *found = B_FALSE;
91*12508Samw@Sun.COM start_seqnum = seqnum - 10;
927348SJose.Borrego@Sun.COM if (start_seqnum < 0)
937348SJose.Borrego@Sun.COM start_seqnum = 0;
94*12508Samw@Sun.COM for (i = start_seqnum; i <= start_seqnum + 20; i++) {
957639SNick.Todd@Sun.COM (void) smb_sign_calc(command, sign, i, mac_sig);
967348SJose.Borrego@Sun.COM if (memcmp(mac_sig, sr_sig, SMB_SIG_SIZE) == 0) {
977348SJose.Borrego@Sun.COM sign->seqnum = i;
987348SJose.Borrego@Sun.COM *found = B_TRUE;
997348SJose.Borrego@Sun.COM break;
1007348SJose.Borrego@Sun.COM }
101*12508Samw@Sun.COM cmn_err(CE_WARN, "smb_sign_find_seqnum: seqnum:%d mismatch", i);
1027348SJose.Borrego@Sun.COM }
1037348SJose.Borrego@Sun.COM cmn_err(CE_WARN, "smb_sign_find_seqnum: found=%d", *found);
1047348SJose.Borrego@Sun.COM }
1057348SJose.Borrego@Sun.COM #endif
106*12508Samw@Sun.COM
1075331Samw /* This holds the MD5 mechanism */
1085331Samw static crypto_mechanism_t crypto_mech = {CRYPTO_MECHANISM_INVALID, 0, 0};
1095331Samw
1105331Samw /*
1115331Samw * smb_sign_init
1125331Samw *
1135331Samw * Intializes MAC key based on the user session key and
1145331Samw * NTLM response and store it in the signing structure.
1155331Samw */
1165331Samw void
smb_sign_init(smb_request_t * sr,smb_session_key_t * session_key,char * resp,int resp_len)1176139Sjb150015 smb_sign_init(smb_request_t *sr, smb_session_key_t *session_key,
1185331Samw char *resp, int resp_len)
1195331Samw {
1206139Sjb150015 struct smb_sign *sign = &sr->session->signing;
1215331Samw
1225331Samw /*
1235331Samw * Initialise the crypto mechanism to MD5 if it not
1245331Samw * already initialised.
1255331Samw */
1265331Samw if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) {
1275331Samw crypto_mech.cm_type = crypto_mech2id(SUN_CKM_MD5);
1285331Samw if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) {
1295331Samw /*
1305331Samw * There is no MD5 crypto mechanism
1315331Samw * so turn off signing
1325331Samw */
1336139Sjb150015 sr->sr_cfg->skc_signing_enable = 0;
1346139Sjb150015 sr->session->secmode &=
1355331Samw (~NEGOTIATE_SECURITY_SIGNATURES_ENABLED);
1365331Samw cmn_err(CE_WARN,
1375331Samw "SmbSignInit: signing disabled (no MD5)");
1385331Samw return;
1395331Samw }
1405331Samw }
1415331Samw
1425331Samw /* MAC key = concat (SessKey, NTLMResponse) */
1435331Samw
1445331Samw bcopy(session_key, sign->mackey, sizeof (smb_session_key_t));
1455331Samw bcopy(resp, &(sign->mackey[sizeof (smb_session_key_t)]),
1465331Samw resp_len);
1475331Samw sign->mackey_len = sizeof (smb_session_key_t) + resp_len;
1485331Samw
149*12508Samw@Sun.COM sr->session->signing.seqnum = 0;
150*12508Samw@Sun.COM sr->sr_seqnum = 2;
1516139Sjb150015 sr->reply_seqnum = 1;
1525331Samw sign->flags = SMB_SIGNING_ENABLED;
1535331Samw
1545331Samw }
1555331Samw
1565331Samw /*
1575331Samw * smb_sign_calc
1585331Samw *
1595331Samw * Calculates MAC signature for the given buffer and returns
1605331Samw * it in the mac_sign parameter.
1615331Samw *
1625331Samw * The sequence number is placed in the first four bytes of the signature
1635331Samw * field of the signature and the other 4 bytes are zeroed.
1645331Samw * The signature is the first 8 bytes of the MD5 result of the
1655331Samw * concatenated MAC key and the SMB message.
1665331Samw *
1675331Samw * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8)
1685331Samw *
1695331Samw * where
1705331Samw *
1715331Samw * MACKey = concat( UserSessionKey, NTLMResp )
1725331Samw *
1735331Samw * and
1745331Samw *
1755331Samw * SMBMsg is the SMB message containing the sequence number.
1765331Samw *
1775331Samw * Return 0 if success else -1
1785331Samw *
1795331Samw */
1807348SJose.Borrego@Sun.COM int
smb_sign_calc(struct mbuf_chain * mbc,struct smb_sign * sign,uint32_t seqnum,unsigned char * mac_sign)1815331Samw smb_sign_calc(struct mbuf_chain *mbc,
1825331Samw struct smb_sign *sign,
1835331Samw uint32_t seqnum,
1845331Samw unsigned char *mac_sign)
1855331Samw {
1865331Samw uint32_t seq_buf[2] = {0, 0};
1875331Samw unsigned char mac[16];
1885331Samw struct mbuf *mbuf = mbc->chain;
1895331Samw int offset = mbc->chain_offset;
1905331Samw int size;
1915331Samw int status;
1925331Samw
1935331Samw crypto_data_t data;
1945331Samw crypto_data_t digest;
1955331Samw crypto_context_t crypto_ctx;
1965331Samw
1975331Samw data.cd_format = CRYPTO_DATA_RAW;
1985331Samw data.cd_offset = 0;
1995331Samw data.cd_length = (size_t)-1;
2005331Samw data.cd_miscdata = 0;
2015331Samw
2025331Samw digest.cd_format = CRYPTO_DATA_RAW;
2035331Samw digest.cd_offset = 0;
2045331Samw digest.cd_length = (size_t)-1;
2055331Samw digest.cd_miscdata = 0;
2065331Samw digest.cd_raw.iov_base = (char *)mac;
2075331Samw digest.cd_raw.iov_len = sizeof (mac);
2085331Samw
2095331Samw status = crypto_digest_init(&crypto_mech, &crypto_ctx, 0);
2106600Sas200622 if (status != CRYPTO_SUCCESS)
2116600Sas200622 goto error;
2125331Samw
2135331Samw /*
2145331Samw * Put the sequence number into the first 4 bytes
2155331Samw * of the signature field in little endian format.
2165331Samw * We are using a buffer to represent the signature
2175331Samw * rather than modifying the SMB message.
2185331Samw */
2195331Samw #ifdef __sparc
2205331Samw {
2215331Samw uint32_t temp;
2225331Samw ((uint8_t *)&temp)[0] = ((uint8_t *)&seqnum)[3];
2235331Samw ((uint8_t *)&temp)[1] = ((uint8_t *)&seqnum)[2];
2245331Samw ((uint8_t *)&temp)[2] = ((uint8_t *)&seqnum)[1];
2255331Samw ((uint8_t *)&temp)[3] = ((uint8_t *)&seqnum)[0];
2265331Samw
2275331Samw seq_buf[0] = temp;
2285331Samw }
2295331Samw #else
2305331Samw seq_buf[0] = seqnum;
2315331Samw #endif
2325331Samw
2335331Samw /* Digest the MACKey */
2345331Samw data.cd_raw.iov_base = (char *)sign->mackey;
2355331Samw data.cd_raw.iov_len = sign->mackey_len;
2366600Sas200622 data.cd_length = sign->mackey_len;
2376600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0);
2386600Sas200622 if (status != CRYPTO_SUCCESS)
2396600Sas200622 goto error;
2405331Samw
2415331Samw /* Find start of data in chain */
2425331Samw while (offset >= mbuf->m_len) {
2435331Samw offset -= mbuf->m_len;
2445331Samw mbuf = mbuf->m_next;
2455331Samw }
2465331Samw
2475331Samw /* Digest the SMB packet up to the signature field */
2485331Samw size = SMB_SIG_OFFS;
2495331Samw while (size >= mbuf->m_len - offset) {
2505331Samw data.cd_raw.iov_base = &mbuf->m_data[offset];
2515331Samw data.cd_raw.iov_len = mbuf->m_len - offset;
2526600Sas200622 data.cd_length = mbuf->m_len - offset;
2536600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0);
2546600Sas200622 if (status != CRYPTO_SUCCESS)
2556600Sas200622 goto error;
2565331Samw
2575331Samw size -= mbuf->m_len - offset;
2585331Samw mbuf = mbuf->m_next;
2595331Samw offset = 0;
2605331Samw }
2615331Samw if (size > 0) {
2625331Samw data.cd_raw.iov_base = &mbuf->m_data[offset];
2635331Samw data.cd_raw.iov_len = size;
2646600Sas200622 data.cd_length = size;
2656600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0);
2666600Sas200622 if (status != CRYPTO_SUCCESS)
2676600Sas200622 goto error;
2685331Samw offset += size;
2695331Samw }
2705331Samw
2715331Samw /*
2725331Samw * Digest in the seq_buf instead of the signature
2735331Samw * which has the sequence number
2745331Samw */
2755331Samw
2765331Samw data.cd_raw.iov_base = (char *)seq_buf;
2775331Samw data.cd_raw.iov_len = SMB_SIG_SIZE;
2786600Sas200622 data.cd_length = SMB_SIG_SIZE;
2796600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0);
2806600Sas200622 if (status != CRYPTO_SUCCESS)
2816600Sas200622 goto error;
2825331Samw
2835331Samw /* Find the end of the signature field */
2845331Samw offset += SMB_SIG_SIZE;
2855331Samw while (offset >= mbuf->m_len) {
2865331Samw offset -= mbuf->m_len;
2875331Samw mbuf = mbuf->m_next;
2885331Samw }
2895331Samw /* Digest the rest of the SMB packet */
2905331Samw while (mbuf) {
2915331Samw data.cd_raw.iov_base = &mbuf->m_data[offset];
2925331Samw data.cd_raw.iov_len = mbuf->m_len - offset;
2936600Sas200622 data.cd_length = mbuf->m_len - offset;
2946600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0);
2956600Sas200622 if (status != CRYPTO_SUCCESS)
2966600Sas200622 goto error;
2975331Samw mbuf = mbuf->m_next;
2985331Samw offset = 0;
2995331Samw }
3006600Sas200622 digest.cd_length = SMBAUTH_SESSION_KEY_SZ;
3016600Sas200622 status = crypto_digest_final(crypto_ctx, &digest, 0);
3026600Sas200622 if (status != CRYPTO_SUCCESS)
3036600Sas200622 goto error;
3045331Samw bcopy(mac, mac_sign, SMB_SIG_SIZE);
3055331Samw return (0);
3065331Samw error:
3075331Samw cmn_err(CE_WARN, "SmbSignCalc: crypto error %d", status);
3085331Samw return (-1);
3095331Samw
3105331Samw }
3115331Samw
3125331Samw
3135331Samw /*
3145331Samw * smb_sign_check_request
3155331Samw *
3165331Samw * Calculates MAC signature for the request mbuf chain
3175331Samw * using the next expected sequence number and compares
3185331Samw * it to the given signature.
3195331Samw *
3205331Samw * Note it does not check the signature for secondary transactions
3215331Samw * as their sequence number is the same as the original request.
3225331Samw *
3235331Samw * Return 0 if the signature verifies, otherwise, returns -1;
3245331Samw *
3255331Samw */
3265331Samw int
smb_sign_check_request(smb_request_t * sr)3276139Sjb150015 smb_sign_check_request(smb_request_t *sr)
3285331Samw {
3296139Sjb150015 struct mbuf_chain command = sr->command;
3305331Samw unsigned char mac_sig[SMB_SIG_SIZE];
3316139Sjb150015 struct smb_sign *sign = &sr->session->signing;
3325331Samw int rtn = 0;
3337348SJose.Borrego@Sun.COM boolean_t found = B_TRUE;
334*12508Samw@Sun.COM
3355331Samw /*
3365331Samw * Don't check secondary transactions - we dont know the sequence
3375331Samw * number.
3385331Samw */
3396139Sjb150015 if (sr->smb_com == SMB_COM_TRANSACTION_SECONDARY ||
3406139Sjb150015 sr->smb_com == SMB_COM_TRANSACTION2_SECONDARY ||
3416139Sjb150015 sr->smb_com == SMB_COM_NT_TRANSACT_SECONDARY)
3425331Samw return (0);
3435331Samw
3447348SJose.Borrego@Sun.COM /* Reset the offset to begining of header */
3457348SJose.Borrego@Sun.COM command.chain_offset = sr->orig_request_hdr;
3465331Samw
3477348SJose.Borrego@Sun.COM /* calculate mac signature */
348*12508Samw@Sun.COM if (smb_sign_calc(&command, sign, sr->sr_seqnum, mac_sig) != 0)
3497348SJose.Borrego@Sun.COM return (-1);
3505331Samw
3517348SJose.Borrego@Sun.COM /* compare the signatures */
3527348SJose.Borrego@Sun.COM if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) {
3537348SJose.Borrego@Sun.COM DTRACE_PROBE2(smb__signing__req, smb_request_t, sr,
3547348SJose.Borrego@Sun.COM smb_sign_t *, sr->smb_sig);
355*12508Samw@Sun.COM cmn_err(CE_NOTE, "smb_sign_check_request: bad signature");
3567348SJose.Borrego@Sun.COM /*
3577348SJose.Borrego@Sun.COM * check nearby sequence numbers in debug mode
3587348SJose.Borrego@Sun.COM */
359*12508Samw@Sun.COM SMB_CHECK_SEQNUM(sr->sr_seqnum, sign, &command,
360*12508Samw@Sun.COM mac_sig, sr->smb_sig, &found);
3617348SJose.Borrego@Sun.COM if (found == B_FALSE)
3625331Samw rtn = -1;
3635331Samw }
3645331Samw return (rtn);
3655331Samw }
3665331Samw
3675331Samw /*
3685331Samw * smb_sign_check_secondary
3695331Samw *
3705331Samw * Calculates MAC signature for the secondary transaction mbuf chain
3715331Samw * and compares it to the given signature.
3725331Samw * Return 0 if the signature verifies, otherwise, returns -1;
3735331Samw *
3745331Samw */
3755331Samw int
smb_sign_check_secondary(smb_request_t * sr,unsigned int reply_seqnum)3766139Sjb150015 smb_sign_check_secondary(smb_request_t *sr, unsigned int reply_seqnum)
3775331Samw {
3786139Sjb150015 struct mbuf_chain command = sr->command;
3795331Samw unsigned char mac_sig[SMB_SIG_SIZE];
3806139Sjb150015 struct smb_sign *sign = &sr->session->signing;
3815331Samw int rtn = 0;
3825331Samw
3837348SJose.Borrego@Sun.COM /* Reset the offset to begining of header */
3847348SJose.Borrego@Sun.COM command.chain_offset = sr->orig_request_hdr;
3855331Samw
3867348SJose.Borrego@Sun.COM /* calculate mac signature */
3877348SJose.Borrego@Sun.COM if (smb_sign_calc(&command, sign, reply_seqnum - 1,
3887348SJose.Borrego@Sun.COM mac_sig) != 0)
3897348SJose.Borrego@Sun.COM return (-1);
3905331Samw
3915331Samw
3927348SJose.Borrego@Sun.COM /* compare the signatures */
3937348SJose.Borrego@Sun.COM if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) {
3947348SJose.Borrego@Sun.COM cmn_err(CE_WARN, "SmbSignCheckSecond: bad signature");
3957348SJose.Borrego@Sun.COM rtn = -1;
3965331Samw }
3975331Samw /* Save the reply sequence number */
3986139Sjb150015 sr->reply_seqnum = reply_seqnum;
3995331Samw
4005331Samw return (rtn);
4015331Samw }
4025331Samw
4035331Samw /*
4045331Samw * smb_sign_reply
4055331Samw *
4065331Samw * Calculates MAC signature for the given mbuf chain,
4075331Samw * and write it to the signature field in the mbuf.
4085331Samw *
4095331Samw */
4105331Samw void
smb_sign_reply(smb_request_t * sr,struct mbuf_chain * reply)4116139Sjb150015 smb_sign_reply(smb_request_t *sr, struct mbuf_chain *reply)
4125331Samw {
4135331Samw struct mbuf_chain resp;
4146139Sjb150015 struct smb_sign *sign = &sr->session->signing;
4155331Samw unsigned char signature[SMB_SIG_SIZE];
4165331Samw struct mbuf *mbuf;
4175331Samw int size = SMB_SIG_SIZE;
4185331Samw unsigned char *sig_ptr = signature;
4195331Samw int offset = 0;
4205331Samw
4215331Samw if (reply)
4225331Samw resp = *reply;
4235331Samw else
4246139Sjb150015 resp = sr->reply;
4255331Samw
4265331Samw /* Reset offset to start of reply */
4275331Samw resp.chain_offset = 0;
4285331Samw mbuf = resp.chain;
4295331Samw
4305331Samw /*
4315331Samw * Calculate MAC signature
4325331Samw */
433*12508Samw@Sun.COM if (smb_sign_calc(&resp, sign, sr->reply_seqnum, signature) != 0) {
434*12508Samw@Sun.COM cmn_err(CE_WARN, "smb_sign_reply: error in smb_sign_calc");
4355331Samw return;
436*12508Samw@Sun.COM }
4375331Samw
4385331Samw /*
4395331Samw * Put signature in the response
4405331Samw *
4415331Samw * First find start of signature in chain (offset + signature offset)
4425331Samw */
4435331Samw offset += SMB_SIG_OFFS;
4445331Samw while (offset >= mbuf->m_len) {
4455331Samw offset -= mbuf->m_len;
4465331Samw mbuf = mbuf->m_next;
4475331Samw }
4485331Samw
4495331Samw while (size >= mbuf->m_len - offset) {
4505331Samw (void) memcpy(&mbuf->m_data[offset],
4515331Samw sig_ptr, mbuf->m_len - offset);
4525331Samw offset = 0;
4535331Samw sig_ptr += mbuf->m_len - offset;
4545331Samw size -= mbuf->m_len - offset;
4555331Samw mbuf = mbuf->m_next;
4565331Samw }
4575331Samw if (size > 0) {
4585331Samw (void) memcpy(&mbuf->m_data[offset], sig_ptr, size);
4595331Samw }
4605331Samw }
461