use crate::{QsslError, QsslResult};
use pqcrypto_falcon::falcon512;
use pqcrypto_sphincsplus::sphincsharaka128fsimple as sphincs;
use pqcrypto_traits::sign::{PublicKey as _, SecretKey as _, DetachedSignature as _};
use serde::{Serialize, Deserialize};
use sha3::{Sha3_256, Digest};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QsslCertificate {
pub version: u8,
pub serial_number: Vec<u8>,
pub issuer: String,
pub subject: String,
pub not_before: u64, pub not_after: u64,
pub public_key: SubjectPublicKey,
pub extensions: Vec<Extension>,
pub signature_algorithm: SignatureAlgorithm,
pub signature: Vec<u8>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubjectPublicKey {
pub algorithm: PublicKeyAlgorithm,
pub falcon_key: Vec<u8>,
pub sphincs_key: Option<Vec<u8>>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum PublicKeyAlgorithm {
Falcon512,
SphincsPlus,
Hybrid, }
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum SignatureAlgorithm {
Falcon512,
SphincsPlus,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Extension {
pub oid: String,
pub critical: bool,
pub value: Vec<u8>,
}
pub struct CertificateBuilder {
cert: QsslCertificate,
}
impl CertificateBuilder {
pub fn new() -> Self {
use std::time::{SystemTime, UNIX_EPOCH};
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
Self {
cert: QsslCertificate {
version: 3, serial_number: Self::generate_serial(),
issuer: String::new(),
subject: String::new(),
not_before: now,
not_after: now + (365 * 24 * 60 * 60), public_key: SubjectPublicKey {
algorithm: PublicKeyAlgorithm::Falcon512,
falcon_key: Vec::new(),
sphincs_key: None,
},
extensions: Vec::new(),
signature_algorithm: SignatureAlgorithm::Falcon512,
signature: Vec::new(),
}
}
}
fn generate_serial() -> Vec<u8> {
let mut serial = vec![0u8; 16];
use rand::RngCore;
rand::thread_rng().fill_bytes(&mut serial);
serial
}
pub fn subject(mut self, subject: &str) -> Self {
self.cert.subject = subject.to_string();
self
}
pub fn issuer(mut self, issuer: &str) -> Self {
self.cert.issuer = issuer.to_string();
self
}
pub fn validity(mut self, not_before: u64, not_after: u64) -> Self {
self.cert.not_before = not_before;
self.cert.not_after = not_after;
self
}
pub fn falcon_public_key(mut self, key: &falcon512::PublicKey) -> Self {
self.cert.public_key.algorithm = PublicKeyAlgorithm::Falcon512;
self.cert.public_key.falcon_key = key.as_bytes().to_vec();
self
}
pub fn sphincs_public_key(mut self, key: &sphincs::PublicKey) -> Self {
self.cert.public_key.algorithm = PublicKeyAlgorithm::SphincsPlus;
self.cert.public_key.sphincs_key = Some(key.as_bytes().to_vec());
self
}
pub fn hybrid_public_key(mut self, falcon: &falcon512::PublicKey, sphincs: &sphincs::PublicKey) -> Self {
self.cert.public_key.algorithm = PublicKeyAlgorithm::Hybrid;
self.cert.public_key.falcon_key = falcon.as_bytes().to_vec();
self.cert.public_key.sphincs_key = Some(sphincs.as_bytes().to_vec());
self
}
pub fn signature_algorithm(mut self, algo: SignatureAlgorithm) -> Self {
self.cert.signature_algorithm = algo;
self
}
pub fn add_extension(mut self, oid: &str, critical: bool, value: Vec<u8>) -> Self {
self.cert.extensions.push(Extension {
oid: oid.to_string(),
critical,
value,
});
self
}
pub fn sign_and_build(mut self, signing_key: &SigningKey) -> QsslResult<QsslCertificate> {
let tbs = self.get_tbs_certificate()?;
let signature = match self.cert.signature_algorithm {
SignatureAlgorithm::Falcon512 => {
match signing_key {
SigningKey::Falcon(sk) => {
let sig = falcon512::detached_sign(&tbs, sk);
sig.as_bytes().to_vec()
}
_ => return Err(QsslError::Crypto("Signing key doesn't match algorithm".to_string())),
}
}
SignatureAlgorithm::SphincsPlus => {
match signing_key {
SigningKey::Sphincs(sk) => {
let sig = sphincs::detached_sign(&tbs, sk);
sig.as_bytes().to_vec()
}
_ => return Err(QsslError::Crypto("Signing key doesn't match algorithm".to_string())),
}
}
};
self.cert.signature = signature;
Ok(self.cert)
}
pub fn self_sign(mut self, falcon_sk: &falcon512::SecretKey, falcon_pk: &falcon512::PublicKey) -> QsslResult<QsslCertificate> {
let subject = self.cert.subject.clone();
self.cert.issuer = subject;
self.cert.public_key.algorithm = PublicKeyAlgorithm::Falcon512;
self.cert.public_key.falcon_key = falcon_pk.as_bytes().to_vec();
self.cert.signature_algorithm = SignatureAlgorithm::Falcon512;
self.sign_and_build(&SigningKey::Falcon(falcon_sk))
}
fn get_tbs_certificate(&self) -> QsslResult<Vec<u8>> {
let tbs = TbsCertificate {
version: self.cert.version,
serial_number: self.cert.serial_number.clone(),
issuer: self.cert.issuer.clone(),
subject: self.cert.subject.clone(),
not_before: self.cert.not_before,
not_after: self.cert.not_after,
public_key: self.cert.public_key.clone(),
extensions: self.cert.extensions.clone(),
signature_algorithm: self.cert.signature_algorithm,
};
bincode::serialize(&tbs)
.map_err(|e| QsslError::Crypto(format!("Failed to serialize TBS: {}", e)))
}
}
#[derive(Serialize, Deserialize)]
struct TbsCertificate {
version: u8,
serial_number: Vec<u8>,
issuer: String,
subject: String,
not_before: u64,
not_after: u64,
public_key: SubjectPublicKey,
extensions: Vec<Extension>,
signature_algorithm: SignatureAlgorithm,
}
pub enum SigningKey<'a> {
Falcon(&'a falcon512::SecretKey),
Sphincs(&'a sphincs::SecretKey),
}
impl QsslCertificate {
pub fn verify(&self, issuer_public_key: Option<&VerificationKey>) -> QsslResult<bool> {
let tbs = self.get_tbs()?;
let verify_key = if let Some(key) = issuer_public_key {
key
} else {
match self.public_key.algorithm {
PublicKeyAlgorithm::Falcon512 => {
let pk = falcon512::PublicKey::from_bytes(&self.public_key.falcon_key)
.map_err(|e| QsslError::Crypto(format!("Invalid Falcon key: {:?}", e)))?;
return self.verify_with_falcon(&tbs, &pk);
}
PublicKeyAlgorithm::SphincsPlus => {
if let Some(ref key_bytes) = self.public_key.sphincs_key {
let pk = sphincs::PublicKey::from_bytes(key_bytes)
.map_err(|e| QsslError::Crypto(format!("Invalid SPHINCS key: {:?}", e)))?;
return self.verify_with_sphincs(&tbs, &pk);
}
return Err(QsslError::Crypto("Missing SPHINCS+ key".to_string()));
}
_ => return Err(QsslError::Crypto("Unsupported self-signed algorithm".to_string())),
}
};
match (self.signature_algorithm, verify_key) {
(SignatureAlgorithm::Falcon512, VerificationKey::Falcon(pk)) => {
self.verify_with_falcon(&tbs, pk)
}
(SignatureAlgorithm::SphincsPlus, VerificationKey::Sphincs(pk)) => {
self.verify_with_sphincs(&tbs, pk)
}
_ => Err(QsslError::Crypto("Algorithm mismatch".to_string())),
}
}
fn verify_with_falcon(&self, tbs: &[u8], pk: &falcon512::PublicKey) -> QsslResult<bool> {
let sig = falcon512::DetachedSignature::from_bytes(&self.signature)
.map_err(|e| QsslError::Crypto(format!("Invalid signature: {:?}", e)))?;
Ok(falcon512::verify_detached_signature(&sig, tbs, pk).is_ok())
}
fn verify_with_sphincs(&self, tbs: &[u8], pk: &sphincs::PublicKey) -> QsslResult<bool> {
let sig = sphincs::DetachedSignature::from_bytes(&self.signature)
.map_err(|e| QsslError::Crypto(format!("Invalid signature: {:?}", e)))?;
Ok(sphincs::verify_detached_signature(&sig, tbs, pk).is_ok())
}
fn get_tbs(&self) -> QsslResult<Vec<u8>> {
let tbs = TbsCertificate {
version: self.version,
serial_number: self.serial_number.clone(),
issuer: self.issuer.clone(),
subject: self.subject.clone(),
not_before: self.not_before,
not_after: self.not_after,
public_key: self.public_key.clone(),
extensions: self.extensions.clone(),
signature_algorithm: self.signature_algorithm,
};
bincode::serialize(&tbs)
.map_err(|e| QsslError::Crypto(format!("Failed to serialize TBS: {}", e)))
}
pub fn is_valid_at(&self, timestamp: u64) -> bool {
timestamp >= self.not_before && timestamp <= self.not_after
}
pub fn fingerprint(&self) -> Vec<u8> {
let mut hasher = Sha3_256::new();
if let Ok(bytes) = bincode::serialize(self) {
hasher.update(bytes);
}
hasher.finalize().to_vec()
}
}
pub enum VerificationKey<'a> {
Falcon(&'a falcon512::PublicKey),
Sphincs(&'a sphincs::PublicKey),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_self_signed_certificate() {
let (pk, sk) = falcon512::keypair();
let cert = CertificateBuilder::new()
.subject("CN=localhost,O=QSSL Test,C=US")
.self_sign(&sk, &pk)
.unwrap();
assert!(cert.verify(None).unwrap());
assert_eq!(cert.subject, cert.issuer);
}
#[test]
fn test_certificate_chain() {
let (ca_pk, ca_sk) = falcon512::keypair();
let ca_cert = CertificateBuilder::new()
.subject("CN=QSSL CA,O=QSSL,C=US")
.self_sign(&ca_sk, &ca_pk)
.unwrap();
let (server_pk, _server_sk) = falcon512::keypair();
let server_cert = CertificateBuilder::new()
.subject("CN=server.example.com,O=Example,C=US")
.issuer("CN=QSSL CA,O=QSSL,C=US")
.falcon_public_key(&server_pk)
.sign_and_build(&SigningKey::Falcon(&ca_sk))
.unwrap();
assert!(server_cert.verify(Some(&VerificationKey::Falcon(&ca_pk))).unwrap());
}
}