[PATCH] erofs-utils: lib: s3: fix SigV4 signature timestamp mismatch
Yifan Zhao
zhaoyifan28 at huawei.com
Wed Jan 14 18:38:08 AEDT 2026
The current SigV4 implementation calls `s3erofs_now()` multiple times
during the signing process. This can cause inconsistent timestamps if a
second boundary is crossed, leading to signature verification failure.
Fix this by generating the timestamp once and passing it throughout the
signing process to ensure consistency.
Signed-off-by: Yifan Zhao <zhaoyifan28 at huawei.com>
---
lib/remotes/s3.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/lib/remotes/s3.c b/lib/remotes/s3.c
index 223c3e8..97f06b4 100644
--- a/lib/remotes/s3.c
+++ b/lib/remotes/s3.c
@@ -315,11 +315,10 @@ enum s3erofs_date_format {
S3EROFS_DATE_YYYYMMDD
};
-static void s3erofs_now(char *buf, size_t maxlen, enum s3erofs_date_format fmt)
+static void s3erofs_format_time(time_t t, char *buf, size_t maxlen, enum s3erofs_date_format fmt)
{
const char *format;
- time_t now = time(NULL);
- struct tm *ptm = gmtime(&now);
+ struct tm *ptm = gmtime(&t);
switch (fmt) {
case S3EROFS_DATE_RFC1123:
@@ -402,10 +401,9 @@ free_string:
// See: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
static char *s3erofs_sigv4_header(const struct curl_slist *headers,
- const char *canonical_uri,
- const char *canonical_query,
- const char *region, const char *ak,
- const char *sk)
+ time_t request_time, const char *canonical_uri,
+ const char *canonical_query, const char *region,
+ const char *ak, const char *sk)
{
u8 ping_buf[EVP_MAX_MD_SIZE], pong_buf[EVP_MAX_MD_SIZE];
char hex_buf[EVP_MAX_MD_SIZE * 2 + 1];
@@ -423,10 +421,12 @@ static char *s3erofs_sigv4_header(const struct curl_slist *headers,
canonical_query = "";
canonical_headers = get_canonical_headers(headers);
+ if (!canonical_headers)
+ return ERR_PTR(-ENOMEM);
// Get current time in required formats
- s3erofs_now(date_str, sizeof(date_str), S3EROFS_DATE_YYYYMMDD);
- s3erofs_now(timestamp, sizeof(timestamp), S3EROFS_DATE_ISO8601);
+ s3erofs_format_time(request_time, date_str, sizeof(date_str), S3EROFS_DATE_YYYYMMDD);
+ s3erofs_format_time(request_time, timestamp, sizeof(timestamp), S3EROFS_DATE_ISO8601);
// Task 1: Create canonical request
if (asprintf(&canonical_request,
@@ -530,9 +530,8 @@ static int s3erofs_request_insert_auth_v2(struct curl_slist **request_headers,
char date[64], *sigv2;
memcpy(date, date_prefix, sizeof(date_prefix) - 1);
- s3erofs_now(date + sizeof(date_prefix) - 1,
- sizeof(date) - sizeof(date_prefix) + 1,
- S3EROFS_DATE_RFC1123);
+ s3erofs_format_time(time(NULL), date + sizeof(date_prefix) - 1,
+ sizeof(date) - sizeof(date_prefix) + 1, S3EROFS_DATE_RFC1123);
sigv2 = s3erofs_sigv2_header(*request_headers, NULL, NULL,
date + sizeof(date_prefix) - 1, req->canonical_uri,
@@ -553,6 +552,7 @@ static int s3erofs_request_insert_auth_v4(struct curl_slist **request_headers,
{
char timestamp[32], *sigv4, *tmp;
const char *host, *host_end;
+ time_t request_time = time(NULL);
/* Add following headers for SigV4 in alphabetical order: */
/* 1. host */
@@ -570,15 +570,15 @@ static int s3erofs_request_insert_auth_v4(struct curl_slist **request_headers,
*request_headers, "x-amz-content-sha256:UNSIGNED-PAYLOAD");
/* 3. x-amz-date */
- s3erofs_now(timestamp, sizeof(timestamp), S3EROFS_DATE_ISO8601);
+ s3erofs_format_time(request_time, timestamp, sizeof(timestamp), S3EROFS_DATE_ISO8601);
if (asprintf(&tmp, "x-amz-date:%s", timestamp) < 0)
return -ENOMEM;
*request_headers = curl_slist_append(*request_headers, tmp);
free(tmp);
- sigv4 = s3erofs_sigv4_header(*request_headers, req->canonical_uri,
- req->canonical_query, s3->region, s3->access_key,
- s3->secret_key);
+ sigv4 = s3erofs_sigv4_header(*request_headers, request_time,
+ req->canonical_uri, req->canonical_query,
+ s3->region, s3->access_key, s3->secret_key);
if (IS_ERR(sigv4))
return PTR_ERR(sigv4);
*request_headers = curl_slist_append(*request_headers, sigv4);
--
2.47.3
More information about the Linux-erofs
mailing list