From 6f3887bdc4546ef7af2fa328de5a4cbfe1356e9a Mon Sep 17 00:00:00 2001 From: Solderpunk Date: Fri, 5 Jun 2020 19:39:28 +0200 Subject: [PATCH] Request client certificates, check validity dates of received certs and pass certs to handleCGI. --- handler.go | 25 ++++++++++++++++++++++--- main.go | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/handler.go b/handler.go index e7fbf4d..f7ae059 100644 --- a/handler.go +++ b/handler.go @@ -3,8 +3,9 @@ package main import ( "bufio" "context" + "crypto/tls" + "crypto/x509" "fmt" - "io" "io/ioutil" "log" "mime" @@ -21,6 +22,7 @@ import ( func handleGeminiRequest(conn net.Conn, config Config, logEntries chan LogEntry) { defer conn.Close() + var tlsConn (*tls.Conn) = conn.(*tls.Conn) var log LogEntry log.Time = time.Now() log.RemoteAddr = conn.RemoteAddr() @@ -41,6 +43,23 @@ func handleGeminiRequest(conn net.Conn, config Config, logEntries chan LogEntry) return } + clientCerts := tlsConn.ConnectionState().PeerCertificates + // Check validity + // This will fail if any of multiple certs are invalid + // Maybe we should just require one valid? + now := time.Now() + for _, cert := range clientCerts { + if now.Before(cert.NotBefore) { + conn.Write([]byte("64 Client certificate not yet valid!\r\n")) + log.Status = 64 + return + } else if now.After(cert.NotAfter) { + conn.Write([]byte("65 Client certificate has expired!\r\n")) + log.Status = 65 + return + } + } + // Parse request as URL URL, err := url.Parse(string(request)) if err != nil { @@ -140,7 +159,7 @@ func handleGeminiRequest(conn net.Conn, config Config, logEntries chan LogEntry) // If this file is executable, get dynamic content inCGIPath, err := regexp.Match(config.CGIPath, []byte(path)) if inCGIPath && info.Mode().Perm() & 0111 == 0111 { - handleCGI(config, path, URL, log, conn) + handleCGI(config, path, URL, clientCerts, log, conn) return } @@ -213,7 +232,7 @@ func serveFile(path string, log LogEntry, conn net.Conn) { conn.Write(contents) } -func handleCGI(config Config, path string, URL *url.URL, log LogEntry, conn net.Conn) { +func handleCGI(config Config, path string, URL *url.URL, clientCerts []*x509.Certificate, log LogEntry, conn net.Conn) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() cmd := exec.CommandContext(ctx, path) diff --git a/main.go b/main.go index 820b6bd..256bcd5 100644 --- a/main.go +++ b/main.go @@ -44,6 +44,7 @@ func main() { tlscfg := &tls.Config{ Certificates: []tls.Certificate{cert}, MinVersion: tls.VersionTLS12, + ClientAuth: tls.RequestClientCert, } // Create TLS listener