diff --git a/CHANGELOG.md b/CHANGELOG.md index 40450dd2d..b839db7c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +# v1.3.6 + +## New Features + +* Add support for IEEE P1363 encoded ECDSA signatures +* Add index performance script (#2042) +* Add support for ed25519ph user keys in hashedrekord (#1945) +* Add metrics for index insertion (#2015) +* Add TLS support for Redis Client implementation (#1998) + +## Bug Fixes + +* fix typo in remoteIp and set full name for trace field + +## Contributors + +* Bob Callaway +* Colleen Murphy +* cpanato +* Hayden B +* Mihkel Pärna +* Riccardo Schirone + # v1.3.5 ## New Features diff --git a/pkg/types/dsse/v0.0.1/entry_test.go b/pkg/types/dsse/v0.0.1/entry_test.go index 6d2627168..92301f9ed 100644 --- a/pkg/types/dsse/v0.0.1/entry_test.go +++ b/pkg/types/dsse/v0.0.1/entry_test.go @@ -24,6 +24,7 @@ import ( "crypto/rand" "crypto/sha256" "crypto/x509" + "encoding/asn1" "encoding/base64" "encoding/hex" "encoding/json" @@ -62,6 +63,52 @@ func TestNewEntryReturnType(t *testing.T) { } } +type ecdsaSignature struct { + R, S *big.Int +} + +// From https://github.com/tink-crypto/tink/blob/43c17d490a6c8391bb5384278963cb59f4b65495/go/signature/subtle/encoding.go#L62 +func ieeeSignatureSize(curveName string) (int, error) { + switch curveName { + case elliptic.P256().Params().Name: + return 64, nil + case elliptic.P384().Params().Name: + return 96, nil + case elliptic.P521().Params().Name: + return 132, nil + default: + return 0, fmt.Errorf("ieeeP1363 unsupported curve name: %q", curveName) + } +} + +// From https://github.com/tink-crypto/tink/blob/43c17d490a6c8391bb5384278963cb59f4b65495/go/signature/subtle/encoding.go#L75 +func ieeeP1363Encode(sig *ecdsaSignature, curveName string) ([]byte, error) { + sigSize, err := ieeeSignatureSize(curveName) + if err != nil { + return nil, err + } + + enc := make([]byte, sigSize) + + // sigR and sigS must be half the size of the signature. If not, we need to pad them with zeros. + offset := 0 + if len(sig.R.Bytes()) < (sigSize / 2) { + offset += (sigSize / 2) - len(sig.R.Bytes()) + } + // Copy sigR after any zero-padding. + copy(enc[offset:], sig.R.Bytes()) + + // Skip the bytes of sigR. + offset = sigSize / 2 + if len(sig.S.Bytes()) < (sigSize / 2) { + offset += (sigSize / 2) - len(sig.S.Bytes()) + } + // Copy sigS after sigR and any zero-padding. + copy(enc[offset:], sig.S.Bytes()) + + return enc, nil +} + func envelope(t *testing.T, k *ecdsa.PrivateKey, payload []byte) *dsse.Envelope { s, err := signature.LoadECDSASigner(k, crypto.SHA256) @@ -118,6 +165,30 @@ func createRekorEnvelope(dsseEnv *dsse.Envelope, pub [][]byte) *models.DSSEV001S return proposedContent } +// transformECDSASignatures converts ASN.1 encoded ECDSA signatures (SEQ{r, s}) +// to IEEE P1363 encoding (r||s) +func transformECDSASignatures(t *testing.T, k *ecdsa.PrivateKey, dsseEnv *dsse.Envelope) *dsse.Envelope { + sigs := dsseEnv.Signatures + var newSigs []dsse.Signature + for _, b64sig := range sigs { + sig, err := base64.StdEncoding.DecodeString(b64sig.Sig) + if err != nil { + t.Fatal(err) + } + ecdsaSig := ecdsaSignature{} + if _, err := asn1.Unmarshal(sig, &ecdsaSig); err != nil { + t.Fatal(err) + } + ieeeP1363Sig, err := ieeeP1363Encode(&ecdsaSig, k.Params().Name) + if err != nil { + t.Fatal(err) + } + newSigs = append(newSigs, dsse.Signature{KeyID: b64sig.KeyID, Sig: base64.StdEncoding.EncodeToString(ieeeP1363Sig)}) + } + dsseEnv.Signatures = newSigs + return dsseEnv +} + func TestV001Entry_Unmarshal(t *testing.T) { key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { @@ -197,6 +268,22 @@ func TestV001Entry_Unmarshal(t *testing.T) { }, wantErr: false, }, + { + env: envelope(t, key, []byte(validPayload)), + name: "key with IEEE P1361 sig", + it: &models.DSSEV001Schema{ + ProposedContent: createRekorEnvelope(transformECDSASignatures(t, key, envelope(t, key, []byte(validPayload))), [][]byte{pub}), + }, + wantErr: false, + }, + { + env: envelope(t, priv, []byte(validPayload)), + name: "cert with IEEE P1361 sig", + it: &models.DSSEV001Schema{ + ProposedContent: createRekorEnvelope(transformECDSASignatures(t, priv, envelope(t, priv, []byte(validPayload))), [][]byte{pemBytes}), + }, + wantErr: false, + }, { env: &invalid, name: "invalid",