-
Notifications
You must be signed in to change notification settings - Fork 112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose mTLS related APIs, introduce ForeignTypeExt + ForeignTypeRefExt, add corresponds macro #262
Conversation
c2993c6
to
c88f335
Compare
5419a22
to
df2386d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would probably be easier overall to review if the "corresponds" macro change was split in to a separate PR. It looks like github now allows you to review each commit individually (at least that's new to me) which is helpful though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah given how difficult it is to get reviews, I highly prefer leaving everything in one PR and relying on the per-commit diff viewer. I can update the title to be more sensible
unsafe { | ||
let ptr = cert_store.as_ptr(); | ||
cvt(ffi::SSL_set0_verify_cert_store(self.as_ptr(), ptr) as c_int)?; | ||
mem::forget(cert_store); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took a brief look at the manpage and it's not clear to me why we need to pass cert_store by value and then forget it, rather than just passing a reference. Is it just that this only happens once on startup and it's okay to leak? It might be nice to have a // SAFETY: block
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also for some reason when I inspect the first commit individually it says the function as a whole is new, but when I look at master it's already there and looking at the second commit it only shows the actual cert_store.as_ptr() change. weird.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On master you may be seeing the SSL_CTX_set0_verify_cert_store
variant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are generally two variants for each API - one that operates on SSL_CTX
(applies to the server generally), and another that operates on SSL
(connection specific)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re: calling mem::forget manually, it's a good question, but I'm mainly following prior art: https://github.com/sfackler/rust-openssl/blob/master/openssl/src/ssl/mod.rs#L3408-L3414
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To summarize: boringssl takes ownership of the X509Store
(as Rushil mentioned above) and gets freed by boringssl, which is why we use the 0 variant and forget the Rust struct. Thanks for taking the time to help me understand!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For posterity, this works by virtue of refcounted objects in c++. When initialized, a X509Store
will have a refcount of 1. Any time the destructor is called, the refcount will be decremented and checked against == 0
before the object is fully freed. By using the set0
variant of the API, we "hand off" the object at refcount == 1 to c++ and leave the memory's lifetime at mercy of the next destructor call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that this is a common pattern I still think it would be nice to document somewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intent should be conveyed by using <X509Store as ForeignType>::into_ptr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opened #267
df2386d
to
9017225
Compare
boring/src/x509/mod.rs
Outdated
/// | ||
/// This function will return `None` if the underlying string contains invalid utf-8. | ||
#[corresponds(X509_NAME_oneline)] | ||
pub fn oneline(&self) -> Option<String> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This API is technically deprecated by openssl, and its use is strongly discouraged. I'm probably going to remove it from this PR and call some unsafe code directly where I need to, until we're able to stop using this API entirely
boring/src/x509/mod.rs
Outdated
let out = CStr::from_ptr(ptr).to_str().map(|s| s.to_string()); | ||
// SAFETY: `X509_NAME_oneline` dynamically allocates memory for the string that's | ||
// ultimately returned. As such, it's the caller's responsibility to free that memory | ||
// after allocating an owned String in rust land. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be in the doc comment if user action is required?
E: oh I see, you mean the bindings, nvm
9017225
to
fd66d4c
Compare
`ForeignTypeExt` and `ForeignTypeRefExt` are inspired by sfackler/rust-openssl#1345, which make dealing with FFI safer and more ergonomic. The new APIs (e.g. from_const_ptr_opt`) also allow for gracefully handling instances where the initial API call results in `NULL`. Instead of crashing the program, `None` will be returned.
Our rustdocs are miserably broken. We manually link to openssl docs in most binding definitions, and openssl keeps changing their documentation URL, so in order to fix everything I'd have to touch every single binding definition in every single file. Instead, we should use the `corresponds` macro from the openssl-macros crate which nicely adds a link to the openssl documentation on our behalf. If the openssl documentation url ever changes again in the future, a simple dependency bump should solve the issue.
fd66d4c
to
786ee18
Compare
5129145
to
b2c1e4c
Compare
); | ||
|
||
unsafe { ffi::SSL_set_client_CA_list(self.as_ptr(), list.as_ptr()) } | ||
mem::forget(list); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this legitimate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SSL_set_client_CA_list
takes ownership of the list: https://github.com/google/boringssl/blob/master/include/openssl/ssl.h#L2966
Constructing the Stack<X509Name>
requires the application to own the Stack
, and the owned type will free the underlying memory if drop
is called. The general pattern here is to pass ownership to boringssl, and call mem::forget
to release that ownership without calling drop
and destroying the underlying stack
ForeignTypeExt
andForeignTypeRefExt
are inspired by sfackler/rust-openssl#1345, which make dealing with FFI safer and more ergonomic. The new APIs also allow for gracefully handling instances where the initial API call results inNULL