DSig Part 3: XML DSig vs. JSON Web Signature

This post was originally published as “DSig Part 3: XML DSig vs. JSON Web Signtaure” on the Levvel Blog.

This post is part three of my Digital Signature series of blog posts. The first post explored the use of XML Digital Signatures; the second post continued with JSON Web Signatures (getting a little closer to our primary focus of APIs). In this post, I will compare the two digital signature specifications. I am focusing on the structure and mechanics of building and validating digital signatures with each specification. I am not going to attempt to analyze known or theoretical vulnerabilities in each — that is far beyond the scope of what can be covered in a single blog post.

While researching this blog post, I searched for “xml digital signature vs json web signature” on Google. Most of the results were about one or the other — not the comparison of both that I was looking to create. Which is great; I am covering new ground. Who wants to be unoriginal? There were several comparisons of a competing JSON digital signature & encryption proposal called Secure Messaging to JWS and JWE (a comparison of XML encryption and JWE specifications will be the subject of another blog post) — these may be good follow-up reading if you are interested in the subject.

Timing

The XML Digital Signature specification had its first working draft published on January 28th, 2000; it gained W3C Recommendation status on August 20th, 2001. The JSON Web Signature specification was published in May, 2015, which is obviously much more recent. It’s interesting to point out that in Section 10 of the JWS specification, two XML Digital Signature-related notes published by the W3C are called out as being relevant to JSON Web Signature: “XML Signature Syntax and Processing Version 2.0” [ W3C.NOTE-xmldsig-core2–20130411] and “XML Signature Best Practices” [ W3C.NOTE-xmldsig-bestpractices-20130411]. It goes on to note that the XML-specific pieces are not relevant to JWS. Using these existing components and industry knowledge undoubtedly saved the creators of the JWS spec much time and demonstrates how this body of work builds on what was learned from the XML Digital Signature specification — both the good and bad.

JSON vs XML

This one should be obvious. One is focused on XML; the other is focused on JSON. I discuss the rise of JSON in the API space here. A slightly biased and humorous analysis of JSON and XML can be found here. A slightly less biased analysis can be found here. My point here is not to debate XML vs. JSON, though this frequently occurs in IT shops around the world. XML has been widely deployed and converting existing service to JSON is a costly endeavor. Some companies have elected to make the investment to do so. The business value of such a decision can be debated. I do, however, think that using JSON for new development activities is a good decision.

Canonicalization (C14N)

This is possibly the largest difference between the two specifications and the largest source of complexity in the XML Digital Signature specification. Canonicalization is the process of converting data from one representation to another, standardized, representation. From the XML Signature Syntax and Processing spec, Section 7, “XML Canonicalization and Syntax Constraint Considerations”, we have:

Digital signatures only work if the verification calculations are performed on exactly the same bits as the signing calculations. If the surface representation of the signed data can change between signing and verification, then some way to standardize the changeable aspect must be used before signing and verification…For this reason, XML digital signatures have a provision for indicating canonicalization methods in the signature…XML that is read and processed using standard XML parsing and processing techniques is frequently changed such that some of its surface representation information is lost or modified. …The kinds of changes in XML that may need to be canonicalized can be divided into four categories. There are those related to the basic [XML]…There are those related to [DOM], [SAX], or similar processing…Third, there is the possibility of coded character set conversion, such as between UTF-8 and UTF-16… And, fourth, there are changes related to namespace declarations and XML namespace attribute contexts.

This passage provides insight into what they were attempting to accomplish with Canonicalization. Moreover, it provides several examples of what Canonicalization algorithms are meant to address with XML messages and digital signatures (in particular, the hashing step) upon them. As one example, if your XML parser represents an empty element as <element></element> , but another one represents an empty element as <element/>, both of which are valid XML syntax that mean the same thing, the hash values (and thus digital signatures) calculated by each will be different. Similar issues arise between platforms that treat the end of line differently (‘\n’ vs. \r\n, for example). There are plenty of other examples of this. So, the concept of Canonicalization was born — and, with it a lot of complexity.

Now, the JWS specification allows JSON text to be used as defined in the JSON Spec (RFC 7159). It specifically states:

JWS represents digitally signed or MACed content using JSON data
structures and base64url encoding. These JSON data structures MAY
contain whitespace and/or line breaks before or after any JSON values
or structural characters, in accordance with
Section 2 of RFC 7159
[
RFC7159]

From the JSON Spec, Section 2, “JSON Grammer”, we have:

Insignificant whitespace is allowed before or after any of the six structural characters.

ws = *(
%x20 / ; Space
%x09 / ; Horizontal tab
%x0A / ; Line feed or New line
%x0D ) ; Carriage return

So, here too, we have the opportunity for some ambiguity. In other words, is:

{

‘a’:’b’,

‘c’:’d’

}

