Allow specifying client certificate

This commit is contained in:
Trevor Slocum 2020-11-23 21:25:18 -08:00
parent fb5e7f4ea4
commit 26115183a9

View file

@ -3,6 +3,7 @@ package gmitohtml
import ( import (
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
@ -14,8 +15,13 @@ import (
var lastRequestTime = time.Now().Unix() 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. // 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 == "" { if u == "" {
return nil, nil, ErrInvalidURL return nil, nil, ErrInvalidURL
} }
@ -39,6 +45,16 @@ func fetch(u string, clientCertFile string, clientCertKey string) ([]byte, []byt
InsecureSkipVerify: true, 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) conn, err := tls.Dial("tcp", host, tlsConfig)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -153,7 +169,7 @@ func handleRequest(writer http.ResponseWriter, request *http.Request) {
u.RawQuery = request.URL.RawQuery u.RawQuery = request.URL.RawQuery
} }
header, data, err := fetch(u.String(), "", "") header, data, err := fetch(u.String())
if err != nil { if err != nil {
fmt.Fprintf(writer, "Error: failed to fetch %s: %s", u, err) fmt.Fprintf(writer, "Error: failed to fetch %s: %s", u, err)
return return
@ -205,3 +221,19 @@ func StartDaemon(address string) error {
func LastRequestTime() int64 { func LastRequestTime() int64 {
return lastRequestTime 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
}