use crate::error::Sec1PemError;
use der::asn1::{ContextSpecific, ObjectIdentifier, OctetString};
pub use der::{Decodable, Message};
use std::option::Option::Some;
#[derive(Clone, Debug, Eq, PartialEq, Message)]
struct EcPrivateKey_<'a> {
version: u8,
key: OctetString<'a>,
curve: Option<ContextSpecific<'a>>,
public_key: Option<ContextSpecific<'a>>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EcPrivateKey {
pub version: u8,
pub key: Vec<u8>,
pub curve: Option<ObjectIdentifier>,
pub public_key: Option<Vec<u8>>,
}
impl From<EcPrivateKey_<'_>> for EcPrivateKey {
fn from(other: EcPrivateKey_<'_>) -> Self {
let version = other.version;
let key = other.key.as_bytes().to_vec();
let curve = other.curve.map(|curve| curve.value.oid().unwrap());
let public_key = other
.public_key
.map(|pub_k| pub_k.value.as_bytes().to_vec());
EcPrivateKey {
version,
key,
curve,
public_key,
}
}
}
const PEM_EC_HEADER: &str = "EC PRIVATE KEY";
pub fn parse_pem(bytes: &[u8]) -> Result<EcPrivateKey, Sec1PemError> {
let parsed = pem::parse_many(bytes);
let pk_pem = parsed.into_iter().find(|pem| pem.tag == PEM_EC_HEADER);
if let Some(pk_pem) = pk_pem {
let key =
EcPrivateKey_::from_der(&pk_pem.contents).map_err(|_| Sec1PemError::ParseError)?;
Ok(key.into())
} else {
Err(Sec1PemError::NoECPrivateKey)
}
}
pub fn parse_der(bytes: &[u8]) -> Result<EcPrivateKey, Sec1PemError> {
Ok(EcPrivateKey_::from_der(bytes)
.map_err(|_| Sec1PemError::ParseError)?
.into())
}
#[cfg(test)]
mod test {
use std::path;
use std::path::PathBuf;
fn get_path() -> PathBuf {
let mut path = path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("resources/");
path
}
#[test]
fn test_pems() {
let path = get_path();
for file in path.read_dir().unwrap() {
let path = file.unwrap().path();
if path.ends_with("pkcs8eckey.pem") || path.ends_with("private_key.der") {
continue;
}
let pem = std::fs::read_to_string(path).unwrap();
let parse = crate::parse_pem(pem.as_bytes()).unwrap();
println!("Parsed: {:?}", parse);
assert_eq!(parse.version, 1);
assert!(!parse.key.is_empty());
assert_eq!(parse.key.len(), 32); assert!(parse.public_key.is_some());
assert!(parse.curve.is_some());
}
}
#[test]
fn test_key_parses_pem() {
let mut path = get_path();
path.push("private_key2.pem"); let pem = std::fs::read_to_string(path).unwrap();
let expected =
hex::decode("04A0A31E2B5E819CE9A8D5023042B235488DB7C777C38ADE6E6FDF86565419A6") .unwrap();
let parsed = crate::parse_pem(pem.as_bytes()).unwrap();
assert_eq!(expected, parsed.key)
}
#[test]
fn test_key_parses_der() {
let mut path = get_path();
path.push("private_key.der");
let pem = std::fs::read(path).unwrap();
let parsed = crate::parse_der(&pem).unwrap();
println!("{:?}", parsed.key);
}
#[test]
fn test_pkcs8_fails() {
let mut path = get_path();
path.push("pkcs8eckey.pem"); let pem = std::fs::read_to_string(path).unwrap();
let fails = crate::parse_pem(pem.as_bytes());
assert_eq!(
fails.unwrap_err(),
crate::error::Sec1PemError::NoECPrivateKey
)
}
}