certmanager

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Sep 9, 2022 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package certmanager manages signed exchange certificates.

To get the certificate managed, the caller needs to specify the location of the PEM file and calls the Manager's Start method at minimum:

m := certmanager.NewManager(certmanager.Config{
	RawChainSource: certmanager.WatchCertFile(certmanager.WatchConfig{
		Path: "/path/to/your.pem",
	})
})
m.Start()
defer m.Stop()

The above code lets the Manager check the PEM file every hour and retrieve the OCSP response from the OCSP responder as needed.

The Manager caches the certificate chain and the OCSP response into a disk if configured with a DiskCache. It enables them to be shared among multiple processes, e.g. with other webpackager instances, in order to reduce the OCSP responder's load.

Internals

Manager consists of two components: Producer and Cache. Producer produces certificates and sends them to Manager continuously. Cache stores produced certificates somewhere and possibly allows sharing them beyond the current running process.

The certmanager package provides Augmentor as the canonical implementation of Producer, which is composed of RawChainSource and OCSPRespSource. It looks for the updated certificate chain and OCSP response at the right timings, and uses NewAugmentedChain to turn them into an AugmentedChain. The "timings" are controlled by RawChainSource and OCSPRespSource; see the GoDoc of those types for details.

BUG(tomokinat): Manager writes to Cache, but certmanager does not reuse the cached information yet.

Index

Examples

Constants

This section is empty.

Variables

View Source
var DefaultBackoff = backoff.Backoff{
	Factor: 2,
	Jitter: true,
	Min:    time.Second,
	Max:    time.Hour,
}

DefaultBackoff is the backoff used by OCSPClient by default.

View Source
var DefaultOCSPClient = NewOCSPClient(OCSPClientConfig{})

DefaultOCSPClient is an OCSPClient with the default configuration.

View Source
var ErrNotFound = errors.New("certmanager: no certificate chain found for the specified digest")

ErrNotFound is returned by Read if it is unable to find the AugmentedChain using the provided digest.

Functions

This section is empty.

Types

type Augmentor

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

Augmentor combines RawChainSource and OCSPRespSource to serve as a Producer.

func NewAugmentor

func NewAugmentor(rcSource RawChainSource, orSource OCSPRespSource) *Augmentor

NewAugmentor creates and initializes a new Augmentor. orSource can be nil, in which case DefaultOCSPClient is used.

NewAugmentor does not start the production of AugmentedChains automatically. To start it, call Start.

func (*Augmentor) Out

func (a *Augmentor) Out() <-chan *certchain.AugmentedChain

Out returns the channel to receive produced AugmentedChains.

func (*Augmentor) Start

func (a *Augmentor) Start() error

Start spawns a goroutine to produce AugmentedChains continuously. It produces the first AugmentedChain before starting the goroutine and blocks until it is ready.

The goroutine is not spawned in case of error.

func (*Augmentor) Stop

func (a *Augmentor) Stop()

Stop kills the goroutine spawned by Start to stop producing AugmentedChains.

type Cache

type Cache interface {
	// Read returns an AugmentedChain with the provided digest. If it cannot
	// find such an AugmentedChain, it returns ErrNotFound.
	Read(digest string) (*certchain.AugmentedChain, error)

	// ReadLatest returns the latest version of the AugmentedChain. If it cannot
	// find such an AugmentedChain, it returns ErrNotFound.
	ReadLatest() (*certchain.AugmentedChain, error)

	// Write writes the AugmentedChain into the Cache.
	Write(ac *certchain.AugmentedChain) error
}

Cache represents a storage to cache an AugmentedChain.

var NullCache Cache = &nullCache{}

NullCache is a dummy Cache that does nothing.

type Config

type Config struct {
	// RawChainSource is used as part of a new Augmentor.
	// It may not be nil unless Producer is specified.
	RawChainSource RawChainSource

	// OCSPRespSource is used as part of a new Augmentor.
	// nil implies DefaultOCSPClient.
	OCSPRespSource OCSPRespSource

	// Producer allows specifying the Producer directly, especially using
	// a custom implementation. Producer takes precedence: RawChainSource
	// and OCSPRespSource will not be used if Producer is set non-nil.
	Producer Producer

	// Cache specifies where to cache the signed exchange certificates.
	// nil implies NullCache, i.e. no caching.
	Cache Cache
}

Config configures Manager.

type FetchTiming

type FetchTiming interface {
	// GetNextRun determines the nextRun return parameter.
	GetNextRun() futureevent.Event
}

