Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

648 lines
24 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: mvcerts.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "global.hxx"
  11. static HRESULT HError ()
  12. {
  13. DWORD dw = GetLastError ();
  14. HRESULT hr;
  15. if ( dw <= (DWORD) 0xFFFF )
  16. hr = HRESULT_FROM_WIN32 ( dw );
  17. else
  18. hr = dw;
  19. if ( ! FAILED ( hr ) )
  20. {
  21. // somebody failed a call without properly setting an error condition
  22. hr = E_UNEXPECTED;
  23. }
  24. return hr;
  25. }
  26. //
  27. // The root of the certificate store that we manage.
  28. //
  29. #define SZIE30CERTROOT "Software\\Microsoft\\Cryptography\\CertificateStore"
  30. #define SZIE30CERTPARENT "Software\\Microsoft\\Cryptography"
  31. #define SZIE30CERTSTORE "CertificateStore"
  32. #define SZIE30CERTBUCKET "Certificates"
  33. #define SZIE30INDEXISSUER "IndexByIssuerName"
  34. #define SZIE30INDEXISSUERSER "IndexByIssuerNameAndSerialNumber"
  35. #define SZIE30INDEXSUBJECT "IndexBySubjectName"
  36. #define SZIE30INDEXKEY "IndexBySubjectPublicKey"
  37. #define SZIE30CERTCLIENTAUTH "Software\\Microsoft\\Cryptography\\PersonalCertificates\\ClientAuth"
  38. #define SZIE30TAGS "CertificateTags"
  39. #define SZIE30AUXINFO "CertificateAuxiliaryInfo"
  40. #define IE30CONVERTEDSTORE "My"
  41. HRESULT PurgeDuplicateCertificate(HCERTSTORE hStore, PCCERT_CONTEXT pCert)
  42. {
  43. HRESULT hr = S_OK;
  44. PCCERT_CONTEXT pExistingCert = NULL;
  45. BOOL fRes = FALSE;
  46. // Check for existing certificates.
  47. pExistingCert = CertGetSubjectCertificateFromStore(hStore,
  48. X509_ASN_ENCODING,
  49. pCert->pCertInfo);
  50. if (pExistingCert)
  51. {
  52. if (CompareFileTime(&pExistingCert->pCertInfo->NotBefore,
  53. &pCert->pCertInfo->NotBefore) <= 0) {
  54. fRes = CertDeleteCertificateFromStore(pExistingCert); // Delete existing
  55. pExistingCert = NULL;
  56. if (!(fRes))
  57. {
  58. goto CertDupError;
  59. }
  60. }
  61. else
  62. {
  63. hr = S_FALSE;
  64. }
  65. }
  66. CommonReturn:
  67. if (pExistingCert)
  68. {
  69. CertFreeCertificateContext(pExistingCert);
  70. }
  71. return hr;
  72. ErrorReturn:
  73. SetLastError((DWORD)hr);
  74. goto CommonReturn;
  75. SET_HRESULT_EX(DBG_SS, CertDupError, GetLastError());
  76. }
  77. HRESULT MoveSpcCerts(BOOL fDelete, HCERTSTORE hStore)
  78. // Check for and copy any existing certificates stored in Bob's
  79. // certificate store. Also, delete Bob's certificate keys from the registry.
  80. {
  81. HRESULT hr = S_OK;
  82. LONG Status;
  83. HKEY hKeyRoot = NULL;
  84. HKEY hKeyParent = NULL;
  85. HKEY hKeyBucket = NULL;
  86. LPSTR pszName = NULL;
  87. BYTE *pbData = NULL;
  88. PKITRY {
  89. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  90. SZIE30CERTROOT,
  91. 0, // dwReserved
  92. KEY_READ,
  93. &hKeyRoot))
  94. PKITHROW(S_OK);
  95. // Copy any existing certificates
  96. if (ERROR_SUCCESS != RegOpenKeyEx(hKeyRoot,
  97. SZIE30CERTBUCKET,
  98. 0, // dwReserved
  99. KEY_READ,
  100. &hKeyBucket))
  101. PKITHROW(HError());
  102. DWORD cValues, cchMaxName, cbMaxData;
  103. // see how many and how big the registry is
  104. if (ERROR_SUCCESS != RegQueryInfoKey(hKeyBucket,
  105. NULL,
  106. NULL,
  107. NULL,
  108. NULL,
  109. NULL,
  110. NULL,
  111. &cValues,
  112. &cchMaxName,
  113. &cbMaxData,
  114. NULL,
  115. NULL
  116. ))
  117. PKITHROW(HError());
  118. // allocate the memory needed to read the reg
  119. pszName = (LPSTR) LocalAlloc(LMEM_ZEROINIT, cchMaxName + 1);
  120. pbData = (BYTE *) LocalAlloc(LMEM_ZEROINIT, cbMaxData);
  121. if (NULL == pszName || NULL == pbData)
  122. PKITHROW(E_OUTOFMEMORY);
  123. // enum the registry getting certs
  124. for (DWORD i = 0; i < cValues; i++ ) {
  125. DWORD dwType;
  126. DWORD cchName = cchMaxName + 1;
  127. DWORD cbData = cbMaxData;
  128. PCCERT_CONTEXT pCert = NULL;
  129. if (ERROR_SUCCESS != RegEnumValueA(hKeyBucket,
  130. i,
  131. pszName,
  132. &cchName,
  133. NULL,
  134. &dwType,
  135. pbData,
  136. &cbData)) {
  137. if (SUCCEEDED(hr))
  138. hr = HError();
  139. } else if (cchName) {
  140. if((pCert = CertCreateCertificateContext(X509_ASN_ENCODING,
  141. pbData,
  142. cbData)) == NULL) {
  143. hr = HError();
  144. }
  145. else {
  146. HRESULT hr2 = PurgeDuplicateCertificate(hStore, pCert);
  147. if(hr2 == S_OK) {
  148. if(!CertAddCertificateContextToStore(hStore,
  149. pCert,
  150. CERT_STORE_ADD_USE_EXISTING,
  151. NULL // ppStoreContext
  152. )) {
  153. /*MessageBox(NULL, "Copy Certificate Failed", NULL,
  154. MB_OK);*/
  155. if(SUCCEEDED(hr))
  156. hr = HError();
  157. }
  158. }
  159. }
  160. if(pCert)
  161. CertFreeCertificateContext(pCert);
  162. /*
  163. if (!CertAddEncodedCertificateToStore(hStore,
  164. X509_ASN_ENCODING,
  165. pbData,
  166. cbData,
  167. CERT_STORE_ADD_USE_EXISTING,
  168. NULL)) { // ppCertContext
  169. MessageBox(NULL, "Copy Certificate Failed", NULL,
  170. MB_OK);
  171. if (SUCCEEDED(hr))
  172. hr = HError();
  173. */
  174. }
  175. }
  176. }
  177. PKICATCH(err) {
  178. hr = err.pkiError;
  179. } PKIEND;
  180. if (pszName)
  181. LocalFree(pszName);
  182. if (pbData)
  183. LocalFree(pbData);
  184. if (hKeyBucket)
  185. RegCloseKey(hKeyBucket);
  186. if (hKeyRoot)
  187. RegCloseKey(hKeyRoot);
  188. if(SUCCEEDED(hr) && fDelete) {
  189. Status = ERROR_SUCCESS;
  190. while (Status == ERROR_SUCCESS) {
  191. // Re-open registry with write/delete access
  192. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  193. SZIE30CERTROOT,
  194. 0, // dwReserved
  195. KEY_ALL_ACCESS,
  196. &hKeyRoot))
  197. return HError();
  198. // Delete all of the store's subkeys including the certificates
  199. CHAR szSubKey[MAX_PATH+1];
  200. if (ERROR_SUCCESS == (Status = RegEnumKey(hKeyRoot,
  201. 0, // iSubKey
  202. szSubKey,
  203. MAX_PATH + 1
  204. )))
  205. Status = RegDeleteKey(hKeyRoot, szSubKey);
  206. RegCloseKey(hKeyRoot);
  207. }
  208. // Open the store's parent registry so we can delete the store
  209. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  210. SZIE30CERTPARENT,
  211. 0, // dwReserved
  212. KEY_ALL_ACCESS,
  213. &hKeyParent))
  214. return HError();
  215. if (ERROR_SUCCESS != RegDeleteKey(hKeyParent, SZIE30CERTSTORE))
  216. hr = HError();
  217. RegCloseKey(hKeyParent);
  218. }
  219. return hr;
  220. }
  221. BOOL TestIE30Store(HKEY hRegRoot, LPCSTR psLoc)
  222. {
  223. HRESULT hr = S_FALSE;
  224. HKEY hKeyRoot = NULL;
  225. HKEY hKeyBucket = NULL;
  226. char pbValueName[MAX_PATH];
  227. DWORD cbValueName = MAX_PATH;
  228. DWORD cSubKeys;
  229. DWORD dwType;
  230. // __asm int 3
  231. PKITRY {
  232. if (ERROR_SUCCESS != RegOpenKeyExA(hRegRoot,
  233. psLoc,
  234. 0, // dwReserved
  235. KEY_READ,
  236. &hKeyRoot))
  237. PKITHROW(S_FALSE);
  238. if (ERROR_SUCCESS != RegOpenKeyExA(hKeyRoot,
  239. SZIE30CERTBUCKET,
  240. 0, // dwReserved
  241. KEY_READ,
  242. &hKeyBucket))
  243. PKITHROW(S_FALSE);
  244. DWORD cValues, cchMaxName, cbMaxData;
  245. // see how many and how big the registry is
  246. if (ERROR_SUCCESS != RegQueryInfoKey(hKeyBucket,
  247. NULL, // lpszClasss
  248. NULL, // lpcchClass
  249. NULL, // lpdwReserved
  250. &cSubKeys,
  251. NULL, // lpcchMaxSubkey
  252. NULL, // lpcchMaxClass
  253. &cValues,
  254. &cchMaxName,
  255. &cbMaxData,
  256. NULL,
  257. NULL
  258. ))
  259. PKITHROW(HError());
  260. if(cchMaxName < 40 && cSubKeys == 0)
  261. hr = S_OK;
  262. }
  263. PKICATCH(err) {
  264. hr = err.pkiError;
  265. } PKIEND
  266. if(hKeyRoot != NULL)
  267. RegCloseKey(hKeyRoot);
  268. if(hKeyBucket != NULL)
  269. RegCloseKey(hKeyBucket);
  270. return hr == S_OK ? TRUE : FALSE;
  271. }
  272. HRESULT TransferIE30Certificates(HKEY hRegRoot, LPCSTR psLoc, HCERTSTORE hStore, BOOL fDelete)
  273. // Check for and copy any existing certificates stored in Bob's
  274. // certificate store.
  275. {
  276. HRESULT hr = S_OK;
  277. LONG Status;
  278. HKEY hKeyRoot = NULL;
  279. HKEY hKeyBucket = NULL;
  280. HKEY hKeyTags = NULL;
  281. HKEY hKeyAux = NULL;
  282. if (ERROR_SUCCESS != RegOpenKeyExA(hRegRoot,
  283. psLoc,
  284. 0, // dwReserved
  285. KEY_READ,
  286. &hKeyRoot
  287. ))
  288. return S_OK;
  289. // Copy any existing certificates
  290. if (ERROR_SUCCESS == RegOpenKeyExA(hKeyRoot,
  291. SZIE30CERTBUCKET,
  292. 0, // dwReserved
  293. KEY_READ,
  294. &hKeyBucket
  295. ) &&
  296. ERROR_SUCCESS == RegOpenKeyExA(hKeyRoot,
  297. SZIE30AUXINFO,
  298. 0, // dwReserved
  299. KEY_READ,
  300. &hKeyAux
  301. ) &&
  302. ERROR_SUCCESS == RegOpenKeyExA(hKeyRoot,
  303. SZIE30TAGS,
  304. 0, // dwReserved
  305. KEY_READ,
  306. &hKeyTags
  307. )) {
  308. DWORD cValuesCert, cchMaxNameCert, cbMaxDataCert;
  309. DWORD cValuesTag, cchMaxNameTag, cbMaxDataTag;
  310. DWORD cValuesAux, cchMaxNameAux, cbMaxDataAux;
  311. LPSTR szName = NULL;
  312. BYTE *pbLoadCert = NULL;
  313. BYTE *pbFixedCert = NULL;
  314. BYTE *pbDataCert = NULL;
  315. BYTE *pbDataAux = NULL;
  316. BYTE *pbDataTag = NULL;
  317. // see how many and how big the registry is
  318. if (ERROR_SUCCESS != RegQueryInfoKey(hKeyBucket,
  319. NULL,
  320. NULL,
  321. NULL,
  322. NULL,
  323. NULL,
  324. NULL,
  325. &cValuesCert,
  326. &cchMaxNameCert,
  327. &cbMaxDataCert,
  328. NULL,
  329. NULL
  330. ) ||
  331. ERROR_SUCCESS != RegQueryInfoKey(hKeyTags,
  332. NULL,
  333. NULL,
  334. NULL,
  335. NULL,
  336. NULL,
  337. NULL,
  338. &cValuesTag,
  339. &cchMaxNameTag,
  340. &cbMaxDataTag,
  341. NULL,
  342. NULL
  343. ) ||
  344. ERROR_SUCCESS != RegQueryInfoKey(hKeyAux,
  345. NULL,
  346. NULL,
  347. NULL,
  348. NULL,
  349. NULL,
  350. NULL,
  351. &cValuesAux,
  352. &cchMaxNameAux,
  353. &cbMaxDataAux,
  354. NULL,
  355. NULL
  356. ))
  357. hr = HError();
  358. else {
  359. // allocate the memory needed to read the reg
  360. szName = (LPSTR) LocalAlloc(LMEM_ZEROINIT, cchMaxNameCert + 1);
  361. pbDataCert = (BYTE *) LocalAlloc(LMEM_ZEROINIT, cbMaxDataCert);
  362. pbDataTag = (BYTE *) LocalAlloc(LMEM_ZEROINIT, cbMaxDataTag);
  363. pbDataAux = (BYTE *) LocalAlloc(LMEM_ZEROINIT, cbMaxDataAux);
  364. if (NULL == szName ||
  365. NULL == pbDataCert ||
  366. NULL == pbDataAux ||
  367. NULL == pbDataTag )
  368. hr = E_OUTOFMEMORY;
  369. }
  370. // enum the registry getting certs
  371. for (DWORD i = 0; SUCCEEDED(hr) && i < cValuesCert; i++ ) {
  372. DWORD dwType;
  373. BYTE * pb;
  374. CRYPT_KEY_PROV_INFO keyInfo;
  375. DWORD cchName = cchMaxNameCert + 1;
  376. DWORD cbDataCert = cbMaxDataCert;
  377. DWORD cbLoadCert = 0;
  378. DWORD cbFixedCert = 0;
  379. DWORD cbDataTag = cbMaxDataTag;
  380. DWORD cbDataAux = cbMaxDataAux;
  381. PCCERT_CONTEXT pCertContxt = NULL;
  382. HRESULT status = S_OK;
  383. // don't have to worry about errors, just skip
  384. // sliently just be cause there is an internal
  385. // error in the registry doesn't mean we should
  386. // get all upset about it.
  387. // get the cert
  388. if (RegEnumValueA(hKeyBucket,
  389. i,
  390. szName,
  391. &cchName,
  392. NULL,
  393. &dwType,
  394. pbDataCert,
  395. &cbDataCert
  396. ) == ERROR_SUCCESS &&
  397. dwType == REG_BINARY) {
  398. if(Fix7FCert(cbDataCert,
  399. pbDataCert,
  400. &cbFixedCert,
  401. &pbFixedCert) &&
  402. cbFixedCert != 0) {
  403. pbLoadCert = pbFixedCert;
  404. cbLoadCert = cbFixedCert;
  405. }
  406. else {
  407. pbLoadCert = pbDataCert;
  408. cbLoadCert = cbDataCert;
  409. }
  410. // get the cert context
  411. if((pCertContxt = CertCreateCertificateContext(X509_ASN_ENCODING,
  412. pbLoadCert,
  413. cbLoadCert)) != NULL) {
  414. // See if it has a tag and aux info.
  415. // get the tag
  416. if(RegQueryValueExA(hKeyTags,
  417. szName,
  418. NULL,
  419. &dwType,
  420. pbDataTag,
  421. &cbDataTag) == ERROR_SUCCESS &&
  422. // get the aux info
  423. RegQueryValueExA(hKeyAux,
  424. (LPTSTR) pbDataTag,
  425. NULL,
  426. &dwType,
  427. pbDataAux,
  428. &cbDataAux) == ERROR_SUCCESS ) {
  429. // aux info is
  430. // wszPurpose
  431. // wszProvider
  432. // wszKeySet
  433. // wszFilename
  434. // wszCredentials
  435. // dwProviderType
  436. // dwKeySpec
  437. pb = pbDataAux;
  438. memset(&keyInfo, 0, sizeof(CRYPT_KEY_PROV_INFO));
  439. // skip purpose, should be client auth
  440. pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
  441. // get the provider
  442. keyInfo.pwszProvName = (LPWSTR) pb;
  443. pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
  444. // get the container name
  445. keyInfo.pwszContainerName = (LPWSTR) pb;
  446. pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
  447. // skip filename, should be '\0'
  448. pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
  449. // skip credential, don't really know what it is?
  450. pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
  451. // get the provider type
  452. keyInfo.dwProvType = *((DWORD *) pb);
  453. pb += sizeof(DWORD);
  454. // get the key spec
  455. keyInfo.dwKeySpec = *((DWORD *) pb);
  456. // add the property to the certificate
  457. if( !CertSetCertificateContextProperty(pCertContxt,
  458. CERT_KEY_PROV_INFO_PROP_ID,
  459. 0,
  460. &keyInfo))
  461. status = S_FALSE;
  462. }
  463. if(status == S_OK) {
  464. HRESULT hr2 = PurgeDuplicateCertificate(hStore, pCertContxt);
  465. if(hr2 == S_OK) {
  466. if(!CertAddCertificateContextToStore(hStore,
  467. pCertContxt,
  468. CERT_STORE_ADD_USE_EXISTING,
  469. NULL // ppStoreContext
  470. )) {
  471. /*MessageBox(NULL,
  472. "Copy Certificate Failed",
  473. NULL,
  474. MB_OK);*/
  475. hr = HError();
  476. }
  477. }
  478. }
  479. }
  480. }
  481. if(pCertContxt != NULL)
  482. CertFreeCertificateContext(pCertContxt);
  483. if(pbFixedCert) {
  484. LocalFree(pbFixedCert);
  485. pbFixedCert = NULL;
  486. }
  487. }
  488. if (szName)
  489. LocalFree(szName);
  490. if (pbDataCert)
  491. LocalFree(pbDataCert);
  492. if(pbDataAux)
  493. LocalFree(pbDataAux);
  494. if(pbDataTag)
  495. LocalFree(pbDataTag);
  496. }
  497. if(hKeyRoot != NULL)
  498. RegCloseKey(hKeyRoot);
  499. if(hKeyBucket != NULL)
  500. RegCloseKey(hKeyBucket);
  501. if(hKeyTags != NULL)
  502. RegCloseKey(hKeyTags);
  503. if(hKeyAux != NULL)
  504. RegCloseKey(hKeyAux);
  505. if (FAILED(hr))
  506. return hr;
  507. if(SUCCEEDED(hr) && fDelete) {
  508. // Re-open registry with write/delete access
  509. if (ERROR_SUCCESS != RegOpenKeyEx(hRegRoot,
  510. psLoc,
  511. 0, // dwRes erved
  512. KEY_ALL_ACCESS,
  513. &hKeyRoot))
  514. return HError();
  515. Status = RegDeleteKey(hKeyRoot, SZIE30CERTBUCKET);
  516. Status = RegDeleteKey(hKeyRoot, SZIE30INDEXISSUER);
  517. Status = RegDeleteKey(hKeyRoot, SZIE30INDEXISSUERSER);
  518. Status = RegDeleteKey(hKeyRoot, SZIE30INDEXSUBJECT);
  519. Status = RegDeleteKey(hKeyRoot, SZIE30INDEXKEY);
  520. Status = RegDeleteKey(hKeyRoot, SZIE30TAGS);
  521. RegCloseKey(hKeyRoot);
  522. }
  523. return hr;
  524. }
  525. HRESULT MoveCertificates(BOOL fDelete)
  526. {
  527. HRESULT hr = S_OK;
  528. HRESULT hr2 = S_OK;
  529. HCERTSTORE hSpcStore = NULL;
  530. HCERTSTORE hStore = NULL;
  531. HCRYPTPROV hCrypt = NULL;
  532. //__asm int 3
  533. PKITRY {
  534. /*
  535. if (!CryptAcquireContext(&hCrypt, NULL, MS_DEF_PROV, PROV_RSA_FULL, 0))
  536. PKITHROW(HError());
  537. */
  538. hSpcStore = CertOpenSystemStore( NULL, TEXT("SPC") );
  539. if(!hSpcStore)
  540. PKITHROW(HError());
  541. hr = MoveSpcCerts(fDelete, hSpcStore);
  542. hStore = CertOpenSystemStore(NULL, TEXT(IE30CONVERTEDSTORE));
  543. if(!hStore)
  544. PKITHROW(HError());
  545. hr2 = TransferIE30Certificates(HKEY_CURRENT_USER, SZIE30CERTCLIENTAUTH, hStore, fDelete);
  546. }
  547. PKICATCH(err) {
  548. hr = err.pkiError;
  549. } PKIEND;
  550. if(SUCCEEDED(hr)) hr = hr2;
  551. if(hSpcStore)
  552. CertCloseStore( hSpcStore, 0 );
  553. if(hStore)
  554. CertCloseStore(hStore, 0);
  555. if(hCrypt)
  556. CryptReleaseContext(hCrypt, 0);
  557. return hr;
  558. }