Skip to content

Commit

Permalink
Add more Secure Session tests (#376)
Browse files Browse the repository at this point in the history
* Reorder method declarations in SecureSessionTransport

Move the required method get_public_key_for_id() first in the trait
definition. This has no semantic meaning but it's important for IDE
autocomplete or example, rustdoc also uses this order, and this is
the order which is most likely to be used by users when defining
transport implementations.

* Add Debug, Clone, Copy impls to SecureSessionState

Every public struct or enum should have a Debug implementation for
logging whatnot, so add it. It is also sometimes useful to copy the
state in the state reporting callback, so add Clone and Copy impls.
This enum is likely to stay simple so copying is cheap.

* Add MockTransport for testing Secure Session

Rust does not have an established popular mocking framework, and mock
objects are generally frowned upon in tests. However, sometimes they
are useful, and the current practice is to roll out your own mocks.

Introduce a simple implementation of SecureSessionTransport based on
closures. This allows to reimplement and change behavior at run-time.

* Replace DummyTransport with MockTransport

Its functionality can be easily reimplemented with a simple utility
that sets the get_public_key_for_id callback to recognize a single
peer and return its public key.

Drop the comments about RSA keys. It is now impossible to pass RSA
keys instead of ECDSA to Secure Session.

* Replace ChannelTransport with MockTransport

Again, we can easily reimplement ad-hoc ChannelTransport with a similar
ad-hoc function that sets up the same communication channel between two
Secure Sessions. The test code is now a bit easier to follow with this
change.

* Test failures in get_public_key_for_id

Both Secure Sessions should fail at connection negotiation stage with
ErrorKind::SessionGetPublicKeyForIdError if any of them does not
recognize its peer by an ID.

* Test reporting connection state in state_changed callback

Check that state changes are reported at correct moment. We use
channels to transport state reports out of a closure. It's a bit
tricky to do otherwise to satisfy the borrow checker.

* Test failures in send/receive callbacks

Check that errors reported from send_data and receive_data callbacks
are correctly forwarded to the user (and that they actually cause
connection failure).

We use yet another tricky setup with channels to override the behavior
of MockTransport. The channels are used to pass one-shot closures that
describe the behavior of the next call to callback. The callbacks then
revert to their previous behavior if there are no pending 'behavior
overrides'. This can be used to test multiple failures in the future.

* Test empty message handling

Secure Session cannot send or receive empty messages for security
reasons because empty message does not contain any authentication
information.

Verify that Secure Session reports errors when the user tries to send
and empty message or when the transport layer returns an empty message.
  • Loading branch information
ilammy authored Feb 12, 2019
1 parent a7dee76 commit 8d47b40
Show file tree
Hide file tree
Showing 2 changed files with 595 additions and 112 deletions.
12 changes: 6 additions & 6 deletions src/wrappers/themis/rust/src/secure_session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ struct SecureSessionContext {
/// [`get_public_key_for_id`]: trait.SecureSessionTransport.html#tymethod.get_public_key_for_id
#[allow(unused_variables)]
pub trait SecureSessionTransport {
/// Get a public key corresponding to a peer ID.
///
/// Return `None` if you are unable to find a corresponding public key.
fn get_public_key_for_id(&mut self, id: &[u8]) -> Option<EcdsaPublicKey>;

/// Send the provided data to the peer, return the number of bytes transferred.
///
/// This callback will be called when Secure Session needs to send some data to its peer.
Expand Down Expand Up @@ -97,11 +102,6 @@ pub trait SecureSessionTransport {
///
/// This method is truly optional and has no effect on Secure Session operation.
fn state_changed(&mut self, state: SecureSessionState) {}

/// Get a public key corresponding to a peer ID.
///
/// Return `None` if you are unable to find a corresponding public key.
fn get_public_key_for_id(&mut self, id: &[u8]) -> Option<EcdsaPublicKey>;
}

/// Transport layer error.
Expand Down Expand Up @@ -220,7 +220,7 @@ impl TransportError {
}

/// State of Secure Session connection.
#[derive(PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SecureSessionState {
/// Newly created sessions start in this state.
Idle,
Expand Down
Loading

0 comments on commit 8d47b40

Please sign in to comment.