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 <[email protected]>
---
 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


Reply via email to