Compare commits

..

5 Commits

10 changed files with 71 additions and 25 deletions

4
Cargo.lock generated
View File

@ -1818,7 +1818,7 @@ dependencies = [
[[package]]
name = "keyfork-qrcode"
version = "0.1.0"
version = "0.1.1"
dependencies = [
"image",
"keyfork-bug",
@ -1879,7 +1879,7 @@ dependencies = [
[[package]]
name = "keyforkd"
version = "0.1.0"
version = "0.1.1"
dependencies = [
"bincode",
"hex-literal",

View File

@ -25,6 +25,9 @@ fn secp256k1_test_suite() {
if chain_len < 2 {
continue;
}
if chain.iter().take(2).any(|index| !index.is_hardened()) {
continue;
}
// Consistency check: ensure the server and the client can each derive the same
// key using an XPrv, for all but the last XPrv, which is verified after this
for i in 2..chain_len {

View File

@ -43,6 +43,10 @@ pub enum DerivationError {
#[error("Invalid derivation length: Expected at least 2, actual: {0}")]
InvalidDerivationLength(usize),
/// The derivation request did not use hardened derivation on the 2 highest indexes.
#[error("Invalid derivation paths: expected index #{0} (1) to be hardened")]
InvalidDerivationPath(usize, u32),
/// An error occurred while deriving data.
#[error("Derivation error: {0}")]
Derivation(String),

View File

@ -1,6 +1,6 @@
[package]
name = "keyforkd"
version = "0.1.0"
version = "0.1.1"
edition = "2021"
license = "AGPL-3.0-only"

View File

@ -69,6 +69,18 @@ impl Service<Request> for Keyforkd {
return Err(DerivationError::InvalidDerivationLength(len).into());
}
if let Some((i, unhardened_index)) = req
.path()
.iter()
.take(2)
.enumerate()
.find(|(_, index)| {
!index.is_hardened()
})
{
return Err(DerivationError::InvalidDerivationPath(i, unhardened_index.inner()).into())
}
#[cfg(feature = "tracing")]
if let Some(target) = guess_target(req.path()) {
info!("Deriving path: {target}");
@ -110,6 +122,9 @@ mod tests {
if chain.len() < 2 {
continue;
}
if chain.iter().take(2).any(|index| !index.is_hardened()) {
continue;
}
let req = DerivationRequest::new(DerivationAlgorithm::Secp256k1, &chain);
let response: DerivationResponse = keyforkd
.ready()

View File

@ -61,7 +61,7 @@ where
));
let socket_dir = tempfile::tempdir().expect(bug!("can't create tempdir"));
let socket_path = socket_dir.path().join("keyforkd.sock");
rt.block_on(async move {
let result = rt.block_on(async move {
let (tx, mut rx) = tokio::sync::mpsc::channel(1);
let server_handle = tokio::spawn({
let socket_path = socket_path.clone();
@ -87,8 +87,13 @@ where
let result = test_handle.await;
server_handle.abort();
result
})
.expect(bug!("runtime could not join all threads"))
});
if let Err(e) = result {
if e.is_panic() {
std::panic::resume_unwind(e.into_panic());
}
}
Ok(())
}
#[cfg(test)]

View File

@ -84,13 +84,23 @@ impl<P: PromptHandler> VerificationHelper for &mut Keyring<P> {
aead_algo,
} => {}
MessageLayer::SignatureGroup { results } => {
for result in results {
if let Err(e) = result {
match &results[..] {
[Ok(_)] => {
return Ok(());
}
_ => {
// FIXME: anyhow leak: VerificationError impl std::error::Error
// return Err(e.context("Invalid signature"));
return Err(anyhow::anyhow!("Error validating signature; either multiple signatures were passed or the single signature was not valid"));
}
}
/*
for result in results {
if let Err(e) = result {
return Err(anyhow::anyhow!("Invalid signature: {e}"));
}
}
*/
}
}
}

View File

@ -193,12 +193,23 @@ impl<P: PromptHandler> VerificationHelper for &mut SmartcardManager<P> {
aead_algo,
} => {}
MessageLayer::SignatureGroup { results } => {
for result in results {
if let Err(e) = result {
// FIXME: anyhow leak
return Err(anyhow::anyhow!("Verification error: {}", e.to_string()));
match &results[..] {
[Ok(_)] => {
return Ok(());
}
_ => {
// FIXME: anyhow leak: VerificationError impl std::error::Error
// return Err(e.context("Invalid signature"));
return Err(anyhow::anyhow!("Error validating signature; either multiple signatures were passed or the single signature was not valid"));
}
}
/*
for result in results {
if let Err(e) = result {
return Err(anyhow::anyhow!("Invalid signature: {e}"));
}
}
*/
}
}
}
@ -264,11 +275,11 @@ impl<P: PromptHandler> DecryptionHelper for &mut SmartcardManager<P> {
} else {
format!("Unlock card {card_id} ({cardholder_name})\n{rpea}: {attempts}\n\nPIN: ")
};
let temp_pin =
self.pm
.lock()
.expect(bug!(POISONED_MUTEX))
.prompt_validated_passphrase(&message, 3, &pin_validator)?;
let temp_pin = self
.pm
.lock()
.expect(bug!(POISONED_MUTEX))
.prompt_validated_passphrase(&message, 3, &pin_validator)?;
let verification_status = transaction.verify_user_pin(temp_pin.as_str().trim());
match verification_status {
#[allow(clippy::ignored_unit_patterns)]

View File

@ -1,6 +1,6 @@
[package]
name = "keyfork-qrcode"
version = "0.1.0"
version = "0.1.1"
repository = "https://git.distrust.co/public/keyfork"
edition = "2021"
license = "MIT"

View File

@ -5,7 +5,7 @@ use keyfork_bug as bug;
use image::io::Reader as ImageReader;
use std::{
io::{Cursor, Write},
time::{Duration, SystemTime},
time::{Duration, Instant},
process::{Command, Stdio},
};
use v4l::{
@ -110,11 +110,10 @@ pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QR
fmt.fourcc = FourCC::new(b"MPG1");
device.set_format(&fmt)?;
let mut stream = Stream::with_buffers(&device, Type::VideoCapture, 4)?;
let start = SystemTime::now();
let start = Instant::now();
while SystemTime::now()
while Instant::now()
.duration_since(start)
.unwrap_or(Duration::from_secs(0))
< timeout
{
let (buffer, _) = stream.next()?;
@ -141,12 +140,11 @@ pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QR
fmt.fourcc = FourCC::new(b"MPG1");
device.set_format(&fmt)?;
let mut stream = Stream::with_buffers(&device, Type::VideoCapture, 4)?;
let start = SystemTime::now();
let start = Instant::now();
let mut scanner = keyfork_zbar::image_scanner::ImageScanner::new();
while SystemTime::now()
while Instant::now()
.duration_since(start)
.unwrap_or(Duration::from_secs(0))
< timeout
{
let (buffer, _) = stream.next()?;