FetchTiming controls the frequency of the Fetch calls on RawChainSource or OCSPRespSource.

var FetchHourly FetchTiming = FetchAtIntervals(time.Hour)

FetchHourly makes Fetch called every hour.

func FetchAtIntervals

func FetchAtIntervals(interval time.Duration) FetchTiming

FetchAtIntervals makes Fetch called at fixed intervals.

func FetchAtIntervalsWithEventFactory

func FetchAtIntervalsWithEventFactory(interval time.Duration, factory futureevent.Factory) FetchTiming

FetchAtIntervalsWithEventFactory is like FetchAtIntervals but uses factory instead of futureevent.DefaultFactory.

func FetchOnSignal

func FetchOnSignal(sig os.Signal) FetchTiming

FetchOnSignal makes Fetch called when signaled by sig.

func FetchOnlyOnce

func FetchOnlyOnce() FetchTiming

FetchOnlyOnce makes Fetch called only once, not repeatedly.

type FetchTimingFunc

type FetchTimingFunc func() futureevent.Event

FetchTimingFunc turns a function into a FetchTiming.

func (FetchTimingFunc) GetNextRun

func (f FetchTimingFunc) GetNextRun() futureevent.Event

GetNextRun calls f().

type LocalCertFile

type LocalCertFile struct {
	LocalCertFileConfig
}

LocalCertFile is a RawChainSource which reads the certificate chain from a local file in the PEM format.

Example (Hourly)

The following code creates a new LocalCertFile that reads cert.pem (roughly) every other hours.

package main

import (
	"time"

	"github.com/layer0-platform/webpackager/certchain/certmanager"
)

func main() {
	c := certmanager.LocalCertFileConfig{
		Path:        "cert.pem",
		FetchTiming: certmanager.FetchAtIntervals(2 * time.Hour),
	}
	_ = certmanager.NewLocalCertFile(c)
}
Output:

Example (Signal)

The following code creates a new LocalCertFile that reads cert.pem every time the running process receives the USR1 signal.

package main

import (
	"syscall"

	"github.com/layer0-platform/webpackager/certchain/certmanager"
)

func main() {
	c := certmanager.LocalCertFileConfig{
		Path:        "cert.pem",
		FetchTiming: certmanager.FetchOnSignal(syscall.SIGUSR1),
	}
	_ = certmanager.NewLocalCertFile(c)
}
Output:

func NewLocalCertFile

func NewLocalCertFile(c LocalCertFileConfig) *LocalCertFile

NewLocalCertFile creates and initializes a new LocalCertFile.

func (*LocalCertFile) Fetch

func (l *LocalCertFile) Fetch(chain *certchain.RawChain, now func() time.Time) (newchain *certchain.RawChain, nextRun futureevent.Event, err error)

Fetch reads the certificate chain from l.Path and returns it as newChain, whether or not it is updated from chain.

type LocalCertFileConfig

type LocalCertFileConfig struct {
	// Path locates the PEM file containing the certificate chain.
	Path string

	// FetchTiming controls the frequency of checking for the certificate.
	// nil implies certmanager.FetchHourly.
	FetchTiming FetchTiming

	// AllowTestCert specifies whether to allow test certificates.
	//
	// LocalCertFile calls VerifyChain and VerifySXGCriteria to make sure
	// RawChain is valid for use with signed exchanges. If AllowTestCert
	// is set true, LocalCertFile skips VerifySXGCriteria and accepts any
	// RawChain as long as it is valid in terms of VerifyChain.
	AllowTestCert bool
}

type Manager

type Manager struct {
	Cache Cache
	// contains filtered or unexported fields
}

Manager keeps a signed exchange certificate up-to-date. See the package document for details.

func NewManager

func NewManager(c Config) *Manager

NewManager creates and initializes a new Manager.

func (*Manager) GetAugmentedChain

func (m *Manager) GetAugmentedChain() *certchain.AugmentedChain

GetAugmentedChain returns the AugmentedChain that m currently holds.

func (*Manager) Start

func (m *Manager) Start() error

Start starts managing the certificate. It starts Producer and waits for the first AugmentedChain, then kicks in a goroutine to keep Cache updated with the received AugmentedChains. The execution is blocked until the first AugmentedChain comes in.

To stop the management, call Stop.

func (*Manager) Stop

func (m *Manager) Stop()

Stop stops the Manager m from managing the certificate: stops m.Producer and the cache updater goroutine spawned by Start.

If m is writing an AugmentedChain to m.Cache when Stop is called, that cache write continues on background. Stop returns without waiting for its completion.

