1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
package client
import (
"github.com/theupdateframework/go-tuf/data"
"github.com/theupdateframework/go-tuf/pkg/targets"
"github.com/theupdateframework/go-tuf/verify"
)
// getTargetFileMeta searches for a verified TargetFileMeta matching a target
// Requires a local snapshot to be loaded and is locked to the snapshot versions.
func (c *Client) getTargetFileMeta(target string) (data.TargetFileMeta, error) {
snapshot, err := c.loadLocalSnapshot()
if err != nil {
return data.TargetFileMeta{}, err
}
targetFileMeta, _, err := c.getTargetFileMetaDelegationPath(target, snapshot)
if err != nil {
return data.TargetFileMeta{}, err
}
return targetFileMeta, nil
}
// getTargetFileMetaDelegationPath searches for a verified TargetFileMeta matching a target
// Requires snapshot to be passed and is locked to that specific snapshot versions.
// Searches through delegated targets following TUF spec 1.0.19 section 5.6.
func (c *Client) getTargetFileMetaDelegationPath(target string, snapshot *data.Snapshot) (data.TargetFileMeta, []string, error) {
// delegationsIterator covers 5.6.7
// - pre-order depth-first search starting with the top targets
// - filter delegations with paths or path_hash_prefixes matching searched target
// - 5.6.7.1 cycles protection
// - 5.6.7.2 terminations
delegations, err := targets.NewDelegationsIterator(target, c.db)
if err != nil {
return data.TargetFileMeta{}, nil, err
}
targetFileMeta := data.TargetFileMeta{}
delegationRole := ""
for i := 0; i < c.MaxDelegations; i++ {
d, ok := delegations.Next()
if !ok {
return data.TargetFileMeta{}, nil, ErrUnknownTarget{target, snapshot.Version}
}
// covers 5.6.{1,2,3,4,5,6}
targets, err := c.loadDelegatedTargets(snapshot, d.Delegatee.Name, d.DB)
if err != nil {
return data.TargetFileMeta{}, nil, err
}
// stop when the searched TargetFileMeta is found
if m, ok := targets.Targets[target]; ok {
delegationRole = d.Delegatee.Name
targetFileMeta = m
break
}
if targets.Delegations != nil {
delegationsDB, err := verify.NewDBFromDelegations(targets.Delegations)
if err != nil {
return data.TargetFileMeta{}, nil, err
}
err = delegations.Add(targets.Delegations.Roles, d.Delegatee.Name, delegationsDB)
if err != nil {
return data.TargetFileMeta{}, nil, err
}
}
}
if len(delegationRole) > 0 {
return targetFileMeta, buildPath(delegations.Parent, delegationRole, ""), nil
}
return data.TargetFileMeta{}, nil, ErrMaxDelegations{
Target: target,
MaxDelegations: c.MaxDelegations,
SnapshotVersion: snapshot.Version,
}
}
func buildPath(parent func(string) string, start string, end string) []string {
if start == end {
return nil
}
path := []string{start}
current := start
for {
current = parent(current)
if current == end {
break
}
path = append(path, current)
}
return path
}
func (c *Client) loadLocalSnapshot() (*data.Snapshot, error) {
if err := c.getLocalMeta(); err != nil {
return nil, err
}
rawS, ok := c.localMeta["snapshot.json"]
if !ok {
return nil, ErrNoLocalSnapshot
}
snapshot := &data.Snapshot{}
if err := c.db.Unmarshal(rawS, snapshot, "snapshot", c.snapshotVer); err != nil {
return nil, ErrDecodeFailed{"snapshot.json", err}
}
return snapshot, nil
}
// loadDelegatedTargets downloads, decodes, verifies and stores targets
func (c *Client) loadDelegatedTargets(snapshot *data.Snapshot, role string, db *verify.DB) (*data.Targets, error) {
var err error
fileName := role + ".json"
fileMeta, ok := snapshot.Meta[fileName]
if !ok {
return nil, ErrRoleNotInSnapshot{role, snapshot.Version}
}
// 5.6.1 download target if not in the local store
// 5.6.2 check against snapshot hash
// 5.6.4 check against snapshot version
raw, alreadyStored := c.localMetaFromSnapshot(fileName, fileMeta)
if !alreadyStored {
raw, err = c.downloadMetaFromSnapshot(fileName, fileMeta)
if err != nil {
return nil, err
}
}
targets := &data.Targets{}
// 5.6.3 verify signature with parent public keys
// 5.6.5 verify that the targets is not expired
// role "targets" is a top role verified by root keys loaded in the client db
err = db.Unmarshal(raw, targets, role, fileMeta.Version)
if err != nil {
return nil, ErrDecodeFailed{fileName, err}
}
// 5.6.6 persist
if !alreadyStored {
if err := c.local.SetMeta(fileName, raw); err != nil {
return nil, err
}
}
return targets, nil
}
|