github.com/core-coin/go-core/v2@v2.1.9/cmd/gocore/version_check.go (about)

     1  // Copyright 2020 by the Authors
     2  // This file is part of go-core.
     3  //
     4  // go-core 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-core 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-core. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	"fmt"
    23  	"io/ioutil"
    24  	"net/http"
    25  	"regexp"
    26  	"strings"
    27  
    28  	"github.com/jedisct1/go-minisign"
    29  	"gopkg.in/urfave/cli.v1"
    30  
    31  	"github.com/core-coin/go-core/v2/log"
    32  )
    33  
    34  var gocorePubKeys []string = []string{
    35  	//minisign public key 138B1CA303E51687
    36  	"RWSHFuUDoxyLEzjszuWZI1xStS66QTyXFFZG18uDfO26CuCsbckX1e9J",
    37  	//minisign public key FD9813B2D2098484
    38  	"RWSEhAnSshOY/b+GmaiDkObbCWefsAoavjoLcPjBo1xn71yuOH5I+Lts",
    39  }
    40  
    41  type vulnJson struct {
    42  	Name        string
    43  	Uid         string
    44  	Summary     string
    45  	Description string
    46  	Links       []string
    47  	Introduced  string
    48  	Fixed       string
    49  	Published   string
    50  	Severity    string
    51  	Check       string
    52  	CVE         string
    53  }
    54  
    55  func versionCheck(ctx *cli.Context) error {
    56  	url := ctx.String(VersionCheckUrlFlag.Name)
    57  	version := ctx.String(VersionCheckVersionFlag.Name)
    58  	log.Info("Checking vulnerabilities", "version", version, "url", url)
    59  	return checkCurrent(url, version)
    60  }
    61  
    62  func checkCurrent(url, current string) error {
    63  	var (
    64  		data []byte
    65  		sig  []byte
    66  		err  error
    67  	)
    68  	if data, err = fetch(url); err != nil {
    69  		return fmt.Errorf("could not retrieve data: %w", err)
    70  	}
    71  	if sig, err = fetch(fmt.Sprintf("%v.minisig", url)); err != nil {
    72  		return fmt.Errorf("could not retrieve signature: %w", err)
    73  	}
    74  	if err = verifySignature(gocorePubKeys, data, sig); err != nil {
    75  		return err
    76  	}
    77  	var vulns []vulnJson
    78  	if err = json.Unmarshal(data, &vulns); err != nil {
    79  		return err
    80  	}
    81  	allOk := true
    82  	for _, vuln := range vulns {
    83  		r, err := regexp.Compile(vuln.Check)
    84  		if err != nil {
    85  			return err
    86  		}
    87  		if r.MatchString(current) {
    88  			allOk = false
    89  			fmt.Printf("## Vulnerable to %v (%v)\n\n", vuln.Uid, vuln.Name)
    90  			fmt.Printf("Severity: %v\n", vuln.Severity)
    91  			fmt.Printf("Summary : %v\n", vuln.Summary)
    92  			fmt.Printf("Fixed in: %v\n", vuln.Fixed)
    93  			if len(vuln.CVE) > 0 {
    94  				fmt.Printf("CVE: %v\n", vuln.CVE)
    95  			}
    96  			if len(vuln.Links) > 0 {
    97  				fmt.Printf("References:\n")
    98  				for _, ref := range vuln.Links {
    99  					fmt.Printf("\t- %v\n", ref)
   100  				}
   101  			}
   102  			fmt.Println()
   103  		}
   104  	}
   105  	if allOk {
   106  		fmt.Println("No vulnerabilities found")
   107  	}
   108  	return nil
   109  }
   110  
   111  // fetch makes an HTTP request to the given url and returns the response body
   112  func fetch(url string) ([]byte, error) {
   113  	if filep := strings.TrimPrefix(url, "file://"); filep != url {
   114  		return ioutil.ReadFile(filep)
   115  	}
   116  	res, err := http.Get(url)
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  	defer res.Body.Close()
   121  	body, err := ioutil.ReadAll(res.Body)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  	return body, nil
   126  }
   127  
   128  // verifySignature checks that the sigData is a valid signature of the given
   129  // data, for pubkey GocorePubkey
   130  func verifySignature(pubkeys []string, data, sigdata []byte) error {
   131  	sig, err := minisign.DecodeSignature(string(sigdata))
   132  	if err != nil {
   133  		return err
   134  	}
   135  	// find the used key
   136  	var key *minisign.PublicKey
   137  	for _, pubkey := range pubkeys {
   138  		pub, err := minisign.NewPublicKey(pubkey)
   139  		if err != nil {
   140  			// our pubkeys should be parseable
   141  			return err
   142  		}
   143  		if pub.KeyId != sig.KeyId {
   144  			continue
   145  		}
   146  		key = &pub
   147  		break
   148  	}
   149  	if key == nil {
   150  		log.Info("Signing key not trusted", "keyid", keyID(sig.KeyId), "error", err)
   151  		return errors.New("signature could not be verified")
   152  	}
   153  	if ok, err := key.Verify(data, sig); !ok || err != nil {
   154  		log.Info("Verification failed error", "keyid", keyID(key.KeyId), "error", err)
   155  		return errors.New("signature could not be verified")
   156  	}
   157  	return nil
   158  }
   159  
   160  // keyID turns a binary minisign key ID into a hex string.
   161  // Note: key IDs are printed in reverse byte order.
   162  func keyID(id [8]byte) string {
   163  	var rev [8]byte
   164  	for i := range id {
   165  		rev[len(rev)-1-i] = id[i]
   166  	}
   167  	return fmt.Sprintf("%X", rev)
   168  }