Skip to content

Commit

Permalink
Implement multithread (#44)
Browse files Browse the repository at this point in the history
* Try to make multithreaded but not tested

* Wrap Signatory::Direct's PrivateKey with Mutex

---------

Co-authored-by: Mitchell Grenier <[email protected]>
  • Loading branch information
timweri and obelisk authored Dec 6, 2023
1 parent 7027da4 commit 7ed477e
Show file tree
Hide file tree
Showing 14 changed files with 267 additions and 222 deletions.
26 changes: 15 additions & 11 deletions rustica-agent-cli/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub enum RusticaAgentAction {
ListPIVKeys(listpivkeys::ListPIVKeysConfig),
ListFidoDevices,
GitConfig(PublicKey),
RefreshAttestedX509(refresh_attested_x509_certificate::RefreshAttestedX509Config)
RefreshAttestedX509(refresh_attested_x509_certificate::RefreshAttestedX509Config),
}

impl From<std::io::Error> for ConfigurationError {
Expand Down Expand Up @@ -85,26 +85,26 @@ fn get_signatory(
match (cmd_slot, config_slot, file, &config_key) {
(Some(slot), _, _, _) => match slot_parser(slot) {
Some(s) => Ok(Signatory::Yubikey(YubikeySigner {
yk: Yubikey::new().unwrap(),
yk: Yubikey::new().unwrap().into(),
slot: s,
})),
None => Err(ConfigurationError::BadSlot),
},
(_, _, Some(file), _) => match PrivateKey::from_path(file) {
Ok(p) => Ok(Signatory::Direct(p)),
Ok(p) => Ok(Signatory::Direct(p.into())),
Err(e) => Err(ConfigurationError::CannotReadFile(format!(
"{}: {}",
e, file
))),
},
(_, Some(slot), _, _) => match slot_parser(slot) {
Some(s) => Ok(Signatory::Yubikey(YubikeySigner {
yk: Yubikey::new().unwrap(),
yk: Yubikey::new().unwrap().into(),
slot: s,
})),
None => Err(ConfigurationError::BadSlot),
},
(_, _, _, Some(key_string)) => Ok(Signatory::Direct(PrivateKey::from_string(key_string)?)),
(_, _, _, Some(key_string)) => Ok(Signatory::Direct(PrivateKey::from_string(key_string)?.into())),
(None, None, None, None) => Err(ConfigurationError::MissingSSHKey),
}
}
Expand Down Expand Up @@ -166,7 +166,9 @@ pub fn add_daemon_options(cmd: Command) -> Command {
)
}

fn parse_config_from_args(matches: &ArgMatches) -> Result<UpdatableConfiguration, ConfigurationError> {
fn parse_config_from_args(
matches: &ArgMatches,
) -> Result<UpdatableConfiguration, ConfigurationError> {
UpdatableConfiguration::new(matches.value_of("config").unwrap())
.map_err(|e| ConfigurationError::BadConfiguration(e))
}
Expand Down Expand Up @@ -255,10 +257,11 @@ pub async fn configure() -> Result<RusticaAgentAction, ConfigurationError> {
.about("Show the git configuration for code-signing with the provided key"),
);

let refresh_x509 = refresh_attested_x509_certificate::add_configuration(new_run_agent_subcommand(
"refresh-attested-x509",
"Refresh an X509 certificate in a Yubikey slot",
));
let refresh_x509 =
refresh_attested_x509_certificate::add_configuration(new_run_agent_subcommand(
"refresh-attested-x509",
"Refresh an X509 certificate in a Yubikey slot",
));

let command_configuration = command_configuration
.subcommand(immediate_mode)
Expand Down Expand Up @@ -312,7 +315,8 @@ pub async fn configure() -> Result<RusticaAgentAction, ConfigurationError> {
}

if let Some(x509_config) = matches.subcommand_matches("refresh-x509") {
return refresh_attested_x509_certificate::configure_refresh_x509_certificate(x509_config).await;
return refresh_attested_x509_certificate::configure_refresh_x509_certificate(x509_config)
.await;
}

cc_help.print_help().unwrap();
Expand Down
15 changes: 7 additions & 8 deletions rustica-agent-cli/src/config/multimode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{collections::HashMap, fs};

use rustica_agent::{
get_all_piv_keys, Handler, RusticaAgentLibraryError, Signatory, YubikeyPIVKeyDescriptor,
YubikeySigner
YubikeySigner,
};

use clap::{Arg, ArgMatches, Command};
Expand Down Expand Up @@ -91,7 +91,7 @@ fn get_signatory(
let key = PublicKey::from_bytes(key).unwrap();
if certificate_fingerprint == key.fingerprint().hash {
let sig = Signatory::Yubikey(YubikeySigner {
yk: Yubikey::open(des.serial).unwrap(),
yk: Yubikey::open(des.serial).unwrap().into(),
slot: des.slot,
});
return Ok((des.public_key.clone(), sig));
Expand All @@ -102,7 +102,7 @@ fn get_signatory(
if certificate_fingerprint == private_key.pubkey.fingerprint().hash {
return Ok((
private_key.pubkey.clone(),
Signatory::Direct(private_key.clone()),
Signatory::Direct(private_key.clone().into()),
));
}
}
Expand Down Expand Up @@ -157,17 +157,16 @@ pub async fn configure_multimode(
key_map.remove(&pubkey.encode().to_vec());

let handler = Handler {
updatable_configuration,
cert: None,
updatable_configuration: updatable_configuration.into(),
cert: None.into(),
pubkey: pubkey.clone(),
signatory,
stale_at: 0,
stale_at: 0.into(),
certificate_options,
identities: private_keys,
identities: private_keys.into(),
piv_identities: key_map,
notification_function: None,
certificate_priority: matches.is_present("certificate-priority"),

};

Ok(RusticaAgentAction::Run(RunConfig {
Expand Down
80 changes: 41 additions & 39 deletions rustica-agent-cli/src/config/refresh_attested_x509_certificate.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::env;

use clap::{Command, Arg, ArgMatches};
use rustica_agent::{slot_validator, slot_parser, Signatory, YubikeySigner, config::UpdatableConfiguration};
use clap::{Arg, ArgMatches, Command};
use rustica_agent::{
config::UpdatableConfiguration, slot_parser, slot_validator, Signatory, YubikeySigner,
};
use sshcerts::yubikey::piv::Yubikey;

use super::{RusticaAgentAction, ConfigurationError, parse_config_from_args};
use super::{parse_config_from_args, ConfigurationError, RusticaAgentAction};

pub struct RefreshAttestedX509Config {
pub updatable_configuration: UpdatableConfiguration,
Expand All @@ -22,7 +24,7 @@ pub async fn configure_refresh_x509_certificate(
let slot = slot_parser(&slot).unwrap();

let signatory = Signatory::Yubikey(YubikeySigner {
yk: Yubikey::new().unwrap(),
yk: Yubikey::new().unwrap().into(),
slot,
});

Expand All @@ -37,42 +39,42 @@ pub async fn configure_refresh_x509_certificate(
Err(_) => return Err(ConfigurationError::YubikeyManagementKeyInvalid),
};


Ok(RusticaAgentAction::RefreshAttestedX509(RefreshAttestedX509Config {
updatable_configuration,
signatory,
pin,
management_key,
}))
Ok(RusticaAgentAction::RefreshAttestedX509(
RefreshAttestedX509Config {
updatable_configuration,
signatory,
pin,
management_key,
},
))
}

pub fn add_configuration(cmd: Command) -> Command {
cmd
.arg(
Arg::new("slot")
.help("Numerical value for the slot on the yubikey to use for your private key")
.long("slot")
.short('s')
.required(true)
.validator(slot_validator)
.takes_value(true),
)
.arg(
Arg::new("pin-env")
.help("Specify a different pin environment variable")
.default_value("YK_PIN")
.long("pinenv")
.short('p')
.required(false)
.takes_value(true),
)
.arg(
Arg::new("management-key")
.help("Specify the management key")
.default_value("010203040506070801020304050607080102030405060708")
.long("mgmkey")
.short('m')
.required(false)
.takes_value(true),
)
cmd.arg(
Arg::new("slot")
.help("Numerical value for the slot on the yubikey to use for your private key")
.long("slot")
.short('s')
.required(true)
.validator(slot_validator)
.takes_value(true),
)
.arg(
Arg::new("pin-env")
.help("Specify a different pin environment variable")
.default_value("YK_PIN")
.long("pinenv")
.short('p')
.required(false)
.takes_value(true),
)
.arg(
Arg::new("management-key")
.help("Specify the management key")
.default_value("010203040506070801020304050607080102030405060708")
.long("mgmkey")
.short('m')
.required(false)
.takes_value(true),
)
}
12 changes: 5 additions & 7 deletions rustica-agent-cli/src/config/register.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use clap::{Arg, ArgMatches, Command};
use rustica_agent::{slot_validator, PIVAttestation, Signatory, config::UpdatableConfiguration};
use rustica_agent::{config::UpdatableConfiguration, slot_validator, PIVAttestation, Signatory};
use yubikey::piv::SlotId;

use super::{get_signatory, parse_config_from_args, ConfigurationError, RusticaAgentAction};
Expand Down Expand Up @@ -32,12 +32,10 @@ pub async fn configure_register(
Signatory::Direct(_) => return Err(ConfigurationError::CannotAttestFileBasedKey),
};

attestation.certificate = signer
.yk
.fetch_attestation(&signer.slot)
.unwrap_or_default();
attestation.intermediate = signer
.yk
let mut yk = signer.yk.lock().await;

attestation.certificate = yk.fetch_attestation(&signer.slot).unwrap_or_default();
attestation.intermediate = yk
.fetch_certificate(&SlotId::Attestation)
.unwrap_or_default();

Expand Down
20 changes: 11 additions & 9 deletions rustica-agent-cli/src/config/singlemode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ pub async fn configure_singlemode(

let mut signatory = get_signatory(&slot, &config.slot, &file, &config.key)?;
let pubkey = match &mut signatory {
Signatory::Yubikey(signer) => match signer.yk.ssh_cert_fetch_pubkey(&signer.slot) {
Ok(cert) => cert,
Err(_) => return Err(ConfigurationError::YubikeyNoKeypairFound),
},
Signatory::Yubikey(signer) => {
match signer.yk.lock().await.ssh_cert_fetch_pubkey(&signer.slot) {
Ok(cert) => cert,
Err(_) => return Err(ConfigurationError::YubikeyNoKeypairFound),
}
}
Signatory::Direct(privkey) => {
let mut privkey = privkey.lock().await;
if let Some(path) = matches.value_of("fido-device-path") {
privkey.set_device_path(path);
}
Expand All @@ -36,17 +39,16 @@ pub async fn configure_singlemode(
};

let handler = Handler {
updatable_configuration,
cert: None,
updatable_configuration: updatable_configuration.into(),
cert: None.into(),
pubkey: pubkey.clone(),
signatory,
stale_at: 0,
stale_at: 0.into(),
certificate_options,
identities: HashMap::new(),
identities: HashMap::new().into(),
piv_identities: HashMap::new(),
notification_function: None,
certificate_priority: matches.is_present("certificate-priority"),

};

Ok(RusticaAgentAction::Run(RunConfig {
Expand Down
22 changes: 14 additions & 8 deletions rustica-agent-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
&config.management_key,
config.require_touch,
config.pin_policy,
) {
)
.await
{
Some(_) => (),
None => {
println!("Provisioning Error");
Expand All @@ -65,7 +67,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(RusticaAgentAction::ProvisionAndRegisterFido(prf)) => {
let new_fido_key = generate_new_ssh_key(&prf.app_name, &prf.comment, prf.pin, None)?;

let mut signatory = Signatory::Direct(new_fido_key.private_key.clone());
let mut signatory = Signatory::Direct(new_fido_key.private_key.clone().into());
let u2f_attestation = U2FAttestation {
auth_data: new_fido_key.attestation.auth_data,
auth_data_sig: new_fido_key.attestation.auth_data_sig,
Expand Down Expand Up @@ -184,15 +186,19 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.await;
}
Ok(RusticaAgentAction::RefreshAttestedX509(mut config)) => {
match rustica_agent::fetch_new_attested_x509_certificate(&config.updatable_configuration.get_configuration().servers, &mut config.signatory)
.await
match rustica_agent::fetch_new_attested_x509_certificate(
&config.updatable_configuration.get_configuration().servers,
&mut config.signatory,
)
.await
{
Ok(cert) => match config.signatory {
Signatory::Yubikey(mut yk) => {
yk.yk
.unlock(config.pin.as_bytes(), &config.management_key)
Signatory::Yubikey(yk) => {
let slot = yk.slot;
let mut yk = yk.yk.lock().await;
yk.unlock(config.pin.as_bytes(), &config.management_key)
.unwrap();
yk.yk.write_certificate(&yk.slot, &cert).unwrap();
yk.write_certificate(&slot, &cert).unwrap();
}
Signatory::Direct(_) => {
let parsed_cert = Certificate::from_bytes(cert.to_vec()).unwrap();
Expand Down
12 changes: 6 additions & 6 deletions rustica-agent-gui/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let agent = load_environments()?; //.into_iter().map(|x| x.to_string_lossy().to_string()).collect();

let options = eframe::NativeOptions::default();
eframe::run_native(
let _ = eframe::run_native(
"Rustica Agent",
options,
Box::new(move |_cc| Box::new(agent)),
Expand Down Expand Up @@ -299,18 +299,18 @@ impl eframe::App for RusticaAgentGui {
private_key.set_device_path(&self.fido_devices[*fido_device].path);

let pubkey = private_key.pubkey.clone();
let signatory = Signatory::Direct(private_key);
let signatory = Signatory::Direct(private_key.into());

let certificate_options = CertificateConfig::from(updatable_configuration.get_configuration().options.clone());

let handler = rustica_agent::Handler {
updatable_configuration,
cert: None,
updatable_configuration: updatable_configuration.into(),
cert: None.into(),
pubkey,
signatory,
stale_at: 0,
stale_at: 0.into(),
certificate_options,
identities: HashMap::new(),
identities:HashMap::new().into(),
piv_identities: self.piv_keys.iter().filter_map(|x| if x.1.in_use {Some((x.0.clone(), x.1.descriptor.clone()))} else {None}).collect(),
notification_function: None,
certificate_priority: self.certificate_priority,
Expand Down
Loading

0 comments on commit 7ed477e

Please sign in to comment.