From a14a49bd0cc26f5a9f74da92ca4a15a99a9802b7 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Fri, 30 Sep 2022 16:19:49 +0200 Subject: [PATCH] Use transparent encrypted storage --- Cargo.lock | 29 ++++----------------- examples/udp_sim/main.rs | 11 ++++++-- src/lib/commands.rs | 56 ++++++++++++++++++++++++++++++---------- src/lib/lib.rs | 1 + src/lib/wcstate.rs | 12 ++++++++- 5 files changed, 69 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9536bda..6ca9a34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -447,20 +447,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ "atty", - "humantime 1.3.0", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "env_logger" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" -dependencies = [ - "atty", - "humantime 2.1.0", + "humantime", "log", "regex", "termcolor", @@ -634,12 +621,6 @@ dependencies = [ "quick-error", ] -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "interchange" version = "0.2.1" @@ -840,7 +821,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" dependencies = [ - "env_logger 0.7.1", + "env_logger", "log", ] @@ -1155,7 +1136,7 @@ dependencies = [ [[package]] name = "trussed" version = "0.1.0" -source = "git+https://github.com/Nitrokey/trussed.git?branch=webcrypt-devel#29cdbe7a8ae88c6ecbc4e021ce12cac256d2748f" +source = "git+https://github.com/Nitrokey/trussed.git?branch=webcrypt-devel#fd03e8291852dc167b84c98590c8235de5c552ac" dependencies = [ "aes", "bitflags", @@ -1251,7 +1232,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "webcrypt" -version = "0.2.2" +version = "0.3.0" dependencies = [ "apdu-dispatch", "cbor-smol", @@ -1259,7 +1240,7 @@ dependencies = [ "ctap-types", "ctaphid-dispatch", "delog", - "env_logger 0.9.0", + "env_logger", "generic-array", "git-version", "heapless", diff --git a/examples/udp_sim/main.rs b/examples/udp_sim/main.rs index 29e1f8a..e6c89de 100644 --- a/examples/udp_sim/main.rs +++ b/examples/udp_sim/main.rs @@ -3,10 +3,12 @@ extern crate delog; use delog::log; use heapless_bytes::{Bytes, Bytes32}; +use std::path::PathBuf; -use webcrypt::{RequestDetails, RequestSource, Webcrypt}; +use webcrypt::{RequestDetails, RequestSource, Webcrypt, DEFAULT_ENCRYPTION_PIN}; use crate::udp_server::UDPServer; +use trussed::types::ClientContext; generate_macros!(); @@ -24,7 +26,12 @@ fn main() -> std::io::Result<()> { log::info!("Initializing Trussed"); let trussed_platform = platform::init_platform("state_file"); let mut trussed_service = trussed::service::Service::new(trussed_platform); - let trussed_client = trussed_service.try_as_new_client("webcrypt").unwrap(); + let trussed_client = trussed_service + .try_as_new_client_ctx(ClientContext::new( + littlefs2::path::PathBuf::from("webcrypt"), + Some(DEFAULT_ENCRYPTION_PIN), + )) + .unwrap(); log::info!("Initializing Webcrypt {}", webcrypt::GIT_VERSION); let mut w = Webcrypt::new(trussed_client); let mut server = UDPServer::new(); diff --git a/src/lib/commands.rs b/src/lib/commands.rs index 21bf1cf..350da82 100644 --- a/src/lib/commands.rs +++ b/src/lib/commands.rs @@ -24,9 +24,9 @@ use crate::types::ERROR_ID; use crate::helpers::hash; use crate::openpgp::OpenPGPData; use crate::types::ERROR_ID::{ - ERR_BAD_FORMAT, ERR_BAD_ORIGIN, ERR_FAILED_LOADING_DATA, ERR_NOT_FOUND, + ERR_BAD_FORMAT, ERR_BAD_ORIGIN, ERR_FAILED_LOADING_DATA, ERR_INVALID_PIN, ERR_NOT_FOUND, }; -use crate::{Message, RequestSource}; +use crate::{Message, RequestSource, DEFAULT_ENCRYPTION_PIN}; type CommandResult = Result<(), ERROR_ID>; @@ -919,16 +919,28 @@ where } }; - let tp = w - .session - .login(req.pin, &mut w.trussed, &rpid, &mut w.state)?; + try_syscall!(w + .trussed + .set_client_context_pin(Bytes::from_slice(req.pin.as_slice()).unwrap())) + .map_err(|_| ERR_INTERNAL_ERROR)?; + // ignore loading errors for now - if !w.state.initialized() { - w.state - .load(&mut w.trussed) - .map_err(|_| ERR_FAILED_LOADING_DATA)? + log::debug!("WC loading state"); + let res = w + .state + .load(&mut w.trussed) + // the cause might be in the corrupted storage as well (ERR_FAILED_LOADING_DATA), + // but we can't differentiate at this point + .map_err(|_| ERR_INVALID_PIN); + if res.is_err() { + w.state.pin.decrease_counter()?; + res? } + let tp = w + .session + .login(req.pin.clone(), &mut w.trussed, &rpid, &mut w.state)?; + w.send_to_output(CommandLoginResponse { tp }); Ok(()) @@ -953,6 +965,10 @@ where // Clear session w.session.logout(); w.state.logout(); + try_syscall!(w + .trussed + .set_client_context_pin(Bytes::from_slice(b"invalid pin").unwrap())) + .map_err(|_| ERR_INTERNAL_ERROR)?; Ok(()) } @@ -974,6 +990,9 @@ where .trussed .remove_dir_all(Location::Internal, PathBuf::from("wcrk"),)); + let default_pin = Bytes::from_slice(DEFAULT_ENCRYPTION_PIN.as_ref()).unwrap(); + try_syscall!(w.trussed.reset_pin(default_pin)).map_err(|_| ERR_INTERNAL_ERROR)?; + // delete persistent state // reset PIN w.state.reset(&mut w.trussed); @@ -1033,7 +1052,15 @@ where let req: CommandSetPINRequest = w .get_input_deserialized() .map_err(|_| ERROR_ID::ERR_BAD_FORMAT)?; - w.state.pin.set_pin(req.pin)?; + w.state.pin.set_pin(req.pin.clone())?; + + try_syscall!(w.trussed.set_client_context_pin( + Bytes::from_slice(DEFAULT_ENCRYPTION_PIN.as_ref()).unwrap() + )) + .map_err(|_| ERR_INTERNAL_ERROR)?; + try_syscall!(w.trussed.change_pin(req.pin.to_bytes().unwrap())) + .map_err(|_| ERR_INTERNAL_ERROR)?; + w.state.initialize(&mut w.trussed); Ok(()) } @@ -1041,7 +1068,12 @@ where let req: CommandChangePINRequest = w .get_input_deserialized() .map_err(|_| ERROR_ID::ERR_BAD_FORMAT)?; - w.state.pin.change_pin(req.pin, req.newpin)?; + w.state.pin.change_pin(req.pin, req.newpin.clone())?; + try_syscall!(w + .trussed + .change_pin(Bytes::from_slice(req.newpin.as_slice()).unwrap())) + .map_err(|_| ERROR_ID::ERR_INTERNAL_ERROR)?; + Ok(()) } _ => Err(ERROR_ID::ERR_INVALID_COMMAND), @@ -1133,8 +1165,6 @@ where .check_token_res(req.tp.unwrap()) .map_err(|_| ERROR_ID::ERR_REQ_AUTH)?; - use trussed::key::Kind; - let private_key = try_syscall!(w.trussed.unsafe_inject_shared_key( // &k.serialize(), req.raw_key_data.as_slice(), diff --git a/src/lib/lib.rs b/src/lib/lib.rs index 9b73eb6..27c7617 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -24,6 +24,7 @@ mod types; mod wcstate; pub const MAX_MESSAGE_LENGTH: usize = 1024; +pub const DEFAULT_ENCRYPTION_PIN: &'static str = "1234"; pub type Message = Bytes; diff --git a/src/lib/wcstate.rs b/src/lib/wcstate.rs index 7ab425c..ff959c8 100644 --- a/src/lib/wcstate.rs +++ b/src/lib/wcstate.rs @@ -45,6 +45,15 @@ impl WebcryptPIN { self.counter } + pub fn decrease_counter(&mut self) -> Result<(), ERROR_ID> { + if self.counter == 0 { + log::info!("Counter PIN used up"); + return Err(ERR_NOT_ALLOWED); + } + self.counter -= 1; + Ok(()) + } + pub fn check_pin(&mut self, pin: Bytes64) -> Result { if self.pin.is_none() { log::info!("PIN not set"); @@ -54,7 +63,8 @@ impl WebcryptPIN { log::info!("Counter PIN used up"); return Err(ERR_NOT_ALLOWED); } - self.counter -= 1; + self.decrease_counter()?; + log::info!("Counter PIN value: {:?}", self.counter); // TODO use side-channels safe comparison library, e.g. subtle