diff --git a/dlls/dssenh/tests/dssenh.c b/dlls/dssenh/tests/dssenh.c index 1553ed115dd..6576f4dbec5 100644 --- a/dlls/dssenh/tests/dssenh.c +++ b/dlls/dssenh/tests/dssenh.c @@ -742,6 +742,256 @@ static void test_cipher_modes(const struct ciphermode_test *tests, int testLen) ok(result, "Expected release of the provider.\n"); } +struct signature_test { + const BYTE *privateKey; + DWORD keyLen; + BYTE* signData; + 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 BYTE AT_SIGNATURE_PrivateKey[] = { +0x07,0x02,0x00,0x00,0x00,0x22,0x00,0x00, 0x44,0x53,0x53,0x32,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,0x16,0xb6,0x1d,0xd4, 0x09,0xc4,0x9a,0x46,0x2d,0x0e,0x75,0x07, +0x31,0x7b,0xed,0x45,0xcd,0x99,0x84,0x14, 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, +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,0xad,0x83,0xcd,0x35, 0xb0,0x4e,0x06,0x68,0xd1,0x69,0x7e,0x73, +0x93,0xbe,0xa5,0x05,0xb3,0xcc,0xd2,0x51, 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)}, + {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) +{ + HCRYPTHASH hHash1, hHash2; + 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; + BOOL result; + int i; + + for (i = 0; i < testLen; i++) + { + DWORD signLen1 = tests[i].dataLen; + DWORD signLen2 = tests[i].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 %x\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 %x\n", GetLastError()); + + result = CryptHashData(hHash1, tests[i].signData, signLen1, 0); + ok(result, "Failed to add data to hash, got %x\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 %x\n", GetLastError()); + + result = CryptHashData(hHash2, tests[i].signData, signLen2, 0); + ok(result, "Failed to add data to hash, got %x\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 %x\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 %x\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."); + ok(!memcmp(hashValue1, hashValue2, hashLen2), "Hashes were not identical.\n"); + + /* Sign hash 1 */ + result = CryptSignHash(hHash1, AT_SIGNATURE, NULL, 0, NULL, &signLen1); + ok(result, "Failed to get signature length, got %x\n", GetLastError()); + ok(signLen1 == 40, "Expected a 40-byte signature, got %d\n", signLen1); + + result = CryptSignHash(hHash1, AT_SIGNATURE, NULL, 0, signValue1, &signLen1); + ok(result, "Failed to sign hash, got %x\n", GetLastError()); + + /* Sign hash 2 */ + result = CryptSignHash(hHash2, AT_SIGNATURE, NULL, 0, NULL, &signLen2); + ok(result, "Failed to get signature length, got %x\n", GetLastError()); + ok(signLen2 == 40, "Expected a 40-byte signature, got %d\n", signLen2); + + result = CryptSignHash(hHash2, AT_SIGNATURE, NULL, 0, signValue2, &signLen2); + ok(result, "Failed to sign hash2, got %x\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."); + + result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, NULL, &pubKeyLen); + ok(result, "Failed to acquire public key length, got %x\n", GetLastError()); + + /* Export the public key */ + result = CryptExportKey(privKey, 0, PUBLICKEYBLOB, 0, pubKeyBuffer, &pubKeyLen); + ok(result, "Failed to export public key, got %x\n", GetLastError()); + + result = CryptDestroyHash(hHash1); + ok(result, "Failed to destroy hash1, got %x\n", GetLastError()); + result = CryptDestroyHash(hHash2); + ok(result, "Failed to destroy hash2, got %x\n", GetLastError()); + + /* Destroy the private key */ + result = CryptDestroyKey(privKey); + ok(result, "Failed to destroy private key, got %x\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 %x\n", GetLastError()); + + result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash1); + ok(result, "Failed to create hash, got %x\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 %x\n", GetLastError()); + + /* Verify signed hash 1 */ + result = CryptVerifySignature(hHash1, signValue1, sizeof(signValue1), pubKey, NULL, 0); + ok(result, "Failed to verify signature, got %x\n", GetLastError()); + + result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash2); + ok(result, "Failed to create hash, got %x\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 %x\n", GetLastError()); + + /* Verify signed hash 2 */ + result = CryptVerifySignature(hHash2, signValue2, sizeof(signValue2), pubKey, NULL, 0); + ok(result, "Failed to verify signature, got %x\n", GetLastError()); + + result = CryptDestroyHash(hHash1); + ok(result, "Failed to destroy hash1, got %x\n", GetLastError()); + result = CryptDestroyHash(hHash2); + ok(result, "Failed to destroy hash2, got %x\n", GetLastError()); + + /* Destroy the public key */ + result = CryptDestroyKey(pubKey); + ok(result, "Failed to destroy public key, got %x\n", GetLastError()); + } +} + +static void test_verify_signature(void) +{ + HCRYPTPROV hProv = 0; + BOOL result; + + /* acquire base dss provider */ + result = CryptAcquireContextA(&hProv, 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"); + + test_signhash_array(hProv, dssSign_data, TESTLEN(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, PROV_DSS_DH, 0); + ok(result, "Failed to acquire CSP.\n"); + + test_signhash_array(hProv, dssSign_data, TESTLEN(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, PROV_DSS_DH, 0); + if(!result && GetLastError() == NTE_KEYSET_NOT_DEF) + { + win_skip("DSSENH and Schannel provider is broken on WinNT4, skipping signature " + "verification tests.\n"); + return; + } + ok(result, "Failed to acquire CSP.\n"); + + test_signhash_array(hProv, dssSign_data, TESTLEN(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, PROV_DH_SCHANNEL, 0); + ok(result, "Failed to acquire CSP.\n"); + + test_signhash_array(hProv, dssSign_data, TESTLEN(dssSign_data)); + + result = CryptReleaseContext(hProv, 0); + ok(result, "Failed to release CSP provider.\n"); +} + START_TEST(dssenh) { test_acquire_context(); @@ -749,4 +999,5 @@ START_TEST(dssenh) test_hash(hash_data, TESTLEN(hash_data)); test_data_encryption(encrypt_data, TESTLEN(encrypt_data)); test_cipher_modes(ciphermode_data, TESTLEN(ciphermode_data)); + test_verify_signature(); }