github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/providers/security/filesec/file_security.go (about)

     1  // Copyright (c) 2020-2022, R.I. Pienaar and the Choria Project contributors
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  // Package filesec provides a manually configurable security Provider
     6  // it allows you set every parameter like key paths etc manually without
     7  // making any assumptions about your system
     8  //
     9  // It does not support any enrollment
    10  package filesec
    11  
    12  import (
    13  	"bytes"
    14  	"context"
    15  	"crypto"
    16  	"crypto/rand"
    17  	"crypto/rsa"
    18  	"crypto/sha256"
    19  	"crypto/tls"
    20  	"crypto/x509"
    21  	"encoding/pem"
    22  	"errors"
    23  	"fmt"
    24  	"net/http"
    25  	"net/url"
    26  	"os"
    27  	"path/filepath"
    28  	"regexp"
    29  	"strings"
    30  	"sync"
    31  	"time"
    32  
    33  	"github.com/choria-io/go-choria/inter"
    34  	"github.com/choria-io/go-choria/internal/util"
    35  	"github.com/choria-io/go-choria/tlssetup"
    36  
    37  	"github.com/sirupsen/logrus"
    38  )
    39  
    40  // used by tests to stub out uids etc, should probably be a class and use dependency injection, meh
    41  var (
    42  	useFakeUID = false
    43  	fakeUID    = 0
    44  	useFakeOS  = false
    45  	fakeOS     = "fake"
    46  	callerIDRe = regexp.MustCompile(`^[a-z]+=([\w\.\-]+)`)
    47  )
    48  
    49  // FileSecurity implements SecurityProvider using files on disk
    50  type FileSecurity struct {
    51  	conf *Config
    52  	log  *logrus.Entry
    53  
    54  	mu *sync.Mutex
    55  }
    56  
    57  // Config is the configuration for FileSecurity
    58  type Config struct {
    59  	// Identity when not empty will force the identity to be used for validations etc
    60  	Identity string
    61  
    62  	// Certificate is the path to the public certificate
    63  	Certificate string
    64  
    65  	// Key is the path to the private key
    66  	Key string
    67  
    68  	// CA is the path to the Certificate Authority
    69  	CA string
    70  
    71  	// PrivilegedUsers is a list of regular expressions that identity privileged users
    72  	PrivilegedUsers []string
    73  
    74  	// AllowList is a list of regular expressions that identity valid users to allow in
    75  	AllowList []string
    76  
    77  	// DisableTLSVerify disables TLS verify in HTTP clients etc
    78  	DisableTLSVerify bool
    79  
    80  	// Is a URL where a remote signer is running
    81  	RemoteSignerURL string
    82  
    83  	// RemoteSignerTokenFile is a file with a token for access to the remote signer
    84  	RemoteSignerTokenFile string
    85  
    86  	// RemoteSignerSeedFile is a file with a seed related to RemoteSignerTokenFile
    87  	RemoteSignerSeedFile string
    88  
    89  	// TLSSetup is the shared TLS configuration state between security providers
    90  	TLSConfig *tlssetup.Config
    91  
    92  	// BackwardCompatVerification enables custom verification that allows legacy certificates without SANs
    93  	BackwardCompatVerification bool
    94  
    95  	// IdentitySuffix is the suffix to append to usernames when creating certnames and identities
    96  	IdentitySuffix string
    97  
    98  	// RemoteSigner is the signer used to sign requests using a remote like AAA Service
    99  	RemoteSigner inter.RequestSigner
   100  }
   101  
   102  // New creates a new instance of the File Security provider
   103  func New(opts ...Option) (*FileSecurity, error) {
   104  	f := &FileSecurity{
   105  		mu: &sync.Mutex{},
   106  	}
   107  
   108  	for _, opt := range opts {
   109  		err := opt(f)
   110  		if err != nil {
   111  			return nil, err
   112  		}
   113  	}
   114  
   115  	if f.conf == nil {
   116  		return nil, errors.New("configuration not given")
   117  	}
   118  
   119  	if f.log == nil {
   120  		return nil, errors.New("logger not given")
   121  	}
   122  
   123  	if f.conf.Identity == "" {
   124  		return nil, errors.New("identity could not be determine automatically via Choria or was not supplied")
   125  	}
   126  
   127  	if f.conf.BackwardCompatVerification {
   128  		f.log.Infof("Enabling support for legacy SAN free certificates")
   129  	}
   130  
   131  	return f, nil
   132  }
   133  
   134  func (s *FileSecurity) BackingTechnology() inter.SecurityTechnology {
   135  	return inter.SecurityTechnologyX509
   136  }
   137  
   138  // Provider reports the name of the security provider
   139  func (s *FileSecurity) Provider() string {
   140  	return "file"
   141  }
   142  
   143  func (s *FileSecurity) TokenBytes() ([]byte, error) {
   144  	return nil, fmt.Errorf("tokens not available for file security provider")
   145  }
   146  
   147  func (s *FileSecurity) RemoteSignerSeedFile() (string, error) {
   148  	if s.conf.RemoteSignerTokenFile != "" && s.conf.RemoteSignerSeedFile == "" {
   149  		// copies the behavior from framework SignerSeedFile()
   150  		s.conf.RemoteSignerSeedFile = fmt.Sprintf("%s.key", strings.TrimSuffix(s.conf.RemoteSignerTokenFile, filepath.Ext(s.conf.RemoteSignerTokenFile)))
   151  	}
   152  
   153  	if s.conf.RemoteSignerSeedFile == "" {
   154  		return "", fmt.Errorf("no seed file defined")
   155  	}
   156  
   157  	return s.conf.RemoteSignerSeedFile, nil
   158  }
   159  
   160  func (s *FileSecurity) RemoteSignerToken() ([]byte, error) {
   161  	if s.conf.RemoteSignerTokenFile == "" {
   162  		return nil, fmt.Errorf("no token file defined")
   163  	}
   164  
   165  	tb, err := os.ReadFile(s.conf.RemoteSignerTokenFile)
   166  	if err != nil {
   167  		return bytes.TrimSpace(tb), fmt.Errorf("could not read token file: %v", err)
   168  	}
   169  
   170  	return tb, err
   171  }
   172  
   173  func (s *FileSecurity) RemoteSignerURL() (*url.URL, error) {
   174  	if s.conf.RemoteSignerURL == "" {
   175  		return nil, fmt.Errorf("no remote url configured")
   176  	}
   177  
   178  	return url.Parse(s.conf.RemoteSignerURL)
   179  }
   180  
   181  // RemoteSignRequest signs a choria request using a remote signer and returns a secure request
   182  func (s *FileSecurity) RemoteSignRequest(ctx context.Context, request []byte) (signed []byte, err error) {
   183  	if s.conf.RemoteSigner == nil {
   184  		return nil, fmt.Errorf("remote signing not configured")
   185  	}
   186  
   187  	s.log.Infof("Signing request using %s", s.conf.RemoteSigner.Kind())
   188  	return s.conf.RemoteSigner.Sign(ctx, request, s)
   189  }
   190  
   191  // Validate determines if the node represents a valid SSL configuration
   192  func (s *FileSecurity) Validate() ([]string, bool) {
   193  	var errors []string
   194  
   195  	if s.publicCertPath() != "" {
   196  		if !s.publicCertExists() {
   197  			errors = append(errors, fmt.Sprintf("public certificate %s does not exist", s.publicCertPath()))
   198  		}
   199  	} else {
   200  		errors = append(errors, "the public certificate path is not configured")
   201  	}
   202  
   203  	if s.privateKeyPath() != "" {
   204  		if !s.privateKeyExists() {
   205  			errors = append(errors, fmt.Sprintf("private key %s does not exist", s.privateKeyPath()))
   206  		}
   207  	} else {
   208  		errors = append(errors, "the private key path is not configured")
   209  	}
   210  
   211  	if s.caPath() != "" {
   212  		if !s.caExists() {
   213  			errors = append(errors, fmt.Sprintf("CA %s does not exist", s.caPath()))
   214  		}
   215  	} else {
   216  		errors = append(errors, "the CA path is not configured")
   217  	}
   218  
   219  	return errors, len(errors) == 0
   220  }
   221  
   222  // ChecksumBytes calculates a sha256 checksum for data
   223  func (s *FileSecurity) ChecksumBytes(data []byte) []byte {
   224  	sum := sha256.Sum256(data)
   225  
   226  	return sum[:]
   227  }
   228  
   229  // SignBytes signs a message using a SHA256 PKCS1v15 protocol
   230  func (s *FileSecurity) SignBytes(str []byte) ([]byte, error) {
   231  	sig := []byte{}
   232  
   233  	pkpem, err := s.privateKeyPEM()
   234  	if err != nil {
   235  		return sig, err
   236  	}
   237  	var parsedKey any
   238  
   239  	parsedKey, err = x509.ParsePKCS1PrivateKey(pkpem.Bytes)
   240  	if err != nil {
   241  		parsedKey, err = x509.ParsePKCS8PrivateKey(pkpem.Bytes)
   242  		if err != nil {
   243  			err = fmt.Errorf("could not parse private key PEM data: %s", err)
   244  			return sig, err
   245  		}
   246  	}
   247  
   248  	rng := rand.Reader
   249  	hashed := s.ChecksumBytes(str)
   250  
   251  	switch t := parsedKey.(type) {
   252  	case *rsa.PrivateKey:
   253  		sig, err = rsa.SignPKCS1v15(rng, t, crypto.SHA256, hashed[:])
   254  	default:
   255  		return sig, fmt.Errorf("unhandled key type %T", t)
   256  	}
   257  
   258  	if err != nil {
   259  		err = fmt.Errorf("could not sign message: %s", err)
   260  	}
   261  
   262  	return sig, err
   263  }
   264  
   265  // VerifyByteSignature verify that dat matches signature sig made by the key, if pub cert is empty the active public key will be used
   266  func (s *FileSecurity) VerifySignatureBytes(dat []byte, sig []byte, public ...[]byte) (should bool, signer string) {
   267  	if len(public) != 1 {
   268  		s.log.Errorf("Could not process public data: only single signer public data is supported")
   269  		return false, ""
   270  	}
   271  
   272  	pubcert := public[0]
   273  
   274  	var err error
   275  
   276  	if len(pubcert) == 0 {
   277  		pubcert, err = s.PublicCertBytes()
   278  		if err != nil {
   279  			s.log.Errorf("Could not load public cert: %v", err)
   280  			return false, ""
   281  		}
   282  	}
   283  
   284  	pkpem, _ := pem.Decode(pubcert)
   285  	if pkpem == nil {
   286  		s.log.Errorf("Could not decode PEM data in public key: invalid pem data")
   287  		return false, ""
   288  	}
   289  
   290  	cert, err := x509.ParseCertificate(pkpem.Bytes)
   291  	if err != nil {
   292  		s.log.Errorf("Could not parse decoded PEM data for public certificate: %s", err)
   293  		return false, ""
   294  	}
   295  
   296  	rsaPublicKey := cert.PublicKey.(*rsa.PublicKey)
   297  	hashed := s.ChecksumBytes(dat)
   298  
   299  	err = rsa.VerifyPKCS1v15(rsaPublicKey, crypto.SHA256, hashed[:], sig)
   300  	if err != nil {
   301  		s.log.Errorf("Signature verification failed: %s", err)
   302  		return false, ""
   303  	}
   304  
   305  	names := []string{cert.Subject.CommonName}
   306  	names = append(names, cert.DNSNames...)
   307  
   308  	if len(names) == 0 {
   309  		s.log.Errorf("Signature verification failed: no names found in signer certificate")
   310  		return false, ""
   311  	}
   312  
   313  	s.log.Debugf("Verified signature from %s", strings.Join(names, ", "))
   314  
   315  	return true, names[0]
   316  }
   317  
   318  // CallerName creates a choria like caller name in the form of choria=identity
   319  func (s *FileSecurity) CallerName() string {
   320  	return fmt.Sprintf("choria=%s", s.Identity())
   321  }
   322  
   323  // CallerIdentity extracts the identity from a choria like caller name in the form of choria=identity
   324  func (s *FileSecurity) CallerIdentity(caller string) (string, error) {
   325  	match := callerIDRe.FindStringSubmatch(caller)
   326  
   327  	if match == nil {
   328  		return "", fmt.Errorf("could not find a valid caller identity name in %s", caller)
   329  	}
   330  
   331  	return match[1], nil
   332  }
   333  
   334  // IsRemoteSigning determines if remote signer is set
   335  func (s *FileSecurity) IsRemoteSigning() bool {
   336  	return s.conf.RemoteSigner != nil
   337  }
   338  
   339  // Identity determines the choria certname
   340  func (s *FileSecurity) Identity() string {
   341  	return s.conf.Identity
   342  }
   343  
   344  // VerifyCertificate verifies a certificate is signed with the configured CA and if
   345  // name is not "" that it matches the name given
   346  func (s *FileSecurity) VerifyCertificate(certpem []byte, name string) error {
   347  	ca := s.caPath()
   348  	capem, err := os.ReadFile(ca)
   349  	if err != nil {
   350  		s.log.Errorf("Could not read CA '%s': %s", ca, err)
   351  		return err
   352  	}
   353  
   354  	roots := x509.NewCertPool()
   355  	if !roots.AppendCertsFromPEM(capem) {
   356  		s.log.Warnf("Could not use CA '%s' as PEM data: %s", ca, err)
   357  		return err
   358  	}
   359  
   360  	block, _ := pem.Decode(certpem)
   361  	if block == nil {
   362  		s.log.Warnf("Could not decode certificate '%s' PEM data: %s", name, err)
   363  		return err
   364  	}
   365  
   366  	cert, err := x509.ParseCertificate(block.Bytes)
   367  	if err != nil {
   368  		s.log.Warnf("Could not parse certificate '%s': %s", name, err)
   369  		return err
   370  	}
   371  
   372  	intermediates := x509.NewCertPool()
   373  	if !intermediates.AppendCertsFromPEM(certpem) {
   374  		s.log.Warnf("Could not add intermediates: %s", err)
   375  		return err
   376  	}
   377  
   378  	opts := x509.VerifyOptions{
   379  		Roots:         roots,
   380  		Intermediates: intermediates,
   381  		KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
   382  	}
   383  
   384  	_, err = cert.Verify(opts)
   385  	if err != nil {
   386  		s.log.Warnf("Certificate does not pass verification as '%s': %s", name, err)
   387  		return err
   388  	}
   389  
   390  	if len(cert.EmailAddresses) > 0 && strings.HasPrefix(name, "email:") {
   391  		s.log.Debug("Email addresses found in certificate, attempting verification")
   392  		for _, email := range cert.EmailAddresses {
   393  			if strings.TrimPrefix(name, "email:") == email {
   394  				return nil
   395  			}
   396  		}
   397  
   398  		return fmt.Errorf("email address not found in SAN: %s, %v", name, cert.EmailAddresses)
   399  	}
   400  
   401  	// ShouldAllowCaller passes in an empty name, we just want it to verify validity of the CA chain at this point
   402  	if name == "" {
   403  		return nil
   404  	}
   405  
   406  	if !findName(cert.DNSNames, name) {
   407  		if cert.Subject.CommonName != name {
   408  			return fmt.Errorf("x509: certificate is valid for %s, not %s", cert.Subject.CommonName, name)
   409  		}
   410  	}
   411  
   412  	return nil
   413  }
   414  
   415  func findName(names []string, name string) bool {
   416  	for _, n := range names {
   417  		if n == name {
   418  			return true
   419  		}
   420  	}
   421  	return false
   422  }
   423  
   424  // HTTPClient creates a standard HTTP client with optional security, it will
   425  // be set to use the CA and client certs for auth. servername should match the
   426  // remote hosts name for SNI
   427  func (s *FileSecurity) HTTPClient(secure bool) (*http.Client, error) {
   428  	client := &http.Client{}
   429  
   430  	if secure {
   431  		tlsc, err := s.TLSConfig()
   432  		if err != nil {
   433  			return nil, fmt.Errorf("could not set up HTTP connection: %s", err)
   434  		}
   435  
   436  		client.Transport = &http.Transport{TLSClientConfig: tlsc}
   437  	}
   438  
   439  	return client, nil
   440  }
   441  
   442  func (s *FileSecurity) ClientTLSConfig() (*tls.Config, error) {
   443  	tlsc, err := s.TLSConfig()
   444  	if err != nil {
   445  		return nil, err
   446  	}
   447  
   448  	if s.conf.BackwardCompatVerification {
   449  		tlsc.InsecureSkipVerify = true
   450  		tlsc.VerifyConnection = s.constructCustomVerifier(tlsc.RootCAs)
   451  	}
   452  
   453  	return tlsc, nil
   454  }
   455  
   456  // TLSConfig creates a TLS configuration for use by NATS, HTTPS etc
   457  func (s *FileSecurity) TLSConfig() (*tls.Config, error) {
   458  	pub := s.publicCertPath()
   459  	pri := s.privateKeyPath()
   460  	ca := s.caPath()
   461  
   462  	tlsc := &tls.Config{
   463  		MinVersion:               tls.VersionTLS12,
   464  		PreferServerCipherSuites: true,
   465  		CipherSuites:             s.conf.TLSConfig.CipherSuites,
   466  		CurvePreferences:         s.conf.TLSConfig.CurvePreferences,
   467  	}
   468  
   469  	if s.privateKeyExists() && s.publicCertExists() {
   470  		cert, err := tls.LoadX509KeyPair(pub, pri)
   471  		if err != nil {
   472  			err = fmt.Errorf("could not load certificate %s and key %s: %s", pub, pri, err)
   473  			return nil, err
   474  		}
   475  
   476  		cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
   477  		if err != nil {
   478  			err = fmt.Errorf("error parsing certificate: %v", err)
   479  			return nil, err
   480  		}
   481  
   482  		tlsc.Certificates = []tls.Certificate{cert}
   483  	}
   484  
   485  	if s.caExists() {
   486  		caCert, err := os.ReadFile(ca)
   487  		if err != nil {
   488  			return nil, err
   489  		}
   490  
   491  		caCertPool := x509.NewCertPool()
   492  		caCertPool.AppendCertsFromPEM(caCert)
   493  
   494  		tlsc.ClientCAs = caCertPool
   495  		tlsc.RootCAs = caCertPool
   496  	}
   497  
   498  	if s.conf.DisableTLSVerify {
   499  		tlsc.InsecureSkipVerify = true
   500  	}
   501  
   502  	return tlsc, nil
   503  }
   504  
   505  func (s *FileSecurity) constructCustomVerifier(pool *x509.CertPool) func(cs tls.ConnectionState) error {
   506  	return func(cs tls.ConnectionState) error {
   507  		s.log.Debug("Verifying connection using legacy SAN free certificate support")
   508  		opts := x509.VerifyOptions{
   509  			Roots:         pool,
   510  			Intermediates: x509.NewCertPool(),
   511  		}
   512  		// If there is no SAN, then fallback to using the CommonName
   513  		hasSanExtension := func(cert *x509.Certificate) bool {
   514  			// oid taken from crypt/x509/x509.go
   515  			var oidExtensionSubjectAltName = []int{2, 5, 29, 17}
   516  			for _, e := range cert.Extensions {
   517  				if e.Id.Equal(oidExtensionSubjectAltName) {
   518  					return true
   519  				}
   520  			}
   521  			return false
   522  		}
   523  		if !hasSanExtension(cs.PeerCertificates[0]) {
   524  			if !strings.EqualFold(cs.ServerName, cs.PeerCertificates[0].Subject.CommonName) {
   525  				return x509.HostnameError{Certificate: cs.PeerCertificates[0], Host: cs.ServerName}
   526  			}
   527  		} else {
   528  			opts.DNSName = cs.ServerName
   529  		}
   530  		for _, cert := range cs.PeerCertificates[1:] {
   531  			opts.Intermediates.AddCert(cert)
   532  		}
   533  		_, err := cs.PeerCertificates[0].Verify(opts)
   534  		return err
   535  	}
   536  }
   537  
   538  // publicCertPem retrieves the public certificate for this instance
   539  func (s *FileSecurity) publicCertPem() (*pem.Block, error) {
   540  	path := s.publicCertPath()
   541  
   542  	return s.decodePEM(path)
   543  }
   544  
   545  // PublicCertBytes retrieves pem data in textual form for the public certificate of the current identity
   546  func (s *FileSecurity) PublicCertBytes() ([]byte, error) {
   547  	path := s.publicCertPath()
   548  
   549  	return os.ReadFile(path)
   550  }
   551  
   552  // PublicCert is the parsed public certificate
   553  func (s *FileSecurity) PublicCert() (*x509.Certificate, error) {
   554  	block, err := s.publicCertPem()
   555  	if err != nil {
   556  		return nil, err
   557  	}
   558  
   559  	cert, err := x509.ParseCertificate(block.Bytes)
   560  	if err != nil {
   561  		return nil, err
   562  	}
   563  
   564  	return cert, nil
   565  }
   566  
   567  // SSLContext creates a SSL context loaded with our certs and ca
   568  func (s *FileSecurity) SSLContext() (*http.Transport, error) {
   569  	tlsConfig, err := s.ClientTLSConfig()
   570  	if err != nil {
   571  		return nil, err
   572  	}
   573  
   574  	transport := &http.Transport{TLSClientConfig: tlsConfig}
   575  
   576  	return transport, nil
   577  }
   578  
   579  // Enroll is not supported
   580  func (s *FileSecurity) Enroll(ctx context.Context, wait time.Duration, cb func(digest string, try int)) error {
   581  	return errors.New("the file security provider does not support enrollment")
   582  }
   583  
   584  func (s *FileSecurity) decodePEM(certpath string) (*pem.Block, error) {
   585  	var err error
   586  
   587  	if certpath == "" {
   588  		return nil, errors.New("invalid certpath '' provided")
   589  	}
   590  
   591  	keydat, err := os.ReadFile(certpath)
   592  	if err != nil {
   593  		return nil, fmt.Errorf("could not read PEM data from %s: %s", certpath, err)
   594  	}
   595  
   596  	pb, _ := pem.Decode(keydat)
   597  	if pb == nil {
   598  		return nil, fmt.Errorf("failed to parse PEM data from key %s", certpath)
   599  	}
   600  
   601  	return pb, nil
   602  }
   603  
   604  func (s *FileSecurity) privateKeyPath() string {
   605  	return filepath.FromSlash(s.conf.Key)
   606  }
   607  
   608  func (s *FileSecurity) publicCertPath() string {
   609  	return filepath.FromSlash(s.conf.Certificate)
   610  }
   611  
   612  func (s *FileSecurity) caPath() string {
   613  	return filepath.FromSlash(s.conf.CA)
   614  }
   615  
   616  func (s *FileSecurity) privateKeyExists() bool {
   617  	return util.FileExist(s.privateKeyPath())
   618  }
   619  
   620  func (s *FileSecurity) publicCertExists() bool {
   621  	return util.FileExist(s.publicCertPath())
   622  }
   623  
   624  func (s *FileSecurity) caExists() bool {
   625  	return util.FileExist(s.caPath())
   626  }
   627  
   628  func (s *FileSecurity) privateKeyPEM() (pb *pem.Block, err error) {
   629  	key := s.privateKeyPath()
   630  
   631  	keydat, err := os.ReadFile(key)
   632  	if err != nil {
   633  		return pb, fmt.Errorf("could not read Private Key %s: %s", key, err)
   634  	}
   635  
   636  	pb, _ = pem.Decode(keydat)
   637  	if pb == nil {
   638  		return pb, fmt.Errorf("failed to parse PEM data from key %s", key)
   639  	}
   640  
   641  	return
   642  }
   643  
   644  func (s *FileSecurity) ShouldAllowCaller(name string, callers ...[]byte) (privileged bool, err error) {
   645  	if len(callers) != 1 {
   646  		s.log.Warnf("Received multiple items of caller identity data in x509 security provider")
   647  		return false, fmt.Errorf("invalid public data")
   648  	}
   649  
   650  	data := callers[0]
   651  
   652  	privNames, err := s.certDNSNames(data)
   653  	if err != nil {
   654  		s.log.Warnf("Could not extract DNS Names from certificate")
   655  		return false, err
   656  	}
   657  
   658  	for _, privName := range privNames {
   659  		if MatchAnyRegex(privName, s.conf.PrivilegedUsers) {
   660  			privileged = true
   661  			break
   662  		}
   663  	}
   664  
   665  	if privileged {
   666  		// Checks if it was signed by a CA issued cert but without any name validation since privileged name wouldnt match
   667  		err = s.VerifyCertificate(data, "")
   668  		if err != nil {
   669  			s.log.Warnf("Received certificate '%s' certificate did not pass verification: %s", name, err)
   670  			return false, err
   671  		}
   672  
   673  		return true, nil
   674  	} else {
   675  		// Checks if it was signed by a CA issued cert that matches name since it must match when not privileged
   676  		err = s.VerifyCertificate(data, name)
   677  		if err != nil {
   678  			s.log.Warnf("Received certificate '%s' did not pass verification: %s", name, err)
   679  			return false, err
   680  		}
   681  	}
   682  
   683  	// Finally if its on the allow list
   684  	if MatchAnyRegex(name, s.conf.AllowList) {
   685  		return false, nil
   686  	}
   687  
   688  	s.log.Warnf("Received certificate '%s' does not match the allowed list '%s'", name, s.conf.AllowList)
   689  
   690  	return false, fmt.Errorf("not on allow list")
   691  }
   692  
   693  func (s *FileSecurity) certDNSNames(certpem []byte) (names []string, err error) {
   694  	block, _ := pem.Decode(certpem)
   695  	if block == nil {
   696  		s.log.Warnf("Could not decode certificate PEM data: %s", err)
   697  		return names, err
   698  	}
   699  
   700  	cert, err := x509.ParseCertificate(block.Bytes)
   701  	if err != nil {
   702  		s.log.Warnf("Could not parse certificate: %s", err)
   703  		return names, err
   704  	}
   705  
   706  	names = append(names, cert.Subject.CommonName)
   707  	names = append(names, cert.DNSNames...)
   708  
   709  	return names, nil
   710  }
   711  
   712  func (s *FileSecurity) ShouldSignReplies() bool { return false }