-
Notifications
You must be signed in to change notification settings - Fork 722
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
feat(bindings): add external psk apis #5061
Conversation
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.
Some initial comments, I want to do another review but ran out of time for today.
// This type acts as if it owns a *mutable pointer to a zero sized type, where | ||
// that type may implement un-synchronized interior mutability. | ||
#[derive(Debug)] | ||
pub(crate) struct Opaque(PhantomData<UnsafeCell<*mut ()>>); |
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 type definition is pretty weird. *mut ()
already has !Send
/!Sync
impls... I guess the UnsafeCell is adding !Freeze
, but that shouldn't ever matter -- after all, this is a pointer to the opaque type, right?
I guess this gets used as &Opaque/&mut Opaque? I'd sort of expect either c_void
here or just struct $struct_name { _priv: () }
.
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 actually don't think that the UnsafeCell
adds !Freeze
.
Some interesting discussion here: sfackler/foreign-types#24
And also here: rust-lang/unsafe-code-guidelines#236 (comment)
I figured it was useful for documentation purposes. But I like the c_void
approach. Will take that in the next iteration.
} | ||
|
||
/// Advance the cursor, returning the currently selected PSK. | ||
pub fn advance(&mut self) -> Result<Option<&OfferedPsk>, crate::error::Error> { |
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 might call this next()
since it's basically the Iterator API, just a lending iterator which borrows from &self.
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 did consider that, but I worry that next
is a bit leading because it doesn't imply the side effect of updating the "currently selected" PSK.
* use &mut instead of addr_of * use null mut instead of cast * use Relaxed instead of SeqCst for single threaded atomics * min for safe cast to u16 * correct mut type * add non-exhaustive and debug to enum
* document not calling choose psk * accept mut reference
* add safety comment for slice from raw parts. * separate send + sync from macro
* return iterator over identities * add offered psk selector to prevent future breakage
/// Before calling [OfferedPskCursor::choose_current_psk], implementors must | ||
/// first append the corresponding [crate::external_psk::ExternalPsk] to the | ||
/// connection using [Connection::append_psk]. | ||
fn select_psk(&self, connection: &mut Connection, psk_list: &mut OfferedPskListRef); |
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.
Docs are stale (OfferedPskCursor vs OfferedPskListRef) -- but I'd avoid "Ref" in the type we expose to users, I'm not sure that's a good name.
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.
Updated the docs.
I agree that it's a mouthful, but I expect that we will be using the pattern more going forward (like the OpenSSL crate does), and if we use this pattern for a pointer that has two ownership modes, then I think the Ref
patten is the easiest way to distinguish them.
E.g. this pattern could be used for s2n_client_hello
// returns an owned struct with a drop impl that frees the `s2n_client_hello`
ClientHello::parse_client_hello -> ClientHello
// returns a "reference" created from the s2n_client_hello pointer. This can't be dropped, because the
// memory is owned by the connection. The "Ref" pattern ensures that.
connection.client_hello -> &ClientHelloRef
Although I can't imagine a scenario where we'd ever expose an owned OfferedPskList, so maybe the disambiguation isn't necessary? But the "Ref" approach seems to offer a bit more flexibility in the future, so I'm leaning towards that.
/// Choose the currently selected PSK to negotiate with. | ||
/// | ||
/// If no offered PSK is acceptable, implementors can return from the callback | ||
/// without calling this function to reject the connection. |
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.
If there were no offered PSKs, what is the behavior of calling choose_current_psk in the "-1" slot (i.e., immediately calling that on creation without calling next?).
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 is covered in the choose_empty_psk
test (renamed to choose_without_current_psk
). A well-formed error is returned by s2n-tls, although it's unfortunately an "internal error": #5085.
* callback/selectors typo * more explicit choose documentation * rename rewind to reset * reference the identity selector in the select_psk docs * use &mut instead of addr_of * rename using test to "without_current" psk
* context associated with callback should be derived from immutable ref
* remove foreign types module * remove macro * rename ExternalPsk -> Psk
pub fn append_psk(&mut self, psk: &Psk) -> Result<(), Error> { | ||
unsafe { | ||
// SAFETY: *mut cast - s2n-tls does not treat the pointer as mutable. | ||
s2n_connection_append_psk(self.as_ptr(), psk.as_s2n_ptr() as *mut _).into_result()? |
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 think it would be better to get the mutable pointer directly rather than casting *const
-> *mut
.
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.
Assumption: There is an intention that s2n-tls C API's be const correct, but we just aren't there yet.
Given that this takes a &Psk
, I wanted a visible red flag that we are casting away the "logical constness" of the underlying data.
Let me know if you think the the friction is causing more noise than safety, and I'll go ahead and make as_s2n_ptr_mut
take in &self
and just add a comment about the safety.
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 I worry about allowing *const
-> *mut
casts in general... I think it's better to just return the *mut
directly from NonNull
and have some safety comments around it all.
* rename external_psk module to psk
* remove monospaced api references
* rename builder methods to set_* * directly retrieve mutable pointer from `ptr` * add comment about safety/reason for doing so
Release Summary:
Add bindings for the External PSK functionality.
Description of changes:
This feature adds External PSK functionality to the s2n-tls bindings.
Update 2024-02-05: The refactor was a bit large, so I removed that from this PR and will be added it as a separate follow on.
Call-outs:
ExternalPSK
instead of justPSK
(Psk
?).callbacks
module rather than theexternal_psk
module which seems a little bit odd, but I think it's the option most consistent with the existing codebase.Testing
Unit tests are added covering the new functionality. Additionally, I wrote examples showing how to use this functionality, but it was a bit large to fit into one PR so you can see that here.
New APIs
Just listing the new public APIs methods here, from
cargo +stable public-api diff latest -p s2n-tls | grep "("
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.