Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -675,7 +675,8 @@ struct TCP_Server_Info {
	unsigned int	max_read;
	unsigned int	max_write;
#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 */
	struct delayed_work reconnect; /* reconnect workqueue job */
	struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
@@ -864,7 +865,7 @@ struct cifs_ses {
	__u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE];
	__u8 smb3decryptionkey[SMB3_SIGN_KEY_SIZE];
#ifdef CONFIG_CIFS_SMB311
	__u8 preauth_sha_hash[64];
	__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
#endif /* 3.1.1 */
};

+64 −0
Original line number Diff line number Diff line
@@ -706,3 +706,67 @@ smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server)

	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
+25 −0
Original line number Diff line number Diff line
@@ -453,6 +453,10 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
		return rc;

	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,
		   SMB3ANY_VERSION_STRING) == 0) {
@@ -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 */

#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 */
	server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
	/* 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)
		return 0;
#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
	 * 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,
	sess_data->buf0_type = CIFS_NO_BUFFER;
	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)
		sess_data->func(sess_data);

+1 −0
Original line number Diff line number Diff line
@@ -264,6 +264,7 @@ struct smb2_negotiate_req {
#define SMB311_SALT_SIZE			32
/* Hash Algorithm Types */
#define SMB2_PREAUTH_INTEGRITY_SHA512	cpu_to_le16(0x0001)
#define SMB2_PREAUTH_HASH_SIZE 64

struct smb2_preauth_neg_context {
	__le16	ContextType; /* 1 */
+2 −0
Original line number Diff line number Diff line
@@ -204,5 +204,7 @@ extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
					enum securityEnum);
#ifdef CONFIG_CIFS_SMB311
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			/* _SMB2PROTO_H */
Loading