use crate::internal_alloc::{String, Vec};
use noxtls_core::{Error, Result};
use noxtls_crypto::{
Ed25519PrivateKey, Ed25519PublicKey, MlDsaPublicKey, P256PrivateKey, P256PublicKey,
RsaPrivateKey, RsaPublicKey, X25519PrivateKey, X25519PublicKey, X448PrivateKey, X448PublicKey,
OID_ID_MLDSA65,
};
#[cfg(feature = "std")]
use noxtls_pem::{der_to_pem_file, pem_file_to_der};
use noxtls_pem::{
ec_private_key_pem_to_der_sec1, private_key_der_to_pem_pkcs8, private_key_pem_to_der_pkcs8,
public_key_der_to_pem_spki, public_key_pem_to_der_spki, rsa_private_key_pem_to_der_pkcs1,
rsa_public_key_der_to_pem_pkcs1, rsa_public_key_pem_to_der_pkcs1,
};
#[cfg(feature = "std")]
use std::path::Path;
use super::parse_der_node;
const OID_RSA_ENCRYPTION: &[u8] = &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01];
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];
const OID_X25519: &[u8] = &[0x2B, 0x65, 0x6E];
const OID_X448: &[u8] = &[0x2B, 0x65, 0x6F];
const OID_ED25519: &[u8] = &[0x2B, 0x65, 0x70];
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct RsaPrivateKeyDerParts {
pub modulus: Vec<u8>,
pub public_exponent: Vec<u8>,
pub private_exponent: Vec<u8>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct RsaPublicKeyDerParts {
pub modulus: Vec<u8>,
pub public_exponent: Vec<u8>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Pkcs8PrivateKeyInfoDerParts {
pub algorithm_oid: Vec<u8>,
pub algorithm_parameters_oid: Option<Vec<u8>>,
pub private_key: Vec<u8>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct SpkiPublicKeyInfoDerParts {
pub algorithm_oid: Vec<u8>,
pub algorithm_parameters_oid: Option<Vec<u8>>,
pub subject_public_key: Vec<u8>,
}
pub fn rsa_public_key_to_pkcs1_der(public: &RsaPublicKey) -> Result<Vec<u8>> {
let modulus = encode_der_integer(&public.n.to_be_bytes());
let exponent = encode_der_integer(&public.e.to_be_bytes());
encode_der_sequence(&[modulus, exponent].concat())
}
pub fn rsa_public_key_to_spki_der(public: &RsaPublicKey) -> Result<Vec<u8>> {
let pkcs1 = rsa_public_key_to_pkcs1_der(public)?;
encode_spki_public_key_info_der(OID_RSA_ENCRYPTION, None, &pkcs1)
}
pub fn rsa_public_key_to_pem_spki(public: &RsaPublicKey) -> Result<String> {
let der = rsa_public_key_to_spki_der(public)?;
public_key_der_to_pem_spki(&der)
}
pub fn rsa_public_key_to_pem_pkcs1(public: &RsaPublicKey) -> Result<String> {
let der = rsa_public_key_to_pkcs1_der(public)?;
rsa_public_key_der_to_pem_pkcs1(&der)
}
pub fn p256_public_key_to_spki_der(public: &P256PublicKey) -> Result<Vec<u8>> {
let sec1 = public.to_uncompressed()?;
encode_spki_public_key_info_der(OID_EC_PUBLIC_KEY, Some(OID_PRIME256V1), &sec1)
}
pub fn p256_public_key_to_pem_spki(public: &P256PublicKey) -> Result<String> {
let der = p256_public_key_to_spki_der(public)?;
public_key_der_to_pem_spki(&der)
}
pub fn x25519_public_key_to_spki_der(public: X25519PublicKey) -> Result<Vec<u8>> {
encode_spki_public_key_info_der(OID_X25519, None, &public.bytes)
}
pub fn x25519_public_key_to_pem_spki(public: X25519PublicKey) -> Result<String> {
let der = x25519_public_key_to_spki_der(public)?;
public_key_der_to_pem_spki(&der)
}
pub fn x448_public_key_to_spki_der(public: X448PublicKey) -> Result<Vec<u8>> {
encode_spki_public_key_info_der(OID_X448, None, &public.bytes)
}
pub fn x448_public_key_to_pem_spki(public: X448PublicKey) -> Result<String> {
let der = x448_public_key_to_spki_der(public)?;
public_key_der_to_pem_spki(&der)
}
pub fn ed25519_public_key_to_spki_der(public: Ed25519PublicKey) -> Result<Vec<u8>> {
encode_spki_public_key_info_der(OID_ED25519, None, &public.to_bytes())
}
pub fn ed25519_public_key_to_pem_spki(public: Ed25519PublicKey) -> Result<String> {
let der = ed25519_public_key_to_spki_der(public)?;
public_key_der_to_pem_spki(&der)
}
pub fn p256_private_key_to_pkcs8_der(private: &P256PrivateKey) -> Result<Vec<u8>> {
let scalar = private.to_bytes()?;
let sec1 = encode_der_sequence(
&[encode_der_integer(&[0x01]), encode_der_node(0x04, &scalar)].concat(),
)?;
encode_pkcs8_private_key_info_der(OID_EC_PUBLIC_KEY, Some(OID_PRIME256V1), &sec1)
}
pub fn p256_private_key_to_pem_pkcs8(private: &P256PrivateKey) -> Result<String> {
let der = p256_private_key_to_pkcs8_der(private)?;
private_key_der_to_pem_pkcs8(&der)
}
pub fn x25519_private_key_to_pkcs8_der(private: X25519PrivateKey) -> Result<Vec<u8>> {
let curve_private_key = encode_der_node(0x04, &private.to_bytes());
encode_pkcs8_private_key_info_der(OID_X25519, None, &curve_private_key)
}
pub fn x25519_private_key_to_pem_pkcs8(private: X25519PrivateKey) -> Result<String> {
let der = x25519_private_key_to_pkcs8_der(private)?;
private_key_der_to_pem_pkcs8(&der)
}
pub fn x448_private_key_to_pkcs8_der(private: X448PrivateKey) -> Result<Vec<u8>> {
let curve_private_key = encode_der_node(0x04, &private.to_bytes());
encode_pkcs8_private_key_info_der(OID_X448, None, &curve_private_key)
}
pub fn x448_private_key_to_pem_pkcs8(private: X448PrivateKey) -> Result<String> {
let der = x448_private_key_to_pkcs8_der(private)?;
private_key_der_to_pem_pkcs8(&der)
}
pub fn ed25519_private_key_to_pkcs8_der(private: &Ed25519PrivateKey) -> Result<Vec<u8>> {
let curve_private_key = encode_der_node(0x04, &private.to_seed());
encode_pkcs8_private_key_info_der(OID_ED25519, None, &curve_private_key)
}
pub fn ed25519_private_key_to_pem_pkcs8(private: &Ed25519PrivateKey) -> Result<String> {
let der = ed25519_private_key_to_pkcs8_der(private)?;
private_key_der_to_pem_pkcs8(&der)
}
pub fn rsa_private_key_from_pkcs1_der(der: &[u8]) -> Result<RsaPrivateKey> {
let parts = parse_pkcs1_rsa_private_key_der(der)?;
RsaPrivateKey::from_be_bytes(&parts.modulus, &parts.private_exponent)
}
pub fn rsa_private_key_from_pkcs8_der(der: &[u8]) -> Result<RsaPrivateKey> {
let info = parse_pkcs8_private_key_info_der(der)?;
if info.algorithm_oid != OID_RSA_ENCRYPTION {
return Err(Error::UnsupportedFeature(
"pkcs8 private key algorithm is not RSA",
));
}
rsa_private_key_from_pkcs1_der(&info.private_key)
}
pub fn p256_private_key_from_pkcs8_der(der: &[u8]) -> Result<P256PrivateKey> {
let info = parse_pkcs8_private_key_info_der(der)?;
if info.algorithm_oid != OID_EC_PUBLIC_KEY {
return Err(Error::UnsupportedFeature(
"pkcs8 private key algorithm is not EC",
));
}
if info.algorithm_parameters_oid.as_deref() != Some(OID_PRIME256V1) {
return Err(Error::UnsupportedFeature(
"pkcs8 ec curve is not prime256v1",
));
}
let scalar = parse_sec1_ec_private_key_scalar(&info.private_key)?;
P256PrivateKey::from_bytes(scalar)
}
pub fn x25519_private_key_from_pkcs8_der(der: &[u8]) -> Result<X25519PrivateKey> {
let info = parse_pkcs8_private_key_info_der(der)?;
if info.algorithm_oid != OID_X25519 {
return Err(Error::UnsupportedFeature(
"pkcs8 private key algorithm is not X25519",
));
}
if info.algorithm_parameters_oid.is_some() {
return Err(Error::UnsupportedFeature(
"x25519 algorithm parameters are not supported",
));
}
let scalar = parse_x25519_private_key_bytes(&info.private_key)?;
Ok(X25519PrivateKey::from_bytes(scalar))
}
pub fn x448_private_key_from_pkcs8_der(der: &[u8]) -> Result<X448PrivateKey> {
let info = parse_pkcs8_private_key_info_der(der)?;
if info.algorithm_oid != OID_X448 {
return Err(Error::UnsupportedFeature(
"pkcs8 private key algorithm is not X448",
));
}
if info.algorithm_parameters_oid.is_some() {
return Err(Error::UnsupportedFeature(
"x448 algorithm parameters are not supported",
));
}
let scalar = parse_x448_private_key_bytes(&info.private_key)?;
Ok(X448PrivateKey::from_bytes(scalar))
}
pub fn ed25519_private_key_from_pkcs8_der(der: &[u8]) -> Result<Ed25519PrivateKey> {
let info = parse_pkcs8_private_key_info_der(der)?;
if info.algorithm_oid != OID_ED25519 {
return Err(Error::UnsupportedFeature(
"pkcs8 private key algorithm is not Ed25519",
));
}
if info.algorithm_parameters_oid.is_some() {
return Err(Error::UnsupportedFeature(
"ed25519 algorithm parameters are not supported",
));
}
let seed = parse_ed25519_private_key_seed(&info.private_key)?;
Ok(Ed25519PrivateKey::from_seed(&seed))
}
pub fn p256_private_key_from_sec1_der(der: &[u8]) -> Result<P256PrivateKey> {
let scalar = parse_sec1_ec_private_key_scalar(der)?;
P256PrivateKey::from_bytes(scalar)
}
pub fn rsa_public_key_from_pkcs1_der(der: &[u8]) -> Result<RsaPublicKey> {
let parts = parse_pkcs1_rsa_public_key_der(der)?;
RsaPublicKey::from_be_bytes(&parts.modulus, &parts.public_exponent)
}
pub fn rsa_public_key_from_spki_der(der: &[u8]) -> Result<RsaPublicKey> {
let info = parse_spki_public_key_info_der(der)?;
if info.algorithm_oid != OID_RSA_ENCRYPTION {
return Err(Error::UnsupportedFeature(
"spki public key algorithm is not RSA",
));
}
rsa_public_key_from_pkcs1_der(&info.subject_public_key)
}
pub fn p256_public_key_from_spki_der(der: &[u8]) -> Result<P256PublicKey> {
let info = parse_spki_public_key_info_der(der)?;
if info.algorithm_oid != OID_EC_PUBLIC_KEY {
return Err(Error::UnsupportedFeature(
"spki public key algorithm is not EC",
));
}
if info.algorithm_parameters_oid.as_deref() != Some(OID_PRIME256V1) {
return Err(Error::UnsupportedFeature("spki ec curve is not prime256v1"));
}
P256PublicKey::from_uncompressed(&info.subject_public_key)
}
pub fn parse_ecdsa_signature_der(signature_der: &[u8]) -> Result<([u8; 32], [u8; 32])> {
let (seq, rem) = parse_der_node(signature_der)?;
if seq.tag != 0x30 || !rem.is_empty() {
return Err(Error::ParseFailure(
"ecdsa signature must be top-level DER sequence",
));
}
let (r_node, rest) = parse_der_node(seq.body)?;
let (s_node, tail) = parse_der_node(rest)?;
if r_node.tag != 0x02 || s_node.tag != 0x02 || !tail.is_empty() {
return Err(Error::ParseFailure(
"ecdsa signature sequence must contain r and s integers only",
));
}
let r = der_integer_to_p256_scalar(r_node.body)?;
let s = der_integer_to_p256_scalar(s_node.body)?;
Ok((r, s))
}
fn der_integer_to_p256_scalar(value: &[u8]) -> Result<[u8; 32]> {
if value.is_empty() {
return Err(Error::ParseFailure("ecdsa der integer must not be empty"));
}
if value[0] & 0x80 != 0 {
return Err(Error::ParseFailure(
"ecdsa der integer must be non-negative",
));
}
if value.len() > 1 && value[0] == 0x00 && value[1] & 0x80 == 0 {
return Err(Error::ParseFailure(
"ecdsa der integer must use minimal encoding",
));
}
let normalized = if value.len() > 1 && value[0] == 0x00 {
&value[1..]
} else {
value
};
if normalized.len() > 32 {
return Err(Error::InvalidLength(
"ecdsa der integer too large for p-256 scalar",
));
}
let mut out = [0_u8; 32];
out[32 - normalized.len()..].copy_from_slice(normalized);
Ok(out)
}
pub fn x25519_public_key_from_spki_der(der: &[u8]) -> Result<X25519PublicKey> {
let info = parse_spki_public_key_info_der(der)?;
if info.algorithm_oid != OID_X25519 {
return Err(Error::UnsupportedFeature(
"spki public key algorithm is not X25519",
));
}
if info.algorithm_parameters_oid.is_some() {
return Err(Error::UnsupportedFeature(
"x25519 algorithm parameters are not supported",
));
}
if info.subject_public_key.len() != 32 {
return Err(Error::InvalidLength("x25519 public key must be 32 bytes"));
}
let mut public = [0_u8; 32];
public.copy_from_slice(&info.subject_public_key);
Ok(X25519PublicKey::from_bytes(public))
}
pub fn x448_public_key_from_spki_der(der: &[u8]) -> Result<X448PublicKey> {
let info = parse_spki_public_key_info_der(der)?;
if info.algorithm_oid != OID_X448 {
return Err(Error::UnsupportedFeature(
"spki public key algorithm is not X448",
));
}
if info.algorithm_parameters_oid.is_some() {
return Err(Error::UnsupportedFeature(
"x448 algorithm parameters are not supported",
));
}
if info.subject_public_key.len() != 56 {
return Err(Error::InvalidLength("x448 public key must be 56 bytes"));
}
let mut public = [0_u8; 56];
public.copy_from_slice(&info.subject_public_key);
Ok(X448PublicKey::from_bytes(public))
}
pub fn ed25519_public_key_from_spki_der(der: &[u8]) -> Result<Ed25519PublicKey> {
let info = parse_spki_public_key_info_der(der)?;
if info.algorithm_oid != OID_ED25519 {
return Err(Error::UnsupportedFeature(
"spki public key algorithm is not Ed25519",
));
}
if info.algorithm_parameters_oid.is_some() {
return Err(Error::UnsupportedFeature(
"ed25519 algorithm parameters are not supported",
));
}
if info.subject_public_key.len() != 32 {
return Err(Error::InvalidLength("ed25519 public key must be 32 bytes"));
}
let mut public = [0_u8; 32];
public.copy_from_slice(&info.subject_public_key);
Ed25519PublicKey::from_bytes(&public)
}
pub fn mldsa_public_key_from_spki_der(der: &[u8]) -> Result<MlDsaPublicKey> {
let info = parse_spki_public_key_info_der(der)?;
if info.algorithm_oid != OID_ID_MLDSA65 {
return Err(Error::UnsupportedFeature(
"spki public key algorithm is not ML-DSA-65",
));
}
if info.algorithm_parameters_oid.is_some() {
return Err(Error::UnsupportedFeature(
"mldsa algorithm parameters are not supported",
));
}
MlDsaPublicKey::from_bytes(&info.subject_public_key)
}
pub fn rsa_private_key_from_pem_pkcs1(pem: &str) -> Result<RsaPrivateKey> {
let der = rsa_private_key_pem_to_der_pkcs1(pem)?;
rsa_private_key_from_pkcs1_der(&der)
}
pub fn rsa_private_key_from_pem_pkcs8(pem: &str) -> Result<RsaPrivateKey> {
let der = private_key_pem_to_der_pkcs8(pem)?;
rsa_private_key_from_pkcs8_der(&der)
}
pub fn p256_private_key_from_pem_pkcs8(pem: &str) -> Result<P256PrivateKey> {
let der = private_key_pem_to_der_pkcs8(pem)?;
p256_private_key_from_pkcs8_der(&der)
}
pub fn x25519_private_key_from_pem_pkcs8(pem: &str) -> Result<X25519PrivateKey> {
let der = private_key_pem_to_der_pkcs8(pem)?;
x25519_private_key_from_pkcs8_der(&der)
}
pub fn x448_private_key_from_pem_pkcs8(pem: &str) -> Result<X448PrivateKey> {
let der = private_key_pem_to_der_pkcs8(pem)?;
x448_private_key_from_pkcs8_der(&der)
}
pub fn ed25519_private_key_from_pem_pkcs8(pem: &str) -> Result<Ed25519PrivateKey> {
let der = private_key_pem_to_der_pkcs8(pem)?;
ed25519_private_key_from_pkcs8_der(&der)
}
pub fn p256_private_key_from_pem_sec1(pem: &str) -> Result<P256PrivateKey> {
let der = ec_private_key_pem_to_der_sec1(pem)?;
p256_private_key_from_sec1_der(&der)
}
pub fn rsa_public_key_from_pem_spki(pem: &str) -> Result<RsaPublicKey> {
let der = public_key_pem_to_der_spki(pem)?;
rsa_public_key_from_spki_der(&der)
}
pub fn rsa_public_key_from_pem_pkcs1(pem: &str) -> Result<RsaPublicKey> {
let der = rsa_public_key_pem_to_der_pkcs1(pem)?;
rsa_public_key_from_pkcs1_der(&der)
}
pub fn p256_public_key_from_pem_spki(pem: &str) -> Result<P256PublicKey> {
let der = public_key_pem_to_der_spki(pem)?;
p256_public_key_from_spki_der(&der)
}
pub fn x25519_public_key_from_pem_spki(pem: &str) -> Result<X25519PublicKey> {
let der = public_key_pem_to_der_spki(pem)?;
x25519_public_key_from_spki_der(&der)
}
pub fn x448_public_key_from_pem_spki(pem: &str) -> Result<X448PublicKey> {
let der = public_key_pem_to_der_spki(pem)?;
x448_public_key_from_spki_der(&der)
}
pub fn ed25519_public_key_from_pem_spki(pem: &str) -> Result<Ed25519PublicKey> {
let der = public_key_pem_to_der_spki(pem)?;
ed25519_public_key_from_spki_der(&der)
}
#[cfg(feature = "std")]
pub fn p256_private_key_from_pem_file_pkcs8(path: &Path) -> Result<P256PrivateKey> {
let der = pem_file_to_der(path, "PRIVATE KEY")?;
p256_private_key_from_pkcs8_der(&der)
}
#[cfg(feature = "std")]
pub fn p256_private_key_to_pem_file_pkcs8(path: &Path, private: &P256PrivateKey) -> Result<()> {
let der = p256_private_key_to_pkcs8_der(private)?;
der_to_pem_file(path, &der, "PRIVATE KEY")
}
#[cfg(feature = "std")]
pub fn x25519_private_key_from_pem_file_pkcs8(path: &Path) -> Result<X25519PrivateKey> {
let der = pem_file_to_der(path, "PRIVATE KEY")?;
x25519_private_key_from_pkcs8_der(&der)
}
#[cfg(feature = "std")]
pub fn x25519_private_key_to_pem_file_pkcs8(path: &Path, private: X25519PrivateKey) -> Result<()> {
let der = x25519_private_key_to_pkcs8_der(private)?;
der_to_pem_file(path, &der, "PRIVATE KEY")
}
#[cfg(feature = "std")]
pub fn x448_private_key_from_pem_file_pkcs8(path: &Path) -> Result<X448PrivateKey> {
let der = pem_file_to_der(path, "PRIVATE KEY")?;
x448_private_key_from_pkcs8_der(&der)
}
#[cfg(feature = "std")]
pub fn x448_private_key_to_pem_file_pkcs8(path: &Path, private: X448PrivateKey) -> Result<()> {
let der = x448_private_key_to_pkcs8_der(private)?;
der_to_pem_file(path, &der, "PRIVATE KEY")
}
#[cfg(feature = "std")]
pub fn ed25519_private_key_from_pem_file_pkcs8(path: &Path) -> Result<Ed25519PrivateKey> {
let der = pem_file_to_der(path, "PRIVATE KEY")?;
ed25519_private_key_from_pkcs8_der(&der)
}
#[cfg(feature = "std")]
pub fn ed25519_private_key_to_pem_file_pkcs8(
path: &Path,
private: &Ed25519PrivateKey,
) -> Result<()> {
let der = ed25519_private_key_to_pkcs8_der(private)?;
der_to_pem_file(path, &der, "PRIVATE KEY")
}
pub fn parse_pkcs1_rsa_private_key_der(der: &[u8]) -> Result<RsaPrivateKeyDerParts> {
let (seq, tail) = parse_der_node(der)?;
if seq.tag != 0x30 || !tail.is_empty() {
return Err(Error::ParseFailure(
"pkcs1 rsa private key must be top-level sequence",
));
}
let mut cursor = seq.body;
let (version, rest) = parse_der_node(cursor)?;
if version.tag != 0x02 || version.body.is_empty() {
return Err(Error::ParseFailure("pkcs1 rsa private key missing version"));
}
if version.body[version.body.len() - 1] > 1 {
return Err(Error::ParseFailure(
"unsupported pkcs1 rsa private key version",
));
}
cursor = rest;
let (modulus, rest) = parse_der_integer(cursor, "pkcs1 rsa private key missing modulus")?;
let (public_exponent, rest) =
parse_der_integer(rest, "pkcs1 rsa private key missing public exponent")?;
let (private_exponent, _rest) =
parse_der_integer(rest, "pkcs1 rsa private key missing private exponent")?;
Ok(RsaPrivateKeyDerParts {
modulus,
public_exponent,
private_exponent,
})
}
pub fn parse_pkcs1_rsa_public_key_der(der: &[u8]) -> Result<RsaPublicKeyDerParts> {
let (seq, tail) = parse_der_node(der)?;
if seq.tag != 0x30 || !tail.is_empty() {
return Err(Error::ParseFailure(
"pkcs1 rsa public key must be top-level sequence",
));
}
let (modulus, rest) = parse_der_integer(seq.body, "pkcs1 rsa public key missing modulus")?;
let (public_exponent, rest) =
parse_der_integer(rest, "pkcs1 rsa public key missing public exponent")?;
if !rest.is_empty() {
return Err(Error::ParseFailure(
"unexpected bytes in pkcs1 rsa public key",
));
}
Ok(RsaPublicKeyDerParts {
modulus,
public_exponent,
})
}
pub fn parse_pkcs8_private_key_info_der(der: &[u8]) -> Result<Pkcs8PrivateKeyInfoDerParts> {
let (seq, tail) = parse_der_node(der)?;
if seq.tag != 0x30 || !tail.is_empty() {
return Err(Error::ParseFailure(
"pkcs8 private key must be top-level sequence",
));
}
let (version, rest) = parse_der_node(seq.body)?;
if version.tag != 0x02 || version.body.is_empty() {
return Err(Error::ParseFailure("pkcs8 private key missing version"));
}
let (algorithm, rest) = parse_der_node(rest)?;
if algorithm.tag != 0x30 {
return Err(Error::ParseFailure(
"pkcs8 private key missing algorithm identifier",
));
}
let (oid, params_tail) = parse_der_node(algorithm.body)?;
if oid.tag != 0x06 {
return Err(Error::ParseFailure(
"pkcs8 private key algorithm missing oid",
));
}
let algorithm_parameters_oid = if params_tail.is_empty() {
None
} else {
let (params, tail) = parse_der_node(params_tail)?;
if !tail.is_empty() {
return Err(Error::ParseFailure(
"unsupported pkcs8 algorithm parameters",
));
}
if params.tag == 0x06 {
Some(params.body.to_vec())
} else if params.tag == 0x05 && params.body.is_empty() {
None
} else {
return Err(Error::ParseFailure(
"unsupported pkcs8 algorithm parameters",
));
}
};
let (private_key, _rest) = parse_der_node(rest)?;
if private_key.tag != 0x04 {
return Err(Error::ParseFailure(
"pkcs8 private key missing private key octets",
));
}
Ok(Pkcs8PrivateKeyInfoDerParts {
algorithm_oid: oid.body.to_vec(),
algorithm_parameters_oid,
private_key: private_key.body.to_vec(),
})
}
pub fn parse_spki_public_key_info_der(der: &[u8]) -> Result<SpkiPublicKeyInfoDerParts> {
let (seq, tail) = parse_der_node(der)?;
if seq.tag != 0x30 || !tail.is_empty() {
return Err(Error::ParseFailure("spki must be top-level sequence"));
}
let (algorithm, rest) = parse_der_node(seq.body)?;
if algorithm.tag != 0x30 {
return Err(Error::ParseFailure("spki missing algorithm identifier"));
}
let (oid, params_tail) = parse_der_node(algorithm.body)?;
if oid.tag != 0x06 {
return Err(Error::ParseFailure("spki algorithm missing oid"));
}
let algorithm_parameters_oid = if params_tail.is_empty() {
None
} else {
let (params, tail) = parse_der_node(params_tail)?;
if !tail.is_empty() {
return Err(Error::ParseFailure("unsupported spki algorithm parameters"));
}
if params.tag == 0x06 {
Some(params.body.to_vec())
} else if params.tag == 0x05 && params.body.is_empty() {
None
} else {
return Err(Error::ParseFailure("unsupported spki algorithm parameters"));
}
};
let (subject_public_key, rest) = parse_der_node(rest)?;
if subject_public_key.tag != 0x03 || !rest.is_empty() {
return Err(Error::ParseFailure(
"spki missing subject public key bit string",
));
}
let key_bytes = parse_der_bit_string(subject_public_key.body)?;
Ok(SpkiPublicKeyInfoDerParts {
algorithm_oid: oid.body.to_vec(),
algorithm_parameters_oid,
subject_public_key: key_bytes,
})
}
fn parse_der_integer<'a>(
input: &'a [u8],
missing_message: &'static str,
) -> Result<(Vec<u8>, &'a [u8])> {
let (node, rest) = parse_der_node(input)?;
if node.tag != 0x02 || node.body.is_empty() {
return Err(Error::ParseFailure(missing_message));
}
let mut bytes = node.body;
if bytes.len() > 1 && bytes[0] == 0x00 {
bytes = &bytes[1..];
}
Ok((bytes.to_vec(), rest))
}
fn parse_der_bit_string(input: &[u8]) -> Result<Vec<u8>> {
if input.is_empty() {
return Err(Error::ParseFailure("empty DER bit string"));
}
if input[0] > 7 {
return Err(Error::ParseFailure(
"invalid DER bit string unused-bit count",
));
}
Ok(input[1..].to_vec())
}
fn parse_sec1_ec_private_key_scalar(der: &[u8]) -> Result<[u8; 32]> {
let (seq, tail) = parse_der_node(der)?;
if seq.tag != 0x30 || !tail.is_empty() {
return Err(Error::ParseFailure(
"sec1 ec private key must be top-level sequence",
));
}
let (version, rest) = parse_der_node(seq.body)?;
if version.tag != 0x02 || version.body.is_empty() {
return Err(Error::ParseFailure("sec1 ec private key missing version"));
}
if version.body[version.body.len() - 1] != 0x01 {
return Err(Error::ParseFailure(
"unsupported sec1 ec private key version",
));
}
let (private_key, _rest) = parse_der_node(rest)?;
if private_key.tag != 0x04 {
return Err(Error::ParseFailure(
"sec1 ec private key missing private key octets",
));
}
if private_key.body.len() != 32 {
return Err(Error::InvalidLength(
"p256 private key scalar must be 32 bytes",
));
}
let mut scalar = [0_u8; 32];
scalar.copy_from_slice(private_key.body);
Ok(scalar)
}
fn parse_x25519_private_key_bytes(input: &[u8]) -> Result<[u8; 32]> {
if input.len() == 32 {
let mut scalar = [0_u8; 32];
scalar.copy_from_slice(input);
return Ok(scalar);
}
let (inner, tail) = parse_der_node(input)?;
if inner.tag != 0x04 || !tail.is_empty() || inner.body.len() != 32 {
return Err(Error::ParseFailure("invalid x25519 private key bytes"));
}
let mut scalar = [0_u8; 32];
scalar.copy_from_slice(inner.body);
Ok(scalar)
}
fn parse_x448_private_key_bytes(input: &[u8]) -> Result<[u8; 56]> {
if input.len() == 56 {
let mut scalar = [0_u8; 56];
scalar.copy_from_slice(input);
return Ok(scalar);
}
let (inner, tail) = parse_der_node(input)?;
if inner.tag != 0x04 || !tail.is_empty() || inner.body.len() != 56 {
return Err(Error::ParseFailure("invalid x448 private key bytes"));
}
let mut scalar = [0_u8; 56];
scalar.copy_from_slice(inner.body);
Ok(scalar)
}
fn parse_ed25519_private_key_seed(input: &[u8]) -> Result<[u8; 32]> {
if input.len() == 32 {
let mut seed = [0_u8; 32];
seed.copy_from_slice(input);
return Ok(seed);
}
let (inner, tail) = parse_der_node(input)?;
if inner.tag != 0x04 || !tail.is_empty() || inner.body.len() != 32 {
return Err(Error::ParseFailure("invalid ed25519 private key bytes"));
}
let mut seed = [0_u8; 32];
seed.copy_from_slice(inner.body);
Ok(seed)
}
fn encode_der_integer(value: &[u8]) -> Vec<u8> {
let mut body = if value.is_empty() {
vec![0x00]
} else {
value.to_vec()
};
while body.len() > 1 && body[0] == 0x00 {
body.remove(0);
}
if body[0] & 0x80 != 0 {
body.insert(0, 0x00);
}
encode_der_node(0x02, &body)
}
fn encode_der_sequence(children: &[u8]) -> Result<Vec<u8>> {
let mut out = vec![0x30];
out.extend_from_slice(&encode_der_len(children.len())?);
out.extend_from_slice(children);
Ok(out)
}
fn encode_der_node(tag: u8, body: &[u8]) -> Vec<u8> {
let mut out = vec![tag];
out.extend_from_slice(&encode_der_len(body.len()).expect("der len should encode"));
out.extend_from_slice(body);
out
}
fn encode_der_len(len: usize) -> Result<Vec<u8>> {
if len < 128 {
return Ok(vec![len as u8]);
}
let len_u32 = u32::try_from(len).map_err(|_| Error::InvalidLength("der length too large"))?;
let bytes = len_u32.to_be_bytes();
let first_nonzero = bytes
.iter()
.position(|byte| *byte != 0)
.unwrap_or(bytes.len() - 1);
let content = &bytes[first_nonzero..];
let mut out = vec![0x80 | (content.len() as u8)];
out.extend_from_slice(content);
Ok(out)
}
fn encode_spki_public_key_info_der(
algorithm_oid: &[u8],
algorithm_parameters_oid: Option<&[u8]>,
subject_public_key: &[u8],
) -> Result<Vec<u8>> {
let algorithm = {
let mut algorithm_body = Vec::new();
algorithm_body.extend_from_slice(&encode_der_node(0x06, algorithm_oid));
if let Some(params_oid) = algorithm_parameters_oid {
algorithm_body.extend_from_slice(&encode_der_node(0x06, params_oid));
}
encode_der_node(0x30, &algorithm_body)
};
let mut bit_string_body = vec![0x00];
bit_string_body.extend_from_slice(subject_public_key);
let subject_public_key = encode_der_node(0x03, &bit_string_body);
encode_der_sequence(&[algorithm, subject_public_key].concat())
}
fn encode_pkcs8_private_key_info_der(
algorithm_oid: &[u8],
algorithm_parameters_oid: Option<&[u8]>,
private_key: &[u8],
) -> Result<Vec<u8>> {
let version = encode_der_integer(&[0x00]);
let algorithm = {
let mut algorithm_body = Vec::new();
algorithm_body.extend_from_slice(&encode_der_node(0x06, algorithm_oid));
if let Some(params_oid) = algorithm_parameters_oid {
algorithm_body.extend_from_slice(&encode_der_node(0x06, params_oid));
}
encode_der_node(0x30, &algorithm_body)
};
let private_key = encode_der_node(0x04, private_key);
encode_der_sequence(&[version, algorithm, private_key].concat())
}
#[cfg(test)]
mod ed25519_pkcs8_tests {
use super::*;
use noxtls_pem::private_key_der_to_pem_pkcs8;
#[cfg(feature = "std")]
use std::{
fs,
path::PathBuf,
time::{SystemTime, UNIX_EPOCH},
};
fn sample_ed25519_seed() -> [u8; 32] {
core::array::from_fn(|i| i as u8 + 1)
}
fn ed25519_pkcs8_der_nested_octet(seed: &[u8; 32]) -> Vec<u8> {
let mut der = Vec::new();
der.extend_from_slice(&[
0x30, 0x2E, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2B, 0x65, 0x70, 0x04, 0x22,
0x04, 0x20,
]);
der.extend_from_slice(seed);
der
}
fn ed25519_pkcs8_der_raw_seed(seed: &[u8; 32]) -> Vec<u8> {
let mut der = Vec::new();
der.extend_from_slice(&[
0x30, 0x2C, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2B, 0x65, 0x70, 0x04, 0x20,
]);
der.extend_from_slice(seed);
der
}
#[test]
fn ed25519_pkcs8_nested_octet_parses_and_spki_roundtrips() {
let seed = sample_ed25519_seed();
let der = ed25519_pkcs8_der_nested_octet(&seed);
let sk = ed25519_private_key_from_pkcs8_der(&der).expect("pkcs8 nested");
let pk_der = ed25519_public_key_to_spki_der(sk.verifying_key()).expect("spki der");
let pk_back = ed25519_public_key_from_spki_der(&pk_der).expect("spki parse");
assert_eq!(pk_back.to_bytes(), sk.verifying_key().to_bytes());
}
#[test]
fn ed25519_pkcs8_raw_seed_in_private_key_field_parses() {
let seed = core::array::from_fn(|i| i as u8 + 7);
let der = ed25519_pkcs8_der_raw_seed(&seed);
let sk = ed25519_private_key_from_pkcs8_der(&der).expect("pkcs8 raw");
let expect = Ed25519PrivateKey::from_seed(&seed)
.verifying_key()
.to_bytes();
assert_eq!(sk.verifying_key().to_bytes(), expect);
}
#[test]
fn ed25519_pem_pkcs8_roundtrip() {
let seed = [9_u8; 32];
let der = ed25519_pkcs8_der_nested_octet(&seed);
let pem = private_key_der_to_pem_pkcs8(&der).expect("pem encode");
let sk = ed25519_private_key_from_pem_pkcs8(&pem).expect("pem decode");
assert_eq!(
sk.verifying_key().to_bytes(),
Ed25519PrivateKey::from_seed(&seed)
.verifying_key()
.to_bytes()
);
}
#[test]
fn ed25519_pem_spki_roundtrip() {
let sk = Ed25519PrivateKey::from_seed(&sample_ed25519_seed());
let pk = sk.verifying_key();
let pem = ed25519_public_key_to_pem_spki(pk).expect("pem spki");
let pk_back = ed25519_public_key_from_pem_spki(&pem).expect("pem parse");
assert_eq!(pk_back.to_bytes(), pk.to_bytes());
}
#[test]
fn p256_pkcs8_serialize_roundtrip() {
let mut scalar = [0_u8; 32];
scalar[31] = 1;
let sk = P256PrivateKey::from_bytes(scalar).expect("p256 seed");
let der = p256_private_key_to_pkcs8_der(&sk).expect("serialize");
let decoded = p256_private_key_from_pkcs8_der(&der).expect("parse");
let expected_pub = sk
.public_key()
.expect("pub a")
.to_uncompressed()
.expect("sec1 a");
let decoded_pub = decoded
.public_key()
.expect("pub b")
.to_uncompressed()
.expect("sec1 b");
assert_eq!(decoded_pub, expected_pub);
}
#[test]
fn x25519_pkcs8_serialize_roundtrip() {
let private = X25519PrivateKey::from_bytes([0x21; 32]);
let der = x25519_private_key_to_pkcs8_der(private.clone()).expect("serialize");
let decoded = x25519_private_key_from_pkcs8_der(&der).expect("parse");
assert_eq!(decoded.public_key().bytes, private.public_key().bytes);
}
#[test]
fn x448_pkcs8_serialize_roundtrip() {
let private = X448PrivateKey::from_bytes([0x37; 56]);
let der = x448_private_key_to_pkcs8_der(private.clone()).expect("serialize");
let decoded = x448_private_key_from_pkcs8_der(&der).expect("parse");
assert_eq!(decoded.to_bytes(), private.to_bytes());
}
#[test]
fn ed25519_pkcs8_serialize_roundtrip() {
let private = Ed25519PrivateKey::from_seed(&sample_ed25519_seed());
let der = ed25519_private_key_to_pkcs8_der(&private).expect("serialize");
let decoded = ed25519_private_key_from_pkcs8_der(&der).expect("parse");
assert_eq!(
decoded.verifying_key().to_bytes(),
private.verifying_key().to_bytes()
);
}
#[cfg(feature = "std")]
fn unique_temp_file(stem: &str) -> PathBuf {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("clock")
.as_nanos();
std::env::temp_dir().join(format!(
"noxtls_{stem}_{}_{}.pem",
std::process::id(),
nanos
))
}
#[cfg(feature = "std")]
#[test]
fn ed25519_pkcs8_file_roundtrip() {
let path = unique_temp_file("ed25519_pkcs8");
let private = Ed25519PrivateKey::from_seed(&sample_ed25519_seed());
ed25519_private_key_to_pem_file_pkcs8(&path, &private).expect("write");
let decoded = ed25519_private_key_from_pem_file_pkcs8(&path).expect("read");
assert_eq!(
decoded.verifying_key().to_bytes(),
private.verifying_key().to_bytes()
);
let _ = fs::remove_file(path);
}
#[cfg(feature = "std")]
#[test]
fn x25519_pkcs8_file_roundtrip() {
let path = unique_temp_file("x25519_pkcs8");
let private = X25519PrivateKey::from_bytes([0x42; 32]);
x25519_private_key_to_pem_file_pkcs8(&path, private.clone()).expect("write");
let decoded = x25519_private_key_from_pem_file_pkcs8(&path).expect("read");
assert_eq!(decoded.public_key().bytes, private.public_key().bytes);
let _ = fs::remove_file(path);
}
#[cfg(feature = "std")]
#[test]
fn p256_pkcs8_file_roundtrip() {
let path = unique_temp_file("p256_pkcs8");
let mut scalar = [0_u8; 32];
scalar[31] = 3;
let private = P256PrivateKey::from_bytes(scalar).expect("p256");
p256_private_key_to_pem_file_pkcs8(&path, &private).expect("write");
let decoded = p256_private_key_from_pem_file_pkcs8(&path).expect("read");
let expected_pub = private
.public_key()
.expect("pub a")
.to_uncompressed()
.expect("sec1 a");
let decoded_pub = decoded
.public_key()
.expect("pub b")
.to_uncompressed()
.expect("sec1 b");
assert_eq!(decoded_pub, expected_pub);
let _ = fs::remove_file(path);
}
#[cfg(feature = "std")]
#[test]
fn x448_pkcs8_file_roundtrip() {
let path = unique_temp_file("x448_pkcs8");
let private = X448PrivateKey::from_bytes([0x17; 56]);
x448_private_key_to_pem_file_pkcs8(&path, private.clone()).expect("write");
let decoded = x448_private_key_from_pem_file_pkcs8(&path).expect("read");
assert_eq!(decoded.to_bytes(), private.to_bytes());
let _ = fs::remove_file(path);
}
}