xref: /kernel/linux/linux-5.10/fs/cifs/cifsencrypt.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *   fs/cifs/cifsencrypt.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *   Encryption and hashing operations relating to NTLM, NTLMv2.  See MS-NLMP
58c2ecf20Sopenharmony_ci *   for more detailed information
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *   Copyright (C) International Business Machines  Corp., 2005,2013
88c2ecf20Sopenharmony_ci *   Author(s): Steve French (sfrench@us.ibm.com)
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *   This library is free software; you can redistribute it and/or modify
118c2ecf20Sopenharmony_ci *   it under the terms of the GNU Lesser General Public License as published
128c2ecf20Sopenharmony_ci *   by the Free Software Foundation; either version 2.1 of the License, or
138c2ecf20Sopenharmony_ci *   (at your option) any later version.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci *   This library is distributed in the hope that it will be useful,
168c2ecf20Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
178c2ecf20Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
188c2ecf20Sopenharmony_ci *   the GNU Lesser General Public License for more details.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci *   You should have received a copy of the GNU Lesser General Public License
218c2ecf20Sopenharmony_ci *   along with this library; if not, write to the Free Software
228c2ecf20Sopenharmony_ci *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <linux/fs.h>
268c2ecf20Sopenharmony_ci#include <linux/slab.h>
278c2ecf20Sopenharmony_ci#include "cifspdu.h"
288c2ecf20Sopenharmony_ci#include "cifsglob.h"
298c2ecf20Sopenharmony_ci#include "cifs_debug.h"
308c2ecf20Sopenharmony_ci#include "cifs_unicode.h"
318c2ecf20Sopenharmony_ci#include "cifsproto.h"
328c2ecf20Sopenharmony_ci#include "ntlmssp.h"
338c2ecf20Sopenharmony_ci#include <linux/ctype.h>
348c2ecf20Sopenharmony_ci#include <linux/random.h>
358c2ecf20Sopenharmony_ci#include <linux/highmem.h>
368c2ecf20Sopenharmony_ci#include <linux/fips.h>
378c2ecf20Sopenharmony_ci#include <crypto/arc4.h>
388c2ecf20Sopenharmony_ci#include <crypto/aead.h>
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ciint __cifs_calc_signature(struct smb_rqst *rqst,
418c2ecf20Sopenharmony_ci			struct TCP_Server_Info *server, char *signature,
428c2ecf20Sopenharmony_ci			struct shash_desc *shash)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	int i;
458c2ecf20Sopenharmony_ci	int rc;
468c2ecf20Sopenharmony_ci	struct kvec *iov = rqst->rq_iov;
478c2ecf20Sopenharmony_ci	int n_vec = rqst->rq_nvec;
488c2ecf20Sopenharmony_ci	int is_smb2 = server->vals->header_preamble_size == 0;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	/* iov[0] is actual data and not the rfc1002 length for SMB2+ */
518c2ecf20Sopenharmony_ci	if (is_smb2) {
528c2ecf20Sopenharmony_ci		if (iov[0].iov_len <= 4)
538c2ecf20Sopenharmony_ci			return -EIO;
548c2ecf20Sopenharmony_ci		i = 0;
558c2ecf20Sopenharmony_ci	} else {
568c2ecf20Sopenharmony_ci		if (n_vec < 2 || iov[0].iov_len != 4)
578c2ecf20Sopenharmony_ci			return -EIO;
588c2ecf20Sopenharmony_ci		i = 1; /* skip rfc1002 length */
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	for (; i < n_vec; i++) {
628c2ecf20Sopenharmony_ci		if (iov[i].iov_len == 0)
638c2ecf20Sopenharmony_ci			continue;
648c2ecf20Sopenharmony_ci		if (iov[i].iov_base == NULL) {
658c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "null iovec entry\n");
668c2ecf20Sopenharmony_ci			return -EIO;
678c2ecf20Sopenharmony_ci		}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci		rc = crypto_shash_update(shash,
708c2ecf20Sopenharmony_ci					 iov[i].iov_base, iov[i].iov_len);
718c2ecf20Sopenharmony_ci		if (rc) {
728c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "%s: Could not update with payload\n",
738c2ecf20Sopenharmony_ci				 __func__);
748c2ecf20Sopenharmony_ci			return rc;
758c2ecf20Sopenharmony_ci		}
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/* now hash over the rq_pages array */
798c2ecf20Sopenharmony_ci	for (i = 0; i < rqst->rq_npages; i++) {
808c2ecf20Sopenharmony_ci		void *kaddr;
818c2ecf20Sopenharmony_ci		unsigned int len, offset;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		rqst_page_get_length(rqst, i, &len, &offset);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci		kaddr = (char *) kmap(rqst->rq_pages[i]) + offset;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci		rc = crypto_shash_update(shash, kaddr, len);
888c2ecf20Sopenharmony_ci		if (rc) {
898c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "%s: Could not update with payload\n",
908c2ecf20Sopenharmony_ci				 __func__);
918c2ecf20Sopenharmony_ci			kunmap(rqst->rq_pages[i]);
928c2ecf20Sopenharmony_ci			return rc;
938c2ecf20Sopenharmony_ci		}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci		kunmap(rqst->rq_pages[i]);
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	rc = crypto_shash_final(shash, signature);
998c2ecf20Sopenharmony_ci	if (rc)
1008c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not generate hash\n", __func__);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	return rc;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/*
1068c2ecf20Sopenharmony_ci * Calculate and return the CIFS signature based on the mac key and SMB PDU.
1078c2ecf20Sopenharmony_ci * The 16 byte signature must be allocated by the caller. Note we only use the
1088c2ecf20Sopenharmony_ci * 1st eight bytes and that the smb header signature field on input contains
1098c2ecf20Sopenharmony_ci * the sequence number before this function is called. Also, this function
1108c2ecf20Sopenharmony_ci * should be called with the server->srv_mutex held.
1118c2ecf20Sopenharmony_ci */
1128c2ecf20Sopenharmony_cistatic int cifs_calc_signature(struct smb_rqst *rqst,
1138c2ecf20Sopenharmony_ci			struct TCP_Server_Info *server, char *signature)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	int rc;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if (!rqst->rq_iov || !signature || !server)
1188c2ecf20Sopenharmony_ci		return -EINVAL;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	rc = cifs_alloc_hash("md5", &server->secmech.md5,
1218c2ecf20Sopenharmony_ci			     &server->secmech.sdescmd5);
1228c2ecf20Sopenharmony_ci	if (rc)
1238c2ecf20Sopenharmony_ci		return -1;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
1268c2ecf20Sopenharmony_ci	if (rc) {
1278c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not init md5\n", __func__);
1288c2ecf20Sopenharmony_ci		return rc;
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	rc = crypto_shash_update(&server->secmech.sdescmd5->shash,
1328c2ecf20Sopenharmony_ci		server->session_key.response, server->session_key.len);
1338c2ecf20Sopenharmony_ci	if (rc) {
1348c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
1358c2ecf20Sopenharmony_ci		return rc;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return __cifs_calc_signature(rqst, server, signature,
1398c2ecf20Sopenharmony_ci				     &server->secmech.sdescmd5->shash);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/* must be called with server->srv_mutex held */
1438c2ecf20Sopenharmony_ciint cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
1448c2ecf20Sopenharmony_ci		   __u32 *pexpected_response_sequence_number)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	int rc = 0;
1478c2ecf20Sopenharmony_ci	char smb_signature[20];
1488c2ecf20Sopenharmony_ci	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	if (rqst->rq_iov[0].iov_len != 4 ||
1518c2ecf20Sopenharmony_ci	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
1528c2ecf20Sopenharmony_ci		return -EIO;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if ((cifs_pdu == NULL) || (server == NULL))
1558c2ecf20Sopenharmony_ci		return -EINVAL;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
1588c2ecf20Sopenharmony_ci	    server->tcpStatus == CifsNeedNegotiate)
1598c2ecf20Sopenharmony_ci		return rc;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	if (!server->session_estab) {
1628c2ecf20Sopenharmony_ci		memcpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
1638c2ecf20Sopenharmony_ci		return rc;
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	cifs_pdu->Signature.Sequence.SequenceNumber =
1678c2ecf20Sopenharmony_ci				cpu_to_le32(server->sequence_number);
1688c2ecf20Sopenharmony_ci	cifs_pdu->Signature.Sequence.Reserved = 0;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	*pexpected_response_sequence_number = ++server->sequence_number;
1718c2ecf20Sopenharmony_ci	++server->sequence_number;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	rc = cifs_calc_signature(rqst, server, smb_signature);
1748c2ecf20Sopenharmony_ci	if (rc)
1758c2ecf20Sopenharmony_ci		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
1768c2ecf20Sopenharmony_ci	else
1778c2ecf20Sopenharmony_ci		memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	return rc;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ciint cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
1838c2ecf20Sopenharmony_ci		   __u32 *pexpected_response_sequence)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	struct smb_rqst rqst = { .rq_iov = iov,
1868c2ecf20Sopenharmony_ci				 .rq_nvec = n_vec };
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	return cifs_sign_rqst(&rqst, server, pexpected_response_sequence);
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci/* must be called with server->srv_mutex held */
1928c2ecf20Sopenharmony_ciint cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
1938c2ecf20Sopenharmony_ci		  __u32 *pexpected_response_sequence_number)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	struct kvec iov[2];
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	iov[0].iov_base = cifs_pdu;
1988c2ecf20Sopenharmony_ci	iov[0].iov_len = 4;
1998c2ecf20Sopenharmony_ci	iov[1].iov_base = (char *)cifs_pdu + 4;
2008c2ecf20Sopenharmony_ci	iov[1].iov_len = be32_to_cpu(cifs_pdu->smb_buf_length);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	return cifs_sign_smbv(iov, 2, server,
2038c2ecf20Sopenharmony_ci			      pexpected_response_sequence_number);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ciint cifs_verify_signature(struct smb_rqst *rqst,
2078c2ecf20Sopenharmony_ci			  struct TCP_Server_Info *server,
2088c2ecf20Sopenharmony_ci			  __u32 expected_sequence_number)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	unsigned int rc;
2118c2ecf20Sopenharmony_ci	char server_response_sig[8];
2128c2ecf20Sopenharmony_ci	char what_we_think_sig_should_be[20];
2138c2ecf20Sopenharmony_ci	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	if (rqst->rq_iov[0].iov_len != 4 ||
2168c2ecf20Sopenharmony_ci	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
2178c2ecf20Sopenharmony_ci		return -EIO;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if (cifs_pdu == NULL || server == NULL)
2208c2ecf20Sopenharmony_ci		return -EINVAL;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	if (!server->session_estab)
2238c2ecf20Sopenharmony_ci		return 0;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
2268c2ecf20Sopenharmony_ci		struct smb_com_lock_req *pSMB =
2278c2ecf20Sopenharmony_ci			(struct smb_com_lock_req *)cifs_pdu;
2288c2ecf20Sopenharmony_ci		if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
2298c2ecf20Sopenharmony_ci			return 0;
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	/* BB what if signatures are supposed to be on for session but
2338c2ecf20Sopenharmony_ci	   server does not send one? BB */
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	/* Do not need to verify session setups with signature "BSRSPYL "  */
2368c2ecf20Sopenharmony_ci	if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0)
2378c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n",
2388c2ecf20Sopenharmony_ci			 cifs_pdu->Command);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/* save off the origiginal signature so we can modify the smb and check
2418c2ecf20Sopenharmony_ci		its signature against what the server sent */
2428c2ecf20Sopenharmony_ci	memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	cifs_pdu->Signature.Sequence.SequenceNumber =
2458c2ecf20Sopenharmony_ci					cpu_to_le32(expected_sequence_number);
2468c2ecf20Sopenharmony_ci	cifs_pdu->Signature.Sequence.Reserved = 0;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	mutex_lock(&server->srv_mutex);
2498c2ecf20Sopenharmony_ci	rc = cifs_calc_signature(rqst, server, what_we_think_sig_should_be);
2508c2ecf20Sopenharmony_ci	mutex_unlock(&server->srv_mutex);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	if (rc)
2538c2ecf20Sopenharmony_ci		return rc;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/*	cifs_dump_mem("what we think it should be: ",
2568c2ecf20Sopenharmony_ci		      what_we_think_sig_should_be, 16); */
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
2598c2ecf20Sopenharmony_ci		return -EACCES;
2608c2ecf20Sopenharmony_ci	else
2618c2ecf20Sopenharmony_ci		return 0;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci/* first calculate 24 bytes ntlm response and then 16 byte session key */
2668c2ecf20Sopenharmony_ciint setup_ntlm_response(struct cifs_ses *ses, const struct nls_table *nls_cp)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	int rc = 0;
2698c2ecf20Sopenharmony_ci	unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE;
2708c2ecf20Sopenharmony_ci	char temp_key[CIFS_SESS_KEY_SIZE];
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (!ses)
2738c2ecf20Sopenharmony_ci		return -EINVAL;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL);
2768c2ecf20Sopenharmony_ci	if (!ses->auth_key.response)
2778c2ecf20Sopenharmony_ci		return -ENOMEM;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	ses->auth_key.len = temp_len;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	rc = SMBNTencrypt(ses->password, ses->server->cryptkey,
2828c2ecf20Sopenharmony_ci			ses->auth_key.response + CIFS_SESS_KEY_SIZE, nls_cp);
2838c2ecf20Sopenharmony_ci	if (rc) {
2848c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "%s Can't generate NTLM response, error: %d\n",
2858c2ecf20Sopenharmony_ci			 __func__, rc);
2868c2ecf20Sopenharmony_ci		return rc;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	rc = E_md4hash(ses->password, temp_key, nls_cp);
2908c2ecf20Sopenharmony_ci	if (rc) {
2918c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "%s Can't generate NT hash, error: %d\n",
2928c2ecf20Sopenharmony_ci			 __func__, rc);
2938c2ecf20Sopenharmony_ci		return rc;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	rc = mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE);
2978c2ecf20Sopenharmony_ci	if (rc)
2988c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "%s Can't generate NTLM session key, error: %d\n",
2998c2ecf20Sopenharmony_ci			 __func__, rc);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	return rc;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_WEAK_PW_HASH
3058c2ecf20Sopenharmony_ciint calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
3068c2ecf20Sopenharmony_ci			char *lnm_session_key)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	int i, len;
3098c2ecf20Sopenharmony_ci	int rc;
3108c2ecf20Sopenharmony_ci	char password_with_pad[CIFS_ENCPWD_SIZE] = {0};
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (password) {
3138c2ecf20Sopenharmony_ci		for (len = 0; len < CIFS_ENCPWD_SIZE; len++)
3148c2ecf20Sopenharmony_ci			if (!password[len])
3158c2ecf20Sopenharmony_ci				break;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		memcpy(password_with_pad, password, len);
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (!encrypt && global_secflags & CIFSSEC_MAY_PLNTXT) {
3218c2ecf20Sopenharmony_ci		memcpy(lnm_session_key, password_with_pad,
3228c2ecf20Sopenharmony_ci			CIFS_ENCPWD_SIZE);
3238c2ecf20Sopenharmony_ci		return 0;
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	/* calculate old style session key */
3278c2ecf20Sopenharmony_ci	/* calling toupper is less broken than repeatedly
3288c2ecf20Sopenharmony_ci	calling nls_toupper would be since that will never
3298c2ecf20Sopenharmony_ci	work for UTF8, but neither handles multibyte code pages
3308c2ecf20Sopenharmony_ci	but the only alternative would be converting to UCS-16 (Unicode)
3318c2ecf20Sopenharmony_ci	(using a routine something like UniStrupr) then
3328c2ecf20Sopenharmony_ci	uppercasing and then converting back from Unicode - which
3338c2ecf20Sopenharmony_ci	would only worth doing it if we knew it were utf8. Basically
3348c2ecf20Sopenharmony_ci	utf8 and other multibyte codepages each need their own strupper
3358c2ecf20Sopenharmony_ci	function since a byte at a time will ont work. */
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	for (i = 0; i < CIFS_ENCPWD_SIZE; i++)
3388c2ecf20Sopenharmony_ci		password_with_pad[i] = toupper(password_with_pad[i]);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	rc = SMBencrypt(password_with_pad, cryptkey, lnm_session_key);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	return rc;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci#endif /* CIFS_WEAK_PW_HASH */
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci/* Build a proper attribute value/target info pairs blob.
3478c2ecf20Sopenharmony_ci * Fill in netbios and dns domain name and workstation name
3488c2ecf20Sopenharmony_ci * and client time (total five av pairs and + one end of fields indicator.
3498c2ecf20Sopenharmony_ci * Allocate domain name which gets freed when session struct is deallocated.
3508c2ecf20Sopenharmony_ci */
3518c2ecf20Sopenharmony_cistatic int
3528c2ecf20Sopenharmony_cibuild_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	unsigned int dlen;
3558c2ecf20Sopenharmony_ci	unsigned int size = 2 * sizeof(struct ntlmssp2_name);
3568c2ecf20Sopenharmony_ci	char *defdmname = "WORKGROUP";
3578c2ecf20Sopenharmony_ci	unsigned char *blobptr;
3588c2ecf20Sopenharmony_ci	struct ntlmssp2_name *attrptr;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (!ses->domainName) {
3618c2ecf20Sopenharmony_ci		ses->domainName = kstrdup(defdmname, GFP_KERNEL);
3628c2ecf20Sopenharmony_ci		if (!ses->domainName)
3638c2ecf20Sopenharmony_ci			return -ENOMEM;
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	dlen = strlen(ses->domainName);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	/*
3698c2ecf20Sopenharmony_ci	 * The length of this blob is two times the size of a
3708c2ecf20Sopenharmony_ci	 * structure (av pair) which holds name/size
3718c2ecf20Sopenharmony_ci	 * ( for NTLMSSP_AV_NB_DOMAIN_NAME followed by NTLMSSP_AV_EOL ) +
3728c2ecf20Sopenharmony_ci	 * unicode length of a netbios domain name
3738c2ecf20Sopenharmony_ci	 */
3748c2ecf20Sopenharmony_ci	ses->auth_key.len = size + 2 * dlen;
3758c2ecf20Sopenharmony_ci	ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL);
3768c2ecf20Sopenharmony_ci	if (!ses->auth_key.response) {
3778c2ecf20Sopenharmony_ci		ses->auth_key.len = 0;
3788c2ecf20Sopenharmony_ci		return -ENOMEM;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	blobptr = ses->auth_key.response;
3828c2ecf20Sopenharmony_ci	attrptr = (struct ntlmssp2_name *) blobptr;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	/*
3858c2ecf20Sopenharmony_ci	 * As defined in MS-NTLM 3.3.2, just this av pair field
3868c2ecf20Sopenharmony_ci	 * is sufficient as part of the temp
3878c2ecf20Sopenharmony_ci	 */
3888c2ecf20Sopenharmony_ci	attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME);
3898c2ecf20Sopenharmony_ci	attrptr->length = cpu_to_le16(2 * dlen);
3908c2ecf20Sopenharmony_ci	blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name);
3918c2ecf20Sopenharmony_ci	cifs_strtoUTF16((__le16 *)blobptr, ses->domainName, dlen, nls_cp);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci/* Server has provided av pairs/target info in the type 2 challenge
3978c2ecf20Sopenharmony_ci * packet and we have plucked it and stored within smb session.
3988c2ecf20Sopenharmony_ci * We parse that blob here to find netbios domain name to be used
3998c2ecf20Sopenharmony_ci * as part of ntlmv2 authentication (in Target String), if not already
4008c2ecf20Sopenharmony_ci * specified on the command line.
4018c2ecf20Sopenharmony_ci * If this function returns without any error but without fetching
4028c2ecf20Sopenharmony_ci * domain name, authentication may fail against some server but
4038c2ecf20Sopenharmony_ci * may not fail against other (those who are not very particular
4048c2ecf20Sopenharmony_ci * about target string i.e. for some, just user name might suffice.
4058c2ecf20Sopenharmony_ci */
4068c2ecf20Sopenharmony_cistatic int
4078c2ecf20Sopenharmony_cifind_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	unsigned int attrsize;
4108c2ecf20Sopenharmony_ci	unsigned int type;
4118c2ecf20Sopenharmony_ci	unsigned int onesize = sizeof(struct ntlmssp2_name);
4128c2ecf20Sopenharmony_ci	unsigned char *blobptr;
4138c2ecf20Sopenharmony_ci	unsigned char *blobend;
4148c2ecf20Sopenharmony_ci	struct ntlmssp2_name *attrptr;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (!ses->auth_key.len || !ses->auth_key.response)
4178c2ecf20Sopenharmony_ci		return 0;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	blobptr = ses->auth_key.response;
4208c2ecf20Sopenharmony_ci	blobend = blobptr + ses->auth_key.len;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	while (blobptr + onesize < blobend) {
4238c2ecf20Sopenharmony_ci		attrptr = (struct ntlmssp2_name *) blobptr;
4248c2ecf20Sopenharmony_ci		type = le16_to_cpu(attrptr->type);
4258c2ecf20Sopenharmony_ci		if (type == NTLMSSP_AV_EOL)
4268c2ecf20Sopenharmony_ci			break;
4278c2ecf20Sopenharmony_ci		blobptr += 2; /* advance attr type */
4288c2ecf20Sopenharmony_ci		attrsize = le16_to_cpu(attrptr->length);
4298c2ecf20Sopenharmony_ci		blobptr += 2; /* advance attr size */
4308c2ecf20Sopenharmony_ci		if (blobptr + attrsize > blobend)
4318c2ecf20Sopenharmony_ci			break;
4328c2ecf20Sopenharmony_ci		if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
4338c2ecf20Sopenharmony_ci			if (!attrsize || attrsize >= CIFS_MAX_DOMAINNAME_LEN)
4348c2ecf20Sopenharmony_ci				break;
4358c2ecf20Sopenharmony_ci			if (!ses->domainName) {
4368c2ecf20Sopenharmony_ci				ses->domainName =
4378c2ecf20Sopenharmony_ci					kmalloc(attrsize + 1, GFP_KERNEL);
4388c2ecf20Sopenharmony_ci				if (!ses->domainName)
4398c2ecf20Sopenharmony_ci						return -ENOMEM;
4408c2ecf20Sopenharmony_ci				cifs_from_utf16(ses->domainName,
4418c2ecf20Sopenharmony_ci					(__le16 *)blobptr, attrsize, attrsize,
4428c2ecf20Sopenharmony_ci					nls_cp, NO_MAP_UNI_RSVD);
4438c2ecf20Sopenharmony_ci				break;
4448c2ecf20Sopenharmony_ci			}
4458c2ecf20Sopenharmony_ci		}
4468c2ecf20Sopenharmony_ci		blobptr += attrsize; /* advance attr  value */
4478c2ecf20Sopenharmony_ci	}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	return 0;
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci/* Server has provided av pairs/target info in the type 2 challenge
4538c2ecf20Sopenharmony_ci * packet and we have plucked it and stored within smb session.
4548c2ecf20Sopenharmony_ci * We parse that blob here to find the server given timestamp
4558c2ecf20Sopenharmony_ci * as part of ntlmv2 authentication (or local current time as
4568c2ecf20Sopenharmony_ci * default in case of failure)
4578c2ecf20Sopenharmony_ci */
4588c2ecf20Sopenharmony_cistatic __le64
4598c2ecf20Sopenharmony_cifind_timestamp(struct cifs_ses *ses)
4608c2ecf20Sopenharmony_ci{
4618c2ecf20Sopenharmony_ci	unsigned int attrsize;
4628c2ecf20Sopenharmony_ci	unsigned int type;
4638c2ecf20Sopenharmony_ci	unsigned int onesize = sizeof(struct ntlmssp2_name);
4648c2ecf20Sopenharmony_ci	unsigned char *blobptr;
4658c2ecf20Sopenharmony_ci	unsigned char *blobend;
4668c2ecf20Sopenharmony_ci	struct ntlmssp2_name *attrptr;
4678c2ecf20Sopenharmony_ci	struct timespec64 ts;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	if (!ses->auth_key.len || !ses->auth_key.response)
4708c2ecf20Sopenharmony_ci		return 0;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	blobptr = ses->auth_key.response;
4738c2ecf20Sopenharmony_ci	blobend = blobptr + ses->auth_key.len;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	while (blobptr + onesize < blobend) {
4768c2ecf20Sopenharmony_ci		attrptr = (struct ntlmssp2_name *) blobptr;
4778c2ecf20Sopenharmony_ci		type = le16_to_cpu(attrptr->type);
4788c2ecf20Sopenharmony_ci		if (type == NTLMSSP_AV_EOL)
4798c2ecf20Sopenharmony_ci			break;
4808c2ecf20Sopenharmony_ci		blobptr += 2; /* advance attr type */
4818c2ecf20Sopenharmony_ci		attrsize = le16_to_cpu(attrptr->length);
4828c2ecf20Sopenharmony_ci		blobptr += 2; /* advance attr size */
4838c2ecf20Sopenharmony_ci		if (blobptr + attrsize > blobend)
4848c2ecf20Sopenharmony_ci			break;
4858c2ecf20Sopenharmony_ci		if (type == NTLMSSP_AV_TIMESTAMP) {
4868c2ecf20Sopenharmony_ci			if (attrsize == sizeof(u64))
4878c2ecf20Sopenharmony_ci				return *((__le64 *)blobptr);
4888c2ecf20Sopenharmony_ci		}
4898c2ecf20Sopenharmony_ci		blobptr += attrsize; /* advance attr value */
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	ktime_get_real_ts64(&ts);
4938c2ecf20Sopenharmony_ci	return cpu_to_le64(cifs_UnixTimeToNT(ts));
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
4978c2ecf20Sopenharmony_ci			    const struct nls_table *nls_cp)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	int rc = 0;
5008c2ecf20Sopenharmony_ci	int len;
5018c2ecf20Sopenharmony_ci	char nt_hash[CIFS_NTHASH_SIZE];
5028c2ecf20Sopenharmony_ci	__le16 *user;
5038c2ecf20Sopenharmony_ci	wchar_t *domain;
5048c2ecf20Sopenharmony_ci	wchar_t *server;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	if (!ses->server->secmech.sdeschmacmd5) {
5078c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__);
5088c2ecf20Sopenharmony_ci		return -1;
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	/* calculate md4 hash of password */
5128c2ecf20Sopenharmony_ci	E_md4hash(ses->password, nt_hash, nls_cp);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash,
5158c2ecf20Sopenharmony_ci				CIFS_NTHASH_SIZE);
5168c2ecf20Sopenharmony_ci	if (rc) {
5178c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not set NT Hash as a key\n", __func__);
5188c2ecf20Sopenharmony_ci		return rc;
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
5228c2ecf20Sopenharmony_ci	if (rc) {
5238c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
5248c2ecf20Sopenharmony_ci		return rc;
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	/* convert ses->user_name to unicode */
5288c2ecf20Sopenharmony_ci	len = ses->user_name ? strlen(ses->user_name) : 0;
5298c2ecf20Sopenharmony_ci	user = kmalloc(2 + (len * 2), GFP_KERNEL);
5308c2ecf20Sopenharmony_ci	if (user == NULL) {
5318c2ecf20Sopenharmony_ci		rc = -ENOMEM;
5328c2ecf20Sopenharmony_ci		return rc;
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	if (len) {
5368c2ecf20Sopenharmony_ci		len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
5378c2ecf20Sopenharmony_ci		UniStrupr(user);
5388c2ecf20Sopenharmony_ci	} else {
5398c2ecf20Sopenharmony_ci		memset(user, '\0', 2);
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
5438c2ecf20Sopenharmony_ci				(char *)user, 2 * len);
5448c2ecf20Sopenharmony_ci	kfree(user);
5458c2ecf20Sopenharmony_ci	if (rc) {
5468c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not update with user\n", __func__);
5478c2ecf20Sopenharmony_ci		return rc;
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	/* convert ses->domainName to unicode and uppercase */
5518c2ecf20Sopenharmony_ci	if (ses->domainName) {
5528c2ecf20Sopenharmony_ci		len = strlen(ses->domainName);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci		domain = kmalloc(2 + (len * 2), GFP_KERNEL);
5558c2ecf20Sopenharmony_ci		if (domain == NULL) {
5568c2ecf20Sopenharmony_ci			rc = -ENOMEM;
5578c2ecf20Sopenharmony_ci			return rc;
5588c2ecf20Sopenharmony_ci		}
5598c2ecf20Sopenharmony_ci		len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len,
5608c2ecf20Sopenharmony_ci				      nls_cp);
5618c2ecf20Sopenharmony_ci		rc =
5628c2ecf20Sopenharmony_ci		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
5638c2ecf20Sopenharmony_ci					(char *)domain, 2 * len);
5648c2ecf20Sopenharmony_ci		kfree(domain);
5658c2ecf20Sopenharmony_ci		if (rc) {
5668c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "%s: Could not update with domain\n",
5678c2ecf20Sopenharmony_ci				 __func__);
5688c2ecf20Sopenharmony_ci			return rc;
5698c2ecf20Sopenharmony_ci		}
5708c2ecf20Sopenharmony_ci	} else {
5718c2ecf20Sopenharmony_ci		/* We use ses->serverName if no domain name available */
5728c2ecf20Sopenharmony_ci		len = strlen(ses->serverName);
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci		server = kmalloc(2 + (len * 2), GFP_KERNEL);
5758c2ecf20Sopenharmony_ci		if (server == NULL) {
5768c2ecf20Sopenharmony_ci			rc = -ENOMEM;
5778c2ecf20Sopenharmony_ci			return rc;
5788c2ecf20Sopenharmony_ci		}
5798c2ecf20Sopenharmony_ci		len = cifs_strtoUTF16((__le16 *)server, ses->serverName, len,
5808c2ecf20Sopenharmony_ci					nls_cp);
5818c2ecf20Sopenharmony_ci		rc =
5828c2ecf20Sopenharmony_ci		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
5838c2ecf20Sopenharmony_ci					(char *)server, 2 * len);
5848c2ecf20Sopenharmony_ci		kfree(server);
5858c2ecf20Sopenharmony_ci		if (rc) {
5868c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "%s: Could not update with server\n",
5878c2ecf20Sopenharmony_ci				 __func__);
5888c2ecf20Sopenharmony_ci			return rc;
5898c2ecf20Sopenharmony_ci		}
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
5938c2ecf20Sopenharmony_ci					ntlmv2_hash);
5948c2ecf20Sopenharmony_ci	if (rc)
5958c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	return rc;
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cistatic int
6018c2ecf20Sopenharmony_ciCalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	int rc;
6048c2ecf20Sopenharmony_ci	struct ntlmv2_resp *ntlmv2 = (struct ntlmv2_resp *)
6058c2ecf20Sopenharmony_ci	    (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
6068c2ecf20Sopenharmony_ci	unsigned int hash_len;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	/* The MD5 hash starts at challenge_key.key */
6098c2ecf20Sopenharmony_ci	hash_len = ses->auth_key.len - (CIFS_SESS_KEY_SIZE +
6108c2ecf20Sopenharmony_ci		offsetof(struct ntlmv2_resp, challenge.key[0]));
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	if (!ses->server->secmech.sdeschmacmd5) {
6138c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__);
6148c2ecf20Sopenharmony_ci		return -1;
6158c2ecf20Sopenharmony_ci	}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5,
6188c2ecf20Sopenharmony_ci				 ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
6198c2ecf20Sopenharmony_ci	if (rc) {
6208c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
6218c2ecf20Sopenharmony_ci			 __func__);
6228c2ecf20Sopenharmony_ci		return rc;
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
6268c2ecf20Sopenharmony_ci	if (rc) {
6278c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
6288c2ecf20Sopenharmony_ci		return rc;
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED)
6328c2ecf20Sopenharmony_ci		memcpy(ntlmv2->challenge.key,
6338c2ecf20Sopenharmony_ci		       ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
6348c2ecf20Sopenharmony_ci	else
6358c2ecf20Sopenharmony_ci		memcpy(ntlmv2->challenge.key,
6368c2ecf20Sopenharmony_ci		       ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
6378c2ecf20Sopenharmony_ci	rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
6388c2ecf20Sopenharmony_ci				 ntlmv2->challenge.key, hash_len);
6398c2ecf20Sopenharmony_ci	if (rc) {
6408c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
6418c2ecf20Sopenharmony_ci		return rc;
6428c2ecf20Sopenharmony_ci	}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	/* Note that the MD5 digest over writes anon.challenge_key.key */
6458c2ecf20Sopenharmony_ci	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
6468c2ecf20Sopenharmony_ci				ntlmv2->ntlmv2_hash);
6478c2ecf20Sopenharmony_ci	if (rc)
6488c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	return rc;
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ciint
6548c2ecf20Sopenharmony_cisetup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	int rc;
6578c2ecf20Sopenharmony_ci	int baselen;
6588c2ecf20Sopenharmony_ci	unsigned int tilen;
6598c2ecf20Sopenharmony_ci	struct ntlmv2_resp *ntlmv2;
6608c2ecf20Sopenharmony_ci	char ntlmv2_hash[16];
6618c2ecf20Sopenharmony_ci	unsigned char *tiblob = NULL; /* target info blob */
6628c2ecf20Sopenharmony_ci	__le64 rsp_timestamp;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) {
6658c2ecf20Sopenharmony_ci		if (!ses->domainName) {
6668c2ecf20Sopenharmony_ci			if (ses->domainAuto) {
6678c2ecf20Sopenharmony_ci				rc = find_domain_name(ses, nls_cp);
6688c2ecf20Sopenharmony_ci				if (rc) {
6698c2ecf20Sopenharmony_ci					cifs_dbg(VFS, "error %d finding domain name\n",
6708c2ecf20Sopenharmony_ci						 rc);
6718c2ecf20Sopenharmony_ci					goto setup_ntlmv2_rsp_ret;
6728c2ecf20Sopenharmony_ci				}
6738c2ecf20Sopenharmony_ci			} else {
6748c2ecf20Sopenharmony_ci				ses->domainName = kstrdup("", GFP_KERNEL);
6758c2ecf20Sopenharmony_ci			}
6768c2ecf20Sopenharmony_ci		}
6778c2ecf20Sopenharmony_ci	} else {
6788c2ecf20Sopenharmony_ci		rc = build_avpair_blob(ses, nls_cp);
6798c2ecf20Sopenharmony_ci		if (rc) {
6808c2ecf20Sopenharmony_ci			cifs_dbg(VFS, "error %d building av pair blob\n", rc);
6818c2ecf20Sopenharmony_ci			goto setup_ntlmv2_rsp_ret;
6828c2ecf20Sopenharmony_ci		}
6838c2ecf20Sopenharmony_ci	}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	/* Must be within 5 minutes of the server (or in range +/-2h
6868c2ecf20Sopenharmony_ci	 * in case of Mac OS X), so simply carry over server timestamp
6878c2ecf20Sopenharmony_ci	 * (as Windows 7 does)
6888c2ecf20Sopenharmony_ci	 */
6898c2ecf20Sopenharmony_ci	rsp_timestamp = find_timestamp(ses);
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp);
6928c2ecf20Sopenharmony_ci	tilen = ses->auth_key.len;
6938c2ecf20Sopenharmony_ci	tiblob = ses->auth_key.response;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL);
6968c2ecf20Sopenharmony_ci	if (!ses->auth_key.response) {
6978c2ecf20Sopenharmony_ci		rc = -ENOMEM;
6988c2ecf20Sopenharmony_ci		ses->auth_key.len = 0;
6998c2ecf20Sopenharmony_ci		goto setup_ntlmv2_rsp_ret;
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci	ses->auth_key.len += baselen;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	ntlmv2 = (struct ntlmv2_resp *)
7048c2ecf20Sopenharmony_ci			(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
7058c2ecf20Sopenharmony_ci	ntlmv2->blob_signature = cpu_to_le32(0x00000101);
7068c2ecf20Sopenharmony_ci	ntlmv2->reserved = 0;
7078c2ecf20Sopenharmony_ci	ntlmv2->time = rsp_timestamp;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
7108c2ecf20Sopenharmony_ci	ntlmv2->reserved2 = 0;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	memcpy(ses->auth_key.response + baselen, tiblob, tilen);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	mutex_lock(&ses->server->srv_mutex);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	rc = cifs_alloc_hash("hmac(md5)",
7178c2ecf20Sopenharmony_ci			     &ses->server->secmech.hmacmd5,
7188c2ecf20Sopenharmony_ci			     &ses->server->secmech.sdeschmacmd5);
7198c2ecf20Sopenharmony_ci	if (rc) {
7208c2ecf20Sopenharmony_ci		goto unlock;
7218c2ecf20Sopenharmony_ci	}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	/* calculate ntlmv2_hash */
7248c2ecf20Sopenharmony_ci	rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
7258c2ecf20Sopenharmony_ci	if (rc) {
7268c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "Could not get v2 hash rc %d\n", rc);
7278c2ecf20Sopenharmony_ci		goto unlock;
7288c2ecf20Sopenharmony_ci	}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	/* calculate first part of the client response (CR1) */
7318c2ecf20Sopenharmony_ci	rc = CalcNTLMv2_response(ses, ntlmv2_hash);
7328c2ecf20Sopenharmony_ci	if (rc) {
7338c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "Could not calculate CR1 rc: %d\n", rc);
7348c2ecf20Sopenharmony_ci		goto unlock;
7358c2ecf20Sopenharmony_ci	}
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	/* now calculate the session key for NTLMv2 */
7388c2ecf20Sopenharmony_ci	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5,
7398c2ecf20Sopenharmony_ci		ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
7408c2ecf20Sopenharmony_ci	if (rc) {
7418c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
7428c2ecf20Sopenharmony_ci			 __func__);
7438c2ecf20Sopenharmony_ci		goto unlock;
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
7478c2ecf20Sopenharmony_ci	if (rc) {
7488c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
7498c2ecf20Sopenharmony_ci		goto unlock;
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
7538c2ecf20Sopenharmony_ci		ntlmv2->ntlmv2_hash,
7548c2ecf20Sopenharmony_ci		CIFS_HMAC_MD5_HASH_SIZE);
7558c2ecf20Sopenharmony_ci	if (rc) {
7568c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
7578c2ecf20Sopenharmony_ci		goto unlock;
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
7618c2ecf20Sopenharmony_ci		ses->auth_key.response);
7628c2ecf20Sopenharmony_ci	if (rc)
7638c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ciunlock:
7668c2ecf20Sopenharmony_ci	mutex_unlock(&ses->server->srv_mutex);
7678c2ecf20Sopenharmony_cisetup_ntlmv2_rsp_ret:
7688c2ecf20Sopenharmony_ci	kfree(tiblob);
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	return rc;
7718c2ecf20Sopenharmony_ci}
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ciint
7748c2ecf20Sopenharmony_cicalc_seckey(struct cifs_ses *ses)
7758c2ecf20Sopenharmony_ci{
7768c2ecf20Sopenharmony_ci	unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */
7778c2ecf20Sopenharmony_ci	struct arc4_ctx *ctx_arc4;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	if (fips_enabled)
7808c2ecf20Sopenharmony_ci		return -ENODEV;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL);
7858c2ecf20Sopenharmony_ci	if (!ctx_arc4) {
7868c2ecf20Sopenharmony_ci		cifs_dbg(VFS, "Could not allocate arc4 context\n");
7878c2ecf20Sopenharmony_ci		return -ENOMEM;
7888c2ecf20Sopenharmony_ci	}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE);
7918c2ecf20Sopenharmony_ci	arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key,
7928c2ecf20Sopenharmony_ci		   CIFS_CPHTXT_SIZE);
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	/* make secondary_key/nonce as session key */
7958c2ecf20Sopenharmony_ci	memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE);
7968c2ecf20Sopenharmony_ci	/* and make len as that of session key only */
7978c2ecf20Sopenharmony_ci	ses->auth_key.len = CIFS_SESS_KEY_SIZE;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	memzero_explicit(sec_key, CIFS_SESS_KEY_SIZE);
8008c2ecf20Sopenharmony_ci	kfree_sensitive(ctx_arc4);
8018c2ecf20Sopenharmony_ci	return 0;
8028c2ecf20Sopenharmony_ci}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_civoid
8058c2ecf20Sopenharmony_cicifs_crypto_secmech_release(struct TCP_Server_Info *server)
8068c2ecf20Sopenharmony_ci{
8078c2ecf20Sopenharmony_ci	if (server->secmech.cmacaes) {
8088c2ecf20Sopenharmony_ci		crypto_free_shash(server->secmech.cmacaes);
8098c2ecf20Sopenharmony_ci		server->secmech.cmacaes = NULL;
8108c2ecf20Sopenharmony_ci	}
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	if (server->secmech.hmacsha256) {
8138c2ecf20Sopenharmony_ci		crypto_free_shash(server->secmech.hmacsha256);
8148c2ecf20Sopenharmony_ci		server->secmech.hmacsha256 = NULL;
8158c2ecf20Sopenharmony_ci	}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	if (server->secmech.md5) {
8188c2ecf20Sopenharmony_ci		crypto_free_shash(server->secmech.md5);
8198c2ecf20Sopenharmony_ci		server->secmech.md5 = NULL;
8208c2ecf20Sopenharmony_ci	}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	if (server->secmech.sha512) {
8238c2ecf20Sopenharmony_ci		crypto_free_shash(server->secmech.sha512);
8248c2ecf20Sopenharmony_ci		server->secmech.sha512 = NULL;
8258c2ecf20Sopenharmony_ci	}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	if (server->secmech.hmacmd5) {
8288c2ecf20Sopenharmony_ci		crypto_free_shash(server->secmech.hmacmd5);
8298c2ecf20Sopenharmony_ci		server->secmech.hmacmd5 = NULL;
8308c2ecf20Sopenharmony_ci	}
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	if (server->secmech.ccmaesencrypt) {
8338c2ecf20Sopenharmony_ci		crypto_free_aead(server->secmech.ccmaesencrypt);
8348c2ecf20Sopenharmony_ci		server->secmech.ccmaesencrypt = NULL;
8358c2ecf20Sopenharmony_ci	}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	if (server->secmech.ccmaesdecrypt) {
8388c2ecf20Sopenharmony_ci		crypto_free_aead(server->secmech.ccmaesdecrypt);
8398c2ecf20Sopenharmony_ci		server->secmech.ccmaesdecrypt = NULL;
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	kfree(server->secmech.sdesccmacaes);
8438c2ecf20Sopenharmony_ci	server->secmech.sdesccmacaes = NULL;
8448c2ecf20Sopenharmony_ci	kfree(server->secmech.sdeschmacsha256);
8458c2ecf20Sopenharmony_ci	server->secmech.sdeschmacsha256 = NULL;
8468c2ecf20Sopenharmony_ci	kfree(server->secmech.sdeschmacmd5);
8478c2ecf20Sopenharmony_ci	server->secmech.sdeschmacmd5 = NULL;
8488c2ecf20Sopenharmony_ci	kfree(server->secmech.sdescmd5);
8498c2ecf20Sopenharmony_ci	server->secmech.sdescmd5 = NULL;
8508c2ecf20Sopenharmony_ci	kfree(server->secmech.sdescsha512);
8518c2ecf20Sopenharmony_ci	server->secmech.sdescsha512 = NULL;
8528c2ecf20Sopenharmony_ci}
853