2018-12-10 13:15:26 +10:00
|
|
|
// Copyright 2015 Matthew Holt
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package certmagic
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2024-04-12 04:23:53 +10:00
|
|
|
weakrand "math/rand"
|
2019-09-14 03:43:02 +10:00
|
|
|
"strings"
|
2018-12-10 13:15:26 +10:00
|
|
|
"sync"
|
|
|
|
"time"
|
2020-07-30 11:38:12 +10:00
|
|
|
|
|
|
|
"go.uber.org/zap"
|
2018-12-10 13:15:26 +10:00
|
|
|
)
|
|
|
|
|
|
|
|
// Cache is a structure that stores certificates in memory.
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// A Cache indexes certificates by name for quick access
|
|
|
|
// during TLS handshakes, and avoids duplicating certificates
|
|
|
|
// in memory. Generally, there should only be one per process.
|
|
|
|
// However, that is not a strict requirement; but using more
|
|
|
|
// than one is a code smell, and may indicate an
|
|
|
|
// over-engineered design.
|
2018-12-10 13:15:26 +10:00
|
|
|
//
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// An empty cache is INVALID and must not be used. Be sure
|
|
|
|
// to call NewCache to get a valid value.
|
2018-12-10 13:15:26 +10:00
|
|
|
//
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// These should be very long-lived values and must not be
|
2018-12-10 13:15:26 +10:00
|
|
|
// copied. Before all references leave scope to be garbage
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// collected, ensure you call Stop() to stop maintenance on
|
|
|
|
// the certificates stored in this cache and release locks.
|
|
|
|
//
|
|
|
|
// Caches are not usually manipulated directly; create a
|
|
|
|
// Config value with a pointer to a Cache, and then use
|
|
|
|
// the Config to interact with the cache. Caches are
|
|
|
|
// agnostic of any particular storage or ACME config,
|
|
|
|
// since each certificate may be managed and stored
|
|
|
|
// differently.
|
2018-12-10 13:15:26 +10:00
|
|
|
type Cache struct {
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// User configuration of the cache
|
2023-07-09 01:56:51 +10:00
|
|
|
options CacheOptions
|
|
|
|
optionsMu sync.RWMutex
|
2018-12-10 13:15:26 +10:00
|
|
|
|
|
|
|
// The cache is keyed by certificate hash
|
|
|
|
cache map[string]Certificate
|
|
|
|
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// cacheIndex is a map of SAN to cache key (cert hash)
|
|
|
|
cacheIndex map[string][]string
|
|
|
|
|
2023-07-09 01:56:51 +10:00
|
|
|
// Protects the cache and cacheIndex maps
|
2018-12-10 13:15:26 +10:00
|
|
|
mu sync.RWMutex
|
|
|
|
|
|
|
|
// Close this channel to cancel asset maintenance
|
|
|
|
stopChan chan struct{}
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
|
|
|
|
// Used to signal when stopping is completed
|
|
|
|
doneChan chan struct{}
|
2020-07-30 11:38:12 +10:00
|
|
|
|
|
|
|
logger *zap.Logger
|
2018-12-10 13:15:26 +10:00
|
|
|
}
|
|
|
|
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// NewCache returns a new, valid Cache for efficiently
|
|
|
|
// accessing certificates in memory. It also begins a
|
|
|
|
// maintenance goroutine to tend to the certificates
|
|
|
|
// in the cache. Call Stop() when you are done with the
|
|
|
|
// cache so it can clean up locks and stuff.
|
2018-12-10 13:15:26 +10:00
|
|
|
//
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// Most users of this package will not need to call this
|
|
|
|
// because a default certificate cache is created for you.
|
|
|
|
// Only advanced use cases require creating a new cache.
|
2018-12-10 13:15:26 +10:00
|
|
|
//
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// This function panics if opts.GetConfigForCert is not
|
|
|
|
// set. The reason is that a cache absolutely needs to
|
|
|
|
// be able to get a Config with which to manage TLS
|
|
|
|
// assets, and it is not safe to assume that the Default
|
|
|
|
// config is always the correct one, since you have
|
|
|
|
// created the cache yourself.
|
|
|
|
//
|
|
|
|
// See the godoc for Cache to use it properly. When
|
|
|
|
// no longer needed, caches should be stopped with
|
|
|
|
// Stop() to clean up resources even if the process
|
|
|
|
// is being terminated, so that it can clean up
|
|
|
|
// any locks for other processes to unblock!
|
|
|
|
func NewCache(opts CacheOptions) *Cache {
|
|
|
|
// assume default options if necessary
|
|
|
|
if opts.OCSPCheckInterval <= 0 {
|
|
|
|
opts.OCSPCheckInterval = DefaultOCSPCheckInterval
|
|
|
|
}
|
|
|
|
if opts.RenewCheckInterval <= 0 {
|
|
|
|
opts.RenewCheckInterval = DefaultRenewCheckInterval
|
|
|
|
}
|
2020-06-02 07:03:14 +10:00
|
|
|
if opts.Capacity < 0 {
|
|
|
|
opts.Capacity = 0
|
|
|
|
}
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
|
|
|
|
// this must be set, because we cannot not
|
|
|
|
// safely assume that the Default Config
|
|
|
|
// is always the correct one to use
|
|
|
|
if opts.GetConfigForCert == nil {
|
|
|
|
panic("cache must be initialized with a GetConfigForCert callback")
|
|
|
|
}
|
|
|
|
|
2018-12-10 13:15:26 +10:00
|
|
|
c := &Cache{
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
options: opts,
|
|
|
|
cache: make(map[string]Certificate),
|
|
|
|
cacheIndex: make(map[string][]string),
|
|
|
|
stopChan: make(chan struct{}),
|
|
|
|
doneChan: make(chan struct{}),
|
2020-07-30 11:38:12 +10:00
|
|
|
logger: opts.Logger,
|
2018-12-10 13:15:26 +10:00
|
|
|
}
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
|
2022-09-27 02:19:28 +10:00
|
|
|
// absolutely do not allow a nil logger; panics galore
|
|
|
|
if c.logger == nil {
|
|
|
|
c.logger = defaultLogger
|
|
|
|
}
|
|
|
|
|
2020-05-14 03:11:27 +10:00
|
|
|
go c.maintainAssets(0)
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
|
2018-12-10 13:15:26 +10:00
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2023-07-09 01:56:51 +10:00
|
|
|
func (certCache *Cache) SetOptions(opts CacheOptions) {
|
|
|
|
certCache.optionsMu.Lock()
|
|
|
|
certCache.options = opts
|
|
|
|
certCache.optionsMu.Unlock()
|
|
|
|
}
|
|
|
|
|
2018-12-10 13:15:26 +10:00
|
|
|
// Stop stops the maintenance goroutine for
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// certificates in certCache. It blocks until
|
|
|
|
// stopping is complete. Once a cache is
|
|
|
|
// stopped, it cannot be reused.
|
2018-12-10 13:15:26 +10:00
|
|
|
func (certCache *Cache) Stop() {
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
close(certCache.stopChan) // signal to stop
|
|
|
|
<-certCache.doneChan // wait for stop to complete
|
|
|
|
}
|
|
|
|
|
|
|
|
// CacheOptions is used to configure certificate caches.
|
|
|
|
// Once a cache has been created with certain options,
|
|
|
|
// those settings cannot be changed.
|
|
|
|
type CacheOptions struct {
|
|
|
|
// REQUIRED. A function that returns a configuration
|
|
|
|
// used for managing a certificate, or for accessing
|
|
|
|
// that certificate's asset storage (e.g. for
|
|
|
|
// OCSP staples, etc). The returned Config MUST
|
2023-06-06 08:33:38 +10:00
|
|
|
// be associated with the same Cache as the caller,
|
|
|
|
// use New to obtain a valid Config.
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
//
|
|
|
|
// The reason this is a callback function, dynamically
|
|
|
|
// returning a Config (instead of attaching a static
|
|
|
|
// pointer to a Config on each certificate) is because
|
|
|
|
// the config for how to manage a domain's certificate
|
|
|
|
// might change from maintenance to maintenance. The
|
|
|
|
// cache is so long-lived, we cannot assume that the
|
|
|
|
// host's situation will always be the same; e.g. the
|
|
|
|
// certificate might switch DNS providers, so the DNS
|
|
|
|
// challenge (if used) would need to be adjusted from
|
|
|
|
// the last time it was run ~8 weeks ago.
|
|
|
|
GetConfigForCert ConfigGetter
|
|
|
|
|
|
|
|
// How often to check certificates for renewal;
|
|
|
|
// if unset, DefaultOCSPCheckInterval will be used.
|
|
|
|
OCSPCheckInterval time.Duration
|
|
|
|
|
|
|
|
// How often to check certificates for renewal;
|
|
|
|
// if unset, DefaultRenewCheckInterval will be used.
|
|
|
|
RenewCheckInterval time.Duration
|
2020-06-02 07:03:14 +10:00
|
|
|
|
|
|
|
// Maximum number of certificates to allow in the cache.
|
|
|
|
// If reached, certificates will be randomly evicted to
|
|
|
|
// make room for new ones. 0 means unlimited.
|
|
|
|
Capacity int
|
2020-07-30 11:38:12 +10:00
|
|
|
|
|
|
|
// Set a logger to enable logging
|
|
|
|
Logger *zap.Logger
|
2018-12-10 13:15:26 +10:00
|
|
|
}
|
|
|
|
|
2020-02-25 05:23:54 +10:00
|
|
|
// ConfigGetter is a function that returns a prepared,
|
|
|
|
// valid config that should be used when managing the
|
|
|
|
// given certificate or its assets.
|
|
|
|
type ConfigGetter func(Certificate) (*Config, error)
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
|
|
|
|
// cacheCertificate calls unsyncedCacheCertificate with a write lock.
|
2018-12-10 13:15:26 +10:00
|
|
|
//
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// This function is safe for concurrent use.
|
|
|
|
func (certCache *Cache) cacheCertificate(cert Certificate) {
|
|
|
|
certCache.mu.Lock()
|
|
|
|
certCache.unsyncedCacheCertificate(cert)
|
|
|
|
certCache.mu.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
// unsyncedCacheCertificate adds cert to the in-memory cache unless
|
|
|
|
// it already exists in the cache (according to cert.Hash). It
|
|
|
|
// updates the name index.
|
2018-12-10 13:15:26 +10:00
|
|
|
//
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// This function is NOT safe for concurrent use. Callers MUST acquire
|
|
|
|
// a write lock on certCache.mu first.
|
|
|
|
func (certCache *Cache) unsyncedCacheCertificate(cert Certificate) {
|
2022-12-06 05:34:37 +10:00
|
|
|
// if this certificate already exists in the cache, this is basically
|
|
|
|
// a no-op so we reuse existing cert (prevent duplication), but we do
|
|
|
|
// modify the cert to add tags it may be missing (see issue #211)
|
|
|
|
if existingCert, ok := certCache.cache[cert.hash]; ok {
|
|
|
|
logMsg := "certificate already cached"
|
|
|
|
|
|
|
|
if len(cert.Tags) > 0 {
|
|
|
|
for _, tag := range cert.Tags {
|
|
|
|
if !existingCert.HasTag(tag) {
|
|
|
|
existingCert.Tags = append(existingCert.Tags, tag)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
certCache.cache[cert.hash] = existingCert
|
|
|
|
logMsg += "; appended any missing tags to cert"
|
|
|
|
}
|
|
|
|
|
2023-01-17 14:48:46 +10:00
|
|
|
certCache.logger.Debug(logMsg,
|
2022-09-27 02:19:28 +10:00
|
|
|
zap.Strings("subjects", cert.Names),
|
|
|
|
zap.Time("expiration", expiresAt(cert.Leaf)),
|
|
|
|
zap.Bool("managed", cert.managed),
|
|
|
|
zap.String("issuer_key", cert.issuerKey),
|
2022-12-06 05:34:37 +10:00
|
|
|
zap.String("hash", cert.hash),
|
|
|
|
zap.Strings("tags", cert.Tags))
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-06-02 07:03:14 +10:00
|
|
|
// if the cache is at capacity, make room for new cert
|
|
|
|
cacheSize := len(certCache.cache)
|
2023-07-09 01:56:51 +10:00
|
|
|
certCache.optionsMu.RLock()
|
|
|
|
atCapacity := certCache.options.Capacity > 0 && cacheSize >= certCache.options.Capacity
|
|
|
|
certCache.optionsMu.RUnlock()
|
|
|
|
|
|
|
|
if atCapacity {
|
2020-06-02 07:03:14 +10:00
|
|
|
// Go maps are "nondeterministic" but not actually random,
|
|
|
|
// so although we could just chop off the "front" of the
|
|
|
|
// map with less code, that is a heavily skewed eviction
|
|
|
|
// strategy; generating random numbers is cheap and
|
|
|
|
// ensures a much better distribution.
|
|
|
|
rnd := weakrand.Intn(cacheSize)
|
|
|
|
i := 0
|
|
|
|
for _, randomCert := range certCache.cache {
|
|
|
|
if i == rnd {
|
2022-09-27 02:19:28 +10:00
|
|
|
certCache.logger.Debug("cache full; evicting random certificate",
|
|
|
|
zap.Strings("removing_subjects", randomCert.Names),
|
|
|
|
zap.String("removing_hash", randomCert.hash),
|
|
|
|
zap.Strings("inserting_subjects", cert.Names),
|
|
|
|
zap.String("inserting_hash", cert.hash))
|
2020-06-02 07:03:14 +10:00
|
|
|
certCache.removeCertificate(randomCert)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// store the certificate
|
2019-06-25 03:51:58 +10:00
|
|
|
certCache.cache[cert.hash] = cert
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
|
|
|
|
// update the index so we can access it by name
|
|
|
|
for _, name := range cert.Names {
|
2019-06-25 03:51:58 +10:00
|
|
|
certCache.cacheIndex[name] = append(certCache.cacheIndex[name], cert.hash)
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
}
|
2021-08-31 03:52:13 +10:00
|
|
|
|
2023-07-09 01:56:51 +10:00
|
|
|
certCache.optionsMu.RLock()
|
2022-09-27 02:19:28 +10:00
|
|
|
certCache.logger.Debug("added certificate to cache",
|
|
|
|
zap.Strings("subjects", cert.Names),
|
|
|
|
zap.Time("expiration", expiresAt(cert.Leaf)),
|
|
|
|
zap.Bool("managed", cert.managed),
|
|
|
|
zap.String("issuer_key", cert.issuerKey),
|
|
|
|
zap.String("hash", cert.hash),
|
|
|
|
zap.Int("cache_size", len(certCache.cache)),
|
|
|
|
zap.Int("cache_capacity", certCache.options.Capacity))
|
2023-07-09 01:56:51 +10:00
|
|
|
certCache.optionsMu.RUnlock()
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// removeCertificate removes cert from the cache.
|
2018-12-10 13:15:26 +10:00
|
|
|
//
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// This function is NOT safe for concurrent use; callers
|
|
|
|
// MUST first acquire a write lock on certCache.mu.
|
|
|
|
func (certCache *Cache) removeCertificate(cert Certificate) {
|
|
|
|
// delete all mentions of this cert from the name index
|
|
|
|
for _, name := range cert.Names {
|
|
|
|
keyList := certCache.cacheIndex[name]
|
2021-08-31 03:52:13 +10:00
|
|
|
for i := 0; i < len(keyList); i++ {
|
|
|
|
if keyList[i] == cert.hash {
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
keyList = append(keyList[:i], keyList[i+1:]...)
|
2021-08-31 03:52:13 +10:00
|
|
|
i--
|
2018-12-10 13:15:26 +10:00
|
|
|
}
|
|
|
|
}
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
if len(keyList) == 0 {
|
|
|
|
delete(certCache.cacheIndex, name)
|
|
|
|
} else {
|
|
|
|
certCache.cacheIndex[name] = keyList
|
2018-12-10 13:15:26 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
// delete the actual cert from the cache
|
2019-06-25 03:51:58 +10:00
|
|
|
delete(certCache.cache, cert.hash)
|
2021-08-31 03:52:13 +10:00
|
|
|
|
2023-07-09 01:56:51 +10:00
|
|
|
certCache.optionsMu.RLock()
|
2022-09-27 02:19:28 +10:00
|
|
|
certCache.logger.Debug("removed certificate from cache",
|
|
|
|
zap.Strings("subjects", cert.Names),
|
|
|
|
zap.Time("expiration", expiresAt(cert.Leaf)),
|
|
|
|
zap.Bool("managed", cert.managed),
|
|
|
|
zap.String("issuer_key", cert.issuerKey),
|
|
|
|
zap.String("hash", cert.hash),
|
|
|
|
zap.Int("cache_size", len(certCache.cache)),
|
|
|
|
zap.Int("cache_capacity", certCache.options.Capacity))
|
2023-07-09 01:56:51 +10:00
|
|
|
certCache.optionsMu.RUnlock()
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// replaceCertificate atomically replaces oldCert with newCert in
|
|
|
|
// the cache.
|
|
|
|
//
|
|
|
|
// This method is safe for concurrent use.
|
|
|
|
func (certCache *Cache) replaceCertificate(oldCert, newCert Certificate) {
|
|
|
|
certCache.mu.Lock()
|
|
|
|
certCache.removeCertificate(oldCert)
|
|
|
|
certCache.unsyncedCacheCertificate(newCert)
|
|
|
|
certCache.mu.Unlock()
|
2022-09-27 02:19:28 +10:00
|
|
|
certCache.logger.Info("replaced certificate in cache",
|
|
|
|
zap.Strings("subjects", newCert.Names),
|
|
|
|
zap.Time("new_expiration", expiresAt(newCert.Leaf)))
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
}
|
|
|
|
|
2023-07-09 01:56:51 +10:00
|
|
|
// getAllMatchingCerts returns all certificates with exactly this subject
|
|
|
|
// (wildcards are NOT expanded).
|
|
|
|
func (certCache *Cache) getAllMatchingCerts(subject string) []Certificate {
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
certCache.mu.RLock()
|
|
|
|
defer certCache.mu.RUnlock()
|
|
|
|
|
2023-07-09 01:56:51 +10:00
|
|
|
allCertKeys := certCache.cacheIndex[subject]
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
|
|
|
|
certs := make([]Certificate, len(allCertKeys))
|
|
|
|
for i := range allCertKeys {
|
|
|
|
certs[i] = certCache.cache[allCertKeys[i]]
|
2018-12-10 13:15:26 +10:00
|
|
|
}
|
|
|
|
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
return certs
|
|
|
|
}
|
|
|
|
|
2020-03-18 08:00:18 +10:00
|
|
|
func (certCache *Cache) getAllCerts() []Certificate {
|
|
|
|
certCache.mu.RLock()
|
|
|
|
defer certCache.mu.RUnlock()
|
|
|
|
certs := make([]Certificate, 0, len(certCache.cache))
|
|
|
|
for _, cert := range certCache.cache {
|
|
|
|
certs = append(certs, cert)
|
|
|
|
}
|
|
|
|
return certs
|
|
|
|
}
|
|
|
|
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
func (certCache *Cache) getConfig(cert Certificate) (*Config, error) {
|
2023-07-09 01:56:51 +10:00
|
|
|
certCache.optionsMu.RLock()
|
|
|
|
getCert := certCache.options.GetConfigForCert
|
|
|
|
certCache.optionsMu.RUnlock()
|
|
|
|
|
|
|
|
cfg, err := getCert(cert)
|
2018-12-10 13:15:26 +10:00
|
|
|
if err != nil {
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
return nil, err
|
2018-12-10 13:15:26 +10:00
|
|
|
}
|
2023-06-06 08:33:38 +10:00
|
|
|
if cfg.certCache == nil {
|
|
|
|
return nil, fmt.Errorf("config returned for certificate %v has nil cache; expected %p (this one)",
|
|
|
|
cert.Names, certCache)
|
|
|
|
}
|
|
|
|
if cfg.certCache != certCache {
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
return nil, fmt.Errorf("config returned for certificate %v is not nil and points to different cache; got %p, expected %p (this one)",
|
|
|
|
cert.Names, cfg.certCache, certCache)
|
|
|
|
}
|
2020-02-25 05:23:54 +10:00
|
|
|
return cfg, nil
|
2018-12-10 13:15:26 +10:00
|
|
|
}
|
|
|
|
|
2019-09-14 03:43:02 +10:00
|
|
|
// AllMatchingCertificates returns a list of all certificates that could
|
|
|
|
// be used to serve the given SNI name, including exact SAN matches and
|
|
|
|
// wildcard matches.
|
|
|
|
func (certCache *Cache) AllMatchingCertificates(name string) []Certificate {
|
|
|
|
// get exact matches first
|
|
|
|
certs := certCache.getAllMatchingCerts(name)
|
|
|
|
|
|
|
|
// then look for wildcard matches by replacing each
|
|
|
|
// label of the domain name with wildcards
|
|
|
|
labels := strings.Split(name, ".")
|
|
|
|
for i := range labels {
|
|
|
|
labels[i] = "*"
|
|
|
|
candidate := strings.Join(labels, ".")
|
|
|
|
certs = append(certs, certCache.getAllMatchingCerts(candidate)...)
|
|
|
|
}
|
|
|
|
|
|
|
|
return certs
|
2019-08-10 04:12:46 +10:00
|
|
|
}
|
|
|
|
|
2024-04-24 03:25:19 +10:00
|
|
|
// SubjectIssuer pairs a subject name with an issuer ID/key.
|
|
|
|
type SubjectIssuer struct {
|
|
|
|
Subject, IssuerKey string
|
|
|
|
}
|
|
|
|
|
2023-07-09 01:56:51 +10:00
|
|
|
// RemoveManaged removes managed certificates for the given subjects from the cache.
|
2024-04-24 03:25:19 +10:00
|
|
|
// This effectively stops maintenance of those certificates. If an IssuerKey is
|
|
|
|
// specified alongside the subject, only certificates for that subject from the
|
|
|
|
// specified issuer will be removed.
|
|
|
|
func (certCache *Cache) RemoveManaged(subjects []SubjectIssuer) {
|
2023-07-09 01:56:51 +10:00
|
|
|
deleteQueue := make([]string, 0, len(subjects))
|
2024-04-24 03:25:19 +10:00
|
|
|
for _, subj := range subjects {
|
|
|
|
certs := certCache.getAllMatchingCerts(subj.Subject) // does NOT expand wildcards; exact matches only
|
2023-07-09 01:56:51 +10:00
|
|
|
for _, cert := range certs {
|
|
|
|
if !cert.managed {
|
|
|
|
continue
|
|
|
|
}
|
2024-04-24 03:25:19 +10:00
|
|
|
if subj.IssuerKey == "" || cert.issuerKey == subj.IssuerKey {
|
2024-04-24 02:47:06 +10:00
|
|
|
deleteQueue = append(deleteQueue, cert.hash)
|
|
|
|
}
|
2023-07-09 01:56:51 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
certCache.Remove(deleteQueue)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove removes certificates with the given hashes from the cache.
|
|
|
|
// This is effectively used to unload manually-loaded certificates.
|
|
|
|
func (certCache *Cache) Remove(hashes []string) {
|
|
|
|
certCache.mu.Lock()
|
|
|
|
for _, h := range hashes {
|
|
|
|
cert := certCache.cache[h]
|
|
|
|
certCache.removeCertificate(cert)
|
|
|
|
}
|
|
|
|
certCache.mu.Unlock()
|
|
|
|
}
|
|
|
|
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
var (
|
|
|
|
defaultCache *Cache
|
|
|
|
defaultCacheMu sync.Mutex
|
|
|
|
)
|