use std::fs::{self, File}; use std::io::{BufWriter, Write}; use std::path::PathBuf; use std::{io, path::Path}; use openssl::bn::BigNumContext; use openssl::hash::MessageDigest; use openssl::x509::{X509NameBuilder, X509}; use openssl::{ asn1::{Asn1Integer, Asn1Time}, bn::BigNum, pkey::PKey, rsa::Rsa, x509::X509Builder, }; mod root_certificate; /// 生成证书,公钥保存为.pem文件,私钥保存为.key文件 /// /// - `storage_path`:证书存储路径 /// - `certificate_name`:证书名称 /// - `key_length`:密钥长度 /// - `available_days`:证书有效天数 /// - `version`:证书版本 /// - `serial_number`:证书序列号,如果不设定则默认为1 pub fn generate_certificate( storage_path: &str, certificate_name: &str, key_length: u32, available_days: u32, version: i32, serial_number: Option, ) -> anyhow::Result<()> { let rsa = Rsa::generate(key_length)?; let private_key = rsa.private_key_to_pem()?; let pkey = PKey::from_rsa(rsa)?; let mut builder = X509Builder::new()?; builder.set_pubkey(&pkey)?; let mut x509_name = X509NameBuilder::new()?; x509_name.append_entry_by_text("CN", certificate_name)?; x509_name.append_entry_by_text("C", "CN")?; x509_name.append_entry_by_text("ST", "Hebei")?; x509_name.append_entry_by_text("L", "Shi Jiazhuang")?; x509_name.append_entry_by_text("O", "archgrid.xyz")?; let x509_name = x509_name.build(); builder.set_subject_name(&x509_name)?; builder.set_issuer_name(&x509_name)?; builder.set_version(version)?; let not_before = Asn1Time::days_from_now(0)?; let not_after = Asn1Time::days_from_now(available_days)?; builder.set_not_before(¬_before)?; builder.set_not_after(¬_after)?; let serial_number = BigNum::from_u32(serial_number.unwrap_or(1))?; let sn = Asn1Integer::from_bn(&serial_number)?; builder.set_serial_number(&sn)?; builder.sign(&pkey, MessageDigest::sha256())?; let certificate = builder.build(); let store_path = PathBuf::from(storage_path); ensure_path_exists(&store_path).unwrap(); let cert_path = store_path.clone().join(format!("{}.pem", certificate_name)); let cert_file = File::create(cert_path)?; let mut writer = BufWriter::new(cert_file); let cert_data = certificate.to_pem()?; writer.write_all(&cert_data)?; writer.flush()?; let private_key_path = store_path.join(format!("{}.key", certificate_name)); let private_key_file = File::create(private_key_path)?; let mut writer = BufWriter::new(private_key_file); writer.write_all(&private_key)?; writer.flush()?; Ok(()) } /// 确保指定路径存在,如果不存在则创建 /// /// - `target_path`:目标路径 fn ensure_path_exists>(target_path: P) -> Result<(), io::Error> { let path = target_path.as_ref(); if !path.exists() { fs::create_dir_all(path)?; } Ok(()) } /// 计算用于net-filter中power插件中Equal所使用的值。 /// /// - `cert`:用于生成EQUAL值的X509证书 pub fn calculate_power_euqal_result(cert: X509) -> anyhow::Result { let x = BigNum::from_slice(cert.signature().as_slice())?; let y = BigNum::from_u32(65537)?; let root_cert_pub_key = root_certificate::x509_certificate()?.public_key()?.rsa()?; let z = root_cert_pub_key.n(); let cert_pub_key = cert.public_key()?.rsa()?; let n = cert_pub_key.n(); let mut ctx = BigNumContext::new()?; let mut result = BigNum::new()?; result.mod_exp(&x, &y, &n, &mut ctx)?; Ok(format!( "EQUAL,{},{},{}->{}", x.to_dec_str()?, y.to_dec_str()?, z.to_dec_str()?, result.to_dec_str()? )) } /// 从.pem文件中读取X509证书 /// /// - `file_path`:证书文件路径 pub fn load_certificate>(file_path: P) -> anyhow::Result { let file_path = file_path.as_ref(); let cert_pem = fs::read(file_path)?; let cert = X509::from_pem(&cert_pem)?; Ok(cert) } /// 从.key文件中读取RSA私钥 /// /// - `file_path`:私钥文件路径 pub fn load_private_key>( file_path: R, ) -> anyhow::Result> { let file_path = file_path.as_ref(); let key_pem = fs::read(file_path)?; let key = PKey::private_key_from_pem(&key_pem)?; Ok(key) }