munge/0004-HKDF-Fix-big-endian-bug-caused-by-size_t-ptr-cast.patch
2021-04-30 09:36:47 +01:00

147 lines
5.0 KiB
Diff

From 2ad81007d2371f536af9e231490357c928eca53a Mon Sep 17 00:00:00 2001
From: Chris Dunlap <cdunlap@llnl.gov>
Date: Wed, 2 Dec 2020 09:50:27 -0800
Subject: [PATCH 4/4] HKDF: Fix big-endian bug caused by size_t ptr cast
When Fedora updated to 0.5.14 and added the new test suite to their
rpm spec's %check, munge successfully built but its test suite failed
on s390x for hkdf_test:
> FAIL: hkdf_test
> ===============
> Failed to finalize HKDF MAC ctx for extraction
This is caused by the cast of prklenp from a size_t * to an int *
in _hkdf_extract().
On s390x, memory ordering is big-endian and size_t is an alias for
unsigned long. Thus, a ptr to an 8-byte size_t was being cast to a
ptr to a 4-byte int.
This worked on little-endian systems (of which all my test systems
had been) since the least-significant byte is stored at the smallest
memory address (the little end), and the stored value always fit
within 4 bytes. But on big-endian systems, the least-significant
byte is stored at the largest memory address (the big end) which
differs for 4-byte and 8-byte values.
Remove the cast by using an int variable as an intermediary.
Reference:
- https://fedoraproject.org/wiki/Architectures/s390x#Notes_for_application_developers_and_package_maintainers
- https://bugzilla.redhat.com/show_bug.cgi?id=1923337
- https://bugs.launchpad.net/bugs/1915457
- https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=982564
Tested:
- Arch Linux
- CentOS Stream 8, 8.3.2011, 7.9.2009, 6.10
- Debian sid, 10.8, 9.13, 8.11, 7.11, 6.0.10, 5.0.10, 4.0
- Fedora 33 [s390x, x86_64], 32, 31
- FreeBSD 12.2, 11.4
- NetBSD 9.1, 9.0, 8.1
- OpenBSD 6.8, 6.7, 6.6
- openSUSE 15.2, 15.1
- Raspberry Pi OS (Raspbian 10) [armv7l]
- Ubuntu 20.10, 20.04.2 LTS, 18.04.5 LTS, 16.04.7 LTS, 14.04.6 LTS, 12.04.5 LTS
Closes #91
---
src/common/hkdf.c | 30 ++++++++++++++++++++++++++----
1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/src/common/hkdf.c b/src/common/hkdf.c
index ac7ab6f..364f3e0 100644
--- a/src/common/hkdf.c
+++ b/src/common/hkdf.c
@@ -32,6 +32,7 @@
#include <assert.h>
#include <errno.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -316,6 +317,7 @@ _hkdf_extract (hkdf_ctx_t *ctxp, void *prk, size_t *prklenp)
{
mac_ctx mac_ctx;
int mac_ctx_is_initialized = 0;
+ int prklen;
int rv = 0;
assert (ctxp != NULL);
@@ -325,6 +327,14 @@ _hkdf_extract (hkdf_ctx_t *ctxp, void *prk, size_t *prklenp)
assert (prklenp != NULL);
assert (*prklenp > 0);
+ /* Convert prklen size_t to int for the call to mac_final() since the parm
+ * is being passed as a ptr, and size of size_t and int may differ.
+ * *prklenp must be representable as an int because it was assigned
+ * (via ctxp->mdlen) by mac_size() which returns an int.
+ */
+ assert (*prklenp <= INT_MAX);
+ prklen = (int) *prklenp;
+
/* Compute the pseudorandom key.
* prk = HMAC (salt, ikm)
*/
@@ -340,7 +350,7 @@ _hkdf_extract (hkdf_ctx_t *ctxp, void *prk, size_t *prklenp)
log_msg (LOG_ERR, "Failed to update HKDF MAC ctx for extraction");
goto err;
}
- rv = mac_final (&mac_ctx, prk, (int *) prklenp);
+ rv = mac_final (&mac_ctx, prk, &prklen);
if (rv == -1) {
log_msg (LOG_ERR, "Failed to finalize HKDF MAC ctx for extraction");
goto err;
@@ -352,6 +362,12 @@ err:
return -1;
}
}
+ /* Update [prklenp] on success.
+ */
+ if (rv >= 0) {
+ assert (prklen >= 0);
+ *prklenp = (size_t) prklen;
+ }
return rv;
}
@@ -371,7 +387,7 @@ _hkdf_expand (hkdf_ctx_t *ctxp, const void *prk, size_t prklen,
unsigned char *dstptr;
size_t dstlen;
unsigned char *okm = NULL;
- size_t okmlen;
+ int okmlen;
int num_rounds;
const int max_rounds = 255;
unsigned char round;
@@ -390,8 +406,14 @@ _hkdf_expand (hkdf_ctx_t *ctxp, const void *prk, size_t prklen,
/* Allocate buffer for output keying material.
* The buffer size is equal to the size of the hash function output.
+ * Note that okmlen must be an int (and not size_t) for the call to
+ * mac_final() since the parm is being passed as a ptr, and size of
+ * size_t and int may differ.
+ * ctxp->mdlen must be representable as an int because it was assigned
+ * by mac_size() which returns an int.
*/
- okmlen = ctxp->mdlen;
+ assert (ctxp->mdlen <= INT_MAX);
+ okmlen = (int) ctxp->mdlen;
okm = calloc (1, okmlen);
if (okm == NULL) {
rv = -1;
@@ -448,7 +470,7 @@ _hkdf_expand (hkdf_ctx_t *ctxp, const void *prk, size_t prklen,
"for expansion round #%u", round);
goto err;
}
- rv = mac_final (&mac_ctx, okm, (int *) &okmlen);
+ rv = mac_final (&mac_ctx, okm, &okmlen);
if (rv == -1) {
log_msg (LOG_ERR,
"Failed to finalize HKDF MAC ctx "
--
2.30.0