github.com/ethereum/go-ethereum@v1.14.4-0.20240516095835-473ee8fc07a3/cmd/geth/version_check_test.go (about)

     1  // Copyright 2020 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"os"
    23  	"path/filepath"
    24  	"regexp"
    25  	"strconv"
    26  	"strings"
    27  	"testing"
    28  
    29  	"github.com/jedisct1/go-minisign"
    30  )
    31  
    32  func TestVerification(t *testing.T) {
    33  	t.Parallel()
    34  	// Signatures generated with `minisign`. Legacy format, not pre-hashed file.
    35  	t.Run("minisig-legacy", func(t *testing.T) {
    36  		t.Parallel()
    37  		// For this test, the pubkey is in testdata/vcheck/minisign.pub
    38  		// (the privkey is `minisign.sec`, if we want to expand this test. Password 'test' )
    39  		pub := "RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp"
    40  		testVerification(t, pub, "./testdata/vcheck/minisig-sigs/")
    41  	})
    42  	t.Run("minisig-new", func(t *testing.T) {
    43  		t.Parallel()
    44  		// For this test, the pubkey is in testdata/vcheck/minisign.pub
    45  		// (the privkey is `minisign.sec`, if we want to expand this test. Password 'test' )
    46  		// `minisign -S -s ./minisign.sec  -m data.json  -x ./minisig-sigs-new/data.json.minisig`
    47  		pub := "RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp"
    48  		testVerification(t, pub, "./testdata/vcheck/minisig-sigs-new/")
    49  	})
    50  	// Signatures generated with `signify-openbsd`
    51  	t.Run("signify-openbsd", func(t *testing.T) {
    52  		t.Parallel()
    53  		t.Skip("This currently fails, minisign expects 4 lines of data, signify provides only 2")
    54  		// For this test, the pubkey is in testdata/vcheck/signifykey.pub
    55  		// (the privkey is `signifykey.sec`, if we want to expand this test. Password 'test' )
    56  		pub := "RWSKLNhZb0KdATtRT7mZC/bybI3t3+Hv/O2i3ye04Dq9fnT9slpZ1a2/"
    57  		testVerification(t, pub, "./testdata/vcheck/signify-sigs/")
    58  	})
    59  }
    60  
    61  func testVerification(t *testing.T, pubkey, sigdir string) {
    62  	// Data to verify
    63  	data, err := os.ReadFile("./testdata/vcheck/data.json")
    64  	if err != nil {
    65  		t.Fatal(err)
    66  	}
    67  	// Signatures, with and without comments, both trusted and untrusted
    68  	files, err := os.ReadDir(sigdir)
    69  	if err != nil {
    70  		t.Fatal(err)
    71  	}
    72  	if len(files) == 0 {
    73  		t.Fatal("Missing tests")
    74  	}
    75  	for _, f := range files {
    76  		sig, err := os.ReadFile(filepath.Join(sigdir, f.Name()))
    77  		if err != nil {
    78  			t.Fatal(err)
    79  		}
    80  		err = verifySignature([]string{pubkey}, data, sig)
    81  		if err != nil {
    82  			t.Fatal(err)
    83  		}
    84  	}
    85  }
    86  
    87  func versionUint(v string) int {
    88  	mustInt := func(s string) int {
    89  		a, err := strconv.Atoi(s)
    90  		if err != nil {
    91  			panic(v)
    92  		}
    93  		return a
    94  	}
    95  	components := strings.Split(strings.TrimPrefix(v, "v"), ".")
    96  	a := mustInt(components[0])
    97  	b := mustInt(components[1])
    98  	c := mustInt(components[2])
    99  	return a*100*100 + b*100 + c
   100  }
   101  
   102  // TestMatching can be used to check that the regexps are correct
   103  func TestMatching(t *testing.T) {
   104  	t.Parallel()
   105  	data, _ := os.ReadFile("./testdata/vcheck/vulnerabilities.json")
   106  	var vulns []vulnJson
   107  	if err := json.Unmarshal(data, &vulns); err != nil {
   108  		t.Fatal(err)
   109  	}
   110  	check := func(version string) {
   111  		vFull := fmt.Sprintf("Geth/%v-unstable-15339cf1-20201204/linux-amd64/go1.15.4", version)
   112  		for _, vuln := range vulns {
   113  			r, err := regexp.Compile(vuln.Check)
   114  			vulnIntro := versionUint(vuln.Introduced)
   115  			vulnFixed := versionUint(vuln.Fixed)
   116  			current := versionUint(version)
   117  			if err != nil {
   118  				t.Fatal(err)
   119  			}
   120  			if vuln.Name == "Denial of service due to Go CVE-2020-28362" {
   121  				// this one is not tied to geth-versions
   122  				continue
   123  			}
   124  			if vulnIntro <= current && vulnFixed > current {
   125  				// Should be vulnerable
   126  				if !r.MatchString(vFull) {
   127  					t.Errorf("Should be vulnerable, version %v, intro: %v, fixed: %v %v %v",
   128  						version, vuln.Introduced, vuln.Fixed, vuln.Name, vuln.Check)
   129  				}
   130  			} else {
   131  				if r.MatchString(vFull) {
   132  					t.Errorf("Should not be flagged vulnerable, version %v, intro: %v, fixed: %v %v %d %d %d",
   133  						version, vuln.Introduced, vuln.Fixed, vuln.Name, vulnIntro, current, vulnFixed)
   134  				}
   135  			}
   136  		}
   137  	}
   138  	for major := 1; major < 2; major++ {
   139  		for minor := 0; minor < 30; minor++ {
   140  			for patch := 0; patch < 30; patch++ {
   141  				vShort := fmt.Sprintf("v%d.%d.%d", major, minor, patch)
   142  				check(vShort)
   143  			}
   144  		}
   145  	}
   146  }
   147  
   148  func TestGethPubKeysParseable(t *testing.T) {
   149  	t.Parallel()
   150  	for _, pubkey := range gethPubKeys {
   151  		_, err := minisign.NewPublicKey(pubkey)
   152  		if err != nil {
   153  			t.Errorf("Should be parseable")
   154  		}
   155  	}
   156  }
   157  
   158  func TestKeyID(t *testing.T) {
   159  	t.Parallel()
   160  	type args struct {
   161  		id [8]byte
   162  	}
   163  	tests := []struct {
   164  		name string
   165  		args args
   166  		want string
   167  	}{
   168  		{"@holiman key", args{id: extractKeyId(gethPubKeys[0])}, "FB1D084D39BAEC24"},
   169  		{"second key", args{id: extractKeyId(gethPubKeys[1])}, "138B1CA303E51687"},
   170  		{"third key", args{id: extractKeyId(gethPubKeys[2])}, "FD9813B2D2098484"},
   171  	}
   172  	for _, tt := range tests {
   173  		tt := tt
   174  		t.Run(tt.name, func(t *testing.T) {
   175  			t.Parallel()
   176  			if got := keyID(tt.args.id); got != tt.want {
   177  				t.Errorf("keyID() = %v, want %v", got, tt.want)
   178  			}
   179  		})
   180  	}
   181  }
   182  
   183  func extractKeyId(pubkey string) [8]byte {
   184  	p, _ := minisign.NewPublicKey(pubkey)
   185  	return p.KeyId
   186  }