Improve parsing of serial numbers (#466)
Checks the length of the data returned when querying the serial number, returning an error if it's longer than 4 bytes, and left-padding with zeroes if it's too short. This fixes some potential panics due to incorrect slice lengths as were experienced in #465
This commit is contained in:
committed by
GitHub
parent
1d33ea1747
commit
f49c617a9d
+15
-16
@@ -105,7 +105,8 @@ impl<'tx> Transaction<'tx> {
|
||||
|
||||
/// Get YubiKey device serial number.
|
||||
pub fn get_serial(&self, version: Version) -> Result<Serial> {
|
||||
let response = if version.major < 5 {
|
||||
match version.major {
|
||||
4 => {
|
||||
// YK4 requires switching to the yk applet to retrieve the serial
|
||||
let sw = Apdu::new(Ins::SelectApplication)
|
||||
.p1(0x04)
|
||||
@@ -118,12 +119,12 @@ impl<'tx> Transaction<'tx> {
|
||||
return Err(Error::GenericError);
|
||||
}
|
||||
|
||||
let resp = Apdu::new(0x01).p1(0x10).transmit(self, 0xFF)?;
|
||||
let response = Apdu::new(0x01).p1(0x10).transmit(self, 0xFF)?;
|
||||
|
||||
if !resp.is_success() {
|
||||
if !response.is_success() {
|
||||
error!(
|
||||
"failed retrieving serial number: {:04x}",
|
||||
resp.status_words().code()
|
||||
response.status_words().code()
|
||||
);
|
||||
return Err(Error::GenericError);
|
||||
}
|
||||
@@ -140,26 +141,24 @@ impl<'tx> Transaction<'tx> {
|
||||
return Err(Error::GenericError);
|
||||
}
|
||||
|
||||
resp
|
||||
} else {
|
||||
response.data().try_into()
|
||||
}
|
||||
5 => {
|
||||
// YK5 implements getting the serial as a PIV applet command (0xf8)
|
||||
let resp = Apdu::new(Ins::GetSerial).transmit(self, 0xFF)?;
|
||||
let response = Apdu::new(Ins::GetSerial).transmit(self, 0xFF)?;
|
||||
|
||||
if !resp.is_success() {
|
||||
if !response.is_success() {
|
||||
error!(
|
||||
"failed retrieving serial number: {:04x}",
|
||||
resp.status_words().code()
|
||||
response.status_words().code()
|
||||
);
|
||||
return Err(Error::GenericError);
|
||||
}
|
||||
|
||||
resp
|
||||
};
|
||||
|
||||
response.data()[..4]
|
||||
.try_into()
|
||||
.map(|serial| Serial::from(u32::from_be_bytes(serial)))
|
||||
.map_err(|_| Error::SizeError)
|
||||
response.data().try_into()
|
||||
}
|
||||
_ => Err(Error::NotSupported),
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify device PIN.
|
||||
|
||||
@@ -98,6 +98,20 @@ impl From<Serial> for u32 {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for Serial {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(bytes: &[u8]) -> Result<Self> {
|
||||
if bytes.len() > 4 {
|
||||
return Err(Error::SizeError);
|
||||
}
|
||||
|
||||
let mut arr = [0u8; 4];
|
||||
arr[(4 - bytes.len())..].copy_from_slice(bytes);
|
||||
Ok(Self(u32::from_be_bytes(arr)))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Serial {
|
||||
type Err = Error;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user