@@ -24,6 +24,7 @@ import (
2424 "crypto/rand"
2525 "crypto/sha256"
2626 "crypto/x509"
27+ "encoding/asn1"
2728 "encoding/base64"
2829 "encoding/hex"
2930 "encoding/json"
@@ -62,6 +63,52 @@ func TestNewEntryReturnType(t *testing.T) {
6263 }
6364}
6465
66+ type ecdsaSignature struct {
67+ R , S * big.Int
68+ }
69+
70+ // From https://github.com/tink-crypto/tink/blob/43c17d490a6c8391bb5384278963cb59f4b65495/go/signature/subtle/encoding.go#L62
71+ func ieeeSignatureSize (curveName string ) (int , error ) {
72+ switch curveName {
73+ case elliptic .P256 ().Params ().Name :
74+ return 64 , nil
75+ case elliptic .P384 ().Params ().Name :
76+ return 96 , nil
77+ case elliptic .P521 ().Params ().Name :
78+ return 132 , nil
79+ default :
80+ return 0 , fmt .Errorf ("ieeeP1363 unsupported curve name: %q" , curveName )
81+ }
82+ }
83+
84+ // From https://github.com/tink-crypto/tink/blob/43c17d490a6c8391bb5384278963cb59f4b65495/go/signature/subtle/encoding.go#L75
85+ func ieeeP1363Encode (sig * ecdsaSignature , curveName string ) ([]byte , error ) {
86+ sigSize , err := ieeeSignatureSize (curveName )
87+ if err != nil {
88+ return nil , err
89+ }
90+
91+ enc := make ([]byte , sigSize )
92+
93+ // sigR and sigS must be half the size of the signature. If not, we need to pad them with zeros.
94+ offset := 0
95+ if len (sig .R .Bytes ()) < (sigSize / 2 ) {
96+ offset += (sigSize / 2 ) - len (sig .R .Bytes ())
97+ }
98+ // Copy sigR after any zero-padding.
99+ copy (enc [offset :], sig .R .Bytes ())
100+
101+ // Skip the bytes of sigR.
102+ offset = sigSize / 2
103+ if len (sig .S .Bytes ()) < (sigSize / 2 ) {
104+ offset += (sigSize / 2 ) - len (sig .S .Bytes ())
105+ }
106+ // Copy sigS after sigR and any zero-padding.
107+ copy (enc [offset :], sig .S .Bytes ())
108+
109+ return enc , nil
110+ }
111+
65112func envelope (t * testing.T , k * ecdsa.PrivateKey , payload []byte ) * dsse.Envelope {
66113
67114 s , err := signature .LoadECDSASigner (k , crypto .SHA256 )
@@ -118,6 +165,30 @@ func createRekorEnvelope(dsseEnv *dsse.Envelope, pub [][]byte) *models.DSSEV001S
118165 return proposedContent
119166}
120167
168+ // transformECDSASignatures converts ASN.1 encoded ECDSA signatures (SEQ{r, s})
169+ // to IEEE P1363 encoding (r||s)
170+ func transformECDSASignatures (t * testing.T , k * ecdsa.PrivateKey , dsseEnv * dsse.Envelope ) * dsse.Envelope {
171+ sigs := dsseEnv .Signatures
172+ var newSigs []dsse.Signature
173+ for _ , b64sig := range sigs {
174+ sig , err := base64 .StdEncoding .DecodeString (b64sig .Sig )
175+ if err != nil {
176+ t .Fatal (err )
177+ }
178+ ecdsaSig := ecdsaSignature {}
179+ if _ , err := asn1 .Unmarshal (sig , & ecdsaSig ); err != nil {
180+ t .Fatal (err )
181+ }
182+ ieeeP1363Sig , err := ieeeP1363Encode (& ecdsaSig , k .Params ().Name )
183+ if err != nil {
184+ t .Fatal (err )
185+ }
186+ newSigs = append (newSigs , dsse.Signature {KeyID : b64sig .KeyID , Sig : base64 .StdEncoding .EncodeToString (ieeeP1363Sig )})
187+ }
188+ dsseEnv .Signatures = newSigs
189+ return dsseEnv
190+ }
191+
121192func TestV001Entry_Unmarshal (t * testing.T ) {
122193 key , err := ecdsa .GenerateKey (elliptic .P256 (), rand .Reader )
123194 if err != nil {
@@ -197,6 +268,22 @@ func TestV001Entry_Unmarshal(t *testing.T) {
197268 },
198269 wantErr : false ,
199270 },
271+ {
272+ env : envelope (t , key , []byte (validPayload )),
273+ name : "key with IEEE P1361 sig" ,
274+ it : & models.DSSEV001Schema {
275+ ProposedContent : createRekorEnvelope (transformECDSASignatures (t , key , envelope (t , key , []byte (validPayload ))), [][]byte {pub }),
276+ },
277+ wantErr : false ,
278+ },
279+ {
280+ env : envelope (t , priv , []byte (validPayload )),
281+ name : "cert with IEEE P1361 sig" ,
282+ it : & models.DSSEV001Schema {
283+ ProposedContent : createRekorEnvelope (transformECDSASignatures (t , priv , envelope (t , priv , []byte (validPayload ))), [][]byte {pemBytes }),
284+ },
285+ wantErr : false ,
286+ },
200287 {
201288 env : & invalid ,
202289 name : "invalid" ,
0 commit comments