certificate.Store: Support client certificates

This commit is contained in:
Adnan Maolood 2021-02-28 18:56:22 -05:00
parent fcc71b76d9
commit ada42ff427

View File

@ -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])