Implement basic TOFU

This commit is contained in:
adnano
2020-09-25 21:43:13 -04:00
parent 4a95fe4a90
commit b4295dd2dc
5 changed files with 73 additions and 17 deletions

View File

@@ -1,5 +1,13 @@
package gemini
import (
"crypto/x509"
"errors"
"log"
"os"
"path/filepath"
)
// Status codes.
const (
StatusInput = 10
@@ -35,3 +43,47 @@ const (
var (
crlf = []byte("\r\n")
)
// TOFUClient is a client that implements Trust-On-First-Use.
type TOFUClient struct {
// Trusts, if not nil, will be called to determine whether the client should
// trust the provided certificate.
Trusts func(cert *x509.Certificate, req *Request) bool
}
func (t *TOFUClient) VerifyCertificate(cert *x509.Certificate, req *Request) error {
if knownHosts.Has(req.URL.Host, cert) {
return nil
}
if t.Trusts != nil && t.Trusts(cert, req) {
host := NewKnownHost(cert)
knownHosts = append(knownHosts, host)
knownHostsFile, err := os.OpenFile(knownHostsPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
log.Print(err)
}
if _, err := host.Write(knownHostsFile); err != nil {
log.Print(err)
}
return nil
}
return errors.New("gemini: certificate not trusted")
}
var (
knownHosts KnownHosts
knownHostsPath string
knownHostsFile *os.File
)
func init() {
configDir, err := os.UserConfigDir()
knownHostsPath = filepath.Join(configDir, "gemini")
os.MkdirAll(knownHostsPath, 0755)
knownHostsPath = filepath.Join(knownHostsPath, "known_hosts")
knownHostsFile, err = os.OpenFile(knownHostsPath, os.O_CREATE|os.O_RDONLY, 0644)
if err != nil {
return
}
knownHosts = ParseKnownHosts(knownHostsFile)
}