aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2020-05-03 02:53:40 -0400
committerJesse Luehrs <doy@tozt.net>2020-05-03 02:53:40 -0400
commitaafefa7f344441c709198e16cd07da11b4651a98 (patch)
tree70253bada8b8b5541125257706d72b580fc9cea9
parent1b0b0e9eaa546f50f6916cc631edaaa7dc8442e8 (diff)
downloadrbw-aafefa7f344441c709198e16cd07da11b4651a98.tar.gz
rbw-aafefa7f344441c709198e16cd07da11b4651a98.zip
also make the agent store decrypted org keys in memory
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--src/actions.rs36
-rw-r--r--src/bin/rbw-agent/actions.rs16
-rw-r--r--src/cipherstring.rs48
-rw-r--r--src/locked.rs14
6 files changed, 109 insertions, 7 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a2d218b..574145b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1030,6 +1030,7 @@ dependencies = [
"humantime",
"log",
"nix",
+ "openssl",
"rand",
"region",
"reqwest",
diff --git a/Cargo.toml b/Cargo.toml
index 52dcb75..b734472 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -25,6 +25,7 @@ env_logger = "0.7"
humantime = "1.3"
log = "0.4"
nix = "0.17"
+openssl = "0.10"
rand = "0.7"
region = "2.1"
reqwest = { version = "0.10", features = ["blocking", "json"] }
diff --git a/src/actions.rs b/src/actions.rs
index b891670..a4b8021 100644
--- a/src/actions.rs
+++ b/src/actions.rs
@@ -32,18 +32,44 @@ pub async fn unlock(
password: &crate::locked::Password,
iterations: u32,
protected_key: &str,
-) -> Result<crate::locked::Keys> {
+ protected_private_key: &str,
+ protected_org_keys: &std::collections::HashMap<String, String>,
+) -> Result<(
+ crate::locked::Keys,
+ std::collections::HashMap<String, crate::locked::Keys>,
+)> {
let identity =
crate::identity::Identity::new(email, password, iterations)?;
let protected_key =
crate::cipherstring::CipherString::new(protected_key)?;
+ let key = match protected_key.decrypt_locked_symmetric(&identity.keys) {
+ Ok(master_keys) => crate::locked::Keys::new(master_keys),
+ Err(Error::InvalidMac) => return Err(Error::IncorrectPassword),
+ Err(e) => return Err(e),
+ };
- match protected_key.decrypt_locked_symmetric(&identity.keys) {
- Ok(master_keys) => Ok(crate::locked::Keys::new(master_keys)),
- Err(Error::InvalidMac) => Err(Error::IncorrectPassword),
- Err(e) => Err(e),
+ let protected_private_key =
+ crate::cipherstring::CipherString::new(protected_private_key)?;
+ let private_key =
+ match protected_private_key.decrypt_locked_symmetric(&key) {
+ Ok(private_key) => crate::locked::PrivateKey::new(private_key),
+ Err(e) => return Err(e),
+ };
+
+ let mut org_keys = std::collections::HashMap::new();
+ for (org_id, protected_org_key) in protected_org_keys {
+ let protected_org_key =
+ crate::cipherstring::CipherString::new(protected_org_key)?;
+ let org_key =
+ match protected_org_key.decrypt_locked_asymmetric(&private_key) {
+ Ok(org_key) => crate::locked::Keys::new(org_key),
+ Err(e) => return Err(e),
+ };
+ org_keys.insert(org_id.to_string(), org_key);
}
+
+ Ok((key, org_keys))
}
pub async fn sync(
diff --git a/src/bin/rbw-agent/actions.rs b/src/bin/rbw-agent/actions.rs
index e24d044..3ca6d51 100644
--- a/src/bin/rbw-agent/actions.rs
+++ b/src/bin/rbw-agent/actions.rs
@@ -115,6 +115,14 @@ pub async fn unlock(
"failed to find protected key in db"
));
};
+ let protected_private_key =
+ if let Some(protected_private_key) = db.protected_private_key {
+ protected_private_key
+ } else {
+ return Err(anyhow::anyhow!(
+ "failed to find protected private key in db"
+ ));
+ };
for i in 1u8..=3 {
let err = if i > 1 {
@@ -135,11 +143,15 @@ pub async fn unlock(
&password,
iterations,
&protected_key,
+ &protected_private_key,
+ &db.protected_org_keys,
)
.await;
match res {
- Ok(keys) => {
- state.write().await.priv_key = Some(keys);
+ Ok((keys, org_keys)) => {
+ let mut state = state.write().await;
+ state.priv_key = Some(keys);
+ state.org_keys = org_keys;
break;
}
Err(rbw::error::Error::IncorrectPassword) => {
diff --git a/src/cipherstring.rs b/src/cipherstring.rs
index 15c9add..7ba64ca 100644
--- a/src/cipherstring.rs
+++ b/src/cipherstring.rs
@@ -10,6 +10,10 @@ pub enum CipherString {
ciphertext: Vec<u8>,
mac: Option<Vec<u8>>,
},
+ Asymmetric {
+ // ty: 4 (RSA_2048_OAEP_SHA1)
+ ciphertext: Vec<u8>,
+ },
}
impl CipherString {
@@ -53,6 +57,11 @@ impl CipherString {
mac,
})
}
+ 4 => {
+ let ciphertext = base64::decode(contents)
+ .context(crate::error::InvalidBase64)?;
+ Ok(Self::Asymmetric { ciphertext })
+ }
_ => Err(Error::InvalidCipherString),
}
}
@@ -106,6 +115,7 @@ impl CipherString {
.decrypt_vec(ciphertext)
.context(crate::error::Decrypt)
}
+ _ => Err(Error::InvalidCipherString),
}
}
@@ -132,6 +142,40 @@ impl CipherString {
.context(crate::error::Decrypt)?;
Ok(res)
}
+ _ => Err(Error::InvalidCipherString),
+ }
+ }
+
+ pub fn decrypt_locked_asymmetric(
+ &self,
+ private_key: &crate::locked::PrivateKey,
+ ) -> Result<crate::locked::Vec> {
+ match self {
+ Self::Asymmetric { ciphertext } => {
+ // ring doesn't currently support asymmetric encryption (only
+ // signatures). see
+ // https://github.com/briansmith/ring/issues/691
+ let pkey = openssl::pkey::PKey::private_key_from_pkcs8(
+ private_key.private_key(),
+ )
+ .unwrap(); // XXX
+ let rsa = pkey.rsa().unwrap(); // XXX
+
+ let mut res = crate::locked::Vec::new();
+ res.extend(std::iter::repeat(0).take(rsa.size() as usize));
+
+ let bytes = rsa
+ .private_decrypt(
+ ciphertext,
+ res.data_mut(),
+ openssl::rsa::Padding::PKCS1_OAEP,
+ )
+ .unwrap(); // XXX
+ res.truncate(bytes);
+
+ Ok(res)
+ }
+ _ => Err(Error::InvalidCipherString),
}
}
}
@@ -183,6 +227,10 @@ impl std::fmt::Display for CipherString {
write!(f, "2.{}|{}", iv, ciphertext)
}
}
+ Self::Asymmetric { ciphertext } => {
+ let ciphertext = base64::encode(&ciphertext);
+ write!(f, "4.{}", ciphertext)
+ }
}
}
}
diff --git a/src/locked.rs b/src/locked.rs
index 4db0423..3cad927 100644
--- a/src/locked.rs
+++ b/src/locked.rs
@@ -89,3 +89,17 @@ impl PasswordHash {
self.hash.data()
}
}
+
+pub struct PrivateKey {
+ private_key: Vec,
+}
+
+impl PrivateKey {
+ pub fn new(private_key: Vec) -> Self {
+ Self { private_key }
+ }
+
+ pub fn private_key(&self) -> &[u8] {
+ self.private_key.data()
+ }
+}