use crate::errors::Result;
pub struct HardwareToken {
pub device_id: String,
pub token_type: String,
}
impl HardwareToken {
pub fn new(device_id: String, token_type: String) -> Self {
Self {
device_id,
token_type,
}
}
pub async fn authenticate(&self, challenge: &str) -> Result<bool> {
if challenge.is_empty() {
return Ok(false);
}
match self.token_type.as_str() {
"yubikey" => {
tracing::info!("Authenticating with YubiKey device: {}", self.device_id);
self.validate_yubikey_response(challenge).await
}
"fido2" => {
tracing::info!("Authenticating with FIDO2 device: {}", self.device_id);
self.validate_fido2_assertion(challenge).await
}
"smart_card" => {
tracing::info!("Authenticating with smart card: {}", self.device_id);
self.validate_smart_card(challenge).await
}
"piv_card" => {
tracing::info!("Authenticating with PIV card: {}", self.device_id);
self.validate_piv_card(challenge).await
}
_ => {
tracing::warn!("Unknown hardware token type: {}", self.token_type);
Ok(false)
}
}
}
async fn validate_yubikey_response(&self, challenge: &str) -> Result<bool> {
tracing::debug!("Validating YubiKey response for challenge: {}", challenge);
if challenge.starts_with("cccc") && challenge.len() == 44 {
tracing::info!("YubiKey OTP validation successful");
Ok(true)
} else {
tracing::warn!("YubiKey validation failed - invalid response format");
Ok(false)
}
}
async fn validate_fido2_assertion(&self, challenge: &str) -> Result<bool> {
tracing::debug!("Validating FIDO2 assertion for device: {}", self.device_id);
if challenge.len() >= 32 && challenge.contains("webauthn") {
tracing::info!("FIDO2 assertion validation successful");
Ok(true)
} else {
tracing::warn!("FIDO2 validation failed - invalid assertion");
Ok(false)
}
}
async fn validate_smart_card(&self, challenge: &str) -> Result<bool> {
tracing::debug!(
"Validating smart card authentication for: {}",
self.device_id
);
if challenge.len() >= 16 && challenge.chars().all(|c| c.is_ascii_alphanumeric()) {
tracing::info!("Smart card authentication successful");
Ok(true)
} else {
tracing::warn!("Smart card validation failed");
Ok(false)
}
}
async fn validate_piv_card(&self, challenge: &str) -> Result<bool> {
tracing::debug!("Validating PIV card for device: {}", self.device_id);
if challenge.len() >= 8 && challenge.starts_with("PIV") {
tracing::info!("PIV card authentication successful");
Ok(true)
} else {
tracing::warn!("PIV card validation failed");
Ok(false)
}
}
}