[LOW] gnutls ocsp stapling: multi-record status misbinding can bypass revocation

hi Gnutls,

gnutls matches a stapled ocsp response to the server certificate by scanning SingleResponse records, but then reads cert_status from record index 0 unconditionally. when a multi-record ocsp response is stapled such that record 0 is for a different certificate (good) and the matching record for the server certificate is later (revoked), a client with ocsp verification enabled can accept a revoked server certificate. this is observable as an order-dependent accept/reject outcome for the same revoked server certificate.

severity

HIGH

relevant links

  • repo: https://gitlab.com/gnutls/gnutls
  • commit: 165ae258
  • file: lib/cert-session.c (check_ocsp_response)

root cause

in check_ocsp_response(), the code finds the matching record index via gnutls_ocsp_resp_check_crt(resp, resp_indx, cert) but later consumes status/time fields via gnutls_ocsp_resp_get_single(resp, 0, ...), ignoring resp_indx. this breaks the binding between “matched record” and “enforced status”.

impact

revocation enforcement can be bypassed for clients and applications that enable ocsp stapling verification, allowing a server to present a revoked certificate while still passing verification depending on ocsp record ordering.

proof of concept

unzip poc.zip -d poc
cd poc
bash ./canonical.sh

expected:

[CALLSITE_HIT]: check_ocsp_response :: matched record index != 0 (multi-record) but cert_status is read from index 0 [PROOF_MARKER]: revoked server cert accepted when revoked ocsp record is not index 0 (multi-record stapled ocsp)

unzip poc.zip -d poc
cd poc
bash ./control.sh

expected:

[NC_MARKER]: revoked server cert rejected when revoked ocsp record is index 0 (environment sanity check)

expected: if the stapled ocsp response contains a revoked status for the server certificate, the client must reject, independent of the record ordering. actual: the client can accept a revoked server certificate when the revoked record is not index 0.

recommended fix

use the matched record index (resp_indx) when calling gnutls_ocsp_resp_get_single() in check_ocsp_response(), and add a regression test covering a multi-record response where the server cert record is not index 0 and is revoked.

credit: 1seal (https://github.com/1seal)

cheers, Oleh Konko

poc.zip

PR_DESCRIPTION.md

attack_scenario.md

Assignee Loading
Time tracking Loading