Open HoneyryderChuck opened 1 week ago
These classes need more careful review of each OpenSSL function. I haven't reviewed enough, but I can spot a few issues:
OpenSSL::X509::Certificate#tbs_bytes
calls i2d_re_X509_tbs()
, which has a side effect of refreshing DER-encoding cache.
OpenSSL::X509::Certificate#sign
modifies itself.
OpenSSL::X509::Name#to_der
seems to be unsafe when the object was previously modified: https://github.com/openssl/openssl/blob/ba6f115ccfbb63fbeb2bc8df3c07918a7a59a186/crypto/x509/x_name.c#L220-L227
The whole X509_NAME
appears to be not written with thread safety in mind.
Added frozen check for the mentioned functions in ossl_x509cert.c.
The whole X509_NAME appears to be not written with thread safety in mind.
Indeed. Zooming out a bit, perhaps we're better off just ensuring "shareable-when-frozen" only for certificates and crls? The whole point of the other objects is to use them to modify certs/crls via the setter methods that are now frozen-checked, so there doesn't seem to be a real usage for them outside of that use-case. LMK what you think.
Added frozen check for the mentioned functions in ossl_x509cert.c.
I have not reviewed other methods. Please check the manpage of each function and the implementation if necessary, as there are so many edge cases in OpenSSL. Not having "set" or "add" in a function name doesn't necessarily mean it is completely read-only.
Zooming out a bit, perhaps we're better off just ensuring "shareable-when-frozen" only for certificates and crls? The whole point of the other objects is to use them to modify certs/crls via the setter methods that are now frozen-checked, so there doesn't seem to be a real usage for them outside of that use-case. LMK what you think.
I don't agree it's the whole point, except for OpenSSL::X509::ExtensionFactory
that is indeed intended for building a certificate. That said, Name
, Attribute
, Revoked
, and Extension
are a non-reference-counted object and we can handle separately, after Certificate
, etc. are done.
Checked all openssl methods used in ossl_x509cert.c as well as ossl_x509crl.c , and found one method requiring frozen check (since fixed). Everything else seems to be safe (internal pointers, should not be freed by caller). Couldn't find documentation nor implementation for PEM_write_bio_X509
and i2d_X509
. Will check other classes some other time.
@rhenium I reviewed the documentation of the remainder of openssl functions used in the scope of these attributes, and while I tweaked/removed some of the previous additions, didn't spot anything particularly dangerous about the assumptions. Implementations may hide some details, but I'm a bit out of my depth navigating openssl code to judge that. But the Name#to_der example you referred to, assuming you mean that it's unsafe due to the modified
flag manipulation on encode, seems a bit concerning, as I don't see a way to work around that, and perhaps that limitation extends to other fields? This may mean that it's impossible to consider Ruby Certificate/CRLs shareable when frozen :/ .
What's really annoying is that OpenSSL's man pages often don't go so much into details. i2d_X509_NAME()
is an unsafe function that directly modifies its fields, and it takes a const pointer! There is no mention about that in the man pages. I think it can't be the only instance.
I checked about the subject and issuer name in certificates. OpenSSL::X509::Certificate#subject=
and #issuer=
use X509_set_*_name()
which encodes the name into the canonical (sorted) form and then copy, clearing the modified
flag, so OpenSSL::X509::Certificate
shouldn't be affected by this, at least in regards to these two fields.
Some part of OpenSSL::X509::Certificate
should be shareable, at least. OpenSSL::X509::Certificate#to_der
= i2d_X509()
is supposed to be thread safe even if it's not explicitly documented so. SSL_CTX
can be shared between threads, and that must be implying that i2d_X509()
can be called concurrently.
Please note that OpenSSL::X509::Certificate
and CRL
depend on OpenSSL::PKey::PKey
being shareable, which is not covered by this PR. I think pkeys can be assumed to be immutable in OpenSSL >= 3.0, but some work is needed for LibreSSL and older versions of OpenSSL.
Looking at your last comment, I believe we could go with the following compromise:
to_der
unsafe functions. I couldn't follow which internal functions * i2d_X509_ATTRIBUTE
and i2d_X509_REVOKED
call, but I suspect that safety won't be ensured by design.WDYT?
Considering we're discussing the semantics of freezing Certs/CRLs here.