use std::fmt;
use der::pem::LineEnding;
use pkcs8::{EncodePrivateKey, PrivateKeyInfo};
use crate::error::{CertKitError, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum KeyType {
Rsa,
EcdsaP256,
EcdsaP384,
EcdsaP521,
Ed25519,
}
impl fmt::Display for KeyType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Rsa => write!(f, "RSA"),
Self::EcdsaP256 => write!(f, "ECDSA P-256"),
Self::EcdsaP384 => write!(f, "ECDSA P-384"),
Self::EcdsaP521 => write!(f, "ECDSA P-521"),
Self::Ed25519 => write!(f, "Ed25519"),
}
}
}
#[cfg(feature = "ed25519")]
use ed25519_dalek::SigningKey as Ed25519SigningKey;
#[cfg(feature = "ed25519")]
use ed25519_dalek::VerifyingKey as Ed25519VerifyingKey;
#[cfg(feature = "p256")]
use p256::ecdsa::{SigningKey as P256SigningKey, VerifyingKey as P256VerifyingKey};
#[cfg(feature = "p384")]
use p384::ecdsa::{SigningKey as P384SigningKey, VerifyingKey as P384VerifyingKey};
#[cfg(feature = "p521")]
use p521::ecdsa::SigningKey as P521SigningKey;
#[cfg(feature = "rsa")]
use rsa::pkcs1v15::SigningKey as RsaSigningKey;
#[cfg(feature = "rsa")]
use rsa::signature::SignatureEncoding;
#[cfg(feature = "rsa")]
use rsa::signature::Signer as RsaSigner;
#[cfg(feature = "rsa")]
use rsa::{
RsaPrivateKey, RsaPublicKey,
pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey, EncodeRsaPublicKey},
traits::PublicKeyParts,
};
#[cfg(feature = "rsa")]
use sha2::Sha256;
#[derive(Clone)]
pub enum KeyPair {
#[cfg(feature = "rsa")]
Rsa {
private: Box<RsaPrivateKey>,
public: RsaPublicKey,
},
#[cfg(feature = "p256")]
EcdsaP256 {
signing_key: P256SigningKey,
verifying_key: P256VerifyingKey,
},
#[cfg(feature = "p384")]
EcdsaP384 {
signing_key: P384SigningKey,
verifying_key: P384VerifyingKey,
},
#[cfg(feature = "p521")]
EcdsaP521 {
secret_key: p521::SecretKey,
public_key: p521::PublicKey,
},
#[cfg(feature = "ed25519")]
Ed25519 { signing_key: Ed25519SigningKey },
}
impl std::fmt::Debug for KeyPair {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
#[cfg(feature = "rsa")]
Self::Rsa { public, .. } => f
.debug_struct("Rsa")
.field("bits", &public.n().bits())
.finish_non_exhaustive(),
#[cfg(feature = "p256")]
Self::EcdsaP256 { .. } => f.debug_struct("EcdsaP256").finish_non_exhaustive(),
#[cfg(feature = "p384")]
Self::EcdsaP384 { .. } => f.debug_struct("EcdsaP384").finish_non_exhaustive(),
#[cfg(feature = "p521")]
Self::EcdsaP521 { .. } => f.debug_struct("EcdsaP521").finish_non_exhaustive(),
#[cfg(feature = "ed25519")]
Self::Ed25519 { .. } => f.debug_struct("Ed25519").finish_non_exhaustive(),
}
}
}
#[cfg(feature = "p521")]
fn p521_signing_key(secret_key: &p521::SecretKey) -> P521SigningKey {
P521SigningKey::from_bytes(&secret_key.to_bytes())
.expect("a stored secret key always holds a valid scalar")
}
impl KeyPair {
#[cfg(feature = "rsa")]
pub fn generate_rsa(bits: usize) -> Result<Self> {
if bits < 2048 {
return Err(CertKitError::InvalidInput(format!(
"RSA key size {bits} bits is below the minimum of 2048"
)));
}
log::debug!("generating RSA-{bits} key pair");
let mut rng = rand_core::OsRng;
let private = RsaPrivateKey::new(&mut rng, bits)?;
let public = RsaPublicKey::from(&private);
Ok(KeyPair::Rsa {
private: Box::new(private),
public,
})
}
#[cfg(feature = "p256")]
pub fn generate_ecdsa_p256() -> Self {
log::debug!("generating ECDSA P-256 key pair");
let mut rng = rand_core::OsRng;
let signing_key = P256SigningKey::random(&mut rng);
let verifying_key = signing_key.verifying_key().to_owned();
KeyPair::EcdsaP256 {
signing_key,
verifying_key,
}
}
#[cfg(feature = "p384")]
pub fn generate_ecdsa_p384() -> Self {
log::debug!("generating ECDSA P-384 key pair");
let mut rng = rand_core::OsRng;
let signing_key = P384SigningKey::random(&mut rng);
let verifying_key = signing_key.verifying_key().to_owned();
KeyPair::EcdsaP384 {
signing_key,
verifying_key,
}
}
#[cfg(feature = "p521")]
pub fn generate_ecdsa_p521() -> Self {
log::debug!("generating ECDSA P-521 key pair");
let mut rng = rand_core::OsRng;
let secret_key = p521::SecretKey::random(&mut rng);
let public_key = secret_key.public_key();
KeyPair::EcdsaP521 {
secret_key,
public_key,
}
}
#[cfg(feature = "ed25519")]
pub fn generate_ed25519() -> Self {
log::debug!("generating Ed25519 key pair");
let mut rng = rand_core::OsRng;
let signing_key: Ed25519SigningKey = Ed25519SigningKey::generate(&mut rng);
KeyPair::Ed25519 { signing_key }
}
pub fn get_public_key_der(&self) -> Vec<u8> {
match self {
#[cfg(feature = "rsa")]
KeyPair::Rsa { public, .. } => public
.to_pkcs1_der()
.expect("valid RSA public key always encodes to PKCS#1 DER")
.as_bytes()
.to_vec(),
#[cfg(feature = "p256")]
KeyPair::EcdsaP256 { verifying_key, .. } => verifying_key.to_sec1_bytes().to_vec(),
#[cfg(feature = "p384")]
KeyPair::EcdsaP384 { verifying_key, .. } => verifying_key.to_sec1_bytes().to_vec(),
#[cfg(feature = "p521")]
KeyPair::EcdsaP521 { public_key, .. } => public_key.to_sec1_bytes().to_vec(),
#[cfg(feature = "ed25519")]
KeyPair::Ed25519 { signing_key } => signing_key.verifying_key().to_bytes().to_vec(),
}
}
pub fn encode_private_key_pem(&self) -> Result<String> {
let key = (match &self {
#[cfg(feature = "rsa")]
KeyPair::Rsa { private, .. } => private.to_pkcs8_pem(LineEnding::default()),
#[cfg(feature = "p256")]
KeyPair::EcdsaP256 { signing_key, .. } => {
EncodePrivateKey::to_pkcs8_pem(signing_key, LineEnding::default())
}
#[cfg(feature = "p384")]
KeyPair::EcdsaP384 { signing_key, .. } => {
EncodePrivateKey::to_pkcs8_pem(signing_key, LineEnding::default())
}
#[cfg(feature = "p521")]
KeyPair::EcdsaP521 { secret_key, .. } => {
EncodePrivateKey::to_pkcs8_pem(secret_key, LineEnding::default())
}
#[cfg(feature = "ed25519")]
KeyPair::Ed25519 { signing_key, .. } => {
EncodePrivateKey::to_pkcs8_pem(signing_key, LineEnding::default())
}
})
.map_err(|e| e.to_string())
.map_err(CertKitError::EncodingError)?;
Ok(key.as_str().to_string())
}
pub fn encode_private_key_der(&self) -> Result<Vec<u8>> {
let doc = (match &self {
#[cfg(feature = "rsa")]
KeyPair::Rsa { private, .. } => private.to_pkcs8_der(),
#[cfg(feature = "p256")]
KeyPair::EcdsaP256 { signing_key, .. } => EncodePrivateKey::to_pkcs8_der(signing_key),
#[cfg(feature = "p384")]
KeyPair::EcdsaP384 { signing_key, .. } => EncodePrivateKey::to_pkcs8_der(signing_key),
#[cfg(feature = "p521")]
KeyPair::EcdsaP521 { secret_key, .. } => EncodePrivateKey::to_pkcs8_der(secret_key),
#[cfg(feature = "ed25519")]
KeyPair::Ed25519 { signing_key, .. } => EncodePrivateKey::to_pkcs8_der(signing_key),
})
.map_err(|e| e.to_string())
.map_err(CertKitError::EncodingError)?;
Ok(doc.as_bytes().to_vec())
}
pub fn key_type(&self) -> KeyType {
match self {
#[cfg(feature = "rsa")]
KeyPair::Rsa { .. } => KeyType::Rsa,
#[cfg(feature = "p256")]
KeyPair::EcdsaP256 { .. } => KeyType::EcdsaP256,
#[cfg(feature = "p384")]
KeyPair::EcdsaP384 { .. } => KeyType::EcdsaP384,
#[cfg(feature = "p521")]
KeyPair::EcdsaP521 { .. } => KeyType::EcdsaP521,
#[cfg(feature = "ed25519")]
KeyPair::Ed25519 { .. } => KeyType::Ed25519,
}
}
pub fn import_from_der(der: &[u8]) -> Result<Self> {
log::trace!("importing key from {} bytes of DER", der.len());
#[cfg(feature = "rsa")]
if let Ok(private) = RsaPrivateKey::from_pkcs1_der(der) {
let public = RsaPublicKey::from(&private);
return Ok(KeyPair::Rsa {
private: Box::new(private),
public,
});
}
let private_key_info = PrivateKeyInfo::try_from(der).map_err(|_| {
CertKitError::DecodingError("Unsupported or invalid key DER encoding".to_string())
})?;
#[cfg(feature = "rsa")]
if let Ok(private) = RsaPrivateKey::try_from(private_key_info.clone()) {
let public = RsaPublicKey::from(&private);
return Ok(KeyPair::Rsa {
private: Box::new(private),
public,
});
}
#[cfg(feature = "p256")]
if let Ok(signing_key) = P256SigningKey::try_from(private_key_info.clone()) {
let verifying_key = signing_key.verifying_key().to_owned();
return Ok(KeyPair::EcdsaP256 {
signing_key,
verifying_key,
});
}
#[cfg(feature = "p384")]
if let Ok(signing_key) = P384SigningKey::try_from(private_key_info.clone()) {
let verifying_key = signing_key.verifying_key().to_owned();
return Ok(KeyPair::EcdsaP384 {
signing_key,
verifying_key,
});
}
#[cfg(feature = "p521")]
if let Ok(secret_key) = p521::SecretKey::try_from(private_key_info.clone()) {
let public_key = secret_key.public_key();
return Ok(KeyPair::EcdsaP521 {
secret_key,
public_key,
});
}
#[cfg(feature = "ed25519")]
if let Ok(signing_key) = Ed25519SigningKey::try_from(private_key_info.clone()) {
return Ok(KeyPair::Ed25519 { signing_key });
}
Err(CertKitError::DecodingError(
"Unsupported or invalid key DER encoding".to_string(),
))
}
pub fn import_from_pkcs8_pem(pem_str: &str) -> Result<Self> {
log::trace!("importing key from PKCS#8 PEM");
let pemd = pem::parse(pem_str)
.map_err(|_| CertKitError::DecodingError("Failed to parse PEM".to_string()))?;
if pemd.tag() == "PRIVATE KEY" {
Self::import_from_der(pemd.contents())
} else {
Err(CertKitError::InvalidInput(format!(
"Unsupported PEM tag: {}",
pemd.tag()
)))
}
}
pub fn as_spki(&self) -> x509_cert::spki::SubjectPublicKeyInfoOwned {
match self {
#[cfg(feature = "rsa")]
KeyPair::Rsa { public, .. } => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(public.clone())
.expect("valid RSA key always encodes to SPKI")
}
#[cfg(feature = "p256")]
KeyPair::EcdsaP256 { verifying_key, .. } => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(*verifying_key)
.expect("valid P-256 key always encodes to SPKI")
}
#[cfg(feature = "p384")]
KeyPair::EcdsaP384 { verifying_key, .. } => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(*verifying_key)
.expect("valid P-384 key always encodes to SPKI")
}
#[cfg(feature = "p521")]
KeyPair::EcdsaP521 { public_key, .. } => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(*public_key)
.expect("valid P-521 key always encodes to SPKI")
}
#[cfg(feature = "ed25519")]
KeyPair::Ed25519 { signing_key } => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(signing_key.verifying_key())
.expect("valid Ed25519 key always encodes to SPKI")
}
}
}
pub fn sign_data(&self, data: &[u8]) -> Result<Vec<u8>> {
log::trace!("signing {} bytes of data", data.len());
match self {
#[cfg(feature = "rsa")]
KeyPair::Rsa { private, .. } => {
let signing_key: RsaSigningKey<Sha256> = RsaSigningKey::new(*(private.clone()));
let signature = signing_key.sign(data);
Ok(signature.to_vec())
}
#[cfg(feature = "p256")]
KeyPair::EcdsaP256 { signing_key, .. } => {
let signature: p256::ecdsa::Signature =
p256::ecdsa::signature::Signer::sign(signing_key, data);
Ok(signature.to_der().as_bytes().to_vec())
}
#[cfg(feature = "p384")]
KeyPair::EcdsaP384 { signing_key, .. } => {
let signature: p384::ecdsa::Signature =
p384::ecdsa::signature::Signer::sign(signing_key, data);
Ok(signature.to_der().as_bytes().to_vec())
}
#[cfg(feature = "p521")]
KeyPair::EcdsaP521 { secret_key, .. } => {
let signing_key = p521_signing_key(secret_key);
let signature: p521::ecdsa::Signature =
p521::ecdsa::signature::Signer::sign(&signing_key, data);
Ok(signature.to_der().as_bytes().to_vec())
}
#[cfg(feature = "ed25519")]
KeyPair::Ed25519 { signing_key } => {
use ed25519_dalek::Signer;
let signature = signing_key.sign(data);
Ok(signature.to_bytes().to_vec())
}
}
}
}
impl fmt::Display for KeyPair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
#[cfg(feature = "rsa")]
Self::Rsa { public, .. } => write!(f, "RSA-{}", public.n().bits()),
#[cfg(feature = "p256")]
Self::EcdsaP256 { .. } => write!(f, "ECDSA P-256"),
#[cfg(feature = "p384")]
Self::EcdsaP384 { .. } => write!(f, "ECDSA P-384"),
#[cfg(feature = "p521")]
Self::EcdsaP521 { .. } => write!(f, "ECDSA P-521"),
#[cfg(feature = "ed25519")]
Self::Ed25519 { .. } => write!(f, "Ed25519"),
}
}
}
#[derive(Debug, Clone)]
pub enum PublicKey {
#[cfg(feature = "rsa")]
Rsa(RsaPublicKey),
#[cfg(feature = "p256")]
EcdsaP256(P256VerifyingKey),
#[cfg(feature = "p384")]
EcdsaP384(P384VerifyingKey),
#[cfg(feature = "p521")]
EcdsaP521(p521::PublicKey),
#[cfg(feature = "ed25519")]
Ed25519(Ed25519VerifyingKey),
}
impl PublicKey {
pub fn to_der(&self) -> Result<Vec<u8>> {
match self {
#[cfg(feature = "rsa")]
PublicKey::Rsa(public) => Ok(public.to_pkcs1_der()?.as_bytes().to_vec()),
#[cfg(feature = "p256")]
PublicKey::EcdsaP256(verifying_key) => Ok(verifying_key.to_sec1_bytes().to_vec()),
#[cfg(feature = "p384")]
PublicKey::EcdsaP384(verifying_key) => Ok(verifying_key.to_sec1_bytes().to_vec()),
#[cfg(feature = "p521")]
PublicKey::EcdsaP521(public_key) => Ok(public_key.to_sec1_bytes().to_vec()),
#[cfg(feature = "ed25519")]
PublicKey::Ed25519(verifying_key) => Ok(verifying_key.to_bytes().to_vec()),
}
}
pub fn as_spki(&self) -> x509_cert::spki::SubjectPublicKeyInfoOwned {
match self {
#[cfg(feature = "rsa")]
PublicKey::Rsa(public) => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(public.clone())
.expect("valid RSA key always encodes to SPKI")
}
#[cfg(feature = "p256")]
PublicKey::EcdsaP256(verifying_key) => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(*verifying_key)
.expect("valid P-256 key always encodes to SPKI")
}
#[cfg(feature = "p384")]
PublicKey::EcdsaP384(verifying_key) => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(*verifying_key)
.expect("valid P-384 key always encodes to SPKI")
}
#[cfg(feature = "p521")]
PublicKey::EcdsaP521(public_key) => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(*public_key)
.expect("valid P-521 key always encodes to SPKI")
}
#[cfg(feature = "ed25519")]
PublicKey::Ed25519(verifying_key) => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(*verifying_key)
.expect("valid Ed25519 key always encodes to SPKI")
}
}
}
#[cfg(feature = "rsa")]
pub fn from_rsa_pkcs1_der(der: &[u8]) -> Result<Self> {
let public = RsaPublicKey::from_pkcs1_der(der)?;
Ok(PublicKey::Rsa(public))
}
pub fn from_key_pair(key_pair: &KeyPair) -> Self {
match key_pair {
#[cfg(feature = "rsa")]
KeyPair::Rsa { public, .. } => PublicKey::Rsa(public.clone()),
#[cfg(feature = "p256")]
KeyPair::EcdsaP256 { verifying_key, .. } => PublicKey::EcdsaP256(*verifying_key),
#[cfg(feature = "p384")]
KeyPair::EcdsaP384 { verifying_key, .. } => PublicKey::EcdsaP384(*verifying_key),
#[cfg(feature = "p521")]
KeyPair::EcdsaP521 { public_key, .. } => PublicKey::EcdsaP521(*public_key),
#[cfg(feature = "ed25519")]
KeyPair::Ed25519 { signing_key, .. } => PublicKey::Ed25519(signing_key.verifying_key()),
}
}
pub fn from_x509spki(spki: &x509_cert::spki::SubjectPublicKeyInfoOwned) -> Result<Self> {
match spki.algorithm.oid {
#[cfg(feature = "rsa")]
const_oid::db::rfc5912::RSA_ENCRYPTION => {
let pk_bytes = spki.subject_public_key.as_bytes().ok_or_else(|| {
CertKitError::DecodingError("Invalid RSA public key bitstring".to_string())
})?;
let public_key = RsaPublicKey::from_pkcs1_der(pk_bytes)?;
Ok(PublicKey::Rsa(public_key))
}
#[cfg(any(feature = "p256", feature = "p384", feature = "p521"))]
const_oid::db::rfc5912::ID_EC_PUBLIC_KEY => {
use der::asn1::ObjectIdentifier;
let params = spki.algorithm.parameters.as_ref().ok_or_else(|| {
CertKitError::DecodingError("Missing EC parameters".to_string())
})?;
let params_oid: ObjectIdentifier = params.decode_as().map_err(|_| {
CertKitError::DecodingError("Invalid EC parameters OID".to_string())
})?;
let raw_bytes = spki.subject_public_key.as_bytes().ok_or_else(|| {
CertKitError::DecodingError("Invalid EC public key bitstring".to_string())
})?;
match params_oid {
#[cfg(feature = "p256")]
const_oid::db::rfc5912::SECP_256_R_1 => {
let verifying_key =
P256VerifyingKey::from_sec1_bytes(raw_bytes).map_err(|_| {
CertKitError::DecodingError(
"Invalid P-256 public key bytes".to_string(),
)
})?;
Ok(PublicKey::EcdsaP256(verifying_key))
}
#[cfg(feature = "p384")]
const_oid::db::rfc5912::SECP_384_R_1 => {
let verifying_key =
P384VerifyingKey::from_sec1_bytes(raw_bytes).map_err(|_| {
CertKitError::DecodingError(
"Invalid P-384 public key bytes".to_string(),
)
})?;
Ok(PublicKey::EcdsaP384(verifying_key))
}
#[cfg(feature = "p521")]
const_oid::db::rfc5912::SECP_521_R_1 => {
let public_key =
p521::PublicKey::from_sec1_bytes(raw_bytes).map_err(|_| {
CertKitError::DecodingError(
"Invalid P-521 public key bytes".to_string(),
)
})?;
Ok(PublicKey::EcdsaP521(public_key))
}
_ => Err(CertKitError::DecodingError(format!(
"Unsupported EC curve OID: {params_oid}"
))),
}
}
#[cfg(feature = "ed25519")]
const_oid::db::rfc8410::ID_ED_25519 => {
let bytes = spki.subject_public_key.as_bytes().ok_or_else(|| {
CertKitError::DecodingError("Invalid Ed25519 public key bitstring".to_string())
})?;
let bytes_array: &[u8; 32] = bytes.try_into().map_err(|_| {
CertKitError::DecodingError("Invalid Ed25519 public key length".to_string())
})?;
let verifying_key = Ed25519VerifyingKey::from_bytes(bytes_array).map_err(|_| {
CertKitError::DecodingError("Invalid Ed25519 public key bytes".to_string())
})?;
Ok(PublicKey::Ed25519(verifying_key))
}
_ => Err(CertKitError::DecodingError(format!(
"Unsupported algorithm: {}",
spki.algorithm.oid
))),
}
}
pub fn key_type(&self) -> KeyType {
match self {
#[cfg(feature = "rsa")]
PublicKey::Rsa(_) => KeyType::Rsa,
#[cfg(feature = "p256")]
PublicKey::EcdsaP256(_) => KeyType::EcdsaP256,
#[cfg(feature = "p384")]
PublicKey::EcdsaP384(_) => KeyType::EcdsaP384,
#[cfg(feature = "p521")]
PublicKey::EcdsaP521(_) => KeyType::EcdsaP521,
#[cfg(feature = "ed25519")]
PublicKey::Ed25519(_) => KeyType::Ed25519,
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
#[cfg(feature = "rsa")]
fn pem_encode_decode_rsa() {
crate::init_test_logger();
let rsa = KeyPair::generate_rsa(2048).unwrap();
let rsa_der = rsa::pkcs8::EncodePrivateKey::to_pkcs8_der(match &rsa {
KeyPair::Rsa { private, .. } => &**private,
_ => unreachable!(),
})
.unwrap();
let rsa_pem = pem::encode(&pem::Pem::new("PRIVATE KEY", rsa_der.as_bytes()));
let rsa_decoded = KeyPair::import_from_pkcs8_pem(&rsa_pem);
assert!(rsa_decoded.is_ok(), "RSA PEM decode should succeed");
}
#[test]
#[cfg(feature = "p256")]
fn pem_encode_decode_ecdsa_p256() {
crate::init_test_logger();
let p256 = KeyPair::generate_ecdsa_p256();
let p256_der = p256::pkcs8::EncodePrivateKey::to_pkcs8_der(match &p256 {
KeyPair::EcdsaP256 { signing_key, .. } => signing_key,
_ => unreachable!(),
})
.unwrap();
let p256_pem = pem::encode(&pem::Pem::new("PRIVATE KEY", p256_der.as_bytes()));
let p256_decoded = KeyPair::import_from_pkcs8_pem(&p256_pem);
assert!(p256_decoded.is_ok(), "P-256 PEM decode should succeed");
}
#[test]
#[cfg(feature = "p384")]
fn pem_encode_decode_ecdsa_p384() {
crate::init_test_logger();
let p384 = KeyPair::generate_ecdsa_p384();
let p384_der = p384::pkcs8::EncodePrivateKey::to_pkcs8_der(match &p384 {
KeyPair::EcdsaP384 { signing_key, .. } => signing_key,
_ => unreachable!(),
})
.unwrap();
let p384_pem = pem::encode(&pem::Pem::new("PRIVATE KEY", p384_der.as_bytes()));
let p384_decoded = KeyPair::import_from_pkcs8_pem(&p384_pem);
assert!(p384_decoded.is_ok(), "P-384 PEM decode should succeed");
}
#[test]
#[cfg(feature = "p521")]
fn pem_encode_decode_ecdsa_p521() {
crate::init_test_logger();
let p521 = KeyPair::generate_ecdsa_p521();
let p521_der = p521::pkcs8::EncodePrivateKey::to_pkcs8_der(match &p521 {
KeyPair::EcdsaP521 { secret_key, .. } => secret_key,
_ => unreachable!(),
})
.unwrap();
let p521_pem = pem::encode(&pem::Pem::new("PRIVATE KEY", p521_der.as_bytes()));
let p521_decoded = KeyPair::import_from_pkcs8_pem(&p521_pem);
assert!(p521_decoded.is_ok(), "P-521 PEM decode should succeed");
}
#[test]
#[cfg(feature = "ed25519")]
fn pem_encode_decode_ed25519() {
crate::init_test_logger();
let ed = KeyPair::generate_ed25519();
let ed_der = ed25519_dalek::pkcs8::EncodePrivateKey::to_pkcs8_der(match &ed {
KeyPair::Ed25519 { signing_key } => signing_key,
_ => unreachable!(),
})
.unwrap();
let ed_pem = pem::encode(&pem::Pem::new("PRIVATE KEY", ed_der.as_bytes()));
let ed_decoded = KeyPair::import_from_pkcs8_pem(&ed_pem);
assert!(ed_decoded.is_ok(), "Ed25519 PEM decode should succeed");
}
#[test]
#[cfg(feature = "p256")]
fn ecdsa_p256_sign_data_is_der_and_verifies() {
use p256::ecdsa::signature::Verifier;
crate::init_test_logger();
let key = KeyPair::generate_ecdsa_p256();
let msg = b"certkit ecdsa signature payload";
let sig_bytes = key.sign_data(msg).unwrap();
let sig = p256::ecdsa::Signature::from_der(&sig_bytes)
.expect("ECDSA P-256 signature must be DER-encoded");
let vk = p256::ecdsa::VerifyingKey::from_sec1_bytes(&key.get_public_key_der()).unwrap();
vk.verify(msg, &sig).expect("signature must verify");
}
#[test]
#[cfg(feature = "p384")]
fn ecdsa_p384_sign_data_is_der_and_verifies() {
use p384::ecdsa::signature::Verifier;
crate::init_test_logger();
let key = KeyPair::generate_ecdsa_p384();
let msg = b"certkit ecdsa signature payload";
let sig_bytes = key.sign_data(msg).unwrap();
let sig = p384::ecdsa::Signature::from_der(&sig_bytes)
.expect("ECDSA P-384 signature must be DER-encoded");
let vk = p384::ecdsa::VerifyingKey::from_sec1_bytes(&key.get_public_key_der()).unwrap();
vk.verify(msg, &sig).expect("signature must verify");
}
#[test]
#[cfg(feature = "p521")]
fn ecdsa_p521_sign_data_is_der_and_verifies() {
use p521::ecdsa::signature::Verifier;
crate::init_test_logger();
let key = KeyPair::generate_ecdsa_p521();
let msg = b"certkit ecdsa signature payload";
let sig_bytes = key.sign_data(msg).unwrap();
let sig = p521::ecdsa::Signature::from_der(&sig_bytes)
.expect("ECDSA P-521 signature must be DER-encoded");
let vk = p521::ecdsa::VerifyingKey::from_sec1_bytes(&key.get_public_key_der()).unwrap();
vk.verify(msg, &sig).expect("signature must verify");
}
}