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
211d4caa984SRandy 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
216d4caa984SRandy 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
299d4caa984SRandy Dunlap * @blob_len: length of the @authblob message
300d4caa984SRandy 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
382d4caa984SRandy Dunlap * @blob_len: length of the @authblob message
383d4caa984SRandy 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
409d4caa984SRandy 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;
1015*450a844cSNamjae Jeon if (enc)
1016*450a844cSNamjae Jeon ksmbd_user_session_get(sess);
101738c8a9a5SSteve French memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE);
101838c8a9a5SSteve French
101938c8a9a5SSteve French return 0;
102038c8a9a5SSteve French }
102138c8a9a5SSteve French
smb2_sg_set_buf(struct scatterlist * sg,const void * buf,unsigned int buflen)102238c8a9a5SSteve French static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf,
102338c8a9a5SSteve French unsigned int buflen)
102438c8a9a5SSteve French {
102538c8a9a5SSteve French void *addr;
102638c8a9a5SSteve French
102738c8a9a5SSteve French if (is_vmalloc_addr(buf))
102838c8a9a5SSteve French addr = vmalloc_to_page(buf);
102938c8a9a5SSteve French else
103038c8a9a5SSteve French addr = virt_to_page(buf);
103138c8a9a5SSteve French sg_set_page(sg, addr, buflen, offset_in_page(buf));
103238c8a9a5SSteve French }
103338c8a9a5SSteve French
ksmbd_init_sg(struct kvec * iov,unsigned int nvec,u8 * sign)103438c8a9a5SSteve French static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec,
103538c8a9a5SSteve French u8 *sign)
103638c8a9a5SSteve French {
103738c8a9a5SSteve French struct scatterlist *sg;
103838c8a9a5SSteve French unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
1039e2b76ab8SNamjae Jeon int i, *nr_entries, total_entries = 0, sg_idx = 0;
104038c8a9a5SSteve French
104138c8a9a5SSteve French if (!nvec)
104238c8a9a5SSteve French return NULL;
104338c8a9a5SSteve French
1044e2b76ab8SNamjae Jeon nr_entries = kcalloc(nvec, sizeof(int), GFP_KERNEL);
1045e2b76ab8SNamjae Jeon if (!nr_entries)
1046e2b76ab8SNamjae Jeon return NULL;
1047e2b76ab8SNamjae Jeon
104838c8a9a5SSteve French for (i = 0; i < nvec - 1; i++) {
104938c8a9a5SSteve French unsigned long kaddr = (unsigned long)iov[i + 1].iov_base;
105038c8a9a5SSteve French
105138c8a9a5SSteve French if (is_vmalloc_addr(iov[i + 1].iov_base)) {
105238c8a9a5SSteve French nr_entries[i] = ((kaddr + iov[i + 1].iov_len +
105338c8a9a5SSteve French PAGE_SIZE - 1) >> PAGE_SHIFT) -
105438c8a9a5SSteve French (kaddr >> PAGE_SHIFT);
105538c8a9a5SSteve French } else {
105638c8a9a5SSteve French nr_entries[i]++;
105738c8a9a5SSteve French }
105838c8a9a5SSteve French total_entries += nr_entries[i];
105938c8a9a5SSteve French }
106038c8a9a5SSteve French
106138c8a9a5SSteve French /* Add two entries for transform header and signature */
106238c8a9a5SSteve French total_entries += 2;
106338c8a9a5SSteve French
106438c8a9a5SSteve French sg = kmalloc_array(total_entries, sizeof(struct scatterlist), GFP_KERNEL);
1065e2b76ab8SNamjae Jeon if (!sg) {
1066e2b76ab8SNamjae Jeon kfree(nr_entries);
106738c8a9a5SSteve French return NULL;
1068e2b76ab8SNamjae Jeon }
106938c8a9a5SSteve French
107038c8a9a5SSteve French sg_init_table(sg, total_entries);
107138c8a9a5SSteve French smb2_sg_set_buf(&sg[sg_idx++], iov[0].iov_base + 24, assoc_data_len);
107238c8a9a5SSteve French for (i = 0; i < nvec - 1; i++) {
107338c8a9a5SSteve French void *data = iov[i + 1].iov_base;
107438c8a9a5SSteve French int len = iov[i + 1].iov_len;
107538c8a9a5SSteve French
107638c8a9a5SSteve French if (is_vmalloc_addr(data)) {
107738c8a9a5SSteve French int j, offset = offset_in_page(data);
107838c8a9a5SSteve French
107938c8a9a5SSteve French for (j = 0; j < nr_entries[i]; j++) {
108038c8a9a5SSteve French unsigned int bytes = PAGE_SIZE - offset;
108138c8a9a5SSteve French
108238c8a9a5SSteve French if (!len)
108338c8a9a5SSteve French break;
108438c8a9a5SSteve French
108538c8a9a5SSteve French if (bytes > len)
108638c8a9a5SSteve French bytes = len;
108738c8a9a5SSteve French
108838c8a9a5SSteve French sg_set_page(&sg[sg_idx++],
108938c8a9a5SSteve French vmalloc_to_page(data), bytes,
109038c8a9a5SSteve French offset_in_page(data));
109138c8a9a5SSteve French
109238c8a9a5SSteve French data += bytes;
109338c8a9a5SSteve French len -= bytes;
109438c8a9a5SSteve French offset = 0;
109538c8a9a5SSteve French }
109638c8a9a5SSteve French } else {
109738c8a9a5SSteve French sg_set_page(&sg[sg_idx++], virt_to_page(data), len,
109838c8a9a5SSteve French offset_in_page(data));
109938c8a9a5SSteve French }
110038c8a9a5SSteve French }
110138c8a9a5SSteve French smb2_sg_set_buf(&sg[sg_idx], sign, SMB2_SIGNATURE_SIZE);
1102e2b76ab8SNamjae Jeon kfree(nr_entries);
110338c8a9a5SSteve French return sg;
110438c8a9a5SSteve French }
110538c8a9a5SSteve French
ksmbd_crypt_message(struct ksmbd_work * work,struct kvec * iov,unsigned int nvec,int enc)110638c8a9a5SSteve French int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
110738c8a9a5SSteve French unsigned int nvec, int enc)
110838c8a9a5SSteve French {
110938c8a9a5SSteve French struct ksmbd_conn *conn = work->conn;
111038c8a9a5SSteve French struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base);
111138c8a9a5SSteve French unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
111238c8a9a5SSteve French int rc;
111338c8a9a5SSteve French struct scatterlist *sg;
111438c8a9a5SSteve French u8 sign[SMB2_SIGNATURE_SIZE] = {};
111538c8a9a5SSteve French u8 key[SMB3_ENC_DEC_KEY_SIZE];
111638c8a9a5SSteve French struct aead_request *req;
111738c8a9a5SSteve French char *iv;
111838c8a9a5SSteve French unsigned int iv_len;
111938c8a9a5SSteve French struct crypto_aead *tfm;
112038c8a9a5SSteve French unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
112138c8a9a5SSteve French struct ksmbd_crypto_ctx *ctx;
112238c8a9a5SSteve French
112338c8a9a5SSteve French rc = ksmbd_get_encryption_key(work,
112438c8a9a5SSteve French le64_to_cpu(tr_hdr->SessionId),
112538c8a9a5SSteve French enc,
112638c8a9a5SSteve French key);
112738c8a9a5SSteve French if (rc) {
112838c8a9a5SSteve French pr_err("Could not get %scryption key\n", enc ? "en" : "de");
112938c8a9a5SSteve French return rc;
113038c8a9a5SSteve French }
113138c8a9a5SSteve French
113238c8a9a5SSteve French if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM ||
113338c8a9a5SSteve French conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
113438c8a9a5SSteve French ctx = ksmbd_crypto_ctx_find_gcm();
113538c8a9a5SSteve French else
113638c8a9a5SSteve French ctx = ksmbd_crypto_ctx_find_ccm();
113738c8a9a5SSteve French if (!ctx) {
113838c8a9a5SSteve French pr_err("crypto alloc failed\n");
113938c8a9a5SSteve French return -ENOMEM;
114038c8a9a5SSteve French }
114138c8a9a5SSteve French
114238c8a9a5SSteve French if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM ||
114338c8a9a5SSteve French conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
114438c8a9a5SSteve French tfm = CRYPTO_GCM(ctx);
114538c8a9a5SSteve French else
114638c8a9a5SSteve French tfm = CRYPTO_CCM(ctx);
114738c8a9a5SSteve French
114838c8a9a5SSteve French if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
114938c8a9a5SSteve French conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
115038c8a9a5SSteve French rc = crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE);
115138c8a9a5SSteve French else
115238c8a9a5SSteve French rc = crypto_aead_setkey(tfm, key, SMB3_GCM128_CRYPTKEY_SIZE);
115338c8a9a5SSteve French if (rc) {
115438c8a9a5SSteve French pr_err("Failed to set aead key %d\n", rc);
115538c8a9a5SSteve French goto free_ctx;
115638c8a9a5SSteve French }
115738c8a9a5SSteve French
115838c8a9a5SSteve French rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE);
115938c8a9a5SSteve French if (rc) {
116038c8a9a5SSteve French pr_err("Failed to set authsize %d\n", rc);
116138c8a9a5SSteve French goto free_ctx;
116238c8a9a5SSteve French }
116338c8a9a5SSteve French
116438c8a9a5SSteve French req = aead_request_alloc(tfm, GFP_KERNEL);
116538c8a9a5SSteve French if (!req) {
116638c8a9a5SSteve French rc = -ENOMEM;
116738c8a9a5SSteve French goto free_ctx;
116838c8a9a5SSteve French }
116938c8a9a5SSteve French
117038c8a9a5SSteve French if (!enc) {
117138c8a9a5SSteve French memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE);
117238c8a9a5SSteve French crypt_len += SMB2_SIGNATURE_SIZE;
117338c8a9a5SSteve French }
117438c8a9a5SSteve French
117538c8a9a5SSteve French sg = ksmbd_init_sg(iov, nvec, sign);
117638c8a9a5SSteve French if (!sg) {
117738c8a9a5SSteve French pr_err("Failed to init sg\n");
117838c8a9a5SSteve French rc = -ENOMEM;
117938c8a9a5SSteve French goto free_req;
118038c8a9a5SSteve French }
118138c8a9a5SSteve French
118238c8a9a5SSteve French iv_len = crypto_aead_ivsize(tfm);
118338c8a9a5SSteve French iv = kzalloc(iv_len, GFP_KERNEL);
118438c8a9a5SSteve French if (!iv) {
118538c8a9a5SSteve French rc = -ENOMEM;
118638c8a9a5SSteve French goto free_sg;
118738c8a9a5SSteve French }
118838c8a9a5SSteve French
118938c8a9a5SSteve French if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM ||
119038c8a9a5SSteve French conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
119138c8a9a5SSteve French memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE);
119238c8a9a5SSteve French } else {
119338c8a9a5SSteve French iv[0] = 3;
119438c8a9a5SSteve French memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE);
119538c8a9a5SSteve French }
119638c8a9a5SSteve French
119738c8a9a5SSteve French aead_request_set_crypt(req, sg, sg, crypt_len, iv);
119838c8a9a5SSteve French aead_request_set_ad(req, assoc_data_len);
119938c8a9a5SSteve French aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
120038c8a9a5SSteve French
120138c8a9a5SSteve French if (enc)
120238c8a9a5SSteve French rc = crypto_aead_encrypt(req);
120338c8a9a5SSteve French else
120438c8a9a5SSteve French rc = crypto_aead_decrypt(req);
120538c8a9a5SSteve French if (rc)
120638c8a9a5SSteve French goto free_iv;
120738c8a9a5SSteve French
120838c8a9a5SSteve French if (enc)
120938c8a9a5SSteve French memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
121038c8a9a5SSteve French
121138c8a9a5SSteve French free_iv:
121238c8a9a5SSteve French kfree(iv);
121338c8a9a5SSteve French free_sg:
121438c8a9a5SSteve French kfree(sg);
121538c8a9a5SSteve French free_req:
121638c8a9a5SSteve French kfree(req);
121738c8a9a5SSteve French free_ctx:
121838c8a9a5SSteve French ksmbd_release_crypto_ctx(ctx);
121938c8a9a5SSteve French return rc;
122038c8a9a5SSteve French }
1221