Zeroize passphrases

Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
Alexis Sellier 2022-11-03 16:52:29 +01:00
parent 6e8e1e0972
commit dc79130988
No known key found for this signature in database
3 changed files with 19 additions and 8 deletions

View File

@ -7,6 +7,9 @@ use zeroize::Zeroizing;
use crate::{KeyPair, PublicKey, SecretKey, Signature, Signer, SignerError}; use crate::{KeyPair, PublicKey, SecretKey, Signature, Signer, SignerError};
/// A secret key passphrase.
pub type Passphrase = Zeroizing<String>;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum Error { pub enum Error {
#[error(transparent)] #[error(transparent)]
@ -83,7 +86,10 @@ impl Keystore {
/// Load the secret key from the store, decrypting it with the given passphrase. /// Load the secret key from the store, decrypting it with the given passphrase.
/// Returns `None` if it wasn't found. /// Returns `None` if it wasn't found.
pub fn secret_key(&self, passphrase: &str) -> Result<Option<Zeroizing<SecretKey>>, Error> { pub fn secret_key(
&self,
passphrase: Passphrase,
) -> Result<Option<Zeroizing<SecretKey>>, Error> {
let path = self.path.join("radicle"); let path = self.path.join("radicle");
if !path.exists() { if !path.exists() {
return Ok(None); return Ok(None);
@ -135,7 +141,7 @@ impl Signer for MemorySigner {
impl MemorySigner { impl MemorySigner {
/// Load this signer from a keystore, given a secret key passphrase. /// Load this signer from a keystore, given a secret key passphrase.
pub fn load(keystore: &Keystore, passphrase: &str) -> Result<Self, MemorySignerError> { pub fn load(keystore: &Keystore, passphrase: Passphrase) -> Result<Self, MemorySignerError> {
let public = keystore let public = keystore
.public_key()? .public_key()?
.ok_or_else(|| MemorySignerError::NotFound(keystore.path().to_path_buf()))?; .ok_or_else(|| MemorySignerError::NotFound(keystore.path().to_path_buf()))?;
@ -177,10 +183,13 @@ mod tests {
let public = store.init("test", "hunter").unwrap(); let public = store.init("test", "hunter").unwrap();
assert_eq!(public, store.public_key().unwrap().unwrap()); assert_eq!(public, store.public_key().unwrap().unwrap());
let secret = store.secret_key("hunter").unwrap().unwrap(); let secret = store
.secret_key("hunter".to_owned().into())
.unwrap()
.unwrap();
assert_eq!(PublicKey::from(secret.public_key()), public); assert_eq!(PublicKey::from(secret.public_key()), public);
store.secret_key("blunder").unwrap_err(); // Wrong passphrase. store.secret_key("blunder".to_owned().into()).unwrap_err(); // Wrong passphrase.
} }
#[test] #[test]
@ -189,7 +198,7 @@ mod tests {
let store = Keystore::new(&tmp.path()); let store = Keystore::new(&tmp.path());
let public = store.init("test", "hunter").unwrap(); let public = store.init("test", "hunter").unwrap();
let signer = MemorySigner::load(&store, "hunter").unwrap(); let signer = MemorySigner::load(&store, "hunter".to_owned().into()).unwrap();
assert_eq!(public, *signer.public_key()); assert_eq!(public, *signer.public_key());
} }

View File

@ -57,8 +57,9 @@ fn main() -> anyhow::Result<()> {
Err(err) => { Err(err) => {
let passphrase = env::var(profile::env::RAD_PASSPHRASE) let passphrase = env::var(profile::env::RAD_PASSPHRASE)
.context("Either ssh-agent must be initialized, or `RAD_PASSPHRASE` must be set") .context("Either ssh-agent must be initialized, or `RAD_PASSPHRASE` must be set")
.context(err)?; .context(err)?
MemorySigner::load(&profile.keystore, &passphrase)?.boxed() .into();
MemorySigner::load(&profile.keystore, passphrase)?.boxed()
} }
}; };
let handle = client.handle(); let handle = client.handle();

View File

@ -18,9 +18,10 @@ fn main() -> anyhow::Result<()> {
let mut passphrase = String::new(); let mut passphrase = String::new();
io::stdin().lock().read_line(&mut passphrase)?; io::stdin().lock().read_line(&mut passphrase)?;
let passphrase = passphrase.trim().to_owned().into();
let secret = profile let secret = profile
.keystore .keystore
.secret_key(passphrase.trim())? .secret_key(passphrase)?
.ok_or_else(|| anyhow!("Key not found in {:?}", profile.keystore.path()))?; .ok_or_else(|| anyhow!("Key not found in {:?}", profile.keystore.path()))?;
agent.register(&secret)?; agent.register(&secret)?;