xref: /openbmc/linux/fs/smb/client/cifsencrypt.c (revision 8fbefa7a)
138c8a9a5SSteve French // SPDX-License-Identifier: LGPL-2.1
238c8a9a5SSteve French /*
338c8a9a5SSteve French  *
438c8a9a5SSteve French  *   Encryption and hashing operations relating to NTLM, NTLMv2.  See MS-NLMP
538c8a9a5SSteve French  *   for more detailed information
638c8a9a5SSteve French  *
738c8a9a5SSteve French  *   Copyright (C) International Business Machines  Corp., 2005,2013
838c8a9a5SSteve French  *   Author(s): Steve French (sfrench@us.ibm.com)
938c8a9a5SSteve French  *
1038c8a9a5SSteve French  */
1138c8a9a5SSteve French 
1238c8a9a5SSteve French #include <linux/fs.h>
1338c8a9a5SSteve French #include <linux/slab.h>
1438c8a9a5SSteve French #include "cifspdu.h"
1538c8a9a5SSteve French #include "cifsglob.h"
1638c8a9a5SSteve French #include "cifs_debug.h"
1738c8a9a5SSteve French #include "cifs_unicode.h"
1838c8a9a5SSteve French #include "cifsproto.h"
1938c8a9a5SSteve French #include "ntlmssp.h"
2038c8a9a5SSteve French #include <linux/ctype.h>
2138c8a9a5SSteve French #include <linux/random.h>
2238c8a9a5SSteve French #include <linux/highmem.h>
2338c8a9a5SSteve French #include <linux/fips.h>
2438c8a9a5SSteve French #include "../common/arc4.h"
2538c8a9a5SSteve French #include <crypto/aead.h>
2638c8a9a5SSteve French 
2738c8a9a5SSteve French /*
2838c8a9a5SSteve French  * Hash data from a BVEC-type iterator.
2938c8a9a5SSteve French  */
cifs_shash_bvec(const struct iov_iter * iter,ssize_t maxsize,struct shash_desc * shash)3038c8a9a5SSteve French static int cifs_shash_bvec(const struct iov_iter *iter, ssize_t maxsize,
3138c8a9a5SSteve French 			   struct shash_desc *shash)
3238c8a9a5SSteve French {
3338c8a9a5SSteve French 	const struct bio_vec *bv = iter->bvec;
3438c8a9a5SSteve French 	unsigned long start = iter->iov_offset;
3538c8a9a5SSteve French 	unsigned int i;
3638c8a9a5SSteve French 	void *p;
3738c8a9a5SSteve French 	int ret;
3838c8a9a5SSteve French 
3938c8a9a5SSteve French 	for (i = 0; i < iter->nr_segs; i++) {
4038c8a9a5SSteve French 		size_t off, len;
4138c8a9a5SSteve French 
4238c8a9a5SSteve French 		len = bv[i].bv_len;
4338c8a9a5SSteve French 		if (start >= len) {
4438c8a9a5SSteve French 			start -= len;
4538c8a9a5SSteve French 			continue;
4638c8a9a5SSteve French 		}
4738c8a9a5SSteve French 
4838c8a9a5SSteve French 		len = min_t(size_t, maxsize, len - start);
4938c8a9a5SSteve French 		off = bv[i].bv_offset + start;
5038c8a9a5SSteve French 
5138c8a9a5SSteve French 		p = kmap_local_page(bv[i].bv_page);
5238c8a9a5SSteve French 		ret = crypto_shash_update(shash, p + off, len);
5338c8a9a5SSteve French 		kunmap_local(p);
5438c8a9a5SSteve French 		if (ret < 0)
5538c8a9a5SSteve French 			return ret;
5638c8a9a5SSteve French 
5738c8a9a5SSteve French 		maxsize -= len;
5838c8a9a5SSteve French 		if (maxsize <= 0)
5938c8a9a5SSteve French 			break;
6038c8a9a5SSteve French 		start = 0;
6138c8a9a5SSteve French 	}
6238c8a9a5SSteve French 
6338c8a9a5SSteve French 	return 0;
6438c8a9a5SSteve French }
6538c8a9a5SSteve French 
6638c8a9a5SSteve French /*
6738c8a9a5SSteve French  * Hash data from a KVEC-type iterator.
6838c8a9a5SSteve French  */
cifs_shash_kvec(const struct iov_iter * iter,ssize_t maxsize,struct shash_desc * shash)6938c8a9a5SSteve French static int cifs_shash_kvec(const struct iov_iter *iter, ssize_t maxsize,
7038c8a9a5SSteve French 			   struct shash_desc *shash)
7138c8a9a5SSteve French {
7238c8a9a5SSteve French 	const struct kvec *kv = iter->kvec;
7338c8a9a5SSteve French 	unsigned long start = iter->iov_offset;
7438c8a9a5SSteve French 	unsigned int i;
7538c8a9a5SSteve French 	int ret;
7638c8a9a5SSteve French 
7738c8a9a5SSteve French 	for (i = 0; i < iter->nr_segs; i++) {
7838c8a9a5SSteve French 		size_t len;
7938c8a9a5SSteve French 
8038c8a9a5SSteve French 		len = kv[i].iov_len;
8138c8a9a5SSteve French 		if (start >= len) {
8238c8a9a5SSteve French 			start -= len;
8338c8a9a5SSteve French 			continue;
8438c8a9a5SSteve French 		}
8538c8a9a5SSteve French 
8638c8a9a5SSteve French 		len = min_t(size_t, maxsize, len - start);
8738c8a9a5SSteve French 		ret = crypto_shash_update(shash, kv[i].iov_base + start, len);
8838c8a9a5SSteve French 		if (ret < 0)
8938c8a9a5SSteve French 			return ret;
9038c8a9a5SSteve French 		maxsize -= len;
9138c8a9a5SSteve French 
9238c8a9a5SSteve French 		if (maxsize <= 0)
9338c8a9a5SSteve French 			break;
9438c8a9a5SSteve French 		start = 0;
9538c8a9a5SSteve French 	}
9638c8a9a5SSteve French 
9738c8a9a5SSteve French 	return 0;
9838c8a9a5SSteve French }
9938c8a9a5SSteve French 
10038c8a9a5SSteve French /*
10138c8a9a5SSteve French  * Hash data from an XARRAY-type iterator.
10238c8a9a5SSteve French  */
cifs_shash_xarray(const struct iov_iter * iter,ssize_t maxsize,struct shash_desc * shash)10338c8a9a5SSteve French static ssize_t cifs_shash_xarray(const struct iov_iter *iter, ssize_t maxsize,
10438c8a9a5SSteve French 				 struct shash_desc *shash)
10538c8a9a5SSteve French {
10638c8a9a5SSteve French 	struct folio *folios[16], *folio;
10738c8a9a5SSteve French 	unsigned int nr, i, j, npages;
10838c8a9a5SSteve French 	loff_t start = iter->xarray_start + iter->iov_offset;
10938c8a9a5SSteve French 	pgoff_t last, index = start / PAGE_SIZE;
11038c8a9a5SSteve French 	ssize_t ret = 0;
11138c8a9a5SSteve French 	size_t len, offset, foffset;
11238c8a9a5SSteve French 	void *p;
11338c8a9a5SSteve French 
11438c8a9a5SSteve French 	if (maxsize == 0)
11538c8a9a5SSteve French 		return 0;
11638c8a9a5SSteve French 
11738c8a9a5SSteve French 	last = (start + maxsize - 1) / PAGE_SIZE;
11838c8a9a5SSteve French 	do {
11938c8a9a5SSteve French 		nr = xa_extract(iter->xarray, (void **)folios, index, last,
12038c8a9a5SSteve French 				ARRAY_SIZE(folios), XA_PRESENT);
12138c8a9a5SSteve French 		if (nr == 0)
12238c8a9a5SSteve French 			return -EIO;
12338c8a9a5SSteve French 
12438c8a9a5SSteve French 		for (i = 0; i < nr; i++) {
12538c8a9a5SSteve French 			folio = folios[i];
12638c8a9a5SSteve French 			npages = folio_nr_pages(folio);
12738c8a9a5SSteve French 			foffset = start - folio_pos(folio);
12838c8a9a5SSteve French 			offset = foffset % PAGE_SIZE;
12938c8a9a5SSteve French 			for (j = foffset / PAGE_SIZE; j < npages; j++) {
13038c8a9a5SSteve French 				len = min_t(size_t, maxsize, PAGE_SIZE - offset);
13138c8a9a5SSteve French 				p = kmap_local_page(folio_page(folio, j));
13238c8a9a5SSteve French 				ret = crypto_shash_update(shash, p, len);
13338c8a9a5SSteve French 				kunmap_local(p);
13438c8a9a5SSteve French 				if (ret < 0)
13538c8a9a5SSteve French 					return ret;
13638c8a9a5SSteve French 				maxsize -= len;
13738c8a9a5SSteve French 				if (maxsize <= 0)
13838c8a9a5SSteve French 					return 0;
13938c8a9a5SSteve French 				start += len;
14038c8a9a5SSteve French 				offset = 0;
14138c8a9a5SSteve French 				index++;
14238c8a9a5SSteve French 			}
14338c8a9a5SSteve French 		}
14438c8a9a5SSteve French 	} while (nr == ARRAY_SIZE(folios));
14538c8a9a5SSteve French 	return 0;
14638c8a9a5SSteve French }
14738c8a9a5SSteve French 
14838c8a9a5SSteve French /*
14938c8a9a5SSteve French  * Pass the data from an iterator into a hash.
15038c8a9a5SSteve French  */
cifs_shash_iter(const struct iov_iter * iter,size_t maxsize,struct shash_desc * shash)15138c8a9a5SSteve French static int cifs_shash_iter(const struct iov_iter *iter, size_t maxsize,
15238c8a9a5SSteve French 			   struct shash_desc *shash)
15338c8a9a5SSteve French {
15438c8a9a5SSteve French 	if (maxsize == 0)
15538c8a9a5SSteve French 		return 0;
15638c8a9a5SSteve French 
15738c8a9a5SSteve French 	switch (iov_iter_type(iter)) {
15838c8a9a5SSteve French 	case ITER_BVEC:
15938c8a9a5SSteve French 		return cifs_shash_bvec(iter, maxsize, shash);
16038c8a9a5SSteve French 	case ITER_KVEC:
16138c8a9a5SSteve French 		return cifs_shash_kvec(iter, maxsize, shash);
16238c8a9a5SSteve French 	case ITER_XARRAY:
16338c8a9a5SSteve French 		return cifs_shash_xarray(iter, maxsize, shash);
16438c8a9a5SSteve French 	default:
16538c8a9a5SSteve French 		pr_err("cifs_shash_iter(%u) unsupported\n", iov_iter_type(iter));
16638c8a9a5SSteve French 		WARN_ON_ONCE(1);
16738c8a9a5SSteve French 		return -EIO;
16838c8a9a5SSteve French 	}
16938c8a9a5SSteve French }
17038c8a9a5SSteve French 
__cifs_calc_signature(struct smb_rqst * rqst,struct TCP_Server_Info * server,char * signature,struct shash_desc * shash)17138c8a9a5SSteve French int __cifs_calc_signature(struct smb_rqst *rqst,
17238c8a9a5SSteve French 			  struct TCP_Server_Info *server, char *signature,
17338c8a9a5SSteve French 			  struct shash_desc *shash)
17438c8a9a5SSteve French {
17538c8a9a5SSteve French 	int i;
17638c8a9a5SSteve French 	ssize_t rc;
17738c8a9a5SSteve French 	struct kvec *iov = rqst->rq_iov;
17838c8a9a5SSteve French 	int n_vec = rqst->rq_nvec;
17938c8a9a5SSteve French 
18038c8a9a5SSteve French 	/* iov[0] is actual data and not the rfc1002 length for SMB2+ */
18138c8a9a5SSteve French 	if (!is_smb1(server)) {
18238c8a9a5SSteve French 		if (iov[0].iov_len <= 4)
18338c8a9a5SSteve French 			return -EIO;
18438c8a9a5SSteve French 		i = 0;
18538c8a9a5SSteve French 	} else {
18638c8a9a5SSteve French 		if (n_vec < 2 || iov[0].iov_len != 4)
18738c8a9a5SSteve French 			return -EIO;
18838c8a9a5SSteve French 		i = 1; /* skip rfc1002 length */
18938c8a9a5SSteve French 	}
19038c8a9a5SSteve French 
19138c8a9a5SSteve French 	for (; i < n_vec; i++) {
19238c8a9a5SSteve French 		if (iov[i].iov_len == 0)
19338c8a9a5SSteve French 			continue;
19438c8a9a5SSteve French 		if (iov[i].iov_base == NULL) {
19538c8a9a5SSteve French 			cifs_dbg(VFS, "null iovec entry\n");
19638c8a9a5SSteve French 			return -EIO;
19738c8a9a5SSteve French 		}
19838c8a9a5SSteve French 
19938c8a9a5SSteve French 		rc = crypto_shash_update(shash,
20038c8a9a5SSteve French 					 iov[i].iov_base, iov[i].iov_len);
20138c8a9a5SSteve French 		if (rc) {
20238c8a9a5SSteve French 			cifs_dbg(VFS, "%s: Could not update with payload\n",
20338c8a9a5SSteve French 				 __func__);
20438c8a9a5SSteve French 			return rc;
20538c8a9a5SSteve French 		}
20638c8a9a5SSteve French 	}
20738c8a9a5SSteve French 
20838c8a9a5SSteve French 	rc = cifs_shash_iter(&rqst->rq_iter, iov_iter_count(&rqst->rq_iter), shash);
20938c8a9a5SSteve French 	if (rc < 0)
21038c8a9a5SSteve French 		return rc;
21138c8a9a5SSteve French 
21238c8a9a5SSteve French 	rc = crypto_shash_final(shash, signature);
21338c8a9a5SSteve French 	if (rc)
21438c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not generate hash\n", __func__);
21538c8a9a5SSteve French 
21638c8a9a5SSteve French 	return rc;
21738c8a9a5SSteve French }
21838c8a9a5SSteve French 
21938c8a9a5SSteve French /*
22038c8a9a5SSteve French  * Calculate and return the CIFS signature based on the mac key and SMB PDU.
22138c8a9a5SSteve French  * The 16 byte signature must be allocated by the caller. Note we only use the
22238c8a9a5SSteve French  * 1st eight bytes and that the smb header signature field on input contains
22338c8a9a5SSteve French  * the sequence number before this function is called. Also, this function
22438c8a9a5SSteve French  * should be called with the server->srv_mutex held.
22538c8a9a5SSteve French  */
cifs_calc_signature(struct smb_rqst * rqst,struct TCP_Server_Info * server,char * signature)22638c8a9a5SSteve French static int cifs_calc_signature(struct smb_rqst *rqst,
22738c8a9a5SSteve French 			struct TCP_Server_Info *server, char *signature)
22838c8a9a5SSteve French {
22938c8a9a5SSteve French 	int rc;
23038c8a9a5SSteve French 
23138c8a9a5SSteve French 	if (!rqst->rq_iov || !signature || !server)
23238c8a9a5SSteve French 		return -EINVAL;
23338c8a9a5SSteve French 
23438c8a9a5SSteve French 	rc = cifs_alloc_hash("md5", &server->secmech.md5);
23538c8a9a5SSteve French 	if (rc)
23638c8a9a5SSteve French 		return -1;
23738c8a9a5SSteve French 
23838c8a9a5SSteve French 	rc = crypto_shash_init(server->secmech.md5);
23938c8a9a5SSteve French 	if (rc) {
24038c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not init md5\n", __func__);
24138c8a9a5SSteve French 		return rc;
24238c8a9a5SSteve French 	}
24338c8a9a5SSteve French 
24438c8a9a5SSteve French 	rc = crypto_shash_update(server->secmech.md5,
24538c8a9a5SSteve French 		server->session_key.response, server->session_key.len);
24638c8a9a5SSteve French 	if (rc) {
24738c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
24838c8a9a5SSteve French 		return rc;
24938c8a9a5SSteve French 	}
25038c8a9a5SSteve French 
25138c8a9a5SSteve French 	return __cifs_calc_signature(rqst, server, signature, server->secmech.md5);
25238c8a9a5SSteve French }
25338c8a9a5SSteve French 
25438c8a9a5SSteve French /* must be called with server->srv_mutex held */
cifs_sign_rqst(struct smb_rqst * rqst,struct TCP_Server_Info * server,__u32 * pexpected_response_sequence_number)25538c8a9a5SSteve French int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
25638c8a9a5SSteve French 		   __u32 *pexpected_response_sequence_number)
25738c8a9a5SSteve French {
25838c8a9a5SSteve French 	int rc = 0;
25938c8a9a5SSteve French 	char smb_signature[20];
26038c8a9a5SSteve French 	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
26138c8a9a5SSteve French 
26238c8a9a5SSteve French 	if (rqst->rq_iov[0].iov_len != 4 ||
26338c8a9a5SSteve French 	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
26438c8a9a5SSteve French 		return -EIO;
26538c8a9a5SSteve French 
26638c8a9a5SSteve French 	if ((cifs_pdu == NULL) || (server == NULL))
26738c8a9a5SSteve French 		return -EINVAL;
26838c8a9a5SSteve French 
26938c8a9a5SSteve French 	spin_lock(&server->srv_lock);
27038c8a9a5SSteve French 	if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
27138c8a9a5SSteve French 	    server->tcpStatus == CifsNeedNegotiate) {
27238c8a9a5SSteve French 		spin_unlock(&server->srv_lock);
27338c8a9a5SSteve French 		return rc;
27438c8a9a5SSteve French 	}
27538c8a9a5SSteve French 	spin_unlock(&server->srv_lock);
27638c8a9a5SSteve French 
27738c8a9a5SSteve French 	if (!server->session_estab) {
27838c8a9a5SSteve French 		memcpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
27938c8a9a5SSteve French 		return rc;
28038c8a9a5SSteve French 	}
28138c8a9a5SSteve French 
28238c8a9a5SSteve French 	cifs_pdu->Signature.Sequence.SequenceNumber =
28338c8a9a5SSteve French 				cpu_to_le32(server->sequence_number);
28438c8a9a5SSteve French 	cifs_pdu->Signature.Sequence.Reserved = 0;
28538c8a9a5SSteve French 
28638c8a9a5SSteve French 	*pexpected_response_sequence_number = ++server->sequence_number;
28738c8a9a5SSteve French 	++server->sequence_number;
28838c8a9a5SSteve French 
28938c8a9a5SSteve French 	rc = cifs_calc_signature(rqst, server, smb_signature);
29038c8a9a5SSteve French 	if (rc)
29138c8a9a5SSteve French 		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
29238c8a9a5SSteve French 	else
29338c8a9a5SSteve French 		memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
29438c8a9a5SSteve French 
29538c8a9a5SSteve French 	return rc;
29638c8a9a5SSteve French }
29738c8a9a5SSteve French 
cifs_sign_smbv(struct kvec * iov,int n_vec,struct TCP_Server_Info * server,__u32 * pexpected_response_sequence)29838c8a9a5SSteve French int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
29938c8a9a5SSteve French 		   __u32 *pexpected_response_sequence)
30038c8a9a5SSteve French {
30138c8a9a5SSteve French 	struct smb_rqst rqst = { .rq_iov = iov,
30238c8a9a5SSteve French 				 .rq_nvec = n_vec };
30338c8a9a5SSteve French 
30438c8a9a5SSteve French 	return cifs_sign_rqst(&rqst, server, pexpected_response_sequence);
30538c8a9a5SSteve French }
30638c8a9a5SSteve French 
30738c8a9a5SSteve French /* must be called with server->srv_mutex held */
cifs_sign_smb(struct smb_hdr * cifs_pdu,struct TCP_Server_Info * server,__u32 * pexpected_response_sequence_number)30838c8a9a5SSteve French int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
30938c8a9a5SSteve French 		  __u32 *pexpected_response_sequence_number)
31038c8a9a5SSteve French {
31138c8a9a5SSteve French 	struct kvec iov[2];
31238c8a9a5SSteve French 
31338c8a9a5SSteve French 	iov[0].iov_base = cifs_pdu;
31438c8a9a5SSteve French 	iov[0].iov_len = 4;
31538c8a9a5SSteve French 	iov[1].iov_base = (char *)cifs_pdu + 4;
31638c8a9a5SSteve French 	iov[1].iov_len = be32_to_cpu(cifs_pdu->smb_buf_length);
31738c8a9a5SSteve French 
31838c8a9a5SSteve French 	return cifs_sign_smbv(iov, 2, server,
31938c8a9a5SSteve French 			      pexpected_response_sequence_number);
32038c8a9a5SSteve French }
32138c8a9a5SSteve French 
cifs_verify_signature(struct smb_rqst * rqst,struct TCP_Server_Info * server,__u32 expected_sequence_number)32238c8a9a5SSteve French int cifs_verify_signature(struct smb_rqst *rqst,
32338c8a9a5SSteve French 			  struct TCP_Server_Info *server,
32438c8a9a5SSteve French 			  __u32 expected_sequence_number)
32538c8a9a5SSteve French {
32638c8a9a5SSteve French 	unsigned int rc;
32738c8a9a5SSteve French 	char server_response_sig[8];
32838c8a9a5SSteve French 	char what_we_think_sig_should_be[20];
32938c8a9a5SSteve French 	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
33038c8a9a5SSteve French 
33138c8a9a5SSteve French 	if (rqst->rq_iov[0].iov_len != 4 ||
33238c8a9a5SSteve French 	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
33338c8a9a5SSteve French 		return -EIO;
33438c8a9a5SSteve French 
33538c8a9a5SSteve French 	if (cifs_pdu == NULL || server == NULL)
33638c8a9a5SSteve French 		return -EINVAL;
33738c8a9a5SSteve French 
33838c8a9a5SSteve French 	if (!server->session_estab)
33938c8a9a5SSteve French 		return 0;
34038c8a9a5SSteve French 
34138c8a9a5SSteve French 	if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
34238c8a9a5SSteve French 		struct smb_com_lock_req *pSMB =
34338c8a9a5SSteve French 			(struct smb_com_lock_req *)cifs_pdu;
34438c8a9a5SSteve French 		if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
34538c8a9a5SSteve French 			return 0;
34638c8a9a5SSteve French 	}
34738c8a9a5SSteve French 
34838c8a9a5SSteve French 	/* BB what if signatures are supposed to be on for session but
34938c8a9a5SSteve French 	   server does not send one? BB */
35038c8a9a5SSteve French 
35138c8a9a5SSteve French 	/* Do not need to verify session setups with signature "BSRSPYL "  */
35238c8a9a5SSteve French 	if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0)
35338c8a9a5SSteve French 		cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n",
35438c8a9a5SSteve French 			 cifs_pdu->Command);
35538c8a9a5SSteve French 
35638c8a9a5SSteve French 	/* save off the origiginal signature so we can modify the smb and check
35738c8a9a5SSteve French 		its signature against what the server sent */
35838c8a9a5SSteve French 	memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8);
35938c8a9a5SSteve French 
36038c8a9a5SSteve French 	cifs_pdu->Signature.Sequence.SequenceNumber =
36138c8a9a5SSteve French 					cpu_to_le32(expected_sequence_number);
36238c8a9a5SSteve French 	cifs_pdu->Signature.Sequence.Reserved = 0;
36338c8a9a5SSteve French 
36438c8a9a5SSteve French 	cifs_server_lock(server);
36538c8a9a5SSteve French 	rc = cifs_calc_signature(rqst, server, what_we_think_sig_should_be);
36638c8a9a5SSteve French 	cifs_server_unlock(server);
36738c8a9a5SSteve French 
36838c8a9a5SSteve French 	if (rc)
36938c8a9a5SSteve French 		return rc;
37038c8a9a5SSteve French 
37138c8a9a5SSteve French /*	cifs_dump_mem("what we think it should be: ",
37238c8a9a5SSteve French 		      what_we_think_sig_should_be, 16); */
37338c8a9a5SSteve French 
37438c8a9a5SSteve French 	if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
37538c8a9a5SSteve French 		return -EACCES;
37638c8a9a5SSteve French 	else
37738c8a9a5SSteve French 		return 0;
37838c8a9a5SSteve French 
37938c8a9a5SSteve French }
38038c8a9a5SSteve French 
38138c8a9a5SSteve French /* Build a proper attribute value/target info pairs blob.
38238c8a9a5SSteve French  * Fill in netbios and dns domain name and workstation name
38338c8a9a5SSteve French  * and client time (total five av pairs and + one end of fields indicator.
38438c8a9a5SSteve French  * Allocate domain name which gets freed when session struct is deallocated.
38538c8a9a5SSteve French  */
38638c8a9a5SSteve French static int
build_avpair_blob(struct cifs_ses * ses,const struct nls_table * nls_cp)38738c8a9a5SSteve French build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp)
38838c8a9a5SSteve French {
38938c8a9a5SSteve French 	unsigned int dlen;
39038c8a9a5SSteve French 	unsigned int size = 2 * sizeof(struct ntlmssp2_name);
39138c8a9a5SSteve French 	char *defdmname = "WORKGROUP";
39238c8a9a5SSteve French 	unsigned char *blobptr;
39338c8a9a5SSteve French 	struct ntlmssp2_name *attrptr;
39438c8a9a5SSteve French 
39538c8a9a5SSteve French 	if (!ses->domainName) {
39638c8a9a5SSteve French 		ses->domainName = kstrdup(defdmname, GFP_KERNEL);
39738c8a9a5SSteve French 		if (!ses->domainName)
39838c8a9a5SSteve French 			return -ENOMEM;
39938c8a9a5SSteve French 	}
40038c8a9a5SSteve French 
40138c8a9a5SSteve French 	dlen = strlen(ses->domainName);
40238c8a9a5SSteve French 
40338c8a9a5SSteve French 	/*
40438c8a9a5SSteve French 	 * The length of this blob is two times the size of a
40538c8a9a5SSteve French 	 * structure (av pair) which holds name/size
40638c8a9a5SSteve French 	 * ( for NTLMSSP_AV_NB_DOMAIN_NAME followed by NTLMSSP_AV_EOL ) +
40738c8a9a5SSteve French 	 * unicode length of a netbios domain name
40838c8a9a5SSteve French 	 */
40938c8a9a5SSteve French 	kfree_sensitive(ses->auth_key.response);
41038c8a9a5SSteve French 	ses->auth_key.len = size + 2 * dlen;
41138c8a9a5SSteve French 	ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL);
41238c8a9a5SSteve French 	if (!ses->auth_key.response) {
41338c8a9a5SSteve French 		ses->auth_key.len = 0;
41438c8a9a5SSteve French 		return -ENOMEM;
41538c8a9a5SSteve French 	}
41638c8a9a5SSteve French 
41738c8a9a5SSteve French 	blobptr = ses->auth_key.response;
41838c8a9a5SSteve French 	attrptr = (struct ntlmssp2_name *) blobptr;
41938c8a9a5SSteve French 
42038c8a9a5SSteve French 	/*
42138c8a9a5SSteve French 	 * As defined in MS-NTLM 3.3.2, just this av pair field
42238c8a9a5SSteve French 	 * is sufficient as part of the temp
42338c8a9a5SSteve French 	 */
42438c8a9a5SSteve French 	attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME);
42538c8a9a5SSteve French 	attrptr->length = cpu_to_le16(2 * dlen);
42638c8a9a5SSteve French 	blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name);
42738c8a9a5SSteve French 	cifs_strtoUTF16((__le16 *)blobptr, ses->domainName, dlen, nls_cp);
42838c8a9a5SSteve French 
42938c8a9a5SSteve French 	return 0;
43038c8a9a5SSteve French }
43138c8a9a5SSteve French 
43238c8a9a5SSteve French /* Server has provided av pairs/target info in the type 2 challenge
43338c8a9a5SSteve French  * packet and we have plucked it and stored within smb session.
43438c8a9a5SSteve French  * We parse that blob here to find netbios domain name to be used
43538c8a9a5SSteve French  * as part of ntlmv2 authentication (in Target String), if not already
43638c8a9a5SSteve French  * specified on the command line.
43738c8a9a5SSteve French  * If this function returns without any error but without fetching
43838c8a9a5SSteve French  * domain name, authentication may fail against some server but
43938c8a9a5SSteve French  * may not fail against other (those who are not very particular
44038c8a9a5SSteve French  * about target string i.e. for some, just user name might suffice.
44138c8a9a5SSteve French  */
44238c8a9a5SSteve French static int
find_domain_name(struct cifs_ses * ses,const struct nls_table * nls_cp)44338c8a9a5SSteve French find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp)
44438c8a9a5SSteve French {
44538c8a9a5SSteve French 	unsigned int attrsize;
44638c8a9a5SSteve French 	unsigned int type;
44738c8a9a5SSteve French 	unsigned int onesize = sizeof(struct ntlmssp2_name);
44838c8a9a5SSteve French 	unsigned char *blobptr;
44938c8a9a5SSteve French 	unsigned char *blobend;
45038c8a9a5SSteve French 	struct ntlmssp2_name *attrptr;
45138c8a9a5SSteve French 
45238c8a9a5SSteve French 	if (!ses->auth_key.len || !ses->auth_key.response)
45338c8a9a5SSteve French 		return 0;
45438c8a9a5SSteve French 
45538c8a9a5SSteve French 	blobptr = ses->auth_key.response;
45638c8a9a5SSteve French 	blobend = blobptr + ses->auth_key.len;
45738c8a9a5SSteve French 
45838c8a9a5SSteve French 	while (blobptr + onesize < blobend) {
45938c8a9a5SSteve French 		attrptr = (struct ntlmssp2_name *) blobptr;
46038c8a9a5SSteve French 		type = le16_to_cpu(attrptr->type);
46138c8a9a5SSteve French 		if (type == NTLMSSP_AV_EOL)
46238c8a9a5SSteve French 			break;
46338c8a9a5SSteve French 		blobptr += 2; /* advance attr type */
46438c8a9a5SSteve French 		attrsize = le16_to_cpu(attrptr->length);
46538c8a9a5SSteve French 		blobptr += 2; /* advance attr size */
46638c8a9a5SSteve French 		if (blobptr + attrsize > blobend)
46738c8a9a5SSteve French 			break;
46838c8a9a5SSteve French 		if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
46938c8a9a5SSteve French 			if (!attrsize || attrsize >= CIFS_MAX_DOMAINNAME_LEN)
47038c8a9a5SSteve French 				break;
47138c8a9a5SSteve French 			if (!ses->domainName) {
47238c8a9a5SSteve French 				ses->domainName =
47338c8a9a5SSteve French 					kmalloc(attrsize + 1, GFP_KERNEL);
47438c8a9a5SSteve French 				if (!ses->domainName)
47538c8a9a5SSteve French 						return -ENOMEM;
47638c8a9a5SSteve French 				cifs_from_utf16(ses->domainName,
47738c8a9a5SSteve French 					(__le16 *)blobptr, attrsize, attrsize,
47838c8a9a5SSteve French 					nls_cp, NO_MAP_UNI_RSVD);
47938c8a9a5SSteve French 				break;
48038c8a9a5SSteve French 			}
48138c8a9a5SSteve French 		}
48238c8a9a5SSteve French 		blobptr += attrsize; /* advance attr  value */
48338c8a9a5SSteve French 	}
48438c8a9a5SSteve French 
48538c8a9a5SSteve French 	return 0;
48638c8a9a5SSteve French }
48738c8a9a5SSteve French 
48838c8a9a5SSteve French /* Server has provided av pairs/target info in the type 2 challenge
48938c8a9a5SSteve French  * packet and we have plucked it and stored within smb session.
49038c8a9a5SSteve French  * We parse that blob here to find the server given timestamp
49138c8a9a5SSteve French  * as part of ntlmv2 authentication (or local current time as
49238c8a9a5SSteve French  * default in case of failure)
49338c8a9a5SSteve French  */
49438c8a9a5SSteve French static __le64
find_timestamp(struct cifs_ses * ses)49538c8a9a5SSteve French find_timestamp(struct cifs_ses *ses)
49638c8a9a5SSteve French {
49738c8a9a5SSteve French 	unsigned int attrsize;
49838c8a9a5SSteve French 	unsigned int type;
49938c8a9a5SSteve French 	unsigned int onesize = sizeof(struct ntlmssp2_name);
50038c8a9a5SSteve French 	unsigned char *blobptr;
50138c8a9a5SSteve French 	unsigned char *blobend;
50238c8a9a5SSteve French 	struct ntlmssp2_name *attrptr;
50338c8a9a5SSteve French 	struct timespec64 ts;
50438c8a9a5SSteve French 
50538c8a9a5SSteve French 	if (!ses->auth_key.len || !ses->auth_key.response)
50638c8a9a5SSteve French 		return 0;
50738c8a9a5SSteve French 
50838c8a9a5SSteve French 	blobptr = ses->auth_key.response;
50938c8a9a5SSteve French 	blobend = blobptr + ses->auth_key.len;
51038c8a9a5SSteve French 
51138c8a9a5SSteve French 	while (blobptr + onesize < blobend) {
51238c8a9a5SSteve French 		attrptr = (struct ntlmssp2_name *) blobptr;
51338c8a9a5SSteve French 		type = le16_to_cpu(attrptr->type);
51438c8a9a5SSteve French 		if (type == NTLMSSP_AV_EOL)
51538c8a9a5SSteve French 			break;
51638c8a9a5SSteve French 		blobptr += 2; /* advance attr type */
51738c8a9a5SSteve French 		attrsize = le16_to_cpu(attrptr->length);
51838c8a9a5SSteve French 		blobptr += 2; /* advance attr size */
51938c8a9a5SSteve French 		if (blobptr + attrsize > blobend)
52038c8a9a5SSteve French 			break;
52138c8a9a5SSteve French 		if (type == NTLMSSP_AV_TIMESTAMP) {
52238c8a9a5SSteve French 			if (attrsize == sizeof(u64))
52338c8a9a5SSteve French 				return *((__le64 *)blobptr);
52438c8a9a5SSteve French 		}
52538c8a9a5SSteve French 		blobptr += attrsize; /* advance attr value */
52638c8a9a5SSteve French 	}
52738c8a9a5SSteve French 
52838c8a9a5SSteve French 	ktime_get_real_ts64(&ts);
52938c8a9a5SSteve French 	return cpu_to_le64(cifs_UnixTimeToNT(ts));
53038c8a9a5SSteve French }
53138c8a9a5SSteve French 
calc_ntlmv2_hash(struct cifs_ses * ses,char * ntlmv2_hash,const struct nls_table * nls_cp)53238c8a9a5SSteve French static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
53338c8a9a5SSteve French 			    const struct nls_table *nls_cp)
53438c8a9a5SSteve French {
53538c8a9a5SSteve French 	int rc = 0;
53638c8a9a5SSteve French 	int len;
53738c8a9a5SSteve French 	char nt_hash[CIFS_NTHASH_SIZE];
53838c8a9a5SSteve French 	__le16 *user;
53938c8a9a5SSteve French 	wchar_t *domain;
54038c8a9a5SSteve French 	wchar_t *server;
54138c8a9a5SSteve French 
54238c8a9a5SSteve French 	if (!ses->server->secmech.hmacmd5) {
54338c8a9a5SSteve French 		cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__);
54438c8a9a5SSteve French 		return -1;
54538c8a9a5SSteve French 	}
54638c8a9a5SSteve French 
54738c8a9a5SSteve French 	/* calculate md4 hash of password */
54838c8a9a5SSteve French 	E_md4hash(ses->password, nt_hash, nls_cp);
54938c8a9a5SSteve French 
55038c8a9a5SSteve French 	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm, nt_hash,
55138c8a9a5SSteve French 				CIFS_NTHASH_SIZE);
55238c8a9a5SSteve French 	if (rc) {
55338c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not set NT Hash as a key\n", __func__);
55438c8a9a5SSteve French 		return rc;
55538c8a9a5SSteve French 	}
55638c8a9a5SSteve French 
55738c8a9a5SSteve French 	rc = crypto_shash_init(ses->server->secmech.hmacmd5);
55838c8a9a5SSteve French 	if (rc) {
55938c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
56038c8a9a5SSteve French 		return rc;
56138c8a9a5SSteve French 	}
56238c8a9a5SSteve French 
56338c8a9a5SSteve French 	/* convert ses->user_name to unicode */
56438c8a9a5SSteve French 	len = ses->user_name ? strlen(ses->user_name) : 0;
56538c8a9a5SSteve French 	user = kmalloc(2 + (len * 2), GFP_KERNEL);
56638c8a9a5SSteve French 	if (user == NULL) {
56738c8a9a5SSteve French 		rc = -ENOMEM;
56838c8a9a5SSteve French 		return rc;
56938c8a9a5SSteve French 	}
57038c8a9a5SSteve French 
57138c8a9a5SSteve French 	if (len) {
57238c8a9a5SSteve French 		len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
57338c8a9a5SSteve French 		UniStrupr(user);
57438c8a9a5SSteve French 	} else {
575*8fbefa7aSKees Cook 		*(u16 *)user = 0;
57638c8a9a5SSteve French 	}
57738c8a9a5SSteve French 
57838c8a9a5SSteve French 	rc = crypto_shash_update(ses->server->secmech.hmacmd5,
57938c8a9a5SSteve French 				(char *)user, 2 * len);
58038c8a9a5SSteve French 	kfree(user);
58138c8a9a5SSteve French 	if (rc) {
58238c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not update with user\n", __func__);
58338c8a9a5SSteve French 		return rc;
58438c8a9a5SSteve French 	}
58538c8a9a5SSteve French 
58638c8a9a5SSteve French 	/* convert ses->domainName to unicode and uppercase */
58738c8a9a5SSteve French 	if (ses->domainName) {
58838c8a9a5SSteve French 		len = strlen(ses->domainName);
58938c8a9a5SSteve French 
59038c8a9a5SSteve French 		domain = kmalloc(2 + (len * 2), GFP_KERNEL);
59138c8a9a5SSteve French 		if (domain == NULL) {
59238c8a9a5SSteve French 			rc = -ENOMEM;
59338c8a9a5SSteve French 			return rc;
59438c8a9a5SSteve French 		}
59538c8a9a5SSteve French 		len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len,
59638c8a9a5SSteve French 				      nls_cp);
59738c8a9a5SSteve French 		rc =
59838c8a9a5SSteve French 		crypto_shash_update(ses->server->secmech.hmacmd5,
59938c8a9a5SSteve French 					(char *)domain, 2 * len);
60038c8a9a5SSteve French 		kfree(domain);
60138c8a9a5SSteve French 		if (rc) {
60238c8a9a5SSteve French 			cifs_dbg(VFS, "%s: Could not update with domain\n",
60338c8a9a5SSteve French 				 __func__);
60438c8a9a5SSteve French 			return rc;
60538c8a9a5SSteve French 		}
60638c8a9a5SSteve French 	} else {
60738c8a9a5SSteve French 		/* We use ses->ip_addr if no domain name available */
60838c8a9a5SSteve French 		len = strlen(ses->ip_addr);
60938c8a9a5SSteve French 
61038c8a9a5SSteve French 		server = kmalloc(2 + (len * 2), GFP_KERNEL);
61138c8a9a5SSteve French 		if (server == NULL) {
61238c8a9a5SSteve French 			rc = -ENOMEM;
61338c8a9a5SSteve French 			return rc;
61438c8a9a5SSteve French 		}
61538c8a9a5SSteve French 		len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len,
61638c8a9a5SSteve French 					nls_cp);
61738c8a9a5SSteve French 		rc =
61838c8a9a5SSteve French 		crypto_shash_update(ses->server->secmech.hmacmd5,
61938c8a9a5SSteve French 					(char *)server, 2 * len);
62038c8a9a5SSteve French 		kfree(server);
62138c8a9a5SSteve French 		if (rc) {
62238c8a9a5SSteve French 			cifs_dbg(VFS, "%s: Could not update with server\n",
62338c8a9a5SSteve French 				 __func__);
62438c8a9a5SSteve French 			return rc;
62538c8a9a5SSteve French 		}
62638c8a9a5SSteve French 	}
62738c8a9a5SSteve French 
62838c8a9a5SSteve French 	rc = crypto_shash_final(ses->server->secmech.hmacmd5,
62938c8a9a5SSteve French 					ntlmv2_hash);
63038c8a9a5SSteve French 	if (rc)
63138c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
63238c8a9a5SSteve French 
63338c8a9a5SSteve French 	return rc;
63438c8a9a5SSteve French }
63538c8a9a5SSteve French 
63638c8a9a5SSteve French static int
CalcNTLMv2_response(const struct cifs_ses * ses,char * ntlmv2_hash)63738c8a9a5SSteve French CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
63838c8a9a5SSteve French {
63938c8a9a5SSteve French 	int rc;
64038c8a9a5SSteve French 	struct ntlmv2_resp *ntlmv2 = (struct ntlmv2_resp *)
64138c8a9a5SSteve French 	    (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
64238c8a9a5SSteve French 	unsigned int hash_len;
64338c8a9a5SSteve French 
64438c8a9a5SSteve French 	/* The MD5 hash starts at challenge_key.key */
64538c8a9a5SSteve French 	hash_len = ses->auth_key.len - (CIFS_SESS_KEY_SIZE +
64638c8a9a5SSteve French 		offsetof(struct ntlmv2_resp, challenge.key[0]));
64738c8a9a5SSteve French 
64838c8a9a5SSteve French 	if (!ses->server->secmech.hmacmd5) {
64938c8a9a5SSteve French 		cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__);
65038c8a9a5SSteve French 		return -1;
65138c8a9a5SSteve French 	}
65238c8a9a5SSteve French 
65338c8a9a5SSteve French 	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm,
65438c8a9a5SSteve French 				 ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
65538c8a9a5SSteve French 	if (rc) {
65638c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
65738c8a9a5SSteve French 			 __func__);
65838c8a9a5SSteve French 		return rc;
65938c8a9a5SSteve French 	}
66038c8a9a5SSteve French 
66138c8a9a5SSteve French 	rc = crypto_shash_init(ses->server->secmech.hmacmd5);
66238c8a9a5SSteve French 	if (rc) {
66338c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
66438c8a9a5SSteve French 		return rc;
66538c8a9a5SSteve French 	}
66638c8a9a5SSteve French 
66738c8a9a5SSteve French 	if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED)
66838c8a9a5SSteve French 		memcpy(ntlmv2->challenge.key,
66938c8a9a5SSteve French 		       ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
67038c8a9a5SSteve French 	else
67138c8a9a5SSteve French 		memcpy(ntlmv2->challenge.key,
67238c8a9a5SSteve French 		       ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
67338c8a9a5SSteve French 	rc = crypto_shash_update(ses->server->secmech.hmacmd5,
67438c8a9a5SSteve French 				 ntlmv2->challenge.key, hash_len);
67538c8a9a5SSteve French 	if (rc) {
67638c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
67738c8a9a5SSteve French 		return rc;
67838c8a9a5SSteve French 	}
67938c8a9a5SSteve French 
68038c8a9a5SSteve French 	/* Note that the MD5 digest over writes anon.challenge_key.key */
68138c8a9a5SSteve French 	rc = crypto_shash_final(ses->server->secmech.hmacmd5,
68238c8a9a5SSteve French 				ntlmv2->ntlmv2_hash);
68338c8a9a5SSteve French 	if (rc)
68438c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
68538c8a9a5SSteve French 
68638c8a9a5SSteve French 	return rc;
68738c8a9a5SSteve French }
68838c8a9a5SSteve French 
68938c8a9a5SSteve French int
setup_ntlmv2_rsp(struct cifs_ses * ses,const struct nls_table * nls_cp)69038c8a9a5SSteve French setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
69138c8a9a5SSteve French {
69238c8a9a5SSteve French 	int rc;
69338c8a9a5SSteve French 	int baselen;
69438c8a9a5SSteve French 	unsigned int tilen;
69538c8a9a5SSteve French 	struct ntlmv2_resp *ntlmv2;
69638c8a9a5SSteve French 	char ntlmv2_hash[16];
69738c8a9a5SSteve French 	unsigned char *tiblob = NULL; /* target info blob */
69838c8a9a5SSteve French 	__le64 rsp_timestamp;
69938c8a9a5SSteve French 
70038c8a9a5SSteve French 	if (nls_cp == NULL) {
70138c8a9a5SSteve French 		cifs_dbg(VFS, "%s called with nls_cp==NULL\n", __func__);
70238c8a9a5SSteve French 		return -EINVAL;
70338c8a9a5SSteve French 	}
70438c8a9a5SSteve French 
70538c8a9a5SSteve French 	if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) {
70638c8a9a5SSteve French 		if (!ses->domainName) {
70738c8a9a5SSteve French 			if (ses->domainAuto) {
70838c8a9a5SSteve French 				rc = find_domain_name(ses, nls_cp);
70938c8a9a5SSteve French 				if (rc) {
71038c8a9a5SSteve French 					cifs_dbg(VFS, "error %d finding domain name\n",
71138c8a9a5SSteve French 						 rc);
71238c8a9a5SSteve French 					goto setup_ntlmv2_rsp_ret;
71338c8a9a5SSteve French 				}
71438c8a9a5SSteve French 			} else {
71538c8a9a5SSteve French 				ses->domainName = kstrdup("", GFP_KERNEL);
71638c8a9a5SSteve French 			}
71738c8a9a5SSteve French 		}
71838c8a9a5SSteve French 	} else {
71938c8a9a5SSteve French 		rc = build_avpair_blob(ses, nls_cp);
72038c8a9a5SSteve French 		if (rc) {
72138c8a9a5SSteve French 			cifs_dbg(VFS, "error %d building av pair blob\n", rc);
72238c8a9a5SSteve French 			goto setup_ntlmv2_rsp_ret;
72338c8a9a5SSteve French 		}
72438c8a9a5SSteve French 	}
72538c8a9a5SSteve French 
72638c8a9a5SSteve French 	/* Must be within 5 minutes of the server (or in range +/-2h
72738c8a9a5SSteve French 	 * in case of Mac OS X), so simply carry over server timestamp
72838c8a9a5SSteve French 	 * (as Windows 7 does)
72938c8a9a5SSteve French 	 */
73038c8a9a5SSteve French 	rsp_timestamp = find_timestamp(ses);
73138c8a9a5SSteve French 
73238c8a9a5SSteve French 	baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp);
73338c8a9a5SSteve French 	tilen = ses->auth_key.len;
73438c8a9a5SSteve French 	tiblob = ses->auth_key.response;
73538c8a9a5SSteve French 
73638c8a9a5SSteve French 	ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL);
73738c8a9a5SSteve French 	if (!ses->auth_key.response) {
73838c8a9a5SSteve French 		rc = -ENOMEM;
73938c8a9a5SSteve French 		ses->auth_key.len = 0;
74038c8a9a5SSteve French 		goto setup_ntlmv2_rsp_ret;
74138c8a9a5SSteve French 	}
74238c8a9a5SSteve French 	ses->auth_key.len += baselen;
74338c8a9a5SSteve French 
74438c8a9a5SSteve French 	ntlmv2 = (struct ntlmv2_resp *)
74538c8a9a5SSteve French 			(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
74638c8a9a5SSteve French 	ntlmv2->blob_signature = cpu_to_le32(0x00000101);
74738c8a9a5SSteve French 	ntlmv2->reserved = 0;
74838c8a9a5SSteve French 	ntlmv2->time = rsp_timestamp;
74938c8a9a5SSteve French 
75038c8a9a5SSteve French 	get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
75138c8a9a5SSteve French 	ntlmv2->reserved2 = 0;
75238c8a9a5SSteve French 
75338c8a9a5SSteve French 	memcpy(ses->auth_key.response + baselen, tiblob, tilen);
75438c8a9a5SSteve French 
75538c8a9a5SSteve French 	cifs_server_lock(ses->server);
75638c8a9a5SSteve French 
75738c8a9a5SSteve French 	rc = cifs_alloc_hash("hmac(md5)", &ses->server->secmech.hmacmd5);
75838c8a9a5SSteve French 	if (rc) {
75938c8a9a5SSteve French 		goto unlock;
76038c8a9a5SSteve French 	}
76138c8a9a5SSteve French 
76238c8a9a5SSteve French 	/* calculate ntlmv2_hash */
76338c8a9a5SSteve French 	rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
76438c8a9a5SSteve French 	if (rc) {
76538c8a9a5SSteve French 		cifs_dbg(VFS, "Could not get v2 hash rc %d\n", rc);
76638c8a9a5SSteve French 		goto unlock;
76738c8a9a5SSteve French 	}
76838c8a9a5SSteve French 
76938c8a9a5SSteve French 	/* calculate first part of the client response (CR1) */
77038c8a9a5SSteve French 	rc = CalcNTLMv2_response(ses, ntlmv2_hash);
77138c8a9a5SSteve French 	if (rc) {
77238c8a9a5SSteve French 		cifs_dbg(VFS, "Could not calculate CR1 rc: %d\n", rc);
77338c8a9a5SSteve French 		goto unlock;
77438c8a9a5SSteve French 	}
77538c8a9a5SSteve French 
77638c8a9a5SSteve French 	/* now calculate the session key for NTLMv2 */
77738c8a9a5SSteve French 	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm,
77838c8a9a5SSteve French 		ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
77938c8a9a5SSteve French 	if (rc) {
78038c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
78138c8a9a5SSteve French 			 __func__);
78238c8a9a5SSteve French 		goto unlock;
78338c8a9a5SSteve French 	}
78438c8a9a5SSteve French 
78538c8a9a5SSteve French 	rc = crypto_shash_init(ses->server->secmech.hmacmd5);
78638c8a9a5SSteve French 	if (rc) {
78738c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
78838c8a9a5SSteve French 		goto unlock;
78938c8a9a5SSteve French 	}
79038c8a9a5SSteve French 
79138c8a9a5SSteve French 	rc = crypto_shash_update(ses->server->secmech.hmacmd5,
79238c8a9a5SSteve French 		ntlmv2->ntlmv2_hash,
79338c8a9a5SSteve French 		CIFS_HMAC_MD5_HASH_SIZE);
79438c8a9a5SSteve French 	if (rc) {
79538c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
79638c8a9a5SSteve French 		goto unlock;
79738c8a9a5SSteve French 	}
79838c8a9a5SSteve French 
79938c8a9a5SSteve French 	rc = crypto_shash_final(ses->server->secmech.hmacmd5,
80038c8a9a5SSteve French 		ses->auth_key.response);
80138c8a9a5SSteve French 	if (rc)
80238c8a9a5SSteve French 		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
80338c8a9a5SSteve French 
80438c8a9a5SSteve French unlock:
80538c8a9a5SSteve French 	cifs_server_unlock(ses->server);
80638c8a9a5SSteve French setup_ntlmv2_rsp_ret:
80738c8a9a5SSteve French 	kfree_sensitive(tiblob);
80838c8a9a5SSteve French 
80938c8a9a5SSteve French 	return rc;
81038c8a9a5SSteve French }
81138c8a9a5SSteve French 
81238c8a9a5SSteve French int
calc_seckey(struct cifs_ses * ses)81338c8a9a5SSteve French calc_seckey(struct cifs_ses *ses)
81438c8a9a5SSteve French {
81538c8a9a5SSteve French 	unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */
81638c8a9a5SSteve French 	struct arc4_ctx *ctx_arc4;
81738c8a9a5SSteve French 
81838c8a9a5SSteve French 	if (fips_enabled)
81938c8a9a5SSteve French 		return -ENODEV;
82038c8a9a5SSteve French 
82138c8a9a5SSteve French 	get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE);
82238c8a9a5SSteve French 
82338c8a9a5SSteve French 	ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL);
82438c8a9a5SSteve French 	if (!ctx_arc4) {
82538c8a9a5SSteve French 		cifs_dbg(VFS, "Could not allocate arc4 context\n");
82638c8a9a5SSteve French 		return -ENOMEM;
82738c8a9a5SSteve French 	}
82838c8a9a5SSteve French 
82938c8a9a5SSteve French 	cifs_arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE);
83038c8a9a5SSteve French 	cifs_arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key,
83138c8a9a5SSteve French 			CIFS_CPHTXT_SIZE);
83238c8a9a5SSteve French 
83338c8a9a5SSteve French 	/* make secondary_key/nonce as session key */
83438c8a9a5SSteve French 	memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE);
83538c8a9a5SSteve French 	/* and make len as that of session key only */
83638c8a9a5SSteve French 	ses->auth_key.len = CIFS_SESS_KEY_SIZE;
83738c8a9a5SSteve French 
83838c8a9a5SSteve French 	memzero_explicit(sec_key, CIFS_SESS_KEY_SIZE);
83938c8a9a5SSteve French 	kfree_sensitive(ctx_arc4);
84038c8a9a5SSteve French 	return 0;
84138c8a9a5SSteve French }
84238c8a9a5SSteve French 
84338c8a9a5SSteve French void
cifs_crypto_secmech_release(struct TCP_Server_Info * server)84438c8a9a5SSteve French cifs_crypto_secmech_release(struct TCP_Server_Info *server)
84538c8a9a5SSteve French {
84638c8a9a5SSteve French 	cifs_free_hash(&server->secmech.aes_cmac);
84738c8a9a5SSteve French 	cifs_free_hash(&server->secmech.hmacsha256);
84838c8a9a5SSteve French 	cifs_free_hash(&server->secmech.md5);
84938c8a9a5SSteve French 	cifs_free_hash(&server->secmech.sha512);
85038c8a9a5SSteve French 	cifs_free_hash(&server->secmech.hmacmd5);
85138c8a9a5SSteve French 
85238c8a9a5SSteve French 	if (server->secmech.enc) {
85338c8a9a5SSteve French 		crypto_free_aead(server->secmech.enc);
85438c8a9a5SSteve French 		server->secmech.enc = NULL;
85538c8a9a5SSteve French 	}
85638c8a9a5SSteve French 
85738c8a9a5SSteve French 	if (server->secmech.dec) {
85838c8a9a5SSteve French 		crypto_free_aead(server->secmech.dec);
85938c8a9a5SSteve French 		server->secmech.dec = NULL;
86038c8a9a5SSteve French 	}
86138c8a9a5SSteve French }
862