package connect
import (
"fmt"
"testing"
"time"
"crypto/x509"
"encoding/pem"
"github.com/hashicorp/consul/agent/structs"
"github.com/stretchr/testify/require"
)
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 ) {
r := require . New ( t )
_ , rsaBlock , err := GeneratePrivateKeyWithConfig ( "rsa" , bits )
r . NoError ( err )
r . Contains ( rsaBlock , "RSA PRIVATE KEY" )
rsaBytes , _ := pem . Decode ( [ ] byte ( rsaBlock ) )
r . NotNil ( rsaBytes )
rsaKey , err := x509 . ParsePKCS1PrivateKey ( rsaBytes . Bytes )
r . NoError ( err )
r . NoError ( rsaKey . Validate ( ) )
r . Equal ( bits / 8 , rsaKey . Size ( ) ) // note: returned size is in bytes. 2048/8==256
}
func testGenerateECDSAKey ( t * testing . T , bits int ) {
r := require . New ( t )
_ , pemBlock , err := GeneratePrivateKeyWithConfig ( "ec" , bits )
r . NoError ( err )
r . Contains ( pemBlock , "EC PRIVATE KEY" )
block , _ := pem . Decode ( [ ] byte ( pemBlock ) )
r . NotNil ( block )
pk , err := x509 . ParseECPrivateKey ( block . Bytes )
r . NoError ( err )
r . Equal ( 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 . New ( t ) . NoError ( 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 . New ( t ) . Error ( 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 ( )
r := require . New ( t )
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 )
r . Equal ( p1 . keyType , ca . PrivateKeyType )
r . Equal ( p1 . keyBits , ca . PrivateKeyBits )
certPEM , keyPEM , err := testLeaf ( t , "foobar.service.consul" , "default" , ca , p2 . keyType , p2 . keyBits )
r . NoError ( err )
_ , err = ParseCert ( certPEM )
r . NoError ( err )
_ , err = ParseSigner ( keyPEM )
r . NoError ( err )
} )
}
}
}