-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
universal.go
222 lines (185 loc) · 5.88 KB
/
universal.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
// 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
}