Skip to content

Commit

Permalink
Merge pull request #67 from adityasaky/key-formats
Browse files Browse the repository at this point in the history
Support PEM encoding for all key types
  • Loading branch information
adityasaky authored Jan 5, 2024
2 parents 7e48227 + f2f97ab commit 217bba2
Show file tree
Hide file tree
Showing 13 changed files with 442 additions and 7 deletions.
10 changes: 9 additions & 1 deletion signerverifier/ecdsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import (
"os"
)

const ECDSAKeyType = "ecdsa"
const (
ECDSAKeyType = "ecdsa"
ECDSAKeyScheme = "ecdsa-sha2-nistp256"
)

// ECDSASignerVerifier is a dsse.SignerVerifier compliant interface to sign and
// verify signatures using ECDSA keys.
Expand Down Expand Up @@ -89,6 +92,11 @@ func (sv *ECDSASignerVerifier) Public() crypto.PublicKey {

// 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 {
Expand Down
91 changes: 91 additions & 0 deletions signerverifier/ecdsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,55 @@ func TestECDSASignerVerifierWithDSSEEnvelope(t *testing.T) {
assert.Equal(t, "98adf38602c48c5479e9a991ee3f8cbf541ee4f985e00f7a5fc4148d9a45b704", acceptedKeys[0].KeyID)
}

func TestECDSASignerVerifierWithDSSEEnvelopeAndPEMKey(t *testing.T) {
key, err := LoadKey(ecdsaPrivateKey)
if err != nil {
t.Fatal(err)
}

sv, err := NewECDSASignerVerifierFromSSLibKey(key)
if err != nil {
t.Fatal(err)
}

payloadType := "application/vnd.dsse+json"
payload := []byte("test message")

es, err := dsse.NewEnvelopeSigner(sv)
if err != nil {
t.Error(err)
}

env, err := es.SignPayload(context.Background(), payloadType, payload)
if err != nil {
t.Error(err)
}

assert.Equal(t, "98adf38602c48c5479e9a991ee3f8cbf541ee4f985e00f7a5fc4148d9a45b704", env.Signatures[0].KeyID)
envPayload, err := env.DecodeB64Payload()
assert.Equal(t, payload, envPayload)
assert.Nil(t, err)

key, err = LoadKey(ecdsaPublicKey)
if err != nil {
t.Fatal(err)
}

sv, err = NewECDSASignerVerifierFromSSLibKey(key)
if err != nil {
t.Fatal(err)
}

ev, err := dsse.NewEnvelopeVerifier(sv)
if err != nil {
t.Error(err)
}

acceptedKeys, err := ev.Verify(context.Background(), env)
assert.Nil(t, err)
assert.Equal(t, "98adf38602c48c5479e9a991ee3f8cbf541ee4f985e00f7a5fc4148d9a45b704", acceptedKeys[0].KeyID)
}

func TestECDSASignerVerifierWithMetablockFile(t *testing.T) {
key, err := LoadECDSAKeyFromFile(filepath.Join("test-data", "ecdsa-test-key.pub"))
if err != nil {
Expand Down Expand Up @@ -189,3 +238,45 @@ func TestECDSASignerVerifierWithMetablockFile(t *testing.T) {
err = sv.Verify(context.Background(), encodedBytes, decodedSig)
assert.Nil(t, err)
}

func TestECDSASignerVerifierWithMetablockFileAndPEMKey(t *testing.T) {
key, err := LoadKey(ecdsaPublicKey)
if err != nil {
t.Fatal(err)
}

sv, err := NewECDSASignerVerifierFromSSLibKey(key)
if err != nil {
t.Fatal(err)
}

metadataBytes, err := os.ReadFile(filepath.Join("test-data", "test-ecdsa.98adf386.link"))
if err != nil {
t.Fatal(err)
}

mb := struct {
Signatures []struct {
KeyID string `json:"keyid"`
Sig string `json:"sig"`
} `json:"signatures"`
Signed any `json:"signed"`
}{}

if err := json.Unmarshal(metadataBytes, &mb); err != nil {
t.Fatal(err)
}

assert.Equal(t, "304502201fbb03c0937504182a48c66f9218bdcb2e99a07ada273e92e5e543867f98c8d7022100dbfa7bbf74fd76d76c1d08676419cba85bbd81dfb000f3ac6a786693ddc508f5", mb.Signatures[0].Sig)
assert.Equal(t, sv.keyID, mb.Signatures[0].KeyID)

encodedBytes, err := cjson.EncodeCanonical(mb.Signed)
if err != nil {
t.Fatal(err)
}

decodedSig := hexDecode(t, mb.Signatures[0].Sig)

err = sv.Verify(context.Background(), encodedBytes, decodedSig)
assert.Nil(t, err)
}
5 changes: 5 additions & 0 deletions signerverifier/ed25519.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ func (sv *ED25519SignerVerifier) Public() crypto.PublicKey {

// LoadED25519KeyFromFile returns an SSLibKey instance for an ED25519 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 LoadED25519KeyFromFile(path string) (*SSLibKey, error) {
contents, err := os.ReadFile(path)
if err != nil {
Expand Down
91 changes: 91 additions & 0 deletions signerverifier/ed25519_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,55 @@ func TestED25519SignerVerifierWithDSSEEnvelope(t *testing.T) {
assert.Equal(t, "52e3b8e73279d6ebdd62a5016e2725ff284f569665eb92ccb145d83817a02997", acceptedKeys[0].KeyID)
}

func TestED25519SignerVerifierWithDSSEEnvelopeAndPEMKey(t *testing.T) {
key, err := LoadKey(ed25519PrivateKey)
if err != nil {
t.Fatal(err)
}

sv, err := NewED25519SignerVerifierFromSSLibKey(key)
if err != nil {
t.Fatal(err)
}

payloadType := "application/vnd.dsse+json"
payload := []byte("test message")

es, err := dsse.NewEnvelopeSigner(sv)
if err != nil {
t.Error(err)
}

env, err := es.SignPayload(context.Background(), payloadType, payload)
if err != nil {
t.Error(err)
}

assert.Equal(t, "52e3b8e73279d6ebdd62a5016e2725ff284f569665eb92ccb145d83817a02997", env.Signatures[0].KeyID)
envPayload, err := env.DecodeB64Payload()
assert.Equal(t, payload, envPayload)
assert.Nil(t, err)

key, err = LoadKey(ed25519PublicKey)
if err != nil {
t.Fatal(err)
}

sv, err = NewED25519SignerVerifierFromSSLibKey(key)
if err != nil {
t.Fatal(err)
}

ev, err := dsse.NewEnvelopeVerifier(sv)
if err != nil {
t.Error(err)
}

acceptedKeys, err := ev.Verify(context.Background(), env)
assert.Nil(t, err)
assert.Equal(t, "52e3b8e73279d6ebdd62a5016e2725ff284f569665eb92ccb145d83817a02997", acceptedKeys[0].KeyID)
}

func TestED25519SignerVerifierWithMetablockFile(t *testing.T) {
key, err := LoadED25519KeyFromFile(filepath.Join("test-data", "ed25519-test-key.pub"))
if err != nil {
Expand Down Expand Up @@ -205,3 +254,45 @@ func TestED25519SignerVerifierWithMetablockFile(t *testing.T) {
err = sv.Verify(context.Background(), encodedBytes, decodedSig)
assert.Nil(t, err)
}

func TestED25519SignerVerifierWithMetablockFileAndPEMKey(t *testing.T) {
key, err := LoadKey(ed25519PublicKey)
if err != nil {
t.Fatal(err)
}

sv, err := NewED25519SignerVerifierFromSSLibKey(key)
if err != nil {
t.Fatal(err)
}

metadataBytes, err := os.ReadFile(filepath.Join("test-data", "test-ed25519.52e3b8e7.link"))
if err != nil {
t.Fatal(err)
}

mb := struct {
Signatures []struct {
KeyID string `json:"keyid"`
Sig string `json:"sig"`
} `json:"signatures"`
Signed any `json:"signed"`
}{}

if err := json.Unmarshal(metadataBytes, &mb); err != nil {
t.Fatal(err)
}

assert.Equal(t, "4c8b7605a9195d4ddba54493bbb5257a9836c1d16056a027fd77e97b95a4f3e36f8bc3c9c9960387d68187760b3072a30c44f992c5bf8f7497c303a3b0a32403", mb.Signatures[0].Sig)
assert.Equal(t, sv.keyID, mb.Signatures[0].KeyID)

encodedBytes, err := cjson.EncodeCanonical(mb.Signed)
if err != nil {
t.Fatal(err)
}

decodedSig := hexDecode(t, mb.Signatures[0].Sig)

err = sv.Verify(context.Background(), encodedBytes, decodedSig)
assert.Nil(t, err)
}
15 changes: 12 additions & 3 deletions signerverifier/rsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ func (sv *RSAPSSSignerVerifier) Public() crypto.PublicKey {

// LoadRSAPSSKeyFromFile returns an SSLibKey instance for an RSA key stored in a
// file.
//
// 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 LoadRSAPSSKeyFromFile(path string) (*SSLibKey, error) {
contents, err := os.ReadFile(path)
if err != nil {
Expand All @@ -103,9 +108,13 @@ func LoadRSAPSSKeyFromFile(path string) (*SSLibKey, error) {
return LoadRSAPSSKeyFromBytes(contents)
}

// LoadRSAPSSKeyFromBytes is a function that takes a byte array as input. This byte array should represent a PEM encoded RSA key, as PEM encoding is required.
// The function returns an SSLibKey instance, which is a struct that holds the key data.

// LoadRSAPSSKeyFromBytes is a function that takes a byte array as input. This
// byte array should represent a PEM encoded RSA key, as PEM encoding is
// required. The function returns an SSLibKey instance, which is a struct that
// holds the key data.
//
// Deprecated: use LoadKey() for all key types, RSA is no longer the only key
// that uses PEM serialization.
func LoadRSAPSSKeyFromBytes(contents []byte) (*SSLibKey, error) {
pemData, keyObj, err := decodeAndParsePEM(contents)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions signerverifier/rsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func TestRSAPSSSignerVerifierSignAndVerify(t *testing.T) {
}

func TestRSAPSSSignerVerifierWithDSSEEnvelope(t *testing.T) {
key, err := LoadRSAPSSKeyFromFile(filepath.Join("test-data", "rsa-test-key"))
key, err := LoadKey(rsaPrivateKey)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -130,7 +130,7 @@ func TestRSAPSSSignerVerifierWithDSSEEnvelope(t *testing.T) {
assert.Equal(t, payload, envPayload)
assert.Nil(t, err)

key, err = LoadRSAPSSKeyFromFile(filepath.Join("test-data", "rsa-test-key.pub"))
key, err = LoadKey(rsaPublicKey)
if err != nil {
t.Fatal(err)
}
Expand All @@ -151,7 +151,7 @@ func TestRSAPSSSignerVerifierWithDSSEEnvelope(t *testing.T) {
}

func TestRSAPSSSignerVerifierWithMetablockFile(t *testing.T) {
key, err := LoadRSAPSSKeyFromFile(filepath.Join("test-data", "rsa-test-key.pub"))
key, err := LoadKey(rsaPublicKey)
if err != nil {
t.Fatal(err)
}
Expand Down
Loading

0 comments on commit 217bba2

Please sign in to comment.