Conversation
a9dbf63 to
8bdab13
Compare
…est suite
Add RFC 7231/IMF-fixdate and ISO 8601 'Z' suffix timestamp parsing, port
HMAC computation to the OpenSSL 3.0 EVP_MAC API, fix 14 correctness and
safety bugs found during code review, and add a full Perl test suite with
CI.
--- Timestamp parsing ---
* Add ISO 8601 UTC 'Z' suffix support ("YYYY-MM-DDThh:mm:ssZ").
Previously fell through to the Unix branch and was silently misread.
* Add RFC 7231 / IMF-fixdate support ("Day, DD Mon YYYY hh:mm:ss GMT"),
including case-insensitive month-name lookup (RFC 7231 §7.1.1.1).
* Fix RFC 7231 internal-comma bug: the embedded comma in "Sun, 06 Nov …"
was previously mistaken for the field separator when an expiry field was
also present, leaving only a 3-byte substring for the timestamp parser.
Now detected and skipped before searching for the next field boundary.
* Extract ngx_http_secure_link_gauss() with calendar-field range checks
(year ≥ 1970, month 1–12, mday 1–31, hour 0–23, min 0–59, sec 0–60).
* Extract ngx_http_secure_link_parse_ts() to centralise all four format
branches; returns (time_t)-1 on any parse or range failure.
--- Security / correctness ---
* Fix Y2038 overflow: "365 * year" was int×int; large dates overflowed
before the (time_t) cast. Fixed: (time_t)year * 365 promotes all Gauss
arithmetic to the wider type.
* Fix strict Unix timestamp validation: replaced sscanf "%llu" fallback
(which accepted any digit-leading string) with a digit-only byte scan
followed by ngx_atotm(). Prevents ISO 8601 year-only values (e.g. "2025")
from being silently accepted.
* Fix size_t/unsigned-int mismatch in token variable handler: passing
(u_int*)&hmac.len to HMAC() wrote only 4 of 8 bytes on LP64; on
big-endian the written bytes were in the wrong half. Use a local
unsigned int hmac_len instead.
* Fix $secure_link_hmac_expires returning token bytes: ctx->expires was
set to value.data/len after value had been trimmed to the token. Now
points to the actual expiry-period substring.
* Fix EVP_MD_size() not checked: OpenSSL 3.0 returns -1 on error; the
unchecked cast to u_int produced a huge length passed to CRYPTO_memcmp.
* Fix GMT-offset sign: two independent `if` statements replaced with
if/else if/else so an unexpected sign character cannot silently apply
no offset.
--- OpenSSL compatibility ---
* Wrap HMAC computation in ngx_http_secure_link_hmac_compute():
uses EVP_MAC on OpenSSL >= 3.0 (no deprecation warning), HMAC() on 1.x.
* NGX_HMAC_MD_SIZE macro wraps EVP_MD_size (1.x) / EVP_MD_get_size (3.x).
* Add key.len overflow guard before narrowing size_t to int for HMAC().
--- Code quality ---
* Remove incorrect (ngx_tm_*_t*) casts from sscanf calls; plain int* is
correct for %d and portable across all platforms.
* Change %02d to %2d in all sscanf format strings (the '0' flag is a
printf-only concept; silently ignored by scanf).
* Fix debug log timestamp width: was hardcoded to 25 bytes; now uses the
actual substring length (int)(ts_end - ts_start).
* Move gmtoff, var, i to inner scopes (cppcheck --enable=all, zero warnings).
* Declare parse_ts ts_last parameter const (cppcheck constParameterPointer).
--- Documentation ---
* Replace verbose BUGS FIXED header block with a concise changelog;
rationale lives in CHANGELOG.md and the commit history.
* Document that the field separator in secure_link_hmac is always a comma
(hardcoded) and the separator in secure_link_hmac_message is freely
chosen by the operator (pipe, colon, slash, none, …).
* Document all three embedded variables ($secure_link_hmac,
$secure_link_hmac_expires, $secure_link_hmac_token) with their exact
possible values and evaluation ordering requirements.
* Add RFC 7231 client examples in PHP (gmdate), Node.js (toUTCString),
and Python (isoformat + Z suffix).
* Expand Security Notes with separator guidance and URL-encoding rules.
--- Testing and CI ---
* Add t/hmac_secure_link.t: 66 Test::Nginx::Socket tests across 10
categories (basic HMAC, Unix/ISO 8601/RFC 7231 timestamps, algorithms,
variable values, separators, config edge cases, access-control patterns).
* Add t/lib/HmacSecureLink.pm: shared token generators, timestamp
formatters, TS_FIXED constant (eliminates timing-race in token tests).
* Add .github/workflows/ci.yml.
* Add Makefile with build, test, test-syntax, lint, cpan-deps targets.
* Add CHANGELOG.md.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add RFC 7231/IMF-fixdate and ISO 8601 'Z' suffix timestamp parsing, port HMAC computation to the OpenSSL 3.0 EVP_MAC API, fix 14 correctness and safety bugs found during code review, and add a full Perl test suite with CI.
Timestamp Parsing
'Z'suffix support ("YYYY-MM-DDThh:mm:ssZ"). Previously, these strings fell through to the Unix branch and were silently misread."Day, DD Mon YYYY hh:mm:ss GMT", including case-insensitive month-name lookup (per RFC 7231 §7.1.1.1)."Sun, 06 Nov …"was mistaken for a field separator. It is now correctly skipped during boundary detection.ngx_http_secure_link_gauss()to perform calendar-field range checks (Year ≥ 1970, Month 1–12, Day 1–31, etc.).ngx_http_secure_link_parse_ts(), which returns(time_t)-1on any failure.Security & Correctness
365 * year(int calculation) to(time_t)year * 365. This promotes arithmetic to the wider type, preventing overflows on large dates.sscanf "%llu"with a digit-only byte scan followed byngx_atotm(). This prevents fragments like"2025"from being accepted as valid timestamps.size_tvsunsigned intmismatch. Passing(u_int*)&hmac.lentoHMAC()caused memory corruption on LP64 and Big-Endian systems. Now uses a localunsigned int hmac_len.$secure_link_hmac_expiresincorrectly returning token bytes by ensuringctx->expirespoints to the actual expiry-period substring.EVP_MD_size(). OpenSSL 3.0 returns-1on error; previously, an unchecked cast produced a huge length passed toCRYPTO_memcmp.if/else if/elseto ensure unexpected characters cannot bypass the offset application.OpenSSL Compatibility
ngx_http_secure_link_hmac_compute().EVP_MACon OpenSSL >= 3.0 to avoid deprecation warnings.HMAC()on OpenSSL 1.x.NGX_HMAC_MD_SIZEnow abstractsEVP_MD_size(1.x) andEVP_MD_get_size(3.x).key.lenoverflow guards before narrowingsize_ttoint.Code Quality
(ngx_tm_t*)casts; used plainint*for%dcompatibility across platforms.%02dto%2dinsscanf. The0flag is aprintffeature and is ignored byscanf.(int)(ts_end - ts_start)instead of a hardcoded 25 bytes.cppcheck --enable=allwarnings by narrowing variable scopes and markingconstpointers.Documentation & Examples
CHANGELOG.md.secure_link_hmac: Separator is always a comma (hardcoded).secure_link_hmac_message: Separator is operator-defined (pipe, colon, slash, none, …).$secure_link_hmac,$secure_link_hmac_expires, and$secure_link_hmac_tokenregarding evaluation ordering.gmdate()toUTCString()isoformat()with'Z'suffix.