allow EC ssh keys in FIPS mode (#44476)

* allow EC ssh keys in FIPS mode

* fix test
This commit is contained in:
Nic Klaassen
2024-07-19 19:59:54 +00:00
committed by GitHub
parent ccdb91e575
commit afca8aefc8
4 changed files with 122 additions and 64 deletions
+17 -6
View File
@@ -17,6 +17,8 @@ limitations under the License.
package sshutils
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"net"
@@ -123,12 +125,21 @@ func validateFIPSAlgorithm(key ssh.PublicKey) error {
if !ok {
return trace.BadParameter("unable to determine underlying public key")
}
k, ok := cryptoKey.CryptoPublicKey().(*rsa.PublicKey)
if !ok {
return trace.BadParameter("only RSA keys supported")
}
if k.N.BitLen() != constants.RSAKeySize {
return trace.BadParameter("found %v-bit key, only %v-bit supported", k.N.BitLen(), constants.RSAKeySize)
switch k := cryptoKey.CryptoPublicKey().(type) {
case *rsa.PublicKey:
if k.N.BitLen() != constants.RSAKeySize {
return trace.BadParameter("found %v-bit RSA key, only %v-bit supported", k.N.BitLen(), constants.RSAKeySize)
}
case *ecdsa.PublicKey:
if k.Curve != elliptic.P256() && k.Curve != elliptic.P384() {
params := k.Curve.Params()
if params == nil {
return trace.BadParameter("unable to determine curve of ECDSA public key")
}
return trace.BadParameter("found ECDSA key with curve %s, only P-256 and P-384 are supported", params.Name)
}
default:
return trace.BadParameter("only RSA and ECDSA keys supported")
}
return nil
}
+65 -53
View File
@@ -17,55 +17,26 @@ limitations under the License.
package sshutils
import (
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/ssh"
"github.com/gravitational/teleport/api/constants"
)
// TestCheckerValidate checks what algorithm are supported in regular (non-FIPS) mode.
func TestCheckerValidate(t *testing.T) {
checker := CertChecker{}
rsaKey, err := rsa.GenerateKey(rand.Reader, constants.RSAKeySize)
require.NoError(t, err)
smallRSAKey, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err)
ellipticKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err)
// 2048-bit RSA keys are valid.
cryptoKey := rsaKey.Public()
sshKey, err := ssh.NewPublicKey(cryptoKey)
require.NoError(t, err)
err = checker.validateFIPS(sshKey)
require.NoError(t, err)
// 1024-bit RSA keys are valid.
cryptoKey = smallRSAKey.Public()
sshKey, err = ssh.NewPublicKey(cryptoKey)
require.NoError(t, err)
err = checker.validateFIPS(sshKey)
require.NoError(t, err)
// ECDSA keys are valid.
cryptoKey = ellipticKey.Public()
sshKey, err = ssh.NewPublicKey(cryptoKey)
require.NoError(t, err)
err = checker.validateFIPS(sshKey)
require.NoError(t, err)
}
// TestCheckerValidateFIPS makes sure the public key is a valid algorithm
// that Teleport supports while in FIPS mode.
func TestCheckerValidateFIPS(t *testing.T) {
checker := CertChecker{
regularChecker := CertChecker{}
fipsChecker := CertChecker{
FIPS: true,
}
@@ -73,27 +44,68 @@ func TestCheckerValidateFIPS(t *testing.T) {
require.NoError(t, err)
smallRSAKey, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err)
ellipticKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
ellipticKeyP224, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
require.NoError(t, err)
ellipticKeyP256, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err)
ellipticKeyP384, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
require.NoError(t, err)
_, ed25519Key, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
// 2048-bit RSA keys are valid.
cryptoKey := rsaKey.Public()
sshKey, err := ssh.NewPublicKey(cryptoKey)
require.NoError(t, err)
err = checker.validateFIPS(sshKey)
require.NoError(t, err)
for _, tc := range []struct {
desc string
key crypto.Signer
expectSSHError bool
expectFIPSError bool
}{
{
desc: "RSA2048",
key: rsaKey,
},
{
desc: "RSA1024",
key: smallRSAKey,
expectFIPSError: true,
},
{
desc: "ECDSAP224",
key: ellipticKeyP224,
expectSSHError: true,
expectFIPSError: true,
},
{
desc: "ECDSAP256",
key: ellipticKeyP256,
},
{
desc: "ECDSAP384",
key: ellipticKeyP384,
},
{
desc: "Ed25519",
key: ed25519Key,
expectFIPSError: true,
},
} {
t.Run(tc.desc, func(t *testing.T) {
cryptoKey := tc.key.Public()
sshKey, err := ssh.NewPublicKey(cryptoKey)
if tc.expectSSHError {
require.Error(t, err)
} else {
require.NoError(t, err)
}
// 1024-bit RSA keys are not valid.
cryptoKey = smallRSAKey.Public()
sshKey, err = ssh.NewPublicKey(cryptoKey)
require.NoError(t, err)
err = checker.validateFIPS(sshKey)
require.Error(t, err)
err = regularChecker.validateFIPS(sshKey)
assert.NoError(t, err)
// ECDSA keys are not valid.
cryptoKey = ellipticKey.Public()
sshKey, err = ssh.NewPublicKey(cryptoKey)
require.NoError(t, err)
err = checker.validateFIPS(sshKey)
require.Error(t, err)
err = fipsChecker.validateFIPS(sshKey)
if tc.expectFIPSError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}