@@ -16,15 +16,47 @@ import (
16
16
"github.com/pkg/errors"
17
17
)
18
18
19
+ // PEMSource represents a provider of some PEM Block
20
+ type PEMSource interface {
21
+ Data () ([]byte , error )
22
+ Name () string
23
+ }
24
+
25
+ // PEMFile is a PEMSource backed by a file
26
+ type PEMFile string
27
+
28
+ // Data returns PEM data from the file
29
+ func (f PEMFile ) Data () ([]byte , error ) {
30
+ return ioutil .ReadFile (string (f ))
31
+ }
32
+
33
+ // Name returns the name of the file
34
+ func (f PEMFile ) Name () string {
35
+ return string (f )
36
+ }
37
+
38
+ // PEMInMemory is a PEMSource from memory
39
+ type PEMInMemory []byte
40
+
41
+ // Data returns PEM data from memory
42
+ func (m PEMInMemory ) Data () ([]byte , error ) {
43
+ return []byte (m ), nil
44
+ }
45
+
46
+ // Name returns <in memory>
47
+ func (m PEMInMemory ) Name () string {
48
+ return "<in memory>"
49
+ }
50
+
19
51
// Options represents the information needed to create client and server TLS configurations.
20
52
type Options struct {
21
- CAFile string
53
+ CA PEMSource
22
54
23
- // If either CertFile or KeyFile is empty , Client() will not load them
55
+ // If either Cert or Key is nil , Client() will not load them
24
56
// preventing the client from authenticating to the server.
25
57
// However, Server() requires them and will error out if they are empty.
26
- CertFile string
27
- KeyFile string
58
+ Cert PEMSource
59
+ Key PEMSource
28
60
29
61
// client-only option
30
62
InsecureSkipVerify bool
@@ -94,7 +126,10 @@ func ClientDefault(ops ...func(*tls.Config)) *tls.Config {
94
126
}
95
127
96
128
// certPool returns an X.509 certificate pool from `caFile`, the certificate file.
97
- func certPool (caFile string , exclusivePool bool ) (* x509.CertPool , error ) {
129
+ func certPool (ca PEMSource , exclusivePool bool ) (* x509.CertPool , error ) {
130
+ if ca == nil {
131
+ return nil , fmt .Errorf ("no CA PEM data" )
132
+ }
98
133
// If we should verify the server, we need to load a trusted ca
99
134
var (
100
135
certPool * x509.CertPool
@@ -108,12 +143,12 @@ func certPool(caFile string, exclusivePool bool) (*x509.CertPool, error) {
108
143
return nil , fmt .Errorf ("failed to read system certificates: %v" , err )
109
144
}
110
145
}
111
- pem , err := ioutil . ReadFile ( caFile )
146
+ pem , err := ca . Data ( )
112
147
if err != nil {
113
- return nil , fmt .Errorf ("could not read CA certificate %q: %v" , caFile , err )
148
+ return nil , fmt .Errorf ("could not read CA certificate %q: %v" , ca . Name () , err )
114
149
}
115
150
if ! certPool .AppendCertsFromPEM (pem ) {
116
- return nil , fmt .Errorf ("failed to append certificates from PEM file: %q" , caFile )
151
+ return nil , fmt .Errorf ("failed to append certificates from PEM file: %q" , ca . Name () )
117
152
}
118
153
return certPool , nil
119
154
}
@@ -172,18 +207,24 @@ func getPrivateKey(keyBytes []byte, passphrase string) ([]byte, error) {
172
207
// if the key is encrypted, the Passphrase in 'options' will be used to
173
208
// decrypt it.
174
209
func getCert (options Options ) ([]tls.Certificate , error ) {
175
- if options .CertFile == "" && options .KeyFile == "" {
210
+ if options .Cert == nil && options .Key == nil {
176
211
return nil , nil
177
212
}
213
+ if options .Cert == nil {
214
+ return nil , errors .New ("cert is missing" )
215
+ }
216
+ if options .Key == nil {
217
+ return nil , errors .New ("key is missing" )
218
+ }
178
219
179
220
errMessage := "Could not load X509 key pair"
180
221
181
- cert , err := ioutil . ReadFile ( options .CertFile )
222
+ cert , err := options .Cert . Data ( )
182
223
if err != nil {
183
224
return nil , errors .Wrap (err , errMessage )
184
225
}
185
226
186
- prKeyBytes , err := ioutil . ReadFile ( options .KeyFile )
227
+ prKeyBytes , err := options .Key . Data ( )
187
228
if err != nil {
188
229
return nil , errors .Wrap (err , errMessage )
189
230
}
@@ -205,8 +246,8 @@ func getCert(options Options) ([]tls.Certificate, error) {
205
246
func Client (options Options ) (* tls.Config , error ) {
206
247
tlsConfig := ClientDefault ()
207
248
tlsConfig .InsecureSkipVerify = options .InsecureSkipVerify
208
- if ! options .InsecureSkipVerify && options .CAFile != "" {
209
- CAs , err := certPool (options .CAFile , options .ExclusiveRootPools )
249
+ if ! options .InsecureSkipVerify && options .CA != nil {
250
+ CAs , err := certPool (options .CA , options .ExclusiveRootPools )
210
251
if err != nil {
211
252
return nil , err
212
253
}
@@ -230,16 +271,33 @@ func Client(options Options) (*tls.Config, error) {
230
271
func Server (options Options ) (* tls.Config , error ) {
231
272
tlsConfig := ServerDefault ()
232
273
tlsConfig .ClientAuth = options .ClientAuth
233
- tlsCert , err := tls .LoadX509KeyPair (options .CertFile , options .KeyFile )
274
+ if options .Cert == nil {
275
+ return nil , errors .New ("cert is missing" )
276
+ }
277
+ if options .Key == nil {
278
+ return nil , errors .New ("key is missing" )
279
+ }
280
+ cert , err := options .Cert .Data ()
234
281
if err != nil {
235
282
if os .IsNotExist (err ) {
236
- return nil , fmt .Errorf ("Could not load X509 key pair (cert: %q, key: %q): %v" , options .CertFile , options .KeyFile , err )
283
+ return nil , fmt .Errorf ("Could not load X509 key pair (cert: %q, key: %q): %v" , options .Cert . Name () , options .Key . Name () , err )
237
284
}
238
- return nil , fmt .Errorf ("Error reading X509 key pair (cert: %q, key: %q): %v. Make sure the key is not encrypted." , options .CertFile , options .KeyFile , err )
285
+ return nil , fmt .Errorf ("could not read cert data: %s" , err )
286
+ }
287
+ key , err := options .Key .Data ()
288
+ if err != nil {
289
+ if os .IsNotExist (err ) {
290
+ return nil , fmt .Errorf ("Could not load X509 key pair (cert: %q, key: %q): %v" , options .Cert .Name (), options .Key .Name (), err )
291
+ }
292
+ return nil , fmt .Errorf ("could not read key data: %s" , err )
293
+ }
294
+ tlsCert , err := tls .X509KeyPair (cert , key )
295
+ if err != nil {
296
+ return nil , fmt .Errorf ("Error reading X509 key pair (cert: %q, key: %q): %v. Make sure the key is not encrypted." , options .Cert .Name (), options .Key .Name (), err )
239
297
}
240
298
tlsConfig .Certificates = []tls.Certificate {tlsCert }
241
- if options .ClientAuth >= tls .VerifyClientCertIfGiven && options .CAFile != "" {
242
- CAs , err := certPool (options .CAFile , options .ExclusiveRootPools )
299
+ if options .ClientAuth >= tls .VerifyClientCertIfGiven && options .CA != nil {
300
+ CAs , err := certPool (options .CA , options .ExclusiveRootPools )
243
301
if err != nil {
244
302
return nil , err
245
303
}
0 commit comments