diff --git a/plugins/grpc-plugin/src/tls.rs b/plugins/grpc-plugin/src/tls.rs index 7f2446b40..8bd198481 100644 --- a/plugins/grpc-plugin/src/tls.rs +++ b/plugins/grpc-plugin/src/tls.rs @@ -59,6 +59,8 @@ fn generate_or_load_identity( filename: &str, parent: Option<&Identity>, ) -> Result { + use std::io::Write; + use std::os::unix::fs::PermissionsExt; // Just our naming convention here. let cert_path = directory.join(format!("{}.pem", filename)); let key_path = directory.join(format!("{}-key.pem", filename)); @@ -70,7 +72,18 @@ fn generate_or_load_identity( &key_path ); let keypair = KeyPair::generate(&rcgen::PKCS_ECDSA_P256_SHA256)?; - std::fs::write(&key_path, keypair.serialize_pem())?; + + // Create the file, but make it user-readable only: + let mut file = std::fs::File::create(&key_path)?; + let mut perms = std::fs::metadata(&key_path)?.permissions(); + perms.set_mode(0o600); + std::fs::set_permissions(&key_path, perms)?; + + // Only after changing the permissions we can write the + // private key + file.write_all(keypair.serialize_pem().as_bytes())?; + drop(file); + debug!( "Generating a new certificate for key {:?} at {:?}", &key_path, &cert_path diff --git a/tests/test_cln_rs.py b/tests/test_cln_rs.py index 442c11657..d965d2cf4 100644 --- a/tests/test_cln_rs.py +++ b/tests/test_cln_rs.py @@ -181,6 +181,11 @@ def test_grpc_generate_certificate(node_factory): assert contents[-2] != files[-2].open().read() assert contents[-1] != files[-1].open().read() + keys = [f for f in files if f.name.endswith('-key.pem')] + modes = [f.stat().st_mode for f in keys] + private = [m % 8 == 0 and (m // 8) % 8 == 0 for m in modes] + assert all(private) + def test_grpc_no_auto_start(node_factory): """Ensure that we do not start cln-grpc unless a port is configured.