From 5e68d81a6346bdd89f19243a0e8318fc2fad4d2e Mon Sep 17 00:00:00 2001 From: sloumdrone Date: Tue, 24 Sep 2019 21:23:44 -0700 Subject: [PATCH] Starts building out a tofu system for certificate pinning --- gemini/gemini.go | 66 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/gemini/gemini.go b/gemini/gemini.go index 4d8b044..39cda6d 100644 --- a/gemini/gemini.go +++ b/gemini/gemini.go @@ -6,10 +6,10 @@ import ( "io/ioutil" "strconv" "strings" - - // "tildegit.org/sloum/mailcap" + "time" ) + type Capsule struct { MimeMaj string MimeMin string @@ -18,6 +18,50 @@ type Capsule struct { Links []string } +type TofuDigest struct { + db map[string][]map[string]string +} + +//------------------------------------------------\\ +// + + + R E C E I V E R S + + + \\ +//--------------------------------------------------\\ + +func (t *TofuDigest) Remove(host string, indexToRemove int) error { + if _, ok := t.db[host]; ok { + if indexToRemove < 0 || indexToRemove >= len(t.db[host]) { + return fmt.Errorf("Invalid index") + } else if len(t.db[host]) > indexToRemove { + t.db[host] = append(t.db[host][:indexToRemove], t.db[host][indexToRemove+1:]...) + } else if len(t.db[host]) - 1 == indexToRemove { + t.db[host] = t.db[host][:indexToRemove] + } + return nil + } + return fmt.Errorf("Invalid host") +} + +func (t *TofuDigest) Add(host, hash string, start, end int64) { + s := strconv.FormatInt(start, 10) + e := strconv.FormatInt(end, 10) + added := strconv.FormatInt(time.Now().Unix(), 10) + entry := map[string]string{"hash": hash, "start": s, "end": e, "added": added} + t.db[host] = append(t.db[host], entry) +} + +// Removes all entries that are expired +func (t *TofuDigest) Clean() { + now := time.Now() + for host, slice := range t.db { + for index, entry := range slice { + intFromStringTime, err := strconv.ParseInt(entry["end"], 10, 64) + if err != nil || now.After(time.Unix(intFromStringTime, 0)) { + t.Remove(host, index) + } + } + } +} + + //------------------------------------------------\\ // + + + F U N C T I O N S + + + \\ //--------------------------------------------------\\ @@ -41,6 +85,24 @@ func Retrieve(host, port, resource string) (string, error) { defer conn.Close() + // Verify that the handshake ahs completed and that + // the hostname on the certificate(s) from the server + // is the hostname we have requested + connState := conn.ConnectionState() + if connState.HandshakeComplete { + if len(connState.PeerCertificates) > 0 { + for _, cert := range connState.PeerCertificates { + if err = cert.VerifyHostname(host); err == nil { + break + } + } + if err != nil { + return "", err + } + } + } + + send := "gemini://" + addr + "/" + resource + "\r\n" _, err = conn.Write([]byte(send))