Tommy Chu
Tommy Chu

Reputation: 103

Incorrect XML digest value

Description

I'm trying to calculate a digest value for a XML digital signature. The problem is that I can't calculate a correct digest value.

For the testing purpose I'm using a sample request which is populated with the valid data and my goal is to calculate the same digest value for the referenced object.

The sample SOAP message (source):

I suggest viewing the message from the source (it is visualized with indentation).

<s:Envelope xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" u:Id="BinaryToken1" xmlns:wse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">MIIEmTCCA4GgAwIBAgIFAKCnuv0wDQYJKoZIhvcNAQELBQAwdzESMBAGCgmSJomT8ixkARkWAkNaMUMwQQYDVQQKDDrEjGVza8OhIFJlcHVibGlrYSDigJMgR2VuZXLDoWxuw60gZmluYW7EjW7DrSDFmWVkaXRlbHN0dsOtMRwwGgYDVQQDExNFRVQgQ0EgMSBQbGF5Z3JvdW5kMB4XDTE5MDgwODE5MjM0MloXDTIyMDgwODE5MjM0MlowQzESMBAGCgmSJomT8ixkARkWAkNaMRMwEQYDVQQDEwpDWjAwMDAwMDE5MRgwFgYDVQQNEw9wcmF2bmlja2Egb3NvYmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDrVmZ6FE2jYqli43/LbXZ1vEG8USMRcC/zbGgk5mAoQQKMtF5PIm5i84pd0cPOSRtduNODc7mwjbPKd5r8p592zNhpei0/XbQcYQ5rpdf0Y84ZNbg9ZmB4nF8YCBy3Gk28YxfW//vIjqvkuQK6InT4l784gtz/iNAV48ZBkgE/jp+MMii1I+y5EyYkQuRZlCJtOTKdPXECnr5OrxrGUtbjmF7bBWLD2LXlspZoUOmh4RFfd9WHH8PmcQfij5aJq6cgIB2YENCBHSA1/HZZEd8vNLv05owb/BOvXj4n86lYJ8tlJVMcorAsrEzVy+XU++78/j9PewL0ft0jETHd0U8DAgMBAAGjggFeMIIBWjAJBgNVHRMEAjAAMB0GA1UdDgQWBBT8zaUMxlfEGXSD/2PZ089ZLGgerTAfBgNVHSMEGDAWgBR8MHaszNaH0ezJH+JwCCzjX94MBzAOBgNVHQ8BAf8EBAMCBsAwYwYDVR0gBFwwWjBYBgpghkgBZQMCATABMEowSAYIKwYBBQUHAgIwPAw6VGVudG8gY2VydGlmaWvDoXQgYnlsIHZ5ZMOhbiBwb3V6ZSBwcm8gdGVzdG92YWPDrSDDusSNZWx5LjCBlwYDVR0fBIGPMIGMMIGJoIGGoIGDhilodHRwOi8vY3JsLmNhMS1wZy5lZXQuY3ovZWV0Y2ExcGcvYWxsLmNybIYqaHR0cDovL2NybDIuY2ExLXBnLmVldC5jei9lZXRjYTFwZy9hbGwuY3JshipodHRwOi8vY3JsMy5jYTEtcGcuZWV0LmN6L2VldGNhMXBnL2FsbC5jcmwwDQYJKoZIhvcNAQELBQADggEBAKVFyv168b/q0X568G+JDvNnz4XVElbJ1r9ro/xv58QP+FD8PJSR5qxN2F7zKGNYTCee0jSo+XY1KEoSkmeoYHXnQpm7+NG7iUYc2OWu0B3hC/wMMhNEDtmsTwqSLjgSk6pZTTRXfvtaHf7zvU8iw1PGFhb9m9bJlOfLwoMeFclOpdfo80pbwRz5t8io/c0lvGodlYj7INHxjlwdwWf3m2mUx4iuKvoAev0ASCdSMDuUWWjYiMT3PEUqeabeM2dn3xccQ2EhgIcCwhQs2MCA/FDLBbiOt63mUJPJHATIFi/31VKtz11/Gc434HHsVYB8U/aammSyIfMp6bNE6LhaFe8=</wse:BinarySecurityToken><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#_1"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>OX7JTeL80dE6yDHOs6ILGQzitQI7DB5lEhBH7TNcmbo=</DigestValue></Reference></SignedInfo><SignatureValue>hn3LK3tdJrYBpFZto6Lahtei7A2nVR1wbs45IzvXElZIae7m6zTHDiLetPliq+ZuzvlvfA7llZPeAgk5JNBQX/BP/6B2gomDUPBwsB55cwdfZGk58At2D6++DVqYzYC3esPlPxafZ6x7UOSpg5ShxUgBJsC9YOYlTyWD5Jmh0Z3bfeoZBcNkj1gb7DHE6vNoNWysZgf4xwCn80WaYVVTxyge0FW0dIJ8MeRTNeac4oOWF0Z3104Iu48/NEYqB+ZkyGiBBLVBSIdW8rb2NuRQ+Dg/N8zFNYaH03uF6fpmx/1El1mhooS5yYJurioMZUSJAcasoGDnLqFuEyGNaDCR6Q==</SignatureValue><KeyInfo><wse:SecurityTokenReference xmlns:wse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wse:Reference URI="#BinaryToken1" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509" /></wse:SecurityTokenReference></KeyInfo></Signature></wsse:Security></s:Header><s:Body u:Id="_1"><Trzba xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://fs.mfcr.cz/eet/schema/v3"><Hlavicka uuid_zpravy="878b2e10-c4a5-4f05-8c90-abc181cd6837" dat_odesl="2019-08-11T15:36:25+02:00" prvni_zaslani="true" overeni="false" /><Data dic_popl="CZ00000019" id_provoz="141" id_pokl="1patro-vpravo" porad_cis="141-18543-05" dat_trzby="2019-08-11T15:36:14+02:00" celk_trzba="236.00" zakl_dan1="100.00" dan1="21.00" zakl_dan2="100.00" dan2="15.00" rezim="0" /><KontrolniKody><pkp digest="SHA256" cipher="RSA2048" encoding="base64" xmlns="http://fs.mfcr.cz/eet/schema/v3">LnIZVjGlkdvO55gRP9Wa4k48X0QZrLU5aWsFDpYlwcCC/S8KHuUI0hxxS9pPP/vhuvKhe+a2YoZJ6wZDMSlPs0QDtt5i6D6XhQx/Oj84Azoo8fgSf5R6QOpnpsmw+X75jsUlwzGm4+YLGrhbScjdUdHIBLw2XCJus5cPXAb3aWcab59X2L/zaZ87oJRIQsmERMgPBtT8GIZNEfnX89OL/EMyyxibUC0C97aEokK1Lvvm55xidC9wWoMJJtKjNjScsGg5HpmOe0Zqekovtyvwt5mYVCx/fXa3OTsas2vVMskZKLyaxd7GYkJ5Y9nWCyuD8/pzKWR/8BxApIL601VHaQ==</pkp><bkp digest="SHA1" encoding="base16" xmlns="http://fs.mfcr.cz/eet/schema/v3">ABA7EB19-7AD8D753-60ED57B3-9AC9957E-C192030B</bkp></KontrolniKody></Trzba></s:Body></s:Envelope>

