keytool 0.1.0

A command-line tool for managing certificates, similar to Java keytool.
Documentation
use openssl::hash::MessageDigest;
use openssl::pkey::PKey;
use openssl::rsa::Rsa;
use openssl::x509::{X509Builder, X509NameBuilder, X509};

use crate::error::KeyToolError;

/// Generate a self-signed certificate + RSA private key,
/// similar to Java keytool default behavior.
pub fn generate_fake_cert(
    alias: &str,
) -> Result<(X509, PKey<openssl::pkey::Private>), KeyToolError> {
    // -------------------------------
    // 1) Generate RSA keypair (2048 bits)
    // -------------------------------
    let rsa = Rsa::generate(2048)?; // ErrorStack -> KeyToolError
    let pkey = PKey::from_rsa(rsa)?; // ErrorStack -> KeyToolError

    // -------------------------------
    // 2) Build X509 subject/issuer
    // -------------------------------
    let mut name = X509NameBuilder::new()?; // ErrorStack -> KeyToolError

    // Same format as Java keytool default:
    // CN=<alias>, O=Unknown, OU=Unknown
    name.append_entry_by_text("CN", alias)?;
    name.append_entry_by_text("O", "Unknown")?;
    name.append_entry_by_text("OU", "Unknown")?;

    let name = name.build();

    // -------------------------------
    // 3) Build X509 certificate
    // -------------------------------
    let mut builder = X509Builder::new()?; // ErrorStack -> KeyToolError

    builder.set_version(2)?; // X509 v3
    builder.set_subject_name(&name)?;
    builder.set_issuer_name(&name)?; // self-signed
    builder.set_pubkey(&pkey)?;

    // Set serial number
    {
        use openssl::bn::BigNum;
        let mut bn = BigNum::new()?;
        bn.rand(64, openssl::bn::MsbOption::MAYBE_ZERO, false)?;
        let serial = bn.to_asn1_integer()?;
        builder.set_serial_number(&serial)?;
    }

    // Valid from now → now + 365 days
    {
        use openssl::asn1::Asn1Time;

        let not_before = Asn1Time::days_from_now(0)?;
        let not_after = Asn1Time::days_from_now(365)?;

        builder.set_not_before(not_before.as_ref())?;
        builder.set_not_after(not_after.as_ref())?;
    }

    // Sign using SHA256
    builder.sign(&pkey, MessageDigest::sha256())?;

    let cert = builder.build();

    Ok((cert, pkey))
}