]> git.kaiwu.me - nginx.git/commitdiff
Secure link: compare hashes in constant time
authorSergey Kandaurov <pluknet@nginx.com>
Wed, 10 Jun 2026 17:32:41 +0000 (21:32 +0400)
committersbhowmik <sou.bhowmik02@gmail.com>
Wed, 10 Jun 2026 20:10:19 +0000 (01:40 +0530)
Reported by kodareef5

src/http/modules/ngx_http_secure_link_module.c

index 025fe341c7109a606d283e4deeaa13fd1cd5ef73..7218b6dd4a22fb58a79a9a31cbff9092c6c49a3f 100644 (file)
@@ -101,10 +101,11 @@ static ngx_int_t
 ngx_http_secure_link_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data)
 {
-    u_char                       *p, *last;
+    u_char                       *p, *last, ch;
     time_t                        expires;
     ngx_str_t                     val, hash;
     ngx_md5_t                     md5;
+    ngx_uint_t                    i;
     ngx_http_secure_link_ctx_t   *ctx;
     ngx_http_secure_link_conf_t  *conf;
     u_char                        hash_buf[18], md5_buf[16];
@@ -175,7 +176,13 @@ ngx_http_secure_link_variable(ngx_http_request_t *r,
     ngx_md5_update(&md5, val.data, val.len);
     ngx_md5_final(md5_buf, &md5);
 
-    if (ngx_memcmp(hash_buf, md5_buf, 16) != 0) {
+    /* constant time comparison */
+
+    for (ch = 0, i = 0; i < 16; i++) {
+        ch |= (hash_buf[i] ^ md5_buf[i]);
+    }
+
+    if (ch) {
         goto not_found;
     }
 
@@ -200,7 +207,7 @@ ngx_http_secure_link_old_variable(ngx_http_request_t *r,
     ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v,
     uintptr_t data)
 {
-    u_char      *p, *start, *end, *last;
+    u_char      *p, *start, *end, *last, ch;
     size_t       len;
     ngx_int_t    n;
     ngx_md5_t    md5;
@@ -243,11 +250,19 @@ url_start:
     ngx_md5_update(&md5, conf->secret.data, conf->secret.len);
     ngx_md5_final(hash, &md5);
 
-    for (i = 0; i < 16; i++) {
+    for (ch = 0, i = 0; i < 16; i++) {
         n = ngx_hextoi(&start[2 * i], 2);
-        if (n == NGX_ERROR || n != hash[i]) {
+        if (n == NGX_ERROR) {
             goto not_found;
         }
+
+        /* constant time comparison */
+
+        ch |= (u_char) n ^ hash[i];
+    }
+
+    if (ch) {
+        goto not_found;
     }
 
     v->len = len;