From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- configure.ac | 1 + dlls/cryptxml/Makefile.in | 3 +- dlls/cryptxml/tests/Makefile.in | 5 + dlls/cryptxml/tests/cryptxml.c | 168 ++++++++++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 dlls/cryptxml/tests/Makefile.in create mode 100644 dlls/cryptxml/tests/cryptxml.c
diff --git a/configure.ac b/configure.ac index 94fb970c7d2..2493369f331 100644 --- a/configure.ac +++ b/configure.ac @@ -2530,6 +2530,7 @@ WINE_CONFIG_MAKEFILE(dlls/cryptsp) WINE_CONFIG_MAKEFILE(dlls/cryptui) WINE_CONFIG_MAKEFILE(dlls/cryptui/tests) WINE_CONFIG_MAKEFILE(dlls/cryptxml) +WINE_CONFIG_MAKEFILE(dlls/cryptxml/tests) WINE_CONFIG_MAKEFILE(dlls/ctapi32) WINE_CONFIG_MAKEFILE(dlls/ctl3d.dll16) WINE_CONFIG_MAKEFILE(dlls/ctl3d32) diff --git a/dlls/cryptxml/Makefile.in b/dlls/cryptxml/Makefile.in index 1fe91fe7019..49414e3cfd8 100644 --- a/dlls/cryptxml/Makefile.in +++ b/dlls/cryptxml/Makefile.in @@ -1,4 +1,5 @@ -MODULE = cryptxml.dll +MODULE = cryptxml.dll +IMPORTLIB = cryptxml
SOURCES = \ cryptxml.c diff --git a/dlls/cryptxml/tests/Makefile.in b/dlls/cryptxml/tests/Makefile.in new file mode 100644 index 00000000000..82a24b26f4d --- /dev/null +++ b/dlls/cryptxml/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = cryptxml.dll +IMPORTS = cryptxml + +SOURCES = \ + cryptxml.c diff --git a/dlls/cryptxml/tests/cryptxml.c b/dlls/cryptxml/tests/cryptxml.c new file mode 100644 index 00000000000..733a374c591 --- /dev/null +++ b/dlls/cryptxml/tests/cryptxml.c @@ -0,0 +1,168 @@ +/* CryptXML Tests + * + * Copyright (C) 2025 Mohamad Al-Jaf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "cryptxml.h" + +#include "wine/test.h" + +#define check_status( handle, expected_size, expected_error, expected_info, todo ) check_status_( __LINE__, handle, expected_size, expected_error, expected_info, todo ) +static void check_status_( unsigned int line, HCRYPTXML handle, ULONG expected_size, DWORD expected_error, DWORD expected_info, BOOL todo ) +{ + CRYPT_XML_STATUS status; + HRESULT hr; + + status.cbSize = 0xdeadbeef; + status.dwErrorStatus = 0xdeadbeef; + status.dwInfoStatus = 0xdeadbeef; + + hr = CryptXmlGetStatus( handle, &status ); + ok_(__FILE__, line)( hr == S_OK, "got CryptXmlGetStatus hr %#lx\n", hr ); + ok_(__FILE__, line)( status.cbSize == expected_size, "got status.cbSize = %lu\n", status.cbSize ); + todo_wine_if( todo ) ok_(__FILE__, line)( status.dwErrorStatus == expected_error, "got status.dwErrorStatus = %ld\n", status.dwErrorStatus ); + ok_(__FILE__, line)( status.dwInfoStatus == expected_info, "got status.dwInfoStatus = %ld\n", status.dwInfoStatus ); +} + +static void test_verify_signature(void) +{ + static const BYTE signature[] = + "<?xml version='1.0' encoding='UTF-8'?>" + "<Envelope xmlns="urn:envelope">" + "<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#%5C%22%3E" + "ds:SignedInfo" + "<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315%5C%22/%3E" + "<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256%5C%22/%3E" + "<ds:Reference URI="">" + "ds:Transforms" + "<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature%5C%22/%3E" + "<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315%5C%22/%3E" + "</ds:Transforms>" + "<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256%5C%22/%3E" + "ds:DigestValue/juoQ4bDxElf1M+KJauO20euW+QAvvPP0nDCruCQooM=</ds:DigestValue>" + "</ds:Reference>" + "</ds:SignedInfo>" + "ds:SignatureValueN0e0G9nH8CKLZPoUii3W2/lZWnu/eFl1mX5kVMLb1VCBdkcDlbIldw44HbHSY9WQruLjsm7YNyR4RjSYJSwk6RqcbaPt5LfzBJCgh3K+Hd/2TLlnN/xRpHzpnP86+11owwz6i475dRARDGRBUBWFcDkXXjdmWQ1nXbz1Pu4fIdBmpUtkPWnKtYitcq+YANnJez55PxShaZMQUZGnBipMJDajfyXTQr106TBrGic39+UJ+wfni6AE2GSeALsliiop9loBa0yekUcMSIUM8fjhBYRqfdg8vls26pacyEpBjDYUool0YA76o2iGHOXchFzndlm5KbQQyekea4ohmtVq2w==</ds:SignatureValue>" + "ds:KeyInfo" + "ds:KeyValue" + "ds:RSAKeyValue" + "ds:ModulussmBoZK3x0L164lUyh0iM8tTfHbR6Mk9yuoHryzryfe1bplF/Vj+mKCKPVXyCPrUvvHMZsDvdoE50EbILeSA3CGDSghDscKMJnWJZv19qNBZSzCi7UlE3PfmivL6NX8VwYuixHR7YbUJDq/gGnMW687gC8+b4JWPEgiBB71tw8OFluMa5hlIMuAfYMXYjr2QqTKuu4rgwRo3uei83HF3np2mglqFwRCVr6vADX+tRsA5YR6cDtVYqMOahF6YOhHbfYl9x2r+aFv82oBo+SussqdE2lthqowrWLTjHMy3htQoVhEJ0jiJULr/Da5isXDWzXENXH6F5jGIb7v86ZsgMQQ==</ds:Modulus>" + "ds:ExponentAQAB</ds:Exponent>" + "</ds:RSAKeyValue>" + "</ds:KeyValue>" + "</ds:KeyInfo>" + "</ds:Signature>" + "</Envelope>"; + const CRYPT_XML_SIGNATURE *sig; + const CRYPT_XML_DOC_CTXT *ctx; + HCRYPTXML handle = NULL; + CRYPT_XML_STATUS status; + CRYPT_XML_BLOB blob; + HRESULT hr; + + hr = CryptXmlOpenToDecode( NULL, 0, NULL, 0, NULL, NULL ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + + handle = (HCRYPTXML)0xdeadbeef; + hr = CryptXmlOpenToDecode( NULL, 0, NULL, 0, NULL, &handle ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + ok( handle == (HCRYPTXML)0xdeadbeef, "got handle %p.\n", handle ); + + blob.dwCharset = CRYPT_XML_CHARSET_UTF8; + blob.cbData = strlen((const char *)signature) - 1; + blob.pbData = (BYTE *)signature; + hr = CryptXmlOpenToDecode( NULL, 0, NULL, 0, &blob, &handle ); + todo_wine + ok( hr == WS_E_INVALID_FORMAT, "got hr %#lx.\n", hr ); + todo_wine + ok( handle == NULL, "got handle %p.\n", handle ); + + hr = CryptXmlClose( NULL ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + + blob.dwCharset = CRYPT_XML_CHARSET_UTF8; + blob.cbData = strlen( (const char *)signature ); + blob.pbData = (BYTE *)signature; + hr = CryptXmlOpenToDecode( NULL, 0, NULL, 0, &blob, &handle ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + hr = CryptXmlGetStatus( handle, NULL ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + hr = CryptXmlGetStatus( NULL, &status ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + + ctx = (CRYPT_XML_DOC_CTXT *)0xdeadbeef; + hr = CryptXmlGetDocContext( NULL, &ctx ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + ok( ctx == (CRYPT_XML_DOC_CTXT *)0xdeadbeef, "got ctx %p\n", ctx ); + hr = CryptXmlGetDocContext( handle, NULL ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + + hr = CryptXmlGetDocContext( handle, &ctx ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + ok( ctx->cSignature == 1, "got signature count %lu\n", ctx->cSignature ); + ok( ctx->rgpSignature != NULL, "got NULL rgpSignature\n" ); + + sig = (CRYPT_XML_SIGNATURE *)0xdeadbeef; + hr = CryptXmlGetSignature( NULL, &sig ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + ok( sig == (CRYPT_XML_SIGNATURE *)0xdeadbeef, "got sig %p\n", sig ); + hr = CryptXmlGetSignature( handle, NULL ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + hr = CryptXmlGetSignature( handle, &sig ); + ok( hr == CRYPT_XML_E_HANDLE, "got hr %#lx.\n", hr ); + ok( sig == NULL, "got sig %p\n", sig ); + + hr = CryptXmlGetSignature( ctx->rgpSignature[0]->hSignature, &sig ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + ok( sig != NULL, "failed to get signature\n" ); + ok( sig->cbSize == sizeof( CRYPT_XML_SIGNATURE ), "got sig->cbSize = %lu\n", sig->cbSize ); + + check_status( handle, sizeof( CRYPT_XML_STATUS ), CRYPT_XML_STATUS_ERROR_NOT_RESOLVED, 0, FALSE ); + + hr = CryptXmlVerifySignature( NULL, NULL, 0 ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + hr = CryptXmlVerifySignature( handle, NULL, 0 ); + ok( hr == CRYPT_XML_E_HANDLE, "got hr %#lx.\n", hr ); + hr = CryptXmlVerifySignature( handle, sig->pKeyInfo->hVerifyKey, 0 ); + ok( hr == CRYPT_XML_E_HANDLE, "got hr %#lx.\n", hr ); + + hr = CryptXmlVerifySignature( sig->hSignature, sig->pKeyInfo->hVerifyKey, 0 ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + check_status( handle, sizeof( CRYPT_XML_STATUS ), CRYPT_XML_STATUS_ERROR_DIGEST_INVALID, CRYPT_XML_STATUS_SIGNATURE_VALID, TRUE ); + check_status( sig->hSignature, sizeof( CRYPT_XML_STATUS ), CRYPT_XML_STATUS_ERROR_DIGEST_INVALID, CRYPT_XML_STATUS_SIGNATURE_VALID, TRUE ); + + ctx = (CRYPT_XML_DOC_CTXT *)0xdeadbeef; + hr = CryptXmlGetDocContext( sig->hSignature, &ctx ); + ok( hr == CRYPT_XML_E_HANDLE, "got hr %#lx.\n", hr ); + ok( ctx == NULL, "got ctx %p\n", ctx ); + + hr = CryptXmlClose( sig->hSignature ); + ok( hr == S_FALSE, "got hr %#lx.\n", hr ); + hr = CryptXmlClose( handle ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); +} + +START_TEST(cryptxml) +{ + test_verify_signature(); +}