Commit 1f3d5477 authored by Enzo Matsumiya's avatar Enzo Matsumiya Committed by Steve French
Browse files

cifs: secmech: use shash_desc directly, remove sdesc



The struct sdesc is just a wrapper around shash_desc, with exact same
memory layout. Replace the hashing TFMs with shash_desc as it's what's
passed to the crypto API anyway.

Also remove the crypto_shash pointers as they can be accessed via
shash_desc->tfm (and are actually only used in the setkey calls).

Adapt cifs_{alloc,free}_hash functions to this change.

Signed-off-by: default avatarEnzo Matsumiya <ematsumiya@suse.de>
Reviewed-by: default avatarPaulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 8698baa1
Loading
Loading
Loading
Loading
+26 −60
Original line number Diff line number Diff line
@@ -103,26 +103,24 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
	if (!rqst->rq_iov || !signature || !server)
		return -EINVAL;

	rc = cifs_alloc_hash("md5", &server->secmech.md5,
			     &server->secmech.sdescmd5);
	rc = cifs_alloc_hash("md5", &server->secmech.md5);
	if (rc)
		return -1;

	rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
	rc = crypto_shash_init(server->secmech.md5);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not init md5\n", __func__);
		return rc;
	}

	rc = crypto_shash_update(&server->secmech.sdescmd5->shash,
	rc = crypto_shash_update(server->secmech.md5,
		server->session_key.response, server->session_key.len);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
		return rc;
	}

	return __cifs_calc_signature(rqst, server, signature,
				     &server->secmech.sdescmd5->shash);
	return __cifs_calc_signature(rqst, server, signature, server->secmech.md5);
}

/* must be called with server->srv_mutex held */
@@ -412,7 +410,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
	wchar_t *domain;
	wchar_t *server;

	if (!ses->server->secmech.sdeschmacmd5) {
	if (!ses->server->secmech.hmacmd5) {
		cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__);
		return -1;
	}
@@ -420,14 +418,14 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
	/* calculate md4 hash of password */
	E_md4hash(ses->password, nt_hash, nls_cp);

	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash,
	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm, nt_hash,
				CIFS_NTHASH_SIZE);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not set NT Hash as a key\n", __func__);
		return rc;
	}

	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
	rc = crypto_shash_init(ses->server->secmech.hmacmd5);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
		return rc;
@@ -448,7 +446,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
		memset(user, '\0', 2);
	}

	rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
	rc = crypto_shash_update(ses->server->secmech.hmacmd5,
				(char *)user, 2 * len);
	kfree(user);
	if (rc) {
@@ -468,7 +466,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
		len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len,
				      nls_cp);
		rc =
		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
		crypto_shash_update(ses->server->secmech.hmacmd5,
					(char *)domain, 2 * len);
		kfree(domain);
		if (rc) {
@@ -488,7 +486,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
		len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len,
					nls_cp);
		rc =
		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
		crypto_shash_update(ses->server->secmech.hmacmd5,
					(char *)server, 2 * len);
		kfree(server);
		if (rc) {
@@ -498,7 +496,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
		}
	}

	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
	rc = crypto_shash_final(ses->server->secmech.hmacmd5,
					ntlmv2_hash);
	if (rc)
		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
@@ -518,12 +516,12 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
	hash_len = ses->auth_key.len - (CIFS_SESS_KEY_SIZE +
		offsetof(struct ntlmv2_resp, challenge.key[0]));

	if (!ses->server->secmech.sdeschmacmd5) {
	if (!ses->server->secmech.hmacmd5) {
		cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__);
		return -1;
	}

	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5,
	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm,
				 ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
@@ -531,7 +529,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
		return rc;
	}

	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
	rc = crypto_shash_init(ses->server->secmech.hmacmd5);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
		return rc;
@@ -543,7 +541,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
	else
		memcpy(ntlmv2->challenge.key,
		       ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
	rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
	rc = crypto_shash_update(ses->server->secmech.hmacmd5,
				 ntlmv2->challenge.key, hash_len);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
@@ -551,7 +549,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
	}

	/* Note that the MD5 digest over writes anon.challenge_key.key */
	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
	rc = crypto_shash_final(ses->server->secmech.hmacmd5,
				ntlmv2->ntlmv2_hash);
	if (rc)
		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
@@ -627,9 +625,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)

	cifs_server_lock(ses->server);

	rc = cifs_alloc_hash("hmac(md5)",
			     &ses->server->secmech.hmacmd5,
			     &ses->server->secmech.sdeschmacmd5);
	rc = cifs_alloc_hash("hmac(md5)", &ses->server->secmech.hmacmd5);
	if (rc) {
		goto unlock;
	}
