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 achall1 = achallenges.KeyAuthorizationAnnotatedChallenge( challb=messages.ChallengeBody( chall=challenges.TLSSNI01(token="kNdwjwOeX0I_A8DXt9Msmg"), uri="https://ca.org/chall0_uri", status=messages.Status("pending"), ), domain="localhost", account_key=self.rsa512jwk) achall2 = achallenges.KeyAuthorizationAnnotatedChallenge( challb=messages.ChallengeBody( chall=challenges.TLSSNI01(token="m8TdO1qik4JVFtgPPurJmg"), uri="https://ca.org/chall1_uri", status=messages.Status("pending"), ), domain="example.com", account_key=self.rsa512jwk) dvsni_ret_val = [ achall1.response(self.rsa512jwk), achall2.response(self.rsa512jwk), ] 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)
class TLSSNI01Test(unittest.TestCase): """Tests for letsencrypt.plugins.common.TLSSNI01.""" auth_key = jose.JWKRSA.load(test_util.load_vector("rsa512_key.pem")) achalls = [ achallenges.KeyAuthorizationAnnotatedChallenge( challb=acme_util.chall_to_challb( challenges.TLSSNI01(token=b'token1'), "pending"), domain="encryption-example.demo", account_key=auth_key), achallenges.KeyAuthorizationAnnotatedChallenge( challb=acme_util.chall_to_challb( challenges.TLSSNI01(token=b'token2'), "pending"), domain="letsencrypt.demo", account_key=auth_key), ] def setUp(self): from letsencrypt.plugins.common import TLSSNI01 self.sni = TLSSNI01(configurator=mock.MagicMock()) def test_add_chall(self): self.sni.add_chall(self.achalls[0], 0) self.assertEqual(1, len(self.sni.achalls)) self.assertEqual([0], self.sni.indices) def test_setup_challenge_cert(self): # This is a helper function that can be used for handling # open context managers more elegantly. It avoids dealing with # __enter__ and __exit__ calls. # http://www.voidspace.org.uk/python/mock/helpers.html#mock.mock_open mock_open, mock_safe_open = mock.mock_open(), mock.mock_open() response = challenges.TLSSNI01Response() achall = mock.MagicMock() key = test_util.load_pyopenssl_private_key("rsa512_key.pem") achall.response_and_validation.return_value = (response, ( test_util.load_cert("cert.pem"), key)) with mock.patch("letsencrypt.plugins.common.open", mock_open, create=True): with mock.patch("letsencrypt.plugins.common.le_util.safe_open", mock_safe_open): # pylint: disable=protected-access self.assertEqual( response, self.sni._setup_challenge_cert(achall, "randomS1")) # pylint: disable=no-member mock_open.assert_called_once_with(self.sni.get_cert_path(achall), "wb") mock_open.return_value.write.assert_called_once_with( test_util.load_vector("cert.pem")) mock_safe_open.assert_called_once_with(self.sni.get_key_path(achall), "wb", chmod=0o400) mock_safe_open.return_value.write.assert_called_once_with( OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key))
def test_start_responding(self, token): """ Calling ``start_responding`` makes an appropriate entry appear in the host map. """ ckey = RSA_KEY_512_RAW challenge = challenges.TLSSNI01(token=token) response = challenge.response(RSA_KEY_512) server_name = response.z_domain.decode('ascii') host_map = {} responder = TLSSNI01Responder() responder._generate_private_key = lambda key_type: ckey wrapped_host_map = responder.wrap_host_map(host_map) self.assertThat(wrapped_host_map, Not(Contains(server_name))) responder.start_responding(u'example.com', challenge, response) self.assertThat( wrapped_host_map.get(server_name.encode('utf-8')).certificate, MatchesPredicate(response.verify_cert, '%r does not verify')) # Starting twice before stopping doesn't break things responder.start_responding(u'example.com', challenge, response) self.assertThat( wrapped_host_map.get(server_name.encode('utf-8')).certificate, MatchesPredicate(response.verify_cert, '%r does not verify')) responder.stop_responding(u'example.com', challenge, response) self.assertThat(wrapped_host_map, Not(Contains(server_name)))
def test_perform_and_cleanup(self, mock_revert, mock_restart, mock_http_perform, mock_tls_perform): # Only tests functionality specific to configurator.perform # Note: As more challenges are offered this will have to be expanded achall1 = achallenges.KeyAuthorizationAnnotatedChallenge( challb=messages.ChallengeBody( chall=challenges.TLSSNI01(token=b"kNdwjwOeX0I_A8DXt9Msmg"), uri="https://ca.org/chall0_uri", status=messages.Status("pending"), ), domain="localhost", account_key=self.rsa512jwk) achall2 = achallenges.KeyAuthorizationAnnotatedChallenge( challb=messages.ChallengeBody( chall=challenges.HTTP01(token=b"m8TdO1qik4JVFtgPPurJmg"), uri="https://ca.org/chall1_uri", status=messages.Status("pending"), ), domain="example.com", account_key=self.rsa512jwk) expected = [ achall1.response(self.rsa512jwk), achall2.response(self.rsa512jwk), ] mock_tls_perform.return_value = expected[:1] mock_http_perform.return_value = expected[1:] responses = self.config.perform([achall1, achall2]) self.assertEqual(mock_tls_perform.call_count, 1) self.assertEqual(mock_http_perform.call_count, 1) self.assertEqual(responses, expected) self.config.cleanup([achall1, achall2]) self.assertEqual(0, self.config._chall_out) # pylint: disable=protected-access self.assertEqual(mock_revert.call_count, 1) self.assertEqual(mock_restart.call_count, 2)
def get_achalls(self): """Return testing achallenges.""" account_key = self.rsa512jwk achall1 = achallenges.KeyAuthorizationAnnotatedChallenge( challb=acme_util.chall_to_challb( challenges.TLSSNI01( token="jIq_Xy1mXGN37tb4L6Xj_es58fW571ZNyXekdZzhh7Q"), "pending"), domain="encryption-example.demo", account_key=account_key) achall2 = achallenges.KeyAuthorizationAnnotatedChallenge( challb=acme_util.chall_to_challb( challenges.TLSSNI01( token="uqnaPzxtrndteOqtrXb0Asl5gOJfWAnnx6QJyvcmlDU"), "pending"), domain="certbot.demo", account_key=account_key) return account_key, achall1, achall2
def _create_achalls(plugin): """Returns a list of annotated challenges to test on plugin""" achalls = list() names = plugin.get_testable_domain_names() for domain in names: prefs = plugin.get_chall_pref(domain) for chall_type in prefs: if chall_type == challenges.TLSSNI01: chall = challenges.TLSSNI01( token=os.urandom(challenges.TLSSNI01.TOKEN_SIZE)) challb = acme_util.chall_to_challb(chall, messages.STATUS_PENDING) achall = achallenges.KeyAuthorizationAnnotatedChallenge( challb=challb, domain=domain, account_key=util.JWK) achalls.append(achall) return achalls
def test_cert_verifies(self, token): """ The certificates generated verify using `~acme.challenges.TLSSNI01Response.verify_cert`. """ ckey = RSA_KEY_512_RAW challenge = challenges.TLSSNI01(token=token) response = challenge.response(RSA_KEY_512) server_name = response.z_domain.decode('ascii') cert, pkey = generate_tls_sni_01_cert( server_name, _generate_private_key=lambda key_type: ckey) self.assertThat(cert, ValidForName(server_name)) ocert = crypto.X509.from_cryptography(cert) self.assertThat( decode(ocert.digest('sha256').replace(b':', b''), 'hex'), Equals(cert.fingerprint(hashes.SHA256()))) okey = crypto.PKey.from_cryptography_key(pkey) # TODO: Can we assert more here? self.assertThat(okey.bits(), Equals(pkey.key_size)) self.assertThat(response.verify_cert(ocert), Equals(True)) verify_hostname(NotAConnection(ocert), server_name)
class TlsSniPerformTest(util.NginxTest): """Test the NginxTlsSni01 challenge.""" account_key = common_test.TLSSNI01Test.auth_key achalls = [ achallenges.KeyAuthorizationAnnotatedChallenge( challb=acme_util.chall_to_challb( challenges.TLSSNI01(token="kNdwjwOeX0I_A8DXt9Msmg"), "pending"), domain="www.example.com", account_key=account_key), achallenges.KeyAuthorizationAnnotatedChallenge( challb=acme_util.chall_to_challb( challenges.TLSSNI01( token="\xba\xa9\xda?<m\xaewmx\xea\xad\xadv\xf4\x02\xc9y" "\x80\xe2_X\t\xe7\xc7\xa4\t\xca\xf7&\x945" ), "pending"), domain="blah", account_key=account_key), achallenges.KeyAuthorizationAnnotatedChallenge( challb=acme_util.chall_to_challb( challenges.TLSSNI01( token="\x8c\x8a\xbf_-f\\cw\xee\xd6\xf8/\xa5\xe3\xfd" "\xeb9\xf1\xf5\xb9\xefVM\xc9w\xa4u\x9c\xe1\x87\xb4" ), "pending"), domain="www.example.org", account_key=account_key), ] def setUp(self): super(TlsSniPerformTest, self).setUp() config = util.get_nginx_configurator( self.config_path, self.config_dir, self.work_dir) from letsencrypt_nginx import tls_sni_01 self.sni = tls_sni_01.NginxTlsSni01(config) def tearDown(self): shutil.rmtree(self.temp_dir) shutil.rmtree(self.config_dir) shutil.rmtree(self.work_dir) @mock.patch("letsencrypt_nginx.configurator" ".NginxConfigurator.choose_vhost") def test_perform(self, mock_choose): self.sni.add_chall(self.achalls[1]) mock_choose.return_value = None result = self.sni.perform() self.assertTrue(result is None) def test_perform0(self): responses = self.sni.perform() self.assertEqual([], responses) @mock.patch("letsencrypt_nginx.configurator.NginxConfigurator.save") def test_perform1(self, mock_save): self.sni.add_chall(self.achalls[0]) response = self.achalls[0].response(self.account_key) mock_setup_cert = mock.MagicMock(return_value=response) # pylint: disable=protected-access self.sni._setup_challenge_cert = mock_setup_cert responses = self.sni.perform() mock_setup_cert.assert_called_once_with(self.achalls[0]) self.assertEqual([response], responses) self.assertEqual(mock_save.call_count, 2) # Make sure challenge config is included in main config http = self.sni.configurator.parser.parsed[ self.sni.configurator.parser.loc["root"]][-1] self.assertTrue( util.contains_at_depth(http, ['include', self.sni.challenge_conf], 1)) def test_perform2(self): acme_responses = [] for achall in self.achalls: self.sni.add_chall(achall) acme_responses.append(achall.response(self.account_key)) mock_setup_cert = mock.MagicMock(side_effect=acme_responses) # pylint: disable=protected-access self.sni._setup_challenge_cert = mock_setup_cert sni_responses = self.sni.perform() self.assertEqual(mock_setup_cert.call_count, 3) for index, achall in enumerate(self.achalls): self.assertEqual( mock_setup_cert.call_args_list[index], mock.call(achall)) http = self.sni.configurator.parser.parsed[ self.sni.configurator.parser.loc["root"]][-1] self.assertTrue(['include', self.sni.challenge_conf] in http[1]) self.assertTrue( util.contains_at_depth(http, ['server_name', 'blah'], 3)) self.assertEqual(len(sni_responses), 3) for i in xrange(3): self.assertEqual(sni_responses[i], acme_responses[i]) def test_mod_config(self): self.sni.add_chall(self.achalls[0]) self.sni.add_chall(self.achalls[2]) v_addr1 = [obj.Addr("69.50.225.155", "9000", True, False), obj.Addr("127.0.0.1", "", False, False)] v_addr2 = [obj.Addr("myhost", "", False, True)] ll_addr = [v_addr1, v_addr2] self.sni._mod_config(ll_addr) # pylint: disable=protected-access self.sni.configurator.save() self.sni.configurator.parser.load() http = self.sni.configurator.parser.parsed[ self.sni.configurator.parser.loc["root"]][-1] self.assertTrue(['include', self.sni.challenge_conf] in http[1]) vhosts = self.sni.configurator.parser.get_vhosts() vhs = [vh for vh in vhosts if vh.filep == self.sni.challenge_conf] for vhost in vhs: if vhost.addrs == set(v_addr1): response = self.achalls[0].response(self.account_key) else: response = self.achalls[2].response(self.account_key) self.assertEqual(vhost.addrs, set(v_addr2)) self.assertEqual(vhost.names, set([response.z_domain])) self.assertEqual(len(vhs), 2) def test_mod_config_fail(self): root = self.sni.configurator.parser.loc["root"] self.sni.configurator.parser.parsed[root] = [['include', 'foo.conf']] # pylint: disable=protected-access self.assertRaises( errors.MisconfigurationError, self.sni._mod_config, [])
"""ACME utilities for testing.""" import datetime import itertools from acme import challenges from acme import jose from acme import messages from letsencrypt.tests import test_util KEY = test_util.load_rsa_private_key('rsa512_key.pem') # Challenges HTTP01 = challenges.HTTP01(token="evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ+PCt92wr+oA") TLSSNI01 = challenges.TLSSNI01( token=jose.b64decode(b"evaGxfADs6pSRb2LAv9IZf17Dt3juxGJyPCt92wrDoA")) DNS = challenges.DNS(token="17817c66b60ce2e4012dfad92657527a") CHALLENGES = [HTTP01, TLSSNI01, DNS] def gen_combos(challbs): """Generate natural combinations for challbs.""" # completing a single DV challenge satisfies the CA return tuple((i, ) for i, _ in enumerate(challbs)) def chall_to_challb(chall, status): # pylint: disable=redefined-outer-name """Return ChallengeBody from Challenge.""" kwargs = { "chall": chall,
import josepy as jose import mock from acme import challenges from certbot import achallenges from certbot import crypto_util from certbot import errors from certbot.compat import os from certbot.tests import acme_util from certbot.tests import util as test_util AUTH_KEY = jose.JWKRSA.load(test_util.load_vector("rsa512_key.pem")) ACHALLS = [ achallenges.KeyAuthorizationAnnotatedChallenge( challb=acme_util.chall_to_challb(challenges.TLSSNI01(token=b'token1'), "pending"), domain="encryption-example.demo", account_key=AUTH_KEY), achallenges.KeyAuthorizationAnnotatedChallenge( challb=acme_util.chall_to_challb(challenges.TLSSNI01(token=b'token2'), "pending"), domain="certbot.demo", account_key=AUTH_KEY), ] class NamespaceFunctionsTest(unittest.TestCase): """Tests for certbot.plugins.common.*_namespace functions.""" def test_option_namespace(self): from certbot.plugins.common import option_namespace
from acme import challenges from certbot import achallenges from certbot import crypto_util from certbot import errors from certbot.compat import os from certbot.compat import filesystem from certbot.tests import acme_util from certbot.tests import util as test_util AUTH_KEY = jose.JWKRSA.load(test_util.load_vector("rsa512_key.pem")) ACHALLS = [ achallenges.KeyAuthorizationAnnotatedChallenge( challb=acme_util.chall_to_challb( challenges.TLSSNI01(token=b'token1'), "pending"), domain="encryption-example.demo", account_key=AUTH_KEY), achallenges.KeyAuthorizationAnnotatedChallenge( challb=acme_util.chall_to_challb( challenges.TLSSNI01(token=b'token2'), "pending"), domain="certbot.demo", account_key=AUTH_KEY), ] class NamespaceFunctionsTest(unittest.TestCase): """Tests for certbot.plugins.common.*_namespace functions.""" def test_option_namespace(self): from certbot.plugins.common import option_namespace self.assertEqual("foo-", option_namespace("foo")) def test_dest_namespace(self):