The Unsinkable Molly Brown: a full-featured Gemini server implemented in Go
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

63 lines
1.6 KiB

package main
import (
"crypto/sha256"
"crypto/x509"
"encoding/hex"
"net"
"net/url"
"regexp"
"time"
)
func enforceCertificateValidity(clientCerts []*x509.Certificate, conn net.Conn, log *LogEntry) {
// 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
}
}
}
func handleCertificateZones(URL *url.URL, clientCerts []*x509.Certificate, config Config, conn net.Conn, log *LogEntry) {
authorised := true
for zone, allowedFingerprints := range config.CertificateZones {
matched, err := regexp.Match(zone, []byte(URL.Path))
if !matched || err != nil {
continue
}
authorised = false
for _, clientCert := range clientCerts {
for _, allowedFingerprint := range allowedFingerprints {
if getCertFingerprint(clientCert) == allowedFingerprint {
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
}
}
func getCertFingerprint(cert *x509.Certificate) string {
hash := sha256.Sum256(cert.Raw)
fingerprint := hex.EncodeToString(hash[:])
return fingerprint
}