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

Commit 16c568ef authored by Al Viro's avatar Al Viro
Browse files

cifs: merge the hash calculation helpers



three practically identical copies...

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 2da62906
Loading
Loading
Loading
Loading
+54 −43
Original line number Diff line number Diff line
@@ -66,45 +66,15 @@ cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
	return 0;
}

/*
 * Calculate and return the CIFS signature based on the mac key and SMB PDU.
 * The 16 byte signature must be allocated by the caller. Note we only use the
 * 1st eight bytes and that the smb header signature field on input contains
 * the sequence number before this function is called. Also, this function
 * should be called with the server->srv_mutex held.
 */
static int cifs_calc_signature(struct smb_rqst *rqst,
			struct TCP_Server_Info *server, char *signature)
int __cifs_calc_signature(struct smb_rqst *rqst,
			struct TCP_Server_Info *server, char *signature,
			struct shash_desc *shash)
{
	int i;
	int rc;
	struct kvec *iov = rqst->rq_iov;
	int n_vec = rqst->rq_nvec;

	if (iov == NULL || signature == NULL || server == NULL)
		return -EINVAL;

	if (!server->secmech.sdescmd5) {
		rc = cifs_crypto_shash_md5_allocate(server);
		if (rc) {
			cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
			return -1;
		}
	}

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

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

	for (i = 0; i < n_vec; i++) {
		if (iov[i].iov_len == 0)
			continue;
@@ -117,12 +87,10 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
		if (i == 0) {
			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
				break; /* nothing to sign or corrupt header */
			rc =
			crypto_shash_update(&server->secmech.sdescmd5->shash,
			rc = crypto_shash_update(shash,
				iov[i].iov_base + 4, iov[i].iov_len - 4);
		} else {
			rc =
			crypto_shash_update(&server->secmech.sdescmd5->shash,
			rc = crypto_shash_update(shash,
				iov[i].iov_base, iov[i].iov_len);
		}
		if (rc) {
@@ -134,21 +102,64 @@ static int cifs_calc_signature(struct smb_rqst *rqst,

	/* now hash over the rq_pages array */
	for (i = 0; i < rqst->rq_npages; i++) {
		struct kvec p_iov;
		void *kaddr = kmap(rqst->rq_pages[i]);
		size_t len = rqst->rq_pagesz;

		if (i == rqst->rq_npages - 1)
			len = rqst->rq_tailsz;

		crypto_shash_update(shash, kaddr, len);

		cifs_rqst_page_to_kvec(rqst, i, &p_iov);
		crypto_shash_update(&server->secmech.sdescmd5->shash,
					p_iov.iov_base, p_iov.iov_len);
		kunmap(rqst->rq_pages[i]);
	}

	rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature);
	rc = crypto_shash_final(shash, signature);
	if (rc)
		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
		cifs_dbg(VFS, "%s: Could not generate hash\n", __func__);

	return rc;
}

/*
 * Calculate and return the CIFS signature based on the mac key and SMB PDU.
 * The 16 byte signature must be allocated by the caller. Note we only use the
 * 1st eight bytes and that the smb header signature field on input contains
 * the sequence number before this function is called. Also, this function
 * should be called with the server->srv_mutex held.
 */
static int cifs_calc_signature(struct smb_rqst *rqst,
			struct TCP_Server_Info *server, char *signature)
{
	int rc;

	if (!rqst->rq_iov || !signature || !server)
		return -EINVAL;

	if (!server->secmech.sdescmd5) {
		rc = cifs_crypto_shash_md5_allocate(server);
		if (rc) {
			cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
			return -1;
		}
	}

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

	rc = crypto_shash_update(&server->secmech.sdescmd5->shash,
		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);
}

/* must be called with server->srv_mutex held */
int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
		   __u32 *pexpected_response_sequence_number)
+3 −0
Original line number Diff line number Diff line
@@ -512,4 +512,7 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
			   struct cifs_sb_info *cifs_sb,
			   const unsigned char *path, char *pbuf,
			   unsigned int *pbytes_written);
int __cifs_calc_signature(struct smb_rqst *rqst,
			struct TCP_Server_Info *server, char *signature,
			struct shash_desc *shash);
#endif			/* _CIFSPROTO_H */
+10 −97
Original line number Diff line number Diff line
@@ -135,11 +135,10 @@ smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server)
int
smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{
	int i, rc;
	int rc;
	unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
	unsigned char *sigptr = smb2_signature;
	struct kvec *iov = rqst->rq_iov;
	int n_vec = rqst->rq_nvec;
	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
	struct cifs_ses *ses;

@@ -171,52 +170,10 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
		return rc;
	}

