Skip to content

Commit

Permalink
Switch from ed25519 to ecdsa (sigstore#52)
Browse files Browse the repository at this point in the history
* Switch from ed25519 to ecdsa

ed25519 hasn't yet been approved and won't work with most KMS systems, so we need to use ecdsa until it will.

I chose the P521 elliptic curve because it is the most secure one available, although I believe the tradeoff is larger keys.
It might be worth it to choose a different curve if we want people to be able to pass in public keys via command line.

Signed-off-by: Priya Wadhwa <priyawadhwa@google.com>

* Use pointer for pubilc key since rekor expects that

Signed-off-by: Priya Wadhwa <priyawadhwa@google.com>

* Hash payload before using SignASN1 or VerifyASN1

Signed-off-by: Priya Wadhwa <priyawadhwa@google.com>

* use pointer

Signed-off-by: Priya Wadhwa <priyawadhwa@google.com>

* Switch to P256 curve so that this will work with KMS's

Signed-off-by: Priya Wadhwa <priyawadhwa@google.com>
Signed-off-by: Dan Lorenc <dlorenc@google.com>
  • Loading branch information
priyawadhwa authored and Dan Lorenc committed Mar 6, 2021
1 parent 1a2a1e2 commit da9a0df
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 24 deletions.
15 changes: 11 additions & 4 deletions cmd/cli/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ package cli

import (
"context"
"crypto/ed25519"
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"flag"
"fmt"
Expand Down Expand Up @@ -120,13 +122,18 @@ func SignCmd(ctx context.Context, keyPath string,
}
kb, err := ioutil.ReadFile(keyPath)
if err != nil {
return err
return errors.Wrapf(err, "reading %s", keyPath)
}
pk, err := cosign.LoadPrivateKey(kb, pass)
if err != nil {
return err
return errors.Wrap(err, "loading private key")
}

h := sha256.Sum256(payload)
signature, err := ecdsa.SignASN1(rand.Reader, pk, h[:])
if err != nil {
return errors.Wrap(err, "signing asn1")
}
signature := ed25519.Sign(pk, payload)

if !upload {
fmt.Println(base64.StdEncoding.EncodeToString(signature))
Expand Down
10 changes: 8 additions & 2 deletions cmd/cli/sign_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ package cli

import (
"context"
"crypto/ed25519"
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"flag"
"fmt"
Expand Down Expand Up @@ -79,7 +81,11 @@ func SignBlobCmd(ctx context.Context, keyPath, payloadPath string, b64 bool, pf
if err != nil {
return err
}
signature := ed25519.Sign(pk, payload)
h := sha256.Sum256(payload)
signature, err := ecdsa.SignASN1(rand.Reader, pk, h[:])
if err != nil {
return err
}
if b64 {
fmt.Println(base64.StdEncoding.EncodeToString(signature))
} else {
Expand Down
15 changes: 11 additions & 4 deletions pkg/cosign/keys.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package cosign

import (
"crypto/ed25519"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"encoding/pem"

"github.com/pkg/errors"
"github.com/theupdateframework/go-tuf/encrypted"
)

Expand All @@ -17,27 +19,32 @@ type Keys struct {
}

func GenerateKeyPair(pf PassFunc) (*Keys, error) {
pub, priv, err := ed25519.GenerateKey(rand.Reader)
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, err
}

x509Encoded, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return nil, errors.Wrap(err, "x509 encoding private key")
}
// Encrypt the private key and store it.
password, err := pf(true)
if err != nil {
return nil, err
}

encBytes, err := encrypted.Encrypt(priv, password)
encBytes, err := encrypted.Encrypt(x509Encoded, password)
if err != nil {
return nil, err
}
// store in PEM format

privBytes := pem.EncodeToMemory(&pem.Block{
Bytes: encBytes,
Type: "ENCRYPTED COSIGN PRIVATE KEY",
})

pub := &priv.PublicKey
b, err := x509.MarshalPKIXPublicKey(pub)
if err != nil {
return nil, err
Expand Down
22 changes: 16 additions & 6 deletions pkg/cosign/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ limitations under the License.
package cosign

import (
"crypto/ed25519"
"crypto/ecdsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"

"github.com/pkg/errors"
"github.com/theupdateframework/go-tuf/encrypted"
)

Expand All @@ -30,7 +31,7 @@ const (
sigkey = "dev.cosignproject.cosign/signature"
)

func LoadPrivateKey(key []byte, pass []byte) (ed25519.PrivateKey, error) {
func LoadPrivateKey(key []byte, pass []byte) (*ecdsa.PrivateKey, error) {
// Decrypt first
p, _ := pem.Decode(key)
if p == nil {
Expand All @@ -40,11 +41,20 @@ func LoadPrivateKey(key []byte, pass []byte) (ed25519.PrivateKey, error) {
return nil, fmt.Errorf("unsupported pem type: %s", p.Type)
}

priv, err := encrypted.Decrypt(p.Bytes, pass)
x509Encoded, err := encrypted.Decrypt(p.Bytes, pass)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "decrypt")
}
return ed25519.PrivateKey(priv), nil

pk, err := x509.ParsePKCS8PrivateKey(x509Encoded)
if err != nil {
return nil, errors.Wrap(err, "parsing private key")
}
epk, ok := pk.(*ecdsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("invalid private key")
}
return epk, nil
}

type SimpleSigning struct {
Expand Down
21 changes: 13 additions & 8 deletions pkg/cosign/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ limitations under the License.
package cosign

import (
"crypto/ed25519"
"crypto/ecdsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/json"
Expand All @@ -33,7 +34,7 @@ import (

const pubKeyPemType = "PUBLIC KEY"

func LoadPublicKey(keyRef string) (ed25519.PublicKey, error) {
func LoadPublicKey(keyRef string) (*ecdsa.PublicKey, error) {
// The key could be plaintext or in a file.
// First check if the file exists.
var pubBytes []byte
Expand Down Expand Up @@ -62,14 +63,17 @@ func LoadPublicKey(keyRef string) (ed25519.PublicKey, error) {
if err != nil {
return nil, err
}
ed, ok := pub.(ed25519.PublicKey)
ed, ok := pub.(*ecdsa.PublicKey)
if !ok {
return nil, fmt.Errorf("invalid public key")
}
return ed, nil
}

func LoadPublicKeyFromPrivKey(pk ed25519.PrivateKey) ([]byte, error) {
func LoadPublicKeyFromPrivKey(pk *ecdsa.PrivateKey) ([]byte, error) {
if pk == nil {
return nil, fmt.Errorf("nil private key")
}
pubKey, err := x509.MarshalPKIXPublicKey(pk.Public())
if err != nil {
return nil, err
Expand All @@ -81,20 +85,21 @@ func LoadPublicKeyFromPrivKey(pk ed25519.PrivateKey) ([]byte, error) {
return pubBytes, nil
}

func VerifySignature(pubkey ed25519.PublicKey, base64sig string, payload []byte) error {
func VerifySignature(pubkey *ecdsa.PublicKey, base64sig string, payload []byte) error {
signature, err := base64.StdEncoding.DecodeString(base64sig)
if err != nil {
return err
}

if !ed25519.Verify(pubkey, payload, signature) {
h := sha256.Sum256(payload)
if !ecdsa.VerifyASN1(pubkey, h[:], signature) {
return errors.New("unable to verify signature")
}

return nil
}

func Verify(ref name.Reference, pubKey ed25519.PublicKey, checkClaims bool, annotations map[string]string) ([]SignedPayload, error) {
func Verify(ref name.Reference, pubKey *ecdsa.PublicKey, checkClaims bool, annotations map[string]string) ([]SignedPayload, error) {
signatures, desc, err := FetchSignatures(ref)
if err != nil {
return nil, err
Expand Down Expand Up @@ -124,7 +129,7 @@ func Verify(ref name.Reference, pubKey ed25519.PublicKey, checkClaims bool, anno
return verified, nil
}

func validSignatures(pubKey ed25519.PublicKey, signatures []SignedPayload) ([]SignedPayload, error) {
func validSignatures(pubKey *ecdsa.PublicKey, signatures []SignedPayload) ([]SignedPayload, error) {
validSignatures := []SignedPayload{}
validationErrs := []string{}

Expand Down

0 comments on commit da9a0df

Please sign in to comment.