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));
132*b9d510e0SDavid Howells ret = crypto_shash_update(shash, p + offset, 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 {
5758fbefa7aSKees 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