Use new go-gemini cert flow
alex wennerberg alex@alexwennerberg.com
Fri, 30 Oct 2020 23:19:32 -0700
A
cert.go
@@ -0,0 +1,46 @@
+package main + +import ( + "crypto" + "crypto/tls" + "crypto/x509" + "encoding/pem" + "io" + "os" +) + +// writeCertificate writes the provided certificate and private key +// to path.crt and path.key respectively. +func writeCertificate(path string, cert tls.Certificate) error { + // Write the certificate + crtPath := path + ".crt" + crtOut, err := os.OpenFile(crtPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + return err + } + if err := marshalX509Certificate(crtOut, cert.Leaf.Raw); err != nil { + return err + } + + // Write the private key + keyPath := path + ".key" + keyOut, err := os.OpenFile(keyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + return err + } + return marshalPrivateKey(keyOut, cert.PrivateKey) +} + +// marshalX509Certificate writes a PEM-encoded version of the given certificate. +func marshalX509Certificate(w io.Writer, cert []byte) error { + return pem.Encode(w, &pem.Block{Type: "CERTIFICATE", Bytes: cert}) +} + +// marshalPrivateKey writes a PEM-encoded version of the given private key. +func marshalPrivateKey(w io.Writer, priv crypto.PrivateKey) error { + privBytes, err := x509.MarshalPKCS8PrivateKey(priv) + if err != nil { + return err + } + return pem.Encode(w, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}) +}
M
example-config.toml
→
example-config.toml
@@ -12,7 +12,10 @@ # Folder containing subfolders for each user's files
FilesDirectory="./files" LogFile="./flounder.log" -# A wildcard TLS cert +# Gemini autogenerates self-signed certs +GeminiCertStore="./" + +# A wildcard TLS cert for HTTPS. TLSCertFile="./server.crt" TLSKeyFile="./server.key"
M
gemini.go
→
gemini.go
@@ -11,6 +11,7 @@ "log"
"path" "path/filepath" "text/template" + "time" ) func gmiIndex(w *gmi.ResponseWriter, r *gmi.Request) {@@ -70,17 +71,17 @@ var server gmi.Server
hostname := strings.SplitN(c.Host, ":", 2)[0] // is this necc? - server.GetCertificate = func(hostname string, store *gmi.CertificateStore) *tls.Certificate { - cert, err := store.Lookup(hostname) - if err != nil { - cert, err := tls.LoadX509KeyPair(c.TLSCertFile, c.TLSKeyFile) - if err != nil { - log.Fatal("Invalid TLS cert") - } - store.Add(hostname, cert) - return &cert + server.CreateCertificate = func(hostname string) (tls.Certificate, error) { + log.Println("Generating certificate for", hostname) + cert, err := gmi.CreateCertificate(gmi.CertificateOptions{ + DNSNames: []string{hostname}, + Duration: time.Minute, // for testing purposes + }) + if err == nil { + // Write the new certificate to disk + err = writeCertificate(path.Join(c.GeminiCertStore, hostname), cert) } - return cert + return cert, err } var mux gmi.ServeMux
M
go.sum
→
go.sum
@@ -1,5 +1,5 @@
-git.sr.ht/~adnano/go-gemini v0.1.1 h1:g6OwUxLviy6dkPiuW2eRQP5Fow412vUsKmKYbCr2H9U= -git.sr.ht/~adnano/go-gemini v0.1.1/go.mod h1:If1VxEWcZDrRt5FeAFnGTcM2Ud1E3BXs3VJ5rnZWKq0= +git.sr.ht/~adnano/go-gemini v0.1.3 h1:uClB4mzTkHBMKBde63/EzrsIhRuHxxaNHVRf1/gApXU= +git.sr.ht/~adnano/go-gemini v0.1.3/go.mod h1:If1VxEWcZDrRt5FeAFnGTcM2Ud1E3BXs3VJ5rnZWKq0= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=