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.

1505 lines
33 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: xcertlib.cpp
  8. //
  9. // Contents: most functions are moved and modofied from certsrv library
  10. //
  11. // History: 03-2000 xtan created
  12. //--------------------------------------------------------------------------
  13. #include <windows.h>
  14. #include <assert.h>
  15. #include <dbgdef.h>
  16. #include <wininet.h>
  17. #include "xelib.h"
  18. // Crypt callback versions: must have certain signatures
  19. LPVOID myCryptAlloc_LocalAlloc(size_t cbSize) { return myAlloc(cbSize, CERTLIB_USE_LOCALALLOC); }
  20. VOID myCryptAlloc_LocalFree(VOID* pv) { myFree(pv, CERTLIB_USE_LOCALALLOC); }
  21. LPVOID myCryptAlloc_CoTaskMemAlloc(size_t cbSize) { return myAlloc(cbSize, CERTLIB_USE_COTASKMEMALLOC); }
  22. VOID myCryptAlloc_CoTaskMemFree(VOID* pv) { myFree(pv, CERTLIB_USE_COTASKMEMALLOC); }
  23. // give callers an easy way to choose what to call: pick allocator based on allocation type
  24. PFN_CRYPT_ALLOC PickAlloc(CERTLIB_ALLOCATOR allocType)
  25. {
  26. if (allocType == CERTLIB_USE_LOCALALLOC)
  27. return myCryptAlloc_LocalAlloc;
  28. else if (allocType == CERTLIB_USE_COTASKMEMALLOC)
  29. return myCryptAlloc_CoTaskMemAlloc;
  30. CSASSERT(!"Bad allocType");
  31. return NULL;
  32. }
  33. PFN_CRYPT_FREE PickFree(CERTLIB_ALLOCATOR allocType)
  34. {
  35. if (allocType == CERTLIB_USE_LOCALALLOC)
  36. return myCryptAlloc_LocalFree;
  37. else if (allocType == CERTLIB_USE_COTASKMEMALLOC)
  38. return myCryptAlloc_CoTaskMemFree;
  39. CSASSERT(!"Bad allocType");
  40. return NULL;
  41. }
  42. VOID *
  43. myAlloc(IN size_t cbBytes, IN CERTLIB_ALLOCATOR allocType)
  44. {
  45. void *pv;
  46. switch (allocType)
  47. {
  48. case CERTLIB_USE_LOCALALLOC:
  49. pv = LocalAlloc(LMEM_FIXED, cbBytes);
  50. break;
  51. case CERTLIB_USE_COTASKMEMALLOC:
  52. pv = CoTaskMemAlloc(cbBytes);
  53. break;
  54. default:
  55. CSASSERT(FALSE);
  56. pv = NULL;
  57. break;
  58. }
  59. if (NULL == pv)
  60. {
  61. _PrintError(E_OUTOFMEMORY, "myAlloc");
  62. SetLastError((DWORD) E_OUTOFMEMORY);
  63. }
  64. return(pv);
  65. }
  66. VOID
  67. myFree(IN void *pv, IN CERTLIB_ALLOCATOR allocType)
  68. {
  69. switch(allocType)
  70. {
  71. case CERTLIB_USE_LOCALALLOC:
  72. LocalFree(pv);
  73. break;
  74. case CERTLIB_USE_COTASKMEMALLOC:
  75. CoTaskMemFree(pv);
  76. break;
  77. default:
  78. CSASSERT(FALSE);
  79. break;
  80. }
  81. }
  82. HRESULT
  83. myHError(HRESULT hr)
  84. {
  85. CSASSERT(S_FALSE != hr);
  86. if (S_OK != hr && S_FALSE != hr && !FAILED(hr))
  87. {
  88. hr = HRESULT_FROM_WIN32(hr);
  89. if (0 == HRESULT_CODE(hr))
  90. {
  91. // A call failed without properly setting an error condition!
  92. hr = E_UNEXPECTED;
  93. }
  94. CSASSERT(FAILED(hr));
  95. }
  96. return(hr);
  97. }
  98. HRESULT
  99. myHLastError(VOID)
  100. {
  101. return(myHError(GetLastError()));
  102. }
  103. #ifdef _XENROLL_SRC_
  104. typedef BOOL
  105. (WINAPI * PFNCryptEncodeObjectEx)
  106. (IN DWORD dwCertEncodingType,
  107. IN LPCSTR lpszStructType,
  108. IN const void *pvStructInfo,
  109. IN DWORD dwFlags,
  110. IN OPTIONAL PCRYPT_ENCODE_PARA pEncodePara,
  111. OUT void *pvEncoded,
  112. IN OUT DWORD *pcbEncoded);
  113. typedef BOOL
  114. (WINAPI * PFNCryptDecodeObjectEx)
  115. (IN DWORD dwCertEncodingType,
  116. IN LPCSTR lpszStructType,
  117. IN const BYTE *pbEncoded,
  118. IN DWORD cbEncoded,
  119. IN DWORD dwFlags,
  120. IN OPTIONAL PCRYPT_DECODE_PARA pDecodePara,
  121. OUT OPTIONAL void *pvStructInfo,
  122. IN OUT DWORD *pcbStructInfo);
  123. #endif //_XENROLL_SRC_
  124. BOOL
  125. myEncodeObject(
  126. DWORD dwEncodingType,
  127. IN LPCSTR lpszStructType,
  128. IN VOID const *pvStructInfo,
  129. IN DWORD dwFlags,
  130. IN CERTLIB_ALLOCATOR allocType,
  131. OUT BYTE **ppbEncoded,
  132. OUT DWORD *pcbEncoded)
  133. {
  134. BOOL b = FALSE;
  135. CSASSERT(NULL != ppbEncoded);
  136. CRYPT_ENCODE_PARA sAllocator;
  137. sAllocator.cbSize = sizeof(sAllocator);
  138. sAllocator.pfnAlloc = PickAlloc(allocType);
  139. sAllocator.pfnFree = PickFree(allocType);
  140. #ifdef _XENROLL_SRC_
  141. PFNCryptEncodeObjectEx pfnCryptEncodeObjectEx = NULL;
  142. HMODULE hModule = GetModuleHandle("crypt32.dll");
  143. if (NULL != hModule)
  144. {
  145. pfnCryptEncodeObjectEx = (PFNCryptEncodeObjectEx)
  146. GetProcAddress(hModule, "CryptEncodeObjectEx");
  147. if (NULL != pfnCryptEncodeObjectEx)
  148. {
  149. b = pfnCryptEncodeObjectEx(
  150. dwEncodingType,
  151. lpszStructType,
  152. const_cast<VOID *>(pvStructInfo),
  153. dwFlags|CRYPT_ENCODE_ALLOC_FLAG,
  154. &sAllocator,
  155. ppbEncoded,
  156. pcbEncoded);
  157. }
  158. }
  159. #else
  160. b = CryptEncodeObjectEx(
  161. dwEncodingType,
  162. lpszStructType,
  163. const_cast<VOID *>(pvStructInfo),
  164. dwFlags|CRYPT_ENCODE_ALLOC_FLAG,
  165. &sAllocator,
  166. ppbEncoded,
  167. pcbEncoded);
  168. if (b && 0 == *pcbEncoded)
  169. {
  170. SetLastError((DWORD) HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  171. b = FALSE;
  172. }
  173. #endif //_XENROLL_SRC_
  174. return(b);
  175. }
  176. BOOL
  177. myDecodeObject(
  178. IN DWORD dwEncodingType,
  179. IN LPCSTR lpszStructType,
  180. IN BYTE const *pbEncoded,
  181. IN DWORD cbEncoded,
  182. IN CERTLIB_ALLOCATOR allocType,
  183. OUT VOID **ppvStructInfo,
  184. OUT DWORD *pcbStructInfo)
  185. {
  186. BOOL b = FALSE;
  187. CRYPT_DECODE_PARA sAllocator;
  188. sAllocator.cbSize = sizeof(sAllocator);
  189. sAllocator.pfnAlloc = PickAlloc(allocType);
  190. sAllocator.pfnFree = PickFree(allocType);
  191. #ifdef _XENROLL_SRC_
  192. PFNCryptDecodeObjectEx pfnCryptDecodeObjectEx = NULL;
  193. HMODULE hModule = GetModuleHandle("crypt32.dll");
  194. if (NULL != hModule)
  195. {
  196. pfnCryptDecodeObjectEx = (PFNCryptDecodeObjectEx)
  197. GetProcAddress(hModule, "CryptDecodeObjectEx");
  198. if (NULL != pfnCryptDecodeObjectEx)
  199. {
  200. b = pfnCryptDecodeObjectEx(
  201. dwEncodingType,
  202. lpszStructType,
  203. pbEncoded,
  204. cbEncoded,
  205. CRYPT_DECODE_ALLOC_FLAG, // dwFlags
  206. &sAllocator,
  207. ppvStructInfo,
  208. pcbStructInfo);
  209. }
  210. }
  211. #else
  212. b = CryptDecodeObjectEx(
  213. dwEncodingType,
  214. lpszStructType,
  215. pbEncoded,
  216. cbEncoded,
  217. CRYPT_DECODE_ALLOC_FLAG, // dwFlags
  218. &sAllocator,
  219. ppvStructInfo,
  220. pcbStructInfo);
  221. if (b && 0 == *pcbStructInfo)
  222. {
  223. SetLastError((DWORD) HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  224. b = FALSE;
  225. }
  226. #endif //_XENROLL_SRC_
  227. return(b);
  228. }
  229. HRESULT
  230. myDecodePKCS7(
  231. IN BYTE const *pbIn,
  232. IN DWORD cbIn,
  233. OPTIONAL OUT BYTE **ppbContents,
  234. OPTIONAL OUT DWORD *pcbContents,
  235. OPTIONAL OUT DWORD *pdwMsgType,
  236. OPTIONAL OUT char **ppszInnerContentObjId,
  237. OPTIONAL OUT DWORD *pcSigner,
  238. OPTIONAL OUT DWORD *pcRecipient,
  239. OPTIONAL OUT HCERTSTORE *phStore,
  240. OPTIONAL OUT HCRYPTMSG *phMsg)
  241. {
  242. HRESULT hr;
  243. BYTE *pbContents = NULL;
  244. HCERTSTORE hStore = NULL;
  245. HCRYPTMSG hMsg = NULL;
  246. DWORD cbContents;
  247. char *pszInnerContentObjId = NULL;
  248. DWORD cb;
  249. if (NULL != ppszInnerContentObjId)
  250. {
  251. *ppszInnerContentObjId = NULL;
  252. }
  253. if (NULL != pcSigner)
  254. {
  255. *pcSigner = 0;
  256. }
  257. if (NULL != pcRecipient)
  258. {
  259. *pcRecipient = 0;
  260. }
  261. if (NULL != ppbContents)
  262. {
  263. *ppbContents = NULL;
  264. }
  265. if (NULL != phStore)
  266. {
  267. *phStore = NULL;
  268. }
  269. if (NULL != phMsg)
  270. {
  271. *phMsg = NULL;
  272. }
  273. if (NULL != phStore)
  274. {
  275. CRYPT_DATA_BLOB blobPKCS7;
  276. blobPKCS7.pbData = (BYTE *) pbIn;
  277. blobPKCS7.cbData = cbIn;
  278. hStore = CertOpenStore(
  279. CERT_STORE_PROV_PKCS7,
  280. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  281. NULL, // hCryptProv
  282. 0, // dwFlags
  283. &blobPKCS7);
  284. if (NULL == hStore)
  285. {
  286. hr = myHLastError();
  287. _JumpError(hr, error, "CertOpenStore");
  288. // _JumpError2(hr, error, "CertOpenStore", CRYPT_E_ASN1_BADTAG);
  289. }
  290. }
  291. hMsg = CryptMsgOpenToDecode(
  292. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  293. 0, // dwFlags
  294. 0, // dwMsgType
  295. NULL, // hCryptProv
  296. NULL, // pRecipientInfo
  297. NULL); // pStreamInfo
  298. if (NULL == hMsg)
  299. {
  300. hr = myHLastError();
  301. _JumpError(hr, error, "CryptMsgOpenToDecode");
  302. }
  303. if (!CryptMsgUpdate(hMsg, pbIn, cbIn, TRUE))
  304. {
  305. hr = myHLastError();
  306. _JumpError(hr, error, "CryptMsgUpdate");
  307. }
  308. hr = myCryptMsgGetParam(
  309. hMsg,
  310. CMSG_INNER_CONTENT_TYPE_PARAM,
  311. 0, // dwIndex
  312. CERTLIB_USE_LOCALALLOC,
  313. (VOID **) &pszInnerContentObjId,
  314. &cb);
  315. _PrintIfError(hr, "myCryptMsgGetParam(inner content type)");
  316. #if 0
  317. DBGPRINT((
  318. DBG_SS_CERTLIBI,
  319. "pszInnerContentObjId = %hs\n",
  320. pszInnerContentObjId));
  321. #endif //0
  322. cbContents = 0;
  323. hr = myCryptMsgGetParam(
  324. hMsg,
  325. CMSG_CONTENT_PARAM,
  326. 0, // dwIndex
  327. CERTLIB_USE_LOCALALLOC,
  328. (VOID **) &pbContents,
  329. &cbContents);
  330. _JumpIfError(hr, error, "myCryptMsgGetParam(content)");
  331. if (NULL != pdwMsgType)
  332. {
  333. cb = sizeof(*pdwMsgType);
  334. if (!CryptMsgGetParam(
  335. hMsg,
  336. CMSG_TYPE_PARAM,
  337. 0,
  338. pdwMsgType,
  339. &cb))
  340. {
  341. hr = myHLastError();
  342. _JumpError(hr, error, "CryptMsgGetParam(type)");
  343. }
  344. }
  345. if (NULL != pcSigner)
  346. {
  347. cb = sizeof(*pcSigner);
  348. if (!CryptMsgGetParam(
  349. hMsg,
  350. CMSG_SIGNER_COUNT_PARAM,
  351. 0,
  352. pcSigner,
  353. &cb))
  354. {
  355. hr = myHLastError();
  356. *pcSigner = 0;
  357. if (CRYPT_E_INVALID_MSG_TYPE != hr)
  358. {
  359. _JumpError(hr, error, "CryptMsgGetParam(signer count)");
  360. }
  361. }
  362. }
  363. if (NULL != pcRecipient)
  364. {
  365. cb = sizeof(*pcRecipient);
  366. if (!CryptMsgGetParam(
  367. hMsg,
  368. CMSG_RECIPIENT_COUNT_PARAM,
  369. 0,
  370. pcRecipient,
  371. &cb))
  372. {
  373. hr = myHLastError();
  374. *pcRecipient = 0;
  375. if (CRYPT_E_INVALID_MSG_TYPE != hr)
  376. {
  377. _JumpError(hr, error, "CryptMsgGetParam(recipient count)");
  378. }
  379. }
  380. }
  381. if (NULL != phMsg)
  382. {
  383. *phMsg = hMsg;
  384. hMsg = NULL;
  385. }
  386. if (NULL != phStore)
  387. {
  388. *phStore = hStore;
  389. hStore = NULL;
  390. }
  391. if (NULL != ppszInnerContentObjId)
  392. {
  393. *ppszInnerContentObjId = pszInnerContentObjId;
  394. pszInnerContentObjId = NULL;
  395. }
  396. if (NULL != pcbContents)
  397. {
  398. *pcbContents = cbContents;
  399. }
  400. if (NULL != ppbContents && 0 != cbContents)
  401. {
  402. *ppbContents = pbContents;
  403. pbContents = NULL;
  404. }
  405. hr = S_OK;
  406. error:
  407. if (NULL != hMsg)
  408. {
  409. CryptMsgClose(hMsg);
  410. }
  411. if (NULL != hStore)
  412. {
  413. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  414. }
  415. if (NULL != pbContents)
  416. {
  417. LocalFree(pbContents);
  418. }
  419. if (NULL != pszInnerContentObjId)
  420. {
  421. LocalFree(pszInnerContentObjId);
  422. }
  423. return(hr);
  424. }
  425. HRESULT
  426. myDupString(
  427. IN WCHAR const *pwszIn,
  428. IN WCHAR **ppwszOut)
  429. {
  430. DWORD cb;
  431. HRESULT hr;
  432. cb = (wcslen(pwszIn) + 1) * sizeof(WCHAR);
  433. *ppwszOut = (WCHAR *) LocalAlloc(LMEM_FIXED, cb);
  434. if (NULL == *ppwszOut)
  435. {
  436. hr = E_OUTOFMEMORY;
  437. _JumpError(hr, error, "LocalAlloc");
  438. }
  439. CopyMemory(*ppwszOut, pwszIn, cb);
  440. hr = S_OK;
  441. error:
  442. return(hr);
  443. }
  444. HRESULT
  445. myAddNameSuffix(
  446. IN WCHAR const *pwszValue,
  447. IN WCHAR const *pwszSuffix,
  448. IN DWORD cwcNameMax,
  449. OUT WCHAR **ppwszOut)
  450. {
  451. HRESULT hr;
  452. DWORD cwcValue = wcslen(pwszValue);
  453. DWORD cwcSuffix = wcslen(pwszSuffix);
  454. WCHAR *pwszOut;
  455. *ppwszOut = NULL;
  456. pwszOut = (WCHAR *) LocalAlloc(
  457. LMEM_FIXED,
  458. sizeof(WCHAR) * (1 + cwcValue + cwcSuffix));
  459. if (NULL == pwszOut)
  460. {
  461. hr = E_OUTOFMEMORY;
  462. _JumpError(hr, error, "LocalAlloc");
  463. }
  464. CSASSERT(cwcNameMax > cwcSuffix);
  465. if (cwcValue > cwcNameMax - cwcSuffix)
  466. {
  467. cwcValue = cwcNameMax - cwcSuffix;
  468. }
  469. wcscpy(pwszOut, pwszValue);
  470. wcscpy(&pwszOut[cwcValue], pwszSuffix);
  471. *ppwszOut = pwszOut;
  472. hr = S_OK;
  473. error:
  474. return(hr);
  475. }
  476. #define OCTECTSPACES
  477. VOID
  478. MultiByteStringSize(
  479. IN BOOL fOctetString,
  480. IN BYTE const *pbIn,
  481. IN OUT DWORD *pcbIn,
  482. OUT DWORD *pcbString)
  483. {
  484. DWORD cbIn = *pcbIn;
  485. DWORD cbString;
  486. if (!fOctetString)
  487. {
  488. while (1 < cbIn && 0 == pbIn[cbIn - 1])
  489. {
  490. cbIn--;
  491. }
  492. }
  493. // Two ascii-hex characters per byte, plus the null terminator:
  494. cbString = ((2 * cbIn) + 1) * sizeof(WCHAR);
  495. #ifdef OCTECTSPACES
  496. // Allow for separating spaces after each byte except the last:
  497. if (fOctetString && 1 < cbIn)
  498. {
  499. cbString += (cbIn - 1) * sizeof(WCHAR);
  500. }
  501. #endif // OCTECTSPACES
  502. *pcbIn = cbIn;
  503. *pcbString = cbString;
  504. }
  505. __inline WCHAR
  506. NibbleToAscii(
  507. IN BYTE b)
  508. {
  509. return(L"0123456789abcdef"[b & 0x0f]);
  510. }
  511. // MultiByteIntegerToWszBuf - convert a little-endian integer blob to
  512. // a big endian null-terminated ascii-hex encoded WCHAR string of even length.
  513. HRESULT
  514. MultiByteIntegerToWszBuf(
  515. IN BOOL fOctetString,
  516. IN DWORD cbIn,
  517. IN BYTE const *pbIn,
  518. IN OUT DWORD *pcbOut,
  519. OPTIONAL OUT WCHAR *pwszOut)
  520. {
  521. HRESULT hr = S_OK;
  522. DWORD cbOut;
  523. BYTE const *pbEnd = &pbIn[cbIn];
  524. MultiByteStringSize(fOctetString, pbIn, &cbIn, &cbOut);
  525. if (NULL != pwszOut)
  526. {
  527. BYTE const *pb;
  528. if (cbOut > *pcbOut)
  529. {
  530. hr = TYPE_E_BUFFERTOOSMALL;
  531. _JumpError(hr, error, "MultiByteIntegerToWsz: buffer overflow");
  532. }
  533. if (fOctetString)
  534. {
  535. for (pb = pbIn; pb < pbEnd; pb++)
  536. {
  537. *pwszOut++ = NibbleToAscii(*pb >> 4);
  538. *pwszOut++ = NibbleToAscii(*pb);
  539. #ifdef OCTECTSPACES
  540. if (pb + 1 < pbEnd)
  541. {
  542. *pwszOut++ = L' ';
  543. }
  544. #endif // OCTECTSPACES
  545. }
  546. }
  547. else
  548. {
  549. for (pb = pbEnd; pb-- > pbIn; )
  550. {
  551. *pwszOut++ = NibbleToAscii(*pb >> 4);
  552. *pwszOut++ = NibbleToAscii(*pb);
  553. }
  554. }
  555. *pwszOut = L'\0';
  556. CSASSERT(
  557. (SAFE_SUBTRACT_POINTERS(pwszOut, pwsz) + 1) * sizeof(WCHAR) ==
  558. cbOut);
  559. }
  560. *pcbOut = cbOut;
  561. error:
  562. return(hr);
  563. }
  564. // MultiByteIntegerToBstr - convert a little-endian integer blob to
  565. // a big endian null-terminated ascii-hex encoded BSTR of even length.
  566. // If fOctetString is TRUE, preserve endian order, as in a hex dump
  567. HRESULT
  568. MultiByteIntegerToBstr(
  569. IN BOOL fOctetString,
  570. IN DWORD cbIn,
  571. IN BYTE const *pbIn,
  572. OUT BSTR *pstrOut)
  573. {
  574. HRESULT hr = S_OK;
  575. BSTR str = NULL;
  576. DWORD cbOut;
  577. MultiByteStringSize(fOctetString, pbIn, &cbIn, &cbOut);
  578. str = SysAllocStringByteLen(NULL, cbOut - sizeof(WCHAR));
  579. if (NULL == str)
  580. {
  581. hr = E_OUTOFMEMORY;
  582. _JumpError(hr, error, "SysAllocStringLen");
  583. }
  584. hr = MultiByteIntegerToWszBuf(fOctetString, cbIn, pbIn, &cbOut, str);
  585. _JumpIfError(hr, error, "MultiByteIntegerToWszBuf");
  586. CSASSERT((wcslen(str) + 1) * sizeof(WCHAR) == cbOut);
  587. CSASSERT(SysStringByteLen(str) + sizeof(WCHAR) == cbOut);
  588. if (NULL != *pstrOut)
  589. {
  590. SysFreeString(*pstrOut);
  591. }
  592. *pstrOut = str;
  593. str = NULL;
  594. error:
  595. if (NULL != str)
  596. {
  597. SysFreeString(str);
  598. }
  599. return(hr);
  600. }
  601. BOOL
  602. myCryptExportPublicKeyInfo(
  603. IN HCRYPTPROV hCryptProv,
  604. IN DWORD dwKeySpec, // AT_SIGNATURE | AT_KEYEXCHANGE
  605. IN CERTLIB_ALLOCATOR allocType,
  606. OUT CERT_PUBLIC_KEY_INFO **ppPubKey,
  607. OUT DWORD *pcbPubKey)
  608. {
  609. BOOL b;
  610. *ppPubKey = NULL;
  611. *pcbPubKey = 0;
  612. for (;;)
  613. {
  614. b = CryptExportPublicKeyInfo(
  615. hCryptProv,
  616. dwKeySpec,
  617. X509_ASN_ENCODING,
  618. *ppPubKey,
  619. pcbPubKey);
  620. if (b && 0 == *pcbPubKey)
  621. {
  622. SetLastError((DWORD) HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  623. b = FALSE;
  624. }
  625. if (!b)
  626. {
  627. if (NULL != *ppPubKey)
  628. {
  629. myFree(*ppPubKey, allocType);
  630. *ppPubKey = NULL;
  631. }
  632. break;
  633. }
  634. if (NULL != *ppPubKey)
  635. {
  636. break;
  637. }
  638. *ppPubKey = (CERT_PUBLIC_KEY_INFO *) myAlloc(*pcbPubKey, allocType);
  639. if (NULL == *ppPubKey)
  640. {
  641. b = FALSE;
  642. break;
  643. }
  644. }
  645. return(b);
  646. }
  647. VOID
  648. myMakeExprDateTime(
  649. IN OUT FILETIME *pft,
  650. IN LONG lDelta,
  651. IN enum ENUM_PERIOD enumPeriod)
  652. {
  653. LONGLONG llDelta;
  654. BOOL fSysTimeDelta;
  655. llDelta = lDelta;
  656. fSysTimeDelta = FALSE;
  657. switch (enumPeriod)
  658. {
  659. case ENUM_PERIOD_WEEKS: llDelta *= CVT_WEEKS; break;
  660. case ENUM_PERIOD_DAYS: llDelta *= CVT_DAYS; break;
  661. case ENUM_PERIOD_HOURS: llDelta *= CVT_HOURS; break;
  662. case ENUM_PERIOD_MINUTES: llDelta *= CVT_MINUTES; break;
  663. case ENUM_PERIOD_SECONDS: break;
  664. //case ENUM_PERIOD_MONTHS:
  665. //case ENUM_PERIOD_YEARS:
  666. default:
  667. // Avoid side effect of round trip SYSTEMTIME conversion
  668. // (avoid truncating microseconds) if lDelta is zero.
  669. if (0 != lDelta)
  670. {
  671. fSysTimeDelta = TRUE;
  672. }
  673. break;
  674. }
  675. if (fSysTimeDelta)
  676. {
  677. SYSTEMTIME SystemTime;
  678. FileTimeToSystemTime(pft, &SystemTime);
  679. switch (enumPeriod)
  680. {
  681. case ENUM_PERIOD_MONTHS:
  682. if (0 > lDelta)
  683. {
  684. DWORD dwDelta = (DWORD) -lDelta;
  685. SystemTime.wYear -= (WORD) (dwDelta / 12) + 1;
  686. SystemTime.wMonth += 12 - (WORD) (dwDelta % 12);
  687. }
  688. else
  689. {
  690. SystemTime.wMonth = (WORD) (SystemTime.wMonth + lDelta);
  691. }
  692. if (12 < SystemTime.wMonth)
  693. {
  694. SystemTime.wYear += (SystemTime.wMonth - 1) / 12;
  695. SystemTime.wMonth = ((SystemTime.wMonth - 1) % 12) + 1;
  696. }
  697. break;
  698. case ENUM_PERIOD_YEARS:
  699. SystemTime.wYear = (WORD) (SystemTime.wYear + lDelta);
  700. break;
  701. default:
  702. SystemTime.wYear += 1;
  703. break;
  704. }
  705. DoConvert:
  706. if (!SystemTimeToFileTime(&SystemTime, pft))
  707. {
  708. if (GetLastError() != ERROR_INVALID_PARAMETER)
  709. {
  710. CSASSERT(!"Unable to do time conversion");
  711. return;
  712. }
  713. // In some cases we'll convert to an invalid month-end
  714. // only one month changes length from year to year
  715. if (SystemTime.wMonth == 2)
  716. {
  717. // > 29? try leap year
  718. if (SystemTime.wDay > 29)
  719. {
  720. SystemTime.wDay = 29;
  721. goto DoConvert;
  722. }
  723. // == 29? try non-leap year
  724. else if (SystemTime.wDay == 29)
  725. {
  726. SystemTime.wDay = 28;
  727. goto DoConvert;
  728. }
  729. }
  730. // sept (9), apr(4), jun(6), nov(11) all have 30 days
  731. else if ((SystemTime.wMonth == 9) ||
  732. (SystemTime.wMonth == 4) ||
  733. (SystemTime.wMonth == 6) ||
  734. (SystemTime.wMonth == 11))
  735. {
  736. if (SystemTime.wDay > 30)
  737. {
  738. SystemTime.wDay = 30;
  739. goto DoConvert;
  740. }
  741. }
  742. // should never get here
  743. CSASSERT(!"Month/year processing: inaccessible code");
  744. return;
  745. }
  746. }
  747. else
  748. {
  749. *(LONGLONG UNALIGNED *) pft += llDelta * CVT_BASE;
  750. }
  751. }
  752. BOOL
  753. myCryptSignCertificate(
  754. IN HCRYPTPROV hCryptProv,
  755. IN DWORD dwKeySpec,
  756. IN DWORD dwEncodingType,
  757. IN BYTE const *pbEncodedToBeSigned,
  758. IN DWORD cbEncodedToBeSigned,
  759. IN CRYPT_ALGORITHM_IDENTIFIER const *pSignatureAlgorithm,
  760. IN CERTLIB_ALLOCATOR allocType,
  761. OUT BYTE **ppbSignature,
  762. OUT DWORD *pcbSignature)
  763. {
  764. BOOL b;
  765. *ppbSignature = NULL;
  766. *pcbSignature = 0;
  767. for (;;)
  768. {
  769. b = CryptSignCertificate(
  770. hCryptProv,
  771. dwKeySpec,
  772. dwEncodingType,
  773. pbEncodedToBeSigned,
  774. cbEncodedToBeSigned,
  775. const_cast<CRYPT_ALGORITHM_IDENTIFIER *>(pSignatureAlgorithm),
  776. NULL, // pvHashAuxInfo
  777. *ppbSignature,
  778. pcbSignature);
  779. if (b && 0 == *pcbSignature)
  780. {
  781. SetLastError((DWORD) HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  782. b = FALSE;
  783. }
  784. if (!b)
  785. {
  786. if (NULL != *ppbSignature)
  787. {
  788. myFree(*ppbSignature, allocType);
  789. *ppbSignature = NULL;
  790. }
  791. break;
  792. }
  793. if (NULL != *ppbSignature)
  794. {
  795. break;
  796. }
  797. *ppbSignature = (BYTE *) myAlloc(*pcbSignature, allocType);
  798. if (NULL == *ppbSignature)
  799. {
  800. b = FALSE;
  801. break;
  802. }
  803. }
  804. return(b);
  805. }
  806. HRESULT
  807. myEncodeSignedContent(
  808. IN HCRYPTPROV hProv,
  809. IN DWORD dwCertEncodingType,
  810. IN char const *pszObjIdSignatureAlgorithm,
  811. IN BYTE *pbToBeSigned,
  812. IN DWORD cbToBeSigned,
  813. IN CERTLIB_ALLOCATOR allocType,
  814. OUT BYTE **ppbSigned,
  815. OUT DWORD *pcbSigned)
  816. {
  817. HRESULT hr;
  818. CERT_SIGNED_CONTENT_INFO csci;
  819. ZeroMemory(&csci, sizeof(csci));
  820. csci.SignatureAlgorithm.pszObjId = (char *) pszObjIdSignatureAlgorithm;
  821. csci.ToBeSigned.cbData = cbToBeSigned;
  822. csci.ToBeSigned.pbData = pbToBeSigned;
  823. *ppbSigned = NULL;
  824. if (!myCryptSignCertificate(
  825. hProv,
  826. AT_SIGNATURE,
  827. dwCertEncodingType,
  828. csci.ToBeSigned.pbData,
  829. csci.ToBeSigned.cbData,
  830. &csci.SignatureAlgorithm,
  831. CERTLIB_USE_LOCALALLOC,
  832. &csci.Signature.pbData,
  833. &csci.Signature.cbData))
  834. {
  835. hr = myHLastError();
  836. _JumpError(hr, error, "myCryptSignCertificate");
  837. }
  838. // if (!myEncodeCert(
  839. if (!myEncodeObject(
  840. dwCertEncodingType,
  841. X509_CERT,
  842. &csci,
  843. 0,
  844. allocType,
  845. ppbSigned,
  846. pcbSigned))
  847. {
  848. hr = myHLastError();
  849. // _JumpError(hr, error, "myEncodeCert");
  850. _JumpError(hr, error, "myEncodeObject");
  851. }
  852. hr = S_OK;
  853. error:
  854. if (NULL != csci.Signature.pbData)
  855. {
  856. LocalFree(csci.Signature.pbData);
  857. }
  858. return(hr);
  859. }
  860. HRESULT
  861. myGetPublicKeyHash(
  862. OPTIONAL IN CERT_INFO const *pCertInfo,
  863. IN CERT_PUBLIC_KEY_INFO const *pPublicKeyInfo,
  864. OUT BYTE **ppbData,
  865. OUT DWORD *pcbData)
  866. {
  867. HRESULT hr;
  868. CRYPT_DATA_BLOB *pBlob = NULL;
  869. DWORD cb;
  870. BYTE const *pb;
  871. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  872. *ppbData = NULL;
  873. if (NULL == pPublicKeyInfo)
  874. {
  875. hr = E_POINTER;
  876. _JumpError(hr, error, "parm NULL");
  877. }
  878. pb = NULL;
  879. cb = 0;
  880. if (NULL != pCertInfo)
  881. {
  882. CERT_EXTENSION const *pExt;
  883. CERT_EXTENSION const *pExtEnd;
  884. pExtEnd = &pCertInfo->rgExtension[pCertInfo->cExtension];
  885. for (pExt = pCertInfo->rgExtension; pExt < pExtEnd; pExt++)
  886. {
  887. if (0 == strcmp(szOID_SUBJECT_KEY_IDENTIFIER, pExt->pszObjId))
  888. {
  889. if (!myDecodeObject(
  890. X509_ASN_ENCODING,
  891. X509_OCTET_STRING,
  892. pExt->Value.pbData,
  893. pExt->Value.cbData,
  894. CERTLIB_USE_LOCALALLOC,
  895. (VOID **) &pBlob,
  896. &cb))
  897. {
  898. hr = myHLastError();
  899. _JumpError(hr, error, "myDecodeObject");
  900. }
  901. pb = pBlob->pbData;
  902. cb = pBlob->cbData;
  903. break;
  904. }
  905. }
  906. }
  907. if (NULL == pb)
  908. {
  909. cb = sizeof(abHash);
  910. if (!CryptHashPublicKeyInfo(
  911. NULL, // hCryptProv
  912. CALG_SHA1,
  913. 0, // dwFlags,
  914. X509_ASN_ENCODING,
  915. const_cast<CERT_PUBLIC_KEY_INFO *>(pPublicKeyInfo),
  916. abHash,
  917. &cb))
  918. {
  919. hr = myHLastError();
  920. _JumpError(hr, error, "CryptHashPublicKeyInfo");
  921. }
  922. pb = abHash;
  923. }
  924. *ppbData = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
  925. if (NULL == *ppbData)
  926. {
  927. hr = E_OUTOFMEMORY;
  928. _JumpError(hr, error, "LocalAlloc");
  929. }
  930. *pcbData = cb;
  931. CopyMemory(*ppbData, pb, cb);
  932. hr = S_OK;
  933. error:
  934. if (NULL != pBlob)
  935. {
  936. LocalFree(pBlob);
  937. }
  938. return(hr);
  939. }
  940. HRESULT
  941. myCreateSubjectKeyIdentifierExtension(
  942. IN CERT_PUBLIC_KEY_INFO const *pPubKey,
  943. OUT BYTE **ppbEncoded,
  944. OUT DWORD *pcbEncoded)
  945. {
  946. HRESULT hr;
  947. CRYPT_DATA_BLOB KeyIdentifier;
  948. KeyIdentifier.pbData = NULL;
  949. hr = myGetPublicKeyHash(
  950. NULL, // pCertInfo
  951. pPubKey,
  952. &KeyIdentifier.pbData,
  953. &KeyIdentifier.cbData);
  954. _JumpIfError(hr, error, "myGetPublicKeyHash");
  955. // Issuer's KeyId:
  956. if (!myEncodeObject(
  957. X509_ASN_ENCODING,
  958. X509_OCTET_STRING,
  959. &KeyIdentifier,
  960. 0,
  961. CERTLIB_USE_LOCALALLOC,
  962. ppbEncoded,
  963. pcbEncoded))
  964. {
  965. hr = myHLastError();
  966. _JumpError(hr, error, "myEncodeObject");
  967. }
  968. hr = S_OK;
  969. error:
  970. if (NULL != KeyIdentifier.pbData)
  971. {
  972. LocalFree(KeyIdentifier.pbData);
  973. }
  974. return(hr);
  975. }
  976. HRESULT
  977. myCalculateKeyArchivalHash(
  978. IN const BYTE *pbEncryptedKey,
  979. IN DWORD cbEncryptedKey,
  980. OUT BYTE **ppbHash,
  981. OUT DWORD *pcbHash)
  982. {
  983. HRESULT hr;
  984. HCRYPTPROV hProv = NULL;
  985. HCRYPTHASH hHash = NULL;
  986. BYTE* pbHash = NULL;
  987. DWORD cbHash = 0;
  988. DWORD dwSize;
  989. if (NULL == pbEncryptedKey ||
  990. NULL == ppbHash ||
  991. NULL == pcbHash)
  992. {
  993. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  994. _JumpError(hr, error, "Invalid parameters");
  995. }
  996. //init
  997. *ppbHash = NULL;
  998. *pcbHash = 0;
  999. if (!CryptAcquireContext(
  1000. &hProv,
  1001. NULL, // pszContainer
  1002. NULL, // pszProvider
  1003. PROV_RSA_FULL,
  1004. CRYPT_VERIFYCONTEXT))
  1005. {
  1006. hr = myHLastError();
  1007. _JumpError(hr, error, "CryptAcquireContext");
  1008. }
  1009. //create a hash object
  1010. if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
  1011. {
  1012. hr = myHLastError();
  1013. _JumpError(hr, error, "CryptCreateHash");
  1014. }
  1015. //hash the data
  1016. if (!CryptHashData(
  1017. hHash,
  1018. pbEncryptedKey,
  1019. cbEncryptedKey,
  1020. 0))
  1021. {
  1022. hr = myHLastError();
  1023. _JumpError(hr, error, "CryptHashData");
  1024. }
  1025. //get the hash size
  1026. dwSize = sizeof(cbHash);
  1027. if (!CryptGetHashParam(
  1028. hHash,
  1029. HP_HASHSIZE,
  1030. (BYTE*)&cbHash,
  1031. &dwSize,
  1032. 0))
  1033. {
  1034. hr = myHLastError();
  1035. _JumpError(hr, error, "CryptGetHashParam");
  1036. }
  1037. //allocate for hash buffer
  1038. pbHash = (BYTE*)LocalAlloc(LMEM_FIXED, cbHash);
  1039. if (NULL == pbHash)
  1040. {
  1041. hr = E_OUTOFMEMORY;
  1042. _JumpError(hr, error, "LocalAlloc");
  1043. }
  1044. dwSize = cbHash;
  1045. //get the hash
  1046. if (!CryptGetHashParam(
  1047. hHash,
  1048. HP_HASHVAL,
  1049. (BYTE*)pbHash,
  1050. &dwSize,
  1051. 0))
  1052. {
  1053. hr = myHLastError();
  1054. _JumpError(hr, error, "CryptGetHashParam");
  1055. }
  1056. //should be the same
  1057. CSASSERT(dwSize == cbHash);
  1058. //return
  1059. *ppbHash = pbHash;
  1060. *pcbHash = cbHash;
  1061. pbHash = NULL;
  1062. hr = S_OK;
  1063. error:
  1064. if (NULL != hHash)
  1065. {
  1066. CryptDestroyHash(hHash);
  1067. }
  1068. if (NULL != hProv)
  1069. {
  1070. CryptReleaseContext(hProv, 0);
  1071. }
  1072. if (NULL != pbHash)
  1073. {
  1074. LocalFree(pbHash);
  1075. }
  1076. return hr;
  1077. }
  1078. //--------------------------------------------------------------------
  1079. // Escapes any characters unsuitable for a URL. Returns a new string.
  1080. HRESULT
  1081. myInternetCanonicalizeUrl(
  1082. IN WCHAR const *pwszIn,
  1083. OUT WCHAR **ppwszOut)
  1084. {
  1085. HRESULT hr;
  1086. WCHAR *pwsz = NULL;
  1087. CSASSERT(NULL != pwszIn);
  1088. if (0 == _wcsnicmp(L"file:", pwszIn, 5))
  1089. {
  1090. hr = myDupString(pwszIn, &pwsz);
  1091. _JumpIfError(hr, error, "myDupString");
  1092. }
  1093. else
  1094. {
  1095. // Calculate required buffer size by passing a very small buffer
  1096. // The call will fail, and tell us how big the buffer should be.
  1097. WCHAR wszPlaceHolder[1];
  1098. DWORD cwc = ARRAYSIZE(wszPlaceHolder);
  1099. BOOL bResult;
  1100. bResult = InternetCanonicalizeUrlW(
  1101. pwszIn, // lpszUrl
  1102. wszPlaceHolder, // lpszBuffer
  1103. &cwc, // lpdwBufferLength
  1104. 0); // dwFlags
  1105. CSASSERT(!bResult); // This will always fail
  1106. hr = myHLastError();
  1107. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  1108. {
  1109. // unexpected error
  1110. _JumpError(hr, error, "InternetCanonicalizeUrl");
  1111. }
  1112. // NOTE: InternetCanonicalizeUrl counts characters, not bytes as doc'd
  1113. // cwc includes trailing L'0'
  1114. pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  1115. if (NULL == pwsz)
  1116. {
  1117. hr = E_OUTOFMEMORY;
  1118. _JumpError(hr, error, "LocalAlloc");
  1119. }
  1120. // canonicalize
  1121. if (!InternetCanonicalizeUrlW(
  1122. pwszIn, // lpszUrl
  1123. pwsz, // lpszBuffer
  1124. &cwc, // lpdwBufferLength
  1125. 0)) // dwFlags
  1126. {
  1127. hr = myHLastError();
  1128. _JumpError(hr, error, "InternetCanonicalizeUrl");
  1129. }
  1130. }
  1131. *ppwszOut = pwsz;
  1132. pwsz = NULL;
  1133. hr = S_OK;
  1134. error:
  1135. if (NULL != pwsz)
  1136. {
  1137. LocalFree(pwsz);
  1138. }
  1139. return(hr);
  1140. }
  1141. // Inverse of InternetCanonicalizeUrl -- Convert "%20" sequences to " ", etc.
  1142. HRESULT
  1143. myInternetUncanonicalizeURL(
  1144. IN WCHAR const *pwszURLIn,
  1145. OUT WCHAR **ppwszURLOut)
  1146. {
  1147. HRESULT hr;
  1148. URL_COMPONENTSW urlcomp;
  1149. WCHAR wszScheme[10]; // L"ldap"
  1150. WCHAR wszHost[MAX_PATH];
  1151. WCHAR wszURL[MAX_PATH];
  1152. WCHAR wszExtra[MAX_PATH];
  1153. WCHAR *pwszURL = NULL;
  1154. DWORD cURL;
  1155. DWORD cwcURLAlloc;
  1156. *ppwszURLOut = NULL;
  1157. ZeroMemory(&urlcomp, sizeof(urlcomp));
  1158. urlcomp.dwStructSize = sizeof(urlcomp);
  1159. urlcomp.lpszScheme = wszScheme;
  1160. urlcomp.dwSchemeLength = ARRAYSIZE(wszScheme);
  1161. urlcomp.lpszHostName = wszHost;
  1162. urlcomp.dwHostNameLength = ARRAYSIZE(wszHost);
  1163. urlcomp.lpszUrlPath = wszURL;
  1164. urlcomp.dwUrlPathLength = ARRAYSIZE(wszURL);
  1165. urlcomp.lpszExtraInfo = wszExtra;
  1166. urlcomp.dwExtraInfoLength = ARRAYSIZE(wszExtra);
  1167. // Decode escape sequemces
  1168. if (!InternetCrackUrlW(pwszURLIn, 0, ICU_ESCAPE, &urlcomp))
  1169. {
  1170. hr = myHLastError();
  1171. _JumpError(hr, error, "InternetCrackUrl");
  1172. }
  1173. cURL = 0;
  1174. for (;;)
  1175. {
  1176. // InternetCreateUrl is spec'd strangely:
  1177. //
  1178. // When called with a NULL input pointer or an insufficient buffer
  1179. // size, the returned count is the number of bytes required, including
  1180. // the trailing L'\0'.
  1181. //
  1182. // When called with a non-NULL input pointer of adequate size, the
  1183. // returned count is the count of chars, excluding the trailing L'\0'.
  1184. //
  1185. // This is just so wierd!
  1186. if (!InternetCreateUrlW(&urlcomp, 0, pwszURL, &cURL))
  1187. {
  1188. hr = myHLastError();
  1189. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr ||
  1190. NULL != pwszURL)
  1191. {
  1192. _JumpError(hr, error, "InternetCreatUrl");
  1193. }
  1194. }
  1195. if (NULL != pwszURL)
  1196. {
  1197. CSASSERT(wcslen(pwszURL) == cURL);
  1198. CSASSERT(cwcURLAlloc == cURL + 1);
  1199. break;
  1200. }
  1201. pwszURL = (WCHAR *) LocalAlloc(LMEM_FIXED, cURL);
  1202. if (NULL == pwszURL)
  1203. {
  1204. hr = E_OUTOFMEMORY;
  1205. _JumpError(hr, error, "LocalAlloc");
  1206. }
  1207. cURL /= sizeof(WCHAR);
  1208. cwcURLAlloc = cURL;
  1209. }
  1210. *ppwszURLOut = pwszURL;
  1211. pwszURL = NULL;
  1212. hr = S_OK;
  1213. error:
  1214. if (NULL != pwszURL)
  1215. {
  1216. LocalFree(pwszURL);
  1217. }
  1218. return(hr);
  1219. }
  1220. BOOL
  1221. ConvertWszToMultiByte(
  1222. OUT CHAR **ppsz,
  1223. IN UINT CodePage,
  1224. IN WCHAR const *pwc,
  1225. IN LONG cwc)
  1226. {
  1227. HRESULT hr;
  1228. LONG cch = 0;
  1229. *ppsz = NULL;
  1230. for (;;)
  1231. {
  1232. cch = WideCharToMultiByte(
  1233. CodePage,
  1234. 0, // dwFlags
  1235. pwc,
  1236. cwc, // cchWideChar, -1 => null terminated
  1237. *ppsz,
  1238. cch,
  1239. NULL,
  1240. NULL);
  1241. if (0 >= cch &&
  1242. (0 != cch || (0 != cwc && (MAXLONG != cwc || L'\0' != *pwc))))
  1243. {
  1244. hr = myHLastError();
  1245. _PrintError(hr, "WideCharToMultiByte");
  1246. if (NULL != *ppsz)
  1247. {
  1248. LocalFree(*ppsz);
  1249. *ppsz = NULL;
  1250. }
  1251. break;
  1252. }
  1253. if (NULL != *ppsz)
  1254. {
  1255. (*ppsz)[cch] = '\0';
  1256. hr = S_OK;
  1257. break;
  1258. }
  1259. *ppsz = (CHAR *) LocalAlloc(LMEM_FIXED, cch + 1);
  1260. if (NULL == *ppsz)
  1261. {
  1262. hr = E_OUTOFMEMORY;
  1263. break;
  1264. }
  1265. }
  1266. if (S_OK != hr)
  1267. {
  1268. SetLastError(hr);
  1269. }
  1270. return(S_OK == hr);
  1271. }
  1272. BOOL
  1273. myConvertWszToUTF8(
  1274. OUT CHAR **ppsz,
  1275. IN WCHAR const *pwc,
  1276. IN LONG cwc)
  1277. {
  1278. return(ConvertWszToMultiByte(ppsz, CP_UTF8, pwc, cwc));
  1279. }
  1280. BOOL
  1281. myConvertWszToSz(
  1282. OUT CHAR **ppsz,
  1283. IN WCHAR const *pwc,
  1284. IN LONG cwc)
  1285. {
  1286. return(ConvertWszToMultiByte(ppsz, GetACP(), pwc, cwc));
  1287. }
  1288. BOOL
  1289. myConvertMultiByteToWsz(
  1290. OUT WCHAR **ppwsz,
  1291. IN UINT CodePage,
  1292. IN CHAR const *pch,
  1293. IN LONG cch)
  1294. {
  1295. HRESULT hr;
  1296. LONG cwc = 0;
  1297. *ppwsz = NULL;
  1298. for (;;)
  1299. {
  1300. cwc = MultiByteToWideChar(CodePage, 0, pch, cch, *ppwsz, cwc);
  1301. if (0 >= cwc)
  1302. {
  1303. hr = myHLastError();
  1304. _PrintError(hr, "MultiByteToWideChar");
  1305. if (NULL != *ppwsz)
  1306. {
  1307. LocalFree(*ppwsz);
  1308. *ppwsz = NULL;
  1309. }
  1310. break;
  1311. }
  1312. if (NULL != *ppwsz)
  1313. {
  1314. (*ppwsz)[cwc] = L'\0';
  1315. hr = S_OK;
  1316. break;
  1317. }
  1318. *ppwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
  1319. if (NULL == *ppwsz)
  1320. {
  1321. hr = E_OUTOFMEMORY;
  1322. break;
  1323. }
  1324. }
  1325. if (S_OK != hr)
  1326. {
  1327. SetLastError(hr);
  1328. }
  1329. return(S_OK == hr);
  1330. }
  1331. BOOL
  1332. myConvertUTF8ToWsz(
  1333. OUT WCHAR **ppwsz,
  1334. IN CHAR const *pch,
  1335. IN LONG cch)
  1336. {
  1337. return(myConvertMultiByteToWsz(ppwsz, CP_UTF8, pch, cch));
  1338. }
  1339. BOOL
  1340. myConvertSzToWsz(
  1341. OUT WCHAR **ppwsz,
  1342. IN CHAR const *pch,
  1343. IN LONG cch)
  1344. {
  1345. return(myConvertMultiByteToWsz(ppwsz, GetACP(), pch, cch));
  1346. }