If I understand it correctly in this case I calculate the digest in these steps:

  1. Canonicalize the referenced object (XML Exclusive C14N)
  2. Hash the referenced object (<s:Body u:Id="_1">...</s:Body>) - with the SHA256 algorithm
  3. Encode it to base64

My solution

So I tried (in Go Playground):

package main

import (
    "bytes"
    "crypto/sha256"
    "encoding/base64"
    "encoding/xml"
    "fmt"

    "github.com/beevik/etree"
    "github.com/ucarion/c14n"
)

func errCheck(err error) {
    if err != nil {
        panic(err)
    }
}

func canonicalize(b []byte) []byte {
    decoder := xml.NewDecoder(bytes.NewReader(b))
    out, err := c14n.Canonicalize(decoder)
    errCheck(err)
    return out
}

func main() {
    sampleEnv := []byte(`<s:Envelope xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" u:Id="BinaryToken1" xmlns:wse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">MIIEmTCCA4GgAwIBAgIFAKCnuv0wDQYJKoZIhvcNAQELBQAwdzESMBAGCgmSJomT8ixkARkWAkNaMUMwQQYDVQQKDDrEjGVza8OhIFJlcHVibGlrYSDigJMgR2VuZXLDoWxuw60gZmluYW7EjW7DrSDFmWVkaXRlbHN0dsOtMRwwGgYDVQQDExNFRVQgQ0EgMSBQbGF5Z3JvdW5kMB4XDTE5MDgwODE5MjM0MloXDTIyMDgwODE5MjM0MlowQzESMBAGCgmSJomT8ixkARkWAkNaMRMwEQYDVQQDEwpDWjAwMDAwMDE5MRgwFgYDVQQNEw9wcmF2bmlja2Egb3NvYmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDrVmZ6FE2jYqli43/LbXZ1vEG8USMRcC/zbGgk5mAoQQKMtF5PIm5i84pd0cPOSRtduNODc7mwjbPKd5r8p592zNhpei0/XbQcYQ5rpdf0Y84ZNbg9ZmB4nF8YCBy3Gk28YxfW//vIjqvkuQK6InT4l784gtz/iNAV48ZBkgE/jp+MMii1I+y5EyYkQuRZlCJtOTKdPXECnr5OrxrGUtbjmF7bBWLD2LXlspZoUOmh4RFfd9WHH8PmcQfij5aJq6cgIB2YENCBHSA1/HZZEd8vNLv05owb/BOvXj4n86lYJ8tlJVMcorAsrEzVy+XU++78/j9PewL0ft0jETHd0U8DAgMBAAGjggFeMIIBWjAJBgNVHRMEAjAAMB0GA1UdDgQWBBT8zaUMxlfEGXSD/2PZ089ZLGgerTAfBgNVHSMEGDAWgBR8MHaszNaH0ezJH+JwCCzjX94MBzAOBgNVHQ8BAf8EBAMCBsAwYwYDVR0gBFwwWjBYBgpghkgBZQMCATABMEowSAYIKwYBBQUHAgIwPAw6VGVudG8gY2VydGlmaWvDoXQgYnlsIHZ5ZMOhbiBwb3V6ZSBwcm8gdGVzdG92YWPDrSDDusSNZWx5LjCBlwYDVR0fBIGPMIGMMIGJoIGGoIGDhilodHRwOi8vY3JsLmNhMS1wZy5lZXQuY3ovZWV0Y2ExcGcvYWxsLmNybIYqaHR0cDovL2NybDIuY2ExLXBnLmVldC5jei9lZXRjYTFwZy9hbGwuY3JshipodHRwOi8vY3JsMy5jYTEtcGcuZWV0LmN6L2VldGNhMXBnL2FsbC5jcmwwDQYJKoZIhvcNAQELBQADggEBAKVFyv168b/q0X568G+JDvNnz4XVElbJ1r9ro/xv58QP+FD8PJSR5qxN2F7zKGNYTCee0jSo+XY1KEoSkmeoYHXnQpm7+NG7iUYc2OWu0B3hC/wMMhNEDtmsTwqSLjgSk6pZTTRXfvtaHf7zvU8iw1PGFhb9m9bJlOfLwoMeFclOpdfo80pbwRz5t8io/c0lvGodlYj7INHxjlwdwWf3m2mUx4iuKvoAev0ASCdSMDuUWWjYiMT3PEUqeabeM2dn3xccQ2EhgIcCwhQs2MCA/FDLBbiOt63mUJPJHATIFi/31VKtz11/Gc434HHsVYB8U/aammSyIfMp6bNE6LhaFe8=</wse:BinarySecurityToken><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#_1"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>OX7JTeL80dE6yDHOs6ILGQzitQI7DB5lEhBH7TNcmbo=</DigestValue></Reference></SignedInfo><SignatureValue>hn3LK3tdJrYBpFZto6Lahtei7A2nVR1wbs45IzvXElZIae7m6zTHDiLetPliq+ZuzvlvfA7llZPeAgk5JNBQX/BP/6B2gomDUPBwsB55cwdfZGk58At2D6++DVqYzYC3esPlPxafZ6x7UOSpg5ShxUgBJsC9YOYlTyWD5Jmh0Z3bfeoZBcNkj1gb7DHE6vNoNWysZgf4xwCn80WaYVVTxyge0FW0dIJ8MeRTNeac4oOWF0Z3104Iu48/NEYqB+ZkyGiBBLVBSIdW8rb2NuRQ+Dg/N8zFNYaH03uF6fpmx/1El1mhooS5yYJurioMZUSJAcasoGDnLqFuEyGNaDCR6Q==</SignatureValue><KeyInfo><wse:SecurityTokenReference xmlns:wse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wse:Reference URI="#BinaryToken1" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509" /></wse:SecurityTokenReference></KeyInfo></Signature></wsse:Security></s:Header><s:Body u:Id="_1"><Trzba xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://fs.mfcr.cz/eet/schema/v3"><Hlavicka uuid_zpravy="878b2e10-c4a5-4f05-8c90-abc181cd6837" dat_odesl="2019-08-11T15:36:25+02:00" prvni_zaslani="true" overeni="false" /><Data dic_popl="CZ00000019" id_provoz="141" id_pokl="1patro-vpravo" porad_cis="141-18543-05" dat_trzby="2019-08-11T15:36:14+02:00" celk_trzba="236.00" zakl_dan1="100.00" dan1="21.00" zakl_dan2="100.00" dan2="15.00" rezim="0" /><KontrolniKody><pkp digest="SHA256" cipher="RSA2048" encoding="base64" xmlns="http://fs.mfcr.cz/eet/schema/v3">LnIZVjGlkdvO55gRP9Wa4k48X0QZrLU5aWsFDpYlwcCC/S8KHuUI0hxxS9pPP/vhuvKhe+a2YoZJ6wZDMSlPs0QDtt5i6D6XhQx/Oj84Azoo8fgSf5R6QOpnpsmw+X75jsUlwzGm4+YLGrhbScjdUdHIBLw2XCJus5cPXAb3aWcab59X2L/zaZ87oJRIQsmERMgPBtT8GIZNEfnX89OL/EMyyxibUC0C97aEokK1Lvvm55xidC9wWoMJJtKjNjScsGg5HpmOe0Zqekovtyvwt5mYVCx/fXa3OTsas2vVMskZKLyaxd7GYkJ5Y9nWCyuD8/pzKWR/8BxApIL601VHaQ==</pkp><bkp digest="SHA1" encoding="base16" xmlns="http://fs.mfcr.cz/eet/schema/v3">ABA7EB19-7AD8D753-60ED57B3-9AC9957E-C192030B</bkp></KontrolniKody></Trzba></s:Body></s:Envelope>`)

    doc := etree.NewDocument()
    err := doc.ReadFromBytes(sampleEnv)
    errCheck(err)

    // isolate the Body element
    bDoc := etree.NewDocument()
    bDoc.SetRoot(doc.FindElement("./Envelope/Body"))
    body, err := bDoc.WriteToBytes()
    errCheck(err)

    // canonicalize
    cBody := canonicalize(body)

    // hash
    hash := sha256.Sum256(cBody)

    // encode to base64
    digest := base64.StdEncoding.EncodeToString(hash[:])

    fmt.Println("Calculated digest:", digest)
    fmt.Println("Correct digest:", doc.FindElement("./Envelope/Header/Security/Signature/SignedInfo/Reference/DigestValue").Text())
}

In the code above I use the library github.com/ucarion/c14n to canonicalize the XML. It implements the required ExcC14N Canonicalization (on Github):

This package is a Golang implementation of XML Canonicalization ("c14n"). In particular, it implements the Exclusive Canonical XML specification, which is the recommended canonicalization scheme used in SAML.

The output:

Calculated digest: 8wZNjinOeoV5iP9Q2j/F1K1m4dG3NbpKeCX9z1OlwZU=
Correct digest: OX7JTeL80dE6yDHOs6ILGQzitQI7DB5lEhBH7TNcmbo=

I would be grateful for any advice (both big and small).

Upvotes: 1

Views: 794

Answers (0)

Related Questions