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 265331Samw #pragma ident "%Z%%M% %I% %E% 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 * 325331Samw */ 335331Samw 345331Samw #include <sys/types.h> 355331Samw #include <sys/uio.h> 365331Samw #include <smbsrv/mbuf.h> 375331Samw #include <smbsrv/msgbuf.h> 385331Samw #include <sys/crypto/api.h> 395331Samw #include <smbsrv/smb_incl.h> 405331Samw 41*6600Sas200622 #define SMBAUTH_SESSION_KEY_SZ 16 425331Samw #define SMB_SIG_SIZE 8 435331Samw #define SMB_SIG_OFFS 14 445331Samw 455331Samw /* This holds the MD5 mechanism */ 465331Samw static crypto_mechanism_t crypto_mech = {CRYPTO_MECHANISM_INVALID, 0, 0}; 475331Samw 485331Samw /* 495331Samw * smb_sign_init 505331Samw * 515331Samw * Intializes MAC key based on the user session key and 525331Samw * NTLM response and store it in the signing structure. 535331Samw */ 545331Samw void 556139Sjb150015 smb_sign_init(smb_request_t *sr, smb_session_key_t *session_key, 565331Samw char *resp, int resp_len) 575331Samw { 586139Sjb150015 struct smb_sign *sign = &sr->session->signing; 595331Samw 605331Samw /* 615331Samw * Initialise the crypto mechanism to MD5 if it not 625331Samw * already initialised. 635331Samw */ 64*6600Sas200622 655331Samw if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) { 665331Samw crypto_mech.cm_type = crypto_mech2id(SUN_CKM_MD5); 675331Samw if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) { 685331Samw /* 695331Samw * There is no MD5 crypto mechanism 705331Samw * so turn off signing 715331Samw */ 726139Sjb150015 sr->sr_cfg->skc_signing_enable = 0; 736139Sjb150015 sr->session->secmode &= 745331Samw (~NEGOTIATE_SECURITY_SIGNATURES_ENABLED); 755331Samw cmn_err(CE_WARN, 765331Samw "SmbSignInit: signing disabled (no MD5)"); 775331Samw return; 785331Samw } 795331Samw } 805331Samw 815331Samw /* MAC key = concat (SessKey, NTLMResponse) */ 825331Samw 835331Samw bcopy(session_key, sign->mackey, sizeof (smb_session_key_t)); 845331Samw bcopy(resp, &(sign->mackey[sizeof (smb_session_key_t)]), 855331Samw resp_len); 865331Samw sign->mackey_len = sizeof (smb_session_key_t) + resp_len; 875331Samw 886139Sjb150015 sr->reply_seqnum = 1; 895331Samw sign->seqnum = 2; 905331Samw sign->flags = SMB_SIGNING_ENABLED; 915331Samw 926139Sjb150015 if (sr->sr_cfg->skc_signing_check) 935331Samw sign->flags |= SMB_SIGNING_CHECK; 945331Samw 955331Samw } 965331Samw 975331Samw /* 985331Samw * smb_sign_calc 995331Samw * 1005331Samw * Calculates MAC signature for the given buffer and returns 1015331Samw * it in the mac_sign parameter. 1025331Samw * 1035331Samw * The sequence number is placed in the first four bytes of the signature 1045331Samw * field of the signature and the other 4 bytes are zeroed. 1055331Samw * The signature is the first 8 bytes of the MD5 result of the 1065331Samw * concatenated MAC key and the SMB message. 1075331Samw * 1085331Samw * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8) 1095331Samw * 1105331Samw * where 1115331Samw * 1125331Samw * MACKey = concat( UserSessionKey, NTLMResp ) 1135331Samw * 1145331Samw * and 1155331Samw * 1165331Samw * SMBMsg is the SMB message containing the sequence number. 1175331Samw * 1185331Samw * Return 0 if success else -1 1195331Samw * 1205331Samw */ 1215331Samw static int 1225331Samw smb_sign_calc(struct mbuf_chain *mbc, 1235331Samw struct smb_sign *sign, 1245331Samw uint32_t seqnum, 1255331Samw unsigned char *mac_sign) 1265331Samw { 1275331Samw uint32_t seq_buf[2] = {0, 0}; 1285331Samw unsigned char mac[16]; 1295331Samw struct mbuf *mbuf = mbc->chain; 1305331Samw int offset = mbc->chain_offset; 1315331Samw int size; 1325331Samw int status; 1335331Samw 1345331Samw crypto_data_t data; 1355331Samw crypto_data_t digest; 1365331Samw crypto_context_t crypto_ctx; 1375331Samw 1385331Samw data.cd_format = CRYPTO_DATA_RAW; 1395331Samw data.cd_offset = 0; 1405331Samw data.cd_length = (size_t)-1; 1415331Samw data.cd_miscdata = 0; 1425331Samw 1435331Samw digest.cd_format = CRYPTO_DATA_RAW; 1445331Samw digest.cd_offset = 0; 1455331Samw digest.cd_length = (size_t)-1; 1465331Samw digest.cd_miscdata = 0; 1475331Samw digest.cd_raw.iov_base = (char *)mac; 1485331Samw digest.cd_raw.iov_len = sizeof (mac); 1495331Samw 1505331Samw status = crypto_digest_init(&crypto_mech, &crypto_ctx, 0); 151*6600Sas200622 if (status != CRYPTO_SUCCESS) 152*6600Sas200622 goto error; 1535331Samw 1545331Samw /* 1555331Samw * Put the sequence number into the first 4 bytes 1565331Samw * of the signature field in little endian format. 1575331Samw * We are using a buffer to represent the signature 1585331Samw * rather than modifying the SMB message. 1595331Samw */ 1605331Samw #ifdef __sparc 1615331Samw { 1625331Samw uint32_t temp; 1635331Samw ((uint8_t *)&temp)[0] = ((uint8_t *)&seqnum)[3]; 1645331Samw ((uint8_t *)&temp)[1] = ((uint8_t *)&seqnum)[2]; 1655331Samw ((uint8_t *)&temp)[2] = ((uint8_t *)&seqnum)[1]; 1665331Samw ((uint8_t *)&temp)[3] = ((uint8_t *)&seqnum)[0]; 1675331Samw 1685331Samw seq_buf[0] = temp; 1695331Samw } 1705331Samw #else 1715331Samw seq_buf[0] = seqnum; 1725331Samw #endif 1735331Samw 1745331Samw /* Digest the MACKey */ 1755331Samw data.cd_raw.iov_base = (char *)sign->mackey; 1765331Samw data.cd_raw.iov_len = sign->mackey_len; 177*6600Sas200622 data.cd_length = sign->mackey_len; 178*6600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 179*6600Sas200622 if (status != CRYPTO_SUCCESS) 180*6600Sas200622 goto error; 1815331Samw 1825331Samw /* Find start of data in chain */ 1835331Samw while (offset >= mbuf->m_len) { 1845331Samw offset -= mbuf->m_len; 1855331Samw mbuf = mbuf->m_next; 1865331Samw } 1875331Samw 1885331Samw /* Digest the SMB packet up to the signature field */ 1895331Samw size = SMB_SIG_OFFS; 1905331Samw while (size >= mbuf->m_len - offset) { 1915331Samw data.cd_raw.iov_base = &mbuf->m_data[offset]; 1925331Samw data.cd_raw.iov_len = mbuf->m_len - offset; 193*6600Sas200622 data.cd_length = mbuf->m_len - offset; 194*6600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 195*6600Sas200622 if (status != CRYPTO_SUCCESS) 196*6600Sas200622 goto error; 1975331Samw 1985331Samw size -= mbuf->m_len - offset; 1995331Samw mbuf = mbuf->m_next; 2005331Samw offset = 0; 2015331Samw } 2025331Samw if (size > 0) { 2035331Samw data.cd_raw.iov_base = &mbuf->m_data[offset]; 2045331Samw data.cd_raw.iov_len = size; 205*6600Sas200622 data.cd_length = size; 206*6600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 207*6600Sas200622 if (status != CRYPTO_SUCCESS) 208*6600Sas200622 goto error; 2095331Samw offset += size; 2105331Samw } 2115331Samw 2125331Samw /* 2135331Samw * Digest in the seq_buf instead of the signature 2145331Samw * which has the sequence number 2155331Samw */ 2165331Samw 2175331Samw data.cd_raw.iov_base = (char *)seq_buf; 2185331Samw data.cd_raw.iov_len = SMB_SIG_SIZE; 219*6600Sas200622 data.cd_length = SMB_SIG_SIZE; 220*6600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 221*6600Sas200622 if (status != CRYPTO_SUCCESS) 222*6600Sas200622 goto error; 2235331Samw 2245331Samw /* Find the end of the signature field */ 2255331Samw offset += SMB_SIG_SIZE; 2265331Samw while (offset >= mbuf->m_len) { 2275331Samw offset -= mbuf->m_len; 2285331Samw mbuf = mbuf->m_next; 2295331Samw } 2305331Samw /* Digest the rest of the SMB packet */ 2315331Samw while (mbuf) { 2325331Samw data.cd_raw.iov_base = &mbuf->m_data[offset]; 2335331Samw data.cd_raw.iov_len = mbuf->m_len - offset; 234*6600Sas200622 data.cd_length = mbuf->m_len - offset; 235*6600Sas200622 status = crypto_digest_update(crypto_ctx, &data, 0); 236*6600Sas200622 if (status != CRYPTO_SUCCESS) 237*6600Sas200622 goto error; 2385331Samw mbuf = mbuf->m_next; 2395331Samw offset = 0; 2405331Samw } 241*6600Sas200622 digest.cd_length = SMBAUTH_SESSION_KEY_SZ; 242*6600Sas200622 status = crypto_digest_final(crypto_ctx, &digest, 0); 243*6600Sas200622 if (status != CRYPTO_SUCCESS) 244*6600Sas200622 goto error; 2455331Samw bcopy(mac, mac_sign, SMB_SIG_SIZE); 2465331Samw return (0); 2475331Samw error: 2485331Samw cmn_err(CE_WARN, "SmbSignCalc: crypto error %d", status); 2495331Samw return (-1); 2505331Samw 2515331Samw } 2525331Samw 2535331Samw 2545331Samw /* 2555331Samw * smb_sign_check_request 2565331Samw * 2575331Samw * Calculates MAC signature for the request mbuf chain 2585331Samw * using the next expected sequence number and compares 2595331Samw * it to the given signature. 2605331Samw * 2615331Samw * Note it does not check the signature for secondary transactions 2625331Samw * as their sequence number is the same as the original request. 2635331Samw * 2645331Samw * Return 0 if the signature verifies, otherwise, returns -1; 2655331Samw * 2665331Samw */ 2675331Samw int 2686139Sjb150015 smb_sign_check_request(smb_request_t *sr) 2695331Samw { 2706139Sjb150015 struct mbuf_chain command = sr->command; 2715331Samw unsigned char mac_sig[SMB_SIG_SIZE]; 2726139Sjb150015 struct smb_sign *sign = &sr->session->signing; 2735331Samw int rtn = 0; 2745331Samw 2755331Samw /* 2765331Samw * Don't check secondary transactions - we dont know the sequence 2775331Samw * number. 2785331Samw */ 2796139Sjb150015 if (sr->smb_com == SMB_COM_TRANSACTION_SECONDARY || 2806139Sjb150015 sr->smb_com == SMB_COM_TRANSACTION2_SECONDARY || 2816139Sjb150015 sr->smb_com == SMB_COM_NT_TRANSACT_SECONDARY) 2825331Samw return (0); 2835331Samw 2845331Samw if (sign->flags & SMB_SIGNING_CHECK) { 2855331Samw 2865331Samw /* Reset the offset to begining of header */ 2876139Sjb150015 command.chain_offset = sr->orig_request_hdr; 2885331Samw 2895331Samw /* calculate mac signature */ 2905331Samw if (smb_sign_calc(&command, sign, sign->seqnum, mac_sig) != 0) 2915331Samw return (-1); 2925331Samw 2935331Samw /* compare the signatures */ 2946139Sjb150015 if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) { 2955331Samw cmn_err(CE_WARN, "SmbSignCheckRequest: " 2965331Samw "bad signature %x %x %x %x %x %x %x %x", 2976139Sjb150015 sr->smb_sig[0], sr->smb_sig[1], 2986139Sjb150015 sr->smb_sig[2], sr->smb_sig[3], 2996139Sjb150015 sr->smb_sig[4], sr->smb_sig[5], 3006139Sjb150015 sr->smb_sig[6], sr->smb_sig[7]); 3015331Samw #ifdef DBG_VERBOSE 3025331Samw /* Debug code to hunt for the sequence number */ 3035331Samw for (i = sign->seqnum - 6; i <= sign->seqnum + 6; i++) { 3045331Samw smb_sign_calc(&command, sign, i, mac_sig); 3056139Sjb150015 if (memcmp(mac_sig, sr->smb_sig, 3065331Samw SMB_SIG_SIZE) == 0) { 3075331Samw sign->seqnum = i; 3085331Samw goto ok; 3095331Samw } 3105331Samw } 3115331Samw #endif 3125331Samw rtn = -1; 3135331Samw } 3145331Samw } 3155331Samw ok: 3165331Samw /* 3175331Samw * Increament the sequence number for the reply, save the reply 3185331Samw * and set it for the next expect command. 3195331Samw * There is no reply for NT Cancel so just increament it for the 3205331Samw * next expected command. 3215331Samw */ 3225331Samw sign->seqnum++; 3235331Samw 3246139Sjb150015 if (sr->smb_com == SMB_COM_NT_CANCEL) 3256139Sjb150015 sr->reply_seqnum = 0; 3265331Samw else 3276139Sjb150015 sr->reply_seqnum = sign->seqnum++; 3285331Samw 3295331Samw return (rtn); 3305331Samw } 3315331Samw 3325331Samw /* 3335331Samw * smb_sign_check_secondary 3345331Samw * 3355331Samw * Calculates MAC signature for the secondary transaction mbuf chain 3365331Samw * and compares it to the given signature. 3375331Samw * Return 0 if the signature verifies, otherwise, returns -1; 3385331Samw * 3395331Samw */ 3405331Samw int 3416139Sjb150015 smb_sign_check_secondary(smb_request_t *sr, unsigned int reply_seqnum) 3425331Samw { 3436139Sjb150015 struct mbuf_chain command = sr->command; 3445331Samw unsigned char mac_sig[SMB_SIG_SIZE]; 3456139Sjb150015 struct smb_sign *sign = &sr->session->signing; 3465331Samw int rtn = 0; 3475331Samw 3485331Samw if (sign->flags & SMB_SIGNING_CHECK) { 3495331Samw /* Reset the offset to begining of header */ 3506139Sjb150015 command.chain_offset = sr->orig_request_hdr; 3515331Samw 3525331Samw /* calculate mac signature */ 3535331Samw if (smb_sign_calc(&command, sign, reply_seqnum - 1, 3545331Samw mac_sig) != 0) 3555331Samw return (-1); 3565331Samw 3575331Samw 3585331Samw /* compare the signatures */ 3596139Sjb150015 if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) { 3605331Samw cmn_err(CE_WARN, "SmbSignCheckSecond: bad signature"); 3615331Samw rtn = -1; 3625331Samw } 3635331Samw } 3645331Samw /* Save the reply sequence number */ 3656139Sjb150015 sr->reply_seqnum = reply_seqnum; 3665331Samw 3675331Samw return (rtn); 3685331Samw } 3695331Samw 3705331Samw 3715331Samw 3725331Samw 3735331Samw /* 3745331Samw * smb_sign_reply 3755331Samw * 3765331Samw * Calculates MAC signature for the given mbuf chain, 3775331Samw * and write it to the signature field in the mbuf. 3785331Samw * 3795331Samw */ 3805331Samw void 3816139Sjb150015 smb_sign_reply(smb_request_t *sr, struct mbuf_chain *reply) 3825331Samw { 3835331Samw struct mbuf_chain resp; 3846139Sjb150015 struct smb_sign *sign = &sr->session->signing; 3855331Samw unsigned char signature[SMB_SIG_SIZE]; 3865331Samw struct mbuf *mbuf; 3875331Samw int size = SMB_SIG_SIZE; 3885331Samw unsigned char *sig_ptr = signature; 3895331Samw int offset = 0; 3905331Samw 3915331Samw if (reply) 3925331Samw resp = *reply; 3935331Samw else 3946139Sjb150015 resp = sr->reply; 3955331Samw 3965331Samw /* Reset offset to start of reply */ 3975331Samw resp.chain_offset = 0; 3985331Samw mbuf = resp.chain; 3995331Samw 4005331Samw /* 4015331Samw * Calculate MAC signature 4025331Samw */ 4036139Sjb150015 if (smb_sign_calc(&resp, sign, sr->reply_seqnum, signature) != 0) 4045331Samw return; 4055331Samw 4065331Samw /* 4075331Samw * Put signature in the response 4085331Samw * 4095331Samw * First find start of signature in chain (offset + signature offset) 4105331Samw */ 4115331Samw offset += SMB_SIG_OFFS; 4125331Samw while (offset >= mbuf->m_len) { 4135331Samw offset -= mbuf->m_len; 4145331Samw mbuf = mbuf->m_next; 4155331Samw } 4165331Samw 4175331Samw while (size >= mbuf->m_len - offset) { 4185331Samw (void) memcpy(&mbuf->m_data[offset], 4195331Samw sig_ptr, mbuf->m_len - offset); 4205331Samw offset = 0; 4215331Samw sig_ptr += mbuf->m_len - offset; 4225331Samw size -= mbuf->m_len - offset; 4235331Samw mbuf = mbuf->m_next; 4245331Samw } 4255331Samw if (size > 0) { 4265331Samw (void) memcpy(&mbuf->m_data[offset], sig_ptr, size); 4275331Samw } 4285331Samw } 429