func (tr *TufRepo) InitRoot(consistent bool) error { rootRoles := make(map[string]*data.RootRole) rootKeys := make(map[string]data.PublicKey) for _, r := range data.ValidRoles { role := tr.keysDB.GetRole(r) if role == nil { return errors.ErrInvalidRole{} } rootRoles[r] = &role.RootRole for _, kid := range role.KeyIDs { // don't need to check if GetKey returns nil, Key presence was // checked by KeyDB when role was added. key := tr.keysDB.GetKey(kid) // Create new key object to doubly ensure private key is excluded k := data.NewPublicKey(key.Algorithm(), key.Public()) rootKeys[kid] = k } } root, err := data.NewRoot(rootKeys, rootRoles, consistent) if err != nil { return err } tr.Root = root return nil }
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.") }
// InitRepo creates the base files for a repo. It inspects data.ValidRoles and // data.ValidTypes to determine what the role names and filename should be. It // also relies on the keysDB having already been populated with the keys and // roles. func (tr *TufRepo) InitRepo(consistent bool) error { rootRoles := make(map[string]*data.RootRole) rootKeys := make(map[string]*data.PublicKey) for _, r := range data.ValidRoles { role := tr.keysDB.GetRole(r) if role == nil { return errors.ErrInvalidRole{} } rootRoles[r] = &role.RootRole for _, kid := range role.KeyIDs { // don't need to check if GetKey returns nil, Key presence was // checked by KeyDB when role was added. key := tr.keysDB.GetKey(kid) // Create new key object to doubly ensure private key is excluded k := data.NewPublicKey(key.Cipher(), key.Public()) rootKeys[kid] = k } } root, err := data.NewRoot(rootKeys, rootRoles, consistent) if err != nil { return err } tr.Root = root targets := data.NewTargets() tr.Targets[data.ValidRoles["targets"]] = targets signedRoot, err := tr.SignRoot(data.DefaultExpires("root")) if err != nil { return err } signedTargets, err := tr.SignTargets("targets", data.DefaultExpires("targets")) if err != nil { return err } snapshot, err := data.NewSnapshot(signedRoot, signedTargets) if err != nil { return err } tr.Snapshot = snapshot signedSnapshot, err := tr.SignSnapshot(data.DefaultExpires("snapshot")) if err != nil { return err } timestamp, err := data.NewTimestamp(signedSnapshot) if err != nil { return err } tr.Timestamp = timestamp return nil }
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) }