From d635f19dbfe15fe0e5d9c8aa8b8b7a8a2f08405d Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Sat, 23 Aug 2025 19:16:30 -0400 Subject: [PATCH] plugins: generate certificates with required extensions Recent versions of urllib3 fail certificate verification if certificates lack the Authority Key Identifier or Key Usages extensions: ``` SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Missing Authority Key Identifier (_ssl.c:1032) SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: CA cert does not include key usage extension (_ssl.c:1032) ``` Luckily, rcgen offers parameters in its CertificateParams structure to add these extensions. Let's use them. Changelog-Fixed: Certificates auto-generated by grpc-plugin, rest-plugin, and wss-proxy-plugin now include the required Authority Key Identifier and Key Usages extensions. --- plugins/grpc-plugin/src/tls.rs | 13 +++++++++---- plugins/rest-plugin/src/certs.rs | 6 ++++++ plugins/wss-proxy-plugin/src/certs.rs | 6 ++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/plugins/grpc-plugin/src/tls.rs b/plugins/grpc-plugin/src/tls.rs index 545c447b4..18f72e819 100644 --- a/plugins/grpc-plugin/src/tls.rs +++ b/plugins/grpc-plugin/src/tls.rs @@ -96,14 +96,19 @@ fn generate_or_load_identity( // Configure the certificate we want. let subject_alt_names = vec!["cln".to_string(), "localhost".to_string()]; let mut params = rcgen::CertificateParams::new(subject_alt_names)?; - params.is_ca = if parent.is_none() { - rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained) + if parent.is_none() { + params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained); + params.key_usages.push(rcgen::KeyUsagePurpose::KeyCertSign); } else { - rcgen::IsCa::NoCa - }; + params.is_ca = rcgen::IsCa::NoCa; + params.key_usages.push(rcgen::KeyUsagePurpose::DigitalSignature); + params.key_usages.push(rcgen::KeyUsagePurpose::KeyEncipherment); + params.key_usages.push(rcgen::KeyUsagePurpose::KeyAgreement); + } params .distinguished_name .push(rcgen::DnType::CommonName, name); + params.use_authority_key_identifier_extension = true; let cert = match parent { None => params.self_signed(&keypair), diff --git a/plugins/rest-plugin/src/certs.rs b/plugins/rest-plugin/src/certs.rs index d01c1e55a..e6ab61345 100644 --- a/plugins/rest-plugin/src/certs.rs +++ b/plugins/rest-plugin/src/certs.rs @@ -12,6 +12,8 @@ pub fn generate_certificates(certs_path: &PathBuf, rest_host: &str) -> Result<() "localhost".to_string(), ])?; ca_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained); + ca_params.key_usages.push(rcgen::KeyUsagePurpose::KeyCertSign); + ca_params.use_authority_key_identifier_extension = true; let ca_key = KeyPair::generate()?; let ca_cert = ca_params.self_signed(&ca_key)?; @@ -30,6 +32,10 @@ pub fn generate_certificates(certs_path: &PathBuf, rest_host: &str) -> Result<() "localhost".to_string(), ])?; server_params.is_ca = rcgen::IsCa::NoCa; + server_params.key_usages.push(rcgen::KeyUsagePurpose::DigitalSignature); + server_params.key_usages.push(rcgen::KeyUsagePurpose::KeyEncipherment); + server_params.key_usages.push(rcgen::KeyUsagePurpose::KeyAgreement); + server_params.use_authority_key_identifier_extension = true; server_params.distinguished_name = DistinguishedName::new(); server_params .distinguished_name diff --git a/plugins/wss-proxy-plugin/src/certs.rs b/plugins/wss-proxy-plugin/src/certs.rs index 2e56b26dd..b08b7d3e7 100644 --- a/plugins/wss-proxy-plugin/src/certs.rs +++ b/plugins/wss-proxy-plugin/src/certs.rs @@ -18,6 +18,8 @@ pub fn generate_certificates(certs_path: &PathBuf, wss_host: &[String]) -> Resul "localhost".to_string(), ])?; ca_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained); + ca_params.key_usages.push(rcgen::KeyUsagePurpose::KeyCertSign); + ca_params.use_authority_key_identifier_extension = true; let ca_key = KeyPair::generate()?; let ca_cert = ca_params.self_signed(&ca_key)?; @@ -36,6 +38,10 @@ pub fn generate_certificates(certs_path: &PathBuf, wss_host: &[String]) -> Resul "localhost".to_string(), ])?; server_params.is_ca = rcgen::IsCa::NoCa; + server_params.key_usages.push(rcgen::KeyUsagePurpose::DigitalSignature); + server_params.key_usages.push(rcgen::KeyUsagePurpose::KeyEncipherment); + server_params.key_usages.push(rcgen::KeyUsagePurpose::KeyAgreement); + server_params.use_authority_key_identifier_extension = true; server_params.distinguished_name = DistinguishedName::new(); server_params .distinguished_name