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.

616 lines
17 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. PBYTE pbTempIn = NULL;
  71. DWORD cbTempIn;
  72. // check params
  73. if ((pDataOut == NULL) ||
  74. (pDataIn == NULL) ||
  75. (pDataIn->pbData == NULL))
  76. {
  77. SetLastError(ERROR_INVALID_PARAMETER);
  78. return FALSE;
  79. }
  80. RpcStatus = BindW(&pszBinding, &h);
  81. if(RpcStatus != RPC_S_OK)
  82. {
  83. SetLastError(RpcStatus);
  84. return FALSE;
  85. }
  86. __try {
  87. PBYTE pbOptionalPassword = NULL;
  88. DWORD cbOptionalPassword = 0;
  89. SSCRYPTPROTECTDATA_PROMPTSTRUCT PromptStruct;
  90. SSCRYPTPROTECTDATA_PROMPTSTRUCT *pLocalPromptStruct = NULL;
  91. // zero so client stub allocates
  92. ZeroMemory(pDataOut, sizeof(DATA_BLOB));
  93. //
  94. // only call UI function if prompt flags dictate, because we don't
  95. // want to bring in cryptui.dll unless necessary.
  96. //
  97. if( (pPromptStruct != NULL) &&
  98. ((pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_UNPROTECT) ||
  99. (pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_PROTECT))
  100. )
  101. {
  102. dwRetVal = I_CryptUIProtect(
  103. pDataIn,
  104. pPromptStruct,
  105. dwFlags,
  106. (PVOID*)&szAlternateDataDescription,
  107. TRUE,
  108. rgbPasswordHash
  109. );
  110. //
  111. // If UI dictated strong security, then supply the hash.
  112. //
  113. if( pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
  114. {
  115. cbOptionalPassword = sizeof(rgbPasswordHash);
  116. pbOptionalPassword = rgbPasswordHash;
  117. }
  118. }
  119. else
  120. {
  121. dwRetVal = ERROR_SUCCESS;
  122. }
  123. //
  124. // Temporarily encrypt the input buffer, so that it's protected
  125. // in the case where RPC leaves memory buffers laying around.
  126. //
  127. if( dwRetVal == ERROR_SUCCESS )
  128. {
  129. DWORD cbPadding;
  130. NTSTATUS Status;
  131. cbPadding = RTL_ENCRYPT_MEMORY_SIZE - pDataIn->cbData % RTL_ENCRYPT_MEMORY_SIZE;
  132. cbTempIn = pDataIn->cbData + cbPadding;
  133. pbTempIn = (PBYTE)LocalAlloc(LMEM_FIXED, cbTempIn);
  134. if(pbTempIn != NULL)
  135. {
  136. CopyMemory(pbTempIn, pDataIn->pbData, pDataIn->cbData);
  137. FillMemory(pbTempIn + pDataIn->cbData, cbPadding, (BYTE)cbPadding);
  138. }
  139. else
  140. {
  141. dwRetVal = ERROR_OUTOFMEMORY;
  142. }
  143. if( dwRetVal == ERROR_SUCCESS )
  144. {
  145. Status = RtlEncryptMemory(pbTempIn,
  146. cbTempIn,
  147. RTL_ENCRYPT_OPTION_SAME_LOGON);
  148. if(!NT_SUCCESS(Status))
  149. {
  150. dwRetVal = ERROR_ENCRYPTION_FAILED;
  151. }
  152. }
  153. }
  154. //
  155. // Call over to the lsass.exe process, where the input buffer will be
  156. // encrypted using the appropriate user (or machine) credentials.
  157. //
  158. if( dwRetVal == ERROR_SUCCESS )
  159. {
  160. if(pPromptStruct != NULL)
  161. {
  162. ZeroMemory(&PromptStruct, sizeof(PromptStruct));
  163. PromptStruct.cbSize = sizeof(PromptStruct);
  164. PromptStruct.dwPromptFlags = pPromptStruct->dwPromptFlags;
  165. pLocalPromptStruct = &PromptStruct;
  166. }
  167. dwRetVal = SSCryptProtectData(
  168. h,
  169. &pDataOut->pbData,
  170. &pDataOut->cbData,
  171. pbTempIn,
  172. cbTempIn,
  173. szAlternateDataDescription,
  174. (pOptionalEntropy) ? pOptionalEntropy->pbData : NULL,
  175. (pOptionalEntropy) ? pOptionalEntropy->cbData : 0,
  176. pLocalPromptStruct,
  177. dwFlags,
  178. pbOptionalPassword,
  179. cbOptionalPassword
  180. );
  181. }
  182. } __except(EXCEPTION_EXECUTE_HANDLER) {
  183. dwRetVal = GetExceptionCode();
  184. }
  185. UnbindW(&pszBinding, &h);
  186. RtlSecureZeroMemory( rgbPasswordHash, sizeof(rgbPasswordHash) );
  187. if( szAlternateDataDescription &&
  188. szAlternateDataDescription != wszDescription )
  189. {
  190. LocalFree( szAlternateDataDescription );
  191. }
  192. if(pbTempIn != NULL)
  193. {
  194. RtlSecureZeroMemory(pbTempIn, cbTempIn);
  195. LocalFree(pbTempIn);
  196. }
  197. if(dwRetVal != ERROR_SUCCESS)
  198. {
  199. SetLastError(dwRetVal);
  200. return FALSE;
  201. }
  202. return TRUE;
  203. }
  204. BOOL
  205. WINAPI
  206. CryptUnprotectData(
  207. DATA_BLOB* pDataIn, // in encr blob
  208. LPWSTR* ppszDataDescr, // out
  209. DATA_BLOB* pOptionalEntropy,
  210. PVOID pvReserved,
  211. CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
  212. DWORD dwFlags,
  213. DATA_BLOB* pDataOut)
  214. {
  215. RPC_BINDING_HANDLE h = NULL;
  216. LPWSTR pszBinding;
  217. RPC_STATUS RpcStatus;
  218. BYTE rgbPasswordHash[ A_SHA_DIGEST_LEN ];
  219. DWORD dwRetVal;
  220. DWORD dwRetryCount = 0;
  221. // check params
  222. if ((pDataOut == NULL) ||
  223. (pDataIn == NULL) ||
  224. (pDataIn->pbData == NULL))
  225. {
  226. SetLastError(ERROR_INVALID_PARAMETER);
  227. return FALSE;
  228. }
  229. RpcStatus = BindW(&pszBinding, &h);
  230. if(RpcStatus != RPC_S_OK)
  231. {
  232. SetLastError(RpcStatus);
  233. return FALSE;
  234. }
  235. __try {
  236. CRYPTPROTECT_PROMPTSTRUCT DerivedPromptStruct;
  237. PBYTE pbOptionalPassword = NULL;
  238. DWORD cbOptionalPassword = 0;
  239. LPCWSTR szDataDescr;
  240. LPUWSTR szDataDescrUnaligned;
  241. SSCRYPTPROTECTDATA_PROMPTSTRUCT PromptStruct;
  242. SSCRYPTPROTECTDATA_PROMPTSTRUCT *pLocalPromptStruct = NULL;
  243. //
  244. // define outer+inner wrapper for security blob.
  245. // this won't be necessary once SAS support is provided by the OS.
  246. //
  247. typedef struct {
  248. DWORD dwOuterVersion;
  249. GUID guidProvider;
  250. DWORD dwVersion;
  251. GUID guidMK;
  252. DWORD dwPromptFlags;
  253. DWORD cbDataDescr;
  254. WCHAR szDataDescr[1];
  255. } sec_blob, *psec_blob;
  256. sec_blob UNALIGNED *SecurityBlob = (sec_blob*)(pDataIn->pbData);
  257. //
  258. // zero so client stub allocates
  259. //
  260. ZeroMemory(pDataOut, sizeof(DATA_BLOB));
  261. if (ppszDataDescr)
  262. *ppszDataDescr = NULL;
  263. //
  264. // recreate the promptstruct and DataDescr from the security blob.
  265. //
  266. DerivedPromptStruct.cbSize = sizeof(DerivedPromptStruct);
  267. DerivedPromptStruct.dwPromptFlags = SecurityBlob->dwPromptFlags;
  268. //
  269. // SecurityBlob may be unaligned. Set szDataDescr to reference
  270. // an aligned copy.
  271. //
  272. szDataDescrUnaligned = (SecurityBlob->szDataDescr);
  273. WSTR_ALIGNED_STACK_COPY(&szDataDescr,szDataDescrUnaligned);
  274. if( pPromptStruct )
  275. {
  276. DerivedPromptStruct.hwndApp = pPromptStruct->hwndApp;
  277. DerivedPromptStruct.szPrompt = pPromptStruct->szPrompt;
  278. } else {
  279. DerivedPromptStruct.szPrompt = NULL;
  280. DerivedPromptStruct.hwndApp = NULL;
  281. }
  282. retry:
  283. //
  284. // determine if UI is to be raised, and what type.
  285. //
  286. //
  287. // only call UI function if prompt flags dictate, because we don't
  288. // want to bring in cryptui.dll unless necessary.
  289. //
  290. if( ((DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_ON_UNPROTECT) ||
  291. (DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_ON_PROTECT))
  292. )
  293. {
  294. dwRetVal = I_CryptUIProtect(
  295. pDataIn,
  296. &DerivedPromptStruct,
  297. dwFlags,
  298. (PVOID*)&szDataDescr,
  299. FALSE,
  300. rgbPasswordHash
  301. );
  302. //
  303. // If UI dictated strong security, then supply the hash.
  304. //
  305. if( DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
  306. {
  307. cbOptionalPassword = sizeof(rgbPasswordHash);
  308. pbOptionalPassword = rgbPasswordHash;
  309. }
  310. } else {
  311. if( DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
  312. {
  313. dwRetVal = ERROR_INVALID_PARAMETER;
  314. } else {
  315. dwRetVal = ERROR_SUCCESS;
  316. }
  317. }
  318. //
  319. // make the RPC call to attempt to unprotect the data.
  320. //
  321. if( dwRetVal == ERROR_SUCCESS )
  322. {
  323. if(pPromptStruct != NULL)
  324. {
  325. ZeroMemory(&PromptStruct, sizeof(PromptStruct));
  326. PromptStruct.cbSize = sizeof(PromptStruct);
  327. PromptStruct.dwPromptFlags = pPromptStruct->dwPromptFlags;
  328. pLocalPromptStruct = &PromptStruct;
  329. }
  330. dwRetVal = SSCryptUnprotectData(
  331. h,
  332. &pDataOut->pbData,
  333. &pDataOut->cbData,
  334. pDataIn->pbData,
  335. pDataIn->cbData,
  336. ppszDataDescr,
  337. (pOptionalEntropy) ? pOptionalEntropy->pbData : NULL,
  338. (pOptionalEntropy) ? pOptionalEntropy->cbData : 0,
  339. pLocalPromptStruct,
  340. dwFlags,
  341. pbOptionalPassword,
  342. cbOptionalPassword
  343. );
  344. if( (dwRetVal == ERROR_INVALID_DATA) &&
  345. (DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG))
  346. {
  347. //
  348. // The data did not decrypt correctly, so warn the user that
  349. // the password might have been entered incorrectly and let them
  350. // try it again up to 3 times.
  351. //
  352. I_CryptUIProtectFailure(
  353. &DerivedPromptStruct,
  354. dwFlags,
  355. (PVOID*)&szDataDescr);
  356. if( dwRetryCount++ < 3 )
  357. {
  358. goto retry;
  359. }
  360. }
  361. if(dwRetVal == ERROR_SUCCESS || dwRetVal == CRYPT_I_NEW_PROTECTION_REQUIRED)
  362. {
  363. if(pDataOut->cbData > 0)
  364. {
  365. NTSTATUS Status;
  366. DWORD cbPadding;
  367. // Decrypt output buffer.
  368. Status = RtlDecryptMemory(pDataOut->pbData,
  369. pDataOut->cbData,
  370. RTL_ENCRYPT_OPTION_SAME_LOGON);
  371. if(!NT_SUCCESS(Status))
  372. {
  373. dwRetVal = ERROR_DECRYPTION_FAILED;
  374. }
  375. // Remove padding
  376. if(dwRetVal == ERROR_SUCCESS)
  377. {
  378. cbPadding = pDataOut->pbData[pDataOut->cbData - 1];
  379. if((cbPadding > 0) &&
  380. (cbPadding <= pDataOut->cbData) &&
  381. (cbPadding <= RTL_ENCRYPT_MEMORY_SIZE))
  382. {
  383. pDataOut->cbData -= cbPadding;
  384. }
  385. else
  386. {
  387. dwRetVal = ERROR_INVALID_DATA;
  388. }
  389. }
  390. }
  391. }
  392. }
  393. } __except(EXCEPTION_EXECUTE_HANDLER) {
  394. dwRetVal = GetExceptionCode();
  395. }
  396. RtlSecureZeroMemory( rgbPasswordHash, sizeof(rgbPasswordHash) );
  397. UnbindW(&pszBinding, &h);
  398. if((dwFlags & CRYPTPROTECT_VERIFY_PROTECTION ) &&
  399. ((CRYPT_I_NEW_PROTECTION_REQUIRED == dwRetVal) ||
  400. (ERROR_SUCCESS == dwRetVal)))
  401. {
  402. SetLastError(dwRetVal);
  403. return TRUE;
  404. }
  405. if(dwRetVal != ERROR_SUCCESS)
  406. {
  407. SetLastError(dwRetVal);
  408. return FALSE;
  409. }
  410. return TRUE;
  411. }
  412. C_ASSERT(CRYPTPROTECTMEMORY_SAME_PROCESS == 0);
  413. C_ASSERT(CRYPTPROTECTMEMORY_CROSS_PROCESS == RTL_ENCRYPT_OPTION_CROSS_PROCESS);
  414. C_ASSERT(CRYPTPROTECTMEMORY_SAME_LOGON == RTL_ENCRYPT_OPTION_SAME_LOGON);
  415. WINCRYPT32API
  416. BOOL
  417. WINAPI
  418. CryptProtectMemory(
  419. IN OUT LPVOID pDataIn, // in out data to encrypt
  420. IN DWORD cbDataIn, // multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
  421. IN DWORD dwFlags
  422. )
  423. {
  424. NTSTATUS Status;
  425. Status = RtlEncryptMemory(pDataIn, cbDataIn, dwFlags);
  426. if( NT_SUCCESS(Status) )
  427. {
  428. return TRUE;
  429. }
  430. SetLastError( LsaNtStatusToWinError( Status ));
  431. return FALSE;
  432. }
  433. WINCRYPT32API
  434. BOOL
  435. WINAPI
  436. CryptUnprotectMemory(
  437. IN OUT LPVOID pDataIn, // in out data to decrypt
  438. IN DWORD cbDataIn, // multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
  439. IN DWORD dwFlags
  440. )
  441. {
  442. NTSTATUS Status;
  443. Status = RtlDecryptMemory(pDataIn, cbDataIn, dwFlags);
  444. if( NT_SUCCESS(Status) )
  445. {
  446. return TRUE;
  447. }
  448. SetLastError( LsaNtStatusToWinError( Status ));
  449. return FALSE;
  450. }
  451. RPC_STATUS BindW(WCHAR **pszBinding, RPC_BINDING_HANDLE *phBind)
  452. {
  453. RPC_STATUS status;
  454. status = RpcStringBindingComposeW(
  455. NULL,
  456. (unsigned short*)DPAPI_LOCAL_PROT_SEQ,
  457. NULL,
  458. (unsigned short*)DPAPI_LOCAL_ENDPOINT,
  459. NULL,
  460. (unsigned short * *)pszBinding
  461. );
  462. if (status)
  463. {
  464. return(status);
  465. }
  466. status = RpcBindingFromStringBindingW((unsigned short *)*pszBinding, phBind);
  467. return status;
  468. }
  469. RPC_STATUS UnbindW(WCHAR **pszBinding, RPC_BINDING_HANDLE *phBind)
  470. {
  471. RPC_STATUS status;
  472. status = RpcStringFreeW((unsigned short **)pszBinding);
  473. if (status)
  474. {
  475. return(status);
  476. }
  477. RpcBindingFree(phBind);
  478. return RPC_S_OK;
  479. }
  480. void __RPC_FAR * __RPC_API midl_user_allocate(size_t len)
  481. {
  482. return LocalAlloc(LMEM_FIXED, len);
  483. }
  484. void __RPC_API midl_user_free(void __RPC_FAR * ptr)
  485. {
  486. ZeroMemory(ptr, LocalSize( ptr ));
  487. LocalFree(ptr);
  488. }