Merge pull request #46 from str4d/37-ignore-otp-string

Detect invalid PIN lengths and ask the user again
This commit is contained in:
str4d
2022-03-20 14:57:48 +00:00
committed by GitHub
2 changed files with 48 additions and 11 deletions
+31 -4
View File
@@ -26,7 +26,7 @@ use crate::{
error::Error,
format::{RecipientLine, STANZA_KEY_LABEL},
p256::{Recipient, TAG_BYTES},
util::Metadata,
util::{otp_serial_prefix, Metadata},
IDENTITY_PREFIX,
};
@@ -372,11 +372,37 @@ impl Connection {
// The policy requires a PIN, so request it.
// Note that we can't distinguish between PinPolicy::Once and PinPolicy::Always
// because this plugin is ephemeral, so we always request the PIN.
let pin = match callbacks.request_secret(&format!(
let mut message = format!(
"Enter PIN for YubiKey with serial {}",
self.yubikey.serial()
))? {
Ok(pin) => pin,
);
let pin = loop {
message = match callbacks.request_secret(&message)? {
Ok(pin) => match pin.expose_secret().len() {
// A PIN must be between 6 and 8 characters.
6..=8 => break pin,
// If the string is 44 bytes and starts with the YubiKey's serial
// encoded as 12-byte modhex, the user probably touched the YubiKey
// early and "typed" an OTP.
44 if pin
.expose_secret()
.starts_with(&otp_serial_prefix(self.yubikey.serial())) =>
{
format!(
"Did you touch the YubiKey by accident? Enter PIN for YubiKey with serial {}",
self.yubikey.serial()
)
}
// Otherwise, the PIN is either too short or too long.
0..=5 => format!(
"PIN was too short. Enter PIN for YubiKey with serial {}",
self.yubikey.serial()
),
_ => format!(
"PIN was too long. Enter PIN for YubiKey with serial {}",
self.yubikey.serial()
),
},
Err(_) => {
return Ok(Err(identity::Error::Identity {
index: self.identity_index,
@@ -387,6 +413,7 @@ impl Connection {
}))
}
};
};
if let Err(e) = self.yubikey.verify_pin(pin.expose_secret().as_bytes()) {
return Ok(Err(identity::Error::Identity {
index: self.identity_index,
+10
View File
@@ -1,4 +1,5 @@
use std::fmt;
use std::iter;
use x509_parser::{certificate::X509Certificate, der_parser::oid::Oid};
use yubikey::{
@@ -61,6 +62,15 @@ pub(crate) fn touch_policy_to_str(policy: Option<TouchPolicy>) -> &'static str {
}
}
const MODHEX: &str = "cbdefghijklnrtuv";
pub(crate) fn otp_serial_prefix(serial: Serial) -> String {
iter::repeat(0)
.take(4)
.chain((0..8).rev().map(|i| (serial.0 >> (4 * i)) & 0x0f))
.map(|i| MODHEX.char_indices().nth(i as usize).unwrap().1)
.collect()
}
pub(crate) fn extract_name(cert: &X509Certificate, all: bool) -> Option<(String, bool)> {
// Look at Subject Organization to determine if we created this.
match cert.subject().iter_organization().next() {