Skip to content

Commit

Permalink
Added more rules
Browse files Browse the repository at this point in the history
* Rule G406 responsible for the usage of deprecated MD4 and RIPEMD160 added.
* Rules G506, G507 responsible for tracking the usage of the already mentioned libraries added.
* Slight changes in the Makefile(`make clean` wasn't removing all expected files)
* Added license to `analyzer_test.go`
  • Loading branch information
Dimitar Banchev authored and ccojocar committed Jun 25, 2024
1 parent 6382394 commit 9a4a741
Show file tree
Hide file tree
Showing 13 changed files with 536 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ build-race:
go build -race -o $(BIN) ./cmd/gosec/

clean:
rm -rf build vendor dist coverage.txt
rm -rf build vendor dist coverage.out
rm -f release image $(BIN)

release:
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,14 @@ directory you can supply `./...` as the input argument.
- G403: Ensure minimum RSA key length of 2048 bits
- G404: Insecure random number source (rand)
- G405: Detect the usage of DES or RC4
- G406: Detect the usage of MD4 or RIPEMD160
- G501: Import blocklist: crypto/md5
- G502: Import blocklist: crypto/des
- G503: Import blocklist: crypto/rc4
- G504: Import blocklist: net/http/cgi
- G505: Import blocklist: crypto/sha1
- G506: Import blocklist: golang.org/x/crypto/md4
- G507: Import blocklist: golang.org/x/crypto/ripemd160
- G601: Implicit memory aliasing of items from a range statement (only for Go 1.21 or lower)
- G602: Slice access out of bounds

Expand Down
321 changes: 321 additions & 0 deletions analyzer_test.go

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions call_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,31 @@ var _ = Describe("Call List", func() {
Expect(matched).Should(Equal(1))
})

It("should match a package call expression", func() {
// Create file to be scanned
pkg := testutils.NewTestPackage()
defer pkg.Close()
pkg.AddFile("md4.go", testutils.SampleCodeG406[0].Code[0])

ctx := pkg.CreateContext("md4.go")

// Search for md4.New()
calls.Add("golang.org/x/crypto/md4", "New")

// Stub out visitor and count number of matched call expr
matched := 0
v := testutils.NewMockVisitor()
v.Context = ctx
v.Callback = func(n ast.Node, ctx *gosec.Context) bool {
if _, ok := n.(*ast.CallExpr); ok && calls.ContainsPkgCallExpr(n, ctx, false) != nil {
matched++
}
return true
}
ast.Walk(v, ctx.Root)
Expect(matched).Should(Equal(1))
})

It("should match a call expression", func() {
// Create file to be scanned
pkg := testutils.NewTestPackage()
Expand Down
3 changes: 3 additions & 0 deletions issue/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,14 @@ var ruleToCWE = map[string]string{
"G403": "310",
"G404": "338",
"G405": "327",
"G406": "328",
"G501": "327",
"G502": "327",
"G503": "327",
"G504": "327",
"G505": "327",
"G506": "327",
"G507": "327",
"G601": "118",
"G602": "118",
}
Expand Down
4 changes: 2 additions & 2 deletions report/formatter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,8 @@ var _ = Describe("Formatter", func() {
"G101", "G102", "G103", "G104", "G106", "G107", "G109",
"G110", "G111", "G112", "G113", "G201", "G202", "G203",
"G204", "G301", "G302", "G303", "G304", "G305", "G401",
"G402", "G403", "G404", "G405", "G501", "G502", "G503",
"G504", "G505", "G601",
"G402", "G403", "G404", "G405", "G406", "G501", "G502",
"G503", "G504", "G505", "G506", "G507", "G601",
}

It("csv formatted report should contain the CWE mapping", func() {
Expand Down
14 changes: 14 additions & 0 deletions rules/blocklist.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,17 @@ func NewBlocklistedImportSHA1(id string, conf gosec.Config) (gosec.Rule, []ast.N
"crypto/sha1": "Blocklisted import crypto/sha1: weak cryptographic primitive",
})
}

// NewBlocklistedImportMD4 fails if MD4 is imported
func NewBlocklistedImportMD4(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return NewBlocklistedImports(id, conf, map[string]string{
"golang.org/x/crypto/md4": "Blocklisted import golang.org/x/crypto/md4: deprecated and weak cryptographic primitive",
})
}

// NewBlocklistedImportRIPEMD160 fails if RIPEMD160 is imported
func NewBlocklistedImportRIPEMD160(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return NewBlocklistedImports(id, conf, map[string]string{
"golang.org/x/crypto/ripemd160": "Blocklisted import golang.org/x/crypto/ripemd160: deprecated and weak cryptographic primitive",
})
}
3 changes: 3 additions & 0 deletions rules/rulelist.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,16 @@ func Generate(trackSuppressions bool, filters ...RuleFilter) RuleList {
{"G403", "Ensure minimum RSA key length of 2048 bits", NewWeakKeyStrength},
{"G404", "Insecure random number source (rand)", NewWeakRandCheck},
{"G405", "Detect the usage of DES or RC4", NewUsesWeakCryptographyEncryption},
{"G406", "Detect the usage of deprecated MD4 or RIPEMD160", NewUsesWeakDeprecatedCryptographyHash},

// blocklist
{"G501", "Import blocklist: crypto/md5", NewBlocklistedImportMD5},
{"G502", "Import blocklist: crypto/des", NewBlocklistedImportDES},
{"G503", "Import blocklist: crypto/rc4", NewBlocklistedImportRC4},
{"G504", "Import blocklist: net/http/cgi", NewBlocklistedImportCGI},
{"G505", "Import blocklist: crypto/sha1", NewBlocklistedImportSHA1},
{"G506", "Import blocklist: golang.org/x/crypto/md4", NewBlocklistedImportMD4},
{"G507", "Import blocklist: golang.org/x/crypto/ripemd160", NewBlocklistedImportRIPEMD160},

// memory safety
{"G601", "Implicit memory aliasing in RangeStmt", NewImplicitAliasing},
Expand Down
16 changes: 16 additions & 0 deletions rules/rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,14 @@ var _ = Describe("gosec rules", func() {
runner("G405", testutils.SampleCodeG405b)
})

It("should detect weak crypto algorithms", func() {
runner("G406", testutils.SampleCodeG406)
})

It("should detect weak crypto algorithms", func() {
runner("G406", testutils.SampleCodeG406b)
})

It("should detect blocklisted imports - MD5", func() {
runner("G501", testutils.SampleCodeG501)
})
Expand All @@ -203,6 +211,14 @@ var _ = Describe("gosec rules", func() {
runner("G505", testutils.SampleCodeG505)
})

It("should detect blocklisted imports - MD4", func() {
runner("G506", testutils.SampleCodeG506)
})

It("should detect blocklisted imports - RIPEMD160", func() {
runner("G507", testutils.SampleCodeG507)
})

It("should detect implicit aliasing in ForRange", func() {
major, minor, _ := gosec.GoVersion()
if major <= 1 && minor < 22 {
Expand Down
57 changes: 57 additions & 0 deletions rules/weakdepricatedcryptohash.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// (c) Copyright 2024 Mercedes-Benz Tech Innovation GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package rules

import (
"go/ast"

"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)

type usesWeakDeprecatedCryptographyHash struct {
issue.MetaData
blocklist map[string][]string
}

func (r *usesWeakDeprecatedCryptographyHash) ID() string {
return r.MetaData.ID
}

func (r *usesWeakDeprecatedCryptographyHash) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
for pkg, funcs := range r.blocklist {
if _, matched := gosec.MatchCallByPackage(n, c, pkg, funcs...); matched {
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
return nil, nil
}

// NewUsesWeakCryptographyHash detects uses of md4.New, ripemd160.New
func NewUsesWeakDeprecatedCryptographyHash(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
calls := make(map[string][]string)
calls["golang.org/x/crypto/md4"] = []string{"New"}
calls["golang.org/x/crypto/ripemd160"] = []string{"New"}
rule := &usesWeakDeprecatedCryptographyHash{
blocklist: calls,
MetaData: issue.MetaData{
ID: id,
Severity: issue.Medium,
Confidence: issue.High,
What: "Use of deprecated weak cryptographic primitive",
},
}
return rule, []ast.Node{(*ast.CallExpr)(nil)}
}
45 changes: 45 additions & 0 deletions testutils/g406_samples.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package testutils

import "github.com/securego/gosec/v2"

var (
// SampleCodeG406 - Use of deprecated weak crypto hash MD4
SampleCodeG406 = []CodeSample{
{[]string{`
package main
import (
"encoding/hex"
"fmt"
"golang.org/x/crypto/md4"
)
func main() {
h := md4.New()
h.Write([]byte("test"))
fmt.Println(hex.EncodeToString(h.Sum(nil)))
}
`}, 1, gosec.NewConfig()},
}

// SampleCodeG406b - Use of deprecated weak crypto hash RIPEMD160
SampleCodeG406b = []CodeSample{
{[]string{`
package main
import (
"encoding/hex"
"fmt"
"golang.org/x/crypto/ripemd160"
)
func main() {
h := ripemd160.New()
h.Write([]byte("test"))
fmt.Println(hex.EncodeToString(h.Sum(nil)))
}
`}, 1, gosec.NewConfig()},
}
)
23 changes: 23 additions & 0 deletions testutils/g506_samples.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package testutils

import "github.com/securego/gosec/v2"

// SampleCodeG506 - Blocklisted import MD4
var SampleCodeG506 = []CodeSample{
{[]string{`
package main
import (
"encoding/hex"
"fmt"
"golang.org/x/crypto/md4"
)
func main() {
h := md4.New()
h.Write([]byte("test"))
fmt.Println(hex.EncodeToString(h.Sum(nil)))
}
`}, 1, gosec.NewConfig()},
}
23 changes: 23 additions & 0 deletions testutils/g507_samples.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package testutils

import "github.com/securego/gosec/v2"

// SampleCodeG507 - Blocklisted import RIPEMD160
var SampleCodeG507 = []CodeSample{
{[]string{`
package main
import (
"encoding/hex"
"fmt"
"golang.org/x/crypto/ripemd160"
)
func main() {
h := ripemd160.New()
h.Write([]byte("test"))
fmt.Println(hex.EncodeToString(h.Sum(nil)))
}
`}, 1, gosec.NewConfig()},
}

0 comments on commit 9a4a741

Please sign in to comment.