use p224::ecdsa::signature::hazmat::PrehashVerifier;
use p224::ecdsa::{Signature, VerifyingKey};
pub const NXP_ORIGINALITY_PUBLIC_KEY_SEC1: [u8; 57] = [
0x04, 0x8A, 0x9B, 0x38, 0x0A, 0xF2, 0xEE, 0x1B, 0x98, 0xDC, 0x41, 0x7F, 0xEC, 0xC2, 0x63, 0xF8,
0x44, 0x9C, 0x76, 0x25, 0xCE, 0xCE, 0x82, 0xD9, 0xB9, 0x16, 0xC9, 0x92, 0xDA, 0x20, 0x9D, 0x68,
0x42, 0x2B, 0x81, 0xEC, 0x20, 0xB6, 0x5A, 0x66, 0xB5, 0x10, 0x2A, 0x61, 0x59, 0x6A, 0xF3, 0x37,
0x92, 0x00, 0x59, 0x93, 0x16, 0xA0, 0x0A, 0x14, 0x10,
];
pub const SIGNATURE_LEN: usize = 56;
const FIELD_BYTES: usize = 28;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum OriginalityError {
UidTooLong,
Malformed,
VerificationFailed,
}
fn verify_with_key(
public_key_sec1: &[u8],
uid: &[u8],
signature: &[u8; SIGNATURE_LEN],
) -> Result<(), OriginalityError> {
if uid.len() > FIELD_BYTES {
return Err(OriginalityError::UidTooLong);
}
let key =
VerifyingKey::from_sec1_bytes(public_key_sec1).map_err(|_| OriginalityError::Malformed)?;
let sig = Signature::from_slice(signature).map_err(|_| OriginalityError::Malformed)?;
let mut prehash = [0u8; FIELD_BYTES];
prehash[FIELD_BYTES - uid.len()..].copy_from_slice(uid);
key.verify_prehash(&prehash, &sig)
.map_err(|_| OriginalityError::VerificationFailed)
}
pub fn verify(uid: &[u8], signature: &[u8; SIGNATURE_LEN]) -> Result<(), OriginalityError> {
verify_with_key(&NXP_ORIGINALITY_PUBLIC_KEY_SEC1, uid, signature)
}
#[cfg(test)]
mod tests {
use super::*;
const TABLE30_UID: [u8; 7] = [0x04, 0x51, 0x8D, 0xFA, 0xA9, 0x61, 0x80];
const TABLE30_SIG: [u8; SIGNATURE_LEN] = [
0xD1, 0x94, 0x0D, 0x17, 0xCF, 0xED, 0xA4, 0xBF, 0xF8, 0x03, 0x59, 0xAB, 0x97, 0x5F, 0x9F,
0x65, 0x14, 0x31, 0x3E, 0x8F, 0x90, 0xC1, 0xD3, 0xCA, 0xAF, 0x59, 0x41, 0xAD, 0x74, 0x4A,
0x1C, 0xDF, 0x9A, 0x83, 0xF8, 0x83, 0xCA, 0xFE, 0x0F, 0xE9, 0x5D, 0x19, 0x39, 0xB1, 0xB7,
0xE4, 0x71, 0x13, 0x99, 0x33, 0x24, 0x47, 0x3B, 0x78, 0x5D, 0x21,
];
#[test]
fn an12196_table30_vector() {
verify(&TABLE30_UID, &TABLE30_SIG).expect("AN12196 Table 30 signature must verify");
}
#[test]
#[cfg_attr(
miri,
ignore = "P-224 ECDSA verify; covered by an12196_table30_vector under miri"
)]
fn rejects_flipped_signature() {
let mut sig = TABLE30_SIG;
sig[0] ^= 0x01;
assert_eq!(
verify(&TABLE30_UID, &sig),
Err(OriginalityError::VerificationFailed)
);
}
#[test]
#[cfg_attr(
miri,
ignore = "P-224 ECDSA verify; covered by an12196_table30_vector under miri"
)]
fn rejects_wrong_uid() {
let mut uid = TABLE30_UID;
uid[6] ^= 0x01;
assert_eq!(
verify(&uid, &TABLE30_SIG),
Err(OriginalityError::VerificationFailed)
);
}
}