Config option for verifying federation certificates (MSC 1711) #4967
Changes from 54 commits
dbb3319
5fd4cd0
9146059
4d1002f
904ea6c
8e89fc5
6de7ab8
8b1c459
ffc9c10
da23aa2
2325928
0ce5b5b
2851e64
d95b4ef
0f07754
86dfaf4
9d27f8e
4f177c5
5575f7a
ee0c7e1
a7d7c5a
fec0c9a
aeffa4d
821baa4
40702b6
cc149b1
8647013
d194e5d
3adf15d
61a39a4
3e29d45
f38da61
3f1fe92
a8adde0
e083ae3
a87b556
983474d
1fd5680
7c432de
4f03528
892c71d
a5ab4af
999f7db
507cdf2
9bd1432
d3f926a
09f6622
e337c2d
433db40
396eb64
3dbad06
595d6ec
edf2dd4
93850f0
6691998
92cc6b0
bc4b148
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 |
---|---|---|
@@ -0,0 +1 @@ | ||
Implementation of [MSC1711](https://github.com/matrix-org/matrix-doc/pull/1711) including config options for requiring valid TLS certificates for federation traffic, the ability to disable TLS validation for specific domains, and the ability to specify your own list of CA certificates. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -257,6 +257,39 @@ listeners: | |
# | ||
#tls_private_key_path: "CONFDIR/SERVERNAME.tls.key" | ||
|
||
# Whether to verify TLS certificates when sending federation traffic. | ||
# | ||
# This currently defaults to `false`, however this will change in | ||
# Synapse 1.0 when valid federation certificates will be required. | ||
# | ||
#federation_verify_certificates: true | ||
|
||
# Skip federation certificate verification on the following whitelist | ||
# of domains. | ||
# | ||
# This setting should only normally be used within a private network of | ||
# homeservers. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree with this warning, there's a bunch of networks where this is useful that aren't private where this is useful. For private networks of homeservers, custom CAs are the right tool, not disabling TLS verification. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jcgruenhage can you propose better wording then please. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about "This setting should only normally be used within a private network of homeservers, and even then using a private CA should be taken into consideration before disabling TLS verification entirely." There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd say "This setting should only be used in very specific cases, such as federation over Tor hidden services and similar. For private networks of homeservers, you likely want to use a private CA instead." |
||
# | ||
# Only effective if federation_verify_certicates is `true`. | ||
# | ||
#federation_certificate_verification_whitelist: | ||
# - lon.example.com | ||
# - *.domain.com | ||
# - *.onion | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Small nitpicky thing about this whitelist, MSC 1711 also spoke about excluding net masks, not only domains. This seems to not be dealt with at all in this PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd quite like to get this PR landed. Let's descope netmasks for now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm fine with that as long as they are still in scope for Synapse 1.0 |
||
|
||
# List of custom certificate authorities for federation traffic. | ||
# | ||
# This setting should only normally be used within a private network of | ||
# homeservers. | ||
# | ||
# Note that this list will replace those that are provided by your | ||
# operating environment. Certificates must be in PEM format. | ||
# | ||
#federation_custom_ca_list: | ||
# - myCA1.pem | ||
# - myCA2.pem | ||
# - myCA3.pem | ||
|
||
# ACME support: This will configure Synapse to request a valid TLS certificate | ||
# for your configured `server_name` via Let's Encrypt. | ||
# | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -111,13 +111,15 @@ def read_config(self, config): | |
self.admin_contact = config.get("admin_contact", None) | ||
|
||
# FIXME: federation_domain_whitelist needs sytests | ||
self.federation_domain_whitelist = None | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why is this code being changed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Left over from previous refactor that was reverted. Have changed code back so there's less diff now. |
||
federation_domain_whitelist = config.get( | ||
"federation_domain_whitelist", None | ||
"federation_domain_whitelist", None, | ||
) | ||
# turn the whitelist into a hash for speed of lookup | ||
|
||
self.federation_domain_whitelist = None | ||
if federation_domain_whitelist is not None: | ||
# turn the whitelist into a hash for speed of lookup | ||
self.federation_domain_whitelist = {} | ||
|
||
for domain in federation_domain_whitelist: | ||
self.federation_domain_whitelist[domain] = True | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,8 +24,10 @@ | |
from unpaddedbase64 import encode_base64 | ||
|
||
from OpenSSL import crypto | ||
from twisted.internet._sslverify import Certificate, trustRootFromCertificates | ||
|
||
from synapse.config._base import Config, ConfigError | ||
from synapse.util import glob_to_regex | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
@@ -70,6 +72,50 @@ def read_config(self, config): | |
|
||
self.tls_fingerprints = list(self._original_tls_fingerprints) | ||
|
||
# Whether to verify certificates on outbound federation traffic | ||
self.federation_verify_certificates = config.get( | ||
"federation_verify_certificates", False, | ||
) | ||
|
||
# Whitelist of domains to not verify certificates for | ||
fed_whitelist_entries = config.get( | ||
"federation_certificate_verification_whitelist", [], | ||
) | ||
|
||
# Support globs (*) in whitelist values | ||
self.federation_certificate_verification_whitelist = [] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for future reference, you could write this:
what you have is fine though. |
||
for entry in fed_whitelist_entries: | ||
# Convert globs to regex | ||
entry_regex = glob_to_regex(entry) | ||
self.federation_certificate_verification_whitelist.append(entry_regex) | ||
|
||
# List of custom certificate authorities for federation traffic validation | ||
custom_ca_list = config.get( | ||
"federation_custom_ca_list", None, | ||
) | ||
|
||
# Read in and parse custom CA certificates | ||
self.federation_ca_trust_root = None | ||
if custom_ca_list is not None: | ||
if len(custom_ca_list) == 0: | ||
raise ConfigError("federation_custom_ca_list specified without " | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a comment as to why this is the right thing to do would be helpful. |
||
"any certificate files") | ||
|
||
certs = [] | ||
for ca_file in custom_ca_list: | ||
logger.debug("Reading custom CA certificate file: %s", ca_file) | ||
content = self.read_file(ca_file) | ||
|
||
# Parse the CA certificates | ||
try: | ||
cert_base = Certificate.loadPEM(content) | ||
certs.append(cert_base) | ||
except Exception as e: | ||
raise ConfigError("Error parsing custom CA certificate file %s: %s" | ||
% (ca_file, e)) | ||
|
||
self.federation_ca_trust_root = trustRootFromCertificates(certs) | ||
|
||
# This config option applies to non-federation HTTP clients | ||
# (e.g. for talking to recaptcha, identity servers, and such) | ||
# It should never be used in production, and is intended for | ||
|
@@ -99,15 +145,15 @@ def is_disk_cert_valid(self, allow_self_signed=True): | |
try: | ||
with open(self.tls_certificate_file, 'rb') as f: | ||
cert_pem = f.read() | ||
except Exception: | ||
logger.exception("Failed to read existing certificate off disk!") | ||
raise | ||
richvdh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
except Exception as e: | ||
raise ConfigError("Failed to read existing certificate file %s: %s" | ||
% (self.tls_certificate_file, e)) | ||
|
||
try: | ||
tls_certificate = crypto.load_certificate(crypto.FILETYPE_PEM, cert_pem) | ||
except Exception: | ||
logger.exception("Failed to parse existing certificate off disk!") | ||
raise | ||
except Exception as e: | ||
raise ConfigError("Failed to parse existing certificate file %s: %s" | ||
% (self.tls_certificate_file, e)) | ||
|
||
if not allow_self_signed: | ||
if tls_certificate.get_subject() == tls_certificate.get_issuer(): | ||
|
@@ -192,6 +238,39 @@ def default_config(self, config_dir_path, server_name, **kwargs): | |
# | ||
#tls_private_key_path: "%(tls_private_key_path)s" | ||
|
||
# Whether to verify TLS certificates when sending federation traffic. | ||
anoadragon453 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# | ||
# This currently defaults to `false`, however this will change in | ||
# Synapse 1.0 when valid federation certificates will be required. | ||
# | ||
#federation_verify_certificates: true | ||
|
||
# Skip federation certificate verification on the following whitelist | ||
# of domains. | ||
# | ||
# This setting should only normally be used within a private network of | ||
# homeservers. | ||
# | ||
# Only effective if federation_verify_certicates is `true`. | ||
# | ||
#federation_certificate_verification_whitelist: | ||
# - lon.example.com | ||
# - *.domain.com | ||
# - *.onion | ||
|
||
# List of custom certificate authorities for federation traffic. | ||
# | ||
# This setting should only normally be used within a private network of | ||
# homeservers. | ||
# | ||
# Note that this list will replace those that are provided by your | ||
# operating environment. Certificates must be in PEM format. | ||
# | ||
#federation_custom_ca_list: | ||
# - myCA1.pem | ||
# - myCA2.pem | ||
# - myCA3.pem | ||
|
||
# ACME support: This will configure Synapse to request a valid TLS certificate | ||
# for your configured `server_name` via Let's Encrypt. | ||
# | ||
|
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.
bit pointless, but ok