forked from Proxmox/proxmox
acme-api: implement funtion to create self signed certificates
Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
This commit is contained in:
parent
f7a22604ae
commit
fcaa4f6758
@ -20,6 +20,8 @@ http = { workspace = true, optional = true }
|
|||||||
log = { workspace = true, optional = true }
|
log = { workspace = true, optional = true }
|
||||||
nix = { workspace = true, optional = true }
|
nix = { workspace = true, optional = true }
|
||||||
lazy_static = { workspace = true, optional = true }
|
lazy_static = { workspace = true, optional = true }
|
||||||
|
openssl = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
|
||||||
proxmox-serde.workspace = true
|
proxmox-serde.workspace = true
|
||||||
proxmox-section-config = { workspace = true, optional = true }
|
proxmox-section-config = { workspace = true, optional = true }
|
||||||
@ -27,6 +29,7 @@ proxmox-rest-server = { workspace = true, optional = true }
|
|||||||
proxmox-router = { workspace = true, optional = true }
|
proxmox-router = { workspace = true, optional = true }
|
||||||
proxmox-sys = { workspace = true, optional = true }
|
proxmox-sys = { workspace = true, optional = true }
|
||||||
proxmox-schema = { workspace = true, features = ["api-macro", "api-types"] }
|
proxmox-schema = { workspace = true, features = ["api-macro", "api-types"] }
|
||||||
|
proxmox-uuid = { workspace = true, optional = true }
|
||||||
proxmox-acme = { workspace = true, features = ["api-types"] }
|
proxmox-acme = { workspace = true, features = ["api-types"] }
|
||||||
proxmox-config-digest = { workspace = true, optional = true }
|
proxmox-config-digest = { workspace = true, optional = true }
|
||||||
proxmox-product-config = { workspace = true, optional = true }
|
proxmox-product-config = { workspace = true, optional = true }
|
||||||
@ -34,6 +37,7 @@ proxmox-product-config = { workspace = true, optional = true }
|
|||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
impl = [
|
impl = [
|
||||||
|
"dep:proxmox-uuid",
|
||||||
"dep:proxmox-config-digest",
|
"dep:proxmox-config-digest",
|
||||||
"proxmox-config-digest?/openssl",
|
"proxmox-config-digest?/openssl",
|
||||||
"dep:proxmox-product-config",
|
"dep:proxmox-product-config",
|
||||||
@ -51,4 +55,5 @@ impl = [
|
|||||||
"dep:proxmox-rest-server",
|
"dep:proxmox-rest-server",
|
||||||
"dep:proxmox-router",
|
"dep:proxmox-router",
|
||||||
"dep:base64",
|
"dep:base64",
|
||||||
|
"dep:openssl",
|
||||||
]
|
]
|
||||||
|
@ -2,6 +2,9 @@ use std::sync::Arc;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
|
use openssl::pkey::{PKey, Private};
|
||||||
|
use openssl::rsa::Rsa;
|
||||||
|
use openssl::x509::{X509Builder, X509};
|
||||||
|
|
||||||
use proxmox_acme::async_client::AcmeClient;
|
use proxmox_acme::async_client::AcmeClient;
|
||||||
use proxmox_rest_server::WorkerTask;
|
use proxmox_rest_server::WorkerTask;
|
||||||
@ -212,3 +215,90 @@ async fn request_validation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_self_signed_cert(
|
||||||
|
product_name: &str,
|
||||||
|
nodename: &str,
|
||||||
|
domain: Option<&str>,
|
||||||
|
) -> Result<(PKey<Private>, X509), Error> {
|
||||||
|
let rsa = Rsa::generate(4096).unwrap();
|
||||||
|
|
||||||
|
let mut x509 = X509Builder::new()?;
|
||||||
|
|
||||||
|
x509.set_version(2)?;
|
||||||
|
|
||||||
|
let today = openssl::asn1::Asn1Time::days_from_now(0)?;
|
||||||
|
x509.set_not_before(&today)?;
|
||||||
|
let expire = openssl::asn1::Asn1Time::days_from_now(365 * 1000)?;
|
||||||
|
x509.set_not_after(&expire)?;
|
||||||
|
|
||||||
|
let mut fqdn = nodename.to_owned();
|
||||||
|
|
||||||
|
if let Some(domain) = domain {
|
||||||
|
fqdn.push('.');
|
||||||
|
fqdn.push_str(domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we try to generate an unique 'subject' to avoid browser problems
|
||||||
|
//(reused serial numbers, ..)
|
||||||
|
let uuid = proxmox_uuid::Uuid::generate();
|
||||||
|
|
||||||
|
let mut subject_name = openssl::x509::X509NameBuilder::new()?;
|
||||||
|
subject_name.append_entry_by_text("O", product_name)?;
|
||||||
|
subject_name.append_entry_by_text("OU", &format!("{:X}", uuid))?;
|
||||||
|
subject_name.append_entry_by_text("CN", &fqdn)?;
|
||||||
|
let subject_name = subject_name.build();
|
||||||
|
|
||||||
|
x509.set_subject_name(&subject_name)?;
|
||||||
|
x509.set_issuer_name(&subject_name)?;
|
||||||
|
|
||||||
|
let bc = openssl::x509::extension::BasicConstraints::new(); // CA = false
|
||||||
|
let bc = bc.build()?;
|
||||||
|
x509.append_extension(bc)?;
|
||||||
|
|
||||||
|
let usage = openssl::x509::extension::ExtendedKeyUsage::new()
|
||||||
|
.server_auth()
|
||||||
|
.build()?;
|
||||||
|
x509.append_extension(usage)?;
|
||||||
|
|
||||||
|
let context = x509.x509v3_context(None, None);
|
||||||
|
|
||||||
|
let mut alt_names = openssl::x509::extension::SubjectAlternativeName::new();
|
||||||
|
|
||||||
|
alt_names.ip("127.0.0.1");
|
||||||
|
alt_names.ip("::1");
|
||||||
|
|
||||||
|
alt_names.dns("localhost");
|
||||||
|
|
||||||
|
if nodename != "localhost" {
|
||||||
|
alt_names.dns(nodename);
|
||||||
|
}
|
||||||
|
if nodename != fqdn {
|
||||||
|
alt_names.dns(&fqdn);
|
||||||
|
}
|
||||||
|
|
||||||
|
let alt_names = alt_names.build(&context)?;
|
||||||
|
|
||||||
|
x509.append_extension(alt_names)?;
|
||||||
|
|
||||||
|
let pub_pem = rsa.public_key_to_pem()?;
|
||||||
|
let pubkey = PKey::public_key_from_pem(&pub_pem)?;
|
||||||
|
|
||||||
|
x509.set_pubkey(&pubkey)?;
|
||||||
|
|
||||||
|
let context = x509.x509v3_context(None, None);
|
||||||
|
let ext = openssl::x509::extension::SubjectKeyIdentifier::new().build(&context)?;
|
||||||
|
x509.append_extension(ext)?;
|
||||||
|
|
||||||
|
let context = x509.x509v3_context(None, None);
|
||||||
|
let ext = openssl::x509::extension::AuthorityKeyIdentifier::new()
|
||||||
|
.keyid(true)
|
||||||
|
.build(&context)?;
|
||||||
|
x509.append_extension(ext)?;
|
||||||
|
|
||||||
|
let privkey = PKey::from_rsa(rsa)?;
|
||||||
|
|
||||||
|
x509.sign(&privkey, openssl::hash::MessageDigest::sha256())?;
|
||||||
|
|
||||||
|
Ok((privkey, x509.build()))
|
||||||
|
}
|
||||||
|
@ -43,4 +43,4 @@ pub(crate) mod acme_plugin;
|
|||||||
#[cfg(feature = "impl")]
|
#[cfg(feature = "impl")]
|
||||||
mod certificate_helpers;
|
mod certificate_helpers;
|
||||||
#[cfg(feature = "impl")]
|
#[cfg(feature = "impl")]
|
||||||
pub use certificate_helpers::{order_certificate, revoke_certificate};
|
pub use certificate_helpers::{create_self_signed_cert, order_certificate, revoke_certificate};
|
||||||
|
Loading…
Reference in New Issue
Block a user