From be385c281092c712a87848e2f7cee011a16ff398 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Sat, 16 May 2020 21:42:17 +0200 Subject: [PATCH] Move Keyring and fingerprint to DcKey trait This moves both the Keyring and the fingerprints to the DcKey trait, unfortunately I was not able to disentangle these two changes. The Keyring now ensures only the right kind of key is added to it. The keyring now uses the DcKey::load_self method rather than re-implement the SQL to load keys from the database. This vastly simpliefies the use and fixes an error where a failed key load or unconfigured would result in the message being treated as plain text and benefits from the in-line key generation path. For the fingerprint a new type representing it is introduced. The aim is to replace more fingerpring uses with this type as now there are various string representations being passed around and converted between. The Display trait is used for the space-separated and multiline format, which is perhaps not the most obvious but seems right together with FromStr etc. --- src/contact.rs | 12 ++-- src/context.rs | 4 +- src/e2ee.rs | 66 +++++++++------------ src/key.rs | 147 +++++++++++++++++++++++++++++++++------------- src/keyring.rs | 93 +++++++++++++++++++++-------- src/peerstate.rs | 54 ++++++++--------- src/pgp.rs | 68 ++++++++++----------- src/securejoin.rs | 4 +- 8 files changed, 272 insertions(+), 176 deletions(-) diff --git a/src/contact.rs b/src/contact.rs index 0fff01025a..67002a6584 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -12,7 +12,7 @@ use crate::context::Context; use crate::dc_tools::*; use crate::error::{bail, ensure, format_err, Result}; use crate::events::Event; -use crate::key::{DcKey, Key, SignedPublicKey}; +use crate::key::{DcKey, SignedPublicKey}; use crate::login_param::LoginParam; use crate::message::{MessageState, MsgId}; use crate::mimeparser::AvatarAction; @@ -691,18 +691,20 @@ impl Contact { }) .await; ret += &p; - let self_key = Key::from(SignedPublicKey::load_self(context).await?); let p = context.stock_str(StockMessage::FingerPrints).await; ret += &format!(" {}:", p); - let fingerprint_self = self_key.formatted_fingerprint(); + let fingerprint_self = SignedPublicKey::load_self(context) + .await? + .fingerprint() + .to_string(); let fingerprint_other_verified = peerstate .peek_key(PeerstateVerifiedStatus::BidirectVerified) - .map(|k| k.formatted_fingerprint()) + .map(|k| k.fingerprint().to_string()) .unwrap_or_default(); let fingerprint_other_unverified = peerstate .peek_key(PeerstateVerifiedStatus::Unverified) - .map(|k| k.formatted_fingerprint()) + .map(|k| k.fingerprint().to_string()) .unwrap_or_default(); if loginparam.addr < peerstate.addr { cat_fingerprint(&mut ret, &loginparam.addr, &fingerprint_self, ""); diff --git a/src/context.rs b/src/context.rs index cb6370b513..de431703ff 100644 --- a/src/context.rs +++ b/src/context.rs @@ -15,7 +15,7 @@ use crate::dc_tools::duration_to_str; use crate::error::*; use crate::events::{Event, EventEmitter, Events}; use crate::job::{self, Action}; -use crate::key::{DcKey, Key, SignedPublicKey}; +use crate::key::{DcKey, SignedPublicKey}; use crate::login_param::LoginParam; use crate::lot::Lot; use crate::message::{self, Message, MessengerMessage, MsgId}; @@ -285,7 +285,7 @@ impl Context { .query_get_value(self, "SELECT COUNT(*) FROM acpeerstates;", paramsv![]) .await; let fingerprint_str = match SignedPublicKey::load_self(self).await { - Ok(key) => Key::from(key).fingerprint(), + Ok(key) => key.fingerprint().hex(), Err(err) => format!("", err), }; diff --git a/src/e2ee.rs b/src/e2ee.rs index bb3f985d3d..bd20279cca 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -93,7 +93,7 @@ impl EncryptHelper { mail_to_encrypt: lettre_email::PartBuilder, peerstates: Vec<(Option>, &str)>, ) -> Result { - let mut keyring = Keyring::default(); + let mut keyring: Keyring = Keyring::new(); for (peerstate, addr) in peerstates .into_iter() @@ -104,8 +104,7 @@ impl EncryptHelper { })?; keyring.add(key); } - let public_key = Key::from(self.public_key); - keyring.add(public_key); + keyring.add(self.public_key.clone()); let sign_key = Key::from(SignedSecretKey::load_self(context).await?); let raw_message = mail_to_encrypt.build().as_string().into_bytes(); @@ -151,40 +150,33 @@ pub async fn try_decrypt( } /* possibly perform decryption */ - let mut public_keyring_for_validate = Keyring::default(); - let mut out_mail = None; + let private_keyring: Keyring = Keyring::new_self(context).await?; + let mut public_keyring_for_validate: Keyring = Keyring::new(); let mut signatures = HashSet::default(); - let self_addr = context.get_config(Config::ConfiguredAddr).await; - if let Some(self_addr) = self_addr { - if let Ok(private_keyring) = - Keyring::load_self_private_for_decrypting(context, self_addr).await - { - if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 { - peerstate = Peerstate::from_addr(&context, &from).await; - } - if let Some(peerstate) = peerstate { - if peerstate.degrade_event.is_some() { - handle_degrade_event(context, &peerstate).await?; - } - if let Some(key) = peerstate.gossip_key { - public_keyring_for_validate.add(key); - } - if let Some(key) = peerstate.public_key { - public_keyring_for_validate.add(key); - } - } - - out_mail = decrypt_if_autocrypt_message( - context, - mail, - private_keyring, - public_keyring_for_validate, - &mut signatures, - ) - .await?; + if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 { + peerstate = Peerstate::from_addr(&context, &from).await; + } + if let Some(peerstate) = peerstate { + if peerstate.degrade_event.is_some() { + handle_degrade_event(context, &peerstate).await?; + } + if let Some(key) = peerstate.gossip_key { + public_keyring_for_validate.add(key); + } + if let Some(key) = peerstate.public_key { + public_keyring_for_validate.add(key); } } + + let out_mail = decrypt_if_autocrypt_message( + context, + mail, + private_keyring, + public_keyring_for_validate, + &mut signatures, + ) + .await?; Ok((out_mail, signatures)) } @@ -218,8 +210,8 @@ fn get_autocrypt_mime<'a, 'b>(mail: &'a ParsedMail<'b>) -> Result<&'a ParsedMail async fn decrypt_if_autocrypt_message<'a>( context: &Context, mail: &ParsedMail<'a>, - private_keyring: Keyring, - public_keyring_for_validate: Keyring, + private_keyring: Keyring, + public_keyring_for_validate: Keyring, ret_valid_signatures: &mut HashSet, ) -> Result>> { // The returned bool is true if we detected an Autocrypt-encrypted @@ -250,8 +242,8 @@ async fn decrypt_if_autocrypt_message<'a>( /// Returns Ok(None) if nothing encrypted was found. async fn decrypt_part( mail: &ParsedMail<'_>, - private_keyring: Keyring, - public_keyring_for_validate: Keyring, + private_keyring: Keyring, + public_keyring_for_validate: Keyring, ret_valid_signatures: &mut HashSet, ) -> Result>> { let data = mail.get_body_raw()?; diff --git a/src/key.rs b/src/key.rs index 035507b5e7..4816e32978 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1,6 +1,7 @@ //! Cryptographic key module use std::collections::BTreeMap; +use std::fmt; use std::io::Cursor; use async_std::path::Path; @@ -50,8 +51,8 @@ pub type Result = std::result::Result; /// [SignedSecretKey] types and makes working with them a little /// easier in the deltachat world. #[async_trait] -pub trait DcKey: Serialize + Deserializable { - type KeyType: Serialize + Deserializable; +pub trait DcKey: Serialize + Deserializable + KeyTrait + Clone { + type KeyType: Serialize + Deserializable + KeyTrait + Clone; /// Create a key from some bytes. fn from_slice(bytes: &[u8]) -> Result { @@ -71,15 +72,25 @@ pub trait DcKey: Serialize + Deserializable { /// Load the users' default key from the database. async fn load_self(context: &Context) -> Result; - /// Serialise the key to a base64 string. - fn to_base64(&self) -> String { + /// Serialise the key as bytes. + fn to_bytes(&self) -> Vec { // Not using Serialize::to_bytes() to make clear *why* it is // safe to ignore this error. // Because we write to a Vec the io::Write impls never // fail and we can hide this error. let mut buf = Vec::new(); self.to_writer(&mut buf).unwrap(); - base64::encode(&buf) + buf + } + + /// Serialise the key to a base64 string. + fn to_base64(&self) -> String { + base64::encode(&DcKey::to_bytes(self)) + } + + /// The fingerprint for the key. + fn fingerprint(&self) -> Fingerprint { + Fingerprint::new(KeyTrait::fingerprint(self)) } } @@ -300,8 +311,8 @@ impl Key { pub fn to_bytes(&self) -> Vec { match self { - Key::Public(k) => k.to_bytes().unwrap_or_default(), - Key::Secret(k) => k.to_bytes().unwrap_or_default(), + Key::Public(k) => Serialize::to_bytes(&k).unwrap_or_default(), + Key::Secret(k) => Serialize::to_bytes(&k).unwrap_or_default(), } } @@ -312,11 +323,6 @@ impl Key { } } - pub fn to_base64(&self) -> String { - let buf = self.to_bytes(); - base64::encode(&buf) - } - pub fn to_armored_string( &self, headers: Option<&BTreeMap>, @@ -353,18 +359,6 @@ impl Key { res } - pub fn fingerprint(&self) -> String { - match self { - Key::Public(k) => hex::encode_upper(k.fingerprint()), - Key::Secret(k) => hex::encode_upper(k.fingerprint()), - } - } - - pub fn formatted_fingerprint(&self) -> String { - let rawhex = self.fingerprint(); - dc_format_fingerprint(&rawhex) - } - pub fn split_key(&self) -> Option { match self { Key::Public(_) => None, @@ -425,14 +419,8 @@ pub async fn store_self_keypair( ) -> std::result::Result<(), SaveKeyError> { // Everything should really be one transaction, more refactoring // is needed for that. - let public_key = keypair - .public - .to_bytes() - .map_err(|err| SaveKeyError::new("failed to serialise public key", err))?; - let secret_key = keypair - .secret - .to_bytes() - .map_err(|err| SaveKeyError::new("failed to serialise secret key", err))?; + let public_key = DcKey::to_bytes(&keypair.public); + let secret_key = DcKey::to_bytes(&keypair.secret); context .sql .execute( @@ -470,6 +458,62 @@ pub async fn store_self_keypair( Ok(()) } +/// A key fingerprint +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Fingerprint(Vec); + +impl Fingerprint { + pub fn new(v: Vec) -> Fingerprint { + Fingerprint(v) + } + + /// Make a hex string from the fingerprint. + /// + /// Use [std::fmt::Display] or [ToString::to_string] to get a + /// human-readable formatted string. + pub fn hex(&self) -> String { + hex::encode_upper(&self.0) + } +} + +/// Make a human-readable fingerprint. +impl fmt::Display for Fingerprint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Split key into chunks of 4 with space and newline at 20 chars + for (i, c) in self.hex().chars().enumerate() { + if i > 0 && i % 20 == 0 { + writeln!(f)?; + } else if i > 0 && i % 4 == 0 { + write!(f, " ")?; + } + write!(f, "{}", c)?; + } + Ok(()) + } +} + +/// Parse a human-readable or otherwise formatted fingerprint. +impl std::str::FromStr for Fingerprint { + type Err = hex::FromHexError; + + fn from_str(input: &str) -> std::result::Result { + let hex_repr: String = input + .chars() + .filter(|&c| c >= '0' && c <= '9' || c >= 'A' && c <= 'F') + .collect(); + let v: Vec = hex::decode(hex_repr)?; + Ok(Fingerprint(v)) + } +} + +/// Bring a human-readable or otherwise formatted fingerprint back to the 40-characters-uppercase-hex format. +pub fn dc_normalize_fingerprint(fp: &str) -> String { + fp.to_uppercase() + .chars() + .filter(|&c| c >= '0' && c <= '9' || c >= 'A' && c <= 'F') + .collect() +} + /// Make a fingerprint human-readable, in hex format. pub fn dc_format_fingerprint(fingerprint: &str) -> String { // split key into chunks of 4 with space, and 20 newline @@ -488,14 +532,6 @@ pub fn dc_format_fingerprint(fingerprint: &str) -> String { res } -/// Bring a human-readable or otherwise formatted fingerprint back to the 40-characters-uppercase-hex format. -pub fn dc_normalize_fingerprint(fp: &str) -> String { - fp.to_uppercase() - .chars() - .filter(|&c| c >= '0' && c <= '9' || c >= 'A' && c <= 'F') - .collect() -} - #[cfg(test)] mod tests { use super::*; @@ -755,4 +791,35 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD // ) // .unwrap(); // } + + #[test] + fn test_fingerprint_from_str() { + let res = Fingerprint::new(vec![1, 2, 4, 8, 16, 32, 64, 128, 255]); + + let fp: Fingerprint = "0102040810204080FF".parse().unwrap(); + assert_eq!(fp, res); + + let fp: Fingerprint = "zzzz 0102 0408\n1020 4080 FF zzz".parse().unwrap(); + assert_eq!(fp, res); + + let err = "1".parse::().err().unwrap(); + assert_eq!(err, hex::FromHexError::OddLength); + } + + #[test] + fn test_fingerprint_hex() { + let fp = Fingerprint::new(vec![1, 2, 4, 8, 16, 32, 64, 128, 255]); + assert_eq!(fp.hex(), "0102040810204080FF"); + } + + #[test] + fn test_fingerprint_to_string() { + let fp = Fingerprint::new(vec![ + 1, 2, 4, 8, 16, 32, 64, 128, 255, 1, 2, 4, 8, 16, 32, 64, 128, 255, + ]); + assert_eq!( + fp.to_string(), + "0102 0408 1020 4080 FF01\n0204 0810 2040 80FF" + ); + } } diff --git a/src/keyring.rs b/src/keyring.rs index c962e3fbd9..4239e47a1c 100644 --- a/src/keyring.rs +++ b/src/keyring.rs @@ -1,17 +1,47 @@ +//! Keyring to perform rpgp operations with. + use anyhow::Result; -use crate::constants::KeyType; use crate::context::Context; -use crate::key::Key; +use crate::key::{self, DcKey}; -#[derive(Default, Clone, Debug)] -pub struct Keyring { - keys: Vec, +/// An in-memory keyring. +/// +/// Instances are usually constructed just for the rpgp operation and +/// short-lived. +#[derive(Clone, Debug, Default)] +pub struct Keyring +where + T: DcKey, +{ + keys: Vec, } -impl Keyring { - pub fn add(&mut self, key: Key) { - self.keys.push(key) +impl Keyring +where + T: DcKey, +{ + /// New empty keyring. + pub fn new() -> Keyring { + Keyring { keys: Vec::new() } + } + + /// Create a new keyring with the the user's secret key loaded. + pub async fn new_self(context: &Context) -> Result, key::Error> { + let mut keyring: Keyring = Keyring::new(); + keyring.load_self(context).await?; + Ok(keyring) + } + + /// Load the user's key into the keyring. + pub async fn load_self(&mut self, context: &Context) -> Result<(), key::Error> { + self.add(T::load_self(context).await?); + Ok(()) + } + + /// Add a key to the keyring. + pub fn add(&mut self, key: T) { + self.keys.push(key); } pub fn len(&self) -> usize { @@ -22,26 +52,41 @@ impl Keyring { self.keys.is_empty() } - pub fn keys(&self) -> &[Key] { + /// A vector with reference to all the keys in the keyring. + pub fn keys(&self) -> &[T] { &self.keys } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::key::{SignedPublicKey, SignedSecretKey}; + use crate::test_utils::*; + + #[test] + fn test_keyring_add_keys() { + let alice = alice_keypair(); + let mut pub_ring: Keyring = Keyring::new(); + pub_ring.add(alice.public.clone()); + assert_eq!(pub_ring.keys(), [alice.public]); + + let mut sec_ring: Keyring = Keyring::new(); + sec_ring.add(alice.secret.clone()); + assert_eq!(sec_ring.keys(), [alice.secret]); + } - pub async fn load_self_private_for_decrypting( - context: &Context, - self_addr: impl AsRef, - ) -> Result { - let blob: Vec = context - .sql - .query_get_value_result( - "SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;", - paramsv![self_addr.as_ref().to_string()], - ) - .await? - .unwrap_or_default(); + #[async_std::test] + async fn test_keyring_load_self() { + // new_self() implies load_self() + let t = dummy_context().await; + configure_alice_keypair(&t.ctx).await; + let alice = alice_keypair(); - let key = async_std::task::spawn_blocking(move || Key::from_slice(&blob, KeyType::Private)) - .await?; + let pub_ring: Keyring = Keyring::new_self(&t.ctx).await.unwrap(); + assert_eq!(pub_ring.keys(), [alice.public]); - Ok(Self { keys: vec![key] }) + let sec_ring: Keyring = Keyring::new_self(&t.ctx).await.unwrap(); + assert_eq!(sec_ring.keys(), [alice.secret]); } } diff --git a/src/peerstate.rs b/src/peerstate.rs index fc36020a6e..f6c460e6ac 100644 --- a/src/peerstate.rs +++ b/src/peerstate.rs @@ -6,9 +6,8 @@ use std::fmt; use num_traits::FromPrimitive; use crate::aheader::*; -use crate::constants::*; use crate::context::Context; -use crate::key::{Key, SignedPublicKey}; +use crate::key::{DcKey, SignedPublicKey}; use crate::sql::Sql; #[derive(Debug)] @@ -32,12 +31,12 @@ pub struct Peerstate<'a> { pub last_seen: i64, pub last_seen_autocrypt: i64, pub prefer_encrypt: EncryptPreference, - pub public_key: Option, + pub public_key: Option, pub public_key_fingerprint: Option, - pub gossip_key: Option, + pub gossip_key: Option, pub gossip_timestamp: i64, pub gossip_key_fingerprint: Option, - pub verified_key: Option, + pub verified_key: Option, pub verified_key_fingerprint: Option, pub to_save: Option, pub degrade_event: Option, @@ -127,7 +126,7 @@ impl<'a> Peerstate<'a> { res.last_seen_autocrypt = message_time; res.to_save = Some(ToSave::All); res.prefer_encrypt = header.prefer_encrypt; - res.public_key = Some(Key::from(header.public_key.clone())); + res.public_key = Some(header.public_key.clone()); res.recalc_fingerprint(); res @@ -138,7 +137,7 @@ impl<'a> Peerstate<'a> { res.gossip_timestamp = message_time; res.to_save = Some(ToSave::All); - res.gossip_key = Some(Key::from(gossip_header.public_key.clone())); + res.gossip_key = Some(gossip_header.public_key.clone()); res.recalc_fingerprint(); res @@ -220,15 +219,15 @@ impl<'a> Peerstate<'a> { res.public_key = row .get(4) .ok() - .and_then(|blob: Vec| Key::from_slice(&blob, KeyType::Public).ok()); + .and_then(|blob: Vec| SignedPublicKey::from_slice(&blob).ok()); res.gossip_key = row .get(6) .ok() - .and_then(|blob: Vec| Key::from_slice(&blob, KeyType::Public).ok()); + .and_then(|blob: Vec| SignedPublicKey::from_slice(&blob).ok()); res.verified_key = row .get(9) .ok() - .and_then(|blob: Vec| Key::from_slice(&blob, KeyType::Public).ok()); + .and_then(|blob: Vec| SignedPublicKey::from_slice(&blob).ok()); Ok(res) }) @@ -239,7 +238,7 @@ impl<'a> Peerstate<'a> { pub fn recalc_fingerprint(&mut self) { if let Some(ref public_key) = self.public_key { let old_public_fingerprint = self.public_key_fingerprint.take(); - self.public_key_fingerprint = Some(public_key.fingerprint()); + self.public_key_fingerprint = Some(public_key.fingerprint().hex()); if old_public_fingerprint.is_none() || self.public_key_fingerprint.is_none() @@ -254,7 +253,7 @@ impl<'a> Peerstate<'a> { if let Some(ref gossip_key) = self.gossip_key { let old_gossip_fingerprint = self.gossip_key_fingerprint.take(); - self.gossip_key_fingerprint = Some(gossip_key.fingerprint()); + self.gossip_key_fingerprint = Some(gossip_key.fingerprint().hex()); if old_gossip_fingerprint.is_none() || self.gossip_key_fingerprint.is_none() @@ -300,8 +299,8 @@ impl<'a> Peerstate<'a> { self.to_save = Some(ToSave::All) } - if self.public_key.as_ref() != Some(&Key::from(header.public_key.clone())) { - self.public_key = Some(Key::from(header.public_key.clone())); + if self.public_key.as_ref() != Some(&header.public_key) { + self.public_key = Some(header.public_key.clone()); self.recalc_fingerprint(); self.to_save = Some(ToSave::All); } @@ -316,9 +315,8 @@ impl<'a> Peerstate<'a> { if message_time > self.gossip_timestamp { self.gossip_timestamp = message_time; self.to_save = Some(ToSave::Timestamps); - let hdr_key = Key::from(gossip_header.public_key.clone()); - if self.gossip_key.as_ref() != Some(&hdr_key) { - self.gossip_key = Some(hdr_key); + if self.gossip_key.as_ref() != Some(&gossip_header.public_key) { + self.gossip_key = Some(gossip_header.public_key.clone()); self.recalc_fingerprint(); self.to_save = Some(ToSave::All) } @@ -367,7 +365,7 @@ impl<'a> Peerstate<'a> { } } - pub fn take_key(mut self, min_verified: PeerstateVerifiedStatus) -> Option { + pub fn take_key(mut self, min_verified: PeerstateVerifiedStatus) -> Option { match min_verified { PeerstateVerifiedStatus::BidirectVerified => self.verified_key.take(), PeerstateVerifiedStatus::Unverified => { @@ -376,7 +374,7 @@ impl<'a> Peerstate<'a> { } } - pub fn peek_key(&self, min_verified: PeerstateVerifiedStatus) -> Option<&Key> { + pub fn peek_key(&self, min_verified: PeerstateVerifiedStatus) -> Option<&SignedPublicKey> { match min_verified { PeerstateVerifiedStatus::BidirectVerified => self.verified_key.as_ref(), PeerstateVerifiedStatus::Unverified => self @@ -495,7 +493,7 @@ mod tests { let ctx = crate::test_utils::dummy_context().await; let addr = "hello@mail.com"; - let pub_key = crate::key::Key::from(alice_keypair().public); + let pub_key = alice_keypair().public; let mut peerstate = Peerstate { context: &ctx.ctx, @@ -504,12 +502,12 @@ mod tests { last_seen_autocrypt: 11, prefer_encrypt: EncryptPreference::Mutual, public_key: Some(pub_key.clone()), - public_key_fingerprint: Some(pub_key.fingerprint()), + public_key_fingerprint: Some(pub_key.fingerprint().hex()), gossip_key: Some(pub_key.clone()), gossip_timestamp: 12, - gossip_key_fingerprint: Some(pub_key.fingerprint()), + gossip_key_fingerprint: Some(pub_key.fingerprint().hex()), verified_key: Some(pub_key.clone()), - verified_key_fingerprint: Some(pub_key.fingerprint()), + verified_key_fingerprint: Some(pub_key.fingerprint().hex()), to_save: Some(ToSave::All), degrade_event: None, }; @@ -527,7 +525,7 @@ mod tests { peerstate.to_save = None; assert_eq!(peerstate, peerstate_new); let peerstate_new2 = - Peerstate::from_fingerprint(&ctx.ctx, &ctx.ctx.sql, &pub_key.fingerprint()) + Peerstate::from_fingerprint(&ctx.ctx, &ctx.ctx.sql, &pub_key.fingerprint().hex()) .await .expect("failed to load peerstate from db"); assert_eq!(peerstate, peerstate_new2); @@ -537,7 +535,7 @@ mod tests { async fn test_peerstate_double_create() { let ctx = crate::test_utils::dummy_context().await; let addr = "hello@mail.com"; - let pub_key = crate::key::Key::from(alice_keypair().public); + let pub_key = alice_keypair().public; let peerstate = Peerstate { context: &ctx.ctx, @@ -546,7 +544,7 @@ mod tests { last_seen_autocrypt: 11, prefer_encrypt: EncryptPreference::Mutual, public_key: Some(pub_key.clone()), - public_key_fingerprint: Some(pub_key.fingerprint()), + public_key_fingerprint: Some(pub_key.fingerprint().hex()), gossip_key: None, gossip_timestamp: 12, gossip_key_fingerprint: None, @@ -571,7 +569,7 @@ mod tests { let ctx = crate::test_utils::dummy_context().await; let addr = "hello@mail.com"; - let pub_key = crate::key::Key::from(alice_keypair().public); + let pub_key = alice_keypair().public; let mut peerstate = Peerstate { context: &ctx.ctx, @@ -580,7 +578,7 @@ mod tests { last_seen_autocrypt: 11, prefer_encrypt: EncryptPreference::Mutual, public_key: Some(pub_key.clone()), - public_key_fingerprint: Some(pub_key.fingerprint()), + public_key_fingerprint: Some(pub_key.fingerprint().hex()), gossip_key: None, gossip_timestamp: 12, gossip_key_fingerprint: None, diff --git a/src/pgp.rs b/src/pgp.rs index fef20379d1..21f68f37f5 100644 --- a/src/pgp.rs +++ b/src/pgp.rs @@ -240,7 +240,7 @@ fn select_pk_for_encryption(key: &SignedPublicKey) -> Option, private_key_for_signing: Option, ) -> Result { let lit_msg = Message::new_literal_bytes("", plain); @@ -249,7 +249,7 @@ pub async fn pk_encrypt( let pkeys: Vec = public_keys_for_encryption .keys() .iter() - .filter_map(|key| key.try_into().ok().and_then(select_pk_for_encryption)) + .filter_map(|key| select_pk_for_encryption(key)) .collect(); let pkeys_refs: Vec<&SignedPublicKeyOrSubkey> = pkeys.iter().collect(); @@ -280,19 +280,15 @@ pub async fn pk_encrypt( #[allow(clippy::implicit_hasher)] pub async fn pk_decrypt( ctext: Vec, - private_keys_for_decryption: Keyring, - public_keys_for_validation: Keyring, + private_keys_for_decryption: Keyring, + public_keys_for_validation: Keyring, ret_signature_fingerprints: Option<&mut HashSet>, ) -> Result> { let msgs = async_std::task::spawn_blocking(move || { let cursor = Cursor::new(ctext); let (msg, _) = Message::from_armor_single(cursor)?; - let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption - .keys() - .iter() - .filter_map(|key| key.try_into().ok()) - .collect(); + let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption.keys().iter().collect(); let (decryptor, _) = msg.decrypt(|| "".into(), || "".into(), &skeys[..])?; decryptor.collect::>>() @@ -311,15 +307,12 @@ pub async fn pk_decrypt( let fingerprints = async_std::task::spawn_blocking(move || { let dec_msg = &msgs[0]; - let pkeys = public_keys_for_validation - .keys() - .iter() - .filter_map(|key| -> Option<&SignedPublicKey> { key.try_into().ok() }); + let pkeys = public_keys_for_validation.keys(); let mut fingerprints = Vec::new(); for pkey in pkeys { if dec_msg.verify(&pkey.primary_key).is_ok() { - let fp = hex::encode_upper(pkey.fingerprint()); + let fp = DcKey::fingerprint(pkey).hex(); fingerprints.push(fp); } } @@ -424,10 +417,10 @@ mod tests { /// [Key] objects to use in tests. struct TestKeys { - alice_secret: Key, - alice_public: Key, - bob_secret: Key, - bob_public: Key, + alice_secret: SignedSecretKey, + alice_public: SignedPublicKey, + bob_secret: SignedSecretKey, + bob_public: SignedPublicKey, } impl TestKeys { @@ -435,10 +428,10 @@ mod tests { let alice = alice_keypair(); let bob = bob_keypair(); TestKeys { - alice_secret: Key::from(alice.secret.clone()), - alice_public: Key::from(alice.public.clone()), - bob_secret: Key::from(bob.secret.clone()), - bob_public: Key::from(bob.public.clone()), + alice_secret: alice.secret.clone(), + alice_public: alice.public.clone(), + bob_secret: bob.secret.clone(), + bob_public: bob.public.clone(), } } } @@ -452,15 +445,15 @@ mod tests { /// A cyphertext encrypted to Alice & Bob, signed by Alice. static ref CTEXT_SIGNED: String = { - let mut keyring = Keyring::default(); + let mut keyring = Keyring::new(); keyring.add(KEYS.alice_public.clone()); keyring.add(KEYS.bob_public.clone()); - smol::block_on(pk_encrypt(CLEARTEXT, keyring, Some(KEYS.alice_secret.clone()))).unwrap() + smol::block_on(pk_encrypt(CLEARTEXT, keyring, Some(Key::from(KEYS.alice_secret.clone())))).unwrap() }; /// A cyphertext encrypted to Alice & Bob, not signed. static ref CTEXT_UNSIGNED: String = { - let mut keyring = Keyring::default(); + let mut keyring = Keyring::new(); keyring.add(KEYS.alice_public.clone()); keyring.add(KEYS.bob_public.clone()); smol::block_on(pk_encrypt(CLEARTEXT, keyring, None)).unwrap() @@ -482,9 +475,9 @@ mod tests { #[async_std::test] async fn test_decrypt_singed() { // Check decrypting as Alice - let mut decrypt_keyring = Keyring::default(); + let mut decrypt_keyring: Keyring = Keyring::new(); decrypt_keyring.add(KEYS.alice_secret.clone()); - let mut sig_check_keyring = Keyring::default(); + let mut sig_check_keyring: Keyring = Keyring::new(); sig_check_keyring.add(KEYS.alice_public.clone()); let mut valid_signatures: HashSet = Default::default(); let plain = pk_decrypt( @@ -500,9 +493,9 @@ mod tests { assert_eq!(valid_signatures.len(), 1); // Check decrypting as Bob - let mut decrypt_keyring = Keyring::default(); + let mut decrypt_keyring = Keyring::new(); decrypt_keyring.add(KEYS.bob_secret.clone()); - let mut sig_check_keyring = Keyring::default(); + let mut sig_check_keyring = Keyring::new(); sig_check_keyring.add(KEYS.alice_public.clone()); let mut valid_signatures: HashSet = Default::default(); let plain = pk_decrypt( @@ -520,9 +513,9 @@ mod tests { #[async_std::test] async fn test_decrypt_no_sig_check() { - let mut keyring = Keyring::default(); + let mut keyring = Keyring::new(); keyring.add(KEYS.alice_secret.clone()); - let empty_keyring = Keyring::default(); + let empty_keyring = Keyring::new(); let mut valid_signatures: HashSet = Default::default(); let plain = pk_decrypt( CTEXT_SIGNED.as_bytes().to_vec(), @@ -539,9 +532,9 @@ mod tests { #[async_std::test] async fn test_decrypt_signed_no_key() { // The validation does not have the public key of the signer. - let mut decrypt_keyring = Keyring::default(); + let mut decrypt_keyring = Keyring::new(); decrypt_keyring.add(KEYS.bob_secret.clone()); - let mut sig_check_keyring = Keyring::default(); + let mut sig_check_keyring = Keyring::new(); sig_check_keyring.add(KEYS.bob_public.clone()); let mut valid_signatures: HashSet = Default::default(); let plain = pk_decrypt( @@ -558,10 +551,9 @@ mod tests { #[async_std::test] async fn test_decrypt_unsigned() { - let mut decrypt_keyring = Keyring::default(); + let mut decrypt_keyring = Keyring::new(); decrypt_keyring.add(KEYS.bob_secret.clone()); - let sig_check_keyring = Keyring::default(); - decrypt_keyring.add(KEYS.alice_public.clone()); + let sig_check_keyring = Keyring::new(); let mut valid_signatures: HashSet = Default::default(); let plain = pk_decrypt( CTEXT_UNSIGNED.as_bytes().to_vec(), @@ -578,9 +570,9 @@ mod tests { #[async_std::test] async fn test_decrypt_signed_no_sigret() { // Check decrypting signed cyphertext without providing the HashSet for signatures. - let mut decrypt_keyring = Keyring::default(); + let mut decrypt_keyring = Keyring::new(); decrypt_keyring.add(KEYS.bob_secret.clone()); - let mut sig_check_keyring = Keyring::default(); + let mut sig_check_keyring = Keyring::new(); sig_check_keyring.add(KEYS.alice_public.clone()); let plain = pk_decrypt( CTEXT_SIGNED.as_bytes().to_vec(), diff --git a/src/securejoin.rs b/src/securejoin.rs index 580238881c..163516bb5a 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -14,7 +14,7 @@ use crate::e2ee::*; use crate::error::{bail, Error}; use crate::events::Event; use crate::headerdef::HeaderDef; -use crate::key::{dc_normalize_fingerprint, DcKey, Key, SignedPublicKey}; +use crate::key::{dc_normalize_fingerprint, DcKey, SignedPublicKey}; use crate::lot::LotState; use crate::message::Message; use crate::mimeparser::*; @@ -142,7 +142,7 @@ pub async fn dc_get_securejoin_qr(context: &Context, group_chat_id: ChatId) -> O async fn get_self_fingerprint(context: &Context) -> Option { match SignedPublicKey::load_self(context).await { - Ok(key) => Some(Key::from(key).fingerprint()), + Ok(key) => Some(key.fingerprint().hex()), Err(_) => { warn!(context, "get_self_fingerprint(): failed to load key"); None