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";