diff --git a/Cargo.lock b/Cargo.lock index a167b6a..c9641b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,6 +109,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + [[package]] name = "cc" version = "1.2.61" @@ -217,6 +223,21 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "getrandom" version = "0.2.17" @@ -252,6 +273,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", + "openssl", "pem", "rcgen", "time", @@ -334,12 +356,56 @@ dependencies = [ "asn1-rs", ] +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + [[package]] name = "once_cell_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "openssl" +version = "0.10.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38c4372413cdaaf3cc79dd92d29d7d9f5ab09b51b10dded508fb90bb70b9222" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-sys" +version = "0.9.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "pem" version = "3.0.6" @@ -350,6 +416,12 @@ dependencies = [ "serde_core", ] +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + [[package]] name = "powerfmt" version = "0.2.0" @@ -543,6 +615,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 73cb2e6..26ffada 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,4 @@ clap = { version = "4.5.53", features = ["derive"] } pem = "3.0.6" rcgen = { version = "0.14.6", features = ["x509-parser"] } time = "0.3.44" +openssl = { version = "0.10.78" } diff --git a/src/bin/j7s_mk_p12.rs b/src/bin/j7s_mk_p12.rs new file mode 100644 index 0000000..55fb369 --- /dev/null +++ b/src/bin/j7s_mk_p12.rs @@ -0,0 +1,60 @@ +/* +Copyright James Pace 2026 + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ +use anyhow::Result; +use clap::Parser; +use std::fs; +use std::path::PathBuf; + +use openssl::pkcs12::Pkcs12; +use openssl::pkey::PKey; +use openssl::x509::X509; + +/// Generate a .p12 file from a generated cert + key. +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + /// Path to folder with key and cert. .p12 will be saved there once generated. + #[arg(long)] + in_path: String, + /// Password for the p12. + #[arg(long)] + password: String, + /// "Friendly name" in p12 nomenclature for what we're generating. + /// Will also be used as the file name. + #[arg(long, default_value = "j7s_cert_pair")] + friendly_name: String, +} + +fn main() -> Result<()> { + let args = Args::parse(); + + // Get the key pair and cert. + let key_file = PathBuf::from(format!("{}/key.pem", &args.in_path)); + let cert_file = PathBuf::from(format!("{}/cert.pem", &args.in_path)); + + let key_pem = fs::read(&key_file)?; + let cert_pem = fs::read(&cert_file)?; + + let key = PKey::private_key_from_pem(&key_pem)?; + let cert = X509::from_pem(&cert_pem)?; + + let p12 = Pkcs12::builder() + .name(&args.friendly_name) + .pkey(&key) + .cert(&cert) + .build2(&args.password)?; + let p12_as_der = p12.to_der()?; + + println!("Saving artifacts."); + fs::write( + format!("{}/{}.p12", &args.in_path, &args.friendly_name), + &p12_as_der, + )?; + + Ok(()) +}