and

{ ‘a’:’b’, ‘c’:’d’}

the same JSON structure? For converting JSON text (string representation of a JSON data structure) to a form that is usable by the programming language/environment at hand, white text (as described above from the JSON spec) is allowed. This means, that a valid JSON Parser (such as JSON.parse() in Javascript) must treat these two representations as the same object. For digital signature purposes according to the JWS specification, the digital signature that is generated will be over the UTF8 representation of the JSON text. The first JSON text will have three instances of “\r\n” (or CRLF) present that the second will not have. Thus, the hash that is generated will be different. And, thus, the digital signature will be different. The way the JWS spec is written, the signature validation algorithm must use the UTF8 representation of the JSON text that is passed in with the Payload. In other words, do not pass the JSON text from the Payload of the JWS into a JSON Parser, convert it to its native representation, then convert it back to JSON text with the expectation that the signature validation results will be the same as if you used the JSON text representation directly.

In this way, the JWS specification creators eliminated the need for canonicalization, but they introduced a discrepancy in the intuitive definition of equality of JSON objects between the JSON spec and the JWS spec. I say intuitive definition because an equality operator is not explicitly defined in either spec in this regards. The JWS validation process calls for validating that the Payload is valid JSON. As long as these rules are kept in mind, there isn’t really a problem. The JWS contains everything that is needed to validate the signature.

The validation process of an XML Digital Signature assumes that the string representation of the XML document is passed into an XML Parser first, then passes through the Canonicalization processes that were described in DSig Part 1, a bunch of other stuff happens, and finally the hash is generated. Subtle, but important, differences to how JWS works.

Space Overhead/Verbosity

Looking at the XML Digital Signature example in DSig Part 1 JWS Compact Serialization form in DSig Part 2, it is quite obvious that the JWS signature is much smaller. Note, that the signature algorithm details in each are similar.

JSON data:

{ ‘a’:’b’,
‘c’:’d’,
‘e’: 1.0
}

JWS Signature:

eyJhbGciOiJSUzI1NiJ9.eyJhIjoiYiIsImMiOiJkIiwiZSI6MX0.CNMaYaDGU3ZhFV1ve6p3sAdYXhEklej8DVIAMqIWCkpNmT6Jp7iigcndXwH5q3WQFHiswgIQU5-_-4rV3jKGptCROmEyWPW8_elhYH1apzAyjOjyZ55ygv37xKHzIFhixzAwmXlAv4pfD4lVelYWVNOSN7REA0QJeCy2vKdqZ5cjqCXQ1lkQUlzOE7dpuNoAkhAhAJJ8HaamFKy7Gl7uwmqbIr-dVYv21d_9O7mO26n0gy3zWXD2nJDxU5Mzl2pZd8-sFvUr9Kmp_YkeRMh4bSe0fr1Uc_YgkjpmYUyu7kaxRWTbAdJ3GwqWFMUDiyfhHdzvZPZyU4VkWreimoydMA

XML data:

</pre>
<soapenv:Envelope xmlns:ws=”http://ws.rcbj.com/" xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <ws:sumResponse>
            <return>9</return>
        </ws:sumResponse>
    </soapenv:Body>
</soapenv:Envelope>

XML Digital Signature:

</pre>
<soapenv:Envelope xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws=”http://ws.rcbj.com/">
    <soapenv:Header>
        <wsse:Security xmlns:wsse=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand=”1">
            <wsu:Timestamp xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id=”Timestamp-c1414e29–208f-4e5a-b0b7-f4e84ce870b9">
                <wsu:Created>2012–12–31T23:50:43Z</wsu:Created>
                <wsu:Expires>2012–12–31T23:55:43Z</wsu:Expires>
            </wsu:Timestamp>
            <wsse:BinarySecurityToken xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id=”SecurityToken-49cac4a4-b108–49eb-af80–7226774dd3e4" 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">
