implement gemini certificate generation helper

This commit is contained in:
yggverse 2024-11-19 16:32:39 +02:00
parent 728a9c06d5
commit 82f5cdc5b4
2 changed files with 64 additions and 0 deletions

View File

@ -32,6 +32,9 @@ features = ["gnome_47"]
package = "rusqlite"
version = "0.32.1"
[dependencies.openssl]
version = "0.10.68"
[patch.crates-io]
#ggemini = { path = "ggemini" }
#ggemtext = { path = "ggemtext" }

View File

@ -0,0 +1,61 @@
use gtk::glib::DateTime;
use openssl::{
asn1::{Asn1Integer, Asn1Time},
bn::{BigNum, MsbOption},
hash::MessageDigest,
pkey::PKey,
rsa::Rsa,
x509::{X509Builder, X509Name},
};
use std::error::Error;
// Defaults
pub const VERSION: i32 = 0; // 1 https://docs.openssl.org/master/man3/X509_get_version
pub const BITS: u32 = 2048;
/// Generate new Gemini certificate
/// * return PEM string as `Result`
pub fn generate(
time: (DateTime, DateTime), // valid (from, to)
name: &str,
) -> Result<String, Box<dyn Error>> {
// Generate new RSA key pair
let rsa = Rsa::generate(BITS)?;
let key = PKey::from_rsa(rsa)?;
// Init X509 name
let mut name_builder = X509Name::builder()?;
name_builder.append_entry_by_text("CN", name)?;
let name = name_builder.build();
// Init serial number
let mut number = BigNum::new()?;
number.rand(128, MsbOption::MAYBE_ZERO, true)?;
let serial = Asn1Integer::from_bn(&number)?;
// Init validity period
let not_before = Asn1Time::from_unix(time.0.to_unix())?;
let not_after = Asn1Time::from_unix(time.1.to_unix())?;
// Build
let mut builder = X509Builder::new()?;
builder.set_version(VERSION)?;
builder.set_serial_number(&serial)?;
builder.set_subject_name(&name)?;
builder.set_issuer_name(&name)?;
builder.set_not_before(&not_before)?;
builder.set_not_after(&not_after)?;
builder.set_pubkey(&key)?;
builder.sign(&key, MessageDigest::sha256())?;
let certificate = builder.build();
// Result
Ok(format!(
"{}{}",
String::from_utf8(certificate.to_pem()?)?,
String::from_utf8(key.private_key_to_pem_pkcs8()?)?,
))
}