fix(native-certgen): address Phase 0-1 validation findings

EC keygen now returns proper SPKI DER instead of raw point bytes.
RSA keygen uses caller-supplied exponent via new_with_exp() and
validates key size to 2048/3072/4096. Keybox parser extracts leaf
subject DN (not issuer). Added AttestKey=7 to KeyPurpose. Realigned
error variants with spec.
This commit is contained in:
Enginex0
2026-03-09 15:21:33 +01:00
parent f840eed42b
commit 7863e8dd17
5 changed files with 110 additions and 31 deletions
+85 -6
View File
@@ -1,13 +1,18 @@
use crate::error::{CertGenError, Result};
use crate::types::{Algorithm, EcCurve, GeneratedKeyPair};
pub fn generate_key_pair(algorithm: Algorithm, key_size: u32, ec_curve: Option<EcCurve>) -> Result<GeneratedKeyPair> {
pub fn generate_key_pair(
algorithm: Algorithm,
key_size: u32,
ec_curve: Option<EcCurve>,
rsa_public_exponent: u64,
) -> Result<GeneratedKeyPair> {
match algorithm {
Algorithm::Ec => {
let curve = ec_curve.ok_or_else(|| CertGenError::InvalidParameter("ec_curve required for EC".into()))?;
generate_ec_key_pair(curve)
}
Algorithm::Rsa => generate_rsa_key_pair(key_size),
Algorithm::Rsa => generate_rsa_key_pair(key_size, rsa_public_exponent),
}
}
@@ -17,25 +22,99 @@ fn generate_ec_key_pair(curve: EcCurve) -> Result<GeneratedKeyPair> {
let alg = match curve {
EcCurve::P256 => &ring::signature::ECDSA_P256_SHA256_ASN1_SIGNING,
EcCurve::P384 => &ring::signature::ECDSA_P384_SHA384_ASN1_SIGNING,
_ => return Err(CertGenError::UnsupportedCurve(curve as i32)),
_ => return Err(CertGenError::UnsupportedEcCurve(curve as i32)),
};
let rng = ring::rand::SystemRandom::new();
let pkcs8_doc = ring::signature::EcdsaKeyPair::generate_pkcs8(alg, &rng)?;
let key_pair = ring::signature::EcdsaKeyPair::from_pkcs8(alg, pkcs8_doc.as_ref(), &rng)?;
let raw_point = key_pair.public_key().as_ref();
let spki = build_ec_spki(curve, raw_point)?;
Ok(GeneratedKeyPair {
private_key_pkcs8: pkcs8_doc.as_ref().to_vec(),
public_key_spki: key_pair.public_key().as_ref().to_vec(),
public_key_spki: spki,
})
}
fn generate_rsa_key_pair(key_size: u32) -> Result<GeneratedKeyPair> {
/// Build SubjectPublicKeyInfo DER from a raw EC uncompressed point.
fn build_ec_spki(curve: EcCurve, raw_point: &[u8]) -> Result<Vec<u8>> {
// SPKI = SEQUENCE { AlgorithmIdentifier, BIT STRING(public key) }
// AlgorithmIdentifier = SEQUENCE { OID(ecPublicKey), OID(curve) }
//
// DER-encode manually — the prefix is fixed per curve, only the point varies.
// OID 1.2.840.10045.2.1 (id-ecPublicKey)
const EC_PUBLIC_KEY_OID: &[u8] = &[0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
let curve_oid: &[u8] = match curve {
// OID 1.2.840.10045.3.1.7 (prime256v1 / P-256)
EcCurve::P256 => &[0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07],
// OID 1.3.132.0.34 (secp384r1 / P-384)
EcCurve::P384 => &[0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22],
_ => return Err(CertGenError::UnsupportedEcCurve(curve as i32)),
};
let alg_id_seq = der_sequence(EC_PUBLIC_KEY_OID, curve_oid);
// BIT STRING: 0x03, length, 0x00 (unused bits), raw_point
let bit_string_content_len = 1 + raw_point.len(); // 0x00 byte + point
let mut bit_string = vec![0x03];
encode_der_length(&mut bit_string, bit_string_content_len);
bit_string.push(0x00); // zero unused bits
bit_string.extend_from_slice(raw_point);
// Outer SEQUENCE
let inner_len = alg_id_seq.len() + bit_string.len();
let mut spki = vec![0x30];
encode_der_length(&mut spki, inner_len);
spki.extend_from_slice(&alg_id_seq);
spki.extend_from_slice(&bit_string);
Ok(spki)
}
fn der_sequence(a: &[u8], b: &[u8]) -> Vec<u8> {
let content_len = a.len() + b.len();
let mut seq = vec![0x30];
encode_der_length(&mut seq, content_len);
seq.extend_from_slice(a);
seq.extend_from_slice(b);
seq
}
fn encode_der_length(buf: &mut Vec<u8>, len: usize) {
if len < 0x80 {
buf.push(len as u8);
} else if len < 0x100 {
buf.push(0x81);
buf.push(len as u8);
} else {
buf.push(0x82);
buf.push((len >> 8) as u8);
buf.push(len as u8);
}
}
fn generate_rsa_key_pair(key_size: u32, rsa_public_exponent: u64) -> Result<GeneratedKeyPair> {
use pkcs8::EncodePrivateKey;
use rsa::pkcs8::EncodePublicKey;
if !matches!(key_size, 2048 | 3072 | 4096) {
return Err(CertGenError::InvalidParameter(
format!("RSA key size must be 2048, 3072, or 4096; got {key_size}")
));
}
let exp = if rsa_public_exponent == 0 {
rsa::BigUint::from(65537u64)
} else {
rsa::BigUint::from(rsa_public_exponent)
};
let mut rng = rand::thread_rng();
let private_key = rsa::RsaPrivateKey::new(&mut rng, key_size as usize)
let private_key = rsa::RsaPrivateKey::new_with_exp(&mut rng, key_size as usize, &exp)
.map_err(|e| CertGenError::KeyGenFailed(e.to_string()))?;
let pkcs8_der = private_key.to_pkcs8_der()