| 
									
										
										
										
											2020-12-04 15:01:47 +01:00
										 |  |  | // Copyright 2020 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of go-ethereum. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package main | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2020-12-09 13:59:24 +01:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2020-12-04 15:01:47 +01:00
										 |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2020-12-09 13:59:24 +01:00
										 |  |  | 	"regexp" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2020-12-04 15:01:47 +01:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestVerification(t *testing.T) { | 
					
						
							|  |  |  | 	// Signatures generated with `minisign` | 
					
						
							|  |  |  | 	t.Run("minisig", func(t *testing.T) { | 
					
						
							|  |  |  | 		// For this test, the pubkey is in testdata/minisign.pub | 
					
						
							|  |  |  | 		// (the privkey is `minisign.sec`, if we want to expand this test. Password 'test' ) | 
					
						
							|  |  |  | 		pub := "RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp" | 
					
						
							|  |  |  | 		testVerification(t, pub, "./testdata/vcheck/minisig-sigs/") | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// Signatures generated with `signify-openbsd` | 
					
						
							|  |  |  | 	t.Run("signify-openbsd", func(t *testing.T) { | 
					
						
							|  |  |  | 		t.Skip("This currently fails, minisign expects 4 lines of data, signify provides only 2") | 
					
						
							|  |  |  | 		// For this test, the pubkey is in testdata/signifykey.pub | 
					
						
							|  |  |  | 		// (the privkey is `signifykey.sec`, if we want to expand this test. Password 'test' ) | 
					
						
							|  |  |  | 		pub := "RWSKLNhZb0KdATtRT7mZC/bybI3t3+Hv/O2i3ye04Dq9fnT9slpZ1a2/" | 
					
						
							|  |  |  | 		testVerification(t, pub, "./testdata/vcheck/signify-sigs/") | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testVerification(t *testing.T, pubkey, sigdir string) { | 
					
						
							|  |  |  | 	// Data to verify | 
					
						
							|  |  |  | 	data, err := ioutil.ReadFile("./testdata/vcheck/data.json") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Signatures, with and without comments, both trusted and untrusted | 
					
						
							|  |  |  | 	files, err := ioutil.ReadDir(sigdir) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, f := range files { | 
					
						
							|  |  |  | 		sig, err := ioutil.ReadFile(filepath.Join(sigdir, f.Name())) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		err = verifySignature([]string{pubkey}, data, sig) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-09 13:59:24 +01:00
										 |  |  | func versionUint(v string) int { | 
					
						
							|  |  |  | 	mustInt := func(s string) int { | 
					
						
							|  |  |  | 		a, err := strconv.Atoi(s) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			panic(v) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return a | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	components := strings.Split(strings.TrimPrefix(v, "v"), ".") | 
					
						
							|  |  |  | 	a := mustInt(components[0]) | 
					
						
							|  |  |  | 	b := mustInt(components[1]) | 
					
						
							|  |  |  | 	c := mustInt(components[2]) | 
					
						
							|  |  |  | 	return a*100*100 + b*100 + c | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestMatching can be used to check that the regexps are correct | 
					
						
							|  |  |  | func TestMatching(t *testing.T) { | 
					
						
							|  |  |  | 	data, _ := ioutil.ReadFile("./testdata/vcheck/vulnerabilities.json") | 
					
						
							| 
									
										
										
										
											2020-12-04 15:01:47 +01:00
										 |  |  | 	var vulns []vulnJson | 
					
						
							|  |  |  | 	if err := json.Unmarshal(data, &vulns); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-12-09 13:59:24 +01:00
										 |  |  | 	check := func(version string) { | 
					
						
							|  |  |  | 		vFull := fmt.Sprintf("Geth/%v-unstable-15339cf1-20201204/linux-amd64/go1.15.4", version) | 
					
						
							|  |  |  | 		for _, vuln := range vulns { | 
					
						
							|  |  |  | 			r, err := regexp.Compile(vuln.Check) | 
					
						
							|  |  |  | 			vulnIntro := versionUint(vuln.Introduced) | 
					
						
							|  |  |  | 			vulnFixed := versionUint(vuln.Fixed) | 
					
						
							|  |  |  | 			current := versionUint(version) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if vuln.Name == "Denial of service due to Go CVE-2020-28362" { | 
					
						
							|  |  |  | 				// this one is not tied to geth-versions | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if vulnIntro <= current && vulnFixed > current { | 
					
						
							|  |  |  | 				// Should be vulnerable | 
					
						
							|  |  |  | 				if !r.MatchString(vFull) { | 
					
						
							|  |  |  | 					t.Errorf("Should be vulnerable, version %v, intro: %v, fixed: %v %v %v", | 
					
						
							|  |  |  | 						version, vuln.Introduced, vuln.Fixed, vuln.Name, vuln.Check) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				if r.MatchString(vFull) { | 
					
						
							|  |  |  | 					t.Errorf("Should not be flagged vulnerable, version %v, intro: %v, fixed: %v %v %d %d %d", | 
					
						
							|  |  |  | 						version, vuln.Introduced, vuln.Fixed, vuln.Name, vulnIntro, current, vulnFixed) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-12-04 15:01:47 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-12-09 13:59:24 +01:00
										 |  |  | 	for major := 1; major < 2; major++ { | 
					
						
							|  |  |  | 		for minor := 0; minor < 30; minor++ { | 
					
						
							|  |  |  | 			for patch := 0; patch < 30; patch++ { | 
					
						
							|  |  |  | 				vShort := fmt.Sprintf("v%d.%d.%d", major, minor, patch) | 
					
						
							|  |  |  | 				check(vShort) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-12-04 15:01:47 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } |