func TestRotationNewSigMissing(t *testing.T) { logrus.SetLevel(logrus.DebugLevel) kdb := keys.NewDB() signer := signed.NewEd25519() repo := tuf.NewRepo(kdb, signer) remote := store.NewMemoryStore(nil, nil) cache := store.NewMemoryStore(nil, nil) // Generate initial root key and role and add to key DB rootKey, err := signer.Create("root", data.ED25519Key) assert.NoError(t, err, "Error creating root key") rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil) assert.NoError(t, err, "Error creating root role") kdb.AddKey(rootKey) err = kdb.AddRole(rootRole) assert.NoError(t, err, "Error adding root role to db") // Generate new key and role. These will appear in the root.json // but will not be added to the keyDB. replacementKey, err := signer.Create("root", data.ED25519Key) assert.NoError(t, err, "Error creating replacement root key") replacementRole, err := data.NewRole("root", 1, []string{replacementKey.ID()}, nil, nil) assert.NoError(t, err, "Error creating replacement root role") assert.NotEqual(t, rootKey.ID(), replacementKey.ID(), "Key IDs are the same") // Generate a new root with the replacement key and role testRoot, err := data.NewRoot( map[string]data.PublicKey{replacementKey.ID(): replacementKey}, map[string]*data.RootRole{"root": &replacementRole.RootRole}, false, ) assert.NoError(t, err, "Failed to create new root") _, ok := testRoot.Signed.Keys[rootKey.ID()] assert.False(t, ok, "Old root key appeared in test root") // Sign testRoot with both old and new keys signedRoot, err := testRoot.ToSigned() err = signed.Sign(signer, signedRoot, rootKey) assert.NoError(t, err, "Failed to sign root") var origKeySig bool var replKeySig bool for _, sig := range signedRoot.Signatures { if sig.KeyID == rootKey.ID() { origKeySig = true } else if sig.KeyID == replacementKey.ID() { replKeySig = true } } assert.True(t, origKeySig, "Original root key signature not present") assert.False(t, replKeySig, "Replacement root key signature was present and shouldn't be") client := NewClient(repo, remote, kdb, cache) err = client.verifyRoot("root", signedRoot, 0) assert.Error(t, err, "Should have errored on verify as replacement signature was missing.") }
func TestUpdateDelegations(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) testKey, err := ed25519.Create("targets/test", data.ED25519Key) if err != nil { t.Fatal(err) } role, err := data.NewRole("targets/test", 1, []string{testKey.ID()}, []string{"test"}, []string{}) if err != nil { t.Fatal(err) } err = repo.UpdateDelegations(role, []data.Key{testKey}, "") if err != nil { t.Fatal(err) } testDeepKey, err := ed25519.Create("targets/test/deep", data.ED25519Key) if err != nil { t.Fatal(err) } roleDeep, err := data.NewRole("targets/test/deep", 1, []string{testDeepKey.ID()}, []string{"test/deep"}, []string{}) if err != nil { t.Fatal(err) } err = repo.UpdateDelegations(roleDeep, []data.Key{testDeepKey}, "") if err != nil { t.Fatal(err) } writeRepo(t, "/tmp/tufdelegation", repo) }
func initRoles(kdb *keys.KeyDB, rootKey, targetsKey, snapshotKey, timestampKey data.PublicKey) error { rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil) if err != nil { return err } targetsRole, err := data.NewRole("targets", 1, []string{targetsKey.ID()}, nil, nil) if err != nil { return err } snapshotRole, err := data.NewRole("snapshot", 1, []string{snapshotKey.ID()}, nil, nil) if err != nil { return err } timestampRole, err := data.NewRole("timestamp", 1, []string{timestampKey.ID()}, nil, nil) if err != nil { return err } if err := kdb.AddRole(rootRole); err != nil { return err } if err := kdb.AddRole(targetsRole); err != nil { return err } if err := kdb.AddRole(snapshotRole); err != nil { return err } if err := kdb.AddRole(timestampRole); err != nil { return err } return nil }
// SetRoot parses the Signed object into a SignedRoot object, sets // the keys and roles in the KeyDB, and sets the TufRepo.Root field // to the SignedRoot object. func (tr *TufRepo) SetRoot(s *data.Signed) error { r, err := data.RootFromSigned(s) if err != nil { return err } for _, key := range r.Signed.Keys { logrus.Debug("Adding key ", key.ID()) tr.keysDB.AddKey(key) } for roleName, role := range r.Signed.Roles { logrus.Debugf("Adding role %s with keys %s", roleName, strings.Join(role.KeyIDs, ",")) baseRole, err := data.NewRole( roleName, role.Threshold, role.KeyIDs, nil, nil, ) if err != nil { return err } err = tr.keysDB.AddRole(baseRole) if err != nil { return err } } tr.Root = r return nil }
// AddBaseKeys is used to add keys to the role in root.json func (tr *Repo) AddBaseKeys(role string, keys ...data.PublicKey) error { if tr.Root == nil { return ErrNotLoaded{role: "root"} } ids := []string{} for _, k := range keys { // Store only the public portion pubKey := data.NewPrivateKey(k.Algorithm(), k.Public(), nil) tr.Root.Signed.Keys[pubKey.ID()] = pubKey tr.keysDB.AddKey(k) tr.Root.Signed.Roles[role].KeyIDs = append(tr.Root.Signed.Roles[role].KeyIDs, pubKey.ID()) ids = append(ids, pubKey.ID()) } r, err := data.NewRole( role, tr.Root.Signed.Roles[role].Threshold, ids, nil, nil, ) if err != nil { return err } tr.keysDB.AddRole(r) tr.Root.Dirty = true return nil }
// SetRoot parses the Signed object into a SignedRoot object, sets // the keys and roles in the KeyDB, and sets the TufRepo.Root field // to the SignedRoot object. func (tr *TufRepo) SetRoot(s *data.Signed) error { r, err := data.RootFromSigned(s) if err != nil { return err } for kid, key := range r.Signed.Keys { tr.keysDB.AddKey(key) logrus.Debug("Given Key ID:", kid, "\nGenerated Key ID:", key.ID()) } for roleName, role := range r.Signed.Roles { baseRole, err := data.NewRole( roleName, role.Threshold, role.KeyIDs, nil, nil, ) if err != nil { return err } err = tr.keysDB.AddRole(baseRole) if err != nil { return err } } tr.Root = r return nil }
// SetRoot parses the Signed object into a SignedRoot object, sets // the keys and roles in the KeyDB, and sets the TufRepo.Root field // to the SignedRoot object. func (tr *TufRepo) SetRoot(s *data.Signed) error { r, err := data.RootFromSigned(s) if err != nil { return err } for _, key := range r.Signed.Keys { tr.keysDB.AddKey(key) } for roleName, role := range r.Signed.Roles { baseRole, err := data.NewRole( roleName, role.Threshold, role.KeyIDs, nil, nil, ) if err != nil { return err } err = tr.keysDB.AddRole(baseRole) if err != nil { return err } } tr.Root = r return nil }
// EmptyRepo creates an in memory key database, crypto service // and initializes a repo with no targets or delegations. func EmptyRepo() (*keys.KeyDB, *tuf.Repo, signed.CryptoService) { c := signed.NewEd25519() kdb := keys.NewDB() r := tuf.NewRepo(kdb, c) for _, role := range []string{"root", "targets", "snapshot", "timestamp"} { key, _ := c.Create(role, data.ED25519Key) role, _ := data.NewRole(role, 1, []string{key.ID()}, nil, nil) kdb.AddKey(key) kdb.AddRole(role) } r.InitRepo(false) return kdb, r, c }
func TestApplyChangelist(t *testing.T) { kdb := keys.NewDB() role, err := data.NewRole("targets", 1, nil, nil, nil) assert.NoError(t, err) kdb.AddRole(role) repo := tuf.NewTufRepo(kdb, nil) err = repo.InitTargets() assert.NoError(t, err) hash := sha256.Sum256([]byte{}) f := &data.FileMeta{ Length: 1, Hashes: map[string][]byte{ "sha256": hash[:], }, } fjson, err := json.Marshal(f) assert.NoError(t, err) cl := changelist.NewMemChangelist() addChange := &changelist.TufChange{ Actn: changelist.ActionCreate, Role: changelist.ScopeTargets, ChangeType: "target", ChangePath: "latest", Data: fjson, } cl.Add(addChange) err = applyChangelist(repo, cl) assert.NoError(t, err) assert.NotNil(t, repo.Targets["targets"].Signed.Targets["latest"]) cl.Clear("") removeChange := &changelist.TufChange{ Actn: changelist.ActionDelete, Role: changelist.ScopeTargets, ChangeType: "target", ChangePath: "latest", Data: nil, } cl.Add(removeChange) err = applyChangelist(repo, cl) assert.NoError(t, err) _, ok := repo.Targets["targets"].Signed.Targets["latest"] assert.False(t, ok) }
func tufInit(cmd *cobra.Command, args []string) { if len(args) < 1 { cmd.Usage() fatalf("Must specify a GUN") } gun := args[0] kdb := keys.NewDB() signer := signed.NewSigner(NewCryptoService(gun)) rootKey, err := signer.Create("root") if err != nil { fatalf(err.Error()) } targetsKey, err := signer.Create("targets") if err != nil { fatalf(err.Error()) } snapshotKey, err := signer.Create("snapshot") if err != nil { fatalf(err.Error()) } timestampKey, err := signer.Create("timestamp") if err != nil { fatalf(err.Error()) } kdb.AddKey(rootKey) kdb.AddKey(targetsKey) kdb.AddKey(snapshotKey) kdb.AddKey(timestampKey) rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil) if err != nil { fatalf(err.Error()) } targetsRole, err := data.NewRole("targets", 1, []string{targetsKey.ID()}, nil, nil) if err != nil { fatalf(err.Error()) } snapshotRole, err := data.NewRole("snapshot", 1, []string{snapshotKey.ID()}, nil, nil) if err != nil { fatalf(err.Error()) } timestampRole, err := data.NewRole("timestamp", 1, []string{timestampKey.ID()}, nil, nil) if err != nil { fatalf(err.Error()) } err = kdb.AddRole(rootRole) if err != nil { fatalf(err.Error()) } err = kdb.AddRole(targetsRole) if err != nil { fatalf(err.Error()) } err = kdb.AddRole(snapshotRole) if err != nil { fatalf(err.Error()) } err = kdb.AddRole(timestampRole) if err != nil { fatalf(err.Error()) } repo := tuf.NewTufRepo(kdb, signer) filestore, err := store.NewFilesystemStore( path.Join(viper.GetString("tufDir"), gun), // TODO: base trust dir from config "metadata", "json", "targets", ) if err != nil { fatalf(err.Error()) } err = repo.InitRepo(false) if err != nil { fatalf(err.Error()) } saveRepo(repo, filestore) }
func testValidateRootRotationMissingNewSig(t *testing.T, keyAlg data.KeyAlgorithm, rootKeyType data.KeyAlgorithm) { // Temporary directory where test files will be created tempBaseDir, err := ioutil.TempDir("", "notary-test-") defer os.RemoveAll(tempBaseDir) assert.NoError(t, err, "failed to create a temporary directory: %s", err) // The gun to test gun := "docker.com/notary" // Create a FileStoreManager keyStoreManager, err := NewKeyStoreManager(tempBaseDir, passphraseRetriever) assert.NoError(t, err) origRootKeyID, err := keyStoreManager.GenRootKey(keyAlg.String()) assert.NoError(t, err) replRootKeyID, err := keyStoreManager.GenRootKey(keyAlg.String()) assert.NoError(t, err) origUnlockedCryptoService, err := keyStoreManager.GetRootCryptoService(origRootKeyID) assert.NoError(t, err) replUnlockedCryptoService, err := keyStoreManager.GetRootCryptoService(replRootKeyID) assert.NoError(t, err) // Generating the certificate automatically adds it to the trusted store origRootCert, err := origUnlockedCryptoService.GenerateCertificate(gun) assert.NoError(t, err) // Add the old root cert part of trustedCertificates keyStoreManager.AddTrustedCert(origRootCert) assert.NoError(t, err) // Generate a certificate for our replacement root key replRootCert, err := replUnlockedCryptoService.GenerateCertificate(gun) assert.NoError(t, err) // We need the PEM representation of the replacement key to put it into the TUF data origRootPEMCert := trustmanager.CertToPEM(origRootCert) replRootPEMCert := trustmanager.CertToPEM(replRootCert) // Tuf key with PEM-encoded x509 certificate origRootKey := data.NewPublicKey(rootKeyType, origRootPEMCert) replRootKey := data.NewPublicKey(rootKeyType, replRootPEMCert) // Link both certificates to the original public keys err = keyStoreManager.RootKeyStore().Link(origRootKeyID+"_root", origRootKey.ID()+"_root") assert.NoError(t, err) err = keyStoreManager.RootKeyStore().Link(replRootKeyID+"_root", replRootKey.ID()+"_root") assert.NoError(t, err) rootRole, err := data.NewRole("root", 1, []string{replRootKey.ID()}, nil, nil) assert.NoError(t, err) testRoot, err := data.NewRoot( map[string]data.PublicKey{replRootKey.ID(): replRootKey}, map[string]*data.RootRole{"root": &rootRole.RootRole}, false, ) assert.NoError(t, err, "Failed to create new root") signedTestRoot, err := testRoot.ToSigned() assert.NoError(t, err) // We only sign with the old key, and not with the new one err = signed.Sign(replUnlockedCryptoService.CryptoService, signedTestRoot, origRootKey) assert.NoError(t, err) // // This call to ValidateRoot will succeed since we are using a valid PEM // encoded certificate, and have no other certificates for this CN // err = keyStoreManager.ValidateRoot(signedTestRoot, gun) assert.Error(t, err, "insuficient signatures on root") // Finally, validate the only trusted certificate that exists is still // the old one certs := keyStoreManager.trustedCertificateStore.GetCertificates() assert.Len(t, certs, 1) assert.Equal(t, certs[0], origRootCert) }
func TestValidateRootRotation(t *testing.T) { _, repo, crypto := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) assert.NoError(t, err) store.UpdateCurrent( "testGUN", storage.MetaUpdate{ Role: "root", Version: 1, Data: root, }, ) oldRootRole := repo.Root.Signed.Roles["root"] oldRootKey := repo.Root.Signed.Keys[oldRootRole.KeyIDs[0]] rootKey, err := crypto.Create("root", data.ED25519Key) assert.NoError(t, err) rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil) assert.NoError(t, err) delete(repo.Root.Signed.Keys, oldRootRole.KeyIDs[0]) repo.Root.Signed.Roles["root"] = &rootRole.RootRole repo.Root.Signed.Keys[rootKey.ID()] = data.NewPrivateKey(rootKey.Algorithm(), rootKey.Public(), nil) r, err = repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole), nil) assert.NoError(t, err) err = signed.Sign(crypto, r, rootKey, oldRootKey) assert.NoError(t, err) rt, err := data.RootFromSigned(r) assert.NoError(t, err) repo.SetRoot(rt) sn, err = repo.SignSnapshot(data.DefaultExpires(data.CanonicalSnapshotRole), nil) assert.NoError(t, err) root, targets, snapshot, timestamp, err = testutils.Serialize(r, tg, sn, ts) assert.NoError(t, err) updates := []storage.MetaUpdate{ { Role: "root", Version: 1, Data: root, }, { Role: "targets", Version: 1, Data: targets, }, { Role: "snapshot", Version: 1, Data: snapshot, }, { Role: "timestamp", Version: 1, Data: timestamp, }, } err = validateUpdate("testGUN", updates, store) assert.NoError(t, err) }
// Initialize creates a new repository by using rootKey as the root Key for the // TUF repository. func (r *NotaryRepository) Initialize(uSigner *UnlockedSigner) error { rootCert, err := uSigner.GenerateCertificate(r.Gun) if err != nil { return err } r.certificateStore.AddCert(rootCert) rootKey := data.NewPublicKey("RSA", trustmanager.CertToPEM(rootCert)) err = r.rootKeyStore.Link(uSigner.ID(), rootKey.ID()) if err != nil { return err } remote, err := getRemoteStore(r.baseURL, r.Gun) rawTSKey, err := remote.GetKey("timestamp") if err != nil { return err } parsedKey := &data.TUFKey{} err = json.Unmarshal(rawTSKey, parsedKey) if err != nil { return err } timestampKey := data.NewPublicKey(parsedKey.Cipher(), parsedKey.Public()) targetsKey, err := r.signer.Create("targets") if err != nil { return err } snapshotKey, err := r.signer.Create("snapshot") if err != nil { return err } kdb := keys.NewDB() kdb.AddKey(rootKey) kdb.AddKey(targetsKey) kdb.AddKey(snapshotKey) kdb.AddKey(timestampKey) rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil) if err != nil { return err } targetsRole, err := data.NewRole("targets", 1, []string{targetsKey.ID()}, nil, nil) if err != nil { return err } snapshotRole, err := data.NewRole("snapshot", 1, []string{snapshotKey.ID()}, nil, nil) if err != nil { return err } timestampRole, err := data.NewRole("timestamp", 1, []string{timestampKey.ID()}, nil, nil) if err != nil { return err } if err := kdb.AddRole(rootRole); err != nil { return err } if err := kdb.AddRole(targetsRole); err != nil { return err } if err := kdb.AddRole(snapshotRole); err != nil { return err } if err := kdb.AddRole(timestampRole); err != nil { return err } r.tufRepo = tuf.NewTufRepo(kdb, r.signer) r.fileStore, err = store.NewFilesystemStore( r.tufRepoPath, "metadata", "json", "targets", ) if err != nil { return err } if err := r.tufRepo.InitRepo(false); err != nil { return err } if err := r.saveMetadata(uSigner.signer); err != nil { return err } // Creates an empty snapshot return r.snapshot() }
// Initialize creates a new repository by using rootKey as the root Key for the // TUF repository. func (r *NotaryRepository) Initialize(uCryptoService *cryptoservice.UnlockedCryptoService) error { rootCert, err := uCryptoService.GenerateCertificate(r.gun) if err != nil { return err } r.KeyStoreManager.AddTrustedCert(rootCert) // The root key gets stored in the TUF metadata X509 encoded, linking // the tuf root.json to our X509 PKI. // If the key is RSA, we store it as type RSAx509, if it is ECDSA we store it // as ECDSAx509 to allow the gotuf verifiers to correctly decode the // key on verification of signatures. var algorithmType data.KeyAlgorithm algorithm := uCryptoService.PrivKey.Algorithm() switch algorithm { case data.RSAKey: algorithmType = data.RSAx509Key case data.ECDSAKey: algorithmType = data.ECDSAx509Key default: return fmt.Errorf("invalid format for root key: %s", algorithm) } // Generate a x509Key using the rootCert as the public key rootKey := data.NewPublicKey(algorithmType, trustmanager.CertToPEM(rootCert)) // Creates a symlink between the certificate ID and the real public key it // is associated with. This is used to be able to retrieve the root private key // associated with a particular certificate logrus.Debugf("Linking %s to %s.", rootKey.ID(), uCryptoService.ID()) err = r.KeyStoreManager.RootKeyStore().Link(uCryptoService.ID(), rootKey.ID()) if err != nil { return err } // All the timestamp keys are generated by the remote server. remote, err := getRemoteStore(r.baseURL, r.gun, r.roundTrip) rawTSKey, err := remote.GetKey("timestamp") if err != nil { return err } parsedKey := &data.TUFKey{} err = json.Unmarshal(rawTSKey, parsedKey) if err != nil { return err } // Turn the JSON timestamp key from the remote server into a TUFKey timestampKey := data.NewPublicKey(parsedKey.Algorithm(), parsedKey.Public()) logrus.Debugf("got remote %s timestamp key with keyID: %s", parsedKey.Algorithm(), timestampKey.ID()) // This is currently hardcoding the targets and snapshots keys to ECDSA // Targets and snapshot keys are always generated locally. targetsKey, err := r.cryptoService.Create("targets", data.ECDSAKey) if err != nil { return err } snapshotKey, err := r.cryptoService.Create("snapshot", data.ECDSAKey) if err != nil { return err } kdb := keys.NewDB() kdb.AddKey(rootKey) kdb.AddKey(targetsKey) kdb.AddKey(snapshotKey) kdb.AddKey(timestampKey) rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil) if err != nil { return err } targetsRole, err := data.NewRole("targets", 1, []string{targetsKey.ID()}, nil, nil) if err != nil { return err } snapshotRole, err := data.NewRole("snapshot", 1, []string{snapshotKey.ID()}, nil, nil) if err != nil { return err } timestampRole, err := data.NewRole("timestamp", 1, []string{timestampKey.ID()}, nil, nil) if err != nil { return err } if err := kdb.AddRole(rootRole); err != nil { return err } if err := kdb.AddRole(targetsRole); err != nil { return err } if err := kdb.AddRole(snapshotRole); err != nil { return err } if err := kdb.AddRole(timestampRole); err != nil { return err } r.tufRepo = tuf.NewTufRepo(kdb, r.cryptoService) r.fileStore, err = store.NewFilesystemStore( r.tufRepoPath, "metadata", "json", "targets", ) if err != nil { return err } if err := r.tufRepo.InitRepo(false); err != nil { return err } if err := r.saveMetadata(uCryptoService.CryptoService); err != nil { return err } // Creates an empty snapshot return r.snapshot() }