Esempio n. 1
0
func testValidateSuccessfulRootRotation(t *testing.T, keyAlg, rootKeyType string) {
	// The gun to test
	gun := "docker.com/notary"

	tempBaseDir, keyStoreManager, certs := filestoreWithTwoCerts(t, gun, keyAlg)
	defer os.RemoveAll(tempBaseDir)
	origRootCert := certs[0]
	replRootCert := certs[1]

	// Add the old root cert part of trustedCertificates
	keyStoreManager.AddTrustedCert(origRootCert)

	// 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)

	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)

	cs := cryptoservice.NewCryptoService(gun, keyStoreManager.KeyStore)

	err = signed.Sign(cs, signedTestRoot, replRootKey)
	assert.NoError(t, err)

	err = signed.Sign(cs, 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.NoError(t, err)

	// Finally, validate the only trusted certificate that exists is the new one
	certs = keyStoreManager.trustedCertificateStore.GetCertificates()
	assert.Len(t, certs, 1)
	assert.Equal(t, certs[0], replRootCert)
}
Esempio n. 2
0
func (tr Repo) sign(signedData *data.Signed, roles []data.BaseRole, optionalKeys []data.PublicKey) (*data.Signed, error) {
	validKeys := optionalKeys
	for _, r := range roles {
		roleKeys := r.ListKeys()
		validKeys = append(roleKeys, validKeys...)
		if err := signed.Sign(tr.cryptoService, signedData, roleKeys, r.Threshold, validKeys); err != nil {
			return nil, err
		}
	}
	// Attempt to sign with the optional keys, but ignore any errors, because these keys are optional
	signed.Sign(tr.cryptoService, signedData, optionalKeys, 0, validKeys)

	return signedData, nil
}
Esempio n. 3
0
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.")

}
Esempio n. 4
0
func TestRotation(t *testing.T) {
	signer := signed.NewEd25519()
	repo := tuf.NewRepo(signer)
	remote := store.NewMemoryStore(nil)
	cache := store.NewMemoryStore(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)
	assert.NoError(t, err, "Error creating root role")

	originalRoot, err := data.NewRoot(
		map[string]data.PublicKey{rootKey.ID(): rootKey},
		map[string]*data.RootRole{"root": &rootRole.RootRole},
		false,
	)

	repo.Root = originalRoot

	// Generate new key and role.
	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)
	assert.NoError(t, err, "Error creating replacement root role")

	// 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{
			data.CanonicalRootRole:      &replacementRole.RootRole,
			data.CanonicalSnapshotRole:  &replacementRole.RootRole,
			data.CanonicalTargetsRole:   &replacementRole.RootRole,
			data.CanonicalTimestampRole: &replacementRole.RootRole,
		},
		false,
	)
	assert.NoError(t, err, "Failed to create new root")

	// Sign testRoot with both old and new keys
	signedRoot, err := testRoot.ToSigned()
	err = signed.Sign(signer, signedRoot, rootKey, replacementKey)
	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.True(t, replKeySig, "Replacement root key signature not present")

	client := NewClient(repo, remote, cache)

	err = client.verifyRoot("root", signedRoot, 0)
	assert.NoError(t, err, "Failed to verify key rotated root")
}
Esempio 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
}
Esempio n. 6
0
func (tr Repo) sign(signedData *data.Signed, role data.BaseRole) (*data.Signed, error) {
	ks := role.ListKeys()
	if len(ks) < 1 {
		return nil, signed.ErrNoKeys{}
	}
	err := signed.Sign(tr.cryptoService, signedData, ks...)
	if err != nil {
		return nil, err
	}
	return signedData, nil
}
Esempio n. 7
0
func testValidateRootRotationMissingNewSig(t *testing.T, keyAlg, rootKeyType string) {
	gun := "docker.com/notary"

	tempBaseDir, certStore, cryptoService, certificates := filestoreWithTwoCerts(
		t, gun, keyAlg)
	defer os.RemoveAll(tempBaseDir)
	origRootCert := certificates[0]
	replRootCert := certificates[1]

	// Add the old root cert part of trustedCertificates
	certStore.AddCert(origRootCert)

	// 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)

	rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{replRootKey.ID()}, nil)
	assert.NoError(t, err)

	testRoot, err := data.NewRoot(
		map[string]data.PublicKey{replRootKey.ID(): replRootKey},
		map[string]*data.RootRole{data.CanonicalRootRole: &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(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 = ValidateRoot(certStore, signedTestRoot, gun)
	assert.Error(t, err, "insuficient signatures on root")

	// Finally, validate the only trusted certificate that exists is still
	// the old one
	certificates = certStore.GetCertificates()
	assert.Len(t, certificates, 1)
	assert.Equal(t, certificates[0], origRootCert)
}
Esempio n. 8
0
func TestValidateRootRotation(t *testing.T) {
	repo, crypto, err := testutils.EmptyRepo("docker.com/notary")
	assert.NoError(t, err)
	store := storage.NewMemStorage()

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

	store.UpdateCurrent("testGUN", 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)
	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()] = rootKey

	r, err = repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole))
	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))
	assert.NoError(t, err)
	root, targets, snapshot, timestamp, err = getUpdates(r, tg, sn, ts)
	assert.NoError(t, err)

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

	copyTimestampKey(t, repo, store, "testGUN")
	_, err = validateUpdate(crypto, "testGUN", updates, store)
	assert.NoError(t, err)
}
Esempio n. 9
0
func (tr Repo) sign(signedData *data.Signed, role data.Role) (*data.Signed, error) {
	ks := make([]data.PublicKey, 0, len(role.KeyIDs))
	for _, kid := range role.KeyIDs {
		k := tr.keysDB.GetKey(kid)
		if k == nil {
			continue
		}
		ks = append(ks, k)
	}
	if len(ks) < 1 {
		return nil, keys.ErrInvalidKey
	}
	err := signed.Sign(tr.cryptoService, signedData, ks...)
	if err != nil {
		return nil, err
	}
	return signedData, nil
}
Esempio n. 10
0
// createSnapshot uses an existing snapshot to create a new one.
// Important things to be aware of:
//   - It requires that a snapshot already exists. We create snapshots
//     on upload so there should always be an existing snapshot if this
//     gets called.
//   - It doesn't update what roles are present in the snapshot, as those
//     were validated during upload.
func createSnapshot(gun string, sn *data.SignedSnapshot, store storage.MetaStore, cryptoService signed.CryptoService) (*data.Signed, int, error) {
	algorithm, public, err := store.GetKey(gun, data.CanonicalSnapshotRole)
	if err != nil {
		// owner of gun must have generated a snapshot key otherwise
		// we won't proceed with generating everything.
		return nil, 0, err
	}
	key := data.NewPublicKey(algorithm, public)

	// update version and expiry
	sn.Signed.Version = sn.Signed.Version + 1
	sn.Signed.Expires = data.DefaultExpires(data.CanonicalSnapshotRole)

	out, err := sn.ToSigned()
	if err != nil {
		return nil, 0, err
	}
	err = signed.Sign(cryptoService, out, key)
	if err != nil {
		return nil, 0, err
	}
	return out, sn.Signed.Version, nil
}
Esempio n. 11
0
// 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
}
Esempio n. 12
0
func testValidateRootRotationMissingNewSig(t *testing.T, keyAlg, rootKeyType string) {
	gun := "docker.com/notary"

	memKeyStore := trustmanager.NewKeyMemoryStore(passphraseRetriever)
	cs := cryptoservice.NewCryptoService(memKeyStore)

	// TUF key with PEM-encoded x509 certificate
	origRootKey, err := testutils.CreateKey(cs, gun, data.CanonicalRootRole, keyAlg)
	require.NoError(t, err)

	origRootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{origRootKey.ID()}, nil)
	require.NoError(t, err)

	origTestRoot, err := data.NewRoot(
		map[string]data.PublicKey{origRootKey.ID(): origRootKey},
		map[string]*data.RootRole{
			data.CanonicalRootRole:      &origRootRole.RootRole,
			data.CanonicalTargetsRole:   &origRootRole.RootRole,
			data.CanonicalSnapshotRole:  &origRootRole.RootRole,
			data.CanonicalTimestampRole: &origRootRole.RootRole,
		},
		false,
	)
	origTestRoot.Signed.Version = 1
	require.NoError(t, err, "Failed to create new root")

	signedOrigTestRoot, err := origTestRoot.ToSigned()
	require.NoError(t, err)

	err = signed.Sign(cs, signedOrigTestRoot, []data.PublicKey{origRootKey}, 1, nil)
	require.NoError(t, err)
	prevRoot, err := data.RootFromSigned(signedOrigTestRoot)
	require.NoError(t, err)

	// TUF key with PEM-encoded x509 certificate
	replRootKey, err := testutils.CreateKey(cs, gun, data.CanonicalRootRole, keyAlg)
	require.NoError(t, err)

	rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{replRootKey.ID()}, nil)
	require.NoError(t, err)

	testRoot, err := data.NewRoot(
		map[string]data.PublicKey{replRootKey.ID(): replRootKey},
		map[string]*data.RootRole{
			data.CanonicalRootRole:      &rootRole.RootRole,
			data.CanonicalTargetsRole:   &rootRole.RootRole,
			data.CanonicalSnapshotRole:  &rootRole.RootRole,
			data.CanonicalTimestampRole: &rootRole.RootRole,
		},
		false,
	)
	require.NoError(t, err, "Failed to create new root")

	signedTestRoot, err := testRoot.ToSigned()
	require.NoError(t, err)

	// We only sign with the old key, and not with the new one
	err = signed.Sign(cs, signedTestRoot, []data.PublicKey{origRootKey}, 1, nil)
	require.NoError(t, err)

	// This call to trustpinning.ValidateRoot will succeed since we are using a valid PEM
	// encoded certificate, and have no other certificates for this CN
	_, err = trustpinning.ValidateRoot(prevRoot, signedTestRoot, gun, trustpinning.TrustPinConfig{})
	require.Error(t, err, "insuficient signatures on root")
}
Esempio n. 13
0
func TestValidateRootWithPinnedCA(t *testing.T) {
	var testSignedRoot data.Signed
	var signedRootBytes bytes.Buffer

	// Temporary directory where test files will be created
	tempBaseDir, err := ioutil.TempDir("", "notary-test-")
	defer os.RemoveAll(tempBaseDir)
	require.NoError(t, err, "failed to create a temporary directory: %s", err)

	templ, _ := template.New("SignedRSARootTemplate").Parse(signedRSARootTemplate)
	templ.Execute(&signedRootBytes, SignedRSARootTemplate{RootPem: validPEMEncodedRSARoot})
	// Unmarshal our signedRoot
	json.Unmarshal(signedRootBytes.Bytes(), &testSignedRoot)
	typedSignedRoot, err := data.RootFromSigned(&testSignedRoot)
	require.NoError(t, err)

	// This call to trustpinning.ValidateRoot will fail because we have an invalid path for the CA
	_, err = trustpinning.ValidateRoot(nil, &testSignedRoot, "docker.com/notary", trustpinning.TrustPinConfig{CA: map[string]string{"docker.com/notary": filepath.Join(tempBaseDir, "nonexistent")}})
	require.Error(t, err)

	// This call to trustpinning.ValidateRoot will fail because we have no valid GUNs to use, and TOFUS is disabled
	_, err = trustpinning.ValidateRoot(nil, &testSignedRoot, "docker.com/notary", trustpinning.TrustPinConfig{CA: map[string]string{"othergun": filepath.Join(tempBaseDir, "nonexistent")}, DisableTOFU: true})
	require.Error(t, err)

	// This call to trustpinning.ValidateRoot will succeed because we have no valid GUNs to use and we fall back to enabled TOFUS
	validatedRoot, err := trustpinning.ValidateRoot(nil, &testSignedRoot, "docker.com/notary", trustpinning.TrustPinConfig{CA: map[string]string{"othergun": filepath.Join(tempBaseDir, "nonexistent")}, DisableTOFU: false})
	require.NoError(t, err)
	generateRootKeyIDs(typedSignedRoot)
	require.Equal(t, typedSignedRoot, validatedRoot)

	// Write an invalid CA cert (not even a PEM) to the tempDir and ensure validation fails when using it
	invalidCAFilepath := filepath.Join(tempBaseDir, "invalid.ca")
	require.NoError(t, ioutil.WriteFile(invalidCAFilepath, []byte("ABSOLUTELY NOT A PEM"), 0644))

	// Using this invalid CA cert should fail on trustpinning.ValidateRoot
	_, err = trustpinning.ValidateRoot(nil, &testSignedRoot, "docker.com/notary", trustpinning.TrustPinConfig{CA: map[string]string{"docker.com/notary": invalidCAFilepath}, DisableTOFU: true})
	require.Error(t, err)

	validCAFilepath := "../fixtures/root-ca.crt"

	// If we pass an invalid Certs entry in addition to this valid CA entry, since Certs has priority for pinning we will fail
	_, err = trustpinning.ValidateRoot(nil, &testSignedRoot, "docker.com/notary", trustpinning.TrustPinConfig{Certs: map[string][]string{"docker.com/notary": {"invalidID"}}, CA: map[string]string{"docker.com/notary": validCAFilepath}, DisableTOFU: true})
	require.Error(t, err)

	// Now construct a new root with a valid cert chain, such that signatures are correct over the 'notary-signer' GUN.  Pin the root-ca and validate
	leafCert, err := trustmanager.LoadCertFromFile("../fixtures/notary-signer.crt")
	require.NoError(t, err)

	intermediateCert, err := trustmanager.LoadCertFromFile("../fixtures/intermediate-ca.crt")
	require.NoError(t, err)

	pemChainBytes, err := trustmanager.CertChainToPEM([]*x509.Certificate{leafCert, intermediateCert})
	require.NoError(t, err)

	newRootKey := data.NewPublicKey(data.RSAx509Key, pemChainBytes)

	rootRole, err := data.NewRole(data.CanonicalRootRole, 1, []string{newRootKey.ID()}, nil)
	require.NoError(t, err)

	testRoot, err := data.NewRoot(
		map[string]data.PublicKey{newRootKey.ID(): newRootKey},
		map[string]*data.RootRole{
			data.CanonicalRootRole:      &rootRole.RootRole,
			data.CanonicalTimestampRole: &rootRole.RootRole,
			data.CanonicalTargetsRole:   &rootRole.RootRole,
			data.CanonicalSnapshotRole:  &rootRole.RootRole},
		false,
	)
	testRoot.Signed.Version = 1
	require.NoError(t, err, "Failed to create new root")

	keyReader, err := os.Open("../fixtures/notary-signer.key")
	require.NoError(t, err, "could not open key file")
	pemBytes, err := ioutil.ReadAll(keyReader)
	require.NoError(t, err, "could not read key file")
	privKey, err := trustmanager.ParsePEMPrivateKey(pemBytes, "")
	require.NoError(t, err)

	store, err := trustmanager.NewKeyFileStore(tempBaseDir, passphraseRetriever)
	require.NoError(t, err)
	cs := cryptoservice.NewCryptoService(store)

	err = store.AddKey(trustmanager.KeyInfo{Role: data.CanonicalRootRole, Gun: "notary-signer"}, privKey)
	require.NoError(t, err)

	newTestSignedRoot, err := testRoot.ToSigned()
	require.NoError(t, err)

	err = signed.Sign(cs, newTestSignedRoot, []data.PublicKey{newRootKey}, 1, nil)
	require.NoError(t, err)

	newTypedSignedRoot, err := data.RootFromSigned(newTestSignedRoot)
	require.NoError(t, err)

	// Check that we validate correctly against a pinned CA and provided bundle
	validatedRoot, err = trustpinning.ValidateRoot(nil, newTestSignedRoot, "notary-signer", trustpinning.TrustPinConfig{CA: map[string]string{"notary-signer": validCAFilepath}, DisableTOFU: true})
	require.NoError(t, err)
	generateRootKeyIDs(newTypedSignedRoot)
	require.Equal(t, newTypedSignedRoot, validatedRoot)

	// Add an expired CA for the same gun to our previous pinned bundle, ensure that we still validate correctly
	goodRootCABundle, err := trustmanager.LoadCertBundleFromFile(validCAFilepath)
	require.NoError(t, err)
	memKeyStore := trustmanager.NewKeyMemoryStore(passphraseRetriever)
	cryptoService := cryptoservice.NewCryptoService(memKeyStore)
	testPubKey, err := cryptoService.Create("root", "notary-signer", data.ECDSAKey)
	require.NoError(t, err)
	testPrivKey, _, err := memKeyStore.GetKey(testPubKey.ID())
	require.NoError(t, err)
	expiredCert, err := generateExpiredTestingCertificate(testPrivKey, "notary-signer")
	require.NoError(t, err)
	bundleWithExpiredCert, err := trustmanager.CertChainToPEM(append(goodRootCABundle, expiredCert))
	require.NoError(t, err)
	bundleWithExpiredCertPath := filepath.Join(tempBaseDir, "bundle_with_expired_cert.pem")
	require.NoError(t, ioutil.WriteFile(bundleWithExpiredCertPath, bundleWithExpiredCert, 0644))

	// Check that we validate correctly against a pinned CA and provided bundle
	validatedRoot, err = trustpinning.ValidateRoot(nil, newTestSignedRoot, "notary-signer", trustpinning.TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithExpiredCertPath}, DisableTOFU: true})
	require.NoError(t, err)
	require.Equal(t, newTypedSignedRoot, validatedRoot)

	testPubKey2, err := cryptoService.Create("root", "notary-signer", data.ECDSAKey)
	require.NoError(t, err)
	testPrivKey2, _, err := memKeyStore.GetKey(testPubKey2.ID())
	require.NoError(t, err)
	expiredCert2, err := generateExpiredTestingCertificate(testPrivKey2, "notary-signer")
	require.NoError(t, err)
	allExpiredCertBundle, err := trustmanager.CertChainToPEM([]*x509.Certificate{expiredCert, expiredCert2})
	require.NoError(t, err)
	allExpiredCertPath := filepath.Join(tempBaseDir, "all_expired_cert.pem")
	require.NoError(t, ioutil.WriteFile(allExpiredCertPath, allExpiredCertBundle, 0644))
	// Now only use expired certs in the bundle, we should fail
	_, err = trustpinning.ValidateRoot(nil, newTestSignedRoot, "notary-signer", trustpinning.TrustPinConfig{CA: map[string]string{"notary-signer": allExpiredCertPath}, DisableTOFU: true})
	require.Error(t, err)

	// Add a CA cert for a that won't validate against the root leaf certificate
	testPubKey3, err := cryptoService.Create("root", "notary-signer", data.ECDSAKey)
	require.NoError(t, err)
	testPrivKey3, _, err := memKeyStore.GetKey(testPubKey3.ID())
	require.NoError(t, err)
	validCert, err := cryptoservice.GenerateCertificate(testPrivKey3, "notary-signer", time.Now(), time.Now().AddDate(1, 0, 0))
	require.NoError(t, err)
	bundleWithWrongCert, err := trustmanager.CertChainToPEM([]*x509.Certificate{validCert})
	require.NoError(t, err)
	bundleWithWrongCertPath := filepath.Join(tempBaseDir, "bundle_with_expired_cert.pem")
	require.NoError(t, ioutil.WriteFile(bundleWithWrongCertPath, bundleWithWrongCert, 0644))
	_, err = trustpinning.ValidateRoot(nil, newTestSignedRoot, "notary-signer", trustpinning.TrustPinConfig{CA: map[string]string{"notary-signer": bundleWithWrongCertPath}, DisableTOFU: true})
	require.Error(t, err)
}
Esempio n. 14
0
func TestValidateRootWithPinnerCertAndIntermediates(t *testing.T) {
	now := time.Now()
	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)

	pass := func(keyName, alias string, createNew bool, attempts int) (passphrase string, giveup bool, err error) {
		return "password", false, nil
	}
	memStore := trustmanager.NewKeyMemoryStore(pass)
	cs := cryptoservice.NewCryptoService(memStore)

	// generate CA cert
	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
	require.NoError(t, err)
	caTmpl := x509.Certificate{
		SerialNumber: serialNumber,
		Subject: pkix.Name{
			CommonName: "notary testing CA",
		},
		NotBefore:             now.Add(-time.Hour),
		NotAfter:              now.Add(time.Hour),
		KeyUsage:              x509.KeyUsageCertSign,
		BasicConstraintsValid: true,
		IsCA:       true,
		MaxPathLen: 3,
	}
	caPrivKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	require.NoError(t, err)
	_, err = x509.CreateCertificate(
		rand.Reader,
		&caTmpl,
		&caTmpl,
		caPrivKey.Public(),
		caPrivKey,
	)

	// generate intermediate
	intTmpl := x509.Certificate{
		SerialNumber: serialNumber,
		Subject: pkix.Name{
			CommonName: "notary testing intermediate",
		},
		NotBefore:             now.Add(-time.Hour),
		NotAfter:              now.Add(time.Hour),
		KeyUsage:              x509.KeyUsageCertSign,
		BasicConstraintsValid: true,
		IsCA:       true,
		MaxPathLen: 2,
	}
	intPrivKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	require.NoError(t, err)
	intCert, err := x509.CreateCertificate(
		rand.Reader,
		&intTmpl,
		&caTmpl,
		intPrivKey.Public(),
		caPrivKey,
	)
	require.NoError(t, err)

	// generate leaf
	serialNumber, err = rand.Int(rand.Reader, serialNumberLimit)
	require.NoError(t, err)
	leafTmpl := x509.Certificate{
		SerialNumber: serialNumber,
		Subject: pkix.Name{
			CommonName: "docker.io/notary/test",
		},
		NotBefore: now.Add(-time.Hour),
		NotAfter:  now.Add(time.Hour),

		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning},
		BasicConstraintsValid: true,
	}

	leafPubKey, err := cs.Create("root", "docker.io/notary/test", data.ECDSAKey)
	require.NoError(t, err)
	leafPrivKey, _, err := cs.GetPrivateKey(leafPubKey.ID())
	require.NoError(t, err)
	signer := leafPrivKey.CryptoSigner()
	leafCert, err := x509.CreateCertificate(
		rand.Reader,
		&leafTmpl,
		&intTmpl,
		signer.Public(),
		intPrivKey,
	)

	rootBundleWriter := bytes.NewBuffer(nil)
	pem.Encode(
		rootBundleWriter,
		&pem.Block{
			Type:  "CERTIFICATE",
			Bytes: leafCert,
		},
	)
	pem.Encode(
		rootBundleWriter,
		&pem.Block{
			Type:  "CERTIFICATE",
			Bytes: intCert,
		},
	)

	rootBundle := rootBundleWriter.Bytes()

	ecdsax509Key := data.NewECDSAx509PublicKey(rootBundle)

	otherKey, err := cs.Create("targets", "docker.io/notary/test", data.ED25519Key)
	require.NoError(t, err)

	root := data.SignedRoot{
		Signatures: make([]data.Signature, 0),
		Signed: data.Root{
			SignedCommon: data.SignedCommon{
				Type:    "Root",
				Expires: now.Add(time.Hour),
				Version: 1,
			},
			Keys: map[string]data.PublicKey{
				ecdsax509Key.ID(): ecdsax509Key,
				otherKey.ID():     otherKey,
			},
			Roles: map[string]*data.RootRole{
				"root": {
					KeyIDs:    []string{ecdsax509Key.ID()},
					Threshold: 1,
				},
				"targets": {
					KeyIDs:    []string{otherKey.ID()},
					Threshold: 1,
				},
				"snapshot": {
					KeyIDs:    []string{otherKey.ID()},
					Threshold: 1,
				},
				"timestamp": {
					KeyIDs:    []string{otherKey.ID()},
					Threshold: 1,
				},
			},
		},
		Dirty: true,
	}

	signedRoot, err := root.ToSigned()
	require.NoError(t, err)
	err = signed.Sign(cs, signedRoot, []data.PublicKey{ecdsax509Key}, 1, nil)
	require.NoError(t, err)

	typedSignedRoot, err := data.RootFromSigned(signedRoot)
	require.NoError(t, err)

	tempBaseDir, err := ioutil.TempDir("", "notary-test-")
	defer os.RemoveAll(tempBaseDir)
	require.NoError(t, err, "failed to create a temporary directory: %s", err)

	validatedRoot, err := trustpinning.ValidateRoot(
		nil,
		signedRoot,
		"docker.io/notary/test",
		trustpinning.TrustPinConfig{
			Certs: map[string][]string{
				"docker.io/notary/test": {ecdsax509Key.ID()},
			},
			DisableTOFU: true,
		},
	)
	require.NoError(t, err, "failed to validate certID with intermediate")
	generateRootKeyIDs(typedSignedRoot)
	require.Equal(t, typedSignedRoot, validatedRoot)
}
Esempio n. 15
0
File: tuf.go Progetto: vmware/vic
func (tr Repo) sign(signedData *data.Signed, role data.BaseRole) (*data.Signed, error) {
	if err := signed.Sign(tr.cryptoService, signedData, role.ListKeys()...); err != nil {
		return nil, err
	}
	return signedData, nil
}
Esempio n. 16
0
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()] = rootKey

	r, err = repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole))
	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))
	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)
}