@@ -16,15 +16,47 @@ import (
1616 "github.com/pkg/errors"
1717)
1818
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 PENSource 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+
1951// Options represents the information needed to create client and server TLS configurations.
2052type Options struct {
21- CAFile string
53+ CA PEMSource
2254
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
2456 // preventing the client from authenticating to the server.
2557 // However, Server() requires them and will error out if they are empty.
26- CertFile string
27- KeyFile string
58+ Cert PEMSource
59+ Key PEMSource
2860
2961 // client-only option
3062 InsecureSkipVerify bool
@@ -94,7 +126,10 @@ func ClientDefault(ops ...func(*tls.Config)) *tls.Config {
94126}
95127
96128// 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+ }
98133 // If we should verify the server, we need to load a trusted ca
99134 var (
100135 certPool * x509.CertPool
@@ -108,12 +143,12 @@ func certPool(caFile string, exclusivePool bool) (*x509.CertPool, error) {
108143 return nil , fmt .Errorf ("failed to read system certificates: %v" , err )
109144 }
110145 }
111- pem , err := ioutil . ReadFile ( caFile )
146+ pem , err := ca . Data ( )
112147 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 )
114149 }
115150 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 () )
117152 }
118153 return certPool , nil
119154}
@@ -172,18 +207,24 @@ func getPrivateKey(keyBytes []byte, passphrase string) ([]byte, error) {
172207// if the key is encrypted, the Passphrase in 'options' will be used to
173208// decrypt it.
174209func getCert (options Options ) ([]tls.Certificate , error ) {
175- if options .CertFile == "" && options .KeyFile == "" {
210+ if options .Cert == nil && options .Key == nil {
176211 return nil , nil
177212 }
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+ }
178219
179220 errMessage := "Could not load X509 key pair"
180221
181- cert , err := ioutil . ReadFile ( options .CertFile )
222+ cert , err := options .Cert . Data ( )
182223 if err != nil {
183224 return nil , errors .Wrap (err , errMessage )
184225 }
185226
186- prKeyBytes , err := ioutil . ReadFile ( options .KeyFile )
227+ prKeyBytes , err := options .Key . Data ( )
187228 if err != nil {
188229 return nil , errors .Wrap (err , errMessage )
189230 }
@@ -205,8 +246,8 @@ func getCert(options Options) ([]tls.Certificate, error) {
205246func Client (options Options ) (* tls.Config , error ) {
206247 tlsConfig := ClientDefault ()
207248 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 )
210251 if err != nil {
211252 return nil , err
212253 }
@@ -230,16 +271,33 @@ func Client(options Options) (*tls.Config, error) {
230271func Server (options Options ) (* tls.Config , error ) {
231272 tlsConfig := ServerDefault ()
232273 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 ()
234281 if err != nil {
235282 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 )
237284 }
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 )
239297 }
240298 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 )
243301 if err != nil {
244302 return nil , err
245303 }
0 commit comments