MIIDOjCCAqOgAwIBAgIEdOq6LjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJVUzELMAkGA1UECBMCT1IxETAPBgNVBAcTCFBvcnRsYW5kMR0wGwYDVQQKExRSQ0JKIENvbnN1bHRpbmcsIExMQzELMAkGA1UECxMCSVQxFjAUBgNVBAMTDUR1bW15RFNpZ0NlcnQwHhcNMTIxMjMxMjM0NDQ3WhcNMjIxMjI5MjM0NDQ3WjBxMQswCQYDVQQGEwJVUzELMAkGA1UECBMCT1IxETAPBgNVBAcTCFBvcnRsYW5kMR0wGwYDVQQKExRSQ0JKIENvbnN1bHRpbmcsIExMQzELMAkGA1UECxMCSVQxFjAUBgNVBAMTDUR1bW15RFNpZ0NlcnQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALd4DQWC6PtcA9NXzpBvcv9jfDXHBpr9k9DWSe5qI5N8HPZ+8ArAyRURz9+cEz7yWcjL7WY0KzLrBrx9Xwn0Ss2Y+xyPfvVKCxVTkPF5kSLfwIWl3oL1bAVyMNyV1aB4GL7tWAHEe8E7y6djKTP2EZwRyUWHHjyKycqDxKADaKWXAgMBAAGjgd4wgdswDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUx+xJOYF+4DagDezOpMX5lwcCsxEwgZ4GA1UdIwSBljCBk4AUx+xJOYF+4DagDezOpMX5lwcCsxGhdaRzMHExCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJPUjERMA8GA1UEBxMIUG9ydGxhbmQxHTAbBgNVBAoTFFJDQkogQ29uc3VsdGluZywgTExDMQswCQYDVQQLEwJJVDEWMBQGA1UEAxMNRHVtbXlEU2lnQ2VydIIEdOq6LjALBgNVHQ8EBAMCArwwDQYJKoZIhvcNAQEFBQADgYEAnPAuf0VmKv8gIxmHbE5D6ljyAHXXVpah6JWonJelmsrXMrkQygudnOEWYI4VjbMFWJ0Oatnx1krYv3M8Xs25xviOTe+jjALLMiq6T/BBU7iz+/WN9UZPJnd12DwrLE5+bXMvdRHlwVkU1krnbuhaIyZl2qlcCsrOqCYRfEqXqe8=
 
            </wsse: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/2000/09/xmldsig#rsa-sha1"/>
                    <Reference URI=”#Timestamp-c1414e29–208f-4e5a-b0b7-f4e84ce870b9">
                        <Transforms>
                            <Transform Algorithm=”http://www.w3.org/2001/10/xml-exc-c14n#"/>
                        </Transforms>
                        <DigestMethod Algorithm=”http://www.w3.org/2000/09/xmldsig#sha1"/>
                        <DigestValue>bj8IHKuebTNIAmBbEp+OMzcC2QA=</DigestValue>
                    </Reference>
                    <Reference URI=”#Body-c4080b95–9986–49bf-abd0–3634de9b2b26">
                        <Transforms>
                            <Transform Algorithm=”http://www.w3.org/2001/10/xml-exc-c14n#"/>
                        </Transforms>
                        <DigestMethod Algorithm=”http://www.w3.org/2000/09/xmldsig#sha1"/>
                        <DigestValue>c2n1AgOTwSnCPawsZuOElayfki4=</DigestValue>
                    </Reference>
                </SignedInfo>
                <SignatureValue>j/qnJQwO4x4zziS4MsdI2Z68yRDmb7FLshu7KmXUwKPQ7j10WuZ2sw+OdarngvrTBsoMmqwF+bIqJ18amvJPnH2FwV7ROHcIvUgxUN461JEFM3aYvwOFd7XnX4oBkHrEf0VhsZnUXrGLHB99H7myWYt6r8d0UA+gXHgiC+laK48=</SignatureValue>
                <KeyInfo>
                    <wsse:SecurityTokenReference xmlns=””>
                        <wsse:Reference URI=”#SecurityToken-49cac4a4-b108–49eb-af80–7226774dd3e4" ValueType=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
                    </wsse:SecurityTokenReference>
                </KeyInfo>
            </Signature>
        </wsse:Security>
    </soapenv:Header>
    <soapenv:Body xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id=”Body-c4080b95–9986–49bf-abd0–3634de9b2b26">
        <ws:sumResponse>
            <return>9</return>
        </ws:sumResponse>
    </soapenv:Body>
</soapenv:Envelope>

Both of these signatures represent what is typical for the use of each signature spec.

The size of the JSON text is 51 bytes; the corresponding JWS signature is 396 bytes. This is roughly an eight-fold increase in size.

The size of the XML (SOAP) message is 231 bytes; the corresponding XML Digital Signature (with original payload) is 4036 bytes. This is roughly an 17.5 times increase in size. Now, let’s be fair. The XML Digital Signature payload included the public certificate corresponding to the private key used to generate the signature. The JWS does not include this information. It is common for JWT tokens (as an example) to reference the signing certificate via thumbprint or some other type of external reference — the JWS spec provides several options. If we strip out the BinarySecurityToken, the signature size drops to 2927 bytes. That is approximately a 12.6 times increase. It should also be pointed out that there are two hashes generated for the XML Digital Signature example (one on the message body and one on the timestamp). The JWS example also doesn’t include a timestamp.

I realize this isn’t the most scientific analysis of this data. But, the take away from this is that the XML Digital Signature on the SOAP message takes up a lot more space than the JWS digital signature.

