openssl icon indicating copy to clipboard operation
openssl copied to clipboard

OCSP signature verification discards OpenSSL error information

Open p-mongo opened this issue 5 years ago • 5 comments

In https://github.com/ruby/openssl/blob/master/ext/openssl/ossl_ocsp.c#L428-L429, ossl_ocspreq_verify does:

    if (result <= 0)
	ossl_clear_error();

return result > 0 ? Qtrue : Qfalse;

If the result is not successful, the error information is cleared. This makes it not available in OpenSSL.errors for inspection by the caller.

Response verification has the same issue.

To get this information, one needs to enable OpenSSL.debug prior to calling the verify method.

Example missing information:

(byebug) resp.verify([ca_cert], store)
Result: 0
false
(byebug) OpenSSL.errors 
[]
(byebug) resp.verify([ca_cert], store)
Result: 0
false
(byebug) OpenSSL.errors 
[]
(byebug) OpenSSL.debug=true
true
(byebug) resp.verify([ca_cert], store)
(byebug):1: warning: error on stack: error:27069065:OCSP routines:OCSP_basic_verify:certificate verify error (Verify error:self signed certificate)
Result: 0
false
(byebug) store.add_cert(ca_cert)
#<OpenSSL::X509::Store:0x00005630c0470120 @verify_callback=nil, @error=nil, @error_string=nil, @chain=nil, @time=nil>
(byebug) resp.verify [],store
(byebug):1: warning: error on stack: error:27069076:OCSP routines:OCSP_basic_verify:signer certificate not found
Result: 0
false
(byebug) resp.verify [ca_cert],store
Result: 1
true

Without the debug information, figuring out why verification failed is impractical.

One way of solving this is to provide a method like verify! which would raise an exception if verification fails, including the openssl error information into the method.

p-mongo avatar Aug 20 '20 16:08 p-mongo

Somewhat related: #312

rhenium avatar Aug 21 '20 04:08 rhenium

If the result is not successful, the error information is cleared. This makes it not available in OpenSSL.errors for inspection by the caller.

This is expected because OpenSSL.errors is meant for debugging this library, for issues like https://bugs.ruby-lang.org/issues/7215. If it ever returns a non-empty array, then there is a missing ossl_clear_error() call somewhere which is a bug that needs to be fixed.

Response verification has the same issue.

Actually, all verify methods in this library have the same issue. In my opinion, this is a design flaw and they could raise an exception on verification failure by default, but we can't fix it.

I don't like the name verify! as it is not "more dangerous" than the current verify. I can't come up with a better one, however.

rhenium avatar Aug 21 '20 05:08 rhenium

but we can't fix it

What is preventing adding new methods that raise exceptions?

p-mongo avatar Aug 27 '20 22:08 p-mongo

Nothing. It is just that we can't change the behavior of existing methods and verify! is not a good fit for the new name.

Two other easy ways I can think of:

  • obj.verify(..., exception: true) - similarly to IO#read_nonblock
  • Let ossl_clear_error() store the error information in thread/fiber-local storage and repurpose OpenSSL.errors to return it (given that nothing uses OpenSSL.errors for the current purpose, apart from Ruby/OpenSSL's regression test)

rhenium avatar Aug 29 '20 15:08 rhenium

I am happy to contribute an implementation. I don't understand what the conclusion/decision is in this ticket, if that is clarified I can look into typing the code up.

p-mongo avatar Aug 30 '20 20:08 p-mongo