	for (i = 0; i < n_vec; i++) {
		if (iov[i].iov_len == 0)
			continue;
		if (iov[i].iov_base == NULL) {
			cifs_dbg(VFS, "null iovec entry\n");
			return -EIO;
		}
		/*
		 * The first entry includes a length field (which does not get
		 * signed that occupies the first 4 bytes before the header).
		 */
		if (i == 0) {
			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
				break; /* nothing to sign or corrupt header */
			rc =
			crypto_shash_update(
				&server->secmech.sdeschmacsha256->shash,
				iov[i].iov_base + 4, iov[i].iov_len - 4);
		} else {
			rc =
			crypto_shash_update(
				&server->secmech.sdeschmacsha256->shash,
				iov[i].iov_base, iov[i].iov_len);
		}
		if (rc) {
			cifs_dbg(VFS, "%s: Could not update with payload\n",
				 __func__);
			return rc;
		}
	}

	/* now hash over the rq_pages array */
	for (i = 0; i < rqst->rq_npages; i++) {
		struct kvec p_iov;

		cifs_rqst_page_to_kvec(rqst, i, &p_iov);
		crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
					p_iov.iov_base, p_iov.iov_len);
		kunmap(rqst->rq_pages[i]);
	}

	rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
				sigptr);
	if (rc)
		cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__);
	rc = __cifs_calc_signature(rqst, server, sigptr,
		&server->secmech.sdeschmacsha256->shash);

	if (!rc)
		memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);

	return rc;
@@ -395,12 +352,10 @@ generate_smb311signingkey(struct cifs_ses *ses)
int
smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{
	int i;
	int rc = 0;
	unsigned char smb3_signature[SMB2_CMACAES_SIZE];
	unsigned char *sigptr = smb3_signature;
	struct kvec *iov = rqst->rq_iov;
	int n_vec = rqst->rq_nvec;
	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
	struct cifs_ses *ses;

@@ -432,52 +387,10 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
		return rc;
	}
	
	for (i = 0; i < n_vec; i++) {
		if (iov[i].iov_len == 0)
			continue;
		if (iov[i].iov_base == NULL) {
			cifs_dbg(VFS, "null iovec entry");
			return -EIO;
		}
		/*
		 * The first entry includes a length field (which does not get
		 * signed that occupies the first 4 bytes before the header).
		 */
		if (i == 0) {
			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
				break; /* nothing to sign or corrupt header */
			rc =
			crypto_shash_update(
				&server->secmech.sdesccmacaes->shash,
				iov[i].iov_base + 4, iov[i].iov_len - 4);
		} else {
			rc =
			crypto_shash_update(
				&server->secmech.sdesccmacaes->shash,
				iov[i].iov_base, iov[i].iov_len);
		}
		if (rc) {
			cifs_dbg(VFS, "%s: Couldn't update cmac aes with payload\n",
							__func__);
			return rc;
		}
	}

	/* now hash over the rq_pages array */
	for (i = 0; i < rqst->rq_npages; i++) {
		struct kvec p_iov;

		cifs_rqst_page_to_kvec(rqst, i, &p_iov);
		crypto_shash_update(&server->secmech.sdesccmacaes->shash,
					p_iov.iov_base, p_iov.iov_len);
		kunmap(rqst->rq_pages[i]);
	}

	rc = crypto_shash_final(&server->secmech.sdesccmacaes->shash,
						sigptr);
	if (rc)
		cifs_dbg(VFS, "%s: Could not generate cmac aes\n", __func__);
	rc = __cifs_calc_signature(rqst, server, sigptr,
				   &server->secmech.sdesccmacaes->shash);

	if (!rc)
		memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);

	return rc;