One of the things that takes up the most room is the signing certificate. Most usage of the XML Digital Signature specification I have seen placed the public certificate corresponding to the private key used for signing in a BinarySecurityToken element. The spec calls out that the KeyInfo element is optional. But, from a practical matter it is always included. The XML Digital Signature spec also provides mechanisms for remote references to the certificate (and/or certificate trust chain) corresponding to the private key used for to generate the signature. But, I’ve never really seen it used. On the other hand, the common convention with JWS and JSON Web Tokens (JWT) is to use some type of reference to the signer certificate (thumb print, remote URL, etc).

Private/Public Key Pair Representation

The JWS specification references the JSON Web Key (JWK) spec as a mechanism for the representation of X509 certificates and trust chains. The JWT spec still provides a mechanism for references to X509 certificate (and trust chain) in PEM format (directly or indirectly). It will be interesting to see which format becomes the defacto standard over the next few years.

The XML Digital Signature spec represents an X509 certificate in what is essentially PEM format with the lines breaks, header, and footer removedwithin a BinarySecurityToken element.

Supported signature algorithms

The JWS specification references the JSON Web Algorithm (JWA) spec for what algorithms must be supported. The JWA spec lists the following digital signature algorithms:

</p>

   +--------------+-------------------------------+--------------------+
   | "alg" Param  | Digital Signature or MAC      | Implementation     |
   | Value        | Algorithm                     | Requirements       |
   +--------------+-------------------------------+--------------------+
   | HS256        | HMAC using SHA-256            | Required           |
   | HS384        | HMAC using SHA-384            | Optional           |
   | HS512        | HMAC using SHA-512            | Optional           |
   | RS256        | RSASSA-PKCS1-v1_5 using       | Recommended        |
   |              | SHA-256                       |                    |
   | RS384        | RSASSA-PKCS1-v1_5 using       | Optional           |
   |              | SHA-384                       |                    |
   | RS512        | RSASSA-PKCS1-v1_5 using       | Optional           |
   |              | SHA-512                       |                    |
   | ES256        | ECDSA using P-256 and SHA-256 | Recommended+       |
   | ES384        | ECDSA using P-384 and SHA-384 | Optional           |
   | ES512        | ECDSA using P-521 and SHA-512 | Optional           |
   | PS256        | RSASSA-PSS using SHA-256 and  | Optional           |
   |              | MGF1 with SHA-256             |                    |
   | PS384        | RSASSA-PSS using SHA-384 and  | Optional           |
   |              | MGF1 with SHA-384             |                    |
   | PS512        | RSASSA-PSS using SHA-512 and  | Optional           |
   |              | MGF1 with SHA-512             |                    |
   | none         | No digital signature or MAC   | Optional           |
   |              | performed                     |                    |
   +--------------+-------------------------------+--------------------+
</pre>

So, for JWS, the only required algorithm is HMAC using SHA-256 (symmetric shared key with a SHA-256 signature algorithm). As noted in DSig Part 2, any commercially viable platform is going to support more than that.

The XML Digital Signature 1.1 Specification algorithm details can be found here.

So, there are a number of differences in what is required between the two signature specifications. In fact, the JWS spec only requires HMAC with SHA256; it doesn’t even require support for RSA-algorithms with X509 private-public key pairs. Though, RSA-SHA256 is recommended.

Enveloped or Detached (XML DSig) versus Compact Serialization or JSON Serialization (JWS)

The next area that is worth calling out is the mechanisms the two specs use for representing the signatures.

The JWS specification provides two mechanisms: Compact Serialization and JSON Serialization. The first is what I used the DSig Part 2 example. The second embeds one or more signatures inside of a JSON data structure similar to how the XML Digital Signature specification does it. For completeness, here is an example of JSON Serialization (from the JWS spec):

{
      "payload":
       "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF
        tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
      "protected":"eyJhbGciOiJFUzI1NiJ9",
      "header":
       {"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
      "signature":
       "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS
        lSApmWQxfKTUJqPP3-Kg6NU1Q"
}

The JSON Serialization has the ability contain multiple signatures and offers more flexibility. But, at the expense of the small footprint.

On the XML side, the Digital Signature specification offers three mechanisms for representing the digital signature. From the spec, “A signature may be (non-exclusively) described as detached,enveloping, or enveloped.”. For SAML tokens and WS-Security, enveloped signatures are used. The example provided in DSig Part1 and referenced above is an example of an enveloped signature (the document being signed contains the Signature element).

Complexity

In general, the XML Digital Signature specification is more complex than the JWS specification. The major components of this complexity are Canonicalization (described earlier in this post) and the ability to apply XSLT transforms to the signed data during the signature generation process. The JWS specification falling back on generating a signature over the string representation (JSON text) of the data is probably the single greatest simplification — lesson learned, let’s move on.

Summary

This concludes the three part series on Digital Signatures. Next I’ll be covering SAML 2.0 and JWT. Leave comments.