From 8ba9e20e07ccd91afa4ea09ec093513afd6e8697 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Tue, 27 Jun 2023 17:11:54 -0400 Subject: [PATCH] update key length check for FIPS compliance --- .../config_entry_inline_certificate.go | 49 ++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/agent/structs/config_entry_inline_certificate.go b/agent/structs/config_entry_inline_certificate.go index 90482e36269d..4900c3874a18 100644 --- a/agent/structs/config_entry_inline_certificate.go +++ b/agent/structs/config_entry_inline_certificate.go @@ -13,6 +13,7 @@ import ( "github.com/miekg/dns" "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/version" ) // InlineCertificateConfigEntry manages the configuration for an inline certificate @@ -43,7 +44,7 @@ func (e *InlineCertificateConfigEntry) GetEnterpriseMeta() *acl.EnterpriseMeta { } func (e *InlineCertificateConfigEntry) GetRaftIndex() *RaftIndex { return &e.RaftIndex } -// Envoy will silently reject any keys that are less than 2048 bytes long +// Envoy will silently reject any RSA keys that are less than 2048 bytes long // https://github.com/envoyproxy/envoy/blob/main/source/extensions/transport_sockets/tls/context_impl.cc#L238 const MinKeyLength = 2048 @@ -58,17 +59,7 @@ func (e *InlineCertificateConfigEntry) Validate() error { return errors.New("failed to parse private key PEM") } - if privateKeyBlock.Type == "RSA PRIVATE KEY" { - key, err := x509.ParsePKCS1PrivateKey(privateKeyBlock.Bytes) - if err != nil { - return err - } - - // ensure private key is of the correct length - if key.N.BitLen() < MinKeyLength { - return errors.New("key length must be at least 2048 bits") - } - } + err := validateKeyLength(privateKeyBlock) certificateBlock, _ := pem.Decode([]byte(e.Certificate)) if certificateBlock == nil { @@ -102,6 +93,40 @@ func (e *InlineCertificateConfigEntry) Validate() error { return nil } +func validateKeyLength(privateKeyBlock *pem.Block) error { + if privateKeyBlock.Type != "RSA PRIVATE KEY" { + return nil + } + + lenCheckFn := nonFipsLenCheck + + if version.IsFIPS() { + lenCheckFn = fipsLenCheck + } + key, err := x509.ParsePKCS1PrivateKey(privateKeyBlock.Bytes) + if err != nil { + return err + } + + return lenCheckFn(key.N.BitLen()) +} + +func nonFipsLenCheck(keyLen int) error { + // ensure private key is of the correct length + if keyLen < MinKeyLength { + return errors.New("key length must be at least 2048 bits") + } + + return nil +} + +func fipsLenCheck(keyLen int) error { + if keyLen != 2048 && keyLen != 3072 && keyLen != 4096 { + return errors.New("key length invalid: only RSA lengths of 2048, 3072, and 4096 are allowed in FIPS mode") + } + return nil +} + func (e *InlineCertificateConfigEntry) Hosts() ([]string, error) { certificateBlock, _ := pem.Decode([]byte(e.Certificate)) if certificateBlock == nil {