certifix/README.md

79 lines
2.9 KiB
Markdown
Raw Normal View History

2024-09-25 20:34:27 +00:00
# Certifix
Not an Asterix character.
2024-09-25 20:30:32 +00:00
A small HTTPS API modelled on the description of the
[Puppet CA "Policy-based autosigning" functionality](
https://www.puppet.com/docs/puppet/7/ssl_attributes_extensions#csr_custom_attributes-recommended-oids-custom-attributes),
that accepts X509 CSRs and automatically signs them without human
interaction if they have a custom `challengePassword` attribute
containing a pre-agreed value.
2024-09-25 20:30:32 +00:00
What's it for? I have a bunch of small devices on my LAN that may or
may not be able to retain persistent state across reboots. I would
like them to be able to talk securely to services on the network using
standard TLS with client authentication, and (because "[zero trust]
(https://en.wikipedia.org/wiki/Zero_trust_security_model)")
without having to rely on network firewall rules to prevent the rest
of the world also being able to talk to the service.
2024-09-25 20:30:32 +00:00
## To try it out
_This is alpha-quality code which was written by someone with only the
most passing familiarity with TLS or cryptography in general, and
has not been audited. Try it at your own risk._
2024-09-25 20:30:32 +00:00
It's written in [Fennel](https://www.fennel-lang.org). To build it
either use Nix or read [package.nix](package.nix) and figure out how
to replicate the steps manually. Note that it requires a patch to the
luaossl module
```
# pick a PSK
echo 'loves labours lost' > psk
2024-09-25 20:30:32 +00:00
chmod 0700 psk
# create CA key and cert used for signing
2024-09-25 20:34:27 +00:00
openssl genrsa -out ca.key 4096
CN=CA openssl req -config openssl.cnf -addext basicConstraints=critical,CA:TRUE,pathlen:1 --x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt
2024-09-25 20:30:32 +00:00
# create key for the server and sign it with the CA
2024-09-27 18:47:11 +00:00
CN=localhost openssl req -config openssl.cnf -newkey rsa:2048 -nodes -keyout server.key --out server.csr
openssl x509 -req -in server.csr -days 365 -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
# create example client CSR for testing (check openssl.cnf against "psk" file)
2024-09-25 20:34:27 +00:00
CN=rotuer openssl req -config openssl.cnf -newkey rsa:2048 -nodes -keyout client.key -out client.csr
2024-09-25 20:30:32 +00:00
# build and start the server
nix-build && result/bin/certifix --challenge-password psk --ca-certificate ca.crt --ca-private-key --server-certificate server.crt --server-private-key server.key localhost:19613
2024-09-25 20:30:32 +00:00
# send it
2024-10-01 23:28:12 +00:00
curl --cacert ca.crt -v -H 'content-type: application/x-pem-file' --data-binary @client.csr https://localhost:19613/sign
2024-09-25 20:30:32 +00:00
```
## Reasons this is not secure
* the CA key is present in the memory of the process that reads and
parses network requests
* there is no "intermediate" key: requests are signed by the root key
* I haven't checked that the protocols or the ciphers are restricted
to modern and sensible defaults
* doesn't set 4.2.1.6. Subject Alternative Name
* doesn't set Key Usage extension (https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.3)
* likewise other TLS best practices
2024-09-25 20:30:32 +00:00
## Background
2024-09-25 20:30:32 +00:00
* [RFC 5967 - spec for a CSR](https://datatracker.ietf.org/doc/html/rfc5967)