Backport of [NET-6593] agent: check for minimum RSA key size into release/1.17.x (#20142)

* backport of commit 0e36f636a4

* manual backport

---------

Co-authored-by: Dan Bond <danbond@protonmail.com>
pull/20146/head
hc-github-team-consul-core 2024-01-10 07:21:43 -06:00 committed by GitHub
parent 14928687bc
commit 55b388b3a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 3 deletions

3
.changelog/20112.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:security
Update RSA key generation to use a key size of at least 2048 bits.
```

View File

@ -7,6 +7,7 @@ import (
"context"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"net"
"net/url"
@ -107,6 +108,45 @@ func TestAutoEncrypt_generateCSR(t *testing.T) {
}
}
func TestAutoEncrypt_generateCSR_RSA(t *testing.T) {
testCases := []struct {
name string
keySize int
expectedKeySize int
}{
{
name: "DefaultKeySize",
keySize: 0,
expectedKeySize: 4096,
},
{
name: "KeySize2048",
keySize: 2048,
expectedKeySize: 2048,
},
}
for _, tcase := range testCases {
t.Run(tcase.name, func(t *testing.T) {
ac := AutoConfig{config: &config.RuntimeConfig{
ConnectCAConfig: map[string]interface{}{
"PrivateKeyType": "rsa",
"PrivateKeyBits": tcase.keySize,
},
}}
// Generate a private RSA key.
_, key, err := ac.generateCSR()
require.NoError(t, err)
// Parse the private key and check it's length.
pemBlock, _ := pem.Decode([]byte(key))
priv, _ := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
require.Equal(t, tcase.expectedKeySize, priv.N.BitLen())
})
}
}
func TestAutoEncrypt_hosts(t *testing.T) {
type testCase struct {
serverProvider ServerProvider

View File

@ -241,7 +241,12 @@ func (ac *AutoConfig) generateCSR() (csr string, key string, err error) {
conf.PrivateKeyType = connect.DefaultPrivateKeyType
}
if conf.PrivateKeyBits == 0 {
conf.PrivateKeyBits = connect.DefaultPrivateKeyBits
// If using an RSA key, a key size of at least 2048 bits is recommended; 4096 bits is better.
if conf.PrivateKeyType == connect.PrivateKeyTypeRSA {
conf.PrivateKeyBits = connect.DefaultPrivateKeyBitsRSA
} else {
conf.PrivateKeyBits = connect.DefaultPrivateKeyBits
}
}
// Create a new private key

View File

@ -21,6 +21,11 @@ const (
DefaultPrivateKeyType = "ec"
DefaultPrivateKeyBits = 256
DefaultIntermediateCertTTL = 24 * 365 * time.Hour
// RSA specific settings.
PrivateKeyTypeRSA = "rsa"
MinPrivateKeyBitsRSA = 2048
DefaultPrivateKeyBitsRSA = 4096
)
func pemEncode(value []byte, blockType string) (string, error) {
@ -35,6 +40,11 @@ func pemEncode(value []byte, blockType string) (string, error) {
func generateRSAKey(keyBits int) (crypto.Signer, string, error) {
var pk *rsa.PrivateKey
// Check for a secure key length.
if keyBits < MinPrivateKeyBitsRSA {
return nil, "", fmt.Errorf("error generating RSA private key: key size must be at least %d bits", MinPrivateKeyBitsRSA)
}
pk, err := rsa.GenerateKey(rand.Reader, keyBits)
if err != nil {
return nil, "", fmt.Errorf("error generating RSA private key: %s", err)
@ -87,9 +97,9 @@ func generateECDSAKey(keyBits int) (crypto.Signer, string, error) {
// GeneratePrivateKey generates a new Private key
func GeneratePrivateKeyWithConfig(keyType string, keyBits int) (crypto.Signer, string, error) {
switch strings.ToLower(keyType) {
case "rsa":
case PrivateKeyTypeRSA:
return generateRSAKey(keyBits)
case "ec":
case DefaultPrivateKeyType:
return generateECDSAKey(keyBits)
default:
return nil, "", fmt.Errorf("unknown private key type requested: %s", keyType)