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.
|
/// Get YubiKey device serial number.
|
||||||
pub fn get_serial(&self, version: Version) -> Result<Serial> {
|
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
|
// YK4 requires switching to the yk applet to retrieve the serial
|
||||||
let sw = Apdu::new(Ins::SelectApplication)
|
let sw = Apdu::new(Ins::SelectApplication)
|
||||||
.p1(0x04)
|
.p1(0x04)
|
||||||
@@ -118,12 +119,12 @@ impl<'tx> Transaction<'tx> {
|
|||||||
return Err(Error::GenericError);
|
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!(
|
error!(
|
||||||
"failed retrieving serial number: {:04x}",
|
"failed retrieving serial number: {:04x}",
|
||||||
resp.status_words().code()
|
response.status_words().code()
|
||||||
);
|
);
|
||||||
return Err(Error::GenericError);
|
return Err(Error::GenericError);
|
||||||
}
|
}
|
||||||
@@ -140,26 +141,24 @@ impl<'tx> Transaction<'tx> {
|
|||||||
return Err(Error::GenericError);
|
return Err(Error::GenericError);
|
||||||
}
|
}
|
||||||
|
|
||||||
resp
|
response.data().try_into()
|
||||||
} else {
|
}
|
||||||
|
5 => {
|
||||||
// YK5 implements getting the serial as a PIV applet command (0xf8)
|
// 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!(
|
error!(
|
||||||
"failed retrieving serial number: {:04x}",
|
"failed retrieving serial number: {:04x}",
|
||||||
resp.status_words().code()
|
response.status_words().code()
|
||||||
);
|
);
|
||||||
return Err(Error::GenericError);
|
return Err(Error::GenericError);
|
||||||
}
|
}
|
||||||
|
|
||||||
resp
|
response.data().try_into()
|
||||||
};
|
}
|
||||||
|
_ => Err(Error::NotSupported),
|
||||||
response.data()[..4]
|
}
|
||||||
.try_into()
|
|
||||||
.map(|serial| Serial::from(u32::from_be_bytes(serial)))
|
|
||||||
.map_err(|_| Error::SizeError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify device PIN.
|
/// 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 {
|
impl FromStr for Serial {
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user