Hardening
- util/file, cache/file: harden file-backed metadata and cache I/O: refuse non-regular files, cap what a file read or a cache entry may allocate, and write metadata files atomically; operator-managed files (metadata, templates, keys) may still be symlinks, the module's own file-cache directory refuses them
- cache/shm: hash cache keys with a per-segment keyed SipHash so an outside party can no longer flood one bucket chain, reclaim expired entries before evicting live ones, size the segment overflow-safely and refuse a huge
OIDCCacheShmMax/OIDCCacheShmEntrySizeMaxat startup, and rate-limit the cache-pressure warning - session: killing a session no longer removes the per-user
sublogout index entry when it points at a newer session of the same user, which made a back-channel logout token carrying only asubsilently miss that session - proto/util: reject a duplicated security-critical protocol parameter (
state/code/access_token/id_tokenin an authorization response,access_tokenin a bearer-token request,logout_tokenin a back-channel logout) with a 400 instead of silently taking the last occurrence - metadata: fail the JWKs forced-refresh rate limit closed on a cache error and stop a throttled or failed refresh from falling through to a second fetch, so during a cache outage an unknown
kidon an unauthenticated request can no longer drive an outbound JWKs fetch per request - proto/jwt: retry a failed no-
kidsignature verification with a JWKs refresh only when the keys came from a JWKs URI: without one the retry handed the HTTP layer a NULL URL and slept through its retry back-off, a delay any client could trigger with a bad token on the back-channel logout or bearer-token endpoint - proto: compare and clamp JWT
exp/iatwithout an out-of-range cast toapr_time_t, so a far-future value ("exp":1e300) can no longer flip validity or wrap the session expiry per platform; a negative or non-finite timestamp is rejected - proto/handle: warn on a cache backend error behind nonce and back-channel-logout
jtireplay detection instead of ignoring it; replay detection still fails open - cache: NUL-terminate the file-cache value buffer so a corrupt or planted cache file cannot cause an over-read
- util: reject a value that is not an importable, GCM-authenticated JWE in
oidc_util_jwt_verifyinstead of returning it as verified
Bugfixes
- proto: parameters repeated within
OIDCAuthRequestParams/OIDCPathAuthRequestParams, or shared between the two (RFC 8707 sendsresourceonce per audience), were dropped by the duplicate guard introduced in 2.4.20.1; every configured occurrence is now sent - http: fix the chunked-cookie chunk count for a value whose length is an exact multiple of
OIDCSessionCookieChunkSize, which dropped the client-cookie session and sent the user round the login loop - http: return NULL when a chunked cookie is missing a chunk, so a broken cookie set re-authenticates instead of resubmitting a truncated value
- cache/redis: do not unlock the serialized-model process mutex twice when the retry backoff could not re-acquire it, which handed the shared connection to two threads at once
- cache/redis: flush the idle connection pool when a checked-out connection turns out dead, so a Redis restart or idle timeout no longer fails operations with Redis reachable
- jose: decide decompression from the payload and pass through what cannot be decoded: a brotli build reads uncompressed or zlib-written payloads again, and a raw cache value that merely looks zlib-framed is no longer destroyed
- jose: stream brotli decompression into a growing buffer; a payload compressing better than 4:1 was unreadable
- config: read the
<alg>[+<alg>...]@key-tuple prefix as an algorithm list only when every token names a known JOSE algorithm, so a kid containing@or a filename likecert@2024.peminOIDCPublicKeyFiles/OIDCPrivateKeyFiles/OIDC(Provider|OAuth)VerifyCertFilesno longer fails startup or truncates the kid - metadata: serve the validated in-memory provider metadata when only the disk write of its cache file failed, instead of failing the authentication
- metadata: fall back to the filename-derived issuer when a provider file has no
issuer, instead of crashing when listing providers - metadata: preserve an HTTP-only provider's scheme when listing providers from disk, instead of silently dropping it
- logout: zero the session struct in the back-/front-channel cleanup, so a stale sid/sub index entry cannot make token revocation read uninitialized memory
- session: fix a leak once per rejected read of a newer-format session payload in a mixed-version fleet
- session: store session timestamps as 64-bit seconds: an expiry after January 2038 wrapped negative and sent the user round the login loop; existing sessions are unaffected
- session: skip the prompt=none "user changed" check when there is no prior remote_user, so a first prompt=none response can establish a session
- http: destroy the pooled curl handles before
curl_global_cleanup(), which could crash a serving process (the Windows winnt MPM child,httpd -X) at shutdown or restart - http: bound the trailing CRLF strip of a captured response header to the value's length; an empty value read before the buffer
- revocation: require the
remove_at_cacheparameter before looking up the access token cache - DPoP: reject an omitted
token_typeexplicitly when DPoP is required, instead of passing NULL to the error message - util: remove the undocumented
OIDC_JWT_INTERNAL_STRIP_HDRenvironment variable, which was broken with a rotating (two-secret)OIDCCryptoPassphrase - userinfo: a UserInfo response that is not a JSON object (e.g. a top-level array) is no longer accepted as claims and falls through to JWT parsing as intended
- util/jose: a query string of only separators (
?&) no longer crashes the worker; the JWK Set parser no longer leaks already-parsed keys when a later key fails to parse - jose: fail the import of an RSA/EC key whose public components OpenSSL 3.x cannot supply, instead of crashing (OSS-Fuzz 550951150)
- jose: PEM-wrap an
x5cJWK element in linear instead of quadratic time and memory, so a provider-supplied key cannot exhaust a worker; likewise for preserved-POST parameters, the published JWKs document and hex encoding (OSS-Fuzz 551146117) - http: build the authorization request URL and POST auto-submit form in linear instead of quadratic time and memory, so many
auth_request_paramson a discovery response cannot exhaust a worker (OSS-Fuzz 551746349) - util: join array claims and propagate a token's claims in linear instead of quadratic memory and time, so a large or claim-heavy token from a provider or client cannot exhaust or stall a worker (OSS-Fuzz 554464974)
- http: redact logged request bodies and provider responses in linear instead of quadratic memory; the log arguments are rendered at any
LogLevel, so a provider response could exhaust a worker (OSS-Fuzz 554483423)
Other
- test: 19 fuzz targets covering the browser-facing endpoints and the JOSE, cookie and metadata parsers now run continuously on OSS-Fuzz
Commercial
- commercial subscription based support for large enterprise businesses is available via sales@openidc.com
- licensed binary packages for various other platforms such as Microsoft Windows, Red Hat Enterprise Linux 7, older Ubuntu and Debian distros, Oracle HTTP Server 12.x/14.x and IBM HTTP Server 9.x, are available under a commercial license and agreement via sales@openidc.com
- support for Redis/Valkey over TLS, Redis/Valkey (TLS) Sentinel, and Redis/Valkey (TLS) Cluster is available under a commercial license and agreement via sales@openidc.com
The RPM packages below are signed with the following RSA PGP key:
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBGh53lgBCADCyoOkfnE5h5rBLlf02oFpI/z2vUXK5W4T56xnNPu0/iIOxbBk
YX9rSypZFhfjv28lhGgelWEg28Ab/Yxs6l0obCgDEuFUDQ5Dv+N+YSMy67vtLwYW
9LM5p9fMN9bXOa62PwvtzRzh+xRyRBcIfMacGJC+SqUK6QhzC0lNwCsr1OaWjzon
mkaodwrloNMxEZVvFn63PvuQDZ3wwQty+0XpYiiChMssGBn6nmPDQJ7pDtQDkhfD
Z5FKY6K7AQJ4fneiVCLGngPBwTXBGcfWa+Y0HCS2ghQwDO6jYXd5GjowVDTjfMK3
QJ3e26Ox9X3V0Fl04R1i5EthEkAWGfy1lksvABEBAAG0HU9wZW5JREMgPHN1cHBv
cnRAb3BlbmlkYy5jb20+iQFRBBMBCgA7FiEEFdjWJA1IGDkAITSxnyZY1L0OSOMF
Amh53lgCGwMFCwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQnyZY1L0OSONG
Jgf+II0wG96R0g28Kp+R4AYzSdX0CEqr6OhwHHw4cFpLsHxZNhojo7I4OnLKEdfc
lFl37rE+hG3QpzD/b4S/fpPjd4hcLkguBQxtdxqZZVAIT8HWbveHRkI8MNnjOPwv
Hy6jBncMs1IT/URV2si/Q34+PLo8tvo/lXNa16svVl2DoYXO8MCszgCE1bx055EF
XPh4Teu5Y4OLHECSicMxrmN746dAD121zy4bLLx9mZ0erhLjvkj1vkFmlHFKyvwY
/pbSqXs9hW/wweW1oQ/xEIJWWS71PeoutUBjr0WC4sILnR5PBPZplgNh297Qex6g
qaW3io0tCH9KxU1tXYn/iL/hbQ==
=mlOy
-----END PGP PUBLIC KEY BLOCK-----