Replace MgmKey::set with MgmKey::{set_default, set_manual} (#224)

* Add MgmKey::set_default method

This wipes any metadata related to derived and PIN-protected management
keys, returning the management key to its default state.

* Transaction::set_mgm_key: Take touch requirement as bool

The Option<u8> was inherited from the original C code's usage of an
unsigned char. We don't need that flexibility, because only two cases
are supported.

* Replace MgmKey::set with MgmKey::set_manual

MgmKey::set_default is now implemented as a wrapper around
MgmKey::set_manual, as they both require clearing metadata related to
derived and PIN-protected management keys.
This commit is contained in:
str4d
2021-02-02 06:27:04 +13:00
committed by GitHub
parent 9d1da84233
commit 18e3636161
3 changed files with 86 additions and 17 deletions
+71 -6
View File
@@ -183,19 +183,84 @@ impl MgmKey {
MgmKey::from_bytes(item) MgmKey::from_bytes(item)
} }
/// Set the management key (MGM) /// Resets the management key for the given YubiKey to the default value.
///
/// This will wipe any metadata related to derived and PIN-protected management keys.
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn set(&self, yubikey: &mut YubiKey, touch: Option<u8>) -> Result<(), Error> { pub fn set_default(yubikey: &mut YubiKey) -> Result<(), Error> {
let txn = yubikey.begin_transaction()?; MgmKey::default().set_manual(yubikey, false)
txn.set_mgm_key(&self, touch)
} }
/// Set protected management key (MGM) /// Configures the given YubiKey to use this management key.
///
/// The management key must be stored by the user, and provided when performing key
/// management operations.
///
/// This will wipe any metadata related to derived and PIN-protected management keys.
#[cfg(feature = "untested")]
pub fn set_manual(&self, yubikey: &mut YubiKey, require_touch: bool) -> Result<(), Error> {
let txn = yubikey.begin_transaction()?;
txn.set_mgm_key(&self, require_touch).map_err(|e| {
// Log a warning, since the device mgm key is corrupt or we're in a state
// where we can't set the mgm key.
error!("could not set new derived mgm key, err = {}", e);
e
})?;
// After this point, we've set the mgm key, so the function should succeed,
// regardless of being able to set the metadata.
if let Ok(mut admin_data) = AdminData::read(&txn) {
// Clear the protected mgm key bit.
if let Ok(item) = admin_data.get_item(TAG_ADMIN_FLAGS_1) {
let mut flags_1 = [0u8; 1];
if item.len() == flags_1.len() {
flags_1.copy_from_slice(item);
flags_1[0] &= !ADMIN_FLAGS_1_PROTECTED_MGM;
if let Err(e) = admin_data.set_item(TAG_ADMIN_FLAGS_1, &flags_1) {
error!("could not set admin flags item, err = {}", e);
}
} else {
error!(
"admin data flags are an incorrect size: {} (expected {})",
item.len(),
flags_1.len()
);
}
}
// Remove any existing salt for a derived mgm key.
if let Err(e) = admin_data.set_item(TAG_ADMIN_SALT, &[]) {
error!("could not unset derived mgm salt (err = {})", e)
}
if let Err(e) = admin_data.write(&txn) {
error!("could not write admin data, err = {}", e);
}
}
// Clear any prior mgm key from protected data.
if let Ok(mut protected_data) = ProtectedData::read(&txn) {
if let Err(e) = protected_data.set_item(TAG_PROTECTED_MGM, &[]) {
error!("could not clear protected mgm item, err = {:?}", e);
} else if let Err(e) = protected_data.write(&txn) {
error!("could not write protected data, err = {:?}", e);
}
}
Ok(())
}
/// Configures the given YubiKey to use this as a PIN-protected management key.
///
/// This enables key management operations to be performed with access to the PIN.
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn set_protected(&self, yubikey: &mut YubiKey) -> Result<(), Error> { pub fn set_protected(&self, yubikey: &mut YubiKey) -> Result<(), Error> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
txn.set_mgm_key(self, None).map_err(|e| { txn.set_mgm_key(self, false).map_err(|e| {
// log a warning, since the device mgm key is corrupt or we're in // log a warning, since the device mgm key is corrupt or we're in
// a state where we can't set the mgm key // a state where we can't set the mgm key
error!("could not set new derived mgm key, err = {}", e); error!("could not set new derived mgm key, err = {}", e);
+2 -8
View File
@@ -229,14 +229,8 @@ impl<'tx> Transaction<'tx> {
/// Set the management key (MGM). /// Set the management key (MGM).
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn set_mgm_key(&self, new_key: &MgmKey, touch: Option<u8>) -> Result<(), Error> { pub fn set_mgm_key(&self, new_key: &MgmKey, require_touch: bool) -> Result<(), Error> {
let p2 = match touch.unwrap_or_default() { let p2 = if require_touch { 0xfe } else { 0xff };
0 => 0xff,
1 => 0xfe,
_ => {
return Err(Error::GenericError);
}
};
let mut data = [0u8; DES_LEN_3DES + 3]; let mut data = [0u8; DES_LEN_3DES + 3];
data[0] = ALGO_3DES; data[0] = ALGO_3DES;
+13 -3
View File
@@ -114,10 +114,11 @@ fn test_verify_pin() {
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
#[test] #[test]
#[ignore] #[ignore]
fn test_protected_mgmkey() { fn test_set_mgmkey() {
let mut yubikey = YUBIKEY.lock().unwrap(); let mut yubikey = YUBIKEY.lock().unwrap();
assert!(yubikey.verify_pin(b"123456").is_ok()); assert!(yubikey.verify_pin(b"123456").is_ok());
assert!(MgmKey::get_protected(&mut yubikey).is_err());
assert!(yubikey.authenticate(MgmKey::default()).is_ok()); assert!(yubikey.authenticate(MgmKey::default()).is_ok());
// Set a protected management key. // Set a protected management key.
@@ -129,10 +130,19 @@ fn test_protected_mgmkey() {
assert!(yubikey.authenticate(MgmKey::default()).is_err()); assert!(yubikey.authenticate(MgmKey::default()).is_err());
assert!(yubikey.authenticate(protected.clone()).is_ok()); assert!(yubikey.authenticate(protected.clone()).is_ok());
// Set a manual management key.
let manual = MgmKey::generate().unwrap();
assert!(manual.set_manual(&mut yubikey, false).is_ok());
assert!(MgmKey::get_protected(&mut yubikey).is_err());
assert!(yubikey.authenticate(MgmKey::default()).is_err());
assert!(yubikey.authenticate(protected.clone()).is_err());
assert!(yubikey.authenticate(manual.clone()).is_ok());
// Set back to the default management key. // Set back to the default management key.
// TODO: This does not clear the previous key from the protected metadata. assert!(MgmKey::set_default(&mut yubikey).is_ok());
assert!(MgmKey::default().set(&mut yubikey, None).is_ok()); assert!(MgmKey::get_protected(&mut yubikey).is_err());
assert!(yubikey.authenticate(protected).is_err()); assert!(yubikey.authenticate(protected).is_err());
assert!(yubikey.authenticate(manual).is_err());
assert!(yubikey.authenticate(MgmKey::default()).is_ok()); assert!(yubikey.authenticate(MgmKey::default()).is_ok());
} }