Leaked source code of windows server 2003
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.

2208 lines
59 KiB

  1. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
  3. File: Common.cpp
  4. Content: Common routines.
  5. History: 11-15-99 dsie created
  6. ------------------------------------------------------------------------------*/
  7. #include "StdAfx.h"
  8. #include "CAPICOM.h"
  9. #include "Common.h"
  10. #include "Convert.h"
  11. LPSTR g_rgpszOSNames[] =
  12. {
  13. "Unknown OS platform",
  14. "Win32s",
  15. "Win9x",
  16. "WinMe",
  17. "WinNT 3.5",
  18. "WinNT 4.0",
  19. "Win2K",
  20. "WinXP",
  21. "Above WinXP"
  22. };
  23. typedef struct _CSP_PROVIDERS
  24. {
  25. DWORD dwProvType;
  26. LPSTR pszProvider;
  27. } CSP_PROVIDERS;
  28. static CSP_PROVIDERS g_rgpProviders[] =
  29. {
  30. PROV_RSA_FULL, NULL, // Default RSA Full provider.
  31. PROV_RSA_FULL, MS_ENHANCED_PROV_A, // Microsoft Enhanced RSA provider.
  32. PROV_RSA_FULL, MS_STRONG_PROV_A, // Microsoft Strong RSA provider.
  33. PROV_RSA_FULL, MS_DEF_PROV_A, // Microsoft Base RSA provider.
  34. PROV_RSA_AES, NULL, // Default RSA AES Full provider.
  35. PROV_RSA_AES, MS_ENH_RSA_AES_PROV_A // Microsoft RSA AES Full provider.
  36. };
  37. #define g_dwNumRSAProviders (4)
  38. #define g_dwNumProviders (ARRAYSIZE(g_rgpProviders))
  39. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  40. Function : GetOSVersion
  41. Synopsis : Get the current OS platform/version.
  42. Parameter: None.
  43. Remark :
  44. ------------------------------------------------------------------------------*/
  45. OSVERSION GetOSVersion ()
  46. {
  47. HRESULT hr = S_OK;
  48. OSVERSION osVersion = OS_WIN_UNKNOWN;
  49. OSVERSIONINFO OSVersionInfo;
  50. DebugTrace("Entering GetOSVersion().\n");
  51. //
  52. // Initialize OSVERSIONINFO struct.
  53. //
  54. OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  55. //
  56. // GetVersionEx() will fail on Windows 3.x or below NT 3.5 systems.
  57. //
  58. if (!::GetVersionEx(&OSVersionInfo))
  59. {
  60. DebugTrace("Error [%#x]: GetVersionEx() failed.\n", hr);
  61. goto CommonExit;
  62. }
  63. //
  64. // Check platform ID.
  65. //
  66. switch (OSVersionInfo.dwPlatformId)
  67. {
  68. case VER_PLATFORM_WIN32s:
  69. {
  70. //
  71. // Win32s.
  72. //
  73. osVersion = OS_WIN_32s;
  74. break;
  75. }
  76. case VER_PLATFORM_WIN32_WINDOWS:
  77. {
  78. if (4 == OSVersionInfo.dwMajorVersion && 90 == OSVersionInfo.dwMinorVersion)
  79. {
  80. //
  81. // WinMe.
  82. //
  83. osVersion = OS_WIN_ME;
  84. }
  85. else
  86. {
  87. //
  88. // Win9x.
  89. //
  90. osVersion = OS_WIN_9X;
  91. }
  92. break;
  93. }
  94. case VER_PLATFORM_WIN32_NT:
  95. {
  96. switch (OSVersionInfo.dwMajorVersion)
  97. {
  98. case 4:
  99. {
  100. //
  101. // NT 4.
  102. //
  103. osVersion = OS_WIN_NT4;
  104. break;
  105. }
  106. case 5:
  107. {
  108. if (0 == OSVersionInfo.dwMinorVersion)
  109. {
  110. //
  111. // Win2K.
  112. //
  113. osVersion = OS_WIN_2K;
  114. }
  115. else if (1 == OSVersionInfo.dwMinorVersion)
  116. {
  117. //
  118. // WinXP.
  119. //
  120. osVersion = OS_WIN_XP;
  121. }
  122. else
  123. {
  124. //
  125. // Above WinXP.
  126. //
  127. osVersion = OS_WIN_ABOVE_XP;
  128. }
  129. break;
  130. }
  131. default:
  132. {
  133. //
  134. // Must be NT 3.5.
  135. //
  136. osVersion = OS_WIN_NT3_5;
  137. break;
  138. }
  139. }
  140. break;
  141. }
  142. default:
  143. {
  144. DebugTrace("Info: unsupported OS (Platform = %d, Major = %d, Minor = %d).\n",
  145. OSVersionInfo.dwPlatformId, OSVersionInfo.dwMajorVersion, OSVersionInfo.dwMinorVersion);
  146. break;
  147. }
  148. }
  149. CommonExit:
  150. DebugTrace("Leaving GetOSVersion().\n");
  151. return osVersion;
  152. }
  153. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  154. Function : EncodeObject
  155. Synopsis : Allocate memory and encode an ASN.1 object using CAPI
  156. CryptEncodeObject() API.
  157. Parameter: LPCSRT pszStructType - see MSDN document for possible
  158. types.
  159. LPVOID pbData - Pointer to data to be encoded
  160. (data type must match
  161. pszStrucType).
  162. CRYPT_DATA_BLOB * pEncodedBlob - Pointer to CRYPT_DATA_BLOB to
  163. receive the encoded length and
  164. data.
  165. Remark : No parameter check is done.
  166. ------------------------------------------------------------------------------*/
  167. HRESULT EncodeObject (LPCSTR pszStructType,
  168. LPVOID pbData,
  169. CRYPT_DATA_BLOB * pEncodedBlob)
  170. {
  171. HRESULT hr = S_OK;
  172. DWORD cbEncoded = 0;
  173. BYTE * pbEncoded = NULL;
  174. DebugTrace("Entering EncodeObject().\n");
  175. //
  176. // Sanity check.
  177. //
  178. ATLASSERT(NULL != pszStructType);
  179. ATLASSERT(NULL != pbData);
  180. ATLASSERT(NULL != pEncodedBlob);
  181. //
  182. // Intialize return value.
  183. //
  184. pEncodedBlob->cbData = 0;
  185. pEncodedBlob->pbData = NULL;
  186. //
  187. // Determine encoded length required.
  188. //
  189. if (!::CryptEncodeObject(CAPICOM_ASN_ENCODING,
  190. pszStructType,
  191. (const void *) pbData,
  192. NULL,
  193. &cbEncoded))
  194. {
  195. hr = HRESULT_FROM_WIN32(::GetLastError());
  196. DebugTrace("Unable to determine object encoded length [0x%x]: CryptEncodeObject() failed.\n", hr);
  197. goto CommonExit;
  198. }
  199. //
  200. // Allocate memory for encoded blob.
  201. //
  202. if (!(pbEncoded = (BYTE *) ::CoTaskMemAlloc(cbEncoded)))
  203. {
  204. hr = E_OUTOFMEMORY;
  205. DebugTrace("Out of memory: CoTaskMemAlloc(cbEncoded) failed.\n");
  206. goto CommonExit;
  207. }
  208. //
  209. // Encode.
  210. //
  211. if (!::CryptEncodeObject(CAPICOM_ASN_ENCODING,
  212. pszStructType,
  213. (const void *) pbData,
  214. pbEncoded,
  215. &cbEncoded))
  216. {
  217. hr = HRESULT_FROM_WIN32(::GetLastError());
  218. DebugTrace("Unable to encode object [0x%x]: CryptEncodeObject() failed.\n", hr);
  219. goto ErrorExit;
  220. }
  221. //
  222. // Return value.
  223. //
  224. pEncodedBlob->cbData = cbEncoded;
  225. pEncodedBlob->pbData = pbEncoded;
  226. CommonExit:
  227. DebugTrace("Leaving EncodeObject().\n");
  228. return hr;
  229. ErrorExit:
  230. //
  231. // Sanity check.
  232. //
  233. ATLASSERT(FAILED(hr));
  234. //
  235. // Free resources.
  236. //
  237. if (pbEncoded)
  238. {
  239. ::CoTaskMemFree((LPVOID) pbEncoded);
  240. }
  241. goto CommonExit;
  242. }
  243. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  244. Function : DecodeObject
  245. Synopsis : Allocate memory and decode an ASN.1 object using CAPI
  246. CryptDecodeObject() API.
  247. Parameter: LPCSRT pszStructType - see MSDN document for possible
  248. types.
  249. BYTE * pbEncoded - Pointer to data to be decoded
  250. (data type must match
  251. pszStructType).
  252. DWORD cbEncoded - Size of encoded data.
  253. CRYPT_DATA_BLOB * pDecodedBlob - Pointer to CRYPT_DATA_BLOB to
  254. receive the decoded length and
  255. data.
  256. Remark : No parameter check is done.
  257. ------------------------------------------------------------------------------*/
  258. HRESULT DecodeObject (LPCSTR pszStructType,
  259. BYTE * pbEncoded,
  260. DWORD cbEncoded,
  261. CRYPT_DATA_BLOB * pDecodedBlob)
  262. {
  263. HRESULT hr = S_OK;
  264. DWORD cbDecoded = 0;
  265. BYTE * pbDecoded = NULL;
  266. DebugTrace("Entering DecodeObject().\n");
  267. //
  268. // Sanity check.
  269. //
  270. ATLASSERT(pszStructType);
  271. ATLASSERT(pbEncoded);
  272. ATLASSERT(pDecodedBlob);
  273. //
  274. // Intialize return value.
  275. //
  276. pDecodedBlob->cbData = 0;
  277. pDecodedBlob->pbData = NULL;
  278. //
  279. // Determine encoded length required.
  280. //
  281. if (!::CryptDecodeObject(CAPICOM_ASN_ENCODING,
  282. pszStructType,
  283. (const BYTE *) pbEncoded,
  284. cbEncoded,
  285. 0,
  286. NULL,
  287. &cbDecoded))
  288. {
  289. hr = HRESULT_FROM_WIN32(::GetLastError());
  290. DebugTrace("Error [%#x]: CryptDecodeObject() failed.\n", hr);
  291. goto ErrorExit;
  292. }
  293. //
  294. // Allocate memory for decoded blob.
  295. //
  296. if (!(pbDecoded = (BYTE *) ::CoTaskMemAlloc(cbDecoded)))
  297. {
  298. hr = E_OUTOFMEMORY;
  299. DebugTrace("Error: out of memory.\n");
  300. goto ErrorExit;
  301. }
  302. //
  303. // Decode.
  304. //
  305. if (!::CryptDecodeObject(CAPICOM_ASN_ENCODING,
  306. pszStructType,
  307. (const BYTE *) pbEncoded,
  308. cbEncoded,
  309. 0,
  310. pbDecoded,
  311. &cbDecoded))
  312. {
  313. hr = HRESULT_FROM_WIN32(::GetLastError());
  314. DebugTrace("Error [%#x]: CryptDecodeObject() failed.\n", hr);
  315. goto ErrorExit;
  316. }
  317. //
  318. // Return value.
  319. //
  320. pDecodedBlob->cbData = cbDecoded;
  321. pDecodedBlob->pbData = pbDecoded;
  322. CommonExit:
  323. DebugTrace("Leaving DecodeObject().\n");
  324. return hr;
  325. ErrorExit:
  326. //
  327. // Sanity check.
  328. //
  329. ATLASSERT(FAILED(hr));
  330. //
  331. // Free resources.
  332. //
  333. if (pbDecoded)
  334. {
  335. ::CoTaskMemFree((LPVOID) pbDecoded);
  336. }
  337. goto CommonExit;
  338. }
  339. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  340. Function : GetKeyParam
  341. Synopsis : Allocate memory and retrieve requested key parameter using
  342. CryptGetKeyParam() API.
  343. Parameter: HCRYPTKEY hKey - Key handler.
  344. DWORD dwParam - Key parameter query.
  345. BYTE ** ppbData - Pointer to receive buffer.
  346. DWORD * pcbData - Size of buffer.
  347. Remark :
  348. ------------------------------------------------------------------------------*/
  349. HRESULT GetKeyParam (HCRYPTKEY hKey,
  350. DWORD dwParam,
  351. BYTE ** ppbData,
  352. DWORD * pcbData)
  353. {
  354. HRESULT hr = S_OK;
  355. DWORD cbData = 0;
  356. BYTE * pbData = NULL;
  357. DebugTrace("Entering GetKeyParam().\n");
  358. //
  359. // Sanity check.
  360. //
  361. ATLASSERT(ppbData);
  362. ATLASSERT(pcbData);
  363. //
  364. // Determine data buffer size.
  365. //
  366. if (!::CryptGetKeyParam(hKey,
  367. dwParam,
  368. NULL,
  369. &cbData,
  370. 0))
  371. {
  372. hr = HRESULT_FROM_WIN32(::GetLastError());
  373. DebugTrace("Error [%#x]: CryptGetKeyParam() failed.\n", hr);
  374. goto ErrorExit;
  375. }
  376. //
  377. // Allocate memory for buffer.
  378. //
  379. if (!(pbData = (BYTE *) ::CoTaskMemAlloc(cbData)))
  380. {
  381. hr = E_OUTOFMEMORY;
  382. DebugTrace("Error: out of memory.\n");
  383. goto ErrorExit;
  384. }
  385. //
  386. // Now get the data.
  387. //
  388. if (!::CryptGetKeyParam(hKey,
  389. dwParam,
  390. pbData,
  391. &cbData,
  392. 0))
  393. {
  394. hr = HRESULT_FROM_WIN32(::GetLastError());
  395. DebugTrace("Error [%#x]: CryptGetKeyParam() failed.\n", hr);
  396. goto ErrorExit;
  397. }
  398. //
  399. // Return key param to caller.
  400. //
  401. *ppbData = pbData;
  402. *pcbData = cbData;
  403. CommonExit:
  404. DebugTrace("Leaving GetKeyParam().\n");
  405. return hr;
  406. ErrorExit:
  407. //
  408. // Sanity check.
  409. //
  410. ATLASSERT(FAILED(hr));
  411. //
  412. // Free resources.
  413. //
  414. if (pbData)
  415. {
  416. ::CoTaskMemFree(pbData);
  417. }
  418. goto CommonExit;
  419. }
  420. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  421. Function : IsAlgSupported
  422. Synopsis : Check to see if the algo is supported by the CSP.
  423. Parameter: HCRYPTPROV hCryptProv - CSP handle.
  424. ALG_ID AlgId - Algorithm ID.
  425. PROV_ENUMALGS_EX * pPeex - Pointer to PROV_ENUMALGS_EX to receive
  426. the found structure.
  427. Remark :
  428. ------------------------------------------------------------------------------*/
  429. HRESULT IsAlgSupported (HCRYPTPROV hCryptProv,
  430. ALG_ID AlgId,
  431. PROV_ENUMALGS_EX * pPeex)
  432. {
  433. DWORD EnumFlag = CRYPT_FIRST;
  434. DWORD cbPeex = sizeof(PROV_ENUMALGS_EX);
  435. //
  436. // Sanity check.
  437. //
  438. ATLASSERT(hCryptProv);
  439. ATLASSERT(pPeex);
  440. //
  441. // Initialize.
  442. //
  443. ::ZeroMemory(pPeex, sizeof(PROV_ENUMALGS_EX));
  444. //
  445. // Get algorithm capability from CSP.
  446. //
  447. while (::CryptGetProvParam(hCryptProv, PP_ENUMALGS_EX, (BYTE *) pPeex,
  448. &cbPeex, EnumFlag))
  449. {
  450. EnumFlag = 0;
  451. if (pPeex->aiAlgid == AlgId)
  452. {
  453. return S_OK;
  454. }
  455. }
  456. return CAPICOM_E_NOT_SUPPORTED;
  457. }
  458. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  459. Function : IsAlgKeyLengthSupported
  460. Synopsis : Check to see if the algo and key length is supported by the CSP.
  461. Parameter: HCRYPTPROV hCryptProv - CSP handle.
  462. ALG_ID AlgID - Algorithm ID.
  463. DWORD dwKeyLength - Key length
  464. Remark :
  465. ------------------------------------------------------------------------------*/
  466. HRESULT IsAlgKeyLengthSupported (HCRYPTPROV hCryptProv,
  467. ALG_ID AlgID,
  468. DWORD dwKeyLength)
  469. {
  470. HRESULT hr;
  471. PROV_ENUMALGS_EX peex;
  472. //
  473. // Sanity check.
  474. //
  475. ATLASSERT(hCryptProv);
  476. //
  477. // Make sure AlgID is supported.
  478. //
  479. if (FAILED(hr = ::IsAlgSupported(hCryptProv, AlgID, &peex)))
  480. {
  481. DebugTrace("Info: AlgID = %d is not supported by this CSP.\n", AlgID);
  482. return hr;
  483. }
  484. //
  485. // Make sure key length is supported for RC2 and RC4.
  486. //
  487. if (AlgID == CALG_RC2 || AlgID == CALG_RC4)
  488. {
  489. if (dwKeyLength < peex.dwMinLen || dwKeyLength > peex.dwMaxLen)
  490. {
  491. DebugTrace("Info: Key length = %d is not supported by this CSP.\n", dwKeyLength);
  492. return CAPICOM_E_NOT_SUPPORTED;
  493. }
  494. }
  495. return S_OK;
  496. }
  497. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  498. Function : AcquireContext
  499. Synopsis : Acquire context for the specified CSP and keyset container.
  500. Parameter: LPSTR pszProvider - CSP provider name or NULL.
  501. LPSTR pszContainer - Keyset container name or NULL.
  502. DWORD dwProvType - Provider type.
  503. DWORD dwFlags - Same as dwFlags of CryptAcquireConext.
  504. BOOL bNewKeyset - TRUE to create new keyset container, else FALSE.
  505. HCRYPTPROV * phCryptProv - Pointer to HCRYPTPROV to recevice
  506. CSP context.
  507. Remark :
  508. ------------------------------------------------------------------------------*/
  509. HRESULT AcquireContext(LPSTR pszProvider,
  510. LPSTR pszContainer,
  511. DWORD dwProvType,
  512. DWORD dwFlags,
  513. BOOL bNewKeyset,
  514. HCRYPTPROV * phCryptProv)
  515. {
  516. HRESULT hr = S_OK;
  517. HCRYPTPROV hCryptProv = NULL;
  518. DebugTrace("Entering AcquireContext().\n");
  519. //
  520. // Sanity check.
  521. //
  522. ATLASSERT(phCryptProv);
  523. //
  524. // Get handle to the specified provider.
  525. //
  526. if(!::CryptAcquireContextA(&hCryptProv,
  527. pszContainer,
  528. pszProvider,
  529. dwProvType,
  530. dwFlags))
  531. {
  532. DWORD dwWinError = ::GetLastError();
  533. if (NTE_BAD_KEYSET != dwWinError || NTE_KEYSET_NOT_DEF == dwWinError || !bNewKeyset)
  534. {
  535. hr = HRESULT_FROM_WIN32(dwWinError);
  536. DebugTrace("Error [%#x]: CryptAcquireContextA() failed.\n", hr);
  537. goto CommonExit;
  538. }
  539. //
  540. // Keyset container not found, so create it.
  541. //
  542. if(!::CryptAcquireContextA(&hCryptProv,
  543. pszContainer,
  544. pszProvider,
  545. dwProvType,
  546. CRYPT_NEWKEYSET | dwFlags))
  547. {
  548. hr = HRESULT_FROM_WIN32(::GetLastError());
  549. DebugTrace("Error [%#x]: CryptAcquireContextA() failed.\n", hr);
  550. goto CommonExit;
  551. }
  552. }
  553. //
  554. // Return handle to caller.
  555. //
  556. *phCryptProv = hCryptProv;
  557. CommonExit:
  558. DebugTrace("Leaving AcquireContext().\n");
  559. return hr;
  560. }
  561. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  562. Function : AcquireContext
  563. Synopsis : Acquire context for the specified CSP and keyset container.
  564. Parameter: LPWSTR pwszProvider - CSP provider name or NULL.
  565. LPWSTR pwszContainer - Keyset container name or NULL.
  566. DWORD dwProvType - Provider type.
  567. DWORD dwFlags - Same as dwFlags of CryptAcquireConext.
  568. BOOL bNewKeyset - TRUE to create new keyset container, else FALSE.
  569. HCRYPTPROV * phCryptProv - Pointer to HCRYPTPROV to recevice
  570. CSP context.
  571. Remark :
  572. ------------------------------------------------------------------------------*/
  573. HRESULT AcquireContext(LPWSTR pwszProvider,
  574. LPWSTR pwszContainer,
  575. DWORD dwProvType,
  576. DWORD dwFlags,
  577. BOOL bNewKeyset,
  578. HCRYPTPROV * phCryptProv)
  579. {
  580. HRESULT hr = S_OK;
  581. LPSTR pszProvider = NULL;
  582. LPSTR pszContainer = NULL;
  583. DebugTrace("Entering AcquireContext().\n");
  584. //
  585. // Sanity check.
  586. //
  587. ATLASSERT(phCryptProv);
  588. //
  589. // Call W directly if available.
  590. //
  591. if (IsWinNTAndAbove())
  592. {
  593. //
  594. // Get handle to the specified provider.
  595. //
  596. if(!::CryptAcquireContextW(phCryptProv,
  597. pwszContainer,
  598. pwszProvider,
  599. dwProvType,
  600. dwFlags))
  601. {
  602. DWORD dwWinError = ::GetLastError();
  603. if (NTE_BAD_KEYSET != dwWinError || NTE_KEYSET_NOT_DEF == dwWinError || !bNewKeyset)
  604. {
  605. hr = HRESULT_FROM_WIN32(dwWinError);
  606. DebugTrace("Error [%#x]: CryptAcquireContextW() failed.\n", hr);
  607. goto ErrorExit;
  608. }
  609. //
  610. // Keyset container not found, so create it.
  611. //
  612. if(!::CryptAcquireContextW(phCryptProv,
  613. pwszContainer,
  614. pwszProvider,
  615. dwProvType,
  616. CRYPT_NEWKEYSET | dwFlags))
  617. {
  618. hr = HRESULT_FROM_WIN32(::GetLastError());
  619. DebugTrace("Error [%#x]: CryptAcquireContextW() failed.\n", hr);
  620. goto ErrorExit;
  621. }
  622. }
  623. }
  624. else
  625. {
  626. //
  627. // Convert to ANSI.
  628. //
  629. if (pwszProvider &&
  630. FAILED(hr = ::UnicodeToAnsi(pwszProvider, -1, &pszProvider, NULL)))
  631. {
  632. DebugTrace("Error [%#x]: UnicodeToAnsi() failed.\n", hr);
  633. goto ErrorExit;
  634. }
  635. if (pwszContainer &&
  636. FAILED(hr = ::UnicodeToAnsi(pwszContainer, -1, &pszContainer, NULL)))
  637. {
  638. DebugTrace("Error [%#x]: UnicodeToAnsi() failed.\n", hr);
  639. goto ErrorExit;
  640. }
  641. //
  642. // Call ANSI version.
  643. //
  644. hr = ::AcquireContext(pszProvider, pszContainer, dwProvType, dwFlags, bNewKeyset, phCryptProv);
  645. }
  646. CommonExit:
  647. //
  648. // Free resources.
  649. //
  650. if (pszProvider)
  651. {
  652. ::CoTaskMemFree((LPVOID) pszProvider);
  653. }
  654. if (pszContainer)
  655. {
  656. ::CoTaskMemFree((LPVOID) pszContainer);
  657. }
  658. DebugTrace("Leaving AcquireContext().\n");
  659. return hr;
  660. ErrorExit:
  661. //
  662. // Sanity check.
  663. //
  664. ATLASSERT(FAILED(hr));
  665. goto CommonExit;
  666. }
  667. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  668. Function : AcquireContext
  669. Synopsis : Acquire context of a CSP using the default container for a
  670. specified hash algorithm.
  671. Parameter: ALG_ID AlgOID - Algorithm ID.
  672. HCRYPTPROV * phCryptProv - Pointer to HCRYPTPROV to recevice
  673. CSP context.
  674. Remark : Note that KeyLength will be ignored for DES and 3DES.
  675. ------------------------------------------------------------------------------*/
  676. HRESULT AcquireContext(ALG_ID AlgID,
  677. HCRYPTPROV * phCryptProv)
  678. {
  679. HRESULT hr = S_OK;
  680. DebugTrace("Entering AcquireContext().\n");
  681. //
  682. // Sanity check.
  683. //
  684. ATLASSERT(phCryptProv);
  685. //
  686. // Find the first provider that support the specified algorithm.
  687. //
  688. for (DWORD i = 0; i < g_dwNumProviders; i++)
  689. {
  690. PROV_ENUMALGS_EX peex;
  691. HCRYPTPROV hCryptProv = NULL;
  692. //
  693. // Acquire CSP handle.
  694. //
  695. if (FAILED(::AcquireContext(g_rgpProviders[i].pszProvider,
  696. NULL,
  697. g_rgpProviders[i].dwProvType,
  698. CRYPT_VERIFYCONTEXT,
  699. TRUE,
  700. &hCryptProv)))
  701. {
  702. DebugTrace("Info: AcquireContext() failed for %s provider of type %#x.\n",
  703. g_rgpProviders[i].pszProvider ? g_rgpProviders[i].pszProvider : "default",
  704. g_rgpProviders[i].dwProvType);
  705. continue;
  706. }
  707. //
  708. // Make sure algo is supported by this CSP.
  709. //
  710. if (FAILED(::IsAlgSupported(hCryptProv, AlgID, &peex)))
  711. {
  712. ::CryptReleaseContext(hCryptProv, 0);
  713. DebugTrace("Info: %s provider does not support AlgID = %d.\n",
  714. g_rgpProviders[i].pszProvider ? g_rgpProviders[i].pszProvider : "Default",
  715. AlgID);
  716. }
  717. else
  718. {
  719. //
  720. // Found the CSP.
  721. //
  722. *phCryptProv = hCryptProv;
  723. break;
  724. }
  725. }
  726. //
  727. // Did we find the CSP.
  728. //
  729. if (i == g_dwNumProviders)
  730. {
  731. *phCryptProv = NULL;
  732. hr = CAPICOM_E_NOT_SUPPORTED;
  733. DebugTrace("Error [%#x]: could not find a CSP that support AlgID = %d.\n",
  734. hr, AlgID);
  735. }
  736. DebugTrace("Leaving AcquireContext().\n");
  737. return hr;
  738. }
  739. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  740. Function : AcquireContext
  741. Synopsis : Acquire context of a CSP using the default container for a
  742. specified encryption algorithm and desired key length.
  743. Parameter: ALG_ID AlgOID - Algorithm ID.
  744. DWORD dwKeyLength - Key length.
  745. HCRYPTPROV * phCryptProv - Pointer to HCRYPTPROV to recevice
  746. CSP context.
  747. Remark : Note that KeyLength will be ignored for DES and 3DES.
  748. ------------------------------------------------------------------------------*/
  749. HRESULT AcquireContext(ALG_ID AlgID,
  750. DWORD dwKeyLength,
  751. HCRYPTPROV * phCryptProv)
  752. {
  753. HRESULT hr = S_OK;
  754. DebugTrace("Entering AcquireContext().\n");
  755. //
  756. // Sanity check.
  757. //
  758. ATLASSERT(phCryptProv);
  759. //
  760. // Find the first provider that support the specified
  761. // algorithm and key length.
  762. //
  763. for (DWORD i = 0; i < g_dwNumProviders; i++)
  764. {
  765. HCRYPTPROV hCryptProv = NULL;
  766. //
  767. // Acquire CSP handle.
  768. //
  769. if (FAILED(::AcquireContext(g_rgpProviders[i].pszProvider,
  770. NULL,
  771. g_rgpProviders[i].dwProvType,
  772. CRYPT_VERIFYCONTEXT,
  773. TRUE,
  774. &hCryptProv)))
  775. {
  776. DebugTrace("Info: AcquireContext() failed for %s provider of type %#x.\n",
  777. g_rgpProviders[i].pszProvider ? g_rgpProviders[i].pszProvider : "default",
  778. g_rgpProviders[i].dwProvType);
  779. continue;
  780. }
  781. //
  782. // Make sure algo and key length are supported by this CSP.
  783. //
  784. if (FAILED(::IsAlgKeyLengthSupported(hCryptProv, AlgID, dwKeyLength)))
  785. {
  786. ::CryptReleaseContext(hCryptProv, 0);
  787. DebugTrace("Info: %s provider does not support AlgID = %d and/or key length = %d.\n",
  788. g_rgpProviders[i].pszProvider ? g_rgpProviders[i].pszProvider : "Default",
  789. AlgID, dwKeyLength);
  790. }
  791. else
  792. {
  793. //
  794. // Found the CSP.
  795. //
  796. DebugTrace("Info: Found CSP = %s.\n", g_rgpProviders[i].pszProvider);
  797. *phCryptProv = hCryptProv;
  798. break;
  799. }
  800. }
  801. //
  802. // Did we find the CSP.
  803. //
  804. if (i == g_dwNumProviders)
  805. {
  806. *phCryptProv = NULL;
  807. hr = CAPICOM_E_NOT_SUPPORTED;
  808. DebugTrace("Error [%#x]: could not find a CSP that support AlgID = %d and/or key length = %d.\n",
  809. hr, AlgID, dwKeyLength);
  810. }
  811. DebugTrace("Leaving AcquireContext().\n");
  812. return hr;
  813. }
  814. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  815. Function : AcquireContext
  816. Synopsis : Acquire context of a CSP using the default container for a
  817. specified algorithm and desired key length.
  818. Parameter: CAPICOM_ENCRYPTION_ALGORITHM AlgoName - Algorithm name.
  819. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength - Key length.
  820. HCRYPTPROV * phCryptProv - Pointer to HCRYPTPROV to recevice
  821. CSP context.
  822. Remark : Note that KeyLength will be ignored for DES and 3DES.
  823. Note also the the returned handle cannot be used to access private
  824. key, and should NOT be used to store assymetric key, as it refers
  825. to the default container, which can be easily destroy any existing
  826. assymetric key pair.
  827. ------------------------------------------------------------------------------*/
  828. HRESULT AcquireContext (CAPICOM_ENCRYPTION_ALGORITHM AlgoName,
  829. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength,
  830. HCRYPTPROV * phCryptProv)
  831. {
  832. HRESULT hr = S_OK;
  833. ALG_ID AlgID = 0;
  834. DWORD dwKeyLength = 0;
  835. DebugTrace("Entering AcquireContext().\n");
  836. //
  837. // Sanity check.
  838. //
  839. ATLASSERT(phCryptProv);
  840. //
  841. // Convert enum name to ALG_ID.
  842. //
  843. if (FAILED(hr = ::EnumNameToAlgID(AlgoName, KeyLength, &AlgID)))
  844. {
  845. DebugTrace("Error [%#x]: EnumNameToAlgID() failed.\n");
  846. goto CommonExit;
  847. }
  848. //
  849. // Convert enum name to key length.
  850. //
  851. if (FAILED(hr = ::EnumNameToKeyLength(KeyLength, AlgID, &dwKeyLength)))
  852. {
  853. DebugTrace("Error [%#x]: EnumNameToKeyLength() failed.\n");
  854. goto CommonExit;
  855. }
  856. //
  857. // Pass on to overloaded version.
  858. //
  859. hr = ::AcquireContext(AlgID, dwKeyLength, phCryptProv);
  860. CommonExit:
  861. DebugTrace("Leaving AcquireContext().\n");
  862. return hr;
  863. }
  864. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  865. Function : AcquireContext
  866. Synopsis : Acquire the proper CSP and access to the private key for
  867. the specified cert.
  868. Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT of cert.
  869. HCRYPTPROV * phCryptProv - Pointer to HCRYPTPROV to recevice
  870. CSP context.
  871. DWORD * pdwKeySpec - Pointer to DWORD to receive key
  872. spec, AT_KEYEXCHANGE or AT_SIGNATURE.
  873. BOOL * pbReleaseContext - Upon successful and if this is set
  874. to TRUE, then the caller must
  875. free the CSP context by calling
  876. CryptReleaseContext(), otherwise
  877. the caller must not free the CSP
  878. context.
  879. Remark :
  880. ------------------------------------------------------------------------------*/
  881. HRESULT AcquireContext (PCCERT_CONTEXT pCertContext,
  882. HCRYPTPROV * phCryptProv,
  883. DWORD * pdwKeySpec,
  884. BOOL * pbReleaseContext)
  885. {
  886. HRESULT hr = S_OK;
  887. DebugTrace("Entering AcquireContext().\n");
  888. //
  889. // Sanity check.
  890. //
  891. ATLASSERT(pCertContext);
  892. ATLASSERT(phCryptProv);
  893. ATLASSERT(pdwKeySpec);
  894. ATLASSERT(pbReleaseContext);
  895. //
  896. // Acquire CSP context and access to the private key associated
  897. // with this cert.
  898. //
  899. if (!::CryptAcquireCertificatePrivateKey(pCertContext,
  900. CRYPT_ACQUIRE_USE_PROV_INFO_FLAG |
  901. CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
  902. NULL,
  903. phCryptProv,
  904. pdwKeySpec,
  905. pbReleaseContext))
  906. {
  907. hr = HRESULT_FROM_WIN32(::GetLastError());
  908. DebugTrace("Error [%#x]: CryptAcquireCertificatePrivateKey() failed.\n", hr);
  909. }
  910. DebugTrace("Leaving AcquireContext().\n");
  911. return hr;
  912. }
  913. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  914. Function : ReleaseContext
  915. Synopsis : Release CSP context.
  916. Parameter: HCRYPTPROV hProv - CSP handle.
  917. Remark :
  918. ------------------------------------------------------------------------------*/
  919. HRESULT ReleaseContext (HCRYPTPROV hProv)
  920. {
  921. HRESULT hr = S_OK;
  922. DebugTrace("Entering ReleaseContext().\n");
  923. //
  924. // Sanity check.
  925. //
  926. ATLASSERT(hProv);
  927. //
  928. // Release the context.
  929. //
  930. if (!::CryptReleaseContext(hProv, 0))
  931. {
  932. hr = HRESULT_FROM_WIN32(::GetLastError());
  933. DebugTrace("Error [%#x]: CryptReleaseContext() failed.\n", hr);
  934. }
  935. DebugTrace("Leaving ReleaseContext().\n");
  936. return hr;
  937. }
  938. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  939. Function : OIDToAlgID
  940. Synopsis : Convert algorithm OID to the corresponding ALG_ID value.
  941. Parameter: LPSTR pszAlgoOID - Algorithm OID string.
  942. ALG_ID * pAlgID - Pointer to ALG_ID to receive the value.
  943. Remark :
  944. ------------------------------------------------------------------------------*/
  945. HRESULT OIDToAlgID (LPSTR pszAlgoOID,
  946. ALG_ID * pAlgID)
  947. {
  948. HRESULT hr = S_OK;
  949. DebugTrace("Entering OIDToAlgID().\n");
  950. //
  951. // Sanity check.
  952. //
  953. ATLASSERT(pszAlgoOID);
  954. ATLASSERT(pAlgID);
  955. //
  956. // Determine ALG_ID.
  957. //
  958. if (0 == ::strcmp(szOID_RSA_RC2CBC, pszAlgoOID))
  959. {
  960. *pAlgID = CALG_RC2;
  961. }
  962. else if (0 == ::strcmp(szOID_RSA_RC4, pszAlgoOID))
  963. {
  964. *pAlgID = CALG_RC4;
  965. }
  966. else if (0 == ::strcmp(szOID_OIWSEC_desCBC, pszAlgoOID))
  967. {
  968. *pAlgID = CALG_DES;
  969. }
  970. else if (0 == ::strcmp(szOID_RSA_DES_EDE3_CBC, pszAlgoOID))
  971. {
  972. *pAlgID = CALG_3DES;
  973. }
  974. else
  975. {
  976. hr = CAPICOM_E_INVALID_ALGORITHM;
  977. DebugTrace("Error: invalid parameter, unknown algorithm OID.\n");
  978. }
  979. DebugTrace("Leaving OIDToAlgID().\n");
  980. return hr;
  981. }
  982. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  983. Function : AlgIDToOID
  984. Synopsis : Convert ALG_ID value to the corresponding algorithm OID.
  985. Parameter: ALG_ID AlgID - ALG_ID to be converted.
  986. LPSTR * ppszAlgoOID - Pointer to LPSTR to receive the OID string.
  987. Remark :
  988. ------------------------------------------------------------------------------*/
  989. HRESULT AlgIDToOID (ALG_ID AlgID,
  990. LPSTR * ppszAlgoOID)
  991. {
  992. HRESULT hr = S_OK;
  993. LPSTR pszAlgoOID = NULL;
  994. DebugTrace("Entering AlgIDToOID().\n");
  995. //
  996. // Sanity check.
  997. //
  998. ATLASSERT(ppszAlgoOID);
  999. //
  1000. // Determine ALG_ID.
  1001. //
  1002. switch (AlgID)
  1003. {
  1004. case CALG_RC2:
  1005. {
  1006. pszAlgoOID = szOID_RSA_RC2CBC;
  1007. break;
  1008. }
  1009. case CALG_RC4:
  1010. {
  1011. pszAlgoOID = szOID_RSA_RC4;
  1012. break;
  1013. }
  1014. case CALG_DES:
  1015. {
  1016. pszAlgoOID = szOID_OIWSEC_desCBC;
  1017. break;
  1018. }
  1019. case CALG_3DES:
  1020. {
  1021. pszAlgoOID = szOID_RSA_DES_EDE3_CBC;
  1022. break;
  1023. }
  1024. default:
  1025. {
  1026. hr = CAPICOM_E_INVALID_ALGORITHM;
  1027. DebugTrace("Error [%#x]: Unknown ALG_ID (%#x).\n", hr, AlgID);
  1028. goto CommonExit;
  1029. }
  1030. }
  1031. //
  1032. // Allocate memory.
  1033. //
  1034. if (!(*ppszAlgoOID = (LPSTR) ::CoTaskMemAlloc(::strlen(pszAlgoOID) + 1)))
  1035. {
  1036. hr = E_OUTOFMEMORY;
  1037. DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
  1038. goto CommonExit;
  1039. }
  1040. //
  1041. // Copy OID string to caller.
  1042. //
  1043. ::strcpy(*ppszAlgoOID, pszAlgoOID);
  1044. CommonExit:
  1045. DebugTrace("Leaving AlgIDToOID().\n");
  1046. return hr;
  1047. }
  1048. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1049. Function : AlgIDToEnumName
  1050. Synopsis : Convert ALG_ID value to the corresponding algorithm enum name.
  1051. Parameter: ALG_ID AlgID - ALG_ID to be converted.
  1052. CAPICOM_ENCRYPTION_ALGORITHM * pAlgoName - Receive algo enum name.
  1053. Remark :
  1054. ------------------------------------------------------------------------------*/
  1055. HRESULT AlgIDToEnumName (ALG_ID AlgID,
  1056. CAPICOM_ENCRYPTION_ALGORITHM * pAlgoName)
  1057. {
  1058. HRESULT hr = S_OK;
  1059. DebugTrace("Entering AlgIDToEnumName().\n");
  1060. //
  1061. // Sanity check.
  1062. //
  1063. ATLASSERT(pAlgoName);
  1064. switch (AlgID)
  1065. {
  1066. case CALG_RC2:
  1067. {
  1068. *pAlgoName = CAPICOM_ENCRYPTION_ALGORITHM_RC2;
  1069. break;
  1070. }
  1071. case CALG_RC4:
  1072. {
  1073. *pAlgoName = CAPICOM_ENCRYPTION_ALGORITHM_RC4;
  1074. break;
  1075. }
  1076. case CALG_DES:
  1077. {
  1078. *pAlgoName = CAPICOM_ENCRYPTION_ALGORITHM_DES;
  1079. break;
  1080. }
  1081. case CALG_3DES:
  1082. {
  1083. *pAlgoName = CAPICOM_ENCRYPTION_ALGORITHM_3DES;
  1084. break;
  1085. }
  1086. case CALG_AES_128:
  1087. case CALG_AES_192:
  1088. case CALG_AES_256:
  1089. {
  1090. *pAlgoName = CAPICOM_ENCRYPTION_ALGORITHM_AES;
  1091. break;
  1092. }
  1093. default:
  1094. {
  1095. hr = CAPICOM_E_INVALID_ALGORITHM;
  1096. DebugTrace("Error: invalid parameter, unknown ALG_ID.\n");
  1097. }
  1098. }
  1099. DebugTrace("Leaving AlgIDToEnumName().\n");
  1100. return hr;
  1101. }
  1102. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1103. Function : EnumNameToAlgID
  1104. Synopsis : Convert algorithm enum name to the corresponding ALG_ID value.
  1105. Parameter: CAPICOM_ENCRYPTION_ALGORITHM AlgoName - Algo enum name.
  1106. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength - Key length.
  1107. ALG_ID * pAlgID - Pointer to ALG_ID to receive the value.
  1108. Remark :
  1109. ------------------------------------------------------------------------------*/
  1110. HRESULT EnumNameToAlgID (CAPICOM_ENCRYPTION_ALGORITHM AlgoName,
  1111. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength,
  1112. ALG_ID * pAlgID)
  1113. {
  1114. HRESULT hr = S_OK;
  1115. DebugTrace("Entering EnumNameToAlgID().\n");
  1116. //
  1117. // Sanity check.
  1118. //
  1119. ATLASSERT(pAlgID);
  1120. switch (AlgoName)
  1121. {
  1122. case CAPICOM_ENCRYPTION_ALGORITHM_RC2:
  1123. {
  1124. *pAlgID = CALG_RC2;
  1125. break;
  1126. }
  1127. case CAPICOM_ENCRYPTION_ALGORITHM_RC4:
  1128. {
  1129. *pAlgID = CALG_RC4;
  1130. break;
  1131. }
  1132. case CAPICOM_ENCRYPTION_ALGORITHM_DES:
  1133. {
  1134. *pAlgID = CALG_DES;
  1135. break;
  1136. }
  1137. case CAPICOM_ENCRYPTION_ALGORITHM_3DES:
  1138. {
  1139. *pAlgID = CALG_3DES;
  1140. break;
  1141. }
  1142. case CAPICOM_ENCRYPTION_ALGORITHM_AES:
  1143. {
  1144. //
  1145. // CAPI uses a different scheme for AES (key length is tied to ALG_ID).
  1146. //
  1147. if (CAPICOM_ENCRYPTION_KEY_LENGTH_MAXIMUM == KeyLength ||
  1148. CAPICOM_ENCRYPTION_KEY_LENGTH_256_BITS == KeyLength)
  1149. {
  1150. *pAlgID = CALG_AES_256;
  1151. }
  1152. else if (CAPICOM_ENCRYPTION_KEY_LENGTH_192_BITS == KeyLength)
  1153. {
  1154. *pAlgID = CALG_AES_192;
  1155. }
  1156. else if (CAPICOM_ENCRYPTION_KEY_LENGTH_128_BITS == KeyLength)
  1157. {
  1158. *pAlgID = CALG_AES_128;
  1159. }
  1160. else
  1161. {
  1162. hr = CAPICOM_E_INVALID_KEY_LENGTH;
  1163. DebugTrace("Error [%#x]: Invalid key length (%d) specified for AES.\n", hr, KeyLength);
  1164. goto ErrorExit;
  1165. }
  1166. break;
  1167. }
  1168. default:
  1169. {
  1170. hr = CAPICOM_E_INVALID_ALGORITHM;
  1171. DebugTrace("Error [%#x]: Unknown CAPICOM_ENCRYPTION_ALGORITHM (%#x).\n", hr, AlgoName);
  1172. }
  1173. }
  1174. CommonExit:
  1175. DebugTrace("Leaving EnumNameToAlgID().\n");
  1176. return hr;
  1177. ErrorExit:
  1178. //
  1179. // Sanity check.
  1180. //
  1181. ATLASSERT(FAILED(hr));
  1182. goto CommonExit;
  1183. }
  1184. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1185. Function : KeyLengthToEnumName
  1186. Synopsis : Convert actual key length value to the corresponding key length
  1187. enum name.
  1188. Parameter: DWORD dwKeyLength - Key length.
  1189. ALG_ID AlgId - Algo ID.
  1190. CAPICOM_ENCRYPTION_KEY_LENGTH * pKeyLengthName - Receive key length
  1191. enum name.
  1192. Remark :
  1193. ------------------------------------------------------------------------------*/
  1194. HRESULT KeyLengthToEnumName (DWORD dwKeyLength,
  1195. ALG_ID AlgId,
  1196. CAPICOM_ENCRYPTION_KEY_LENGTH * pKeyLengthName)
  1197. {
  1198. HRESULT hr = S_OK;
  1199. DebugTrace("Entering KeyLengthToEnumName().\n");
  1200. //
  1201. // Sanity check.
  1202. //
  1203. ATLASSERT(pKeyLengthName);
  1204. switch (AlgId)
  1205. {
  1206. case CALG_AES_256:
  1207. {
  1208. *pKeyLengthName = CAPICOM_ENCRYPTION_KEY_LENGTH_256_BITS;
  1209. break;
  1210. }
  1211. case CALG_AES_192:
  1212. {
  1213. *pKeyLengthName = CAPICOM_ENCRYPTION_KEY_LENGTH_192_BITS;
  1214. break;
  1215. }
  1216. case CALG_AES_128:
  1217. {
  1218. *pKeyLengthName = CAPICOM_ENCRYPTION_KEY_LENGTH_128_BITS;
  1219. break;
  1220. }
  1221. default:
  1222. {
  1223. switch (dwKeyLength)
  1224. {
  1225. case 40:
  1226. {
  1227. *pKeyLengthName = CAPICOM_ENCRYPTION_KEY_LENGTH_40_BITS;
  1228. break;
  1229. }
  1230. case 56:
  1231. {
  1232. *pKeyLengthName = CAPICOM_ENCRYPTION_KEY_LENGTH_56_BITS;
  1233. break;
  1234. }
  1235. case 128:
  1236. {
  1237. *pKeyLengthName = CAPICOM_ENCRYPTION_KEY_LENGTH_128_BITS;
  1238. break;
  1239. }
  1240. default:
  1241. {
  1242. hr = CAPICOM_E_INVALID_KEY_LENGTH;
  1243. DebugTrace("Error [%#x]: Unknown key length (%#x).\n", hr, dwKeyLength);
  1244. }
  1245. }
  1246. }
  1247. }
  1248. DebugTrace("Leaving KeyLengthToEnumName().\n");
  1249. return hr;
  1250. }
  1251. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1252. Function : EnumNameToKeyLength
  1253. Synopsis : Convert key length enum name to the corresponding actual key length
  1254. value .
  1255. Parameter: CAPICOM_ENCRYPTION_KEY_LENGTH KeyLengthName - Key length enum name.
  1256. ALG_ID AlgId - Algorithm ID.
  1257. DWORD * pdwKeyLength - Pointer to DWORD to receive value.
  1258. Remark :
  1259. ------------------------------------------------------------------------------*/
  1260. HRESULT EnumNameToKeyLength (CAPICOM_ENCRYPTION_KEY_LENGTH KeyLengthName,
  1261. ALG_ID AlgId,
  1262. DWORD * pdwKeyLength)
  1263. {
  1264. HRESULT hr = S_OK;
  1265. DebugTrace("Entering EnumNameToKeyLength().\n");
  1266. //
  1267. // Sanity check.
  1268. //
  1269. ATLASSERT(pdwKeyLength);
  1270. *pdwKeyLength = 0;
  1271. switch (KeyLengthName)
  1272. {
  1273. case CAPICOM_ENCRYPTION_KEY_LENGTH_40_BITS:
  1274. {
  1275. *pdwKeyLength = 40;
  1276. break;
  1277. }
  1278. case CAPICOM_ENCRYPTION_KEY_LENGTH_56_BITS:
  1279. {
  1280. *pdwKeyLength = 56;
  1281. break;
  1282. }
  1283. case CAPICOM_ENCRYPTION_KEY_LENGTH_128_BITS:
  1284. {
  1285. *pdwKeyLength = 128;
  1286. break;
  1287. }
  1288. case CAPICOM_ENCRYPTION_KEY_LENGTH_192_BITS:
  1289. {
  1290. *pdwKeyLength = 192;
  1291. break;
  1292. }
  1293. case CAPICOM_ENCRYPTION_KEY_LENGTH_256_BITS:
  1294. {
  1295. *pdwKeyLength = 256;
  1296. break;
  1297. }
  1298. case CAPICOM_ENCRYPTION_KEY_LENGTH_MAXIMUM:
  1299. {
  1300. switch (AlgId)
  1301. {
  1302. case CALG_AES_128:
  1303. {
  1304. *pdwKeyLength = 128;
  1305. break;
  1306. }
  1307. case CALG_AES_192:
  1308. {
  1309. *pdwKeyLength = 192;
  1310. break;
  1311. }
  1312. case CALG_AES_256:
  1313. {
  1314. *pdwKeyLength = 256;
  1315. break;
  1316. }
  1317. default:
  1318. {
  1319. DWORD dwFlags = 0;
  1320. //
  1321. // No need to access assymetric key.
  1322. //
  1323. if (IsWin2KAndAbove())
  1324. {
  1325. dwFlags = CRYPT_VERIFYCONTEXT;
  1326. }
  1327. //
  1328. // Find the first RSA provider that supports the specified algorithm.
  1329. //
  1330. for (DWORD i = 0; i < g_dwNumRSAProviders; i++)
  1331. {
  1332. PROV_ENUMALGS_EX peex;
  1333. HCRYPTPROV hCryptProv = NULL;
  1334. //
  1335. // Acquire CSP handle.
  1336. //
  1337. if (FAILED(::AcquireContext(g_rgpProviders[i].pszProvider,
  1338. NULL,
  1339. g_rgpProviders[i].dwProvType,
  1340. dwFlags,
  1341. TRUE,
  1342. &hCryptProv)))
  1343. {
  1344. DebugTrace("Info: AcquireContext() failed for %s provider of type %#x.\n",
  1345. g_rgpProviders[i].pszProvider ? g_rgpProviders[i].pszProvider : "default",
  1346. g_rgpProviders[i].dwProvType);
  1347. continue;
  1348. }
  1349. //
  1350. // Is this algorithm supported?
  1351. //
  1352. if (FAILED(::IsAlgSupported(hCryptProv, AlgId, &peex)))
  1353. {
  1354. ::CryptReleaseContext(hCryptProv, 0);
  1355. DebugTrace("Info: %s provider does not support AlgID = %d.\n",
  1356. g_rgpProviders[i].pszProvider ? g_rgpProviders[i].pszProvider : "default",
  1357. AlgId);
  1358. continue;
  1359. }
  1360. //
  1361. // Set key length
  1362. //
  1363. if (CALG_DES == AlgId)
  1364. {
  1365. *pdwKeyLength = 56;
  1366. break;
  1367. }
  1368. else if (CALG_3DES == AlgId)
  1369. {
  1370. *pdwKeyLength = 168;
  1371. break;
  1372. }
  1373. else if (peex.dwMaxLen >= 128)
  1374. {
  1375. *pdwKeyLength = 128;
  1376. break;
  1377. }
  1378. else if (peex.dwMaxLen >= 56)
  1379. {
  1380. *pdwKeyLength = 56;
  1381. break;
  1382. }
  1383. else if (peex.dwMaxLen >= 40)
  1384. {
  1385. *pdwKeyLength = 40;
  1386. break;
  1387. }
  1388. }
  1389. //
  1390. // Did wet find the CSP?
  1391. //
  1392. if (i == g_dwNumRSAProviders)
  1393. {
  1394. hr = CAPICOM_E_NOT_SUPPORTED;
  1395. DebugTrace("Error [%#x]: could not find a CSP that supports AlgID = %d and/or key length = 40.\n",
  1396. hr, AlgId);
  1397. }
  1398. break;
  1399. }
  1400. }
  1401. break;
  1402. }
  1403. default:
  1404. {
  1405. hr = CAPICOM_E_INVALID_KEY_LENGTH;
  1406. DebugTrace("Error [%#x]: Unknown CAPICOM_ENCRYPTION_KEY_LENGTH (%#x).\n", hr, KeyLengthName);
  1407. break;
  1408. }
  1409. }
  1410. DebugTrace("Leaving EnumNameToKeyLength().\n");
  1411. return hr;
  1412. }
  1413. //-----------------------------------------------------------------------------
  1414. //
  1415. // ExpandString
  1416. //
  1417. //-----------------------------------------------------------------------------
  1418. static LPWSTR ExpandString (LPCWSTR pwszString)
  1419. {
  1420. DWORD dwExpanded = 0;
  1421. LPWSTR pwszExpanded = NULL;
  1422. //
  1423. // Sanity check.
  1424. //
  1425. ATLASSERT(pwszString);
  1426. dwExpanded = ::ExpandEnvironmentStringsU(pwszString, NULL, 0);
  1427. if (!(pwszExpanded = (LPWSTR) ::CoTaskMemAlloc(dwExpanded * sizeof(WCHAR))))
  1428. {
  1429. SetLastError((DWORD) E_OUTOFMEMORY);
  1430. return (NULL);
  1431. }
  1432. if (0 == ExpandEnvironmentStringsU(pwszString, pwszExpanded, dwExpanded))
  1433. {
  1434. ::CoTaskMemFree(pwszExpanded);
  1435. return (NULL);
  1436. }
  1437. return (pwszExpanded);
  1438. }
  1439. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1440. Function : IsDiskFile
  1441. Synopsis : Check if a the file name represents a disk file.
  1442. Parameter: LPWSTR pwszFileName - File name.
  1443. Remark :
  1444. ------------------------------------------------------------------------------*/
  1445. HRESULT IsDiskFile (LPWSTR pwszFileName)
  1446. {
  1447. HRESULT hr = S_OK;
  1448. HANDLE hFile = INVALID_HANDLE_VALUE;
  1449. LPWSTR pwszExpandedFileName = NULL;
  1450. DWORD dwFileType = FILE_TYPE_UNKNOWN;
  1451. DebugTrace("Entering IsDiskFile().\n");
  1452. //
  1453. // Sanity check.
  1454. //
  1455. ATLASSERT(pwszFileName);
  1456. //
  1457. // Expand filename string.
  1458. //
  1459. if (!(pwszExpandedFileName = ::ExpandString(pwszFileName)))
  1460. {
  1461. hr = HRESULT_FROM_WIN32(::GetLastError());
  1462. DebugTrace("Error [%#x]: ExpandString() failed.\n", hr);
  1463. goto ErrorExit;
  1464. }
  1465. //
  1466. // Open for generic read.
  1467. //
  1468. if (INVALID_HANDLE_VALUE == (hFile = ::CreateFileU(pwszExpandedFileName,
  1469. GENERIC_READ,
  1470. FILE_SHARE_READ,
  1471. NULL,
  1472. OPEN_EXISTING,
  1473. FILE_ATTRIBUTE_NORMAL,
  1474. NULL)))
  1475. {
  1476. hr = HRESULT_FROM_WIN32(::GetLastError());
  1477. DebugTrace("Error [%#x]: CreateFileU() failed.\n", hr);
  1478. goto ErrorExit;
  1479. }
  1480. //
  1481. // Make sure it is a disk file.
  1482. //
  1483. if (FILE_TYPE_DISK != (dwFileType = ::GetFileType(hFile)))
  1484. {
  1485. hr = E_INVALIDARG;
  1486. DebugTrace("Error [%#x]: Not a disk file (%#x).\n", hr, dwFileType);
  1487. goto ErrorExit;
  1488. }
  1489. CommonExit:
  1490. //
  1491. // Free resources.
  1492. //
  1493. if (hFile && hFile != INVALID_HANDLE_VALUE)
  1494. {
  1495. ::CloseHandle(hFile);
  1496. }
  1497. if (pwszExpandedFileName)
  1498. {
  1499. ::CoTaskMemFree((LPVOID) pwszExpandedFileName);
  1500. }
  1501. DebugTrace("Leaving IsDiskFile().\n");
  1502. return hr;
  1503. ErrorExit:
  1504. //
  1505. // Sanity check.
  1506. //
  1507. ATLASSERT(FAILED(hr));
  1508. goto CommonExit;
  1509. }
  1510. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1511. Function : ReadFileContent
  1512. Synopsis : Read all bytes from the specified file.
  1513. Parameter: LPWSTR pwszFileName - File name.
  1514. DATA_BLOB * pDataBlob - Pointer to DATA_BLOB to receive the
  1515. file content.
  1516. Remark :
  1517. ------------------------------------------------------------------------------*/
  1518. HRESULT ReadFileContent (LPWSTR pwszFileName,
  1519. DATA_BLOB * pDataBlob)
  1520. {
  1521. HRESULT hr = S_OK;
  1522. DWORD cbData = 0;
  1523. DWORD cbHighSize = 0;
  1524. HANDLE hFile = INVALID_HANDLE_VALUE;
  1525. HANDLE hFileMapping = NULL;
  1526. LPWSTR pwszExpandedFileName = NULL;
  1527. LPBYTE pbData = NULL;
  1528. DWORD dwFileType = FILE_TYPE_UNKNOWN;
  1529. DebugTrace("Entering ReadFileContent().\n");
  1530. //
  1531. // Sanity check.
  1532. //
  1533. ATLASSERT(pwszFileName);
  1534. ATLASSERT(pDataBlob);
  1535. //
  1536. // Expand filename string.
  1537. //
  1538. if (!(pwszExpandedFileName = ::ExpandString(pwszFileName)))
  1539. {
  1540. hr = HRESULT_FROM_WIN32(::GetLastError());
  1541. DebugTrace("Error [%#x]: ExpandString() failed.\n", hr);
  1542. goto ErrorExit;
  1543. }
  1544. //
  1545. // Open for generic read.
  1546. //
  1547. if (INVALID_HANDLE_VALUE == (hFile = ::CreateFileU(pwszExpandedFileName,
  1548. GENERIC_READ,
  1549. FILE_SHARE_READ,
  1550. NULL,
  1551. OPEN_EXISTING,
  1552. FILE_ATTRIBUTE_NORMAL,
  1553. NULL)))
  1554. {
  1555. hr = HRESULT_FROM_WIN32(::GetLastError());
  1556. DebugTrace("Error [%#x]: CreateFileU() failed.\n", hr);
  1557. goto ErrorExit;
  1558. }
  1559. //
  1560. // Make sure it is a disk file.
  1561. //
  1562. if (FILE_TYPE_DISK != (dwFileType = ::GetFileType(hFile)))
  1563. {
  1564. hr = E_INVALIDARG;
  1565. DebugTrace("Error [%#x]: Not a disk file (%#x).\n", hr, dwFileType);
  1566. goto ErrorExit;
  1567. }
  1568. //
  1569. // Get file size.
  1570. //
  1571. if ((cbData = ::GetFileSize(hFile, &cbHighSize)) == 0xffffffff)
  1572. {
  1573. hr = HRESULT_FROM_WIN32(::GetLastError());
  1574. DebugTrace("Error [%#x]: GetFileSize() failed.\n", hr);
  1575. goto ErrorExit;
  1576. }
  1577. //
  1578. // We do not handle file more than 4G bytes.
  1579. //
  1580. if (cbHighSize != 0)
  1581. {
  1582. hr = E_FAIL;
  1583. DebugTrace("Error [%#x]: File size greater 4G bytes.\n", hr);
  1584. goto ErrorExit;
  1585. }
  1586. //
  1587. // Create a file mapping object.
  1588. //
  1589. if (NULL == (hFileMapping = ::CreateFileMapping(hFile,
  1590. NULL,
  1591. PAGE_READONLY,
  1592. 0,
  1593. 0,
  1594. NULL)))
  1595. {
  1596. hr = HRESULT_FROM_WIN32(::GetLastError());
  1597. DebugTrace("Error [%#x]: CreateFileMapping() failed.\n", hr);
  1598. goto ErrorExit;
  1599. }
  1600. //
  1601. // Now create a view of the file.
  1602. //
  1603. if (NULL == (pbData = (BYTE *) ::MapViewOfFile(hFileMapping,
  1604. FILE_MAP_READ,
  1605. 0,
  1606. 0,
  1607. cbData)))
  1608. {
  1609. hr = HRESULT_FROM_WIN32(::GetLastError());
  1610. DebugTrace("Error [%#x]: MapViewOfFile() failed.\n", hr);
  1611. goto ErrorExit;
  1612. }
  1613. //
  1614. // Return data to caller.
  1615. //
  1616. pDataBlob->cbData = cbData;
  1617. pDataBlob->pbData = pbData;
  1618. CommonExit:
  1619. //
  1620. // Free resources.
  1621. //
  1622. if (hFile && hFile != INVALID_HANDLE_VALUE)
  1623. {
  1624. ::CloseHandle(hFile);
  1625. }
  1626. if (hFileMapping)
  1627. {
  1628. ::CloseHandle(hFileMapping);
  1629. }
  1630. if (pwszExpandedFileName)
  1631. {
  1632. ::CoTaskMemFree((LPVOID) pwszExpandedFileName);
  1633. }
  1634. DebugTrace("Leaving ReadFileContent().\n");
  1635. return hr;
  1636. ErrorExit:
  1637. //
  1638. // Sanity check.
  1639. //
  1640. ATLASSERT(FAILED(hr));
  1641. goto CommonExit;
  1642. }
  1643. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1644. Function : WriteFileContent
  1645. Synopsis : Write all bytes of blob to the specified file.
  1646. Parameter: LPWSTR pwszFileName - File name.
  1647. DATA_BLOB DataBlob - Blob to be written.
  1648. Remark :
  1649. ------------------------------------------------------------------------------*/
  1650. HRESULT WriteFileContent(LPCWSTR pwszFileName,
  1651. DATA_BLOB DataBlob)
  1652. {
  1653. HRESULT hr = S_OK;
  1654. HANDLE hFile = NULL;
  1655. DWORD dwBytesWritten = 0;
  1656. LPWSTR pwszExpandedFileName = NULL;
  1657. DWORD dwFileType = FILE_TYPE_UNKNOWN;
  1658. DebugTrace("Entering WriteFileContent().\n");
  1659. //
  1660. // Sanity check.
  1661. //
  1662. ATLASSERT(pwszFileName);
  1663. ATLASSERT(DataBlob.cbData);
  1664. ATLASSERT(DataBlob.pbData);
  1665. //
  1666. // Expand filename string.
  1667. //
  1668. if (!(pwszExpandedFileName = ::ExpandString(pwszFileName)))
  1669. {
  1670. hr = HRESULT_FROM_WIN32(::GetLastError());
  1671. DebugTrace("Error [%#x]: ExpandString() failed.\n", hr);
  1672. goto ErrorExit;
  1673. }
  1674. //
  1675. // Open for generic write.
  1676. //
  1677. if (INVALID_HANDLE_VALUE == (hFile = ::CreateFileU(pwszExpandedFileName,
  1678. GENERIC_WRITE,
  1679. 0,
  1680. NULL,
  1681. CREATE_ALWAYS,
  1682. FILE_ATTRIBUTE_NORMAL,
  1683. NULL)))
  1684. {
  1685. hr = HRESULT_FROM_WIN32(::GetLastError());
  1686. DebugTrace("Error [%#x]: CreateFileU() failed.\n", hr);
  1687. goto ErrorExit;
  1688. }
  1689. //
  1690. // Make sure it is a disk file.
  1691. //
  1692. if (FILE_TYPE_DISK != (dwFileType = ::GetFileType(hFile)))
  1693. {
  1694. hr = E_INVALIDARG;
  1695. DebugTrace("Error [%#x]: Invalid file type (%#x).\n", hr, dwFileType);
  1696. goto ErrorExit;
  1697. }
  1698. //
  1699. // Now write it out.
  1700. //
  1701. if (!::WriteFile(hFile, DataBlob.pbData, DataBlob.cbData, &dwBytesWritten, NULL))
  1702. {
  1703. hr = HRESULT_FROM_WIN32(::GetLastError());
  1704. DebugTrace("Error [%#x]: CreateFileU() failed.\n", hr);
  1705. goto ErrorExit;
  1706. }
  1707. //
  1708. // Make sure we wrote everything out.
  1709. //
  1710. if (dwBytesWritten != DataBlob.cbData)
  1711. {
  1712. hr = E_FAIL;
  1713. DebugTrace("Error [%#x]: Not able to write all data (only partial).\n", hr);
  1714. goto ErrorExit;
  1715. }
  1716. CommonExit:
  1717. //
  1718. // Free resources.
  1719. //
  1720. if (hFile && hFile != INVALID_HANDLE_VALUE)
  1721. {
  1722. ::CloseHandle(hFile);
  1723. }
  1724. if (pwszExpandedFileName)
  1725. {
  1726. ::CoTaskMemFree((LPVOID) pwszExpandedFileName);
  1727. }
  1728. DebugTrace("Leaving WriteFileContent().\n");
  1729. return hr;
  1730. ErrorExit:
  1731. //
  1732. // Sanity check.
  1733. //
  1734. ATLASSERT(FAILED(hr));
  1735. goto CommonExit;
  1736. }