[Bug 60273] New: crypt32: signature verification re-sorts PKCS#7 authenticated attributes, breaking valid signatures whose SignedAttrs are not in DER order (FL Studio 26.1.5 fails to start)
http://bugs.winehq.org/show_bug.cgi?id=60273 Bug ID: 60273 Summary: crypt32: signature verification re-sorts PKCS#7 authenticated attributes, breaking valid signatures whose SignedAttrs are not in DER order (FL Studio 26.1.5 fails to start) Product: Wine Version: 11.0 Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: crypt32 Assignee: wine-bugs@list.winehq.org Reporter: mcnster@gmail.com Target Milestone: --- Distribution: --- Created attachment 81992 --> http://bugs.winehq.org/attachment.cgi?id=81992 Minimal WinVerifyTrust reproducer, builds with mingw-w64 FL Studio 2026 version 26.1.5.5618 fails to start under Wine. The application displays "The validity of the program could not be verified. Please reinstall it and try again." and exits. Version 26.1.3.5570 of the same application starts and runs normally in the same prefix. The two builds are signed by the same CA with the same algorithms; the only change is a routine renewal of the leaf code-signing certificate. The signature on the 26.1.5 binaries is valid. osslsigncode and OpenSSL verify it successfully, including the PE image hash, the certificate chain to DigiCert Trusted Root G4, and the RFC 3161 timestamp. The binaries also run correctly on Windows. Wine's WinVerifyTrust rejects them. STEPS TO REPRODUCE 1. Install FL Studio 26.1.5.5618 into a clean prefix. The free trial installer is the same binary and requires no license, so this is reproducible without purchasing anything. 2. Run FL64.exe. The validity dialog appears and the program exits. Or, without installing the application, using the attached reproducer (wvt.c, ~30 lines, builds with mingw-w64): x86_64-w64-mingw32-gcc -o wvt.exe wvt.c -lwintrust wine wvt.exe FL64-2615.exe EXPECTED RESULT WinVerifyTrust returns 0, as it does on Windows and as OpenSSL's verification of the same file agrees it should. ACTUAL RESULT WinVerifyTrust: 0x80096004 (TRUST_E_CERT_SIGNATURE) Against the equivalent file from 26.1.3 the same reproducer returns 0x00000000. WHERE IT FAILS WINEDEBUG=+wintrust,+chain,+crypt,+cryptasn,+bcrypt Failing (26.1.5): trace:crypt:new_key alg = "RSA_KEYX", dwKeyLen = 3072 trace:crypt:CryptVerifySignatureW (..., 384, ..., (null), 00000000) trace:crypt:RSAENH_CPVerifySignature (... dwSigLen=384 ...) trace:wintrust:WinVerifyTrust returning 80096004 Working (26.1.3): trace:crypt:new_key alg = "RSA_KEYX", dwKeyLen = 4096 trace:crypt:CryptVerifySignatureW (..., 512, ..., (null), 00000000) trace:crypt:RSAENH_CPVerifySignature (... dwSigLen=512 ...) trace:crypt:new_key alg = "RSA_SIGN", dwKeyLen = 4096 <- chain trace:crypt:new_key alg = "RSA_SIGN", dwKeyLen = 4096 trace:crypt:new_key alg = "RSA_SIGN", dwKeyLen = 4096 trace:wintrust:WinVerifyTrust returning 00000000 The failure occurs inside CryptMsgControl(hMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE, ...) at the first RSA operation, one millisecond into the call. CertGetCertificateChain is never reached; CertFreeCertificateChain receives a NULL handle. This is a SignerInfo signature failure, not a certificate chain failure, despite the returned HRESULT. RULED OUT BY TESTING - Certificate chain. Never built. The intermediate is byte-for-byte identical in both versions (DigiCert Trusted G4 Code Signing RSA4096 SHA384 2021 CA1, serial 08:AD:40:B2...), chaining to DigiCert Trusted Root G4 in both cases. - PE image hash. Computed and accepted before the failure point, and independently confirmed by osslsigncode. - Timestamp. RFC 3161 token at 1.3.6.1.4.1.311.3.3.1 in both versions. Never reached. - Signature algorithms. Both versions: SHA-256 message digest, rsaEncryption, sha256WithRSAEncryption leaf, sha384WithRSAEncryption intermediate. No RSASSA-PSS, no ECDSA. - Dual/nested signing. Neither version has 1.3.6.1.4.1.311.2.4.1. Single signature in both. - RSA key size. The leaf key changed from 4096-bit to 3072-bit (signature 512 to 384 bytes). Tested directly against rsaenh with synthetic keys via CryptImportPublicKeyInfoEx and CryptVerifySignatureW: 2048, 3072 and 4096 all verify correctly. - rsaenh entirely. Feeding the real leaf public key, the real 384-byte enc_digest and the real 126-byte SignedAttrs in stored order through CryptImportPublicKeyInfoEx + CryptVerifySignatureW under Wine returns success. The identical key, signature and octets fail when the same rsaenh code is reached via WinVerifyTrust. The sole difference is that crypt32 hashes re-encoded attributes rather than the original ones. THE ONE STRUCTURAL DIFFERENCE The PKCS#7 authenticated attributes appear in a different order in the two files. Each attribute is a SEQUENCE with a single-byte length, so DER ordering is decided by that length octet: attribute encoding length SPC_SP_OPUS_INFO (2.1.12) 30 10 0x10 contentType (1.2.840.113549.1.9.3) 30 19 0x19 SPC_STATEMENT_TYPE (2.1.11) 30 1C 0x1C messageDigest (1.2.840.113549.1.9.4) 30 2F 0x2F 26.1.3 file order: 0x10, 0x19, 0x1C, 0x2F ascending 26.1.5 file order: 0x1C, 0x10, 0x19, 0x2F NOT ascending X.690 11.6 requires the components of a SET OF to appear in ascending order compared as octet strings. The 26.1.5 SignedAttrs set does not satisfy this. It is nonetheless the encoding the signature was computed over, since OpenSSL verifies the file successfully and OpenSSL hashes the attributes in their decoded order (PKCS7_ATTR_VERIFY is declared with ASN1_TFLG_SET_ORDER, which preserves order rather than sorting). Windows accepts the file as well. CONFIRMATION THAT THE SIGNATURE COVERS THE UNSORTED BYTES The 126-byte SignedAttrs region was extracted from the DER PKCS#7 blob with the implicit [0] tag replaced by SET (0x31), leaving the attribute order exactly as stored in the file. The 384-byte enc_digest and the leaf public key were extracted from the same file. Then: openssl dgst -sha256 -verify leafpub.pem -signature encdigest.bin attrs.bin Verified OK So the signature was computed over the attributes in their stored, non-DER order. Any verifier that re-orders them before hashing will compute a different digest and reject a valid signature. ROOT CAUSE CSignedMsgData_UpdateAuthenticatedAttributes (dlls/crypt32/msg.c:1106) re-encodes the decoded attributes via CryptEncodeObjectEx(PKCS_ATTRIBUTES) and hashes the result, rather than hashing the attribute bytes as they appear in the file. That reaches CRYPT_AsnEncodePKCSAttributes (dlls/crypt32/encode.c:1896), which calls CRYPT_DEREncodeItemsAsSet (encode.c:1239). That function qsort()s the encoded attributes into DER order at encode.c:1294 before concatenating them. (Note there is a second sorting encoder, CRYPT_DEREncodeSet at encode.c:1195, qsort at 1217. It sorts the values within a single attribute, not the attributes themselves. Every attribute here has one value, so it is a no-op in this case.) The sorted 126 bytes therefore differ from the 126 bytes the signer signed, the digest does not match, and the RSA verification fails. This explains why 26.1.3 works and 26.1.5 does not: 26.1.3's attributes are already in ascending DER order, so the sort is a no-op. Note that sorting does not change the total length, which is 126 bytes either way, so length is not a useful diagnostic signal here. Sorting is correct behaviour when producing a signature. It is wrong when verifying one, because it discards the exact octets the signature was computed over. SUGGESTED FIX DIRECTION For signature verification, hash the authenticated attributes in the order they were decoded, rather than round-tripping them through a DER set encoder that sorts. This is what Windows does, and it is why non-canonically-ordered SignedAttrs verify there. A patch implementing this, together with a conformance test, has been written and tested. It adds an order-preserving attribute encoder and uses it on the verify path only. With it applied: - the new test in dlls/crypt32/tests/msg.c passes, and fails without it - crypt32, wintrust and rsaenh tests report 0 failures on both i386 and x86_64 - FL Studio 26.1.5 starts and runs normally A merge request will be linked here. VERSIONS TESTED - wine-11.0 (winehq-stable), Debian 13 trixie, x86-64 -- fails - Community reports indicate wine-11.16 is also affected, so this is not fixed in current development branches. - Affected application builds: 26.1.4.5589 and 26.1.5.5618 fail; 26.1.3.5570 and earlier work. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #1 from mcnster@gmail.com --- Created attachment 81993 --> http://bugs.winehq.org/attachment.cgi?id=81993 WINEDEBUG trace, failing binary, returns 80096004 -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #2 from mcnster@gmail.com --- Created attachment 81994 --> http://bugs.winehq.org/attachment.cgi?id=81994 Same channels, working binary, returns 0 -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #3 from mcnster@gmail.com --- Created attachment 81995 --> http://bugs.winehq.org/attachment.cgi?id=81995 126-byte SignedAttrs from 26.1.5, stored order, [0] retagged to SET -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #4 from mcnster@gmail.com --- Created attachment 81996 --> http://bugs.winehq.org/attachment.cgi?id=81996 384-byte SignerInfo enc_digest from 26.1.5 -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #5 from mcnster@gmail.com --- Created attachment 81997 --> http://bugs.winehq.org/attachment.cgi?id=81997 Signer public key, for the openssl dgst -verify above -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #6 from mcnster@gmail.com --- Created attachment 81998 --> http://bugs.winehq.org/attachment.cgi?id=81998 Full extracted PKCS#7 signature, 26.1.5 -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #7 from mcnster@gmail.com --- Created attachment 81999 --> http://bugs.winehq.org/attachment.cgi?id=81999 Full extracted PKCS#7 signature, 26.1.3 -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #8 from mcnster@gmail.com --- Created attachment 82000 --> http://bugs.winehq.org/attachment.cgi?id=82000 Proposed fix plus conformance test -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #9 from mcnster@gmail.com --- Created attachment 82001 --> http://bugs.winehq.org/attachment.cgi?id=82001 PKCS#7 structure dump showing attribute order -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #10 from mcnster@gmail.com --- Created attachment 82002 --> http://bugs.winehq.org/attachment.cgi?id=82002 Same, ordered correctly, for comparison -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #11 from mcnster@gmail.com --- Created attachment 82003 --> http://bugs.winehq.org/attachment.cgi?id=82003 osslsigncode verify output, succeeds independently of Wine -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #12 from mcnster@gmail.com --- Created attachment 82004 --> http://bugs.winehq.org/attachment.cgi?id=82004 Isolation tool used to exonerate rsaenh and key size -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #13 from mcnster@gmail.com --- Created attachment 82005 --> http://bugs.winehq.org/attachment.cgi?id=82005 Generator for the conformance test vector -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 mcnster@gmail.com changed: What |Removed |Added ---------------------------------------------------------------------------- Keywords| |patch -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 mcnster@gmail.com changed: What |Removed |Added ---------------------------------------------------------------------------- Keywords| |win64 -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 mcnster@gmail.com changed: What |Removed |Added ---------------------------------------------------------------------------- Version|11.0 |11.16 -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 mcnster@gmail.com changed: What |Removed |Added ---------------------------------------------------------------------------- Version|11.16 |11.0 -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 mcnster@gmail.com changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |mcnster@gmail.com -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 --- Comment #14 from mcnster@gmail.com --- Merge request: https://gitlab.winehq.org/wine/wine/-/merge_requests/11824 Two commits: the fix in crypt32, and a conformance test using a generated PKCS#7 message whose authenticated attributes are deliberately out of DER order. Tested on Debian 13 x86-64 against current master. The new test passes with the fix and fails without it. crypt32, wintrust and rsaenh tests report 0 failures on both i386 and x86_64. FL Studio 26.1.5 starts and runs normally with the patch applied. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 mcnster@gmail.com changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #82000|0 |1 is obsolete| | -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60273 Mirey Mackey <winehq.sheet918@passmail.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |winehq.sheet918@passmail.co | |m -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
participants (1)
-
WineHQ Bugzilla