use crate::Error;
pub mod oid {
pub const EC_PUBLIC_KEY: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
pub const PRIME256V1: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07];
pub const SECP384R1: &[u8] = &[0x2b, 0x81, 0x04, 0x00, 0x22];
pub const RSA_ENCRYPTION: &[u8] = &[0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01];
pub const ED25519: &[u8] = &[0x2b, 0x65, 0x70];
}
pub fn read_tlv(input: &[u8]) -> Result<(u8, &[u8], &[u8]), Error> {
if input.len() < 2 {
return Err(Error::InvalidInput);
}
let tag = input[0];
let first = input[1] as usize;
let (len, rest_off) = if first < 0x80 {
(first, 2)
} else {
let n = first & 0x7f;
if n == 0 || n > 4 || n + 2 > input.len() {
return Err(Error::InvalidInput);
}
let mut len = 0usize;
for k in 0..n {
len = (len << 8) | input[2 + k] as usize;
}
if input[2] == 0 || len < 0x80 {
return Err(Error::InvalidInput);
}
(len, 2 + n)
};
if rest_off + len > input.len() {
return Err(Error::InvalidInput);
}
Ok((
tag,
&input[rest_off..rest_off + len],
&input[rest_off + len..],
))
}
pub fn expect(tag: u8, input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
let (t, content, rest) = read_tlv(input)?;
if t != tag {
return Err(Error::InvalidInput);
}
Ok((content, rest))
}
pub fn sequence(input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
expect(0x30, input)
}
pub fn octet_string(input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
expect(0x04, input)
}
pub fn bit_string(input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
let (content, rest) = expect(0x03, input)?;
if content.is_empty() || content[0] != 0 {
return Err(Error::InvalidInput);
}
Ok((&content[1..], rest))
}
pub fn object_identifier(input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
expect(0x06, input)
}
pub fn integer(input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
let (content, rest) = expect(0x02, input)?;
if content.is_empty() {
return Err(Error::InvalidInput);
}
if content[0] & 0x80 != 0 {
return Err(Error::InvalidInput);
}
if content.len() >= 2 && content[0] == 0 && content[1] & 0x80 == 0 {
return Err(Error::InvalidInput);
}
let mut s = 0;
while s + 1 < content.len() && content[s] == 0 {
s += 1;
}
Ok((&content[s..], rest))
}
#[derive(Debug)]
pub enum ParsedPrivateKey {
P256 {
scalar: [u8; 32],
public_sec1: Option<Vec<u8>>,
},
P384 {
scalar: [u8; 48],
public_sec1: Option<Vec<u8>>,
},
RsaPkcs1(Vec<u8>),
Ed25519(Vec<u8>),
}
pub fn parse_pkcs8_private_key(der: &[u8]) -> Result<ParsedPrivateKey, Error> {
let (seq, rest) = sequence(der)?;
if !rest.is_empty() {
return Err(Error::InvalidInput);
}
let (version, rest) = integer(seq)?;
if version.len() != 1 || version[0] != 0 {
return Err(Error::InvalidInput);
}
let (alg_seq, rest) = sequence(rest)?;
let (oid, alg_rest) = object_identifier(alg_seq)?;
let (_ptag, _params, _alg_rest_rest) = match read_tlv(alg_rest) {
Ok(x) => x,
Err(_) => return Err(Error::InvalidInput),
};
let (key_bytes, rest) = octet_string(rest)?;
if !rest.is_empty() && rest[0] != 0xa0 {
return Err(Error::InvalidInput);
}
if oid == oid::ED25519 {
let (seed, inner_rest) = octet_string(key_bytes)?;
if !inner_rest.is_empty() || seed.len() != 32 {
return Err(Error::InvalidInput);
}
return Ok(ParsedPrivateKey::Ed25519(seed.to_vec()));
}
if oid == oid::RSA_ENCRYPTION {
return Ok(ParsedPrivateKey::RsaPkcs1(key_bytes.to_vec()));
}
if oid == oid::EC_PUBLIC_KEY {
let (ptag, params, _alg_rest_rest) = read_tlv(alg_rest)?;
if ptag != 0x06 {
return Err(Error::InvalidInput);
}
let curve_oid = params;
let curve = if curve_oid == oid::PRIME256V1 {
32usize
} else if curve_oid == oid::SECP384R1 {
48usize
} else {
return Err(Error::InvalidInput);
};
let (sec1, sec1_rest) = sequence(key_bytes)?;
if !sec1_rest.is_empty() {
return Err(Error::InvalidInput);
}
let (sec_ver, sec1_rest) = integer(sec1)?;
if sec_ver.len() != 1 || sec_ver[0] != 1 {
return Err(Error::InvalidInput);
}
let (priv_key, sec1_rest) = octet_string(sec1_rest)?;
if priv_key.len() != curve || !sec1_rest.is_empty() && sec1_rest[0] != 0xa1 {
return Err(Error::InvalidInput);
}
let mut public_sec1 = None;
if !sec1_rest.is_empty() {
let (ptag, content, pub_rest) = read_tlv(sec1_rest)?;
if ptag != 0xa1 || !pub_rest.is_empty() || content.is_empty() {
return Err(Error::InvalidInput);
}
let point: &[u8] = if content[0] == 0x03 {
let (itag, bits, rest2) = read_tlv(content)?;
if itag != 0x03 || !rest2.is_empty() || bits.is_empty() || bits[0] != 0 {
return Err(Error::InvalidInput);
}
&bits[1..]
} else if content[0] == 0x00 {
&content[1..]
} else {
return Err(Error::InvalidInput);
};
if point.len() != 1 + 2 * curve || point[0] != 0x04 {
return Err(Error::InvalidInput);
}
public_sec1 = Some(point.to_vec());
}
let mut scalar = [0u8; 48];
scalar[..curve].copy_from_slice(priv_key);
return if curve == 32 {
let mut s256 = [0u8; 32];
s256.copy_from_slice(&scalar[..32]);
Ok(ParsedPrivateKey::P256 {
scalar: s256,
public_sec1,
})
} else {
Ok(ParsedPrivateKey::P384 {
scalar,
public_sec1,
})
};
}
Err(Error::InvalidInput)
}