tuf.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // Unless explicitly stated otherwise all files in this repository are licensed
  2. // under the Apache License Version 2.0.
  3. // This product includes software developed at Datadog (https://www.datadoghq.com/).
  4. // Copyright 2022-present Datadog, Inc.
  5. package state
  6. import (
  7. "bytes"
  8. "encoding/json"
  9. "fmt"
  10. "io"
  11. "strconv"
  12. "strings"
  13. "github.com/DataDog/go-tuf/client"
  14. "github.com/DataDog/go-tuf/data"
  15. "github.com/DataDog/go-tuf/util"
  16. "github.com/DataDog/go-tuf/verify"
  17. )
  18. type tufRootsClient struct {
  19. rootClient *client.Client
  20. rootLocalStore client.LocalStore
  21. rootRemoteStore *rootClientRemoteStore
  22. }
  23. func newTufRootsClient(root []byte) (*tufRootsClient, error) {
  24. rootLocalStore := client.MemoryLocalStore()
  25. rootRemoteStore := &rootClientRemoteStore{}
  26. rootClient := client.NewClient(rootLocalStore, rootRemoteStore)
  27. err := rootClient.InitLocal(root)
  28. if err != nil {
  29. return nil, err
  30. }
  31. return &tufRootsClient{
  32. rootClient: rootClient,
  33. rootLocalStore: rootLocalStore,
  34. rootRemoteStore: rootRemoteStore,
  35. }, nil
  36. }
  37. func (trc *tufRootsClient) clone() (*tufRootsClient, error) {
  38. root, err := trc.latestRootRaw()
  39. if err != nil {
  40. return nil, err
  41. }
  42. return newTufRootsClient(root)
  43. }
  44. func (trc *tufRootsClient) updateRoots(newRoots [][]byte) error {
  45. if len(newRoots) == 0 {
  46. return nil
  47. }
  48. trc.rootRemoteStore.roots = append(trc.rootRemoteStore.roots, newRoots...)
  49. return trc.rootClient.UpdateRoots()
  50. }
  51. func (trc *tufRootsClient) latestRoot() (*data.Root, error) {
  52. raw, err := trc.latestRootRaw()
  53. if err != nil {
  54. return nil, err
  55. }
  56. return unsafeUnmarshalRoot(raw)
  57. }
  58. func (trc *tufRootsClient) latestRootRaw() ([]byte, error) {
  59. metas, err := trc.rootLocalStore.GetMeta()
  60. if err != nil {
  61. return nil, err
  62. }
  63. rawRoot := metas["root.json"]
  64. return rawRoot, nil
  65. }
  66. func (trc *tufRootsClient) validateTargets(rawTargets []byte) (*data.Targets, error) {
  67. root, err := trc.latestRoot()
  68. if err != nil {
  69. return nil, err
  70. }
  71. db := verify.NewDB()
  72. for _, key := range root.Keys {
  73. for _, id := range key.IDs() {
  74. if err := db.AddKey(id, key); err != nil {
  75. return nil, err
  76. }
  77. }
  78. }
  79. targetsRole, hasRoleTargets := root.Roles["targets"]
  80. if !hasRoleTargets {
  81. return nil, fmt.Errorf("root is missing a targets role")
  82. }
  83. role := &data.Role{Threshold: targetsRole.Threshold, KeyIDs: targetsRole.KeyIDs}
  84. if err := db.AddRole("targets", role); err != nil {
  85. return nil, fmt.Errorf("could not add targets role to db: %v", err)
  86. }
  87. var targets data.Targets
  88. err = db.Unmarshal(rawTargets, &targets, "targets", 0)
  89. if err != nil {
  90. return nil, err
  91. }
  92. return &targets, nil
  93. }
  94. type rootClientRemoteStore struct {
  95. roots [][]byte
  96. }
  97. func (s *rootClientRemoteStore) GetMeta(name string) (stream io.ReadCloser, size int64, err error) {
  98. metaPath, err := parseMetaPath(name)
  99. if err != nil {
  100. return nil, 0, err
  101. }
  102. if metaPath.role != roleRoot || !metaPath.versionSet {
  103. return nil, 0, client.ErrNotFound{File: name}
  104. }
  105. for _, root := range s.roots {
  106. parsedRoot, err := unsafeUnmarshalRoot(root)
  107. if err != nil {
  108. return nil, 0, err
  109. }
  110. if parsedRoot.Version == metaPath.version {
  111. return io.NopCloser(bytes.NewReader(root)), int64(len(root)), nil
  112. }
  113. }
  114. return nil, 0, client.ErrNotFound{File: name}
  115. }
  116. func (s *rootClientRemoteStore) GetTarget(path string) (stream io.ReadCloser, size int64, err error) {
  117. return nil, 0, client.ErrNotFound{File: path}
  118. }
  119. type role string
  120. const (
  121. roleRoot role = "root"
  122. )
  123. type metaPath struct {
  124. role role
  125. version int64
  126. versionSet bool
  127. }
  128. func parseMetaPath(rawMetaPath string) (metaPath, error) {
  129. splitRawMetaPath := strings.SplitN(rawMetaPath, ".", 3)
  130. if len(splitRawMetaPath) != 2 && len(splitRawMetaPath) != 3 {
  131. return metaPath{}, fmt.Errorf("invalid metadata path '%s'", rawMetaPath)
  132. }
  133. suffix := splitRawMetaPath[len(splitRawMetaPath)-1]
  134. if suffix != "json" {
  135. return metaPath{}, fmt.Errorf("invalid metadata path (suffix) '%s'", rawMetaPath)
  136. }
  137. rawRole := splitRawMetaPath[len(splitRawMetaPath)-2]
  138. if rawRole == "" {
  139. return metaPath{}, fmt.Errorf("invalid metadata path (role) '%s'", rawMetaPath)
  140. }
  141. if len(splitRawMetaPath) == 2 {
  142. return metaPath{
  143. role: role(rawRole),
  144. }, nil
  145. }
  146. rawVersion, err := strconv.ParseInt(splitRawMetaPath[0], 10, 64)
  147. if err != nil {
  148. return metaPath{}, fmt.Errorf("invalid metadata path (version) '%s': %w", rawMetaPath, err)
  149. }
  150. return metaPath{
  151. role: role(rawRole),
  152. version: rawVersion,
  153. versionSet: true,
  154. }, nil
  155. }
  156. func validateTargetFileHash(targetMeta data.TargetFileMeta, targetFile []byte) error {
  157. if len(targetMeta.HashAlgorithms()) == 0 {
  158. return fmt.Errorf("target file has no hash")
  159. }
  160. generatedMeta, err := util.GenerateFileMeta(bytes.NewBuffer(targetFile), targetMeta.HashAlgorithms()...)
  161. if err != nil {
  162. return err
  163. }
  164. err = util.FileMetaEqual(targetMeta.FileMeta, generatedMeta)
  165. if err != nil {
  166. return err
  167. }
  168. return nil
  169. }
  170. func unsafeUnmarshalRoot(raw []byte) (*data.Root, error) {
  171. var signedRoot data.Signed
  172. err := json.Unmarshal(raw, &signedRoot)
  173. if err != nil {
  174. return nil, err
  175. }
  176. var root data.Root
  177. err = json.Unmarshal(signedRoot.Signed, &root)
  178. if err != nil {
  179. return nil, err
  180. }
  181. return &root, err
  182. }
  183. func unsafeUnmarshalTargets(raw []byte) (*data.Targets, error) {
  184. var signedTargets data.Signed
  185. err := json.Unmarshal(raw, &signedTargets)
  186. if err != nil {
  187. return nil, err
  188. }
  189. var targets data.Targets
  190. err = json.Unmarshal(signedTargets.Signed, &targets)
  191. if err != nil {
  192. return nil, err
  193. }
  194. return &targets, err
  195. }
  196. func extractRootVersion(raw []byte) (int64, error) {
  197. root, err := unsafeUnmarshalRoot(raw)
  198. if err != nil {
  199. return 0, err
  200. }
  201. return root.Version, nil
  202. }