initial commit

This commit is contained in:
Daniel Barlow 2024-09-25 10:20:14 +01:00
commit 6ddae21727
5 changed files with 137 additions and 0 deletions

7
Makefile Normal file
View File

@ -0,0 +1,7 @@
.DELETE_ON_ERROR:
default:
install: default
mkdir -p $(TARGET)/lib/
cp *.fnl $(TARGET)/lib

26
README Normal file
View File

@ -0,0 +1,26 @@
A small HTTPS API that accepts X509 CSRs and signs them if they
contain the magic number.
Modelled on the Puppet CA "Policy-based autosigning" functionality,
but without the rest of Puppet
[ This README is speculative ]
---
DOMAIN="/C=GB/ST=London/L=London/O=Telent"
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -subj "${DOMAIN}/CN=CA" -out ca.crt
openssl req -newkey rsa:2048 -nodes -keyout domain.key -out domain.csr -subj "${DOMAIN}/OU=devices/CN=rotuer"
https://www.puppet.com/docs/puppet/7/ssl_attributes_extensions#csr_custom_attributes-recommended-oids-custom-attributes
Custom attributes can use any public or site-specific OID, with the exception of the OIDs used for core X.509 functionality. This means you cant re-use existing OIDs for things like subject alternative names.
One useful OID is the challengePassword attribute — 1.2.840.113549.1.9.7. This is a rarely-used corner of X.509 that can easily be repurposed to hold a pre-shared key.

1
default.nix Normal file
View File

@ -0,0 +1 @@
with import <nixpkgs> {}; callPackage ./package.nix {}

69
main.fnl Normal file
View File

@ -0,0 +1,69 @@
(local { : view} (require :fennel))
(local server (require :http.server))
(local headers (require :http.headers))
(local ssl (require :openssl))
(local csr (require :openssl.x509.csr))
(local x509 (require :openssl.x509))
(local pkey (require :openssl.pkey))
(fn not-found [out]
(doto (headers.new)
(: :append ":status" :404)
(: :append :content-type :text/plain)
(out:write_headers false))
(out:write_chunk "not found" true))
(fn slurp [filename]
(with-open [f (io.open filename "r")] (f:read "*a")))
(local ca-key (pkey.new (slurp "ca.key")))
(local ca-crt (x509.new (slurp "ca.crt")))
(fn new-crt [csr]
(let [crt
(doto (x509.new)
(: :setVersion 2)
(: :setSerial 42)
(: :setIssuer (ca-crt:getSubject))
(: :setLifetime (os.time) (+ (* 365 86400) (os.time)))
(: :setSubject (csr:getSubject))
(: :setPublicKey (csr:getPublicKey))
(: :sign ca-key))]
(crt:toPEM)))
(fn handle-sign-csr [out]
(let [body (out:get_body_as_string)]
(doto (headers.new)
(: :append ":status" :200)
(: :append :content-type :text/plain)
(out:write_headers false))
(let [req (csr.new body)]
(print :subject (req:getSubject))
(out:write_chunk (new-crt req) true))))
(fn on-stream [sv out]
(let [hdrs (out:get_headers)
method (hdrs:get ":method")
path (or (hdrs:get ":path") "/")]
(print :path path)
(case path
"/sign"
(handle-sign-csr out)
_
(not-found out))))
(fn new-server []
(server.listen
{
:host :localhost
:port 8201
:onstream on-stream
}))
(doto (new-server)
(: :listen)
(print "server ready")
(: :loop))

34
package.nix Normal file
View File

@ -0,0 +1,34 @@
{
lua5_3
, stdenv
, makeWrapper
}:
let
pname = "certifix";
lua = lua5_3.withPackages (ps: [
# ps.dkjson
# ps.lpeg
ps.http
ps.luaposix
]);
inherit makeWrapper;
inherit (lua.pkgs) fennel;
in stdenv.mkDerivation {
inherit pname;
version = "0.1";
src = ./.;
makeFlags = [ "TARGET=${placeholder "out"}" ];
postInstall = ''
lua_path="`lua -e 'print(package.path)'`"
lua_cpath="`lua -e 'print(package.cpath)'`"
makeWrapper ${fennel}/bin/fennel \
$out/bin/${pname} \
--add-flags "--add-fennel-path $out/lib/?.fnl" \
--add-flags "--add-package-path '$out/lib/?.lua$lua_path'" \
--add-flags "--add-package-cpath '$out/lib/?.lua$lua_cpath'" \
--add-flags "$out/lib/main.fnl"
'';
buildInputs = [lua fennel];
nativeBuildInputs = [ makeWrapper ];
}