GNOME Bugzilla – Bug 745493
DSA handled incorrectly
Last modified: 2015-03-06 00:39:14 UTC
xmlsec1 1.2.20 (openssl) The official XML Security specification for DSA is located here: http://www.w3.org/TR/xmldsig-core1/#sec-DSA (and http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf) The information is long winded and doesn't state plainly the rules. Let me summarize them: The following DSA signatures combinations are specified for XML Security: (1024, 160) - DSAwithSHA1 - http://www.w3.org/2000/09/xmldsig#dsa-sha1 (2048, 256) - DSAwithSHA256 - http://www.w3.org/2009/xmldsig11#dsa-sha256 (3072, 256) - DSAwithSHA256 - http://www.w3.org/2009/xmldsig11#dsa-sha256 Among other things, the first variable specifies the amount of bits in the key, the second the size of a DSA signature component, which matches the size of the digest algorithm output. DSA signatures consist of two components of the same size, r and s, the former being a random value, the latter being an encrypted digest. XML Security wants to see both of them raw, concatenated together, and base64 encoded. There are two issues here I've noticed with the present implementation: 1) Unspecified combinations are allowed without warnings, for example, 2048 bit DSA keys used with sha1. In some cases, when signing, these combinations go through but with truncated results. 2) 2048 and 3072 bit keys with sha256 cannot be used, as xmlsec1 errors out by saying that 64 > 40. While technically, there's no reason why all different key sizes (even unspecified ones like 4096 bit) can't be mixed and matched with the two specified digest algorithms, they're not allowed by the specification. At the very least there should be some kind of warning when used in signing or verifying. Regarding the larger keys with sha256, the XML specification says that: "Integer to octet-stream conversion must be done according to the I2OSP operation defined in the RFC 3447 [PKCS1] specification with a l parameter equal to 20." This statement in its current form in terms of size is only talking about sha1, and probably left over from an earlier version of the specification prior to sha256 being allowed, as the second value of the (L, N) pair should correspond with the digest algorithm output size. FIPS 186-3 has this to say on the matter: "It is recommended that the security strength of the (L, N) pair and the security strength of the hash function used for the generation of digital signatures be the same unless an agreement has been made between participating entities to use a stronger hash function. When the length of the output of the hash function is greater than N (i.e., the bit length of q), then the leftmost N bits of the hash function output block shall be used in any calculation using the hash function output during the generation or verification of a digital signature. A hash function that provides a lower security strength than the (L, N) pair ordinarily should not be used, since this would reduce the security strength of the digital signature process to a level no greater than that provided by the hash function." A hard rule of 20 bytes for sha256, would fall under FIPS 186-3 "should not be used" guideline. Furthermore, if that is the intention of the XML Security specification, it doesn't even define how the data is supposed to be truncated to fit the size! (and more so, restored for verification purposes) Unless one wants to adhere to an unlikely interpretation of the specification, xmlsec1 should raise the byte size for a DSA signature for sha256 two 64 bytes (32*2 for r and s, up from 20).
Sorry, I just wanted to clarify something in case someone reads this for a purpose other than the one I was aiming for here. > "DSA signatures consist of two components of the same size, r and s, the former being a random value, the latter being an encrypted digest." Isn't strictly true. The values are generated in a more complex fashion, and the randomly generated variables end up being a part of the calculation for s not r. However, as a mnemonic, it helps to remember that DSA signatures consist of randomness as well as the digest and encryption data.
Fixed the problem #2 with DSA-SHA256 signatures. Funny there was a very similar issue with ECDSA signatures and similar constant :) Now I need to figure out how to handle "unsupported" cases. [master 78f720b] fix DSA-SHA256 signatures + test cases (bug #745493) 30 files changed, 1045 insertions(+), 315 deletions(-) rewrite docs/xmlsec-man.html (100%) create mode 100644 tests/aleksey-xmldsig-01/enveloping-sha256-dsa2048-sha256.tmpl create mode 100644 tests/aleksey-xmldsig-01/enveloping-sha256-dsa2048-sha256.xml create mode 100644 tests/aleksey-xmldsig-01/enveloping-sha256-dsa3072-sha256.tmpl create mode 100644 tests/aleksey-xmldsig-01/enveloping-sha256-dsa3072-sha256.xml create mode 100644 tests/keys/demoCA/newcerts/AFA28BB933ADDAB2.pem create mode 100644 tests/keys/demoCA/newcerts/AFA28BB933ADDAB3.pem create mode 100644 tests/keys/dsa2048cert.der create mode 100644 tests/keys/dsa2048cert.pem create mode 100644 tests/keys/dsa2048key.der create mode 100644 tests/keys/dsa2048key.p12 create mode 100644 tests/keys/dsa2048key.p8-der create mode 100644 tests/keys/dsa2048key.p8-pem create mode 100644 tests/keys/dsa2048key.pem create mode 100644 tests/keys/dsa3072cert.der create mode 100644 tests/keys/dsa3072cert.pem create mode 100644 tests/keys/dsa3072key.der create mode 100644 tests/keys/dsa3072key.p12 create mode 100644 tests/keys/dsa3072key.p8-der create mode 100644 tests/keys/dsa3072key.p8-pem create mode 100644 tests/keys/dsa3072key.pem
Actually, #1 is also fixed with this change. There is no truncation anymore and the signature value will simply be longer. This is not exactly "by the spec" but it is reasonable extension :) Thanks again for reporting the problem!
> Funny there was a very similar issue with ECDSA signatures and similar constant Well, I see the issue as natural for the situation at hand. The XML Security group decided for (EC)DSA to not use an ASN.1 signature, and used fix length per DSA settings, to add additional work to handling for XML Signatures. Therefore, signatures could no longer be used directly, but need to be parsed and handled specifically for each size. Thanks to constant advancement in the field, these "fixed" sizes will keep growing. > Now I need to figure out how to handle "unsupported" cases. Regarding unsupported cases, here's what we're doing to handle them: After loading the key, use EVP_PKEY_bits() to get amount of bits. if dsa switch bits case 1024: dsa component size = 20 case 2048: case 3072: dsa component size = 32 else if ecdsa dsa component size = (bits + 7) / 8 ----- if dsa if algo is sha1 if dsa component size doesn't equal 20 throw error else if algo is sha256 if dsa component size doesn't equal 32 throw error else throw error ----- Another thing we're doing, which may or not be required depending on the ASN.1 parser and component to byte functions being used, is sanitizing the components from the signature. loop if output component size > dsa component size and leading zero remove leading zero from output component loop if output component size < dsa component size add leading zero to output component if output component size doesn't equal dsa component size throw error ----- This above pseudo code should handle all the current cases. However, it will need to be updated each time the DSA specification is expanded further, which is annoying. Although due to the way XML Security requires explicit strings for each signature and hash algorithm combination to be added, I don't see any alternative. Just need to keep such additions in sync with the new bit pairs supported. The recently published FIPS 186-4 doesn't add on any new pairs, so at least it's unlikely for XML Security to make changes here any time soon.
I might add another inconsistency with XML Security spec is not just having two subtags in the XML of <r></r> and <s></s> of any size, which would avoid the issue entirely. Although as Peter Gutmann said, the specification for XML Security, was designed to be difficult, just so they can be seen as working really hard on this. Thanks for the fixes.