Skip to content

Commit ec287d9

Browse files
committed
Remove support for encrypted TLS private keys
> Legacy PEM encryption as specified in RFC 1423 is insecure by design. Since > it does not authenticate the ciphertext, it is vulnerable to padding oracle > attacks that can let an attacker recover the plaintext From https://go-review.googlesource.com/c/go/+/264159 > It's unfortunate that we don't implement PKCS#8 encryption so we can't > recommend an alternative but PEM encryption is so broken that it's worth > deprecating outright. This feature allowed using an encrypted private key with a supplied password, but did not provide additional security as the encryption is known to be broken, and the key is sitting next to the password in the filesystem. Users are recommended to decrypt the private key, and store it un-encrypted to continue using it. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent ca61e7b commit ec287d9

File tree

2 files changed

+14
-56
lines changed

2 files changed

+14
-56
lines changed

tlsconfig/config.go

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,6 @@ type Options struct {
3434
// the system pool will be used.
3535
ExclusiveRootPools bool
3636
MinVersion uint16
37-
// If Passphrase is set, it will be used to decrypt a TLS private key
38-
// if the key is encrypted.
39-
//
40-
// Deprecated: Use of encrypted TLS private keys has been deprecated, and
41-
// will be removed in a future release. Golang has deprecated support for
42-
// legacy PEM encryption (as specified in RFC 1423), as it is insecure by
43-
// design (see https://go-review.googlesource.com/c/go/+/264159).
44-
Passphrase string
4537
}
4638

4739
// Extra (server-side) accepted CBC cipher suites - will phase out in the future
@@ -144,34 +136,20 @@ func adjustMinVersion(options Options, config *tls.Config) error {
144136
return nil
145137
}
146138

147-
// IsErrEncryptedKey returns true if the 'err' is an error of incorrect
148-
// password when trying to decrypt a TLS private key.
149-
//
150-
// Deprecated: Use of encrypted TLS private keys has been deprecated, and
151-
// will be removed in a future release. Golang has deprecated support for
152-
// legacy PEM encryption (as specified in RFC 1423), as it is insecure by
153-
// design (see https://go-review.googlesource.com/c/go/+/264159).
154-
func IsErrEncryptedKey(err error) bool {
155-
return errors.Is(err, x509.IncorrectPasswordError)
156-
}
139+
var errEncryptedKeyDeprecated = errors.New("private key is encrypted; support for encrypted private keys has been deprecated, see https://docs.docker.com/go/deprecated/")
157140

158141
// getPrivateKey returns the private key in 'keyBytes', in PEM-encoded format.
159-
// If the private key is encrypted, 'passphrase' is used to decrypted the
160-
// private key.
161-
func getPrivateKey(keyBytes []byte, passphrase string) ([]byte, error) {
142+
// It returns an error if the file could not be decoded or was protected by
143+
// a passphrase.
144+
func getPrivateKey(keyBytes []byte) ([]byte, error) {
162145
// this section makes some small changes to code from notary/tuf/utils/x509.go
163146
pemBlock, _ := pem.Decode(keyBytes)
164147
if pemBlock == nil {
165148
return nil, fmt.Errorf("no valid private key found")
166149
}
167150

168-
var err error
169151
if x509.IsEncryptedPEMBlock(pemBlock) { //nolint:staticcheck // Ignore SA1019 (IsEncryptedPEMBlock is deprecated)
170-
keyBytes, err = x509.DecryptPEMBlock(pemBlock, []byte(passphrase)) //nolint:staticcheck // Ignore SA1019 (DecryptPEMBlock is deprecated)
171-
if err != nil {
172-
return nil, fmt.Errorf("private key is encrypted, but could not decrypt it: %w", err)
173-
}
174-
keyBytes = pem.EncodeToMemory(&pem.Block{Type: pemBlock.Type, Bytes: keyBytes})
152+
return nil, errEncryptedKeyDeprecated
175153
}
176154

177155
return keyBytes, nil
@@ -195,7 +173,7 @@ func getCert(options Options) ([]tls.Certificate, error) {
195173
return nil, err
196174
}
197175

198-
prKeyBytes, err = getPrivateKey(prKeyBytes, options.Passphrase)
176+
prKeyBytes, err = getPrivateKey(prKeyBytes)
199177
if err != nil {
200178
return nil, err
201179
}

tlsconfig/config_test.go

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"crypto/tls"
66
"crypto/x509"
77
"encoding/pem"
8+
"errors"
89
"os"
910
"reflect"
1011
"runtime"
@@ -523,39 +524,18 @@ func TestConfigClientTLSValidClientCertAndKey(t *testing.T) {
523524
}
524525
}
525526

526-
// The certificate is set if the client cert and encrypted client key are
527-
// provided and valid and passphrase can decrypt the key
528-
func TestConfigClientTLSValidClientCertAndEncryptedKey(t *testing.T) {
527+
func TestConfigClientTLSEncryptedKey(t *testing.T) {
529528
key, cert := getCertAndEncryptedKey()
530529

531530
tlsConfig, err := Client(Options{
532-
CertFile: cert,
533-
KeyFile: key,
534-
Passphrase: "FooBar123",
531+
CertFile: cert,
532+
KeyFile: key,
535533
})
536-
537-
if err != nil || tlsConfig == nil {
538-
t.Fatal("Unable to configure client TLS", err)
539-
}
540-
541-
if len(tlsConfig.Certificates) != 1 {
542-
t.Fatal("Unexpected client certificates")
534+
if !errors.Is(err, errEncryptedKeyDeprecated) {
535+
t.Errorf("Expected %v but got %v", errEncryptedKeyDeprecated, err)
543536
}
544-
}
545-
546-
// The certificate is not set if the provided passphrase cannot decrypt
547-
// the encrypted key.
548-
func TestConfigClientTLSNotSetWithInvalidPassphrase(t *testing.T) {
549-
key, cert := getCertAndEncryptedKey()
550-
551-
tlsConfig, err := Client(Options{
552-
CertFile: cert,
553-
KeyFile: key,
554-
Passphrase: "InvalidPassphrase",
555-
})
556-
557-
if !IsErrEncryptedKey(err) || tlsConfig != nil {
558-
t.Fatal("Expected failure due to incorrect passphrase.")
537+
if tlsConfig != nil {
538+
t.Errorf("Expected nil but got %v", tlsConfig)
559539
}
560540
}
561541

0 commit comments

Comments
 (0)