jetbrains-license-server/cert_lib/src/lib.rs

139 lines
4.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<u32>,
) -> 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(&not_before)?;
builder.set_not_after(&not_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<P: AsRef<Path>>(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<String> {
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<P: AsRef<Path>>(file_path: P) -> anyhow::Result<X509> {
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<R: AsRef<Path>>(
file_path: R,
) -> anyhow::Result<PKey<openssl::pkey::Private>> {
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)
}