tofu

package module
v0.0.0-...-a007927 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 21, 2024 License: BSD-3-Clause Imports: 10 Imported by: 1

README

CI status License Go Report Card

tofu

Introduction

This package implements the TOFU (trust on first use) authentication scheme.

To read more about it, check out the following links:

Usage

tofu provides an interface, Store, to allow the library consumer to choose how they want to manage their known hosts.

There are two implementations, a FileStore and an InMemoryStore.
When using FileStore, the implementation assumes a format similar to the known_hosts file used by SSH, each line is a comma-separated set of values:

  • hash(address)
  • fingerprint - hash(data)
  • comment (optional)
Example

Define a connection verification function.

var (
    ErrInvalidCert = errors.New("invalid certificate")
    ErrNoPeerCerts = errors.New("no peer certificates")
)

func verifyConn(store tofu.Store) verifyFunc {
    return func(state tls.ConnectionState) error {
        // check for peer certificates
        peerCerts := state.PeerCertificates
        if len(peerCerts) == 0 {
            return ErrNoPeerCerts
        }

        leaf := state.PeerCertificates[0]

        // get fingerprint
        host := tofu.Host{
            Address:     state.ServerName,
            Fingerprint: tofu.Fingerprint(leaf),
        }

        // verify host with fingerprint
        valid, err := tofu.Verify(store, host)
        if err != nil {
            return fmt.Errorf("error verifying: %w", err)
        }

        if !valid {
            return ErrInvalidCert
        }

        return nil
    }
}

Pass it into a tls.Config

const minTLSVersion = tls.VersionTLS12

config := &tls.Config{
	MinVersion:         minTLSVersion,
	InsecureSkipVerify: true,
	VerifyConnection:   verifyConn(myCertStore),
}

Documentation

Overview

Package tofu implements the TOFU (trust on first use) authentication scheme.

To read more about it, check out the following links:

Usage

The package provides an interface, Store, to allow the library consumer to choose however they want to handle known hosts.

There are two implementations, FileStore and InMemoryStore.

When using FileStore, the implementation assumes a format similar to the known_hosts file used by SSH, that is, each line is a comma-separated set of values:

  • hash(address)
  • fingerprint - hash(data)
  • comment (optional)

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrHostAlreadyExists = errors.New("host already exists")
	ErrHostNotFound      = errors.New("host not found")
)

Functions

func Fingerprint

func Fingerprint(cert *x509.Certificate) string

Fingerprint returns the md5 hash of the DER encoded bytes.

func Update

func Update(store Store, h Host) error

Update will use the Store's methods to update a given host. It deletes the old host, then adds the new one.

func Verify

func Verify(store Store, host Host) (bool, error)

Verify performs TOFU verification on a Host using the provided Store. It returns true if the verification passes. If a host is not known, it will add it to the known hosts.

Types

type FileStore

type FileStore struct {
	// contains filtered or unexported fields
}

FileStore is implemented as an InMemoryStore that is backed by a file. By convention, the public methods can be assumed to be concurrency-safe but none of the private methods should be assumed to be concurrency-safe as they may not be.

@TODO: the mutex should be used and named better (fileMutex?).

func NewFileStore

func NewFileStore(fpath string) (*FileStore, error)

func (*FileStore) Add

func (store *FileStore) Add(h Host) error

Add will add a Host to the list of known hosts. If the host has already been added, it will return a ErrHostAlreadyExists error instead.

func (*FileStore) Delete

func (store *FileStore) Delete(address string) error

Delete will delete the Host matching address from the known hosts. If it has not been added, ErrHostNotFound will be returned.

func (*FileStore) Lookup

func (store *FileStore) Lookup(address string) (Host, error)

Lookup will look for the host matching "address" in the known_hosts file. If no Host is found ErrHostNotFound is returned.

type Host

type Host struct {
	Address     string
	Fingerprint string
	Comment     string
}

type InMemoryStore

type InMemoryStore struct {
	// contains filtered or unexported fields
}

InMemoryStore is a concurrency-safe in-memory store of known hosts.

func NewInMemoryStore

func NewInMemoryStore() *InMemoryStore

func (*InMemoryStore) Add

func (store *InMemoryStore) Add(host Host) error

Add will add a Host to the list of known hosts. If the Host has already been added, it will return a ErrHostAlreadyExists error instead.

func (*InMemoryStore) Delete

func (store *InMemoryStore) Delete(address string) error

Delete will delete the Host matching address. If it has not been added, ErrHostNotFound will be returned.

func (*InMemoryStore) Lookup

func (store *InMemoryStore) Lookup(address string) (Host, error)

Lookup will look for the Host matching "address" If no Host is found ErrHostNotFound is returned.

type Store

type Store interface {
	// Add will add a host. If it is already known, it is
	// expected implementations will return ErrHostAlreadyExists.
	Add(h Host) error

	// Delete will delete the host if it is found, otherwise
	// it is expected implementations will return ErrHostNotFound.
	Delete(address string) error

	// Lookup will check if a host is present otherwise it
	// is expected that implementations will return ErrHostNotFound.
	Lookup(address string) (Host, error)
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL