make x509 certs viable as delegated public key object

Signed-off-by: David Lawrence <david.lawrence@docker.com> (github: endophage)
This commit is contained in:
David Lawrence 2015-12-22 14:49:43 -08:00 committed by Ying Li
parent 2bf5d4b09a
commit fa788cb2a9
3 changed files with 100 additions and 4 deletions

View File

@ -367,7 +367,7 @@ func (r *NotaryRepository) RemoveDelegation(name string) error {
// AddTarget creates new changelist entries to add a target to the given roles
// in the repository when the changelist gets appied at publish time.
// If roles are unspecified, the default role is "target".
// If roles are unspecified, the default role is "targets".
func (r *NotaryRepository) AddTarget(target *Target, roles ...string) error {
cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist"))

View File

@ -15,6 +15,7 @@ import (
"sort"
"strings"
"testing"
"time"
"github.com/Sirupsen/logrus"
ctxu "github.com/docker/distribution/context"
@ -1581,6 +1582,93 @@ func TestPublishDelegations(t *testing.T) {
}
}
// Publishing delegations works so long as the delegation parent exists by the
// time that delegation addition change is applied. Most of the tests for
// applying delegation changes in in helpers_test.go (applyTargets tests), so
// this is just a sanity test to make sure Publish calls it correctly and
// no fallback happens.
func TestPublishDelegationsX509(t *testing.T) {
var tempDirs [2]string
for i := 0; i < 2; i++ {
tempBaseDir, err := ioutil.TempDir("", "notary-test-")
assert.NoError(t, err, "failed to create a temporary directory: %s", err)
defer os.RemoveAll(tempBaseDir)
tempDirs[i] = tempBaseDir
}
gun := "docker.com/notary"
ts := fullTestServer(t)
defer ts.Close()
repo1, _ := initializeRepo(t, data.ECDSAKey, tempDirs[0], gun, ts.URL, false)
delgKey, err := repo1.CryptoService.Create("targets/a", data.ECDSAKey)
assert.NoError(t, err, "error creating delegation key")
start := time.Now()
privKey, _, err := repo1.CryptoService.GetPrivateKey(delgKey.ID())
assert.NoError(t, err)
cert, err := cryptoservice.GenerateCertificate(
privKey, "targets/a", start, start.AddDate(1, 0, 0),
)
assert.NoError(t, err)
delgCert := data.NewECDSAx509PublicKey(trustmanager.CertToPEM(cert))
// This should publish fine, even though targets/a/b is dependent upon
// targets/a, because these should execute in order
for _, delgName := range []string{"targets/a", "targets/a/b", "targets/c"} {
assert.NoError(t,
repo1.AddDelegation(delgName, 1, []data.PublicKey{delgCert}, []string{""}),
"error creating delegation")
}
assert.Len(t, getChanges(t, repo1), 3, "wrong number of changelist files found")
assert.NoError(t, repo1.Publish())
assert.Len(t, getChanges(t, repo1), 0, "wrong number of changelist files found")
// this should not publish, because targets/z doesn't exist
assert.NoError(t,
repo1.AddDelegation("targets/z/y", 1, []data.PublicKey{delgCert}, []string{""}),
"error creating delegation")
assert.Len(t, getChanges(t, repo1), 1, "wrong number of changelist files found")
assert.Error(t, repo1.Publish())
assert.Len(t, getChanges(t, repo1), 1, "wrong number of changelist files found")
// Create a new repo and pull from the server
repo2, err := NewNotaryRepository(tempDirs[1], gun, ts.URL,
http.DefaultTransport, passphraseRetriever)
assert.NoError(t, err, "error creating repository: %s", err)
// pull
_, err = repo2.ListTargets()
assert.NoError(t, err, "unable to pull repo")
for _, repo := range []*NotaryRepository{repo1, repo2} {
// targets should have delegations targets/a and targets/c
targets := repo.tufRepo.Targets[data.CanonicalTargetsRole]
assert.Len(t, targets.Signed.Delegations.Roles, 2)
assert.Len(t, targets.Signed.Delegations.Keys, 1)
_, ok := targets.Signed.Delegations.Keys[delgCert.ID()]
assert.True(t, ok)
foundRoleNames := make(map[string]bool)
for _, r := range targets.Signed.Delegations.Roles {
foundRoleNames[r.Name] = true
}
assert.True(t, foundRoleNames["targets/a"])
assert.True(t, foundRoleNames["targets/c"])
// targets/a should have delegation targets/a/b only
a := repo.tufRepo.Targets["targets/a"]
assert.Len(t, a.Signed.Delegations.Roles, 1)
assert.Len(t, a.Signed.Delegations.Keys, 1)
_, ok = a.Signed.Delegations.Keys[delgCert.ID()]
assert.True(t, ok)
assert.Equal(t, "targets/a/b", a.Signed.Delegations.Roles[0].Name)
}
}
// If a changelist specifies a particular role to push targets to, and there
// is no such role, publish will try to publish to its parent. If the parent
// doesn't work, it falls back on its parent, and so forth, and eventually

View File

@ -530,9 +530,17 @@ func (tr *Repo) VerifyCanSign(roleName string) error {
}
for _, keyID := range role.KeyIDs {
p, _, err := tr.cryptoService.GetPrivateKey(keyID)
if err == nil && p != nil {
return nil
k := tr.keysDB.GetKey(keyID)
canonicalID, err := utils.CanonicalKeyID(k)
check := []string{keyID}
if err == nil {
check = append(check, canonicalID)
}
for _, id := range check {
p, _, err := tr.cryptoService.GetPrivateKey(id)
if err == nil && p != nil {
return nil
}
}
}
return signed.ErrNoKeys{KeyIDs: role.KeyIDs}