1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
package signerverifier
import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"fmt"
"os"
)
const (
ECDSAKeyType = "ecdsa"
ECDSAKeyScheme = "ecdsa-sha2-nistp256"
)
// 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.
//
// Deprecated: use LoadKey(). The custom serialization format has been
// deprecated. Use
// https://github.com/secure-systems-lab/securesystemslib/blob/main/docs/migrate_key.py
// to convert your key.
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{}
}
|