xref: /linux/fs/smb/server/auth.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
138c8a9a5SSteve French // SPDX-License-Identifier: GPL-2.0-or-later
238c8a9a5SSteve French /*
338c8a9a5SSteve French  *   Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org>
438c8a9a5SSteve French  *   Copyright (C) 2018 Samsung Electronics Co., Ltd.
538c8a9a5SSteve French  */
638c8a9a5SSteve French 
738c8a9a5SSteve French #include <linux/kernel.h>
838c8a9a5SSteve French #include <linux/fs.h>
938c8a9a5SSteve French #include <linux/uaccess.h>
1038c8a9a5SSteve French #include <linux/backing-dev.h>
1138c8a9a5SSteve French #include <linux/writeback.h>
1238c8a9a5SSteve French #include <linux/uio.h>
1338c8a9a5SSteve French #include <linux/xattr.h>
1438c8a9a5SSteve French #include <crypto/hash.h>
1538c8a9a5SSteve French #include <crypto/aead.h>
1638c8a9a5SSteve French #include <linux/random.h>
1738c8a9a5SSteve French #include <linux/scatterlist.h>
1838c8a9a5SSteve French 
1938c8a9a5SSteve French #include "auth.h"
2038c8a9a5SSteve French #include "glob.h"
2138c8a9a5SSteve French 
2238c8a9a5SSteve French #include <linux/fips.h>
2338c8a9a5SSteve French #include <crypto/des.h>
2438c8a9a5SSteve French 
2538c8a9a5SSteve French #include "server.h"
2638c8a9a5SSteve French #include "smb_common.h"
2738c8a9a5SSteve French #include "connection.h"
2838c8a9a5SSteve French #include "mgmt/user_session.h"
2938c8a9a5SSteve French #include "mgmt/user_config.h"
3038c8a9a5SSteve French #include "crypto_ctx.h"
3138c8a9a5SSteve French #include "transport_ipc.h"
3238c8a9a5SSteve French #include "../common/arc4.h"
3338c8a9a5SSteve French 
3438c8a9a5SSteve French /*
3538c8a9a5SSteve French  * Fixed format data defining GSS header and fixed string
3638c8a9a5SSteve French  * "not_defined_in_RFC4178@please_ignore".
3738c8a9a5SSteve French  * So sec blob data in neg phase could be generated statically.
3838c8a9a5SSteve French  */
3938c8a9a5SSteve French static char NEGOTIATE_GSS_HEADER[AUTH_GSS_LENGTH] = {
4038c8a9a5SSteve French #ifdef CONFIG_SMB_SERVER_KERBEROS5
4138c8a9a5SSteve French 	0x60, 0x5e, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05,
4238c8a9a5SSteve French 	0x05, 0x02, 0xa0, 0x54, 0x30, 0x52, 0xa0, 0x24,
4338c8a9a5SSteve French 	0x30, 0x22, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
4438c8a9a5SSteve French 	0xf7, 0x12, 0x01, 0x02, 0x02, 0x06, 0x09, 0x2a,
4538c8a9a5SSteve French 	0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02,
4638c8a9a5SSteve French 	0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82,
4738c8a9a5SSteve French 	0x37, 0x02, 0x02, 0x0a, 0xa3, 0x2a, 0x30, 0x28,
4838c8a9a5SSteve French 	0xa0, 0x26, 0x1b, 0x24, 0x6e, 0x6f, 0x74, 0x5f,
4938c8a9a5SSteve French 	0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f,
5038c8a9a5SSteve French 	0x69, 0x6e, 0x5f, 0x52, 0x46, 0x43, 0x34, 0x31,
5138c8a9a5SSteve French 	0x37, 0x38, 0x40, 0x70, 0x6c, 0x65, 0x61, 0x73,
5238c8a9a5SSteve French 	0x65, 0x5f, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65
5338c8a9a5SSteve French #else
5438c8a9a5SSteve French 	0x60, 0x48, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05,
5538c8a9a5SSteve French 	0x05, 0x02, 0xa0, 0x3e, 0x30, 0x3c, 0xa0, 0x0e,
5638c8a9a5SSteve French 	0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
5738c8a9a5SSteve French 	0x01, 0x82, 0x37, 0x02, 0x02, 0x0a, 0xa3, 0x2a,
5838c8a9a5SSteve French 	0x30, 0x28, 0xa0, 0x26, 0x1b, 0x24, 0x6e, 0x6f,
5938c8a9a5SSteve French 	0x74, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65,
6038c8a9a5SSteve French 	0x64, 0x5f, 0x69, 0x6e, 0x5f, 0x52, 0x46, 0x43,
6138c8a9a5SSteve French 	0x34, 0x31, 0x37, 0x38, 0x40, 0x70, 0x6c, 0x65,
6238c8a9a5SSteve French 	0x61, 0x73, 0x65, 0x5f, 0x69, 0x67, 0x6e, 0x6f,
6338c8a9a5SSteve French 	0x72, 0x65
6438c8a9a5SSteve French #endif
6538c8a9a5SSteve French };
6638c8a9a5SSteve French 
ksmbd_copy_gss_neg_header(void * buf)6738c8a9a5SSteve French void ksmbd_copy_gss_neg_header(void *buf)
6838c8a9a5SSteve French {
6938c8a9a5SSteve French 	memcpy(buf, NEGOTIATE_GSS_HEADER, AUTH_GSS_LENGTH);
7038c8a9a5SSteve French }
7138c8a9a5SSteve French 
7238c8a9a5SSteve French /**
7338c8a9a5SSteve French  * ksmbd_gen_sess_key() - function to generate session key
7438c8a9a5SSteve French  * @sess:	session of connection
7538c8a9a5SSteve French  * @hash:	source hash value to be used for find session key
7638c8a9a5SSteve French  * @hmac:	source hmac value to be used for finding session key
7738c8a9a5SSteve French  *
7838c8a9a5SSteve French  */
ksmbd_gen_sess_key(struct ksmbd_session * sess,char * hash,char * hmac)7938c8a9a5SSteve French static int ksmbd_gen_sess_key(struct ksmbd_session *sess, char *hash,
8038c8a9a5SSteve French 			      char *hmac)
8138c8a9a5SSteve French {
8238c8a9a5SSteve French 	struct ksmbd_crypto_ctx *ctx;
8338c8a9a5SSteve French 	int rc;
8438c8a9a5SSteve French 
8538c8a9a5SSteve French 	ctx = ksmbd_crypto_ctx_find_hmacmd5();
8638c8a9a5SSteve French 	if (!ctx) {
8738c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n");
8838c8a9a5SSteve French 		return -ENOMEM;
8938c8a9a5SSteve French 	}
9038c8a9a5SSteve French 
9138c8a9a5SSteve French 	rc = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx),
9238c8a9a5SSteve French 				 hash,
9338c8a9a5SSteve French 				 CIFS_HMAC_MD5_HASH_SIZE);
9438c8a9a5SSteve French 	if (rc) {
9538c8a9a5SSteve French 		ksmbd_debug(AUTH, "hmacmd5 set key fail error %d\n", rc);
9638c8a9a5SSteve French 		goto out;
9738c8a9a5SSteve French 	}
9838c8a9a5SSteve French 
9938c8a9a5SSteve French 	rc = crypto_shash_init(CRYPTO_HMACMD5(ctx));
10038c8a9a5SSteve French 	if (rc) {
10138c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not init hmacmd5 error %d\n", rc);
10238c8a9a5SSteve French 		goto out;
10338c8a9a5SSteve French 	}
10438c8a9a5SSteve French 
10538c8a9a5SSteve French 	rc = crypto_shash_update(CRYPTO_HMACMD5(ctx),
10638c8a9a5SSteve French 				 hmac,
10738c8a9a5SSteve French 				 SMB2_NTLMV2_SESSKEY_SIZE);
10838c8a9a5SSteve French 	if (rc) {
10938c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not update with response error %d\n", rc);
11038c8a9a5SSteve French 		goto out;
11138c8a9a5SSteve French 	}
11238c8a9a5SSteve French 
11338c8a9a5SSteve French 	rc = crypto_shash_final(CRYPTO_HMACMD5(ctx), sess->sess_key);
11438c8a9a5SSteve French 	if (rc) {
11538c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not generate hmacmd5 hash error %d\n", rc);
11638c8a9a5SSteve French 		goto out;
11738c8a9a5SSteve French 	}
11838c8a9a5SSteve French 
11938c8a9a5SSteve French out:
12038c8a9a5SSteve French 	ksmbd_release_crypto_ctx(ctx);
12138c8a9a5SSteve French 	return rc;
12238c8a9a5SSteve French }
12338c8a9a5SSteve French 
calc_ntlmv2_hash(struct ksmbd_conn * conn,struct ksmbd_session * sess,char * ntlmv2_hash,char * dname)12438c8a9a5SSteve French static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess,
12538c8a9a5SSteve French 			    char *ntlmv2_hash, char *dname)
12638c8a9a5SSteve French {
12738c8a9a5SSteve French 	int ret, len, conv_len;
12838c8a9a5SSteve French 	wchar_t *domain = NULL;
12938c8a9a5SSteve French 	__le16 *uniname = NULL;
13038c8a9a5SSteve French 	struct ksmbd_crypto_ctx *ctx;
13138c8a9a5SSteve French 
13238c8a9a5SSteve French 	ctx = ksmbd_crypto_ctx_find_hmacmd5();
13338c8a9a5SSteve French 	if (!ctx) {
13438c8a9a5SSteve French 		ksmbd_debug(AUTH, "can't generate ntlmv2 hash\n");
13538c8a9a5SSteve French 		return -ENOMEM;
13638c8a9a5SSteve French 	}
13738c8a9a5SSteve French 
13838c8a9a5SSteve French 	ret = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx),
13938c8a9a5SSteve French 				  user_passkey(sess->user),
14038c8a9a5SSteve French 				  CIFS_ENCPWD_SIZE);
14138c8a9a5SSteve French 	if (ret) {
14238c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not set NT Hash as a key\n");
14338c8a9a5SSteve French 		goto out;
14438c8a9a5SSteve French 	}
14538c8a9a5SSteve French 
14638c8a9a5SSteve French 	ret = crypto_shash_init(CRYPTO_HMACMD5(ctx));
14738c8a9a5SSteve French 	if (ret) {
14838c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not init hmacmd5\n");
14938c8a9a5SSteve French 		goto out;
15038c8a9a5SSteve French 	}
15138c8a9a5SSteve French 
15238c8a9a5SSteve French 	/* convert user_name to unicode */
15338c8a9a5SSteve French 	len = strlen(user_name(sess->user));
15438c8a9a5SSteve French 	uniname = kzalloc(2 + UNICODE_LEN(len), GFP_KERNEL);
15538c8a9a5SSteve French 	if (!uniname) {
15638c8a9a5SSteve French 		ret = -ENOMEM;
15738c8a9a5SSteve French 		goto out;
15838c8a9a5SSteve French 	}
15938c8a9a5SSteve French 
16038c8a9a5SSteve French 	conv_len = smb_strtoUTF16(uniname, user_name(sess->user), len,
16138c8a9a5SSteve French 				  conn->local_nls);
16238c8a9a5SSteve French 	if (conv_len < 0 || conv_len > len) {
16338c8a9a5SSteve French 		ret = -EINVAL;
16438c8a9a5SSteve French 		goto out;
16538c8a9a5SSteve French 	}
16638c8a9a5SSteve French 	UniStrupr(uniname);
16738c8a9a5SSteve French 
16838c8a9a5SSteve French 	ret = crypto_shash_update(CRYPTO_HMACMD5(ctx),
16938c8a9a5SSteve French 				  (char *)uniname,
17038c8a9a5SSteve French 				  UNICODE_LEN(conv_len));
17138c8a9a5SSteve French 	if (ret) {
17238c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not update with user\n");
17338c8a9a5SSteve French 		goto out;
17438c8a9a5SSteve French 	}
17538c8a9a5SSteve French 
17638c8a9a5SSteve French 	/* Convert domain name or conn name to unicode and uppercase */
17738c8a9a5SSteve French 	len = strlen(dname);
17838c8a9a5SSteve French 	domain = kzalloc(2 + UNICODE_LEN(len), GFP_KERNEL);
17938c8a9a5SSteve French 	if (!domain) {
18038c8a9a5SSteve French 		ret = -ENOMEM;
18138c8a9a5SSteve French 		goto out;
18238c8a9a5SSteve French 	}
18338c8a9a5SSteve French 
18438c8a9a5SSteve French 	conv_len = smb_strtoUTF16((__le16 *)domain, dname, len,
18538c8a9a5SSteve French 				  conn->local_nls);
18638c8a9a5SSteve French 	if (conv_len < 0 || conv_len > len) {
18738c8a9a5SSteve French 		ret = -EINVAL;
18838c8a9a5SSteve French 		goto out;
18938c8a9a5SSteve French 	}
19038c8a9a5SSteve French 
19138c8a9a5SSteve French 	ret = crypto_shash_update(CRYPTO_HMACMD5(ctx),
19238c8a9a5SSteve French 				  (char *)domain,
19338c8a9a5SSteve French 				  UNICODE_LEN(conv_len));
19438c8a9a5SSteve French 	if (ret) {
19538c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not update with domain\n");
19638c8a9a5SSteve French 		goto out;
19738c8a9a5SSteve French 	}
19838c8a9a5SSteve French 
19938c8a9a5SSteve French 	ret = crypto_shash_final(CRYPTO_HMACMD5(ctx), ntlmv2_hash);
20038c8a9a5SSteve French 	if (ret)
20138c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not generate md5 hash\n");
20238c8a9a5SSteve French out:
20338c8a9a5SSteve French 	kfree(uniname);
20438c8a9a5SSteve French 	kfree(domain);
20538c8a9a5SSteve French 	ksmbd_release_crypto_ctx(ctx);
20638c8a9a5SSteve French 	return ret;
20738c8a9a5SSteve French }
20838c8a9a5SSteve French 
20938c8a9a5SSteve French /**
21038c8a9a5SSteve French  * ksmbd_auth_ntlmv2() - NTLMv2 authentication handler
211*b4068f1eSRandy Dunlap  * @conn:		connection
21238c8a9a5SSteve French  * @sess:		session of connection
21338c8a9a5SSteve French  * @ntlmv2:		NTLMv2 challenge response
21438c8a9a5SSteve French  * @blen:		NTLMv2 blob length
21538c8a9a5SSteve French  * @domain_name:	domain name
216*b4068f1eSRandy Dunlap  * @cryptkey:		session crypto key
21738c8a9a5SSteve French  *
21838c8a9a5SSteve French  * Return:	0 on success, error number on error
21938c8a9a5SSteve French  */
ksmbd_auth_ntlmv2(struct ksmbd_conn * conn,struct ksmbd_session * sess,struct ntlmv2_resp * ntlmv2,int blen,char * domain_name,char * cryptkey)22038c8a9a5SSteve French int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
22138c8a9a5SSteve French 		      struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
22238c8a9a5SSteve French 		      char *cryptkey)
22338c8a9a5SSteve French {
22438c8a9a5SSteve French 	char ntlmv2_hash[CIFS_ENCPWD_SIZE];
22538c8a9a5SSteve French 	char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
22638c8a9a5SSteve French 	struct ksmbd_crypto_ctx *ctx = NULL;
22738c8a9a5SSteve French 	char *construct = NULL;
22838c8a9a5SSteve French 	int rc, len;
22938c8a9a5SSteve French 
23038c8a9a5SSteve French 	rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name);
23138c8a9a5SSteve French 	if (rc) {
23238c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc);
23338c8a9a5SSteve French 		goto out;
23438c8a9a5SSteve French 	}
23538c8a9a5SSteve French 
23638c8a9a5SSteve French 	ctx = ksmbd_crypto_ctx_find_hmacmd5();
23738c8a9a5SSteve French 	if (!ctx) {
23838c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n");
23938c8a9a5SSteve French 		return -ENOMEM;
24038c8a9a5SSteve French 	}
24138c8a9a5SSteve French 
24238c8a9a5SSteve French 	rc = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx),
24338c8a9a5SSteve French 				 ntlmv2_hash,
24438c8a9a5SSteve French 				 CIFS_HMAC_MD5_HASH_SIZE);
24538c8a9a5SSteve French 	if (rc) {
24638c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not set NTLMV2 Hash as a key\n");
24738c8a9a5SSteve French 		goto out;
24838c8a9a5SSteve French 	}
24938c8a9a5SSteve French 
25038c8a9a5SSteve French 	rc = crypto_shash_init(CRYPTO_HMACMD5(ctx));
25138c8a9a5SSteve French 	if (rc) {
25238c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not init hmacmd5\n");
25338c8a9a5SSteve French 		goto out;
25438c8a9a5SSteve French 	}
25538c8a9a5SSteve French 
25638c8a9a5SSteve French 	len = CIFS_CRYPTO_KEY_SIZE + blen;
25738c8a9a5SSteve French 	construct = kzalloc(len, GFP_KERNEL);
25838c8a9a5SSteve French 	if (!construct) {
25938c8a9a5SSteve French 		rc = -ENOMEM;
26038c8a9a5SSteve French 		goto out;
26138c8a9a5SSteve French 	}
26238c8a9a5SSteve French 
26338c8a9a5SSteve French 	memcpy(construct, cryptkey, CIFS_CRYPTO_KEY_SIZE);
26438c8a9a5SSteve French 	memcpy(construct + CIFS_CRYPTO_KEY_SIZE, &ntlmv2->blob_signature, blen);
26538c8a9a5SSteve French 
26638c8a9a5SSteve French 	rc = crypto_shash_update(CRYPTO_HMACMD5(ctx), construct, len);
26738c8a9a5SSteve French 	if (rc) {
26838c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not update with response\n");
26938c8a9a5SSteve French 		goto out;
27038c8a9a5SSteve French 	}
27138c8a9a5SSteve French 
27238c8a9a5SSteve French 	rc = crypto_shash_final(CRYPTO_HMACMD5(ctx), ntlmv2_rsp);
27338c8a9a5SSteve French 	if (rc) {
27438c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not generate md5 hash\n");
27538c8a9a5SSteve French 		goto out;
27638c8a9a5SSteve French 	}
27738c8a9a5SSteve French 	ksmbd_release_crypto_ctx(ctx);
27838c8a9a5SSteve French 	ctx = NULL;
27938c8a9a5SSteve French 
28038c8a9a5SSteve French 	rc = ksmbd_gen_sess_key(sess, ntlmv2_hash, ntlmv2_rsp);
28138c8a9a5SSteve French 	if (rc) {
28238c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not generate sess key\n");
28338c8a9a5SSteve French 		goto out;
28438c8a9a5SSteve French 	}
28538c8a9a5SSteve French 
28638c8a9a5SSteve French 	if (memcmp(ntlmv2->ntlmv2_hash, ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE) != 0)
28738c8a9a5SSteve French 		rc = -EINVAL;
28838c8a9a5SSteve French out:
28938c8a9a5SSteve French 	if (ctx)
29038c8a9a5SSteve French 		ksmbd_release_crypto_ctx(ctx);
29138c8a9a5SSteve French 	kfree(construct);
29238c8a9a5SSteve French 	return rc;
29338c8a9a5SSteve French }
29438c8a9a5SSteve French 
29538c8a9a5SSteve French /**
29638c8a9a5SSteve French  * ksmbd_decode_ntlmssp_auth_blob() - helper function to construct
29738c8a9a5SSteve French  * authenticate blob
29838c8a9a5SSteve French  * @authblob:	authenticate blob source pointer
299*b4068f1eSRandy Dunlap  * @blob_len:	length of the @authblob message
300*b4068f1eSRandy Dunlap  * @conn:	connection
30138c8a9a5SSteve French  * @sess:	session of connection
30238c8a9a5SSteve French  *
30338c8a9a5SSteve French  * Return:	0 on success, error number on error
30438c8a9a5SSteve French  */
ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message * authblob,int blob_len,struct ksmbd_conn * conn,struct ksmbd_session * sess)30538c8a9a5SSteve French int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
30638c8a9a5SSteve French 				   int blob_len, struct ksmbd_conn *conn,
30738c8a9a5SSteve French 				   struct ksmbd_session *sess)
30838c8a9a5SSteve French {
30938c8a9a5SSteve French 	char *domain_name;
31038c8a9a5SSteve French 	unsigned int nt_off, dn_off;
31138c8a9a5SSteve French 	unsigned short nt_len, dn_len;
31238c8a9a5SSteve French 	int ret;
31338c8a9a5SSteve French 
31438c8a9a5SSteve French 	if (blob_len < sizeof(struct authenticate_message)) {
31538c8a9a5SSteve French 		ksmbd_debug(AUTH, "negotiate blob len %d too small\n",
31638c8a9a5SSteve French 			    blob_len);
31738c8a9a5SSteve French 		return -EINVAL;
31838c8a9a5SSteve French 	}
31938c8a9a5SSteve French 
32038c8a9a5SSteve French 	if (memcmp(authblob->Signature, "NTLMSSP", 8)) {
32138c8a9a5SSteve French 		ksmbd_debug(AUTH, "blob signature incorrect %s\n",
32238c8a9a5SSteve French 			    authblob->Signature);
32338c8a9a5SSteve French 		return -EINVAL;
32438c8a9a5SSteve French 	}
32538c8a9a5SSteve French 
32638c8a9a5SSteve French 	nt_off = le32_to_cpu(authblob->NtChallengeResponse.BufferOffset);
32738c8a9a5SSteve French 	nt_len = le16_to_cpu(authblob->NtChallengeResponse.Length);
32838c8a9a5SSteve French 	dn_off = le32_to_cpu(authblob->DomainName.BufferOffset);
32938c8a9a5SSteve French 	dn_len = le16_to_cpu(authblob->DomainName.Length);
33038c8a9a5SSteve French 
33138c8a9a5SSteve French 	if (blob_len < (u64)dn_off + dn_len || blob_len < (u64)nt_off + nt_len ||
33238c8a9a5SSteve French 	    nt_len < CIFS_ENCPWD_SIZE)
33338c8a9a5SSteve French 		return -EINVAL;
33438c8a9a5SSteve French 
33538c8a9a5SSteve French 	/* TODO : use domain name that imported from configuration file */
33638c8a9a5SSteve French 	domain_name = smb_strndup_from_utf16((const char *)authblob + dn_off,
33738c8a9a5SSteve French 					     dn_len, true, conn->local_nls);
33838c8a9a5SSteve French 	if (IS_ERR(domain_name))
33938c8a9a5SSteve French 		return PTR_ERR(domain_name);
34038c8a9a5SSteve French 
34138c8a9a5SSteve French 	/* process NTLMv2 authentication */
34238c8a9a5SSteve French 	ksmbd_debug(AUTH, "decode_ntlmssp_authenticate_blob dname%s\n",
34338c8a9a5SSteve French 		    domain_name);
34438c8a9a5SSteve French 	ret = ksmbd_auth_ntlmv2(conn, sess,
34538c8a9a5SSteve French 				(struct ntlmv2_resp *)((char *)authblob + nt_off),
34638c8a9a5SSteve French 				nt_len - CIFS_ENCPWD_SIZE,
34738c8a9a5SSteve French 				domain_name, conn->ntlmssp.cryptkey);
34838c8a9a5SSteve French 	kfree(domain_name);
34938c8a9a5SSteve French 
35038c8a9a5SSteve French 	/* The recovered secondary session key */
35138c8a9a5SSteve French 	if (conn->ntlmssp.client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) {
35238c8a9a5SSteve French 		struct arc4_ctx *ctx_arc4;
35338c8a9a5SSteve French 		unsigned int sess_key_off, sess_key_len;
35438c8a9a5SSteve French 
35538c8a9a5SSteve French 		sess_key_off = le32_to_cpu(authblob->SessionKey.BufferOffset);
35638c8a9a5SSteve French 		sess_key_len = le16_to_cpu(authblob->SessionKey.Length);
35738c8a9a5SSteve French 
35838c8a9a5SSteve French 		if (blob_len < (u64)sess_key_off + sess_key_len)
35938c8a9a5SSteve French 			return -EINVAL;
36038c8a9a5SSteve French 
3614b081ce0SNamjae Jeon 		if (sess_key_len > CIFS_KEY_SIZE)
3624b081ce0SNamjae Jeon 			return -EINVAL;
3634b081ce0SNamjae Jeon 
36438c8a9a5SSteve French 		ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL);
36538c8a9a5SSteve French 		if (!ctx_arc4)
36638c8a9a5SSteve French 			return -ENOMEM;
36738c8a9a5SSteve French 
36838c8a9a5SSteve French 		cifs_arc4_setkey(ctx_arc4, sess->sess_key,
36938c8a9a5SSteve French 				 SMB2_NTLMV2_SESSKEY_SIZE);
37038c8a9a5SSteve French 		cifs_arc4_crypt(ctx_arc4, sess->sess_key,
37138c8a9a5SSteve French 				(char *)authblob + sess_key_off, sess_key_len);
37238c8a9a5SSteve French 		kfree_sensitive(ctx_arc4);
37338c8a9a5SSteve French 	}
37438c8a9a5SSteve French 
37538c8a9a5SSteve French 	return ret;
37638c8a9a5SSteve French }
37738c8a9a5SSteve French 
37838c8a9a5SSteve French /**
37938c8a9a5SSteve French  * ksmbd_decode_ntlmssp_neg_blob() - helper function to construct
38038c8a9a5SSteve French  * negotiate blob
38138c8a9a5SSteve French  * @negblob: negotiate blob source pointer
382*b4068f1eSRandy Dunlap  * @blob_len:	length of the @authblob message
383*b4068f1eSRandy Dunlap  * @conn:	connection
38438c8a9a5SSteve French  *
38538c8a9a5SSteve French  */
ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message * negblob,int blob_len,struct ksmbd_conn * conn)38638c8a9a5SSteve French int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
38738c8a9a5SSteve French 				  int blob_len, struct ksmbd_conn *conn)
38838c8a9a5SSteve French {
38938c8a9a5SSteve French 	if (blob_len < sizeof(struct negotiate_message)) {
39038c8a9a5SSteve French 		ksmbd_debug(AUTH, "negotiate blob len %d too small\n",
39138c8a9a5SSteve French 			    blob_len);
39238c8a9a5SSteve French 		return -EINVAL;
39338c8a9a5SSteve French 	}
39438c8a9a5SSteve French 
39538c8a9a5SSteve French 	if (memcmp(negblob->Signature, "NTLMSSP", 8)) {
39638c8a9a5SSteve French 		ksmbd_debug(AUTH, "blob signature incorrect %s\n",
39738c8a9a5SSteve French 			    negblob->Signature);
39838c8a9a5SSteve French 		return -EINVAL;
39938c8a9a5SSteve French 	}
40038c8a9a5SSteve French 
40138c8a9a5SSteve French 	conn->ntlmssp.client_flags = le32_to_cpu(negblob->NegotiateFlags);
40238c8a9a5SSteve French 	return 0;
40338c8a9a5SSteve French }
40438c8a9a5SSteve French 
40538c8a9a5SSteve French /**
40638c8a9a5SSteve French  * ksmbd_build_ntlmssp_challenge_blob() - helper function to construct
40738c8a9a5SSteve French  * challenge blob
40838c8a9a5SSteve French  * @chgblob: challenge blob source pointer to initialize
409*b4068f1eSRandy Dunlap  * @conn:	connection
41038c8a9a5SSteve French  *
41138c8a9a5SSteve French  */
41238c8a9a5SSteve French unsigned int
ksmbd_build_ntlmssp_challenge_blob(struct challenge_message * chgblob,struct ksmbd_conn * conn)41338c8a9a5SSteve French ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
41438c8a9a5SSteve French 				   struct ksmbd_conn *conn)
41538c8a9a5SSteve French {
41638c8a9a5SSteve French 	struct target_info *tinfo;
41738c8a9a5SSteve French 	wchar_t *name;
41838c8a9a5SSteve French 	__u8 *target_name;
41938c8a9a5SSteve French 	unsigned int flags, blob_off, blob_len, type, target_info_len = 0;
42038c8a9a5SSteve French 	int len, uni_len, conv_len;
42138c8a9a5SSteve French 	int cflags = conn->ntlmssp.client_flags;
42238c8a9a5SSteve French 
42338c8a9a5SSteve French 	memcpy(chgblob->Signature, NTLMSSP_SIGNATURE, 8);
42438c8a9a5SSteve French 	chgblob->MessageType = NtLmChallenge;
42538c8a9a5SSteve French 
42638c8a9a5SSteve French 	flags = NTLMSSP_NEGOTIATE_UNICODE |
42738c8a9a5SSteve French 		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_TARGET_TYPE_SERVER |
42838c8a9a5SSteve French 		NTLMSSP_NEGOTIATE_TARGET_INFO;
42938c8a9a5SSteve French 
43038c8a9a5SSteve French 	if (cflags & NTLMSSP_NEGOTIATE_SIGN) {
43138c8a9a5SSteve French 		flags |= NTLMSSP_NEGOTIATE_SIGN;
43238c8a9a5SSteve French 		flags |= cflags & (NTLMSSP_NEGOTIATE_128 |
43338c8a9a5SSteve French 				   NTLMSSP_NEGOTIATE_56);
43438c8a9a5SSteve French 	}
43538c8a9a5SSteve French 
43638c8a9a5SSteve French 	if (cflags & NTLMSSP_NEGOTIATE_SEAL && smb3_encryption_negotiated(conn))
43738c8a9a5SSteve French 		flags |= NTLMSSP_NEGOTIATE_SEAL;
43838c8a9a5SSteve French 
43938c8a9a5SSteve French 	if (cflags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
44038c8a9a5SSteve French 		flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
44138c8a9a5SSteve French 
44238c8a9a5SSteve French 	if (cflags & NTLMSSP_REQUEST_TARGET)
44338c8a9a5SSteve French 		flags |= NTLMSSP_REQUEST_TARGET;
44438c8a9a5SSteve French 
44538c8a9a5SSteve French 	if (conn->use_spnego &&
44638c8a9a5SSteve French 	    (cflags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
44738c8a9a5SSteve French 		flags |= NTLMSSP_NEGOTIATE_EXTENDED_SEC;
44838c8a9a5SSteve French 
44938c8a9a5SSteve French 	if (cflags & NTLMSSP_NEGOTIATE_KEY_XCH)
45038c8a9a5SSteve French 		flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
45138c8a9a5SSteve French 
45238c8a9a5SSteve French 	chgblob->NegotiateFlags = cpu_to_le32(flags);
45338c8a9a5SSteve French 	len = strlen(ksmbd_netbios_name());
45438c8a9a5SSteve French 	name = kmalloc(2 + UNICODE_LEN(len), GFP_KERNEL);
45538c8a9a5SSteve French 	if (!name)
45638c8a9a5SSteve French 		return -ENOMEM;
45738c8a9a5SSteve French 
45838c8a9a5SSteve French 	conv_len = smb_strtoUTF16((__le16 *)name, ksmbd_netbios_name(), len,
45938c8a9a5SSteve French 				  conn->local_nls);
46038c8a9a5SSteve French 	if (conv_len < 0 || conv_len > len) {
46138c8a9a5SSteve French 		kfree(name);
46238c8a9a5SSteve French 		return -EINVAL;
46338c8a9a5SSteve French 	}
46438c8a9a5SSteve French 
46538c8a9a5SSteve French 	uni_len = UNICODE_LEN(conv_len);
46638c8a9a5SSteve French 
46738c8a9a5SSteve French 	blob_off = sizeof(struct challenge_message);
46838c8a9a5SSteve French 	blob_len = blob_off + uni_len;
46938c8a9a5SSteve French 
47038c8a9a5SSteve French 	chgblob->TargetName.Length = cpu_to_le16(uni_len);
47138c8a9a5SSteve French 	chgblob->TargetName.MaximumLength = cpu_to_le16(uni_len);
47238c8a9a5SSteve French 	chgblob->TargetName.BufferOffset = cpu_to_le32(blob_off);
47338c8a9a5SSteve French 
47438c8a9a5SSteve French 	/* Initialize random conn challenge */
47538c8a9a5SSteve French 	get_random_bytes(conn->ntlmssp.cryptkey, sizeof(__u64));
47638c8a9a5SSteve French 	memcpy(chgblob->Challenge, conn->ntlmssp.cryptkey,
47738c8a9a5SSteve French 	       CIFS_CRYPTO_KEY_SIZE);
47838c8a9a5SSteve French 
47938c8a9a5SSteve French 	/* Add Target Information to security buffer */
48038c8a9a5SSteve French 	chgblob->TargetInfoArray.BufferOffset = cpu_to_le32(blob_len);
48138c8a9a5SSteve French 
48238c8a9a5SSteve French 	target_name = (__u8 *)chgblob + blob_off;
48338c8a9a5SSteve French 	memcpy(target_name, name, uni_len);
48438c8a9a5SSteve French 	tinfo = (struct target_info *)(target_name + uni_len);
48538c8a9a5SSteve French 
48638c8a9a5SSteve French 	chgblob->TargetInfoArray.Length = 0;
48738c8a9a5SSteve French 	/* Add target info list for NetBIOS/DNS settings */
48838c8a9a5SSteve French 	for (type = NTLMSSP_AV_NB_COMPUTER_NAME;
48938c8a9a5SSteve French 	     type <= NTLMSSP_AV_DNS_DOMAIN_NAME; type++) {
49038c8a9a5SSteve French 		tinfo->Type = cpu_to_le16(type);
49138c8a9a5SSteve French 		tinfo->Length = cpu_to_le16(uni_len);
49238c8a9a5SSteve French 		memcpy(tinfo->Content, name, uni_len);
49338c8a9a5SSteve French 		tinfo = (struct target_info *)((char *)tinfo + 4 + uni_len);
49438c8a9a5SSteve French 		target_info_len += 4 + uni_len;
49538c8a9a5SSteve French 	}
49638c8a9a5SSteve French 
49738c8a9a5SSteve French 	/* Add terminator subblock */
49838c8a9a5SSteve French 	tinfo->Type = 0;
49938c8a9a5SSteve French 	tinfo->Length = 0;
50038c8a9a5SSteve French 	target_info_len += 4;
50138c8a9a5SSteve French 
50238c8a9a5SSteve French 	chgblob->TargetInfoArray.Length = cpu_to_le16(target_info_len);
50338c8a9a5SSteve French 	chgblob->TargetInfoArray.MaximumLength = cpu_to_le16(target_info_len);
50438c8a9a5SSteve French 	blob_len += target_info_len;
50538c8a9a5SSteve French 	kfree(name);
50638c8a9a5SSteve French 	ksmbd_debug(AUTH, "NTLMSSP SecurityBufferLength %d\n", blob_len);
50738c8a9a5SSteve French 	return blob_len;
50838c8a9a5SSteve French }
50938c8a9a5SSteve French 
51038c8a9a5SSteve French #ifdef CONFIG_SMB_SERVER_KERBEROS5
ksmbd_krb5_authenticate(struct ksmbd_session * sess,char * in_blob,int in_len,char * out_blob,int * out_len)51138c8a9a5SSteve French int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
51238c8a9a5SSteve French 			    int in_len, char *out_blob, int *out_len)
51338c8a9a5SSteve French {
51438c8a9a5SSteve French 	struct ksmbd_spnego_authen_response *resp;
51538c8a9a5SSteve French 	struct ksmbd_user *user = NULL;
51638c8a9a5SSteve French 	int retval;
51738c8a9a5SSteve French 
51838c8a9a5SSteve French 	resp = ksmbd_ipc_spnego_authen_request(in_blob, in_len);
51938c8a9a5SSteve French 	if (!resp) {
52038c8a9a5SSteve French 		ksmbd_debug(AUTH, "SPNEGO_AUTHEN_REQUEST failure\n");
52138c8a9a5SSteve French 		return -EINVAL;
52238c8a9a5SSteve French 	}
52338c8a9a5SSteve French 
52438c8a9a5SSteve French 	if (!(resp->login_response.status & KSMBD_USER_FLAG_OK)) {
52538c8a9a5SSteve French 		ksmbd_debug(AUTH, "krb5 authentication failure\n");
52638c8a9a5SSteve French 		retval = -EPERM;
52738c8a9a5SSteve French 		goto out;
52838c8a9a5SSteve French 	}
52938c8a9a5SSteve French 
53038c8a9a5SSteve French 	if (*out_len <= resp->spnego_blob_len) {
53138c8a9a5SSteve French 		ksmbd_debug(AUTH, "buf len %d, but blob len %d\n",
53238c8a9a5SSteve French 			    *out_len, resp->spnego_blob_len);
53338c8a9a5SSteve French 		retval = -EINVAL;
53438c8a9a5SSteve French 		goto out;
53538c8a9a5SSteve French 	}
53638c8a9a5SSteve French 
53738c8a9a5SSteve French 	if (resp->session_key_len > sizeof(sess->sess_key)) {
53838c8a9a5SSteve French 		ksmbd_debug(AUTH, "session key is too long\n");
53938c8a9a5SSteve French 		retval = -EINVAL;
54038c8a9a5SSteve French 		goto out;
54138c8a9a5SSteve French 	}
54238c8a9a5SSteve French 
54338c8a9a5SSteve French 	user = ksmbd_alloc_user(&resp->login_response);
54438c8a9a5SSteve French 	if (!user) {
54538c8a9a5SSteve French 		ksmbd_debug(AUTH, "login failure\n");
54638c8a9a5SSteve French 		retval = -ENOMEM;
54738c8a9a5SSteve French 		goto out;
54838c8a9a5SSteve French 	}
54938c8a9a5SSteve French 	sess->user = user;
55038c8a9a5SSteve French 
55138c8a9a5SSteve French 	memcpy(sess->sess_key, resp->payload, resp->session_key_len);
55238c8a9a5SSteve French 	memcpy(out_blob, resp->payload + resp->session_key_len,
55338c8a9a5SSteve French 	       resp->spnego_blob_len);
55438c8a9a5SSteve French 	*out_len = resp->spnego_blob_len;
55538c8a9a5SSteve French 	retval = 0;
55638c8a9a5SSteve French out:
55738c8a9a5SSteve French 	kvfree(resp);
55838c8a9a5SSteve French 	return retval;
55938c8a9a5SSteve French }
56038c8a9a5SSteve French #else
ksmbd_krb5_authenticate(struct ksmbd_session * sess,char * in_blob,int in_len,char * out_blob,int * out_len)56138c8a9a5SSteve French int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
56238c8a9a5SSteve French 			    int in_len, char *out_blob, int *out_len)
56338c8a9a5SSteve French {
56438c8a9a5SSteve French 	return -EOPNOTSUPP;
56538c8a9a5SSteve French }
56638c8a9a5SSteve French #endif
56738c8a9a5SSteve French 
56838c8a9a5SSteve French /**
56938c8a9a5SSteve French  * ksmbd_sign_smb2_pdu() - function to generate packet signing
57038c8a9a5SSteve French  * @conn:	connection
57138c8a9a5SSteve French  * @key:	signing key
57238c8a9a5SSteve French  * @iov:        buffer iov array
57338c8a9a5SSteve French  * @n_vec:	number of iovecs
57438c8a9a5SSteve French  * @sig:	signature value generated for client request packet
57538c8a9a5SSteve French  *
57638c8a9a5SSteve French  */
ksmbd_sign_smb2_pdu(struct ksmbd_conn * conn,char * key,struct kvec * iov,int n_vec,char * sig)57738c8a9a5SSteve French int ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
57838c8a9a5SSteve French 			int n_vec, char *sig)
57938c8a9a5SSteve French {
58038c8a9a5SSteve French 	struct ksmbd_crypto_ctx *ctx;
58138c8a9a5SSteve French 	int rc, i;
58238c8a9a5SSteve French 
58338c8a9a5SSteve French 	ctx = ksmbd_crypto_ctx_find_hmacsha256();
58438c8a9a5SSteve French 	if (!ctx) {
58538c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n");
58638c8a9a5SSteve French 		return -ENOMEM;
58738c8a9a5SSteve French 	}
58838c8a9a5SSteve French 
58938c8a9a5SSteve French 	rc = crypto_shash_setkey(CRYPTO_HMACSHA256_TFM(ctx),
59038c8a9a5SSteve French 				 key,
59138c8a9a5SSteve French 				 SMB2_NTLMV2_SESSKEY_SIZE);
59238c8a9a5SSteve French 	if (rc)
59338c8a9a5SSteve French 		goto out;
59438c8a9a5SSteve French 
59538c8a9a5SSteve French 	rc = crypto_shash_init(CRYPTO_HMACSHA256(ctx));
59638c8a9a5SSteve French 	if (rc) {
59738c8a9a5SSteve French 		ksmbd_debug(AUTH, "hmacsha256 init error %d\n", rc);
59838c8a9a5SSteve French 		goto out;
59938c8a9a5SSteve French 	}
60038c8a9a5SSteve French 
60138c8a9a5SSteve French 	for (i = 0; i < n_vec; i++) {
60238c8a9a5SSteve French 		rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx),
60338c8a9a5SSteve French 					 iov[i].iov_base,
60438c8a9a5SSteve French 					 iov[i].iov_len);
60538c8a9a5SSteve French 		if (rc) {
60638c8a9a5SSteve French 			ksmbd_debug(AUTH, "hmacsha256 update error %d\n", rc);
60738c8a9a5SSteve French 			goto out;
60838c8a9a5SSteve French 		}
60938c8a9a5SSteve French 	}
61038c8a9a5SSteve French 
61138c8a9a5SSteve French 	rc = crypto_shash_final(CRYPTO_HMACSHA256(ctx), sig);
61238c8a9a5SSteve French 	if (rc)
61338c8a9a5SSteve French 		ksmbd_debug(AUTH, "hmacsha256 generation error %d\n", rc);
61438c8a9a5SSteve French out:
61538c8a9a5SSteve French 	ksmbd_release_crypto_ctx(ctx);
61638c8a9a5SSteve French 	return rc;
61738c8a9a5SSteve French }
61838c8a9a5SSteve French 
61938c8a9a5SSteve French /**
62038c8a9a5SSteve French  * ksmbd_sign_smb3_pdu() - function to generate packet signing
62138c8a9a5SSteve French  * @conn:	connection
62238c8a9a5SSteve French  * @key:	signing key
62338c8a9a5SSteve French  * @iov:        buffer iov array
62438c8a9a5SSteve French  * @n_vec:	number of iovecs
62538c8a9a5SSteve French  * @sig:	signature value generated for client request packet
62638c8a9a5SSteve French  *
62738c8a9a5SSteve French  */
ksmbd_sign_smb3_pdu(struct ksmbd_conn * conn,char * key,struct kvec * iov,int n_vec,char * sig)62838c8a9a5SSteve French int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
62938c8a9a5SSteve French 			int n_vec, char *sig)
63038c8a9a5SSteve French {
63138c8a9a5SSteve French 	struct ksmbd_crypto_ctx *ctx;
63238c8a9a5SSteve French 	int rc, i;
63338c8a9a5SSteve French 
63438c8a9a5SSteve French 	ctx = ksmbd_crypto_ctx_find_cmacaes();
63538c8a9a5SSteve French 	if (!ctx) {
63638c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not crypto alloc cmac\n");
63738c8a9a5SSteve French 		return -ENOMEM;
63838c8a9a5SSteve French 	}
63938c8a9a5SSteve French 
64038c8a9a5SSteve French 	rc = crypto_shash_setkey(CRYPTO_CMACAES_TFM(ctx),
64138c8a9a5SSteve French 				 key,
64238c8a9a5SSteve French 				 SMB2_CMACAES_SIZE);
64338c8a9a5SSteve French 	if (rc)
64438c8a9a5SSteve French 		goto out;
64538c8a9a5SSteve French 
64638c8a9a5SSteve French 	rc = crypto_shash_init(CRYPTO_CMACAES(ctx));
64738c8a9a5SSteve French 	if (rc) {
64838c8a9a5SSteve French 		ksmbd_debug(AUTH, "cmaces init error %d\n", rc);
64938c8a9a5SSteve French 		goto out;
65038c8a9a5SSteve French 	}
65138c8a9a5SSteve French 
65238c8a9a5SSteve French 	for (i = 0; i < n_vec; i++) {
65338c8a9a5SSteve French 		rc = crypto_shash_update(CRYPTO_CMACAES(ctx),
65438c8a9a5SSteve French 					 iov[i].iov_base,
65538c8a9a5SSteve French 					 iov[i].iov_len);
65638c8a9a5SSteve French 		if (rc) {
65738c8a9a5SSteve French 			ksmbd_debug(AUTH, "cmaces update error %d\n", rc);
65838c8a9a5SSteve French 			goto out;
65938c8a9a5SSteve French 		}
66038c8a9a5SSteve French 	}
66138c8a9a5SSteve French 
66238c8a9a5SSteve French 	rc = crypto_shash_final(CRYPTO_CMACAES(ctx), sig);
66338c8a9a5SSteve French 	if (rc)
66438c8a9a5SSteve French 		ksmbd_debug(AUTH, "cmaces generation error %d\n", rc);
66538c8a9a5SSteve French out:
66638c8a9a5SSteve French 	ksmbd_release_crypto_ctx(ctx);
66738c8a9a5SSteve French 	return rc;
66838c8a9a5SSteve French }
66938c8a9a5SSteve French 
67038c8a9a5SSteve French struct derivation {
67138c8a9a5SSteve French 	struct kvec label;
67238c8a9a5SSteve French 	struct kvec context;
67338c8a9a5SSteve French 	bool binding;
67438c8a9a5SSteve French };
67538c8a9a5SSteve French 
generate_key(struct ksmbd_conn * conn,struct ksmbd_session * sess,struct kvec label,struct kvec context,__u8 * key,unsigned int key_size)67638c8a9a5SSteve French static int generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess,
67738c8a9a5SSteve French 			struct kvec label, struct kvec context, __u8 *key,
67838c8a9a5SSteve French 			unsigned int key_size)
67938c8a9a5SSteve French {
68038c8a9a5SSteve French 	unsigned char zero = 0x0;
68138c8a9a5SSteve French 	__u8 i[4] = {0, 0, 0, 1};
68238c8a9a5SSteve French 	__u8 L128[4] = {0, 0, 0, 128};
68338c8a9a5SSteve French 	__u8 L256[4] = {0, 0, 1, 0};
68438c8a9a5SSteve French 	int rc;
68538c8a9a5SSteve French 	unsigned char prfhash[SMB2_HMACSHA256_SIZE];
68638c8a9a5SSteve French 	unsigned char *hashptr = prfhash;
68738c8a9a5SSteve French 	struct ksmbd_crypto_ctx *ctx;
68838c8a9a5SSteve French 
68938c8a9a5SSteve French 	memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
69038c8a9a5SSteve French 	memset(key, 0x0, key_size);
69138c8a9a5SSteve French 
69238c8a9a5SSteve French 	ctx = ksmbd_crypto_ctx_find_hmacsha256();
69338c8a9a5SSteve French 	if (!ctx) {
69438c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n");
69538c8a9a5SSteve French 		return -ENOMEM;
69638c8a9a5SSteve French 	}
69738c8a9a5SSteve French 
69838c8a9a5SSteve French 	rc = crypto_shash_setkey(CRYPTO_HMACSHA256_TFM(ctx),
69938c8a9a5SSteve French 				 sess->sess_key,
70038c8a9a5SSteve French 				 SMB2_NTLMV2_SESSKEY_SIZE);
70138c8a9a5SSteve French 	if (rc)
70238c8a9a5SSteve French 		goto smb3signkey_ret;
70338c8a9a5SSteve French 
70438c8a9a5SSteve French 	rc = crypto_shash_init(CRYPTO_HMACSHA256(ctx));
70538c8a9a5SSteve French 	if (rc) {
70638c8a9a5SSteve French 		ksmbd_debug(AUTH, "hmacsha256 init error %d\n", rc);
70738c8a9a5SSteve French 		goto smb3signkey_ret;
70838c8a9a5SSteve French 	}
70938c8a9a5SSteve French 
71038c8a9a5SSteve French 	rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), i, 4);
71138c8a9a5SSteve French 	if (rc) {
71238c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not update with n\n");
71338c8a9a5SSteve French 		goto smb3signkey_ret;
71438c8a9a5SSteve French 	}
71538c8a9a5SSteve French 
71638c8a9a5SSteve French 	rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx),
71738c8a9a5SSteve French 				 label.iov_base,
71838c8a9a5SSteve French 				 label.iov_len);
71938c8a9a5SSteve French 	if (rc) {
72038c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not update with label\n");
72138c8a9a5SSteve French 		goto smb3signkey_ret;
72238c8a9a5SSteve French 	}
72338c8a9a5SSteve French 
72438c8a9a5SSteve French 	rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), &zero, 1);
72538c8a9a5SSteve French 	if (rc) {
72638c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not update with zero\n");
72738c8a9a5SSteve French 		goto smb3signkey_ret;
72838c8a9a5SSteve French 	}
72938c8a9a5SSteve French 
73038c8a9a5SSteve French 	rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx),
73138c8a9a5SSteve French 				 context.iov_base,
73238c8a9a5SSteve French 				 context.iov_len);
73338c8a9a5SSteve French 	if (rc) {
73438c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not update with context\n");
73538c8a9a5SSteve French 		goto smb3signkey_ret;
73638c8a9a5SSteve French 	}
73738c8a9a5SSteve French 
73838c8a9a5SSteve French 	if (key_size == SMB3_ENC_DEC_KEY_SIZE &&
73938c8a9a5SSteve French 	    (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
74038c8a9a5SSteve French 	     conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
74138c8a9a5SSteve French 		rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L256, 4);
74238c8a9a5SSteve French 	else
74338c8a9a5SSteve French 		rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L128, 4);
74438c8a9a5SSteve French 	if (rc) {
74538c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not update with L\n");
74638c8a9a5SSteve French 		goto smb3signkey_ret;
74738c8a9a5SSteve French 	}
74838c8a9a5SSteve French 
74938c8a9a5SSteve French 	rc = crypto_shash_final(CRYPTO_HMACSHA256(ctx), hashptr);
75038c8a9a5SSteve French 	if (rc) {
75138c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not generate hmacmd5 hash error %d\n",
75238c8a9a5SSteve French 			    rc);
75338c8a9a5SSteve French 		goto smb3signkey_ret;
75438c8a9a5SSteve French 	}
75538c8a9a5SSteve French 
75638c8a9a5SSteve French 	memcpy(key, hashptr, key_size);
75738c8a9a5SSteve French 
75838c8a9a5SSteve French smb3signkey_ret:
75938c8a9a5SSteve French 	ksmbd_release_crypto_ctx(ctx);
76038c8a9a5SSteve French 	return rc;
76138c8a9a5SSteve French }
76238c8a9a5SSteve French 
generate_smb3signingkey(struct ksmbd_session * sess,struct ksmbd_conn * conn,const struct derivation * signing)76338c8a9a5SSteve French static int generate_smb3signingkey(struct ksmbd_session *sess,
76438c8a9a5SSteve French 				   struct ksmbd_conn *conn,
76538c8a9a5SSteve French 				   const struct derivation *signing)
76638c8a9a5SSteve French {
76738c8a9a5SSteve French 	int rc;
76838c8a9a5SSteve French 	struct channel *chann;
76938c8a9a5SSteve French 	char *key;
77038c8a9a5SSteve French 
77138c8a9a5SSteve French 	chann = lookup_chann_list(sess, conn);
77238c8a9a5SSteve French 	if (!chann)
77338c8a9a5SSteve French 		return 0;
77438c8a9a5SSteve French 
77538c8a9a5SSteve French 	if (conn->dialect >= SMB30_PROT_ID && signing->binding)
77638c8a9a5SSteve French 		key = chann->smb3signingkey;
77738c8a9a5SSteve French 	else
77838c8a9a5SSteve French 		key = sess->smb3signingkey;
77938c8a9a5SSteve French 
78038c8a9a5SSteve French 	rc = generate_key(conn, sess, signing->label, signing->context, key,
78138c8a9a5SSteve French 			  SMB3_SIGN_KEY_SIZE);
78238c8a9a5SSteve French 	if (rc)
78338c8a9a5SSteve French 		return rc;
78438c8a9a5SSteve French 
78538c8a9a5SSteve French 	if (!(conn->dialect >= SMB30_PROT_ID && signing->binding))
78638c8a9a5SSteve French 		memcpy(chann->smb3signingkey, key, SMB3_SIGN_KEY_SIZE);
78738c8a9a5SSteve French 
78838c8a9a5SSteve French 	ksmbd_debug(AUTH, "dumping generated AES signing keys\n");
78938c8a9a5SSteve French 	ksmbd_debug(AUTH, "Session Id    %llu\n", sess->id);
79038c8a9a5SSteve French 	ksmbd_debug(AUTH, "Session Key   %*ph\n",
79138c8a9a5SSteve French 		    SMB2_NTLMV2_SESSKEY_SIZE, sess->sess_key);
79238c8a9a5SSteve French 	ksmbd_debug(AUTH, "Signing Key   %*ph\n",
79338c8a9a5SSteve French 		    SMB3_SIGN_KEY_SIZE, key);
79438c8a9a5SSteve French 	return 0;
79538c8a9a5SSteve French }
79638c8a9a5SSteve French 
ksmbd_gen_smb30_signingkey(struct ksmbd_session * sess,struct ksmbd_conn * conn)79738c8a9a5SSteve French int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess,
79838c8a9a5SSteve French 			       struct ksmbd_conn *conn)
79938c8a9a5SSteve French {
80038c8a9a5SSteve French 	struct derivation d;
80138c8a9a5SSteve French 
80238c8a9a5SSteve French 	d.label.iov_base = "SMB2AESCMAC";
80338c8a9a5SSteve French 	d.label.iov_len = 12;
80438c8a9a5SSteve French 	d.context.iov_base = "SmbSign";
80538c8a9a5SSteve French 	d.context.iov_len = 8;
80638c8a9a5SSteve French 	d.binding = conn->binding;
80738c8a9a5SSteve French 
80838c8a9a5SSteve French 	return generate_smb3signingkey(sess, conn, &d);
80938c8a9a5SSteve French }
81038c8a9a5SSteve French 
ksmbd_gen_smb311_signingkey(struct ksmbd_session * sess,struct ksmbd_conn * conn)81138c8a9a5SSteve French int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess,
81238c8a9a5SSteve French 				struct ksmbd_conn *conn)
81338c8a9a5SSteve French {
81438c8a9a5SSteve French 	struct derivation d;
81538c8a9a5SSteve French 
81638c8a9a5SSteve French 	d.label.iov_base = "SMBSigningKey";
81738c8a9a5SSteve French 	d.label.iov_len = 14;
81838c8a9a5SSteve French 	if (conn->binding) {
81938c8a9a5SSteve French 		struct preauth_session *preauth_sess;
82038c8a9a5SSteve French 
82138c8a9a5SSteve French 		preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id);
82238c8a9a5SSteve French 		if (!preauth_sess)
82338c8a9a5SSteve French 			return -ENOENT;
82438c8a9a5SSteve French 		d.context.iov_base = preauth_sess->Preauth_HashValue;
82538c8a9a5SSteve French 	} else {
82638c8a9a5SSteve French 		d.context.iov_base = sess->Preauth_HashValue;
82738c8a9a5SSteve French 	}
82838c8a9a5SSteve French 	d.context.iov_len = 64;
82938c8a9a5SSteve French 	d.binding = conn->binding;
83038c8a9a5SSteve French 
83138c8a9a5SSteve French 	return generate_smb3signingkey(sess, conn, &d);
83238c8a9a5SSteve French }
83338c8a9a5SSteve French 
83438c8a9a5SSteve French struct derivation_twin {
83538c8a9a5SSteve French 	struct derivation encryption;
83638c8a9a5SSteve French 	struct derivation decryption;
83738c8a9a5SSteve French };
83838c8a9a5SSteve French 
generate_smb3encryptionkey(struct ksmbd_conn * conn,struct ksmbd_session * sess,const struct derivation_twin * ptwin)83938c8a9a5SSteve French static int generate_smb3encryptionkey(struct ksmbd_conn *conn,
84038c8a9a5SSteve French 				      struct ksmbd_session *sess,
84138c8a9a5SSteve French 				      const struct derivation_twin *ptwin)
84238c8a9a5SSteve French {
84338c8a9a5SSteve French 	int rc;
84438c8a9a5SSteve French 
84538c8a9a5SSteve French 	rc = generate_key(conn, sess, ptwin->encryption.label,
84638c8a9a5SSteve French 			  ptwin->encryption.context, sess->smb3encryptionkey,
84738c8a9a5SSteve French 			  SMB3_ENC_DEC_KEY_SIZE);
84838c8a9a5SSteve French 	if (rc)
84938c8a9a5SSteve French 		return rc;
85038c8a9a5SSteve French 
85138c8a9a5SSteve French 	rc = generate_key(conn, sess, ptwin->decryption.label,
85238c8a9a5SSteve French 			  ptwin->decryption.context,
85338c8a9a5SSteve French 			  sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE);
85438c8a9a5SSteve French 	if (rc)
85538c8a9a5SSteve French 		return rc;
85638c8a9a5SSteve French 
85738c8a9a5SSteve French 	ksmbd_debug(AUTH, "dumping generated AES encryption keys\n");
85838c8a9a5SSteve French 	ksmbd_debug(AUTH, "Cipher type   %d\n", conn->cipher_type);
85938c8a9a5SSteve French 	ksmbd_debug(AUTH, "Session Id    %llu\n", sess->id);
86038c8a9a5SSteve French 	ksmbd_debug(AUTH, "Session Key   %*ph\n",
86138c8a9a5SSteve French 		    SMB2_NTLMV2_SESSKEY_SIZE, sess->sess_key);
86238c8a9a5SSteve French 	if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
86338c8a9a5SSteve French 	    conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
86438c8a9a5SSteve French 		ksmbd_debug(AUTH, "ServerIn Key  %*ph\n",
86538c8a9a5SSteve French 			    SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3encryptionkey);
86638c8a9a5SSteve French 		ksmbd_debug(AUTH, "ServerOut Key %*ph\n",
86738c8a9a5SSteve French 			    SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3decryptionkey);
86838c8a9a5SSteve French 	} else {
86938c8a9a5SSteve French 		ksmbd_debug(AUTH, "ServerIn Key  %*ph\n",
87038c8a9a5SSteve French 			    SMB3_GCM128_CRYPTKEY_SIZE, sess->smb3encryptionkey);
87138c8a9a5SSteve French 		ksmbd_debug(AUTH, "ServerOut Key %*ph\n",
87238c8a9a5SSteve French 			    SMB3_GCM128_CRYPTKEY_SIZE, sess->smb3decryptionkey);
87338c8a9a5SSteve French 	}
87438c8a9a5SSteve French 	return 0;
87538c8a9a5SSteve French }
87638c8a9a5SSteve French 
ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn * conn,struct ksmbd_session * sess)87738c8a9a5SSteve French int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn,
87838c8a9a5SSteve French 				  struct ksmbd_session *sess)
87938c8a9a5SSteve French {
88038c8a9a5SSteve French 	struct derivation_twin twin;
88138c8a9a5SSteve French 	struct derivation *d;
88238c8a9a5SSteve French 
88338c8a9a5SSteve French 	d = &twin.encryption;
88438c8a9a5SSteve French 	d->label.iov_base = "SMB2AESCCM";
88538c8a9a5SSteve French 	d->label.iov_len = 11;
88638c8a9a5SSteve French 	d->context.iov_base = "ServerOut";
88738c8a9a5SSteve French 	d->context.iov_len = 10;
88838c8a9a5SSteve French 
88938c8a9a5SSteve French 	d = &twin.decryption;
89038c8a9a5SSteve French 	d->label.iov_base = "SMB2AESCCM";
89138c8a9a5SSteve French 	d->label.iov_len = 11;
89238c8a9a5SSteve French 	d->context.iov_base = "ServerIn ";
89338c8a9a5SSteve French 	d->context.iov_len = 10;
89438c8a9a5SSteve French 
89538c8a9a5SSteve French 	return generate_smb3encryptionkey(conn, sess, &twin);
89638c8a9a5SSteve French }
89738c8a9a5SSteve French 
ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn * conn,struct ksmbd_session * sess)89838c8a9a5SSteve French int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn,
89938c8a9a5SSteve French 				   struct ksmbd_session *sess)
90038c8a9a5SSteve French {
90138c8a9a5SSteve French 	struct derivation_twin twin;
90238c8a9a5SSteve French 	struct derivation *d;
90338c8a9a5SSteve French 
90438c8a9a5SSteve French 	d = &twin.encryption;
90538c8a9a5SSteve French 	d->label.iov_base = "SMBS2CCipherKey";
90638c8a9a5SSteve French 	d->label.iov_len = 16;
90738c8a9a5SSteve French 	d->context.iov_base = sess->Preauth_HashValue;
90838c8a9a5SSteve French 	d->context.iov_len = 64;
90938c8a9a5SSteve French 
91038c8a9a5SSteve French 	d = &twin.decryption;
91138c8a9a5SSteve French 	d->label.iov_base = "SMBC2SCipherKey";
91238c8a9a5SSteve French 	d->label.iov_len = 16;
91338c8a9a5SSteve French 	d->context.iov_base = sess->Preauth_HashValue;
91438c8a9a5SSteve French 	d->context.iov_len = 64;
91538c8a9a5SSteve French 
91638c8a9a5SSteve French 	return generate_smb3encryptionkey(conn, sess, &twin);
91738c8a9a5SSteve French }
91838c8a9a5SSteve French 
ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn * conn,char * buf,__u8 * pi_hash)91938c8a9a5SSteve French int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
92038c8a9a5SSteve French 				     __u8 *pi_hash)
92138c8a9a5SSteve French {
92238c8a9a5SSteve French 	int rc;
92338c8a9a5SSteve French 	struct smb2_hdr *rcv_hdr = smb2_get_msg(buf);
92438c8a9a5SSteve French 	char *all_bytes_msg = (char *)&rcv_hdr->ProtocolId;
92538c8a9a5SSteve French 	int msg_size = get_rfc1002_len(buf);
92638c8a9a5SSteve French 	struct ksmbd_crypto_ctx *ctx = NULL;
92738c8a9a5SSteve French 
92838c8a9a5SSteve French 	if (conn->preauth_info->Preauth_HashId !=
92938c8a9a5SSteve French 	    SMB2_PREAUTH_INTEGRITY_SHA512)
93038c8a9a5SSteve French 		return -EINVAL;
93138c8a9a5SSteve French 
93238c8a9a5SSteve French 	ctx = ksmbd_crypto_ctx_find_sha512();
93338c8a9a5SSteve French 	if (!ctx) {
93438c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not alloc sha512\n");
93538c8a9a5SSteve French 		return -ENOMEM;
93638c8a9a5SSteve French 	}
93738c8a9a5SSteve French 
93838c8a9a5SSteve French 	rc = crypto_shash_init(CRYPTO_SHA512(ctx));
93938c8a9a5SSteve French 	if (rc) {
94038c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not init shashn");
94138c8a9a5SSteve French 		goto out;
94238c8a9a5SSteve French 	}
94338c8a9a5SSteve French 
94438c8a9a5SSteve French 	rc = crypto_shash_update(CRYPTO_SHA512(ctx), pi_hash, 64);
94538c8a9a5SSteve French 	if (rc) {
94638c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not update with n\n");
94738c8a9a5SSteve French 		goto out;
94838c8a9a5SSteve French 	}
94938c8a9a5SSteve French 
95038c8a9a5SSteve French 	rc = crypto_shash_update(CRYPTO_SHA512(ctx), all_bytes_msg, msg_size);
95138c8a9a5SSteve French 	if (rc) {
95238c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not update with n\n");
95338c8a9a5SSteve French 		goto out;
95438c8a9a5SSteve French 	}
95538c8a9a5SSteve French 
95638c8a9a5SSteve French 	rc = crypto_shash_final(CRYPTO_SHA512(ctx), pi_hash);
95738c8a9a5SSteve French 	if (rc) {
95838c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not generate hash err : %d\n", rc);
95938c8a9a5SSteve French 		goto out;
96038c8a9a5SSteve French 	}
96138c8a9a5SSteve French out:
96238c8a9a5SSteve French 	ksmbd_release_crypto_ctx(ctx);
96338c8a9a5SSteve French 	return rc;
96438c8a9a5SSteve French }
96538c8a9a5SSteve French 
ksmbd_gen_sd_hash(struct ksmbd_conn * conn,char * sd_buf,int len,__u8 * pi_hash)96638c8a9a5SSteve French int ksmbd_gen_sd_hash(struct ksmbd_conn *conn, char *sd_buf, int len,
96738c8a9a5SSteve French 		      __u8 *pi_hash)
96838c8a9a5SSteve French {
96938c8a9a5SSteve French 	int rc;
97038c8a9a5SSteve French 	struct ksmbd_crypto_ctx *ctx = NULL;
97138c8a9a5SSteve French 
97238c8a9a5SSteve French 	ctx = ksmbd_crypto_ctx_find_sha256();
97338c8a9a5SSteve French 	if (!ctx) {
97438c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not alloc sha256\n");
97538c8a9a5SSteve French 		return -ENOMEM;
97638c8a9a5SSteve French 	}
97738c8a9a5SSteve French 
97838c8a9a5SSteve French 	rc = crypto_shash_init(CRYPTO_SHA256(ctx));
97938c8a9a5SSteve French 	if (rc) {
98038c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not init shashn");
98138c8a9a5SSteve French 		goto out;
98238c8a9a5SSteve French 	}
98338c8a9a5SSteve French 
98438c8a9a5SSteve French 	rc = crypto_shash_update(CRYPTO_SHA256(ctx), sd_buf, len);
98538c8a9a5SSteve French 	if (rc) {
98638c8a9a5SSteve French 		ksmbd_debug(AUTH, "could not update with n\n");
98738c8a9a5SSteve French 		goto out;
98838c8a9a5SSteve French 	}
98938c8a9a5SSteve French 
99038c8a9a5SSteve French 	rc = crypto_shash_final(CRYPTO_SHA256(ctx), pi_hash);
99138c8a9a5SSteve French 	if (rc) {
99238c8a9a5SSteve French 		ksmbd_debug(AUTH, "Could not generate hash err : %d\n", rc);
99338c8a9a5SSteve French 		goto out;
99438c8a9a5SSteve French 	}
99538c8a9a5SSteve French out:
99638c8a9a5SSteve French 	ksmbd_release_crypto_ctx(ctx);
99738c8a9a5SSteve French 	return rc;
99838c8a9a5SSteve French }
99938c8a9a5SSteve French 
ksmbd_get_encryption_key(struct ksmbd_work * work,__u64 ses_id,int enc,u8 * key)100038c8a9a5SSteve French static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id,
100138c8a9a5SSteve French 				    int enc, u8 *key)
100238c8a9a5SSteve French {
100338c8a9a5SSteve French 	struct ksmbd_session *sess;
100438c8a9a5SSteve French 	u8 *ses_enc_key;
100538c8a9a5SSteve French 
100638c8a9a5SSteve French 	if (enc)
100738c8a9a5SSteve French 		sess = work->sess;
100838c8a9a5SSteve French 	else
100938c8a9a5SSteve French 		sess = ksmbd_session_lookup_all(work->conn, ses_id);
101038c8a9a5SSteve French 	if (!sess)
101138c8a9a5SSteve French 		return -EINVAL;
101238c8a9a5SSteve French 
101338c8a9a5SSteve French 	ses_enc_key = enc ? sess->smb3encryptionkey :
101438c8a9a5SSteve French 		sess->smb3decryptionkey;
101538c8a9a5SSteve French 	memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE);
101638c8a9a5SSteve French 
101738c8a9a5SSteve French 	return 0;
101838c8a9a5SSteve French }
101938c8a9a5SSteve French 
smb2_sg_set_buf(struct scatterlist * sg,const void * buf,unsigned int buflen)102038c8a9a5SSteve French static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf,
102138c8a9a5SSteve French 				   unsigned int buflen)
102238c8a9a5SSteve French {
102338c8a9a5SSteve French 	void *addr;
102438c8a9a5SSteve French 
102538c8a9a5SSteve French 	if (is_vmalloc_addr(buf))
102638c8a9a5SSteve French 		addr = vmalloc_to_page(buf);
102738c8a9a5SSteve French 	else
102838c8a9a5SSteve French 		addr = virt_to_page(buf);
102938c8a9a5SSteve French 	sg_set_page(sg, addr, buflen, offset_in_page(buf));
103038c8a9a5SSteve French }
103138c8a9a5SSteve French 
ksmbd_init_sg(struct kvec * iov,unsigned int nvec,u8 * sign)103238c8a9a5SSteve French static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec,
103338c8a9a5SSteve French 					 u8 *sign)
103438c8a9a5SSteve French {
103538c8a9a5SSteve French 	struct scatterlist *sg;
103638c8a9a5SSteve French 	unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
1037e2b76ab8SNamjae Jeon 	int i, *nr_entries, total_entries = 0, sg_idx = 0;
103838c8a9a5SSteve French 
103938c8a9a5SSteve French 	if (!nvec)
104038c8a9a5SSteve French 		return NULL;
104138c8a9a5SSteve French 
1042e2b76ab8SNamjae Jeon 	nr_entries = kcalloc(nvec, sizeof(int), GFP_KERNEL);
1043e2b76ab8SNamjae Jeon 	if (!nr_entries)
1044e2b76ab8SNamjae Jeon 		return NULL;
1045e2b76ab8SNamjae Jeon 
104638c8a9a5SSteve French 	for (i = 0; i < nvec - 1; i++) {
104738c8a9a5SSteve French 		unsigned long kaddr = (unsigned long)iov[i + 1].iov_base;
104838c8a9a5SSteve French 
104938c8a9a5SSteve French 		if (is_vmalloc_addr(iov[i + 1].iov_base)) {
105038c8a9a5SSteve French 			nr_entries[i] = ((kaddr + iov[i + 1].iov_len +
105138c8a9a5SSteve French 					PAGE_SIZE - 1) >> PAGE_SHIFT) -
105238c8a9a5SSteve French 				(kaddr >> PAGE_SHIFT);
105338c8a9a5SSteve French 		} else {
105438c8a9a5SSteve French 			nr_entries[i]++;
105538c8a9a5SSteve French 		}
105638c8a9a5SSteve French 		total_entries += nr_entries[i];
105738c8a9a5SSteve French 	}
105838c8a9a5SSteve French 
105938c8a9a5SSteve French 	/* Add two entries for transform header and signature */
106038c8a9a5SSteve French 	total_entries += 2;
106138c8a9a5SSteve French 
106238c8a9a5SSteve French 	sg = kmalloc_array(total_entries, sizeof(struct scatterlist), GFP_KERNEL);
1063e2b76ab8SNamjae Jeon 	if (!sg) {
1064e2b76ab8SNamjae Jeon 		kfree(nr_entries);
106538c8a9a5SSteve French 		return NULL;
1066e2b76ab8SNamjae Jeon 	}
106738c8a9a5SSteve French 
106838c8a9a5SSteve French 	sg_init_table(sg, total_entries);
106938c8a9a5SSteve French 	smb2_sg_set_buf(&sg[sg_idx++], iov[0].iov_base + 24, assoc_data_len);
107038c8a9a5SSteve French 	for (i = 0; i < nvec - 1; i++) {
107138c8a9a5SSteve French 		void *data = iov[i + 1].iov_base;
107238c8a9a5SSteve French 		int len = iov[i + 1].iov_len;
107338c8a9a5SSteve French 
107438c8a9a5SSteve French 		if (is_vmalloc_addr(data)) {
107538c8a9a5SSteve French 			int j, offset = offset_in_page(data);
107638c8a9a5SSteve French 
107738c8a9a5SSteve French 			for (j = 0; j < nr_entries[i]; j++) {
107838c8a9a5SSteve French 				unsigned int bytes = PAGE_SIZE - offset;
107938c8a9a5SSteve French 
108038c8a9a5SSteve French 				if (!len)
108138c8a9a5SSteve French 					break;
108238c8a9a5SSteve French 
108338c8a9a5SSteve French 				if (bytes > len)
108438c8a9a5SSteve French 					bytes = len;
108538c8a9a5SSteve French 
108638c8a9a5SSteve French 				sg_set_page(&sg[sg_idx++],
108738c8a9a5SSteve French 					    vmalloc_to_page(data), bytes,
108838c8a9a5SSteve French 					    offset_in_page(data));
108938c8a9a5SSteve French 
109038c8a9a5SSteve French 				data += bytes;
109138c8a9a5SSteve French 				len -= bytes;
109238c8a9a5SSteve French 				offset = 0;
109338c8a9a5SSteve French 			}
109438c8a9a5SSteve French 		} else {
109538c8a9a5SSteve French 			sg_set_page(&sg[sg_idx++], virt_to_page(data), len,
109638c8a9a5SSteve French 				    offset_in_page(data));
109738c8a9a5SSteve French 		}
109838c8a9a5SSteve French 	}
109938c8a9a5SSteve French 	smb2_sg_set_buf(&sg[sg_idx], sign, SMB2_SIGNATURE_SIZE);
1100e2b76ab8SNamjae Jeon 	kfree(nr_entries);
110138c8a9a5SSteve French 	return sg;
110238c8a9a5SSteve French }
110338c8a9a5SSteve French 
ksmbd_crypt_message(struct ksmbd_work * work,struct kvec * iov,unsigned int nvec,int enc)110438c8a9a5SSteve French int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
110538c8a9a5SSteve French 			unsigned int nvec, int enc)
110638c8a9a5SSteve French {
110738c8a9a5SSteve French 	struct ksmbd_conn *conn = work->conn;
110838c8a9a5SSteve French 	struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base);
110938c8a9a5SSteve French 	unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
111038c8a9a5SSteve French 	int rc;
111138c8a9a5SSteve French 	struct scatterlist *sg;
111238c8a9a5SSteve French 	u8 sign[SMB2_SIGNATURE_SIZE] = {};
111338c8a9a5SSteve French 	u8 key[SMB3_ENC_DEC_KEY_SIZE];
111438c8a9a5SSteve French 	struct aead_request *req;
111538c8a9a5SSteve French 	char *iv;
111638c8a9a5SSteve French 	unsigned int iv_len;
111738c8a9a5SSteve French 	struct crypto_aead *tfm;
111838c8a9a5SSteve French 	unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
111938c8a9a5SSteve French 	struct ksmbd_crypto_ctx *ctx;
112038c8a9a5SSteve French 
112138c8a9a5SSteve French 	rc = ksmbd_get_encryption_key(work,
112238c8a9a5SSteve French 				      le64_to_cpu(tr_hdr->SessionId),
112338c8a9a5SSteve French 				      enc,
112438c8a9a5SSteve French 				      key);
112538c8a9a5SSteve French 	if (rc) {
112638c8a9a5SSteve French 		pr_err("Could not get %scryption key\n", enc ? "en" : "de");
112738c8a9a5SSteve French 		return rc;
112838c8a9a5SSteve French 	}
112938c8a9a5SSteve French 
113038c8a9a5SSteve French 	if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM ||
113138c8a9a5SSteve French 	    conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
113238c8a9a5SSteve French 		ctx = ksmbd_crypto_ctx_find_gcm();
113338c8a9a5SSteve French 	else
113438c8a9a5SSteve French 		ctx = ksmbd_crypto_ctx_find_ccm();
113538c8a9a5SSteve French 	if (!ctx) {
113638c8a9a5SSteve French 		pr_err("crypto alloc failed\n");
113738c8a9a5SSteve French 		return -ENOMEM;
113838c8a9a5SSteve French 	}
113938c8a9a5SSteve French 
114038c8a9a5SSteve French 	if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM ||
114138c8a9a5SSteve French 	    conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
114238c8a9a5SSteve French 		tfm = CRYPTO_GCM(ctx);
114338c8a9a5SSteve French 	else
114438c8a9a5SSteve French 		tfm = CRYPTO_CCM(ctx);
114538c8a9a5SSteve French 
114638c8a9a5SSteve French 	if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
114738c8a9a5SSteve French 	    conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
114838c8a9a5SSteve French 		rc = crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE);
114938c8a9a5SSteve French 	else
115038c8a9a5SSteve French 		rc = crypto_aead_setkey(tfm, key, SMB3_GCM128_CRYPTKEY_SIZE);
115138c8a9a5SSteve French 	if (rc) {
115238c8a9a5SSteve French 		pr_err("Failed to set aead key %d\n", rc);
115338c8a9a5SSteve French 		goto free_ctx;
115438c8a9a5SSteve French 	}
115538c8a9a5SSteve French 
115638c8a9a5SSteve French 	rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE);
115738c8a9a5SSteve French 	if (rc) {
115838c8a9a5SSteve French 		pr_err("Failed to set authsize %d\n", rc);
115938c8a9a5SSteve French 		goto free_ctx;
116038c8a9a5SSteve French 	}
116138c8a9a5SSteve French 
116238c8a9a5SSteve French 	req = aead_request_alloc(tfm, GFP_KERNEL);
116338c8a9a5SSteve French 	if (!req) {
116438c8a9a5SSteve French 		rc = -ENOMEM;
116538c8a9a5SSteve French 		goto free_ctx;
116638c8a9a5SSteve French 	}
116738c8a9a5SSteve French 
116838c8a9a5SSteve French 	if (!enc) {
116938c8a9a5SSteve French 		memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE);
117038c8a9a5SSteve French 		crypt_len += SMB2_SIGNATURE_SIZE;
117138c8a9a5SSteve French 	}
117238c8a9a5SSteve French 
117338c8a9a5SSteve French 	sg = ksmbd_init_sg(iov, nvec, sign);
117438c8a9a5SSteve French 	if (!sg) {
117538c8a9a5SSteve French 		pr_err("Failed to init sg\n");
117638c8a9a5SSteve French 		rc = -ENOMEM;
117738c8a9a5SSteve French 		goto free_req;
117838c8a9a5SSteve French 	}
117938c8a9a5SSteve French 
118038c8a9a5SSteve French 	iv_len = crypto_aead_ivsize(tfm);
118138c8a9a5SSteve French 	iv = kzalloc(iv_len, GFP_KERNEL);
118238c8a9a5SSteve French 	if (!iv) {
118338c8a9a5SSteve French 		rc = -ENOMEM;
118438c8a9a5SSteve French 		goto free_sg;
118538c8a9a5SSteve French 	}
118638c8a9a5SSteve French 
118738c8a9a5SSteve French 	if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM ||
118838c8a9a5SSteve French 	    conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
118938c8a9a5SSteve French 		memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE);
119038c8a9a5SSteve French 	} else {
119138c8a9a5SSteve French 		iv[0] = 3;
119238c8a9a5SSteve French 		memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE);
119338c8a9a5SSteve French 	}
119438c8a9a5SSteve French 
119538c8a9a5SSteve French 	aead_request_set_crypt(req, sg, sg, crypt_len, iv);
119638c8a9a5SSteve French 	aead_request_set_ad(req, assoc_data_len);
119738c8a9a5SSteve French 	aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
119838c8a9a5SSteve French 
119938c8a9a5SSteve French 	if (enc)
120038c8a9a5SSteve French 		rc = crypto_aead_encrypt(req);
120138c8a9a5SSteve French 	else
120238c8a9a5SSteve French 		rc = crypto_aead_decrypt(req);
120338c8a9a5SSteve French 	if (rc)
120438c8a9a5SSteve French 		goto free_iv;
120538c8a9a5SSteve French 
120638c8a9a5SSteve French 	if (enc)
120738c8a9a5SSteve French 		memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
120838c8a9a5SSteve French 
120938c8a9a5SSteve French free_iv:
121038c8a9a5SSteve French 	kfree(iv);
121138c8a9a5SSteve French free_sg:
121238c8a9a5SSteve French 	kfree(sg);
121338c8a9a5SSteve French free_req:
121438c8a9a5SSteve French 	kfree(req);
121538c8a9a5SSteve French free_ctx:
121638c8a9a5SSteve French 	ksmbd_release_crypto_ctx(ctx);
121738c8a9a5SSteve French 	return rc;
121838c8a9a5SSteve French }
1219