Request client certificates, check validity dates of received certs and pass certs to handleCGI.

This commit is contained in:
Solderpunk 2020-06-05 19:39:28 +02:00
parent 4e262d634a
commit 6f3887bdc4
2 changed files with 23 additions and 3 deletions

View File

@ -3,8 +3,9 @@ package main
import ( import (
"bufio" "bufio"
"context" "context"
"crypto/tls"
"crypto/x509"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"log" "log"
"mime" "mime"
@ -21,6 +22,7 @@ import (
func handleGeminiRequest(conn net.Conn, config Config, logEntries chan LogEntry) { func handleGeminiRequest(conn net.Conn, config Config, logEntries chan LogEntry) {
defer conn.Close() defer conn.Close()
var tlsConn (*tls.Conn) = conn.(*tls.Conn)
var log LogEntry var log LogEntry
log.Time = time.Now() log.Time = time.Now()
log.RemoteAddr = conn.RemoteAddr() log.RemoteAddr = conn.RemoteAddr()
@ -41,6 +43,23 @@ func handleGeminiRequest(conn net.Conn, config Config, logEntries chan LogEntry)
return 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 // Parse request as URL
URL, err := url.Parse(string(request)) URL, err := url.Parse(string(request))
if err != nil { 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 // If this file is executable, get dynamic content
inCGIPath, err := regexp.Match(config.CGIPath, []byte(path)) inCGIPath, err := regexp.Match(config.CGIPath, []byte(path))
if inCGIPath && info.Mode().Perm() & 0111 == 0111 { if inCGIPath && info.Mode().Perm() & 0111 == 0111 {
handleCGI(config, path, URL, log, conn) handleCGI(config, path, URL, clientCerts, log, conn)
return return
} }
@ -213,7 +232,7 @@ func serveFile(path string, log LogEntry, conn net.Conn) {
conn.Write(contents) 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) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel() defer cancel()
cmd := exec.CommandContext(ctx, path) cmd := exec.CommandContext(ctx, path)

View File

@ -44,6 +44,7 @@ func main() {
tlscfg := &tls.Config{ tlscfg := &tls.Config{
Certificates: []tls.Certificate{cert}, Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS12, MinVersion: tls.VersionTLS12,
ClientAuth: tls.RequestClientCert,
} }
// Create TLS listener // Create TLS listener