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:
+71
-6
@@ -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
@@ -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
@@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user