def no_localhost_san_server( tmp_path_factory: pytest.TempPathFactory, ) -> Generator[ServerConfig, None, None]: tmpdir = tmp_path_factory.mktemp("certs") ca = trustme.CA() # non localhost common name server_cert = ca.issue_cert("example.com") with run_server_in_thread("https", "localhost", tmpdir, ca, server_cert) as cfg: yield cfg
def ip_san_server( tmp_path_factory: pytest.TempPathFactory, ) -> Generator[ServerConfig, None, None]: tmpdir = tmp_path_factory.mktemp("certs") ca = trustme.CA() # IP address in Subject Alternative Name server_cert = ca.issue_cert("127.0.0.1") with run_server_in_thread("https", "127.0.0.1", tmpdir, ca, server_cert) as cfg: yield cfg
def ipv6_san_server(tmp_path_factory): if not HAS_IPV6: pytest.skip("Only runs on IPv6 systems") tmpdir = tmp_path_factory.mktemp("certs") ca = trustme.CA() # IP address in Subject Alternative Name server_cert = ca.issue_cert(u"::1") with run_server_in_thread("https", "::1", tmpdir, ca, server_cert) as cfg: yield cfg
def no_san_proxy_with_server( tmp_path_factory: pytest.TempPathFactory, ) -> Generator[Tuple[ServerConfig, ServerConfig], None, None]: tmpdir = tmp_path_factory.mktemp("certs") ca = trustme.CA() # only common name, no subject alternative names proxy_cert = ca.issue_cert(common_name="localhost") server_cert = ca.issue_cert("localhost") with run_server_and_proxy_in_thread("https", "localhost", tmpdir, ca, proxy_cert, server_cert) as cfg: yield cfg
def ipv6_no_san_server( tmp_path_factory: pytest.TempPathFactory, ) -> Generator[ServerConfig, None, None]: if not HAS_IPV6: pytest.skip("Only runs on IPv6 systems") tmpdir = tmp_path_factory.mktemp("certs") ca = trustme.CA() # IP address in Common Name server_cert = ca.issue_cert(common_name="::1") with run_server_in_thread("https", "::1", tmpdir, ca, server_cert) as cfg: yield cfg
def ipv6_san_proxy_with_server( tmp_path_factory: pytest.TempPathFactory, ) -> Generator[Tuple[ServerConfig, ServerConfig], None, None]: tmpdir = tmp_path_factory.mktemp("certs") ca = trustme.CA() # IP addresses in Subject Alternative Name proxy_cert = ca.issue_cert("::1") server_cert = ca.issue_cert("localhost") with run_server_and_proxy_in_thread("https", "::1", tmpdir, ca, proxy_cert, server_cert) as cfg: yield cfg
async def test_serve_ssl(nursery): server_context = trio.ssl.create_default_context( trio.ssl.Purpose.CLIENT_AUTH) client_context = trio.ssl.create_default_context() ca = trustme.CA() ca.configure_trust(client_context) cert = ca.issue_server_cert(HOST) cert.configure_cert(server_context) server = await nursery.start(serve_websocket, echo_handler, HOST, 0, server_context) port = server.port async with open_websocket(HOST, port, RESOURCE, client_context) as conn: assert not conn.is_closed
def test_get_cbt_data(self, mock_get_server_cert): cert_bytes = trustme.CA().cert_pem.bytes() mock_get_server_cert.return_value = cert_bytes response = HTTPResponse() cbt_data = requests_ntlm2.core.get_cbt_data(response) mock_get_server_cert.assert_called_once_with(response) assert isinstance( cbt_data, ntlm_auth.gss_channel_bindings.GssChannelBindingsStruct) key = ntlm_auth.gss_channel_bindings.GssChannelBindingsStruct.APPLICATION_DATA assert cbt_data.fields[key] == b"tls-server-end-point:" + cert_bytes assert cbt_data.get_data().startswith( b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x05\x00\x00" b"tls-server-end-point:")
def httpserver_ssl_context(): ca = trustme.CA() client_context = ssl.SSLContext() server_context = ssl.SSLContext() server_cert = ca.issue_cert("test-host.example.org") ca.configure_trust(client_context) server_cert.configure_cert(server_context) def default_context(): return client_context ssl._create_default_https_context = default_context return server_context
async def asyncSetUp(self) -> None: await super().asyncSetUp() # Create and place the self-signed certificate for openresty to use. fake_ca = trustme.CA() server_cert = fake_ca.issue_cert("127.0.0.1", "localhost") cert_path = Path(self.config_sec["client"]["server_cert"]) first_in_chain = True for pem in server_cert.cert_chain_pems: pem.write_to_path(cert_path, append=not first_in_chain) first_in_chain = False fake_ca.cert_pem.write_to_path(cert_path, append=True) key_path = cert_path.parent / "resty-auto-ssl-fallback.key" server_cert.private_key_pem.write_to_path(key_path) # The environment variable is set to the server cert so that the requests module uses it (certbot). import os os.environ["REQUESTS_CA_BUNDLE"] = self.config_sec["client"][ "server_cert"] # Disable SSL verification for urllib3 (acmetiny). import ssl ssl._create_default_https_context = ssl._create_unverified_context # Disable resty-auto-ssl with open("/usr/local/bin/resty-auto-ssl/dehydrated", "w") as f: f.write("echo 1;") self.nginx_proc = await asyncio.create_subprocess_shell( '/usr/local/openresty/nginx/sbin/nginx -g "daemon off; master_process on;"', None, None, ) runner, ca = await AcmeCA.runner(self.config_sec["ca"]) ca.register_challenge_validator(RequestIPDNSChallengeValidator()) await ca._db._recreate() aiohttp_jinja2.setup(ca.app, loader=jinja2.FileSystemLoader("../tpl/")) aiohttp_jinja2.get_env(ca.app).globals.update({"url_for": _url_for}) self.runner = runner
def main(): here = pathlib.Path(__file__).parent ca_path = here / 'fake.ca.pem' server_path = here / 'fake.server.pem' if ca_path.exists() and server_path.exists(): print('The CA ceritificate and server certificate already exist.') sys.exit(1) print('Creating self-signed certificate for localhost/127.0.0.1:') ca_cert = trustme.CA() ca_cert.cert_pem.write_to_path(ca_path) print(' * CA certificate: {}'.format(ca_path)) server_cert = ca_cert.issue_server_cert('localhost', '127.0.0.1') server_cert.private_key_and_cert_chain_pem.write_to_path(server_path) print(' * Server certificate: {}'.format(server_path)) print('Done')
def setup_class(cls): super().setup_class() cls.http_url = f"http://{cls.http_host}:{int(cls.http_port)}" cls.http_url_alt = f"http://{cls.http_host_alt}:{int(cls.http_port)}" cls.https_url = f"https://{cls.https_host}:{int(cls.https_port)}" cls.https_url_alt = f"https://{cls.https_host_alt}:{int(cls.https_port)}" cls.proxy_url = f"http://{cls.proxy_host}:{int(cls.proxy_port)}" cls.https_proxy_url = f"https://{cls.proxy_host}:{int(cls.https_proxy_port)}" # Generate another CA to test verification failure cls.certs_dir = tempfile.mkdtemp() bad_ca = trustme.CA() cls.bad_ca_path = os.path.join(cls.certs_dir, "ca_bad.pem") bad_ca.cert_pem.write_to_path(cls.bad_ca_path)
def setup_class(cls): super(TestHTTPProxyManager, cls).setup_class() cls.http_url = "http://%s:%d" % (cls.http_host, cls.http_port) cls.http_url_alt = "http://%s:%d" % (cls.http_host_alt, cls.http_port) cls.https_url = "https://%s:%d" % (cls.https_host, cls.https_port) cls.https_url_alt = "https://%s:%d" % (cls.https_host_alt, cls.https_port) cls.proxy_url = "http://%s:%d" % (cls.proxy_host, cls.proxy_port) # Generate another CA to test verification failure cls.certs_dir = tempfile.mkdtemp() bad_ca = trustme.CA() cls.bad_ca_path = os.path.join(cls.certs_dir, "ca_bad.pem") bad_ca.cert_pem.write_to_path(cls.bad_ca_path)
def test_https_impostor_works_with_cert_supplied(mock_server): ca = trustme.CA() server_cert = ca.issue_cert("localhost") imposter = Imposter( Stub(Predicate(path="/test"), Response(body="sausages")), protocol=Imposter.Protocol.HTTPS, mutual_auth=True, key=server_cert.private_key_pem.bytes().decode("utf-8"), cert=server_cert.cert_chain_pems[0].bytes().decode("utf-8"), ) with mock_server(imposter), ca.cert_pem.tempfile() as certfile: response = requests.get(f"{imposter.url}/test", verify=certfile) assert_that(response, is_response().with_status_code(200).and_body("sausages"))
def main(): if len(sys.argv) != 2: logging.error('Usage: %s <hostname>', sys.argv[0]) sys.exit(1) hostname = sys.argv[1] here = pathlib.Path(__file__).parent ca_path = here / 'ca.crt' server_path = here / 'server.crt' logging.info('Creating self-signed certificate for "%s"', hostname) ca_cert = trustme.CA() ca_cert.cert_pem.write_to_path(ca_path) logging.info(' * CA certificate: {}'.format(ca_path)) server_cert = ca_cert.issue_server_cert(hostname) server_cert.private_key_and_cert_chain_pem.write_to_path(server_path) logging.info(' * Server certificate: {}'.format(server_path)) logging.info('Done')
def nosan_server(tmp_path_factory): tmpdir = tmp_path_factory.mktemp("certs") ca = trustme.CA() # only commonName, no subjectAltName server_cert = ca.issue_cert(common_name=u"localhost") ca_bundle = str(tmpdir / "ca.pem") ca.cert_pem.write_to_path(ca_bundle) context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) server_cert.configure_cert(context) server = HTTPServer(("localhost", 0), SimpleHTTPRequestHandler) server.socket = context.wrap_socket(server.socket, server_side=True) server_thread = threading.Thread(target=server.serve_forever) server_thread.start() yield "localhost", server.server_address[1], ca_bundle server.shutdown() server_thread.join()
def setup_class(cls): cls.tmpdir = tempfile.mkdtemp("certs") ca = trustme.CA() # only common name, no subject alternative names server_cert = ca.issue_cert(common_name=u"localhost") cls.ca_certs = os.path.join(cls.tmpdir, "ca.pem") cls.server_cert_path = os.path.join(cls.tmpdir, "server.pem") cls.server_key_path = os.path.join(cls.tmpdir, "server.key") ca.cert_pem.write_to_path(cls.ca_certs) server_cert.private_key_pem.write_to_path(cls.server_key_path) server_cert.cert_chain_pems[0].write_to_path(cls.server_cert_path) cls.certs = { "keyfile": cls.server_key_path, "certfile": cls.server_cert_path } super(TestHTTPS_NoSAN, cls)._start_server()
def test_custom_auth_subscription(self): ca = trustme.CA() with ca.cert_pem.tempfile() as ca_temp_path: os.environ["NGAS_CA_PATH"] = ca_temp_path server_cert = ca.issue_cert( u"localhost", six.u(getHostName()), u"127.0.0.1", ) cert_file = genTmpFilename(suffix='pem') server_cert.private_key_and_cert_chain_pem.write_to_path(cert_file) # We configure the second server to send notifications via socket # to the listener we start later auth_plugin_cfg = (("NgamsCfg.SubscriptionAuth[1].PlugInName", 'test.support.subscription_auth_plugin'), ) self._prep_subscription_cluster( (8778, auth_plugin_cfg, False), (8779, [], True), cert_file=cert_file, ) subscription_listener = self.upload_subscription_files(8778, 8779) # Create subscription params = { 'url': 'https://localhost:8779/QARCHIVE', 'subscr_id': 'HERE-TO-THERE', 'priority': 1, 'start_date': '%sT00:00:00.000' % time.strftime("%Y-%m-%d"), 'concurrent_threads': 1 } self.assertEqual( requests.get( "https://127.0.0.1:8778/SUBSCRIBE", params=params, verify=ca_temp_path, ).status_code, 200) self.check_subscription_transfer(subscription_listener, 8779) del os.environ["NGAS_CA_PATH"]
def no_san_server(tmp_path_factory): tmpdir = tmp_path_factory.mktemp("certs") ca = trustme.CA() # only common name, no subject alternative names server_cert = ca.issue_cert(common_name=u"localhost") ca_cert_path = str(tmpdir / "ca.pem") server_cert_path = str(tmpdir / "server.pem") server_key_path = str(tmpdir / "server.key") ca.cert_pem.write_to_path(ca_cert_path) server_cert.private_key_pem.write_to_path(server_key_path) server_cert.cert_chain_pems[0].write_to_path(server_cert_path) with run_server_in_thread( "https", "localhost", ca_cert_path, {"keyfile": server_key_path, "certfile": server_cert_path}, ) as cfg: yield cfg
def ip_san_server(tmp_path_factory): tmpdir = tmp_path_factory.mktemp("certs") ca = trustme.CA() # IP address in Subject Alternative Name server_cert = ca.issue_cert(u"127.0.0.1") ca_cert_path = str(tmpdir / "ca.pem") server_cert_path = str(tmpdir / "server.pem") server_key_path = str(tmpdir / "server.key") ca.cert_pem.write_to_path(ca_cert_path) server_cert.private_key_pem.write_to_path(server_key_path) server_cert.cert_chain_pems[0].write_to_path(server_cert_path) with run_server_in_thread( "https", "127.0.0.1", ca_cert_path, {"keyfile": server_key_path, "certfile": server_cert_path}, ) as cfg: yield cfg
def setup_class(cls): super(TestHTTPProxyManager, cls).setup_class() cls.http_url = "http://%s:%d" % (cls.http_host, cls.http_port) cls.http_url_alt = "http://%s:%d" % (cls.http_host_alt, cls.http_port) cls.https_url = "https://%s:%d" % (cls.https_host, cls.https_port) cls.https_url_alt = "https://%s:%d" % (cls.https_host_alt, cls.https_port) cls.proxy_url = "http://%s:%d" % (cls.proxy_host, cls.proxy_port) # This URL is used only to test that a warning is # raised due to an improper config. urllib3 doesn't # support HTTPS proxies in v1.25.* cls.https_proxy_url = "https://%s:%d" % (cls.proxy_host, cls.proxy_port) # Generate another CA to test verification failure cls.certs_dir = tempfile.mkdtemp() bad_ca = trustme.CA() cls.bad_ca_path = os.path.join(cls.certs_dir, "ca_bad.pem") bad_ca.cert_pem.write_to_path(cls.bad_ca_path)
def ssl_conf(request): @attr.s class SSLConf: @property def use_ssl(self): return bool(self.backend_opts) client_env = attr.ib(factory=dict) backend_opts = attr.ib(default="") if not request.param: yield SSLConf() else: ca = trustme.CA() server_cert = ca.issue_cert("localhost") with ca.cert_pem.tempfile() as ca_certfile, server_cert.cert_chain_pems[ 0 ].tempfile() as server_certfile, server_cert.private_key_pem.tempfile() as server_keyfile: yield SSLConf( backend_opts=f" --ssl-keyfile={server_keyfile} --ssl-certfile={server_certfile} ", client_env={"SSL_CAFILE": ca_certfile}, )
def nosan_server(tmp_path_factory): # delay importing until the fixture in order to make it possible # to deselect the test via command-line when trustme is not available import trustme tmpdir = tmp_path_factory.mktemp("certs") ca = trustme.CA() # only commonName, no subjectAltName server_cert = ca.issue_cert(common_name="localhost") ca_bundle = str(tmpdir / "ca.pem") ca.cert_pem.write_to_path(ca_bundle) context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) server_cert.configure_cert(context) server = HTTPServer(("localhost", 0), SimpleHTTPRequestHandler) server.socket = context.wrap_socket(server.socket, server_side=True) server_thread = threading.Thread(target=server.serve_forever) server_thread.start() yield "localhost", server.server_address[1], ca_bundle server.shutdown() server_thread.join()
def cert_authority(): return trustme.CA()
def tls_certificate_authority() -> trustme.CA: return trustme.CA()
import os import pytest import subprocess import ssl import time import trustme import bmemcached import test_simple_functions ca = trustme.CA() server_cert = ca.issue_cert(os.environ["MEMCACHED_HOST"] + u"") @pytest.yield_fixture(scope="module", autouse=True) def memcached_tls(): key = server_cert.private_key_pem cert = server_cert.cert_chain_pems[0] with cert.tempfile() as c, key.tempfile() as k: p = subprocess.Popen( [ "memcached", "-p5001", "-Z", "-o", "ssl_key={}".format(k), "-o", "ssl_chain_cert={}".format(c), "-o",
def tls_certificate_authority() -> Any: if not TRUSTME: pytest.xfail("trustme fails on 32bit Linux") return trustme.CA()
def main(argv=None): if argv is None: argv = sys.argv[1:] parser = argparse.ArgumentParser(prog="trustme") parser.add_argument( "-d", "--dir", default=os.getcwd(), help= "Directory where certificates and keys are written to. Defaults to cwd.", ) parser.add_argument( "-i", "--identities", nargs="*", default=("localhost", "127.0.0.1", "::1"), help= "Identities for the certificate. Defaults to 'localhost 127.0.0.1 ::1'.", ) parser.add_argument( "--common-name", nargs=1, default=None, help= "Also sets the deprecated 'commonName' field (only for the first identity passed).", ) parser.add_argument( "-x", "--expires-on", default=None, help= "Set the date the certificate will expire on (in YYYY-MM-DD format).", metavar='YYYY-MM-DD', ) parser.add_argument( "-q", "--quiet", action="store_true", help="Doesn't print out helpful information for humans.", ) args = parser.parse_args(argv) cert_dir = args.dir identities = [unicode(identity) for identity in args.identities] common_name = unicode(args.common_name[0]) if args.common_name else None expires_on = None if args.expires_on is None else datetime.strptime( args.expires_on, DATE_FORMAT) quiet = args.quiet if not os.path.isdir(cert_dir): raise ValueError("--dir={} is not a directory".format(cert_dir)) if len(identities) < 1: raise ValueError("Must include at least one identity") # Generate the CA certificate ca = trustme.CA() cert = ca.issue_cert(*identities, common_name=common_name, not_after=expires_on) # Write the certificate and private key the server should use server_key = os.path.join(cert_dir, "server.key") server_cert = os.path.join(cert_dir, "server.pem") cert.private_key_pem.write_to_path(path=server_key) with open(server_cert, mode="w") as f: f.truncate() for blob in cert.cert_chain_pems: blob.write_to_path(path=server_cert, append=True) # Write the certificate the client should trust client_cert = os.path.join(cert_dir, "client.pem") ca.cert_pem.write_to_path(path=client_cert) if not quiet: idents = "', '".join(identities) print("Generated a certificate for '{}'".format(idents)) print("Configure your server to use the following files:") print(" cert={}".format(server_cert)) print(" key={}".format(server_key)) print("Configure your client to use the following files:") print(" cert={}".format(client_cert))
# validate interoperability in a semi-realistic setting. # # The second is a very weird virtual echo server that lives inside a custom # Stream class. It lives entirely inside the Python object space; there are no # operating system calls in it at all. No threads, no I/O, nothing. It's # 'send_all' call takes encrypted data from a client and feeds it directly into # the server-side TLS state engine to decrypt, then takes that data, feeds it # back through to get the encrypted response, and returns it from 'receive_some'. This # gives us full control and reproducibility. This server is written using # PyOpenSSL, so that we can trigger renegotiations on demand. It also allows # us to insert random (virtual) delays, to really exercise all the weird paths # in SSLStream's state engine. # # Both present a certificate for "trio-test-1.example.org". TRIO_TEST_CA = trustme.CA() TRIO_TEST_1_CERT = TRIO_TEST_CA.issue_server_cert("trio-test-1.example.org") SERVER_CTX = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) if hasattr(ssl, "OP_IGNORE_UNEXPECTED_EOF"): SERVER_CTX.options &= ~ssl.OP_IGNORE_UNEXPECTED_EOF TRIO_TEST_1_CERT.configure_cert(SERVER_CTX) # TLS 1.3 has a lot of changes from previous versions. So we want to run tests # with both TLS 1.3, and TLS 1.2. # "tls13" means that we're willing to negotiate TLS 1.3. Usually that's # what will happen, but the renegotiation tests explicitly force a # downgrade on the server side. "tls12" means we refuse to negotiate TLS # 1.3, so we'll almost certainly use TLS 1.2.
def test_tls_client_auth( # FIXME: remove twisted logic, separate tests mocker, tls_http_server, adapter_type, ca, tls_certificate, tls_certificate_chain_pem_path, tls_certificate_private_key_pem_path, tls_ca_certificate_pem_path, is_trusted_cert, tls_client_identity, tls_verify_mode, ): """Verify that client TLS certificate auth works correctly.""" test_cert_rejection = (tls_verify_mode != ssl.CERT_NONE and not is_trusted_cert) interface, _host, port = _get_conn_data(ANY_INTERFACE_IPV4) client_cert_root_ca = ca if is_trusted_cert else trustme.CA() with mocker.mock_module.patch( 'idna.core.ulabel', return_value=ntob(tls_client_identity), ): client_cert = client_cert_root_ca.issue_server_cert( # FIXME: change to issue_cert once new trustme is out ntou(tls_client_identity), ) del client_cert_root_ca with client_cert.private_key_and_cert_chain_pem.tempfile() as cl_pem: tls_adapter_cls = get_ssl_adapter_class(name=adapter_type) tls_adapter = tls_adapter_cls( tls_certificate_chain_pem_path, tls_certificate_private_key_pem_path, ) if adapter_type == 'pyopenssl': tls_adapter.context = tls_adapter.get_context() tls_adapter.context.set_verify( _stdlib_to_openssl_verify[tls_verify_mode], lambda conn, cert, errno, depth, preverify_ok: preverify_ok, ) else: tls_adapter.context.verify_mode = tls_verify_mode ca.configure_trust(tls_adapter.context) tls_certificate.configure_cert(tls_adapter.context) tlshttpserver = tls_http_server.send(( (interface, port), tls_adapter, ), ) interface, _host, port = _get_conn_data(tlshttpserver.bind_addr) make_https_request = functools.partial( requests.get, 'https://' + interface + ':' + str(port) + '/', # Server TLS certificate verification: verify=tls_ca_certificate_pem_path, # Client TLS certificate verification: cert=cl_pem, ) if not test_cert_rejection: resp = make_https_request() is_req_successful = resp.status_code == 200 if (not is_req_successful and IS_PYOPENSSL_SSL_VERSION_1_0 and adapter_type == 'builtin' and tls_verify_mode == ssl.CERT_REQUIRED and tls_client_identity == 'localhost' and is_trusted_cert) or PY34: pytest.xfail( 'OpenSSL 1.0 has problems with verifying client certs', ) assert is_req_successful assert resp.text == 'Hello world!' return expected_ssl_errors = ( requests.exceptions.SSLError, OpenSSL.SSL.Error, ) if PY34 else (requests.exceptions.SSLError, ) with pytest.raises(expected_ssl_errors) as ssl_err: make_https_request() if PY34 and isinstance(ssl_err, OpenSSL.SSL.Error): pytest.xfail( 'OpenSSL behaves wierdly under Python 3.4 ' 'because of an outdated urllib3', ) try: err_text = ssl_err.value.args[0].reason.args[0].args[0] except AttributeError: if PY34: pytest.xfail('OpenSSL behaves wierdly under Python 3.4') raise expected_substrings = ('sslv3 alert bad certificate' if IS_LIBRESSL_BACKEND else 'tlsv1 alert unknown ca', ) if six.PY3: if IS_MACOS and IS_PYPY and adapter_type == 'pyopenssl': expected_substrings = ('tlsv1 alert unknown ca', ) if (IS_WINDOWS and tls_verify_mode in ( ssl.CERT_REQUIRED, ssl.CERT_OPTIONAL, ) and not is_trusted_cert and tls_client_identity == 'localhost' and adapter_type == 'builtin'): expected_substrings += ( 'bad handshake: ' "SysCallError(10054, 'WSAECONNRESET')", ) assert any(e in err_text for e in expected_substrings)