Basic implementation of certificate zones - only one authorised cert per zone.

This commit is contained in:
Solderpunk 2020-06-28 13:47:30 +02:00
parent 5377c2941f
commit a0dacf4bbd
3 changed files with 35 additions and 3 deletions

View File

@ -20,6 +20,7 @@ type Config struct {
MimeOverrides map[string]string
CGIPaths []string
SCGIPaths map[string]string
CertificateZones map[string]string
DirectorySort string
DirectoryReverse bool
DirectoryTitles bool

View File

@ -5,6 +5,7 @@ import (
"context"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"io"
"net"
@ -145,13 +146,17 @@ func prepareGatewayVariables(config Config, URL *url.URL, conn net.Conn) map[str
clientCerts := connState.PeerCertificates
if len(clientCerts) > 0 {
cert := clientCerts[0]
fingerprint := sha256.Sum256(cert.Raw)
vars["TLS_CLIENT_HASH"] = hex.EncodeToString(fingerprint[:])
vars["TLS_CLIENT_HASH"] = getCertFingerprint(cert)
vars["TLS_CLIENT_ISSUER"] = cert.Issuer.String()
vars["TLS_CLIENT_ISSUER_CN"] = cert.Issuer.CommonName
vars["TLS_CLIENT_SUBJECT"] = cert.Subject.String()
vars["TLS_CLIENT_SUBJECT_CN"] = cert.Subject.CommonName
}
return vars
}
func getCertFingerprint(cert *x509.Certificate) string {
hash := sha256.Sum256(cert.Raw)
fingerprint := hex.EncodeToString(hash[:])
return fingerprint
}

View File

@ -92,6 +92,32 @@ func handleGeminiRequest(conn net.Conn, config Config, logEntries chan LogEntry)
}
}
// Check whether this URL is in a certificate zone
authorised := true
for zone, allowed_fingerprint := range config.CertificateZones {
matched, err := regexp.Match(zone, []byte(URL.Path))
if !matched || err != nil {
continue
}
authorised = false
for _, cert := range clientCerts {
if getCertFingerprint(cert) == allowed_fingerprint {
authorised = true
break
}
}
}
if !authorised {
if len(clientCerts) > 0 {
conn.Write([]byte("61 Provided certificate not authorised for this resource\r\n"))
log.Status = 61
} else {
conn.Write([]byte("60 A pre-authorised certificate is required to access this resource\r\n"))
log.Status = 60
}
return
}
// Check whether this URL is mapped to an SCGI app
for scgi_url, scgi_socket := range config.SCGIPaths {
matched, err := regexp.Match(scgi_url, []byte(URL.Path))