-
Notifications
You must be signed in to change notification settings - Fork 22
feat(dgw): generate self-signed certificate when no TLS cert is configured for CredSSP #1682
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -12,6 +12,7 @@ use picky::pem::Pem; | |||||||||||||||||||
| use tap::prelude::*; | ||||||||||||||||||||
| use tokio::sync::Notify; | ||||||||||||||||||||
| use tokio_rustls::rustls::pki_types; | ||||||||||||||||||||
| use tracing::info; | ||||||||||||||||||||
| use url::Url; | ||||||||||||||||||||
| use uuid::Uuid; | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
|
@@ -95,7 +96,7 @@ pub struct Conf { | |||||||||||||||||||
| pub job_queue_database: Utf8PathBuf, | ||||||||||||||||||||
| pub traffic_audit_database: Utf8PathBuf, | ||||||||||||||||||||
| pub tls: Option<Tls>, | ||||||||||||||||||||
| pub credssp_tls: Option<Tls>, | ||||||||||||||||||||
| pub credssp_tls: Tls, | ||||||||||||||||||||
| pub provisioner_public_key: PublicKey, | ||||||||||||||||||||
| pub provisioner_private_key: Option<PrivateKey>, | ||||||||||||||||||||
| pub sub_provisioner_public_key: Option<Subkey>, | ||||||||||||||||||||
|
|
@@ -703,7 +704,6 @@ impl Conf { | |||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| let credssp_tls = match conf_file.credssp_certificate_file.as_ref() { | ||||||||||||||||||||
| None => None, | ||||||||||||||||||||
| Some(certificate_path) => { | ||||||||||||||||||||
| let (certificates, private_key) = match certificate_path.extension() { | ||||||||||||||||||||
| Some("pfx" | "p12") => { | ||||||||||||||||||||
|
|
@@ -730,13 +730,34 @@ impl Conf { | |||||||||||||||||||
| private_key, | ||||||||||||||||||||
| }; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| let credssp_tls = | ||||||||||||||||||||
| Tls::init(cert_source, strict_checks).context("failed to initialize CredSSP TLS configuration")?; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Some(credssp_tls) | ||||||||||||||||||||
| Tls::init(cert_source, strict_checks).context("failed to initialize CredSSP TLS configuration")? | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }; | ||||||||||||||||||||
| None => match tls.clone() { | ||||||||||||||||||||
| Some(tls) => tls, | ||||||||||||||||||||
| None => { | ||||||||||||||||||||
| // The self-signed certificate is intentionally not saved to disk. | ||||||||||||||||||||
| // Users who need a stable certificate should configure one explicitly. | ||||||||||||||||||||
| // When performing proxy-based credential injection, Devolutions Gateway | ||||||||||||||||||||
| // is trusted via the provisioner (e.g.: Devolutions Server), | ||||||||||||||||||||
| // and the client (e.g.: RDM) may automatically ignore the warnings. | ||||||||||||||||||||
| info!("No TLS certificate configured; generating a self-signed certificate for CredSSP"); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| let (certificates, private_key) = generate_self_signed_certificate(&hostname) | ||||||||||||||||||||
| .context("generate self-signed CredSSP certificate")?; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| let cert_source = crate::tls::CertificateSource::External { | ||||||||||||||||||||
| certificates, | ||||||||||||||||||||
| private_key, | ||||||||||||||||||||
| }; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Strict checks are not enforced for the auto-generated CredSSP | ||||||||||||||||||||
| // self-signed certificate specifically, as it is only used for | ||||||||||||||||||||
| // the CredSSP MITM with the client. | ||||||||||||||||||||
| Tls::init(cert_source, false) | ||||||||||||||||||||
| .context("failed to initialize self-signed CredSSP TLS configuration")? | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| }; | ||||||||||||||||||||
| let data_dir = get_data_dir(); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| let log_file = conf_file | ||||||||||||||||||||
|
|
@@ -1106,6 +1127,49 @@ fn default_hostname() -> Option<String> { | |||||||||||||||||||
| hostname::get().ok()?.into_string().ok() | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| fn generate_self_signed_certificate( | ||||||||||||||||||||
| hostname: &str, | ||||||||||||||||||||
| ) -> anyhow::Result<( | ||||||||||||||||||||
| Vec<pki_types::CertificateDer<'static>>, | ||||||||||||||||||||
| pki_types::PrivateKeyDer<'static>, | ||||||||||||||||||||
| )> { | ||||||||||||||||||||
| use picky::x509::certificate::CertificateBuilder; | ||||||||||||||||||||
| use picky::x509::date::UtcDate; | ||||||||||||||||||||
| use picky::x509::name::DirectoryName; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| let private_key = PrivateKey::generate_rsa(2048).context("generate RSA private key")?; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| let now = time::OffsetDateTime::now_utc(); | ||||||||||||||||||||
| let not_before = UtcDate::ymd( | ||||||||||||||||||||
| now.year().try_into().expect("valid year"), | ||||||||||||||||||||
| now.month().into(), | ||||||||||||||||||||
| now.day(), | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| .context("build not_before date")?; | ||||||||||||||||||||
| let not_after = UtcDate::ymd( | ||||||||||||||||||||
| (now.year() + 2).try_into().expect("valid year"), | ||||||||||||||||||||
CBenoit marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||
| now.month().into(), | ||||||||||||||||||||
| now.day(), | ||||||||||||||||||||
|
Comment on lines
+1149
to
+1152
|
||||||||||||||||||||
| let not_after = UtcDate::ymd( | |
| (now.year() + 2).try_into().expect("valid year"), | |
| now.month().into(), | |
| now.day(), | |
| let then = now + time::Duration::days(365_i64 * 2); | |
| let not_after = UtcDate::ymd( | |
| then.year().try_into().expect("valid year"), | |
| then.month().into(), | |
| then.day(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A self-signed RSA keypair/certificate is generated during config loading when no TLS cert is configured. Since
Confis constructed on every startup (even if CredSSP injection is never used), this adds avoidable startup CPU/entropy cost and could slow/block startup on low-entropy systems. Consider lazy/on-demand generation (only when credential injection is invoked).