1// (c) Copyright 2016 Hewlett Packard Enterprise Development LP 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15//go:generate tlsconfig 16 17package rules 18 19import ( 20 "crypto/tls" 21 "fmt" 22 "go/ast" 23 24 "github.com/securego/gosec/v2" 25) 26 27type insecureConfigTLS struct { 28 gosec.MetaData 29 MinVersion int16 30 MaxVersion int16 31 requiredType string 32 goodCiphers []string 33 actualMinVersion int16 34 actualMaxVersion int16 35} 36 37func (t *insecureConfigTLS) ID() string { 38 return t.MetaData.ID 39} 40 41func stringInSlice(a string, list []string) bool { 42 for _, b := range list { 43 if b == a { 44 return true 45 } 46 } 47 return false 48} 49 50func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gosec.Context) *gosec.Issue { 51 if ciphers, ok := n.(*ast.CompositeLit); ok { 52 for _, cipher := range ciphers.Elts { 53 if ident, ok := cipher.(*ast.SelectorExpr); ok { 54 if !stringInSlice(ident.Sel.Name, t.goodCiphers) { 55 err := fmt.Sprintf("TLS Bad Cipher Suite: %s", ident.Sel.Name) 56 return gosec.NewIssue(c, ident, t.ID(), err, gosec.High, gosec.High) 57 } 58 } 59 } 60 } 61 return nil 62} 63 64func (t *insecureConfigTLS) processTLSConfVal(n *ast.KeyValueExpr, c *gosec.Context) *gosec.Issue { 65 if ident, ok := n.Key.(*ast.Ident); ok { 66 switch ident.Name { 67 case "InsecureSkipVerify": 68 if node, ok := n.Value.(*ast.Ident); ok { 69 if node.Name != "false" { 70 return gosec.NewIssue(c, n, t.ID(), "TLS InsecureSkipVerify set true.", gosec.High, gosec.High) 71 } 72 } else { 73 // TODO(tk): symbol tab look up to get the actual value 74 return gosec.NewIssue(c, n, t.ID(), "TLS InsecureSkipVerify may be true.", gosec.High, gosec.Low) 75 } 76 77 case "PreferServerCipherSuites": 78 if node, ok := n.Value.(*ast.Ident); ok { 79 if node.Name == "false" { 80 return gosec.NewIssue(c, n, t.ID(), "TLS PreferServerCipherSuites set false.", gosec.Medium, gosec.High) 81 } 82 } else { 83 // TODO(tk): symbol tab look up to get the actual value 84 return gosec.NewIssue(c, n, t.ID(), "TLS PreferServerCipherSuites may be false.", gosec.Medium, gosec.Low) 85 } 86 87 case "MinVersion": 88 if ival, ierr := gosec.GetInt(n.Value); ierr == nil { 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 } 95 } 96 } 97 98 case "MaxVersion": 99 if ival, ierr := gosec.GetInt(n.Value); ierr == nil { 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 } 106 } 107 } 108 109 case "CipherSuites": 110 if ret := t.processTLSCipherSuites(n.Value, c); ret != nil { 111 return ret 112 } 113 114 } 115 116 } 117 return nil 118} 119 120func (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 135func (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 greater 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 149func (t *insecureConfigTLS) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { 150 if complit, ok := n.(*ast.CompositeLit); ok && complit.Type != nil { 151 actualType := c.Info.TypeOf(complit.Type) 152 if actualType != nil && actualType.String() == t.requiredType { 153 for _, elt := range complit.Elts { 154 if kve, ok := elt.(*ast.KeyValueExpr); ok { 155 issue := t.processTLSConfVal(kve, c) 156 if issue != nil { 157 return issue, nil 158 } 159 } 160 } 161 return t.checkVersion(complit, c), nil 162 } 163 } 164 return nil, nil 165} 166