-use std::collections::HashMap;
-
-use anyhow::{bail, format_err, Error};
-use openssl::hash::MessageDigest;
-use openssl::nid::Nid;
-use openssl::pkey::PKey;
-use openssl::rsa::Rsa;
-use openssl::x509::{X509Extension, X509Name, X509Req};
-use serde_bytes::ByteBuf;
-
#[perlmod::package(name = "PMG::RS::CSR", lib = "pmg_rs")]
pub mod export {
use std::collections::HashMap;
use anyhow::Error;
use serde_bytes::ByteBuf;
+ use proxmox_acme_rs::util::Csr;
+
/// Generates a CSR and its accompanying private key.
///
/// The CSR is DER formatted, the private key is a PEM formatted pkcs8 private key.
identifiers: Vec<&str>,
attributes: HashMap<String, &str>,
) -> Result<(ByteBuf, ByteBuf), Error> {
- super::generate_csr(identifiers, attributes)
- }
-}
-
-fn generate_csr(
- identifiers: Vec<&str>,
- attributes: HashMap<String, &str>,
-) -> Result<(ByteBuf, ByteBuf), Error> {
- if identifiers.is_empty() {
- bail!("cannot generate empty CSR");
+ let csr = Csr::generate(&identifiers, &attributes)?;
+ Ok((
+ ByteBuf::from(csr.data),
+ ByteBuf::from(csr.private_key_pem),
+ ))
}
-
- let private_key = Rsa::generate(4096)
- .and_then(PKey::from_rsa)
- .map_err(|err| format_err!("failed to generate RSA key: {}", err))?;
-
- let private_key_pem = private_key
- .private_key_to_pem_pkcs8()
- .map_err(|err| format_err!("failed to format private key as PEM pkcs8: {}", err))?;
-
- let mut name = X509Name::builder()?;
- if !attributes.contains_key("CN") {
- name.append_entry_by_nid(Nid::COMMONNAME, identifiers[0])?;
- }
- for (key, value) in attributes {
- name.append_entry_by_text(&key, &value)?;
- }
- let name = name.build();
-
- let mut csr = X509Req::builder()?;
- csr.set_subject_name(&name)?;
- csr.set_pubkey(&private_key)?;
-
- let context = csr.x509v3_context(None);
- let mut ext = openssl::stack::Stack::new()?;
- ext.push(X509Extension::new_nid(
- None,
- None,
- Nid::BASIC_CONSTRAINTS,
- "CA:FALSE",
- )?)?;
- ext.push(X509Extension::new_nid(
- None,
- None,
- Nid::KEY_USAGE,
- "digitalSignature,keyEncipherment",
- )?)?;
- ext.push(X509Extension::new_nid(
- None,
- None,
- Nid::EXT_KEY_USAGE,
- "serverAuth,clientAuth",
- )?)?;
- ext.push(X509Extension::new_nid(
- None,
- Some(&context),
- Nid::SUBJECT_ALT_NAME,
- &identifiers
- .into_iter()
- .try_fold(String::new(), |mut acc, dns| {
- if !acc.is_empty() {
- acc.push(',');
- }
- use std::fmt::Write;
- write!(acc, "DNS:{}", dns)?;
- Ok::<_, std::fmt::Error>(acc)
- })?,
- )?)?;
- csr.add_extensions(&ext)?;
-
- csr.sign(&private_key, MessageDigest::sha256())?;
-
- Ok((
- ByteBuf::from(csr.build().to_der()?),
- ByteBuf::from(private_key_pem),
- ))
}