From 76386afe5ddd642058c5bade80b682aee9ef47e9 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Fri, 16 Sep 2022 11:06:31 -0500 Subject: [PATCH 1/4] feat: pass logger into repo and client Signed-off-by: Asra Ali --- client/client.go | 27 +++++++++++--- client/delegations.go | 3 +- pkg/deprecated/deprecated_repo_test.go | 11 +++++- pkg/keys/deprecated_ecdsa.go | 28 ++++++++++++--- pkg/keys/deprecated_ecdsa_test.go | 21 +++++++++++ pkg/keys/ecdsa.go | 2 +- pkg/keys/ed25519.go | 2 +- pkg/keys/keys.go | 13 +++++-- pkg/keys/rsa.go | 2 +- repo.go | 50 +++++++++++++++++++++++--- verify/db.go | 34 +++++++++++++----- 11 files changed, 165 insertions(+), 28 deletions(-) diff --git a/client/client.go b/client/client.go index 17ddc980..8e226905 100644 --- a/client/client.go +++ b/client/client.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "encoding/json" "io" + "log" "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/util" @@ -88,6 +89,10 @@ type Client struct { // consistent snapshots (as specified in root.json) consistentSnapshot bool + // this is an optional log writer. + // if nil, uses io.Discard + logger *log.Logger + // MaxDelegations limits by default the number of delegations visited for any // target MaxDelegations int @@ -96,13 +101,26 @@ type Client struct { MaxRootRotations int } -func NewClient(local LocalStore, remote RemoteStore) *Client { - return &Client{ +type ClientOpts func(c *Client) + +func WithLogger(logger *log.Logger) ClientOpts { + return func(c *Client) { + c.logger = logger + } +} + +func NewClient(local LocalStore, remote RemoteStore, opts ...ClientOpts) *Client { + client := &Client{ local: local, remote: remote, MaxDelegations: defaultMaxDelegations, MaxRootRotations: defaultMaxRootRotations, + logger: log.New(io.Discard, "", 0), + } + for _, opt := range opts { + opt(client) } + return client } // Init initializes a local repository from root metadata. @@ -452,7 +470,8 @@ func (c *Client) loadAndVerifyRootMeta(rootJSON []byte, ignoreExpiredCheck bool) if err := json.Unmarshal(s.Signed, root); err != nil { return err } - ndb := verify.NewDB() + + ndb := verify.NewDB(verify.WithLogger(c.logger)) for id, k := range root.Keys { if err := ndb.AddKey(id, k); err != nil { return err @@ -500,7 +519,7 @@ func (c *Client) verifyRoot(aJSON []byte, bJSON []byte) (*data.Root, error) { return nil, err } - ndb := verify.NewDB() + ndb := verify.NewDB(verify.WithLogger(c.logger)) for id, k := range aRoot.Keys { if err := ndb.AddKey(id, k); err != nil { return nil, err diff --git a/client/delegations.go b/client/delegations.go index de3e6647..773226c7 100644 --- a/client/delegations.go +++ b/client/delegations.go @@ -43,7 +43,8 @@ func (c *Client) getTargetFileMeta(target string) (data.TargetFileMeta, error) { } if targets.Delegations != nil { - delegationsDB, err := verify.NewDBFromDelegations(targets.Delegations) + delegationsDB, err := verify.NewDBFromDelegations(targets.Delegations, + verify.WithLogger(c.logger)) if err != nil { return data.TargetFileMeta{}, err } diff --git a/pkg/deprecated/deprecated_repo_test.go b/pkg/deprecated/deprecated_repo_test.go index 6d194ab5..9500219f 100644 --- a/pkg/deprecated/deprecated_repo_test.go +++ b/pkg/deprecated/deprecated_repo_test.go @@ -1,11 +1,14 @@ package deprecated import ( + "bytes" "crypto" "crypto/elliptic" "crypto/rand" "crypto/sha256" "encoding/json" + "log" + "strings" "testing" "github.com/secure-systems-lab/go-securesystemslib/cjson" @@ -34,7 +37,10 @@ func genKey(c *C, r *repo.Repo, role string) []string { func (rs *RepoSuite) TestDeprecatedHexEncodedKeysSucceed(c *C) { files := map[string][]byte{"foo.txt": []byte("foo")} local := repo.MemoryStore(make(map[string]json.RawMessage), files) - r, err := repo.NewRepo(local) + var logBytes bytes.Buffer + opts := repo.WithLogger(log.New(&logBytes, "", 0)) + + r, err := repo.NewRepoWithOpts(local, opts) c.Assert(err, IsNil) r.Init(false) @@ -79,4 +85,7 @@ func (rs *RepoSuite) TestDeprecatedHexEncodedKeysSucceed(c *C) { c.Assert(r.Snapshot(), IsNil) c.Assert(r.Timestamp(), IsNil) c.Assert(r.Commit(), IsNil) + + // Check logs. + c.Assert(strings.Contains(logBytes.String(), keys.WarnDeprecatedEcdsaKey), Equals, true) } diff --git a/pkg/keys/deprecated_ecdsa.go b/pkg/keys/deprecated_ecdsa.go index 4a8f151e..d12a22bf 100644 --- a/pkg/keys/deprecated_ecdsa.go +++ b/pkg/keys/deprecated_ecdsa.go @@ -9,13 +9,25 @@ import ( "errors" "fmt" "io" - "os" + "log" "github.com/theupdateframework/go-tuf/data" ) -func NewDeprecatedEcdsaVerifier() Verifier { - return &ecdsaVerifierWithDeprecatedSupport{} +var ( + WarnDeprecatedEcdsaKey = "tuf: warning using deprecated ecdsa hex-encoded keys" +) + +func NewDeprecatedEcdsaVerifier(opts ...VerifierOpts) Verifier { + verifier := &ecdsaVerifierWithDeprecatedSupport{ + logger: log.New(io.Discard, "", log.LstdFlags), + } + for _, opt := range opts { + if opt.Logger != nil { + verifier.logger = opt.Logger + } + } + return verifier } type ecdsaVerifierWithDeprecatedSupport struct { @@ -23,6 +35,8 @@ type ecdsaVerifierWithDeprecatedSupport struct { // This will switch based on whether this is a PEM-encoded key // or a deprecated hex-encoded key. Verifier + // This is used to write the deprecated warning to. + logger *log.Logger } func (p *ecdsaVerifierWithDeprecatedSupport) UnmarshalPublicKey(key *data.PublicKey) error { @@ -30,7 +44,9 @@ func (p *ecdsaVerifierWithDeprecatedSupport) UnmarshalPublicKey(key *data.Public pemVerifier := &EcdsaVerifier{} if err := pemVerifier.UnmarshalPublicKey(key); err != nil { // Try the deprecated hex-encoded verifier - hexVerifier := &deprecatedP256Verifier{} + hexVerifier := &deprecatedP256Verifier{ + logger: p.logger, + } if err := hexVerifier.UnmarshalPublicKey(key); err != nil { return err } @@ -51,6 +67,8 @@ func (p *ecdsaVerifierWithDeprecatedSupport) UnmarshalPublicKey(key *data.Public type deprecatedP256Verifier struct { PublicKey data.HexBytes `json:"public"` key *data.PublicKey + // This is used to write the deprecated warning to. + logger *log.Logger } func (p *deprecatedP256Verifier) Public() string { @@ -98,6 +116,6 @@ func (p *deprecatedP256Verifier) UnmarshalPublicKey(key *data.PublicKey) error { } p.key = key - fmt.Fprintln(os.Stderr, "tuf: warning using deprecated ecdsa hex-encoded keys") + p.logger.Print(WarnDeprecatedEcdsaKey) return nil } diff --git a/pkg/keys/deprecated_ecdsa_test.go b/pkg/keys/deprecated_ecdsa_test.go index ddfaa84d..57563b29 100644 --- a/pkg/keys/deprecated_ecdsa_test.go +++ b/pkg/keys/deprecated_ecdsa_test.go @@ -1,6 +1,7 @@ package keys import ( + "bytes" "crypto" "crypto/ecdsa" "crypto/elliptic" @@ -8,6 +9,8 @@ import ( "crypto/sha256" "encoding/json" "errors" + "log" + "strings" "github.com/theupdateframework/go-tuf/data" . "gopkg.in/check.v1" @@ -127,3 +130,21 @@ func (DeprecatedECDSASuite) TestMarshalUnmarshalPublicKey(c *C) { c.Assert(deprecatedEcdsa.MarshalPublicKey(), DeepEquals, pub) } + +func (DeprecatedECDSASuite) TestLogMessageWriter(c *C) { + signer, err := generatedDeprecatedSigner() + c.Assert(err, IsNil) + + pub := signer.PublicData() + + var logBytes bytes.Buffer + opts := WithLogger(log.New(&logBytes, "", 0)) + + deprecatedEcdsa := NewDeprecatedEcdsaVerifier(opts) + err = deprecatedEcdsa.UnmarshalPublicKey(pub) + c.Assert(err, IsNil) + c.Assert(strings.TrimSuffix(logBytes.String(), "\n"), Equals, + WarnDeprecatedEcdsaKey) + + c.Assert(deprecatedEcdsa.MarshalPublicKey(), DeepEquals, pub) +} diff --git a/pkg/keys/ecdsa.go b/pkg/keys/ecdsa.go index ee93e330..c7083e8a 100644 --- a/pkg/keys/ecdsa.go +++ b/pkg/keys/ecdsa.go @@ -24,7 +24,7 @@ func init() { SignerMap.Store(data.KeyTypeECDSA_SHA2_P256, newEcdsaSigner) } -func NewEcdsaVerifier() Verifier { +func NewEcdsaVerifier(_ ...VerifierOpts) Verifier { return &EcdsaVerifier{} } diff --git a/pkg/keys/ed25519.go b/pkg/keys/ed25519.go index 1e4c66cc..f7309b1b 100644 --- a/pkg/keys/ed25519.go +++ b/pkg/keys/ed25519.go @@ -23,7 +23,7 @@ func NewEd25519Signer() Signer { return &ed25519Signer{} } -func NewEd25519Verifier() Verifier { +func NewEd25519Verifier(_ ...VerifierOpts) Verifier { return &ed25519Verifier{} } diff --git a/pkg/keys/keys.go b/pkg/keys/keys.go index dc5f3ea2..7ac9c13e 100644 --- a/pkg/keys/keys.go +++ b/pkg/keys/keys.go @@ -3,6 +3,7 @@ package keys import ( "errors" "fmt" + "log" "sync" "github.com/theupdateframework/go-tuf/data" @@ -57,12 +58,20 @@ type Signer interface { SignMessage(message []byte) ([]byte, error) } -func GetVerifier(key *data.PublicKey) (Verifier, error) { +type VerifierOpts struct { + Logger *log.Logger +} + +func WithLogger(logger *log.Logger) VerifierOpts { + return VerifierOpts{logger} +} + +func GetVerifier(key *data.PublicKey, opts ...VerifierOpts) (Verifier, error) { st, ok := VerifierMap.Load(key.Type) if !ok { return nil, ErrInvalidKey } - s := st.(func() Verifier)() + s := st.(func(opts ...VerifierOpts) Verifier)(opts...) if err := s.UnmarshalPublicKey(key); err != nil { return nil, fmt.Errorf("tuf: error unmarshalling key: %w", err) } diff --git a/pkg/keys/rsa.go b/pkg/keys/rsa.go index 618f104e..3fc82cde 100644 --- a/pkg/keys/rsa.go +++ b/pkg/keys/rsa.go @@ -21,7 +21,7 @@ func init() { SignerMap.Store(data.KeyTypeRSASSA_PSS_SHA256, newRsaSigner) } -func newRsaVerifier() Verifier { +func newRsaVerifier(_ ...VerifierOpts) Verifier { return &rsaVerifier{} } diff --git a/repo.go b/repo.go index 603785f1..732dee01 100644 --- a/repo.go +++ b/repo.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "log" "path" "sort" "strings" @@ -48,18 +49,47 @@ type Repo struct { meta map[string]json.RawMessage prefix string indent string + logger *log.Logger +} + +type RepoOpts func(r *Repo) + +func WithLogger(logger *log.Logger) RepoOpts { + return func(r *Repo) { + r.logger = logger + } +} + +func WithHashAlgorithms(hashAlgorithms ...string) RepoOpts { + return func(r *Repo) { + r.hashAlgorithms = hashAlgorithms + } +} + +func WithPrefix(prefix string) RepoOpts { + return func(r *Repo) { + r.prefix = prefix + } +} + +func WithIndex(indent string) RepoOpts { + return func(r *Repo) { + r.indent = indent + } } func NewRepo(local LocalStore, hashAlgorithms ...string) (*Repo, error) { return NewRepoIndent(local, "", "", hashAlgorithms...) } -func NewRepoIndent(local LocalStore, prefix string, indent string, hashAlgorithms ...string) (*Repo, error) { +func NewRepoIndent(local LocalStore, prefix string, indent string, + hashAlgorithms ...string) (*Repo, error) { r := &Repo{ local: local, hashAlgorithms: hashAlgorithms, prefix: prefix, indent: indent, + logger: log.New(io.Discard, "", 0), } var err error @@ -70,6 +100,17 @@ func NewRepoIndent(local LocalStore, prefix string, indent string, hashAlgorithm return r, nil } +func NewRepoWithOpts(local LocalStore, opts ...RepoOpts) (*Repo, error) { + r, err := NewRepo(local) + if err != nil { + return nil, err + } + for _, opt := range opts { + opt(r) + } + return r, nil +} + func (r *Repo) Init(consistentSnapshot bool) error { t, err := r.topLevelTargets() if err != nil { @@ -96,7 +137,7 @@ func (r *Repo) Init(consistentSnapshot bool) error { } func (r *Repo) topLevelKeysDB() (*verify.DB, error) { - db := verify.NewDB() + db := verify.NewDB(verify.WithLogger(r.logger)) root, err := r.root() if err != nil { return nil, err @@ -934,7 +975,7 @@ func (r *Repo) delegatorDBs(delegateeRole string) ([]*verify.DB, error) { continue } - db, err := verify.NewDBFromDelegations(t.Delegations) + db, err := verify.NewDBFromDelegations(t.Delegations, verify.WithLogger(r.logger)) if err != nil { return nil, err } @@ -983,7 +1024,8 @@ func (r *Repo) targetDelegationForPath(path string, preferredRole string) (*data } if targetsMeta.Delegations != nil && len(targetsMeta.Delegations.Roles) > 0 { - db, err := verify.NewDBFromDelegations(targetsMeta.Delegations) + db, err := verify.NewDBFromDelegations(targetsMeta.Delegations, + verify.WithLogger(r.logger)) if err != nil { return nil, nil, err } diff --git a/verify/db.go b/verify/db.go index 04f5bf1c..acaf7b6e 100644 --- a/verify/db.go +++ b/verify/db.go @@ -1,6 +1,9 @@ package verify import ( + "io" + "log" + "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/internal/roles" "github.com/theupdateframework/go-tuf/pkg/keys" @@ -19,22 +22,33 @@ func (r *Role) ValidKey(id string) bool { type DB struct { roles map[string]*Role verifiers map[string]keys.Verifier + logger *log.Logger +} + +type DBOpts func(db *DB) + +func WithLogger(logger *log.Logger) DBOpts { + return func(db *DB) { + db.logger = logger + } } -func NewDB() *DB { - return &DB{ +func NewDB(opts ...DBOpts) *DB { + db := &DB{ roles: make(map[string]*Role), verifiers: make(map[string]keys.Verifier), + logger: log.New(io.Discard, "", 0), + } + for _, opt := range opts { + opt(db) } + return db } // NewDBFromDelegations returns a DB that verifies delegations // of a given Targets. -func NewDBFromDelegations(d *data.Delegations) (*DB, error) { - db := &DB{ - roles: make(map[string]*Role, len(d.Roles)), - verifiers: make(map[string]keys.Verifier, len(d.Keys)), - } +func NewDBFromDelegations(d *data.Delegations, opts ...DBOpts) (*DB, error) { + db := NewDB(opts...) for _, r := range d.Roles { if _, ok := roles.TopLevelRoles[r.Name]; ok { return nil, ErrInvalidDelegatedRole @@ -53,7 +67,11 @@ func NewDBFromDelegations(d *data.Delegations) (*DB, error) { } func (db *DB) AddKey(id string, k *data.PublicKey) error { - verifier, err := keys.GetVerifier(k) + opts := make([]keys.VerifierOpts, 0) + if db.logger != nil { + opts = append(opts, keys.WithLogger(db.logger)) + } + verifier, err := keys.GetVerifier(k, opts...) if err != nil { return err // ErrInvalidKey } From 89b085e0a7738097435eda3cbfe50bde90f9907d Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Fri, 16 Sep 2022 11:10:06 -0500 Subject: [PATCH 2/4] remove prints in repo Signed-off-by: Asra Ali --- repo.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/repo.go b/repo.go index 732dee01..cb4fb976 100644 --- a/repo.go +++ b/repo.go @@ -132,7 +132,7 @@ func (r *Repo) Init(consistentSnapshot bool) error { return err } - fmt.Println("Repository initialized") + r.logger.Println("Repository initialized") return nil } @@ -574,7 +574,7 @@ func (r *Repo) RevokeKeyWithExpires(keyRole, id string, expires time.Time) error err = r.setMeta("root.json", root) if err == nil { - fmt.Println("Revoked", keyRole, "key with ID", id, "in root metadata") + r.logger.Println("Revoked", keyRole, "key with ID", id, "in root metadata") } return err } @@ -824,7 +824,7 @@ func (r *Repo) Sign(roleFilename string) error { r.meta[roleFilename] = b err = r.local.SetMeta(roleFilename, b) if err == nil { - fmt.Println("Signed", roleFilename, "with", numKeys, "key(s)") + r.logger.Println("Signed", roleFilename, "with", numKeys, "key(s)") } return err } @@ -1265,7 +1265,7 @@ func (r *Repo) removeTargetsWithExpiresFromMeta(metaName string, paths []string, for _, path := range paths { path = util.NormalizeTarget(path) if _, ok := t.Targets[path]; !ok { - fmt.Printf("[%v] The following target is not present: %v\n", metaName, path) + r.logger.Printf("[%v] The following target is not present: %v\n", metaName, path) continue } removed = true @@ -1285,17 +1285,17 @@ func (r *Repo) removeTargetsWithExpiresFromMeta(metaName string, paths []string, err = r.setMeta(metaName, t) if err == nil { - fmt.Printf("[%v] Removed targets:\n", metaName) + r.logger.Printf("[%v] Removed targets:\n", metaName) for _, v := range removed_targets { - fmt.Println("*", v) + r.logger.Println("*", v) } if len(t.Targets) != 0 { - fmt.Printf("[%v] Added/staged targets:\n", metaName) + r.logger.Printf("[%v] Added/staged targets:\n", metaName) for k := range t.Targets { - fmt.Println("*", k) + r.logger.Println("*", k) } } else { - fmt.Printf("[%v] There are no added/staged targets\n", metaName) + r.logger.Printf("[%v] There are no added/staged targets\n", metaName) } } return err @@ -1349,7 +1349,7 @@ func (r *Repo) SnapshotWithExpires(expires time.Time) error { } err = r.setMeta("snapshot.json", snapshot) if err == nil { - fmt.Println("Staged snapshot.json metadata with expiration date:", snapshot.Expires) + r.logger.Println("Staged snapshot.json metadata with expiration date:", snapshot.Expires) } return err } @@ -1381,7 +1381,7 @@ func (r *Repo) TimestampWithExpires(expires time.Time) error { err = r.setMeta("timestamp.json", timestamp) if err == nil { - fmt.Println("Staged timestamp.json metadata with expiration date:", timestamp.Expires) + r.logger.Println("Staged timestamp.json metadata with expiration date:", timestamp.Expires) } return err } @@ -1547,7 +1547,7 @@ func (r *Repo) Commit() error { err = r.local.Commit(root.ConsistentSnapshot, versions, hashes) if err == nil { - fmt.Println("Committed successfully") + r.logger.Println("Committed successfully") } return err } @@ -1555,7 +1555,7 @@ func (r *Repo) Commit() error { func (r *Repo) Clean() error { err := r.local.Clean() if err == nil { - fmt.Println("Removed all staged metadata and target files") + r.logger.Println("Removed all staged metadata and target files") } return err } From 4780a8c798b2c8494572b2684d68843214d5ef06 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Mon, 19 Sep 2022 10:16:02 -0400 Subject: [PATCH 3/4] remove logger from client Signed-off-by: Asra Ali --- client/client.go | 27 +++----------------- client/delegations.go | 3 +-- internal/fsutil/perm_test.go | 2 -- local_store.go | 31 +++++++++++++++++++++-- pkg/deprecated/deprecated_repo_test.go | 11 +-------- pkg/keys/deprecated_ecdsa.go | 26 +++----------------- pkg/keys/deprecated_ecdsa_test.go | 21 ---------------- pkg/keys/ecdsa.go | 2 +- pkg/keys/ed25519.go | 2 +- pkg/keys/keys.go | 13 ++-------- pkg/keys/rsa.go | 2 +- repo.go | 7 +++--- repo_test.go | 9 ++++++- verify/db.go | 34 ++++++-------------------- 14 files changed, 62 insertions(+), 128 deletions(-) diff --git a/client/client.go b/client/client.go index 8e226905..17ddc980 100644 --- a/client/client.go +++ b/client/client.go @@ -5,7 +5,6 @@ import ( "encoding/hex" "encoding/json" "io" - "log" "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/util" @@ -89,10 +88,6 @@ type Client struct { // consistent snapshots (as specified in root.json) consistentSnapshot bool - // this is an optional log writer. - // if nil, uses io.Discard - logger *log.Logger - // MaxDelegations limits by default the number of delegations visited for any // target MaxDelegations int @@ -101,26 +96,13 @@ type Client struct { MaxRootRotations int } -type ClientOpts func(c *Client) - -func WithLogger(logger *log.Logger) ClientOpts { - return func(c *Client) { - c.logger = logger - } -} - -func NewClient(local LocalStore, remote RemoteStore, opts ...ClientOpts) *Client { - client := &Client{ +func NewClient(local LocalStore, remote RemoteStore) *Client { + return &Client{ local: local, remote: remote, MaxDelegations: defaultMaxDelegations, MaxRootRotations: defaultMaxRootRotations, - logger: log.New(io.Discard, "", 0), - } - for _, opt := range opts { - opt(client) } - return client } // Init initializes a local repository from root metadata. @@ -470,8 +452,7 @@ func (c *Client) loadAndVerifyRootMeta(rootJSON []byte, ignoreExpiredCheck bool) if err := json.Unmarshal(s.Signed, root); err != nil { return err } - - ndb := verify.NewDB(verify.WithLogger(c.logger)) + ndb := verify.NewDB() for id, k := range root.Keys { if err := ndb.AddKey(id, k); err != nil { return err @@ -519,7 +500,7 @@ func (c *Client) verifyRoot(aJSON []byte, bJSON []byte) (*data.Root, error) { return nil, err } - ndb := verify.NewDB(verify.WithLogger(c.logger)) + ndb := verify.NewDB() for id, k := range aRoot.Keys { if err := ndb.AddKey(id, k); err != nil { return nil, err diff --git a/client/delegations.go b/client/delegations.go index 773226c7..de3e6647 100644 --- a/client/delegations.go +++ b/client/delegations.go @@ -43,8 +43,7 @@ func (c *Client) getTargetFileMeta(target string) (data.TargetFileMeta, error) { } if targets.Delegations != nil { - delegationsDB, err := verify.NewDBFromDelegations(targets.Delegations, - verify.WithLogger(c.logger)) + delegationsDB, err := verify.NewDBFromDelegations(targets.Delegations) if err != nil { return data.TargetFileMeta{}, err } diff --git a/internal/fsutil/perm_test.go b/internal/fsutil/perm_test.go index 6061d291..f80ef94a 100644 --- a/internal/fsutil/perm_test.go +++ b/internal/fsutil/perm_test.go @@ -4,7 +4,6 @@ package fsutil import ( - "fmt" "os" "path/filepath" "testing" @@ -59,7 +58,6 @@ func TestEnsureMaxPermissions(t *testing.T) { assert.NoError(t, err) err = EnsureMaxPermissions(fi, os.FileMode(0222)) assert.Error(t, err) - fmt.Println(err) // Check matching due to more restrictive perms on file err = os.Chmod(p, 0444) diff --git a/local_store.go b/local_store.go index 1b4a7f60..fee03f31 100644 --- a/local_store.go +++ b/local_store.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "io/fs" + "log" "os" "path/filepath" "strings" @@ -197,18 +198,44 @@ type persistedKeys struct { Data json.RawMessage `json:"data"` } +type StoreOpts struct { + Logger *log.Logger + PassFunc util.PassphraseFunc +} + func FileSystemStore(dir string, p util.PassphraseFunc) LocalStore { return &fileSystemStore{ dir: dir, passphraseFunc: p, + logger: log.New(io.Discard, "", 0), signerForKeyID: make(map[string]keys.Signer), keyIDsForRole: make(map[string][]string), } } +func FileSystemStoreWithOpts(dir string, opts ...StoreOpts) LocalStore { + store := &fileSystemStore{ + dir: dir, + passphraseFunc: nil, + logger: log.New(io.Discard, "", 0), + signerForKeyID: make(map[string]keys.Signer), + keyIDsForRole: make(map[string][]string), + } + for _, opt := range opts { + if opt.Logger != nil { + store.logger = opt.Logger + } + if opt.PassFunc != nil { + store.passphraseFunc = opt.PassFunc + } + } + return store +} + type fileSystemStore struct { dir string passphraseFunc util.PassphraseFunc + logger *log.Logger signerForKeyID map[string]keys.Signer keyIDsForRole map[string][]string @@ -526,7 +553,7 @@ func (f *fileSystemStore) ChangePassphrase(role string) error { keys, _, err := f.loadPrivateKeys(role) if err != nil { if os.IsNotExist(err) { - fmt.Printf("Failed to change passphrase. Missing keys file for %s role. \n", role) + f.logger.Printf("Failed to change passphrase. Missing keys file for %s role. \n", role) } return err } @@ -548,7 +575,7 @@ func (f *fileSystemStore) ChangePassphrase(role string) error { if err := util.AtomicallyWriteFile(f.keysPath(role), append(data, '\n'), 0600); err != nil { return err } - fmt.Printf("Successfully changed passphrase for %s keys file\n", role) + f.logger.Printf("Successfully changed passphrase for %s keys file\n", role) return nil } diff --git a/pkg/deprecated/deprecated_repo_test.go b/pkg/deprecated/deprecated_repo_test.go index 9500219f..6d194ab5 100644 --- a/pkg/deprecated/deprecated_repo_test.go +++ b/pkg/deprecated/deprecated_repo_test.go @@ -1,14 +1,11 @@ package deprecated import ( - "bytes" "crypto" "crypto/elliptic" "crypto/rand" "crypto/sha256" "encoding/json" - "log" - "strings" "testing" "github.com/secure-systems-lab/go-securesystemslib/cjson" @@ -37,10 +34,7 @@ func genKey(c *C, r *repo.Repo, role string) []string { func (rs *RepoSuite) TestDeprecatedHexEncodedKeysSucceed(c *C) { files := map[string][]byte{"foo.txt": []byte("foo")} local := repo.MemoryStore(make(map[string]json.RawMessage), files) - var logBytes bytes.Buffer - opts := repo.WithLogger(log.New(&logBytes, "", 0)) - - r, err := repo.NewRepoWithOpts(local, opts) + r, err := repo.NewRepo(local) c.Assert(err, IsNil) r.Init(false) @@ -85,7 +79,4 @@ func (rs *RepoSuite) TestDeprecatedHexEncodedKeysSucceed(c *C) { c.Assert(r.Snapshot(), IsNil) c.Assert(r.Timestamp(), IsNil) c.Assert(r.Commit(), IsNil) - - // Check logs. - c.Assert(strings.Contains(logBytes.String(), keys.WarnDeprecatedEcdsaKey), Equals, true) } diff --git a/pkg/keys/deprecated_ecdsa.go b/pkg/keys/deprecated_ecdsa.go index d12a22bf..6d48c9d6 100644 --- a/pkg/keys/deprecated_ecdsa.go +++ b/pkg/keys/deprecated_ecdsa.go @@ -9,25 +9,12 @@ import ( "errors" "fmt" "io" - "log" "github.com/theupdateframework/go-tuf/data" ) -var ( - WarnDeprecatedEcdsaKey = "tuf: warning using deprecated ecdsa hex-encoded keys" -) - -func NewDeprecatedEcdsaVerifier(opts ...VerifierOpts) Verifier { - verifier := &ecdsaVerifierWithDeprecatedSupport{ - logger: log.New(io.Discard, "", log.LstdFlags), - } - for _, opt := range opts { - if opt.Logger != nil { - verifier.logger = opt.Logger - } - } - return verifier +func NewDeprecatedEcdsaVerifier() Verifier { + return &ecdsaVerifierWithDeprecatedSupport{} } type ecdsaVerifierWithDeprecatedSupport struct { @@ -35,8 +22,6 @@ type ecdsaVerifierWithDeprecatedSupport struct { // This will switch based on whether this is a PEM-encoded key // or a deprecated hex-encoded key. Verifier - // This is used to write the deprecated warning to. - logger *log.Logger } func (p *ecdsaVerifierWithDeprecatedSupport) UnmarshalPublicKey(key *data.PublicKey) error { @@ -44,9 +29,7 @@ func (p *ecdsaVerifierWithDeprecatedSupport) UnmarshalPublicKey(key *data.Public pemVerifier := &EcdsaVerifier{} if err := pemVerifier.UnmarshalPublicKey(key); err != nil { // Try the deprecated hex-encoded verifier - hexVerifier := &deprecatedP256Verifier{ - logger: p.logger, - } + hexVerifier := &deprecatedP256Verifier{} if err := hexVerifier.UnmarshalPublicKey(key); err != nil { return err } @@ -67,8 +50,6 @@ func (p *ecdsaVerifierWithDeprecatedSupport) UnmarshalPublicKey(key *data.Public type deprecatedP256Verifier struct { PublicKey data.HexBytes `json:"public"` key *data.PublicKey - // This is used to write the deprecated warning to. - logger *log.Logger } func (p *deprecatedP256Verifier) Public() string { @@ -116,6 +97,5 @@ func (p *deprecatedP256Verifier) UnmarshalPublicKey(key *data.PublicKey) error { } p.key = key - p.logger.Print(WarnDeprecatedEcdsaKey) return nil } diff --git a/pkg/keys/deprecated_ecdsa_test.go b/pkg/keys/deprecated_ecdsa_test.go index 57563b29..ddfaa84d 100644 --- a/pkg/keys/deprecated_ecdsa_test.go +++ b/pkg/keys/deprecated_ecdsa_test.go @@ -1,7 +1,6 @@ package keys import ( - "bytes" "crypto" "crypto/ecdsa" "crypto/elliptic" @@ -9,8 +8,6 @@ import ( "crypto/sha256" "encoding/json" "errors" - "log" - "strings" "github.com/theupdateframework/go-tuf/data" . "gopkg.in/check.v1" @@ -130,21 +127,3 @@ func (DeprecatedECDSASuite) TestMarshalUnmarshalPublicKey(c *C) { c.Assert(deprecatedEcdsa.MarshalPublicKey(), DeepEquals, pub) } - -func (DeprecatedECDSASuite) TestLogMessageWriter(c *C) { - signer, err := generatedDeprecatedSigner() - c.Assert(err, IsNil) - - pub := signer.PublicData() - - var logBytes bytes.Buffer - opts := WithLogger(log.New(&logBytes, "", 0)) - - deprecatedEcdsa := NewDeprecatedEcdsaVerifier(opts) - err = deprecatedEcdsa.UnmarshalPublicKey(pub) - c.Assert(err, IsNil) - c.Assert(strings.TrimSuffix(logBytes.String(), "\n"), Equals, - WarnDeprecatedEcdsaKey) - - c.Assert(deprecatedEcdsa.MarshalPublicKey(), DeepEquals, pub) -} diff --git a/pkg/keys/ecdsa.go b/pkg/keys/ecdsa.go index c7083e8a..ee93e330 100644 --- a/pkg/keys/ecdsa.go +++ b/pkg/keys/ecdsa.go @@ -24,7 +24,7 @@ func init() { SignerMap.Store(data.KeyTypeECDSA_SHA2_P256, newEcdsaSigner) } -func NewEcdsaVerifier(_ ...VerifierOpts) Verifier { +func NewEcdsaVerifier() Verifier { return &EcdsaVerifier{} } diff --git a/pkg/keys/ed25519.go b/pkg/keys/ed25519.go index f7309b1b..1e4c66cc 100644 --- a/pkg/keys/ed25519.go +++ b/pkg/keys/ed25519.go @@ -23,7 +23,7 @@ func NewEd25519Signer() Signer { return &ed25519Signer{} } -func NewEd25519Verifier(_ ...VerifierOpts) Verifier { +func NewEd25519Verifier() Verifier { return &ed25519Verifier{} } diff --git a/pkg/keys/keys.go b/pkg/keys/keys.go index 7ac9c13e..dc5f3ea2 100644 --- a/pkg/keys/keys.go +++ b/pkg/keys/keys.go @@ -3,7 +3,6 @@ package keys import ( "errors" "fmt" - "log" "sync" "github.com/theupdateframework/go-tuf/data" @@ -58,20 +57,12 @@ type Signer interface { SignMessage(message []byte) ([]byte, error) } -type VerifierOpts struct { - Logger *log.Logger -} - -func WithLogger(logger *log.Logger) VerifierOpts { - return VerifierOpts{logger} -} - -func GetVerifier(key *data.PublicKey, opts ...VerifierOpts) (Verifier, error) { +func GetVerifier(key *data.PublicKey) (Verifier, error) { st, ok := VerifierMap.Load(key.Type) if !ok { return nil, ErrInvalidKey } - s := st.(func(opts ...VerifierOpts) Verifier)(opts...) + s := st.(func() Verifier)() if err := s.UnmarshalPublicKey(key); err != nil { return nil, fmt.Errorf("tuf: error unmarshalling key: %w", err) } diff --git a/pkg/keys/rsa.go b/pkg/keys/rsa.go index 3fc82cde..618f104e 100644 --- a/pkg/keys/rsa.go +++ b/pkg/keys/rsa.go @@ -21,7 +21,7 @@ func init() { SignerMap.Store(data.KeyTypeRSASSA_PSS_SHA256, newRsaSigner) } -func newRsaVerifier(_ ...VerifierOpts) Verifier { +func newRsaVerifier() Verifier { return &rsaVerifier{} } diff --git a/repo.go b/repo.go index cb4fb976..cce0020f 100644 --- a/repo.go +++ b/repo.go @@ -137,7 +137,7 @@ func (r *Repo) Init(consistentSnapshot bool) error { } func (r *Repo) topLevelKeysDB() (*verify.DB, error) { - db := verify.NewDB(verify.WithLogger(r.logger)) + db := verify.NewDB() root, err := r.root() if err != nil { return nil, err @@ -975,7 +975,7 @@ func (r *Repo) delegatorDBs(delegateeRole string) ([]*verify.DB, error) { continue } - db, err := verify.NewDBFromDelegations(t.Delegations, verify.WithLogger(r.logger)) + db, err := verify.NewDBFromDelegations(t.Delegations) if err != nil { return nil, err } @@ -1024,8 +1024,7 @@ func (r *Repo) targetDelegationForPath(path string, preferredRole string) (*data } if targetsMeta.Delegations != nil && len(targetsMeta.Delegations.Roles) > 0 { - db, err := verify.NewDBFromDelegations(targetsMeta.Delegations, - verify.WithLogger(r.logger)) + db, err := verify.NewDBFromDelegations(targetsMeta.Delegations) if err != nil { return nil, nil, err } diff --git a/repo_test.go b/repo_test.go index 2f3aebb4..d841bb59 100644 --- a/repo_test.go +++ b/repo_test.go @@ -9,6 +9,7 @@ import ( "encoding/json" "errors" "fmt" + "log" "os" "path" "path/filepath" @@ -1422,7 +1423,12 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) { // Test changing the passphrase // 1. Create a secure store with a passphrase (create new object and temp folder so we discard any previous state) tmp = newTmpDir(c) - store = FileSystemStore(tmp.path, testPassphraseFunc) + var logBytes bytes.Buffer + storeOpts := StoreOpts{ + Logger: log.New(&logBytes, "", 0), + PassFunc: testPassphraseFunc, + } + store = FileSystemStoreWithOpts(tmp.path, storeOpts) // 1.5. Changing passphrase works for top-level and delegated roles. r, err := NewRepo(store) @@ -1433,6 +1439,7 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) { // 2. Test changing the passphrase when the keys file does not exist - should FAIL c.Assert(store.(PassphraseChanger).ChangePassphrase("root"), NotNil) + c.Assert(strings.Contains(logBytes.String(), "Missing keys file"), Equals, true) // 3. Generate a new key signer, err = keys.GenerateEd25519Key() diff --git a/verify/db.go b/verify/db.go index acaf7b6e..04f5bf1c 100644 --- a/verify/db.go +++ b/verify/db.go @@ -1,9 +1,6 @@ package verify import ( - "io" - "log" - "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/internal/roles" "github.com/theupdateframework/go-tuf/pkg/keys" @@ -22,33 +19,22 @@ func (r *Role) ValidKey(id string) bool { type DB struct { roles map[string]*Role verifiers map[string]keys.Verifier - logger *log.Logger -} - -type DBOpts func(db *DB) - -func WithLogger(logger *log.Logger) DBOpts { - return func(db *DB) { - db.logger = logger - } } -func NewDB(opts ...DBOpts) *DB { - db := &DB{ +func NewDB() *DB { + return &DB{ roles: make(map[string]*Role), verifiers: make(map[string]keys.Verifier), - logger: log.New(io.Discard, "", 0), - } - for _, opt := range opts { - opt(db) } - return db } // NewDBFromDelegations returns a DB that verifies delegations // of a given Targets. -func NewDBFromDelegations(d *data.Delegations, opts ...DBOpts) (*DB, error) { - db := NewDB(opts...) +func NewDBFromDelegations(d *data.Delegations) (*DB, error) { + db := &DB{ + roles: make(map[string]*Role, len(d.Roles)), + verifiers: make(map[string]keys.Verifier, len(d.Keys)), + } for _, r := range d.Roles { if _, ok := roles.TopLevelRoles[r.Name]; ok { return nil, ErrInvalidDelegatedRole @@ -67,11 +53,7 @@ func NewDBFromDelegations(d *data.Delegations, opts ...DBOpts) (*DB, error) { } func (db *DB) AddKey(id string, k *data.PublicKey) error { - opts := make([]keys.VerifierOpts, 0) - if db.logger != nil { - opts = append(opts, keys.WithLogger(db.logger)) - } - verifier, err := keys.GetVerifier(k, opts...) + verifier, err := keys.GetVerifier(k) if err != nil { return err // ErrInvalidKey } From ff7c5b69b7066f0bbce02140a5235892d5761806 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Mon, 19 Sep 2022 10:54:45 -0400 Subject: [PATCH 4/4] add linter rule prohibiting fmt.Print and fix cmd/ Signed-off-by: Asra Ali --- .golangci.yml | 1 + cmd/tuf-client/main.go | 3 ++- cmd/tuf/gen_key.go | 5 +++-- cmd/tuf/get_threshold.go | 3 ++- cmd/tuf/main.go | 8 ++++++-- cmd/tuf/payload.go | 3 ++- cmd/tuf/set_threshold.go | 3 ++- cmd/tuf/sign_payload.go | 2 +- 8 files changed, 19 insertions(+), 9 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 6e8bf3c8..570c05d6 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -13,3 +13,4 @@ linters: - gosimple - unused - typecheck + - forbidigo diff --git a/cmd/tuf-client/main.go b/cmd/tuf-client/main.go index 15d03fad..25a32005 100644 --- a/cmd/tuf-client/main.go +++ b/cmd/tuf-client/main.go @@ -3,6 +3,7 @@ package main import ( "fmt" "log" + "os" docopt "github.com/flynn/go-docopt" tuf "github.com/theupdateframework/go-tuf/client" @@ -32,7 +33,7 @@ See "tuf-client help " for more information on a specific command. if cmd == "help" { if len(cmdArgs) == 0 { // `tuf-client help` - fmt.Println(usage) + fmt.Fprint(os.Stderr, usage) return } else { // `tuf-client help ` cmd = cmdArgs[0] diff --git a/cmd/tuf/gen_key.go b/cmd/tuf/gen_key.go index bd4334ae..2ad77a58 100644 --- a/cmd/tuf/gen_key.go +++ b/cmd/tuf/gen_key.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "os" "time" "github.com/flynn/go-docopt" @@ -39,7 +40,7 @@ func cmdGenKey(args *docopt.Args, repo *tuf.Repo) error { string(data.KeySchemeRSASSA_PSS_SHA256): keyScheme = data.KeyScheme(t) default: - fmt.Println("Using default key scheme", keyScheme) + fmt.Fprint(os.Stderr, "Using default key scheme", keyScheme) } var err error @@ -57,7 +58,7 @@ func cmdGenKey(args *docopt.Args, repo *tuf.Repo) error { return err } for _, id := range keyids { - fmt.Println("Generated", role, keyScheme, "key with ID", id) + fmt.Fprintf(os.Stdout, "Generated %s %s key with ID %s", role, keyScheme, id) } return nil } diff --git a/cmd/tuf/get_threshold.go b/cmd/tuf/get_threshold.go index e40ec26e..a0d78fdd 100644 --- a/cmd/tuf/get_threshold.go +++ b/cmd/tuf/get_threshold.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "os" "github.com/flynn/go-docopt" "github.com/theupdateframework/go-tuf" @@ -23,6 +24,6 @@ func cmdGetThreshold(args *docopt.Args, repo *tuf.Repo) error { return err } - fmt.Println("The threshold for", role, "role is", threshold) + fmt.Fprintf(os.Stdout, "The threshold for %s role is %d", role, threshold) return nil } diff --git a/cmd/tuf/main.go b/cmd/tuf/main.go index f2b73972..6ee220b2 100644 --- a/cmd/tuf/main.go +++ b/cmd/tuf/main.go @@ -58,7 +58,7 @@ See "tuf help " for more information on a specific command if cmd == "help" { if len(cmdArgs) == 0 { // `tuf help` - fmt.Println(usage) + fmt.Fprint(os.Stderr, usage) return } else { // `tuf help ` cmd = cmdArgs[0] @@ -115,7 +115,11 @@ func runCommand(name string, args []string, dir string, insecure bool) error { if !insecure { p = getPassphrase } - repo, err := tuf.NewRepo(tuf.FileSystemStore(dir, p)) + logger := log.New(os.Stdout, "", 0) + storeOpts := tuf.StoreOpts{Logger: logger, PassFunc: p} + + repo, err := tuf.NewRepoWithOpts(tuf.FileSystemStoreWithOpts(dir, storeOpts), + tuf.WithLogger(logger)) if err != nil { return err } diff --git a/cmd/tuf/payload.go b/cmd/tuf/payload.go index 8cc0c2ff..3ae2c891 100644 --- a/cmd/tuf/payload.go +++ b/cmd/tuf/payload.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "os" "github.com/flynn/go-docopt" "github.com/theupdateframework/go-tuf" @@ -20,6 +21,6 @@ func cmdPayload(args *docopt.Args, repo *tuf.Repo) error { if err != nil { return err } - fmt.Print(string(p)) + fmt.Fprint(os.Stdout, string(p)) return nil } diff --git a/cmd/tuf/set_threshold.go b/cmd/tuf/set_threshold.go index 57754d24..29149ff9 100644 --- a/cmd/tuf/set_threshold.go +++ b/cmd/tuf/set_threshold.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "os" "strconv" "github.com/flynn/go-docopt" @@ -28,6 +29,6 @@ func cmdSetThreshold(args *docopt.Args, repo *tuf.Repo) error { return err } - fmt.Println("The threshold for", role, "role is now", threshold) + fmt.Fprintf(os.Stdout, "The threshold for %s role is now %d", role, threshold) return nil } diff --git a/cmd/tuf/sign_payload.go b/cmd/tuf/sign_payload.go index 8da5642b..6772972c 100644 --- a/cmd/tuf/sign_payload.go +++ b/cmd/tuf/sign_payload.go @@ -36,7 +36,7 @@ func cmdSignPayload(args *docopt.Args, repo *tuf.Repo) error { if err != nil { return err } - fmt.Print(string(bytes)) + fmt.Fprint(os.Stdout, string(bytes)) fmt.Fprintln(os.Stderr, "tuf: signed with", numKeys, "key(s)") return nil