162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2002, 2011 562306a36Sopenharmony_ci * Etersoft, 2012 662306a36Sopenharmony_ci * Author(s): Steve French (sfrench@us.ibm.com) 762306a36Sopenharmony_ci * Jeremy Allison (jra@samba.org) 2006 862306a36Sopenharmony_ci * Pavel Shilovsky (pshilovsky@samba.org) 2012 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/fs.h> 1362306a36Sopenharmony_ci#include <linux/list.h> 1462306a36Sopenharmony_ci#include <linux/wait.h> 1562306a36Sopenharmony_ci#include <linux/net.h> 1662306a36Sopenharmony_ci#include <linux/delay.h> 1762306a36Sopenharmony_ci#include <linux/uaccess.h> 1862306a36Sopenharmony_ci#include <asm/processor.h> 1962306a36Sopenharmony_ci#include <linux/mempool.h> 2062306a36Sopenharmony_ci#include <linux/highmem.h> 2162306a36Sopenharmony_ci#include <crypto/aead.h> 2262306a36Sopenharmony_ci#include "cifsglob.h" 2362306a36Sopenharmony_ci#include "cifsproto.h" 2462306a36Sopenharmony_ci#include "smb2proto.h" 2562306a36Sopenharmony_ci#include "cifs_debug.h" 2662306a36Sopenharmony_ci#include "smb2status.h" 2762306a36Sopenharmony_ci#include "smb2glob.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic int 3062306a36Sopenharmony_cismb3_crypto_shash_allocate(struct TCP_Server_Info *server) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct cifs_secmech *p = &server->secmech; 3362306a36Sopenharmony_ci int rc; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci rc = cifs_alloc_hash("hmac(sha256)", &p->hmacsha256); 3662306a36Sopenharmony_ci if (rc) 3762306a36Sopenharmony_ci goto err; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci rc = cifs_alloc_hash("cmac(aes)", &p->aes_cmac); 4062306a36Sopenharmony_ci if (rc) 4162306a36Sopenharmony_ci goto err; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci return 0; 4462306a36Sopenharmony_cierr: 4562306a36Sopenharmony_ci cifs_free_hash(&p->hmacsha256); 4662306a36Sopenharmony_ci return rc; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ciint 5062306a36Sopenharmony_cismb311_crypto_shash_allocate(struct TCP_Server_Info *server) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct cifs_secmech *p = &server->secmech; 5362306a36Sopenharmony_ci int rc = 0; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci rc = cifs_alloc_hash("hmac(sha256)", &p->hmacsha256); 5662306a36Sopenharmony_ci if (rc) 5762306a36Sopenharmony_ci return rc; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci rc = cifs_alloc_hash("cmac(aes)", &p->aes_cmac); 6062306a36Sopenharmony_ci if (rc) 6162306a36Sopenharmony_ci goto err; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci rc = cifs_alloc_hash("sha512", &p->sha512); 6462306a36Sopenharmony_ci if (rc) 6562306a36Sopenharmony_ci goto err; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return 0; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cierr: 7062306a36Sopenharmony_ci cifs_free_hash(&p->aes_cmac); 7162306a36Sopenharmony_ci cifs_free_hash(&p->hmacsha256); 7262306a36Sopenharmony_ci return rc; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic 7762306a36Sopenharmony_ciint smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct cifs_chan *chan; 8062306a36Sopenharmony_ci struct TCP_Server_Info *pserver; 8162306a36Sopenharmony_ci struct cifs_ses *ses = NULL; 8262306a36Sopenharmony_ci int i; 8362306a36Sopenharmony_ci int rc = 0; 8462306a36Sopenharmony_ci bool is_binding = false; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci spin_lock(&cifs_tcp_ses_lock); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* If server is a channel, select the primary channel */ 8962306a36Sopenharmony_ci pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 9262306a36Sopenharmony_ci if (ses->Suid == ses_id) 9362306a36Sopenharmony_ci goto found; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci trace_smb3_ses_not_found(ses_id); 9662306a36Sopenharmony_ci cifs_server_dbg(FYI, "%s: Could not find session 0x%llx\n", 9762306a36Sopenharmony_ci __func__, ses_id); 9862306a36Sopenharmony_ci rc = -ENOENT; 9962306a36Sopenharmony_ci goto out; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cifound: 10262306a36Sopenharmony_ci spin_lock(&ses->ses_lock); 10362306a36Sopenharmony_ci spin_lock(&ses->chan_lock); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci is_binding = (cifs_chan_needs_reconnect(ses, server) && 10662306a36Sopenharmony_ci ses->ses_status == SES_GOOD); 10762306a36Sopenharmony_ci if (is_binding) { 10862306a36Sopenharmony_ci /* 10962306a36Sopenharmony_ci * If we are in the process of binding a new channel 11062306a36Sopenharmony_ci * to an existing session, use the master connection 11162306a36Sopenharmony_ci * session key 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci memcpy(key, ses->smb3signingkey, SMB3_SIGN_KEY_SIZE); 11462306a36Sopenharmony_ci spin_unlock(&ses->chan_lock); 11562306a36Sopenharmony_ci spin_unlock(&ses->ses_lock); 11662306a36Sopenharmony_ci goto out; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* 12062306a36Sopenharmony_ci * Otherwise, use the channel key. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci for (i = 0; i < ses->chan_count; i++) { 12462306a36Sopenharmony_ci chan = ses->chans + i; 12562306a36Sopenharmony_ci if (chan->server == server) { 12662306a36Sopenharmony_ci memcpy(key, chan->signkey, SMB3_SIGN_KEY_SIZE); 12762306a36Sopenharmony_ci spin_unlock(&ses->chan_lock); 12862306a36Sopenharmony_ci spin_unlock(&ses->ses_lock); 12962306a36Sopenharmony_ci goto out; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci spin_unlock(&ses->chan_lock); 13362306a36Sopenharmony_ci spin_unlock(&ses->ses_lock); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci cifs_dbg(VFS, 13662306a36Sopenharmony_ci "%s: Could not find channel signing key for session 0x%llx\n", 13762306a36Sopenharmony_ci __func__, ses_id); 13862306a36Sopenharmony_ci rc = -ENOENT; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ciout: 14162306a36Sopenharmony_ci spin_unlock(&cifs_tcp_ses_lock); 14262306a36Sopenharmony_ci return rc; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic struct cifs_ses * 14662306a36Sopenharmony_cismb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct TCP_Server_Info *pserver; 14962306a36Sopenharmony_ci struct cifs_ses *ses; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* If server is a channel, select the primary channel */ 15262306a36Sopenharmony_ci pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 15562306a36Sopenharmony_ci if (ses->Suid != ses_id) 15662306a36Sopenharmony_ci continue; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci spin_lock(&ses->ses_lock); 15962306a36Sopenharmony_ci if (ses->ses_status == SES_EXITING) { 16062306a36Sopenharmony_ci spin_unlock(&ses->ses_lock); 16162306a36Sopenharmony_ci continue; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci cifs_smb_ses_inc_refcount(ses); 16462306a36Sopenharmony_ci spin_unlock(&ses->ses_lock); 16562306a36Sopenharmony_ci return ses; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return NULL; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistruct cifs_ses * 17262306a36Sopenharmony_cismb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct cifs_ses *ses; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci spin_lock(&cifs_tcp_ses_lock); 17762306a36Sopenharmony_ci ses = smb2_find_smb_ses_unlocked(server, ses_id); 17862306a36Sopenharmony_ci spin_unlock(&cifs_tcp_ses_lock); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return ses; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic struct cifs_tcon * 18462306a36Sopenharmony_cismb2_find_smb_sess_tcon_unlocked(struct cifs_ses *ses, __u32 tid) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct cifs_tcon *tcon; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 18962306a36Sopenharmony_ci if (tcon->tid != tid) 19062306a36Sopenharmony_ci continue; 19162306a36Sopenharmony_ci ++tcon->tc_count; 19262306a36Sopenharmony_ci return tcon; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return NULL; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci/* 19962306a36Sopenharmony_ci * Obtain tcon corresponding to the tid in the given 20062306a36Sopenharmony_ci * cifs_ses 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistruct cifs_tcon * 20462306a36Sopenharmony_cismb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct cifs_ses *ses; 20762306a36Sopenharmony_ci struct cifs_tcon *tcon; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci spin_lock(&cifs_tcp_ses_lock); 21062306a36Sopenharmony_ci ses = smb2_find_smb_ses_unlocked(server, ses_id); 21162306a36Sopenharmony_ci if (!ses) { 21262306a36Sopenharmony_ci spin_unlock(&cifs_tcp_ses_lock); 21362306a36Sopenharmony_ci return NULL; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid); 21662306a36Sopenharmony_ci if (!tcon) { 21762306a36Sopenharmony_ci cifs_put_smb_ses(ses); 21862306a36Sopenharmony_ci spin_unlock(&cifs_tcp_ses_lock); 21962306a36Sopenharmony_ci return NULL; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci spin_unlock(&cifs_tcp_ses_lock); 22262306a36Sopenharmony_ci /* tcon already has a ref to ses, so we don't need ses anymore */ 22362306a36Sopenharmony_ci cifs_put_smb_ses(ses); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return tcon; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ciint 22962306a36Sopenharmony_cismb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, 23062306a36Sopenharmony_ci bool allocate_crypto) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci int rc; 23362306a36Sopenharmony_ci unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; 23462306a36Sopenharmony_ci unsigned char *sigptr = smb2_signature; 23562306a36Sopenharmony_ci struct kvec *iov = rqst->rq_iov; 23662306a36Sopenharmony_ci struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base; 23762306a36Sopenharmony_ci struct cifs_ses *ses; 23862306a36Sopenharmony_ci struct shash_desc *shash = NULL; 23962306a36Sopenharmony_ci struct smb_rqst drqst; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci ses = smb2_find_smb_ses(server, le64_to_cpu(shdr->SessionId)); 24262306a36Sopenharmony_ci if (unlikely(!ses)) { 24362306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Could not find session\n", __func__); 24462306a36Sopenharmony_ci return -ENOENT; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE); 24862306a36Sopenharmony_ci memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (allocate_crypto) { 25162306a36Sopenharmony_ci rc = cifs_alloc_hash("hmac(sha256)", &shash); 25262306a36Sopenharmony_ci if (rc) { 25362306a36Sopenharmony_ci cifs_server_dbg(VFS, 25462306a36Sopenharmony_ci "%s: sha256 alloc failed\n", __func__); 25562306a36Sopenharmony_ci goto out; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci } else { 25862306a36Sopenharmony_ci shash = server->secmech.hmacsha256; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci rc = crypto_shash_setkey(shash->tfm, ses->auth_key.response, 26262306a36Sopenharmony_ci SMB2_NTLMV2_SESSKEY_SIZE); 26362306a36Sopenharmony_ci if (rc) { 26462306a36Sopenharmony_ci cifs_server_dbg(VFS, 26562306a36Sopenharmony_ci "%s: Could not update with response\n", 26662306a36Sopenharmony_ci __func__); 26762306a36Sopenharmony_ci goto out; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci rc = crypto_shash_init(shash); 27162306a36Sopenharmony_ci if (rc) { 27262306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Could not init sha256", __func__); 27362306a36Sopenharmony_ci goto out; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* 27762306a36Sopenharmony_ci * For SMB2+, __cifs_calc_signature() expects to sign only the actual 27862306a36Sopenharmony_ci * data, that is, iov[0] should not contain a rfc1002 length. 27962306a36Sopenharmony_ci * 28062306a36Sopenharmony_ci * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to 28162306a36Sopenharmony_ci * __cifs_calc_signature(). 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_ci drqst = *rqst; 28462306a36Sopenharmony_ci if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) { 28562306a36Sopenharmony_ci rc = crypto_shash_update(shash, iov[0].iov_base, 28662306a36Sopenharmony_ci iov[0].iov_len); 28762306a36Sopenharmony_ci if (rc) { 28862306a36Sopenharmony_ci cifs_server_dbg(VFS, 28962306a36Sopenharmony_ci "%s: Could not update with payload\n", 29062306a36Sopenharmony_ci __func__); 29162306a36Sopenharmony_ci goto out; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci drqst.rq_iov++; 29462306a36Sopenharmony_ci drqst.rq_nvec--; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci rc = __cifs_calc_signature(&drqst, server, sigptr, shash); 29862306a36Sopenharmony_ci if (!rc) 29962306a36Sopenharmony_ci memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ciout: 30262306a36Sopenharmony_ci if (allocate_crypto) 30362306a36Sopenharmony_ci cifs_free_hash(&shash); 30462306a36Sopenharmony_ci if (ses) 30562306a36Sopenharmony_ci cifs_put_smb_ses(ses); 30662306a36Sopenharmony_ci return rc; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic int generate_key(struct cifs_ses *ses, struct kvec label, 31062306a36Sopenharmony_ci struct kvec context, __u8 *key, unsigned int key_size) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci unsigned char zero = 0x0; 31362306a36Sopenharmony_ci __u8 i[4] = {0, 0, 0, 1}; 31462306a36Sopenharmony_ci __u8 L128[4] = {0, 0, 0, 128}; 31562306a36Sopenharmony_ci __u8 L256[4] = {0, 0, 1, 0}; 31662306a36Sopenharmony_ci int rc = 0; 31762306a36Sopenharmony_ci unsigned char prfhash[SMB2_HMACSHA256_SIZE]; 31862306a36Sopenharmony_ci unsigned char *hashptr = prfhash; 31962306a36Sopenharmony_ci struct TCP_Server_Info *server = ses->server; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); 32262306a36Sopenharmony_ci memset(key, 0x0, key_size); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci rc = smb3_crypto_shash_allocate(server); 32562306a36Sopenharmony_ci if (rc) { 32662306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__); 32762306a36Sopenharmony_ci goto smb3signkey_ret; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci rc = crypto_shash_setkey(server->secmech.hmacsha256->tfm, 33162306a36Sopenharmony_ci ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); 33262306a36Sopenharmony_ci if (rc) { 33362306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Could not set with session key\n", __func__); 33462306a36Sopenharmony_ci goto smb3signkey_ret; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci rc = crypto_shash_init(server->secmech.hmacsha256); 33862306a36Sopenharmony_ci if (rc) { 33962306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Could not init sign hmac\n", __func__); 34062306a36Sopenharmony_ci goto smb3signkey_ret; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci rc = crypto_shash_update(server->secmech.hmacsha256, i, 4); 34462306a36Sopenharmony_ci if (rc) { 34562306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Could not update with n\n", __func__); 34662306a36Sopenharmony_ci goto smb3signkey_ret; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci rc = crypto_shash_update(server->secmech.hmacsha256, label.iov_base, label.iov_len); 35062306a36Sopenharmony_ci if (rc) { 35162306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Could not update with label\n", __func__); 35262306a36Sopenharmony_ci goto smb3signkey_ret; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci rc = crypto_shash_update(server->secmech.hmacsha256, &zero, 1); 35662306a36Sopenharmony_ci if (rc) { 35762306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Could not update with zero\n", __func__); 35862306a36Sopenharmony_ci goto smb3signkey_ret; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci rc = crypto_shash_update(server->secmech.hmacsha256, context.iov_base, context.iov_len); 36262306a36Sopenharmony_ci if (rc) { 36362306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Could not update with context\n", __func__); 36462306a36Sopenharmony_ci goto smb3signkey_ret; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) || 36862306a36Sopenharmony_ci (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) { 36962306a36Sopenharmony_ci rc = crypto_shash_update(server->secmech.hmacsha256, L256, 4); 37062306a36Sopenharmony_ci } else { 37162306a36Sopenharmony_ci rc = crypto_shash_update(server->secmech.hmacsha256, L128, 4); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci if (rc) { 37462306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Could not update with L\n", __func__); 37562306a36Sopenharmony_ci goto smb3signkey_ret; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci rc = crypto_shash_final(server->secmech.hmacsha256, hashptr); 37962306a36Sopenharmony_ci if (rc) { 38062306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); 38162306a36Sopenharmony_ci goto smb3signkey_ret; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci memcpy(key, hashptr, key_size); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cismb3signkey_ret: 38762306a36Sopenharmony_ci return rc; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistruct derivation { 39162306a36Sopenharmony_ci struct kvec label; 39262306a36Sopenharmony_ci struct kvec context; 39362306a36Sopenharmony_ci}; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistruct derivation_triplet { 39662306a36Sopenharmony_ci struct derivation signing; 39762306a36Sopenharmony_ci struct derivation encryption; 39862306a36Sopenharmony_ci struct derivation decryption; 39962306a36Sopenharmony_ci}; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic int 40262306a36Sopenharmony_cigenerate_smb3signingkey(struct cifs_ses *ses, 40362306a36Sopenharmony_ci struct TCP_Server_Info *server, 40462306a36Sopenharmony_ci const struct derivation_triplet *ptriplet) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci int rc; 40762306a36Sopenharmony_ci bool is_binding = false; 40862306a36Sopenharmony_ci int chan_index = 0; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci spin_lock(&ses->ses_lock); 41162306a36Sopenharmony_ci spin_lock(&ses->chan_lock); 41262306a36Sopenharmony_ci is_binding = (cifs_chan_needs_reconnect(ses, server) && 41362306a36Sopenharmony_ci ses->ses_status == SES_GOOD); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci chan_index = cifs_ses_get_chan_index(ses, server); 41662306a36Sopenharmony_ci if (chan_index == CIFS_INVAL_CHAN_INDEX) { 41762306a36Sopenharmony_ci spin_unlock(&ses->chan_lock); 41862306a36Sopenharmony_ci spin_unlock(&ses->ses_lock); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return -EINVAL; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci spin_unlock(&ses->chan_lock); 42462306a36Sopenharmony_ci spin_unlock(&ses->ses_lock); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* 42762306a36Sopenharmony_ci * All channels use the same encryption/decryption keys but 42862306a36Sopenharmony_ci * they have their own signing key. 42962306a36Sopenharmony_ci * 43062306a36Sopenharmony_ci * When we generate the keys, check if it is for a new channel 43162306a36Sopenharmony_ci * (binding) in which case we only need to generate a signing 43262306a36Sopenharmony_ci * key and store it in the channel as to not overwrite the 43362306a36Sopenharmony_ci * master connection signing key stored in the session 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (is_binding) { 43762306a36Sopenharmony_ci rc = generate_key(ses, ptriplet->signing.label, 43862306a36Sopenharmony_ci ptriplet->signing.context, 43962306a36Sopenharmony_ci ses->chans[chan_index].signkey, 44062306a36Sopenharmony_ci SMB3_SIGN_KEY_SIZE); 44162306a36Sopenharmony_ci if (rc) 44262306a36Sopenharmony_ci return rc; 44362306a36Sopenharmony_ci } else { 44462306a36Sopenharmony_ci rc = generate_key(ses, ptriplet->signing.label, 44562306a36Sopenharmony_ci ptriplet->signing.context, 44662306a36Sopenharmony_ci ses->smb3signingkey, 44762306a36Sopenharmony_ci SMB3_SIGN_KEY_SIZE); 44862306a36Sopenharmony_ci if (rc) 44962306a36Sopenharmony_ci return rc; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* safe to access primary channel, since it will never go away */ 45262306a36Sopenharmony_ci spin_lock(&ses->chan_lock); 45362306a36Sopenharmony_ci memcpy(ses->chans[chan_index].signkey, ses->smb3signingkey, 45462306a36Sopenharmony_ci SMB3_SIGN_KEY_SIZE); 45562306a36Sopenharmony_ci spin_unlock(&ses->chan_lock); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci rc = generate_key(ses, ptriplet->encryption.label, 45862306a36Sopenharmony_ci ptriplet->encryption.context, 45962306a36Sopenharmony_ci ses->smb3encryptionkey, 46062306a36Sopenharmony_ci SMB3_ENC_DEC_KEY_SIZE); 46162306a36Sopenharmony_ci if (rc) 46262306a36Sopenharmony_ci return rc; 46362306a36Sopenharmony_ci rc = generate_key(ses, ptriplet->decryption.label, 46462306a36Sopenharmony_ci ptriplet->decryption.context, 46562306a36Sopenharmony_ci ses->smb3decryptionkey, 46662306a36Sopenharmony_ci SMB3_ENC_DEC_KEY_SIZE); 46762306a36Sopenharmony_ci if (rc) 46862306a36Sopenharmony_ci return rc; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci#ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS 47262306a36Sopenharmony_ci cifs_dbg(VFS, "%s: dumping generated AES session keys\n", __func__); 47362306a36Sopenharmony_ci /* 47462306a36Sopenharmony_ci * The session id is opaque in terms of endianness, so we can't 47562306a36Sopenharmony_ci * print it as a long long. we dump it as we got it on the wire 47662306a36Sopenharmony_ci */ 47762306a36Sopenharmony_ci cifs_dbg(VFS, "Session Id %*ph\n", (int)sizeof(ses->Suid), 47862306a36Sopenharmony_ci &ses->Suid); 47962306a36Sopenharmony_ci cifs_dbg(VFS, "Cipher type %d\n", server->cipher_type); 48062306a36Sopenharmony_ci cifs_dbg(VFS, "Session Key %*ph\n", 48162306a36Sopenharmony_ci SMB2_NTLMV2_SESSKEY_SIZE, ses->auth_key.response); 48262306a36Sopenharmony_ci cifs_dbg(VFS, "Signing Key %*ph\n", 48362306a36Sopenharmony_ci SMB3_SIGN_KEY_SIZE, ses->smb3signingkey); 48462306a36Sopenharmony_ci if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) || 48562306a36Sopenharmony_ci (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) { 48662306a36Sopenharmony_ci cifs_dbg(VFS, "ServerIn Key %*ph\n", 48762306a36Sopenharmony_ci SMB3_GCM256_CRYPTKEY_SIZE, ses->smb3encryptionkey); 48862306a36Sopenharmony_ci cifs_dbg(VFS, "ServerOut Key %*ph\n", 48962306a36Sopenharmony_ci SMB3_GCM256_CRYPTKEY_SIZE, ses->smb3decryptionkey); 49062306a36Sopenharmony_ci } else { 49162306a36Sopenharmony_ci cifs_dbg(VFS, "ServerIn Key %*ph\n", 49262306a36Sopenharmony_ci SMB3_GCM128_CRYPTKEY_SIZE, ses->smb3encryptionkey); 49362306a36Sopenharmony_ci cifs_dbg(VFS, "ServerOut Key %*ph\n", 49462306a36Sopenharmony_ci SMB3_GCM128_CRYPTKEY_SIZE, ses->smb3decryptionkey); 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci#endif 49762306a36Sopenharmony_ci return rc; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ciint 50162306a36Sopenharmony_cigenerate_smb30signingkey(struct cifs_ses *ses, 50262306a36Sopenharmony_ci struct TCP_Server_Info *server) 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci struct derivation_triplet triplet; 50662306a36Sopenharmony_ci struct derivation *d; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci d = &triplet.signing; 50962306a36Sopenharmony_ci d->label.iov_base = "SMB2AESCMAC"; 51062306a36Sopenharmony_ci d->label.iov_len = 12; 51162306a36Sopenharmony_ci d->context.iov_base = "SmbSign"; 51262306a36Sopenharmony_ci d->context.iov_len = 8; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci d = &triplet.encryption; 51562306a36Sopenharmony_ci d->label.iov_base = "SMB2AESCCM"; 51662306a36Sopenharmony_ci d->label.iov_len = 11; 51762306a36Sopenharmony_ci d->context.iov_base = "ServerIn "; 51862306a36Sopenharmony_ci d->context.iov_len = 10; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci d = &triplet.decryption; 52162306a36Sopenharmony_ci d->label.iov_base = "SMB2AESCCM"; 52262306a36Sopenharmony_ci d->label.iov_len = 11; 52362306a36Sopenharmony_ci d->context.iov_base = "ServerOut"; 52462306a36Sopenharmony_ci d->context.iov_len = 10; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci return generate_smb3signingkey(ses, server, &triplet); 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ciint 53062306a36Sopenharmony_cigenerate_smb311signingkey(struct cifs_ses *ses, 53162306a36Sopenharmony_ci struct TCP_Server_Info *server) 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct derivation_triplet triplet; 53562306a36Sopenharmony_ci struct derivation *d; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci d = &triplet.signing; 53862306a36Sopenharmony_ci d->label.iov_base = "SMBSigningKey"; 53962306a36Sopenharmony_ci d->label.iov_len = 14; 54062306a36Sopenharmony_ci d->context.iov_base = ses->preauth_sha_hash; 54162306a36Sopenharmony_ci d->context.iov_len = 64; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci d = &triplet.encryption; 54462306a36Sopenharmony_ci d->label.iov_base = "SMBC2SCipherKey"; 54562306a36Sopenharmony_ci d->label.iov_len = 16; 54662306a36Sopenharmony_ci d->context.iov_base = ses->preauth_sha_hash; 54762306a36Sopenharmony_ci d->context.iov_len = 64; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci d = &triplet.decryption; 55062306a36Sopenharmony_ci d->label.iov_base = "SMBS2CCipherKey"; 55162306a36Sopenharmony_ci d->label.iov_len = 16; 55262306a36Sopenharmony_ci d->context.iov_base = ses->preauth_sha_hash; 55362306a36Sopenharmony_ci d->context.iov_len = 64; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci return generate_smb3signingkey(ses, server, &triplet); 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ciint 55962306a36Sopenharmony_cismb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, 56062306a36Sopenharmony_ci bool allocate_crypto) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci int rc; 56362306a36Sopenharmony_ci unsigned char smb3_signature[SMB2_CMACAES_SIZE]; 56462306a36Sopenharmony_ci unsigned char *sigptr = smb3_signature; 56562306a36Sopenharmony_ci struct kvec *iov = rqst->rq_iov; 56662306a36Sopenharmony_ci struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base; 56762306a36Sopenharmony_ci struct shash_desc *shash = NULL; 56862306a36Sopenharmony_ci struct smb_rqst drqst; 56962306a36Sopenharmony_ci u8 key[SMB3_SIGN_KEY_SIZE]; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci rc = smb2_get_sign_key(le64_to_cpu(shdr->SessionId), server, key); 57262306a36Sopenharmony_ci if (unlikely(rc)) { 57362306a36Sopenharmony_ci cifs_server_dbg(FYI, "%s: Could not get signing key\n", __func__); 57462306a36Sopenharmony_ci return rc; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (allocate_crypto) { 57862306a36Sopenharmony_ci rc = cifs_alloc_hash("cmac(aes)", &shash); 57962306a36Sopenharmony_ci if (rc) 58062306a36Sopenharmony_ci return rc; 58162306a36Sopenharmony_ci } else { 58262306a36Sopenharmony_ci shash = server->secmech.aes_cmac; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE); 58662306a36Sopenharmony_ci memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci rc = crypto_shash_setkey(shash->tfm, key, SMB2_CMACAES_SIZE); 58962306a36Sopenharmony_ci if (rc) { 59062306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__); 59162306a36Sopenharmony_ci goto out; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* 59562306a36Sopenharmony_ci * we already allocate aes_cmac when we init smb3 signing key, 59662306a36Sopenharmony_ci * so unlike smb2 case we do not have to check here if secmech are 59762306a36Sopenharmony_ci * initialized 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_ci rc = crypto_shash_init(shash); 60062306a36Sopenharmony_ci if (rc) { 60162306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Could not init cmac aes\n", __func__); 60262306a36Sopenharmony_ci goto out; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* 60662306a36Sopenharmony_ci * For SMB2+, __cifs_calc_signature() expects to sign only the actual 60762306a36Sopenharmony_ci * data, that is, iov[0] should not contain a rfc1002 length. 60862306a36Sopenharmony_ci * 60962306a36Sopenharmony_ci * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to 61062306a36Sopenharmony_ci * __cifs_calc_signature(). 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_ci drqst = *rqst; 61362306a36Sopenharmony_ci if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) { 61462306a36Sopenharmony_ci rc = crypto_shash_update(shash, iov[0].iov_base, 61562306a36Sopenharmony_ci iov[0].iov_len); 61662306a36Sopenharmony_ci if (rc) { 61762306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Could not update with payload\n", 61862306a36Sopenharmony_ci __func__); 61962306a36Sopenharmony_ci goto out; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci drqst.rq_iov++; 62262306a36Sopenharmony_ci drqst.rq_nvec--; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci rc = __cifs_calc_signature(&drqst, server, sigptr, shash); 62662306a36Sopenharmony_ci if (!rc) 62762306a36Sopenharmony_ci memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ciout: 63062306a36Sopenharmony_ci if (allocate_crypto) 63162306a36Sopenharmony_ci cifs_free_hash(&shash); 63262306a36Sopenharmony_ci return rc; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci/* must be called with server->srv_mutex held */ 63662306a36Sopenharmony_cistatic int 63762306a36Sopenharmony_cismb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci int rc = 0; 64062306a36Sopenharmony_ci struct smb2_hdr *shdr; 64162306a36Sopenharmony_ci struct smb2_sess_setup_req *ssr; 64262306a36Sopenharmony_ci bool is_binding; 64362306a36Sopenharmony_ci bool is_signed; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci shdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base; 64662306a36Sopenharmony_ci ssr = (struct smb2_sess_setup_req *)shdr; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci is_binding = shdr->Command == SMB2_SESSION_SETUP && 64962306a36Sopenharmony_ci (ssr->Flags & SMB2_SESSION_REQ_FLAG_BINDING); 65062306a36Sopenharmony_ci is_signed = shdr->Flags & SMB2_FLAGS_SIGNED; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (!is_signed) 65362306a36Sopenharmony_ci return 0; 65462306a36Sopenharmony_ci spin_lock(&server->srv_lock); 65562306a36Sopenharmony_ci if (server->ops->need_neg && 65662306a36Sopenharmony_ci server->ops->need_neg(server)) { 65762306a36Sopenharmony_ci spin_unlock(&server->srv_lock); 65862306a36Sopenharmony_ci return 0; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci spin_unlock(&server->srv_lock); 66162306a36Sopenharmony_ci if (!is_binding && !server->session_estab) { 66262306a36Sopenharmony_ci strncpy(shdr->Signature, "BSRSPYL", 8); 66362306a36Sopenharmony_ci return 0; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci rc = server->ops->calc_signature(rqst, server, false); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci return rc; 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ciint 67262306a36Sopenharmony_cismb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci unsigned int rc; 67562306a36Sopenharmony_ci char server_response_sig[SMB2_SIGNATURE_SIZE]; 67662306a36Sopenharmony_ci struct smb2_hdr *shdr = 67762306a36Sopenharmony_ci (struct smb2_hdr *)rqst->rq_iov[0].iov_base; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if ((shdr->Command == SMB2_NEGOTIATE) || 68062306a36Sopenharmony_ci (shdr->Command == SMB2_SESSION_SETUP) || 68162306a36Sopenharmony_ci (shdr->Command == SMB2_OPLOCK_BREAK) || 68262306a36Sopenharmony_ci server->ignore_signature || 68362306a36Sopenharmony_ci (!server->session_estab)) 68462306a36Sopenharmony_ci return 0; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* 68762306a36Sopenharmony_ci * BB what if signatures are supposed to be on for session but 68862306a36Sopenharmony_ci * server does not send one? BB 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci /* Do not need to verify session setups with signature "BSRSPYL " */ 69262306a36Sopenharmony_ci if (memcmp(shdr->Signature, "BSRSPYL ", 8) == 0) 69362306a36Sopenharmony_ci cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n", 69462306a36Sopenharmony_ci shdr->Command); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* 69762306a36Sopenharmony_ci * Save off the origiginal signature so we can modify the smb and check 69862306a36Sopenharmony_ci * our calculated signature against what the server sent. 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_ci memcpy(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci rc = server->ops->calc_signature(rqst, server, true); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (rc) 70762306a36Sopenharmony_ci return rc; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (memcmp(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE)) { 71062306a36Sopenharmony_ci cifs_dbg(VFS, "sign fail cmd 0x%x message id 0x%llx\n", 71162306a36Sopenharmony_ci shdr->Command, shdr->MessageId); 71262306a36Sopenharmony_ci return -EACCES; 71362306a36Sopenharmony_ci } else 71462306a36Sopenharmony_ci return 0; 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci/* 71862306a36Sopenharmony_ci * Set message id for the request. Should be called after wait_for_free_request 71962306a36Sopenharmony_ci * and when srv_mutex is held. 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_cistatic inline void 72262306a36Sopenharmony_cismb2_seq_num_into_buf(struct TCP_Server_Info *server, 72362306a36Sopenharmony_ci struct smb2_hdr *shdr) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci unsigned int i, num = le16_to_cpu(shdr->CreditCharge); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci shdr->MessageId = get_next_mid64(server); 72862306a36Sopenharmony_ci /* skip message numbers according to CreditCharge field */ 72962306a36Sopenharmony_ci for (i = 1; i < num; i++) 73062306a36Sopenharmony_ci get_next_mid(server); 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic struct mid_q_entry * 73462306a36Sopenharmony_cismb2_mid_entry_alloc(const struct smb2_hdr *shdr, 73562306a36Sopenharmony_ci struct TCP_Server_Info *server) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci struct mid_q_entry *temp; 73862306a36Sopenharmony_ci unsigned int credits = le16_to_cpu(shdr->CreditCharge); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (server == NULL) { 74162306a36Sopenharmony_ci cifs_dbg(VFS, "Null TCP session in smb2_mid_entry_alloc\n"); 74262306a36Sopenharmony_ci return NULL; 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS); 74662306a36Sopenharmony_ci memset(temp, 0, sizeof(struct mid_q_entry)); 74762306a36Sopenharmony_ci kref_init(&temp->refcount); 74862306a36Sopenharmony_ci temp->mid = le64_to_cpu(shdr->MessageId); 74962306a36Sopenharmony_ci temp->credits = credits > 0 ? credits : 1; 75062306a36Sopenharmony_ci temp->pid = current->pid; 75162306a36Sopenharmony_ci temp->command = shdr->Command; /* Always LE */ 75262306a36Sopenharmony_ci temp->when_alloc = jiffies; 75362306a36Sopenharmony_ci temp->server = server; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* 75662306a36Sopenharmony_ci * The default is for the mid to be synchronous, so the 75762306a36Sopenharmony_ci * default callback just wakes up the current task. 75862306a36Sopenharmony_ci */ 75962306a36Sopenharmony_ci get_task_struct(current); 76062306a36Sopenharmony_ci temp->creator = current; 76162306a36Sopenharmony_ci temp->callback = cifs_wake_up_task; 76262306a36Sopenharmony_ci temp->callback_data = current; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci atomic_inc(&mid_count); 76562306a36Sopenharmony_ci temp->mid_state = MID_REQUEST_ALLOCATED; 76662306a36Sopenharmony_ci trace_smb3_cmd_enter(le32_to_cpu(shdr->Id.SyncId.TreeId), 76762306a36Sopenharmony_ci le64_to_cpu(shdr->SessionId), 76862306a36Sopenharmony_ci le16_to_cpu(shdr->Command), temp->mid); 76962306a36Sopenharmony_ci return temp; 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic int 77362306a36Sopenharmony_cismb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server, 77462306a36Sopenharmony_ci struct smb2_hdr *shdr, struct mid_q_entry **mid) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci spin_lock(&server->srv_lock); 77762306a36Sopenharmony_ci if (server->tcpStatus == CifsExiting) { 77862306a36Sopenharmony_ci spin_unlock(&server->srv_lock); 77962306a36Sopenharmony_ci return -ENOENT; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (server->tcpStatus == CifsNeedReconnect) { 78362306a36Sopenharmony_ci spin_unlock(&server->srv_lock); 78462306a36Sopenharmony_ci cifs_dbg(FYI, "tcp session dead - return to caller to retry\n"); 78562306a36Sopenharmony_ci return -EAGAIN; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (server->tcpStatus == CifsNeedNegotiate && 78962306a36Sopenharmony_ci shdr->Command != SMB2_NEGOTIATE) { 79062306a36Sopenharmony_ci spin_unlock(&server->srv_lock); 79162306a36Sopenharmony_ci return -EAGAIN; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci spin_unlock(&server->srv_lock); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci spin_lock(&ses->ses_lock); 79662306a36Sopenharmony_ci if (ses->ses_status == SES_NEW) { 79762306a36Sopenharmony_ci if ((shdr->Command != SMB2_SESSION_SETUP) && 79862306a36Sopenharmony_ci (shdr->Command != SMB2_NEGOTIATE)) { 79962306a36Sopenharmony_ci spin_unlock(&ses->ses_lock); 80062306a36Sopenharmony_ci return -EAGAIN; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci /* else ok - we are setting up session */ 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (ses->ses_status == SES_EXITING) { 80662306a36Sopenharmony_ci if (shdr->Command != SMB2_LOGOFF) { 80762306a36Sopenharmony_ci spin_unlock(&ses->ses_lock); 80862306a36Sopenharmony_ci return -EAGAIN; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci /* else ok - we are shutting down the session */ 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci spin_unlock(&ses->ses_lock); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci *mid = smb2_mid_entry_alloc(shdr, server); 81562306a36Sopenharmony_ci if (*mid == NULL) 81662306a36Sopenharmony_ci return -ENOMEM; 81762306a36Sopenharmony_ci spin_lock(&server->mid_lock); 81862306a36Sopenharmony_ci list_add_tail(&(*mid)->qhead, &server->pending_mid_q); 81962306a36Sopenharmony_ci spin_unlock(&server->mid_lock); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci return 0; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ciint 82562306a36Sopenharmony_cismb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, 82662306a36Sopenharmony_ci bool log_error) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci unsigned int len = mid->resp_buf_size; 82962306a36Sopenharmony_ci struct kvec iov[1]; 83062306a36Sopenharmony_ci struct smb_rqst rqst = { .rq_iov = iov, 83162306a36Sopenharmony_ci .rq_nvec = 1 }; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci iov[0].iov_base = (char *)mid->resp_buf; 83462306a36Sopenharmony_ci iov[0].iov_len = len; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci dump_smb(mid->resp_buf, min_t(u32, 80, len)); 83762306a36Sopenharmony_ci /* convert the length into a more usable form */ 83862306a36Sopenharmony_ci if (len > 24 && server->sign && !mid->decrypted) { 83962306a36Sopenharmony_ci int rc; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci rc = smb2_verify_signature(&rqst, server); 84262306a36Sopenharmony_ci if (rc) 84362306a36Sopenharmony_ci cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n", 84462306a36Sopenharmony_ci rc); 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci return map_smb2_to_linux_error(mid->resp_buf, log_error); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistruct mid_q_entry * 85162306a36Sopenharmony_cismb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server, 85262306a36Sopenharmony_ci struct smb_rqst *rqst) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci int rc; 85562306a36Sopenharmony_ci struct smb2_hdr *shdr = 85662306a36Sopenharmony_ci (struct smb2_hdr *)rqst->rq_iov[0].iov_base; 85762306a36Sopenharmony_ci struct mid_q_entry *mid; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci smb2_seq_num_into_buf(server, shdr); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci rc = smb2_get_mid_entry(ses, server, shdr, &mid); 86262306a36Sopenharmony_ci if (rc) { 86362306a36Sopenharmony_ci revert_current_mid_from_hdr(server, shdr); 86462306a36Sopenharmony_ci return ERR_PTR(rc); 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci rc = smb2_sign_rqst(rqst, server); 86862306a36Sopenharmony_ci if (rc) { 86962306a36Sopenharmony_ci revert_current_mid_from_hdr(server, shdr); 87062306a36Sopenharmony_ci delete_mid(mid); 87162306a36Sopenharmony_ci return ERR_PTR(rc); 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci return mid; 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_cistruct mid_q_entry * 87862306a36Sopenharmony_cismb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci int rc; 88162306a36Sopenharmony_ci struct smb2_hdr *shdr = 88262306a36Sopenharmony_ci (struct smb2_hdr *)rqst->rq_iov[0].iov_base; 88362306a36Sopenharmony_ci struct mid_q_entry *mid; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci spin_lock(&server->srv_lock); 88662306a36Sopenharmony_ci if (server->tcpStatus == CifsNeedNegotiate && 88762306a36Sopenharmony_ci shdr->Command != SMB2_NEGOTIATE) { 88862306a36Sopenharmony_ci spin_unlock(&server->srv_lock); 88962306a36Sopenharmony_ci return ERR_PTR(-EAGAIN); 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci spin_unlock(&server->srv_lock); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci smb2_seq_num_into_buf(server, shdr); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci mid = smb2_mid_entry_alloc(shdr, server); 89662306a36Sopenharmony_ci if (mid == NULL) { 89762306a36Sopenharmony_ci revert_current_mid_from_hdr(server, shdr); 89862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci rc = smb2_sign_rqst(rqst, server); 90262306a36Sopenharmony_ci if (rc) { 90362306a36Sopenharmony_ci revert_current_mid_from_hdr(server, shdr); 90462306a36Sopenharmony_ci release_mid(mid); 90562306a36Sopenharmony_ci return ERR_PTR(rc); 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci return mid; 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ciint 91262306a36Sopenharmony_cismb3_crypto_aead_allocate(struct TCP_Server_Info *server) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci struct crypto_aead *tfm; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (!server->secmech.enc) { 91762306a36Sopenharmony_ci if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) || 91862306a36Sopenharmony_ci (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) 91962306a36Sopenharmony_ci tfm = crypto_alloc_aead("gcm(aes)", 0, 0); 92062306a36Sopenharmony_ci else 92162306a36Sopenharmony_ci tfm = crypto_alloc_aead("ccm(aes)", 0, 0); 92262306a36Sopenharmony_ci if (IS_ERR(tfm)) { 92362306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Failed alloc encrypt aead\n", 92462306a36Sopenharmony_ci __func__); 92562306a36Sopenharmony_ci return PTR_ERR(tfm); 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci server->secmech.enc = tfm; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (!server->secmech.dec) { 93162306a36Sopenharmony_ci if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) || 93262306a36Sopenharmony_ci (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) 93362306a36Sopenharmony_ci tfm = crypto_alloc_aead("gcm(aes)", 0, 0); 93462306a36Sopenharmony_ci else 93562306a36Sopenharmony_ci tfm = crypto_alloc_aead("ccm(aes)", 0, 0); 93662306a36Sopenharmony_ci if (IS_ERR(tfm)) { 93762306a36Sopenharmony_ci crypto_free_aead(server->secmech.enc); 93862306a36Sopenharmony_ci server->secmech.enc = NULL; 93962306a36Sopenharmony_ci cifs_server_dbg(VFS, "%s: Failed to alloc decrypt aead\n", 94062306a36Sopenharmony_ci __func__); 94162306a36Sopenharmony_ci return PTR_ERR(tfm); 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci server->secmech.dec = tfm; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci return 0; 94762306a36Sopenharmony_ci} 948