tie oscp stapling to enhancements system

This commit is contained in:
Brad Warren
2016-09-21 15:38:37 -07:00
parent dff1368765
commit 8b553fa88f
2 changed files with 73 additions and 62 deletions
+42 -29
View File
@@ -94,7 +94,8 @@ class NginxConfigurator(common.Plugin):
# These will be set in the prepare function
self.parser = None
self.version = version
self._enhance_func = {"redirect": self._enable_redirect}
self._enhance_func = {"redirect": self._enable_redirect,
"staple-ocsp": self._enable_ocsp_stapling}
# Set up reverter
self.reverter = reverter.Reverter(self.config)
@@ -137,11 +138,6 @@ class NginxConfigurator(common.Plugin):
.. note:: Aborts if the vhost is missing ssl_certificate or
ssl_certificate_key.
.. note:: Nginx doesn't have a cert chain directive.
It expects the cert file to have the concatenated chain.
However, we use the chain file as input to the
ssl_trusted_certificate directive, used for verify OCSP responses.
.. note:: This doesn't save the config files!
:raises errors.PluginError: When unable to deploy certificate due to
@@ -157,26 +153,9 @@ class NginxConfigurator(common.Plugin):
cert_directives = [['\n', 'ssl_certificate', ' ', fullchain_path],
['\n', 'ssl_certificate_key', ' ', key_path]]
# OCSP stapling was introduced in Nginx 1.3.7. If we have that version
# or greater, add config settings for it.
stapling_directives = []
if self.version >= (1, 3, 7):
stapling_directives = [
['\n ', 'ssl_trusted_certificate', ' ', chain_path],
['\n ', 'ssl_stapling', ' ', 'on'],
['\n ', 'ssl_stapling_verify', ' ', 'on'], ['\n']]
if len(stapling_directives) != 0 and not chain_path:
raise errors.PluginError(
"--chain-path is required to enable "
"Online Certificate Status Protocol (OCSP) stapling "
"on nginx >= 1.3.7.")
try:
self.parser.add_server_directives(vhost.filep, vhost.names,
cert_directives, replace=True)
self.parser.add_server_directives(vhost.filep, vhost.names,
stapling_directives, replace=False)
logger.info("Deployed Certificate to VirtualHost %s for %s",
vhost.filep, vhost.names)
except errors.MisconfigurationError as error:
@@ -192,12 +171,6 @@ class NginxConfigurator(common.Plugin):
", ".join(str(addr) for addr in vhost.addrs)))
self.save_notes += "\tssl_certificate %s\n" % fullchain_path
self.save_notes += "\tssl_certificate_key %s\n" % key_path
if len(stapling_directives) > 0:
self.save_notes += "\tssl_trusted_certificate %s\n" % chain_path
self.save_notes += "\tssl_stapling on\n"
self.save_notes += "\tssl_stapling_verify on\n"
#######################
# Vhost parsing methods
@@ -394,6 +367,7 @@ class NginxConfigurator(common.Plugin):
"Unsupported enhancement: {0}".format(enhancement))
except errors.PluginError:
logger.warning("Failed %s for %s", enhancement, domain)
raise
def _enable_redirect(self, vhost, unused_options):
"""Redirect all equivalent HTTP traffic to ssl_vhost.
@@ -417,6 +391,45 @@ class NginxConfigurator(common.Plugin):
vhost.filep, vhost.names, redirect_block, replace=False)
logger.info("Redirecting all traffic to ssl in %s", vhost.filep)
def _enable_ocsp_stapling(self, vhost, chain_path):
"""Include OCSP response in TLS handshake
:param vhost: Destination of traffic, an ssl enabled vhost
:type vhost: :class:`~certbot_nginx.obj.VirtualHost`
:param chain_path: chain file path
:type chain_path: `str` or `None`
"""
if self.version < (1, 3, 7):
raise errors.PluginError("Version 1.3.7 or greater of nginx "
"is needed to enable OCSP stapling")
if chain_path is None:
raise errors.PluginError(
"--chain-path is required to enable "
"Online Certificate Status Protocol (OCSP) stapling "
"on nginx >= 1.3.7.")
stapling_directives = [
['\n ', 'ssl_trusted_certificate', ' ', chain_path],
['\n ', 'ssl_stapling', ' ', 'on'],
['\n ', 'ssl_stapling_verify', ' ', 'on'], ['\n']]
try:
self.parser.add_server_directives(vhost.filep, vhost.names,
stapling_directives, replace=False)
except errors.MisconfigurationError as error:
logger.debug(error)
raise errors.PluginError("An error occurred while enabling OCSP "
"stapling for {0}.".format(vhost.names))
self.save_notes += ("OCSP Stapling was enabled "
"on SSL Vhost: {0}.\n".format(vhost.filep))
self.save_notes += "\tssl_trusted_certificate {0}\n".format(chain_path)
self.save_notes += "\tssl_stapling on\n"
self.save_notes += "\tssl_stapling_verify on\n"
######################################
# Nginx server management (IInstaller)
######################################
@@ -141,37 +141,6 @@ class NginxConfiguratorTest(util.NginxTest):
def test_more_info(self):
self.assertTrue('nginx.conf' in self.config.more_info())
def test_deploy_cert_stapling(self):
# Choose a version of Nginx greater than 1.3.7 so stapling code gets
# invoked.
self.config.version = (1, 9, 6)
example_conf = self.config.parser.abs_path('sites-enabled/example.com')
self.config.deploy_cert(
"www.example.com",
"example/cert.pem",
"example/key.pem",
"example/chain.pem",
"example/fullchain.pem")
self.config.save()
self.config.parser.load()
generated_conf = self.config.parser.parsed[example_conf]
self.assertTrue(util.contains_at_depth(generated_conf,
['ssl_stapling', 'on'], 2))
self.assertTrue(util.contains_at_depth(generated_conf,
['ssl_stapling_verify', 'on'], 2))
self.assertTrue(util.contains_at_depth(generated_conf,
['ssl_trusted_certificate', 'example/chain.pem'], 2))
def test_deploy_cert_stapling_requires_chain_path(self):
self.config.version = (1, 3, 7)
self.assertRaises(errors.PluginError, self.config.deploy_cert,
"www.example.com",
"example/cert.pem",
"example/key.pem",
None,
"example/fullchain.pem")
def test_deploy_cert_requires_fullchain_path(self):
self.config.version = (1, 3, 1)
self.assertRaises(errors.PluginError, self.config.deploy_cert,
@@ -185,8 +154,6 @@ class NginxConfiguratorTest(util.NginxTest):
server_conf = self.config.parser.abs_path('server.conf')
nginx_conf = self.config.parser.abs_path('nginx.conf')
example_conf = self.config.parser.abs_path('sites-enabled/example.com')
# Choose a version of Nginx less than 1.3.7 so stapling code doesn't get
# invoked.
self.config.version = (1, 3, 1)
# Get the default SSL vhost
@@ -429,5 +396,36 @@ class NginxConfiguratorTest(util.NginxTest):
generated_conf = self.config.parser.parsed[example_conf]
self.assertTrue(util.contains_at_depth(generated_conf, expected, 2))
def test_staple_ocsp_bad_version(self):
self.config.version = (1, 3, 1)
self.assertRaises(errors.PluginError, self.config.enhance,
"www.example.com", "staple-ocsp", "chain_path")
def test_staple_ocsp_no_chain_path(self):
self.assertRaises(errors.PluginError, self.config.enhance,
"www.example.com", "staple-ocsp", None)
def test_staple_ocsp_internal_error(self):
self.config.enhance("www.example.com", "staple-ocsp", "chain_path")
# error is raised because the server block has conflicting directives
self.assertRaises(errors.PluginError, self.config.enhance,
"www.example.com", "staple-ocsp", "different_path")
def test_staple_ocsp(self):
chain_path = "example/chain.pem"
self.config.enhance("www.example.com", "staple-ocsp", chain_path)
example_conf = self.config.parser.abs_path('sites-enabled/example.com')
generated_conf = self.config.parser.parsed[example_conf]
self.assertTrue(util.contains_at_depth(
generated_conf,
['ssl_trusted_certificate', 'example/chain.pem'], 2))
self.assertTrue(util.contains_at_depth(
generated_conf, ['ssl_stapling', 'on'], 2))
self.assertTrue(util.contains_at_depth(
generated_conf, ['ssl_stapling_verify', 'on'], 2))
if __name__ == "__main__":
unittest.main() # pragma: no cover