feat(*) openssl 4.0#236
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates the library to support OpenSSL 4.x by introducing the OPENSSL_3X_UP and OPENSSL_4X version flags and replacing OPENSSL_3X checks across the codebase. It also refactors the certificate store tests to use a dynamically created temporary directory instead of the system's certificate directory. The review feedback highlights a logic bug in pkey.lua where the built-in type function is used instead of the local variable typ, a forward-compatibility concern in version.lua regarding the upper bound of OPENSSL_3X_UP, and a test reliability issue in store.t where temporary files are not cleaned up if assertions fail.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| if fmt == "JWK" and (typ == "pu" or type == "pr") and not OPENSSL_3X_UP then | ||
| return nil, "explictly load private or public key from JWK format is not supported on OpenSSL 1.1.1" | ||
| end |
There was a problem hiding this comment.
There is a logic bug in the conditional check on line 68. It uses the built-in Lua function type instead of the local variable typ (which is defined on line 63) when checking if the key type is "pr".\n\nBecause type is a function, type == "pr" will always evaluate to false, making the check completely ineffective for private keys ("pr"). This has been corrected to use typ instead, and the typo in the error message (explictly -> explicitly) has also been fixed.
if fmt == "JWK" and (typ == "pu" or typ == "pr") and not OPENSSL_3X_UP then\n return nil, "explicitly load private or public key from JWK format is not supported on OpenSSL 1.1.1"\n end
| OPENSSL_30 = version_num >= 0x30000000 and version_num < 0x30100000, | ||
| OPENSSL_3X = version_num >= 0x30000000 and version_num < 0x40000000, | ||
| OPENSSL_4X = version_num >= 0x40000000 and version_num < 0x50000000, | ||
| OPENSSL_3X_UP = version_num >= 0x30000000 and version_num < 0x50000000, |
There was a problem hiding this comment.
The variable OPENSSL_3X_UP is named with the _UP suffix, which conventionally indicates 'OpenSSL 3.0 and any newer version' (i.e., >= 3.0.0). However, the current implementation caps it at < 0x50000000 (OpenSSL 5.0). This means that when OpenSSL 5.0 is eventually released, OPENSSL_3X_UP will evaluate to false, and the library will fall back to legacy OpenSSL 1.1.1 code paths, which will fail.\n\nSince the provider-based architecture and EVP APIs introduced in OpenSSL 3.0 are expected to remain standard in 5.0 and beyond, removing the upper bound makes the library forward-compatible with future major versions of OpenSSL without requiring another global find-and-replace.
OPENSSL_3X_UP = version_num >= 0x30000000,
| myassert(s:load_directory(dir)) | ||
|
|
||
| local chain = myassert(s:verify(c, nil, true)) | ||
| ngx.say(#chain) | ||
|
|
||
| os.remove(path) | ||
| os.execute("rmdir " .. dir) |
There was a problem hiding this comment.
If s:load_directory or s:verify fails or throws an error, the test execution will terminate immediately, and the cleanup code (os.remove and os.execute(\"rmdir ...\")) will never be executed. This leaves temporary files and directories (certs7/ and the hashed certificate file) on the disk, which can pollute the test environment and cause subsequent test runs to fail or behave unpredictably.\n\nWrapping the test assertions in a pcall ensures that the cleanup code is always executed, and any caught error is rethrown afterward to correctly fail the test.
local ok, err = pcall(function()\n myassert(s:load_directory(dir))\n local chain = myassert(s:verify(c, nil, true))\n ngx.say(#chain)\n end)\n\n os.remove(path)\n os.execute("rmdir " .. dir)\n\n if not ok then\n error(err)\n end
There was a problem hiding this comment.
Pull request overview
This PR updates lua-resty-openssl to treat OpenSSL 4.x as part of the “provider-era” API surface (similar to 3.x), and adjusts the Lua bindings and test suite accordingly.
Changes:
- Extend OpenSSL version detection to recognize 4.x (
OPENSSL_4X) and introduce a “provider-era” gate (OPENSSL_3X_UP) used across the codebase. - Update provider-era feature gates throughout EVP/provider-dependent modules (cipher/digest/kdf/mac/pkey/x509/ssl/etc.) to allow OpenSSL 4.x.
- Refresh tests for OpenSSL 4.x behaviors and add flexibility for locating the
opensslCLI in SSL ctx server tests.
Reviewed changes
Copilot reviewed 50 out of 50 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| t/openssl/x509/store.t | Reworks directory-loading test to avoid system CA directories by writing a hashed cert file locally. |
| t/openssl/x509/extension.t | Adjusts extension expectations/validation for provider-era versions (3.x and 4.x). |
| t/openssl/version.t | Adds a test to classify OpenSSL 4.x as provider-era. |
| t/openssl/ssl/ssl_ctx_server.t | Allows overriding the openssl CLI path via env var for s_client probing. |
| t/openssl/provider.t | Updates provider-era gating from 3.x-only to 3.x-and-up (through 4.x). |
| t/openssl/pkey.t | Updates provider-era conditionals in key-related tests. |
| t/openssl/pkcs12.t | Updates legacy-provider load behavior gating for provider-era. |
| t/openssl/mac.t | Updates provider-era conditionals in MAC tests. |
| t/openssl/kdf.t | Updates provider-era conditionals in KDF tests. |
| t/openssl/helper.lua | Updates helper’s version flag name to provider-era gate. |
| t/openssl/digest.t | Updates provider-era conditionals in digest tests. |
| t/openssl/ctx.t | Updates provider-era conditionals in ctx tests. |
| t/openssl/cipher.t | Updates provider-era conditionals in cipher tests. |
| t/openssl/aux/jwk.t | Updates provider-era conditionals in JWK auxiliary tests. |
| t/openssl.t | Updates algorithm-listing tests to treat 4.x like provider-era. |
| t/fips.t | Updates FIPS-mode tests to treat 4.x like provider-era. |
| lib/resty/openssl/x509/store.lua | Switches X509 store ctx creation path to use provider-era gate for *_new_ex APIs. |
| lib/resty/openssl/x509/init.lua | Switches X509 object creation and digest sizing to provider-era gate. |
| lib/resty/openssl/x509/extension.lua | Enables issuer_pkey plumbing for provider-era (3.x/4.x). |
| lib/resty/openssl/x509/csr.lua | Switches CSR creation to provider-era gate for *_new_ex APIs. |
| lib/resty/openssl/x509/crl.lua | Switches CRL creation to provider-era gate for *_new_ex APIs. |
| lib/resty/openssl/version.lua | Adds libcrypto .so.4 lookup and defines OPENSSL_4X / OPENSSL_3X_UP. |
| lib/resty/openssl/ssl.lua | Switches peer-certificate accessor to provider-era gate (SSL_get1_peer_certificate). |
| lib/resty/openssl/rand.lua | Switches RAND_bytes path to provider-era gate for *_ex APIs. |
| lib/resty/openssl/provider.lua | Expands provider module support gate from 3.x-only to provider-era (3.x/4.x). |
| lib/resty/openssl/pkey.lua | Expands provider-era checks for EVP/pkey behaviors and legacy APIs. |
| lib/resty/openssl/pkcs12.lua | Switches PKCS12 creation path to provider-era gate for *_create_ex. |
| lib/resty/openssl/mac.lua | Expands EVP_MAC availability gate to provider-era. |
| lib/resty/openssl/kdf.lua | Expands provider-era path (fetch APIs, HKDF sizing) to cover 4.x. |
| lib/resty/openssl/include/x509/extension.lua | Expands provider-era cdefs to cover 4.x. |
| lib/resty/openssl/include/x509/csr.lua | Expands provider-era cdefs to cover 4.x. |
| lib/resty/openssl/include/x509_vfy.lua | Expands provider-era cdefs to cover 4.x. |
| lib/resty/openssl/include/ssl.lua | Expands provider-era SSL cdefs to cover 4.x. |
| lib/resty/openssl/include/rand.lua | Expands provider-era RAND cdefs to cover 4.x. |
| lib/resty/openssl/include/pkcs12.lua | Expands provider-era PKCS12 cdefs to cover 4.x. |
| lib/resty/openssl/include/evp/pkey.lua | Expands provider-era EVP_PKEY cdefs to cover 4.x. |
| lib/resty/openssl/include/evp/md.lua | Expands provider-era EVP_MD cdefs to cover 4.x. |
| lib/resty/openssl/include/evp/kdf.lua | Expands provider-era KDF cdefs to cover 4.x. |
| lib/resty/openssl/include/evp/cipher.lua | Expands provider-era cipher cdefs to cover 4.x. |
| lib/resty/openssl/include/evp.lua | Expands provider-era EVP feature gating and legacy constants to cover 4.x. |
| lib/resty/openssl/include/err.lua | Expands provider-era ERR cdefs to cover 4.x. |
| lib/resty/openssl/include/asn1.lua | Expands provider-era ASN.1 _new_ex declarations to cover 4.x. |
| lib/resty/openssl/hmac.lua | Switches digest sizing helper to provider-era gate. |
| lib/resty/openssl/err.lua | Switches ERR formatting path to provider-era gate. |
| lib/resty/openssl/digest.lua | Switches EVP_MD fetch + provider-name paths to provider-era gate. |
| lib/resty/openssl/ctx.lua | Expands ctx module support gate to provider-era (3.x/4.x). |
| lib/resty/openssl/cipher.lua | Switches cipher fetch + sizing + provider-name paths to provider-era gate. |
| lib/resty/openssl/auxiliary/nginx.lua | Rewraps long conditional lines for readability (no functional change intended). |
| lib/resty/openssl/auxiliary/jwk.lua | Expands JWK load helper selection to provider-era (3.x/4.x). |
| lib/resty/openssl.lua | Expands module loading and provider-era features (provider/mac/ctx/kdf list) to cover 4.x. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if fmt == "JWK" and (typ == "pu" or type == "pr") and not OPENSSL_3X_UP then | ||
| return nil, "explictly load private or public key from JWK format is not supported on OpenSSL 1.1.1" | ||
| end |
| function _M.set_default_properties(props) | ||
| if not OPENSSL_3X then | ||
| if not OPENSSL_3X_UP then | ||
| return nil, "openssl.set_default_properties is only not supported from OpenSSL 3.0" | ||
| end |
| local dir = "certs7" | ||
| os.execute("mkdir -p " .. dir) | ||
| local path = string.format("%s/%08x.0", dir, | ||
| tonumber(ffi.C.X509_subject_name_hash(c.ctx))) | ||
| local cert_file = assert(io.open(path, "w")) | ||
| cert_file:write(c:tostring()) | ||
| cert_file:close() | ||
|
|
||
| myassert(s:load_directory(dir)) | ||
|
|
||
| local chain = myassert(s:verify(c, nil, true)) | ||
| ngx.say(#chain) | ||
|
|
||
| os.remove(path) | ||
| os.execute("rmdir " .. dir) |
86e24d6 to
9e537b4
Compare
45a932f to
d3b2263
Compare
No description provided.