From 6ddae21727b23faa58f9ecb1a935785f612ac946 Mon Sep 17 00:00:00 2001 From: Daniel Barlow Date: Wed, 25 Sep 2024 10:20:14 +0100 Subject: [PATCH] initial commit --- Makefile | 7 ++++++ README | 26 ++++++++++++++++++++ default.nix | 1 + main.fnl | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++ package.nix | 34 ++++++++++++++++++++++++++ 5 files changed, 137 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 default.nix create mode 100644 main.fnl create mode 100644 package.nix diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..92532c7 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +.DELETE_ON_ERROR: + +default: + +install: default + mkdir -p $(TARGET)/lib/ + cp *.fnl $(TARGET)/lib diff --git a/README b/README new file mode 100644 index 0000000..c6ac5ef --- /dev/null +++ b/README @@ -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 can’t 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. \ No newline at end of file diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..85b3742 --- /dev/null +++ b/default.nix @@ -0,0 +1 @@ +with import {}; callPackage ./package.nix {} diff --git a/main.fnl b/main.fnl new file mode 100644 index 0000000..86868df --- /dev/null +++ b/main.fnl @@ -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)) diff --git a/package.nix b/package.nix new file mode 100644 index 0000000..8aae4e6 --- /dev/null +++ b/package.nix @@ -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 ]; +}