Skip to content

Commit 1178069

Browse files
authored
feat(fips): restrict supported ciphers in fips mode (#288)
no CBC mode drop ciphers using non NIST-approved algos only pick ciphers from secure list
1 parent 12e5e9c commit 1178069

File tree

7 files changed

+139
-4
lines changed

7 files changed

+139
-4
lines changed

transport/tlscommon/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ func (c *Config) Validate() error {
9898
}
9999

100100
}
101+
for _, cs := range c.CipherSuites {
102+
if err := cs.Validate(); err != nil {
103+
return err
104+
}
105+
}
101106
return c.Certificate.Validate()
102107
}
103108

transport/tlscommon/tls_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func TestValuesSet(t *testing.T) {
7474
key: mycert.key
7575
verification_mode: none
7676
cipher_suites:
77-
- ECDHE-ECDSA-AES-256-CBC-SHA
77+
- ECDHE-ECDSA-AES-128-GCM-SHA256
7878
- ECDHE-ECDSA-AES-256-GCM-SHA384
7979
supported_protocols: [TLSv1.3]
8080
curve_types:
@@ -124,7 +124,7 @@ func TestApplyWithConfig(t *testing.T) {
124124
certificate_authorities: [testdata/ca_test.pem]
125125
verification_mode: none
126126
cipher_suites:
127-
- "ECDHE-ECDSA-AES-256-CBC-SHA"
127+
- "ECDHE-ECDSA-AES-128-GCM-SHA256"
128128
- "ECDHE-ECDSA-AES-256-GCM-SHA384"
129129
curve_types: [P-384]
130130
renegotiation: once

transport/tlscommon/types.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ var tlsCipherSuites = map[string]CipherSuite{
7171
"TLS-CHACHA20-POLY1305-SHA256": CipherSuite(tls.TLS_CHACHA20_POLY1305_SHA256),
7272
}
7373

74+
var supportedCipherSuites = make(map[CipherSuite]string, len(tlsCipherSuites))
7475
var tlsCipherSuitesInverse = make(map[CipherSuite]string, len(tlsCipherSuites))
7576
var tlsRenegotiationSupportTypesInverse = make(map[TLSRenegotiationSupport]string, len(tlsRenegotiationSupportTypes))
7677
var tlsVerificationModesInverse = make(map[TLSVerificationMode]string, len(tlsVerificationModes))
@@ -256,6 +257,13 @@ func (cs *CipherSuite) Unpack(i interface{}) error {
256257
return nil
257258
}
258259

260+
func (cs *CipherSuite) Validate() error {
261+
if _, ok := supportedCipherSuites[*cs]; !ok {
262+
return fmt.Errorf("unsupported tls cipher suite: %s", tls.CipherSuiteName(uint16(*cs)))
263+
}
264+
return nil
265+
}
266+
259267
func (cs CipherSuite) String() string {
260268
if s, found := tlsCipherSuitesInverse[cs]; found {
261269
return s

transport/tlscommon/types_fips.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Licensed to Elasticsearch B.V. under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Elasticsearch B.V. licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
//go:build requirefips
19+
20+
package tlscommon
21+
22+
import "crypto/tls"
23+
24+
func init() {
25+
// try to stick to NIST SP 800-52 Rev.2
26+
// avoid CBC mode
27+
// avoid go insecure cipher suites
28+
// pick ciphers with NIST-approved algorithms
29+
for cipherName, i := range tlsCipherSuites {
30+
switch uint16(i) {
31+
case tls.TLS_AES_128_GCM_SHA256,
32+
tls.TLS_AES_256_GCM_SHA384,
33+
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
34+
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
35+
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
36+
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
37+
supportedCipherSuites[i] = cipherName
38+
}
39+
}
40+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Licensed to Elasticsearch B.V. under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Elasticsearch B.V. licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
//go:build requirefips
19+
20+
package tlscommon
21+
22+
import (
23+
"testing"
24+
25+
"github.com/stretchr/testify/assert"
26+
)
27+
28+
func TestLoadUnsupporteTLSVersion(t *testing.T) {
29+
cfg, err := load(`
30+
enabled: true
31+
certificate: mycert.pem
32+
key: mycert.key
33+
verification_mode: ""
34+
supported_protocols: [TLSv1.1, TLSv1.2]
35+
renegotiation: freely
36+
`)
37+
38+
assert.ErrorContains(t, err, "unsupported tls version")
39+
assert.Nil(t, cfg)
40+
}
41+
42+
func TestLoadUnsupportedCiphers(t *testing.T) {
43+
cfg, err := load(`
44+
enabled: true
45+
certificate: mycert.pem
46+
key: mycert.key
47+
verification_mode: ""
48+
supported_protocols: [TLSv1.2, TLSv1.3]
49+
cipher_suites: ["RSA-AES-256-CBC-SHA"]
50+
renegotiation: freely
51+
`)
52+
53+
assert.ErrorContains(t, err, "unsupported tls cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA")
54+
assert.Nil(t, cfg)
55+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Licensed to Elasticsearch B.V. under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Elasticsearch B.V. licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
//go:build !requirefips
19+
20+
package tlscommon
21+
22+
func init() {
23+
// all tls cipher suites are supported
24+
for cipherName, i := range tlsCipherSuites {
25+
supportedCipherSuites[i] = cipherName
26+
}
27+
}

transport/tlscommon/types_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func TestRepackConfig(t *testing.T) {
9292
verification_mode: certificate
9393
supported_protocols: [TLSv1.2, TLSv1.3]
9494
cipher_suites:
95-
- RSA-AES-256-CBC-SHA
95+
- ECDHE-ECDSA-AES-256-GCM-SHA384
9696
certificate_authorities:
9797
- /path/to/ca.crt
9898
certificate: /path/to/cert.crt
@@ -121,7 +121,7 @@ func TestRepackConfigFromJSON(t *testing.T) {
121121
"enabled": true,
122122
"verification_mode": "certificate",
123123
"supported_protocols": ["TLSv1.2", "TLSv1.3"],
124-
"cipher_suites": ["RSA-AES-256-CBC-SHA"],
124+
"cipher_suites": ["ECDHE-ECDSA-AES-256-GCM-SHA384"],
125125
"certificate_authorities": ["/path/to/ca.crt"],
126126
"certificate": "/path/to/cert.crt",
127127
"key": "/path/to/key.crt",

0 commit comments

Comments
 (0)