type MultiCertDiskCache

type MultiCertDiskCache struct {
	MultiCertDiskCacheConfig
}

MultiCertDiskCache is a Cache on a local filesystem. It writes the certificate chain in the PEM format and the OCSP response in the DER format to separate files as specified by MultiCertDiskCacheConfig. It uses the digest of the certificate chain as the basename for the certificate and OCSP files.

func NewMultiCertDiskCache

func NewMultiCertDiskCache(config MultiCertDiskCacheConfig) (*MultiCertDiskCache, error)

NewMultiCertDiskCache creates and initializes a new MultiCertDiskCache.

func (*MultiCertDiskCache) Read

Read reads the certificate chain and the OCSP response from local files and reproduces an AugmentedChain. Read uses digest as the base filename used to retrieve the elements needed to construct the AugmentedChain. Read returns a multierror.Error (hashicorp/go-multierror) to report as many problems as possible.

func (*MultiCertDiskCache) ReadLatest

func (d *MultiCertDiskCache) ReadLatest() (*certchain.AugmentedChain, error)

ReadLatest returns the latest version of the AugmentedChain in the cache, ErrNotFound otherwise.

func (*MultiCertDiskCache) Write

Write writes the certificate chain and the OCSP response from ac into local files. It returns a multierror.Error (hashicorp/go-multierror) to report as many problems as possible.

type MultiCertDiskCacheConfig

type MultiCertDiskCacheConfig struct {
	// CertDir locates the directory to write the certificate chain to.
	// If CertDir is empty, NewMultiCertDiskCache returns an error.
	CertDir string

	// LatestCertFile specifies the filename to be used for the latest
	// version of the certificate. The file will be located in CertDir.
	// If LatestCertFile is empty, NewMultiCertDiskCache returns an error.
	LatestCertFile string

	// LatestOCSPFile specifies the filename to be used for the latest
	// version of the OCSP. The file will be located in CertDir.
	// If LatestOCSPFile is empty, NewMultiCertDiskCache returns an error.
	LatestOCSPFile string

	// LockFile locates the lock file. Must be non-empty. The file will be
	// located in CertDir. If LockFile is empty, NewMultiCertDiskCache returns
	// an error.
	LockFile string
}

MultiCertDiskCacheConfig configures DiskCache.

type OCSPClient

type OCSPClient struct {
	OCSPClientConfig
}

OCSPClient represents a client of OCSP over HTTP.

func NewOCSPClient

func NewOCSPClient(config OCSPClientConfig) *OCSPClient

NewOCSPClient creates and initializes a new OCSPClient.

func (OCSPClient) Fetch

func (c OCSPClient) Fetch(chain *certchain.RawChain, now func() time.Time) (ocspResp *certchain.OCSPResponse, nextRun futureevent.Event, err error)

Fetch sends an OCSP request to the OCSP responder at chain.OCSPServer and returns the parsed OCSP response, with a futureevent.Event to notify when this OCSPClient expects the next call of Fetch.

now is a function that returns the current time, usually time.Now. Fetch calls it after retrieving and parsing the OCSP response and examines the validity as of the returned time.

On success, nextRun will be set with the middle point between ThisUpdate and NextUpdate of the OCSP response or the cache expiry time of the HTTP response, whichever comes earlier. On failure, the next Fetch will be scheduled for a retry at the time determined based on c.RetryPolicy.

Keep in mind that a clock skew between the local machine and the OCSP server could cause a valid response to be judged invalid. To mitigate it, include some tweaks in the now function.

type OCSPClientConfig

type OCSPClientConfig struct {
	// HTTPClient is an HTTP client used to send an OCSP request.
	// nil implies http.DefaultClient.
	HTTPClient *http.Client

	// RetryPolicy determines when to make a retry on fetch failure.
	// nil implies DefaultBackoff.
	RetryPolicy *backoff.Backoff

	// AllowTestCert specifies whether to allow certificates without
	// any OCSP URI. If AllowTestCert is set true, OCSPClient returns
	// DummyOCSPResponse for OCSP-less certificates.
	AllowTestCert bool

	// NewFutureEventAt is called by Fetch to create the nextRun return
	// parameter. nil implies futureevent.DefaultFactory.
	NewFutureEventAt futureevent.Factory
}

OCSPClientConfig configures OCSPClient.

type OCSPRespSource

