summaryrefslogtreecommitdiffstats
path: root/signerverifier/ecdsa.go
diff options
context:
space:
mode:
Diffstat (limited to 'signerverifier/ecdsa.go')
-rw-r--r--signerverifier/ecdsa.go111
1 files changed, 111 insertions, 0 deletions
diff --git a/signerverifier/ecdsa.go b/signerverifier/ecdsa.go
new file mode 100644
index 0000000..f3e6c20
--- /dev/null
+++ b/signerverifier/ecdsa.go
@@ -0,0 +1,111 @@
+package signerverifier
+
+import (
+ "context"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/rand"
+ "crypto/sha256"
+ "crypto/sha512"
+ "fmt"
+ "os"
+)
+
+const ECDSAKeyType = "ecdsa"
+
+// ECDSASignerVerifier is a dsse.SignerVerifier compliant interface to sign and
+// verify signatures using ECDSA keys.
+type ECDSASignerVerifier struct {
+ keyID string
+ curveSize int
+ private *ecdsa.PrivateKey
+ public *ecdsa.PublicKey
+}
+
+// NewECDSASignerVerifierFromSSLibKey creates an ECDSASignerVerifier from an
+// SSLibKey.
+func NewECDSASignerVerifierFromSSLibKey(key *SSLibKey) (*ECDSASignerVerifier, error) {
+ if len(key.KeyVal.Public) == 0 {
+ return nil, ErrInvalidKey
+ }
+
+ _, publicParsedKey, err := decodeAndParsePEM([]byte(key.KeyVal.Public))
+ if err != nil {
+ return nil, fmt.Errorf("unable to create ECDSA signerverifier: %w", err)
+ }
+
+ sv := &ECDSASignerVerifier{
+ keyID: key.KeyID,
+ curveSize: publicParsedKey.(*ecdsa.PublicKey).Params().BitSize,
+ public: publicParsedKey.(*ecdsa.PublicKey),
+ private: nil,
+ }
+
+ if len(key.KeyVal.Private) > 0 {
+ _, privateParsedKey, err := decodeAndParsePEM([]byte(key.KeyVal.Private))
+ if err != nil {
+ return nil, fmt.Errorf("unable to create ECDSA signerverifier: %w", err)
+ }
+
+ sv.private = privateParsedKey.(*ecdsa.PrivateKey)
+ }
+
+ return sv, nil
+}
+
+// Sign creates a signature for `data`.
+func (sv *ECDSASignerVerifier) Sign(ctx context.Context, data []byte) ([]byte, error) {
+ if sv.private == nil {
+ return nil, ErrNotPrivateKey
+ }
+
+ hashedData := getECDSAHashedData(data, sv.curveSize)
+
+ return ecdsa.SignASN1(rand.Reader, sv.private, hashedData)
+}
+
+// Verify verifies the `sig` value passed in against `data`.
+func (sv *ECDSASignerVerifier) Verify(ctx context.Context, data []byte, sig []byte) error {
+ hashedData := getECDSAHashedData(data, sv.curveSize)
+
+ if ok := ecdsa.VerifyASN1(sv.public, hashedData, sig); !ok {
+ return ErrSignatureVerificationFailed
+ }
+
+ return nil
+}
+
+// KeyID returns the identifier of the key used to create the
+// ECDSASignerVerifier instance.
+func (sv *ECDSASignerVerifier) KeyID() (string, error) {
+ return sv.keyID, nil
+}
+
+// Public returns the public portion of the key used to create the
+// ECDSASignerVerifier instance.
+func (sv *ECDSASignerVerifier) Public() crypto.PublicKey {
+ return sv.public
+}
+
+// LoadECDSAKeyFromFile returns an SSLibKey instance for an ECDSA key stored in
+// a file in the custom securesystemslib format.
+func LoadECDSAKeyFromFile(path string) (*SSLibKey, error) {
+ contents, err := os.ReadFile(path)
+ if err != nil {
+ return nil, fmt.Errorf("unable to load ECDSA key from file: %w", err)
+ }
+
+ return LoadKeyFromSSLibBytes(contents)
+}
+
+func getECDSAHashedData(data []byte, curveSize int) []byte {
+ switch {
+ case curveSize <= 256:
+ return hashBeforeSigning(data, sha256.New())
+ case 256 < curveSize && curveSize <= 384:
+ return hashBeforeSigning(data, sha512.New384())
+ case curveSize > 384:
+ return hashBeforeSigning(data, sha512.New())
+ }
+ return []byte{}
+}