Browse code

vendor docker/go-connections to include the enhacement for decrypting keys

Signed-off-by: Arash Deshmeh <adeshmeh@ca.ibm.com>

Arash Deshmeh authored on 2017/04/06 01:21:40
Showing 2 changed files
... ...
@@ -17,7 +17,7 @@ github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
17 17
 golang.org/x/net c427ad74c6d7a814201695e9ffde0c5d400a7674
18 18
 golang.org/x/sys 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9
19 19
 github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
20
-github.com/docker/go-connections a2afab9802043837035592f1c24827fb70766de9
20
+github.com/docker/go-connections e15c02316c12de00874640cd76311849de2aeed5
21 21
 golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
22 22
 
23 23
 github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
... ...
@@ -8,11 +8,13 @@ package tlsconfig
8 8
 import (
9 9
 	"crypto/tls"
10 10
 	"crypto/x509"
11
+	"encoding/pem"
11 12
 	"fmt"
12 13
 	"io/ioutil"
13 14
 	"os"
14 15
 
15 16
 	"github.com/Sirupsen/logrus"
17
+	"github.com/pkg/errors"
16 18
 )
17 19
 
18 20
 // Options represents the information needed to create client and server TLS configurations.
... ...
@@ -34,6 +36,9 @@ type Options struct {
34 34
 	// the system pool will be used.
35 35
 	ExclusiveRootPools bool
36 36
 	MinVersion         uint16
37
+	// If Passphrase is set, it will be used to decrypt a TLS private key
38
+	// if the key is encrypted
39
+	Passphrase string
37 40
 }
38 41
 
39 42
 // Extra (server-side) accepted CBC cipher suites - will phase out in the future
... ...
@@ -127,6 +132,67 @@ func adjustMinVersion(options Options, config *tls.Config) error {
127 127
 	return nil
128 128
 }
129 129
 
130
+// IsErrEncryptedKey returns true if the 'err' is an error of incorrect
131
+// password when tryin to decrypt a TLS private key
132
+func IsErrEncryptedKey(err error) bool {
133
+	return errors.Cause(err) == x509.IncorrectPasswordError
134
+}
135
+
136
+// getPrivateKey returns the private key in 'keyBytes', in PEM-encoded format.
137
+// If the private key is encrypted, 'passphrase' is used to decrypted the
138
+// private key.
139
+func getPrivateKey(keyBytes []byte, passphrase string) ([]byte, error) {
140
+	// this section makes some small changes to code from notary/tuf/utils/x509.go
141
+	pemBlock, _ := pem.Decode(keyBytes)
142
+	if pemBlock == nil {
143
+		return nil, fmt.Errorf("no valid private key found")
144
+	}
145
+
146
+	var err error
147
+	if x509.IsEncryptedPEMBlock(pemBlock) {
148
+		keyBytes, err = x509.DecryptPEMBlock(pemBlock, []byte(passphrase))
149
+		if err != nil {
150
+			return nil, errors.Wrap(err, "private key is encrypted, but could not decrypt it")
151
+		}
152
+		keyBytes = pem.EncodeToMemory(&pem.Block{Type: pemBlock.Type, Bytes: keyBytes})
153
+	}
154
+
155
+	return keyBytes, nil
156
+}
157
+
158
+// getCert returns a Certificate from the CertFile and KeyFile in 'options',
159
+// if the key is encrypted, the Passphrase in 'options' will be used to
160
+// decrypt it.
161
+func getCert(options Options) ([]tls.Certificate, error) {
162
+	if options.CertFile == "" && options.KeyFile == "" {
163
+		return nil, nil
164
+	}
165
+
166
+	errMessage := "Could not load X509 key pair"
167
+
168
+	cert, err := ioutil.ReadFile(options.CertFile)
169
+	if err != nil {
170
+		return nil, errors.Wrap(err, errMessage)
171
+	}
172
+
173
+	prKeyBytes, err := ioutil.ReadFile(options.KeyFile)
174
+	if err != nil {
175
+		return nil, errors.Wrap(err, errMessage)
176
+	}
177
+
178
+	prKeyBytes, err = getPrivateKey(prKeyBytes, options.Passphrase)
179
+	if err != nil {
180
+		return nil, errors.Wrap(err, errMessage)
181
+	}
182
+
183
+	tlsCert, err := tls.X509KeyPair(cert, prKeyBytes)
184
+	if err != nil {
185
+		return nil, errors.Wrap(err, errMessage)
186
+	}
187
+
188
+	return []tls.Certificate{tlsCert}, nil
189
+}
190
+
130 191
 // Client returns a TLS configuration meant to be used by a client.
131 192
 func Client(options Options) (*tls.Config, error) {
132 193
 	tlsConfig := ClientDefault()
... ...
@@ -139,13 +205,11 @@ func Client(options Options) (*tls.Config, error) {
139 139
 		tlsConfig.RootCAs = CAs
140 140
 	}
141 141
 
142
-	if options.CertFile != "" || options.KeyFile != "" {
143
-		tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile)
144
-		if err != nil {
145
-			return nil, fmt.Errorf("Could not load X509 key pair: %v. Make sure the key is not encrypted", err)
146
-		}
147
-		tlsConfig.Certificates = []tls.Certificate{tlsCert}
142
+	tlsCerts, err := getCert(options)
143
+	if err != nil {
144
+		return nil, err
148 145
 	}
146
+	tlsConfig.Certificates = tlsCerts
149 147
 
150 148
 	if err := adjustMinVersion(options, tlsConfig); err != nil {
151 149
 		return nil, err