@@ -649,7 +645,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
	}

	/* now calculate the session key for NTLMv2 */
	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5,
	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm,
		ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
@@ -657,13 +653,13 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
		goto unlock;
	}

	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
	rc = crypto_shash_init(ses->server->secmech.hmacmd5);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
		goto unlock;
	}

	rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
	rc = crypto_shash_update(ses->server->secmech.hmacmd5,
		ntlmv2->ntlmv2_hash,
		CIFS_HMAC_MD5_HASH_SIZE);
	if (rc) {
@@ -671,7 +667,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
		goto unlock;
	}

	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
	rc = crypto_shash_final(ses->server->secmech.hmacmd5,
		ses->auth_key.response);
	if (rc)
		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
@@ -718,30 +714,11 @@ calc_seckey(struct cifs_ses *ses)
void
cifs_crypto_secmech_release(struct TCP_Server_Info *server)
{
	if (server->secmech.cmacaes) {
		crypto_free_shash(server->secmech.cmacaes);
		server->secmech.cmacaes = NULL;
	}

	if (server->secmech.hmacsha256) {
		crypto_free_shash(server->secmech.hmacsha256);
		server->secmech.hmacsha256 = NULL;
	}

	if (server->secmech.md5) {
		crypto_free_shash(server->secmech.md5);
		server->secmech.md5 = NULL;
	}

	if (server->secmech.sha512) {
		crypto_free_shash(server->secmech.sha512);
		server->secmech.sha512 = NULL;
	}

	if (server->secmech.hmacmd5) {
		crypto_free_shash(server->secmech.hmacmd5);
		server->secmech.hmacmd5 = NULL;
	}
	cifs_free_hash(&server->secmech.aes_cmac);
	cifs_free_hash(&server->secmech.hmacsha256);
	cifs_free_hash(&server->secmech.md5);
	cifs_free_hash(&server->secmech.sha512);
	cifs_free_hash(&server->secmech.hmacmd5);

	if (server->secmech.enc) {
		crypto_free_aead(server->secmech.enc);
@@ -752,15 +729,4 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server)
		crypto_free_aead(server->secmech.dec);
		server->secmech.dec = NULL;
	}

	kfree_sensitive(server->secmech.sdesccmacaes);
	server->secmech.sdesccmacaes = NULL;
	kfree_sensitive(server->secmech.sdeschmacsha256);
	server->secmech.sdeschmacsha256 = NULL;
	kfree_sensitive(server->secmech.sdeschmacmd5);
	server->secmech.sdeschmacmd5 = NULL;
	kfree_sensitive(server->secmech.sdescmd5);
	server->secmech.sdescmd5 = NULL;
	kfree_sensitive(server->secmech.sdescsha512);
	server->secmech.sdescsha512 = NULL;
}
+8 −18
Original line number Diff line number Diff line
@@ -153,26 +153,16 @@ struct session_key {
	char *response;
};

/* crypto security descriptor definition */
struct sdesc {
	struct shash_desc shash;
	char ctx[];
};

/* crypto hashing related structure/fields, not specific to a sec mech */
struct cifs_secmech {
	struct crypto_shash *hmacmd5; /* hmac-md5 hash function */
	struct crypto_shash *md5; /* md5 hash function */
	struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */
	struct crypto_shash *cmacaes; /* block-cipher based MAC function */
	struct crypto_shash *sha512; /* sha512 hash function */
	struct sdesc *sdeschmacmd5;  /* ctxt to generate ntlmv2 hash, CR1 */
	struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
	struct sdesc *sdeschmacsha256;  /* ctxt to generate smb2 signature */
	struct sdesc *sdesccmacaes;  /* ctxt to generate smb3 signature */
	struct sdesc *sdescsha512; /* ctxt to generate smb3.11 signing key */
	struct crypto_aead *enc; /* smb3 AEAD encryption TFM (AES-CCM and AES-GCM) */
	struct crypto_aead *dec; /* smb3 AEAD decryption TFM (AES-CCM and AES-GCM) */
	struct shash_desc *hmacmd5; /* hmacmd5 hash function, for NTLMv2/CR1 hashes */
	struct shash_desc *md5; /* md5 hash function, for CIFS/SMB1 signatures */
	struct shash_desc *hmacsha256; /* hmac-sha256 hash function, for SMB2 signatures */
	struct shash_desc *sha512; /* sha512 hash function, for SMB3.1.1 preauth hash */
	struct shash_desc *aes_cmac; /* block-cipher based MAC function, for SMB3 signatures */

	struct crypto_aead *enc; /* smb3 encryption AEAD TFM (AES-CCM and AES-GCM) */
	struct crypto_aead *dec; /* smb3 decryption AEAD TFM (AES-CCM and AES-GCM) */
};

