generate self-signed (TOFU) ECC certs for TLS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Robey 92347c7f3c lock file 4 months ago
lib decode ed25519 public keys and minimal rsa-sha256 recognition 4 months ago
stubs fix some stubs 4 months ago
tests can now regurgitate an ed25519 cert 1 year ago
.gitignore checkpoint: read and do a tiny bit of validation on a cert 1 year ago
LICENSE.txt add some docs 1 year ago
Makefile split x509 from asn, put both in lib/, add support for reading/writing x509 ECDSA certs of a specific type (nist p256 r1), and add a test proving that 1 year ago explain why 1 year ago -k will now try to display a public key too 4 months ago add some docs 1 year ago mypy is mad about this 4 months ago
mypy.ini checkpoint: got it to parse and save a private key file 1 year ago
poetry.lock lock file 4 months ago
pyproject.toml fix some stubs 4 months ago


Certified is a small CLI tool for generating a TLS self-signed ("TOFU") ECC certificate and private key, suitable for using in small distributed networks, like gemini.

Two ECC formats are supported:

  • Ed25519 aka Curve25519
    • using PyNaCl, recommended and generally (as of 2021) considered the most trustworthy algorithm
  • ECDSA using secp256r1 (aka nist256p1 aka prime256v1)
    • using the python ecdsa library, subject to side channel attacks, and primarily for toy use


It's possible to use the openssl toolchain to create self-signed ECC certificates using curve 25519: check out the first reference link for a great explanation and example. But I think these tools are written for people who live, breathe, and swim in the world of X.509 arcana. This app is meant to demonstrate an imagined world where we don't care about hierarchical certificate authorities, or going through a three-step process to request and then confirm a request for a certificate to ourselves from ourselves, when that certificate is little more than a gold filigree doily wrapped around a public key.

You can just run this script, a bit over 500 lines of python, to generate the public/private key pair, and wrap them in the ceremony that makes them palatable to the TLS 1.3 infrastructure. Feel free to copy this code and its ideas for your own projects, subject only to the Apache 2.0 license.


You need a basic python 3 installation, and poetry.

Clone this repository, and then:

poetry install

If you have some other preferred way of dealing with python packages, all of the dependencies are listed in pyproject.toml. They are:

  • python 3.7+
  • ecdsa
  • PyNaCl


./ --help

# create a new Ed25519 certificate in "myserver-x509-cert.pem" (and its
# private key in "myserver-x509-key.pem") with the CN "myserver", that will
# expire in 365 days:
./ -g myserver-x509 --name myserver --days 365

# show the contents of the certificate:
./ -p myserver-x509-cert.pem

# show the contents of the private key (_including the private key data_):
./ -k myserver-x509-key.pem

# dump out the ASN.1 structure of any random pem file (if you like exploring):
./ --pp myserver-x509-key.pem

Try it out by running the test program, which will start a snarky echo service over TLS on a local socket and tell you how to connect to it with openssl s_client. Type a line of text through s_client and if it's echoed back to you, congratulations! You have a certificate and key file that can be used in a TLS service!

./ -c myserver-x509

Note that LibreSSL won't work here, because they haven't implemented Ed25519 certificate support yet. If you're on OS X, where LibreSSL is masquerading as openssl, you can install the real openssl via "brew" and run it from /usr/share/opt/openssl/bin/openssl.




Apache 2.0 license, included in LICENSE.txt.