Conversation
…fix bugs, and fix todos
…nnection_integration
src/rpc.rs
Outdated
| @@ -1,14 +1,15 @@ | |||
| // TODO: replace this with amino | |||
There was a problem hiding this comment.
Can probably get rid of this, eh?
|
Just made an issue to summarize where we're at (to my knowledge) per request at the tendermint meeting: tendermint/tendermint#2039 |
- fix DH key exchange: order of local and remote key were mixed up, which made the secrent connection and the challenge signature verification fail - fix seal_in_place: we were calling it on `sealed_frame` which was all zeroes -> now it contains the frame data - fix decoding of remote_eph_pubkey (start with an empty buffer instead of appending to it); prev. caused secret connection decryption error - decoding chunk len specifier (4 not 2 bytes) - switch from u32 -> usize to avoid a bunch of unnecessary casts - delete unused code - add a simple test
src/main.rs
Outdated
| @@ -1,8 +1,10 @@ | |||
| //! Key Management System for Cosmos Validators | |||
| //! key Management System for Cosmos Validators | |||
src/secret_connection.rs
Outdated
| chunk.clone_from_slice( | ||
| &frame_copy | ||
| [DATA_LEN_SIZE ..(DATA_LEN_SIZE + chunk_length as usize)], | ||
| &frame_copy[DATA_LEN_SIZE..(DATA_LEN_SIZE + chunk_length as usize)], |
There was a problem hiding this comment.
I'd suggest using checked arithmetic throughout this module to avoid potential integer overflow issues, i.e.
&frame_copy[DATA_LEN_SIZE..(DATA_LEN_SIZE.checked_add(chunk_length).unwrap() as usize)]There was a problem hiding this comment.
Good point! I changed all constants which will mostly be used as usize to actually being usizes. So I changed the above to DATA_LEN_SIZE.checked_add(chunk_length as usize).unwrap(), where chunk_length is read from 4 bytes. So the inner cast should be fine.
src/secret_connection.rs
Outdated
| let mut cnt = 0; | ||
| while 0 < data_copy.len() { | ||
| cnt+=1; | ||
| cnt += 1; |
There was a problem hiding this comment.
Would suggest:
cnt = cnt.checked_add(1).unwrap();
There was a problem hiding this comment.
I've deleted cnt because it wasn't used anywhere. But good to know!
- establish secret connection - send message over sc (poison pill to stop process)
|
Interestingly, now circleci fails on subtle 0.3.0 (rustc 1.27.1). Regarding the secret connection integration: As the signing logic isn't ready yet, I changed the integration test basically being about establishing a secret connection and and let the server handle a simple message (namely, the |
Cargo.toml
Outdated
| chrono = "0.4.2" | ||
| byteorder = "^1.2" | ||
| lazy_static = "1.1.0" | ||
| x25519-dalek = "^0.1" |
There was a problem hiding this comment.
It looks like this is an old version and that's what's causing it to pull in an old version of subtle. Can you bump this to 0.3? (the ^ is also unnecessary as Cargo is semver-by-default)
There was a problem hiding this comment.
Thanks, updated x25519-dalek to 0.3 and randto0.5`. This still fails on stable.
Cargo.toml
Outdated
| chrono = "0.4.2" | ||
| byteorder = "^1.2" | ||
| lazy_static = "1.1.0" | ||
| x25519-dalek = "0.3" |
There was a problem hiding this comment.
It looks like x25519-dalek enables its nightly feature (and vicariously subtle's nightly feature) by default (which is probably a mistake/oversight):
https://github.com/dalek-cryptography/x25519-dalek/blob/2abfb37/Cargo.toml#L38
I think this will fix it:
x25519-dalek = { version = "0.3", default-features = false, features = ["std", "u64_backend"] }There was a problem hiding this comment.
Thanks, that fixes that indeed (at least locally it works now).
src/secret_connection.rs
Outdated
| // increment nonce big-endian by 2 with wraparound. | ||
| fn incr_nonce(nonce: &mut [u8; 12]) { | ||
| for i in (0..AEAD_NONCE_SIZE).rev() { | ||
| nonce[i] += 1; |
There was a problem hiding this comment.
---- secret_connection::tests::test_incr_nonce stdout ----
thread 'secret_connection::tests::test_incr_nonce' panicked at 'attempt to add with overflow', src/secret_connection.rs:356:9
I think this would be a lot clearer (and panic-free!) if you just kept an internal 64-bit counter and used BigEndian::write_u64 (from the byteorder crate) to serialize it.
That'd also make it easier to switch to little endian, if there's still time to do that 😉
|
It's green! Woohoo!
@liamsi I think it's fine to land this on Will go through it and leave some notes. |
src/secret_connection.rs
Outdated
| } | ||
| } | ||
|
|
||
| impl<IoHandler: io::Read + io::Write + Send + Sync> io::Write for SecretConnection<IoHandler> { |
There was a problem hiding this comment.
Suggestion:
impl<IoHandler> io::Write for SecretConnection<IoHandler>
where
IoHandler: : io::Read + io::Write + Send + Sync>
{
src/secret_connection.rs
Outdated
| if !self.recv_buffer.is_empty() { | ||
| let n = cmp::min(data.len(), self.recv_buffer.len()); | ||
| data.copy_from_slice(&self.recv_buffer[..n]); | ||
| let mut leftover_portion = vec![0; self.recv_buffer.len() - n]; |
There was a problem hiding this comment.
Would suggest checked arithmetic everywhere (really wish clippy had a lint for this):
let mut leftover_portion = vec![0; self.recv_buffer.len().checked_sub(n).unwrap()];
src/secret_connection.rs
Outdated
| } | ||
| } | ||
|
|
||
| impl<IoHandler: io::Read + io::Write + Send + Sync> io::Read for SecretConnection<IoHandler> { |
There was a problem hiding this comment.
Suggestion:
impl<IoHandler> io::Read for SecretConnection<IoHandler>
where
IoHandler: : io::Read + io::Write + Send + Sync
{
src/secret_connection.rs
Outdated
| let in_out = &mut out[..ciphertext.len()]; | ||
| in_out.copy_from_slice(ciphertext); | ||
| let len = aead::open_in_place(opening_key, nonce, authtext, 0, in_out) | ||
| .map_err(|_| ())? |
There was a problem hiding this comment.
I think it'd be good to define an ErrorKind variant for MAC verification errors (perhaps VerificationError or CryptoError?) and use an Error here
src/secret_connection.rs
Outdated
|
|
||
| fn open( | ||
| opening_key: &aead::OpeningKey, | ||
| nonce: &[u8; 12], |
There was a problem hiding this comment.
Given opening_key and nonce both come from SecretConnection, any reason to not make this a private method on SecretConnection? It looks like a corresponding seal() method could be useful too.
src/secret_connection.rs
Outdated
| } | ||
| let chunk_length = chunk.len(); | ||
|
|
||
| BigEndian::write_u32_into(&[chunk_length as u32], &mut frame[..DATA_LEN_SIZE]); |
There was a problem hiding this comment.
You should be able to just use BigEndian::write_u32 here and avoid boxing chunk_length in an array
src/secret_connection.rs
Outdated
| // end encryption | ||
|
|
||
| self.io_handler.write_all(&sealed_frame)?; | ||
| n += chunk.len(); |
There was a problem hiding this comment.
Suggest checked arithmetic:
n = n.checked_add(chunk.len()).unwrap();
src/secret_connection.rs
Outdated
| } | ||
|
|
||
| // increment nonce big-endian by 2 with wraparound. | ||
| fn incr_nonce(nonce: &mut [u8; 12]) { |
There was a problem hiding this comment.
I'd suggest replacing this with a u64 counter, and using BigEndian::write_u64 to serialize it. To fill a 96-bit nonce, you can fill the first 32-bits with zeroes, e.g.:
struct Nonce(pub [u8; 12]);
impl From<u64> for Nonce {
fn from(counter: u64) -> Nonce {
let mut nonce = [0u8; 12];
BigEndian::write_u64(counter, &mut nonce[4..]);
Nonce(nonce)
}
}Or if you're really into doing arithmetic on byte arrays, you could do it like this:
struct Nonce(pub [u8; 12]);
impl Default for Nonce {
fn default() {
Nonce([0u8; 12])
}
}
impl Nonce {
fn increment(&mut self) {
let counter = BigEndian::read_u64(&self.0[4..]);
BigEndian::write_u64(counter.checked_add(1).unwrap(), &mut self.0[4..]);
}
}There was a problem hiding this comment.
Thanks!
I went with the 2nd approach but changed increment to behave exactly as the golang implementation (which makes another counter for the 1st 4 bytes necessary). If you think we should stick with 64 bits, I'll quickly change it. See 2e5d98f
There was a problem hiding this comment.
I think it's a lot simpler to just use a 64-bit integer (and panic on overflow). The chances of overflowing one in practice actually sending network messages are practically nonexistent (and you should rekey long before that anyway).
There was a problem hiding this comment.
OK, will change to 64 bits and update the tests.
- improve increment nonce situation: - suggestion changed slightly to match with the behaviour in golang - use `impl ... for ... where ...`
- add ErrorKind AuthCryptoError - wrap it with an io::Error in Read / Write - add seal and open methods to SecretConnection - cargo fmt
(review comment)
This is still a work in progress.
It depends on
Improve SecretConnection/STS KDF? tendermint#1165secret connection update tendermint#2054 (?)To Dos
I'll add additional to dos as i think of them.
But this should be much easier to get help on now as well.