@@ -24,6 +24,7 @@ import (
24
24
"crypto/rand"
25
25
"crypto/sha256"
26
26
"crypto/x509"
27
+ "encoding/asn1"
27
28
"encoding/base64"
28
29
"encoding/hex"
29
30
"encoding/json"
@@ -62,6 +63,52 @@ func TestNewEntryReturnType(t *testing.T) {
62
63
}
63
64
}
64
65
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
+
65
112
func envelope (t * testing.T , k * ecdsa.PrivateKey , payload []byte ) * dsse.Envelope {
66
113
67
114
s , err := signature .LoadECDSASigner (k , crypto .SHA256 )
@@ -118,6 +165,30 @@ func createRekorEnvelope(dsseEnv *dsse.Envelope, pub [][]byte) *models.DSSEV001S
118
165
return proposedContent
119
166
}
120
167
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
+
121
192
func TestV001Entry_Unmarshal (t * testing.T ) {
122
193
key , err := ecdsa .GenerateKey (elliptic .P256 (), rand .Reader )
123
194
if err != nil {
@@ -197,6 +268,22 @@ func TestV001Entry_Unmarshal(t *testing.T) {
197
268
},
198
269
wantErr : false ,
199
270
},
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
+ },
200
287
{
201
288
env : & invalid ,
202
289
name : "invalid" ,
0 commit comments