4
4
"bytes"
5
5
"crypto/x509"
6
6
"encoding/base64"
7
+ "encoding/xml"
7
8
"errors"
8
9
"fmt"
9
10
"regexp"
@@ -169,6 +170,7 @@ func (ctx *ValidationContext) transform(
169
170
return el , canonicalizer , nil
170
171
}
171
172
173
+ // deprecated
172
174
func (ctx * ValidationContext ) digest (el * etree.Element , digestAlgorithmId string , canonicalizer Canonicalizer ) ([]byte , error ) {
173
175
data , err := canonicalizer .Canonicalize (el )
174
176
if err != nil {
@@ -189,6 +191,33 @@ func (ctx *ValidationContext) digest(el *etree.Element, digestAlgorithmId string
189
191
return hash .Sum (nil ), nil
190
192
}
191
193
194
+ func (ctx * ValidationContext ) getCanonicalSignedInfo (sig * types.Signature ) ([]byte , error ) {
195
+ signatureElement := sig .UnderlyingElement ()
196
+
197
+ nsCtx , err := etreeutils .NSBuildParentContext (signatureElement )
198
+ if err != nil {
199
+ return nil , err
200
+ }
201
+
202
+ signedInfo , err := etreeutils .NSFindOneChildCtx (nsCtx , signatureElement , Namespace , SignedInfoTag )
203
+ if err != nil {
204
+ return nil , err
205
+ }
206
+
207
+ if signedInfo == nil {
208
+ return nil , errors .New ("Missing SignedInfo" )
209
+ }
210
+
211
+ // Canonicalize the xml
212
+ canonical , err := canonicalSerialize (signedInfo )
213
+ if err != nil {
214
+ return nil , err
215
+ }
216
+
217
+ return canonical , nil
218
+ }
219
+
220
+ // deprecated
192
221
func (ctx * ValidationContext ) verifySignedInfo (sig * types.Signature , canonicalizer Canonicalizer , signatureMethodId string , cert * x509.Certificate , decodedSignature []byte ) error {
193
222
signatureElement := sig .UnderlyingElement ()
194
223
@@ -226,6 +255,48 @@ func (ctx *ValidationContext) verifySignedInfo(sig *types.Signature, canonicaliz
226
255
}
227
256
228
257
func (ctx * ValidationContext ) validateSignature (el * etree.Element , sig * types.Signature , cert * x509.Certificate ) (* etree.Element , error ) {
258
+
259
+ // Actually verify the 'SignedInfo' was signed by a trusted source
260
+ signatureMethod := sig .SignedInfo .SignatureMethod .Algorithm
261
+
262
+ canonicalSignedInfoBytes , err := ctx .getCanonicalSignedInfo (sig )
263
+ if err != nil {
264
+ return nil , errors .New ("Could not obtain canonical signed info bytes" )
265
+ }
266
+
267
+ if canonicalSignedInfoBytes == nil {
268
+ return nil , errors .New ("Missing SignedInfo" )
269
+ }
270
+
271
+ algo , ok := x509SignatureAlgorithmByIdentifier [signatureMethod ]
272
+ if ! ok {
273
+ return nil , errors .New ("Unknown signature method: " + signatureMethod )
274
+ }
275
+
276
+ if sig .SignatureValue == nil {
277
+ return nil , errors .New ("Signature could not be verified" )
278
+ }
279
+
280
+ // Decode the 'SignatureValue' so we can compare against it
281
+ decodedSignature , err := base64 .StdEncoding .DecodeString (sig .SignatureValue .Data )
282
+ if err != nil {
283
+ return nil , errors .New ("Could not decode signature" )
284
+ }
285
+
286
+ err = cert .CheckSignature (algo , canonicalSignedInfoBytes , decodedSignature )
287
+ if err != nil {
288
+ return nil , err
289
+ }
290
+
291
+ // only use the verified canonicalSignedInfoBytes
292
+ // unmarshal canonicalSignedInfoBytes into a new SignedInfo type
293
+ // to obtain the reference
294
+ signedInfo := & types.SignedInfo {}
295
+ err = xml .Unmarshal (canonicalSignedInfoBytes , signedInfo )
296
+ if err != nil {
297
+ return nil , err
298
+ }
299
+
229
300
idAttrEl := el .SelectAttr (ctx .IdAttribute )
230
301
idAttr := ""
231
302
if idAttrEl != nil {
@@ -235,53 +306,69 @@ func (ctx *ValidationContext) validateSignature(el *etree.Element, sig *types.Si
235
306
var ref * types.Reference
236
307
237
308
// Find the first reference which references the top-level element
238
- for _ , _ref := range sig . SignedInfo .References {
309
+ for _ , _ref := range signedInfo .References {
239
310
if _ref .URI == "" || _ref .URI [1 :] == idAttr {
240
311
ref = & _ref
241
312
}
242
313
}
243
314
315
+ // prevents null pointer deref
316
+ if ref == nil {
317
+ return nil , errors .New ("Missing reference" )
318
+ }
319
+
320
+ digestAlgorithmId := ref .DigestAlgo .Algorithm
321
+ signedDigestValue , err := base64 .StdEncoding .DecodeString (ref .DigestValue )
322
+ if err != nil {
323
+ return nil , err
324
+ }
325
+
244
326
// Perform all transformations listed in the 'SignedInfo'
245
327
// Basically, this means removing the 'SignedInfo'
246
328
transformed , canonicalizer , err := ctx .transform (el , sig , ref )
247
329
if err != nil {
248
330
return nil , err
249
331
}
250
332
251
- digestAlgorithm := ref .DigestAlgo .Algorithm
252
-
253
- // Digest the transformed XML and compare it to the 'DigestValue' from the 'SignedInfo'
254
- digest , err := ctx .digest (transformed , digestAlgorithm , canonicalizer )
333
+ referencedBytes , err := canonicalizer .Canonicalize (transformed )
255
334
if err != nil {
256
335
return nil , err
257
336
}
258
337
259
- decodedDigestValue , err := base64 .StdEncoding .DecodeString (ref .DigestValue )
338
+ // use a known digest hashing algorithm
339
+ hashAlgorithm , ok := digestAlgorithmsByIdentifier [digestAlgorithmId ]
340
+ if ! ok {
341
+ return nil , errors .New ("Unknown digest algorithm: " + digestAlgorithmId )
342
+ }
343
+
344
+ hash := hashAlgorithm .New ()
345
+ _ , err = hash .Write (referencedBytes )
260
346
if err != nil {
261
347
return nil , err
262
348
}
263
349
264
- if ! bytes .Equal (digest , decodedDigestValue ) {
265
- return nil , errors .New ("Signature could not be verified" )
266
- }
267
- if sig .SignatureValue == nil {
350
+ computedDigest := hash .Sum (nil )
351
+ /* Digest the transformed XML and compare it to the 'DigestValue' from the 'SignedInfo'
352
+ digest, err := ctx.digest(transformed, digestAlgorithm, canonicalizer)
353
+ */
354
+
355
+ if ! bytes .Equal (computedDigest , signedDigestValue ) {
268
356
return nil , errors .New ("Signature could not be verified" )
269
357
}
270
358
271
- // Decode the 'SignatureValue' so we can compare against it
272
- decodedSignature , err := base64 .StdEncoding .DecodeString (sig .SignatureValue .Data )
273
- if err != nil {
274
- return nil , errors .New ("Could not decode signature" )
359
+ if ! (len (computedDigest ) >= 20 ) {
360
+ return nil , errors .New ("Computed digest is less than 20 something went wrong" )
275
361
}
276
362
277
- // Actually verify the 'SignedInfo' was signed by a trusted source
278
- signatureMethod := sig .SignedInfo .SignatureMethod .Algorithm
279
- err = ctx .verifySignedInfo (sig , canonicalizer , signatureMethod , cert , decodedSignature )
363
+ // now only the referencedBytes is verified,
364
+ // unmarshal into new etree
365
+ doc := etree .NewDocument ()
366
+ err = doc .ReadFromBytes (referencedBytes )
280
367
if err != nil {
281
368
return nil , err
282
369
}
283
370
284
- return transformed , nil
371
+ return doc . Root () , nil
285
372
}
286
373
287
374
func contains (roots []* x509.Certificate , cert * x509.Certificate ) bool {
0 commit comments