Skip to content

Commit 880cd3c

Browse files
authored
Merge pull request #183 from cipherstash/dont-log-pem-on-error
fix: ensure pem data is never logged
2 parents df1abc1 + 9c1bb5a commit 880cd3c

File tree

10 files changed

+185
-117
lines changed

10 files changed

+185
-117
lines changed

README.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -527,12 +527,20 @@ schema_reload_interval = "60"
527527

528528
[tls]
529529
# Certificate path
530-
# Env: CS_TLS__CERTIFICATE
531-
certificate = "./server.cert"
530+
# Env: CS_TLS__CERTIFICATE_PATH
531+
certificate_path = "./server.cert"
532532

533533
# Private Key path
534-
# Env: CS_TLS__PRIVATE_KEY
535-
private_key = "./server.key"
534+
# Env: CS_TLS__PRIVATE_KEY_PATH
535+
private_key_path = "./server.key"
536+
537+
# Certificate path
538+
# Env: CS_TLS__CERTIFICATE_PEM
539+
certificate_pem = "..."
540+
541+
# Private Key path
542+
# Env: CS_TLS__PRIVATE_KEY_PEM
543+
private_key_pem = "..."
536544

537545

538546
[auth]

docs/errors.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
- [Unknown table](#encrypt-unknown-table)
2222
- [Unknown index term](#encrypt-unknown-index-term)
2323

24+
- Configuration Errors:
25+
- [Missing or invalid TLS configuration](#config-missing-or-invalid-tls)
2426
<!-- ---------------------------------------------------------------------------------------------------- -->
2527

2628
<!-- ---------------------------------------------------------------------------------------------------- -->
@@ -339,3 +341,40 @@ Unknown Index Term for column '{column_name}' in table '{table_name}'.
339341
1. Define the encrypted configuration using [EQL](https://github.com/cipherstash/encrypt-query-language).
340342

341343

344+
<!-- ---------------------------------------------------------------------------------------------------- -->
345+
346+
347+
348+
<!-- ---------------------------------------------------------------------------------------------------- -->
349+
350+
# Configuration Errors
351+
352+
353+
## Database <a id='config-missing-or-invalid-tls'></a>
354+
355+
There was a problem with the Tls configuration.
356+
357+
358+
### Error message
359+
360+
```
361+
# PEM-based configuration
362+
Invalid Transport Layer Security (TLS) certificate.
363+
Invalid Transport Layer Security (TLS) private key.
364+
365+
# Path-based configuration
366+
Missing Transport Layer Security (TLS) certificate at path: {path}.
367+
Missing Transport Layer Security (TLS) private key at path: {path}.
368+
```
369+
370+
### How to Fix
371+
372+
If using path-based configuration:
373+
Check that the certificate and private key exists at the specified path.
374+
Check that the certificate and private key are valid.
375+
376+
If using PEM-based configuration:
377+
Check that the certificate and private key are valid.
378+
379+
380+
<!-- ---------------------------------------------------------------------------------------------------- -->

mise.local.example.toml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@ CS_EQL_VERSION="eql-0.5.4"
2323
# the respective .pem contents (starting with '-----BEGIN').
2424
# When TYPE is "Path", CERTIFICATE and PRIVATE_KEY must contain
2525
# the paths to the respoctive files.
26-
CS_TLS__TYPE = "Path"
27-
CS_TLS__CERTIFICATE = "tests/tls/server.cert"
28-
CS_TLS__PRIVATE_KEY = "tests/tls/server.key"
29-
# CS_TLS__TYPE = "Pem"
30-
# certificate = """-----BEGIN CERTIFICATE-----
26+
27+
CS_TLS__CERTIFICATE_PATH = "tests/tls/server.cert"
28+
CS_TLS__PRIVATE_KEY_PATH = "tests/tls/server.key"
29+
30+
31+
# CS_TLS__CERTIFICATE_PEM = """-----BEGIN CERTIFICATE-----
3132
# ...your certificate content here...
3233
# -----END CERTIFICATE-----
3334
# """
34-
# private_key = """-----BEGIN PRIVATE KEY-----
35+
# CS_TLS__PRIVATE_KEY_PEM = """-----BEGIN PRIVATE KEY-----
3536
# ...your private key content here...
3637
# -----END PRIVATE KEY-----
3738
# """

packages/cipherstash-proxy/src/config/tls.rs

Lines changed: 60 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,85 +4,77 @@ use rustls_pki_types::{pem::PemObject, CertificateDer, PrivateKeyDer};
44
use serde::Deserialize;
55
use tracing::debug;
66

7-
use crate::log::CONFIG;
7+
use crate::{error::TlsConfigError, log::CONFIG};
88

99
///
1010
/// Server TLS Configuration
1111
/// This is listener/inbound connection config
1212
///
1313
#[derive(Clone, Debug, Deserialize)]
14-
#[serde(tag = "type")]
14+
#[serde(untagged)]
1515
pub enum TlsConfig {
1616
Pem {
17-
certificate: String,
18-
private_key: String,
17+
certificate_pem: String,
18+
private_key_pem: String,
1919
},
2020
Path {
21-
certificate: String,
22-
private_key: String,
21+
certificate_path: String,
22+
private_key_path: String,
2323
},
2424
}
2525

26-
#[derive(Clone, Debug, Deserialize)]
27-
pub struct KeyCertPair {
28-
pub certificate: String,
29-
pub private_key: String,
30-
}
31-
3226
impl TlsConfig {
33-
pub fn cert_exists(&self) -> bool {
27+
pub fn check_cert(&self) -> Result<(), TlsConfigError> {
3428
match self {
35-
TlsConfig::Pem { certificate, .. } => {
36-
debug!(target: CONFIG, msg = "TLS certificate is a pem string (content omitted)");
29+
TlsConfig::Pem {
30+
certificate_pem: certificate,
31+
..
32+
} => {
33+
debug!(target: CONFIG, msg = "TLS certificate from PEM string");
3734
let certs = CertificateDer::pem_slice_iter(certificate.as_bytes())
3835
.collect::<Result<Vec<_>, _>>()
3936
.unwrap_or(Vec::new());
40-
!certs.is_empty()
37+
if certs.is_empty() {
38+
return Err(TlsConfigError::InvalidCertificate);
39+
}
4140
}
42-
TlsConfig::Path { certificate, .. } => {
43-
debug!(target: CONFIG, msg = "TLS certificate is a path: {}", certificate);
44-
PathBuf::from(certificate).exists()
41+
TlsConfig::Path {
42+
certificate_path, ..
43+
} => {
44+
debug!(target: CONFIG, msg = "TLS certificate from path", certificate_path);
45+
if !PathBuf::from(certificate_path).exists() {
46+
return Err(TlsConfigError::MissingCertificate {
47+
path: certificate_path.to_owned(),
48+
});
49+
}
4550
}
4651
}
52+
Ok(())
4753
}
4854

49-
pub fn private_key_exists(&self) -> bool {
55+
pub fn check_private_key(&self) -> Result<(), TlsConfigError> {
5056
match self {
51-
TlsConfig::Pem { private_key, .. } => {
52-
debug!(target: CONFIG, msg = "TLS private_key is a pem string (content omitted)");
53-
PrivateKeyDer::from_pem_slice(private_key.as_bytes()).is_ok()
57+
TlsConfig::Pem {
58+
private_key_pem: private_key,
59+
..
60+
} => {
61+
debug!(target: CONFIG, msg = "TLS private key from PEM string");
62+
if PrivateKeyDer::from_pem_slice(private_key.as_bytes()).is_err() {
63+
return Err(TlsConfigError::InvalidPrivateKey);
64+
}
5465
}
55-
TlsConfig::Path { private_key, .. } => {
56-
debug!(target: CONFIG, msg = "TLS private_key is a path: {}", private_key);
57-
PathBuf::from(private_key).exists()
66+
TlsConfig::Path {
67+
private_key_path, ..
68+
} => {
69+
debug!(target: CONFIG, msg = "TLS private key from path", private_key_path);
70+
if !PathBuf::from(private_key_path).exists() {
71+
return Err(TlsConfigError::MissingPrivateKey {
72+
path: private_key_path.to_owned(),
73+
});
74+
}
5875
}
5976
}
60-
}
61-
62-
pub fn certificate(&self) -> &str {
63-
match self {
64-
Self::Pem { certificate, .. } | Self::Path { certificate, .. } => certificate,
65-
}
66-
}
67-
68-
pub fn private_key(&self) -> &str {
69-
match self {
70-
Self::Pem { private_key, .. } | Self::Path { private_key, .. } => private_key,
71-
}
72-
}
73-
74-
pub fn certificate_err_msg(&self) -> &str {
75-
match self {
76-
Self::Pem { .. } => "Transport Layer Security (TLS) Certificate is invalid",
77-
Self::Path { .. } => "Transport Layer Security (TLS) Certificate not found",
78-
}
79-
}
80-
81-
pub fn private_key_err_msg(&self) -> &str {
82-
match self {
83-
Self::Pem { .. } => "Transport Layer Security (TLS) Private key is invalid",
84-
Self::Path { .. } => "Transport Layer Security (TLS) Private key not found",
85-
}
77+
Ok(())
8678
}
8779
}
8880

@@ -92,21 +84,21 @@ mod tests {
9284

9385
fn test_config_with_path() -> TlsConfig {
9486
TlsConfig::Path {
95-
certificate: "../../tests/tls/server.cert".to_string(),
96-
private_key: "../../tests/tls/server.key".to_string(),
87+
certificate_path: "../../tests/tls/server.cert".to_string(),
88+
private_key_path: "../../tests/tls/server.key".to_string(),
9789
}
9890
}
9991

10092
fn test_config_with_invalid_path() -> TlsConfig {
10193
TlsConfig::Path {
102-
certificate: "/path/to/non-existent/file".to_string(),
103-
private_key: "/path/to/non-existent/file".to_string(),
94+
certificate_path: "/path/to/non-existent/file".to_string(),
95+
private_key_path: "/path/to/non-existent/file".to_string(),
10496
}
10597
}
10698

10799
fn test_config_with_pem() -> TlsConfig {
108100
TlsConfig::Pem {
109-
certificate: "\
101+
certificate_pem: "\
110102
-----BEGIN CERTIFICATE-----
111103
MIIDKzCCAhOgAwIBAgIUMXfu7Mj22j+e9Gt2gjV73TBg20wwDQYJKoZIhvcNAQEL
112104
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MDEyNjAxNDkzMVoXDTI2MDEy
@@ -128,7 +120,7 @@ TU/T2RF2sDsSHrUIVMeifhYc0jfNlRwnUG5liN9BiGo1QxNZ9jGY/3ts5eu8+XM=
128120
-----END CERTIFICATE-----
129121
"
130122
.to_string(),
131-
private_key: "\
123+
private_key_pem: "\
132124
-----BEGIN PRIVATE KEY-----
133125
MIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCm6o6q/Q/wg97t
134126
OZAY7Yd47QOM+shXJhgK0lcTJSE9K6rbR4+Nvo/IJ4CUbzvd8lbj59IXpg/Sexvs
@@ -164,32 +156,32 @@ B+qwsnNEiDoJhgYj+cQ=
164156

165157
fn test_config_with_invalid_pem() -> TlsConfig {
166158
TlsConfig::Pem {
167-
certificate: "-----INVALID PEM-----".to_string(),
168-
private_key: "-----INVALID PEM-----".to_string(),
159+
certificate_pem: "-----INVALID PEM-----".to_string(),
160+
private_key_pem: "-----INVALID PEM-----".to_string(),
169161
}
170162
}
171163

172164
#[test]
173165
fn test_tls_cert_exists_with_path() {
174-
assert!(test_config_with_path().cert_exists());
175-
assert!(!test_config_with_invalid_path().cert_exists());
166+
assert!(test_config_with_path().check_cert().is_ok());
167+
assert!(test_config_with_invalid_path().check_cert().is_err());
176168
}
177169

178170
#[test]
179171
fn test_tls_cert_exists_with_pem() {
180-
assert!(test_config_with_pem().cert_exists());
181-
assert!(!test_config_with_invalid_pem().cert_exists());
172+
assert!(test_config_with_pem().check_cert().is_ok());
173+
assert!(test_config_with_invalid_pem().check_cert().is_err());
182174
}
183175

184176
#[test]
185177
fn test_tls_private_key_exists_with_path() {
186-
assert!(test_config_with_path().private_key_exists());
187-
assert!(!test_config_with_invalid_path().private_key_exists());
178+
assert!(test_config_with_path().check_private_key().is_ok());
179+
assert!(test_config_with_invalid_path().check_private_key().is_err());
188180
}
189181

190182
#[test]
191183
fn test_tls_private_key_exists_with_pem() {
192-
assert!(test_config_with_pem().private_key_exists());
193-
assert!(!test_config_with_invalid_pem().private_key_exists());
184+
assert!(test_config_with_pem().check_private_key().is_ok());
185+
assert!(test_config_with_invalid_pem().check_private_key().is_err());
194186
}
195187
}

packages/cipherstash-proxy/src/error.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ pub enum ConfigError {
104104
#[error(transparent)]
105105
Database(#[from] tokio_postgres::Error),
106106

107+
#[error(transparent)]
108+
FileOrEnvironment(#[from] config::ConfigError),
109+
107110
#[error("Dataset id is not a valid UUID.")]
108111
InvalidDatasetId,
109112

@@ -122,9 +125,6 @@ pub enum ConfigError {
122125
#[error("Expected an Encrypt configuration table")]
123126
MissingEncryptConfigTable,
124127

125-
#[error("Missing Transport Layer Security (TLS) certificate")]
126-
MissingCertificate,
127-
128128
#[error(transparent)]
129129
Parse(#[from] serde_json::Error),
130130

@@ -135,7 +135,34 @@ pub enum ConfigError {
135135
TlsRequired,
136136

137137
#[error(transparent)]
138-
FileOrEnvironment(#[from] config::ConfigError),
138+
TlsConfigError(#[from] TlsConfigError),
139+
}
140+
141+
#[derive(Error, Debug)]
142+
pub enum TlsConfigError {
143+
#[error(
144+
"Invalid Transport Layer Security (TLS) certificate. For help visit {}#config-missing-or-invalid-tls",
145+
ERROR_DOC_BASE_URL
146+
)]
147+
InvalidCertificate,
148+
149+
#[error(
150+
"Invalid Transport Layer Security (TLS) private key. For help visit {}#config-missing-or-invalid-tls",
151+
ERROR_DOC_BASE_URL
152+
)]
153+
InvalidPrivateKey,
154+
155+
#[error(
156+
"Missing Transport Layer Security (TLS) certificate at path: {path}. For help visit {}#config-missing-or-invalid-tls",
157+
ERROR_DOC_BASE_URL
158+
)]
159+
MissingCertificate { path: String },
160+
161+
#[error(
162+
"Missing Transport Layer Security (TLS) private key at path: {path}. For help visit {}#config-missing-or-invalid-tls",
163+
ERROR_DOC_BASE_URL
164+
)]
165+
MissingPrivateKey { path: String },
139166
}
140167

141168
#[derive(Error, Debug)]

packages/cipherstash-proxy/src/main.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -175,21 +175,15 @@ async fn init(mut config: TandemConfig) -> Encrypt {
175175

176176
match config.tls {
177177
Some(ref mut tls) => {
178-
if !tls.cert_exists() {
179-
error!(
180-
msg = tls.certificate_err_msg(),
181-
certificate = ?tls.certificate().lines().next().unwrap_or("") // show first line of PEM, or path (_should_ be 1 line)
182-
);
178+
_ = tls.check_cert().inspect_err(|err| {
179+
error!(msg = err.to_string());
183180
std::process::exit(exitcode::CONFIG);
184-
}
181+
});
185182

186-
if !tls.private_key_exists() {
187-
error!(
188-
msg = tls.private_key_err_msg(),
189-
private_key = ?tls.private_key().lines().next().unwrap_or("") // show first line of PEM, or path (_should_ be 1 line)
190-
);
183+
_ = tls.check_private_key().inspect_err(|err| {
184+
error!(msg = err.to_string());
191185
std::process::exit(exitcode::CONFIG);
192-
};
186+
});
193187

194188
match tls::configure_server(tls) {
195189
Ok(_) => {

0 commit comments

Comments
 (0)