Skip to content

Commit 55d368f

Browse files
ccojocarCosmin Cojocar
authored andcommitted
Improve the TLS version checking
Signed-off-by: Cosmin Cojocar <cosmin.cojocar@gmx.ch>
1 parent ad1cb7e commit 55d368f

2 files changed

Lines changed: 68 additions & 15 deletions

File tree

rules/tls.go

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package rules
1818

1919
import (
20+
"crypto/tls"
2021
"fmt"
2122
"go/ast"
2223

@@ -25,10 +26,12 @@ import (
2526

2627
type insecureConfigTLS struct {
2728
gosec.MetaData
28-
MinVersion int16
29-
MaxVersion int16
30-
requiredType string
31-
goodCiphers []string
29+
MinVersion int16
30+
MaxVersion int16
31+
requiredType string
32+
goodCiphers []string
33+
actualMinVersion int16
34+
actualMaxVersion int16
3235
}
3336

3437
func (t *insecureConfigTLS) ID() string {
@@ -45,7 +48,6 @@ func stringInSlice(a string, list []string) bool {
4548
}
4649

4750
func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gosec.Context) *gosec.Issue {
48-
4951
if ciphers, ok := n.(*ast.CompositeLit); ok {
5052
for _, cipher := range ciphers.Elts {
5153
if ident, ok := cipher.(*ast.SelectorExpr); ok {
@@ -62,7 +64,6 @@ func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gosec.Context)
6264
func (t *insecureConfigTLS) processTLSConfVal(n *ast.KeyValueExpr, c *gosec.Context) *gosec.Issue {
6365
if ident, ok := n.Key.(*ast.Ident); ok {
6466
switch ident.Name {
65-
6667
case "InsecureSkipVerify":
6768
if node, ok := n.Value.(*ast.Ident); ok {
6869
if node.Name != "false" {
@@ -85,20 +86,24 @@ func (t *insecureConfigTLS) processTLSConfVal(n *ast.KeyValueExpr, c *gosec.Cont
8586

8687
case "MinVersion":
8788
if ival, ierr := gosec.GetInt(n.Value); ierr == nil {
88-
if (int16)(ival) < t.MinVersion {
89-
return gosec.NewIssue(c, n, t.ID(), "TLS MinVersion too low.", gosec.High, gosec.High)
89+
t.actualMinVersion = (int16)(ival)
90+
} else {
91+
if se, ok := n.Value.(*ast.SelectorExpr); ok {
92+
if pkg, ok := se.X.(*ast.Ident); ok && pkg.Name == "tls" {
93+
t.actualMinVersion = t.mapVersion(se.Sel.Name)
94+
}
9095
}
91-
// TODO(tk): symbol tab look up to get the actual value
92-
return gosec.NewIssue(c, n, t.ID(), "TLS MinVersion may be too low.", gosec.High, gosec.Low)
9396
}
9497

9598
case "MaxVersion":
9699
if ival, ierr := gosec.GetInt(n.Value); ierr == nil {
97-
if (int16)(ival) < t.MaxVersion {
98-
return gosec.NewIssue(c, n, t.ID(), "TLS MaxVersion too low.", gosec.High, gosec.High)
100+
t.actualMaxVersion = (int16)(ival)
101+
} else {
102+
if se, ok := n.Value.(*ast.SelectorExpr); ok {
103+
if pkg, ok := se.X.(*ast.Ident); ok && pkg.Name == "tls" {
104+
t.actualMaxVersion = t.mapVersion(se.Sel.Name)
105+
}
99106
}
100-
// TODO(tk): symbol tab look up to get the actual value
101-
return gosec.NewIssue(c, n, t.ID(), "TLS MaxVersion may be too low.", gosec.High, gosec.Low)
102107
}
103108

104109
case "CipherSuites":
@@ -112,6 +117,35 @@ func (t *insecureConfigTLS) processTLSConfVal(n *ast.KeyValueExpr, c *gosec.Cont
112117
return nil
113118
}
114119

120+
func (t *insecureConfigTLS) mapVersion(version string) int16 {
121+
var v int16
122+
switch version {
123+
case "VersionTLS13":
124+
v = tls.VersionTLS13
125+
case "VersionTLS12":
126+
v = tls.VersionTLS12
127+
case "VersionTLS11":
128+
v = tls.VersionTLS11
129+
case "VersionTLS10":
130+
v = tls.VersionTLS10
131+
}
132+
return v
133+
}
134+
135+
func (t *insecureConfigTLS) checkVersion(n ast.Node, c *gosec.Context) *gosec.Issue {
136+
if t.actualMaxVersion == 0 && t.actualMinVersion >= t.MinVersion {
137+
// no warning is generated since the min version is grater than the secure min version
138+
return nil
139+
}
140+
if t.actualMinVersion < t.MinVersion {
141+
return gosec.NewIssue(c, n, t.ID(), "TLS MinVersion too low.", gosec.High, gosec.High)
142+
}
143+
if t.actualMaxVersion < t.MaxVersion {
144+
return gosec.NewIssue(c, n, t.ID(), "TLS MaxVersion too low.", gosec.High, gosec.High)
145+
}
146+
return nil
147+
}
148+
115149
func (t *insecureConfigTLS) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
116150
if complit, ok := n.(*ast.CompositeLit); ok && complit.Type != nil {
117151
actualType := c.Info.TypeOf(complit.Type)
@@ -124,6 +158,7 @@ func (t *insecureConfigTLS) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, e
124158
}
125159
}
126160
}
161+
return t.checkVersion(complit, c), nil
127162
}
128163
}
129164
return nil, nil

testutils/source.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1887,7 +1887,25 @@ func main() {
18871887
if err != nil {
18881888
fmt.Println(err)
18891889
}
1890-
}`}, 1, gosec.NewConfig()}}
1890+
}`}, 1, gosec.NewConfig()}, {[]string{`
1891+
// secure max version when min version is specified
1892+
package main
1893+
import (
1894+
"crypto/tls"
1895+
"fmt"
1896+
"net/http"
1897+
)
1898+
func main() {
1899+
tr := &http.Transport{
1900+
TLSClientConfig: &tls.Config{MaxVersion: 0, MinVersion: tls.VersionTLS13},
1901+
}
1902+
client := &http.Client{Transport: tr}
1903+
_, err := client.Get("https://golang.org/")
1904+
if err != nil {
1905+
fmt.Println(err)
1906+
}
1907+
}
1908+
}`}, 0, gosec.NewConfig()}}
18911909

18921910
// SampleCodeG403 - weak key strength
18931911
SampleCodeG403 = []CodeSample{

0 commit comments

Comments
 (0)