Skip to content

ECDSA signatures are incorrectly required to be ASN.1 encoded #163

@daniel-weisse

Description

@daniel-weisse

According to the XML Signature specification, the value of the SignatureValue field is supposed to be "the base64 encoding of the concatenation of two octet-streams that respectively result from the octet-encoding of the values r and s" of the ECDSA signature.

ValidationContext.Validate calls x509.Certificate.CheckSignature to verify the XML signature, which, for ECDSA signatures, calls ecdsa.VerifyASN1.
As the name suggests, this function requires the signature to be ASN.1 encoded, making the function fail for valid XML signatures.

Reproducer

I verified this using xmlsec1 to create a signed XML document.
The resulting signature can not be validated using goxmldsig, resulting in an x509: ECDSA verification failure error.

The steps are as follows:

  1. Start by creating an XML template file and save it as template.xml:
<root>
  <data>TestDocument</data>
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-c14n11"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384"/><ds:Reference URI=""><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#sha384"/><ds:DigestValue></ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue></ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate></ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>
</root>
  1. Generate an EC key and certificate:
openssl req -new -x509 -key signing_key.pem -sha384 -days 365 -out signing_cert.pem -subj "/CN=ECDSA Test/O=Example/C=US"
  1. Create the signed XML document:
xmlsec1 --sign --output signed.xml --privkey-pem signing_key.key,signing_cert.crt template.xml
  1. Verify the XML signature:
xmlsec1 --verify --trusted-pem signing_cert.crt signed.xml

This should return the following:

OK
SignedInfo References (ok/all): 1/1
Manifests References (ok/all): 0/0
  1. Run the following Go program to check the result
package main

import (
	"crypto/x509"
	_ "embed"
	"encoding/pem"

	"github.com/beevik/etree"
	dsig "github.com/russellhaering/goxmldsig"
)

//go:embed doc.xml
var xmlData []byte

//go:embed signing_cert.pem
var signingCert []byte

func main() {
	doc := etree.NewDocument()
	if err := doc.ReadFromBytes(xmlData); err != nil {
		panic(err)
	}

	certPEM, _ := pem.Decode(signingCert)
	cert, err := x509.ParseCertificate(certPEM.Bytes)
	if err != nil {
		panic(err)
	}
	ctx := dsig.NewDefaultValidationContext(&dsig.MemoryX509CertificateStore{
		Roots: []*x509.Certificate{cert},
	})
	if _, err := ctx.Validate(doc.Root()); err != nil {
		panic(err)
	}
}

This will return the following:

panic: x509: ECDSA verification failure

Conversely, manually updating SignatureValue to the ASN.1 encoding of the signature results in the Go code succeeding, but other XML signature verification tools in failing to do so

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions