Skip to content

Commit

Permalink
Merge pull request #53 from call-stack/remove-xml-declaration-signature
Browse files Browse the repository at this point in the history
removed XML declaration before signature operations
  • Loading branch information
adamdecaf authored Jun 10, 2024
2 parents c2bbfb1 + 0f8ea12 commit bf61a08
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 5 deletions.
30 changes: 30 additions & 0 deletions signedxml.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,3 +339,33 @@ func calculateHash(reference *etree.Element, doc *etree.Document) (string, error

return calculatedValue, nil
}

// removeXMLDeclaration searches for and removes the XML declaration processing instruction.
func removeXMLDeclaration(doc *etree.Document) {
for _, t := range doc.Child {
if p, ok := t.(*etree.ProcInst); ok && p.Target == "xml" {
doc.RemoveChild(p)
break
}
}

// Remove CharData right after removing the XML declaration
for _, t2 := range doc.Child {
if p2, ok := t2.(*etree.CharData); ok {
doc.RemoveChild(p2)
}
}
}

// parseXML parses an XML string into an etree.Document and removes the XML declaration if present.
func parseXML(xml string) (*etree.Document, error) {
doc := etree.NewDocument()
if err := doc.ReadFromString(xml); err != nil {
return nil, err
}

doc.ReadSettings.PreserveCData = true
removeXMLDeclaration(doc)

return doc, nil
}
47 changes: 47 additions & 0 deletions signedxml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,53 @@ import (
. "github.com/smartystreets/goconvey/convey"
)

func TestSignatureLogicWithCLibXMLSec(t *testing.T) {
pemString, _ := os.ReadFile("./testdata/rsa.crt")
pemBlock, _ := pem.Decode([]byte(pemString))
cert, _ := x509.ParseCertificate(pemBlock.Bytes)

b64Bytes, _ := os.ReadFile("./testdata/rsa.key.b64")
pemString, _ = base64.StdEncoding.DecodeString(string(b64Bytes))
pemBlock, _ = pem.Decode([]byte(pemString))
key, _ := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)

xmlGeneratedSign, _ := os.ReadFile("./testdata/signature-generate-using-xmlseclib.xml")
signedDoc := etree.NewDocument()
signedDoc.ReadFromString(string(xmlGeneratedSign))
signature := signedDoc.Root()
digestValueElement := signature.SelectElement("Signature").SelectElement("SignedInfo").SelectElement("Reference").SelectElement("DigestValue")

Convey("Given an XML, certificate, and RSA key", t, func() {
xml, _ := os.ReadFile("./testdata/doc.xml")

Convey("When generating the signature", func() {
signer, _ := NewSigner(string(xml))
xmlStr, err := signer.Sign(key)
generatedDigestValue := signer.signedInfo.SelectElement("Reference").SelectElement("DigestValue")
Convey("Then no error occurs", func() {
So(err, ShouldBeNil)
})
Convey("And the signature should be valid", func() {
validator, _ := NewValidator(xmlStr)
validator.Certificates = append(validator.Certificates, *cert)
refs, err := validator.ValidateReferences()
So(err, ShouldBeNil)
So(len(refs), ShouldEqual, 1)
})
Convey("And signature digest should match with signature generated using xmlsec", func() {
So(generatedDigestValue.Text(), ShouldEqual, digestValueElement.Text())
})
Convey("And signature generated using xmlsec should be valid", func() {
validator, _ := NewValidator(string(xmlGeneratedSign))
validator.Certificates = append(validator.Certificates, *cert)
refs, err := validator.ValidateReferences()
So(err, ShouldBeNil)
So(len(refs), ShouldEqual, 1)
})
})
})
}

func TestSign(t *testing.T) {
pemString, _ := os.ReadFile("./testdata/rsa.crt")
pemBlock, _ := pem.Decode([]byte(pemString))
Expand Down
4 changes: 1 addition & 3 deletions signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ type Signer struct {

// NewSigner returns a *Signer for the XML provided
func NewSigner(xml string) (*Signer, error) {
doc := etree.NewDocument()
doc.ReadSettings.PreserveCData = true
err := doc.ReadFromString(xml)
doc, err := parseXML(xml)
if err != nil {
return nil, err
}
Expand Down
33 changes: 33 additions & 0 deletions testdata/doc.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<References>
<Book>
<Author>
<FirstName>Bruce</FirstName>
<LastName>Schneier</LastName>
</Author>
<Title>Applied Cryptography</Title>
</Book>
<Web>
<Title>XMLSec</Title>
<Url>http://www.aleksey.com/xmlsec/</Url>
</Web>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<CanonicalizationMethod Algorithm=
"http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm=
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<Reference URI="">
<Transforms>
<Transform Algorithm=
"http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm=
"http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue></DigestValue>
</Reference>
</SignedInfo>
<SignatureValue />
<KeyInfo>
</KeyInfo>
</Signature>
</References>
40 changes: 40 additions & 0 deletions testdata/signature-generate-using-xmlseclib.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0"?>
<References>
<Book>
<Author>
<FirstName>Bruce</FirstName>
<LastName>Schneier</LastName>
</Author>
<Title>Applied Cryptography</Title>
</Book>
<Web>
<Title>XMLSec</Title>
<Url>http://www.aleksey.com/xmlsec/</Url>
</Web>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>kXaaD5Gor8lfNc6eYV31AyF0ekT9H/YY28Oh665mooQ=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>Z81G62a0rLOLlgOQyJJN5amwIQ9Wu3vqoCc5CDp8wHz8xVHBGv6MOcaXtzkXOveQ
KFRuFsxWtlNdxyUyfHzkwHk1BLfzUNbG1BNNjgktJ63leO5w3C4v64/3/HnIPEq1
eE1uSMO0HDevDrgethWofa2ExxBG2CU8bY4pGzLx95uhBUxk5ilkR1P4tayJp1Va
U0/roVBZTo8WH+ol15hj5FFV4rjTMPV2kPy9geNsMDZi+N30C/RNHB7n5MScnBC+
OiCMRmJEcgJpA8/GXCX+y7WFKsVB9p6VO5euC8UUD9dvezvHhMDBwqncjvbnvjOk
BD58sY6v8LpLIabJUmg3Yt6YjU8dToxv36QrIjsN/m1p5sCsWIMWCdW9MtsR0VGl
MjkBCQUE70aCUzVbNrtJZaGY+YH9oDvHsLHKzTZusOvYLGCtKwaBcqVEuad/7Nvs
e7JjYVl6HfyHWZPY6PDt0Q180f+U9QV2C1EdI+r2sbMd+HMft2Jp6Wii3mHZD6hy
jFr54lztG0x9/X75jwBIaoMv8RtTl8lKfFpBiUc9UrpxKJBOOhMPWiYdwrrAzE1g
NEHZvU3wbZiFWCAo+4RtCB++pWnoEJ16tuGHKlEIWTJRAnqm4ld1hX0zo7ZVkabD
ixthaEIn8XmlaL92X5ZAI0P+yFC5kXSDKtLVnf6TgfE=</SignatureValue>
<KeyInfo>
</KeyInfo>
</Signature>
</References>
3 changes: 1 addition & 2 deletions validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ type Validator struct {

// NewValidator returns a *Validator for the XML provided
func NewValidator(xml string) (*Validator, error) {
doc := etree.NewDocument()
err := doc.ReadFromString(xml)
doc, err := parseXML(xml)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit bf61a08

Please sign in to comment.