Zeroize passphrases
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
parent
6e8e1e0972
commit
dc79130988
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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)?;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue