mirror of https://github.com/docker/docs.git
736 lines
20 KiB
Go
736 lines
20 KiB
Go
package testutils
|
|
|
|
import (
|
|
"bytes"
|
|
"path"
|
|
"time"
|
|
|
|
"github.com/docker/go/canonical/json"
|
|
"github.com/docker/notary/cryptoservice"
|
|
"github.com/docker/notary/passphrase"
|
|
"github.com/docker/notary/trustmanager"
|
|
"github.com/docker/notary/tuf"
|
|
"github.com/docker/notary/tuf/data"
|
|
"github.com/docker/notary/tuf/signed"
|
|
"github.com/docker/notary/tuf/store"
|
|
)
|
|
|
|
// ErrNoKeyForRole returns an error when the cryptoservice provided to
|
|
// MetadataSwizzler has no key for a particular role
|
|
type ErrNoKeyForRole struct {
|
|
Role string
|
|
}
|
|
|
|
func (e ErrNoKeyForRole) Error() string {
|
|
return "Swizzler's cryptoservice has no key for role " + e.Role
|
|
}
|
|
|
|
// MetadataSwizzler fuzzes the metadata in a MetadataStore
|
|
type MetadataSwizzler struct {
|
|
Gun string
|
|
MetadataCache store.MetadataStore
|
|
CryptoService signed.CryptoService
|
|
Roles []string // list of Roles in the metadataStore
|
|
}
|
|
|
|
func getPubKeys(cs signed.CryptoService, s *data.Signed, role string) ([]data.PublicKey, error) {
|
|
var pubKeys []data.PublicKey
|
|
if role == data.CanonicalRootRole {
|
|
// if this is root metadata, we have to get the keys from the root because they
|
|
// are certs
|
|
root := &data.Root{}
|
|
if err := json.Unmarshal(*s.Signed, root); err != nil {
|
|
return nil, err
|
|
}
|
|
rootRole, ok := root.Roles[data.CanonicalRootRole]
|
|
if !ok || rootRole == nil {
|
|
return nil, tuf.ErrNotLoaded{}
|
|
}
|
|
for _, pubKeyID := range rootRole.KeyIDs {
|
|
pubKeys = append(pubKeys, root.Keys[pubKeyID])
|
|
}
|
|
} else {
|
|
pubKeyIDs := cs.ListKeys(role)
|
|
for _, pubKeyID := range pubKeyIDs {
|
|
pubKey := cs.GetKey(pubKeyID)
|
|
if pubKey != nil {
|
|
pubKeys = append(pubKeys, pubKey)
|
|
}
|
|
}
|
|
}
|
|
return pubKeys, nil
|
|
}
|
|
|
|
// signs the new metadata, replacing whatever signature was there
|
|
func serializeMetadata(cs signed.CryptoService, s *data.Signed, role string,
|
|
pubKeys ...data.PublicKey) ([]byte, error) {
|
|
|
|
// delete the existing signatures
|
|
s.Signatures = []data.Signature{}
|
|
|
|
if len(pubKeys) < 1 {
|
|
return nil, ErrNoKeyForRole{role}
|
|
}
|
|
|
|
if err := signed.Sign(cs, s, pubKeys, 1, nil); err != nil {
|
|
if _, ok := err.(signed.ErrInsufficientSignatures); ok {
|
|
return nil, ErrNoKeyForRole{Role: role}
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
metaBytes, err := json.Marshal(s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return metaBytes, nil
|
|
}
|
|
|
|
// gets a Signed from the metadata store
|
|
func signedFromStore(cache store.MetadataStore, role string) (*data.Signed, error) {
|
|
b, err := cache.GetMeta(role, -1)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
signed := &data.Signed{}
|
|
if err := json.Unmarshal(b, signed); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return signed, nil
|
|
}
|
|
|
|
// NewMetadataSwizzler returns a new swizzler when given a gun,
|
|
// mapping of roles to initial metadata bytes, and a cryptoservice
|
|
func NewMetadataSwizzler(gun string, initialMetadata map[string][]byte,
|
|
cryptoService signed.CryptoService) *MetadataSwizzler {
|
|
|
|
var roles []string
|
|
for roleName := range initialMetadata {
|
|
roles = append(roles, roleName)
|
|
}
|
|
|
|
return &MetadataSwizzler{
|
|
Gun: gun,
|
|
MetadataCache: store.NewMemoryStore(initialMetadata),
|
|
CryptoService: cryptoService,
|
|
Roles: roles,
|
|
}
|
|
}
|
|
|
|
// SetInvalidJSON corrupts metadata into something that is no longer valid JSON
|
|
func (m *MetadataSwizzler) SetInvalidJSON(role string) error {
|
|
metaBytes, err := m.MetadataCache.GetMeta(role, -1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(role, metaBytes[5:])
|
|
}
|
|
|
|
// AddExtraSpace adds an extra space to the beginning and end of the serialized
|
|
// JSON bytes, which should not affect serialization, but will change the checksum
|
|
// of the file.
|
|
func (m *MetadataSwizzler) AddExtraSpace(role string) error {
|
|
metaBytes, err := m.MetadataCache.GetMeta(role, -1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
newBytes := append(append([]byte{' '}, metaBytes...), ' ')
|
|
return m.MetadataCache.SetMeta(role, newBytes)
|
|
}
|
|
|
|
// SetInvalidSigned corrupts the metadata into something that is valid JSON,
|
|
// but not unmarshallable into signed JSON
|
|
func (m *MetadataSwizzler) SetInvalidSigned(role string) error {
|
|
signedThing, err := signedFromStore(m.MetadataCache, role)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
metaBytes, err := json.MarshalCanonical(map[string]interface{}{
|
|
"signed": signedThing.Signed,
|
|
"signatures": "not list",
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(role, metaBytes)
|
|
}
|
|
|
|
// SetInvalidSignedMeta corrupts the metadata into something that is unmarshallable
|
|
// as a Signed object, but not unmarshallable into a SignedMeta object
|
|
func (m *MetadataSwizzler) SetInvalidSignedMeta(role string) error {
|
|
signedThing, err := signedFromStore(m.MetadataCache, role)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pubKeys, err := getPubKeys(m.CryptoService, signedThing, role)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var unmarshalled map[string]interface{}
|
|
if err := json.Unmarshal(*signedThing.Signed, &unmarshalled); err != nil {
|
|
return err
|
|
}
|
|
|
|
unmarshalled["_type"] = []string{"not a string"}
|
|
unmarshalled["version"] = "string not int"
|
|
unmarshalled["expires"] = "cannot be parsed as time"
|
|
|
|
metaBytes, err := json.MarshalCanonical(unmarshalled)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
signedThing.Signed = (*json.RawMessage)(&metaBytes)
|
|
|
|
metaBytes, err = serializeMetadata(m.CryptoService, signedThing, role, pubKeys...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(role, metaBytes)
|
|
}
|
|
|
|
// TODO: corrupt metadata in such a way that it can be unmarshalled as a
|
|
// SignedMeta, but not as a SignedRoot or SignedTarget, etc. (Signed*)
|
|
|
|
// SetInvalidMetadataType unmarshallable, but has the wrong metadata type (not
|
|
// actually a metadata type)
|
|
func (m *MetadataSwizzler) SetInvalidMetadataType(role string) error {
|
|
signedThing, err := signedFromStore(m.MetadataCache, role)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var unmarshalled map[string]interface{}
|
|
if err := json.Unmarshal(*signedThing.Signed, &unmarshalled); err != nil {
|
|
return err
|
|
}
|
|
|
|
unmarshalled["_type"] = "not_real"
|
|
|
|
metaBytes, err := json.MarshalCanonical(unmarshalled)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
signedThing.Signed = (*json.RawMessage)(&metaBytes)
|
|
|
|
pubKeys, err := getPubKeys(m.CryptoService, signedThing, role)
|
|
if err == nil {
|
|
metaBytes, err = serializeMetadata(m.CryptoService, signedThing, role, pubKeys...)
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(role, metaBytes)
|
|
}
|
|
|
|
// InvalidateMetadataSignatures signs with the right key(s) but wrong hash
|
|
func (m *MetadataSwizzler) InvalidateMetadataSignatures(role string) error {
|
|
signedThing, err := signedFromStore(m.MetadataCache, role)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
sigs := make([]data.Signature, len(signedThing.Signatures))
|
|
for i, origSig := range signedThing.Signatures {
|
|
sigs[i] = data.Signature{
|
|
KeyID: origSig.KeyID,
|
|
Signature: []byte("invalid signature"),
|
|
Method: origSig.Method,
|
|
}
|
|
}
|
|
signedThing.Signatures = sigs
|
|
|
|
metaBytes, err := json.Marshal(signedThing)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(role, metaBytes)
|
|
}
|
|
|
|
// TODO: AddExtraSignedInfo - add an extra field to Signed that doesn't get
|
|
// unmarshalled, and the whole thing is correctly signed, so shouldn't cause
|
|
// problems there. Should this fail a canonical JSON check?
|
|
|
|
// RemoveMetadata deletes the metadata entirely
|
|
func (m *MetadataSwizzler) RemoveMetadata(role string) error {
|
|
return m.MetadataCache.RemoveMeta(role)
|
|
}
|
|
|
|
// SignMetadataWithInvalidKey signs the metadata with the wrong key
|
|
func (m *MetadataSwizzler) SignMetadataWithInvalidKey(role string) error {
|
|
signedThing, err := signedFromStore(m.MetadataCache, role)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// create an invalid key, but not in the existing CryptoService
|
|
cs := cryptoservice.NewCryptoService(trustmanager.NewKeyMemoryStore(passphrase.ConstantRetriever("")))
|
|
key, err := CreateKey(cs, m.Gun, role, data.ECDSAKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
metaBytes, err := serializeMetadata(cs, signedThing, "root", key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(role, metaBytes)
|
|
}
|
|
|
|
// OffsetMetadataVersion updates the metadata version
|
|
func (m *MetadataSwizzler) OffsetMetadataVersion(role string, offset int) error {
|
|
signedThing, err := signedFromStore(m.MetadataCache, role)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var unmarshalled map[string]interface{}
|
|
if err := json.Unmarshal(*signedThing.Signed, &unmarshalled); err != nil {
|
|
return err
|
|
}
|
|
|
|
oldVersion, ok := unmarshalled["version"].(float64)
|
|
if !ok {
|
|
oldVersion = float64(0) // just ignore the error and set it to 0
|
|
}
|
|
unmarshalled["version"] = int(oldVersion) + offset
|
|
|
|
metaBytes, err := json.MarshalCanonical(unmarshalled)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
signedThing.Signed = (*json.RawMessage)(&metaBytes)
|
|
|
|
pubKeys, err := getPubKeys(m.CryptoService, signedThing, role)
|
|
if err == nil {
|
|
metaBytes, err = serializeMetadata(m.CryptoService, signedThing, role, pubKeys...)
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(role, metaBytes)
|
|
}
|
|
|
|
// ExpireMetadata expires the metadata, which would make it invalid - don't do anything if
|
|
// we don't have the timestamp key
|
|
func (m *MetadataSwizzler) ExpireMetadata(role string) error {
|
|
signedThing, err := signedFromStore(m.MetadataCache, role)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var unmarshalled map[string]interface{}
|
|
if err := json.Unmarshal(*signedThing.Signed, &unmarshalled); err != nil {
|
|
return err
|
|
}
|
|
|
|
unmarshalled["expires"] = time.Now().AddDate(-1, -1, -1)
|
|
|
|
metaBytes, err := json.MarshalCanonical(unmarshalled)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
signedThing.Signed = (*json.RawMessage)(&metaBytes)
|
|
|
|
pubKeys, err := getPubKeys(m.CryptoService, signedThing, role)
|
|
if err == nil {
|
|
metaBytes, err = serializeMetadata(m.CryptoService, signedThing, role, pubKeys...)
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(role, metaBytes)
|
|
}
|
|
|
|
// SetThreshold sets a threshold for a metadata role - can invalidate metadata for which
|
|
// the threshold is increased, if there aren't enough signatures or can be invalid because
|
|
// the threshold is 0
|
|
func (m *MetadataSwizzler) SetThreshold(role string, newThreshold int) error {
|
|
roleSpecifier := data.CanonicalRootRole
|
|
if data.IsDelegation(role) {
|
|
roleSpecifier = path.Dir(role)
|
|
}
|
|
|
|
b, err := m.MetadataCache.GetMeta(roleSpecifier, -1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
signedThing := &data.Signed{}
|
|
if err := json.Unmarshal(b, signedThing); err != nil {
|
|
return err
|
|
}
|
|
|
|
if roleSpecifier == data.CanonicalRootRole {
|
|
signedRoot, err := data.RootFromSigned(signedThing)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
signedRoot.Signed.Roles[role].Threshold = newThreshold
|
|
if signedThing, err = signedRoot.ToSigned(); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
signedTargets, err := data.TargetsFromSigned(signedThing, roleSpecifier)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, roleObject := range signedTargets.Signed.Delegations.Roles {
|
|
if roleObject.Name == role {
|
|
roleObject.Threshold = newThreshold
|
|
break
|
|
}
|
|
}
|
|
if signedThing, err = signedTargets.ToSigned(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
var metaBytes []byte
|
|
pubKeys, err := getPubKeys(m.CryptoService, signedThing, roleSpecifier)
|
|
if err == nil {
|
|
metaBytes, err = serializeMetadata(m.CryptoService, signedThing, roleSpecifier, pubKeys...)
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(roleSpecifier, metaBytes)
|
|
}
|
|
|
|
// RotateKey rotates the key for a role - this can invalidate that role's metadata
|
|
// if it is not signed by that key. Particularly if the key being rotated is the
|
|
// root key, because it is not signed by the new key, only the old key.
|
|
func (m *MetadataSwizzler) RotateKey(role string, key data.PublicKey) error {
|
|
roleSpecifier := data.CanonicalRootRole
|
|
if data.IsDelegation(role) {
|
|
roleSpecifier = path.Dir(role)
|
|
}
|
|
|
|
b, err := m.MetadataCache.GetMeta(roleSpecifier, -1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
signedThing := &data.Signed{}
|
|
if err := json.Unmarshal(b, signedThing); err != nil {
|
|
return err
|
|
}
|
|
|
|
// get keys before the keys are rotated
|
|
pubKeys, err := getPubKeys(m.CryptoService, signedThing, roleSpecifier)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if roleSpecifier == data.CanonicalRootRole {
|
|
signedRoot, err := data.RootFromSigned(signedThing)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
signedRoot.Signed.Roles[role].KeyIDs = []string{key.ID()}
|
|
signedRoot.Signed.Keys[key.ID()] = key
|
|
if signedThing, err = signedRoot.ToSigned(); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
signedTargets, err := data.TargetsFromSigned(signedThing, roleSpecifier)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, roleObject := range signedTargets.Signed.Delegations.Roles {
|
|
if roleObject.Name == role {
|
|
roleObject.KeyIDs = []string{key.ID()}
|
|
break
|
|
}
|
|
}
|
|
signedTargets.Signed.Delegations.Keys[key.ID()] = key
|
|
if signedThing, err = signedTargets.ToSigned(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
metaBytes, err := serializeMetadata(m.CryptoService, signedThing, roleSpecifier, pubKeys...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(roleSpecifier, metaBytes)
|
|
}
|
|
|
|
// ChangeRootKey swaps out the root key with a new key, and re-signs the metadata
|
|
// with the new key
|
|
func (m *MetadataSwizzler) ChangeRootKey() error {
|
|
key, err := CreateKey(m.CryptoService, m.Gun, data.CanonicalRootRole, data.ECDSAKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
b, err := m.MetadataCache.GetMeta(data.CanonicalRootRole, -1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
signedRoot := &data.SignedRoot{}
|
|
if err := json.Unmarshal(b, signedRoot); err != nil {
|
|
return err
|
|
}
|
|
|
|
signedRoot.Signed.Keys[key.ID()] = key
|
|
signedRoot.Signed.Roles[data.CanonicalRootRole].KeyIDs = []string{key.ID()}
|
|
|
|
var signedThing *data.Signed
|
|
if signedThing, err = signedRoot.ToSigned(); err != nil {
|
|
return err
|
|
}
|
|
|
|
var metaBytes []byte
|
|
pubKeys, err := getPubKeys(m.CryptoService, signedThing, data.CanonicalRootRole)
|
|
if err == nil {
|
|
metaBytes, err = serializeMetadata(m.CryptoService, signedThing, data.CanonicalRootRole, pubKeys...)
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(data.CanonicalRootRole, metaBytes)
|
|
}
|
|
|
|
// UpdateSnapshotHashes updates the snapshot to reflect the latest hash changes, to
|
|
// ensure that failure isn't because the snapshot has the wrong hash.
|
|
func (m *MetadataSwizzler) UpdateSnapshotHashes(roles ...string) error {
|
|
var (
|
|
metaBytes []byte
|
|
snapshotSigned *data.Signed
|
|
err error
|
|
)
|
|
if metaBytes, err = m.MetadataCache.GetMeta(data.CanonicalSnapshotRole, -1); err != nil {
|
|
return err
|
|
}
|
|
|
|
snapshot := data.SignedSnapshot{}
|
|
if err = json.Unmarshal(metaBytes, &snapshot); err != nil {
|
|
return err
|
|
}
|
|
|
|
// just rebuild everything if roles is not specified
|
|
if len(roles) == 0 {
|
|
roles = m.Roles
|
|
}
|
|
|
|
for _, role := range roles {
|
|
if role != data.CanonicalSnapshotRole && role != data.CanonicalTimestampRole {
|
|
if metaBytes, err = m.MetadataCache.GetMeta(role, -1); err != nil {
|
|
return err
|
|
}
|
|
|
|
meta, err := data.NewFileMeta(bytes.NewReader(metaBytes), data.NotaryDefaultHashes...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
snapshot.Signed.Meta[role] = meta
|
|
}
|
|
}
|
|
|
|
if snapshotSigned, err = snapshot.ToSigned(); err != nil {
|
|
return err
|
|
}
|
|
pubKeys, err := getPubKeys(m.CryptoService, snapshotSigned, data.CanonicalSnapshotRole)
|
|
if err == nil {
|
|
metaBytes, err = serializeMetadata(m.CryptoService, snapshotSigned, data.CanonicalSnapshotRole, pubKeys...)
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(data.CanonicalSnapshotRole, metaBytes)
|
|
}
|
|
|
|
// UpdateTimestampHash updates the timestamp to reflect the latest snapshot changes, to
|
|
// ensure that failure isn't because the timestamp has the wrong hash.
|
|
func (m *MetadataSwizzler) UpdateTimestampHash() error {
|
|
var (
|
|
metaBytes []byte
|
|
timestamp = &data.SignedTimestamp{}
|
|
timestampSigned *data.Signed
|
|
err error
|
|
)
|
|
if metaBytes, err = m.MetadataCache.GetMeta(data.CanonicalTimestampRole, -1); err != nil {
|
|
return err
|
|
}
|
|
// we can't just create a new timestamp, because then the expiry would be
|
|
// different
|
|
if err = json.Unmarshal(metaBytes, timestamp); err != nil {
|
|
return err
|
|
}
|
|
|
|
if metaBytes, err = m.MetadataCache.GetMeta(data.CanonicalSnapshotRole, -1); err != nil {
|
|
return err
|
|
}
|
|
|
|
snapshotMeta, err := data.NewFileMeta(bytes.NewReader(metaBytes), data.NotaryDefaultHashes...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
timestamp.Signed.Meta[data.CanonicalSnapshotRole] = snapshotMeta
|
|
|
|
timestampSigned, err = timestamp.ToSigned()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
pubKeys, err := getPubKeys(m.CryptoService, timestampSigned, data.CanonicalTimestampRole)
|
|
if err == nil {
|
|
metaBytes, err = serializeMetadata(m.CryptoService, timestampSigned, data.CanonicalTimestampRole, pubKeys...)
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(data.CanonicalTimestampRole, metaBytes)
|
|
}
|
|
|
|
// MutateRoot takes a function that mutates the root metadata - once done, it
|
|
// serializes the root again
|
|
func (m *MetadataSwizzler) MutateRoot(mutate func(*data.Root)) error {
|
|
signedThing, err := signedFromStore(m.MetadataCache, data.CanonicalRootRole)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var root data.Root
|
|
if err := json.Unmarshal(*signedThing.Signed, &root); err != nil {
|
|
return err
|
|
}
|
|
|
|
// get the original keys, in case the mutation messes with the signing keys
|
|
oldPubKeys, err := getPubKeys(m.CryptoService, signedThing, data.CanonicalRootRole)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
mutate(&root)
|
|
|
|
sRoot := &data.SignedRoot{Signed: root, Signatures: signedThing.Signatures}
|
|
signedThing, err = sRoot.ToSigned()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pubKeys, err := getPubKeys(m.CryptoService, signedThing, data.CanonicalRootRole)
|
|
if err != nil || len(pubKeys) == 0 { // we have to sign it somehow - might as well use the old keys
|
|
pubKeys = oldPubKeys
|
|
}
|
|
|
|
metaBytes, err := serializeMetadata(m.CryptoService, signedThing, data.CanonicalRootRole, pubKeys...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(data.CanonicalRootRole, metaBytes)
|
|
}
|
|
|
|
// MutateTimestamp takes a function that mutates the timestamp metadata - once done, it
|
|
// serializes the timestamp again
|
|
func (m *MetadataSwizzler) MutateTimestamp(mutate func(*data.Timestamp)) error {
|
|
signedThing, err := signedFromStore(m.MetadataCache, data.CanonicalTimestampRole)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var timestamp data.Timestamp
|
|
if err := json.Unmarshal(*signedThing.Signed, ×tamp); err != nil {
|
|
return err
|
|
}
|
|
|
|
mutate(×tamp)
|
|
|
|
sTimestamp := &data.SignedTimestamp{Signed: timestamp, Signatures: signedThing.Signatures}
|
|
signedThing, err = sTimestamp.ToSigned()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pubKeys, err := getPubKeys(m.CryptoService, signedThing, data.CanonicalTimestampRole)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
metaBytes, err := serializeMetadata(m.CryptoService, signedThing, data.CanonicalTimestampRole, pubKeys...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(data.CanonicalTimestampRole, metaBytes)
|
|
}
|
|
|
|
// MutateSnapshot takes a function that mutates the snapshot metadata - once done, it
|
|
// serializes the snapshot again
|
|
func (m *MetadataSwizzler) MutateSnapshot(mutate func(*data.Snapshot)) error {
|
|
signedThing, err := signedFromStore(m.MetadataCache, data.CanonicalSnapshotRole)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var snapshot data.Snapshot
|
|
if err := json.Unmarshal(*signedThing.Signed, &snapshot); err != nil {
|
|
return err
|
|
}
|
|
|
|
mutate(&snapshot)
|
|
|
|
sSnapshot := &data.SignedSnapshot{Signed: snapshot, Signatures: signedThing.Signatures}
|
|
signedThing, err = sSnapshot.ToSigned()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pubKeys, err := getPubKeys(m.CryptoService, signedThing, data.CanonicalSnapshotRole)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
metaBytes, err := serializeMetadata(m.CryptoService, signedThing, data.CanonicalSnapshotRole, pubKeys...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(data.CanonicalSnapshotRole, metaBytes)
|
|
}
|
|
|
|
// MutateTargets takes a function that mutates the targets metadata - once done, it
|
|
// serializes the targets again
|
|
func (m *MetadataSwizzler) MutateTargets(mutate func(*data.Targets)) error {
|
|
signedThing, err := signedFromStore(m.MetadataCache, data.CanonicalTargetsRole)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var targets data.Targets
|
|
if err := json.Unmarshal(*signedThing.Signed, &targets); err != nil {
|
|
return err
|
|
}
|
|
|
|
mutate(&targets)
|
|
|
|
sTargets := &data.SignedTargets{Signed: targets, Signatures: signedThing.Signatures}
|
|
signedThing, err = sTargets.ToSigned()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pubKeys, err := getPubKeys(m.CryptoService, signedThing, data.CanonicalTargetsRole)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
metaBytes, err := serializeMetadata(m.CryptoService, signedThing, data.CanonicalTargetsRole, pubKeys...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.MetadataCache.SetMeta(data.CanonicalTargetsRole, metaBytes)
|
|
}
|