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 /* 226139Sjb150015 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 26*7348SJose.Borrego@Sun.COM #pragma ident "@(#)smb_signing.c 1.4 08/07/08 SMI" 275331Samw 285331Samw /* 295331Samw * These routines provide the SMB MAC signing for the SMB server. 305331Samw * The routines calculate the signature of a SMB message in an mbuf chain. 315331Samw * 32*7348SJose.Borrego@Sun.COM * The following table describes the client server 33*7348SJose.Borrego@Sun.COM * signing registry relationship 34*7348SJose.Borrego@Sun.COM * 35*7348SJose.Borrego@Sun.COM * | Required | Enabled | Disabled 36*7348SJose.Borrego@Sun.COM * -------------+---------------+------------ +-------------- 37*7348SJose.Borrego@Sun.COM * Required | Signed | Signed | Fail 38*7348SJose.Borrego@Sun.COM * -------------+---------------+-------------+----------------- 39*7348SJose.Borrego@Sun.COM * Enabled | Signed | Signed | Not Signed 40*7348SJose.Borrego@Sun.COM * -------------+---------------+-------------+---------------- 41*7348SJose.Borrego@Sun.COM * Disabled | Fail | Not Signed | Not Signed 425331Samw */ 435331Samw 445331Samw #include <sys/uio.h> 455331Samw #include <smbsrv/mbuf.h> 465331Samw #include <smbsrv/msgbuf.h> 475331Samw #include <sys/crypto/api.h> 485331Samw #include <smbsrv/smb_incl.h> 495331Samw 506600Sas200622 #define SMBAUTH_SESSION_KEY_SZ 16 515331Samw #define SMB_SIG_SIZE 8 525331Samw #define SMB_SIG_OFFS 14 535331Samw 54*7348SJose.Borrego@Sun.COM int 55*7348SJose.Borrego@Sun.COM smb_sign_calc(struct mbuf_chain *mbc, 56*7348SJose.Borrego@Sun.COM struct smb_sign *sign, 57*7348SJose.Borrego@Sun.COM uint32_t seqnum, 58*7348SJose.Borrego@Sun.COM unsigned char *mac_sign); 59*7348SJose.Borrego@Sun.COM 60*7348SJose.Borrego@Sun.COM #ifdef DEBUG 61*7348SJose.Borrego@Sun.COM void smb_sign_find_seqnum( 62*7348SJose.Borrego@Sun.COM struct smb_sign *sign, 63*7348SJose.Borrego@Sun.COM struct mbuf_chain *command, 64*7348SJose.Borrego@Sun.COM unsigned char *mac_sig, 65*7348SJose.Borrego@Sun.COM unsigned char *sr_sig, 66*7348SJose.Borrego@Sun.COM boolean_t *found); 67*7348SJose.Borrego@Sun.COM 68*7348SJose.Borrego@Sun.COM #define SMB_CHECK_SEQNUM(sign, command, mac_sig, sr_sig, found) \ 69*7348SJose.Borrego@Sun.COM { \ 70*7348SJose.Borrego@Sun.COM if (smb_sign_debug) \ 71*7348SJose.Borrego@Sun.COM smb_sign_find_seqnum(sign, command, mac_sig, sr_sig, found); \ 72*7348SJose.Borrego@Sun.COM } 73*7348SJose.Borrego@Sun.COM #else 74*7348SJose.Borrego@Sun.COM #define SMB_CHECK_SEQNUM(sign, command, mac_sig, sr_sig, found) \ 75*7348SJose.Borrego@Sun.COM { } 76*7348SJose.Borrego@Sun.COM #endif 77*7348SJose.Borrego@Sun.COM 78*7348SJose.Borrego@Sun.COM #ifdef DEBUG 79*7348SJose.Borrego@Sun.COM void 80*7348SJose.Borrego@Sun.COM smb_sign_find_seqnum( 81*7348SJose.Borrego@Sun.COM struct smb_sign *sign, 82*7348SJose.Borrego@Sun.COM struct mbuf_chain *command, 83*7348SJose.Borrego@Sun.COM unsigned char *mac_sig, 84*7348SJose.Borrego@Sun.COM unsigned char *sr_sig, 85*7348SJose.Borrego@Sun.COM boolean_t *found) 86*7348SJose.Borrego@Sun.COM { 87*7348SJose.Borrego@Sun.COM int start_seqnum; 88*7348SJose.Borrego@Sun.COM int i; 89*7348SJose.Borrego@Sun.COM 90*7348SJose.Borrego@Sun.COM /* Debug code to hunt for the sequence number */ 91*7348SJose.Borrego@Sun.COM *found = B_FALSE; 92*7348SJose.Borrego@Sun.COM start_seqnum = (int)sign->seqnum - 6; 93*7348SJose.Borrego@Sun.COM if (start_seqnum < 0) 94*7348SJose.Borrego@Sun.COM start_seqnum = 0; 95*7348SJose.Borrego@Sun.COM for (i = start_seqnum; i <= start_seqnum + 6; i++) { 96*7348SJose.Borrego@Sun.COM smb_sign_calc(command, sign, i, mac_sig); 97*7348SJose.Borrego@Sun.COM if (memcmp(mac_sig, sr_sig, SMB_SIG_SIZE) == 0) { 98*7348SJose.Borrego@Sun.COM sign->seqnum = i; 99*7348SJose.Borrego@Sun.COM *found = B_TRUE; 100*7348SJose.Borrego@Sun.COM break; 101*7348SJose.Borrego@Sun.COM } 102*7348SJose.Borrego@Sun.COM cmn_err(CE_WARN, "smb_sign_find_seqnum: seqnum%d mismatch", i); 103*7348SJose.Borrego@Sun.COM } 104*7348SJose.Borrego@Sun.COM cmn_err(CE_WARN, "smb_sign_find_seqnum: found=%d", *found); 105*7348SJose.Borrego@Sun.COM } 106*7348SJose.Borrego@Sun.COM #endif 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 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 1496139Sjb150015 sr->reply_seqnum = 1; 1505331Samw sign->seqnum = 2; 1515331Samw sign->flags = SMB_SIGNING_ENABLED; 1525331Samw 1535331Samw } 1545331Samw 1555331Samw /* 1565331Samw * smb_sign_calc 1575331Samw * 1585331Samw * Calculates MAC signature for the given buffer and returns 1595331Samw * it in the mac_sign parameter. 1605331Samw * 1615331Samw * The sequence number is placed in the first four bytes of the signature 1625331Samw * field of the signature and the other 4 bytes are zeroed. 1635331Samw * The signature is the first 8 bytes of the MD5 result of the 1645331Samw * concatenated MAC key and the SMB message. 1655331Samw * 1665331Samw * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8) 1675331Samw * 1685331Samw * where 1695331Samw * 1705331Samw * MACKey = concat( UserSessionKey, NTLMResp ) 1715331Samw * 1725331Samw * and 1735331Samw * 1745331Samw * SMBMsg is the SMB message containing the sequence number. 1755331Samw * 1765331Samw * Return 0 if success else -1 1775331Samw * 1785331Samw */ 179*7348SJose.Borrego@Sun.COM int 1805331Samw smb_sign_calc(struct mbuf_chain *mbc, 1815331Samw struct smb_sign *sign, 1825331Samw uint32_t seqnum, 1835331Samw unsigned char *mac_sign) 1845331Samw { 1855331Samw uint32_t seq_buf[2] = {0, 0}; 1865331Samw unsigned char mac[16]; 1875331Samw struct mbuf *mbuf = mbc->chain; 1885331Samw int offset = mbc->chain_offset; 1895331Samw int size; 1905331Samw int status; 1915331Samw 1925331Samw crypto_data_t data; 1935331Samw crypto_data_t digest; 1945331Samw crypto_context_t crypto_ctx; 1955331Samw 1965331Samw data.cd_format = CRYPTO_DATA_RAW; 1975331Samw data.cd_offset = 0; 1985331Samw data.cd_length = (size_t)-1; 1995331Samw data.cd_miscdata = 0; 2005331Samw 2015331Samw digest.cd_format = CRYPTO_DATA_RAW; 2025331Samw digest.cd_offset = 0; 2035331Samw digest.cd_length = (size_t)-1; 2045331Samw digest.cd_miscdata = 0; 2055331Samw digest.cd_raw.iov_base = (char *)mac; 2065331Samw digest.cd_raw.iov_len = sizeof (mac); 2075331Samw 2085331Samw status = crypto_digest_init(&crypto_mech, &crypto_ctx, 0); 2096600Sas200622 if (status != CRYPTO_SUCCESS) 2106600Sas200622 goto error; 2115331Samw 2125331Samw /* 2135331Samw * Put the sequence number into the first 4 bytes 2145331Samw * of the signature field in little endian format. 2155331Samw * We are using a buffer to represent the signature 2165331Samw * rather than modifying the SMB message. 2175331Samw */ 2185331Samw #ifdef __sparc 2195331Samw { 2205331Samw uint32_t temp; 2215331Samw ((uint8_t *)&temp)[0] = ((uint8_t *)&seqnum)[3]; 2225331Samw ((uint8_t *)&temp)[1] = ((uint8_t *)&seqnum)[2]; 2235331Samw ((uint8_t *)&temp)[2] = ((uint8_t *)&seqnum)[1]; 2245331Samw ((uint8_t *)&temp)[3] = ((uint8_t *)&seqnum)[0]; 2255331Samw 2265331Samw seq_buf[0] = temp; 2275331Samw } 2285331Samw #else 2295331Samw seq_buf[0] = seqnum; 2305331Samw #endif 2315331Samw 2325331Samw /* Digest the MACKey */ 2335331Samw data.cd_raw.iov_base = (char *)sign->mackey; 2345331Samw data.cd_raw.iov_len = sign->mackey_len; 2356600Sas200622 data.cd_length = sign->mackey_len; 2366600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 2376600Sas200622 if (status != CRYPTO_SUCCESS) 2386600Sas200622 goto error; 2395331Samw 2405331Samw /* Find start of data in chain */ 2415331Samw while (offset >= mbuf->m_len) { 2425331Samw offset -= mbuf->m_len; 2435331Samw mbuf = mbuf->m_next; 2445331Samw } 2455331Samw 2465331Samw /* Digest the SMB packet up to the signature field */ 2475331Samw size = SMB_SIG_OFFS; 2485331Samw while (size >= mbuf->m_len - offset) { 2495331Samw data.cd_raw.iov_base = &mbuf->m_data[offset]; 2505331Samw data.cd_raw.iov_len = mbuf->m_len - offset; 2516600Sas200622 data.cd_length = mbuf->m_len - offset; 2526600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 2536600Sas200622 if (status != CRYPTO_SUCCESS) 2546600Sas200622 goto error; 2555331Samw 2565331Samw size -= mbuf->m_len - offset; 2575331Samw mbuf = mbuf->m_next; 2585331Samw offset = 0; 2595331Samw } 2605331Samw if (size > 0) { 2615331Samw data.cd_raw.iov_base = &mbuf->m_data[offset]; 2625331Samw data.cd_raw.iov_len = size; 2636600Sas200622 data.cd_length = size; 2646600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 2656600Sas200622 if (status != CRYPTO_SUCCESS) 2666600Sas200622 goto error; 2675331Samw offset += size; 2685331Samw } 2695331Samw 2705331Samw /* 2715331Samw * Digest in the seq_buf instead of the signature 2725331Samw * which has the sequence number 2735331Samw */ 2745331Samw 2755331Samw data.cd_raw.iov_base = (char *)seq_buf; 2765331Samw data.cd_raw.iov_len = SMB_SIG_SIZE; 2776600Sas200622 data.cd_length = SMB_SIG_SIZE; 2786600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 2796600Sas200622 if (status != CRYPTO_SUCCESS) 2806600Sas200622 goto error; 2815331Samw 2825331Samw /* Find the end of the signature field */ 2835331Samw offset += SMB_SIG_SIZE; 2845331Samw while (offset >= mbuf->m_len) { 2855331Samw offset -= mbuf->m_len; 2865331Samw mbuf = mbuf->m_next; 2875331Samw } 2885331Samw /* Digest the rest of the SMB packet */ 2895331Samw while (mbuf) { 2905331Samw data.cd_raw.iov_base = &mbuf->m_data[offset]; 2915331Samw data.cd_raw.iov_len = mbuf->m_len - offset; 2926600Sas200622 data.cd_length = mbuf->m_len - offset; 2936600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 2946600Sas200622 if (status != CRYPTO_SUCCESS) 2956600Sas200622 goto error; 2965331Samw mbuf = mbuf->m_next; 2975331Samw offset = 0; 2985331Samw } 2996600Sas200622 digest.cd_length = SMBAUTH_SESSION_KEY_SZ; 3006600Sas200622 status = crypto_digest_final(crypto_ctx, &digest, 0); 3016600Sas200622 if (status != CRYPTO_SUCCESS) 3026600Sas200622 goto error; 3035331Samw bcopy(mac, mac_sign, SMB_SIG_SIZE); 3045331Samw return (0); 3055331Samw error: 3065331Samw cmn_err(CE_WARN, "SmbSignCalc: crypto error %d", status); 3075331Samw return (-1); 3085331Samw 3095331Samw } 3105331Samw 3115331Samw 3125331Samw /* 3135331Samw * smb_sign_check_request 3145331Samw * 3155331Samw * Calculates MAC signature for the request mbuf chain 3165331Samw * using the next expected sequence number and compares 3175331Samw * it to the given signature. 3185331Samw * 3195331Samw * Note it does not check the signature for secondary transactions 3205331Samw * as their sequence number is the same as the original request. 3215331Samw * 3225331Samw * Return 0 if the signature verifies, otherwise, returns -1; 3235331Samw * 3245331Samw */ 3255331Samw int 3266139Sjb150015 smb_sign_check_request(smb_request_t *sr) 3275331Samw { 3286139Sjb150015 struct mbuf_chain command = sr->command; 3295331Samw unsigned char mac_sig[SMB_SIG_SIZE]; 3306139Sjb150015 struct smb_sign *sign = &sr->session->signing; 3315331Samw int rtn = 0; 332*7348SJose.Borrego@Sun.COM boolean_t found = B_TRUE; 3335331Samw /* 3345331Samw * Don't check secondary transactions - we dont know the sequence 3355331Samw * number. 3365331Samw */ 3376139Sjb150015 if (sr->smb_com == SMB_COM_TRANSACTION_SECONDARY || 3386139Sjb150015 sr->smb_com == SMB_COM_TRANSACTION2_SECONDARY || 3396139Sjb150015 sr->smb_com == SMB_COM_NT_TRANSACT_SECONDARY) 3405331Samw return (0); 3415331Samw 342*7348SJose.Borrego@Sun.COM /* Reset the offset to begining of header */ 343*7348SJose.Borrego@Sun.COM command.chain_offset = sr->orig_request_hdr; 3445331Samw 345*7348SJose.Borrego@Sun.COM /* calculate mac signature */ 346*7348SJose.Borrego@Sun.COM if (smb_sign_calc(&command, sign, sign->seqnum, mac_sig) != 0) 347*7348SJose.Borrego@Sun.COM return (-1); 3485331Samw 349*7348SJose.Borrego@Sun.COM /* compare the signatures */ 350*7348SJose.Borrego@Sun.COM if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) { 351*7348SJose.Borrego@Sun.COM DTRACE_PROBE2(smb__signing__req, smb_request_t, sr, 352*7348SJose.Borrego@Sun.COM smb_sign_t *, sr->smb_sig); 353*7348SJose.Borrego@Sun.COM cmn_err(CE_NOTE, "message signing: bad signature"); 354*7348SJose.Borrego@Sun.COM /* 355*7348SJose.Borrego@Sun.COM * check nearby sequence numbers in debug mode 356*7348SJose.Borrego@Sun.COM */ 357*7348SJose.Borrego@Sun.COM SMB_CHECK_SEQNUM(sign, &command, mac_sig, sr->smb_sig, &found); 358*7348SJose.Borrego@Sun.COM if (found == B_FALSE) 3595331Samw rtn = -1; 3605331Samw } 3615331Samw /* 362*7348SJose.Borrego@Sun.COM * Increment the sequence number for the reply, save the reply 3635331Samw * and set it for the next expect command. 364*7348SJose.Borrego@Sun.COM * There is no reply for NT Cancel so just increment it for the 3655331Samw * next expected command. 3665331Samw */ 3675331Samw sign->seqnum++; 3685331Samw 3696139Sjb150015 if (sr->smb_com == SMB_COM_NT_CANCEL) 3706139Sjb150015 sr->reply_seqnum = 0; 3715331Samw else 3726139Sjb150015 sr->reply_seqnum = sign->seqnum++; 3735331Samw 3745331Samw return (rtn); 3755331Samw } 3765331Samw 3775331Samw /* 3785331Samw * smb_sign_check_secondary 3795331Samw * 3805331Samw * Calculates MAC signature for the secondary transaction mbuf chain 3815331Samw * and compares it to the given signature. 3825331Samw * Return 0 if the signature verifies, otherwise, returns -1; 3835331Samw * 3845331Samw */ 3855331Samw int 3866139Sjb150015 smb_sign_check_secondary(smb_request_t *sr, unsigned int reply_seqnum) 3875331Samw { 3886139Sjb150015 struct mbuf_chain command = sr->command; 3895331Samw unsigned char mac_sig[SMB_SIG_SIZE]; 3906139Sjb150015 struct smb_sign *sign = &sr->session->signing; 3915331Samw int rtn = 0; 3925331Samw 393*7348SJose.Borrego@Sun.COM /* Reset the offset to begining of header */ 394*7348SJose.Borrego@Sun.COM command.chain_offset = sr->orig_request_hdr; 3955331Samw 396*7348SJose.Borrego@Sun.COM /* calculate mac signature */ 397*7348SJose.Borrego@Sun.COM if (smb_sign_calc(&command, sign, reply_seqnum - 1, 398*7348SJose.Borrego@Sun.COM mac_sig) != 0) 399*7348SJose.Borrego@Sun.COM return (-1); 4005331Samw 4015331Samw 402*7348SJose.Borrego@Sun.COM /* compare the signatures */ 403*7348SJose.Borrego@Sun.COM if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) { 404*7348SJose.Borrego@Sun.COM cmn_err(CE_WARN, "SmbSignCheckSecond: bad signature"); 405*7348SJose.Borrego@Sun.COM rtn = -1; 4065331Samw } 4075331Samw /* Save the reply sequence number */ 4086139Sjb150015 sr->reply_seqnum = reply_seqnum; 4095331Samw 4105331Samw return (rtn); 4115331Samw } 4125331Samw 4135331Samw 4145331Samw 4155331Samw 4165331Samw /* 4175331Samw * smb_sign_reply 4185331Samw * 4195331Samw * Calculates MAC signature for the given mbuf chain, 4205331Samw * and write it to the signature field in the mbuf. 4215331Samw * 4225331Samw */ 4235331Samw void 4246139Sjb150015 smb_sign_reply(smb_request_t *sr, struct mbuf_chain *reply) 4255331Samw { 4265331Samw struct mbuf_chain resp; 4276139Sjb150015 struct smb_sign *sign = &sr->session->signing; 4285331Samw unsigned char signature[SMB_SIG_SIZE]; 4295331Samw struct mbuf *mbuf; 4305331Samw int size = SMB_SIG_SIZE; 4315331Samw unsigned char *sig_ptr = signature; 4325331Samw int offset = 0; 4335331Samw 4345331Samw if (reply) 4355331Samw resp = *reply; 4365331Samw else 4376139Sjb150015 resp = sr->reply; 4385331Samw 4395331Samw /* Reset offset to start of reply */ 4405331Samw resp.chain_offset = 0; 4415331Samw mbuf = resp.chain; 4425331Samw 4435331Samw /* 4445331Samw * Calculate MAC signature 4455331Samw */ 4466139Sjb150015 if (smb_sign_calc(&resp, sign, sr->reply_seqnum, signature) != 0) 4475331Samw return; 4485331Samw 4495331Samw /* 4505331Samw * Put signature in the response 4515331Samw * 4525331Samw * First find start of signature in chain (offset + signature offset) 4535331Samw */ 4545331Samw offset += SMB_SIG_OFFS; 4555331Samw while (offset >= mbuf->m_len) { 4565331Samw offset -= mbuf->m_len; 4575331Samw mbuf = mbuf->m_next; 4585331Samw } 4595331Samw 4605331Samw while (size >= mbuf->m_len - offset) { 4615331Samw (void) memcpy(&mbuf->m_data[offset], 4625331Samw sig_ptr, mbuf->m_len - offset); 4635331Samw offset = 0; 4645331Samw sig_ptr += mbuf->m_len - offset; 4655331Samw size -= mbuf->m_len - offset; 4665331Samw mbuf = mbuf->m_next; 4675331Samw } 4685331Samw if (size > 0) { 4695331Samw (void) memcpy(&mbuf->m_data[offset], sig_ptr, size); 4705331Samw } 4715331Samw } 472