def setUp(self): super(DvsniPerformTest, self).setUp() config = util.get_nginx_configurator(self.config_path, self.config_dir, self.work_dir, self.ssl_options) rsa256_file = pkg_resources.resource_filename( "letsencrypt.client.tests", "testdata/rsa256_key.pem") rsa256_pem = pkg_resources.resource_string("letsencrypt.client.tests", "testdata/rsa256_key.pem") auth_key = le_util.Key(rsa256_file, rsa256_pem) from letsencrypt.client.plugins.nginx import dvsni self.sni = dvsni.NginxDvsni(config) self.achalls = [ achallenges.DVSNI(chall=challenges.DVSNI( r="foo", nonce="bar", ), domain="www.example.com", key=auth_key), achallenges.DVSNI(chall=challenges.DVSNI( r="\xba\xa9\xda?<m\xaewmx\xea\xad\xadv\xf4\x02\xc9y\x80" "\xe2_X\t\xe7\xc7\xa4\t\xca\xf7&\x945", nonce="Y\xed\x01L\xac\x95\xf7pW\xb1\xd7" "\xa1\xb2\xc5\x96\xba", ), domain="blah", key=auth_key), ]
def setUp(self): super(DvsniPerformTest, self).setUp() with mock.patch("letsencrypt.client.plugins.apache.configurator." "mod_loaded") as mock_load: mock_load.return_value = True config = util.get_apache_configurator( self.config_path, self.config_dir, self.work_dir, self.ssl_options) from letsencrypt.client.plugins.apache import dvsni self.sni = dvsni.ApacheDvsni(config) rsa256_file = pkg_resources.resource_filename( "letsencrypt.client.tests", "testdata/rsa256_key.pem") rsa256_pem = pkg_resources.resource_string( "letsencrypt.client.tests", "testdata/rsa256_key.pem") auth_key = le_util.Key(rsa256_file, rsa256_pem) self.achalls = [ achallenges.DVSNI( chall=challenges.DVSNI( r="\x8c\x8a\xbf_-f\\cw\xee\xd6\xf8/\xa5\xe3\xfd\xeb9\xf1" "\xf5\xb9\xefVM\xc9w\xa4u\x9c\xe1\x87\xb4", nonce="7\xbc^\xb7]>\x00\xa1\x9bOcU\x84^Z\x18", ), domain="encryption-example.demo", key=auth_key), achallenges.DVSNI( chall=challenges.DVSNI( r="\xba\xa9\xda?<m\xaewmx\xea\xad\xadv\xf4\x02\xc9y\x80" "\xe2_X\t\xe7\xc7\xa4\t\xca\xf7&\x945", nonce="Y\xed\x01L\xac\x95\xf7pW\xb1\xd7" "\xa1\xb2\xc5\x96\xba", ), domain="letsencrypt.demo", key=auth_key), ]
def test_perform(self, mock_restart, mock_dvsni_perform): # Only tests functionality specific to configurator.perform # Note: As more challenges are offered this will have to be expanded auth_key = le_util.Key(self.rsa256_file, self.rsa256_pem) chall1 = challenge_util.DvsniChall( "encryption-example.demo", "jIq_Xy1mXGN37tb4L6Xj_es58fW571ZNyXekdZzhh7Q", "37bc5eb75d3e00a19b4f6355845e5a18", auth_key) chall2 = challenge_util.DvsniChall( "letsencrypt.demo", "uqnaPzxtrndteOqtrXb0Asl5gOJfWAnnx6QJyvcmlDU", "59ed014cac95f77057b1d7a1b2c596ba", auth_key) dvsni_ret_val = [{ "type": "dvsni", "s": "randomS1" }, { "type": "dvsni", "s": "randomS2" }] mock_dvsni_perform.return_value = dvsni_ret_val responses = self.config.perform([chall1, chall2]) self.assertEqual(mock_dvsni_perform.call_count, 1) self.assertEqual(responses, dvsni_ret_val) self.assertEqual(mock_restart.call_count, 1)
def test_perform(self, mock_restart, mock_dvsni_perform): # Only tests functionality specific to configurator.perform # Note: As more challenges are offered this will have to be expanded auth_key = le_util.Key(self.rsa256_file, self.rsa256_pem) achall1 = achallenges.DVSNI(chall=challenges.DVSNI( r="jIq_Xy1mXGN37tb4L6Xj_es58fW571ZNyXekdZzhh7Q", nonce="37bc5eb75d3e00a19b4f6355845e5a18"), domain="encryption-example.demo", key=auth_key) achall2 = achallenges.DVSNI(chall=challenges.DVSNI( r="uqnaPzxtrndteOqtrXb0Asl5gOJfWAnnx6QJyvcmlDU", nonce="59ed014cac95f77057b1d7a1b2c596ba"), domain="letsencrypt.demo", key=auth_key) dvsni_ret_val = [ challenges.DVSNIResponse(s="randomS1"), challenges.DVSNIResponse(s="randomS2"), ] mock_dvsni_perform.return_value = dvsni_ret_val responses = self.config.perform([achall1, achall2]) self.assertEqual(mock_dvsni_perform.call_count, 1) self.assertEqual(responses, dvsni_ret_val) self.assertEqual(mock_restart.call_count, 1)
def setUp(self): super(DvsniPerformTest, self).setUp() with mock.patch("letsencrypt.client.apache.configurator." "mod_loaded") as mock_load: mock_load.return_value = True config = util.get_apache_configurator( self.config_path, self.config_dir, self.work_dir, self.ssl_options) from letsencrypt.client.apache import dvsni self.sni = dvsni.ApacheDvsni(config) rsa256_file = pkg_resources.resource_filename( "letsencrypt.client.tests", 'testdata/rsa256_key.pem') rsa256_pem = pkg_resources.resource_string( "letsencrypt.client.tests", 'testdata/rsa256_key.pem') auth_key = le_util.Key(rsa256_file, rsa256_pem) self.challs = [] self.challs.append(challenge_util.DvsniChall( "encryption-example.demo", "jIq_Xy1mXGN37tb4L6Xj_es58fW571ZNyXekdZzhh7Q", "37bc5eb75d3e00a19b4f6355845e5a18", auth_key)) self.challs.append(challenge_util.DvsniChall( "letsencrypt.demo", "uqnaPzxtrndteOqtrXb0Asl5gOJfWAnnx6QJyvcmlDU", "59ed014cac95f77057b1d7a1b2c596ba", auth_key))
def init_key(key_size, key_dir): """Initializes privkey. Inits key and CSR using provided files or generating new files if necessary. Both will be saved in PEM format on the filesystem. The CSR is placed into DER format to allow the namedtuple to easily work with the protocol. :param str key_dir: Key save directory. """ try: key_pem = crypto_util.make_key(key_size) except ValueError as err: logging.fatal(str(err)) sys.exit(1) # Save file le_util.make_or_verify_dir(key_dir, 0o700) key_f, key_filename = le_util.unique_file( os.path.join(key_dir, "key-letsencrypt.pem"), 0o600) key_f.write(key_pem) key_f.close() logging.info("Generating key (%d bits): %s", key_size, key_filename) return le_util.Key(key_filename, key_pem)
def test_can_perform(self): """What happens if start_listener() returns True.""" test_key = pkg_resources.resource_string(__name__, "testdata/rsa256_key.pem") key = le_util.Key("something", test_key) chall1 = challenge_util.DvsniChall("foo.example.com", "whee", "foononce", key) chall2 = challenge_util.DvsniChall("bar.example.com", "whee", "barnonce", key) bad_chall = ("This", "Represents", "A Non-DVSNI", "Challenge") self.authenticator.start_listener = mock.Mock() self.authenticator.start_listener.return_value = True result = self.authenticator.perform([chall1, chall2, bad_chall]) self.assertEqual(len(self.authenticator.tasks), 2) self.assertTrue( self.authenticator.tasks.has_key("foononce.acme.invalid")) self.assertTrue( self.authenticator.tasks.has_key("barnonce.acme.invalid")) self.assertTrue(isinstance(result, list)) self.assertEqual(len(result), 3) self.assertTrue(isinstance(result[0], dict)) self.assertTrue(isinstance(result[1], dict)) self.assertFalse(result[2]) self.assertTrue(result[0].has_key("s")) self.assertTrue(result[1].has_key("s")) self.authenticator.start_listener.assert_called_once_with(443, key)
def test_perform(self, mock_restart, mock_dvsni_perform): # Only tests functionality specific to configurator.perform # Note: As more challenges are offered this will have to be expanded auth_key = le_util.Key(self.rsa256_file, self.rsa256_pem) achall1 = achallenges.DVSNI( chall=challenges.DVSNI( r="foo", nonce="bar"), domain="localhost", key=auth_key) achall2 = achallenges.DVSNI( chall=challenges.DVSNI( r="abc", nonce="def"), domain="example.com", key=auth_key) dvsni_ret_val = [ challenges.DVSNIResponse(s="irrelevant"), challenges.DVSNIResponse(s="arbitrary"), ] mock_dvsni_perform.return_value = dvsni_ret_val responses = self.config.perform([achall1, achall2]) self.assertEqual(mock_dvsni_perform.call_count, 1) self.assertEqual(responses, dvsni_ret_val) self.assertEqual(mock_restart.call_count, 1)
def _from_config_fp(cls, config, config_fp): try: acc_config = configobj.ConfigObj(infile=config_fp, file_error=True, create_empty=False) except IOError: raise errors.LetsEncryptClientError( "Account for %s does not exist" % os.path.basename(config_fp)) if os.path.basename(config_fp) != "default": email = os.path.basename(config_fp) else: email = None phone = acc_config["phone"] if acc_config["phone"] != "None" else None with open(acc_config["key"]) as key_file: key = le_util.Key(acc_config["key"], key_file.read()) if "RegistrationResource" in acc_config: acc_config_rr = acc_config["RegistrationResource"] regr = messages2.RegistrationResource( uri=acc_config_rr["uri"], new_authzr_uri=acc_config_rr["new_authzr_uri"], terms_of_service=acc_config_rr["terms_of_service"], body=messages2.Registration.from_json(acc_config_rr["body"])) else: regr = None return cls(config, key, email, phone, regr)
def setUp(self): self.chall = challenges.DVSNI(r="r_value", nonce="12345ABCDE") self.response = challenges.DVSNIResponse() key = le_util.Key( "path", pkg_resources.resource_string( __name__, os.path.join("testdata", "rsa256_key.pem"))) from letsencrypt.client.achallenges import DVSNI self.achall = DVSNI(chall=self.chall, domain="example.com", key=key)
def test_perform_when_already_listening(self): test_key = pkg_resources.resource_string(__name__, "testdata/rsa256_key.pem") key = le_util.Key("something", test_key) chall1 = challenge_util.DvsniChall("foo.example.com", "whee", "foononce", key) self.authenticator.already_listening = mock.Mock() self.authenticator.already_listening.return_value = True result = self.authenticator.perform([chall1]) self.assertEqual(result, [None])
def setUp(self): from letsencrypt.client.revoker import Revoker super(RevokerTest, self).setUp() with open(self.key_path) as key_file: self.key = le_util.Key(self.key_path, key_file.read()) self._store_certs() self.revoker = Revoker( mock.MagicMock(spec=configurator.ApacheConfigurator), self.mock_config)
def test_revoke_by_wrong_key(self, mock_display, mock_net): mock_display().confirm_revocation.return_value = True key_path = pkg_resources.resource_filename( "letsencrypt.client.tests", os.path.join("testdata", "rsa256_key.pem")) wrong_key = le_util.Key(key_path, open(key_path).read()) self.revoker.revoke_from_key(wrong_key) # Nothing was removed self.assertEqual(len(self._get_rows()), 2) # No revocation went through self.assertEqual(mock_net.call_count, 0)
def test_standard(self): """Basic test for straightline code.""" domain = "example.com" dvsni_r = "r_value" r_b64 = jose.b64encode(dvsni_r) pem = pkg_resources.resource_string( __name__, os.path.join("testdata", "rsa256_key.pem")) key = le_util.Key("path", pem) nonce = "12345ABCDE" cert_pem, s_b64 = self._call(domain, r_b64, nonce, key) # pylint: disable=protected-access ext = challenge_util._dvsni_gen_ext(dvsni_r, jose.b64decode(s_b64)) self._standard_check_cert(cert_pem, domain, nonce, ext)
def setUp(self): from letsencrypt.client.standalone_authenticator import \ StandaloneAuthenticator self.authenticator = StandaloneAuthenticator() name, r_b64 = "example.com", jose.b64encode("x" * 32) test_key = pkg_resources.resource_string(__name__, "testdata/rsa256_key.pem") nonce, key = "abcdef", le_util.Key("foo", test_key) self.cert = challenge_util.dvsni_gen_cert(name, r_b64, nonce, key)[0] private_key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, key.pem) self.authenticator.private_key = private_key self.authenticator.tasks = {"abcdef.acme.invalid": self.cert} self.authenticator.child_pid = 12345
def setUp(self): from letsencrypt.client.standalone_authenticator import \ StandaloneAuthenticator self.authenticator = StandaloneAuthenticator() test_key = pkg_resources.resource_string( __name__, "testdata/rsa256_key.pem") key = le_util.Key("foo", test_key) self.cert = achallenges.DVSNI( chall=challenges.DVSNI(r="x"*32, nonce="abcdef"), domain="example.com", key=key).gen_cert_and_response()[0] private_key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, key.pem) self.authenticator.private_key = private_key self.authenticator.tasks = {"abcdef.acme.invalid": self.cert} self.authenticator.child_pid = 12345
def setUp(self): from letsencrypt.client.standalone_authenticator import \ StandaloneAuthenticator self.authenticator = StandaloneAuthenticator() test_key = pkg_resources.resource_string( __name__, "testdata/rsa256_key.pem") self.key = le_util.Key("something", test_key) self.achall1 = achallenges.DVSNI( chall=challenges.DVSNI(r="whee", nonce="foo"), domain="foo.example.com", key=self.key) self.achall2 = achallenges.DVSNI( chall=challenges.DVSNI(r="whee", nonce="bar"), domain="bar.example.com", key=self.key) bad_achall = ("This", "Represents", "A Non-DVSNI", "Challenge") self.achalls = [self.achall1, self.achall2, bad_achall]
def setUp(self): zope.component.provideUtility(display_util.FileDisplay(sys.stdout)) self.accounts_dir = tempfile.mkdtemp("accounts") self.account_keys_dir = os.path.join(self.accounts_dir, "keys") os.makedirs(self.account_keys_dir, 0o700) self.config = mock.MagicMock(accounts_dir=self.accounts_dir, account_keys_dir=self.account_keys_dir, server="letsencrypt-demo.org") self.key = le_util.Key("keypath", "pem") self.acc1 = account.Account(self.config, self.key, "*****@*****.**") self.acc2 = account.Account(self.config, self.key, "*****@*****.**", "phone") self.acc1.save() self.acc2.save()
def revoke(config, no_confirm, cert, authkey): """Revoke certificates. :param config: Configuration. :type config: :class:`letsencrypt.client.interfaces.IConfig` """ # Misconfigurations don't really matter. Determine installer better choose # correctly though. # This will need some better prepared or properly configured parameter... # I will figure it out later... installer = determine_installer(config) revoc = revoker.Revoker(installer, config, no_confirm) # Cert is most selective, so it is chosen first. if cert is not None: revoc.revoke_from_cert(cert[0]) elif authkey is not None: revoc.revoke_from_key(le_util.Key(authkey[0], authkey[1])) else: revoc.revoke_from_menu()
def setUp(self): from letsencrypt.client.auth_handler import AuthHandler self.mock_dv_auth = mock.MagicMock(name="ApacheConfigurator") self.mock_cont_auth = mock.MagicMock(name="ContinuityAuthenticator") self.mock_dv_auth.get_chall_pref.return_value = [challenges.DVSNI] self.mock_cont_auth.get_chall_pref.return_value = [ challenges.RecoveryToken ] self.mock_cont_auth.perform.side_effect = gen_auth_resp self.mock_dv_auth.perform.side_effect = gen_auth_resp self.mock_account = mock.Mock(key=le_util.Key("file_path", "PEM")) self.mock_net = mock.MagicMock(spec=network2.Network) self.handler = AuthHandler(self.mock_dv_auth, self.mock_cont_auth, self.mock_net, self.mock_account) logging.disable(logging.CRITICAL)
def determine_account(self, mock_op, mock_prompt): """Test determine account""" from letsencrypt.client import client key = le_util.Key("file", "pem") test_acc = account.Account(self.config, key, "*****@*****.**") mock_op.return_value = test_acc # Test 0 mock_prompt.return_value = None self.assertTrue(client.determine_account(self.config) is None) # Test 1 test_acc.save() acc = client.determine_account(self.config) self.assertEqual(acc.email, test_acc.email) # Test multiple self.assertFalse(mock_op.called) acc2 = account.Account(self.config, key) acc2.save() chosen_acc = client.determine_account(self.config) self.assertTrue(mock_op.called) self.assertTrue(chosen_acc.email, test_acc.email)
import socket import unittest import mock import OpenSSL.crypto import OpenSSL.SSL from letsencrypt.acme import challenges from letsencrypt.client import achallenges from letsencrypt.client import le_util from letsencrypt.client.tests import acme_util KEY = le_util.Key("foo", pkg_resources.resource_string( "letsencrypt.acme.jose", os.path.join("testdata", "rsa512_key.pem"))) PRIVATE_KEY = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, KEY.pem) # Classes based on to allow interrupting infinite loop under test # after one iteration, based on. # http://igorsobreira.com/2013/03/17/testing-infinite-loops.html class _SocketAcceptOnlyNTimes(object): # pylint: disable=too-few-public-methods """ Callable that will raise `CallableExhausted` exception after `limit` calls, modified to also return a tuple simulating the return values of a socket.accept() call
def main(): # pylint: disable=too-many-branches, too-many-statements """Command line argument parsing and main script execution.""" # note: arg parser internally handles --help (and exits afterwards) args = create_parser().parse_args() config = configuration.NamespaceConfig(args) # note: check is done after arg parsing as --help should work w/o root also. if not os.geteuid() == 0: sys.exit( "{0}Root is required to run letsencrypt. Please use sudo.{0}". format(os.linesep)) # Set up logging logger = logging.getLogger() logger.setLevel(logging.INFO) if args.use_curses: logger.addHandler(log.DialogHandler()) displayer = display_util.NcursesDisplay() else: displayer = display_util.FileDisplay(sys.stdout) zope.component.provideUtility(displayer) if args.view_config_changes: client.view_config_changes(config) sys.exit() if args.revoke or args.rev_cert is not None or args.rev_key is not None: client.revoke(config, args.no_confirm, args.rev_cert, args.rev_key) sys.exit() if args.rollback > 0: client.rollback(args.rollback, config) sys.exit() if not args.eula: display_eula() all_auths = init_auths(config) logging.debug('Initialized authenticators: %s', all_auths.keys()) try: auth = client.determine_authenticator(all_auths, config) logging.debug("Selected authenticator: %s", auth) except errors.LetsEncryptClientError as err: logging.critical(str(err)) sys.exit(1) if auth is None: sys.exit(0) # Use the same object if possible if interfaces.IInstaller.providedBy(auth): # pylint: disable=no-member installer = auth else: # This is simple and avoids confusion right now. installer = None if args.domains is None: doms = display_ops.choose_names(installer) else: doms = args.domains if not doms: sys.exit(0) # Prepare for init of Client if args.authkey is None: authkey = client.init_key(args.rsa_key_size, config.key_dir) else: authkey = le_util.Key(args.authkey[0], args.authkey[1]) acme = client.Client(config, authkey, auth, installer) # Validate the key and csr client.validate_key_csr(authkey) # This more closely mimics the capabilities of the CLI # It should be possible for reconfig only, install-only, no-install # I am not sure the best way to handle all of the unimplemented abilities, # but this code should be safe on all environments. cert_file = None if auth is not None: cert_file, chain_file = acme.obtain_certificate(doms) if installer is not None and cert_file is not None: acme.deploy_certificate(doms, authkey, cert_file, chain_file) if installer is not None: acme.enhance_config(doms, args.redirect)
def main(): # pylint: disable=too-many-branches """Command line argument parsing and main script execution.""" # note: arg parser internally handles --help (and exits afterwards) args = create_parser().parse_args() config = configuration.NamespaceConfig(args) # note: check is done after arg parsing as --help should work w/o root also. if not os.geteuid() == 0: sys.exit( "{0}Root is required to run letsencrypt. Please use sudo.{0}". format(os.linesep)) # Set up logging logger = logging.getLogger() logger.setLevel(logging.INFO) if args.use_curses: logger.addHandler(log.DialogHandler()) displayer = display.NcursesDisplay() else: displayer = display.FileDisplay(sys.stdout) zope.component.provideUtility(displayer) if args.view_config_changes: client.view_config_changes(config) sys.exit() if args.revoke: client.revoke(config) sys.exit() if args.rollback > 0: client.rollback(args.rollback, config) sys.exit() if not args.eula: display_eula() # Make sure we actually get an installer that is functioning properly # before we begin to try to use it. try: installer = client.determine_installer(config) except errors.LetsEncryptMisconfigurationError as err: logging.fatal( "Please fix your configuration before proceeding. " "The Installer exited with the following message: " "%s", err) sys.exit(1) # Use the same object if possible if interfaces.IAuthenticator.providedBy(installer): # pylint: disable=no-member auth = installer else: auth = client.determine_authenticator(config) doms = choose_names(installer) if args.domains is None else args.domains # Prepare for init of Client if args.privkey is None: privkey = client.init_key(args.rsa_key_size, config.key_dir) else: privkey = le_util.Key(args.privkey[0], args.privkey[1]) acme = client.Client(config, privkey, auth, installer) # Validate the key and csr client.validate_key_csr(privkey) # This more closely mimics the capabilities of the CLI # It should be possible for reconfig only, install-only, no-install # I am not sure the best way to handle all of the unimplemented abilities, # but this code should be safe on all environments. if auth is not None: cert_file, chain_file = acme.obtain_certificate(doms) if installer is not None and cert_file is not None: acme.deploy_certificate(doms, privkey, cert_file, chain_file) if installer is not None: acme.enhance_config(doms, args.redirect)