From 731bc3e10fb3540f9fccae572408be162f86e61b Mon Sep 17 00:00:00 2001 From: Toby Bristow Date: Sat, 16 Apr 2022 19:37:41 +0100 Subject: [PATCH 1/4] add support for ecdsa and rsa keys --- data/pkix.go | 46 ++++++++++++++ data/pkix_test.go | 42 +++++++++++++ pkg/keys/ecdsa.go | 132 ++++++++++++++++++++++++++++++--------- pkg/keys/ecdsa_test.go | 44 +++++++++++++ pkg/keys/ed25519.go | 8 +-- pkg/keys/ed25519_test.go | 2 +- pkg/keys/rsa.go | 96 ++++++++++++++-------------- pkg/keys/rsa_test.go | 14 +++++ 8 files changed, 299 insertions(+), 85 deletions(-) create mode 100644 data/pkix.go create mode 100644 data/pkix_test.go create mode 100644 pkg/keys/ecdsa_test.go diff --git a/data/pkix.go b/data/pkix.go new file mode 100644 index 00000000..4d718b6b --- /dev/null +++ b/data/pkix.go @@ -0,0 +1,46 @@ +package data + +import ( + "crypto" + "crypto/x509" + "encoding/json" + "encoding/pem" + "errors" + "fmt" +) + +type PKIXPublicKey struct { + crypto.PublicKey +} + +func (p *PKIXPublicKey) MarshalJSON() ([]byte, error) { + bytes, err := x509.MarshalPKIXPublicKey(p.PublicKey) + if err != nil { + return nil, err + } + pemBytes := pem.EncodeToMemory(&pem.Block{ + Type: "PUBLIC KEY", + Bytes: bytes, + }) + return json.Marshal(string(pemBytes)) +} + +func (p *PKIXPublicKey) UnmarshalJSON(b []byte) error { + var pemValue string + if err := json.Unmarshal(b, &pemValue); err != nil { + return err + } + block, _ := pem.Decode([]byte(pemValue)) + if block == nil { + return errors.New("invalid PEM value") + } + if block.Type != "PUBLIC KEY" { + return fmt.Errorf("invalid block type: %s", block.Type) + } + pub, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return err + } + p.PublicKey = pub + return nil +} diff --git a/data/pkix_test.go b/data/pkix_test.go new file mode 100644 index 00000000..11b75140 --- /dev/null +++ b/data/pkix_test.go @@ -0,0 +1,42 @@ +package data + +import ( + "crypto/ecdsa" + "crypto/x509" + "encoding/json" + "encoding/pem" + + . "gopkg.in/check.v1" +) + +const ecdsaKey = `-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEftgasQA68yvumeXZmcOTSIHKfbmx +WT1oYuRF0Un3tKxnzip6xAYwlz0Dt96DUh+0P7BruHH2O6s4MiRR9/TuNw== +-----END PUBLIC KEY----- +` + +type PKIXSuite struct{} + +var _ = Suite(&PKIXSuite{}) + +func (PKIXSuite) TestMarshalJSON(c *C) { + block, _ := pem.Decode([]byte(ecdsaKey)) + key, err := x509.ParsePKIXPublicKey(block.Bytes) + c.Assert(err, IsNil) + k := PKIXPublicKey{PublicKey: key} + buf, err := json.Marshal(&k) + c.Assert(err, IsNil) + var val string + err = json.Unmarshal(buf, &val) + c.Assert(err, IsNil) + c.Assert(val, Equals, ecdsaKey) +} + +func (PKIXSuite) TestUnmarshalJSON(c *C) { + buf, err := json.Marshal(ecdsaKey) + c.Assert(err, IsNil) + var k PKIXPublicKey + err = json.Unmarshal(buf, &k) + c.Assert(err, IsNil) + c.Assert(k.PublicKey, FitsTypeOf, (*ecdsa.PublicKey)(nil)) +} diff --git a/pkg/keys/ecdsa.go b/pkg/keys/ecdsa.go index 1471235b..8bfa9ec0 100644 --- a/pkg/keys/ecdsa.go +++ b/pkg/keys/ecdsa.go @@ -3,69 +3,139 @@ package keys import ( "crypto/ecdsa" "crypto/elliptic" + "crypto/rand" "crypto/sha256" - "encoding/asn1" + "crypto/x509" "encoding/json" + "encoding/pem" "errors" - "math/big" + "fmt" "github.com/theupdateframework/go-tuf/data" ) func init() { - VerifierMap.Store(data.KeyTypeECDSA_SHA2_P256, NewEcdsaVerifier) + VerifierMap.Store(data.KeyTypeECDSA_SHA2_P256, newEcdsaVerifier) + SignerMap.Store(data.KeyTypeECDSA_SHA2_P256, newEcdsaSigner) } -func NewEcdsaVerifier() Verifier { - return &p256Verifier{} +func newEcdsaVerifier() Verifier { + return &ecdsaVerifier{} } -type ecdsaSignature struct { - R, S *big.Int +func newEcdsaSigner() Signer { + return &ecdsaSigner{} } -type p256Verifier struct { - PublicKey data.HexBytes `json:"public"` +type ecdsaVerifier struct { + PublicKey *data.PKIXPublicKey `json:"public"` + ecdsaKey *ecdsa.PublicKey key *data.PublicKey } -func (p *p256Verifier) Public() string { - return p.PublicKey.String() +func (p *ecdsaVerifier) Public() string { + r, _ := x509.MarshalPKIXPublicKey(p.ecdsaKey) + return string(r) } -func (p *p256Verifier) Verify(msg, sigBytes []byte) error { - x, y := elliptic.Unmarshal(elliptic.P256(), p.PublicKey) - k := &ecdsa.PublicKey{ - Curve: elliptic.P256(), - X: x, - Y: y, - } - - var sig ecdsaSignature - if _, err := asn1.Unmarshal(sigBytes, &sig); err != nil { - return err - } - +func (p *ecdsaVerifier) Verify(msg, sigBytes []byte) error { hash := sha256.Sum256(msg) - if !ecdsa.Verify(k, hash[:], sig.R, sig.S) { - return errors.New("tuf: ecdsa signature verification failed") + if !ecdsa.VerifyASN1(p.ecdsaKey, hash[:], sigBytes) { + return errors.New("signature verification failed") } return nil } -func (p *p256Verifier) MarshalPublicKey() *data.PublicKey { +func (p *ecdsaVerifier) MarshalPublicKey() *data.PublicKey { return p.key } -func (p *p256Verifier) UnmarshalPublicKey(key *data.PublicKey) error { +func (p *ecdsaVerifier) UnmarshalPublicKey(key *data.PublicKey) error { if err := json.Unmarshal(key.Value, p); err != nil { return err } - x, _ := elliptic.Unmarshal(elliptic.P256(), p.PublicKey) - if x == nil { - return errors.New("tuf: invalid ecdsa public key point") + ecdsaKey, ok := p.PublicKey.PublicKey.(*ecdsa.PublicKey) + if !ok { + return fmt.Errorf("invalid public key") } + p.ecdsaKey = ecdsaKey p.key = key return nil } + +type ecdsaSigner struct { + *ecdsa.PrivateKey +} + +type ecdsaPrivateKeyValue struct { + Private string `json:"private"` + Public *data.PKIXPublicKey `json:"public"` +} + +func (s *ecdsaSigner) PublicData() *data.PublicKey { + keyValBytes, _ := json.Marshal(ecdsaVerifier{PublicKey: &data.PKIXPublicKey{PublicKey: s.Public()}}) + return &data.PublicKey{ + Type: data.KeyTypeECDSA_SHA2_P256, + Scheme: data.KeySchemeECDSA_SHA2_P256, + Algorithms: data.HashAlgorithms, + Value: keyValBytes, + } +} + +func (s *ecdsaSigner) SignMessage(message []byte) ([]byte, error) { + hash := sha256.Sum256(message) + return ecdsa.SignASN1(rand.Reader, s.PrivateKey, hash[:]) +} + +func (s *ecdsaSigner) MarshalPrivateKey() (*data.PrivateKey, error) { + priv, err := x509.MarshalECPrivateKey(s.PrivateKey) + if err != nil { + return nil, err + } + pemKey := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: priv}) + val, err := json.Marshal(ecdsaPrivateKeyValue{ + Private: string(pemKey), + Public: &data.PKIXPublicKey{PublicKey: s.Public()}, + }) + if err != nil { + return nil, err + } + return &data.PrivateKey{ + Type: data.KeyTypeECDSA_SHA2_P256, + Scheme: data.KeySchemeECDSA_SHA2_P256, + Algorithms: data.HashAlgorithms, + Value: val, + }, nil +} + +func (s *ecdsaSigner) UnmarshalPrivateKey(key *data.PrivateKey) error { + val := ecdsaPrivateKeyValue{} + if err := json.Unmarshal(key.Value, &val); err != nil { + return err + } + block, _ := pem.Decode([]byte(val.Private)) + if block == nil { + return errors.New("invalid PEM value") + } + if block.Type != "EC PRIVATE KEY" { + return fmt.Errorf("invalid block type: %s", block.Type) + } + k, err := x509.ParseECPrivateKey(block.Bytes) + if err != nil { + return err + } + if k.Curve != elliptic.P256() { + return errors.New("invalid ecdsa curve") + } + s.PrivateKey = k + return nil +} + +func GenerateEcdsaKey() (*ecdsaSigner, error) { + privkey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil, err + } + return &ecdsaSigner{privkey}, nil +} diff --git a/pkg/keys/ecdsa_test.go b/pkg/keys/ecdsa_test.go new file mode 100644 index 00000000..0cbca77a --- /dev/null +++ b/pkg/keys/ecdsa_test.go @@ -0,0 +1,44 @@ +package keys + +import ( + "github.com/theupdateframework/go-tuf/data" + . "gopkg.in/check.v1" +) + +type EcdsaSuite struct{} + +var _ = Suite(EcdsaSuite{}) + +func (EcdsaSuite) TestSignVerify(c *C) { + signer, err := GenerateEcdsaKey() + c.Assert(err, IsNil) + msg := []byte("foo") + sig, err := signer.SignMessage(msg) + c.Assert(err, IsNil) + publicData := signer.PublicData() + pubKey, err := GetVerifier(publicData) + c.Assert(err, IsNil) + c.Assert(pubKey.Verify(msg, sig), IsNil) +} + +func (EcdsaSuite) TestMarshalUnmarshalPublicKey(c *C) { + signer, err := GenerateEcdsaKey() + c.Assert(err, IsNil) + publicData := signer.PublicData() + pubKey, err := GetVerifier(publicData) + c.Assert(err, IsNil) + c.Assert(pubKey.MarshalPublicKey(), DeepEquals, publicData) +} + +func (EcdsaSuite) TestMarshalUnmarshalPrivateKey(c *C) { + signer, err := GenerateEcdsaKey() + c.Assert(err, IsNil) + privateData, err := signer.MarshalPrivateKey() + c.Assert(err, IsNil) + c.Assert(privateData.Type, Equals, data.KeyTypeECDSA_SHA2_P256) + c.Assert(privateData.Scheme, Equals, data.KeySchemeECDSA_SHA2_P256) + c.Assert(privateData.Algorithms, DeepEquals, data.HashAlgorithms) + s, err := GetSigner(privateData) + c.Assert(err, IsNil) + c.Assert(s, DeepEquals, signer) +} diff --git a/pkg/keys/ed25519.go b/pkg/keys/ed25519.go index 88f6f864..ffaa0fc1 100644 --- a/pkg/keys/ed25519.go +++ b/pkg/keys/ed25519.go @@ -11,15 +11,15 @@ import ( ) func init() { - SignerMap.Store(data.KeySchemeEd25519, NewP256Signer) - VerifierMap.Store(data.KeySchemeEd25519, NewP256Verifier) + SignerMap.Store(data.KeyTypeEd25519, newEd25519Signer) + VerifierMap.Store(data.KeyTypeEd25519, newEd25519Verifier) } -func NewP256Signer() Signer { +func newEd25519Signer() Signer { return &ed25519Signer{} } -func NewP256Verifier() Verifier { +func newEd25519Verifier() Verifier { return &ed25519Verifier{} } diff --git a/pkg/keys/ed25519_test.go b/pkg/keys/ed25519_test.go index 657b16ce..2eedbabd 100644 --- a/pkg/keys/ed25519_test.go +++ b/pkg/keys/ed25519_test.go @@ -19,7 +19,7 @@ func (Ed25519Suite) TestUnmarshalEd25519(c *C) { Algorithms: data.HashAlgorithms, Value: badKeyValue, } - verifier := NewP256Verifier() + verifier := newEd25519Verifier() c.Assert(verifier.UnmarshalPublicKey(badKey), ErrorMatches, "json: cannot unmarshal.*") } diff --git a/pkg/keys/rsa.go b/pkg/keys/rsa.go index 28c82d14..97206ab8 100644 --- a/pkg/keys/rsa.go +++ b/pkg/keys/rsa.go @@ -9,37 +9,32 @@ import ( "encoding/json" "encoding/pem" "errors" + "fmt" "github.com/theupdateframework/go-tuf/data" ) func init() { - VerifierMap.Store(data.KeyTypeRSASSA_PSS_SHA256, NewRsaVerifier) - SignerMap.Store(data.KeyTypeRSASSA_PSS_SHA256, NewRsaSigner) + VerifierMap.Store(data.KeyTypeRSASSA_PSS_SHA256, newRsaVerifier) + SignerMap.Store(data.KeyTypeRSASSA_PSS_SHA256, newRsaSigner) } -func NewRsaVerifier() Verifier { +func newRsaVerifier() Verifier { return &rsaVerifier{} } -func NewRsaSigner() Signer { +func newRsaSigner() Signer { return &rsaSigner{} } type rsaVerifier struct { - PublicKey string `json:"public"` + PublicKey *data.PKIXPublicKey `json:"public"` rsaKey *rsa.PublicKey key *data.PublicKey } func (p *rsaVerifier) Public() string { - // Unique public key identifier, use a uniform encodng - r, err := x509.MarshalPKIXPublicKey(p.rsaKey) - if err != nil { - // This shouldn't happen with a valid rsa key, but fallback on the - // JSON public key string - return string(p.PublicKey) - } + r, _ := x509.MarshalPKIXPublicKey(p.rsaKey) return string(r) } @@ -57,53 +52,26 @@ func (p *rsaVerifier) UnmarshalPublicKey(key *data.PublicKey) error { if err := json.Unmarshal(key.Value, p); err != nil { return err } - var err error - p.rsaKey, err = parseKey(p.PublicKey) - if err != nil { - return err + rsaKey, ok := p.PublicKey.PublicKey.(*rsa.PublicKey) + if !ok { + return fmt.Errorf("invalid public key") } + p.rsaKey = rsaKey p.key = key return nil } -// parseKey tries to parse a PEM []byte slice by attempting PKCS1 and PKIX in order. -func parseKey(data string) (*rsa.PublicKey, error) { - block, _ := pem.Decode([]byte(data)) - if block == nil { - return nil, errors.New("tuf: pem decoding public key failed") - } - rsaPub, err := x509.ParsePKCS1PublicKey(block.Bytes) - if err == nil { - return rsaPub, nil - } - key, err := x509.ParsePKIXPublicKey(block.Bytes) - if err == nil { - rsaPub, ok := key.(*rsa.PublicKey) - if !ok { - return nil, errors.New("tuf: invalid rsa key") - } - return rsaPub, nil - } - return nil, errors.New("tuf: error unmarshalling rsa key") -} - type rsaSigner struct { *rsa.PrivateKey } -type rsaPublic struct { - // PEM encoded public key. - PublicKey string `json:"public"` +type rsaPrivateKeyValue struct { + Private string `json:"private"` + Public *data.PKIXPublicKey `json:"public"` } func (s *rsaSigner) PublicData() *data.PublicKey { - pub, _ := x509.MarshalPKIXPublicKey(s.Public().(*rsa.PublicKey)) - pubBytes := pem.EncodeToMemory(&pem.Block{ - Type: "RSA PUBLIC KEY", - Bytes: pub, - }) - - keyValBytes, _ := json.Marshal(rsaPublic{PublicKey: string(pubBytes)}) + keyValBytes, _ := json.Marshal(rsaVerifier{PublicKey: &data.PKIXPublicKey{PublicKey: s.Public()}}) return &data.PublicKey{ Type: data.KeyTypeRSASSA_PSS_SHA256, Scheme: data.KeySchemeRSASSA_PSS_SHA256, @@ -122,11 +90,41 @@ func (s *rsaSigner) ContainsID(id string) bool { } func (s *rsaSigner) MarshalPrivateKey() (*data.PrivateKey, error) { - return nil, errors.New("not implemented for test") + priv := x509.MarshalPKCS1PrivateKey(s.PrivateKey) + pemKey := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: priv}) + val, err := json.Marshal(rsaPrivateKeyValue{ + Private: string(pemKey), + Public: &data.PKIXPublicKey{PublicKey: s.Public()}, + }) + if err != nil { + return nil, err + } + return &data.PrivateKey{ + Type: data.KeyTypeRSASSA_PSS_SHA256, + Scheme: data.KeySchemeRSASSA_PSS_SHA256, + Algorithms: data.HashAlgorithms, + Value: val, + }, nil } func (s *rsaSigner) UnmarshalPrivateKey(key *data.PrivateKey) error { - return errors.New("not implemented for test") + val := rsaPrivateKeyValue{} + if err := json.Unmarshal(key.Value, &val); err != nil { + return err + } + block, _ := pem.Decode([]byte(val.Private)) + if block == nil { + return errors.New("invalid PEM value") + } + if block.Type != "RSA PRIVATE KEY" { + return fmt.Errorf("invalid block type: %s", block.Type) + } + k, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return err + } + s.PrivateKey = k + return nil } func GenerateRsaKey() (*rsaSigner, error) { diff --git a/pkg/keys/rsa_test.go b/pkg/keys/rsa_test.go index d0e3e862..8735fb8e 100644 --- a/pkg/keys/rsa_test.go +++ b/pkg/keys/rsa_test.go @@ -1,6 +1,7 @@ package keys import ( + "github.com/theupdateframework/go-tuf/data" . "gopkg.in/check.v1" ) @@ -28,3 +29,16 @@ func (RsaSuite) TestMarshalUnmarshal(c *C) { c.Assert(err, IsNil) c.Assert(pubKey.MarshalPublicKey(), DeepEquals, publicData) } + +func (RsaSuite) TestMarshalUnmarshalPrivateKey(c *C) { + signer, err := GenerateRsaKey() + c.Assert(err, IsNil) + privateData, err := signer.MarshalPrivateKey() + c.Assert(err, IsNil) + c.Assert(privateData.Type, Equals, data.KeyTypeRSASSA_PSS_SHA256) + c.Assert(privateData.Scheme, Equals, data.KeySchemeRSASSA_PSS_SHA256) + c.Assert(privateData.Algorithms, DeepEquals, data.HashAlgorithms) + s, err := GetSigner(privateData) + c.Assert(err, IsNil) + c.Assert(s, DeepEquals, signer) +} From 05a6b19e80f1eaa97d0b28ec5def2b7cd062444e Mon Sep 17 00:00:00 2001 From: Toby Bristow Date: Sat, 16 Apr 2022 21:07:29 +0100 Subject: [PATCH 2/4] Make specific types for key types, schemes and hash algorithms --- data/types.go | 39 +++++++++++++++++++++++------------- internal/signer/sort_test.go | 2 +- pkg/keys/ed25519.go | 31 +++++++++------------------- pkg/keys/keys_test.go | 3 ++- verify/db_test.go | 2 +- 5 files changed, 38 insertions(+), 39 deletions(-) diff --git a/data/types.go b/data/types.go index 6ec2fc34..ee2d1671 100644 --- a/data/types.go +++ b/data/types.go @@ -14,18 +14,29 @@ import ( "github.com/secure-systems-lab/go-securesystemslib/cjson" ) +type KeyType string + +type KeyScheme string + +type HashAlgorithm string + const ( - KeyIDLength = sha256.Size * 2 - KeyTypeEd25519 = "ed25519" - KeyTypeECDSA_SHA2_P256 = "ecdsa-sha2-nistp256" - KeySchemeEd25519 = "ed25519" - KeySchemeECDSA_SHA2_P256 = "ecdsa-sha2-nistp256" - KeyTypeRSASSA_PSS_SHA256 = "rsa" - KeySchemeRSASSA_PSS_SHA256 = "rsassa-pss-sha256" + KeyIDLength = sha256.Size * 2 + + KeyTypeEd25519 KeyType = "ed25519" + KeyTypeECDSA_SHA2_P256 KeyType = "ecdsa-sha2-nistp256" + KeyTypeRSASSA_PSS_SHA256 KeyType = "rsa" + + KeySchemeEd25519 KeyScheme = "ed25519" + KeySchemeECDSA_SHA2_P256 KeyScheme = "ecdsa-sha2-nistp256" + KeySchemeRSASSA_PSS_SHA256 KeyScheme = "rsassa-pss-sha256" + + HashAlgorithmSHA256 HashAlgorithm = "sha256" + HashAlgorithmSHA512 HashAlgorithm = "sha512" ) var ( - HashAlgorithms = []string{"sha256", "sha512"} + HashAlgorithms = []HashAlgorithm{HashAlgorithmSHA256, HashAlgorithmSHA512} ErrPathsAndPathHashesSet = errors.New("tuf: failed validation of delegated target: paths and path_hash_prefixes are both set") ) @@ -40,9 +51,9 @@ type Signature struct { } type PublicKey struct { - Type string `json:"keytype"` - Scheme string `json:"scheme"` - Algorithms []string `json:"keyid_hash_algorithms,omitempty"` + Type KeyType `json:"keytype"` + Scheme KeyScheme `json:"scheme"` + Algorithms []HashAlgorithm `json:"keyid_hash_algorithms,omitempty"` Value json.RawMessage `json:"keyval"` ids []string @@ -50,9 +61,9 @@ type PublicKey struct { } type PrivateKey struct { - Type string `json:"keytype"` - Scheme string `json:"scheme,omitempty"` - Algorithms []string `json:"keyid_hash_algorithms,omitempty"` + Type KeyType `json:"keytype"` + Scheme KeyScheme `json:"scheme,omitempty"` + Algorithms []HashAlgorithm `json:"keyid_hash_algorithms,omitempty"` Value json.RawMessage `json:"keyval"` } diff --git a/internal/signer/sort_test.go b/internal/signer/sort_test.go index eb9f94d7..afda5f87 100644 --- a/internal/signer/sort_test.go +++ b/internal/signer/sort_test.go @@ -26,7 +26,7 @@ func (s *mockSigner) PublicData() *data.PublicKey { return &data.PublicKey{ Type: "mock", Scheme: "mock", - Algorithms: []string{"mock"}, + Algorithms: []data.HashAlgorithm{"mock"}, Value: s.value, } } diff --git a/pkg/keys/ed25519.go b/pkg/keys/ed25519.go index ffaa0fc1..9b8c2dfb 100644 --- a/pkg/keys/ed25519.go +++ b/pkg/keys/ed25519.go @@ -61,10 +61,6 @@ type Ed25519PrivateKeyValue struct { type ed25519Signer struct { ed25519.PrivateKey - - keyType string - keyScheme string - keyAlgorithms []string } func GenerateEd25519Key() (*ed25519Signer, error) { @@ -76,19 +72,13 @@ func GenerateEd25519Key() (*ed25519Signer, error) { return nil, err } return &ed25519Signer{ - PrivateKey: ed25519.PrivateKey(data.HexBytes(private)), - keyType: data.KeyTypeEd25519, - keyScheme: data.KeySchemeEd25519, - keyAlgorithms: data.HashAlgorithms, + PrivateKey: ed25519.PrivateKey(data.HexBytes(private)), }, nil } func NewEd25519Signer(keyValue Ed25519PrivateKeyValue) *ed25519Signer { return &ed25519Signer{ - PrivateKey: ed25519.PrivateKey(data.HexBytes(keyValue.Private)), - keyType: data.KeyTypeEd25519, - keyScheme: data.KeySchemeEd25519, - keyAlgorithms: data.HashAlgorithms, + PrivateKey: ed25519.PrivateKey(data.HexBytes(keyValue.Private)), } } @@ -105,9 +95,9 @@ func (e *ed25519Signer) MarshalPrivateKey() (*data.PrivateKey, error) { return nil, err } return &data.PrivateKey{ - Type: e.keyType, - Scheme: e.keyScheme, - Algorithms: e.keyAlgorithms, + Type: data.KeyTypeEd25519, + Scheme: data.KeySchemeEd25519, + Algorithms: data.HashAlgorithms, Value: valueBytes, }, nil } @@ -118,10 +108,7 @@ func (e *ed25519Signer) UnmarshalPrivateKey(key *data.PrivateKey) error { return err } *e = ed25519Signer{ - PrivateKey: ed25519.PrivateKey(data.HexBytes(keyValue.Private)), - keyType: key.Type, - keyScheme: key.Scheme, - keyAlgorithms: key.Algorithms, + PrivateKey: ed25519.PrivateKey(data.HexBytes(keyValue.Private)), } return nil } @@ -129,9 +116,9 @@ func (e *ed25519Signer) UnmarshalPrivateKey(key *data.PrivateKey) error { func (e *ed25519Signer) PublicData() *data.PublicKey { keyValBytes, _ := json.Marshal(ed25519Verifier{PublicKey: []byte(e.PrivateKey.Public().(ed25519.PublicKey))}) return &data.PublicKey{ - Type: e.keyType, - Scheme: e.keyScheme, - Algorithms: e.keyAlgorithms, + Type: data.KeyTypeEd25519, + Scheme: data.KeySchemeEd25519, + Algorithms: data.HashAlgorithms, Value: keyValBytes, } } diff --git a/pkg/keys/keys_test.go b/pkg/keys/keys_test.go index 956a318e..c1a7d018 100644 --- a/pkg/keys/keys_test.go +++ b/pkg/keys/keys_test.go @@ -3,6 +3,7 @@ package keys import ( "testing" + "github.com/theupdateframework/go-tuf/data" . "gopkg.in/check.v1" ) @@ -32,7 +33,7 @@ func (KeysSuite) TestSignerKeyIDs(c *C) { c.Assert(err, IsNil) privKey, err = signer.MarshalPrivateKey() c.Assert(err, IsNil) - privKey.Algorithms = []string{} + privKey.Algorithms = []data.HashAlgorithm{} err = signer.UnmarshalPrivateKey(privKey) c.Assert(err, IsNil) } diff --git a/verify/db_test.go b/verify/db_test.go index 84031ffb..a624d6ef 100644 --- a/verify/db_test.go +++ b/verify/db_test.go @@ -36,7 +36,7 @@ func TestDelegationsDB(t *testing.T) { { testName: "invalid keys", delegations: &data.Delegations{Keys: map[string]*data.PublicKey{ - "a": {Type: data.KeySchemeEd25519}, + "a": {Type: data.KeyTypeEd25519}, }}, initErr: ErrWrongID{}, }, From 4a565fce5aa49e319624c59416fb37573b47aa19 Mon Sep 17 00:00:00 2001 From: Toby Bristow Date: Sat, 16 Apr 2022 21:13:34 +0100 Subject: [PATCH 3/4] add type flag to gen-key command --- cmd/tuf/gen_key.go | 26 ++++++++++++++++++++------ repo.go | 27 +++++++++++++++++++++------ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/cmd/tuf/gen_key.go b/cmd/tuf/gen_key.go index b994843a..3f9f0a10 100644 --- a/cmd/tuf/gen_key.go +++ b/cmd/tuf/gen_key.go @@ -1,16 +1,18 @@ package main import ( + "errors" "fmt" "time" "github.com/flynn/go-docopt" "github.com/theupdateframework/go-tuf" + "github.com/theupdateframework/go-tuf/data" ) func init() { register("gen-key", cmdGenKey, ` -usage: tuf gen-key [--expires=] +usage: tuf gen-key [--expires=] [--type=] Generate a new signing key for the given role. @@ -23,23 +25,35 @@ form of TUF_{{ROLE}}_PASSPHRASE Options: --expires= Set the root metadata file to expire days from now. + --type= Set the type of key to generate [default: ed25519]. `) } func cmdGenKey(args *docopt.Args, repo *tuf.Repo) error { role := args.String[""] var keyids []string - var err error + + var keyType data.KeyType + switch t := args.String["--type"]; t { + case string(data.KeyTypeEd25519), + string(data.KeyTypeECDSA_SHA2_P256), + string(data.KeyTypeRSASSA_PSS_SHA256): + keyType = data.KeyType(t) + default: + return errors.New("invalid key type") + } + + var expires time.Time if arg := args.String["--expires"]; arg != "" { - var expires time.Time - expires, err = parseExpires(arg) + exp, err := parseExpires(arg) if err != nil { return err } - keyids, err = repo.GenKeyWithExpires(role, expires) + expires = exp } else { - keyids, err = repo.GenKey(role) + expires = data.DefaultExpires(role) } + keyids, err := repo.GenKeyWithTypeAndExpires(role, expires, data.KeyType(keyType)) if err != nil { return err } diff --git a/repo.go b/repo.go index 10d13af3..85b0ee3d 100644 --- a/repo.go +++ b/repo.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/hex" "encoding/json" + "errors" "fmt" "io" "path" @@ -302,16 +303,30 @@ func (r *Repo) GenKey(role string) ([]string, error) { } func (r *Repo) GenKeyWithExpires(keyRole string, expires time.Time) (keyids []string, err error) { - signer, err := keys.GenerateEd25519Key() + return r.GenKeyWithTypeAndExpires(keyRole, expires, data.KeyTypeEd25519) +} + +func (r *Repo) GenKeyWithTypeAndExpires(role string, expires time.Time, keyType data.KeyType) ([]string, error) { + var signer keys.Signer + var err error + switch keyType { + case data.KeyTypeEd25519: + signer, err = keys.GenerateEd25519Key() + case data.KeyTypeECDSA_SHA2_P256: + signer, err = keys.GenerateEcdsaKey() + case data.KeyTypeRSASSA_PSS_SHA256: + signer, err = keys.GenerateRsaKey() + default: + return nil, errors.New("unknown key type") + } if err != nil { - return []string{}, err + return nil, err } - if err = r.AddPrivateKeyWithExpires(keyRole, signer, expires); err != nil { - return []string{}, err + if err := r.AddPrivateKeyWithExpires(role, signer, expires); err != nil { + return nil, err } - keyids = signer.PublicData().IDs() - return + return signer.PublicData().IDs(), nil } func (r *Repo) AddPrivateKey(role string, signer keys.Signer) error { From 488fb529594a63ae43c0a30a0273835aa4e0e7a2 Mon Sep 17 00:00:00 2001 From: Toby Bristow Date: Sat, 16 Apr 2022 21:58:09 +0100 Subject: [PATCH 4/4] test fixes --- verify/db.go | 2 +- verify/verify_test.go | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/verify/db.go b/verify/db.go index a14a5149..aa46a510 100644 --- a/verify/db.go +++ b/verify/db.go @@ -58,7 +58,7 @@ func (db *DB) AddKey(id string, k *data.PublicKey) error { } verifier, err := keys.GetVerifier(k) if err != nil { - return ErrInvalidKey + return err // ErrInvalidKey } db.verifiers[id] = verifier return nil diff --git a/verify/verify_test.go b/verify/verify_test.go index 4d9d3794..acf96f27 100644 --- a/verify/verify_test.go +++ b/verify/verify_test.go @@ -31,12 +31,11 @@ type ecdsaSigner struct { } type ecdsaPublic struct { - PublicKey data.HexBytes `json:"public"` + PublicKey *data.PKIXPublicKey `json:"public"` } func (s ecdsaSigner) PublicData() *data.PublicKey { - pub := s.Public().(*ecdsa.PublicKey) - keyValBytes, _ := json.Marshal(ecdsaPublic{PublicKey: elliptic.Marshal(pub.Curve, pub.X, pub.Y)}) + keyValBytes, _ := json.Marshal(ecdsaPublic{PublicKey: &data.PKIXPublicKey{PublicKey: s.Public()}}) return &data.PublicKey{ Type: data.KeyTypeECDSA_SHA2_P256, Scheme: data.KeySchemeECDSA_SHA2_P256,