certifix-client.fnl (2521B)
1 (local { : view } (require :fennel)) 2 (local { : assoc : split } (require :anoia)) 3 4 (local ctx (require :openssl.ssl.context)) 5 (local csr (require :openssl.x509.csr)) 6 (local altname (require :openssl.x509.altname)) 7 (local pkey (require :openssl.pkey)) 8 (local xn (require :openssl.x509.name)) 9 10 (local request (require :http.request)) 11 (local http_tls (require :http.tls)) 12 (local x509 (require :openssl.x509)) 13 14 (macro ncall [f] 15 `(case ,f 16 ok# ok# 17 (nil err#) (error err#))) 18 19 20 (fn x509-name [subj] 21 (let [n (xn.new)] 22 (each [_ c (ipairs (split "," subj))] 23 (let [(k v) (string.match c "(.-)=(.+)")] 24 (n:add k v))) 25 n)) 26 27 (fn x509-altname [subj] 28 (let [an (altname.new)] 29 (each [_ c (ipairs (split "," subj))] 30 (let [(k v) (string.match c "(.-)=(.+)")] 31 (if (= k "CN") (an:add "DNS" v)))) 32 an)) 33 34 (fn parse-args [args] 35 (case args 36 ["--secret" secret & rest] 37 (assoc (parse-args rest) 38 :secret (with-open [f (ncall (io.open secret :r))] (f:read "l"))) 39 40 ["--subject" subject & rest] 41 (assoc (parse-args rest) :subject subject) 42 43 ["--key-out" pathname & rest] 44 (assoc (parse-args rest) :key-out pathname) 45 46 ["--certificate-out" pathname & rest] 47 (assoc (parse-args rest) :certificate-out pathname) 48 49 [server] { : server } 50 _ {})) 51 52 53 (local options (parse-args arg)) 54 55 (fn private-key [] 56 (pkey.new { :type :rsa :bits 2048 })) 57 58 (fn signing-request [pk] 59 (doto (csr.new) 60 (: :setVersion 1) 61 (: :setSubject (x509-name options.subject)) 62 (: :setSubjectAlt (x509-altname options.subject)) 63 (: :setPublicKey pk) 64 (: :addAttribute :challengePassword [options.secret]) 65 (: :sign pk))) 66 67 (fn http-post [url body] 68 (let [r (request.new_from_uri url) 69 h r.headers] 70 (h:upsert ":method" :POST) 71 (h:upsert "content-type" "application/x-pem-file") 72 (when body 73 (r:set_body body)) 74 (or 75 (case (r:go) 76 (headers stream) 77 (if (= (headers:get ":status") "200") 78 (stream:get_body_as_string) 79 (error (.. "error response from server: " 80 (headers:get ":status")))) 81 82 (nil failure) 83 (error (.. "error: " failure)))))) 84 85 (fn run [] 86 (let [pk (private-key) 87 csr (signing-request pk) 88 cert (http-post options.server (csr:toPEM))] 89 (with-open [f (ncall (io.open options.key-out :w))] 90 (f:write (pk:toPEM :private))) 91 (with-open [f (ncall (io.open options.certificate-out :w))] 92 (f:write cert)) 93 (print "done"))) 94 95 96 { : run }