trustme: #1 quality TLS certs while you wait

You wrote a cool network client or server. It encrypts connections using TLS. Your test suite needs to make TLS connections to itself.

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.

Vital statistics

Install: pip install -U trustme


Bug tracker and source code:

Tested on: Python 2.7 and Python 3.5+, CPython and PyPy

License: MIT or Apache 2, your choice.

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

Cheat sheet

import trustme

# ----- Creating certs -----

# Look, you just created your own certificate authority!
ca = trustme.CA()

# And now you issued a cert signed by this fake CA
server_cert = ca.issue_cert(u"")

# That's it!

# ----- Using your shiny new certs -----

# You can configure SSL context objects to trust this CA:
# Or configure them to present the server certificate
# You can use standard library or PyOpenSSL context objects here,
# trustme is happy either way.

# ----- or -----

# Save the PEM-encoded data to a file to use in non-Python test
# suites:

# ----- or -----

# Put the PEM-encoded data in a temporary file, for libraries that
# insist on that:
with ca.cert_pem.tempfile() as ca_temp_path:
    requests.get("https://...", verify=ca_temp_path)


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. Actually easier, in many cases.

What if I want to test how my code handles some really weird TLS configuration? Sure, I’m happy to extend the API to give more control over the generated certificates, at least as long as it doesn’t turn into a second-rate re-export of everything in cryptography. (If you really need a fully general X.509 library then they do a great job at that.) Let’s talk, or send a PR.

Full working example

Here’s a fully working example you can run to see how trustme works. It demonstrates a simple TLS server and client that connect to each other using trustme-generated certs.

This example requires Trio (pip install -U trio) and Python 3.5+. Note that while trustme is maintained by the Trio project, trustme is happy to work with any networking library, and also supports Python 2.

The key lines are the calls to configure_trust(), configure_cert() – try commenting them out one at a time to see what happens! Also notice that the hostname appears twice – try changing one of the strings so that the two copies no longer match, and see what happens then!


import trustme
import trio
import ssl

# Create our fake certificates
ca = trustme.CA()
server_cert = ca.issue_cert(u"")
client_cert = ca.issue_cert(u"")

