#!python3 import collections import os import sys import tempfile import pytest # append cwd to module importable paths (pytest-3 should be executed from main # directory). sys.path.append(os.path.realpath(".")) import acme_dns_tiny DOMAIN = os.getenv('TEST_DOMAIN') ACME_STAGING_DIRECTORY = \ 'https://acme-staging-v02.api.letsencrypt.org/directory' CONTACT = os.getenv('TEST_CONTACT') # form: mailto:name@domain def test_sanity_env(): assert DOMAIN assert CONTACT @pytest.fixture(scope='module') def casemap(tmpdir_factory): tmpdir = tmpdir_factory.mktemp("data") def _gen_key(name, size): path = str(tmpdir.join(name)) acme_dns_tiny.openssl(['genrsa', '-out', path, str(size)]) return path account_key = _gen_key('account_key', 4096) domain_key = _gen_key('domain_key', 4096) weak_account_key = _gen_key('weak_account_key', 1024) weak_domain_key = _gen_key('weak_domain_key', 1024) default_args = { '--acme-directory': ACME_STAGING_DIRECTORY, '--script': 'tests/test_script.sh', '--account-key': account_key, #'--ttl': 60, # already the default '--ttl': None, '--contact': None, #'--contact': [CONTACT], # not supported by staging directory '--verbose': None, '--quiet': None, } def _csr(name, domain_key, subj=f'/CN={DOMAIN}'): path = str(tmpdir.join(name)) acme_dns_tiny.openssl([ 'req', '-new', '-key', domain_key, '-subj', subj, '-out', path ]) return {**default_args, '--csr': path} def _san_csr(name, subj='/', san=None): path = str(tmpdir.join(name)) with tempfile.NamedTemporaryFile('w', encoding='utf8') as conf, \ open('/etc/ssl/openssl.cnf', 'r', encoding='utf8') as orig: conf.write(orig.read()) conf.write(f'\n[SAN]\nsubjectAltName={san}\n') conf.flush() acme_dns_tiny.openssl([ 'req', '-new', '-key', domain_key, '-subj', subj, '-reqexts', 'SAN', '-config', conf.name, '-out', path ]) return {**default_args, '--csr': path} return { # single domain 'single': _csr('csr_single', domain_key), # single, but weak account key used 'weakaccountkey': { **_csr('csr_simple', domain_key), '--account-key': weak_account_key, }, # single, but weak domain key used to sign csr 'weakdomainkey': _csr('csr_weakdomain', weak_domain_key), # single, csr wrongly signed by account key 'csrbyaccount': _csr('csr_byaccount', account_key), # wildcard domain in CN 'wildcard': _csr('csr_wildcard', domain_key, f'/CN=*.{DOMAIN}'), # san only 'sanonly': _san_csr('csr_sanonly', san=f'DNS:{DOMAIN},DNS:www.{DOMAIN}'), # san and cn 'san': _san_csr('csr_san', subj=f'/CN={DOMAIN}', san=f'DNS:www.{DOMAIN}'), # san wildcard (domain + *.domain, contrary to wildcard in cn) 'wildcardsan': _san_csr('csr_wildcardsan', san=f'DNS:{DOMAIN},DNS:*.{DOMAIN}') } def assert_certificate_chain(captured): #assert not captured.err certlist = captured.out.split('-----BEGIN CERTIFICATE-----') assert len(certlist) == 3 assert certlist[0] == '' assert '-----END CERTIFICATE-----\n' in certlist[1] assert '-----END CERTIFICATE-----\n' in certlist[2] textchain = acme_dns_tiny.openssl(['x509', '-text', '-noout'], stdin=captured.out) assert 'Issuer' in textchain def test_success(capsys, casemap): for name in ('single', 'wildcard', 'sanonly', 'san', 'wildcardsan'): print(f'test_success case: {name}', file=sys.stderr) acme_dns_tiny.main(casemap[name]) captured = capsys.readouterr() assert_certificate_chain(captured) def test_assert(casemap): for name in ('weakaccountkey', 'weakdomainkey', 'csrbyaccount'): print(f'test_assert case: {name}', file=sys.stderr) with pytest.raises(ValueError): acme_dns_tiny.main(casemap[name])