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.

526 lines
14 KiB

  1. /*++
  2. Copyright (C) 1996, 1997 Microsoft Corporation
  3. Module Name:
  4. nt5wrap.cpp
  5. Abstract:
  6. Client side CryptXXXData calls.
  7. Client funcs are preceeded by "CS" == Client Side
  8. Server functions are preceeded by "SS" == Server Side
  9. Author:
  10. Scott Field (sfield) 14-Aug-97
  11. Revisions:
  12. Todds 04-Sep-97 Ported to .dll
  13. Matt Thomlinson (mattt) 09-Oct-97 Moved to common area for link by crypt32
  14. philh 03-Dec-97 Added I_CertProtectFunction
  15. philh 29-Sep-98 Renamed I_CertProtectFunction to
  16. I_CertCltProtectFunction.
  17. I_CertProtectFunction was moved to
  18. ..\ispu\pki\certstor\protroot.cpp
  19. --*/
  20. #ifndef _CRYPT32_
  21. #define _CRYPT32_ // use correct Dll Linkage
  22. #endif
  23. #include <nt.h>
  24. #include <ntrtl.h>
  25. #include <nturtl.h>
  26. #include <windows.h>
  27. #include <wincrypt.h>
  28. #include <cryptui.h>
  29. #include <sha.h>
  30. #include "crypt.h"
  31. #include <lm.h>
  32. #include <malloc.h>
  33. #include "unicode.h"
  34. #include "certprot.h"
  35. // midl generated files
  36. #include "dprpc.h"
  37. #include "dpapiprv.h"
  38. // fwds
  39. RPC_STATUS BindW(
  40. WCHAR **pszBinding,
  41. RPC_BINDING_HANDLE *phBind
  42. );
  43. RPC_STATUS BindBackupKeyW(
  44. LPCWSTR szComputerName,
  45. WCHAR **pszBinding,
  46. RPC_BINDING_HANDLE *phBind
  47. );
  48. RPC_STATUS UnbindW(
  49. WCHAR **pszBinding,
  50. RPC_BINDING_HANDLE *phBind
  51. );
  52. BOOL
  53. WINAPI
  54. CryptProtectData(
  55. DATA_BLOB* pDataIn,
  56. LPCWSTR szDataDescr,
  57. DATA_BLOB* pOptionalEntropy,
  58. PVOID pvReserved,
  59. CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
  60. DWORD dwFlags,
  61. DATA_BLOB* pDataOut)
  62. {
  63. RPC_BINDING_HANDLE h = NULL;
  64. LPWSTR pszBinding;
  65. RPC_STATUS RpcStatus;
  66. BYTE rgbPasswordHash[ A_SHA_DIGEST_LEN ];
  67. LPCWSTR wszDescription = szDataDescr?szDataDescr:L"";
  68. LPWSTR szAlternateDataDescription = (LPWSTR)wszDescription;
  69. DWORD dwRetVal = ERROR_INVALID_PARAMETER;
  70. // check params
  71. if ((pDataOut == NULL) ||
  72. (pDataIn == NULL) ||
  73. (pDataIn->pbData == NULL))
  74. {
  75. SetLastError(ERROR_INVALID_PARAMETER);
  76. return FALSE;
  77. }
  78. RpcStatus = BindW(&pszBinding, &h);
  79. if(RpcStatus != RPC_S_OK) {
  80. SetLastError(RpcStatus);
  81. return FALSE;
  82. }
  83. __try {
  84. PBYTE pbOptionalPassword = NULL;
  85. DWORD cbOptionalPassword = 0;
  86. SSCRYPTPROTECTDATA_PROMPTSTRUCT PromptStruct;
  87. SSCRYPTPROTECTDATA_PROMPTSTRUCT *pLocalPromptStruct = NULL;
  88. // zero so client stub allocates
  89. ZeroMemory(pDataOut, sizeof(DATA_BLOB));
  90. //
  91. // only call UI function if prompt flags dictate, because we don't
  92. // want to bring in cryptui.dll unless necessary.
  93. //
  94. if( (pPromptStruct != NULL) &&
  95. ((pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_UNPROTECT) ||
  96. (pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_PROTECT))
  97. )
  98. {
  99. dwRetVal = I_CryptUIProtect(
  100. pDataIn,
  101. pPromptStruct,
  102. dwFlags,
  103. (PVOID*)&szAlternateDataDescription,
  104. TRUE,
  105. rgbPasswordHash
  106. );
  107. //
  108. // If UI dictated strong security, then supply the hash.
  109. //
  110. if( pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
  111. {
  112. cbOptionalPassword = sizeof(rgbPasswordHash);
  113. pbOptionalPassword = rgbPasswordHash;
  114. }
  115. } else {
  116. dwRetVal = ERROR_SUCCESS;
  117. }
  118. if( dwRetVal == ERROR_SUCCESS )
  119. {
  120. if(pPromptStruct != NULL)
  121. {
  122. ZeroMemory(&PromptStruct, sizeof(PromptStruct));
  123. PromptStruct.cbSize = sizeof(PromptStruct);
  124. PromptStruct.dwPromptFlags = pPromptStruct->dwPromptFlags;
  125. pLocalPromptStruct = &PromptStruct;
  126. }
  127. dwRetVal = SSCryptProtectData(
  128. h,
  129. &pDataOut->pbData,
  130. &pDataOut->cbData,
  131. pDataIn->pbData,
  132. pDataIn->cbData,
  133. szAlternateDataDescription,
  134. (pOptionalEntropy) ? pOptionalEntropy->pbData : NULL,
  135. (pOptionalEntropy) ? pOptionalEntropy->cbData : 0,
  136. (GUID*)pvReserved,
  137. pLocalPromptStruct,
  138. dwFlags,
  139. pbOptionalPassword,
  140. cbOptionalPassword
  141. );
  142. }
  143. } __except(EXCEPTION_EXECUTE_HANDLER) {
  144. dwRetVal = GetExceptionCode();
  145. }
  146. UnbindW(&pszBinding, &h);
  147. ZeroMemory( rgbPasswordHash, sizeof(rgbPasswordHash) );
  148. if( szAlternateDataDescription &&
  149. szAlternateDataDescription != wszDescription )
  150. {
  151. LocalFree( szAlternateDataDescription );
  152. }
  153. if(dwRetVal != ERROR_SUCCESS) {
  154. SetLastError(dwRetVal);
  155. return FALSE;
  156. }
  157. return TRUE;
  158. }
  159. BOOL
  160. WINAPI
  161. CryptUnprotectData(
  162. DATA_BLOB* pDataIn, // in encr blob
  163. LPWSTR* ppszDataDescr, // out
  164. DATA_BLOB* pOptionalEntropy,
  165. PVOID pvReserved,
  166. CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
  167. DWORD dwFlags,
  168. DATA_BLOB* pDataOut)
  169. {
  170. RPC_BINDING_HANDLE h = NULL;
  171. LPWSTR pszBinding;
  172. RPC_STATUS RpcStatus;
  173. BYTE rgbPasswordHash[ A_SHA_DIGEST_LEN ];
  174. DWORD dwRetVal;
  175. DWORD dwRetryCount = 0;
  176. // check params
  177. if ((pDataOut == NULL) ||
  178. (pDataIn == NULL) ||
  179. (pDataIn->pbData == NULL))
  180. {
  181. SetLastError(ERROR_INVALID_PARAMETER);
  182. return FALSE;
  183. }
  184. RpcStatus = BindW(&pszBinding, &h);
  185. if(RpcStatus != RPC_S_OK) {
  186. SetLastError(RpcStatus);
  187. return FALSE;
  188. }
  189. __try {
  190. CRYPTPROTECT_PROMPTSTRUCT DerivedPromptStruct;
  191. PBYTE pbOptionalPassword = NULL;
  192. DWORD cbOptionalPassword = 0;
  193. LPCWSTR szDataDescr;
  194. LPUWSTR szDataDescrUnaligned;
  195. SSCRYPTPROTECTDATA_PROMPTSTRUCT PromptStruct;
  196. SSCRYPTPROTECTDATA_PROMPTSTRUCT *pLocalPromptStruct = NULL;
  197. //
  198. // define outer+inner wrapper for security blob.
  199. // this won't be necessary once SAS support is provided by the OS.
  200. //
  201. typedef struct {
  202. DWORD dwOuterVersion;
  203. GUID guidProvider;
  204. DWORD dwVersion;
  205. GUID guidMK;
  206. DWORD dwPromptFlags;
  207. DWORD cbDataDescr;
  208. WCHAR szDataDescr[1];
  209. } sec_blob, *psec_blob;
  210. sec_blob UNALIGNED *SecurityBlob = (sec_blob*)(pDataIn->pbData);
  211. //
  212. // zero so client stub allocates
  213. //
  214. ZeroMemory(pDataOut, sizeof(DATA_BLOB));
  215. if (ppszDataDescr)
  216. *ppszDataDescr = NULL;
  217. //
  218. // recreate the promptstruct and DataDescr from the security blob.
  219. //
  220. DerivedPromptStruct.cbSize = sizeof(DerivedPromptStruct);
  221. DerivedPromptStruct.dwPromptFlags = SecurityBlob->dwPromptFlags;
  222. //
  223. // SecurityBlob may be unaligned. Set szDataDescr to reference
  224. // an aligned copy.
  225. //
  226. szDataDescrUnaligned = (SecurityBlob->szDataDescr);
  227. WSTR_ALIGNED_STACK_COPY(&szDataDescr,szDataDescrUnaligned);
  228. if( pPromptStruct )
  229. {
  230. DerivedPromptStruct.hwndApp = pPromptStruct->hwndApp;
  231. DerivedPromptStruct.szPrompt = pPromptStruct->szPrompt;
  232. } else {
  233. DerivedPromptStruct.szPrompt = NULL;
  234. DerivedPromptStruct.hwndApp = NULL;
  235. }
  236. retry:
  237. //
  238. // determine if UI is to be raised, and what type.
  239. //
  240. //
  241. // only call UI function if prompt flags dictate, because we don't
  242. // want to bring in cryptui.dll unless necessary.
  243. //
  244. if( ((DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_ON_UNPROTECT) ||
  245. (DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_ON_PROTECT))
  246. )
  247. {
  248. dwRetVal = I_CryptUIProtect(
  249. pDataIn,
  250. &DerivedPromptStruct,
  251. dwFlags,
  252. (PVOID*)&szDataDescr,
  253. FALSE,
  254. rgbPasswordHash
  255. );
  256. //
  257. // If UI dictated strong security, then supply the hash.
  258. //
  259. if( DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
  260. {
  261. cbOptionalPassword = sizeof(rgbPasswordHash);
  262. pbOptionalPassword = rgbPasswordHash;
  263. }
  264. } else {
  265. if( DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
  266. {
  267. dwRetVal = ERROR_INVALID_PARAMETER;
  268. } else {
  269. dwRetVal = ERROR_SUCCESS;
  270. }
  271. }
  272. //
  273. // make the RPC call to attempt to unprotect the data.
  274. //
  275. if( dwRetVal == ERROR_SUCCESS )
  276. {
  277. if(pPromptStruct != NULL)
  278. {
  279. ZeroMemory(&PromptStruct, sizeof(PromptStruct));
  280. PromptStruct.cbSize = sizeof(PromptStruct);
  281. PromptStruct.dwPromptFlags = pPromptStruct->dwPromptFlags;
  282. pLocalPromptStruct = &PromptStruct;
  283. }
  284. dwRetVal = SSCryptUnprotectData(
  285. h,
  286. &pDataOut->pbData,
  287. &pDataOut->cbData,
  288. pDataIn->pbData,
  289. pDataIn->cbData,
  290. ppszDataDescr,
  291. (pOptionalEntropy) ? pOptionalEntropy->pbData : NULL,
  292. (pOptionalEntropy) ? pOptionalEntropy->cbData : 0,
  293. (GUID*)pvReserved,
  294. pLocalPromptStruct,
  295. dwFlags,
  296. pbOptionalPassword,
  297. cbOptionalPassword
  298. );
  299. if( dwRetVal == ERROR_INVALID_DATA &&
  300. DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
  301. {
  302. //
  303. // The data did not decrypt correctly, so warn the user that
  304. // the password might have been entered incorrectly and let them
  305. // try it again up to 3 times.
  306. //
  307. I_CryptUIProtectFailure(
  308. &DerivedPromptStruct,
  309. dwFlags,
  310. (PVOID*)&szDataDescr);
  311. if( dwRetryCount++ < 3 )
  312. {
  313. goto retry;
  314. }
  315. }
  316. if(dwRetVal == ERROR_SUCCESS || dwRetVal == CRYPT_I_NEW_PROTECTION_REQUIRED)
  317. {
  318. if(pDataOut->cbData > 0)
  319. {
  320. NTSTATUS Status;
  321. DWORD cbPadding;
  322. // Decrypt output buffer.
  323. Status = RtlDecryptMemory(pDataOut->pbData,
  324. pDataOut->cbData,
  325. RTL_ENCRYPT_OPTION_SAME_LOGON);
  326. if(!NT_SUCCESS(Status))
  327. {
  328. dwRetVal = ERROR_DECRYPTION_FAILED;
  329. }
  330. // Remove padding
  331. if(dwRetVal == ERROR_SUCCESS)
  332. {
  333. cbPadding = pDataOut->pbData[pDataOut->cbData - 1];
  334. if((cbPadding <= pDataOut->cbData) && (cbPadding <= RTL_ENCRYPT_MEMORY_SIZE))
  335. {
  336. pDataOut->cbData -= cbPadding;
  337. }
  338. else
  339. {
  340. dwRetVal = ERROR_INVALID_DATA;
  341. }
  342. }
  343. }
  344. }
  345. }
  346. } __except(EXCEPTION_EXECUTE_HANDLER) {
  347. dwRetVal = GetExceptionCode();
  348. }
  349. ZeroMemory( rgbPasswordHash, sizeof(rgbPasswordHash) );
  350. UnbindW(&pszBinding, &h);
  351. if((dwFlags & CRYPTPROTECT_VERIFY_PROTECTION ) &&
  352. ((CRYPT_I_NEW_PROTECTION_REQUIRED == dwRetVal) ||
  353. (ERROR_SUCCESS == dwRetVal)))
  354. {
  355. SetLastError(dwRetVal);
  356. return TRUE;
  357. }
  358. if(dwRetVal != ERROR_SUCCESS) {
  359. SetLastError(dwRetVal);
  360. return FALSE;
  361. }
  362. return TRUE;
  363. }
  364. RPC_STATUS BindW(WCHAR **pszBinding, RPC_BINDING_HANDLE *phBind)
  365. {
  366. RPC_STATUS status;
  367. //
  368. // on WinNT5, go to the shared services.exe RPC server
  369. //
  370. status = RpcStringBindingComposeW(
  371. NULL,
  372. (unsigned short*)DPAPI_LOCAL_PROT_SEQ,
  373. NULL,
  374. (unsigned short*)DPAPI_LOCAL_ENDPOINT,
  375. NULL,
  376. (unsigned short * *)pszBinding
  377. );
  378. if (status)
  379. {
  380. return(status);
  381. }
  382. status = RpcBindingFromStringBindingW((unsigned short *)*pszBinding, phBind);
  383. return status;
  384. }
  385. RPC_STATUS UnbindW(WCHAR **pszBinding, RPC_BINDING_HANDLE *phBind)
  386. {
  387. RPC_STATUS status;
  388. status = RpcStringFreeW((unsigned short **)pszBinding);
  389. if (status)
  390. {
  391. return(status);
  392. }
  393. RpcBindingFree(phBind);
  394. return RPC_S_OK;
  395. }
  396. void __RPC_FAR * __RPC_API midl_user_allocate(size_t len)
  397. {
  398. return LocalAlloc(LMEM_FIXED, len);
  399. }
  400. void __RPC_API midl_user_free(void __RPC_FAR * ptr)
  401. {
  402. ZeroMemory(ptr, LocalSize( ptr ));
  403. LocalFree(ptr);
  404. }