Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add FFI call to fetch mTLS identities and to provision PIV slot #56

Merged
merged 3 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions rustica-agent/src/ffi/enrollment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,3 +290,33 @@ pub unsafe extern "C" fn generate_and_enroll(
error!("All servers failed to register key");
false
}

#[no_mangle]
// Provision a new nistp384 key in the given slot
pub unsafe extern "C" fn provision_piv(
yubikey_serial: u32,
slot: u8,
subject: *const c_char,
pin: *const c_char,
management_key: *const c_char,
) -> bool {
let alg = AlgorithmId::EccP384;
let slot = SlotId::try_from(slot).unwrap();

println!("Provisioning new PIV key in slot {:?}", slot);

let pin = CStr::from_ptr(pin);
let management_key = CStr::from_ptr(management_key);
let management_key = hex::decode(&management_key.to_str().unwrap()).unwrap();
let subject = CStr::from_ptr(subject);
let policy = TouchPolicy::Always;

let mut yk = Yubikey::open(yubikey_serial).unwrap();

if yk.unlock(pin.to_str().unwrap().as_bytes(), &management_key).is_err() {
println!("Could not unlock key");
return false
}

yk.provision(&slot, subject.to_str().unwrap(), alg, policy, PinPolicy::Never).is_ok()
}
4 changes: 4 additions & 0 deletions rustica-agent/src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod allowed_signer;
mod signing;
mod utils;
mod yubikey_utils;
mod mtls;

use std::ffi::{c_char, c_long, CStr};

Expand All @@ -25,6 +26,9 @@ pub use utils::*;
/// For functions that handle YubiKey specific functionality (generally PIV)
pub use yubikey_utils::*;

/// For functions that handle mTLS configs
pub use mtls::*;

use crate::config::UpdatableConfiguration;

#[no_mangle]
Expand Down
50 changes: 50 additions & 0 deletions rustica-agent/src/ffi/mtls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use crate::config::UpdatableConfiguration;
use std::{ffi::{c_char, CStr, CString}, ptr::null};

#[no_mangle]
/// Read the mTLS identities of the primary server (the first one) given a config path
pub unsafe extern "C" fn ffi_get_identities_of_primary_server(config_path: *const c_char) -> *const c_char {
let cf = CStr::from_ptr(config_path);
let config_path = match cf.to_str() {
Err(_) => return null(),
Ok(s) => s,
};

let updatable_configuration = match UpdatableConfiguration::new(config_path) {

Ok(c) => c,
Err(e) => {
error!("Configuration was invalid: {e}");
return null();
}
};

let server = match updatable_configuration.get_configuration().servers.first() {
Some(s) => &s.mtls_cert,
None => return null(),
};

let cert = match x509_parser::pem::parse_x509_pem(server.as_bytes()) {
Err(e) => {
error!("Unable to parse mTLS cert PEM: {e}");
return null();
},
Ok((_, s)) => s,
};

let subject = match cert.parse_x509() {
Err(e) => {
error!("Unable to parse mTLS cert: {e}");
return null();
},
Ok(c) => c.tbs_certificate.subject().to_string(),
};

match CString::new(subject) {
Err(e) => {
error!("Unable to marshall subject to CString: {e}");
return null();
},
Ok(s) => s.into_raw(),
}
}
Loading