Skip to content
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

Wireguard Review 2021-03-12 #1

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
Draft

Conversation

nickray
Copy link
Member

@nickray nickray commented Mar 12, 2021

No description provided.

Comment on lines +235 to +244
let mut arr : [u8; 32] = [0;32];
let chars = hex::decode( s);

for (index, c) in chars.unwrap().iter().enumerate()
{
arr[index] = c.clone();
}

return Ok(arr.clone())
}
Copy link
Member Author

@nickray nickray Mar 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try getting acquainted with "standard Rust traits", mainly From/Into and their fallible variants TryFrom/TryInto.

Also combinators on Result, such as map/map_err, and the ? operator.

The key to readable/idiomatic Rust code (in my opinion) is to separate data conversion (such as this) from program logic.

E.g. here something like:

let decoded = hex::decode(s)
use core::conver::TryFrom;
let arr: [u8; 32] = decoded.try_int().map_err(|_| anyhow::anyhow!("String too long"))?;
Ok(arr)

You can also always run cargo clean; cargo clippy to get hints from the compiler. E.g. bytes are Copy, so these clones are redundant.

Comment on lines +179 to +184
let pin = match command.value_of("PIN") {
Some(s) => {s},
None => {return Err(anyhow::anyhow!("Could not parse pin"));}

};
return Ok(WgCommand::Unlock(Unlock {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just stylistic, but similar to the hex_string_to32_char_array below, combinators compactify this kind of thing:

let pin = command.value_of("PIN").ok_or_else(|| anyhow::anyhow!("Could not parse pin"))?.to_string();
return Ok(WgCommand::Unlock(Unlock { pin }))

Note that return is usually only used for explicit early error returns, if you can setup the code that the main Result of the function is "at then end", you can leave out the return keyword.

//setup wireguard
let trussed_platform_wg = platform::init_platform(state_file.clone());
let mut trussed_service_wg = trussed::service::Service::new(trussed_platform_wg);
let client_id_wg = "wireguard";
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use wg here, as this client ID goes in all filenames on the flash. Premature optimization probably xD

Comment on lines +55 to +57
match wg_command {
wireguard::WgCommand::Unlock(unlock) =>
{
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A pattern I use here is bringing all the enum variants in scope:

use wireguard::WgCommand::*;
match command {
  Unlock(unlock) => (...)

Also, generally it's a C-ism to use prefixes like wg_ or Wg. When the WgCommand is already in the wireguard module, it's clear that wireguard::Command refers to a WireGuard command. If you want to import without the module path prefix, you can do that at call site: use wireguard::Command as WgCommand.

src/main.rs Outdated
Comment on lines 66 to 68
{

}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd put a todo!("handle Command::UpdateKeypair") or similar here, instead of an empty match.

Comment on lines +24 to +29
Perhaps not interesting for NPX:

set time - No RTC available on the STM32, that was capable of incrementing a day/month/year.
Restricted to time exclusively. Solution: transmit the current epoch and extract the date.

get time - get the device time. Mostly to check, whether a new timestamp is needed.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand this. I'd never rely on an RTC if this is about a timestamp that's relevant to the protocol, this should come from a desktop/client (which hopefully has some kind of NTP set up).


no permissions / unknown user :

Authenticate params: PIN/pass - Unlocks the device to use it.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just FYI, I am planning to add a "global PIN" to Trussed, so apps don't necessarily have to do their own PIN handling. Depending on the app, they of course may choose to do so all the same.

#[allow(missing_docs)]
pub struct GetAead
{
pub pubkey: [u8;SIZE_PUBKEY],
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally this is a newtype PublicKey([u8; SIZE_PUBKEY]), with appropriate TryFrom/TryInto implementations (possibly also normal constructors inherent to the struct, not coming from traits). The idea being that by making the inner array not pub, the constructor/converter can enforce validity of the data (e.g., the bag-of-bytes is a valid point on the curve).

{
pub privkey : [u8; SIZE_PRIVKEY],
pub pubkey : [u8; SIZE_PUBKEY],
pub label : String
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not wrong to start using heapless::String<CAPACITY> soon-ish, as you won't have alloc::String on the device.

Comment on lines +159 to +163
impl core::fmt::Display for AEAD {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:x?}", self.0)
}
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems more like a Debug impl to me than a Display (which is intended for final / user-facing representation).

src/wireguard.rs Outdated

impl core::fmt::Display for KeyResponse {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:x?} w/ UID: {} pubkey : {:x?}", self.key_info.id, self.key_info.label, self.key_info.pubkey)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, seems more Debug than Display. In any case, might be useful to look at https://doc.rust-lang.org/std/fmt/struct.Formatter.html#method.debug_struct if you're not aware.

src/wireguard.rs Outdated

pub fn unlock(&mut self, parameters: &Unlock) -> Result<()> {

print!("Unlock called: {:?}", parameters);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest using our delog library for this. Possibly needs out-of-band discussion to explain how to use. The point is, it will let you have debug!, info! etc. calls in the code that get completely compiled out, unless explicitly opted in from the runner.

src/wireguard.rs Outdated
return KeyResponse
*/

Ok(KeyResponse{ key_info : KeyInfo{ pubkey : [0;32], id : 0, label : String::from("A key label!")}})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should definitely be some kind of check on the pubkey here.

Copy link
Member Author

@nickray nickray left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some feedback.

@nickray nickray changed the title Wireguard WIP Wireguard Review 2021-03-12 Mar 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants