version_check.go 4.4 KB

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