version_check.go 4.4 KB

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