type OCSPRespSource interface {
	// Fetch retrieves an OCSP response for chain and returns the parsed OCSP
	// response with a futureevent.Event to notify when the OCSPRespSource
	// expects the next call of Fetch.
	//
	// now is a function which returns the current time. Fetch calls it after
	// retriving and parsing the OCSP response and examines the validity as
	// of the returned time. time.Now will do in most of the time, but the
	// caller may want to use a different function in unit testing or to deal
	// with clock skews.
	//
	// nextRun is always non-nil and valid, even in the error case.
	Fetch(chain *certchain.RawChain, now func() time.Time) (ocspResp *certchain.OCSPResponse, nextRun futureevent.Event, err error)
}

OCSPRespSource provides an OCSPResponse. It is designed to be called repeatedly: the Fetch method does not just return the OCSP response, but also instructs when it should be called again to receive the next update.

var DummyOCSPRespSource OCSPRespSource = &dummyOCSPRespSource{}

DummyOCSPRespSource always returns certchain.DummyOCSPResponse.

type Producer

type Producer interface {
	// Out returns the channel to receive produced AugmentedChains.
	Out() <-chan *certchain.AugmentedChain
	// Start starts producing new AugmentedChains.
	Start() error
	// Stop stops producing new AugmentedChains.
	Stop()
}

Producer produces a new AugmentedChain repeatedly and sends it through a channel every time Producer completes the production.

type RawChainSource

type RawChainSource interface {
	// Fetch returns a new RawChain to replace chain with a futureevent.Event
	// to notify when the RawChainSource expects the next call of Fetch.
	//
	// chain can be nil. Fetch returns a valid RawChain, which the caller can
	// use as the initial one.
	//
	// now is a function which returns the current time. Fetch calls it after
	// retrieving and parsing the certificate chain and examines the validity
	// as of the returned time. time.Now will do in most of the time, but the
	// caller may want to use a different function in unit testing or to deal
	// with clock skews.
	//
	// Fetch may return chain as newChain if it is valid and still up-to-date.
	//
	// nextRun is always non-nil and valid, even in the error case.
	Fetch(chain *certchain.RawChain, now func() time.Time) (newChain *certchain.RawChain, nextRun futureevent.Event, err error)
}

RawChainSource provides a RawChain. It is designed to be called repeatedly: the Fetch method does not just return the latest certificate chain, but also instructs when it should be called again to receive the next update.

type SingleCertDiskCache

type SingleCertDiskCache struct {
	SingleCertDiskCacheConfig
}

SingleCertDiskCache is a Cache on a local filesystem. It writes the certificate chain in the PEM format and the OCSP response in the DER format to separate files as specified by SingleCertDiskCacheConfig.

func NewSingleCertDiskCache

func NewSingleCertDiskCache(config SingleCertDiskCacheConfig) *SingleCertDiskCache

NewSingleCertDiskCache creates and initializes a new SingleCertDiskCache.

func (*SingleCertDiskCache) Read

Read reads the certificate chain and the OCSP response from local files and reproduces an AugmentedChain. Read works only when d.CertPath and d.OCSPPath are both non-empty and otherwise returns an error. Read returns a multierror.Error (hashicorp/go-multierror) to report as many problems as possible.

func (*SingleCertDiskCache) ReadLatest

func (d *SingleCertDiskCache) ReadLatest() (*certchain.AugmentedChain, error)

ReadLatest returns the cached AugmentedChain, otherwise it returns an error.

func (*SingleCertDiskCache) Write

Write writes the certificate chain and the OCSP response from ac into local files. It returns a multierror.Error (hashicorp/go-multierror) to report as many problems as possible.

type SingleCertDiskCacheConfig

type SingleCertDiskCacheConfig struct {
	// CertPath locates the PEM file to write the certificate chain to.
	// If CertPath is empty, the certificate chain is not cached.
	CertPath string

	// OCSPPath locates the file to write the OCSP response DER bytes to.
	// If OCSPPath is empty, the OCSP response is not cached.
	OCSPPath string

	// LockPath locates the lock file. Must be non-empty.
	LockPath string
}

SingleCertDiskCacheConfig configures SingleCertDiskCache.

Notes

Bugs

  • Manager writes to Cache, but certmanager does not reuse the cached information yet.

Directories

Path Synopsis
Package acmeclient provides a RawChainSource to acquire a signed exchange certificate using the ACME protocol.
Package acmeclient provides a RawChainSource to acquire a signed exchange certificate using the ACME protocol.
Package futureevent defines interface to handle future events.
Package futureevent defines interface to handle future events.

Jump to

Keyboard shortcuts

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