xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_signing.c (revision 6600:4e63bcd27ae9)
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