mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-25 10:40:02 +08:00
allow EC ssh keys in FIPS mode (#44476)
* allow EC ssh keys in FIPS mode * fix test
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user