From 29cd960d879963dc0149292e64dfb5d75e34dac3 Mon Sep 17 00:00:00 2001 From: Marko Bencun Date: Wed, 1 Jul 2020 17:56:01 +0200 Subject: [PATCH] rust/hww: protobuf plumbing and set device name call in Rust --- src/rust/bitbox02-rust/src/hww/api/api.rs | 122 ++++++++++++++++++++++ src/rust/bitbox02-rust/src/hww/api/mod.rs | 3 + src/rust/bitbox02-rust/src/hww/noise.rs | 2 +- src/rust/bitbox02/src/commander.rs | 2 +- 4 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 src/rust/bitbox02-rust/src/hww/api/api.rs diff --git a/src/rust/bitbox02-rust/src/hww/api/api.rs b/src/rust/bitbox02-rust/src/hww/api/api.rs new file mode 100644 index 0000000000..1af16afbbe --- /dev/null +++ b/src/rust/bitbox02-rust/src/hww/api/api.rs @@ -0,0 +1,122 @@ +// Copyright 2020 Shift Crypto AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use alloc::vec::Vec; + +use super::pb; +use super::pb::request::Request; +use super::pb::response::Response; +use bitbox02::commander::Error; + +/// Creates an Error response. Corresponds to commander.c:_report_error(). +fn make_error(err: bitbox02::commander::Error) -> Response { + use Error::*; + let err = match err { + COMMANDER_OK => panic!("can't call this function with COMMANDER_OK"), + COMMANDER_ERR_INVALID_INPUT => pb::Error { + code: 101, + message: "invalid input".into(), + }, + COMMANDER_ERR_MEMORY => pb::Error { + code: 102, + message: "memory".into(), + }, + COMMANDER_ERR_GENERIC => pb::Error { + code: 103, + message: "generic error".into(), + }, + COMMANDER_ERR_USER_ABORT => pb::Error { + code: 104, + message: "aborted by the user".into(), + }, + COMMANDER_ERR_INVALID_STATE => pb::Error { + code: 105, + message: "can't call this endpoint: wrong state".into(), + }, + COMMANDER_ERR_DISABLED => pb::Error { + code: 106, + message: "function disabled".into(), + }, + COMMANDER_ERR_DUPLICATE => pb::Error { + code: 107, + message: "duplicate entry".into(), + }, + }; + Response::Error(err) +} + +/// Encodes a protobuf Response message. +fn encode(response: Response) -> Vec { + use prost::Message; + let response = pb::Response { + response: Some(response), + }; + let mut out = Vec::::new(); + response.encode(&mut out).unwrap(); + out +} + +async fn api_set_device_name( + pb::SetDeviceNameRequest { name }: &pb::SetDeviceNameRequest, +) -> Response { + use crate::workflow::confirm; + let params = confirm::Params { + title: "Name", + body: &name, + scrollable: true, + ..Default::default() + }; + + if !confirm::confirm(¶ms).await { + return make_error(Error::COMMANDER_ERR_USER_ABORT); + } + + if bitbox02::memory::set_device_name(&name).is_err() { + return make_error(Error::COMMANDER_ERR_MEMORY); + } + + Response::Success(pb::Success {}) +} + +/// Handle a protobuf api call. +/// +/// Returns `None` if the call was not handled by Rust, in which case +/// it should be handled by the C commander. +async fn process_api(request: &Request) -> Option { + match request { + Request::DeviceName(ref request) => Some(api_set_device_name(request).await), + _ => None, + } +} + +/// Handle a protobuf api call. API calls not handled by Rust are +/// handled by the C commander, which allows us to use Rust for new +/// api calls and port the old calls step by step. +/// +/// `input` is a hww.proto Request message, protobuf encoded. +/// Returns a protobuf encoded hww.proto Response message. +pub async fn process(input: Vec) -> Vec { + use prost::Message; + let request = match pb::Request::decode(&input[..]) { + Ok(pb::Request { + request: Some(request), + }) => request, + _ => return encode(make_error(Error::COMMANDER_ERR_INVALID_INPUT)), + }; + match process_api(&request).await { + Some(response) => encode(response), + // Api call not handled Rust -> handle it in C. + _ => bitbox02::commander::commander(input), + } +} diff --git a/src/rust/bitbox02-rust/src/hww/api/mod.rs b/src/rust/bitbox02-rust/src/hww/api/mod.rs index e9ea4149f7..ed19bfa0ba 100644 --- a/src/rust/bitbox02-rust/src/hww/api/mod.rs +++ b/src/rust/bitbox02-rust/src/hww/api/mod.rs @@ -15,3 +15,6 @@ mod pb { include!("./shiftcrypto.bitbox02.rs"); } + +mod api; +pub use api::process; diff --git a/src/rust/bitbox02-rust/src/hww/noise.rs b/src/rust/bitbox02-rust/src/hww/noise.rs index 0d45252c49..dfd3d97d37 100644 --- a/src/rust/bitbox02-rust/src/hww/noise.rs +++ b/src/rust/bitbox02-rust/src/hww/noise.rs @@ -117,7 +117,7 @@ pub(crate) async fn process(usb_in: Vec, usb_out: &mut Vec) -> Result<() } Some((&OP_NOISE_MSG, encrypted_msg)) => { let decrypted_msg = state.decrypt(encrypted_msg)?; - let response = bitbox02::commander::commander(decrypted_msg); + let response = super::api::process(decrypted_msg).await; state.encrypt(&response, usb_out)?; Ok(()) } diff --git a/src/rust/bitbox02/src/commander.rs b/src/rust/bitbox02/src/commander.rs index 643b82cabf..4d6ca6ced7 100644 --- a/src/rust/bitbox02/src/commander.rs +++ b/src/rust/bitbox02/src/commander.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub type Error = bitbox02_sys::commander_error_t; +pub use bitbox02_sys::commander_error_t as Error; extern crate alloc; use alloc::vec::Vec;