Skip to content

ocsp: fix uninitialized variables in BasicResponse#status#1004

Merged
rhenium merged 1 commit intoruby:masterfrom
swhitt:fix-ocsp-basic-response-uninitialized-revtime
Feb 16, 2026
Merged

ocsp: fix uninitialized variables in BasicResponse#status#1004
rhenium merged 1 commit intoruby:masterfrom
swhitt:fix-ocsp-basic-response-uninitialized-revtime

Conversation

@swhitt
Copy link
Contributor

@swhitt swhitt commented Feb 16, 2026

BasicResponse#status raises OpenSSL::ASN1::ASN1Error: ASN1_TIME_to_tm for any OCSP response with a GOOD or UNKNOWN certificate status. REVOKED works fine.

I hit this while checking OCSP status for google.com.

Minimal reproduction:

require "openssl"
# Ruby 4.0.1, openssl gem 4.0.0, OpenSSL 3.6.1

key = OpenSSL::PKey::RSA.generate(2048)
ca = OpenSSL::X509::Certificate.new.tap { |c|
  c.subject = c.issuer = OpenSSL::X509::Name.parse("/CN=CA")
  c.serial, c.version, c.public_key = 1, 2, key
  c.not_before, c.not_after = Time.now, Time.now + 86400
  c.sign(key, "SHA256")
}

cid = OpenSSL::OCSP::CertificateId.new(ca, ca)
bres = OpenSSL::OCSP::BasicResponse.new
bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, nil)
bres.sign(ca, key)

bres.status # => OpenSSL::ASN1::ASN1Error: ASN1_TIME_to_tm

Querying Google's OCSP responder:

require "openssl"
require "net/http"

sock = TCPSocket.new("google.com", 443)
ctx = OpenSSL::SSL::SSLContext.new
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
ctx.cert_store = OpenSSL::X509::Store.new.tap(&:set_default_paths)
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
ssl.hostname = "google.com"
ssl.connect
cert, issuer = ssl.peer_cert_chain[0..1]
ssl.close; sock.close

cid = OpenSSL::OCSP::CertificateId.new(cert, issuer, OpenSSL::Digest.new("SHA1"))
req = OpenSSL::OCSP::Request.new
req.add_certid(cid)

uri = URI("http://o.pki.goog/we2")
resp = Net::HTTP.new(uri.host, uri.port).post(uri.path, req.to_der, "Content-Type" => "application/ocsp-request")
basic = OpenSSL::OCSP::Response.new(resp.body).basic

basic.verify([issuer], ctx.cert_store) # => true (response is valid)
basic.status                           # => OpenSSL::ASN1::ASN1Error: ASN1_TIME_to_tm

Cause / fix - In ossl_ocspbres_get_status(), revtime is declared but not initialized before being passed to OCSP_single_get0_status():

ASN1_TIME *revtime, *thisupd, *nextupd;
int reason;

int status = OCSP_single_get0_status(single, &reason, &revtime, &thisupd, &nextupd);
// ...
rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil);

For GOOD and UNKNOWN, OpenSSL's OCSP_single_get0_status doesn't write to revtime (only REVOKED does). So revtime holds whatever was on the stack, the nil guard passes, and asn1time_to_time dereferences a garbage pointer.

The fix initializes all four variables before the call. Also adds test coverage for BasicResponse#status with GOOD and REVOKED status. Previously, no tests exercised this method (existing tests use BasicResponse#responses instead).

revtime, thisupd, nextupd, and reason are not initialized before
being passed to OCSP_single_get0_status(). For GOOD and UNKNOWN
status, OpenSSL doesn't write to revtime or reason (only REVOKED
does), so they keep whatever was on the stack. The nil guard
`revtime ? asn1time_to_time(revtime) : Qnil` then tries to
convert a garbage pointer, which blows up with ASN1_TIME_to_tm.

Initialize all four to safe defaults before the call.
@swhitt swhitt force-pushed the fix-ocsp-basic-response-uninitialized-revtime branch from 3a2ab96 to 667ce07 Compare February 16, 2026 15:59
Copy link
Member

@rhenium rhenium left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this!

Commit 7e0288e introduced this regression, which is in v4.0.0.

@rhenium rhenium merged commit 93d79fc into ruby:master Feb 16, 2026
47 of 48 checks passed
@swhitt swhitt deleted the fix-ocsp-basic-response-uninitialized-revtime branch February 16, 2026 17:02
@swhitt
Copy link
Contributor Author

swhitt commented Feb 16, 2026

Rebased to include a fix for the openssl-master CI failure (-Werror=discarded-qualifiers in ossl_pkcs7.c and ossl_x509attr.c due to OpenSSL master constifying PKCS7_get_signed_attribute(), X509_ATTRIBUTE_get0_object(), and X509_ATTRIBUTE_get0_type() return types).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants