1 /* 2 * Unit test suite for crypt32.dll's OID support functions. 3 * 4 * Copyright 2005 Juan Lang 5 * Copyright 2018 Dmitry Timoshkov 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 #include <stdio.h> 22 #include <stdarg.h> 23 #include <windef.h> 24 #include <winbase.h> 25 #include <winerror.h> 26 #define CRYPT_OID_INFO_HAS_EXTRA_FIELDS 27 #include <wincrypt.h> 28 #include <winreg.h> 29 30 #include "wine/test.h" 31 32 33 static BOOL (WINAPI *pCryptEnumOIDInfo)(DWORD,DWORD,void*,PFN_CRYPT_ENUM_OID_INFO); 34 35 36 struct OIDToAlgID 37 { 38 LPCSTR oid; 39 LPCSTR altOid; 40 DWORD algID; 41 DWORD altAlgID; 42 }; 43 44 static const struct OIDToAlgID oidToAlgID[] = { 45 { szOID_RSA_RSA, NULL, CALG_RSA_KEYX }, 46 { szOID_RSA_MD2RSA, NULL, CALG_MD2 }, 47 { szOID_RSA_MD4RSA, NULL, CALG_MD4 }, 48 { szOID_RSA_MD5RSA, NULL, CALG_MD5 }, 49 { szOID_RSA_SHA1RSA, NULL, CALG_SHA }, 50 { szOID_RSA_DH, NULL, CALG_DH_SF }, 51 { szOID_RSA_SMIMEalgESDH, NULL, CALG_DH_EPHEM }, 52 { szOID_RSA_SMIMEalgCMS3DESwrap, NULL, CALG_3DES }, 53 { szOID_RSA_SMIMEalgCMSRC2wrap, NULL, CALG_RC2 }, 54 { szOID_RSA_MD2, NULL, CALG_MD2 }, 55 { szOID_RSA_MD4, NULL, CALG_MD4 }, 56 { szOID_RSA_MD5, NULL, CALG_MD5 }, 57 { szOID_RSA_RC2CBC, NULL, CALG_RC2 }, 58 { szOID_RSA_RC4, NULL, CALG_RC4 }, 59 { szOID_RSA_DES_EDE3_CBC, NULL, CALG_3DES }, 60 { szOID_ANSI_X942_DH, NULL, CALG_DH_SF }, 61 { szOID_X957_DSA, NULL, CALG_DSS_SIGN }, 62 { szOID_X957_SHA1DSA, NULL, CALG_SHA }, 63 { szOID_OIWSEC_md4RSA, NULL, CALG_MD4 }, 64 { szOID_OIWSEC_md5RSA, NULL, CALG_MD5 }, 65 { szOID_OIWSEC_md4RSA2, NULL, CALG_MD4 }, 66 { szOID_OIWSEC_desCBC, NULL, CALG_DES }, 67 { szOID_OIWSEC_dsa, NULL, CALG_DSS_SIGN }, 68 { szOID_OIWSEC_shaDSA, NULL, CALG_SHA }, 69 { szOID_OIWSEC_shaRSA, NULL, CALG_SHA }, 70 { szOID_OIWSEC_sha, NULL, CALG_SHA }, 71 { szOID_OIWSEC_rsaXchg, NULL, CALG_RSA_KEYX }, 72 { szOID_OIWSEC_sha1, NULL, CALG_SHA }, 73 { szOID_OIWSEC_dsaSHA1, NULL, CALG_SHA }, 74 { szOID_OIWSEC_sha1RSASign, NULL, CALG_SHA }, 75 { szOID_OIWDIR_md2RSA, NULL, CALG_MD2 }, 76 { szOID_INFOSEC_mosaicUpdatedSig, NULL, CALG_SHA }, 77 { szOID_INFOSEC_mosaicKMandUpdSig, NULL, CALG_DSS_SIGN }, 78 { szOID_NIST_sha256, NULL, CALG_SHA_256, -1 }, 79 { szOID_NIST_sha384, NULL, CALG_SHA_384, -1 }, 80 { szOID_NIST_sha512, NULL, CALG_SHA_512, -1 } 81 }; 82 83 static const struct OIDToAlgID algIDToOID[] = { 84 { szOID_RSA_RSA, NULL, CALG_RSA_KEYX }, 85 { szOID_RSA_SMIMEalgESDH, NULL, CALG_DH_EPHEM }, 86 { szOID_RSA_MD2, NULL, CALG_MD2 }, 87 { szOID_RSA_MD4, NULL, CALG_MD4 }, 88 { szOID_RSA_MD5, NULL, CALG_MD5 }, 89 { szOID_RSA_RC2CBC, NULL, CALG_RC2 }, 90 { szOID_RSA_RC4, NULL, CALG_RC4 }, 91 { szOID_RSA_DES_EDE3_CBC, NULL, CALG_3DES }, 92 { szOID_ANSI_X942_DH, NULL, CALG_DH_SF }, 93 { szOID_X957_DSA, szOID_OIWSEC_dsa /* some Win98 */, CALG_DSS_SIGN }, 94 { szOID_OIWSEC_desCBC, NULL, CALG_DES }, 95 { szOID_OIWSEC_sha1, NULL, CALG_SHA }, 96 }; 97 98 static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 }; 99 static const WCHAR bogus2Dll[] = { 'b','o','g','u','s','2','.','d','l','l',0 }; 100 101 static void testOIDToAlgID(void) 102 { 103 int i; 104 DWORD alg; 105 106 /* Test with a bogus one */ 107 alg = CertOIDToAlgId("1.2.3"); 108 ok(!alg, "Expected failure, got %d\n", alg); 109 110 for (i = 0; i < ARRAY_SIZE(oidToAlgID); i++) 111 { 112 alg = CertOIDToAlgId(oidToAlgID[i].oid); 113 ok(alg == oidToAlgID[i].algID || (oidToAlgID[i].altAlgID && alg == oidToAlgID[i].altAlgID), 114 "Expected %d, got %d\n", oidToAlgID[i].algID, alg); 115 } 116 } 117 118 static void testAlgIDToOID(void) 119 { 120 int i; 121 LPCSTR oid; 122 123 /* Test with a bogus one */ 124 SetLastError(0xdeadbeef); 125 oid = CertAlgIdToOID(ALG_CLASS_SIGNATURE | ALG_TYPE_ANY | 80); 126 ok(!oid && GetLastError() == 0xdeadbeef, 127 "Didn't expect last error (%08x) to be set\n", GetLastError()); 128 for (i = 0; i < ARRAY_SIZE(algIDToOID); i++) 129 { 130 oid = CertAlgIdToOID(algIDToOID[i].algID); 131 /* Allow failure, not every version of Windows supports every algo */ 132 ok(oid != NULL || broken(!oid), "CertAlgIdToOID failed, expected %s\n", algIDToOID[i].oid); 133 if (oid) 134 { 135 if (strcmp(oid, algIDToOID[i].oid)) 136 { 137 if (algIDToOID[i].altOid) 138 ok(!strcmp(oid, algIDToOID[i].altOid), 139 "Expected %s or %s, got %s\n", algIDToOID[i].oid, 140 algIDToOID[i].altOid, oid); 141 else 142 { 143 /* No need to rerun the test, we already know it failed. */ 144 ok(0, "Expected %s, got %s\n", algIDToOID[i].oid, oid); 145 } 146 } 147 else 148 { 149 /* No need to rerun the test, we already know it succeeded. */ 150 ok(1, "Expected %s, got %s\n", algIDToOID[i].oid, oid); 151 } 152 } 153 } 154 } 155 156 static void test_oidFunctionSet(void) 157 { 158 HCRYPTOIDFUNCSET set1, set2; 159 BOOL ret; 160 LPWSTR buf = NULL; 161 DWORD size; 162 163 /* This crashes 164 set = CryptInitOIDFunctionSet(NULL, 0); 165 */ 166 167 /* The name doesn't mean much */ 168 set1 = CryptInitOIDFunctionSet("funky", 0); 169 ok(set1 != 0, "CryptInitOIDFunctionSet failed: %08x\n", GetLastError()); 170 if (set1) 171 { 172 /* These crash 173 ret = CryptGetDefaultOIDDllList(NULL, 0, NULL, NULL); 174 ret = CryptGetDefaultOIDDllList(NULL, 0, NULL, &size); 175 */ 176 size = 0; 177 ret = CryptGetDefaultOIDDllList(set1, 0, NULL, &size); 178 ok(ret, "CryptGetDefaultOIDDllList failed: %08x\n", GetLastError()); 179 if (ret) 180 { 181 buf = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); 182 if (buf) 183 { 184 ret = CryptGetDefaultOIDDllList(set1, 0, buf, &size); 185 ok(ret, "CryptGetDefaultOIDDllList failed: %08x\n", 186 GetLastError()); 187 ok(!*buf, "Expected empty DLL list\n"); 188 HeapFree(GetProcessHeap(), 0, buf); 189 } 190 } 191 } 192 193 /* MSDN says flags must be 0, but it's not checked */ 194 set1 = CryptInitOIDFunctionSet("", 1); 195 ok(set1 != 0, "CryptInitOIDFunctionSet failed: %08x\n", GetLastError()); 196 set2 = CryptInitOIDFunctionSet("", 0); 197 ok(set2 != 0, "CryptInitOIDFunctionSet failed: %08x\n", GetLastError()); 198 /* There isn't a free function, so there must be only one set per name to 199 * limit leaks. (I guess the sets are freed when crypt32 is unloaded.) 200 */ 201 ok(set1 == set2, "Expected identical sets\n"); 202 if (set1) 203 { 204 /* The empty name function set used here seems to correspond to 205 * DEFAULT. 206 */ 207 } 208 209 /* There's no installed function for a built-in encoding. */ 210 set1 = CryptInitOIDFunctionSet("CryptDllEncodeObject", 0); 211 ok(set1 != 0, "CryptInitOIDFunctionSet failed: %08x\n", GetLastError()); 212 if (set1) 213 { 214 void *funcAddr; 215 HCRYPTOIDFUNCADDR hFuncAddr; 216 217 ret = CryptGetOIDFunctionAddress(set1, X509_ASN_ENCODING, X509_CERT, 0, 218 &funcAddr, &hFuncAddr); 219 ok((!ret && GetLastError() == ERROR_FILE_NOT_FOUND) || 220 broken(ret) /* some Win98 */, 221 "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); 222 } 223 } 224 225 typedef int (*funcY)(int); 226 227 static int funky(int x) 228 { 229 return x; 230 } 231 232 static void test_installOIDFunctionAddress(void) 233 { 234 BOOL ret; 235 CRYPT_OID_FUNC_ENTRY entry = { CRYPT_DEFAULT_OID, funky }; 236 HCRYPTOIDFUNCSET set; 237 238 /* This crashes 239 ret = CryptInstallOIDFunctionAddress(NULL, 0, NULL, 0, NULL, 0); 240 */ 241 242 /* Installing zero functions should work */ 243 SetLastError(0xdeadbeef); 244 ret = CryptInstallOIDFunctionAddress(NULL, 0, "CryptDllEncodeObject", 0, 245 NULL, 0); 246 ok(ret && GetLastError() == 0xdeadbeef, "Expected success, got %08x\n", 247 GetLastError()); 248 249 /* The function name doesn't much matter */ 250 SetLastError(0xdeadbeef); 251 ret = CryptInstallOIDFunctionAddress(NULL, 0, "OhSoFunky", 0, NULL, 0); 252 ok(ret && GetLastError() == 0xdeadbeef, "Expected success, got %08x\n", 253 GetLastError()); 254 SetLastError(0xdeadbeef); 255 entry.pszOID = X509_CERT; 256 ret = CryptInstallOIDFunctionAddress(NULL, 0, "OhSoFunky", 1, &entry, 0); 257 ok(ret && GetLastError() == 0xdeadbeef, "Expected success, got %08x\n", 258 GetLastError()); 259 set = CryptInitOIDFunctionSet("OhSoFunky", 0); 260 ok(set != 0, "CryptInitOIDFunctionSet failed: %08x\n", GetLastError()); 261 if (set) 262 { 263 funcY funcAddr = NULL; 264 HCRYPTOIDFUNCADDR hFuncAddr = NULL; 265 266 /* This crashes 267 ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, 0, 0, NULL, 268 NULL); 269 */ 270 ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, 0, 0, 271 (void **)&funcAddr, &hFuncAddr); 272 ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND || 273 GetLastError() == E_INVALIDARG /* some Win98 */), 274 "Expected ERROR_FILE_NOT_FOUND or E_INVALIDARG, got %d\n", 275 GetLastError()); 276 ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, X509_CERT, 0, 277 (void **)&funcAddr, &hFuncAddr); 278 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, 279 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 280 ret = CryptGetOIDFunctionAddress(set, 0, X509_CERT, 0, 281 (void **)&funcAddr, &hFuncAddr); 282 ok(ret, "CryptGetOIDFunctionAddress failed: %d\n", GetLastError()); 283 if (funcAddr) 284 { 285 int y = funcAddr(0xabadc0da); 286 287 ok(y == 0xabadc0da, "Unexpected return (%d) from function\n", y); 288 CryptFreeOIDFunctionAddress(hFuncAddr, 0); 289 } 290 } 291 } 292 293 static void test_registerOIDFunction(void) 294 { 295 BOOL ret; 296 297 /* oddly, this succeeds under WinXP; the function name key is merely 298 * omitted. This may be a side effect of the registry code, I don't know. 299 * I don't check it because I doubt anyone would depend on it. 300 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, NULL, 301 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL); 302 */ 303 /* On windows XP, GetLastError is incorrectly being set with an HRESULT, 304 * E_INVALIDARG 305 */ 306 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", NULL, bogusDll, 307 NULL); 308 ok(!ret && GetLastError() == E_INVALIDARG, 309 "Expected E_INVALIDARG: %d\n", GetLastError()); 310 /* This has no effect, but "succeeds" on XP */ 311 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", 312 "1.2.3.4.5.6.7.8.9.10", NULL, NULL); 313 ok(ret, "Expected pseudo-success, got %d\n", GetLastError()); 314 SetLastError(0xdeadbeef); 315 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject", 316 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL); 317 if (!ret && GetLastError() == ERROR_ACCESS_DENIED) 318 { 319 skip("Need admin rights\n"); 320 return; 321 } 322 ok(ret, "CryptRegisterOIDFunction failed: %d\n", GetLastError()); 323 ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject", 324 "1.2.3.4.5.6.7.8.9.10"); 325 ok(ret, "CryptUnregisterOIDFunction failed: %d\n", GetLastError()); 326 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "bogus", 327 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL); 328 ok(ret, "CryptRegisterOIDFunction failed: %d\n", GetLastError()); 329 ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "bogus", 330 "1.2.3.4.5.6.7.8.9.10"); 331 ok(ret, "CryptUnregisterOIDFunction failed: %d\n", GetLastError()); 332 /* Unwanted Cryptography\OID\EncodingType 1\bogus\ will still be there */ 333 ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, 334 "SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType 1\\bogus"), 335 "Could not delete bogus key\n"); 336 /* Shouldn't have effect but registry keys are created */ 337 ret = CryptRegisterOIDFunction(PKCS_7_ASN_ENCODING, "CryptDllEncodeObject", 338 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL); 339 ok(ret, "CryptRegisterOIDFunction failed: %d\n", GetLastError()); 340 ret = CryptUnregisterOIDFunction(PKCS_7_ASN_ENCODING, "CryptDllEncodeObject", 341 "1.2.3.4.5.6.7.8.9.10"); 342 ok(ret, "CryptUnregisterOIDFunction failed: %d\n", GetLastError()); 343 /* Check with bogus encoding type. Registry keys are still created */ 344 ret = CryptRegisterOIDFunction(0, "CryptDllEncodeObject", 345 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL); 346 ok(ret, "CryptRegisterOIDFunction failed: %d\n", GetLastError()); 347 ret = CryptUnregisterOIDFunction(0, "CryptDllEncodeObject", 348 "1.2.3.4.5.6.7.8.9.10"); 349 ok(ret, "CryptUnregisterOIDFunction failed: %d\n", GetLastError()); 350 /* Unwanted Cryptography\OID\EncodingType 0\CryptDllEncodeObject\ 351 * will still be there 352 */ 353 ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, 354 "SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CryptDllEncodeObject"), 355 "Could not delete CryptDllEncodeObject key\n"); 356 /* This is written with value 3 verbatim. Thus, the encoding type isn't 357 * (for now) treated as a mask. Registry keys are created. 358 */ 359 ret = CryptRegisterOIDFunction(3, "CryptDllEncodeObject", 360 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL); 361 ok(ret, "CryptRegisterOIDFunction failed: %d\n", GetLastError()); 362 ret = CryptUnregisterOIDFunction(3, "CryptDllEncodeObject", 363 "1.2.3.4.5.6.7.8.9.10"); 364 ok(ret, "CryptUnregisterOIDFunction failed: %d\n", GetLastError()); 365 /* Unwanted Cryptography\OID\EncodingType 3\CryptDllEncodeObject 366 * will still be there. 367 */ 368 ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, 369 "SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType 3\\CryptDllEncodeObject"), 370 "Could not delete CryptDllEncodeObject key\n"); 371 ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, 372 "SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType 3"), 373 "Could not delete 'EncodingType 3' key\n"); 374 } 375 376 static void test_registerDefaultOIDFunction(void) 377 { 378 static const char fmt[] = 379 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %d\\%s\\DEFAULT"; 380 static const char func[] = "CertDllOpenStoreProv"; 381 char buf[MAX_PATH]; 382 BOOL ret; 383 LSTATUS rc; 384 HKEY key; 385 386 ret = CryptRegisterDefaultOIDFunction(0, NULL, 0, NULL); 387 ok(!ret && GetLastError() == E_INVALIDARG, 388 "Expected E_INVALIDARG, got %08x\n", GetLastError()); 389 /* This succeeds on WinXP, although the bogus entry is unusable. 390 ret = CryptRegisterDefaultOIDFunction(0, NULL, 0, bogusDll); 391 */ 392 /* Register one at index 0 */ 393 SetLastError(0xdeadbeef); 394 ret = CryptRegisterDefaultOIDFunction(0, "CertDllOpenStoreProv", 0, 395 bogusDll); 396 if (!ret && GetLastError() == ERROR_ACCESS_DENIED) 397 { 398 skip("Need admin rights\n"); 399 return; 400 } 401 ok(ret, "CryptRegisterDefaultOIDFunction failed: %08x\n", GetLastError()); 402 /* Reregistering should fail */ 403 ret = CryptRegisterDefaultOIDFunction(0, "CertDllOpenStoreProv", 0, 404 bogusDll); 405 ok(!ret && GetLastError() == ERROR_FILE_EXISTS, 406 "Expected ERROR_FILE_EXISTS, got %08x\n", GetLastError()); 407 /* Registering the same one at index 1 should also fail */ 408 ret = CryptRegisterDefaultOIDFunction(0, "CertDllOpenStoreProv", 1, 409 bogusDll); 410 ok(!ret && GetLastError() == ERROR_FILE_EXISTS, 411 "Expected ERROR_FILE_EXISTS, got %08x\n", GetLastError()); 412 /* Registering a different one at index 1 succeeds */ 413 ret = CryptRegisterDefaultOIDFunction(0, "CertDllOpenStoreProv", 1, 414 bogus2Dll); 415 ok(ret, "CryptRegisterDefaultOIDFunction failed: %08x\n", GetLastError()); 416 sprintf(buf, fmt, 0, func); 417 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, buf, &key); 418 ok(rc == 0, "Expected key to exist, RegOpenKeyA failed: %d\n", rc); 419 if (rc == 0) 420 { 421 static const CHAR dllA[] = "Dll"; 422 static const CHAR bogusDll_A[] = "bogus.dll"; 423 static const CHAR bogus2Dll_A[] = "bogus2.dll"; 424 CHAR dllBuf[MAX_PATH]; 425 DWORD type, size; 426 LPSTR ptr; 427 428 size = ARRAY_SIZE(dllBuf); 429 rc = RegQueryValueExA(key, dllA, NULL, &type, (LPBYTE)dllBuf, &size); 430 ok(rc == 0, 431 "Expected Dll value to exist, RegQueryValueExA failed: %d\n", rc); 432 ok(type == REG_MULTI_SZ, "Expected type REG_MULTI_SZ, got %d\n", type); 433 /* bogusDll was registered first, so that should be first */ 434 ptr = dllBuf; 435 ok(!lstrcmpiA(ptr, bogusDll_A), "Unexpected dll\n"); 436 ptr += lstrlenA(ptr) + 1; 437 ok(!lstrcmpiA(ptr, bogus2Dll_A), "Unexpected dll\n"); 438 RegCloseKey(key); 439 } 440 /* Unregister both of them */ 441 ret = CryptUnregisterDefaultOIDFunction(0, "CertDllOpenStoreProv", 442 bogusDll); 443 ok(ret, "CryptUnregisterDefaultOIDFunction failed: %08x\n", 444 GetLastError()); 445 ret = CryptUnregisterDefaultOIDFunction(0, "CertDllOpenStoreProv", 446 bogus2Dll); 447 ok(ret, "CryptUnregisterDefaultOIDFunction failed: %08x\n", 448 GetLastError()); 449 /* Now that they're both unregistered, unregistering should fail */ 450 ret = CryptUnregisterDefaultOIDFunction(0, "CertDllOpenStoreProv", 451 bogusDll); 452 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, 453 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 454 455 /* Repeat a few tests on the normal encoding type */ 456 ret = CryptRegisterDefaultOIDFunction(X509_ASN_ENCODING, 457 "CertDllOpenStoreProv", 0, bogusDll); 458 ok(ret, "CryptRegisterDefaultOIDFunction failed\n"); 459 ret = CryptUnregisterDefaultOIDFunction(X509_ASN_ENCODING, 460 "CertDllOpenStoreProv", bogusDll); 461 ok(ret, "CryptUnregisterDefaultOIDFunction failed\n"); 462 ret = CryptUnregisterDefaultOIDFunction(X509_ASN_ENCODING, 463 "CertDllOpenStoreProv", bogusDll); 464 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, 465 "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); 466 } 467 468 static void test_getDefaultOIDFunctionAddress(void) 469 { 470 BOOL ret; 471 HCRYPTOIDFUNCSET set; 472 void *funcAddr; 473 HCRYPTOIDFUNCADDR hFuncAddr; 474 475 /* Crash 476 ret = CryptGetDefaultOIDFunctionAddress(0, 0, NULL, 0, NULL, NULL); 477 ret = CryptGetDefaultOIDFunctionAddress(0, 0, NULL, 0, &funcAddr, NULL); 478 ret = CryptGetDefaultOIDFunctionAddress(0, 0, NULL, 0, NULL, &hFuncAddr); 479 ret = CryptGetDefaultOIDFunctionAddress(0, 0, NULL, 0, &funcAddr, 480 &hFuncAddr); 481 */ 482 set = CryptInitOIDFunctionSet("CertDllOpenStoreProv", 0); 483 ok(set != 0, "CryptInitOIDFunctionSet failed: %d\n", GetLastError()); 484 /* This crashes if hFuncAddr is not 0 to begin with */ 485 hFuncAddr = 0; 486 ret = CryptGetDefaultOIDFunctionAddress(set, 0, NULL, 0, &funcAddr, 487 &hFuncAddr); 488 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, 489 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 490 /* This fails with the normal encoding too, so built-in functions aren't 491 * returned. 492 */ 493 ret = CryptGetDefaultOIDFunctionAddress(set, X509_ASN_ENCODING, NULL, 0, 494 &funcAddr, &hFuncAddr); 495 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, 496 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 497 498 /* Even with a registered dll, this fails (since the dll doesn't exist) */ 499 SetLastError(0xdeadbeef); 500 ret = CryptRegisterDefaultOIDFunction(0, "CertDllOpenStoreProv", 0, 501 bogusDll); 502 if (!ret && GetLastError() == ERROR_ACCESS_DENIED) 503 skip("Need admin rights\n"); 504 else 505 ok(ret, "CryptRegisterDefaultOIDFunction failed: %08x\n", GetLastError()); 506 ret = CryptGetDefaultOIDFunctionAddress(set, 0, NULL, 0, &funcAddr, 507 &hFuncAddr); 508 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, 509 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 510 CryptUnregisterDefaultOIDFunction(0, "CertDllOpenStoreProv", bogusDll); 511 } 512 513 static BOOL WINAPI countOidInfo(PCCRYPT_OID_INFO pInfo, void *pvArg) 514 { 515 (*(DWORD *)pvArg)++; 516 return TRUE; 517 } 518 519 static BOOL WINAPI noOidInfo(PCCRYPT_OID_INFO pInfo, void *pvArg) 520 { 521 return FALSE; 522 } 523 524 static void test_enumOIDInfo(void) 525 { 526 BOOL ret; 527 DWORD count = 0; 528 529 if (!pCryptEnumOIDInfo) 530 { 531 win_skip("CryptEnumOIDInfo() is not available\n"); 532 return; 533 } 534 535 /* This crashes 536 ret = pCryptEnumOIDInfo(7, 0, NULL, NULL); 537 */ 538 539 /* Silly tests, check that more than one thing is enumerated */ 540 ret = pCryptEnumOIDInfo(0, 0, &count, countOidInfo); 541 ok(ret && count > 0, "Expected more than item enumerated\n"); 542 ret = pCryptEnumOIDInfo(0, 0, NULL, noOidInfo); 543 ok(!ret, "Expected FALSE\n"); 544 } 545 546 static void test_findOIDInfo(void) 547 { 548 static WCHAR sha256ECDSA[] = { 's','h','a','2','5','6','E','C','D','S','A',0 }; 549 static WCHAR sha1[] = { 's','h','a','1',0 }; 550 static CHAR oid_rsa_md5[] = szOID_RSA_MD5, oid_sha256[] = szOID_NIST_sha256; 551 static CHAR oid_ecdsa_sha256[] = szOID_ECDSA_SHA256; 552 ALG_ID alg = CALG_SHA1; 553 ALG_ID algs[2] = { CALG_MD5, CALG_RSA_SIGN }; 554 const struct oid_info 555 { 556 DWORD key_type; 557 void *key; 558 const char *oid; 559 ALG_ID algid; 560 ALG_ID broken_algid; 561 } oid_test_info [] = 562 { 563 { CRYPT_OID_INFO_OID_KEY, oid_rsa_md5, szOID_RSA_MD5, CALG_MD5 }, 564 { CRYPT_OID_INFO_NAME_KEY, sha1, szOID_OIWSEC_sha1, CALG_SHA1 }, 565 { CRYPT_OID_INFO_ALGID_KEY, &alg, szOID_OIWSEC_sha1, CALG_SHA1 }, 566 { CRYPT_OID_INFO_SIGN_KEY, algs, szOID_RSA_MD5RSA, CALG_MD5 }, 567 { CRYPT_OID_INFO_OID_KEY, oid_sha256, szOID_NIST_sha256, CALG_SHA_256, -1 }, 568 }; 569 PCCRYPT_OID_INFO info; 570 int i; 571 572 info = CryptFindOIDInfo(0, NULL, 0); 573 ok(info == NULL, "Expected NULL\n"); 574 575 for (i = 0; i < ARRAY_SIZE(oid_test_info); i++) 576 { 577 const struct oid_info *test = &oid_test_info[i]; 578 579 info = CryptFindOIDInfo(test->key_type, test->key, 0); 580 ok(info != NULL, "Failed to find %s.\n", test->oid); 581 if (info) 582 { 583 ok(!strcmp(info->pszOID, test->oid), "Unexpected OID %s, expected %s\n", info->pszOID, test->oid); 584 ok(U(*info).Algid == test->algid || broken(U(*info).Algid == test->broken_algid), 585 "Unexpected Algid %d, expected %d\n", U(*info).Algid, test->algid); 586 } 587 } 588 589 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid_ecdsa_sha256, 0); 590 if (info) 591 { 592 DWORD *data; 593 594 ok(info->cbSize == sizeof(*info), "Unexpected structure size %d.\n", info->cbSize); 595 ok(!strcmp(info->pszOID, oid_ecdsa_sha256), "Expected %s, got %s\n", oid_ecdsa_sha256, info->pszOID); 596 ok(!lstrcmpW(info->pwszName, sha256ECDSA), "Expected %s, got %s\n", 597 wine_dbgstr_w(sha256ECDSA), wine_dbgstr_w(info->pwszName)); 598 ok(info->dwGroupId == CRYPT_SIGN_ALG_OID_GROUP_ID, 599 "Expected CRYPT_SIGN_ALG_OID_GROUP_ID, got %u\n", info->dwGroupId); 600 ok(U(*info).Algid == CALG_OID_INFO_CNG_ONLY, 601 "Expected CALG_OID_INFO_CNG_ONLY, got %d\n", U(*info).Algid); 602 603 data = (DWORD *)info->ExtraInfo.pbData; 604 ok(info->ExtraInfo.cbData == 8, "Expected 8, got %d\n", info->ExtraInfo.cbData); 605 ok(data[0] == CALG_OID_INFO_PARAMETERS, "Expected CALG_OID_INFO_PARAMETERS, got %x\n", data[0]); 606 ok(data[1] == CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG, 607 "Expected CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG, got %x\n", data[1]); 608 609 ok(!lstrcmpW(info->pwszCNGAlgid, BCRYPT_SHA256_ALGORITHM), "Expected %s, got %s\n", 610 wine_dbgstr_w(BCRYPT_SHA256_ALGORITHM), wine_dbgstr_w(info->pwszCNGAlgid)); 611 ok(!lstrcmpW(info->pwszCNGExtraAlgid, CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM), "Expected %s, got %s\n", 612 wine_dbgstr_w(CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM), wine_dbgstr_w(info->pwszCNGExtraAlgid)); 613 } 614 else 615 win_skip("Host does not support ECDSA_SHA256, skipping test\n"); 616 } 617 618 static void test_registerOIDInfo(void) 619 { 620 static const WCHAR winetestW[] = { 'w','i','n','e','t','e','s','t',0 }; 621 static char test_oid[] = "1.2.3.4.5.6.7.8.9.10"; 622 CRYPT_OID_INFO info1; 623 const CRYPT_OID_INFO *info2; 624 HKEY key; 625 DWORD ret, size, type, value; 626 char buf[256]; 627 628 SetLastError(0xdeadbeef); 629 ret = CryptUnregisterOIDInfo(NULL); 630 ok(!ret, "should fail\n"); 631 ok(GetLastError() == E_INVALIDARG, "got %#x\n", GetLastError()); 632 633 memset(&info1, 0, sizeof(info1)); 634 SetLastError(0xdeadbeef); 635 ret = CryptUnregisterOIDInfo(&info1); 636 ok(!ret, "should fail\n"); 637 ok(GetLastError() == E_INVALIDARG, "got %#x\n", GetLastError()); 638 639 info1.cbSize = sizeof(info1); 640 SetLastError(0xdeadbeef); 641 ret = CryptUnregisterOIDInfo(&info1); 642 ok(!ret, "should fail\n"); 643 ok(GetLastError() == E_INVALIDARG, "got %#x\n", GetLastError()); 644 645 info1.pszOID = test_oid; 646 SetLastError(0xdeadbeef); 647 ret = CryptUnregisterOIDInfo(&info1); 648 ok(!ret, "should fail\n"); 649 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got %u\n", GetLastError()); 650 651 info2 = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, (void *)test_oid, 0); 652 ok(!info2, "should fail\n"); 653 654 SetLastError(0xdeadbeef); 655 /* While it succeeds, the next call does not write anything to the 656 * registry on Windows because dwGroupId == 0. 657 */ 658 ret = CryptRegisterOIDInfo(&info1, 0); 659 ok(ret, "got %u\n", GetLastError()); 660 661 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CryptDllFindOIDInfo\\1.2.3.4.5.6.7.8.9.10!1", &key); 662 ok(ret == ERROR_FILE_NOT_FOUND, "got %u\n", ret); 663 664 info2 = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, (void *)test_oid, 0); 665 ok(!info2, "should fail\n"); 666 667 info1.pwszName = winetestW; 668 info1.dwGroupId = CRYPT_HASH_ALG_OID_GROUP_ID; 669 SetLastError(0xdeadbeef); 670 ret = CryptRegisterOIDInfo(&info1, CRYPT_INSTALL_OID_INFO_BEFORE_FLAG); 671 if (!ret && GetLastError() == ERROR_ACCESS_DENIED) 672 { 673 skip("Need admin rights\n"); 674 return; 675 } 676 ok(ret, "got %u\n", GetLastError()); 677 678 /* It looks like crypt32 reads the OID info from registry only on load, 679 * and CryptFindOIDInfo will find the registered OID on next run 680 */ 681 info2 = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, (void *)test_oid, 0); 682 ok(!info2, "should fail\n"); 683 684 ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CryptDllFindOIDInfo\\1.2.3.4.5.6.7.8.9.10!1", &key); 685 ok(!ret, "got %u\n", ret); 686 687 memset(buf, 0, sizeof(buf)); 688 size = sizeof(buf); 689 ret = RegQueryValueExA(key, "Name", NULL, &type, (BYTE *)buf, &size); 690 ok(!ret, "got %u\n", ret); 691 ok(type == REG_SZ, "got %u\n", type); 692 ok(!strcmp(buf, "winetest"), "got %s\n", buf); 693 694 value = 0xdeadbeef; 695 size = sizeof(value); 696 ret = RegQueryValueExA(key, "Flags", NULL, &type, (BYTE *)&value, &size); 697 ok(!ret, "got %u\n", ret); 698 ok(type == REG_DWORD, "got %u\n", type); 699 ok(value == 1, "got %u\n", value); 700 701 RegCloseKey(key); 702 703 CryptUnregisterOIDInfo(&info1); 704 705 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CryptDllFindOIDInfo\\1.2.3.4.5.6.7.8.9.10!1", &key); 706 ok(ret == ERROR_FILE_NOT_FOUND, "got %u\n", ret); 707 } 708 709 START_TEST(oid) 710 { 711 HMODULE hCrypt32 = GetModuleHandleA("crypt32.dll"); 712 pCryptEnumOIDInfo = (void*)GetProcAddress(hCrypt32, "CryptEnumOIDInfo"); 713 714 testOIDToAlgID(); 715 testAlgIDToOID(); 716 test_enumOIDInfo(); 717 test_findOIDInfo(); 718 test_registerOIDInfo(); 719 test_oidFunctionSet(); 720 test_installOIDFunctionAddress(); 721 test_registerOIDFunction(); 722 test_registerDefaultOIDFunction(); 723 test_getDefaultOIDFunctionAddress(); 724 } 725