From a5611ca7ea33ec5edcb0100c4a4ccea46af0ec53 Mon Sep 17 00:00:00 2001 From: Mitchell Grenier Date: Tue, 15 Apr 2025 18:57:14 -0700 Subject: [PATCH 1/6] builds --- Cargo.toml | 12 ++-- examples/yk-provision.rs | 24 +++++--- src/yubikey/piv/management.rs | 101 +++++++++++++++++++++++----------- 3 files changed, 91 insertions(+), 46 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6cc0653..b181fae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sshcerts" -version = "0.13.2" +version = "0.14.0" authors = ["Mitchell Grenier "] edition = "2021" license-file = "LICENSE" @@ -48,7 +48,7 @@ fido-lite = ["minicbor", "x509-parser"] rsa-signing = ["simple_asn1", "num-bigint"] x509-support = ["der-parser", "x509", "x509-parser"] yubikey-support = ["rcgen", "yubikey", "yubikey-lite"] -yubikey-lite = ["x509-support"] +yubikey-lite = ["x509-support", "der", "x509-cert"] [dependencies] base64 = "0.13" @@ -61,12 +61,14 @@ simple_asn1 = { version = "0.5", optional = true } num-bigint = { version = "0.4", optional = true } # Dependencies for yubikey-support -yubikey = { version = "0.7", features = ["untested"], optional = true } +yubikey = { version = "0.8", features = ["untested"], optional = true } lexical-core = { version = ">0.7.4", optional = true } rcgen = { version = "0.11", optional = true } x509 = { version = "0.2", optional = true } x509-parser = { version = "0.15", features = ["verify"], optional = true } der-parser = { version = "5", optional = true } +der = { version = "0.7", optional = true } +x509-cert = { version = "0.2", optional = true } # Dependencies for encrypted-keys aes = { version = "0.7", features = ["ctr"], optional = true } @@ -83,8 +85,8 @@ authenticator = { version = "0.4.0-alpha.24", default-features = false, features # authenticator = { path = "../authenticator-rs", default-features = false, features = [ # "crypto_openssl", # ], optional = true } - - +p256 = "*" +p384 = "*" # Dependencies for fido-support ctap-hid-fido2 = { version = "3", optional = true } #ctap-hid-fido2 = {git = "https://github.com/gebogebogebo/ctap-hid-fido2", branch="master", optional = true} diff --git a/examples/yk-provision.rs b/examples/yk-provision.rs index 60c4333..bdf82e4 100644 --- a/examples/yk-provision.rs +++ b/examples/yk-provision.rs @@ -15,11 +15,6 @@ fn provision_new_key( alg: &str, secure: bool, ) { - let alg = match alg { - "p256" => AlgorithmId::EccP256, - _ => AlgorithmId::EccP384, - }; - println!( "Provisioning new {:?} key called [{}] in slot: {:?}", alg, subject, slot @@ -34,11 +29,22 @@ fn provision_new_key( let mut yk = Yubikey::new().unwrap(); yk.unlock(pin.as_bytes(), mgm_key).unwrap(); - match yk.provision(&slot, subject, alg, policy, PinPolicy::Never) { - Ok(pk) => { - println!("New hardware backed SSH Public Key: {}", pk); + match alg { + "p256" => match yk.provision::(&slot, subject, policy, PinPolicy::Never) { + Ok(pk) => { + println!("New hardware backed SSH Public Key: {}", pk); + } + Err(e) => panic!("Could not provision device with new key: {:?}", e), + }, + _ => { + println!("Using P384"); + match yk.provision::(&slot, subject, policy, PinPolicy::Never) { + Ok(pk) => { + println!("New hardware backed SSH Public Key: {}", pk); + } + Err(e) => panic!("Could not provision device with new key: {:?}", e), + } } - Err(e) => panic!("Could not provision device with new key: {:?}", e), } } diff --git a/src/yubikey/piv/management.rs b/src/yubikey/piv/management.rs index 686cb22..5bba579 100644 --- a/src/yubikey/piv/management.rs +++ b/src/yubikey/piv/management.rs @@ -1,16 +1,24 @@ use crate::PublicKey; +use der::oid::ObjectIdentifier; use ring::digest; -use yubikey::certificate::{Certificate, PublicKeyInfo}; +use yubikey::certificate::Certificate; use yubikey::piv::{attest, sign_data as yk_sign_data, AlgorithmId, SlotId}; use yubikey::{MgmKey, YubiKey}; use yubikey::{PinPolicy, TouchPolicy}; -use x509::RelativeDistinguishedName; - use super::{Error, Result}; +use der::Encode; +use x509_cert::name::Name; +use x509_cert::{serial_number::SerialNumber, time::Validity}; + +use std::str::FromStr; +use yubikey::certificate::yubikey_signer; + +use x509_parser::der_parser::asn1_rs::ToDer; + #[derive(Debug)] /// A struct that allows the generation of CSRs via the rcgen library. This is /// only used when calling the `generate_csr` function. @@ -21,16 +29,34 @@ pub struct CSRSigner { algorithm: AlgorithmId, } +const NISTP256_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7"); +const SECG384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.132.0.34"); + impl CSRSigner { /// Create a new certificate signer based on a Yubikey serial /// and slot pub fn new(serial: u32, slot: SlotId) -> Self { let mut yk = super::Yubikey::open(serial).unwrap(); - let pki = yk.configured(&slot).unwrap(); - let (public_key, algorithm) = match pki { - PublicKeyInfo::Rsa { pubkey: _, .. } => panic!("RSA keys not supported"), - PublicKeyInfo::EcP256(pubkey) => (pubkey.as_bytes().to_vec(), AlgorithmId::EccP256), - PublicKeyInfo::EcP384(pubkey) => (pubkey.as_bytes().to_vec(), AlgorithmId::EccP384), + let cert = yk.configured(&slot).unwrap(); + let pki = cert.subject_pki(); + let (public_key, algorithm) = match pki.algorithm.oid { + NISTP256_OID => { + // This is the OID for ECDSA with SHA256 + ( + pki.subject_public_key.raw_bytes().to_der_vec().unwrap(), + AlgorithmId::EccP256, + ) + } + SECG384_OID => { + // This is the OID for ECDSA with SHA384 + ( + pki.subject_public_key.raw_bytes().to_der_vec().unwrap(), + AlgorithmId::EccP384, + ) + } + _ => { + panic!("Unsupported algorithm"); + } }; Self { @@ -54,7 +80,8 @@ impl rcgen::RemoteKeyPair for CSRSigner { return Err(rcgen::RcgenError::RemoteKeyError); }; - yk.sign_data(message, self.algorithm, &self.slot).map_err(|_| rcgen::RcgenError::RemoteKeyError) + yk.sign_data(message, self.algorithm, &self.slot) + .map_err(|_| rcgen::RcgenError::RemoteKeyError) } fn algorithm(&self) -> &'static rcgen::SignatureAlgorithm { @@ -108,9 +135,9 @@ impl super::Yubikey { } /// Check to see that a provided Yubikey and slot is configured for signing - pub fn configured(&mut self, slot: &SlotId) -> Result { + pub fn configured(&mut self, slot: &SlotId) -> Result { let cert = Certificate::read(&mut self.yk, *slot)?; - Ok(cert.subject_pki().clone()) + Ok(cert) } /// Check to see that a provided Yubikey and slot is configured for signing @@ -122,7 +149,9 @@ impl super::Yubikey { /// Fetch the certificate from a given Yubikey slot. pub fn fetch_certificate(&mut self, slot: &SlotId) -> Result> { let cert = Certificate::read(&mut self.yk, *slot)?; - Ok(cert.as_ref().to_vec()) + Ok(cert.cert.to_der().map_err(|e| { + Error::InternalYubiKeyError(format!("Failed to encode certificate: {}", e)) + })?) } /// Write the certificate from a given Yubikey slot. @@ -142,9 +171,11 @@ impl super::Yubikey { /// Generate CSR for slot pub fn generate_csr(&mut self, slot: &SlotId, common_name: &str) -> Result> { let mut params = rcgen::CertificateParams::new(vec![]); - params.alg = match self.configured(slot)? { - PublicKeyInfo::EcP256(_) => &rcgen::PKCS_ECDSA_P256_SHA256, - PublicKeyInfo::EcP384(_) => &rcgen::PKCS_ECDSA_P384_SHA384, + let cert = self.configured(&slot).unwrap(); + let pki = cert.subject_pki(); + params.alg = match pki.algorithm.oid { + NISTP256_OID => &rcgen::PKCS_ECDSA_P256_SHA256, + SECG384_OID => &rcgen::PKCS_ECDSA_P384_SHA384, _ => return Err(Error::Unsupported), }; params @@ -152,35 +183,40 @@ impl super::Yubikey { .push(rcgen::DnType::CommonName, common_name.to_string()); let csr_signer = CSRSigner::new(self.yk.serial().into(), *slot); - params.key_pair = Some(rcgen::KeyPair::from_remote(Box::new(csr_signer)).map_err(|e| Error::InternalYubiKeyError(format!("{}", e)))?); + params.key_pair = Some( + rcgen::KeyPair::from_remote(Box::new(csr_signer)) + .map_err(|e| Error::InternalYubiKeyError(format!("{}", e)))?, + ); - let csr = rcgen::Certificate::from_params(params).map_err(|e| Error::InternalYubiKeyError(format!("{}", e)))?; - let csr = csr.serialize_request_der().map_err(|e| Error::InternalYubiKeyError(format!("{}", e)))?; + let csr = rcgen::Certificate::from_params(params) + .map_err(|e| Error::InternalYubiKeyError(format!("{}", e)))?; + let csr = csr + .serialize_request_der() + .map_err(|e| Error::InternalYubiKeyError(format!("{}", e)))?; Ok(csr) } /// Provisions the YubiKey with a new certificate generated on the device. /// Only keys that are generated this way can use the attestation functionality. - pub fn provision( + pub fn provision( &mut self, slot: &SlotId, common_name: &str, - alg: AlgorithmId, touch_policy: TouchPolicy, pin_policy: PinPolicy, ) -> Result { - let key_info = yubikey::piv::generate(&mut self.yk, *slot, alg, pin_policy, touch_policy)?; - let extensions: &[x509::Extension<'_, &[u64]>] = &[]; + let key_info = + yubikey::piv::generate(&mut self.yk, *slot, KT::ALGORITHM, pin_policy, touch_policy)?; // Generate a self-signed certificate for the new key. - Certificate::generate_self_signed( + Certificate::generate_self_signed::<_, KT>( &mut self.yk, *slot, - [0u8; 20], - None, - &[RelativeDistinguishedName::common_name(common_name)], + SerialNumber::new(&[0; 8]).unwrap(), + Validity::from_now(std::time::Duration::new(3600 * 24 * 3650, 0)).unwrap(), + Name::from_str(&format!("CN={}", common_name)).unwrap(), key_info, - extensions, + |_builder| Ok(()), )?; self.ssh_cert_fetch_pubkey(slot) @@ -191,11 +227,12 @@ impl super::Yubikey { /// If the requested algorithm doesn't match the key in the slot (or the slot /// is empty) this will error. pub fn sign_data(&mut self, data: &[u8], alg: AlgorithmId, slot: &SlotId) -> Result> { - let (slot_alg, hash_alg) = match self.configured(slot) { - Ok(PublicKeyInfo::EcP256(_)) => (AlgorithmId::EccP256, &digest::SHA256), - Ok(PublicKeyInfo::EcP384(_)) => (AlgorithmId::EccP384, &digest::SHA384), - Ok(_) => (AlgorithmId::Rsa2048, &digest::SHA256), // RSAish - Err(_) => return Err(Error::Unprovisioned), + let cert = self.configured(&slot).unwrap(); + let pki = cert.subject_pki(); + let (slot_alg, hash_alg) = match pki.algorithm.oid { + NISTP256_OID => (AlgorithmId::EccP256, &digest::SHA256), + SECG384_OID => (AlgorithmId::EccP384, &digest::SHA384), + _ => return Err(Error::Unprovisioned), }; if slot_alg != alg { From f532486bdafcaaa3e2f75b2a4f90afaa6dae94dd Mon Sep 17 00:00:00 2001 From: Mitchell Grenier Date: Tue, 15 Apr 2025 19:10:46 -0700 Subject: [PATCH 2/6] Works but not good --- Cargo.toml | 5 +++-- benches/certs_per_second.rs | 4 ++-- examples/yk-provision.rs | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b181fae..381fae1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,8 +85,7 @@ authenticator = { version = "0.4.0-alpha.24", default-features = false, features # authenticator = { path = "../authenticator-rs", default-features = false, features = [ # "crypto_openssl", # ], optional = true } -p256 = "*" -p384 = "*" + # Dependencies for fido-support ctap-hid-fido2 = { version = "3", optional = true } #ctap-hid-fido2 = {git = "https://github.com/gebogebogebo/ctap-hid-fido2", branch="master", optional = true} @@ -98,6 +97,8 @@ env_logger = "0.8.2" hex = "0.4.2" clap = "3.0.5" criterion = "0.3" +p256 = "*" +p384 = "*" [[bench]] name = "certs_per_second" diff --git a/benches/certs_per_second.rs b/benches/certs_per_second.rs index 489c7e5..7efed67 100644 --- a/benches/certs_per_second.rs +++ b/benches/certs_per_second.rs @@ -1,6 +1,6 @@ use criterion::{criterion_group, criterion_main, Criterion}; - -use sshcerts::yubikey::{RetiredSlotId, SlotId, Yubikey}; +use sshcerts::yubikey::piv::Yubikey; +use yubikey::piv::{RetiredSlotId, SlotId}; fn generate_certs(n: u64) -> () { let data = [0; 32]; diff --git a/examples/yk-provision.rs b/examples/yk-provision.rs index bdf82e4..bf102f7 100644 --- a/examples/yk-provision.rs +++ b/examples/yk-provision.rs @@ -3,7 +3,7 @@ use std::env; use clap::{Arg, Command}; use sshcerts::yubikey::piv::Yubikey; -use sshcerts::yubikey::piv::{AlgorithmId, PinPolicy, RetiredSlotId, SlotId, TouchPolicy}; +use sshcerts::yubikey::piv::{PinPolicy, RetiredSlotId, SlotId, TouchPolicy}; use std::convert::TryFrom; From 5809ba5c08e98fa695037743d789444eb3447bb3 Mon Sep 17 00:00:00 2001 From: Mitchell Grenier Date: Tue, 15 Apr 2025 19:41:12 -0700 Subject: [PATCH 3/6] More tested --- examples/sign-cert-with-yubikey.rs | 35 ++++++++++++++++++++++++++++-- src/yubikey/piv/management.rs | 28 +++++++++++++++++------- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/examples/sign-cert-with-yubikey.rs b/examples/sign-cert-with-yubikey.rs index 5d24523..981d987 100644 --- a/examples/sign-cert-with-yubikey.rs +++ b/examples/sign-cert-with-yubikey.rs @@ -36,14 +36,22 @@ fn slot_validator(slot: &str) -> Result<(), String> { struct YubikeySigner { slot: SlotId, + pin: String, + mgm_key: Vec, } impl SSHCertificateSigner for YubikeySigner { fn sign(&self, buffer: &[u8]) -> Option> { let mut yk = Yubikey::new().unwrap(); + yk.unlock(self.pin.as_bytes(), &self.mgm_key).unwrap(); + println!("Unlocking Successful"); + match yk.ssh_cert_signer(buffer, &self.slot) { Ok(sig) => Some(sig), - Err(_) => None, + Err(e) => { + println!("Error signing: {:?}", e); + None + } } } } @@ -79,14 +87,37 @@ fn main() { .required(true) .takes_value(true), ) + .arg( + Arg::new("pin") + .help("Provision this slot with a new private key. The pin number must be passed as parameter here") + .default_value("123456") + .long("pin") + .short('p') + .takes_value(true), + ) + .arg( + Arg::new("management-key") + .help("Provision this slot with a new private key. The pin number must be passed as parameter here") + .default_value("010203040506070801020304050607080102030405060708") + .long("mgmkey") + .short('m') + .takes_value(true), + ) .get_matches(); let slot = slot_parser(matches.value_of("slot").unwrap()).unwrap(); let mut yk = Yubikey::new().unwrap(); + let yk_pubkey = yk.ssh_cert_fetch_pubkey(&slot).unwrap(); + let ssh_pubkey = PublicKey::from_path(matches.value_of("key").unwrap()).unwrap(); + println!("Signing {ssh_pubkey} with {yk_pubkey}"); - let yk_signer = YubikeySigner { slot }; + let yk_signer = YubikeySigner { + slot, + pin: matches.value_of("pin").unwrap().to_string(), + mgm_key: hex::decode(matches.value_of("management-key").unwrap()).unwrap(), + }; let user_cert = Certificate::builder(&ssh_pubkey, CertType::User, &yk_pubkey) .unwrap() diff --git a/src/yubikey/piv/management.rs b/src/yubikey/piv/management.rs index 5bba579..b4614a2 100644 --- a/src/yubikey/piv/management.rs +++ b/src/yubikey/piv/management.rs @@ -30,7 +30,7 @@ pub struct CSRSigner { } const NISTP256_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7"); -const SECG384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.132.0.34"); +const SECP384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.132.0.34"); impl CSRSigner { /// Create a new certificate signer based on a Yubikey serial @@ -39,7 +39,9 @@ impl CSRSigner { let mut yk = super::Yubikey::open(serial).unwrap(); let cert = yk.configured(&slot).unwrap(); let pki = cert.subject_pki(); - let (public_key, algorithm) = match pki.algorithm.oid { + let oid_alg = pki.algorithm.parameters_oid().unwrap(); + + let (public_key, algorithm) = match oid_alg { NISTP256_OID => { // This is the OID for ECDSA with SHA256 ( @@ -47,7 +49,7 @@ impl CSRSigner { AlgorithmId::EccP256, ) } - SECG384_OID => { + SECP384_OID => { // This is the OID for ECDSA with SHA384 ( pki.subject_public_key.raw_bytes().to_der_vec().unwrap(), @@ -173,9 +175,14 @@ impl super::Yubikey { let mut params = rcgen::CertificateParams::new(vec![]); let cert = self.configured(&slot).unwrap(); let pki = cert.subject_pki(); - params.alg = match pki.algorithm.oid { + let oid_alg = pki + .algorithm + .parameters_oid() + .map_err(|_| Error::Unsupported)?; + + params.alg = match oid_alg { NISTP256_OID => &rcgen::PKCS_ECDSA_P256_SHA256, - SECG384_OID => &rcgen::PKCS_ECDSA_P384_SHA384, + SECP384_OID => &rcgen::PKCS_ECDSA_P384_SHA384, _ => return Err(Error::Unsupported), }; params @@ -212,7 +219,7 @@ impl super::Yubikey { Certificate::generate_self_signed::<_, KT>( &mut self.yk, *slot, - SerialNumber::new(&[0; 8]).unwrap(), + SerialNumber::new(&[0; 20]).unwrap(), Validity::from_now(std::time::Duration::new(3600 * 24 * 3650, 0)).unwrap(), Name::from_str(&format!("CN={}", common_name)).unwrap(), key_info, @@ -229,9 +236,14 @@ impl super::Yubikey { pub fn sign_data(&mut self, data: &[u8], alg: AlgorithmId, slot: &SlotId) -> Result> { let cert = self.configured(&slot).unwrap(); let pki = cert.subject_pki(); - let (slot_alg, hash_alg) = match pki.algorithm.oid { + let oid_alg = pki + .algorithm + .parameters_oid() + .map_err(|_| Error::Unprovisioned)?; + + let (slot_alg, hash_alg) = match oid_alg { NISTP256_OID => (AlgorithmId::EccP256, &digest::SHA256), - SECG384_OID => (AlgorithmId::EccP384, &digest::SHA384), + SECP384_OID => (AlgorithmId::EccP384, &digest::SHA384), _ => return Err(Error::Unprovisioned), }; From 4feae31f9fd580bbe7a1da204e95a1d1253d5ed0 Mon Sep 17 00:00:00 2001 From: Mitchell Grenier Date: Tue, 15 Apr 2025 19:59:04 -0700 Subject: [PATCH 4/6] Bump authentictor-rs --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 381fae1..543a3ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,7 +79,7 @@ ctr = { version = "0.8", optional = true } minicbor = { version = "0.13", optional = true } # Dependencies for fido-support-mozilla -authenticator = { version = "0.4.0-alpha.24", default-features = false, features = [ +authenticator = { version = "0.4.1", default-features = false, features = [ "crypto_openssl", ], optional = true } # authenticator = { path = "../authenticator-rs", default-features = false, features = [ From 92e3c4f5dc23293443fe461ac9886addb8a79131 Mon Sep 17 00:00:00 2001 From: Mitchell Grenier Date: Tue, 15 Apr 2025 20:06:51 -0700 Subject: [PATCH 5/6] Remove x509-parser from piv management module --- src/yubikey/piv/management.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/yubikey/piv/management.rs b/src/yubikey/piv/management.rs index b4614a2..a3cc01e 100644 --- a/src/yubikey/piv/management.rs +++ b/src/yubikey/piv/management.rs @@ -1,6 +1,5 @@ use crate::PublicKey; -use der::oid::ObjectIdentifier; use ring::digest; use yubikey::certificate::Certificate; @@ -10,15 +9,16 @@ use yubikey::{PinPolicy, TouchPolicy}; use super::{Error, Result}; -use der::Encode; -use x509_cert::name::Name; -use x509_cert::{serial_number::SerialNumber, time::Validity}; +use x509_cert::{ + der::{oid::ObjectIdentifier, Encode}, + name::Name, + serial_number::SerialNumber, + time::Validity, +}; use std::str::FromStr; use yubikey::certificate::yubikey_signer; -use x509_parser::der_parser::asn1_rs::ToDer; - #[derive(Debug)] /// A struct that allows the generation of CSRs via the rcgen library. This is /// only used when calling the `generate_csr` function. @@ -45,14 +45,22 @@ impl CSRSigner { NISTP256_OID => { // This is the OID for ECDSA with SHA256 ( - pki.subject_public_key.raw_bytes().to_der_vec().unwrap(), + pki.subject_public_key + .raw_bytes() + .to_vec() + .to_der() + .unwrap(), AlgorithmId::EccP256, ) } SECP384_OID => { // This is the OID for ECDSA with SHA384 ( - pki.subject_public_key.raw_bytes().to_der_vec().unwrap(), + pki.subject_public_key + .raw_bytes() + .to_vec() + .to_der() + .unwrap(), AlgorithmId::EccP384, ) } From 3382bf56003086e2c66c40203a16cf01197447e2 Mon Sep 17 00:00:00 2001 From: Mitchell Grenier Date: Wed, 16 Apr 2025 16:39:23 -0700 Subject: [PATCH 6/6] Clean up test --- examples/yk-provision.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/examples/yk-provision.rs b/examples/yk-provision.rs index bf102f7..14d5db7 100644 --- a/examples/yk-provision.rs +++ b/examples/yk-provision.rs @@ -29,22 +29,16 @@ fn provision_new_key( let mut yk = Yubikey::new().unwrap(); yk.unlock(pin.as_bytes(), mgm_key).unwrap(); - match alg { - "p256" => match yk.provision::(&slot, subject, policy, PinPolicy::Never) { - Ok(pk) => { - println!("New hardware backed SSH Public Key: {}", pk); - } - Err(e) => panic!("Could not provision device with new key: {:?}", e), - }, + let result = match alg { + "p256" => yk.provision::(&slot, subject, policy, PinPolicy::Never), _ => { println!("Using P384"); - match yk.provision::(&slot, subject, policy, PinPolicy::Never) { - Ok(pk) => { - println!("New hardware backed SSH Public Key: {}", pk); - } - Err(e) => panic!("Could not provision device with new key: {:?}", e), - } + yk.provision::(&slot, subject, policy, PinPolicy::Never) } + }; + match result { + Ok(pk) => println!("New hardware backed SSH Public Key: {}", pk), + Err(e) => panic!("Could not provision device with new key: {:?}", e), } }