From 26115183a99bed5c7f0a1b09bba393b1c83c7fdd Mon Sep 17 00:00:00 2001 From: Trevor Slocum Date: Mon, 23 Nov 2020 21:25:18 -0800 Subject: [PATCH] Allow specifying client certificate --- pkg/gmitohtml/daemon.go | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/pkg/gmitohtml/daemon.go b/pkg/gmitohtml/daemon.go index 46e9971..e385b3c 100644 --- a/pkg/gmitohtml/daemon.go +++ b/pkg/gmitohtml/daemon.go @@ -3,6 +3,7 @@ package gmitohtml import ( "bytes" "crypto/tls" + "errors" "fmt" "io/ioutil" "log" @@ -14,8 +15,13 @@ import ( var lastRequestTime = time.Now().Unix() +var clientCerts = make(map[string]tls.Certificate) + +// ErrInvalidCertificate is the error returned when an invalid certificate is provided. +var ErrInvalidCertificate = errors.New("invalid certificate") + // Fetch downloads and converts a Gemini page. -func fetch(u string, clientCertFile string, clientCertKey string) ([]byte, []byte, error) { +func fetch(u string) ([]byte, []byte, error) { if u == "" { return nil, nil, ErrInvalidURL } @@ -39,6 +45,16 @@ func fetch(u string, clientCertFile string, clientCertKey string) ([]byte, []byt InsecureSkipVerify: true, } + certHost := requestURL.Hostname() + if strings.HasPrefix(certHost, "www.") { + certHost = certHost[4:] + } + + clientCert, certAvailable := clientCerts[certHost] + if certAvailable { + tlsConfig.Certificates = []tls.Certificate{clientCert} + } + conn, err := tls.Dial("tcp", host, tlsConfig) if err != nil { return nil, nil, err @@ -153,7 +169,7 @@ func handleRequest(writer http.ResponseWriter, request *http.Request) { u.RawQuery = request.URL.RawQuery } - header, data, err := fetch(u.String(), "", "") + header, data, err := fetch(u.String()) if err != nil { fmt.Fprintf(writer, "Error: failed to fetch %s: %s", u, err) return @@ -205,3 +221,19 @@ func StartDaemon(address string) error { func LastRequestTime() int64 { return lastRequestTime } + +// SetClientCertificate sets the client certificate to use for a domain. +func SetClientCertificate(domain string, certificate string, privateKey string) error { + if len(certificate) == 0 || len(privateKey) == 0 { + delete(clientCerts, domain) + return nil + } + + clientCert, err := tls.LoadX509KeyPair(certificate, privateKey) + if err != nil { + return ErrInvalidCertificate + } + + clientCerts[domain] = clientCert + return nil +}