/* per smb session structure/fields */
+2 −3
Original line number Diff line number Diff line
@@ -598,9 +598,8 @@ struct cifs_aio_ctx *cifs_aio_ctx_alloc(void);
void cifs_aio_ctx_release(struct kref *refcount);
int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw);

int cifs_alloc_hash(const char *name, struct crypto_shash **shash,
		    struct sdesc **sdesc);
void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc);
int cifs_alloc_hash(const char *name, struct shash_desc **sdesc);
void cifs_free_hash(struct shash_desc **sdesc);

extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
				unsigned int *len, unsigned int *offset);
+6 −7
Original line number Diff line number Diff line
@@ -38,29 +38,28 @@ static int
symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
{
	int rc;
	struct crypto_shash *md5 = NULL;
	struct sdesc *sdescmd5 = NULL;
	struct shash_desc *md5 = NULL;

	rc = cifs_alloc_hash("md5", &md5, &sdescmd5);
	rc = cifs_alloc_hash("md5", &md5);
	if (rc)
		goto symlink_hash_err;

	rc = crypto_shash_init(&sdescmd5->shash);
	rc = crypto_shash_init(md5);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not init md5 shash\n", __func__);
		goto symlink_hash_err;
	}
	rc = crypto_shash_update(&sdescmd5->shash, link_str, link_len);
	rc = crypto_shash_update(md5, link_str, link_len);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with link_str\n", __func__);
		goto symlink_hash_err;
	}
	rc = crypto_shash_final(&sdescmd5->shash, md5_hash);
	rc = crypto_shash_final(md5, md5_hash);
	if (rc)
		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);

symlink_hash_err:
	cifs_free_hash(&md5, &sdescmd5);
	cifs_free_hash(&md5);
	return rc;
}

+24 −25
Original line number Diff line number Diff line
@@ -1071,59 +1071,58 @@ setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw)
/**
 * cifs_alloc_hash - allocate hash and hash context together
 * @name: The name of the crypto hash algo
 * @shash: Where to put the pointer to the hash algo
 * @sdesc: Where to put the pointer to the hash descriptor
 * @sdesc: SHASH descriptor where to put the pointer to the hash TFM
 *
 * The caller has to make sure @sdesc is initialized to either NULL or
 * a valid context. Both can be freed via cifs_free_hash().
 * a valid context. It can be freed via cifs_free_hash().
 */
int
cifs_alloc_hash(const char *name,
		struct crypto_shash **shash, struct sdesc **sdesc)
cifs_alloc_hash(const char *name, struct shash_desc **sdesc)
{
	int rc = 0;
	size_t size;
	struct crypto_shash *alg = NULL;

	if (*sdesc != NULL)
	if (*sdesc)
		return 0;

	*shash = crypto_alloc_shash(name, 0, 0);
	if (IS_ERR(*shash)) {
		cifs_dbg(VFS, "Could not allocate crypto %s\n", name);
		rc = PTR_ERR(*shash);
		*shash = NULL;
	alg = crypto_alloc_shash(name, 0, 0);
	if (IS_ERR(alg)) {
		cifs_dbg(VFS, "Could not allocate shash TFM '%s'\n", name);
		rc = PTR_ERR(alg);
		*sdesc = NULL;
		return rc;
	}

	size = sizeof(struct shash_desc) + crypto_shash_descsize(*shash);
	*sdesc = kmalloc(size, GFP_KERNEL);
	*sdesc = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(alg), GFP_KERNEL);
	if (*sdesc == NULL) {
		cifs_dbg(VFS, "no memory left to allocate crypto %s\n", name);
		crypto_free_shash(*shash);
		*shash = NULL;
		cifs_dbg(VFS, "no memory left to allocate shash TFM '%s'\n", name);
		crypto_free_shash(alg);
		return -ENOMEM;
	}

	(*sdesc)->shash.tfm = *shash;
	(*sdesc)->tfm = alg;
	return 0;
}

/**
 * cifs_free_hash - free hash and hash context together
 * @shash: Where to find the pointer to the hash algo
 * @sdesc: Where to find the pointer to the hash descriptor
 * @sdesc: Where to find the pointer to the hash TFM
 *
 * Freeing a NULL hash or context is safe.
 * Freeing a NULL descriptor is safe.
 */
void
cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc)
cifs_free_hash(struct shash_desc **sdesc)
{
	if (unlikely(!sdesc) || !*sdesc)
		return;

	if ((*sdesc)->tfm) {
		crypto_free_shash((*sdesc)->tfm);
		(*sdesc)->tfm = NULL;
	}

	kfree_sensitive(*sdesc);
	*sdesc = NULL;
	if (*shash)
		crypto_free_shash(*shash);
	*shash = NULL;
}

/**
Loading