From 6e5c2473e736a90b06124bda3ded6a2c6248f855 Mon Sep 17 00:00:00 2001 From: Adnan Maolood Date: Sat, 6 Mar 2021 15:24:14 -0500 Subject: [PATCH] tofu: Use base64-encoded sha256 fingerprints --- examples/client.go | 3 +- tofu/tofu.go | 82 ++++++++++------------------------------------ 2 files changed, 18 insertions(+), 67 deletions(-) diff --git a/examples/client.go b/examples/client.go index 69a928f..ad114f0 100644 --- a/examples/client.go +++ b/examples/client.go @@ -6,7 +6,6 @@ package main import ( "bufio" - "bytes" "context" "crypto/x509" "errors" @@ -64,7 +63,7 @@ func trustCertificate(hostname string, cert *x509.Certificate) error { knownHost, ok := hosts.Lookup(hostname) if ok { // Check fingerprint - if bytes.Equal(knownHost.Fingerprint, host.Fingerprint) { + if knownHost.Fingerprint != host.Fingerprint { return nil } return errors.New("error: fingerprint does not match!") diff --git a/tofu/tofu.go b/tofu/tofu.go index fb7361b..554b260 100644 --- a/tofu/tofu.go +++ b/tofu/tofu.go @@ -4,14 +4,14 @@ package tofu import ( "bufio" "bytes" - "crypto/sha512" + "crypto/sha256" "crypto/x509" + "encoding/base64" "errors" "fmt" "io" "os" "sort" - "strconv" "strings" "sync" ) @@ -150,7 +150,7 @@ func (k *KnownHosts) TOFU(hostname string, cert *x509.Certificate) error { k.Add(host) return nil } - if !bytes.Equal(knownHost.Fingerprint, host.Fingerprint) { + if host.Fingerprint != knownHost.Fingerprint { return fmt.Errorf("fingerprint for %q does not match", hostname) } return nil @@ -267,7 +267,7 @@ func (p *PersistentHosts) TOFU(hostname string, cert *x509.Certificate) error { if !ok { return p.Add(host) } - if !bytes.Equal(knownHost.Fingerprint, host.Fingerprint) { + if host.Fingerprint != knownHost.Fingerprint { return fmt.Errorf("fingerprint for %q does not match", hostname) } return nil @@ -280,20 +280,20 @@ func (p *PersistentHosts) Close() error { // Host represents a host entry with a fingerprint using a certain algorithm. type Host struct { - Hostname string // hostname - Algorithm string // fingerprint algorithm e.g. SHA-512 - Fingerprint Fingerprint // fingerprint + Hostname string // hostname + Algorithm string // fingerprint algorithm e.g. sha256 + Fingerprint string // fingerprint } -// NewHost returns a new host with a SHA-512 fingerprint of +// NewHost returns a new host with a SHA256 fingerprint of // the provided raw data. func NewHost(hostname string, raw []byte) Host { - sum := sha512.Sum512(raw) + sum := sha256.Sum256(raw) return Host{ Hostname: hostname, - Algorithm: "SHA-512", - Fingerprint: sum[:], + Algorithm: "sha256", + Fingerprint: base64.StdEncoding.EncodeToString(sum[:]), } } @@ -311,7 +311,7 @@ func (h Host) String() string { b.WriteByte(' ') b.WriteString(h.Algorithm) b.WriteByte(' ') - b.WriteString(h.Fingerprint.String()) + b.WriteString(h.Fingerprint) return b.String() } @@ -331,66 +331,18 @@ func (h *Host) UnmarshalText(text []byte) error { h.Hostname = string(parts[0]) algorithm := string(parts[1]) - if algorithm != "SHA-512" { + if algorithm != "sha256" { return fmt.Errorf("unsupported algorithm %q", algorithm) } h.Algorithm = algorithm - fingerprint := make([]byte, 0, sha512.Size) - scanner := bufio.NewScanner(bytes.NewReader(parts[2])) - scanner.Split(scanFingerprint) - - for scanner.Scan() { - b, err := strconv.ParseUint(scanner.Text(), 16, 8) - if err != nil { - return fmt.Errorf("failed to parse fingerprint hash: %w", err) - } - fingerprint = append(fingerprint, byte(b)) + fingerprint, err := base64.StdEncoding.DecodeString(string(parts[2])) + if err != nil { + return err } - if len(fingerprint) != sha512.Size { - return fmt.Errorf("invalid fingerprint size %d, expected %d", - len(fingerprint), sha512.Size) - } - - h.Fingerprint = fingerprint + h.Fingerprint = string(fingerprint) return nil } - -func scanFingerprint(data []byte, atEOF bool) (advance int, token []byte, err error) { - if atEOF && len(data) == 0 { - return 0, nil, nil - } - if i := bytes.IndexByte(data, ':'); i >= 0 { - // We have a full newline-terminated line. - return i + 1, data[0:i], nil - } - - // If we're at EOF, we have a final, non-terminated hex byte - if atEOF { - return len(data), data, nil - } - - // Request more data. - return 0, nil, nil -} - -// Fingerprint represents a fingerprint. -type Fingerprint []byte - -// String returns a string representation of the fingerprint. -func (f Fingerprint) String() string { - var sb strings.Builder - - for i, b := range f { - if i > 0 { - sb.WriteByte(':') - } - - fmt.Fprintf(&sb, "%02X", b) - } - - return sb.String() -}