Ejemplo n.º 1
0
// Unmarshal unmarshals and verifys the raw bytes for a given role's metadata
func Unmarshal(b []byte, v interface{}, role string, minVersion int, db *keys.KeyDB) error {
	s := &data.Signed{}
	if err := json.Unmarshal(b, s); err != nil {
		return err
	}
	if err := Verify(s, role, minVersion, db); err != nil {
		return err
	}
	return json.Unmarshal(s.Signed, v)
}
Ejemplo n.º 2
0
// UnmarshalTrusted unmarshals and verifies signatures only, not metadata, for a
// given role's metadata
func UnmarshalTrusted(b []byte, v interface{}, role string, db *keys.KeyDB) error {
	s := &data.Signed{}
	if err := json.Unmarshal(b, s); err != nil {
		return err
	}
	if err := VerifySignatures(s, role, db); err != nil {
		return err
	}
	return json.Unmarshal(s.Signed, v)
}
Ejemplo n.º 3
0
func changeTargetsDelegation(repo *tuf.Repo, c changelist.Change) error {
	switch c.Action() {
	case changelist.ActionCreate:
		td := changelist.TufDelegation{}
		err := json.Unmarshal(c.Content(), &td)
		if err != nil {
			return err
		}
		r, err := repo.GetDelegation(c.Scope())
		if _, ok := err.(data.ErrNoSuchRole); err != nil && !ok {
			// error that wasn't ErrNoSuchRole
			return err
		}
		if err == nil {
			// role existed
			return data.ErrInvalidRole{
				Role:   c.Scope(),
				Reason: "cannot create a role that already exists",
			}
		}
		// role doesn't exist, create brand new
		r, err = td.ToNewRole(c.Scope())
		if err != nil {
			return err
		}
		return repo.UpdateDelegations(r, td.AddKeys)
	case changelist.ActionUpdate:
		td := changelist.TufDelegation{}
		err := json.Unmarshal(c.Content(), &td)
		if err != nil {
			return err
		}
		r, err := repo.GetDelegation(c.Scope())
		if err != nil {
			return err
		}
		// role exists, merge
		if err := r.AddPaths(td.AddPaths); err != nil {
			return err
		}
		if err := r.AddPathHashPrefixes(td.AddPathHashPrefixes); err != nil {
			return err
		}
		r.RemoveKeys(td.RemoveKeys)
		r.RemovePaths(td.RemovePaths)
		r.RemovePathHashPrefixes(td.RemovePathHashPrefixes)
		return repo.UpdateDelegations(r, td.AddKeys)
	case changelist.ActionDelete:
		r := data.Role{Name: c.Scope()}
		return repo.DeleteDelegation(r)
	default:
		return fmt.Errorf("unsupported action against delegations: %s", c.Action())
	}

}
Ejemplo n.º 4
0
func TestHTTPStoreGetMeta(t *testing.T) {
	handler := func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(testRoot))
	}
	server := httptest.NewServer(http.HandlerFunc(handler))
	defer server.Close()
	store, err := NewHTTPStore(
		server.URL,
		"metadata",
		"txt",
		"targets",
		"key",
		&http.Transport{},
	)
	if err != nil {
		t.Fatal(err)
	}
	j, err := store.GetMeta("root", 4801)
	if err != nil {
		t.Fatal(err)
	}
	p := &data.Signed{}
	err = json.Unmarshal(j, p)
	if err != nil {
		t.Fatal(err)
	}
	rootKey, err := base64.StdEncoding.DecodeString(testRootKey)
	assert.NoError(t, err)
	k := data.NewPublicKey("ecdsa-x509", rootKey)

	sigBytes := p.Signatures[0].Signature
	if err != nil {
		t.Fatal(err)
	}
	var decoded map[string]interface{}
	if err := json.Unmarshal(p.Signed, &decoded); err != nil {
		t.Fatal(err)
	}
	msg, err := json.MarshalCanonical(decoded)
	if err != nil {
		t.Fatal(err)
	}
	method := p.Signatures[0].Method
	err = signed.Verifiers[method].Verify(k, sigBytes, msg)
	if err != nil {
		t.Fatal(err)
	}

}
Ejemplo n.º 5
0
// CreateTimestamp creates a new timestamp. If a prev timestamp is provided, it
// is assumed this is the immediately previous one, and the new one will have a
// version number one higher than prev. The store is used to lookup the current
// snapshot, this function does not save the newly generated timestamp.
func CreateTimestamp(gun string, prev *data.SignedTimestamp, snapshot []byte, store storage.MetaStore, cryptoService signed.CryptoService) (*data.Signed, int, error) {
	algorithm, public, err := store.GetKey(gun, data.CanonicalTimestampRole)
	if err != nil {
		// owner of gun must have generated a timestamp key otherwise
		// we won't proceed with generating everything.
		return nil, 0, err
	}
	key := data.NewPublicKey(algorithm, public)
	sn := &data.Signed{}
	err = json.Unmarshal(snapshot, sn)
	if err != nil {
		// couldn't parse snapshot
		return nil, 0, err
	}
	ts, err := data.NewTimestamp(sn)
	if err != nil {
		return nil, 0, err
	}
	if prev != nil {
		ts.Signed.Version = prev.Signed.Version + 1
	}
	sgndTs, err := json.MarshalCanonical(ts.Signed)
	if err != nil {
		return nil, 0, err
	}
	out := &data.Signed{
		Signatures: ts.Signatures,
		Signed:     sgndTs,
	}
	err = signed.Sign(cryptoService, out, key)
	if err != nil {
		return nil, 0, err
	}
	return out, ts.Signed.Version, nil
}
Ejemplo n.º 6
0
func changeTargetMeta(repo *tuf.Repo, c changelist.Change) error {
	var err error
	switch c.Action() {
	case changelist.ActionCreate:
		logrus.Debug("changelist add: ", c.Path())
		meta := &data.FileMeta{}
		err = json.Unmarshal(c.Content(), meta)
		if err != nil {
			return err
		}
		files := data.Files{c.Path(): *meta}

		err = doWithRoleFallback(c.Scope(), func(role string) error {
			_, e := repo.AddTargets(role, files)
			return e
		})
		if err != nil {
			logrus.Errorf("couldn't add target to %s: %s", c.Scope(), err.Error())
		}

	case changelist.ActionDelete:
		logrus.Debug("changelist remove: ", c.Path())

		err = doWithRoleFallback(c.Scope(), func(role string) error {
			return repo.RemoveTargets(role, c.Path())
		})
		if err != nil {
			logrus.Errorf("couldn't remove target from %s: %s", c.Scope(), err.Error())
		}

	default:
		logrus.Debug("action not yet supported: ", c.Action())
	}
	return err
}
Ejemplo n.º 7
0
func (r *NotaryRepository) bootstrapClient() (*tufclient.Client, error) {
	var rootJSON []byte
	remote, err := getRemoteStore(r.baseURL, r.gun, r.roundTrip)
	if err == nil {
		// if remote store successfully set up, try and get root from remote
		rootJSON, err = remote.GetMeta("root", maxSize)
	}

	// if remote store couldn't be setup, or we failed to get a root from it
	// load the root from cache (offline operation)
	if err != nil {
		if err, ok := err.(store.ErrMetaNotFound); ok {
			// if the error was MetaNotFound then we successfully contacted
			// the store and it doesn't know about the repo.
			return nil, err
		}
		result, cacheErr := r.fileStore.GetMeta("root", maxSize)
		if cacheErr != nil {
			// if cache didn't return a root, we cannot proceed - just return
			// the original error.
			return nil, err
		}
		rootJSON = result
		logrus.Debugf(
			"Using local cache instead of remote due to failure: %s", err.Error())
	}
	// can't just unmarshal into SignedRoot because validate root
	// needs the root.Signed field to still be []byte for signature
	// validation
	root := &data.Signed{}
	err = json.Unmarshal(rootJSON, root)
	if err != nil {
		return nil, err
	}

	err = r.CertManager.ValidateRoot(root, r.gun)
	if err != nil {
		return nil, err
	}

	kdb := keys.NewDB()
	r.tufRepo = tuf.NewRepo(kdb, r.CryptoService)

	signedRoot, err := data.RootFromSigned(root)
	if err != nil {
		return nil, err
	}
	err = r.tufRepo.SetRoot(signedRoot)
	if err != nil {
		return nil, err
	}

	return tufclient.NewClient(
		r.tufRepo,
		remote,
		kdb,
		r.fileStore,
	), nil
}
Ejemplo n.º 8
0
// UnmarshalPrivateKey is used to parse individual private keys in JSON
func UnmarshalPrivateKey(data []byte) (PrivateKey, error) {
	var parsed tufKey
	err := json.Unmarshal(data, &parsed)
	if err != nil {
		return nil, err
	}
	return typedPrivateKey(parsed)
}
Ejemplo n.º 9
0
// bootstrapRepo loads the repository from the local file system.  This attempts
// to load metadata for all roles.  Since server snapshots are supported,
// if the snapshot metadata fails to load, that's ok.
// This can also be unified with some cache reading tools from tuf/client.
// This assumes that bootstrapRepo is only used by Publish()
func (r *NotaryRepository) bootstrapRepo() error {
	kdb := keys.NewDB()
	tufRepo := tuf.NewRepo(kdb, r.CryptoService)

	logrus.Debugf("Loading trusted collection.")
	rootJSON, err := r.fileStore.GetMeta("root", 0)
	if err != nil {
		return err
	}
	root := &data.SignedRoot{}
	err = json.Unmarshal(rootJSON, root)
	if err != nil {
		return err
	}
	err = tufRepo.SetRoot(root)
	if err != nil {
		return err
	}
	targetsJSON, err := r.fileStore.GetMeta("targets", 0)
	if err != nil {
		return err
	}
	targets := &data.SignedTargets{}
	err = json.Unmarshal(targetsJSON, targets)
	if err != nil {
		return err
	}
	tufRepo.SetTargets("targets", targets)

	snapshotJSON, err := r.fileStore.GetMeta("snapshot", 0)
	if err == nil {
		snapshot := &data.SignedSnapshot{}
		err = json.Unmarshal(snapshotJSON, snapshot)
		if err != nil {
			return err
		}
		tufRepo.SetSnapshot(snapshot)
	} else if _, ok := err.(store.ErrMetaNotFound); !ok {
		return err
	}

	r.tufRepo = tufRepo

	return nil
}
Ejemplo n.º 10
0
// VerifySignatures checks the we have sufficient valid signatures for the given role
func VerifySignatures(s *data.Signed, role string, db *keys.KeyDB) error {
	if len(s.Signatures) == 0 {
		return ErrNoSignatures
	}

	roleData := db.GetRole(role)
	if roleData == nil {
		return ErrUnknownRole
	}

	if roleData.Threshold < 1 {
		return ErrRoleThreshold{}
	}
	logrus.Debugf("%s role has key IDs: %s", role, strings.Join(roleData.KeyIDs, ","))

	var decoded map[string]interface{}
	if err := json.Unmarshal(s.Signed, &decoded); err != nil {
		return err
	}
	msg, err := json.MarshalCanonical(decoded)
	if err != nil {
		return err
	}

	valid := make(map[string]struct{})
	for _, sig := range s.Signatures {
		logrus.Debug("verifying signature for key ID: ", sig.KeyID)
		if !roleData.ValidKey(sig.KeyID) {
			logrus.Debugf("continuing b/c keyid was invalid: %s for roledata %s\n", sig.KeyID, roleData)
			continue
		}
		key := db.GetKey(sig.KeyID)
		if key == nil {
			logrus.Debugf("continuing b/c keyid lookup was nil: %s\n", sig.KeyID)
			continue
		}
		// method lookup is consistent due to Unmarshal JSON doing lower case for us.
		method := sig.Method
		verifier, ok := Verifiers[method]
		if !ok {
			logrus.Debugf("continuing b/c signing method is not supported: %s\n", sig.Method)
			continue
		}

		if err := verifier.Verify(key, sig.Signature, msg); err != nil {
			logrus.Debugf("continuing b/c signature was invalid\n")
			continue
		}
		valid[sig.KeyID] = struct{}{}

	}
	if len(valid) < roleData.Threshold {
		return ErrRoleThreshold{}
	}

	return nil
}
Ejemplo n.º 11
0
func TestSignatureUnmarshalJSON(t *testing.T) {
	signatureJSON := `{"keyid":"97e8e1b51b6e7cf8720a56b5334bd8692ac5b28233c590b89fab0b0cd93eeedc","method":"RSA","sig":"2230cba525e4f5f8fc744f234221ca9a92924da4cc5faf69a778848882fcf7a20dbb57296add87f600891f2569a9c36706314c240f9361c60fd36f5a915a0e9712fc437b761e8f480868d7a4444724daa0d29a2669c0edbd4046046649a506b3d711d0aa5e70cb9d09dec7381e7de27a3168e77731e08f6ed56fcce2478855e837816fb69aff53412477748cd198dce783850080d37aeb929ad0f81460ebd31e61b772b6c7aa56977c787d4281fa45dbdefbb38d449eb5bccb2702964a52c78811545939712c8280dee0b23b2fa9fbbdd6a0c42476689ace655eba0745b4a21ba108bcd03ad00fdefff416dc74e08486a0538f8fd24989e1b9fc89e675141b7c"}`

	var sig Signature
	err := json.Unmarshal([]byte(signatureJSON), &sig)
	assert.NoError(t, err)

	// Check that the method string is lowercased
	assert.Equal(t, sig.Method.String(), "rsa")
}
Ejemplo n.º 12
0
// UnmarshalJSON does a custom unmarshalling of the signature JSON
func (s *Signature) UnmarshalJSON(data []byte) error {
	uSignature := unmarshalledSignature{}
	err := json.Unmarshal(data, &uSignature)
	if err != nil {
		return err
	}
	uSignature.Method = SigAlgorithm(strings.ToLower(string(uSignature.Method)))
	*s = Signature(uSignature)
	return nil
}
Ejemplo n.º 13
0
// TargetsFromSigned fully unpacks a Signed object into a SignedTargets
func TargetsFromSigned(s *Signed) (*SignedTargets, error) {
	t := Targets{}
	err := json.Unmarshal(s.Signed, &t)
	if err != nil {
		return nil, err
	}
	sigs := make([]Signature, len(s.Signatures))
	copy(sigs, s.Signatures)
	return &SignedTargets{
		Signatures: sigs,
		Signed:     t,
	}, nil
}
Ejemplo n.º 14
0
// UnmarshalJSON implements the json.Unmarshaller interface
func (ks *KeyList) UnmarshalJSON(data []byte) error {
	parsed := make([]tufKey, 0, 1)
	err := json.Unmarshal(data, &parsed)
	if err != nil {
		return err
	}
	final := make([]PublicKey, 0, len(parsed))
	for _, tk := range parsed {
		final = append(final, typedPublicKey(tk))
	}
	*ks = final
	return nil
}
Ejemplo n.º 15
0
// UnmarshalJSON implements the json.Unmarshaller interface
func (ks *Keys) UnmarshalJSON(data []byte) error {
	parsed := make(map[string]tufKey)
	err := json.Unmarshal(data, &parsed)
	if err != nil {
		return err
	}
	final := make(map[string]PublicKey)
	for k, tk := range parsed {
		final[k] = typedPublicKey(tk)
	}
	*ks = final
	return nil
}
Ejemplo n.º 16
0
// RootFromSigned fully unpacks a Signed object into a SignedRoot
func RootFromSigned(s *Signed) (*SignedRoot, error) {
	r := Root{}
	err := json.Unmarshal(s.Signed, &r)
	if err != nil {
		return nil, err
	}
	sigs := make([]Signature, len(s.Signatures))
	copy(sigs, s.Signatures)
	return &SignedRoot{
		Signatures: sigs,
		Signed:     r,
	}, nil
}
Ejemplo n.º 17
0
func TimestampFromSigned(s *Signed) (*SignedTimestamp, error) {
	ts := Timestamp{}
	err := json.Unmarshal(s.Signed, &ts)
	if err != nil {
		return nil, err
	}
	sigs := make([]Signature, len(s.Signatures))
	copy(sigs, s.Signatures)
	return &SignedTimestamp{
		Signatures: sigs,
		Signed:     ts,
	}, nil
}
Ejemplo n.º 18
0
func SnapshotFromSigned(s *Signed) (*SignedSnapshot, error) {
	sp := Snapshot{}
	err := json.Unmarshal(s.Signed, &sp)
	if err != nil {
		return nil, err
	}
	sigs := make([]Signature, len(s.Signatures))
	copy(sigs, s.Signatures)
	return &SignedSnapshot{
		Signatures: sigs,
		Signed:     sp,
	}, nil
}
Ejemplo n.º 19
0
func verifyMeta(s *data.Signed, role string, minVersion int) error {
	sm := &data.SignedCommon{}
	if err := json.Unmarshal(s.Signed, sm); err != nil {
		return err
	}
	if !data.ValidTUFType(sm.Type, role) {
		return ErrWrongType
	}
	if IsExpired(sm.Expires) {
		logrus.Errorf("Metadata for %s expired", role)
		return ErrExpired{Role: role, Expired: sm.Expires.Format("Mon Jan 2 15:04:05 MST 2006")}
	}
	if sm.Version < minVersion {
		return ErrLowVersion{sm.Version, minVersion}
	}

	return nil
}
Ejemplo n.º 20
0
func applyRootRoleChange(repo *tuf.Repo, c changelist.Change) error {
	switch c.Action() {
	case changelist.ActionCreate:
		// replaces all keys for a role
		d := &changelist.TufRootData{}
		err := json.Unmarshal(c.Content(), d)
		if err != nil {
			return err
		}
		err = repo.ReplaceBaseKeys(d.RoleName, d.Keys...)
		if err != nil {
			return err
		}
	default:
		logrus.Debug("action not yet supported for root: ", c.Action())
	}
	return nil
}
Ejemplo n.º 21
0
// GetOrCreateTimestamp returns the current timestamp for the gun. This may mean
// a new timestamp is generated either because none exists, or because the current
// one has expired. Once generated, the timestamp is saved in the store.
func GetOrCreateTimestamp(gun string, store storage.MetaStore, cryptoService signed.CryptoService) ([]byte, error) {
	snapshot, err := store.GetCurrent(gun, "snapshot")
	if err != nil {
		return nil, err
	}
	d, err := store.GetCurrent(gun, "timestamp")
	if err != nil {
		if _, ok := err.(storage.ErrNotFound); !ok {
			logrus.Error("error retrieving timestamp: ", err.Error())
			return nil, err
		}
		logrus.Debug("No timestamp found, will proceed to create first timestamp")
	}
	ts := &data.SignedTimestamp{}
	if d != nil {
		err := json.Unmarshal(d, ts)
		if err != nil {
			logrus.Error("Failed to unmarshal existing timestamp")
			return nil, err
		}
		if !timestampExpired(ts) && !snapshotExpired(ts, snapshot) {
			return d, nil
		}
	}
	sgnd, version, err := CreateTimestamp(gun, ts, snapshot, store, cryptoService)
	if err != nil {
		logrus.Error("Failed to create a new timestamp")
		return nil, err
	}
	out, err := json.MarshalCanonical(sgnd)
	if err != nil {
		logrus.Error("Failed to marshal new timestamp")
		return nil, err
	}
	err = store.UpdateCurrent(gun, storage.MetaUpdate{Role: "timestamp", Version: version, Data: out})
	if err != nil {
		return nil, err
	}
	return out, nil
}
Ejemplo n.º 22
0
func TestValidateSnapshotGenerateWithPrev(t *testing.T) {
	kdb, repo, cs := testutils.EmptyRepo()
	store := storage.NewMemStorage()
	snapRole := kdb.GetRole(data.CanonicalSnapshotRole)

	for _, id := range snapRole.KeyIDs {
		k := kdb.GetKey(id)
		assert.NotNil(t, k)
		err := store.SetKey("testGUN", data.CanonicalSnapshotRole, k.Algorithm(), k.Public())
		assert.NoError(t, err)
	}

	r, tg, sn, ts, err := testutils.Sign(repo)
	assert.NoError(t, err)
	root, targets, snapshot, _, err := getUpdates(r, tg, sn, ts)
	assert.NoError(t, err)

	updates := []storage.MetaUpdate{root, targets}

	// set the current snapshot in the store manually so we find it when generating
	// the next version
	store.UpdateCurrent("testGUN", snapshot)

	prev, err := data.SnapshotFromSigned(sn)
	assert.NoError(t, err)

	copyTimestampKey(t, kdb, store, "testGUN")
	updates, err = validateUpdate(cs, "testGUN", updates, store)
	assert.NoError(t, err)

	for _, u := range updates {
		if u.Role == data.CanonicalSnapshotRole {
			curr := &data.SignedSnapshot{}
			err = json.Unmarshal(u.Data, curr)
			assert.Equal(t, prev.Signed.Version+1, curr.Signed.Version)
			assert.Equal(t, u.Version, curr.Signed.Version)
		}
	}
}
Ejemplo n.º 23
0
// VerifyRoot checks if a given root file is valid against a known set of keys.
// Threshold is always assumed to be 1
func VerifyRoot(s *data.Signed, minVersion int, keys map[string]data.PublicKey) error {
	if len(s.Signatures) == 0 {
		return ErrNoSignatures
	}

	var decoded map[string]interface{}
	if err := json.Unmarshal(s.Signed, &decoded); err != nil {
		return err
	}
	msg, err := json.MarshalCanonical(decoded)
	if err != nil {
		return err
	}

	for _, sig := range s.Signatures {
		// method lookup is consistent due to Unmarshal JSON doing lower case for us.
		method := sig.Method
		verifier, ok := Verifiers[method]
		if !ok {
			logrus.Debugf("continuing b/c signing method is not supported for verify root: %s\n", sig.Method)
			continue
		}

		key, ok := keys[sig.KeyID]
		if !ok {
			logrus.Debugf("continuing b/c signing key isn't present in keys: %s\n", sig.KeyID)
			continue
		}

		if err := verifier.Verify(key, sig.Signature, msg); err != nil {
			logrus.Debugf("continuing b/c signature was invalid\n")
			continue
		}
		// threshold of 1 so return on first success
		return verifyMeta(s, "root", minVersion)
	}
	return ErrRoleThreshold{}
}
Ejemplo n.º 24
0
// GetOrCreateSnapshot either returns the exisiting latest snapshot, or uses
// whatever the most recent snapshot is to create the next one, only updating
// the expiry time and version.
func GetOrCreateSnapshot(gun string, store storage.MetaStore, cryptoService signed.CryptoService) ([]byte, error) {

	d, err := store.GetCurrent(gun, "snapshot")
	if err != nil {
		return nil, err
	}

	sn := &data.SignedSnapshot{}
	if d != nil {
		err := json.Unmarshal(d, sn)
		if err != nil {
			logrus.Error("Failed to unmarshal existing snapshot")
			return nil, err
		}

		if !snapshotExpired(sn) {
			return d, nil
		}
	}

	sgnd, version, err := createSnapshot(gun, sn, store, cryptoService)
	if err != nil {
		logrus.Error("Failed to create a new snapshot")
		return nil, err
	}
	out, err := json.MarshalCanonical(sgnd)
	if err != nil {
		logrus.Error("Failed to marshal new snapshot")
		return nil, err
	}
	err = store.UpdateCurrent(gun, storage.MetaUpdate{Role: "snapshot", Version: version, Data: out})
	if err != nil {
		return nil, err
	}
	return out, nil
}
Ejemplo n.º 25
0
// GetKeys returns private keys
func (dbs *dbStore) GetKeys(role string) ([]data.PrivateKey, error) {
	keys := []data.PrivateKey{}
	var r *sql.Rows
	var err error
	sql := "SELECT `key` FROM `keys` WHERE `role` = ? AND `namespace` = ?;"
	tx, err := dbs.db.Begin()
	defer tx.Rollback()
	r, err = tx.Query(sql, role, dbs.imageName)
	if err != nil {
		return nil, err
	}
	defer r.Close()
	for r.Next() {
		var jsonStr string
		key := new(data.TUFKey)
		r.Scan(&jsonStr)
		err := json.Unmarshal([]byte(jsonStr), key)
		if err != nil {
			return nil, err
		}
		keys = append(keys, key)
	}
	return keys, nil
}
Ejemplo n.º 26
0
// Unmarshal unmarshals some JSON bytes
func (c canonicalJSON) Unmarshal(from []byte, to interface{}) error {
	return json.Unmarshal(from, to)
}