async def demo_server(server_raw_stream):
    server_ssl_context = ssl.create_default_context(

    # Set up the server's SSLContext to use our fake server cert

    # Set up the server's SSLContext to trust our fake CA, that signed
    # our client cert, so that it can validate client's cert.

    # Verify that client sent us their TLS cert signed by a trusted CA
    server_ssl_context.verify_mode = ssl.CERT_REQUIRED

    server_ssl_stream = trio.SSLStream(

    # Send some data to check that the connection is really working
    await server_ssl_stream.send_all(b"x")
    print("Server successfully sent data over the encrypted channel!")
    print("Client cert looks like:", server_ssl_stream.getpeercert())

async def demo_client(client_raw_stream):
    client_ssl_context = ssl.create_default_context()

    # Set up the client's SSLContext to trust our fake CA, that signed
    # our server cert, so that it can validate server's cert.

    # Set up the client's SSLContext to use our fake client cert

    client_ssl_stream = trio.SSLStream(
        # Tell the client that it's looking for a trusted cert for this
        # particular hostname (must match what we passed to issue_cert)

    assert await client_ssl_stream.receive_some(1) == b"x"
    print("Client successfully received data over the encrypted channel!")
    print("Server cert looks like:", client_ssl_stream.getpeercert())

async def main():
    from trio.testing import memory_stream_pair
    server_raw_stream, client_raw_stream = memory_stream_pair()

    async with trio.open_nursery() as nursery:
        nursery.start_soon(demo_server, server_raw_stream)
        nursery.start_soon(demo_client, client_raw_stream)

API reference

class trustme.CA(parent_cert=None, path_length=9)

A certificate authority.


The PEM-encoded certificate for this CA. Add this to your trust store to trust this CA.




The PEM-encoded private key for this CA. Use this to sign other certificates from this CA.




Creates a child certificate authority


the newly-generated certificate authority

Return type



ValueError – if the CA path length is 0

issue_cert(*identities, common_name=None)

Issues a certificate. The certificate can be used for either servers or clients.

All arguments must be text strings (unicode on Python 2, str on Python 3).

  • identities

    The identities that this certificate will be valid for. Most commonly, these are just hostnames, but we accept any of the following forms:

    • Regular hostname:

    • Wildcard hostname: *

    • International Domain Name (IDN): café

    • IDN in A-label form:

    • IPv4 address:

    • IPv6 address: ::1

    • IPv4 network:

    • IPv6 network: 2001::/16

    • Email address:

    These ultimately end up as “Subject Alternative Names”, which are what modern programs are supposed to use when checking identity.

  • common_name – Sets the “Common Name” of the certificate. This is a legacy field that used to be used to check identity. It’s an arbitrary string with poorly-defined semantics, so modern programs are supposed to ignore it. But it might be useful if you need to test how your software handles legacy or buggy certificates.


the newly-generated certificate.

Return type



Configure the given context object to trust certificates signed by this CA.


ctx (ssl.SSLContext or OpenSSL.SSL.Context) – The SSL context to be modified.

class trustme.LeafCert

A server or client certificate.

This type has no public constructor; you get one by calling CA.issue_cert or similar.


The PEM-encoded private key corresponding to this certificate.




The zeroth entry in this list is the actual PEM-encoded certificate, and any entries after that are the rest of the certificate chain needed to reach the root CA.


list of Blob objects


A single Blob containing the concatenation of the PEM-encoded private key and the PEM-encoded cert chain.




Configure the given context object to present this certificate.


ctx (ssl.SSLContext or OpenSSL.SSL.Context) – The SSL context to be modified.

class trustme.Blob

A convenience wrapper for a blob of bytes.

This type has no public constructor. They’re used to provide a handy interface to the PEM-encoded data generated by trustme. For example, see CA.cert_pem or LeafCert.private_key_and_cert_chain_pem.


Returns the data as a bytes object.

with tempfile(dir=None) as path

Context manager for writing data to a temporary file.

The file is created when you enter the context manager, and automatically deleted when the context manager exits.

Many libraries have annoying APIs which require that certificates be specified as filesystem paths, so even if you have already the data in memory, you have to write it out to disk and then let them read it back in again. If you encouter such a library, you should probably file a bug. But in the mean time, this context manager makes it easy to give them what they want.


Here’s how to get requests to use a trustme CA (see also):

ca = trustme.CA()
with ca.cert_pem.tempfile() as ca_cert_path:
    requests.get("https://localhost/...", verify=ca_cert_path)

dir (str or None) – Passed to tempfile.NamedTemporaryFile.

write_to_path(path, append=False)

Writes the data to the file at the given path.

  • path (str) – The path to write to.

  • append (bool) – If False (the default), replace any existing file with the given name. If True, append to any existing file.

Change history

Trustme 0.5.2 (2019-06-03)


  • Update to avoid a deprecation warning on cryptography 2.7. (#47)

Trustme 0.5.1 (2019-04-15)


  • Update key size to 2048 bits, as required by recent Debian. (#45)

Trustme 0.5.0 (2019-01-21)


  • Added CA.create_child_ca() to allow for certificate chains (#3)

  • Added CA.private_key_pem to export CA private keys; this allows signing other certs with the same CA outside of trustme. (#27)

  • CAs now include the KeyUsage and ExtendedKeyUsage extensions configured for SSL certificates. (#30)

  • CA.issue_cert now accepts email addresses as a valid form of identity. (#33)

  • It’s now possible to set the “common name” of generated certs; see CA.issue_cert for details. (#34)

  • CA.issue_server_cert has been renamed to CA.issue_cert, since it supports both server and client certs. To preserve backwards compatibility, the old name is retained as an undocumented alias. (#35)


  • Make sure cert expiration dates don’t exceed 2038-01-01, to avoid issues on some 32-bit platforms that suffer from the Y2038 problem. (#41)

Trustme 0.4.0 (2017-08-06)



  • Start doing our own handling of Unicode hostname (IDNs), instead of relying on cryptography to do it; this allows us to correctly handle a broader range of cases, and avoids relying on soon-to-be-deprecated behavior (#17)

  • Generated certs no longer contain a subject:commonName field, to better match CABF guidelines (#18)

Trustme 0.3.0 (2017-08-03)


  • Don’t crash on Windows (#10)


Trustme 0.2.0 (2017-08-02)

  • Broke and re-did almost the entire public API. Sorry! Let’s just pretend v0.1.0 never happened.

  • Hey there are docs now though, that should be worth something right?

Trustme 0.1.0 (2017-07-18)

  • Initial release


This is basically just a trivial wrapper around the awesome Python cryptography library. Also, Glyph originally 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.