Skip to main content

#1 quality TLS certs while you wait, for the discerning tester

Project description

trustme: #1 quality TLS certs while you wait

https://vignette2.wikia.nocookie.net/jadensadventures/images/1/1e/Kaa%27s_hypnotic_eyes.jpg/revision/latest?cb=20140310173415

You wrote a cool network client or server. You encrypt your connections using TLS. Your test suite needs to make TLS connections.

Uh oh. Your test suite probably doesn’t have a valid TLS certificate. Now what?

trustme is a tiny Python package that does one thing: it gives you a fake certificate authority (CA) that you can use to generate fake TLS certs to use in your tests. Well, technically they’re real certs, they’re just signed by your CA, which nobody trusts. But you can trust it. Trust me.

Example

from trustme import CA

# Look, you just became a certificate authority
ca = CA()

# Issue a server cert, signed by your fake CA
# https://en.wikipedia.org/wiki/Example.org
server_cert = ca.issue_server_cert(u"my-test-host.example.org")

# That's it! You have your certs. Now let's see how to use them.

###########

# The simplest thing to do is to take the raw PEM certificates, and
# write them out to some files. Maybe this is useful if you want to
# use them for a test suite written in some other language.

with open("fake-ca.pem", "wb") as f:
    f.write(ca.cert_pem)
with open("fake-server-private-key-and-cert-chain.pem", "wb") as f:
    f.write(server_cert.private_key_and_cert_chain_pem)

###########

# Or, you can use them directly, for example to make a within-process
# connection between two threads.

import ssl, socket, threading

# Client side
def fake_ssl_client(raw_client_sock):
    # Get an ssl.SSLContext object configured to trust your CA
    ssl_ctx = ca.stdlib_client_context()
    wrapped_client_sock = ssl_ctx.wrap_socket(
        raw_client_sock, server_hostname="my-test-host.example.org")
    # Look, here's the cert presented by the server
    print("Client got server cert:", wrapped_client_sock.getpeercert())
    # Send some data to prove the connection is good
    wrapped_client_sock.send(b"x")

# Server side
def fake_ssl_server(raw_server_sock):
    # Get an ssl.SSLContext object configured to use your server cert
    ssl_ctx = server_cert.stdlib_server_context()
    wrapped_server_sock = ssl_ctx.wrap_socket(raw_server_sock, server_side=True)
    # Prove that we're connected
    print("server encrypted with:", wrapped_server_sock.cipher())
    assert wrapped_server_sock.recv(1) == b"x"

# Blah blah blah actually run the things
raw_client_sock, raw_server_sock = socket.socketpair()
client_thread = threading.Thread(target=fake_ssl_client, args=(raw_client_sock,))
server_thread = threading.Thread(target=fake_ssl_server, args=(raw_server_sock,))
client_thread.start()
server_thread.start()
client_thread.join()
server_thread.join()

Docs

CA() gives you a certificate authority. It has attributes .cert_pem which is a bytestring containing what it sounds like, .issue_server_cert(hostname1, [hostname2, ...]) which does what it says on the tin, and .stdlib_client_context(), which is a convenience method that returns an ssl.SSLContext object preconfigured to trust this CA.

CA.issue_server_cert returns a ServerCert object, which has attributes .private_key_pem, .cert_chain_pem, and .private_key_and_cert_chain_pem, which are bytestrings containing what they sound like. It also has a convenience method .stdlib_server_context() which returns an ssl.SSLContext object preconfigured to present this cert to any client that connects.

The .stdlib_*_context methods accept **kwargs, which are passed on to ssl.create_default_context.

Probably this should get moved into Sphinx or something but whatever, hopefully you get the idea. Or feel free to send a PR converting this into proper docs.

FAQ

Should I use these certs for anything real? Certainly not.

Why not just use self-signed certificates? These are more realistic. You don’t have to disable your certificate validation code in your test suite, which is good, because you want to test what you run in production, and you would never disable your certificate validation code in production, right? Plus they’re just as easy to work with. Maybe easier.

Why do you only have convenience methods for the stdlib ssl module, and not PyOpenSSL / Twisted / …? Because you didn’t send me a PR yet.

I want to test some weirdo TLS configuration. I’m happy to accept PRs to do simple things like override the default validity period or set key sizes or whatever, within reason. But if you have complicated needs then you’re probably better offer stealing the code from this library and adapting it to do what you want. The underlying API is pretty straightforward. This is just a convenience library for those of us who need a cheat sheet to tie our shoelaces, X.509-wise.

Vital statistics

Bug tracker and source code: https://github.com/python-trio/trustme

License: MIT or Apache 2, your choice.

Install: pip install -U trustme

Code of conduct: Contributors are requested to follow our code of conduct in all project spaces.

Acknowledgements

This is basically just a trivial wrapper around the awesome Python cryptography library. Also, Glyph wrote most of the tricky bits. I got tired of never being able to remember how this works or find the magic snippets to copy/paste, so I stole the code out of Twisted and wrapped it in a bow.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

trustme-0.1.0.tar.gz (13.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

trustme-0.1.0-py2.py3-none-any.whl (9.3 kB view details)

Uploaded Python 2Python 3

File details

Details for the file trustme-0.1.0.tar.gz.

File metadata

  • Download URL: trustme-0.1.0.tar.gz
  • Upload date:
  • Size: 13.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for trustme-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9cb7a3dd6583cfc751658d01faa6c994b4607da6bd7241f3a291babd6d62773c
MD5 c6ec3d630ce9659506661665d1200512
BLAKE2b-256 42c5829584610901dc132c46c79abca3f34ab22507aa977e11d032d86f24e446

See more details on using hashes here.

File details

Details for the file trustme-0.1.0-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for trustme-0.1.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 65d270b0d8d28cf1af96a33228d01dfe096248e2e0231070b9ddb0a4232310bd
MD5 9ac5f505bf4f4054863aa0f6f6e853fe
BLAKE2b-256 ebd476844eee31296cffa6a7bb7ac6a647b21fc51601573cd316677bb629827e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page