kubernetes/vendor/github.com/cloudflare/cfssl/signer/universal/universal.go
2018-08-08 21:22:01 -07:00

223 lines
5.9 KiB
Go

// Package universal implements a signer that can do remote or local
package universal
import (
"crypto/x509"
"net/http"
"github.com/cloudflare/cfssl/certdb"
"github.com/cloudflare/cfssl/config"
cferr "github.com/cloudflare/cfssl/errors"
"github.com/cloudflare/cfssl/info"
"github.com/cloudflare/cfssl/signer"
"github.com/cloudflare/cfssl/signer/local"
"github.com/cloudflare/cfssl/signer/remote"
)
// Signer represents a universal signer which is both local and remote
// to fulfill the signer.Signer interface.
type Signer struct {
local signer.Signer
remote signer.Signer
policy *config.Signing
}
// Root is used to define where the universal signer gets its public
// certificate and private keys for signing.
type Root struct {
Config map[string]string
ForceRemote bool
}
// a localSignerCheck looks at the Config keys in the Root, and
// decides whether it has enough information to produce a signer.
type localSignerCheck func(root *Root, policy *config.Signing) (signer.Signer, bool, error)
// fileBackedSigner determines whether a file-backed local signer is supported.
func fileBackedSigner(root *Root, policy *config.Signing) (signer.Signer, bool, error) {
keyFile := root.Config["key-file"]
certFile := root.Config["cert-file"]
if keyFile == "" {
return nil, false, nil
}
signer, err := local.NewSignerFromFile(certFile, keyFile, policy)
return signer, true, err
}
var localSignerList = []localSignerCheck{
fileBackedSigner,
}
// PrependLocalSignerToList prepends signer to the local signer's list
func PrependLocalSignerToList(signer localSignerCheck) {
localSignerList = append([]localSignerCheck{signer}, localSignerList...)
}
func newLocalSigner(root Root, policy *config.Signing) (s signer.Signer, err error) {
// shouldProvide indicates whether the
// function *should* have produced a key. If
// it's true, we should use the signer and
// error returned. Otherwise, keep looking for
// signers.
var shouldProvide bool
// localSignerList is a list of signers defined
// here or in the universal_signers*.go files.
// These activate and deactivate signers based
// on build flags.
for _, possibleSigner := range localSignerList {
s, shouldProvide, err = possibleSigner(&root, policy)
if shouldProvide {
break
}
}
if s == nil {
err = cferr.New(cferr.PrivateKeyError, cferr.Unknown)
}
return s, err
}
func newUniversalSigner(root Root, policy *config.Signing) (*Signer, error) {
ls, err := newLocalSigner(root, policy)
if err != nil {
return nil, err
}
rs, err := remote.NewSigner(policy)
if err != nil {
return nil, err
}
s := &Signer{
policy: policy,
local: ls,
remote: rs,
}
return s, err
}
// NewSigner generates a new certificate signer from a Root structure.
// This is one of two standard signers: local or remote. If the root
// structure specifies a force remote, then a remote signer is created,
// otherwise either a remote or local signer is generated based on the
// policy. For a local signer, the CertFile and KeyFile need to be
// defined in Root.
func NewSigner(root Root, policy *config.Signing) (signer.Signer, error) {
if policy == nil {
policy = &config.Signing{
Profiles: map[string]*config.SigningProfile{},
Default: config.DefaultConfig(),
}
}
if !policy.Valid() {
return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
}
var s signer.Signer
var err error
if root.ForceRemote {
s, err = remote.NewSigner(policy)
} else {
if policy.NeedsLocalSigner() && policy.NeedsRemoteSigner() {
s, err = newUniversalSigner(root, policy)
} else {
if policy.NeedsLocalSigner() {
s, err = newLocalSigner(root, policy)
}
if policy.NeedsRemoteSigner() {
s, err = remote.NewSigner(policy)
}
}
}
return s, err
}
// getMatchingProfile returns the SigningProfile that matches the profile passed.
// if an empty profile string is passed it returns the default profile.
func (s *Signer) getMatchingProfile(profile string) (*config.SigningProfile, error) {
if profile == "" {
return s.policy.Default, nil
}
for p, signingProfile := range s.policy.Profiles {
if p == profile {
return signingProfile, nil
}
}
return nil, cferr.New(cferr.PolicyError, cferr.UnknownProfile)
}
// Sign sends a signature request to either the remote or local signer,
// receiving a signed certificate or an error in response.
func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
profile, err := s.getMatchingProfile(req.Profile)
if err != nil {
return cert, err
}
if profile.RemoteServer != "" {
return s.remote.Sign(req)
}
return s.local.Sign(req)
}
// Info sends an info request to the remote or local CFSSL server
// receiving an Resp struct or an error in response.
func (s *Signer) Info(req info.Req) (resp *info.Resp, err error) {
profile, err := s.getMatchingProfile(req.Profile)
if err != nil {
return resp, err
}
if profile.RemoteServer != "" {
return s.remote.Info(req)
}
return s.local.Info(req)
}
// SetDBAccessor sets the signer's cert db accessor.
func (s *Signer) SetDBAccessor(dba certdb.Accessor) {
s.local.SetDBAccessor(dba)
}
// GetDBAccessor returns the signer's cert db accessor.
func (s *Signer) GetDBAccessor() certdb.Accessor {
return s.local.GetDBAccessor()
}
// SetReqModifier sets the function to call to modify the HTTP request prior to sending it
func (s *Signer) SetReqModifier(mod func(*http.Request, []byte)) {
s.local.SetReqModifier(mod)
s.remote.SetReqModifier(mod)
}
// SigAlgo returns the RSA signer's signature algorithm.
func (s *Signer) SigAlgo() x509.SignatureAlgorithm {
if s.local != nil {
return s.local.SigAlgo()
}
// currently remote.SigAlgo just returns
// x509.UnknownSignatureAlgorithm.
return s.remote.SigAlgo()
}
// SetPolicy sets the signer's signature policy.
func (s *Signer) SetPolicy(policy *config.Signing) {
s.policy = policy
}
// Policy returns the signer's policy.
func (s *Signer) Policy() *config.Signing {
return s.policy
}