diff --git a/docs/ciphers.rst b/docs/ciphers.rst index fb854f307..c8ff26117 100644 --- a/docs/ciphers.rst +++ b/docs/ciphers.rst @@ -107,7 +107,7 @@ and the version implemented by the Let's Encrypt client will be the version that was most current as of the release date of each client version. Mozilla offers three separate sets of cryptographic options, which trade off security and compatibility differently. These are -referred to as as the "Modern", "Intermediate", and "Old" configurations +referred to as the "Modern", "Intermediate", and "Old" configurations (in order from most secure to least secure, and least-backwards compatible to most-backwards compatible). The client will follow the Mozilla defaults for the *Intermediate* configuration by default, at least with regards to diff --git a/letsencrypt-apache/letsencrypt_apache/configurator.py b/letsencrypt-apache/letsencrypt_apache/configurator.py index 5ca2ddcb6..0ab16ff06 100644 --- a/letsencrypt-apache/letsencrypt_apache/configurator.py +++ b/letsencrypt-apache/letsencrypt_apache/configurator.py @@ -644,11 +644,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): """ if self.conf("handle-modules"): - if "ssl_module" not in self.parser.modules: - self.enable_mod("ssl", temp=temp) if self.version >= (2, 4) and ("socache_shmcb_module" not in self.parser.modules): self.enable_mod("socache_shmcb", temp=temp) + if "ssl_module" not in self.parser.modules: + self.enable_mod("ssl", temp=temp) def make_addrs_sni_ready(self, addrs): """Checks to see if the server is ready for SNI challenges. diff --git a/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py b/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py index a04f7904c..5b15a20d1 100644 --- a/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py +++ b/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py @@ -429,9 +429,15 @@ class TwoVhost80Test(util.ApacheTest): self.config.parser.add_dir_to_ifmodssl = mock_add_dir self.config.prepare_server_https("443") + # Changing the order these modules are enabled breaks the reverter + self.assertEqual(mock_enable.call_args_list[0][0][0], "socache_shmcb") + self.assertEqual(mock_enable.call_args[0][0], "ssl") self.assertEqual(mock_enable.call_args[1], {"temp": False}) self.config.prepare_server_https("8080", temp=True) + # Changing the order these modules are enabled breaks the reverter + self.assertEqual(mock_enable.call_args_list[2][0][0], "socache_shmcb") + self.assertEqual(mock_enable.call_args[0][0], "ssl") # Enable mod is temporary self.assertEqual(mock_enable.call_args[1], {"temp": True}) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 5f16f55a8..64b06048b 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -436,8 +436,8 @@ if [ "$NO_SELF_UPGRADE" = 1 ]; then # ------------------------------------------------------------------------- cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt" # This is the flattened list of packages letsencrypt-auto installs. To generate -# this, do `pip install -e acme -e . -e letsencrypt-apache`, `pip freeze`, -# and then gather the hashes. +# this, do `pip install --no-cache-dir -e acme -e . -e letsencrypt-apache`, and +# then use `hashin` or a more secure method to gather the hashes. # sha256: wxZH7baf09RlqEfqMVfTe-0flfGXYLEaR6qRwEtmYxQ # sha256: YrCJpVvh2JSc0rx-DfC9254Cj678jDIDjMhIYq791uQ @@ -506,6 +506,10 @@ idna==2.0 # sha256: WjGCsyKnBlJcRigspvBk0noCz_vUSfn0dBbx3JaqcbA ipaddress==1.0.16 +# sha256: 54vpwKDfy6xxL-BPv5K5bN2ugLG4QvJCSCFMhJbwBu8 +# sha256: Syb_TnEQ23butvWntkqCYjg51ZXCA47tpmLyott46Xw +linecache2==1.0.0 + # sha256: 6MFV_evZxLywgQtO0BrhmHVUse4DTddTLXuP2uOKYnQ ndg-httpsclient==0.4.0 @@ -597,6 +601,14 @@ requests==2.9.1 # sha256: EF-NaGFvgkjiS_DpNy7wTTzBAQTxmA9U1Xss5zpa1Wo six==1.10.0 +# sha256: glPOvsSxkJTWfMXtWvmb8duhKFKSIm6Yoxkp-HpdayM +# sha256: BazGegmYDC7P7dNCP3rgEEg57MtV_GRXc-HKoJUcMDA +traceback2==1.4.0 + +# sha256: E_d9CHXbbZtDXh1PQedK1MwutuHVyCSZYJKzQw8Ii7g +# sha256: IogqDkGMKE4fcYqCKzsCKUTVPS2QjhaQsxmp0-ssBXk +unittest2==1.1.0 + # sha256: aUkbUwUVfDxuDwSnAZhNaud_1yn8HJrNJQd_HfOFMms # sha256: 619wCpv8lkILBVY1r5AC02YuQ9gMP_0x8iTCW8DV9GI Werkzeug==0.11.3 diff --git a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt index 739e19f20..c83396de2 100644 --- a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt +++ b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt @@ -1,6 +1,6 @@ # This is the flattened list of packages letsencrypt-auto installs. To generate -# this, do `pip install -e acme -e . -e letsencrypt-apache`, `pip freeze`, -# and then gather the hashes. +# this, do `pip install --no-cache-dir -e acme -e . -e letsencrypt-apache`, and +# then use `hashin` or a more secure method to gather the hashes. # sha256: wxZH7baf09RlqEfqMVfTe-0flfGXYLEaR6qRwEtmYxQ # sha256: YrCJpVvh2JSc0rx-DfC9254Cj678jDIDjMhIYq791uQ @@ -69,6 +69,10 @@ idna==2.0 # sha256: WjGCsyKnBlJcRigspvBk0noCz_vUSfn0dBbx3JaqcbA ipaddress==1.0.16 +# sha256: 54vpwKDfy6xxL-BPv5K5bN2ugLG4QvJCSCFMhJbwBu8 +# sha256: Syb_TnEQ23butvWntkqCYjg51ZXCA47tpmLyott46Xw +linecache2==1.0.0 + # sha256: 6MFV_evZxLywgQtO0BrhmHVUse4DTddTLXuP2uOKYnQ ndg-httpsclient==0.4.0 @@ -160,6 +164,14 @@ requests==2.9.1 # sha256: EF-NaGFvgkjiS_DpNy7wTTzBAQTxmA9U1Xss5zpa1Wo six==1.10.0 +# sha256: glPOvsSxkJTWfMXtWvmb8duhKFKSIm6Yoxkp-HpdayM +# sha256: BazGegmYDC7P7dNCP3rgEEg57MtV_GRXc-HKoJUcMDA +traceback2==1.4.0 + +# sha256: E_d9CHXbbZtDXh1PQedK1MwutuHVyCSZYJKzQw8Ii7g +# sha256: IogqDkGMKE4fcYqCKzsCKUTVPS2QjhaQsxmp0-ssBXk +unittest2==1.1.0 + # sha256: aUkbUwUVfDxuDwSnAZhNaud_1yn8HJrNJQd_HfOFMms # sha256: 619wCpv8lkILBVY1r5AC02YuQ9gMP_0x8iTCW8DV9GI Werkzeug==0.11.3 diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index f3657fdcf..58caf5862 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -1304,7 +1304,9 @@ def _plugins_parsing(helpful, plugins): help="JSON dictionary mapping domains to webroot paths; this implies -d " "for each entry. You may need to escape this from your shell. " """Eg: --webroot-map '{"eg1.is,m.eg1.is":"/www/eg1/", "eg2.is":"/www/eg2"}' """ - "This option is merged with, but takes precedence over, -w / -d entries") + "This option is merged with, but takes precedence over, -w / -d entries." + " At present, if you put webroot-map in a config file, it needs to be " + ' on a single line, like: webroot-map = {"example.com":"/var/www"}.') class WebrootPathProcessor(argparse.Action): # pylint: disable=missing-docstring def __init__(self, *args, **kwargs): @@ -1333,8 +1335,6 @@ class WebrootPathProcessor(argparse.Action): # pylint: disable=missing-docstring config.webroot_path.append(webroot) -_undot = lambda domain: domain[:-1] if domain.endswith('.') else domain - def _process_domain(config, domain_arg, webroot_path=None): """ Process a new -d flag, helping the webroot plugin construct a map of @@ -1343,8 +1343,8 @@ def _process_domain(config, domain_arg, webroot_path=None): webroot_path = webroot_path if webroot_path else config.webroot_path for domain in (d.strip() for d in domain_arg.split(",")): + domain = le_util.enforce_domain_sanity(domain) if domain not in config.domains: - domain = _undot(domain) config.domains.append(domain) # Each domain has a webroot_path of the most recent -w flag # unless it was explicitly included in webroot_map diff --git a/letsencrypt/configuration.py b/letsencrypt/configuration.py index afd5edbe4..37eaba3bd 100644 --- a/letsencrypt/configuration.py +++ b/letsencrypt/configuration.py @@ -124,4 +124,5 @@ def check_config_sanity(config): # Domain checks if config.namespace.domains is not None: for domain in config.namespace.domains: - le_util.check_domain_sanity(domain) + # This may be redundant, but let's be paranoid + le_util.enforce_domain_sanity(domain) diff --git a/letsencrypt/display/ops.py b/letsencrypt/display/ops.py index b3c057301..f0dec8b06 100644 --- a/letsencrypt/display/ops.py +++ b/letsencrypt/display/ops.py @@ -239,8 +239,7 @@ def get_valid_domains(domains): valid_domains = [] for domain in domains: try: - le_util.check_domain_sanity(domain) - valid_domains.append(domain) + valid_domains.append(le_util.enforce_domain_sanity(domain)) except errors.ConfigurationError: continue return valid_domains @@ -282,9 +281,9 @@ def _choose_names_manually(): "supported.{0}{0}Would you like to re-enter the " "names?{0}").format(os.linesep) - for domain in domain_list: + for i, domain in enumerate(domain_list): try: - le_util.check_domain_sanity(domain) + domain_list[i] = le_util.enforce_domain_sanity(domain) except errors.ConfigurationError as e: invalid_domains[domain] = e.message diff --git a/letsencrypt/le_util.py b/letsencrypt/le_util.py index d97d43dc6..35793849e 100644 --- a/letsencrypt/le_util.py +++ b/letsencrypt/le_util.py @@ -285,15 +285,17 @@ def add_deprecated_argument(add_argument, argument_name, nargs): help=argparse.SUPPRESS, nargs=nargs) -def check_domain_sanity(domain): +def enforce_domain_sanity(domain): """Method which validates domain value and errors out if the requirements are not met. :param domain: Domain to check - :type domains: `string` + :type domains: `str` or `unicode` :raises ConfigurationError: for invalid domains and cases where Let's Encrypt currently will not issue certificates + :returns: The domain cast to `str`, with ASCII-only contents + :rtype: str """ # Check if there's a wildcard domain if domain.startswith("*."): @@ -306,12 +308,15 @@ def check_domain_sanity(domain): # Unicode try: - domain.encode('ascii') + domain = domain.encode('ascii') except UnicodeDecodeError: raise errors.ConfigurationError( "Internationalized domain names are not presently supported: {0}" .format(domain)) + # Remove trailing dot + domain = domain[:-1] if domain.endswith('.') else domain + # FQDN checks from # http://www.mkyong.com/regular-expressions/domain-name-regular-expression-example/ # Characters used, domain parts < 63 chars, tld > 1 < 64 chars @@ -319,3 +324,4 @@ def check_domain_sanity(domain): fqdn = re.compile("^((?!-)[A-Za-z0-9-]{1,63}(?