certifix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

README.md (5138B)


      1 # Certifix
      2 
      3 Not an Asterix character.
      4 
      5 A small HTTPS API modelled on the description of the
      6 [Puppet CA "Policy-based autosigning" functionality](
      7 https://www.puppet.com/docs/puppet/7/ssl_attributes_extensions#csr_custom_attributes-recommended-oids-custom-attributes),
      8 that accepts X509 CSRs and automatically signs them without human
      9 interaction if they have a custom `challengePassword` attribute
     10 containing a pre-agreed value.
     11 
     12 What's it for? I have a bunch of small devices on my LAN that may or
     13 may not be able to retain persistent state across reboots. I would
     14 like them to be able to talk securely to services on the network using
     15 standard TLS with client authentication, and (because "[zero trust]
     16 (https://en.wikipedia.org/wiki/Zero_trust_security_model)")
     17 without having to rely on network firewall rules to prevent the rest
     18 of the world also being able to talk to the service.
     19 
     20 ## To try it out
     21 
     22 _This is alpha-quality code which was written by someone with only the
     23 most passing familiarity with TLS or cryptography in general, and
     24 has not been audited. Try it at your own risk._
     25 
     26 It's written in [Fennel](https://www.fennel-lang.org). To build it
     27 either use Nix or read [package.nix](package.nix) and figure out how
     28 to replicate the steps manually.  Note that it requires a patch to the
     29 luaossl module.
     30 
     31 ### CA key and cert
     32 
     33 Create the CA key and the certificate used for signing. You will be
     34 asked a bunch of questions that will be incorporated into the
     35 certificate: when prompted for "Common Name", say "Certificate
     36 Authority" or something like that
     37 
     38 ```
     39 openssl genrsa -out private/ca.key 4096
     40 openssl req  -addext basicConstraints=critical,CA:TRUE,pathlen:0  --x509 -new -nodes -key private/ca.key -sha256 -days 3650  -out certs/ca.crt
     41 ```
     42 
     43 ### Server key and cert
     44 
     45 The certifix service is exposed over HTTPS, so it needs its own
     46 certificate signed by the CA. Use your hostname when prompted for
     47 Common Name. If your server host is reachable using different
     48 names from different clients then you need to provide _all_ of them
     49 as `subjectAltName` - as in the example below.
     50 
     51 ```
     52 # it's important to list all the hostnames of your server machine in the
     53 # subjectAltName field
     54 openssl req -newkey rsa:2048  -addext "subjectAltName = DNS:loaclhost.lan,DNS:localhost,DNS:loaclhost.telent.net" -nodes -keyout private/server.key --out certs/server.csr
     55 openssl x509 -req -in certs/server.csr -days 365 -CA certs/ca.crt -CAkey private/ca.key -CAcreateserial -copy_extensions copyall -out certs/server.crt
     56 
     57 ```
     58 
     59 ### Build and start the server
     60 
     61 The server needs to be told of all of the preceding files, _plus_ a
     62 file containing the expected value of the pre-shared key that you want
     63 it to check client certificate requests against.
     64 
     65 ```
     66 echo 'loves labours lost' > psk
     67 chmod 0700 psk
     68 nix-build
     69 result/bin/certifix  --challenge-password psk  --ca-certificate certs/ca.crt --ca-private-key private/ca.key --server-certificate certs/server.crt --server-private-key private/server.key localhost:19613
     70 ```
     71 
     72 * To listen on all interfaces, use a wildcard address instead of
     73   `localhost` - e.g. `::0:19613' will (at least on my machine) accept
     74   IPv4 and IPv6 connections on any interface
     75 
     76 
     77 ### Try it and see if it works
     78 
     79 To set the `challengePassword` attribute in a CSR using OpenSSL, you
     80 need to create a configuration file.  Copy `openssl.cnf.example` to
     81 `openssl.cnf` and edit it for your setup.
     82 
     83 * the values in `req_distinguished_name` should match your organisation
     84 * the `challengePassword` attribute must match whatever you told the
     85  service to expect (`psk` file in the preceding step)
     86 
     87 ```
     88 # make CSR
     89 CN=mydevice openssl req -config openssl.cnf -addext "subjectAltName = DNS:mydevice.lan" -newkey rsa:2048 -nodes -keyout client.key -out client.csr
     90 
     91 # send it to certifix, should get a certificate in response
     92 curl --cacert certs/ca.crt   -v -H 'content-type: application/x-pem-file' --data-binary @client.csr  https://localhost:19613/sign
     93 ```
     94 
     95 
     96 ## Reasons this is not secure
     97 
     98 * the CA key is readable by and present in the memory of the process
     99   that reads and parses network requests. Bearing in mind the the
    100   whole point is to automate signing we can only do so much about
    101   this, but at least we could move the actual signing to a separate
    102   process which is only invoked once an acceptable request has been
    103   received.
    104 
    105 * on that note, in the setup that this README describes there is no
    106   intermediate key - the requests are signed directly by the root
    107   CA. For a robust setup you might consider ignoring my instructions
    108   for generating a self-signed root cert, and instead create a CA
    109   signed by an existing (offline?) root CA
    110 
    111 * I haven't checked that the protocols or the ciphers are restricted
    112   to modern and sensible defaults
    113 
    114 * it has _not_ been reviewed by anyone who knows about TLS best
    115   practices. If you are that person, please look at the new-crt
    116   function in [main.fnl](main.fnl) and let me know :-)
    117 
    118 
    119 ## Background
    120 
    121 
    122 * [RFC 5967 - spec for a CSR](https://datatracker.ietf.org/doc/html/rfc5967)
    123 * [A gentle introduction to ASN1. and DER](https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/)