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.

423 lines
11 KiB

  1. #include "global.h"
  2. //+-------------------------------------------------------------------------
  3. // Private Key file definitions
  4. //
  5. // The file consists of the FILE_HDR followed by cbEncryptData optional
  6. // bytes used to encrypt the private key and then the private key.
  7. // The private key is encrypted according to dwEncryptType.
  8. //
  9. // The public key is included with the private key.
  10. //--------------------------------------------------------------------------
  11. typedef struct _FILE_HDR {
  12. DWORD dwMagic;
  13. DWORD dwVersion;
  14. DWORD dwKeySpec;
  15. DWORD dwEncryptType;
  16. DWORD cbEncryptData;
  17. DWORD cbPvk;
  18. } FILE_HDR, *PFILE_HDR;
  19. // BUGBUG: enum from pvk.h?
  20. #ifndef ENTER_PASSWORD
  21. #define ENTER_PASSWORD 0
  22. #endif // ENTER_PASSWORD
  23. #define PVK_FILE_VERSION_0 0
  24. #define PVK_MAGIC 0xb0b5f11e
  25. // Private key encrypt types
  26. #define PVK_NO_ENCRYPT 0
  27. #define MAX_PVK_FILE_LEN 4096
  28. typedef BOOL (* PFNREAD)(HANDLE h, void * p, DWORD cb);
  29. extern DWORD g_dwSubjectStoreFlag;
  30. //+-------------------------------------------------------------------------
  31. // Read & Write to memory fucntion
  32. //--------------------------------------------------------------------------
  33. typedef struct _MEMINFO {
  34. BYTE * pb;
  35. DWORD cb;
  36. DWORD cbSeek;
  37. } MEMINFO, * PMEMINFO;
  38. static BOOL ReadFromMemory(
  39. IN HANDLE h,
  40. IN void * p,
  41. IN DWORD cb
  42. )
  43. {
  44. PMEMINFO pMemInfo = (PMEMINFO) h;
  45. if (pMemInfo->cbSeek + cb <= pMemInfo->cb) {
  46. // copy the bytes
  47. memcpy(p, &pMemInfo->pb[pMemInfo->cbSeek], cb);
  48. pMemInfo->cbSeek += cb;
  49. return TRUE;
  50. } else {
  51. SetLastError(ERROR_END_OF_MEDIA);
  52. return FALSE;
  53. }
  54. }
  55. //+-------------------------------------------------------------------------
  56. // Converts the bytes into WCHAR hex
  57. //
  58. // Needs (cb * 2 + 1) * sizeof(WCHAR) bytes of space in wsz
  59. //--------------------------------------------------------------------------
  60. static void BytesToWStr(ULONG cb, void* pv, LPWSTR wsz)
  61. {
  62. BYTE* pb = (BYTE*) pv;
  63. for (ULONG i = 0; i<cb; i++) {
  64. int b;
  65. b = (*pb & 0xF0) >> 4;
  66. *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A';
  67. b = *pb & 0x0F;
  68. *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A';
  69. pb++;
  70. }
  71. *wsz++ = 0;
  72. }
  73. #define UUID_WSTR_BYTES ((sizeof(GUID) * 2 + 1) * sizeof(WCHAR))
  74. //-------------------------------------------------------------------------
  75. //
  76. // Call GetLastError and convert the return code to HRESULT
  77. //--------------------------------------------------------------------------
  78. HRESULT WINAPI SignError ()
  79. {
  80. DWORD dw = GetLastError ();
  81. HRESULT hr;
  82. if ( dw <= (DWORD) 0xFFFF )
  83. hr = HRESULT_FROM_WIN32 ( dw );
  84. else
  85. hr = dw;
  86. if ( ! FAILED ( hr ) )
  87. {
  88. // somebody failed a call without properly setting an error condition
  89. hr = E_UNEXPECTED;
  90. }
  91. return hr;
  92. }
  93. static BOOL LoadKeyW(
  94. IN HCRYPTPROV hCryptProv,
  95. IN HANDLE hRead,
  96. IN PFNREAD pfnRead,
  97. IN DWORD cbKeyData,
  98. IN HWND hwndOwner,
  99. IN LPCWSTR pwszKeyName,
  100. IN DWORD dwFlags,
  101. IN OUT OPTIONAL DWORD *pdwKeySpec
  102. )
  103. {
  104. BOOL fResult;
  105. FILE_HDR Hdr;
  106. HCRYPTKEY hKey = 0;
  107. BYTE *pbPvk = NULL;
  108. DWORD cbPvk;
  109. // Read the file header and verify
  110. if (!pfnRead(hRead, &Hdr, sizeof(Hdr)))
  111. {
  112. ERROR_OUT(("can't read in-memory pvk file hdr"));
  113. goto BadPvkFile;
  114. }
  115. ASSERT( Hdr.dwMagic == PVK_MAGIC );
  116. // Treat as a "normal" private key file
  117. cbPvk = Hdr.cbPvk;
  118. if (Hdr.dwVersion != PVK_FILE_VERSION_0 ||
  119. Hdr.cbEncryptData > MAX_PVK_FILE_LEN ||
  120. cbPvk == 0 || cbPvk > MAX_PVK_FILE_LEN)
  121. goto BadPvkFile;
  122. if (pdwKeySpec) {
  123. DWORD dwKeySpec = *pdwKeySpec;
  124. *pdwKeySpec = Hdr.dwKeySpec;
  125. if (dwKeySpec && dwKeySpec != Hdr.dwKeySpec) {
  126. SetLastError(PVK_HELPER_WRONG_KEY_TYPE);
  127. goto ErrorReturn;
  128. }
  129. }
  130. // Allocate and read the private key
  131. if (NULL == (pbPvk = new BYTE[cbPvk]))
  132. goto ErrorReturn;
  133. if (!pfnRead(hRead, pbPvk, cbPvk))
  134. goto BadPvkFile;
  135. ASSERT(Hdr.dwEncryptType == PVK_NO_ENCRYPT);
  136. // Decrypt and import the private key
  137. if (!CryptImportKey(hCryptProv, pbPvk, cbPvk, 0, dwFlags,
  138. &hKey))
  139. goto ErrorReturn;
  140. fResult = TRUE;
  141. goto CommonReturn;
  142. BadPvkFile:
  143. SetLastError(PVK_HELPER_BAD_PVK_FILE);
  144. if (pdwKeySpec)
  145. *pdwKeySpec = 0;
  146. ErrorReturn:
  147. fResult = FALSE;
  148. CommonReturn:
  149. if (pbPvk)
  150. delete (pbPvk);
  151. if (hKey)
  152. CryptDestroyKey(hKey);
  153. return fResult;
  154. }
  155. static BOOL AcquireKeyContextW(
  156. IN LPCWSTR pwszProvName,
  157. IN DWORD dwProvType,
  158. IN HANDLE hRead,
  159. IN PFNREAD pfnRead,
  160. IN DWORD cbKeyData,
  161. IN HWND hwndOwner,
  162. IN LPCWSTR pwszKeyName,
  163. IN OUT OPTIONAL DWORD *pdwKeySpec,
  164. OUT HCRYPTPROV *phCryptProv
  165. )
  166. {
  167. BOOL fResult;
  168. HCRYPTPROV hProv = 0;
  169. GUID TmpContainerUuid;
  170. LPWSTR pwszTmpContainer = NULL;
  171. // Create a temporary keyset to load the private key into
  172. // UuidCreate(&TmpContainerUuid);
  173. if (CoCreateGuid((GUID *)&TmpContainerUuid) != S_OK)
  174. {
  175. goto ErrorReturn;
  176. }
  177. if (NULL == (pwszTmpContainer = (LPWSTR) new BYTE[
  178. 6 * sizeof(WCHAR) + UUID_WSTR_BYTES]))
  179. goto ErrorReturn;
  180. LStrCpyW(pwszTmpContainer, L"TmpKey");
  181. BytesToWStr(sizeof(UUID), &TmpContainerUuid, pwszTmpContainer + 6);
  182. if (!CryptAcquireContextU(
  183. &hProv,
  184. pwszTmpContainer,
  185. pwszProvName,
  186. dwProvType,
  187. CRYPT_NEWKEYSET |
  188. ( g_dwSubjectStoreFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE ?
  189. CRYPT_MACHINE_KEYSET : 0 )))
  190. goto ErrorReturn;
  191. if (!LoadKeyW(
  192. hProv,
  193. hRead,
  194. pfnRead,
  195. cbKeyData,
  196. hwndOwner,
  197. pwszKeyName,
  198. 0, // dwFlags
  199. pdwKeySpec
  200. ))
  201. goto DeleteKeySetReturn;
  202. fResult = TRUE;
  203. goto CommonReturn;
  204. DeleteKeySetReturn:
  205. CryptReleaseContext(hProv, 0);
  206. CryptAcquireContextU(
  207. &hProv,
  208. pwszTmpContainer,
  209. pwszProvName,
  210. dwProvType,
  211. CRYPT_DELETEKEYSET
  212. );
  213. hProv = 0;
  214. ErrorReturn:
  215. if (hProv) {
  216. CryptReleaseContext(hProv, 0);
  217. hProv = 0;
  218. }
  219. fResult = FALSE;
  220. CommonReturn:
  221. if (pwszTmpContainer) {
  222. delete (pwszTmpContainer);
  223. }
  224. *phCryptProv = hProv;
  225. return fResult;
  226. }
  227. //+-------------------------------------------------------------------------
  228. // Creates a temporary container in the provider and loads the private key
  229. // from memory.
  230. // For success, returns a handle to a cryptographic provider for the private
  231. // key and the name of the temporary container. PrivateKeyReleaseContext must
  232. // be called to release the hCryptProv and delete the temporary container.
  233. //
  234. // PrivateKeyLoadFromMemory is called to load the private key into the
  235. // temporary container.
  236. //--------------------------------------------------------------------------
  237. BOOL
  238. WINAPI
  239. PvkPrivateKeyAcquireContextFromMemory(
  240. IN LPCWSTR pwszProvName,
  241. IN DWORD dwProvType,
  242. IN BYTE *pbData,
  243. IN DWORD cbData,
  244. IN HWND hwndOwner,
  245. IN LPCWSTR pwszKeyName,
  246. IN OUT OPTIONAL DWORD *pdwKeySpec,
  247. OUT HCRYPTPROV *phCryptProv
  248. )
  249. {
  250. HRESULT hr = S_OK;
  251. if(FAILED(hr))
  252. return FALSE;
  253. MEMINFO MemInfo;
  254. MemInfo.pb = pbData;
  255. MemInfo.cb = cbData;
  256. MemInfo.cbSeek = 0;
  257. BOOL fhr = AcquireKeyContextW(
  258. pwszProvName,
  259. dwProvType,
  260. (HANDLE) &MemInfo,
  261. ReadFromMemory,
  262. cbData,
  263. hwndOwner,
  264. pwszKeyName,
  265. pdwKeySpec,
  266. phCryptProv
  267. );
  268. return fhr;
  269. }
  270. //+-------------------------------------------------------------------------
  271. // Releases the cryptographic provider and deletes the temporary container
  272. // created by PrivateKeyAcquireContext or PrivateKeyAcquireContextFromMemory.
  273. //--------------------------------------------------------------------------
  274. BOOL
  275. WINAPI
  276. PvkPrivateKeyReleaseContext(
  277. IN HCRYPTPROV hCryptProv,
  278. IN LPCWSTR pwszProvName,
  279. IN DWORD dwProvType,
  280. IN LPWSTR pwszTmpContainer
  281. )
  282. {
  283. HRESULT hr = S_OK;
  284. if (hCryptProv)
  285. CryptReleaseContext(hCryptProv, 0);
  286. if (pwszTmpContainer) {
  287. // Delete the temporary container for the private key from
  288. // the provider
  289. //
  290. // Note: for CRYPT_DELETEKEYSET, the returned hCryptProv is undefined
  291. // and must not be released.
  292. CryptAcquireContextU(
  293. &hCryptProv,
  294. pwszTmpContainer,
  295. pwszProvName,
  296. dwProvType,
  297. CRYPT_DELETEKEYSET
  298. );
  299. delete (pwszTmpContainer);
  300. }
  301. return TRUE;
  302. }
  303. //+-------------------------------------------------------------------------
  304. // Get crypto provider to based on either the pvkfile or key container name
  305. //--------------------------------------------------------------------------
  306. HRESULT WINAPI PvkGetCryptProv( IN HWND hwnd,
  307. IN LPCWSTR pwszCaption,
  308. IN LPCWSTR pwszCapiProvider,
  309. IN DWORD dwProviderType,
  310. IN LPCWSTR pwszPvkFile,
  311. IN LPCWSTR pwszKeyContainerName,
  312. IN DWORD *pdwKeySpec,
  313. OUT LPWSTR *ppwszTmpContainer,
  314. OUT HCRYPTPROV *phCryptProv)
  315. {
  316. HANDLE hFile=NULL;
  317. HRESULT hr=E_FAIL;
  318. DWORD dwRequiredKeySpec=0;
  319. //Init
  320. *ppwszTmpContainer=NULL;
  321. *phCryptProv=NULL;
  322. //get the provider handle based on the key container name
  323. if(!CryptAcquireContextU(phCryptProv,
  324. pwszKeyContainerName,
  325. pwszCapiProvider,
  326. dwProviderType,
  327. ( g_dwSubjectStoreFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE ?
  328. CRYPT_MACHINE_KEYSET : 0 )))
  329. return SignError();
  330. dwRequiredKeySpec=*pdwKeySpec;
  331. //make sure *pdwKeySpec is the correct key spec
  332. HCRYPTKEY hPubKey;
  333. if (CryptGetUserKey(
  334. *phCryptProv,
  335. dwRequiredKeySpec,
  336. &hPubKey
  337. ))
  338. {
  339. CryptDestroyKey(hPubKey);
  340. *pdwKeySpec=dwRequiredKeySpec;
  341. return S_OK;
  342. }
  343. else
  344. {
  345. // Doesn't have the specified public key
  346. hr=SignError();
  347. CryptReleaseContext(*phCryptProv, 0);
  348. *phCryptProv=NULL;
  349. return hr;
  350. }
  351. }
  352. void WINAPI PvkFreeCryptProv(IN HCRYPTPROV hProv,
  353. IN LPCWSTR pwszCapiProvider,
  354. IN DWORD dwProviderType,
  355. IN LPWSTR pwszTmpContainer)
  356. {
  357. if (pwszTmpContainer) {
  358. // Delete the temporary container for the private key from
  359. // the provider
  360. PvkPrivateKeyReleaseContext(hProv,
  361. pwszCapiProvider,
  362. dwProviderType,
  363. pwszTmpContainer);
  364. } else {
  365. if (hProv)
  366. CryptReleaseContext(hProv, 0);
  367. }
  368. }