Commit 8bd68c6e authored by Aurelien Aptel's avatar Aurelien Aptel Committed by Steve French

CIFS: implement v3.11 preauth integrity

SMB3.11 clients must implement pre-authentification integrity.

* new mechanism to certify requests/responses happening before Tree
  Connect.
* supersedes VALIDATE_NEGOTIATE
* fixes signing for SMB3.11
Signed-off-by: default avatarAurelien Aptel <aaptel@suse.com>
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
CC: Stable <stable@vger.kernel.org>
Reviewed-by: default avatarRonnie Sahlberg <lsahlber@redhat.com>
parent 5fcd7f3f
...@@ -675,7 +675,8 @@ struct TCP_Server_Info { ...@@ -675,7 +675,8 @@ struct TCP_Server_Info {
unsigned int max_read; unsigned int max_read;
unsigned int max_write; unsigned int max_write;
#ifdef CONFIG_CIFS_SMB311 #ifdef CONFIG_CIFS_SMB311
__u8 preauth_sha_hash[64]; /* save initital negprot hash */ /* save initital negprot hash */
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
#endif /* 3.1.1 */ #endif /* 3.1.1 */
struct delayed_work reconnect; /* reconnect workqueue job */ struct delayed_work reconnect; /* reconnect workqueue job */
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */ struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
...@@ -864,7 +865,7 @@ struct cifs_ses { ...@@ -864,7 +865,7 @@ struct cifs_ses {
__u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE]; __u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE];
__u8 smb3decryptionkey[SMB3_SIGN_KEY_SIZE]; __u8 smb3decryptionkey[SMB3_SIGN_KEY_SIZE];
#ifdef CONFIG_CIFS_SMB311 #ifdef CONFIG_CIFS_SMB311
__u8 preauth_sha_hash[64]; __u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
#endif /* 3.1.1 */ #endif /* 3.1.1 */
}; };
......
...@@ -706,3 +706,67 @@ smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server) ...@@ -706,3 +706,67 @@ smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server)
return 0; return 0;
} }
#ifdef CONFIG_CIFS_SMB311
/**
* smb311_update_preauth_hash - update @ses hash with the packet data in @iov
*
* Assumes @iov does not contain the rfc1002 length and iov[0] has the
* SMB2 header.
*/
int
smb311_update_preauth_hash(struct cifs_ses *ses, struct kvec *iov, int nvec)
{
int i, rc;
struct sdesc *d;
struct smb2_sync_hdr *hdr;
if (ses->server->tcpStatus == CifsGood) {
/* skip non smb311 connections */
if (ses->server->dialect != SMB311_PROT_ID)
return 0;
/* skip last sess setup response */
hdr = (struct smb2_sync_hdr *)iov[0].iov_base;
if (hdr->Flags & SMB2_FLAGS_SIGNED)
return 0;
}
rc = smb311_crypto_shash_allocate(ses->server);
if (rc)
return rc;
d = ses->server->secmech.sdescsha512;
rc = crypto_shash_init(&d->shash);
if (rc) {
cifs_dbg(VFS, "%s: could not init sha512 shash\n", __func__);
return rc;
}
rc = crypto_shash_update(&d->shash, ses->preauth_sha_hash,
SMB2_PREAUTH_HASH_SIZE);
if (rc) {
cifs_dbg(VFS, "%s: could not update sha512 shash\n", __func__);
return rc;
}
for (i = 0; i < nvec; i++) {
rc = crypto_shash_update(&d->shash,
iov[i].iov_base, iov[i].iov_len);
if (rc) {
cifs_dbg(VFS, "%s: could not update sha512 shash\n",
__func__);
return rc;
}
}
rc = crypto_shash_final(&d->shash, ses->preauth_sha_hash);
if (rc) {
cifs_dbg(VFS, "%s: could not finalize sha512 shash\n",
__func__);
return rc;
}
return 0;
}
#endif
...@@ -453,6 +453,10 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) ...@@ -453,6 +453,10 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
return rc; return rc;
req->sync_hdr.SessionId = 0; req->sync_hdr.SessionId = 0;
#ifdef CONFIG_CIFS_SMB311
memset(server->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE);
memset(ses->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE);
#endif
if (strcmp(ses->server->vals->version_string, if (strcmp(ses->server->vals->version_string,
SMB3ANY_VERSION_STRING) == 0) { SMB3ANY_VERSION_STRING) == 0) {
...@@ -564,6 +568,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) ...@@ -564,6 +568,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
/* BB: add check that dialect was valid given dialect(s) we asked for */ /* BB: add check that dialect was valid given dialect(s) we asked for */
#ifdef CONFIG_CIFS_SMB311
/*
* Keep a copy of the hash after negprot. This hash will be
* the starting hash value for all sessions made from this
* server.
*/
memcpy(server->preauth_sha_hash, ses->preauth_sha_hash,
SMB2_PREAUTH_HASH_SIZE);
#endif
/* SMB2 only has an extended negflavor */ /* SMB2 only has an extended negflavor */
server->negflavor = CIFS_NEGFLAVOR_EXTENDED; server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
/* set it to the maximum buffer size value we can send with 1 credit */ /* set it to the maximum buffer size value we can send with 1 credit */
...@@ -621,6 +634,10 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -621,6 +634,10 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
return 0; return 0;
#endif #endif
/* In SMB3.11 preauth integrity supersedes validate negotiate */
if (tcon->ses->server->dialect == SMB311_PROT_ID)
return 0;
/* /*
* validation ioctl must be signed, so no point sending this if we * validation ioctl must be signed, so no point sending this if we
* can not sign it (ie are not known user). Even if signing is not * can not sign it (ie are not known user). Even if signing is not
...@@ -1148,6 +1165,14 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -1148,6 +1165,14 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
sess_data->buf0_type = CIFS_NO_BUFFER; sess_data->buf0_type = CIFS_NO_BUFFER;
sess_data->nls_cp = (struct nls_table *) nls_cp; sess_data->nls_cp = (struct nls_table *) nls_cp;
#ifdef CONFIG_CIFS_SMB311
/*
* Initialize the session hash with the server one.
*/
memcpy(ses->preauth_sha_hash, ses->server->preauth_sha_hash,
SMB2_PREAUTH_HASH_SIZE);
#endif
while (sess_data->func) while (sess_data->func)
sess_data->func(sess_data); sess_data->func(sess_data);
......
...@@ -264,6 +264,7 @@ struct smb2_negotiate_req { ...@@ -264,6 +264,7 @@ struct smb2_negotiate_req {
#define SMB311_SALT_SIZE 32 #define SMB311_SALT_SIZE 32
/* Hash Algorithm Types */ /* Hash Algorithm Types */
#define SMB2_PREAUTH_INTEGRITY_SHA512 cpu_to_le16(0x0001) #define SMB2_PREAUTH_INTEGRITY_SHA512 cpu_to_le16(0x0001)
#define SMB2_PREAUTH_HASH_SIZE 64
struct smb2_preauth_neg_context { struct smb2_preauth_neg_context {
__le16 ContextType; /* 1 */ __le16 ContextType; /* 1 */
......
...@@ -204,5 +204,7 @@ extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, ...@@ -204,5 +204,7 @@ extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
enum securityEnum); enum securityEnum);
#ifdef CONFIG_CIFS_SMB311 #ifdef CONFIG_CIFS_SMB311
extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server); extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server);
extern int smb311_update_preauth_hash(struct cifs_ses *ses,
struct kvec *iov, int nvec);
#endif #endif
#endif /* _SMB2PROTO_H */ #endif /* _SMB2PROTO_H */
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "cifsglob.h" #include "cifsglob.h"
#include "cifsproto.h" #include "cifsproto.h"
#include "cifs_debug.h" #include "cifs_debug.h"
#include "smb2proto.h"
#include "smbdirect.h" #include "smbdirect.h"
/* Max number of iovectors we can use off the stack when sending requests. */ /* Max number of iovectors we can use off the stack when sending requests. */
...@@ -751,6 +752,12 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -751,6 +752,12 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
if (rc < 0) if (rc < 0)
goto out; goto out;
#ifdef CONFIG_CIFS_SMB311
if (ses->status == CifsNew)
smb311_update_preauth_hash(ses, rqst->rq_iov+1,
rqst->rq_nvec-1);
#endif
if (timeout == CIFS_ASYNC_OP) if (timeout == CIFS_ASYNC_OP)
goto out; goto out;
...@@ -789,6 +796,16 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -789,6 +796,16 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
else else
*resp_buf_type = CIFS_SMALL_BUFFER; *resp_buf_type = CIFS_SMALL_BUFFER;
#ifdef CONFIG_CIFS_SMB311
if (ses->status == CifsNew) {
struct kvec iov = {
.iov_base = buf + 4,
.iov_len = get_rfc1002_length(buf)
};
smb311_update_preauth_hash(ses, &iov, 1);
}
#endif
credits = ses->server->ops->get_credits(midQ); credits = ses->server->ops->get_credits(midQ);
rc = ses->server->ops->check_receive(midQ, ses->server, rc = ses->server->ops->check_receive(midQ, ses->server,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment