-
Notifications
You must be signed in to change notification settings - Fork 5
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
base: main
Are you sure you want to change the base?
Conversation
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()) | ||
} |
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.
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.
let pin = match command.value_of("PIN") { | ||
Some(s) => {s}, | ||
None => {return Err(anyhow::anyhow!("Could not parse pin"));} | ||
|
||
}; | ||
return Ok(WgCommand::Unlock(Unlock { |
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.
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"; |
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.
Could use wg
here, as this client ID goes in all filenames on the flash. Premature optimization probably xD
match wg_command { | ||
wireguard::WgCommand::Unlock(unlock) => | ||
{ |
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.
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
{ | ||
|
||
} |
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'd put a todo!("handle Command::UpdateKeypair")
or similar here, instead of an empty match.
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. |
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.
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. |
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.
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], |
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.
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 |
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.
Probably not wrong to start using heapless::String<CAPACITY>
soon-ish, as you won't have alloc::String
on the device.
impl core::fmt::Display for AEAD { | ||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
write!(f, "{:x?}", self.0) | ||
} | ||
} |
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 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) |
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.
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); |
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'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!")}}) |
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 should definitely be some kind of check on the pubkey here.
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 feedback.
No description provided.