🐛 Use domain from URL for TOFU, not from cert

This commit is contained in:
makeworld 2020-06-24 13:31:01 -04:00
parent 3db81c3ac6
commit e75c539dac
4 changed files with 19 additions and 22 deletions

View File

@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Disabling color in config affects UI elements (#16)
- Keep bold for headings even with color disabled
- Don't make whole link text bold when color is disabled
- Get domain from URL for TOFU, not from certificate
## [1.0.0] - 2020-06-18

View File

@ -10,15 +10,15 @@ import (
// Fetch returns response data and an error.
// The error text is human friendly and should be displayed.
func Fetch(u string) (*gemini.Response, error) {
resp, err := gemini.Fetch(u)
res, err := gemini.Fetch(u)
if err != nil {
return nil, err
}
parsed, _ := url.Parse(u)
ok := handleTofu(resp.Cert, parsed.Port())
ok := handleTofu(parsed.Hostname(), parsed.Port(), res.Cert)
if !ok {
return resp, ErrTofu
return res, ErrTofu
}
return resp, err
return res, err
}

View File

@ -62,17 +62,14 @@ func certID(cert *x509.Certificate) string {
// origCertID uses cert.Raw, which was used in v1.0.0 of the app.
func origCertID(cert *x509.Certificate) string {
h := sha256.New()
h.Write(cert.Raw) // Better than cert.Raw, see #7
h.Write(cert.Raw)
return fmt.Sprintf("%X", h.Sum(nil))
}
func saveTofuEntry(cert *x509.Certificate, port string) {
tofuStore.Set(idKey(cert.Subject.CommonName, port), certID(cert))
tofuStore.Set(expiryKey(cert.Subject.CommonName, port), cert.NotAfter.UTC())
err := tofuStore.WriteConfig()
if err != nil {
panic(err)
}
func saveTofuEntry(domain, port string, cert *x509.Certificate) {
tofuStore.Set(idKey(domain, port), certID(cert))
tofuStore.Set(expiryKey(domain, port), cert.NotAfter.UTC())
tofuStore.WriteConfig()
}
// handleTofu is the abstracted interface for taking care of TOFU.
@ -80,17 +77,17 @@ func saveTofuEntry(cert *x509.Certificate, port string) {
// It returns a bool indicating if the cert is valid according to
// the TOFU database.
// If false is returned, the connection should not go ahead.
func handleTofu(cert *x509.Certificate, port string) bool {
id, expiry, err := loadTofuEntry(cert.Subject.CommonName, port)
func handleTofu(domain, port string, cert *x509.Certificate) bool {
id, expiry, err := loadTofuEntry(domain, port)
if err != nil {
// Cert isn't in database or data is malformed
// So it can't be checked and anything is valid
saveTofuEntry(cert, port)
saveTofuEntry(domain, port, cert)
return true
}
if time.Now().After(expiry) {
// Old cert expired, so anything is valid
saveTofuEntry(cert, port)
saveTofuEntry(domain, port, cert)
return true
}
if certID(cert) == id {
@ -99,7 +96,7 @@ func handleTofu(cert *x509.Certificate, port string) bool {
}
if origCertID(cert) == id {
// Valid but uses old ID type
saveTofuEntry(cert, port)
saveTofuEntry(domain, port, cert)
return true
}
return false
@ -107,7 +104,6 @@ func handleTofu(cert *x509.Certificate, port string) bool {
// ResetTofuEntry forces the cert passed to be valid, overwriting any previous TOFU entry.
// The port string can be empty, to indicate port 1965.
func ResetTofuEntry(cert *x509.Certificate, port string) {
tofuStore.Set(idKey(cert.Subject.CommonName, port), "")
tofuStore.WriteConfig()
func ResetTofuEntry(domain, port string, cert *x509.Certificate) {
saveTofuEntry(domain, port, cert)
}

View File

@ -228,8 +228,8 @@ func handleURL(u string) (string, bool) {
if err == client.ErrTofu {
if Tofu(parsed.Host) {
// They want to continue anyway
client.ResetTofuEntry(res.Cert, parsed.Port())
// Response can be used further down
client.ResetTofuEntry(parsed.Hostname(), parsed.Port(), res.Cert)
// Response can be used further down, no need to reload
} else {
// They don't want to continue
// Set the bar back to original URL