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