Пример #1
0
// CreateKey creates a new key inside the cryptoservice for the given role and gun,
// returning the public key.  If the role is a root role, create an x509 key.
func CreateKey(cs signed.CryptoService, gun, role, keyAlgorithm string) (data.PublicKey, error) {
	key, err := cs.Create(role, gun, keyAlgorithm)
	if err != nil {
		return nil, err
	}
	if role == data.CanonicalRootRole {
		start := time.Now().AddDate(0, 0, -1)
		privKey, _, err := cs.GetPrivateKey(key.ID())
		if err != nil {
			return nil, err
		}
		cert, err := cryptoservice.GenerateCertificate(
			privKey, gun, start, start.AddDate(1, 0, 0),
		)
		if err != nil {
			return nil, err
		}
		// Keep the x509 key type consistent with the key's algorithm
		switch keyAlgorithm {
		case data.RSAKey:
			key = data.NewRSAx509PublicKey(trustmanager.CertToPEM(cert))
		case data.ECDSAKey:
			key = data.NewECDSAx509PublicKey(trustmanager.CertToPEM(cert))
		default:
			// This should be impossible because of the Create() call above, but just in case
			return nil, fmt.Errorf("invalid key algorithm type")
		}

	}
	return key, nil
}
Пример #2
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)
}
Пример #3
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)
}
Пример #4
0
// generates a multiple-certificate file with both RSA and ECDSA certs and
// returns the filename so that cleanup can be deferred.
func generateMultiCert(t *testing.T) string {
	tempFile, err := ioutil.TempFile("/tmp", "cert-test")
	defer tempFile.Close()
	assert.NoError(t, err)

	rsaKey, err := rsa.GenerateKey(rand.Reader, 2048)
	assert.NoError(t, err)
	ecKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	assert.NoError(t, err)
	template, err := trustmanager.NewCertificate("gun")
	assert.NoError(t, err)

	for _, key := range []crypto.Signer{rsaKey, ecKey} {
		derBytes, err := x509.CreateCertificate(
			rand.Reader, template, template, key.Public(), key)
		assert.NoError(t, err)

		cert, err := x509.ParseCertificate(derBytes)
		assert.NoError(t, err)

		pemBytes := trustmanager.CertToPEM(cert)
		nBytes, err := tempFile.Write(pemBytes)
		assert.NoError(t, err)
		assert.Equal(t, nBytes, len(pemBytes))
	}
	return tempFile.Name()
}
Пример #5
0
func TestAddInvalidShortPubkeyCert(t *testing.T) {
	// Cleanup after test
	defer os.RemoveAll(testTrustDir)

	// Setup certificate
	tempFile, err := ioutil.TempFile("/tmp", "pemfile")
	require.NoError(t, err)
	cert, _, err := generateShortRSAKeyTestCert()
	_, err = tempFile.Write(trustmanager.CertToPEM(cert))
	require.NoError(t, err)
	tempFile.Close()
	defer os.Remove(tempFile.Name())

	// Setup commander
	commander := setup()

	// Should error due to short RSA key
	err = commander.delegationAdd(commander.GetCommand(), []string{"gun", "targets/delegation", tempFile.Name(), "--paths", "path"})
	require.Error(t, err)
}
Пример #6
0
func TestAddInvalidDelegationName(t *testing.T) {
	// Cleanup after test
	defer os.RemoveAll(testTrustDir)

	// Setup certificate
	tempFile, err := ioutil.TempFile("/tmp", "pemfile")
	require.NoError(t, err)
	cert, _, err := generateValidTestCert()
	_, err = tempFile.Write(trustmanager.CertToPEM(cert))
	require.NoError(t, err)
	tempFile.Close()
	defer os.Remove(tempFile.Name())

	// Setup commander
	commander := setup()

	// Should error due to invalid delegation name (should be prefixed by "targets/")
	err = commander.delegationAdd(commander.GetCommand(), []string{"gun", "INVALID_NAME", tempFile.Name()})
	require.Error(t, err)
}
Пример #7
0
func createKey(cs signed.CryptoService, gun, role string) (data.PublicKey, error) {
	key, err := cs.Create(role, data.ECDSAKey)
	if err != nil {
		return nil, err
	}
	if role == data.CanonicalRootRole {
		start := time.Now().AddDate(0, 0, -1)
		privKey, _, err := cs.GetPrivateKey(key.ID())
		if err != nil {
			return nil, err
		}
		cert, err := cryptoservice.GenerateCertificate(
			privKey, gun, start, start.AddDate(1, 0, 0),
		)
		if err != nil {
			return nil, err
		}
		key = data.NewECDSAx509PublicKey(trustmanager.CertToPEM(cert))
	}
	return key, nil
}
Пример #8
0
// generates a multiple-certificate file with both RSA and ECDSA certs and
// returns the filename so that cleanup can be deferred.
func generateMultiCert(t *testing.T) string {
	tempFile, err := ioutil.TempFile("/tmp", "cert-test")
	defer tempFile.Close()
	assert.NoError(t, err)

	rsaKey, err := rsa.GenerateKey(rand.Reader, 2048)
	assert.NoError(t, err)
	ecKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	assert.NoError(t, err)

	for _, key := range []crypto.Signer{rsaKey, ecKey} {
		cert, err := cryptoservice.GenerateTestingCertificate(key, "gun")
		assert.NoError(t, err)

		pemBytes := trustmanager.CertToPEM(cert)
		nBytes, err := tempFile.Write(pemBytes)
		assert.NoError(t, err)
		assert.Equal(t, nBytes, len(pemBytes))
	}
	return tempFile.Name()
}
Пример #9
0
// Initialize creates a new repository by using rootKey as the root Key for the
// TUF repository.
func (r *NotaryRepository) Initialize(rootKeyID string, serverManagedRoles ...string) error {
	privKey, _, err := r.CryptoService.GetPrivateKey(rootKeyID)
	if err != nil {
		return err
	}

	// currently we only support server managing timestamps and snapshots, and
	// nothing else - timestamps are always managed by the server, and implicit
	// (do not have to be passed in as part of `serverManagedRoles`, so that
	// the API of Initialize doens't change).
	var serverManagesSnapshot bool
	locallyManagedKeys := []string{
		data.CanonicalTargetsRole,
		data.CanonicalSnapshotRole,
		// root is also locally managed, but that should have been created
		// already
	}
	remotelyManagedKeys := []string{data.CanonicalTimestampRole}
	for _, role := range serverManagedRoles {
		switch role {
		case data.CanonicalTimestampRole:
			continue // timestamp is already in the right place
		case data.CanonicalSnapshotRole:
			// because we put Snapshot last
			locallyManagedKeys = []string{data.CanonicalTargetsRole}
			remotelyManagedKeys = append(
				remotelyManagedKeys, data.CanonicalSnapshotRole)
			serverManagesSnapshot = true
		default:
			return ErrInvalidRemoteRole{Role: role}
		}
	}

	// Hard-coded policy: the generated certificate expires in 10 years.
	startTime := time.Now()
	rootCert, err := cryptoservice.GenerateCertificate(
		privKey, r.gun, startTime, startTime.AddDate(10, 0, 0))

	if err != nil {
		return err
	}
	r.CertManager.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 rootKey data.PublicKey
	switch privKey.Algorithm() {
	case data.RSAKey:
		rootKey = data.NewRSAx509PublicKey(trustmanager.CertToPEM(rootCert))
	case data.ECDSAKey:
		rootKey = data.NewECDSAx509PublicKey(trustmanager.CertToPEM(rootCert))
	default:
		return fmt.Errorf("invalid format for root key: %s", privKey.Algorithm())
	}

	kdb := keys.NewDB()
	err = addKeyForRole(kdb, data.CanonicalRootRole, rootKey)
	if err != nil {
		return err
	}

	// we want to create all the local keys first so we don't have to
	// make unnecessary network calls
	for _, role := range locallyManagedKeys {
		// This is currently hardcoding the keys to ECDSA.
		key, err := r.CryptoService.Create(role, data.ECDSAKey)
		if err != nil {
			return err
		}
		if err := addKeyForRole(kdb, role, key); err != nil {
			return err
		}
	}
	for _, role := range remotelyManagedKeys {
		// This key is generated by the remote server.
		key, err := getRemoteKey(r.baseURL, r.gun, role, r.roundTrip)
		if err != nil {
			return err
		}
		logrus.Debugf("got remote %s %s key with keyID: %s",
			role, key.Algorithm(), key.ID())
		if err := addKeyForRole(kdb, role, key); err != nil {
			return err
		}
	}

	r.tufRepo = tuf.NewRepo(kdb, r.CryptoService)

	err = r.tufRepo.InitRoot(false)
	if err != nil {
		logrus.Debug("Error on InitRoot: ", err.Error())
		return err
	}
	_, err = r.tufRepo.InitTargets(data.CanonicalTargetsRole)
	if err != nil {
		logrus.Debug("Error on InitTargets: ", err.Error())
		return err
	}
	err = r.tufRepo.InitSnapshot()
	if err != nil {
		logrus.Debug("Error on InitSnapshot: ", err.Error())
		return err
	}

	return r.saveMetadata(serverManagesSnapshot)
}
Пример #10
0
// 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()+"_root", rootKey.ID()+"_root")
	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)

	err = initRoles(kdb, rootKey, targetsKey, snapshotKey, timestampKey)
	if err != nil {
		return err
	}

	r.tufRepo = tuf.NewTufRepo(kdb, r.cryptoService)

	err = r.tufRepo.InitRoot(false)
	if err != nil {
		logrus.Debug("Error on InitRoot: ", err.Error())
		switch err.(type) {
		case tuferrors.ErrInsufficientSignatures, trustmanager.ErrPasswordInvalid:
		default:
			return err
		}
	}
	err = r.tufRepo.InitTargets()
	if err != nil {
		logrus.Debug("Error on InitTargets: ", err.Error())
		return err
	}
	err = r.tufRepo.InitSnapshot()
	if err != nil {
		logrus.Debug("Error on InitSnapshot: ", err.Error())
		return err
	}

	return r.saveMetadata(uCryptoService.CryptoService)
}
Пример #11
0
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)
}
Пример #12
0
// Initialize creates a new repository by using rootKey as the root Key for the
// TUF repository.
func (r *NotaryRepository) Initialize(rootKeyID string) error {
	privKey, _, err := r.CryptoService.GetPrivateKey(rootKeyID)
	if err != nil {
		return err
	}

	rootCert, err := cryptoservice.GenerateCertificate(privKey, 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 rootKey data.PublicKey
	switch privKey.Algorithm() {
	case data.RSAKey:
		rootKey = data.NewRSAx509PublicKey(trustmanager.CertToPEM(rootCert))
	case data.ECDSAKey:
		rootKey = data.NewECDSAx509PublicKey(trustmanager.CertToPEM(rootCert))
	default:
		return fmt.Errorf("invalid format for root key: %s", privKey.Algorithm())
	}

	// All the timestamp keys are generated by the remote server.
	remote, err := getRemoteStore(r.baseURL, r.gun, r.roundTrip)
	if err != nil {
		return err
	}
	rawTSKey, err := remote.GetKey("timestamp")
	if err != nil {
		return err
	}

	timestampKey, err := data.UnmarshalPublicKey(rawTSKey)
	if err != nil {
		return err
	}

	logrus.Debugf("got remote %s timestamp key with keyID: %s", timestampKey.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)

	err = initRoles(kdb, rootKey, targetsKey, snapshotKey, timestampKey)
	if err != nil {
		return err
	}

	r.tufRepo = tuf.NewRepo(kdb, r.CryptoService)

	err = r.tufRepo.InitRoot(false)
	if err != nil {
		logrus.Debug("Error on InitRoot: ", err.Error())
		switch err.(type) {
		case tuferrors.ErrInsufficientSignatures, trustmanager.ErrPasswordInvalid:
		default:
			return err
		}
	}
	err = r.tufRepo.InitTargets()
	if err != nil {
		logrus.Debug("Error on InitTargets: ", err.Error())
		return err
	}
	err = r.tufRepo.InitSnapshot()
	if err != nil {
		logrus.Debug("Error on InitSnapshot: ", err.Error())
		return err
	}

	return r.saveMetadata()
}
Пример #13
0
// Initialize repo and test publishing targets with delegation roles
func TestClientDelegationsPublishing(t *testing.T) {
	setUp(t)

	tempDir := tempDirWithConfig(t, "{}")
	defer os.RemoveAll(tempDir)

	server := setupServer()
	defer server.Close()

	// Setup certificate for delegation role
	tempFile, err := ioutil.TempFile("", "pemfile")
	assert.NoError(t, err)

	privKey, err := trustmanager.GenerateRSAKey(rand.Reader, 2048)
	assert.NoError(t, err)
	privKeyBytesNoRole, err := trustmanager.KeyToPEM(privKey, "")
	assert.NoError(t, err)
	privKeyBytesWithRole, err := trustmanager.KeyToPEM(privKey, "user")
	assert.NoError(t, err)
	startTime := time.Now()
	endTime := startTime.AddDate(10, 0, 0)
	cert, err := cryptoservice.GenerateCertificate(privKey, "gun", startTime, endTime)
	assert.NoError(t, err)

	_, err = tempFile.Write(trustmanager.CertToPEM(cert))
	assert.NoError(t, err)
	tempFile.Close()
	defer os.Remove(tempFile.Name())

	rawPubBytes, _ := ioutil.ReadFile(tempFile.Name())
	parsedPubKey, _ := trustmanager.ParsePEMPublicKey(rawPubBytes)
	canonicalKeyID, err := utils.CanonicalKeyID(parsedPubKey)
	assert.NoError(t, err)

	// Set up targets for publishing
	tempTargetFile, err := ioutil.TempFile("", "targetfile")
	assert.NoError(t, err)
	tempTargetFile.Close()
	defer os.Remove(tempTargetFile.Name())

	var target = "sdgkadga"

	var output string

	// init repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "init", "gun")
	assert.NoError(t, err)

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - none yet
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, "No delegations present in this repository.")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// validate that we have all keys, including snapshot
	assertNumKeys(t, tempDir, 1, 2, true)

	// rotate the snapshot key to server
	output, err = runCommand(t, tempDir, "-s", server.URL, "key", "rotate", "gun", "-r", "--key-type", "snapshot")
	assert.NoError(t, err)

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// validate that we lost the snapshot signing key
	_, signingKeyIDs := assertNumKeys(t, tempDir, 1, 1, true)
	targetKeyID := signingKeyIDs[0]

	// add new valid delegation with single new cert
	output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/releases", tempFile.Name(), "--paths", "\"\"")
	assert.NoError(t, err)
	assert.Contains(t, output, "Addition of delegation role")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see our one delegation
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.NotContains(t, output, "No delegations present in this repository.")

	// remove the targets key to demonstrate that delegates don't need this key
	keyDir := filepath.Join(tempDir, "private", "tuf_keys")
	assert.NoError(t, os.Remove(filepath.Join(keyDir, "gun", targetKeyID+".key")))

	// Note that we need to use the canonical key ID, followed by the base of the role here
	err = ioutil.WriteFile(filepath.Join(keyDir, canonicalKeyID+"_releases.key"), privKeyBytesNoRole, 0700)
	assert.NoError(t, err)

	// add a target using the delegation -- will only add to targets/releases
	_, err = runCommand(t, tempDir, "add", "gun", target, tempTargetFile.Name(), "--roles", "targets/releases")
	assert.NoError(t, err)

	// list targets for targets/releases - we should see no targets until we publish
	output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases")
	assert.NoError(t, err)
	assert.Contains(t, output, "No targets")

	output, err = runCommand(t, tempDir, "-s", server.URL, "status", "gun")
	assert.NoError(t, err)

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list targets for targets/releases - we should see our target!
	output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases")
	assert.NoError(t, err)
	assert.Contains(t, output, "targets/releases")

	// remove the target for this role only
	_, err = runCommand(t, tempDir, "remove", "gun", target, "--roles", "targets/releases")
	assert.NoError(t, err)

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list targets for targets/releases - we should see no targets
	output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases")
	assert.NoError(t, err)
	assert.Contains(t, output, "No targets present")

	// Try adding a target with a different key style - private/tuf_keys/canonicalKeyID.key with "user" set as the "role" PEM header
	// First remove the old key and add the new style
	assert.NoError(t, os.Remove(filepath.Join(keyDir, canonicalKeyID+"_releases.key")))
	err = ioutil.WriteFile(filepath.Join(keyDir, canonicalKeyID+".key"), privKeyBytesWithRole, 0700)
	assert.NoError(t, err)

	// add a target using the delegation -- will only add to targets/releases
	_, err = runCommand(t, tempDir, "add", "gun", target, tempTargetFile.Name(), "--roles", "targets/releases")
	assert.NoError(t, err)

	// list targets for targets/releases - we should see no targets until we publish
	output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases")
	assert.NoError(t, err)
	assert.Contains(t, output, "No targets")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list targets for targets/releases - we should see our target!
	output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases")
	assert.NoError(t, err)
	assert.Contains(t, output, "targets/releases")

	// remove the target for this role only
	_, err = runCommand(t, tempDir, "remove", "gun", target, "--roles", "targets/releases")
	assert.NoError(t, err)

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// Now remove this key, and make a new file to import the delegation's key from
	assert.NoError(t, os.Remove(filepath.Join(keyDir, canonicalKeyID+".key")))
	tempPrivFile, err := ioutil.TempFile("/tmp", "privfile")
	assert.NoError(t, err)
	defer os.Remove(tempPrivFile.Name())

	// Write the private key to a file so we can import it
	_, err = tempPrivFile.Write(privKeyBytesNoRole)
	assert.NoError(t, err)
	tempPrivFile.Close()

	// Import the private key, associating it with our delegation role
	_, err = runCommand(t, tempDir, "key", "import", tempPrivFile.Name(), "--role", "targets/releases")
	assert.NoError(t, err)

	// add a target using the delegation -- will only add to targets/releases
	_, err = runCommand(t, tempDir, "add", "gun", target, tempTargetFile.Name(), "--roles", "targets/releases")
	assert.NoError(t, err)

	// list targets for targets/releases - we should see no targets until we publish
	output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases")
	assert.NoError(t, err)
	assert.Contains(t, output, "No targets")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list targets for targets/releases - we should see our target!
	output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases")
	assert.NoError(t, err)
	assert.Contains(t, output, "targets/releases")
}
Пример #14
0
// Initialize repo and test delegations commands by adding, listing, and removing delegations
func TestClientDelegationsInteraction(t *testing.T) {
	setUp(t)

	tempDir := tempDirWithConfig(t, "{}")
	defer os.RemoveAll(tempDir)

	server := setupServer()
	defer server.Close()

	// Setup certificate
	tempFile, err := ioutil.TempFile("", "pemfile")
	assert.NoError(t, err)

	privKey, err := trustmanager.GenerateECDSAKey(rand.Reader)
	startTime := time.Now()
	endTime := startTime.AddDate(10, 0, 0)
	cert, err := cryptoservice.GenerateCertificate(privKey, "gun", startTime, endTime)
	assert.NoError(t, err)

	_, err = tempFile.Write(trustmanager.CertToPEM(cert))
	assert.NoError(t, err)
	tempFile.Close()
	defer os.Remove(tempFile.Name())

	rawPubBytes, _ := ioutil.ReadFile(tempFile.Name())
	parsedPubKey, _ := trustmanager.ParsePEMPublicKey(rawPubBytes)
	keyID, err := utils.CanonicalKeyID(parsedPubKey)
	assert.NoError(t, err)

	var output string

	// -- tests --

	// init repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "init", "gun")
	assert.NoError(t, err)

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - none yet
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, "No delegations present in this repository.")

	// add new valid delegation with single new cert, and no path
	output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", tempFile.Name())
	assert.NoError(t, err)
	assert.Contains(t, output, "Addition of delegation role")
	assert.NotContains(t, output, "path")

	// check status - see delegation
	output, err = runCommand(t, tempDir, "status", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, "Unpublished changes for gun")

	// list delegations - none yet because still unpublished
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, "No delegations present in this repository.")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// check status - no changelist
	output, err = runCommand(t, tempDir, "status", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, "No unpublished changes for gun")

	// list delegations - we should see our added delegation, with no paths
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, "targets/delegation")
	assert.Contains(t, output, keyID)
	assert.NotContains(t, output, "\"\"")

	// add all paths to this delegation
	output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--all-paths")
	assert.NoError(t, err)
	assert.Contains(t, output, "Addition of delegation role")
	assert.Contains(t, output, "\"\"")
	assert.Contains(t, output, "<all paths>")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see our added delegation, with no paths
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, "targets/delegation")
	assert.Contains(t, output, "\"\"")
	assert.Contains(t, output, "<all paths>")

	// Setup another certificate
	tempFile2, err := ioutil.TempFile("", "pemfile2")
	assert.NoError(t, err)

	privKey, err = trustmanager.GenerateECDSAKey(rand.Reader)
	startTime = time.Now()
	endTime = startTime.AddDate(10, 0, 0)
	cert, err = cryptoservice.GenerateCertificate(privKey, "gun", startTime, endTime)
	assert.NoError(t, err)

	_, err = tempFile2.Write(trustmanager.CertToPEM(cert))
	assert.NoError(t, err)
	assert.NoError(t, err)
	tempFile2.Close()
	defer os.Remove(tempFile2.Name())

	rawPubBytes2, _ := ioutil.ReadFile(tempFile2.Name())
	parsedPubKey2, _ := trustmanager.ParsePEMPublicKey(rawPubBytes2)
	keyID2, err := utils.CanonicalKeyID(parsedPubKey2)
	assert.NoError(t, err)

	// add to the delegation by specifying the same role, this time add a scoped path
	output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", tempFile2.Name(), "--paths", "path")
	assert.NoError(t, err)
	assert.Contains(t, output, "Addition of delegation role")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see two keys
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, ",")
	assert.Contains(t, output, "path")
	assert.Contains(t, output, keyID)
	assert.Contains(t, output, keyID2)

	// remove the delegation's first key
	output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", keyID)
	assert.NoError(t, err)
	assert.Contains(t, output, "Removal of delegation role")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see the delegation but with only the second key
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.NotContains(t, output, keyID)
	assert.Contains(t, output, keyID2)

	// remove the delegation's second key
	output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", keyID2)
	assert.NoError(t, err)
	assert.Contains(t, output, "Removal of delegation role")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see no delegations
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, "No delegations present in this repository.")

	// add delegation with multiple certs and multiple paths
	output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", tempFile.Name(), tempFile2.Name(), "--paths", "path1,path2")
	assert.NoError(t, err)
	assert.Contains(t, output, "Addition of delegation role")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see two keys
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, ",")
	assert.Contains(t, output, "path1,path2")
	assert.Contains(t, output, keyID)
	assert.Contains(t, output, keyID2)

	// add delegation with multiple certs and multiple paths
	output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--paths", "path3")
	assert.NoError(t, err)
	assert.Contains(t, output, "Addition of delegation role")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see two keys
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, ",")
	assert.Contains(t, output, "path1,path2,path3")

	// just remove two paths from this delegation
	output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", "--paths", "path2,path3")
	assert.NoError(t, err)
	assert.Contains(t, output, "Removal of delegation role")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see the same two keys, and only path1
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, ",")
	assert.Contains(t, output, "path1")
	assert.NotContains(t, output, "path2")
	assert.NotContains(t, output, "path3")
	assert.Contains(t, output, keyID)
	assert.Contains(t, output, keyID2)

	// remove the remaining path, should not remove the delegation entirely
	output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", "--paths", "path1")
	assert.NoError(t, err)
	assert.Contains(t, output, "Removal of delegation role")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see the same two keys, and no paths
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, ",")
	assert.NotContains(t, output, "path1")
	assert.NotContains(t, output, "path2")
	assert.NotContains(t, output, "path3")
	assert.Contains(t, output, keyID)
	assert.Contains(t, output, keyID2)

	// Add a bunch of individual paths so we can test a delegation remove --all-paths
	output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--paths", "abcdef,123456")
	assert.NoError(t, err)

	// Add more individual paths so we can test a delegation remove --all-paths
	output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--paths", "banana/split,apple/crumble/pie,orange.peel,kiwi")
	assert.NoError(t, err)

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see all of our paths
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, "abcdef")
	assert.Contains(t, output, "123456")
	assert.Contains(t, output, "banana/split")
	assert.Contains(t, output, "apple/crumble/pie")
	assert.Contains(t, output, "orange.peel")
	assert.Contains(t, output, "kiwi")

	// Try adding "", and check that adding it with other paths clears out the others
	output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--paths", "\"\",grapefruit,pomegranate")
	assert.NoError(t, err)

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see all of our old paths, and ""
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, "abcdef")
	assert.Contains(t, output, "123456")
	assert.Contains(t, output, "banana/split")
	assert.Contains(t, output, "apple/crumble/pie")
	assert.Contains(t, output, "orange.peel")
	assert.Contains(t, output, "kiwi")
	assert.Contains(t, output, "\"\"")
	assert.NotContains(t, output, "grapefruit")
	assert.NotContains(t, output, "pomegranate")

	// Try removing just ""
	output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", "--paths", "\"\"")
	assert.NoError(t, err)

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see all of our old paths without ""
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, "abcdef")
	assert.Contains(t, output, "123456")
	assert.Contains(t, output, "banana/split")
	assert.Contains(t, output, "apple/crumble/pie")
	assert.Contains(t, output, "orange.peel")
	assert.Contains(t, output, "kiwi")
	assert.NotContains(t, output, "\"\"")

	// Remove --all-paths to clear out all paths from this delegation
	output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", "--all-paths")
	assert.NoError(t, err)

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see all of our paths
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.NotContains(t, output, "abcdef")
	assert.NotContains(t, output, "123456")
	assert.NotContains(t, output, "banana/split")
	assert.NotContains(t, output, "apple/crumble/pie")
	assert.NotContains(t, output, "orange.peel")
	assert.NotContains(t, output, "kiwi")

	// Check that we ignore other --paths if we pass in --all-paths on an add
	output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--all-paths", "--paths", "grapefruit,pomegranate")
	assert.NoError(t, err)

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should only see "", and not the other paths specified
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, "\"\"")
	assert.NotContains(t, output, "grapefruit")
	assert.NotContains(t, output, "pomegranate")

	// Add those extra paths we ignored to set up the next test
	output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--paths", "grapefruit,pomegranate")
	assert.NoError(t, err)

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// Check that we ignore other --paths if we pass in --all-paths on a remove
	output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", "--all-paths", "--paths", "pomegranate")
	assert.NoError(t, err)

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see no paths
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.NotContains(t, output, "\"\"")
	assert.NotContains(t, output, "grapefruit")
	assert.NotContains(t, output, "pomegranate")

	// remove by force to delete the delegation entirely
	output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", "-y")
	assert.NoError(t, err)
	assert.Contains(t, output, "Forced removal (including all keys and paths) of delegation role")

	// publish repo
	_, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun")
	assert.NoError(t, err)

	// list delegations - we should see no delegations
	output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun")
	assert.NoError(t, err)
	assert.Contains(t, output, "No delegations present in this repository.")
}
Пример #15
0
// 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()
}