With the goal of fixing the [Sven Bømwøllen series: Several games crash after loading screen](https://bugs.winehq.org/show_bug.cgi?id=55936) issue, I did some refactoring on the corresponding tests to separate them. Afterwards I've added a signature verification test for this bug and fixed the wrong byte order in the dssenh signatures.
With the refactoring of the tests, they also caught a missing BCryptFinishHash in the CPSignHash function.
From: Sven Püschel <Sven\u2007Pschel@akarisu.de>
As the signature verification is already implemented, there is no more need to skip the signature tests.
This may be related to the VerifySignature following fix: 1d0551ca49f ("dssenh: Finalize the hash if necessary in CPVerifySignature().")
Signed-off-by: Sven Püschel <Sven Püschel@akarisu.de> --- dlls/dssenh/tests/dssenh.c | 5 ----- 1 file changed, 5 deletions(-)
diff --git a/dlls/dssenh/tests/dssenh.c b/dlls/dssenh/tests/dssenh.c index fb9ab820330..c5e2d0ba43d 100644 --- a/dlls/dssenh/tests/dssenh.c +++ b/dlls/dssenh/tests/dssenh.c @@ -963,11 +963,6 @@ static void test_signhash_array(HCRYPTPROV hProv, const struct signature_test *t
/* Verify signed hash 1 */ result = CryptVerifySignatureA(hHash1, signValue1, sizeof(signValue1), pubKey, NULL, 0); - if (!result) - { - skip("skipping sign tests\n"); - return; - } ok(result, "Failed to verify signature, got %lx\n", GetLastError());
result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash2);
From: Sven Püschel <Sven\u2007Pschel@akarisu.de>
Testing with two simple sentences as strings is redundant. Testing a common input (sentence) is enough and all other inputs should be edge cases like empty strings, min/max integer values, etc.
Signed-off-by: Sven Püschel <Sven Püschel@akarisu.de> --- dlls/dssenh/tests/dssenh.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/dlls/dssenh/tests/dssenh.c b/dlls/dssenh/tests/dssenh.c index c5e2d0ba43d..1ee0fd1ec49 100644 --- a/dlls/dssenh/tests/dssenh.c +++ b/dlls/dssenh/tests/dssenh.c @@ -796,9 +796,8 @@ struct signature_test { DWORD dataLen; };
-static const char dataToSign1[] = "Put your hands up for Cryptography :)"; -static const char dataToSign2[] = "With DSSENH implemented, applications requiring it will now work."; -static const char dataToSign3[] = ""; +static const char dataToSign1[] = "With DSSENH implemented, applications requiring it will now work."; +static const char dataToSign2[] = "";
static const BYTE AT_SIGNATURE_PrivateKey[] = { 0x07,0x02,0x00,0x00,0x00,0x22,0x00,0x00, 0x44,0x53,0x53,0x32,0x00,0x04,0x00,0x00, @@ -851,10 +850,8 @@ static const BYTE DSS_SIGN_PrivateKey[] = { static const struct signature_test dssSign_data[] = { {AT_SIGNATURE_PrivateKey, sizeof(AT_SIGNATURE_PrivateKey), (BYTE *)dataToSign1, sizeof(dataToSign1)}, {AT_SIGNATURE_PrivateKey, sizeof(AT_SIGNATURE_PrivateKey), (BYTE *)dataToSign2, sizeof(dataToSign2)}, - {AT_SIGNATURE_PrivateKey, sizeof(AT_SIGNATURE_PrivateKey), (BYTE *)dataToSign3, sizeof(dataToSign3)}, {DSS_SIGN_PrivateKey, sizeof(DSS_SIGN_PrivateKey), (BYTE *)dataToSign1, sizeof(dataToSign1)}, {DSS_SIGN_PrivateKey, sizeof(DSS_SIGN_PrivateKey), (BYTE *)dataToSign2, sizeof(dataToSign2)}, - {DSS_SIGN_PrivateKey, sizeof(DSS_SIGN_PrivateKey), (BYTE *)dataToSign3, sizeof(dataToSign3)} };
static void test_signhash_array(HCRYPTPROV hProv, const struct signature_test *tests, int testLen)
From: Sven Püschel <Sven\u2007Pschel@akarisu.de>
Move the test loop out of the test_signhash_array function to allow splitting the function into parts without duplicating the loop.
Signed-off-by: Sven Püschel <Sven Püschel@akarisu.de> --- dlls/dssenh/tests/dssenh.c | 214 +++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 113 deletions(-)
diff --git a/dlls/dssenh/tests/dssenh.c b/dlls/dssenh/tests/dssenh.c index 1ee0fd1ec49..530bc6c6d60 100644 --- a/dlls/dssenh/tests/dssenh.c +++ b/dlls/dssenh/tests/dssenh.c @@ -854,7 +854,7 @@ static const struct signature_test dssSign_data[] = { {DSS_SIGN_PrivateKey, sizeof(DSS_SIGN_PrivateKey), (BYTE *)dataToSign2, sizeof(dataToSign2)}, };
-static void test_signhash_array(HCRYPTPROV hProv, const struct signature_test *tests, int testLen) +static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test) { HCRYPTHASH hHash1, hHash2; HCRYPTKEY privKey = 0, pubKey = 0; @@ -864,133 +864,130 @@ static void test_signhash_array(HCRYPTPROV hProv, const struct signature_test *t DWORD hashLen1, hashLen2, pubKeyLen; DWORD dataLen1, dataLen2; BOOL result; - int i;
- for (i = 0; i < testLen; i++) - { - DWORD signLen1 = tests[i].dataLen; - DWORD signLen2 = tests[i].dataLen; + DWORD signLen1 = test->dataLen; + DWORD signLen2 = test->dataLen;
- /* Get a private key of array specified ALG_ID */ - result = CryptImportKey(hProv, tests[i].privateKey, tests[i].keyLen, 0, 0, &privKey); - ok(result, "Failed to imported key, got %lx\n", GetLastError()); + /* Get a private key of array specified ALG_ID */ + result = CryptImportKey(hProv, test->privateKey, test->keyLen, 0, 0, &privKey); + ok(result, "Failed to imported key, got %lx\n", GetLastError());
- /* Create hash object and add data for signature 1 */ - result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash1); - ok(result, "Failed to create a hash, got %lx\n", GetLastError()); + /* Create hash object and add data for signature 1 */ + result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash1); + ok(result, "Failed to create a hash, got %lx\n", GetLastError());
- result = CryptHashData(hHash1, tests[i].signData, signLen1, 0); - ok(result, "Failed to add data to hash, got %lx\n", GetLastError()); + result = CryptHashData(hHash1, test->signData, signLen1, 0); + ok(result, "Failed to add data to hash, got %lx\n", GetLastError());
- /* Create hash object and add data for signature 2 */ - result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash2); - ok(result, "Failed to create a hash, got %lx\n", GetLastError()); + /* Create hash object and add data for signature 2 */ + result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash2); + ok(result, "Failed to create a hash, got %lx\n", GetLastError());
- result = CryptHashData(hHash2, tests[i].signData, signLen2, 0); - ok(result, "Failed to add data to hash, got %lx\n", GetLastError()); + result = CryptHashData(hHash2, test->signData, signLen2, 0); + ok(result, "Failed to add data to hash, got %lx\n", GetLastError());
- /* Acquire hash length and hash value */ - dataLen1 = sizeof(DWORD); - result = CryptGetHashParam(hHash1, HP_HASHSIZE, (BYTE *)&hashLen1, &dataLen1, 0); - ok(result, "Failed to get hash length, got %lx\n", GetLastError()); + /* Acquire hash length and hash value */ + dataLen1 = sizeof(DWORD); + result = CryptGetHashParam(hHash1, HP_HASHSIZE, (BYTE *)&hashLen1, &dataLen1, 0); + ok(result, "Failed to get hash length, got %lx\n", GetLastError());
- result = CryptGetHashParam(hHash1, HP_HASHVAL, hashValue1, &hashLen1, 0); - ok(result, "Failed to return hash value.\n"); + result = CryptGetHashParam(hHash1, HP_HASHVAL, hashValue1, &hashLen1, 0); + ok(result, "Failed to return hash value.\n");
- dataLen2 = sizeof(DWORD); - result = CryptGetHashParam(hHash2, HP_HASHSIZE, (BYTE *)&hashLen2, &dataLen2, 0); - ok(result, "Failed to get hash length, got %lx\n", GetLastError()); + dataLen2 = sizeof(DWORD); + result = CryptGetHashParam(hHash2, HP_HASHSIZE, (BYTE *)&hashLen2, &dataLen2, 0); + ok(result, "Failed to get hash length, got %lx\n", GetLastError());
- result = CryptGetHashParam(hHash2, HP_HASHVAL, hashValue2, &hashLen2, 0); - ok(result, "Failed to return hash value.\n"); + result = CryptGetHashParam(hHash2, HP_HASHVAL, hashValue2, &hashLen2, 0); + ok(result, "Failed to return hash value.\n");
- /* Compare hashes to ensure they are the same */ - ok(hashLen1 == hashLen2, "Hash lengths were not the same.\n"); - ok(!memcmp(hashValue1, hashValue2, hashLen2), "Hashes were not identical.\n"); + /* Compare hashes to ensure they are the same */ + ok(hashLen1 == hashLen2, "Hash lengths were not the same.\n"); + ok(!memcmp(hashValue1, hashValue2, hashLen2), "Hashes were not identical.\n");
- /* Sign hash 1 */ - signLen1 = 0; - result = CryptSignHashA(hHash1, AT_SIGNATURE, NULL, 0, NULL, &signLen1); - ok(result, "Failed to get signature length, got %lx\n", GetLastError()); - ok(signLen1 == 40, "Expected a 40-byte signature, got %ld\n", signLen1); + /* Sign hash 1 */ + signLen1 = 0; + result = CryptSignHashA(hHash1, AT_SIGNATURE, NULL, 0, NULL, &signLen1); + ok(result, "Failed to get signature length, got %lx\n", GetLastError()); + ok(signLen1 == 40, "Expected a 40-byte signature, got %ld\n", signLen1);
- result = CryptSignHashA(hHash1, AT_SIGNATURE, NULL, 0, signValue1, &signLen1); - ok(result, "Failed to sign hash, got %lx\n", GetLastError()); + result = CryptSignHashA(hHash1, AT_SIGNATURE, NULL, 0, signValue1, &signLen1); + ok(result, "Failed to sign hash, got %lx\n", GetLastError());
- /* Sign hash 2 */ - signLen2 = 0; - result = CryptSignHashA(hHash2, AT_SIGNATURE, NULL, 0, NULL, &signLen2); - ok(result, "Failed to get signature length, got %lx\n", GetLastError()); - ok(signLen2 == 40, "Expected a 40-byte signature, got %ld\n", signLen2); + /* Sign hash 2 */ + signLen2 = 0; + result = CryptSignHashA(hHash2, AT_SIGNATURE, NULL, 0, NULL, &signLen2); + ok(result, "Failed to get signature length, got %lx\n", GetLastError()); + ok(signLen2 == 40, "Expected a 40-byte signature, got %ld\n", signLen2);
- result = CryptSignHashA(hHash2, AT_SIGNATURE, NULL, 0, signValue2, &signLen2); - ok(result, "Failed to sign hash2, got %lx\n", GetLastError()); + result = CryptSignHashA(hHash2, AT_SIGNATURE, NULL, 0, signValue2, &signLen2); + ok(result, "Failed to sign hash2, got %lx\n", GetLastError());
- /* Compare signatures to ensure they are both different, because every DSS signature - should be different even if the input hash data is identical */ - ok(memcmp(signValue1, signValue2, signLen2), "Expected two different signatures from " - "the same hash input.\n"); + /* Compare signatures to ensure they are both different, because every DSS signature + should be different even if the input hash data is identical */ + ok(memcmp(signValue1, signValue2, signLen2), "Expected two different signatures from " + "the same hash input.\n");
- result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, NULL, &pubKeyLen); - ok(result, "Failed to acquire public key length, got %lx\n", GetLastError()); + result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, NULL, &pubKeyLen); + ok(result, "Failed to acquire public key length, got %lx\n", GetLastError());
- /* Export the public key */ - result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, pubKeyBuffer, &pubKeyLen); - ok(result, "Failed to export public key, got %lx\n", GetLastError()); + /* Export the public key */ + result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, pubKeyBuffer, &pubKeyLen); + ok(result, "Failed to export public key, got %lx\n", GetLastError());
- result = CryptDestroyHash(hHash1); - ok(result, "Failed to destroy hash1, got %lx\n", GetLastError()); - result = CryptDestroyHash(hHash2); - ok(result, "Failed to destroy hash2, got %lx\n", GetLastError()); + result = CryptDestroyHash(hHash1); + ok(result, "Failed to destroy hash1, got %lx\n", GetLastError()); + result = CryptDestroyHash(hHash2); + ok(result, "Failed to destroy hash2, got %lx\n", GetLastError());
- /* Destroy the private key */ - result = CryptDestroyKey(privKey); - ok(result, "Failed to destroy private key, got %lx\n", GetLastError()); + /* Destroy the private key */ + result = CryptDestroyKey(privKey); + ok(result, "Failed to destroy private key, got %lx\n", GetLastError());
- /* Import the public key we obtained earlier */ - result = CryptImportKey(hProv, pubKeyBuffer, pubKeyLen, 0, 0, &pubKey); - ok(result, "Failed to import public key, got %lx\n", GetLastError()); + /* Import the public key we obtained earlier */ + result = CryptImportKey(hProv, pubKeyBuffer, pubKeyLen, 0, 0, &pubKey); + ok(result, "Failed to import public key, got %lx\n", GetLastError());
- result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash1); - ok(result, "Failed to create hash, got %lx\n", GetLastError()); + result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash1); + ok(result, "Failed to create hash, got %lx\n", GetLastError());
- /* Hash the data to compare with the signed hash */ - result = CryptHashData(hHash1, tests[i].signData, tests[i].dataLen, 0); - ok(result, "Failed to add data to hash1, got %lx\n", GetLastError()); + /* Hash the data to compare with the signed hash */ + result = CryptHashData(hHash1, test->signData, test->dataLen, 0); + ok(result, "Failed to add data to hash1, got %lx\n", GetLastError());
- /* Verify signed hash 1 */ - result = CryptVerifySignatureA(hHash1, signValue1, sizeof(signValue1), pubKey, NULL, 0); - ok(result, "Failed to verify signature, got %lx\n", GetLastError()); + /* Verify signed hash 1 */ + result = CryptVerifySignatureA(hHash1, signValue1, sizeof(signValue1), pubKey, NULL, 0); + ok(result, "Failed to verify signature, got %lx\n", GetLastError());
- result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash2); - ok(result, "Failed to create hash, got %lx\n", GetLastError()); + result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash2); + ok(result, "Failed to create hash, got %lx\n", GetLastError());
- /* Hash the data to compare with the signed hash */ - result = CryptHashData(hHash2, tests[i].signData, tests[i].dataLen, 0); - ok(result, "Failed to add data to hash2, got %lx\n", GetLastError()); + /* Hash the data to compare with the signed hash */ + result = CryptHashData(hHash2, test->signData, test->dataLen, 0); + ok(result, "Failed to add data to hash2, got %lx\n", GetLastError());
- /* Verify signed hash 2 */ - result = CryptVerifySignatureA(hHash2, signValue2, sizeof(signValue2), pubKey, NULL, 0); - ok(result, "Failed to verify signature, got %lx\n", GetLastError()); + /* Verify signed hash 2 */ + result = CryptVerifySignatureA(hHash2, signValue2, sizeof(signValue2), pubKey, NULL, 0); + ok(result, "Failed to verify signature, got %lx\n", GetLastError());
- result = CryptDestroyHash(hHash1); - ok(result, "Failed to destroy hash1, got %lx\n", GetLastError()); - result = CryptDestroyHash(hHash2); - ok(result, "Failed to destroy hash2, got %lx\n", GetLastError()); + result = CryptDestroyHash(hHash1); + ok(result, "Failed to destroy hash1, got %lx\n", GetLastError()); + result = CryptDestroyHash(hHash2); + ok(result, "Failed to destroy hash2, got %lx\n", GetLastError());
- /* Destroy the public key */ - result = CryptDestroyKey(pubKey); - ok(result, "Failed to destroy public key, got %lx\n", GetLastError()); - } + /* Destroy the public key */ + result = CryptDestroyKey(pubKey); + ok(result, "Failed to destroy public key, got %lx\n", GetLastError()); }
static void test_verify_signature(void) { - HCRYPTPROV hProv = 0; + HCRYPTPROV hProv[4]; BOOL result; + int i, j;
/* acquire base dss provider */ - result = CryptAcquireContextA(&hProv, NULL, MS_DEF_DSS_PROV_A, PROV_DSS, 0); + result = CryptAcquireContextA(&hProv[0], NULL, MS_DEF_DSS_PROV_A, PROV_DSS, 0); if(!result) { skip("DSSENH is currently not available, skipping signature verification tests.\n"); @@ -998,38 +995,29 @@ static void test_verify_signature(void) } ok(result, "Failed to acquire CSP.\n");
- test_signhash_array(hProv, dssSign_data, ARRAY_SIZE(dssSign_data)); - - result = CryptReleaseContext(hProv, 0); - ok(result, "Failed to release CSP provider.\n"); - /* acquire diffie hellman dss provider */ - result = CryptAcquireContextA(&hProv, NULL, MS_DEF_DSS_DH_PROV_A, PROV_DSS_DH, 0); + result = CryptAcquireContextA(&hProv[1], NULL, MS_DEF_DSS_DH_PROV_A, PROV_DSS_DH, 0); ok(result, "Failed to acquire CSP.\n");
- test_signhash_array(hProv, dssSign_data, ARRAY_SIZE(dssSign_data)); - - result = CryptReleaseContext(hProv, 0); - ok(result, "Failed to release CSP provider.\n"); - /* acquire enhanced dss provider */ SetLastError(0xdeadbeef); - result = CryptAcquireContextA(&hProv, NULL, MS_ENH_DSS_DH_PROV_A, PROV_DSS_DH, 0); + result = CryptAcquireContextA(&hProv[2], NULL, MS_ENH_DSS_DH_PROV_A, PROV_DSS_DH, 0); ok(result, "Failed to acquire CSP.\n");
- test_signhash_array(hProv, dssSign_data, ARRAY_SIZE(dssSign_data)); - - result = CryptReleaseContext(hProv, 0); - ok(result, "Failed to release CSP provider.\n"); - /* acquire schannel dss provider */ - result = CryptAcquireContextA(&hProv, NULL, MS_DEF_DH_SCHANNEL_PROV_A, PROV_DH_SCHANNEL, 0); + result = CryptAcquireContextA(&hProv[3], NULL, MS_DEF_DH_SCHANNEL_PROV_A, PROV_DH_SCHANNEL, 0); ok(result, "Failed to acquire CSP.\n");
- test_signhash_array(hProv, dssSign_data, ARRAY_SIZE(dssSign_data)); + for (i = 0; i < ARRAY_SIZE(hProv); i++) + { + for (j = 0; j < ARRAY_SIZE(dssSign_data); j++) + { + test_signhash(hProv[i], &dssSign_data[j]); + }
- result = CryptReleaseContext(hProv, 0); - ok(result, "Failed to release CSP provider.\n"); + result = CryptReleaseContext(hProv[i], 0); + ok(result, "Failed to release CSP provider %d.\n", i); + } }
struct keyExchange_test {
From: Sven Püschel <Sven\u2007Pschel@akarisu.de>
Don't test the hashes to be equal before creating a signature. The correct hash generation is already tested in the test_hash function.
Also reordered the hash creation and destruction, so that one HCRYPTHASH variable is enough.
Furthermore removing this check caused the signature verification to fail. Testing on a Windows 10 machine reveals that this is a wine bug. Therefore marked the signature verification as todo_wine.
Signed-off-by: Sven Püschel <Sven Püschel@akarisu.de> --- dlls/dssenh/tests/dssenh.c | 93 +++++++++++++++----------------------- 1 file changed, 37 insertions(+), 56 deletions(-)
diff --git a/dlls/dssenh/tests/dssenh.c b/dlls/dssenh/tests/dssenh.c index 530bc6c6d60..2f9e491c0e0 100644 --- a/dlls/dssenh/tests/dssenh.c +++ b/dlls/dssenh/tests/dssenh.c @@ -856,13 +856,11 @@ static const struct signature_test dssSign_data[] = {
static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test) { - HCRYPTHASH hHash1, hHash2; + HCRYPTHASH hHash; HCRYPTKEY privKey = 0, pubKey = 0; BYTE pubKeyBuffer[512]; BYTE signValue1[40], signValue2[40]; - BYTE hashValue1[40], hashValue2[40]; - DWORD hashLen1, hashLen2, pubKeyLen; - DWORD dataLen1, dataLen2; + DWORD pubKeyLen; BOOL result;
DWORD signLen1 = test->dataLen; @@ -873,55 +871,42 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test) ok(result, "Failed to imported key, got %lx\n", GetLastError());
/* Create hash object and add data for signature 1 */ - result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash1); + result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); ok(result, "Failed to create a hash, got %lx\n", GetLastError());
- result = CryptHashData(hHash1, test->signData, signLen1, 0); + result = CryptHashData(hHash, test->signData, signLen1, 0); ok(result, "Failed to add data to hash, got %lx\n", GetLastError());
- /* Create hash object and add data for signature 2 */ - result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash2); - ok(result, "Failed to create a hash, got %lx\n", GetLastError()); - - result = CryptHashData(hHash2, test->signData, signLen2, 0); - ok(result, "Failed to add data to hash, got %lx\n", GetLastError()); - - /* Acquire hash length and hash value */ - dataLen1 = sizeof(DWORD); - result = CryptGetHashParam(hHash1, HP_HASHSIZE, (BYTE *)&hashLen1, &dataLen1, 0); - ok(result, "Failed to get hash length, got %lx\n", GetLastError()); - - result = CryptGetHashParam(hHash1, HP_HASHVAL, hashValue1, &hashLen1, 0); - ok(result, "Failed to return hash value.\n"); - - dataLen2 = sizeof(DWORD); - result = CryptGetHashParam(hHash2, HP_HASHSIZE, (BYTE *)&hashLen2, &dataLen2, 0); - ok(result, "Failed to get hash length, got %lx\n", GetLastError()); - - result = CryptGetHashParam(hHash2, HP_HASHVAL, hashValue2, &hashLen2, 0); - ok(result, "Failed to return hash value.\n"); - - /* Compare hashes to ensure they are the same */ - ok(hashLen1 == hashLen2, "Hash lengths were not the same.\n"); - ok(!memcmp(hashValue1, hashValue2, hashLen2), "Hashes were not identical.\n"); - /* Sign hash 1 */ signLen1 = 0; - result = CryptSignHashA(hHash1, AT_SIGNATURE, NULL, 0, NULL, &signLen1); + result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, NULL, &signLen1); ok(result, "Failed to get signature length, got %lx\n", GetLastError()); ok(signLen1 == 40, "Expected a 40-byte signature, got %ld\n", signLen1);
- result = CryptSignHashA(hHash1, AT_SIGNATURE, NULL, 0, signValue1, &signLen1); + result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, signValue1, &signLen1); ok(result, "Failed to sign hash, got %lx\n", GetLastError());
+ result = CryptDestroyHash(hHash); + ok(result, "Failed to destroy hash, got %lx\n", GetLastError()); + + /* Create hash object and add data for signature 2 */ + result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); + ok(result, "Failed to create a hash, got %lx\n", GetLastError()); + + result = CryptHashData(hHash, test->signData, signLen2, 0); + ok(result, "Failed to add data to hash, got %lx\n", GetLastError()); + /* Sign hash 2 */ signLen2 = 0; - result = CryptSignHashA(hHash2, AT_SIGNATURE, NULL, 0, NULL, &signLen2); + result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, NULL, &signLen2); ok(result, "Failed to get signature length, got %lx\n", GetLastError()); ok(signLen2 == 40, "Expected a 40-byte signature, got %ld\n", signLen2);
- result = CryptSignHashA(hHash2, AT_SIGNATURE, NULL, 0, signValue2, &signLen2); - ok(result, "Failed to sign hash2, got %lx\n", GetLastError()); + result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, signValue2, &signLen2); + ok(result, "Failed to sign hash, got %lx\n", GetLastError()); + + result = CryptDestroyHash(hHash); + ok(result, "Failed to destroy hash, got %lx\n", GetLastError());
/* Compare signatures to ensure they are both different, because every DSS signature should be different even if the input hash data is identical */ @@ -935,11 +920,6 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test) result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, pubKeyBuffer, &pubKeyLen); ok(result, "Failed to export public key, got %lx\n", GetLastError());
- result = CryptDestroyHash(hHash1); - ok(result, "Failed to destroy hash1, got %lx\n", GetLastError()); - result = CryptDestroyHash(hHash2); - ok(result, "Failed to destroy hash2, got %lx\n", GetLastError()); - /* Destroy the private key */ result = CryptDestroyKey(privKey); ok(result, "Failed to destroy private key, got %lx\n", GetLastError()); @@ -948,32 +928,33 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test) result = CryptImportKey(hProv, pubKeyBuffer, pubKeyLen, 0, 0, &pubKey); ok(result, "Failed to import public key, got %lx\n", GetLastError());
- result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash1); + result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); ok(result, "Failed to create hash, got %lx\n", GetLastError());
/* Hash the data to compare with the signed hash */ - result = CryptHashData(hHash1, test->signData, test->dataLen, 0); - ok(result, "Failed to add data to hash1, got %lx\n", GetLastError()); + result = CryptHashData(hHash, test->signData, test->dataLen, 0); + ok(result, "Failed to add data to hash, got %lx\n", GetLastError());
/* Verify signed hash 1 */ - result = CryptVerifySignatureA(hHash1, signValue1, sizeof(signValue1), pubKey, NULL, 0); - ok(result, "Failed to verify signature, got %lx\n", GetLastError()); + result = CryptVerifySignatureA(hHash, signValue1, sizeof(signValue1), pubKey, NULL, 0); + todo_wine ok(result, "Failed to verify signature, got %lx\n", GetLastError()); + + result = CryptDestroyHash(hHash); + ok(result, "Failed to destroy hash, got %lx\n", GetLastError());
- result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash2); + result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); ok(result, "Failed to create hash, got %lx\n", GetLastError());
/* Hash the data to compare with the signed hash */ - result = CryptHashData(hHash2, test->signData, test->dataLen, 0); - ok(result, "Failed to add data to hash2, got %lx\n", GetLastError()); + result = CryptHashData(hHash, test->signData, test->dataLen, 0); + ok(result, "Failed to add data to hash, got %lx\n", GetLastError());
/* Verify signed hash 2 */ - result = CryptVerifySignatureA(hHash2, signValue2, sizeof(signValue2), pubKey, NULL, 0); - ok(result, "Failed to verify signature, got %lx\n", GetLastError()); + result = CryptVerifySignatureA(hHash, signValue2, sizeof(signValue2), pubKey, NULL, 0); + todo_wine ok(result, "Failed to verify signature, got %lx\n", GetLastError());
- result = CryptDestroyHash(hHash1); - ok(result, "Failed to destroy hash1, got %lx\n", GetLastError()); - result = CryptDestroyHash(hHash2); - ok(result, "Failed to destroy hash2, got %lx\n", GetLastError()); + result = CryptDestroyHash(hHash); + ok(result, "Failed to destroy hash, got %lx\n", GetLastError());
/* Destroy the public key */ result = CryptDestroyKey(pubKey);
From: Sven Püschel <Sven\u2007Pschel@akarisu.de>
Finish the Hash before trying to sign it, as Windows will also allow this behaviour.
Signed-off-by: Sven Püschel <Sven Püschel@akarisu.de> --- dlls/dssenh/main.c | 6 ++++++ dlls/dssenh/tests/dssenh.c | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/dlls/dssenh/main.c b/dlls/dssenh/main.c index f6f01772d35..fa6993f9317 100644 --- a/dlls/dssenh/main.c +++ b/dlls/dssenh/main.c @@ -994,6 +994,12 @@ BOOL WINAPI CPSignHash( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD keyspec, const TRACE( "%p, %p, %lu, %s, %08lx, %p, %p\n", (void *)hprov, (void *)hhash, keyspec, debugstr_w(desc), flags, sig, siglen );
+ if (!hash->finished) + { + if (BCryptFinishHash( hash->handle, hash->value, hash->len, 0 )) return FALSE; + hash->finished = TRUE; + } + if (container->magic != MAGIC_CONTAINER || !container->sign_key) return FALSE; if (hash->magic != MAGIC_HASH) return FALSE;
diff --git a/dlls/dssenh/tests/dssenh.c b/dlls/dssenh/tests/dssenh.c index 2f9e491c0e0..29125386f79 100644 --- a/dlls/dssenh/tests/dssenh.c +++ b/dlls/dssenh/tests/dssenh.c @@ -937,7 +937,7 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test)
/* Verify signed hash 1 */ result = CryptVerifySignatureA(hHash, signValue1, sizeof(signValue1), pubKey, NULL, 0); - todo_wine ok(result, "Failed to verify signature, got %lx\n", GetLastError()); + ok(result, "Failed to verify signature, got %lx\n", GetLastError());
result = CryptDestroyHash(hHash); ok(result, "Failed to destroy hash, got %lx\n", GetLastError()); @@ -951,7 +951,7 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test)
/* Verify signed hash 2 */ result = CryptVerifySignatureA(hHash, signValue2, sizeof(signValue2), pubKey, NULL, 0); - todo_wine ok(result, "Failed to verify signature, got %lx\n", GetLastError()); + ok(result, "Failed to verify signature, got %lx\n", GetLastError());
result = CryptDestroyHash(hHash); ok(result, "Failed to destroy hash, got %lx\n", GetLastError());
From: Sven Püschel <Sven\u2007Pschel@akarisu.de>
Remove the use of signLen to store the input data length. The variable is used to store the generated signature length. Also using the ARRAY_SIZE macro instead of the signLen, as in case of the signLen returning an invalid value, we would compare or sign memory outside of the arrays (as the failing length test check won't abort the whole test).
Signed-off-by: Sven Püschel <Sven Püschel@akarisu.de> --- dlls/dssenh/tests/dssenh.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/dlls/dssenh/tests/dssenh.c b/dlls/dssenh/tests/dssenh.c index 29125386f79..f99cd937b50 100644 --- a/dlls/dssenh/tests/dssenh.c +++ b/dlls/dssenh/tests/dssenh.c @@ -860,12 +860,10 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test) HCRYPTKEY privKey = 0, pubKey = 0; BYTE pubKeyBuffer[512]; BYTE signValue1[40], signValue2[40]; + DWORD signLen; DWORD pubKeyLen; BOOL result;
- DWORD signLen1 = test->dataLen; - DWORD signLen2 = test->dataLen; - /* Get a private key of array specified ALG_ID */ result = CryptImportKey(hProv, test->privateKey, test->keyLen, 0, 0, &privKey); ok(result, "Failed to imported key, got %lx\n", GetLastError()); @@ -874,16 +872,17 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test) result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); ok(result, "Failed to create a hash, got %lx\n", GetLastError());
- result = CryptHashData(hHash, test->signData, signLen1, 0); + result = CryptHashData(hHash, test->signData, test->dataLen, 0); ok(result, "Failed to add data to hash, got %lx\n", GetLastError());
/* Sign hash 1 */ - signLen1 = 0; - result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, NULL, &signLen1); + signLen = 0; + result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, NULL, &signLen); ok(result, "Failed to get signature length, got %lx\n", GetLastError()); - ok(signLen1 == 40, "Expected a 40-byte signature, got %ld\n", signLen1); + ok(signLen == 40, "Expected a 40-byte signature, got %ld\n", signLen);
- result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, signValue1, &signLen1); + signLen = ARRAY_SIZE(signValue1); + result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, signValue1, &signLen); ok(result, "Failed to sign hash, got %lx\n", GetLastError());
result = CryptDestroyHash(hHash); @@ -893,16 +892,17 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test) result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); ok(result, "Failed to create a hash, got %lx\n", GetLastError());
- result = CryptHashData(hHash, test->signData, signLen2, 0); + result = CryptHashData(hHash, test->signData, test->dataLen, 0); ok(result, "Failed to add data to hash, got %lx\n", GetLastError());
/* Sign hash 2 */ - signLen2 = 0; - result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, NULL, &signLen2); + signLen = 0; + result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, NULL, &signLen); ok(result, "Failed to get signature length, got %lx\n", GetLastError()); - ok(signLen2 == 40, "Expected a 40-byte signature, got %ld\n", signLen2); + ok(signLen == 40, "Expected a 40-byte signature, got %ld\n", signLen);
- result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, signValue2, &signLen2); + signLen = ARRAY_SIZE(signValue2); + result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, signValue2, &signLen); ok(result, "Failed to sign hash, got %lx\n", GetLastError());
result = CryptDestroyHash(hHash); @@ -910,8 +910,8 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test)
/* Compare signatures to ensure they are both different, because every DSS signature should be different even if the input hash data is identical */ - ok(memcmp(signValue1, signValue2, signLen2), "Expected two different signatures from " - "the same hash input.\n"); + ok(memcmp(signValue1, signValue2, ARRAY_SIZE(signValue1)), + "Expected two different signatures from the same hash input.\n");
result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, NULL, &pubKeyLen); ok(result, "Failed to acquire public key length, got %lx\n", GetLastError());
From: Sven Püschel <Sven\u2007Pschel@akarisu.de>
Set 0xdeadbeef as the last error before exection of a function, as it is a common pattern to distinguish if the output was from the failing function or from the previous executed function.
Signed-off-by: Sven Püschel <Sven Püschel@akarisu.de> --- dlls/dssenh/tests/dssenh.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-)
diff --git a/dlls/dssenh/tests/dssenh.c b/dlls/dssenh/tests/dssenh.c index f99cd937b50..cc78eef1391 100644 --- a/dlls/dssenh/tests/dssenh.c +++ b/dlls/dssenh/tests/dssenh.c @@ -865,46 +865,57 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test) BOOL result;
/* Get a private key of array specified ALG_ID */ + SetLastError(0xdeadbeef); result = CryptImportKey(hProv, test->privateKey, test->keyLen, 0, 0, &privKey); ok(result, "Failed to imported key, got %lx\n", GetLastError());
/* Create hash object and add data for signature 1 */ + SetLastError(0xdeadbeef); result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); ok(result, "Failed to create a hash, got %lx\n", GetLastError());
+ SetLastError(0xdeadbeef); result = CryptHashData(hHash, test->signData, test->dataLen, 0); ok(result, "Failed to add data to hash, got %lx\n", GetLastError());
/* Sign hash 1 */ signLen = 0; + SetLastError(0xdeadbeef); result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, NULL, &signLen); ok(result, "Failed to get signature length, got %lx\n", GetLastError()); ok(signLen == 40, "Expected a 40-byte signature, got %ld\n", signLen);
signLen = ARRAY_SIZE(signValue1); + SetLastError(0xdeadbeef); result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, signValue1, &signLen); ok(result, "Failed to sign hash, got %lx\n", GetLastError());
+ SetLastError(0xdeadbeef); result = CryptDestroyHash(hHash); ok(result, "Failed to destroy hash, got %lx\n", GetLastError());
/* Create hash object and add data for signature 2 */ + SetLastError(0xdeadbeef); result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); ok(result, "Failed to create a hash, got %lx\n", GetLastError());
+ SetLastError(0xdeadbeef); result = CryptHashData(hHash, test->signData, test->dataLen, 0); ok(result, "Failed to add data to hash, got %lx\n", GetLastError());
/* Sign hash 2 */ signLen = 0; + SetLastError(0xdeadbeef); result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, NULL, &signLen); ok(result, "Failed to get signature length, got %lx\n", GetLastError()); ok(signLen == 40, "Expected a 40-byte signature, got %ld\n", signLen);
signLen = ARRAY_SIZE(signValue2); + SetLastError(0xdeadbeef); result = CryptSignHashA(hHash, AT_SIGNATURE, NULL, 0, signValue2, &signLen); ok(result, "Failed to sign hash, got %lx\n", GetLastError());
+ SetLastError(0xdeadbeef); result = CryptDestroyHash(hHash); ok(result, "Failed to destroy hash, got %lx\n", GetLastError());
@@ -913,50 +924,63 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test) ok(memcmp(signValue1, signValue2, ARRAY_SIZE(signValue1)), "Expected two different signatures from the same hash input.\n");
+ SetLastError(0xdeadbeef); result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, NULL, &pubKeyLen); ok(result, "Failed to acquire public key length, got %lx\n", GetLastError());
/* Export the public key */ + SetLastError(0xdeadbeef); result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, pubKeyBuffer, &pubKeyLen); ok(result, "Failed to export public key, got %lx\n", GetLastError());
/* Destroy the private key */ + SetLastError(0xdeadbeef); result = CryptDestroyKey(privKey); ok(result, "Failed to destroy private key, got %lx\n", GetLastError());
/* Import the public key we obtained earlier */ + SetLastError(0xdeadbeef); result = CryptImportKey(hProv, pubKeyBuffer, pubKeyLen, 0, 0, &pubKey); ok(result, "Failed to import public key, got %lx\n", GetLastError());
+ SetLastError(0xdeadbeef); result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); ok(result, "Failed to create hash, got %lx\n", GetLastError());
/* Hash the data to compare with the signed hash */ + SetLastError(0xdeadbeef); result = CryptHashData(hHash, test->signData, test->dataLen, 0); ok(result, "Failed to add data to hash, got %lx\n", GetLastError());
/* Verify signed hash 1 */ + SetLastError(0xdeadbeef); result = CryptVerifySignatureA(hHash, signValue1, sizeof(signValue1), pubKey, NULL, 0); ok(result, "Failed to verify signature, got %lx\n", GetLastError());
+ SetLastError(0xdeadbeef); result = CryptDestroyHash(hHash); ok(result, "Failed to destroy hash, got %lx\n", GetLastError());
+ SetLastError(0xdeadbeef); result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); ok(result, "Failed to create hash, got %lx\n", GetLastError());
/* Hash the data to compare with the signed hash */ + SetLastError(0xdeadbeef); result = CryptHashData(hHash, test->signData, test->dataLen, 0); ok(result, "Failed to add data to hash, got %lx\n", GetLastError());
/* Verify signed hash 2 */ + SetLastError(0xdeadbeef); result = CryptVerifySignatureA(hHash, signValue2, sizeof(signValue2), pubKey, NULL, 0); ok(result, "Failed to verify signature, got %lx\n", GetLastError());
+ SetLastError(0xdeadbeef); result = CryptDestroyHash(hHash); ok(result, "Failed to destroy hash, got %lx\n", GetLastError());
/* Destroy the public key */ + SetLastError(0xdeadbeef); result = CryptDestroyKey(pubKey); ok(result, "Failed to destroy public key, got %lx\n", GetLastError()); } @@ -968,26 +992,29 @@ static void test_verify_signature(void) int i, j;
/* acquire base dss provider */ + SetLastError(0xdeadbeef); result = CryptAcquireContextA(&hProv[0], NULL, MS_DEF_DSS_PROV_A, PROV_DSS, 0); if(!result) { skip("DSSENH is currently not available, skipping signature verification tests.\n"); return; } - ok(result, "Failed to acquire CSP.\n"); + ok(result, "Failed to acquire CSP, got %lx\n", GetLastError());
/* acquire diffie hellman dss provider */ + SetLastError(0xdeadbeef); result = CryptAcquireContextA(&hProv[1], NULL, MS_DEF_DSS_DH_PROV_A, PROV_DSS_DH, 0); - ok(result, "Failed to acquire CSP.\n"); + ok(result, "Failed to acquire CSP, got %lx\n", GetLastError());
/* acquire enhanced dss provider */ SetLastError(0xdeadbeef); result = CryptAcquireContextA(&hProv[2], NULL, MS_ENH_DSS_DH_PROV_A, PROV_DSS_DH, 0); - ok(result, "Failed to acquire CSP.\n"); + ok(result, "Failed to acquire CSP, got %lx\n", GetLastError());
/* acquire schannel dss provider */ + SetLastError(0xdeadbeef); result = CryptAcquireContextA(&hProv[3], NULL, MS_DEF_DH_SCHANNEL_PROV_A, PROV_DH_SCHANNEL, 0); - ok(result, "Failed to acquire CSP.\n"); + ok(result, "Failed to acquire CSP, got %lx\n", GetLastError());
for (i = 0; i < ARRAY_SIZE(hProv); i++) { @@ -996,8 +1023,9 @@ static void test_verify_signature(void) test_signhash(hProv[i], &dssSign_data[j]); }
+ SetLastError(0xdeadbeef); result = CryptReleaseContext(hProv[i], 0); - ok(result, "Failed to release CSP provider %d.\n", i); + ok(result, "Failed to release CSP provider %d, got %lx\n", i, GetLastError()); } }
From: Sven Püschel <Sven\u2007Pschel@akarisu.de>
Don't verify the second signature, as the signature has identical inputs as the first signature. The reason for two identical signature inputs is to test the same input generates different signatures.
Signed-off-by: Sven Püschel <Sven Püschel@akarisu.de> --- dlls/dssenh/tests/dssenh.c | 18 ------------------ 1 file changed, 18 deletions(-)
diff --git a/dlls/dssenh/tests/dssenh.c b/dlls/dssenh/tests/dssenh.c index cc78eef1391..dd347ed3041 100644 --- a/dlls/dssenh/tests/dssenh.c +++ b/dlls/dssenh/tests/dssenh.c @@ -961,24 +961,6 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test) result = CryptDestroyHash(hHash); ok(result, "Failed to destroy hash, got %lx\n", GetLastError());
- SetLastError(0xdeadbeef); - result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); - ok(result, "Failed to create hash, got %lx\n", GetLastError()); - - /* Hash the data to compare with the signed hash */ - SetLastError(0xdeadbeef); - result = CryptHashData(hHash, test->signData, test->dataLen, 0); - ok(result, "Failed to add data to hash, got %lx\n", GetLastError()); - - /* Verify signed hash 2 */ - SetLastError(0xdeadbeef); - result = CryptVerifySignatureA(hHash, signValue2, sizeof(signValue2), pubKey, NULL, 0); - ok(result, "Failed to verify signature, got %lx\n", GetLastError()); - - SetLastError(0xdeadbeef); - result = CryptDestroyHash(hHash); - ok(result, "Failed to destroy hash, got %lx\n", GetLastError()); - /* Destroy the public key */ SetLastError(0xdeadbeef); result = CryptDestroyKey(pubKey);
From: Sven Püschel <Sven\u2007Pschel@akarisu.de>
Separate the exporting of the public key out of the signhash test. As VerifySignature can also use a privete key, the conversion of the private key to a public key is removed.
The public key export is kept and moved to a separate test. A precalculated public key is used to check, that the output format is correct.
Furthermore change the test_verify_signature -> test_signature as the test only tested primarely the SignHash function and only used VerifySignature to check the generated signature is valid.
Signed-off-by: Sven Püschel <Sven Püschel@akarisu.de> --- dlls/dssenh/tests/dssenh.c | 161 +++++++++++++++++++++++++++++-------- 1 file changed, 127 insertions(+), 34 deletions(-)
diff --git a/dlls/dssenh/tests/dssenh.c b/dlls/dssenh/tests/dssenh.c index dd347ed3041..9eaa843907b 100644 --- a/dlls/dssenh/tests/dssenh.c +++ b/dlls/dssenh/tests/dssenh.c @@ -791,7 +791,9 @@ static void test_cipher_modes(const struct ciphermode_test *tests, int testLen)
struct signature_test { const BYTE *privateKey; - DWORD keyLen; + DWORD privateKeyLen; + const BYTE *publicKey; + DWORD publicKeyLen; BYTE* signData; DWORD dataLen; }; @@ -823,6 +825,37 @@ static const BYTE AT_SIGNATURE_PrivateKey[] = { 0x34,0x05,0xeb,0x98,0x3b,0x5f,0x2f,0x11, 0xa4,0xa5,0xc4,0xff,0xfb,0x22,0x7c,0x54 };
+static const BYTE AT_SIGNATURE_PublicKey[] = { +0x06,0x02,0x00,0x00,0x00,0x22,0x00,0x00, 0x44,0x53,0x53,0x31,0x00,0x04,0x00,0x00, +0x01,0xd1,0xfc,0x7a,0x70,0x53,0xb2,0x48, 0x70,0x23,0x19,0x1f,0x3c,0xe1,0x26,0x14, +0x7e,0x9f,0x0f,0x7f,0x33,0x5e,0x2b,0xf7, 0xca,0x01,0x74,0x8c,0xb4,0xfd,0xf6,0x44, +0x95,0x35,0x56,0xaa,0x4d,0x62,0x48,0xe2, 0xd1,0xa2,0x7e,0x6e,0xeb,0xd6,0xcc,0x7c, +0xe8,0xfd,0x21,0x9a,0xa2,0xfd,0x7a,0x9d, 0x1a,0x38,0x69,0x87,0x39,0x5a,0x91,0xc0, +0x52,0x2b,0x9f,0x2a,0x54,0x78,0x37,0x82, 0x9a,0x70,0x57,0xab,0xec,0x93,0x8e,0xac, +0x73,0x04,0xe8,0x53,0x72,0x72,0x32,0xc6, 0xcb,0xef,0x47,0x98,0x3c,0x56,0x49,0x62, +0xcb,0xbb,0xe7,0x34,0x84,0xa6,0x72,0x3a, 0xbe,0x26,0x46,0x86,0xca,0xcb,0x35,0x62, +0x4f,0x19,0x18,0x0b,0xb0,0x78,0xae,0xd5, 0x42,0xdf,0x26,0xdb,0x85,0x63,0x77,0x85, +0x01,0x3b,0x32,0xbe,0x5c,0xf8,0x05,0xc8, 0xde,0x17,0x7f,0xb9,0x03,0x82,0xfa,0xf1, +0x9e,0x32,0x73,0xfa,0x8d,0xea,0xa3,0x30, 0x48,0xe2,0xdf,0x5a,0xcb,0x83,0x3d,0xff, +0x56,0xe9,0xc0,0x94,0xf8,0x6d,0xb3,0xaf, 0x4a,0x97,0xb9,0x43,0x0e,0xd4,0x28,0x98, +0x57,0x2e,0x3a,0xca,0xde,0x6f,0x45,0x0d, 0xfb,0x58,0xec,0x78,0x34,0x2e,0x46,0x4d, +0xfe,0x98,0x02,0xbb,0xef,0x07,0x1a,0x13, 0xb6,0xc2,0x2c,0x06,0xd9,0x0c,0xc4,0xb0, +0x4c,0x3a,0xfc,0x01,0x63,0xb5,0x5a,0x5d, 0x2d,0x9c,0x47,0x04,0x67,0x51,0xf2,0x52, +0xf5,0x82,0x36,0xeb,0x6e,0x66,0x58,0x4c, 0x10,0x2c,0x29,0x72,0x4a,0x6f,0x6b,0x6c, +0xe0,0x93,0x31,0x42,0xf6,0xda,0xfa,0x5b, 0x22,0x43,0x9b,0x1a,0x98,0x71,0xe7,0x41, +0x74,0xe9,0x12,0xa4,0x1f,0x27,0x0a,0x63, 0x94,0x49,0xd7,0xad,0xa5,0xc4,0x5c,0xc3, +0xc9,0x70,0xb3,0x7b,0xd0,0x5b,0xdd,0x7c, 0x02,0x99,0x77,0x52,0x19,0x35,0x3d,0xc7, +0x1f,0xc5,0x73,0xcb,0xea,0x06,0x3f,0x96, 0x86,0x86,0xa3,0xc2,0x46,0xc8,0x39,0xba, +0xe7,0xee,0xf9,0x00,0x9c,0x04,0x32,0xac, 0x19,0xcf,0x74,0xee,0x33,0x16,0x8c,0x99, +0xdb,0xf5,0x46,0x90,0x75,0x50,0x22,0x0d, 0xe0,0x8e,0x47,0xf1,0xd1,0xfa,0xc4,0x51, +0x90,0xb1,0x33,0x7f,0x41,0xc7,0x23,0xb9, 0xe4,0x2c,0xa4,0xca,0x77,0x07,0xe5,0xf8, +0x30,0xdf,0xf5,0xdf,0x6d,0x63,0x38,0x82, 0x24,0x5f,0xb3,0x81,0x37,0x53,0x9e,0x47, +0x01,0x40,0x48,0xa6,0x73,0xa3,0xbc,0x31, 0xd4,0xa6,0xc6,0x4f,0x90,0xa6,0x96,0x1b, +0xc7,0x1d,0xa1,0xc5,0x91,0xb1,0x7d,0x81, 0x97,0x73,0x93,0x2b,0x9d,0xb4,0x8f,0x2e, +0x8c,0xe9,0xe0,0x3e,0xf1,0x01,0x00,0x00, 0x93,0xd5,0xa3,0xe4,0x34,0x05,0xeb,0x98, +0x3b,0x5f,0x2f,0x11,0xa4,0xa5,0xc4,0xff, 0xfb,0x22,0x7c,0x54 +}; + static const BYTE DSS_SIGN_PrivateKey[] = { 0x07,0x02,0x00,0x00,0x00,0x22,0x00,0x00, 0x44,0x53,0x53,0x32,0x00,0x04,0x00,0x00, 0xf7,0x9e,0x89,0xa2,0xcd,0x0b,0x61,0xe0, 0xa3,0xe5,0x86,0x6b,0x04,0x98,0x80,0x9c, @@ -847,26 +880,71 @@ static const BYTE DSS_SIGN_PrivateKey[] = { 0xdc,0x68,0xae,0x03,0xad,0xf7,0xb9,0xca, 0x0d,0xca,0x27,0xef,0x76,0xda,0xe5,0xcb };
+static const BYTE DSS_SIGN_PublicKey[] = { +0x06,0x02,0x00,0x00,0x00,0x22,0x00,0x00, 0x44,0x53,0x53,0x31,0x00,0x04,0x00,0x00, +0xf7,0x9e,0x89,0xa2,0xcd,0x0b,0x61,0xe0, 0xa3,0xe5,0x86,0x6b,0x04,0x98,0x80,0x9c, +0x36,0xc2,0x76,0x4e,0x22,0xd5,0x21,0xaa, 0x03,0x59,0xf4,0x95,0xb2,0x11,0x1f,0xa0, +0xc5,0xfc,0xbe,0x5d,0x1f,0x2e,0xf4,0x36, 0x40,0x48,0x81,0x51,0xb4,0x25,0x86,0xe0, +0x98,0xc8,0x4d,0xa0,0x08,0x99,0xa1,0x00, 0x45,0x1b,0x75,0x6b,0x0d,0x3e,0x7d,0x13, +0xd7,0x23,0x32,0x08,0xf4,0xeb,0x27,0x9e, 0xe9,0x05,0x5d,0xac,0xc8,0xd7,0x62,0x13, +0x43,0x2a,0x69,0x65,0xdc,0xe6,0x52,0xf9, 0x6a,0xe8,0x07,0xcf,0x3e,0xf8,0xc9,0x1d, +0x8e,0xdf,0x4e,0x9a,0xd1,0x48,0xf2,0xda, 0x9e,0xfa,0x92,0x5f,0x6d,0x57,0xf2,0xa4, +0x5f,0x60,0xce,0x92,0x7a,0x80,0x39,0x21, 0x9d,0x4d,0x3a,0x60,0x76,0x4c,0x2f,0xc0, +0xd3,0xf4,0x14,0x03,0x03,0x05,0xa9,0x0c, 0x57,0x72,0x4f,0x60,0x3c,0xe9,0x09,0x54, +0x0c,0x2a,0x56,0xda,0x30,0xb6,0x2e,0x6a, 0x96,0x7f,0x4a,0x8f,0x83,0x0a,0xb9,0x5c, +0xff,0x84,0xfa,0x0e,0x85,0x81,0x46,0xe9, 0x1c,0xbb,0x78,0x1d,0x78,0x25,0x00,0x8c, +0x78,0x56,0x68,0xe4,0x06,0x37,0xcc,0xc7, 0x22,0x27,0xee,0x0e,0xf8,0xca,0xfc,0x72, +0x0e,0xd6,0xe6,0x90,0x30,0x66,0x22,0xe2, 0xa2,0xbf,0x2e,0x35,0xbc,0xe7,0xd6,0x24, +0x6a,0x3d,0x06,0xe8,0xe2,0xbe,0x96,0xcc, 0x9a,0x08,0x06,0xb5,0x44,0x83,0xb0,0x7b, +0x70,0x7b,0x2d,0xc3,0x46,0x9a,0xc5,0x6b, 0xd9,0xde,0x9a,0x24,0xc9,0xea,0xf5,0x28, +0x69,0x8a,0x17,0xca,0xdf,0xc4,0x0e,0xa3, 0x08,0x22,0x99,0xd2,0x27,0xdc,0x9b,0x08, +0x54,0x4a,0xf9,0xb1,0x74,0x3a,0x9d,0xd9, 0xc2,0x82,0x21,0xf5,0x97,0x04,0x90,0x37, +0xda,0xd9,0xdc,0x19,0x88,0x7c,0x8b,0xc7, 0xdb,0xb5,0xea,0x9e,0x96,0x03,0x11,0x49, +0x07,0xa3,0xe2,0x3d,0xbe,0xa1,0xf3,0xaf, 0x26,0xc4,0xbf,0x39,0xa9,0xcd,0x69,0xd1, +0x40,0x07,0x88,0x21,0x58,0xa4,0xcf,0xb3, 0x0a,0x9b,0x7a,0xea,0x89,0x10,0x8a,0x6a, +0x98,0x6f,0xfe,0x30,0xf2,0xc2,0xd3,0x88, 0x52,0x57,0x02,0x53,0x4f,0x0d,0x03,0x08, +0x48,0x2e,0x82,0xad,0x7a,0x0a,0x2b,0xeb, 0xe2,0xd7,0xa2,0x3e,0x64,0xbc,0xeb,0x49, +0xe1,0x14,0x2f,0x0c,0x84,0xf7,0xc3,0xb9, 0x60,0x2f,0x95,0x4f,0x7a,0x3b,0xcb,0xa4, +0x5a,0x3a,0x6a,0x20,0xb3,0x9c,0xaf,0xba, 0xe1,0x94,0xe2,0x57,0xfc,0xc8,0x4e,0x07, +0x29,0xa4,0x25,0xbe,0x1f,0x7a,0x4c,0xe8, 0x61,0x23,0xc9,0x5d,0x8d,0x11,0x4d,0x5d, +0xba,0xfa,0x47,0x5d,0x3c,0x00,0x00,0x00, 0x16,0xe1,0xac,0x17,0xdc,0x68,0xae,0x03, +0xad,0xf7,0xb9,0xca,0x0d,0xca,0x27,0xef, 0x76,0xda,0xe5,0xcb +}; + static const struct signature_test dssSign_data[] = { - {AT_SIGNATURE_PrivateKey, sizeof(AT_SIGNATURE_PrivateKey), (BYTE *)dataToSign1, sizeof(dataToSign1)}, - {AT_SIGNATURE_PrivateKey, sizeof(AT_SIGNATURE_PrivateKey), (BYTE *)dataToSign2, sizeof(dataToSign2)}, - {DSS_SIGN_PrivateKey, sizeof(DSS_SIGN_PrivateKey), (BYTE *)dataToSign1, sizeof(dataToSign1)}, - {DSS_SIGN_PrivateKey, sizeof(DSS_SIGN_PrivateKey), (BYTE *)dataToSign2, sizeof(dataToSign2)}, + { + .privateKey = AT_SIGNATURE_PrivateKey, .privateKeyLen = sizeof(AT_SIGNATURE_PrivateKey), + .publicKey = AT_SIGNATURE_PublicKey, .publicKeyLen = sizeof(AT_SIGNATURE_PublicKey), + .signData = (BYTE *)dataToSign1, .dataLen = sizeof(dataToSign1), + }, + { + .privateKey = AT_SIGNATURE_PrivateKey, .privateKeyLen = sizeof(AT_SIGNATURE_PrivateKey), + .publicKey = AT_SIGNATURE_PublicKey, .publicKeyLen = sizeof(AT_SIGNATURE_PublicKey), + .signData = (BYTE *)dataToSign2, .dataLen = sizeof(dataToSign2), + }, + { + .privateKey = DSS_SIGN_PrivateKey, .privateKeyLen = sizeof(DSS_SIGN_PrivateKey), + .publicKey = DSS_SIGN_PublicKey, .publicKeyLen = sizeof(DSS_SIGN_PublicKey), + .signData = (BYTE *)dataToSign1, .dataLen = sizeof(dataToSign1), + }, + { + .privateKey = DSS_SIGN_PrivateKey, .privateKeyLen = sizeof(DSS_SIGN_PrivateKey), + .publicKey = DSS_SIGN_PublicKey, .publicKeyLen = sizeof(DSS_SIGN_PublicKey), + .signData = (BYTE *)dataToSign2, .dataLen = sizeof(dataToSign2), + }, };
static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test) { + HCRYPTKEY privKey = 0; HCRYPTHASH hHash; - HCRYPTKEY privKey = 0, pubKey = 0; - BYTE pubKeyBuffer[512]; BYTE signValue1[40], signValue2[40]; DWORD signLen; - DWORD pubKeyLen; BOOL result;
/* Get a private key of array specified ALG_ID */ SetLastError(0xdeadbeef); - result = CryptImportKey(hProv, test->privateKey, test->keyLen, 0, 0, &privKey); + result = CryptImportKey(hProv, test->privateKey, test->privateKeyLen, 0, 0, &privKey); ok(result, "Failed to imported key, got %lx\n", GetLastError());
/* Create hash object and add data for signature 1 */ @@ -924,25 +1002,6 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test) ok(memcmp(signValue1, signValue2, ARRAY_SIZE(signValue1)), "Expected two different signatures from the same hash input.\n");
- SetLastError(0xdeadbeef); - result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, NULL, &pubKeyLen); - ok(result, "Failed to acquire public key length, got %lx\n", GetLastError()); - - /* Export the public key */ - SetLastError(0xdeadbeef); - result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, pubKeyBuffer, &pubKeyLen); - ok(result, "Failed to export public key, got %lx\n", GetLastError()); - - /* Destroy the private key */ - SetLastError(0xdeadbeef); - result = CryptDestroyKey(privKey); - ok(result, "Failed to destroy private key, got %lx\n", GetLastError()); - - /* Import the public key we obtained earlier */ - SetLastError(0xdeadbeef); - result = CryptImportKey(hProv, pubKeyBuffer, pubKeyLen, 0, 0, &pubKey); - ok(result, "Failed to import public key, got %lx\n", GetLastError()); - SetLastError(0xdeadbeef); result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); ok(result, "Failed to create hash, got %lx\n", GetLastError()); @@ -954,20 +1013,53 @@ static void test_signhash(HCRYPTPROV hProv, const struct signature_test *test)
/* Verify signed hash 1 */ SetLastError(0xdeadbeef); - result = CryptVerifySignatureA(hHash, signValue1, sizeof(signValue1), pubKey, NULL, 0); + result = CryptVerifySignatureA(hHash, signValue1, sizeof(signValue1), privKey, NULL, 0); ok(result, "Failed to verify signature, got %lx\n", GetLastError());
SetLastError(0xdeadbeef); result = CryptDestroyHash(hHash); ok(result, "Failed to destroy hash, got %lx\n", GetLastError());
- /* Destroy the public key */ + /* Destroy the private key */ + SetLastError(0xdeadbeef); + result = CryptDestroyKey(privKey); + ok(result, "Failed to destroy private key, got %lx\n", GetLastError()); +} + +static void test_exportkey(HCRYPTPROV hProv, const struct signature_test *test) +{ + HCRYPTKEY privKey = 0; + BYTE pubKeyBuffer[512]; + DWORD pubKeyLen; + BOOL result; + + /* Get a private key of array specified ALG_ID */ + SetLastError(0xdeadbeef); + result = CryptImportKey(hProv, test->privateKey, test->privateKeyLen, 0, 0, &privKey); + ok(result, "Failed to imported key, got %lx\n", GetLastError()); + + SetLastError(0xdeadbeef); + result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, NULL, &pubKeyLen); + ok(result, "Failed to acquire public key length, got %lx\n", GetLastError()); + ok(pubKeyLen == test->publicKeyLen, + "Expected the public key to be %ld bytes long, but got %ld bytes\n", test->publicKeyLen, pubKeyLen); + + /* Export the public key */ + pubKeyLen = ARRAY_SIZE(pubKeyBuffer); SetLastError(0xdeadbeef); - result = CryptDestroyKey(pubKey); - ok(result, "Failed to destroy public key, got %lx\n", GetLastError()); + result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, pubKeyBuffer, &pubKeyLen); + ok(result, "Failed to export public key, got %lx\n", GetLastError()); + + ok(memcmp(test->publicKey, pubKeyBuffer, test->publicKeyLen) == 0, + "The exported public key doesn't match the expected public key\n"); + + /* Destroy the private key */ + SetLastError(0xdeadbeef); + result = CryptDestroyKey(privKey); + ok(result, "Failed to destroy private key, got %lx\n", GetLastError()); }
-static void test_verify_signature(void) +static void test_signature(void) { HCRYPTPROV hProv[4]; BOOL result; @@ -1003,6 +1095,7 @@ static void test_verify_signature(void) for (j = 0; j < ARRAY_SIZE(dssSign_data); j++) { test_signhash(hProv[i], &dssSign_data[j]); + test_exportkey(hProv[i], &dssSign_data[j]); }
SetLastError(0xdeadbeef); @@ -1542,7 +1635,7 @@ START_TEST(dssenh) test_hash(hash_data, ARRAY_SIZE(hash_data)); test_data_encryption(encrypt_data, ARRAY_SIZE(encrypt_data)); test_cipher_modes(ciphermode_data, ARRAY_SIZE(ciphermode_data)); - test_verify_signature(); + test_signature(); test_key_exchange(); test_duplicate_hash(); test_userkey();
From: Sven Püschel <Sven\u2007Pschel@akarisu.de>
Add a test for the VerifySignatureA function. Currently the tests only use VerifySignatureA to verify the signature generation functions. But this doesn't test if the signature format is correct. Therefore including signatures generated on a Windows 10 machine test run to check that Wine can also verify these correctly.
As wine currently fails to verify these signatures, the tests are marked as todo_wine.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55936 Signed-off-by: Sven Püschel <Sven Püschel@akarisu.de> --- dlls/dssenh/tests/dssenh.c | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+)
diff --git a/dlls/dssenh/tests/dssenh.c b/dlls/dssenh/tests/dssenh.c index 9eaa843907b..6931554fc65 100644 --- a/dlls/dssenh/tests/dssenh.c +++ b/dlls/dssenh/tests/dssenh.c @@ -796,6 +796,8 @@ struct signature_test { DWORD publicKeyLen; BYTE* signData; DWORD dataLen; + const BYTE* signature; + DWORD signatureLen; };
static const char dataToSign1[] = "With DSSENH implemented, applications requiring it will now work."; @@ -911,26 +913,54 @@ static const BYTE DSS_SIGN_PublicKey[] = { 0xad,0xf7,0xb9,0xca,0x0d,0xca,0x27,0xef, 0x76,0xda,0xe5,0xcb };
+static const BYTE AT_Signature1[] = { +0x43,0x6d,0x82,0xf9,0xc1,0x9d,0x46,0x36, 0x25,0x87,0x6f,0x3c,0xd5,0x1e,0xd2,0xc9, +0xb1,0x7e,0x08,0x4e,0x98,0x8b,0x3c,0x2e, 0x39,0x13,0xa2,0xf0,0xab,0x1d,0x78,0x99, +0xa8,0x2a,0x0e,0x3b,0x83,0x15,0xf5,0x3c +}; + +static const BYTE AT_Signature2[] = { +0xd8,0x65,0x67,0xf8,0x3b,0x67,0x4c,0xb6, 0x2f,0x54,0x1f,0x27,0xf1,0xbe,0xb6,0x88, +0xf1,0x49,0xd3,0x2a,0x6b,0xf6,0x9b,0x91, 0x58,0x07,0x5e,0x42,0xe2,0x95,0x07,0x55, +0xfb,0x60,0xe9,0x00,0x90,0x99,0x8f,0x5d +}; + +static const BYTE DSS_Signature1[] = { +0xdb,0x43,0x66,0xa8,0x66,0x1e,0xc1,0xaf, 0x07,0xaf,0x25,0x86,0x3f,0x1d,0x06,0x6e, +0xf3,0x68,0x66,0x61,0xaf,0x68,0x43,0x7a, 0xe3,0x63,0xc8,0x0f,0x38,0x38,0xe9,0x60, +0x1f,0x9c,0x51,0x53,0xdd,0x3f,0x05,0x35 +}; + +static const BYTE DSS_Signature2[] = { +0xb6,0x9c,0x92,0x71,0x2b,0x6d,0x91,0x1e, 0x17,0xa3,0x2a,0x67,0x15,0x87,0x4c,0xd4, +0x65,0x88,0x7f,0x99,0x2f,0x61,0x02,0x87, 0xcd,0x8e,0x63,0x81,0x2f,0xcb,0x2a,0x82, +0x07,0x97,0xf4,0xf3,0xfe,0x42,0x66,0x0a +}; + static const struct signature_test dssSign_data[] = { { .privateKey = AT_SIGNATURE_PrivateKey, .privateKeyLen = sizeof(AT_SIGNATURE_PrivateKey), .publicKey = AT_SIGNATURE_PublicKey, .publicKeyLen = sizeof(AT_SIGNATURE_PublicKey), .signData = (BYTE *)dataToSign1, .dataLen = sizeof(dataToSign1), + .signature = AT_Signature1, .signatureLen = sizeof(AT_Signature1), }, { .privateKey = AT_SIGNATURE_PrivateKey, .privateKeyLen = sizeof(AT_SIGNATURE_PrivateKey), .publicKey = AT_SIGNATURE_PublicKey, .publicKeyLen = sizeof(AT_SIGNATURE_PublicKey), .signData = (BYTE *)dataToSign2, .dataLen = sizeof(dataToSign2), + .signature = AT_Signature2, .signatureLen = sizeof(AT_Signature2), }, { .privateKey = DSS_SIGN_PrivateKey, .privateKeyLen = sizeof(DSS_SIGN_PrivateKey), .publicKey = DSS_SIGN_PublicKey, .publicKeyLen = sizeof(DSS_SIGN_PublicKey), .signData = (BYTE *)dataToSign1, .dataLen = sizeof(dataToSign1), + .signature = DSS_Signature1, .signatureLen = sizeof(DSS_Signature1), }, { .privateKey = DSS_SIGN_PrivateKey, .privateKeyLen = sizeof(DSS_SIGN_PrivateKey), .publicKey = DSS_SIGN_PublicKey, .publicKeyLen = sizeof(DSS_SIGN_PublicKey), .signData = (BYTE *)dataToSign2, .dataLen = sizeof(dataToSign2), + .signature = DSS_Signature2, .signatureLen = sizeof(DSS_Signature2), }, };
@@ -1059,6 +1089,41 @@ static void test_exportkey(HCRYPTPROV hProv, const struct signature_test *test) ok(result, "Failed to destroy private key, got %lx\n", GetLastError()); }
+static void test_verifysignature(HCRYPTPROV hProv, const struct signature_test *test) +{ + HCRYPTKEY pubKey = 0; + HCRYPTHASH hHash; + BOOL result; + + /* Get a public key of array specified ALG_ID */ + SetLastError(0xdeadbeef); + result = CryptImportKey(hProv, test->publicKey, test->publicKeyLen, 0, 0, &pubKey); + ok(result, "Failed to imported key, got %lx\n", GetLastError()); + + SetLastError(0xdeadbeef); + result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); + ok(result, "Failed to create hash, got %lx\n", GetLastError()); + + /* Hash the data to compare with the signed hash */ + SetLastError(0xdeadbeef); + result = CryptHashData(hHash, test->signData, test->dataLen, 0); + ok(result, "Failed to add data to hash, got %lx\n", GetLastError()); + + /* Verify signed hash */ + SetLastError(0xdeadbeef); + result = CryptVerifySignatureA(hHash, test->signature, test->signatureLen, pubKey, NULL, 0); + todo_wine ok(result, "Failed to verify signature, got %lx\n", GetLastError()); + + SetLastError(0xdeadbeef); + result = CryptDestroyHash(hHash); + ok(result, "Failed to destroy hash, got %lx\n", GetLastError()); + + /* Destroy the public key */ + SetLastError(0xdeadbeef); + result = CryptDestroyKey(pubKey); + ok(result, "Failed to destroy public key, got %lx\n", GetLastError()); +} + static void test_signature(void) { HCRYPTPROV hProv[4]; @@ -1096,6 +1161,7 @@ static void test_signature(void) { test_signhash(hProv[i], &dssSign_data[j]); test_exportkey(hProv[i], &dssSign_data[j]); + test_verifysignature(hProv[i], &dssSign_data[j]); }
SetLastError(0xdeadbeef);
From: Sven Püschel <Sven\u2007Pschel@akarisu.de>
Swap the endianess of the r and s integers of the signature. These are expected to be little-endian in the dssenh API, but the BCrypt API uses big endian integers.
Link: https://learn.microsoft.com/en-us/windows/win32/seccrypto/dss-provider-key-b... Link: https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_... Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55936 Signed-off-by: Sven Püschel <Sven Püschel@akarisu.de> --- dlls/dssenh/main.c | 39 +++++++++++++++++++++++++++++++++++--- dlls/dssenh/tests/dssenh.c | 2 +- 2 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/dlls/dssenh/main.c b/dlls/dssenh/main.c index fa6993f9317..62c02b34e36 100644 --- a/dlls/dssenh/main.c +++ b/dlls/dssenh/main.c @@ -989,7 +989,8 @@ BOOL WINAPI CPSignHash( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD keyspec, const { struct container *container = (struct container *)hprov; struct hash *hash = (struct hash *)hhash; - ULONG len; + ULONG len, i; + BYTE temp;
TRACE( "%p, %p, %lu, %s, %08lx, %p, %p\n", (void *)hprov, (void *)hhash, keyspec, debugstr_w(desc), flags, sig, siglen ); @@ -1010,12 +1011,31 @@ BOOL WINAPI CPSignHash( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD keyspec, const return TRUE; }
- return !BCryptSignHash( container->sign_key->handle, NULL, hash->value, hash->len, sig, *siglen, siglen, 0 ); + if (BCryptSignHash( container->sign_key->handle, NULL, hash->value, hash->len, sig, *siglen, siglen, 0 )) + { + return FALSE; + } + + /* Swap the r and s integers in the signature from big-endian to little-endian */ + for (i = 0; i < len / 4; i++) { + /* r */ + temp = sig[i]; + sig[i] = sig[len / 2 - 1 - i]; + sig[len / 2 - 1 - i] = temp; + /* s */ + temp = sig[len / 2 + i]; + sig[len / 2 + i] = sig[len - 1 - i]; + sig[len - 1 - i] = temp; + } + + return TRUE; }
BOOL WINAPI CPVerifySignature( HCRYPTPROV hprov, HCRYPTHASH hhash, const BYTE *sig, DWORD siglen, HCRYPTKEY hpubkey, const WCHAR *desc, DWORD flags ) { + UCHAR signature[40]; + DWORD i; struct hash *hash = (struct hash *)hhash; struct key *key = (struct key *)hpubkey;
@@ -1029,11 +1049,24 @@ BOOL WINAPI CPVerifySignature( HCRYPTPROV hprov, HCRYPTHASH hhash, const BYTE *s return FALSE; }
+ if (siglen > sizeof(signature)) + { + FIXME( "signature longer than 40 bytes is not supported\n"); + return FALSE; + } + + /* Swap the r and s integers in the signature from little-endian to big-endian */ + for (i = 0; i < siglen / 2; i++) + { + signature[i] = sig[siglen / 2 - 1 - i]; /* r */ + signature[siglen / 2 + i] = sig[siglen - 1 - i]; /* s */ + } + if (!hash->finished) { if (BCryptFinishHash( hash->handle, hash->value, hash->len, 0 )) return FALSE; hash->finished = TRUE; }
- return !BCryptVerifySignature( key->handle, NULL, hash->value, hash->len, (UCHAR *)sig, siglen, 0 ); + return !BCryptVerifySignature( key->handle, NULL, hash->value, hash->len, signature, siglen, 0 ); } diff --git a/dlls/dssenh/tests/dssenh.c b/dlls/dssenh/tests/dssenh.c index 6931554fc65..75fc88fe623 100644 --- a/dlls/dssenh/tests/dssenh.c +++ b/dlls/dssenh/tests/dssenh.c @@ -1112,7 +1112,7 @@ static void test_verifysignature(HCRYPTPROV hProv, const struct signature_test * /* Verify signed hash */ SetLastError(0xdeadbeef); result = CryptVerifySignatureA(hHash, test->signature, test->signatureLen, pubKey, NULL, 0); - todo_wine ok(result, "Failed to verify signature, got %lx\n", GetLastError()); + ok(result, "Failed to verify signature, got %lx\n", GetLastError());
SetLastError(0xdeadbeef); result = CryptDestroyHash(hHash);
Looks good, thanks!
This merge request was approved by Hans Leidekker.