certificate.Store: Support client certificates
This commit is contained in:
parent
fcc71b76d9
commit
ada42ff427
@ -6,53 +6,56 @@ import (
|
|||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Store represents a certificate store.
|
// A Store represents a TLS certificate store.
|
||||||
// It generates certificates as needed and automatically rotates expired certificates.
|
|
||||||
// The zero value for Store is an empty store ready to use.
|
// The zero value for Store is an empty store ready to use.
|
||||||
//
|
//
|
||||||
// Certificate scopes must be registered with Register before calling Get or Load.
|
// Store can be used to store server certificates.
|
||||||
// This prevents the Store from creating or loading unnecessary certificates.
|
// Servers should provide a hostname or wildcard pattern as a certificate scope.
|
||||||
|
// Servers will most likely use the methods Register, Load and Get.
|
||||||
|
//
|
||||||
|
// Store can also be used to store client certificates.
|
||||||
|
// Clients should provide the hostname and path of a URL as a certificate scope.
|
||||||
|
// Clients will most likely use the methods Add, Load, and Lookup.
|
||||||
//
|
//
|
||||||
// Store is safe for concurrent use by multiple goroutines.
|
// Store is safe for concurrent use by multiple goroutines.
|
||||||
type Store struct {
|
type Store struct {
|
||||||
// CreateCertificate, if not nil, is called to create a new certificate
|
// CreateCertificate, if not nil, is called by Get to create a new
|
||||||
// to replace a missing or expired certificate. If CreateCertificate
|
// certificate to replace a missing or expired certificate.
|
||||||
// is nil, a certificate with a duration of 1 year will be created.
|
|
||||||
// The provided scope is suitable for use in a certificate's DNSNames.
|
// The provided scope is suitable for use in a certificate's DNSNames.
|
||||||
CreateCertificate func(scope string) (tls.Certificate, error)
|
CreateCertificate func(scope string) (tls.Certificate, error)
|
||||||
|
|
||||||
certs map[string]tls.Certificate
|
scopes map[string]struct{}
|
||||||
path string
|
certs map[string]tls.Certificate
|
||||||
mu sync.RWMutex
|
path string
|
||||||
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register registers the provided scope with the certificate store.
|
// Register registers the provided scope with the certificate store.
|
||||||
// The scope can either be a hostname or a wildcard pattern (e.g. "*.example.com").
|
// The scope can either be a hostname or a wildcard pattern (e.g. "*.example.com").
|
||||||
// To accept all hostnames, use the special pattern "*".
|
// To accept all hostnames, use the special pattern "*".
|
||||||
|
//
|
||||||
|
// Calls to Get will only succeed for registered scopes.
|
||||||
|
// Other methods are not affected.
|
||||||
func (s *Store) Register(scope string) {
|
func (s *Store) Register(scope string) {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
if s.certs == nil {
|
if s.scopes == nil {
|
||||||
s.certs = make(map[string]tls.Certificate)
|
s.scopes = make(map[string]struct{})
|
||||||
}
|
}
|
||||||
s.certs[scope] = tls.Certificate{}
|
s.scopes[scope] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add adds a certificate with the given scope to the certificate store.
|
// Add registers the certificate for the given scope.
|
||||||
// If a certificate for the given scope already exists, Add will overwrite it.
|
// If a certificate already exists for scope, Add will overwrite it.
|
||||||
func (s *Store) Add(scope string, cert tls.Certificate) error {
|
func (s *Store) Add(scope string, cert tls.Certificate) error {
|
||||||
s.mu.Lock()
|
|
||||||
defer s.mu.Unlock()
|
|
||||||
if s.certs == nil {
|
|
||||||
s.certs = make(map[string]tls.Certificate)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse certificate if not already parsed
|
// Parse certificate if not already parsed
|
||||||
if cert.Leaf == nil {
|
if cert.Leaf == nil {
|
||||||
parsed, err := x509.ParseCertificate(cert.Certificate[0])
|
parsed, err := x509.ParseCertificate(cert.Certificate[0])
|
||||||