use super::{Result, bail};
use alloc::vec::Vec;
fn tlv(input: &[u8]) -> Result<(u8, &[u8], &[u8])> {
if input.len() < 2 {
bail!("DER: truncated header");
}
let tag = input[0];
let first = input[1];
let mut idx = 2;
let len = if first & 0x80 == 0 {
first as usize
} else {
let n = (first & 0x7f) as usize;
if n == 0 || n > 4 || input.len() < idx + n {
bail!("DER: unsupported length encoding");
}
let mut l = 0usize;
for byte in &input[idx..idx + n] {
l = (l << 8) | *byte as usize;
}
idx += n;
l
};
if input.len() < idx + len {
bail!("DER: contents overrun");
}
Ok((tag, &input[idx..idx + len], &input[idx + len..]))
}
fn expect<'a>(input: &'a [u8], tag: u8, what: &'static str) -> Result<(&'a [u8], &'a [u8])> {
let (t, contents, rest) = tlv(input)?;
if t != tag {
bail!(
"DER: expected tag {:#04x} for {}, got {:#04x}",
tag,
what,
t
);
}
Ok((contents, rest))
}
const OID_EC_PUBLIC_KEY: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
const OID_PRIME256V1: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07];
pub(crate) fn extract_p256_point(certificate_der: &[u8]) -> Result<Vec<u8>> {
let (cert, _) = expect(certificate_der, 0x30, "Certificate")?;
let (tbs, _) = expect(cert, 0x30, "tbsCertificate")?;
let mut rest = tbs;
if rest.first() == Some(&0xa0) {
let (_, r) = expect(rest, 0xa0, "version")?;
rest = r;
}
let (_, r) = expect(rest, 0x02, "serialNumber")?;
rest = r;
let (_, r) = expect(rest, 0x30, "signature AlgorithmIdentifier")?;
rest = r;
let (_, r) = expect(rest, 0x30, "issuer")?;
rest = r;
let (_, r) = expect(rest, 0x30, "validity")?;
rest = r;
let (_, r) = expect(rest, 0x30, "subject")?;
rest = r;
let (spki, _) = expect(rest, 0x30, "subjectPublicKeyInfo")?;
let (alg, spki_rest) = expect(spki, 0x30, "algorithm")?;
let (ec_oid, alg_rest) = expect(alg, 0x06, "ecPublicKey OID")?;
if ec_oid != OID_EC_PUBLIC_KEY {
bail!("certificate public key is not id-ecPublicKey");
}
let (curve_oid, _) = expect(alg_rest, 0x06, "named curve OID")?;
if curve_oid != OID_PRIME256V1 {
bail!("certificate curve is not prime256v1");
}
let (bits, _) = expect(spki_rest, 0x03, "subjectPublicKey")?;
if bits.is_empty() || bits[0] != 0 {
bail!("subjectPublicKey has unexpected unused bits");
}
Ok(bits[1..].to_vec())
}