client.go 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. package client
  2. import (
  3. "bytes"
  4. "encoding/hex"
  5. "encoding/json"
  6. "io"
  7. "io/ioutil"
  8. "github.com/DataDog/go-tuf/data"
  9. "github.com/DataDog/go-tuf/internal/roles"
  10. "github.com/DataDog/go-tuf/util"
  11. "github.com/DataDog/go-tuf/verify"
  12. )
  13. const (
  14. // This is the upper limit in bytes we will use to limit the download
  15. // size of the root/timestamp roles, since we might not don't know how
  16. // big it is.
  17. defaultRootDownloadLimit = 512000
  18. defaultTimestampDownloadLimit = 16384
  19. defaultMaxDelegations = 32
  20. defaultMaxRootRotations = 1e3
  21. )
  22. // LocalStore is local storage for downloaded top-level metadata.
  23. type LocalStore interface {
  24. io.Closer
  25. // GetMeta returns top-level metadata from local storage. The keys are
  26. // in the form `ROLE.json`, with ROLE being a valid top-level role.
  27. GetMeta() (map[string]json.RawMessage, error)
  28. // SetMeta persists the given top-level metadata in local storage, the
  29. // name taking the same format as the keys returned by GetMeta.
  30. SetMeta(name string, meta json.RawMessage) error
  31. // DeleteMeta deletes a given metadata.
  32. DeleteMeta(name string) error
  33. }
  34. // RemoteStore downloads top-level metadata and target files from a remote
  35. // repository.
  36. type RemoteStore interface {
  37. // GetMeta downloads the given metadata from remote storage.
  38. //
  39. // `name` is the filename of the metadata (e.g. "root.json")
  40. //
  41. // `err` is ErrNotFound if the given file does not exist.
  42. //
  43. // `size` is the size of the stream, -1 indicating an unknown length.
  44. GetMeta(name string) (stream io.ReadCloser, size int64, err error)
  45. // GetTarget downloads the given target file from remote storage.
  46. //
  47. // `path` is the path of the file relative to the root of the remote
  48. // targets directory (e.g. "/path/to/file.txt").
  49. //
  50. // `err` is ErrNotFound if the given file does not exist.
  51. //
  52. // `size` is the size of the stream, -1 indicating an unknown length.
  53. GetTarget(path string) (stream io.ReadCloser, size int64, err error)
  54. }
  55. // Client provides methods for fetching updates from a remote repository and
  56. // downloading remote target files.
  57. type Client struct {
  58. local LocalStore
  59. remote RemoteStore
  60. // The following four fields represent the versions of metatdata either
  61. // from local storage or from recently downloaded metadata
  62. rootVer int64
  63. targetsVer int64
  64. snapshotVer int64
  65. timestampVer int64
  66. // targets is the list of available targets, either from local storage
  67. // or from recently downloaded targets metadata
  68. targets data.TargetFiles
  69. // localMeta is the raw metadata from local storage and is used to
  70. // check whether remote metadata is present locally
  71. localMeta map[string]json.RawMessage
  72. // db is a key DB used for verifying metadata
  73. db *verify.DB
  74. // consistentSnapshot indicates whether the remote storage is using
  75. // consistent snapshots (as specified in root.json)
  76. consistentSnapshot bool
  77. // MaxDelegations limits by default the number of delegations visited for any
  78. // target
  79. MaxDelegations int
  80. // MaxRootRotations limits the number of downloaded roots in 1.0.19 root updater
  81. MaxRootRotations int
  82. }
  83. func NewClient(local LocalStore, remote RemoteStore) *Client {
  84. return &Client{
  85. local: local,
  86. remote: remote,
  87. MaxDelegations: defaultMaxDelegations,
  88. MaxRootRotations: defaultMaxRootRotations,
  89. }
  90. }
  91. // Init initializes a local repository.
  92. //
  93. // The latest root.json is fetched from remote storage, verified using rootKeys
  94. // and threshold, and then saved in local storage. It is expected that rootKeys
  95. // were securely distributed with the software being updated.
  96. //
  97. // Deprecated: Use c.InitLocal and c.Update to initialize a local repository.
  98. func (c *Client) Init(rootKeys []*data.PublicKey, threshold int) error {
  99. if len(rootKeys) < threshold {
  100. return ErrInsufficientKeys
  101. }
  102. rootJSON, err := c.downloadMetaUnsafe("root.json", defaultRootDownloadLimit)
  103. if err != nil {
  104. return err
  105. }
  106. // create a new key database, and add all the public `rootKeys` to it.
  107. c.db = verify.NewDB()
  108. rootKeyIDs := make([]string, 0, len(rootKeys))
  109. for _, key := range rootKeys {
  110. for _, id := range key.IDs() {
  111. rootKeyIDs = append(rootKeyIDs, id)
  112. if err := c.db.AddKey(id, key); err != nil {
  113. return err
  114. }
  115. }
  116. }
  117. // add a mock "root" role that trusts the passed in key ids. These keys
  118. // will be used to verify the `root.json` we just fetched.
  119. role := &data.Role{Threshold: threshold, KeyIDs: rootKeyIDs}
  120. if err := c.db.AddRole("root", role); err != nil {
  121. return err
  122. }
  123. // verify that the new root is valid.
  124. if err := c.decodeRoot(rootJSON); err != nil {
  125. return err
  126. }
  127. return c.local.SetMeta("root.json", rootJSON)
  128. }
  129. // InitLocal initializes a local repository from root metadata.
  130. //
  131. // The root's keys are extracted from the root and saved in local storage.
  132. // Root expiration is not checked.
  133. // It is expected that rootJSON was securely distributed with the software
  134. // being updated.
  135. func (c *Client) InitLocal(rootJSON []byte) error {
  136. err := c.loadAndVerifyRootMeta(rootJSON, true /*ignoreExpiredCheck*/)
  137. if err != nil {
  138. return err
  139. }
  140. return c.local.SetMeta("root.json", rootJSON)
  141. }
  142. // Update downloads and verifies remote metadata and returns updated targets.
  143. // It always performs root update (5.2 and 5.3) section of the v1.0.19 spec.
  144. //
  145. // https://DataDog.github.io/specification/v1.0.19/index.html#load-trusted-root
  146. func (c *Client) Update() (data.TargetFiles, error) {
  147. if err := c.UpdateRoots(); err != nil {
  148. if _, ok := err.(verify.ErrExpired); ok {
  149. // For backward compatibility, we wrap the ErrExpired inside
  150. // ErrDecodeFailed.
  151. return nil, ErrDecodeFailed{"root.json", err}
  152. }
  153. return nil, err
  154. }
  155. // Load trusted metadata files, if any, and verify them against the latest root
  156. c.getLocalMeta()
  157. // 5.4.1 - Download the timestamp metadata
  158. timestampJSON, err := c.downloadMetaUnsafe("timestamp.json", defaultTimestampDownloadLimit)
  159. if err != nil {
  160. return nil, err
  161. }
  162. // 5.4.(2,3 and 4) - Verify timestamp against various attacks
  163. // Returns the extracted snapshot metadata
  164. snapshotMeta, err := c.decodeTimestamp(timestampJSON)
  165. if err != nil {
  166. return nil, err
  167. }
  168. // 5.4.5 - Persist the timestamp metadata
  169. if err := c.local.SetMeta("timestamp.json", timestampJSON); err != nil {
  170. return nil, err
  171. }
  172. // 5.5.1 - Download snapshot metadata
  173. // 5.5.2 and 5.5.4 - Check against timestamp role's snapshot hash and version
  174. snapshotJSON, err := c.downloadMetaFromTimestamp("snapshot.json", snapshotMeta)
  175. if err != nil {
  176. return nil, err
  177. }
  178. // 5.5.(3,5 and 6) - Verify snapshot against various attacks
  179. // Returns the extracted metadata files
  180. snapshotMetas, err := c.decodeSnapshot(snapshotJSON)
  181. if err != nil {
  182. return nil, err
  183. }
  184. // 5.5.7 - Persist snapshot metadata
  185. if err := c.local.SetMeta("snapshot.json", snapshotJSON); err != nil {
  186. return nil, err
  187. }
  188. // If we don't have the targets.json, download it, determine updated
  189. // targets and save targets.json in local storage
  190. var updatedTargets data.TargetFiles
  191. targetsMeta := snapshotMetas["targets.json"]
  192. if !c.hasMetaFromSnapshot("targets.json", targetsMeta) {
  193. // 5.6.1 - Download the top-level targets metadata file
  194. // 5.6.2 and 5.6.4 - Check against snapshot role's targets hash and version
  195. targetsJSON, err := c.downloadMetaFromSnapshot("targets.json", targetsMeta)
  196. if err != nil {
  197. return nil, err
  198. }
  199. // 5.6.(3 and 5) - Verify signatures and check against freeze attack
  200. updatedTargets, err = c.decodeTargets(targetsJSON)
  201. if err != nil {
  202. return nil, err
  203. }
  204. // 5.6.6 - Persist targets metadata
  205. if err := c.local.SetMeta("targets.json", targetsJSON); err != nil {
  206. return nil, err
  207. }
  208. }
  209. return updatedTargets, nil
  210. }
  211. func (c *Client) UpdateRoots() error {
  212. // https://DataDog.github.io/specification/v1.0.19/index.html#load-trusted-root
  213. // 5.2 Load the trusted root metadata file. We assume that a good,
  214. // trusted copy of this file was shipped with the package manager
  215. // or software updater using an out-of-band process.
  216. if err := c.loadAndVerifyLocalRootMeta( /*ignoreExpiredCheck=*/ true); err != nil {
  217. return err
  218. }
  219. m, err := c.local.GetMeta()
  220. if err != nil {
  221. return err
  222. }
  223. type KeyInfo struct {
  224. KeyIDs map[string]bool
  225. Threshold int
  226. }
  227. // Prepare for 5.3.11: If the timestamp and / or snapshot keys have been rotated,
  228. // then delete the trusted timestamp and snapshot metadata files.
  229. getKeyInfo := func(role string) KeyInfo {
  230. keyIDs := make(map[string]bool)
  231. for k := range c.db.GetRole(role).KeyIDs {
  232. keyIDs[k] = true
  233. }
  234. return KeyInfo{keyIDs, c.db.GetRole(role).Threshold}
  235. }
  236. // The nonRootKeyInfo looks like this:
  237. // {
  238. // "timestamp": {KeyIDs={"KEYID1": true, "KEYID2": true}, Threshold=2},
  239. // "snapshot": {KeyIDs={"KEYID3": true}, Threshold=1},
  240. // "targets": {KeyIDs={"KEYID4": true, "KEYID5": true, "KEYID6": true}, Threshold=1}
  241. // }
  242. nonRootKeyInfo := map[string]KeyInfo{"timestamp": {}, "snapshot": {}, "targets": {}}
  243. for k := range nonRootKeyInfo {
  244. nonRootKeyInfo[k] = getKeyInfo(k)
  245. }
  246. // 5.3.1 Temorarily turn on the consistent snapshots in order to download
  247. // versioned root metadata files as described next.
  248. consistentSnapshot := c.consistentSnapshot
  249. c.consistentSnapshot = true
  250. nRootMetadata := m["root.json"]
  251. // https://DataDog.github.io/specification/v1.0.19/index.html#update-root
  252. // 5.3.1 Since it may now be signed using entirely different keys,
  253. // the client MUST somehow be able to establish a trusted line of
  254. // continuity to the latest set of keys (see § 6.1 Key
  255. // management and migration). To do so, the client MUST
  256. // download intermediate root metadata files, until the
  257. // latest available one is reached. Therefore, it MUST
  258. // temporarily turn on consistent snapshots in order to
  259. // download versioned root metadata files as described next.
  260. // This loop returns on error or breaks after downloading the lastest root metadata.
  261. // 5.3.2 Let N denote the version number of the trusted root metadata file.
  262. for i := 0; i < c.MaxRootRotations; i++ {
  263. // 5.3.3 Try downloading version nPlusOne of the root metadata file.
  264. // NOTE: as a side effect, we do update c.rootVer to nPlusOne between iterations.
  265. nPlusOne := c.rootVer + 1
  266. nPlusOneRootPath := util.VersionedPath("root.json", nPlusOne)
  267. nPlusOneRootMetadata, err := c.downloadMetaUnsafe(nPlusOneRootPath, defaultRootDownloadLimit)
  268. if err != nil {
  269. if _, ok := err.(ErrMissingRemoteMetadata); ok {
  270. // stop when the next root can't be downloaded
  271. break
  272. }
  273. return err
  274. }
  275. // 5.3.4 Check for an arbitrary software attack.
  276. // 5.3.4.1 Check that N signed N+1
  277. nPlusOneRootMetadataSigned, err := c.verifyRoot(nRootMetadata, nPlusOneRootMetadata)
  278. if err != nil {
  279. return err
  280. }
  281. // 5.3.4.2 check that N+1 signed itself.
  282. if _, err := c.verifyRoot(nPlusOneRootMetadata, nPlusOneRootMetadata); err != nil {
  283. // 5.3.6 Note that the expiration of the new (intermediate) root
  284. // metadata file does not matter yet, because we will check for
  285. // it in step 5.3.10.
  286. return err
  287. }
  288. // 5.3.5 Check for a rollback attack. Here, we check that nPlusOneRootMetadataSigned.version == nPlusOne.
  289. if nPlusOneRootMetadataSigned.Version != nPlusOne {
  290. return verify.ErrWrongVersion{
  291. Given: nPlusOneRootMetadataSigned.Version,
  292. Expected: nPlusOne,
  293. }
  294. }
  295. // 5.3.7 Set the trusted root metadata file to the new root metadata file.
  296. c.rootVer = nPlusOneRootMetadataSigned.Version
  297. // NOTE: following up on 5.3.1, we want to always have consistent snapshots on for the duration
  298. // of root rotation. AFTER the rotation is over, we will set it to the value of the last root.
  299. consistentSnapshot = nPlusOneRootMetadataSigned.ConsistentSnapshot
  300. // 5.3.8 Persist root metadata. The client MUST write the file to non-volatile storage as FILENAME.EXT (e.g. root.json).
  301. // NOTE: Internally, setMeta stores metadata in LevelDB in a persistent manner.
  302. if err := c.local.SetMeta("root.json", nPlusOneRootMetadata); err != nil {
  303. return err
  304. }
  305. nRootMetadata = nPlusOneRootMetadata
  306. // 5.3.9 Repeat steps 5.3.2 to 5.3.9
  307. } // End of the for loop.
  308. // 5.3.10 Check for a freeze attack.
  309. // NOTE: This will check for any, including freeze, attack.
  310. if err := c.loadAndVerifyLocalRootMeta( /*ignoreExpiredCheck=*/ false); err != nil {
  311. return err
  312. }
  313. countDeleted := func(s1 map[string]bool, s2 map[string]bool) int {
  314. c := 0
  315. for k := range s1 {
  316. if _, ok := s2[k]; !ok {
  317. c++
  318. }
  319. }
  320. return c
  321. }
  322. // 5.3.11 To recover from fast-forward attack, certain metadata files need
  323. // to be deleted if a threshold of keys are revoked.
  324. // List of metadata that should be deleted per role if a threshold of keys
  325. // are revoked:
  326. // (based on the ongoing PR: https://github.com/mnm678/specification/tree/e50151d9df632299ddea364c4f44fe8ca9c10184)
  327. // timestamp -> delete timestamp.json
  328. // snapshot -> delete timestamp.json and snapshot.json
  329. // targets -> delete snapshot.json and targets.json
  330. //
  331. // nonRootKeyInfo contains the keys and thresholds from root.json
  332. // that were on disk before the root update process begins.
  333. for topLevelRolename := range nonRootKeyInfo {
  334. // ki contains the keys and thresholds from the latest downloaded root.json.
  335. ki := getKeyInfo(topLevelRolename)
  336. if countDeleted(nonRootKeyInfo[topLevelRolename].KeyIDs, ki.KeyIDs) >= nonRootKeyInfo[topLevelRolename].Threshold {
  337. deleteMeta := map[string][]string{
  338. "timestamp": {"timestamp.json"},
  339. "snapshot": {"timestamp.json", "snapshot.json"},
  340. "targets": {"snapshot.json", "targets.json"},
  341. }
  342. for _, r := range deleteMeta[topLevelRolename] {
  343. c.local.DeleteMeta(r)
  344. }
  345. }
  346. }
  347. // 5.3.12 Set whether consistent snapshots are used as per the trusted root metadata file.
  348. c.consistentSnapshot = consistentSnapshot
  349. return nil
  350. }
  351. // getLocalMeta decodes and verifies metadata from local storage.
  352. // The verification of local files is purely for consistency, if an attacker
  353. // has compromised the local storage, there is no guarantee it can be trusted.
  354. // Before trying to load the metadata files, it clears the in-memory copy of the local metadata.
  355. // This is to insure that all of the loaded metadata files at the end are indeed verified by the latest root.
  356. // If some of the metadata files fail to load it will proceed with trying to load the rest,
  357. // but still return an error at the end, if such occurred. Otherwise returns nil.
  358. func (c *Client) getLocalMeta() error {
  359. var retErr error
  360. loadFailed := false
  361. // Clear the in-memory copy of the local metadata. The goal is to reload and take into account
  362. // only the metadata files that are verified by the latest root. Otherwise, their content should
  363. // be ignored.
  364. c.localMeta = make(map[string]json.RawMessage)
  365. // Load the latest root meta
  366. if err := c.loadAndVerifyLocalRootMeta( /*ignoreExpiredCheck=*/ false); err != nil {
  367. return err
  368. }
  369. // Load into memory the existing meta, if any, from the local storage
  370. meta, err := c.local.GetMeta()
  371. if err != nil {
  372. return nil
  373. }
  374. // Verify the top-level metadata (timestamp, snapshot and targets) against the latest root and load it, if okay
  375. if timestampJSON, ok := meta["timestamp.json"]; ok {
  376. timestamp := &data.Timestamp{}
  377. if err := c.db.UnmarshalTrusted(timestampJSON, timestamp, "timestamp"); err != nil {
  378. loadFailed = true
  379. retErr = err
  380. } else {
  381. c.localMeta["timestamp.json"] = meta["timestamp.json"]
  382. c.timestampVer = timestamp.Version
  383. }
  384. }
  385. if snapshotJSON, ok := meta["snapshot.json"]; ok {
  386. snapshot := &data.Snapshot{}
  387. if err := c.db.UnmarshalTrusted(snapshotJSON, snapshot, "snapshot"); err != nil {
  388. loadFailed = true
  389. retErr = err
  390. } else {
  391. c.localMeta["snapshot.json"] = meta["snapshot.json"]
  392. c.snapshotVer = snapshot.Version
  393. }
  394. }
  395. if targetsJSON, ok := meta["targets.json"]; ok {
  396. targets := &data.Targets{}
  397. if err := c.db.UnmarshalTrusted(targetsJSON, targets, "targets"); err != nil {
  398. loadFailed = true
  399. retErr = err
  400. } else {
  401. c.localMeta["targets.json"] = meta["targets.json"]
  402. c.targetsVer = targets.Version
  403. // FIXME(TUF-0.9) temporarily support files with leading path separators.
  404. // c.targets = targets.Targets
  405. c.loadTargets(targets.Targets)
  406. }
  407. }
  408. for fileName := range meta {
  409. if roles.IsDelegatedTargetsManifest(fileName) {
  410. c.localMeta[fileName] = meta[fileName]
  411. }
  412. }
  413. if loadFailed {
  414. // If any of the metadata failed to be verified, return the reason for that failure
  415. return retErr
  416. }
  417. return nil
  418. }
  419. // loadAndVerifyLocalRootMeta decodes and verifies root metadata from
  420. // local storage and loads the top-level keys. This method first clears
  421. // the DB for top-level keys and then loads the new keys.
  422. func (c *Client) loadAndVerifyLocalRootMeta(ignoreExpiredCheck bool) error {
  423. meta, err := c.local.GetMeta()
  424. if err != nil {
  425. return err
  426. }
  427. rootJSON, ok := meta["root.json"]
  428. if !ok {
  429. return ErrNoRootKeys
  430. }
  431. return c.loadAndVerifyRootMeta(rootJSON, ignoreExpiredCheck)
  432. }
  433. // loadAndVerifyRootMeta decodes and verifies root metadata and loads the top-level keys.
  434. // This method first clears the DB for top-level keys and then loads the new keys.
  435. func (c *Client) loadAndVerifyRootMeta(rootJSON []byte, ignoreExpiredCheck bool) error {
  436. // unmarshal root.json without verifying as we need the root
  437. // keys first
  438. s := &data.Signed{}
  439. if err := json.Unmarshal(rootJSON, s); err != nil {
  440. return err
  441. }
  442. root := &data.Root{}
  443. if err := json.Unmarshal(s.Signed, root); err != nil {
  444. return err
  445. }
  446. ndb := verify.NewDB()
  447. for id, k := range root.Keys {
  448. if err := ndb.AddKey(id, k); err != nil {
  449. // TUF is considering in TAP-12 removing the
  450. // requirement that the keyid hash algorithm be derived
  451. // from the public key. So to be forwards compatible,
  452. // we ignore `ErrWrongID` errors.
  453. //
  454. // TAP-12: https://github.com/DataDog/taps/blob/master/tap12.md
  455. if _, ok := err.(verify.ErrWrongID); !ok {
  456. return err
  457. }
  458. }
  459. }
  460. for name, role := range root.Roles {
  461. if err := ndb.AddRole(name, role); err != nil {
  462. return err
  463. }
  464. }
  465. // Any trusted local root metadata version must be greater than 0.
  466. if ignoreExpiredCheck {
  467. if err := ndb.VerifyIgnoreExpiredCheck(s, "root", 0); err != nil {
  468. return err
  469. }
  470. } else {
  471. if err := ndb.Verify(s, "root", 0); err != nil {
  472. return err
  473. }
  474. }
  475. c.consistentSnapshot = root.ConsistentSnapshot
  476. c.rootVer = root.Version
  477. c.db = ndb
  478. return nil
  479. }
  480. // verifyRoot verifies Signed section of the bJSON
  481. // using verification keys in aJSON.
  482. func (c *Client) verifyRoot(aJSON []byte, bJSON []byte) (*data.Root, error) {
  483. aSigned := &data.Signed{}
  484. if err := json.Unmarshal(aJSON, aSigned); err != nil {
  485. return nil, err
  486. }
  487. aRoot := &data.Root{}
  488. if err := json.Unmarshal(aSigned.Signed, aRoot); err != nil {
  489. return nil, err
  490. }
  491. bSigned := &data.Signed{}
  492. if err := json.Unmarshal(bJSON, bSigned); err != nil {
  493. return nil, err
  494. }
  495. bRoot := &data.Root{}
  496. if err := json.Unmarshal(bSigned.Signed, bRoot); err != nil {
  497. return nil, err
  498. }
  499. ndb := verify.NewDB()
  500. for id, k := range aRoot.Keys {
  501. if err := ndb.AddKey(id, k); err != nil {
  502. // TUF is considering in TAP-12 removing the
  503. // requirement that the keyid hash algorithm be derived
  504. // from the public key. So to be forwards compatible,
  505. // we ignore `ErrWrongID` errors.
  506. //
  507. // TAP-12: https://github.com/DataDog/taps/blob/master/tap12.md
  508. if _, ok := err.(verify.ErrWrongID); !ok {
  509. return nil, err
  510. }
  511. }
  512. }
  513. for name, role := range aRoot.Roles {
  514. if err := ndb.AddRole(name, role); err != nil {
  515. return nil, err
  516. }
  517. }
  518. if err := ndb.VerifySignatures(bSigned, "root"); err != nil {
  519. return nil, err
  520. }
  521. return bRoot, nil
  522. }
  523. // FIXME(TUF-0.9) TUF is considering removing support for target files starting
  524. // with a leading path separator. In order to be backwards compatible, we'll
  525. // just remove leading separators for now.
  526. func (c *Client) loadTargets(targets data.TargetFiles) {
  527. c.targets = make(data.TargetFiles)
  528. for name, meta := range targets {
  529. c.targets[name] = meta
  530. c.targets[util.NormalizeTarget(name)] = meta
  531. }
  532. }
  533. // downloadMetaUnsafe downloads top-level metadata from remote storage without
  534. // verifying it's length and hashes (used for example to download timestamp.json
  535. // which has unknown size). It will download at most maxMetaSize bytes.
  536. func (c *Client) downloadMetaUnsafe(name string, maxMetaSize int64) ([]byte, error) {
  537. r, size, err := c.remote.GetMeta(name)
  538. if err != nil {
  539. if IsNotFound(err) {
  540. return nil, ErrMissingRemoteMetadata{name}
  541. }
  542. return nil, ErrDownloadFailed{name, err}
  543. }
  544. defer r.Close()
  545. // return ErrMetaTooLarge if the reported size is greater than maxMetaSize
  546. if size > maxMetaSize {
  547. return nil, ErrMetaTooLarge{name, size, maxMetaSize}
  548. }
  549. // although the size has been checked above, use a LimitReader in case
  550. // the reported size is inaccurate, or size is -1 which indicates an
  551. // unknown length
  552. return ioutil.ReadAll(io.LimitReader(r, maxMetaSize))
  553. }
  554. // remoteGetFunc is the type of function the download method uses to download
  555. // remote files
  556. type remoteGetFunc func(string) (io.ReadCloser, int64, error)
  557. // downloadHashed tries to download the hashed prefixed version of the file.
  558. func (c *Client) downloadHashed(file string, get remoteGetFunc, hashes data.Hashes) (io.ReadCloser, int64, error) {
  559. // try each hashed path in turn, and either return the contents,
  560. // try the next one if a 404 is returned, or return an error
  561. for _, path := range util.HashedPaths(file, hashes) {
  562. r, size, err := get(path)
  563. if err != nil {
  564. if IsNotFound(err) {
  565. continue
  566. }
  567. return nil, 0, err
  568. }
  569. return r, size, nil
  570. }
  571. return nil, 0, ErrNotFound{file}
  572. }
  573. // download downloads the given target file from remote storage using the get
  574. // function, adding hashes to the path if consistent snapshots are in use
  575. func (c *Client) downloadTarget(file string, get remoteGetFunc, hashes data.Hashes) (io.ReadCloser, int64, error) {
  576. if c.consistentSnapshot {
  577. return c.downloadHashed(file, get, hashes)
  578. } else {
  579. return get(file)
  580. }
  581. }
  582. // downloadVersionedMeta downloads top-level metadata from remote storage and
  583. // verifies it using the given file metadata.
  584. func (c *Client) downloadMeta(name string, version int64, m data.FileMeta) ([]byte, error) {
  585. r, size, err := func() (io.ReadCloser, int64, error) {
  586. if c.consistentSnapshot {
  587. path := util.VersionedPath(name, version)
  588. r, size, err := c.remote.GetMeta(path)
  589. if err == nil {
  590. return r, size, nil
  591. }
  592. return nil, 0, err
  593. } else {
  594. return c.remote.GetMeta(name)
  595. }
  596. }()
  597. if err != nil {
  598. if IsNotFound(err) {
  599. return nil, ErrMissingRemoteMetadata{name}
  600. }
  601. return nil, err
  602. }
  603. defer r.Close()
  604. // return ErrWrongSize if the reported size is known and incorrect
  605. var stream io.Reader
  606. if m.Length != 0 {
  607. if size >= 0 && size != m.Length {
  608. return nil, ErrWrongSize{name, size, m.Length}
  609. }
  610. // wrap the data in a LimitReader so we download at most m.Length bytes
  611. stream = io.LimitReader(r, m.Length)
  612. } else {
  613. stream = r
  614. }
  615. return ioutil.ReadAll(stream)
  616. }
  617. func (c *Client) downloadMetaFromSnapshot(name string, m data.SnapshotFileMeta) ([]byte, error) {
  618. b, err := c.downloadMeta(name, m.Version, m.FileMeta)
  619. if err != nil {
  620. return nil, err
  621. }
  622. meta, err := util.GenerateSnapshotFileMeta(bytes.NewReader(b), m.HashAlgorithms()...)
  623. if err != nil {
  624. return nil, err
  625. }
  626. // 5.6.2 and 5.6.4 - Check against snapshot role's targets hash and version
  627. if err := util.SnapshotFileMetaEqual(meta, m); err != nil {
  628. return nil, ErrDownloadFailed{name, err}
  629. }
  630. return b, nil
  631. }
  632. func (c *Client) downloadMetaFromTimestamp(name string, m data.TimestampFileMeta) ([]byte, error) {
  633. b, err := c.downloadMeta(name, m.Version, m.FileMeta)
  634. if err != nil {
  635. return nil, err
  636. }
  637. meta, err := util.GenerateTimestampFileMeta(bytes.NewReader(b), m.HashAlgorithms()...)
  638. if err != nil {
  639. return nil, err
  640. }
  641. // 5.5.2 and 5.5.4 - Check against timestamp role's snapshot hash and version
  642. if err := util.TimestampFileMetaEqual(meta, m); err != nil {
  643. return nil, ErrDownloadFailed{name, err}
  644. }
  645. return b, nil
  646. }
  647. // decodeRoot decodes and verifies root metadata.
  648. func (c *Client) decodeRoot(b json.RawMessage) error {
  649. root := &data.Root{}
  650. if err := c.db.Unmarshal(b, root, "root", c.rootVer); err != nil {
  651. return ErrDecodeFailed{"root.json", err}
  652. }
  653. c.rootVer = root.Version
  654. c.consistentSnapshot = root.ConsistentSnapshot
  655. return nil
  656. }
  657. // decodeSnapshot decodes and verifies snapshot metadata, and returns the new
  658. // root and targets file meta.
  659. func (c *Client) decodeSnapshot(b json.RawMessage) (data.SnapshotFiles, error) {
  660. snapshot := &data.Snapshot{}
  661. // 5.5.(3 and 6) - Verify it's signed correctly and it's not expired
  662. if err := c.db.Unmarshal(b, snapshot, "snapshot", c.snapshotVer); err != nil {
  663. return data.SnapshotFiles{}, ErrDecodeFailed{"snapshot.json", err}
  664. }
  665. // 5.5.5 - Check for top-level targets rollback attack
  666. // Verify explicitly that current targets meta version is less than or equal to the new one
  667. if snapshot.Meta["targets.json"].Version < c.targetsVer {
  668. return data.SnapshotFiles{}, verify.ErrLowVersion{Actual: snapshot.Meta["targets.json"].Version, Current: c.targetsVer}
  669. }
  670. // 5.5.5 - Get the local/trusted snapshot metadata, if any, and check all target metafiles against rollback attack
  671. // In case the local snapshot metadata was not verified by the keys in the latest root during getLocalMeta(),
  672. // snapshot.json won't be present in c.localMeta and thus this check will not be processed.
  673. if snapshotJSON, ok := c.localMeta["snapshot.json"]; ok {
  674. currentSnapshot := &data.Snapshot{}
  675. if err := c.db.UnmarshalTrusted(snapshotJSON, currentSnapshot, "snapshot"); err != nil {
  676. return data.SnapshotFiles{}, err
  677. }
  678. // 5.5.5 - Check for rollback attacks in both top-level and delegated targets roles (note that the Meta object includes both)
  679. for path, local := range currentSnapshot.Meta {
  680. if newMeta, ok := snapshot.Meta[path]; ok {
  681. // 5.5.5 - Check for rollback attack
  682. if newMeta.Version < local.Version {
  683. return data.SnapshotFiles{}, verify.ErrLowVersion{Actual: newMeta.Version, Current: local.Version}
  684. }
  685. } else {
  686. // 5.5.5 - Abort the update if a target file has been removed from the new snapshot file
  687. return data.SnapshotFiles{}, verify.ErrMissingTargetFile
  688. }
  689. }
  690. }
  691. // At this point we can trust the new snapshot, the top-level targets, and any delegated targets versions it refers to
  692. // so we can update the client's trusted versions and proceed with persisting the new snapshot metadata
  693. // c.snapshotVer was already set when we verified the timestamp metadata
  694. c.targetsVer = snapshot.Meta["targets.json"].Version
  695. return snapshot.Meta, nil
  696. }
  697. // decodeTargets decodes and verifies targets metadata, sets c.targets and
  698. // returns updated targets.
  699. func (c *Client) decodeTargets(b json.RawMessage) (data.TargetFiles, error) {
  700. targets := &data.Targets{}
  701. // 5.6.(3 and 5) - Verify signatures and check against freeze attack
  702. if err := c.db.Unmarshal(b, targets, "targets", c.targetsVer); err != nil {
  703. return nil, ErrDecodeFailed{"targets.json", err}
  704. }
  705. // Generate a list with the updated targets
  706. updatedTargets := make(data.TargetFiles)
  707. for path, meta := range targets.Targets {
  708. if local, ok := c.targets[path]; ok {
  709. if err := util.TargetFileMetaEqual(local, meta); err == nil {
  710. continue
  711. }
  712. }
  713. updatedTargets[path] = meta
  714. }
  715. // c.targetsVer was already updated when we verified the snapshot metadata
  716. // FIXME(TUF-0.9) temporarily support files with leading path separators.
  717. // c.targets = targets.Targets
  718. c.loadTargets(targets.Targets)
  719. return updatedTargets, nil
  720. }
  721. // decodeTimestamp decodes and verifies timestamp metadata, and returns the
  722. // new snapshot file meta.
  723. func (c *Client) decodeTimestamp(b json.RawMessage) (data.TimestampFileMeta, error) {
  724. timestamp := &data.Timestamp{}
  725. if err := c.db.Unmarshal(b, timestamp, "timestamp", c.timestampVer); err != nil {
  726. return data.TimestampFileMeta{}, ErrDecodeFailed{"timestamp.json", err}
  727. }
  728. // 5.4.3.2 - Check for snapshot rollback attack
  729. // Verify that the current snapshot meta version is less than or equal to the new one
  730. if timestamp.Meta["snapshot.json"].Version < c.snapshotVer {
  731. return data.TimestampFileMeta{}, verify.ErrLowVersion{Actual: timestamp.Meta["snapshot.json"].Version, Current: c.snapshotVer}
  732. }
  733. // At this point we can trust the new timestamp and the snaphost version it refers to
  734. // so we can update the client's trusted versions and proceed with persisting the new timestamp
  735. c.timestampVer = timestamp.Version
  736. c.snapshotVer = timestamp.Meta["snapshot.json"].Version
  737. return timestamp.Meta["snapshot.json"], nil
  738. }
  739. // hasMetaFromSnapshot checks whether local metadata has the given meta
  740. func (c *Client) hasMetaFromSnapshot(name string, m data.SnapshotFileMeta) bool {
  741. _, ok := c.localMetaFromSnapshot(name, m)
  742. return ok
  743. }
  744. // localMetaFromSnapshot returns localmetadata if it matches the snapshot
  745. func (c *Client) localMetaFromSnapshot(name string, m data.SnapshotFileMeta) (json.RawMessage, bool) {
  746. b, ok := c.localMeta[name]
  747. if !ok {
  748. return nil, false
  749. }
  750. meta, err := util.GenerateSnapshotFileMeta(bytes.NewReader(b), m.HashAlgorithms()...)
  751. if err != nil {
  752. return nil, false
  753. }
  754. err = util.SnapshotFileMetaEqual(meta, m)
  755. return b, err == nil
  756. }
  757. // hasTargetsMeta checks whether local metadata has the given snapshot meta
  758. //
  759. //lint:ignore U1000 unused
  760. func (c *Client) hasTargetsMeta(m data.SnapshotFileMeta) bool {
  761. b, ok := c.localMeta["targets.json"]
  762. if !ok {
  763. return false
  764. }
  765. meta, err := util.GenerateSnapshotFileMeta(bytes.NewReader(b), m.HashAlgorithms()...)
  766. if err != nil {
  767. return false
  768. }
  769. err = util.SnapshotFileMetaEqual(meta, m)
  770. return err == nil
  771. }
  772. // hasSnapshotMeta checks whether local metadata has the given meta
  773. //
  774. //lint:ignore U1000 unused
  775. func (c *Client) hasMetaFromTimestamp(name string, m data.TimestampFileMeta) bool {
  776. b, ok := c.localMeta[name]
  777. if !ok {
  778. return false
  779. }
  780. meta, err := util.GenerateTimestampFileMeta(bytes.NewReader(b), m.HashAlgorithms()...)
  781. if err != nil {
  782. return false
  783. }
  784. err = util.TimestampFileMetaEqual(meta, m)
  785. return err == nil
  786. }
  787. type Destination interface {
  788. io.Writer
  789. Delete() error
  790. }
  791. // Download downloads the given target file from remote storage into dest.
  792. //
  793. // dest will be deleted and an error returned in the following situations:
  794. //
  795. // - The target does not exist in the local targets.json
  796. // - Failed to fetch the chain of delegations accessible from local snapshot.json
  797. // - The target does not exist in any targets
  798. // - Metadata cannot be generated for the downloaded data
  799. // - Generated metadata does not match local metadata for the given file
  800. func (c *Client) Download(name string, dest Destination) (err error) {
  801. // delete dest if there is an error
  802. defer func() {
  803. if err != nil {
  804. dest.Delete()
  805. }
  806. }()
  807. // populate c.targets from local storage if not set
  808. if c.targets == nil {
  809. if err := c.getLocalMeta(); err != nil {
  810. return err
  811. }
  812. }
  813. normalizedName := util.NormalizeTarget(name)
  814. localMeta, ok := c.targets[normalizedName]
  815. if !ok {
  816. // search in delegations
  817. localMeta, err = c.getTargetFileMeta(normalizedName)
  818. if err != nil {
  819. return err
  820. }
  821. }
  822. // get the data from remote storage
  823. r, size, err := c.downloadTarget(normalizedName, c.remote.GetTarget, localMeta.Hashes)
  824. if err != nil {
  825. return err
  826. }
  827. defer r.Close()
  828. // return ErrWrongSize if the reported size is known and incorrect
  829. if size >= 0 && size != localMeta.Length {
  830. return ErrWrongSize{name, size, localMeta.Length}
  831. }
  832. // wrap the data in a LimitReader so we download at most localMeta.Length bytes
  833. stream := io.LimitReader(r, localMeta.Length)
  834. // read the data, simultaneously writing it to dest and generating metadata
  835. actual, err := util.GenerateTargetFileMeta(io.TeeReader(stream, dest), localMeta.HashAlgorithms()...)
  836. if err != nil {
  837. return ErrDownloadFailed{name, err}
  838. }
  839. // check the data has the correct length and hashes
  840. if err := util.TargetFileMetaEqual(actual, localMeta); err != nil {
  841. if e, ok := err.(util.ErrWrongLength); ok {
  842. return ErrWrongSize{name, e.Actual, e.Expected}
  843. }
  844. return ErrDownloadFailed{name, err}
  845. }
  846. return nil
  847. }
  848. func (c *Client) VerifyDigest(digest string, digestAlg string, length int64, path string) error {
  849. localMeta, ok := c.targets[path]
  850. if !ok {
  851. return ErrUnknownTarget{Name: path, SnapshotVersion: c.snapshotVer}
  852. }
  853. actual := data.FileMeta{Length: length, Hashes: make(data.Hashes, 1)}
  854. var err error
  855. actual.Hashes[digestAlg], err = hex.DecodeString(digest)
  856. if err != nil {
  857. return err
  858. }
  859. if err := util.TargetFileMetaEqual(data.TargetFileMeta{FileMeta: actual}, localMeta); err != nil {
  860. if e, ok := err.(util.ErrWrongLength); ok {
  861. return ErrWrongSize{path, e.Actual, e.Expected}
  862. }
  863. return ErrDownloadFailed{path, err}
  864. }
  865. return nil
  866. }
  867. // Target returns the target metadata for a specific target if it
  868. // exists, searching from top-level level targets then through
  869. // all delegations. If it does not, ErrNotFound will be returned.
  870. func (c *Client) Target(name string) (data.TargetFileMeta, error) {
  871. target, err := c.getTargetFileMeta(util.NormalizeTarget(name))
  872. if err == nil {
  873. return target, nil
  874. }
  875. if _, ok := err.(ErrUnknownTarget); ok {
  876. return data.TargetFileMeta{}, ErrNotFound{name}
  877. }
  878. return data.TargetFileMeta{}, err
  879. }
  880. // Targets returns the complete list of available top-level targets.
  881. func (c *Client) Targets() (data.TargetFiles, error) {
  882. // populate c.targets from local storage if not set
  883. if c.targets == nil {
  884. if err := c.getLocalMeta(); err != nil {
  885. return nil, err
  886. }
  887. }
  888. return c.targets, nil
  889. }