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.

838 lines
20 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: pkifmt.cpp
  7. //
  8. // Contents: data format conversion
  9. //
  10. // History: 25-Jul-96 vich created
  11. // 2/2000 xtan moved from certsrv to pki
  12. //
  13. //---------------------------------------------------------------------------
  14. #include <windows.h>
  15. #include <assert.h>
  16. #include <stdio.h>
  17. #include <wincrypt.h>
  18. #include <dbgdef.h>
  19. #include "pkifmt.h"
  20. #if DBG
  21. # ifdef UNICODE
  22. # define _DecodeCertSub _DecodeCertSubW
  23. # else
  24. # define _DecodeCertSub _DecodeCertSubA
  25. # endif
  26. #endif //DBG
  27. DWORD
  28. _DecodeCertSub(
  29. IN TCHAR const *pchIn,
  30. IN DWORD cchIn,
  31. IN DWORD Flags,
  32. IN OUT BYTE *pbOut,
  33. IN OUT DWORD *pcbOut,
  34. OUT OPTIONAL DWORD *pdwSkip)
  35. {
  36. DWORD dwErr = ERROR_SUCCESS;
  37. DWORD cbOut = 0;
  38. if (NULL != pbOut)
  39. {
  40. cbOut = *pcbOut;
  41. }
  42. switch (Flags)
  43. {
  44. case CRYPT_STRING_BASE64HEADER:
  45. case CRYPT_STRING_BASE64REQUESTHEADER:
  46. case CRYPT_STRING_BASE64X509CRLHEADER:
  47. {
  48. TCHAR const *pchInEnd;
  49. DWORD cchHeader;
  50. DWORD cchSkip;
  51. pchInEnd = &pchIn[cchIn];
  52. // Skip to the starting '-----....' then skip that line.
  53. dwErr = ERROR_INVALID_DATA;
  54. cchHeader = SizeBase64Header(pchIn, cchIn, TRUE, &cchSkip);
  55. if (MAXDWORD == cchHeader)
  56. {
  57. goto SizeBase64HeaderStartError;
  58. }
  59. if (NULL != pdwSkip)
  60. {
  61. *pdwSkip = cchHeader; //for return
  62. }
  63. pchIn += cchHeader + cchSkip;
  64. cchHeader = SizeBase64Header(
  65. pchIn,
  66. SAFE_SUBTRACT_POINTERS(pchInEnd, pchIn),
  67. FALSE,
  68. &cchSkip);
  69. if (MAXDWORD == cchHeader)
  70. {
  71. goto SizeBase64HeaderEndError;
  72. }
  73. cchIn = cchHeader;
  74. Flags = CRYPT_STRING_BASE64; // headers have been removed...
  75. // FALLTHROUGH
  76. }
  77. case CRYPT_STRING_BASE64:
  78. dwErr = Base64Decode(pchIn, cchIn, pbOut, &cbOut);
  79. if (ERROR_SUCCESS != dwErr)
  80. {
  81. #if DBG
  82. if (ERROR_INVALID_DATA != dwErr)
  83. {
  84. DbgPrintf(DBG_SS_TRACE,
  85. "Base64Decode err = 0x%x\n", dwErr);
  86. }
  87. #endif //DBG
  88. goto Base64DecodeError;
  89. }
  90. break;
  91. case CRYPT_STRING_HEX:
  92. case CRYPT_STRING_HEXASCII:
  93. case CRYPT_STRING_HEXADDR:
  94. case CRYPT_STRING_HEXASCIIADDR:
  95. dwErr = HexDecode(pchIn, cchIn, Flags, pbOut, &cbOut);
  96. if (ERROR_SUCCESS != dwErr)
  97. {
  98. #if DBG
  99. if (ERROR_INVALID_DATA != dwErr)
  100. {
  101. DbgPrintf(DBG_SS_TRACE,
  102. "HexDecode err = 0x%x\n", dwErr);
  103. }
  104. #endif //DBG
  105. goto HexDecodeError;
  106. }
  107. break;
  108. case CRYPT_STRING_BINARY:
  109. if (NULL != pbOut)
  110. {
  111. //assert(sizeof(TCHAR) * cchIn == cbOut);
  112. if (*pcbOut < cbOut)
  113. {
  114. *pcbOut = cbOut;
  115. dwErr = ERROR_MORE_DATA;
  116. goto MoreDataError;
  117. }
  118. CopyMemory(pbOut, (BYTE *) pchIn, cbOut);
  119. }
  120. else
  121. {
  122. cbOut = sizeof(TCHAR) * cchIn;
  123. }
  124. break;
  125. default:
  126. dwErr = ERROR_INVALID_DATA; //hr = E_INVALIDARG
  127. break;
  128. }
  129. *pcbOut = cbOut;
  130. ErrorReturn:
  131. return (dwErr);
  132. SET_ERROR(MoreDataError, dwErr)
  133. SET_ERROR(SizeBase64HeaderEndError, dwErr)
  134. SET_ERROR(SizeBase64HeaderStartError, dwErr)
  135. TRACE_ERROR(HexDecodeError)
  136. TRACE_ERROR(Base64DecodeError)
  137. }
  138. BOOL
  139. WINAPI
  140. CryptStringToBinaryA(
  141. IN LPCSTR pszString,
  142. IN DWORD cchString,
  143. IN DWORD dwFlags,
  144. IN OUT BYTE *pbBinary,
  145. IN OUT DWORD *pcbBinary,
  146. IN OUT DWORD *pdwSkip, //OPTIONAL
  147. IN OUT DWORD *pdwFlags) //OPTIONAL
  148. {
  149. DWORD dwErr;
  150. DWORD cbOut;
  151. DWORD const *pFlags;
  152. DWORD const *pFlagsEnd;
  153. static DWORD s_aDecodeFlags[] = {
  154. CRYPT_STRING_BASE64HEADER,
  155. CRYPT_STRING_BASE64,
  156. CRYPT_STRING_BINARY // must be last
  157. };
  158. static DWORD s_aHexDecodeFlags[] = {
  159. CRYPT_STRING_HEXADDR,
  160. CRYPT_STRING_HEXASCIIADDR,
  161. CRYPT_STRING_HEX,
  162. CRYPT_STRING_HEXASCII,
  163. };
  164. if (NULL == pszString)
  165. {
  166. dwErr = ERROR_INVALID_PARAMETER;
  167. goto InvalidDataError;
  168. }
  169. if (0 == cchString)
  170. {
  171. // assume null terminated string
  172. cchString = strlen(pszString) + 1; //include null terminator
  173. }
  174. //init
  175. if (NULL != pdwSkip)
  176. {
  177. *pdwSkip = 0;
  178. }
  179. if (NULL != pdwFlags)
  180. {
  181. *pdwFlags = 0;
  182. }
  183. if (NULL == pbBinary)
  184. {
  185. *pcbBinary = 0;
  186. }
  187. pFlags = &dwFlags;
  188. pFlagsEnd = &pFlags[1];
  189. if (CRYPT_STRING_BASE64_ANY == dwFlags || CRYPT_STRING_ANY == dwFlags)
  190. {
  191. pFlags = s_aDecodeFlags;
  192. pFlagsEnd = &pFlags[sizeof(s_aDecodeFlags)/sizeof(s_aDecodeFlags[0])];
  193. if (CRYPT_STRING_BASE64_ANY == dwFlags)
  194. {
  195. pFlagsEnd--; // Disallow CRYPT_STRING_BINARY
  196. }
  197. }
  198. if (CRYPT_STRING_HEX_ANY == dwFlags)
  199. {
  200. pFlags = s_aHexDecodeFlags;
  201. pFlagsEnd = &pFlags[sizeof(s_aHexDecodeFlags)/sizeof(s_aHexDecodeFlags[0])];
  202. }
  203. dwErr = ERROR_SUCCESS;
  204. for ( ; pFlags < pFlagsEnd; pFlags++)
  205. {
  206. cbOut = *pcbBinary;
  207. dwErr = _DecodeCertSub(
  208. pszString,
  209. cchString,
  210. *pFlags,
  211. pbBinary,
  212. &cbOut,
  213. pdwSkip);
  214. if (ERROR_SUCCESS == dwErr)
  215. {
  216. //for return
  217. *pcbBinary = cbOut;
  218. if (NULL != pdwFlags)
  219. {
  220. *pdwFlags = *pFlags;
  221. }
  222. break;
  223. }
  224. #if DBG
  225. if (ERROR_INVALID_DATA != dwErr)
  226. {
  227. DbgPrintf(DBG_SS_TRACE, "_DecodeCertSub err = 0x%x\n", dwErr);
  228. }
  229. #endif //DBG
  230. }
  231. if (ERROR_SUCCESS != dwErr)
  232. {
  233. goto DecodeCertSubError;
  234. }
  235. ErrorReturn:
  236. return (ERROR_SUCCESS == dwErr);
  237. SET_ERROR(DecodeCertSubError, dwErr)
  238. SET_ERROR(InvalidDataError, dwErr)
  239. }
  240. DWORD
  241. BinaryEncode(
  242. IN BYTE const *pbIn,
  243. IN DWORD cbIn,
  244. OPTIONAL OUT TCHAR *pchOut,
  245. IN OUT DWORD *pcchOut)
  246. {
  247. DWORD dwErr;
  248. if (NULL != pchOut)
  249. {
  250. if (*pcchOut < cbIn)
  251. {
  252. dwErr = ERROR_MORE_DATA;
  253. goto MoreDataError;
  254. }
  255. CopyMemory(pchOut, pbIn, cbIn);
  256. }
  257. dwErr = ERROR_SUCCESS;
  258. ErrorReturn:
  259. //get size any way
  260. *pcchOut = cbIn;
  261. return dwErr;
  262. SET_ERROR(MoreDataError, dwErr)
  263. }
  264. static TCHAR const szBeginCert[] = TEXT("-----BEGIN CERTIFICATE-----");
  265. static TCHAR const szEndCert[] = TEXT("-----END CERTIFICATE-----");
  266. #define CB_BEGINCERT (sizeof(szBeginCert) - sizeof(TCHAR))
  267. #define CB_ENDCERT (sizeof(szEndCert) - sizeof(TCHAR))
  268. static TCHAR const szBeginCertRequest[] = TEXT("-----BEGIN NEW CERTIFICATE REQUEST-----");
  269. static TCHAR const szEndCertRequest[] = TEXT("-----END NEW CERTIFICATE REQUEST-----");
  270. #define CB_BEGINCERTREQUEST (sizeof(szBeginCertRequest) - sizeof(TCHAR))
  271. #define CB_ENDCERTREQUEST (sizeof(szEndCertRequest) - sizeof(TCHAR))
  272. static TCHAR const szBeginCRL[] = TEXT("-----BEGIN X509 CRL-----");
  273. static TCHAR const szEndCRL[] = TEXT("-----END X509 CRL-----");
  274. #define CB_BEGINCRL (sizeof(szBeginCRL) - sizeof(TCHAR))
  275. #define CB_ENDCRL (sizeof(szEndCRL) - sizeof(TCHAR))
  276. typedef struct _CERTHEADER
  277. {
  278. TCHAR const *pszBegin;
  279. DWORD cbBegin;
  280. TCHAR const *pszEnd;
  281. DWORD cbEnd;
  282. } CERTHEADER;
  283. static CERTHEADER const CertHeaderCert =
  284. {
  285. szBeginCert,
  286. CB_BEGINCERT,
  287. szEndCert,
  288. CB_ENDCERT
  289. };
  290. static CERTHEADER const CertHeaderCertRequest =
  291. {
  292. szBeginCertRequest,
  293. CB_BEGINCERTREQUEST,
  294. szEndCertRequest,
  295. CB_ENDCERTREQUEST
  296. };
  297. static CERTHEADER const CertHeaderCRL =
  298. {
  299. szBeginCRL,
  300. CB_BEGINCRL,
  301. szEndCRL,
  302. CB_ENDCRL
  303. };
  304. BOOL
  305. WINAPI
  306. CryptBinaryToStringA(
  307. IN CONST BYTE *pbBinary,
  308. IN DWORD cbBinary,
  309. IN DWORD dwFlags,
  310. OUT LPSTR pszString,
  311. OUT DWORD *pcchString)
  312. {
  313. DWORD dwErr;
  314. TCHAR *pchEncode;
  315. DWORD cchMax;
  316. DWORD cchOut;
  317. DWORD cbTotal;
  318. CERTHEADER const *pCertHeader = NULL;
  319. BOOL fNoCR = 0 != (CRYPT_STRING_NOCR & dwFlags);
  320. DWORD cchnl = fNoCR? 1 : 2;
  321. BOOL fBinaryCopy = FALSE;
  322. if (NULL == pbBinary || 0 == cbBinary || NULL == pcchString)
  323. {
  324. dwErr = ERROR_INVALID_PARAMETER;
  325. goto InvalidDataError;
  326. }
  327. if (NULL == pszString)
  328. {
  329. *pcchString = 0;
  330. }
  331. switch (~CRYPT_STRING_NOCR & dwFlags)
  332. {
  333. case CRYPT_STRING_BASE64HEADER:
  334. pCertHeader = &CertHeaderCert;
  335. break;
  336. case CRYPT_STRING_BASE64REQUESTHEADER:
  337. pCertHeader = &CertHeaderCertRequest;
  338. break;
  339. case CRYPT_STRING_BASE64X509CRLHEADER:
  340. pCertHeader = &CertHeaderCRL;
  341. break;
  342. }
  343. pchEncode = pszString;
  344. cchMax = *pcchString;
  345. cchOut = cchMax;
  346. if (NULL != pszString && NULL != pCertHeader)
  347. {
  348. // Make sure there's room for the BEGIN header and CR-LF sequence
  349. if (pCertHeader->cbBegin + cchnl > cchMax)
  350. {
  351. dwErr = ERROR_MORE_DATA;
  352. goto MoreDataError;
  353. }
  354. cchOut -= pCertHeader->cbBegin + cchnl;
  355. CopyMemory(pchEncode, pCertHeader->pszBegin, pCertHeader->cbBegin);
  356. pchEncode += pCertHeader->cbBegin/sizeof(TCHAR);
  357. if (!fNoCR)
  358. {
  359. *pchEncode++ = '\r';
  360. }
  361. *pchEncode++ = '\n';
  362. }
  363. // first determine size
  364. switch (~CRYPT_STRING_NOCR & dwFlags)
  365. {
  366. case CRYPT_STRING_BINARY:
  367. dwErr = BinaryEncode(pbBinary, cbBinary, pchEncode, &cchOut);
  368. if (ERROR_SUCCESS != dwErr)
  369. {
  370. goto BinaryEncodeError;
  371. }
  372. fBinaryCopy = TRUE;
  373. break;
  374. case CRYPT_STRING_HEX:
  375. case CRYPT_STRING_HEXASCII:
  376. case CRYPT_STRING_HEXADDR:
  377. case CRYPT_STRING_HEXASCIIADDR:
  378. dwErr = HexEncode(pbBinary, cbBinary, dwFlags, pchEncode, &cchOut);
  379. if (ERROR_SUCCESS != dwErr)
  380. {
  381. goto HexEncodeError;
  382. }
  383. break;
  384. default:
  385. dwErr = Base64Encode(pbBinary, cbBinary, dwFlags, pchEncode, &cchOut);
  386. if (ERROR_SUCCESS != dwErr)
  387. {
  388. goto Base64EncodeError;
  389. }
  390. break;
  391. }
  392. // Compute total size, including the trailing '\0' character.
  393. if (fBinaryCopy)
  394. {
  395. cbTotal = cchOut;
  396. }
  397. else
  398. {
  399. cbTotal = (cchOut + 1) * sizeof(CHAR);
  400. }
  401. // Add space for the BEGIN & END headers, if requested.
  402. if (NULL != pCertHeader)
  403. {
  404. cbTotal += pCertHeader->cbBegin + pCertHeader->cbEnd;
  405. if (!fNoCR)
  406. {
  407. cbTotal += 2 * sizeof(TCHAR); // for BEGIN & END '\r' chars
  408. }
  409. cbTotal += 2 * sizeof(TCHAR); // for BEGIN & END '\n' chars
  410. }
  411. if (fBinaryCopy)
  412. {
  413. *pcchString = cbTotal;
  414. }
  415. else
  416. {
  417. // if pszString is NULL, set size to include trailing '\0'
  418. *pcchString = cbTotal / sizeof(CHAR);
  419. }
  420. if (NULL == pszString)
  421. {
  422. // only determine size, done
  423. goto done;
  424. }
  425. if (NULL != pCertHeader)
  426. {
  427. cchOut += pCertHeader->cbBegin/sizeof(CHAR) + cchnl;
  428. // Make sure there's room for the END header, CR-LF sequence, and '\0'
  429. if (cchOut + pCertHeader->cbEnd + cchnl + 1 > cchMax)
  430. {
  431. dwErr = ERROR_MORE_DATA;
  432. goto MoreDataError;
  433. }
  434. CopyMemory(&pszString[cchOut], pCertHeader->pszEnd, pCertHeader->cbEnd);
  435. cchOut += pCertHeader->cbEnd/sizeof(CHAR);
  436. if (!fNoCR)
  437. {
  438. pszString[cchOut++] = '\r';
  439. }
  440. pszString[cchOut++] = '\n';
  441. }
  442. if (!fBinaryCopy)
  443. {
  444. pszString[cchOut] = '\0';
  445. assert((cchOut + 1) * sizeof(CHAR) == cbTotal);
  446. // pszString is not NULL, don't include trailing '\0' in length
  447. *pcchString = cchOut;
  448. }
  449. done:
  450. dwErr = ERROR_SUCCESS;
  451. ErrorReturn:
  452. return(ERROR_SUCCESS == dwErr);
  453. TRACE_ERROR(Base64EncodeError)
  454. TRACE_ERROR(HexEncodeError)
  455. TRACE_ERROR(BinaryEncodeError)
  456. SET_ERROR(InvalidDataError, dwErr)
  457. SET_ERROR(MoreDataError, dwErr)
  458. }
  459. static TCHAR const szBeginMatch[] = TEXT("-----BEGIN ");
  460. static TCHAR const szEndMatch[] = TEXT("-----END ");
  461. static TCHAR const szMinus[] = TEXT("-----");
  462. #define CCH_BEGINMATCH sizeof(szBeginMatch)/sizeof(szBeginMatch[0]) - 1
  463. #define CCH_ENDMATCH sizeof(szEndMatch)/sizeof(szEndMatch[0]) - 1
  464. #define CCH_MINUS sizeof(szMinus)/sizeof(szMinus[0]) - 1
  465. // Returns the count of characters up to the -----BEGIN/-----END delimiter,
  466. // MAXDWORD on error.
  467. //
  468. // On successful return, *pcchSkip is the count of characters in the delimiter
  469. // string.
  470. DWORD
  471. SizeBase64Header(
  472. IN TCHAR const *pchIn,
  473. IN DWORD cchIn,
  474. IN BOOL fBegin,
  475. OUT DWORD *pcchSkip)
  476. {
  477. DWORD cchHeader = MAXDWORD;
  478. TCHAR const *pchT;
  479. TCHAR const *pchT2;
  480. TCHAR const *pchEnd;
  481. TCHAR const *pchMatch;
  482. DWORD cchMatch;
  483. // Skip to the starting '-----....' & return count of skipped characters.
  484. *pcchSkip = 0;
  485. if (fBegin)
  486. {
  487. pchMatch = szBeginMatch;
  488. cchMatch = CCH_BEGINMATCH;
  489. }
  490. else
  491. {
  492. pchMatch = szEndMatch;
  493. cchMatch = CCH_ENDMATCH;
  494. }
  495. pchT = pchIn;
  496. pchEnd = &pchIn[cchIn];
  497. for (;;)
  498. {
  499. // Skip until we match the first character.
  500. while (pchT < pchEnd && *pchT != *pchMatch)
  501. {
  502. pchT++;
  503. }
  504. if (&pchT[cchMatch] > pchEnd)
  505. {
  506. // no room for the "-----BEGIN "/"-----END " string
  507. break;
  508. }
  509. if (0 == strncmp(pchT, pchMatch, cchMatch))
  510. {
  511. pchT2 = &pchT[cchMatch];
  512. while (pchT2 < pchEnd && *pchT2 != szMinus[0])
  513. {
  514. pchT2++;
  515. }
  516. if (&pchT2[CCH_MINUS] > pchEnd)
  517. {
  518. // no room for the trailing "-----" string
  519. break;
  520. }
  521. if (0 == strncmp(pchT2, szMinus, CCH_MINUS))
  522. {
  523. // Allow up to 2 extra leading minus signs
  524. DWORD cchMinus = 0;
  525. while (2 > cchMinus && pchT > pchIn)
  526. {
  527. if (TEXT('-') != *--pchT)
  528. {
  529. pchT++; // oops, went too far
  530. break;
  531. }
  532. cchMinus++;
  533. }
  534. #if DBG
  535. if (0 != cchMinus)
  536. {
  537. DbgPrintf(DBG_SS_TRACE,
  538. "Ignored leading data: \"%.*" szFMTTSTR "\"\n",
  539. cchMinus,
  540. TEXT("--"));
  541. }
  542. #endif //DBG
  543. cchHeader = SAFE_SUBTRACT_POINTERS(pchT, pchIn);
  544. *pcchSkip = SAFE_SUBTRACT_POINTERS(pchT2, pchT) + CCH_MINUS;
  545. #if DBG
  546. #if 0
  547. DbgPrintf(
  548. DBG_SS_TRACE,
  549. "Skipping(%u, %x, %x):\n[%.*" szFMTTSTR "]\n",
  550. fBegin,
  551. cchHeader,
  552. *pcchSkip,
  553. cchHeader,
  554. pchIn);
  555. #endif
  556. #endif // DBG
  557. break;
  558. }
  559. }
  560. pchT++;
  561. }
  562. return(cchHeader);
  563. }
  564. BOOL
  565. WINAPI
  566. CryptBinaryToStringW(
  567. IN CONST BYTE *pbBinary,
  568. IN DWORD cbBinary,
  569. IN DWORD dwFlags,
  570. OUT LPWSTR pwszString,
  571. OUT DWORD *pcchString)
  572. {
  573. BOOL fRet = FALSE;
  574. BOOL fConversion = FALSE;
  575. DWORD dwErr;
  576. int len;
  577. CHAR *pszString = NULL;
  578. if (NULL == pwszString)
  579. {
  580. //only return size
  581. fRet = CryptBinaryToStringA(
  582. pbBinary,
  583. cbBinary,
  584. dwFlags,
  585. NULL, //for size
  586. pcchString);
  587. }
  588. else
  589. {
  590. if (0 == *pcchString)
  591. {
  592. //must bigger than 0
  593. dwErr = ERROR_INVALID_PARAMETER;
  594. goto InvalidDataError;
  595. }
  596. if (CRYPT_STRING_BINARY == (~CRYPT_STRING_NOCR & dwFlags))
  597. {
  598. //no conversion needed
  599. pszString = (CHAR*)pwszString;
  600. }
  601. else
  602. {
  603. pszString = (CHAR*)LocalAlloc(LMEM_FIXED, *pcchString * sizeof(CHAR));
  604. if (NULL == pszString)
  605. {
  606. goto LocalAllocError;
  607. }
  608. fConversion = TRUE;
  609. }
  610. fRet = CryptBinaryToStringA(
  611. pbBinary,
  612. cbBinary,
  613. dwFlags,
  614. pszString,
  615. pcchString);
  616. if (!fRet)
  617. {
  618. goto CryptBinaryToStringAError;
  619. }
  620. //pszString in above call is not NULL, so pcchString can be 1 smaller
  621. //then IN size after the call for exlucding NULL
  622. if (fConversion)
  623. {
  624. len = MultiByteToWideChar(
  625. GetACP(),
  626. 0,
  627. pszString,
  628. (*pcchString + 1) * sizeof(CHAR),
  629. pwszString,
  630. *pcchString + 1);
  631. //add 1 to *pcchString to include NULL for the conversion
  632. //but keep *pcchString for return
  633. if (0 == len)
  634. {
  635. fRet = FALSE;
  636. goto MultiByteToWideCharError;
  637. }
  638. assert(len == (int)(*pcchString + 1));
  639. }
  640. }
  641. ErrorReturn:
  642. if (fConversion && NULL != pszString)
  643. {
  644. LocalFree(pszString);
  645. }
  646. return fRet;
  647. TRACE_ERROR(MultiByteToWideCharError)
  648. TRACE_ERROR(CryptBinaryToStringAError)
  649. TRACE_ERROR(LocalAllocError)
  650. SET_ERROR(InvalidDataError, dwErr)
  651. }
  652. #define NOTEPAD_UNICODE_SPECIAL_WCHAR L'\xfeff'
  653. BOOL
  654. WINAPI
  655. CryptStringToBinaryW(
  656. IN LPCWSTR pwszString,
  657. IN DWORD cchString,
  658. IN DWORD dwFlags,
  659. IN OUT BYTE *pbBinary,
  660. IN OUT DWORD *pcbBinary,
  661. IN OUT DWORD *pdwSkip, //OPTIONAL
  662. IN OUT DWORD *pdwFlags) //OPTIONAL
  663. {
  664. BOOL fRet = FALSE;
  665. BOOL fFree = FALSE;
  666. DWORD dwErr;
  667. CHAR *pszString = NULL;
  668. if (NULL == pwszString || NULL == pcbBinary)
  669. {
  670. dwErr = ERROR_INVALID_PARAMETER;
  671. goto InvalidDataError;
  672. }
  673. if (dwFlags == CRYPT_STRING_BINARY)
  674. {
  675. //its binary, no conversion
  676. pszString = (CHAR*)pwszString;
  677. }
  678. else
  679. {
  680. if (0 == cchString)
  681. {
  682. //assume null terminated string
  683. cchString = wcslen(pwszString) + 1;
  684. }
  685. // Check for the special Notepad UNICODE character inserted at the
  686. // beginning and skip past it if present.
  687. if (0 < cchString && NOTEPAD_UNICODE_SPECIAL_WCHAR == *pwszString)
  688. {
  689. cchString--;
  690. pwszString++;
  691. }
  692. pszString = (CHAR*)LocalAlloc(LMEM_FIXED, cchString * sizeof(CHAR));
  693. if (NULL == pszString)
  694. {
  695. dwErr = ERROR_OUTOFMEMORY;
  696. goto LocalAllocError;
  697. }
  698. fFree = TRUE;
  699. if (0 == WideCharToMultiByte(
  700. GetACP(),
  701. 0,
  702. pwszString,
  703. cchString,
  704. pszString,
  705. cchString,
  706. NULL,
  707. NULL))
  708. {
  709. goto WideCharToMultiByteError;
  710. }
  711. }
  712. fRet = CryptStringToBinaryA(
  713. pszString,
  714. cchString,
  715. dwFlags,
  716. pbBinary,
  717. pcbBinary,
  718. pdwSkip,
  719. pdwFlags);
  720. if (!fRet)
  721. {
  722. goto CryptStringToBinaryAError;
  723. }
  724. ErrorReturn:
  725. if (fFree && NULL != pszString)
  726. {
  727. LocalFree(pszString);
  728. }
  729. return fRet;
  730. TRACE_ERROR(CryptStringToBinaryAError)
  731. SET_ERROR(LocalAllocError, dwErr)
  732. SET_ERROR(InvalidDataError, dwErr)
  733. TRACE_ERROR(WideCharToMultiByteError)
  734. }