From e9222c5d3f00377fa0f83d5c11849422f9c90a06 Mon Sep 17 00:00:00 2001 From: Philip Tricca Date: Wed, 20 Nov 2024 21:11:52 -0800 Subject: [PATCH] Move all of the backup key stuff into a module. This is an intermediate state. Eventually the Hsm type won't touch any of they backup key creation and splitting. The main module will take over that part and the Hsm module will continue to deminish. --- Cargo.lock | 1 + Cargo.toml | 1 + src/backup.rs | 260 ++++++++++++++++++++++++++++++++++++++++ src/bin/printer-test.rs | 5 +- src/hsm.rs | 259 ++------------------------------------- src/lib.rs | 1 + src/main.rs | 15 ++- src/secret_reader.rs | 2 +- src/secret_writer.rs | 2 +- 9 files changed, 286 insertions(+), 260 deletions(-) create mode 100644 src/backup.rs diff --git a/Cargo.lock b/Cargo.lock index ae9633c..9e8fda7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1059,6 +1059,7 @@ dependencies = [ "x509-cert", "yubihsm", "zeroize", + "zeroize_derive", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f0fd513..99df1c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,3 +36,4 @@ vsss-rs = "2.7.1" x509-cert = "0.2.5" yubihsm = { git = "https://github.com/oxidecomputer/yubihsm.rs", branch = "session-close", features = ["usb", "untested"] } zeroize = "1.8.1" +zeroize_derive = "1.4.2" diff --git a/src/backup.rs b/src/backup.rs new file mode 100644 index 0000000..d7bccc6 --- /dev/null +++ b/src/backup.rs @@ -0,0 +1,260 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use anyhow::Result; +use log::{debug, info}; +use p256::{ + elliptic_curve::PrimeField, NonZeroScalar, ProjectivePoint, Scalar, + SecretKey, +}; +use rand_core::{CryptoRng, RngCore}; +use std::ops::Deref; +use vsss_rs::{Feldman, FeldmanVerifier}; +use zeroize::{DefaultIsZeroes, Zeroizing}; + +pub const KEY_LEN: usize = 32; +const SHARE_LEN: usize = KEY_LEN + 1; + +pub const LIMIT: usize = 5; +pub const THRESHOLD: usize = 3; +static_assertions::const_assert!(THRESHOLD <= LIMIT); + +pub type Share = vsss_rs::Share; +pub type SharesMax = [Share; LIMIT]; +pub type Verifier = FeldmanVerifier; + +/// A key we use to backup keys in the HSM. This type implements operations we +/// perform on / with this key when it's not in the HSM. +#[derive(Clone, Copy, Default)] +pub struct BackupKey([u8; KEY_LEN]); + +impl DefaultIsZeroes for BackupKey {} + +impl BackupKey { + pub fn from_rng(rng: &mut T) -> Result { + let mut key = [0u8; KEY_LEN]; + rng.try_fill_bytes(&mut key)?; + Ok(Self(key)) + } + + // use as_bytes::AsBytes; + pub fn as_bytes(&self) -> &[u8] { + &self.0 + } + + // impl From for BackupKey {} or something? + pub fn from_shares(shares: Zeroizing>) -> Result { + let scalar = Feldman::::combine_shares::< + Scalar, + SHARE_LEN, + >(shares.deref()) + .map_err(|e| { + anyhow::anyhow!(format!("Failed to combine_shares: {}", e)) + })?; + + let nz_scalar = NonZeroScalar::from_repr(scalar.to_repr()); + let nz_scalar = if nz_scalar.is_some().into() { + nz_scalar.unwrap() + } else { + return Err(anyhow::anyhow!( + "Failed to construct NonZeroScalar from Scalar" + )); + }; + + // not sure this is necessary ... can we just get it from the Scalar? + let wrap_key = SecretKey::from(nz_scalar); + + //let foo: [u8; KEY_LEN] = wrap_key.to_be_bytes().try_into()?; + + Ok(Self(wrap_key.to_be_bytes().into())) + } + + pub fn split( + &self, + rng: &mut R, + ) -> Result<(Zeroizing, Verifier)> { + info!("Splitting wrap key into {} shares.", LIMIT); + let wrap_key = + SecretKey::from_be_bytes(self.as_bytes()).map_err(|e| { + anyhow::anyhow!("Failed to construct SecretKey: {}", e) + })?; + debug!("wrap key: {:?}", wrap_key.to_be_bytes()); + + let nzs = wrap_key.to_nonzero_scalar(); + let (shares, verifier) = Feldman::::split_secret::< + Scalar, + ProjectivePoint, + R, + SHARE_LEN, + >(*nzs.as_ref(), None, &mut *rng) + .map_err(|e| anyhow::anyhow!("Failed to split_secret: {}", e))?; + + Ok((Zeroizing::new(shares), verifier)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use anyhow::Context; + + // secret split into the feldman verifier & shares below + const SECRET: &str = + "f259a45c17624b9317d8e292050c46a0f3d7387724b4cd26dd94f8bd3d1c0e1a"; + + // verifier created and serialized to json by `new_split_wrap` + const VERIFIER: &str = r#" + { + "generator": "036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", + "commitments": [ + "022f65c477affe7de97a51b8e562e763030218a8f0a8ecd7c349a50df7ded44985", + "03365076080ebeeab74e2421fa0f4e4c5796ad3cbd157cc0405b100a45ae89f22f", + "02bbd29359d702ff89ab2cbdb9e6ae102dfb1c4108aeab0701a469f28f0ad1e813" + ] + }"#; + + // shares dumped to the printer by `new_split_wrap` + const SHARE_ARRAY: [&str; LIMIT] = [ + "01a69b62eb1a7c9deb5435ca73bf6f5e280279ba9cbdcd873d4decb665fb8aaf34", + "020495513aa59e274196125218ff57b2f01f6bf97d817d24a1a00c5fbf29af08a8", + "030c476f49b8c6e796dd6e7981c4c544f90794efc716db43d8c7adbf8bc3ec3fc7", + "04bdb1bd1853f6deeb2a4a40ae0fb81442baf49d797de7e4e2c4d0d5cbca425491", + "0518d43aa8772e0d3c7ca5a79de03020cdbfbd0d396873cab5b0020cf943eafc64", + ]; + + fn secret_bytes() -> [u8; KEY_LEN] { + let mut secret = [0u8; KEY_LEN]; + hex::decode_to_slice(SECRET, &mut secret).unwrap(); + + secret + } + + fn deserialize_share(share: &str) -> Result { + // filter out whitespace to keep hex::decode happy + let share: String = + share.chars().filter(|c| !c.is_whitespace()).collect(); + let share = hex::decode(share) + .context("failed to decode share from hex string")?; + + Ok(Share::try_from(&share[..]) + .context("Failed to construct Share from bytes.")?) + } + + #[test] + fn round_trip() -> Result<()> { + use rand::rngs::ThreadRng; + + let secret = secret_bytes(); + let secret_key = SecretKey::from_be_bytes(&secret)?; + let nzs = secret_key.to_nonzero_scalar(); + + let mut rng = ThreadRng::default(); + let (shares, verifier) = Feldman::::split_secret::< + Scalar, + ProjectivePoint, + ThreadRng, + SHARE_LEN, + >(*nzs.as_ref(), None, &mut rng) + .map_err(|e| anyhow::anyhow!("failed to split secret: {}", e))?; + + for s in &shares { + assert!(verifier.verify(s)); + } + + let scalar = Feldman::::combine_shares::< + Scalar, + SHARE_LEN, + >(&shares) + .map_err(|e| anyhow::anyhow!("failed to combine secret: {}", e))?; + + let nzs_dup = NonZeroScalar::from_repr(scalar.to_repr()).unwrap(); + let sk_dup = SecretKey::from(nzs_dup); + let new_secret: [u8; KEY_LEN] = sk_dup.to_be_bytes().try_into()?; + + assert_eq!(new_secret, secret); + + Ok(()) + } + + // deserialize a verifier & use it to verify the shares in SHARE_ARRAY + #[test] + fn verify_shares() -> Result<()> { + let verifier: Verifier = serde_json::from_str(VERIFIER) + .context("Failed to deserialize Verifier from JSON.")?; + + for share in SHARE_ARRAY { + let share = deserialize_share(share)?; + assert!(verifier.verify(&share)); + } + + Ok(()) + } + + #[test] + fn verify_zero_share() -> Result<()> { + let verifier: Verifier = serde_json::from_str(VERIFIER) + .context("Failed to deserialize FeldmanVerifier from JSON.")?; + + let share = Share::try_from([0u8; SHARE_LEN].as_ref()) + .context("Failed to create Share from static array.")?; + + assert!(!verifier.verify(&share)); + + Ok(()) + } + + // TODO: I had expected that changing a single bit in a share would case + // the verifier to fail but that seems to be very wrong. + #[test] + fn verify_share_with_changed_byte() -> Result<()> { + let verifier: Verifier = serde_json::from_str(VERIFIER) + .context("Failed to deserialize FeldmanVerifier from JSON.")?; + + let mut share = deserialize_share(SHARE_ARRAY[0])?; + println!("share: {}", share.0[0]); + share.0[1] = 0xff; + share.0[2] = 0xff; + share.0[3] = 0xff; + // If we don't change the next byte this test will start failing. + // I had (wrongly?) expected that the share would fail to verify w/ + // a single changed byte + share.0[4] = 0xff; + + assert!(!verifier.verify(&share)); + + Ok(()) + } + + #[test] + fn recover_secret() -> Result<()> { + let mut shares: Vec = Vec::new(); + for share in SHARE_ARRAY { + shares.push(deserialize_share(share)?); + } + + let scalar = Feldman::::combine_shares::< + Scalar, + SHARE_LEN, + >(&shares) + .map_err(|e| anyhow::anyhow!("failed to combine secret: {}", e))?; + + let nzs_dup = NonZeroScalar::from_repr(scalar.to_repr()).unwrap(); + let sk_dup = SecretKey::from(nzs_dup); + let secret: [u8; KEY_LEN] = sk_dup.to_be_bytes().try_into()?; + + assert_eq!(secret, secret_bytes()); + + Ok(()) + } + + #[test] + fn from_rng() -> Result<()> { + let mut rng = rand::thread_rng(); + let backup_key = BackupKey::from_rng(&mut rng); + + assert!(backup_key.is_ok()); + + Ok(()) + } +} diff --git a/src/bin/printer-test.rs b/src/bin/printer-test.rs index 4b951b5..403bbe3 100644 --- a/src/bin/printer-test.rs +++ b/src/bin/printer-test.rs @@ -7,10 +7,7 @@ use std::path::PathBuf; use anyhow::Result; use clap::{Parser, Subcommand}; use hex::ToHex; -use oks::{ - hsm::{Alphabet, Share}, - secret_writer::PrinterSecretWriter, -}; +use oks::{backup::Share, hsm::Alphabet, secret_writer::PrinterSecretWriter}; use rand::{thread_rng, Rng}; use zeroize::Zeroizing; diff --git a/src/hsm.rs b/src/hsm.rs index 708dd8a..e0b5406 100644 --- a/src/hsm.rs +++ b/src/hsm.rs @@ -4,21 +4,16 @@ use anyhow::{Context, Result}; use log::{debug, error, info}; -use p256::elliptic_curve::PrimeField; -use p256::{NonZeroScalar, ProjectivePoint, Scalar, SecretKey}; use pem_rfc7468::LineEnding; use rand_core::{impls, CryptoRng, Error as RngError, RngCore}; -use static_assertions as sa; use std::collections::HashSet; use std::{ fs, io::{self, Write}, - ops::Deref, path::{Path, PathBuf}, str::FromStr, }; use thiserror::Error; -use vsss_rs::{Feldman, FeldmanVerifier}; use yubihsm::{ authentication::{self, Key, DEFAULT_AUTHENTICATION_KEY_ID}, object::{Id, Label, Type}, @@ -28,7 +23,10 @@ use yubihsm::{ }; use zeroize::Zeroizing; -use crate::config::{self, KeySpec, Transport, KEYSPEC_EXT}; +use crate::{ + backup::BackupKey, + config::{self, KeySpec, Transport, KEYSPEC_EXT}, +}; const WRAP_ID: Id = 1; @@ -37,21 +35,11 @@ const CAPS: Capability = Capability::all(); const DELEGATED_CAPS: Capability = Capability::all(); const DOMAIN: Domain = Domain::all(); const ID: Id = 0x1; -const KEY_LEN: usize = 32; -const SHARE_LEN: usize = KEY_LEN + 1; const LABEL: &str = "backup"; -pub const LIMIT: usize = 5; -pub const THRESHOLD: usize = 3; -sa::const_assert!(THRESHOLD <= LIMIT); - const BACKUP_EXT: &str = ".backup.json"; const ATTEST_FILE_NAME: &str = "hsm.attest.cert.pem"; -pub type Share = vsss_rs::Share; -pub type SharesMax = [Share; LIMIT]; -pub type Verifier = FeldmanVerifier; - #[derive(Error, Debug)] pub enum HsmError { #[error("path not a directory")] @@ -207,45 +195,22 @@ impl Hsm { /// then put the key into the YubiHSM. The shares and the verifier are then /// returned to the caller. Generally they will then be distributed /// 'off-platform' somehow. - pub fn new_split_wrap( - &mut self, - ) -> Result<(Zeroizing, Verifier)> { + pub fn import_backup_key(&mut self, key: BackupKey) -> Result<()> { info!( "Generating wrap / backup key from HSM PRNG with label: \"{}\"", LABEL.to_string() ); - // get 32 bytes from YubiHSM PRNG - // TODO: zeroize - let mut wrap_key = [0u8; KEY_LEN]; - self.try_fill_bytes(&mut wrap_key)?; - let wrap_key = wrap_key; - - info!("Splitting wrap key into {} shares.", LIMIT); - let wrap_key = SecretKey::from_be_bytes(&wrap_key)?; - debug!("wrap key: {:?}", wrap_key.to_be_bytes()); - - let nzs = wrap_key.to_nonzero_scalar(); - // we add a byte to the key length per instructions from the library: - // https://docs.rs/vsss-rs/2.7.1/src/vsss_rs/lib.rs.html#34 - let (shares, verifier) = Feldman::::split_secret::< - Scalar, - ProjectivePoint, - Self, - SHARE_LEN, - >(*nzs.as_ref(), None, &mut *self) - .map_err(|e| HsmError::SplitKeyFailed { e })?; - - // put 32 random bytes into the YubiHSM as an Aes256Ccm wrap key + info!("Storing wrap key in YubiHSM."); let id = self.client - .put_wrap_key::<[u8; 32]>( + .put_wrap_key( ID, Label::from_bytes(LABEL.as_bytes())?, DOMAIN, CAPS, DELEGATED_CAPS, ALG, - wrap_key.to_be_bytes().into(), + key.as_bytes(), ) .with_context(|| { format!( @@ -257,8 +222,7 @@ impl Hsm { // Future commands assume that our wrap key has id 1. If we got a wrap // key with any other id the HSM isn't in the state we think it is. assert_eq!(id, WRAP_ID); - - Ok((Zeroizing::new(shares), verifier)) + Ok(()) } // create a new auth key, remove the default auth key, then export the new @@ -373,57 +337,6 @@ impl Hsm { Ok(id) } - /// This function prompts the user to enter M of the N backup shares. It - /// uses these shares to reconstitute the wrap key. This wrap key can then - /// be used to restore previously backed up / export wrapped keys. - /// This function prompts the user to enter M of the N backup shares. It - /// uses these shares to reconstitute the wrap key. This wrap key can then - /// be used to restore previously backed up / export wrapped keys. - pub fn restore_wrap(&self, shares: Zeroizing>) -> Result<()> { - info!("Restoring HSM from backup"); - - if shares.len() < THRESHOLD { - return Err(HsmError::NotEnoughShares.into()); - } - - let scalar = Feldman::::combine_shares::< - Scalar, - SHARE_LEN, - >(shares.deref()) - .map_err(|e| HsmError::CombineKeyFailed { e })?; - - let nz_scalar = NonZeroScalar::from_repr(scalar.to_repr()); - let nz_scalar = if nz_scalar.is_some().into() { - nz_scalar.unwrap() - } else { - return Err(HsmError::BadScalar.into()); - }; - let wrap_key = SecretKey::from(nz_scalar); - - debug!("restored wrap key: {:?}", wrap_key.to_be_bytes()); - - // put restored wrap key the YubiHSM as an Aes256Ccm wrap key - let id = self.client - .put_wrap_key::<[u8; KEY_LEN]>( - ID, - Label::from_bytes(LABEL.as_bytes())?, - DOMAIN, - CAPS, - DELEGATED_CAPS, - ALG, - wrap_key.to_be_bytes().into(), - ) - .with_context(|| { - format!( - "Failed to put wrap key into YubiHSM domains {:?} with id {}", - DOMAIN, ID - ) - })?; - info!("wrap id: {}", id); - - Ok(()) - } - /// Write the cert for default attesation key in hsm to the provided /// filepath or a default location under self.output pub fn dump_attest_cert>( @@ -606,157 +519,3 @@ fn are_you_sure() -> Result { Ok(buffer == "y") } - -#[cfg(test)] -mod tests { - use super::*; - - // secret split into the feldman verifier & shares below - const SECRET: &str = - "f259a45c17624b9317d8e292050c46a0f3d7387724b4cd26dd94f8bd3d1c0e1a"; - - // verifier created and serialized to json by `new_split_wrap` - const VERIFIER: &str = r#" - { - "generator": "036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", - "commitments": [ - "022f65c477affe7de97a51b8e562e763030218a8f0a8ecd7c349a50df7ded44985", - "03365076080ebeeab74e2421fa0f4e4c5796ad3cbd157cc0405b100a45ae89f22f", - "02bbd29359d702ff89ab2cbdb9e6ae102dfb1c4108aeab0701a469f28f0ad1e813" - ] - }"#; - - // shares dumped to the printer by `new_split_wrap` - const SHARE_ARRAY: [&str; LIMIT] = [ - "01a69b62eb1a7c9deb5435ca73bf6f5e280279ba9cbdcd873d4decb665fb8aaf34", - "020495513aa59e274196125218ff57b2f01f6bf97d817d24a1a00c5fbf29af08a8", - "030c476f49b8c6e796dd6e7981c4c544f90794efc716db43d8c7adbf8bc3ec3fc7", - "04bdb1bd1853f6deeb2a4a40ae0fb81442baf49d797de7e4e2c4d0d5cbca425491", - "0518d43aa8772e0d3c7ca5a79de03020cdbfbd0d396873cab5b0020cf943eafc64", - ]; - - fn secret_bytes() -> [u8; KEY_LEN] { - let mut secret = [0u8; KEY_LEN]; - hex::decode_to_slice(SECRET, &mut secret).unwrap(); - - secret - } - - fn deserialize_share(share: &str) -> Result { - // filter out whitespace to keep hex::decode happy - let share: String = - share.chars().filter(|c| !c.is_whitespace()).collect(); - let share = hex::decode(share) - .context("failed to decode share from hex string")?; - - Ok(Share::try_from(&share[..]) - .context("Failed to construct Share from bytes.")?) - } - - #[test] - fn round_trip() -> Result<()> { - use rand::rngs::ThreadRng; - - let secret = secret_bytes(); - let secret_key = SecretKey::from_be_bytes(&secret)?; - let nzs = secret_key.to_nonzero_scalar(); - - let mut rng = ThreadRng::default(); - let (shares, verifier) = Feldman::::split_secret::< - Scalar, - ProjectivePoint, - ThreadRng, - SHARE_LEN, - >(*nzs.as_ref(), None, &mut rng) - .map_err(|e| anyhow::anyhow!("failed to split secret: {}", e))?; - - for s in &shares { - assert!(verifier.verify(s)); - } - - let scalar = Feldman::::combine_shares::< - Scalar, - SHARE_LEN, - >(&shares) - .map_err(|e| anyhow::anyhow!("failed to combine secret: {}", e))?; - - let nzs_dup = NonZeroScalar::from_repr(scalar.to_repr()).unwrap(); - let sk_dup = SecretKey::from(nzs_dup); - let new_secret: [u8; KEY_LEN] = sk_dup.to_be_bytes().try_into()?; - - assert_eq!(new_secret, secret); - - Ok(()) - } - - // deserialize a verifier & use it to verify the shares in SHARE_ARRAY - #[test] - fn verify_shares() -> Result<()> { - let verifier: Verifier = serde_json::from_str(VERIFIER) - .context("Failed to deserialize Verifier from JSON.")?; - - for share in SHARE_ARRAY { - let share = deserialize_share(share)?; - assert!(verifier.verify(&share)); - } - - Ok(()) - } - - #[test] - fn verify_zero_share() -> Result<()> { - let verifier: Verifier = serde_json::from_str(VERIFIER) - .context("Failed to deserialize FeldmanVerifier from JSON.")?; - - let share = Share::try_from([0u8; SHARE_LEN].as_ref()) - .context("Failed to create Share from static array.")?; - - assert!(!verifier.verify(&share)); - - Ok(()) - } - - // TODO: I had expected that changing a single bit in a share would case - // the verifier to fail but that seems to be very wrong. - #[test] - fn verify_share_with_changed_byte() -> Result<()> { - let verifier: Verifier = serde_json::from_str(VERIFIER) - .context("Failed to deserialize FeldmanVerifier from JSON.")?; - - let mut share = deserialize_share(SHARE_ARRAY[0])?; - println!("share: {}", share.0[0]); - share.0[1] = 0xff; - share.0[2] = 0xff; - share.0[3] = 0xff; - // If we don't change the next byte this test will start failing. - // I had (wrongly?) expected that the share would fail to verify w/ - // a single changed byte - share.0[4] = 0xff; - - assert!(!verifier.verify(&share)); - - Ok(()) - } - - #[test] - fn recover_secret() -> Result<()> { - let mut shares: Vec = Vec::new(); - for share in SHARE_ARRAY { - shares.push(deserialize_share(share)?); - } - - let scalar = Feldman::::combine_shares::< - Scalar, - SHARE_LEN, - >(&shares) - .map_err(|e| anyhow::anyhow!("failed to combine secret: {}", e))?; - - let nzs_dup = NonZeroScalar::from_repr(scalar.to_repr()).unwrap(); - let sk_dup = SecretKey::from(nzs_dup); - let secret: [u8; KEY_LEN] = sk_dup.to_be_bytes().try_into()?; - - assert_eq!(secret, secret_bytes()); - - Ok(()) - } -} diff --git a/src/lib.rs b/src/lib.rs index 149fca7..8e64c0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +pub mod backup; pub mod ca; pub mod config; pub mod hsm; diff --git a/src/main.rs b/src/main.rs index 3166f33..e6964ca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,12 +17,13 @@ use yubihsm::object::{Id, Type}; use zeroize::Zeroizing; use oks::{ + backup::{BackupKey, Share, Verifier, LIMIT, THRESHOLD}, ca::{Ca, CertOrCsr}, config::{ self, CsrSpec, DcsrSpec, KeySpec, Transport, CSRSPEC_EXT, DCSRSPEC_EXT, ENV_NEW_PASSWORD, ENV_PASSWORD, KEYSPEC_EXT, }, - hsm::{Hsm, Share, Verifier, LIMIT, THRESHOLD}, + hsm::Hsm, secret_reader::{StdioPasswordReader, StdioShareReader}, secret_writer::{PrinterSecretWriter, DEFAULT_PRINT_DEV}, util, @@ -313,7 +314,8 @@ fn do_ceremony>( args.transport, )?; - let (shares, verifier) = hsm.new_split_wrap()?; + let wrap = BackupKey::from_rng(&mut hsm)?; + let (shares, verifier) = wrap.split(&mut hsm)?; let verifier = serde_json::to_string(&verifier)?; debug!("JSON: {}", verifier); let verifier_path = args.output.join(VERIFIER_FILE); @@ -354,6 +356,8 @@ fn do_ceremony>( ); util::wait_for_line()?; } + + hsm.import_backup_key(wrap)?; info!("Collecting YubiHSM attestation cert."); hsm.dump_attest_cert::(None)?; @@ -704,7 +708,8 @@ fn main() -> Result<()> { passwd_challenge, } => { debug!("Initialize"); - let (shares, verifier) = hsm.new_split_wrap()?; + let wrap = BackupKey::from_rng(&mut hsm)?; + let (shares, verifier) = wrap.split(&mut hsm)?; let verifier = serde_json::to_string(&verifier)?; debug!("JSON: {}", verifier); let verifier_path = args.output.join(VERIFIER_FILE); @@ -761,6 +766,7 @@ fn main() -> Result<()> { PrinterSecretWriter::new(Some(&print_dev)); secret_writer.password(&passwd_new)?; + hsm.import_backup_key(wrap)?; hsm.dump_attest_cert::(None)?; hsm.replace_default_auth(&passwd_new) } @@ -779,7 +785,8 @@ fn main() -> Result<()> { } } - hsm.restore_wrap(shares)?; + let wrap = BackupKey::from_shares(shares)?; + hsm.import_backup_key(wrap)?; oks::hsm::restore(&hsm.client, backups)?; info!("Deleting default authentication key"); oks::hsm::delete(&hsm.client, 1, Type::AuthenticationKey) diff --git a/src/secret_reader.rs b/src/secret_reader.rs index cdbf85c..ba9c135 100644 --- a/src/secret_reader.rs +++ b/src/secret_reader.rs @@ -9,7 +9,7 @@ use std::{ }; use zeroize::Zeroizing; -use crate::hsm::{Share, Verifier}; +use crate::backup::{Share, Verifier}; #[derive(Default)] pub struct StdioPasswordReader {} diff --git a/src/secret_writer.rs b/src/secret_writer.rs index 61f6f4a..94afe7a 100644 --- a/src/secret_writer.rs +++ b/src/secret_writer.rs @@ -11,7 +11,7 @@ use std::{ }; use zeroize::Zeroizing; -use crate::{hsm::Share, util}; +use crate::{backup::Share, util}; pub const DEFAULT_PRINT_DEV: &str = "/dev/usb/lp0";