...

Source file src/github.com/theupdateframework/go-tuf/client/delegations.go

Documentation: github.com/theupdateframework/go-tuf/client

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

View as plain text