builder.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. package tuf
  2. import (
  3. "fmt"
  4. "github.com/docker/go/canonical/json"
  5. "github.com/docker/notary"
  6. "github.com/docker/notary/trustpinning"
  7. "github.com/docker/notary/tuf/data"
  8. "github.com/docker/notary/tuf/signed"
  9. "github.com/docker/notary/tuf/utils"
  10. )
  11. // ErrBuildDone is returned when any functions are called on RepoBuilder, and it
  12. // is already finished building
  13. var ErrBuildDone = fmt.Errorf(
  14. "the builder has finished building and cannot accept any more input or produce any more output")
  15. // ErrInvalidBuilderInput is returned when RepoBuilder.Load is called
  16. // with the wrong type of metadata for the state that it's in
  17. type ErrInvalidBuilderInput struct{ msg string }
  18. func (e ErrInvalidBuilderInput) Error() string {
  19. return e.msg
  20. }
  21. // ConsistentInfo is the consistent name and size of a role, or just the name
  22. // of the role and a -1 if no file metadata for the role is known
  23. type ConsistentInfo struct {
  24. RoleName string
  25. fileMeta data.FileMeta
  26. }
  27. // ChecksumKnown determines whether or not we know enough to provide a size and
  28. // consistent name
  29. func (c ConsistentInfo) ChecksumKnown() bool {
  30. // empty hash, no size : this is the zero value
  31. return len(c.fileMeta.Hashes) > 0 || c.fileMeta.Length != 0
  32. }
  33. // ConsistentName returns the consistent name (rolename.sha256) for the role
  34. // given this consistent information
  35. func (c ConsistentInfo) ConsistentName() string {
  36. return utils.ConsistentName(c.RoleName, c.fileMeta.Hashes[notary.SHA256])
  37. }
  38. // Length returns the expected length of the role as per this consistent
  39. // information - if no checksum information is known, the size is -1.
  40. func (c ConsistentInfo) Length() int64 {
  41. if c.ChecksumKnown() {
  42. return c.fileMeta.Length
  43. }
  44. return -1
  45. }
  46. // RepoBuilder is an interface for an object which builds a tuf.Repo
  47. type RepoBuilder interface {
  48. Load(roleName string, content []byte, minVersion int, allowExpired bool) error
  49. GenerateSnapshot(prev *data.SignedSnapshot) ([]byte, int, error)
  50. GenerateTimestamp(prev *data.SignedTimestamp) ([]byte, int, error)
  51. Finish() (*Repo, *Repo, error)
  52. BootstrapNewBuilder() RepoBuilder
  53. BootstrapNewBuilderWithNewTrustpin(trustpin trustpinning.TrustPinConfig) RepoBuilder
  54. // informative functions
  55. IsLoaded(roleName string) bool
  56. GetLoadedVersion(roleName string) int
  57. GetConsistentInfo(roleName string) ConsistentInfo
  58. }
  59. // finishedBuilder refuses any more input or output
  60. type finishedBuilder struct{}
  61. func (f finishedBuilder) Load(roleName string, content []byte, minVersion int, allowExpired bool) error {
  62. return ErrBuildDone
  63. }
  64. func (f finishedBuilder) GenerateSnapshot(prev *data.SignedSnapshot) ([]byte, int, error) {
  65. return nil, 0, ErrBuildDone
  66. }
  67. func (f finishedBuilder) GenerateTimestamp(prev *data.SignedTimestamp) ([]byte, int, error) {
  68. return nil, 0, ErrBuildDone
  69. }
  70. func (f finishedBuilder) Finish() (*Repo, *Repo, error) { return nil, nil, ErrBuildDone }
  71. func (f finishedBuilder) BootstrapNewBuilder() RepoBuilder { return f }
  72. func (f finishedBuilder) BootstrapNewBuilderWithNewTrustpin(trustpin trustpinning.TrustPinConfig) RepoBuilder {
  73. return f
  74. }
  75. func (f finishedBuilder) IsLoaded(roleName string) bool { return false }
  76. func (f finishedBuilder) GetLoadedVersion(roleName string) int { return 0 }
  77. func (f finishedBuilder) GetConsistentInfo(roleName string) ConsistentInfo {
  78. return ConsistentInfo{RoleName: roleName}
  79. }
  80. // NewRepoBuilder is the only way to get a pre-built RepoBuilder
  81. func NewRepoBuilder(gun string, cs signed.CryptoService, trustpin trustpinning.TrustPinConfig) RepoBuilder {
  82. return NewBuilderFromRepo(gun, NewRepo(cs), trustpin)
  83. }
  84. // NewBuilderFromRepo allows us to bootstrap a builder given existing repo data.
  85. // YOU PROBABLY SHOULDN'T BE USING THIS OUTSIDE OF TESTING CODE!!!
  86. func NewBuilderFromRepo(gun string, repo *Repo, trustpin trustpinning.TrustPinConfig) RepoBuilder {
  87. return &repoBuilderWrapper{
  88. RepoBuilder: &repoBuilder{
  89. repo: repo,
  90. invalidRoles: NewRepo(nil),
  91. gun: gun,
  92. trustpin: trustpin,
  93. loadedNotChecksummed: make(map[string][]byte),
  94. },
  95. }
  96. }
  97. // repoBuilderWrapper embeds a repoBuilder, but once Finish is called, swaps
  98. // the embed out with a finishedBuilder
  99. type repoBuilderWrapper struct {
  100. RepoBuilder
  101. }
  102. func (rbw *repoBuilderWrapper) Finish() (*Repo, *Repo, error) {
  103. switch rbw.RepoBuilder.(type) {
  104. case finishedBuilder:
  105. return rbw.RepoBuilder.Finish()
  106. default:
  107. old := rbw.RepoBuilder
  108. rbw.RepoBuilder = finishedBuilder{}
  109. return old.Finish()
  110. }
  111. }
  112. // repoBuilder actually builds a tuf.Repo
  113. type repoBuilder struct {
  114. repo *Repo
  115. invalidRoles *Repo
  116. // needed for root trust pininng verification
  117. gun string
  118. trustpin trustpinning.TrustPinConfig
  119. // in case we load root and/or targets before snapshot and timestamp (
  120. // or snapshot and not timestamp), so we know what to verify when the
  121. // data with checksums come in
  122. loadedNotChecksummed map[string][]byte
  123. // bootstrapped values to validate a new root
  124. prevRoot *data.SignedRoot
  125. bootstrappedRootChecksum *data.FileMeta
  126. // for bootstrapping the next builder
  127. nextRootChecksum *data.FileMeta
  128. }
  129. func (rb *repoBuilder) Finish() (*Repo, *Repo, error) {
  130. return rb.repo, rb.invalidRoles, nil
  131. }
  132. func (rb *repoBuilder) BootstrapNewBuilder() RepoBuilder {
  133. return &repoBuilderWrapper{RepoBuilder: &repoBuilder{
  134. repo: NewRepo(rb.repo.cryptoService),
  135. invalidRoles: NewRepo(nil),
  136. gun: rb.gun,
  137. loadedNotChecksummed: make(map[string][]byte),
  138. trustpin: rb.trustpin,
  139. prevRoot: rb.repo.Root,
  140. bootstrappedRootChecksum: rb.nextRootChecksum,
  141. }}
  142. }
  143. func (rb *repoBuilder) BootstrapNewBuilderWithNewTrustpin(trustpin trustpinning.TrustPinConfig) RepoBuilder {
  144. return &repoBuilderWrapper{RepoBuilder: &repoBuilder{
  145. repo: NewRepo(rb.repo.cryptoService),
  146. gun: rb.gun,
  147. loadedNotChecksummed: make(map[string][]byte),
  148. trustpin: trustpin,
  149. prevRoot: rb.repo.Root,
  150. bootstrappedRootChecksum: rb.nextRootChecksum,
  151. }}
  152. }
  153. // IsLoaded returns whether a particular role has already been loaded
  154. func (rb *repoBuilder) IsLoaded(roleName string) bool {
  155. switch roleName {
  156. case data.CanonicalRootRole:
  157. return rb.repo.Root != nil
  158. case data.CanonicalSnapshotRole:
  159. return rb.repo.Snapshot != nil
  160. case data.CanonicalTimestampRole:
  161. return rb.repo.Timestamp != nil
  162. default:
  163. return rb.repo.Targets[roleName] != nil
  164. }
  165. }
  166. // GetLoadedVersion returns the metadata version, if it is loaded, or 1 (the
  167. // minimum valid version number) otherwise
  168. func (rb *repoBuilder) GetLoadedVersion(roleName string) int {
  169. switch {
  170. case roleName == data.CanonicalRootRole && rb.repo.Root != nil:
  171. return rb.repo.Root.Signed.Version
  172. case roleName == data.CanonicalSnapshotRole && rb.repo.Snapshot != nil:
  173. return rb.repo.Snapshot.Signed.Version
  174. case roleName == data.CanonicalTimestampRole && rb.repo.Timestamp != nil:
  175. return rb.repo.Timestamp.Signed.Version
  176. default:
  177. if tgts, ok := rb.repo.Targets[roleName]; ok {
  178. return tgts.Signed.Version
  179. }
  180. }
  181. return 1
  182. }
  183. // GetConsistentInfo returns the consistent name and size of a role, if it is known,
  184. // otherwise just the rolename and a -1 for size (both of which are inside a
  185. // ConsistentInfo object)
  186. func (rb *repoBuilder) GetConsistentInfo(roleName string) ConsistentInfo {
  187. info := ConsistentInfo{RoleName: roleName} // starts out with unknown filemeta
  188. switch roleName {
  189. case data.CanonicalTimestampRole:
  190. // we do not want to get a consistent timestamp, but we do want to
  191. // limit its size
  192. info.fileMeta.Length = notary.MaxTimestampSize
  193. case data.CanonicalSnapshotRole:
  194. if rb.repo.Timestamp != nil {
  195. info.fileMeta = rb.repo.Timestamp.Signed.Meta[roleName]
  196. }
  197. case data.CanonicalRootRole:
  198. switch {
  199. case rb.bootstrappedRootChecksum != nil:
  200. info.fileMeta = *rb.bootstrappedRootChecksum
  201. case rb.repo.Snapshot != nil:
  202. info.fileMeta = rb.repo.Snapshot.Signed.Meta[roleName]
  203. }
  204. default:
  205. if rb.repo.Snapshot != nil {
  206. info.fileMeta = rb.repo.Snapshot.Signed.Meta[roleName]
  207. }
  208. }
  209. return info
  210. }
  211. func (rb *repoBuilder) Load(roleName string, content []byte, minVersion int, allowExpired bool) error {
  212. if !data.ValidRole(roleName) {
  213. return ErrInvalidBuilderInput{msg: fmt.Sprintf("%s is an invalid role", roleName)}
  214. }
  215. if rb.IsLoaded(roleName) {
  216. return ErrInvalidBuilderInput{msg: fmt.Sprintf("%s has already been loaded", roleName)}
  217. }
  218. var err error
  219. switch roleName {
  220. case data.CanonicalRootRole:
  221. break
  222. case data.CanonicalTimestampRole, data.CanonicalSnapshotRole, data.CanonicalTargetsRole:
  223. err = rb.checkPrereqsLoaded([]string{data.CanonicalRootRole})
  224. default: // delegations
  225. err = rb.checkPrereqsLoaded([]string{data.CanonicalRootRole, data.CanonicalTargetsRole})
  226. }
  227. if err != nil {
  228. return err
  229. }
  230. switch roleName {
  231. case data.CanonicalRootRole:
  232. return rb.loadRoot(content, minVersion, allowExpired)
  233. case data.CanonicalSnapshotRole:
  234. return rb.loadSnapshot(content, minVersion, allowExpired)
  235. case data.CanonicalTimestampRole:
  236. return rb.loadTimestamp(content, minVersion, allowExpired)
  237. case data.CanonicalTargetsRole:
  238. return rb.loadTargets(content, minVersion, allowExpired)
  239. default:
  240. return rb.loadDelegation(roleName, content, minVersion, allowExpired)
  241. }
  242. }
  243. func (rb *repoBuilder) checkPrereqsLoaded(prereqRoles []string) error {
  244. for _, req := range prereqRoles {
  245. if !rb.IsLoaded(req) {
  246. return ErrInvalidBuilderInput{msg: fmt.Sprintf("%s must be loaded first", req)}
  247. }
  248. }
  249. return nil
  250. }
  251. // GenerateSnapshot generates a new snapshot given a previous (optional) snapshot
  252. // We can't just load the previous snapshot, because it may have been signed by a different
  253. // snapshot key (maybe from a previous root version). Note that we need the root role and
  254. // targets role to be loaded, because we need to generate metadata for both (and we need
  255. // the root to be loaded so we can get the snapshot role to sign with)
  256. func (rb *repoBuilder) GenerateSnapshot(prev *data.SignedSnapshot) ([]byte, int, error) {
  257. switch {
  258. case rb.repo.cryptoService == nil:
  259. return nil, 0, ErrInvalidBuilderInput{msg: "cannot generate snapshot without a cryptoservice"}
  260. case rb.IsLoaded(data.CanonicalSnapshotRole):
  261. return nil, 0, ErrInvalidBuilderInput{msg: "snapshot has already been loaded"}
  262. case rb.IsLoaded(data.CanonicalTimestampRole):
  263. return nil, 0, ErrInvalidBuilderInput{msg: "cannot generate snapshot if timestamp has already been loaded"}
  264. }
  265. if err := rb.checkPrereqsLoaded([]string{data.CanonicalRootRole}); err != nil {
  266. return nil, 0, err
  267. }
  268. // If there is no previous snapshot, we need to generate one, and so the targets must
  269. // have already been loaded. Otherwise, so long as the previous snapshot structure is
  270. // valid (it has a targets meta), we're good.
  271. switch prev {
  272. case nil:
  273. if err := rb.checkPrereqsLoaded([]string{data.CanonicalTargetsRole}); err != nil {
  274. return nil, 0, err
  275. }
  276. if err := rb.repo.InitSnapshot(); err != nil {
  277. rb.repo.Snapshot = nil
  278. return nil, 0, err
  279. }
  280. default:
  281. if err := data.IsValidSnapshotStructure(prev.Signed); err != nil {
  282. return nil, 0, err
  283. }
  284. rb.repo.Snapshot = prev
  285. }
  286. sgnd, err := rb.repo.SignSnapshot(data.DefaultExpires(data.CanonicalSnapshotRole))
  287. if err != nil {
  288. rb.repo.Snapshot = nil
  289. return nil, 0, err
  290. }
  291. sgndJSON, err := json.Marshal(sgnd)
  292. if err != nil {
  293. rb.repo.Snapshot = nil
  294. return nil, 0, err
  295. }
  296. // loadedNotChecksummed should currently contain the root awaiting checksumming,
  297. // since it has to have been loaded. Since the snapshot was generated using
  298. // the root and targets data (there may not be any) that that have been loaded,
  299. // remove all of them from rb.loadedNotChecksummed
  300. for tgtName := range rb.repo.Targets {
  301. delete(rb.loadedNotChecksummed, tgtName)
  302. }
  303. delete(rb.loadedNotChecksummed, data.CanonicalRootRole)
  304. // The timestamp can't have been loaded yet, so we want to cache the snapshot
  305. // bytes so we can validate the checksum when a timestamp gets generated or
  306. // loaded later.
  307. rb.loadedNotChecksummed[data.CanonicalSnapshotRole] = sgndJSON
  308. return sgndJSON, rb.repo.Snapshot.Signed.Version, nil
  309. }
  310. // GenerateTimestamp generates a new timestamp given a previous (optional) timestamp
  311. // We can't just load the previous timestamp, because it may have been signed by a different
  312. // timestamp key (maybe from a previous root version)
  313. func (rb *repoBuilder) GenerateTimestamp(prev *data.SignedTimestamp) ([]byte, int, error) {
  314. switch {
  315. case rb.repo.cryptoService == nil:
  316. return nil, 0, ErrInvalidBuilderInput{msg: "cannot generate timestamp without a cryptoservice"}
  317. case rb.IsLoaded(data.CanonicalTimestampRole):
  318. return nil, 0, ErrInvalidBuilderInput{msg: "timestamp has already been loaded"}
  319. }
  320. // SignTimestamp always serializes the loaded snapshot and signs in the data, so we must always
  321. // have the snapshot loaded first
  322. if err := rb.checkPrereqsLoaded([]string{data.CanonicalRootRole, data.CanonicalSnapshotRole}); err != nil {
  323. return nil, 0, err
  324. }
  325. switch prev {
  326. case nil:
  327. if err := rb.repo.InitTimestamp(); err != nil {
  328. rb.repo.Timestamp = nil
  329. return nil, 0, err
  330. }
  331. default:
  332. if err := data.IsValidTimestampStructure(prev.Signed); err != nil {
  333. return nil, 0, err
  334. }
  335. rb.repo.Timestamp = prev
  336. }
  337. sgnd, err := rb.repo.SignTimestamp(data.DefaultExpires(data.CanonicalTimestampRole))
  338. if err != nil {
  339. rb.repo.Timestamp = nil
  340. return nil, 0, err
  341. }
  342. sgndJSON, err := json.Marshal(sgnd)
  343. if err != nil {
  344. rb.repo.Timestamp = nil
  345. return nil, 0, err
  346. }
  347. // The snapshot should have been loaded (and not checksummed, since a timestamp
  348. // cannot have been loaded), so it is awaiting checksumming. Since this
  349. // timestamp was generated using the snapshot awaiting checksumming, we can
  350. // remove it from rb.loadedNotChecksummed. There should be no other items
  351. // awaiting checksumming now since loading/generating a snapshot should have
  352. // cleared out everything else in `loadNotChecksummed`.
  353. delete(rb.loadedNotChecksummed, data.CanonicalSnapshotRole)
  354. return sgndJSON, rb.repo.Timestamp.Signed.Version, nil
  355. }
  356. // loadRoot loads a root if one has not been loaded
  357. func (rb *repoBuilder) loadRoot(content []byte, minVersion int, allowExpired bool) error {
  358. roleName := data.CanonicalRootRole
  359. signedObj, err := rb.bytesToSigned(content, data.CanonicalRootRole)
  360. if err != nil {
  361. return err
  362. }
  363. // ValidateRoot validates against the previous root's role, as well as validates that the root
  364. // itself is self-consistent with its own signatures and thresholds.
  365. // This assumes that ValidateRoot calls data.RootFromSigned, which validates
  366. // the metadata, rather than just unmarshalling signedObject into a SignedRoot object itself.
  367. signedRoot, err := trustpinning.ValidateRoot(rb.prevRoot, signedObj, rb.gun, rb.trustpin)
  368. if err != nil {
  369. return err
  370. }
  371. if err := signed.VerifyVersion(&(signedRoot.Signed.SignedCommon), minVersion); err != nil {
  372. return err
  373. }
  374. if !allowExpired { // check must go at the end because all other validation should pass
  375. if err := signed.VerifyExpiry(&(signedRoot.Signed.SignedCommon), roleName); err != nil {
  376. return err
  377. }
  378. }
  379. rootRole, err := signedRoot.BuildBaseRole(data.CanonicalRootRole)
  380. if err != nil { // this should never happen since the root has been validated
  381. return err
  382. }
  383. rb.repo.Root = signedRoot
  384. rb.repo.originalRootRole = rootRole
  385. return nil
  386. }
  387. func (rb *repoBuilder) loadTimestamp(content []byte, minVersion int, allowExpired bool) error {
  388. roleName := data.CanonicalTimestampRole
  389. timestampRole, err := rb.repo.Root.BuildBaseRole(roleName)
  390. if err != nil { // this should never happen, since it's already been validated
  391. return err
  392. }
  393. signedObj, err := rb.bytesToSignedAndValidateSigs(timestampRole, content)
  394. if err != nil {
  395. return err
  396. }
  397. signedTimestamp, err := data.TimestampFromSigned(signedObj)
  398. if err != nil {
  399. return err
  400. }
  401. if err := signed.VerifyVersion(&(signedTimestamp.Signed.SignedCommon), minVersion); err != nil {
  402. return err
  403. }
  404. if !allowExpired { // check must go at the end because all other validation should pass
  405. if err := signed.VerifyExpiry(&(signedTimestamp.Signed.SignedCommon), roleName); err != nil {
  406. return err
  407. }
  408. }
  409. if err := rb.validateChecksumsFromTimestamp(signedTimestamp); err != nil {
  410. return err
  411. }
  412. rb.repo.Timestamp = signedTimestamp
  413. return nil
  414. }
  415. func (rb *repoBuilder) loadSnapshot(content []byte, minVersion int, allowExpired bool) error {
  416. roleName := data.CanonicalSnapshotRole
  417. snapshotRole, err := rb.repo.Root.BuildBaseRole(roleName)
  418. if err != nil { // this should never happen, since it's already been validated
  419. return err
  420. }
  421. signedObj, err := rb.bytesToSignedAndValidateSigs(snapshotRole, content)
  422. if err != nil {
  423. return err
  424. }
  425. signedSnapshot, err := data.SnapshotFromSigned(signedObj)
  426. if err != nil {
  427. return err
  428. }
  429. if err := signed.VerifyVersion(&(signedSnapshot.Signed.SignedCommon), minVersion); err != nil {
  430. return err
  431. }
  432. if !allowExpired { // check must go at the end because all other validation should pass
  433. if err := signed.VerifyExpiry(&(signedSnapshot.Signed.SignedCommon), roleName); err != nil {
  434. return err
  435. }
  436. }
  437. // at this point, the only thing left to validate is existing checksums - we can use
  438. // this snapshot to bootstrap the next builder if needed - and we don't need to do
  439. // the 2-value assignment since we've already validated the signedSnapshot, which MUST
  440. // have root metadata
  441. rootMeta := signedSnapshot.Signed.Meta[data.CanonicalRootRole]
  442. rb.nextRootChecksum = &rootMeta
  443. if err := rb.validateChecksumsFromSnapshot(signedSnapshot); err != nil {
  444. return err
  445. }
  446. rb.repo.Snapshot = signedSnapshot
  447. return nil
  448. }
  449. func (rb *repoBuilder) loadTargets(content []byte, minVersion int, allowExpired bool) error {
  450. roleName := data.CanonicalTargetsRole
  451. targetsRole, err := rb.repo.Root.BuildBaseRole(roleName)
  452. if err != nil { // this should never happen, since it's already been validated
  453. return err
  454. }
  455. signedObj, err := rb.bytesToSignedAndValidateSigs(targetsRole, content)
  456. if err != nil {
  457. return err
  458. }
  459. signedTargets, err := data.TargetsFromSigned(signedObj, roleName)
  460. if err != nil {
  461. return err
  462. }
  463. if err := signed.VerifyVersion(&(signedTargets.Signed.SignedCommon), minVersion); err != nil {
  464. return err
  465. }
  466. if !allowExpired { // check must go at the end because all other validation should pass
  467. if err := signed.VerifyExpiry(&(signedTargets.Signed.SignedCommon), roleName); err != nil {
  468. return err
  469. }
  470. }
  471. signedTargets.Signatures = signedObj.Signatures
  472. rb.repo.Targets[roleName] = signedTargets
  473. return nil
  474. }
  475. func (rb *repoBuilder) loadDelegation(roleName string, content []byte, minVersion int, allowExpired bool) error {
  476. delegationRole, err := rb.repo.GetDelegationRole(roleName)
  477. if err != nil {
  478. return err
  479. }
  480. // bytesToSigned checks checksum
  481. signedObj, err := rb.bytesToSigned(content, roleName)
  482. if err != nil {
  483. return err
  484. }
  485. signedTargets, err := data.TargetsFromSigned(signedObj, roleName)
  486. if err != nil {
  487. return err
  488. }
  489. if err := signed.VerifyVersion(&(signedTargets.Signed.SignedCommon), minVersion); err != nil {
  490. // don't capture in invalidRoles because the role we received is a rollback
  491. return err
  492. }
  493. // verify signature
  494. if err := signed.VerifySignatures(signedObj, delegationRole.BaseRole); err != nil {
  495. rb.invalidRoles.Targets[roleName] = signedTargets
  496. return err
  497. }
  498. if !allowExpired { // check must go at the end because all other validation should pass
  499. if err := signed.VerifyExpiry(&(signedTargets.Signed.SignedCommon), roleName); err != nil {
  500. rb.invalidRoles.Targets[roleName] = signedTargets
  501. return err
  502. }
  503. }
  504. signedTargets.Signatures = signedObj.Signatures
  505. rb.repo.Targets[roleName] = signedTargets
  506. return nil
  507. }
  508. func (rb *repoBuilder) validateChecksumsFromTimestamp(ts *data.SignedTimestamp) error {
  509. sn, ok := rb.loadedNotChecksummed[data.CanonicalSnapshotRole]
  510. if ok {
  511. // by this point, the SignedTimestamp has been validated so it must have a snapshot hash
  512. snMeta := ts.Signed.Meta[data.CanonicalSnapshotRole].Hashes
  513. if err := data.CheckHashes(sn, data.CanonicalSnapshotRole, snMeta); err != nil {
  514. return err
  515. }
  516. delete(rb.loadedNotChecksummed, data.CanonicalSnapshotRole)
  517. }
  518. return nil
  519. }
  520. func (rb *repoBuilder) validateChecksumsFromSnapshot(sn *data.SignedSnapshot) error {
  521. var goodRoles []string
  522. for roleName, loadedBytes := range rb.loadedNotChecksummed {
  523. switch roleName {
  524. case data.CanonicalSnapshotRole, data.CanonicalTimestampRole:
  525. break
  526. default:
  527. if err := data.CheckHashes(loadedBytes, roleName, sn.Signed.Meta[roleName].Hashes); err != nil {
  528. return err
  529. }
  530. goodRoles = append(goodRoles, roleName)
  531. }
  532. }
  533. for _, roleName := range goodRoles {
  534. delete(rb.loadedNotChecksummed, roleName)
  535. }
  536. return nil
  537. }
  538. func (rb *repoBuilder) validateChecksumFor(content []byte, roleName string) error {
  539. // validate the bootstrap checksum for root, if provided
  540. if roleName == data.CanonicalRootRole && rb.bootstrappedRootChecksum != nil {
  541. if err := data.CheckHashes(content, roleName, rb.bootstrappedRootChecksum.Hashes); err != nil {
  542. return err
  543. }
  544. }
  545. // but we also want to cache the root content, so that when the snapshot is
  546. // loaded it is validated (to make sure everything in the repo is self-consistent)
  547. checksums := rb.getChecksumsFor(roleName)
  548. if checksums != nil { // as opposed to empty, in which case hash check should fail
  549. if err := data.CheckHashes(content, roleName, *checksums); err != nil {
  550. return err
  551. }
  552. } else if roleName != data.CanonicalTimestampRole {
  553. // timestamp is the only role which does not need to be checksummed, but
  554. // for everything else, cache the contents in the list of roles that have
  555. // not been checksummed by the snapshot/timestamp yet
  556. rb.loadedNotChecksummed[roleName] = content
  557. }
  558. return nil
  559. }
  560. // Checksums the given bytes, and if they validate, convert to a data.Signed object.
  561. // If a checksums are nil (as opposed to empty), adds the bytes to the list of roles that
  562. // haven't been checksummed (unless it's a timestamp, which has no checksum reference).
  563. func (rb *repoBuilder) bytesToSigned(content []byte, roleName string) (*data.Signed, error) {
  564. if err := rb.validateChecksumFor(content, roleName); err != nil {
  565. return nil, err
  566. }
  567. // unmarshal to signed
  568. signedObj := &data.Signed{}
  569. if err := json.Unmarshal(content, signedObj); err != nil {
  570. return nil, err
  571. }
  572. return signedObj, nil
  573. }
  574. func (rb *repoBuilder) bytesToSignedAndValidateSigs(role data.BaseRole, content []byte) (*data.Signed, error) {
  575. signedObj, err := rb.bytesToSigned(content, role.Name)
  576. if err != nil {
  577. return nil, err
  578. }
  579. // verify signature
  580. if err := signed.VerifySignatures(signedObj, role); err != nil {
  581. return nil, err
  582. }
  583. return signedObj, nil
  584. }
  585. // If the checksum reference (the loaded timestamp for the snapshot role, and
  586. // the loaded snapshot for every other role except timestamp and snapshot) is nil,
  587. // then return nil for the checksums, meaning that the checksum is not yet
  588. // available. If the checksum reference *is* loaded, then always returns the
  589. // Hashes object for the given role - if it doesn't exist, returns an empty Hash
  590. // object (against which any checksum validation would fail).
  591. func (rb *repoBuilder) getChecksumsFor(role string) *data.Hashes {
  592. var hashes data.Hashes
  593. switch role {
  594. case data.CanonicalTimestampRole:
  595. return nil
  596. case data.CanonicalSnapshotRole:
  597. if rb.repo.Timestamp == nil {
  598. return nil
  599. }
  600. hashes = rb.repo.Timestamp.Signed.Meta[data.CanonicalSnapshotRole].Hashes
  601. default:
  602. if rb.repo.Snapshot == nil {
  603. return nil
  604. }
  605. hashes = rb.repo.Snapshot.Signed.Meta[role].Hashes
  606. }
  607. return &hashes
  608. }