open-consul/agent/connect/generate_test.go

155 lines
4.3 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package connect
import (
"fmt"
"testing"
"time"
"crypto/x509"
"encoding/pem"
"github.com/stretchr/testify/require"
"github.com/hashicorp/consul/agent/structs"
)
type KeyConfig struct {
keyType string
keyBits int
}
var goodParams = []KeyConfig{
{keyType: "rsa", keyBits: 2048},
{keyType: "rsa", keyBits: 4096},
{keyType: "ec", keyBits: 224},
{keyType: "ec", keyBits: 256},
{keyType: "ec", keyBits: 384},
{keyType: "ec", keyBits: 521},
}
var badParams = []KeyConfig{
{keyType: "rsa", keyBits: 0},
{keyType: "rsa", keyBits: 1024},
{keyType: "rsa", keyBits: 24601},
{keyType: "ec", keyBits: 0},
{keyType: "ec", keyBits: 512},
{keyType: "ec", keyBits: 321},
{keyType: "ecdsa", keyBits: 256}, // test for "ecdsa" instead of "ec"
{keyType: "aes", keyBits: 128},
}
func makeConfig(kc KeyConfig) structs.CommonCAProviderConfig {
return structs.CommonCAProviderConfig{
LeafCertTTL: 3 * 24 * time.Hour,
IntermediateCertTTL: 365 * 24 * time.Hour,
RootCertTTL: 10 * 365 * 24 * time.Hour,
PrivateKeyType: kc.keyType,
PrivateKeyBits: kc.keyBits,
}
}
func testGenerateRSAKey(t *testing.T, bits int) {
_, rsaBlock, err := GeneratePrivateKeyWithConfig("rsa", bits)
require.NoError(t, err)
require.Contains(t, rsaBlock, "RSA PRIVATE KEY")
rsaBytes, _ := pem.Decode([]byte(rsaBlock))
require.NotNil(t, rsaBytes)
rsaKey, err := x509.ParsePKCS1PrivateKey(rsaBytes.Bytes)
require.NoError(t, err)
require.NoError(t, rsaKey.Validate())
require.Equal(t, bits/8, rsaKey.Size()) // note: returned size is in bytes. 2048/8==256
}
func testGenerateECDSAKey(t *testing.T, bits int) {
_, pemBlock, err := GeneratePrivateKeyWithConfig("ec", bits)
require.NoError(t, err)
require.Contains(t, pemBlock, "EC PRIVATE KEY")
block, _ := pem.Decode([]byte(pemBlock))
require.NotNil(t, block)
pk, err := x509.ParseECPrivateKey(block.Bytes)
require.NoError(t, err)
require.Equal(t, bits, pk.Curve.Params().BitSize)
}
// Tests to make sure we are able to generate every type of private key supported by the x509 lib.
func TestGenerateKeys(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}
t.Parallel()
for _, params := range goodParams {
t.Run(fmt.Sprintf("TestGenerateKeys-%s-%d", params.keyType, params.keyBits),
func(t *testing.T) {
switch params.keyType {
case "rsa":
testGenerateRSAKey(t, params.keyBits)
case "ec":
testGenerateECDSAKey(t, params.keyBits)
default:
t.Fatalf("unknown key type: %s", params.keyType)
}
})
}
}
// Tests a variety of valid private key configs to make sure they're accepted.
func TestValidateGoodConfigs(t *testing.T) {
t.Parallel()
for _, params := range goodParams {
config := makeConfig(params)
t.Run(fmt.Sprintf("TestValidateGoodConfigs-%s-%d", params.keyType, params.keyBits),
func(t *testing.T) {
require.NoError(t, config.Validate(), "unexpected error: type=%s bits=%d",
params.keyType, params.keyBits)
})
}
}
// Tests a variety of invalid private key configs to make sure they're caught.
func TestValidateBadConfigs(t *testing.T) {
t.Parallel()
for _, params := range badParams {
config := makeConfig(params)
t.Run(fmt.Sprintf("TestValidateBadConfigs-%s-%d", params.keyType, params.keyBits), func(t *testing.T) {
require.Error(t, config.Validate(), "expected error: type=%s bits=%d",
params.keyType, params.keyBits)
})
}
}
// Tests the ability of a CA to sign a CSR using a different key type. This is
// allowed by TLS 1.2 and should succeed in all combinations.
func TestSignatureMismatches(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}
t.Parallel()
for _, p1 := range goodParams {
for _, p2 := range goodParams {
if p1 == p2 {
continue
}
t.Run(fmt.Sprintf("TestMismatches-%s%d-%s%d", p1.keyType, p1.keyBits, p2.keyType, p2.keyBits), func(t *testing.T) {
ca := TestCAWithKeyType(t, nil, p1.keyType, p1.keyBits)
require.Equal(t, p1.keyType, ca.PrivateKeyType)
require.Equal(t, p1.keyBits, ca.PrivateKeyBits)
certPEM, keyPEM, err := testLeaf(t, "foobar.service.consul", "default", ca, p2.keyType, p2.keyBits)
require.NoError(t, err)
_, err = ParseCert(certPEM)
require.NoError(t, err)
_, err = ParseSigner(keyPEM)
require.NoError(t, err)
})
}
}
}