diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 86c139233c..837215a6ec 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -47,7 +47,7 @@ }, { "ImportPath": "github.com/endophage/gotuf", - "Rev": "c7154b63cf6e8485ea4af4c7f299ccbea6731d43" + "Rev": "b6ca3574afa7c5a395280b4894850bb3aa47560c" }, { "ImportPath": "github.com/go-sql-driver/mysql", diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/client/client b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/client/client new file mode 100644 index 0000000000..195504e45b Binary files /dev/null and b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/client/client differ diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/data/keys.go b/Godeps/_workspace/src/github.com/endophage/gotuf/data/keys.go index 7e1b27c04e..00d09e8cfd 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/data/keys.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/data/keys.go @@ -41,6 +41,7 @@ func (k TUFKey) Cipher() string { } func (k *TUFKey) ID() string { + logrus.Debug("Generating Key ID") if k.id == "" { logrus.Debug("Generating Key ID") pubK := NewTUFKey(k.Cipher(), k.Public(), "") diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/data/snapshot.go b/Godeps/_workspace/src/github.com/endophage/gotuf/data/snapshot.go index 1519f38150..c0f499df5c 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/data/snapshot.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/data/snapshot.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" + "github.com/Sirupsen/logrus" cjson "github.com/tent/canonical-json-go" ) @@ -21,12 +22,15 @@ type Snapshot struct { } func NewSnapshot(root *Signed, targets *Signed) (*SignedSnapshot, error) { - rootJSON, err := json.Marshal(root) - if err != nil { - return nil, err - } + logrus.Debug("NewSnapshot") targetsJSON, err := json.Marshal(targets) if err != nil { + logrus.Debug("Error Marshalling Targets") + return nil, err + } + rootJSON, err := json.Marshal(root) + if err != nil { + logrus.Debug("Error Marshalling Root") return nil, err } rootMeta, err := NewFileMeta(bytes.NewReader(rootJSON), "sha256") diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/ed25519.go b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/ed25519.go index ff9390ce76..692e7fa8db 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/ed25519.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/ed25519.go @@ -68,8 +68,3 @@ func (trust *Ed25519) PublicKeys(keyIDs ...string) (map[string]*data.PublicKey, } return k, nil } - -func (trust *Ed25519) CanSign(keyID string) bool { - _, ok := trust.keys[keyID] - return ok -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/interface.go b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/interface.go index e7f8edf49d..b4fadfee73 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/interface.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/interface.go @@ -10,12 +10,6 @@ type SigningService interface { // Sign takes a slice of keyIDs and a piece of data to sign // and returns a slice of signatures and an error Sign(keyIDs []string, data []byte) ([]data.Signature, error) - - // CanSign takes a single keyID and returns a boolean indicating - // whether the caller is able to sign with the keyID (i.e. does - // this signing service hold the private key associated with - // they keyID) - CanSign(keyID string) bool } // KeyService provides management of keys locally. It will never @@ -27,7 +21,7 @@ type KeyService interface { Create() (*data.PublicKey, error) // PublicKeys return the PublicKey instances for the given KeyIDs - PublicKeys(keyIDs ...string) (map[string]*data.PublicKey, error) + // PublicKeys(keyIDs ...string) (map[string]*data.PublicKey, error) } // CryptoService defines a unified Signing and Key Service as this diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/sign.go b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/sign.go index 7b421b6df7..899dffc5a9 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/sign.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/sign.go @@ -2,6 +2,7 @@ package signed import ( "github.com/endophage/gotuf/data" + "strings" ) // Signer encapsulates a signing service with some convenience methods to @@ -40,9 +41,11 @@ func (signer *Signer) Sign(s *data.Signed, keys ...*data.PublicKey) error { } func (signer *Signer) Create() (*data.PublicKey, error) { - return signer.service.Create() + key, err := signer.service.Create() + key.TUFKey.Value.Public = strings.Replace(key.TUFKey.Value.Public, "\n", "\\n", -1) + return key, err } -func (signer *Signer) PublicKeys(keyIDs ...string) (map[string]*data.PublicKey, error) { - return signer.service.PublicKeys(keyIDs...) -} +//func (signer *Signer) PublicKeys(keyIDs ...string) (map[string]*data.PublicKey, error) { +// return signer.service.PublicKeys(keyIDs...) +//} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verifiers.go b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verifiers.go index 82db1d67ca..9bc9e56280 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verifiers.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verifiers.go @@ -22,7 +22,8 @@ import ( var Verifiers = map[string]Verifier{ "ed25519": Ed25519Verifier{}, "rsa": RSAVerifier{}, - "pycrypto-pkcs#1 pss": RSAPSSVerifier{}, + "rsassa-pkcs1-v1_5-sign": RSAPemVerifier{}, + "pycrypto-pkcs#1 pss": RSAPSSVerifier{}, } // RegisterVerifier provides a convenience function for init() functions @@ -88,6 +89,31 @@ func (v RSAVerifier) Verify(key data.Key, sig []byte, msg []byte) error { return nil } +type RSAPemVerifier struct{} + +func (v RSAPemVerifier) Verify(key data.Key, sig []byte, msg []byte) error { + digest := sha256.Sum256(msg) + + k, _ := pem.Decode([]byte(key.Public())) + pub, err := x509.ParsePKIXPublicKey(k.Bytes) + if err != nil { + logrus.Infof("Failed to parse public key: %s\n", err) + return ErrInvalid + } + + rsaPub, ok := pub.(*rsa.PublicKey) + if !ok { + logrus.Infof("Value returned from ParsePKIXPublicKey was not an RSA public key") + return ErrInvalid + } + + if err = rsa.VerifyPKCS1v15(rsaPub, crypto.SHA256, digest[:], sig); err != nil { + logrus.Infof("Failed verification: %s", err) + return ErrInvalid + } + return nil +} + // RSAPSSVerifier checks RSASSA-PSS signatures type RSAPSSVerifier struct{} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/store/filestore.go b/Godeps/_workspace/src/github.com/endophage/gotuf/store/filestore.go index 134c8fa184..882e5f7248 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/store/filestore.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/store/filestore.go @@ -14,11 +14,11 @@ func NewFilesystemStore(baseDir, metaSubDir, metaExtension, targetsSubDir string targetsDir := path.Join(baseDir, targetsSubDir) // Make sure we can create the necessary dirs and they are writable - err := os.MkdirAll(metaDir, 0644) + err := os.MkdirAll(metaDir, 0744) if err != nil { return nil, err } - err = os.MkdirAll(targetsDir, 0644) + err = os.MkdirAll(targetsDir, 0744) if err != nil { return nil, err } diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/tuf.go b/Godeps/_workspace/src/github.com/endophage/gotuf/tuf.go index 326f34b99a..92fea41042 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/tuf.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/tuf.go @@ -82,11 +82,6 @@ func (tr *TufRepo) AddBaseKeys(role string, keys ...data.Key) error { tr.Root.Signed.Roles[role].KeyIDs = append(tr.Root.Signed.Roles[role].KeyIDs, key.ID()) } tr.Root.Dirty = true - signedRoot, err := tr.SignRoot(data.DefaultExpires("root")) - err = tr.UpdateSnapshot("root", signedRoot) - if err != nil { - return err - } return nil } @@ -126,11 +121,6 @@ func (tr *TufRepo) RemoveBaseKeys(role string, keyIDs ...string) error { delete(tr.Root.Signed.Keys, k) } tr.Root.Dirty = true - signedRoot, err := tr.SignRoot(data.DefaultExpires("root")) - err = tr.UpdateSnapshot("root", signedRoot) - if err != nil { - return err - } return nil } @@ -175,26 +165,9 @@ func (tr *TufRepo) UpdateDelegations(role *data.Role, keys []data.Key, before st } p.Dirty = true - roleTargets := data.NewTargets() + roleTargets := data.NewTargets() // NewTargets always marked Dirty tr.Targets[role.Name] = roleTargets - signedParent, err := tr.SignTargets(parent, data.DefaultExpires("targets")) - if err != nil { - return err - } - err = tr.UpdateSnapshot(role.Name, signedParent) - if err != nil { - return err - } - signedTargets, err := tr.SignTargets(role.Name, data.DefaultExpires("targets")) - if err != nil { - return err - } - err = tr.UpdateSnapshot(role.Name, signedTargets) - if err != nil { - return err - } - tr.keysDB.AddRole(role) return nil @@ -410,14 +383,6 @@ func (tr *TufRepo) AddTargets(role string, targets data.Files) (data.Files, erro } } t.Dirty = true - signedTargets, err := tr.SignTargets(role, data.DefaultExpires("targets")) - if err != nil { - return invalid, err - } - err = tr.UpdateSnapshot(role, signedTargets) - if err != nil { - return invalid, err - } if len(invalid) > 0 { return invalid, fmt.Errorf("Could not add all targets") } @@ -434,10 +399,26 @@ func (tr *TufRepo) UpdateSnapshot(role string, s *data.Signed) error { return err } tr.Snapshot.Signed.Meta[role] = meta + tr.Snapshot.Dirty = true + return nil +} + +func (tr *TufRepo) UpdateTimestamp(s *data.Signed) error { + jsonData, err := json.Marshal(s) + if err != nil { + return err + } + meta, err := data.NewFileMeta(bytes.NewReader(jsonData), "sha256") + if err != nil { + return err + } + tr.Timestamp.Signed.Meta["snapshot"] = meta + tr.Timestamp.Dirty = true return nil } func (tr *TufRepo) SignRoot(expires time.Time) (*data.Signed, error) { + logrus.Debug("SignRoot") signed, err := tr.Root.ToSigned() if err != nil { return nil, err @@ -452,44 +433,94 @@ func (tr *TufRepo) SignRoot(expires time.Time) (*data.Signed, error) { } func (tr *TufRepo) SignTargets(role string, expires time.Time) (*data.Signed, error) { + logrus.Debug("SignTargets") signed, err := tr.Targets[role].ToSigned() if err != nil { + logrus.Debug("errored getting targets data.Signed object") return nil, err } - targets := tr.keysDB.GetRole(role) - signed, err = tr.sign(signed, *targets) - if err != nil { - return nil, err + logrus.Debug("Got targets data.Signed object") + if tr.Targets[role].Dirty { + targets := tr.keysDB.GetRole(role) + logrus.Debug("About to sign ", role) + signed, err = tr.sign(signed, *targets) + if err != nil { + logrus.Debug("errored signing ", role) + return nil, err + } + logrus.Debug("success signing ", role) + tr.Targets[role].Signatures = signed.Signatures } - tr.Targets[role].Signatures = signed.Signatures return signed, nil } func (tr *TufRepo) SignSnapshot(expires time.Time) (*data.Signed, error) { + logrus.Debug("SignSnapshot") + if tr.Root.Dirty { + signedRoot, err := tr.SignRoot(data.DefaultExpires("root")) + if err != nil { + return nil, err + } + err = tr.UpdateSnapshot("root", signedRoot) + if err != nil { + return nil, err + } + tr.Root.Dirty = false // root dirty until changes captures in snapshot + } + for role, targets := range tr.Targets { + if !targets.Dirty { + continue + } + signedTargets, err := tr.SignTargets(role, data.DefaultExpires("targets")) + if err != nil { + return nil, err + } + err = tr.UpdateSnapshot(role, signedTargets) + if err != nil { + return nil, err + } + tr.Targets[role].Dirty = false // target role dirty until changes captured in snapshot + } signed, err := tr.Snapshot.ToSigned() if err != nil { return nil, err } - snapshot := tr.keysDB.GetRole(data.ValidRoles["snapshot"]) - signed, err = tr.sign(signed, *snapshot) - if err != nil { - return nil, err + if tr.Snapshot.Dirty { + snapshot := tr.keysDB.GetRole(data.ValidRoles["snapshot"]) + signed, err = tr.sign(signed, *snapshot) + if err != nil { + return nil, err + } + tr.Snapshot.Signatures = signed.Signatures } - tr.Snapshot.Signatures = signed.Signatures return signed, nil } func (tr *TufRepo) SignTimestamp(expires time.Time) (*data.Signed, error) { + logrus.Debug("SignTimestamp") + if tr.Snapshot.Dirty { + signedSnapshot, err := tr.SignSnapshot(data.DefaultExpires("snapshot")) + if err != nil { + return nil, err + } + err = tr.UpdateTimestamp(signedSnapshot) + if err != nil { + return nil, err + } + } signed, err := tr.Timestamp.ToSigned() - if err != nil { - return nil, err + if tr.Timestamp.Dirty { + if err != nil { + return nil, err + } + timestamp := tr.keysDB.GetRole(data.ValidRoles["timestamp"]) + signed, err = tr.sign(signed, *timestamp) + if err != nil { + return nil, err + } + tr.Timestamp.Signatures = signed.Signatures + tr.Snapshot.Dirty = false // snapshot is dirty until changes have been captured in timestamp } - timestamp := tr.keysDB.GetRole(data.ValidRoles["timestamp"]) - signed, err = tr.sign(signed, *timestamp) - if err != nil { - return nil, err - } - tr.Timestamp.Signatures = signed.Signatures return signed, nil } diff --git a/cmd/notary/main.go b/cmd/notary/main.go index 67dd6bc252..1499d8c786 100644 --- a/cmd/notary/main.go +++ b/cmd/notary/main.go @@ -8,6 +8,7 @@ import ( "path" "time" + "github.com/Sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -20,11 +21,13 @@ const configFileName string = "config" const configPath string = ".docker/trust/" const trustDir string = configPath + "repository_certificates/" const privDir string = configPath + "private/" +const tufDir string = configPath + "tuf/" var caStore trustmanager.X509Store var privStore trustmanager.X509Store func init() { + logrus.SetLevel(logrus.DebugLevel) // Retrieve current user to get home directory usr, err := user.Current() if err != nil { @@ -54,6 +57,7 @@ func init() { // Set up the defaults for our config viper.SetDefault("trustDir", path.Join(homeDir, path.Dir(trustDir))) viper.SetDefault("privDir", path.Join(homeDir, path.Dir(privDir))) + viper.SetDefault("tufDir", path.Join(homeDir, path.Dir(tufDir))) // Get the final value for the CA directory finalTrustDir := viper.GetString("trustDir") diff --git a/cmd/notary/tuf.go b/cmd/notary/tuf.go index db43854d04..220fee74c8 100644 --- a/cmd/notary/tuf.go +++ b/cmd/notary/tuf.go @@ -13,6 +13,7 @@ import ( "github.com/endophage/gotuf/client" "github.com/endophage/gotuf/data" "github.com/endophage/gotuf/keys" + "github.com/endophage/gotuf/signed" "github.com/endophage/gotuf/store" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -39,61 +40,61 @@ func init() { } var cmdTufAdd = &cobra.Command{ - Use: "add [ GUN ] ", + Use: "add [ QDN ] ", Short: "pushes local updates.", Long: "pushes all local updates within a specific TUF repo to remote trust server.", Run: tufAdd, } var cmdTufRemove = &cobra.Command{ - Use: "remove [ GUN ] ", + Use: "remove [ QDN ] ", Short: "Removes a target from the TUF repo.", - Long: "removes a target from the local TUF repo identified by a Global Unique Name.", + Long: "removes a target from the local TUF repo identified by a Qualified Docker Name.", Run: tufRemove, } var cmdTufInit = &cobra.Command{ - Use: "init [ GUN ]", + Use: "init [ QDN ]", Short: "initializes the local TUF repository.", - Long: "creates locally the initial set of TUF metadata for the Global Unique Name.", + Long: "creates locally the initial set of TUF metadata for the Qualified Docker Name.", Run: tufInit, } var cmdTufList = &cobra.Command{ - Use: "list [ GUN ]", + Use: "list [ QDN ]", Short: "Lists all targets in a TUF repository.", - Long: "lists all the targets in the TUF repository identified by the Global Unique Name.", + Long: "lists all the targets in the TUF repository identified by the Qualified Docker Name.", Run: tufList, } var cmdTufLookup = &cobra.Command{ - Use: "lookup [ GUN ] ", + Use: "lookup [ QDN ] ", Short: "Looks up a specific TUF target in a repository.", - Long: "looks up a TUF target in a repository given a Global Unique Name.", + Long: "looks up a TUF target in a repository given a Qualified Docker Name.", Run: tufLookup, } var cmdTufPush = &cobra.Command{ - Use: "push [ GUN ]", + Use: "push [ QDN ]", Short: "initializes the local TUF repository.", - Long: "creates locally the initial set of TUF metadata for the Global Unique Name.", + Long: "creates locally the initial set of TUF metadata for the Qualified Docker Name.", Run: tufPush, } func tufAdd(cmd *cobra.Command, args []string) { if len(args) < 3 { cmd.Usage() - fatalf("must specify a GUN, target name, and local path to target data") + fatalf("must specify a QDN, target name, and local path to target data") } - gun := args[0] + qdn := args[0] targetName := args[1] targetPath := args[2] kdb := keys.NewDB() repo := tuf.NewTufRepo(kdb, nil) filestore, err := store.NewFilesystemStore( - path.Join(viper.GetString("tufDir"), gun), // TODO: base trust dir from config + path.Join(viper.GetString("tufDir"), qdn), // TODO: base trust dir from config "metadata", "json", "targets", @@ -157,13 +158,34 @@ func tufAdd(cmd *cobra.Command, args []string) { func tufInit(cmd *cobra.Command, args []string) { if len(args) < 1 { cmd.Usage() - fatalf("must specify a Global Unique Name") + fatalf("Must specify a GUN") } gun := args[0] - // cryptoService := NewCryptoService(gun) kdb := keys.NewDB() - repo := tuf.NewTufRepo(kdb, nil) + signer := signed.NewSigner(NewCryptoService(gun)) + + rootKey, err := signer.Create() + targetsKey, err := signer.Create() + snapshotKey, err := signer.Create() + timestampKey, err := signer.Create() + + kdb.AddKey(rootKey) + kdb.AddKey(targetsKey) + kdb.AddKey(snapshotKey) + kdb.AddKey(timestampKey) + + rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil) + targetsRole, err := data.NewRole("targets", 1, []string{targetsKey.ID()}, nil, nil) + snapshotRole, err := data.NewRole("snapshot", 1, []string{snapshotKey.ID()}, nil, nil) + timestampRole, err := data.NewRole("timestamp", 1, []string{timestampKey.ID()}, nil, nil) + + kdb.AddRole(rootRole) + kdb.AddRole(targetsRole) + kdb.AddRole(snapshotRole) + kdb.AddRole(timestampRole) + + repo := tuf.NewTufRepo(kdb, signer) filestore, err := store.NewFilesystemStore( path.Join(viper.GetString("tufDir"), gun), // TODO: base trust dir from config @@ -171,6 +193,9 @@ func tufInit(cmd *cobra.Command, args []string) { "json", "targets", ) + if err != nil { + fatalf(err.Error()) + } err = repo.InitRepo(false) if err != nil { @@ -182,24 +207,24 @@ func tufInit(cmd *cobra.Command, args []string) { func tufList(cmd *cobra.Command, args []string) { if len(args) < 1 { cmd.Usage() - fatalf("must specify a Global Unique Name") + fatalf("must specify a QDN") } } func tufLookup(cmd *cobra.Command, args []string) { if len(args) < 2 { cmd.Usage() - fatalf("must specify a Global Unique Name and target path to look up.") + fatalf("must specify a QDN and target path to look up.") } fmt.Println("Remote trust server configured: " + remoteTrustServer) - gun := args[0] + qdn := args[0] targetName := args[1] kdb := keys.NewDB() repo := tuf.NewTufRepo(kdb, nil) remote, err := store.NewHTTPStore( - "https://localhost:4443/v2"+gun+"/_trust/tuf/", + "https://localhost:4443/v2"+qdn+"/_trust/tuf/", "", "json", "", @@ -232,13 +257,13 @@ func tufLookup(cmd *cobra.Command, args []string) { func tufPush(cmd *cobra.Command, args []string) { if len(args) < 1 { cmd.Usage() - fatalf("must specify a Global Unique Name") + fatalf("must specify a QDN") } - gun := args[0] + qdn := args[0] remote, err := store.NewHTTPStore( - "https://localhost:4443/v2"+gun+"/_trust/tuf/", + "https://localhost:4443/v2"+qdn+"/_trust/tuf/", "", "json", "", @@ -288,7 +313,7 @@ func tufPush(cmd *cobra.Command, args []string) { func tufRemove(cmd *cobra.Command, args []string) { if len(args) < 1 { cmd.Usage() - fatalf("must specify a Global Unique Name") + fatalf("must specify a QDN") } } @@ -297,10 +322,12 @@ func saveRepo(repo *tuf.TufRepo, filestore store.MetadataStore) error { if err != nil { return err } + fmt.Println("Marshalling root") rootJSON, _ := json.Marshal(signedRoot) filestore.SetMeta("root", rootJSON) for r, _ := range repo.Targets { + fmt.Println("Marshalling ", r) signedTargets, err := repo.SignTargets(r, data.DefaultExpires("targets")) if err != nil { return err @@ -315,6 +342,7 @@ func saveRepo(repo *tuf.TufRepo, filestore store.MetadataStore) error { if err != nil { return err } + fmt.Println("Marshalling snapshot") snapshotJSON, _ := json.Marshal(signedSnapshot) filestore.SetMeta("snapshot", snapshotJSON) @@ -322,6 +350,7 @@ func saveRepo(repo *tuf.TufRepo, filestore store.MetadataStore) error { if err != nil { return err } + fmt.Println("Marshalling timestamp") timestampJSON, _ := json.Marshal(signedTimestamp) filestore.SetMeta("timestamp", timestampJSON) return nil