1use crate::{
34 consts::{
35 TAG_ADMIN_FLAGS_1, TAG_ADMIN_SALT, TAG_ADMIN_TIMESTAMP, TAG_PROTECTED_FLAGS_1,
36 TAG_PROTECTED_MGM,
37 },
38 metadata::{AdminData, ProtectedData},
39 mgm::{MgmType, ADMIN_FLAGS_1_PROTECTED_MGM},
40 yubikey::{YubiKey, ADMIN_FLAGS_1_PUK_BLOCKED},
41 Result,
42};
43use log::error;
44use std::time::{Duration, SystemTime, UNIX_EPOCH};
45
46const CB_ADMIN_TIMESTAMP: usize = 0x04;
47const PROTECTED_FLAGS_1_PUK_NOBLOCK: u8 = 0x01;
48
49#[derive(Copy, Clone, Debug)]
51pub struct Config {
52 pub protected_data_available: bool,
54
55 pub puk_blocked: bool,
57
58 pub puk_noblock_on_upgrade: bool,
60
61 pub pin_last_changed: Option<SystemTime>,
63
64 pub mgm_type: MgmType,
66}
67
68impl Default for Config {
69 fn default() -> Config {
70 Config {
71 protected_data_available: false,
72 puk_blocked: false,
73 puk_noblock_on_upgrade: false,
74 pin_last_changed: None,
75 mgm_type: MgmType::Manual,
76 }
77 }
78}
79
80impl Config {
81 pub(crate) fn get(yubikey: &mut YubiKey) -> Result<Config> {
83 let mut config = Self::default();
84 let txn = yubikey.begin_transaction()?;
85
86 if let Ok(admin_data) = AdminData::read(&txn) {
87 if let Ok(item) = admin_data.get_item(TAG_ADMIN_FLAGS_1) {
88 if item.is_empty() {
89 error!("empty response for admin flags metadata item! ignoring");
90 } else {
91 if item[0] & ADMIN_FLAGS_1_PUK_BLOCKED != 0 {
92 config.puk_blocked = true;
93 }
94
95 if item[0] & ADMIN_FLAGS_1_PROTECTED_MGM != 0 {
96 config.mgm_type = MgmType::Protected;
97 }
98 }
99 }
100
101 if admin_data.get_item(TAG_ADMIN_SALT).is_ok() {
102 if config.mgm_type != MgmType::Manual {
103 error!("conflicting types of MGM key administration configured");
104 } else {
105 config.mgm_type = MgmType::Derived;
106 }
107 }
108
109 if let Ok(item) = admin_data.get_item(TAG_ADMIN_TIMESTAMP) {
110 if item.len() != CB_ADMIN_TIMESTAMP {
111 error!("pin timestamp in admin metadata is an invalid size");
112 } else {
113 let pin_last_changed = u32::from_le_bytes([item[0], item[1], item[2], item[3]]);
115
116 if pin_last_changed != 0 {
117 config.pin_last_changed =
118 Some(UNIX_EPOCH + Duration::from_secs(pin_last_changed as u64));
119 }
120 }
121 }
122 }
123
124 if let Ok(protected_data) = ProtectedData::read(&txn) {
125 config.protected_data_available = true;
126
127 if let Ok(item) = protected_data.get_item(TAG_PROTECTED_FLAGS_1) {
128 if item.is_empty() {
129 error!("empty response for protected flags metadata item! ignoring");
130 } else if item[0] & PROTECTED_FLAGS_1_PUK_NOBLOCK != 0 {
131 config.puk_noblock_on_upgrade = true;
132 }
133 }
134
135 if protected_data.get_item(TAG_PROTECTED_MGM).is_ok() {
136 if config.mgm_type != MgmType::Protected {
137 error!("conflicting MGM key types: protected MGM exists");
138 }
139
140 config.mgm_type = MgmType::Protected;
142 }
143 }
144
145 Ok(config)
146 }
147}