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.

3272 lines
102 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: certstr.cpp
  8. //
  9. // Contents: Certificate String and Unicode Helper APIs
  10. //
  11. // Functions:
  12. // CertRDNValueToStrA
  13. // CertRDNValueToStrW
  14. // UnicodeNameValueEncodeEx
  15. // UnicodeNameValueDecodeEx
  16. // UnicodeNameInfoEncodeEx
  17. // UnicodeNameInfoDecodeEx
  18. // CertNameToStrW
  19. // CertNameToStrA
  20. // CertStrToNameW
  21. // CertStrToNameA
  22. // CertGetNameStringW
  23. // CertGetNameStringA
  24. //
  25. // Note:
  26. // Linked into xenroll.dll. xenroll.dll must be able to work with
  27. // crypt32.dll 3.02 which doesn't export CryptEncodeObjectEx.
  28. // xenroll.dll only calls CertNameToStrW.
  29. //
  30. // History: 24-Mar-96 philh created
  31. //--------------------------------------------------------------------------
  32. #include "global.hxx"
  33. #include <dbgdef.h>
  34. // All the *pvInfo extra stuff needs to be aligned
  35. #define INFO_LEN_ALIGN(Len) ((Len + 7) & ~7)
  36. // Unicode Surrogate Pairs map to Universal characters as follows:
  37. // D800 - DBFF : 0000 0000 0000 0000 1101 10YY YYYY YYYY (10 Bits)
  38. // DC00 - DFFF : 0000 0000 0000 0000 1101 11XX XXXX XXXX (10 Bits)
  39. //
  40. // 10000 - 10FFFF : 0000 0000 0000 YYYY YYYY YYXX XXXX XXXX (20 Bits)
  41. // +
  42. // 0000 0000 0000 0001 0000 0000 0000 0000
  43. // Unicode Surrogate Pair Character ranges
  44. #define UNICODE_HIGH_SURROGATE_START 0xD800
  45. #define UNICODE_HIGH_SURROGATE_END 0xDBFF
  46. #define UNICODE_LOW_SURROGATE_START 0xDC00
  47. #define UNICODE_LOW_SURROGATE_END 0xDFFF
  48. // Any Universal characters > 10FFFF map to the following Unicode character
  49. #define UNICODE_REPLACEMENT_CHAR 0xFFFD
  50. // Universal Surrogate Character ranges
  51. #define UNIVERSAL_SURROGATE_START 0x00010000
  52. #define UNIVERSAL_SURROGATE_END 0x0010FFFF
  53. //+-------------------------------------------------------------------------
  54. // Maps an ASN.1 8 bit character string to a new wide-character (Unicode).
  55. //
  56. // If fDisableIE4UTF8 isn't set, the 8 bit character string is initially
  57. // processed as UTF-8 encoded characters.
  58. //
  59. // If fDisableIE4UTF8 is set or the UTF-8 conversion fails, converts to
  60. // wide characters by doing a WCHAR cast.
  61. //--------------------------------------------------------------------------
  62. static int WINAPI Asn1ToWideChar(
  63. IN LPCSTR lp8BitStr,
  64. IN int cch8Bit,
  65. IN BOOL fDisableIE4UTF8,
  66. OUT LPWSTR lpWideCharStr,
  67. IN int cchWideChar
  68. )
  69. {
  70. int cchOutWideChar;
  71. if (!fDisableIE4UTF8) {
  72. int cchUTF8WideChar;
  73. cchUTF8WideChar = UTF8ToWideChar(
  74. lp8BitStr,
  75. cch8Bit,
  76. lpWideCharStr,
  77. cchWideChar
  78. );
  79. if (0 < cchUTF8WideChar)
  80. return cchUTF8WideChar;
  81. }
  82. if (cch8Bit < 0)
  83. cch8Bit = strlen(lp8BitStr) + 1;
  84. cchOutWideChar = cch8Bit;
  85. if (cchWideChar < 0)
  86. goto InvalidParameter;
  87. else if (0 == cchWideChar)
  88. goto CommonReturn;
  89. else if (cchOutWideChar > cchWideChar)
  90. goto InsufficientBuffer;
  91. while (cch8Bit--)
  92. *lpWideCharStr++ = (unsigned char) *lp8BitStr++;
  93. CommonReturn:
  94. return cchOutWideChar;
  95. ErrorReturn:
  96. cchOutWideChar = 0;
  97. goto CommonReturn;
  98. SET_ERROR(InvalidParameter, ERROR_INVALID_PARAMETER)
  99. SET_ERROR(InsufficientBuffer, ERROR_INSUFFICIENT_BUFFER)
  100. }
  101. //+-------------------------------------------------------------------------
  102. // Maps a wide-character (Unicode) string to a new ASN.1 8 bit character
  103. // string.
  104. //--------------------------------------------------------------------------
  105. static inline void WideCharToAsn1(
  106. IN LPCWSTR lpWideCharStr,
  107. IN DWORD cchWideChar,
  108. OUT LPSTR lp8BitStr
  109. )
  110. {
  111. while (cchWideChar--)
  112. *lp8BitStr++ = (unsigned char) (*lpWideCharStr++ & 0xFF);
  113. }
  114. static void *AllocAndDecodeObject(
  115. IN DWORD dwCertEncodingType,
  116. IN LPCSTR lpszStructType,
  117. IN const BYTE *pbEncoded,
  118. IN DWORD cbEncoded,
  119. IN DWORD dwFlags,
  120. OUT OPTIONAL DWORD *pcbStructInfo = NULL
  121. )
  122. {
  123. DWORD cbStructInfo;
  124. void *pvStructInfo;
  125. if (!CryptDecodeObjectEx(
  126. dwCertEncodingType,
  127. lpszStructType,
  128. pbEncoded,
  129. cbEncoded,
  130. dwFlags | CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
  131. &PkiDecodePara,
  132. (void *) &pvStructInfo,
  133. &cbStructInfo
  134. ))
  135. goto ErrorReturn;
  136. CommonReturn:
  137. if (pcbStructInfo)
  138. *pcbStructInfo = cbStructInfo;
  139. return pvStructInfo;
  140. ErrorReturn:
  141. pvStructInfo = NULL;
  142. cbStructInfo = 0;
  143. goto CommonReturn;
  144. }
  145. typedef BOOL (WINAPI *PFN_NESTED_DECODE_INFO_EX_CALLBACK)(
  146. IN void *pvDecodeInfo,
  147. IN DWORD dwFlags,
  148. IN OPTIONAL PCRYPT_DECODE_PARA pDecodePara,
  149. OUT OPTIONAL void *pvStructInfo,
  150. IN OUT LONG *plRemainExtra
  151. );
  152. static BOOL WINAPI NestedDecodeAndAllocInfoEx(
  153. IN DWORD dwCertEncodingType,
  154. IN LPCSTR lpszStructType,
  155. IN const BYTE *pbEncoded,
  156. IN DWORD cbEncoded,
  157. IN DWORD dwFlags,
  158. IN OPTIONAL PCRYPT_DECODE_PARA pDecodePara,
  159. IN PFN_NESTED_DECODE_INFO_EX_CALLBACK pfnDecodeInfoExCallback,
  160. OUT OPTIONAL void *pvStructInfo,
  161. IN OUT DWORD *pcbStructInfo
  162. )
  163. {
  164. BOOL fResult;
  165. LONG lRemainExtra;
  166. DWORD cbStructInfo;
  167. void *pvDecodeInfo = NULL;
  168. DWORD cbDecodeInfo;
  169. if (NULL == pvStructInfo || (dwFlags & CRYPT_DECODE_ALLOC_FLAG)) {
  170. cbStructInfo = 0;
  171. lRemainExtra = 0;
  172. } else {
  173. cbStructInfo = *pcbStructInfo;
  174. lRemainExtra = (LONG) cbStructInfo;
  175. }
  176. if (!CryptDecodeObjectEx(
  177. dwCertEncodingType,
  178. lpszStructType,
  179. pbEncoded,
  180. cbEncoded,
  181. CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
  182. &PkiDecodePara,
  183. (void *) &pvDecodeInfo,
  184. &cbDecodeInfo
  185. )) goto DecodeObjectError;
  186. if (!pfnDecodeInfoExCallback(
  187. pvDecodeInfo,
  188. dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
  189. pDecodePara,
  190. pvStructInfo,
  191. &lRemainExtra
  192. )) goto DecodeCallbackError;
  193. if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) {
  194. void *pv;
  195. PFN_CRYPT_ALLOC pfnAlloc = PkiGetDecodeAllocFunction(pDecodePara);
  196. assert(0 > lRemainExtra);
  197. lRemainExtra = -lRemainExtra;
  198. cbStructInfo = (DWORD) lRemainExtra;
  199. if (NULL == (pv = pfnAlloc(cbStructInfo)))
  200. goto OutOfMemory;
  201. if (!pfnDecodeInfoExCallback(
  202. pvDecodeInfo,
  203. dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
  204. pDecodePara,
  205. pv,
  206. &lRemainExtra
  207. )) {
  208. PFN_CRYPT_FREE pfnFree = PkiGetDecodeFreeFunction(pDecodePara);
  209. pfnFree(pv);
  210. goto DecodeCallbackError;
  211. }
  212. *((void **) pvStructInfo) = pv;
  213. assert(0 <= lRemainExtra);
  214. }
  215. if (0 <= lRemainExtra) {
  216. cbStructInfo -= (DWORD) lRemainExtra;
  217. } else {
  218. cbStructInfo += (DWORD) -lRemainExtra;
  219. if (pvStructInfo) {
  220. SetLastError((DWORD) ERROR_MORE_DATA);
  221. fResult = FALSE;
  222. goto CommonReturn;
  223. }
  224. }
  225. fResult = TRUE;
  226. CommonReturn:
  227. *pcbStructInfo = cbStructInfo;
  228. PkiFree(pvDecodeInfo);
  229. return fResult;
  230. ErrorReturn:
  231. if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
  232. *((void **) pvStructInfo) = NULL;
  233. cbStructInfo = 0;
  234. fResult = FALSE;
  235. goto CommonReturn;
  236. TRACE_ERROR(DecodeObjectError)
  237. TRACE_ERROR(DecodeCallbackError)
  238. TRACE_ERROR(OutOfMemory)
  239. }
  240. //+-------------------------------------------------------------------------
  241. // Convert a Name Value to a null terminated char string
  242. //
  243. // Returns the number of bytes converted including the terminating null
  244. // character. If psz is NULL or csz is 0, returns the required size of the
  245. // destination string (including the terminating null char).
  246. //
  247. // If psz != NULL && csz != 0, returned psz is always NULL terminated.
  248. //
  249. // Note: csz includes the NULL char.
  250. //--------------------------------------------------------------------------
  251. DWORD
  252. WINAPI
  253. CertRDNValueToStrA(
  254. IN DWORD dwValueType,
  255. IN PCERT_RDN_VALUE_BLOB pValue,
  256. OUT OPTIONAL LPSTR psz,
  257. IN DWORD csz
  258. )
  259. {
  260. DWORD cszOut = 0;
  261. LPWSTR pwsz = NULL;
  262. DWORD cwsz;
  263. if (psz == NULL)
  264. csz = 0;
  265. cwsz = CertRDNValueToStrW(
  266. dwValueType,
  267. pValue,
  268. NULL, // pwsz
  269. 0 // cwsz
  270. );
  271. if (pwsz = (LPWSTR) PkiNonzeroAlloc(cwsz * sizeof(WCHAR))) {
  272. CertRDNValueToStrW(
  273. dwValueType,
  274. pValue,
  275. pwsz,
  276. cwsz
  277. );
  278. int cchMultiByte;
  279. cchMultiByte = WideCharToMultiByte(
  280. CP_ACP,
  281. 0, // dwFlags
  282. pwsz,
  283. -1, // Null terminated
  284. psz,
  285. (int) csz,
  286. NULL, // lpDefaultChar
  287. NULL // lpfUsedDefaultChar
  288. );
  289. if (cchMultiByte < 1)
  290. cszOut = 0;
  291. else
  292. // Subtract off the trailing null terminator
  293. cszOut = (DWORD) cchMultiByte - 1;
  294. PkiFree(pwsz);
  295. }
  296. if (csz != 0) {
  297. // Always NULL terminate
  298. *(psz + cszOut) = '\0';
  299. }
  300. return cszOut + 1;
  301. }
  302. DWORD
  303. WINAPI
  304. GetSurrogatePairCountFromUniversalString(
  305. IN DWORD *pdw,
  306. IN DWORD cdw
  307. )
  308. {
  309. DWORD cSP = 0;
  310. for ( ; cdw > 0; cdw--, pdw++) {
  311. DWORD dw = *pdw;
  312. if (dw >= UNIVERSAL_SURROGATE_START &&
  313. dw <= UNIVERSAL_SURROGATE_END)
  314. cSP++;
  315. }
  316. return cSP;
  317. }
  318. //+-------------------------------------------------------------------------
  319. // Convert a Name Value to a null terminated WCHAR string
  320. //
  321. // Returns the number of WCHARs converted including the terminating null
  322. // WCHAR. If pwsz is NULL or cwsz is 0, returns the required size of the
  323. // destination string (including the terminating null WCHAR).
  324. //
  325. // If pwsz != NULL && cwsz != 0, returned pwsz is always NULL terminated.
  326. //
  327. // Note: cwsz includes the NULL WCHAR.
  328. //--------------------------------------------------------------------------
  329. DWORD
  330. WINAPI
  331. CertRDNValueToStrW(
  332. IN DWORD dwValueType,
  333. IN PCERT_RDN_VALUE_BLOB pValue,
  334. OUT OPTIONAL LPWSTR pwsz,
  335. IN DWORD cwsz
  336. )
  337. {
  338. BOOL fDisableIE4UTF8;
  339. DWORD cwszOut = 0;
  340. if (pwsz == NULL)
  341. cwsz = 0;
  342. fDisableIE4UTF8 = (0 != (dwValueType & CERT_RDN_DISABLE_IE4_UTF8_FLAG));
  343. dwValueType &= CERT_RDN_TYPE_MASK;
  344. if (dwValueType == CERT_RDN_UNICODE_STRING ||
  345. dwValueType == CERT_RDN_UTF8_STRING) {
  346. cwszOut = pValue->cbData / sizeof(WCHAR);
  347. if (cwsz > 0) {
  348. cwszOut = min(cwszOut, cwsz - 1);
  349. if (cwszOut)
  350. memcpy((BYTE *) pwsz, pValue->pbData, cwszOut * sizeof(WCHAR));
  351. }
  352. } else if (dwValueType == CERT_RDN_UNIVERSAL_STRING) {
  353. // 4 byte string. Characters < 0x10000 are converted directly to
  354. // Unicode. Characters within 0x10000 .. 0x10FFFF are mapped
  355. // to a surrogate pair. Any character > 0x10FFFF is mapped to
  356. // the replacement character, 0xFFFD.
  357. DWORD *pdwIn = (DWORD *) pValue->pbData;
  358. DWORD cdwIn = pValue->cbData / sizeof(DWORD);
  359. cwszOut = cdwIn +
  360. GetSurrogatePairCountFromUniversalString(pdwIn, cdwIn);
  361. if (cwsz > 0) {
  362. DWORD cOut;
  363. LPWSTR pwszOut;
  364. cwszOut = min(cwszOut, cwsz - 1);
  365. cOut = cwszOut;
  366. pwszOut = pwsz;
  367. for ( ; cdwIn > 0 && cOut > 0; cdwIn--, cOut--) {
  368. DWORD dw = *pdwIn++;
  369. if (dw < UNIVERSAL_SURROGATE_START)
  370. *pwszOut++ = (WCHAR) dw;
  371. else if (dw <= UNIVERSAL_SURROGATE_END) {
  372. if (cOut > 1) {
  373. // Surrogate pair contains 20 bits.
  374. DWORD dw20Bits;
  375. dw20Bits = dw - UNIVERSAL_SURROGATE_START;
  376. assert(dw20Bits <= 0xFFFFF);
  377. *pwszOut++ = (WCHAR) (UNICODE_HIGH_SURROGATE_START +
  378. (dw20Bits >> 10));
  379. *pwszOut++ = (WCHAR) (UNICODE_LOW_SURROGATE_START +
  380. (dw20Bits & 0x3FF));
  381. cOut--;
  382. } else
  383. *pwszOut++ = UNICODE_REPLACEMENT_CHAR;
  384. } else
  385. *pwszOut++ = UNICODE_REPLACEMENT_CHAR;
  386. }
  387. }
  388. } else {
  389. // Treat as a 8 bit character string
  390. if (cwsz != 1) {
  391. int cchWideChar;
  392. if (cwsz == 0)
  393. cchWideChar = 0;
  394. else
  395. cchWideChar = cwsz - 1;
  396. if (dwValueType != CERT_RDN_T61_STRING)
  397. fDisableIE4UTF8 = TRUE;
  398. cchWideChar = Asn1ToWideChar(
  399. (LPSTR) pValue->pbData,
  400. pValue->cbData,
  401. fDisableIE4UTF8,
  402. pwsz,
  403. cchWideChar
  404. );
  405. if (cchWideChar <= 0)
  406. cwszOut = 0;
  407. else
  408. cwszOut = (DWORD) cchWideChar;
  409. }
  410. }
  411. if (cwsz != 0) {
  412. // Always NULL terminate
  413. *(pwsz + cwszOut) = L'\0';
  414. }
  415. return cwszOut + 1;
  416. }
  417. //+-------------------------------------------------------------------------
  418. // Wide Character functions
  419. //
  420. // Needed, since we don't link with 'C' runtime
  421. //--------------------------------------------------------------------------
  422. static inline BOOL IsSpaceW(WCHAR wc)
  423. {
  424. return wc == L' ' || (wc >= 0x09 && wc <= 0x0d);
  425. }
  426. static BOOL IsInStrW(LPCWSTR pwszList, WCHAR wc)
  427. {
  428. WCHAR wcList;
  429. while (wcList = *pwszList++)
  430. if (wc == wcList)
  431. return TRUE;
  432. return FALSE;
  433. }
  434. //+-------------------------------------------------------------------------
  435. // Checks if an ASN.1 numeric character
  436. //--------------------------------------------------------------------------
  437. static inline BOOL IsNumericW(WCHAR wc)
  438. {
  439. return (wc >= L'0' && wc <= L'9') || wc == L' ';
  440. }
  441. //+-------------------------------------------------------------------------
  442. // Checks if an ASN.1 printable character
  443. //--------------------------------------------------------------------------
  444. static inline BOOL IsPrintableW(WCHAR wc)
  445. {
  446. return (wc >= L'A' && wc <= L'Z') || (wc >= L'a' && wc <= L'z') ||
  447. IsNumericW(wc) || IsInStrW(L"\'()+,-./:=?", wc);
  448. }
  449. //+-------------------------------------------------------------------------
  450. // Returns 0 if the unicode character string doesn't contain any invalid
  451. // characters. Otherwise, returns CRYPT_E_INVALID_NUMERIC_STRING,
  452. // CRYPT_E_INVALID_PRINTABLE_STRING or CRYPT_E_INVALID_IA5_STRING with
  453. // *pdwErrLocation updated with the index of the first invalid character.
  454. //--------------------------------------------------------------------------
  455. static DWORD CheckUnicodeValueType(
  456. IN DWORD dwValueType,
  457. IN LPCWSTR pwszAttr,
  458. IN DWORD cchAttr,
  459. OUT DWORD *pdwErrLocation
  460. )
  461. {
  462. DWORD i;
  463. DWORD dwErr;
  464. assert(dwValueType & CERT_RDN_TYPE_MASK);
  465. *pdwErrLocation = 0;
  466. dwErr = 0;
  467. for (i = 0; i < cchAttr; i++) {
  468. WCHAR wc = pwszAttr[i];
  469. switch (dwValueType & CERT_RDN_TYPE_MASK) {
  470. case CERT_RDN_NUMERIC_STRING:
  471. if (!IsNumericW(wc))
  472. dwErr = (DWORD) CRYPT_E_INVALID_NUMERIC_STRING;
  473. break;
  474. case CERT_RDN_PRINTABLE_STRING:
  475. if (!IsPrintableW(wc))
  476. dwErr = (DWORD) CRYPT_E_INVALID_PRINTABLE_STRING;
  477. break;
  478. case CERT_RDN_IA5_STRING:
  479. if (wc > 0x7F)
  480. dwErr = (DWORD) CRYPT_E_INVALID_IA5_STRING;
  481. break;
  482. default:
  483. return 0;
  484. }
  485. if (0 != dwErr) {
  486. assert(i <= CERT_UNICODE_VALUE_ERR_INDEX_MASK);
  487. *pdwErrLocation = i & CERT_UNICODE_VALUE_ERR_INDEX_MASK;
  488. return dwErr;
  489. }
  490. }
  491. return 0;
  492. }
  493. //+-------------------------------------------------------------------------
  494. // Set/Free/Get CERT_RDN attribute value. The values are unicode.
  495. //+-------------------------------------------------------------------------
  496. static BOOL SetUnicodeRDNAttributeValue(
  497. IN DWORD dwValueType,
  498. IN PCERT_RDN_VALUE_BLOB pSrcValue,
  499. IN BOOL fDisableCheckType,
  500. OUT PCERT_RDN_VALUE_BLOB pDstValue,
  501. OUT OPTIONAL DWORD *pdwErrLocation
  502. )
  503. {
  504. BOOL fResult;
  505. LPCWSTR pwszAttr;
  506. DWORD cchAttr;
  507. DWORD dwErr;
  508. if (pdwErrLocation)
  509. *pdwErrLocation = 0;
  510. dwValueType &= CERT_RDN_TYPE_MASK;
  511. memset(pDstValue, 0, sizeof(CERT_RDN_VALUE_BLOB));
  512. if (CERT_RDN_ANY_TYPE == dwValueType)
  513. goto InvalidArg;
  514. assert(IS_CERT_RDN_CHAR_STRING(dwValueType));
  515. pwszAttr = pSrcValue->pbData ? (LPCWSTR) pSrcValue->pbData : L"";
  516. cchAttr = (DWORD)( pSrcValue->cbData ?
  517. pSrcValue->cbData / sizeof(WCHAR) : wcslen(pwszAttr) );
  518. // Update Destination Value
  519. if (cchAttr) {
  520. switch (dwValueType) {
  521. case CERT_RDN_UNICODE_STRING:
  522. case CERT_RDN_UTF8_STRING:
  523. // Use source. No allocation or copy required
  524. pDstValue->pbData = (BYTE *) pwszAttr;
  525. pDstValue->cbData = cchAttr * sizeof(WCHAR);
  526. break;
  527. case CERT_RDN_UNIVERSAL_STRING:
  528. // Update the "low" 16 bits of each 32 bit integer with
  529. // the UNICODE character. Also handle surrogate pairs.
  530. {
  531. DWORD cdw = cchAttr;
  532. DWORD cbData = cdw * sizeof(DWORD);
  533. DWORD *pdwDst;
  534. LPCWSTR pwszSrc = pwszAttr;
  535. if (NULL == (pdwDst = (DWORD *) PkiNonzeroAlloc(cbData)))
  536. goto OutOfMemory;
  537. pDstValue->pbData = (BYTE *) pdwDst;
  538. for ( ; cdw > 0; cdw--) {
  539. WCHAR wc = *pwszSrc++;
  540. WCHAR wc2;
  541. if (wc >= UNICODE_HIGH_SURROGATE_START &&
  542. wc <= UNICODE_HIGH_SURROGATE_END
  543. &&
  544. cdw > 1
  545. &&
  546. (wc2 = *pwszSrc) >= UNICODE_LOW_SURROGATE_START &&
  547. wc2 <= UNICODE_LOW_SURROGATE_END) {
  548. pwszSrc++;
  549. cdw--;
  550. cbData -= sizeof(DWORD);
  551. *pdwDst++ =
  552. (((DWORD)(wc - UNICODE_HIGH_SURROGATE_START)) << 10)
  553. +
  554. ((DWORD)(wc2 - UNICODE_LOW_SURROGATE_START))
  555. +
  556. UNIVERSAL_SURROGATE_START;
  557. } else
  558. *pdwDst++ = ((DWORD) wc) & 0xFFFF;
  559. }
  560. pDstValue->cbData = cbData;
  561. }
  562. break;
  563. default:
  564. // Convert each unicode character to 8 Bit character
  565. {
  566. BYTE *pbDst;
  567. if (pdwErrLocation && !fDisableCheckType) {
  568. // Check that the unicode string doesn't contain any
  569. // invalid dwValueType characters.
  570. if (0 != (dwErr = CheckUnicodeValueType(
  571. dwValueType,
  572. pwszAttr,
  573. cchAttr,
  574. pdwErrLocation
  575. ))) goto InvalidUnicodeValueType;
  576. }
  577. if (NULL == (pbDst = (BYTE *) PkiNonzeroAlloc(cchAttr)))
  578. goto OutOfMemory;
  579. pDstValue->pbData = pbDst;
  580. pDstValue->cbData = cchAttr;
  581. WideCharToAsn1(
  582. pwszAttr,
  583. cchAttr,
  584. (LPSTR) pbDst
  585. );
  586. }
  587. }
  588. }
  589. fResult = TRUE;
  590. CommonReturn:
  591. return fResult;
  592. ErrorReturn:
  593. fResult = FALSE;
  594. goto CommonReturn;
  595. SET_ERROR(InvalidArg, E_INVALIDARG)
  596. SET_ERROR_VAR(InvalidUnicodeValueType, dwErr)
  597. TRACE_ERROR(OutOfMemory)
  598. }
  599. static void FreeUnicodeRDNAttributeValue(
  600. IN DWORD dwValueType,
  601. IN OUT PCERT_RDN_VALUE_BLOB pValue
  602. )
  603. {
  604. switch (dwValueType & CERT_RDN_TYPE_MASK) {
  605. case CERT_RDN_UNICODE_STRING:
  606. case CERT_RDN_UTF8_STRING:
  607. case CERT_RDN_ENCODED_BLOB:
  608. case CERT_RDN_OCTET_STRING:
  609. break;
  610. default:
  611. PkiFree(pValue->pbData);
  612. }
  613. }
  614. static BOOL GetUnicodeRDNAttributeValue(
  615. IN DWORD dwValueType,
  616. IN PCERT_RDN_VALUE_BLOB pSrcValue,
  617. IN DWORD dwFlags,
  618. OUT PCERT_RDN_VALUE_BLOB pDstValue,
  619. IN OUT BYTE **ppbExtra,
  620. IN OUT LONG *plRemainExtra
  621. )
  622. {
  623. BOOL fResult;
  624. LONG lRemainExtra = *plRemainExtra;
  625. BYTE *pbExtra = *ppbExtra;
  626. LONG lAlignExtra;
  627. DWORD cbData;
  628. BYTE *pbSrcData;
  629. BOOL fDisableIE4UTF8;
  630. // Get Unicode value length
  631. cbData = pSrcValue->cbData;
  632. pbSrcData = pSrcValue->pbData;
  633. fDisableIE4UTF8 =
  634. (0 != (dwFlags & CRYPT_UNICODE_NAME_DECODE_DISABLE_IE4_UTF8_FLAG));
  635. assert(0 == (dwValueType & ~CERT_RDN_TYPE_MASK));
  636. dwValueType &= CERT_RDN_TYPE_MASK;
  637. switch (dwValueType) {
  638. case CERT_RDN_UNICODE_STRING:
  639. case CERT_RDN_UTF8_STRING:
  640. case CERT_RDN_ENCODED_BLOB:
  641. case CERT_RDN_OCTET_STRING:
  642. // The above cbData
  643. break;
  644. case CERT_RDN_UNIVERSAL_STRING:
  645. // 4 byte string. Characters < 0x10000 are converted directly to
  646. // Unicode. Characters within 0x10000 .. 0x10FFFF are mapped
  647. // to surrogate pair. Any character > 0x10FFFF is mapped to
  648. // the replacement character, 0xFFFD.
  649. cbData = (cbData / 4) * sizeof(WCHAR);
  650. cbData += GetSurrogatePairCountFromUniversalString(
  651. (DWORD *) pbSrcData,
  652. cbData / sizeof(WCHAR)) * sizeof(WCHAR);
  653. break;
  654. default:
  655. // Length of resultant WideChar
  656. if (cbData) {
  657. int cchWideChar;
  658. if (dwValueType != CERT_RDN_T61_STRING)
  659. fDisableIE4UTF8 = TRUE;
  660. cchWideChar = Asn1ToWideChar(
  661. (LPSTR) pbSrcData,
  662. cbData,
  663. fDisableIE4UTF8,
  664. NULL, // lpWideCharStr
  665. 0 // cchWideChar
  666. );
  667. if (cchWideChar <= 0)
  668. goto Asn1ToWideCharError;
  669. cbData = cchWideChar * sizeof(WCHAR);
  670. }
  671. }
  672. // Note, +sizeof(WCHAR) is unicode value's NULL terminator
  673. lAlignExtra = INFO_LEN_ALIGN(cbData + sizeof(WCHAR));
  674. lRemainExtra -= lAlignExtra;
  675. if (lRemainExtra >= 0) {
  676. pDstValue->pbData = pbExtra;
  677. pDstValue->cbData = cbData;
  678. switch (dwValueType) {
  679. case CERT_RDN_UNICODE_STRING:
  680. case CERT_RDN_UTF8_STRING:
  681. case CERT_RDN_ENCODED_BLOB:
  682. case CERT_RDN_OCTET_STRING:
  683. if (cbData)
  684. memcpy(pbExtra, pbSrcData, cbData);
  685. break;
  686. case CERT_RDN_UNIVERSAL_STRING:
  687. // Convert Universal to Unicode. See above comments.
  688. {
  689. DWORD cdw = pSrcValue->cbData / sizeof (DWORD);
  690. DWORD *pdwSrc = (DWORD *) pbSrcData;
  691. LPWSTR pwszDst = (LPWSTR) pbExtra;
  692. for ( ; cdw > 0; cdw--) {
  693. DWORD dw = *pdwSrc++;
  694. if (dw < UNIVERSAL_SURROGATE_START)
  695. *pwszDst++ = (WCHAR) dw;
  696. else if (dw <= UNIVERSAL_SURROGATE_END) {
  697. // Surrogate pair contains 20 bits.
  698. DWORD dw20Bits;
  699. dw20Bits = dw - UNIVERSAL_SURROGATE_START;
  700. assert(dw20Bits <= 0xFFFFF);
  701. *pwszDst++ = (WCHAR) (UNICODE_HIGH_SURROGATE_START +
  702. (dw20Bits >> 10));
  703. *pwszDst++ = (WCHAR) (UNICODE_LOW_SURROGATE_START +
  704. (dw20Bits & 0x3FF));
  705. } else
  706. *pwszDst++ = UNICODE_REPLACEMENT_CHAR;
  707. }
  708. assert(pbExtra + cbData == (BYTE *) pwszDst);
  709. }
  710. break;
  711. default:
  712. // Convert UTF8 to unicode
  713. if (cbData) {
  714. int cchWideChar;
  715. cchWideChar = Asn1ToWideChar(
  716. (LPSTR) pbSrcData,
  717. pSrcValue->cbData,
  718. fDisableIE4UTF8,
  719. (LPWSTR) pbExtra,
  720. cbData / sizeof(WCHAR)
  721. );
  722. if (cchWideChar > 0) {
  723. if (((DWORD) cchWideChar * sizeof(WCHAR)) <= cbData) {
  724. pDstValue->cbData = cchWideChar * sizeof(WCHAR);
  725. *((LPWSTR) pbExtra + cchWideChar) = L'\0';
  726. }
  727. } else {
  728. assert(0);
  729. goto Asn1ToWideCharError;
  730. }
  731. }
  732. }
  733. // Ensure NULL termination
  734. memset(pbExtra + cbData, 0, sizeof(WCHAR));
  735. pbExtra += lAlignExtra;
  736. }
  737. *plRemainExtra = lRemainExtra;
  738. *ppbExtra = pbExtra;
  739. fResult = TRUE;
  740. CommonReturn:
  741. return fResult;
  742. ErrorReturn:
  743. fResult = FALSE;
  744. goto CommonReturn;
  745. TRACE_ERROR(Asn1ToWideCharError)
  746. }
  747. //+-------------------------------------------------------------------------
  748. // Encode the "UNICODE" Name Value
  749. //--------------------------------------------------------------------------
  750. BOOL WINAPI UnicodeNameValueEncodeEx(
  751. IN DWORD dwCertEncodingType,
  752. IN LPCSTR lpszStructType,
  753. IN PCERT_NAME_VALUE pInfo,
  754. IN DWORD dwFlags,
  755. IN OPTIONAL PCRYPT_ENCODE_PARA pEncodePara,
  756. OUT OPTIONAL void *pvEncoded,
  757. IN OUT DWORD *pcbEncoded
  758. )
  759. {
  760. BOOL fResult;
  761. DWORD dwValueType;
  762. CERT_NAME_VALUE DstInfo;
  763. DWORD dwErrLocation;
  764. BOOL fDisableCheckType;
  765. if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
  766. *((void **) pvEncoded) = NULL;
  767. dwValueType = pInfo->dwValueType;
  768. if (!IS_CERT_RDN_CHAR_STRING(dwValueType)) {
  769. *pcbEncoded = 0;
  770. SetLastError((DWORD) CRYPT_E_NOT_CHAR_STRING);
  771. return FALSE;
  772. }
  773. DstInfo.dwValueType = dwValueType & CERT_RDN_TYPE_MASK;
  774. fDisableCheckType =
  775. (0 != (dwFlags & CRYPT_UNICODE_NAME_ENCODE_DISABLE_CHECK_TYPE_FLAG) ||
  776. 0 != (dwValueType & CERT_RDN_DISABLE_CHECK_TYPE_FLAG));
  777. if (!SetUnicodeRDNAttributeValue(dwValueType, &pInfo->Value,
  778. fDisableCheckType, &DstInfo.Value, &dwErrLocation)) {
  779. fResult = FALSE;
  780. *pcbEncoded = dwErrLocation;
  781. goto CommonReturn;
  782. }
  783. fResult = CryptEncodeObjectEx(
  784. dwCertEncodingType,
  785. X509_NAME_VALUE,
  786. &DstInfo,
  787. dwFlags & ~CRYPT_UNICODE_NAME_ENCODE_DISABLE_CHECK_TYPE_FLAG,
  788. pEncodePara,
  789. pvEncoded,
  790. pcbEncoded
  791. );
  792. CommonReturn:
  793. FreeUnicodeRDNAttributeValue(dwValueType, &DstInfo.Value);
  794. return fResult;
  795. }
  796. //+-------------------------------------------------------------------------
  797. // Decode the "UNICODE" Name Value
  798. //--------------------------------------------------------------------------
  799. BOOL WINAPI UnicodeNameValueDecodeExCallback(
  800. IN void *pvDecodeInfo,
  801. IN DWORD dwFlags,
  802. IN OPTIONAL PCRYPT_DECODE_PARA pDecodePara,
  803. OUT OPTIONAL void *pvStructInfo,
  804. IN OUT LONG *plRemainExtra
  805. )
  806. {
  807. BOOL fResult;
  808. PCERT_NAME_VALUE pNameValue = (PCERT_NAME_VALUE) pvDecodeInfo;
  809. PCERT_NAME_VALUE pInfo = (PCERT_NAME_VALUE) pvStructInfo;
  810. LONG lRemainExtra = *plRemainExtra;
  811. BYTE *pbExtra;
  812. PCERT_RDN_VALUE_BLOB pValue;
  813. if (!IS_CERT_RDN_CHAR_STRING(pNameValue->dwValueType))
  814. goto NotCharString;
  815. lRemainExtra -= sizeof(CERT_NAME_VALUE);
  816. if (lRemainExtra < 0) {
  817. pbExtra = NULL;
  818. pValue = NULL;
  819. } else {
  820. pbExtra = (BYTE *) pInfo + sizeof(CERT_NAME_VALUE);
  821. pInfo->dwValueType = pNameValue->dwValueType;
  822. pValue = &pInfo->Value;
  823. }
  824. if (!GetUnicodeRDNAttributeValue(
  825. pNameValue->dwValueType,
  826. &pNameValue->Value,
  827. dwFlags,
  828. pValue,
  829. &pbExtra,
  830. &lRemainExtra
  831. )) goto DecodeError;
  832. fResult = TRUE;
  833. CommonReturn:
  834. *plRemainExtra = lRemainExtra;
  835. return fResult;
  836. ErrorReturn:
  837. fResult = FALSE;
  838. goto CommonReturn;
  839. SET_ERROR(NotCharString, CRYPT_E_NOT_CHAR_STRING)
  840. TRACE_ERROR(DecodeError)
  841. }
  842. BOOL WINAPI UnicodeNameValueDecodeEx(
  843. IN DWORD dwCertEncodingType,
  844. IN LPCSTR lpszStructType,
  845. IN const BYTE *pbEncoded,
  846. IN DWORD cbEncoded,
  847. IN DWORD dwFlags,
  848. IN OPTIONAL PCRYPT_DECODE_PARA pDecodePara,
  849. OUT OPTIONAL void *pvStructInfo,
  850. IN OUT DWORD *pcbStructInfo
  851. )
  852. {
  853. return NestedDecodeAndAllocInfoEx(
  854. dwCertEncodingType,
  855. X509_NAME_VALUE,
  856. pbEncoded,
  857. cbEncoded,
  858. dwFlags,
  859. pDecodePara,
  860. UnicodeNameValueDecodeExCallback,
  861. pvStructInfo,
  862. pcbStructInfo
  863. );
  864. }
  865. //+-------------------------------------------------------------------------
  866. // Default ordered list of acceptable RDN attribute value types. Used when
  867. // OIDInfo's ExtraInfo.cbData == 0. Or when ExtraInfo contains an empty
  868. // list.
  869. //--------------------------------------------------------------------------
  870. static const DWORD rgdwDefaultValueType[] = {
  871. CERT_RDN_PRINTABLE_STRING,
  872. CERT_RDN_UNICODE_STRING,
  873. 0
  874. };
  875. //+-------------------------------------------------------------------------
  876. // Default X500 OID Information entry
  877. //--------------------------------------------------------------------------
  878. static CCRYPT_OID_INFO DefaultX500Info = {
  879. sizeof(CCRYPT_OID_INFO), // cbSize
  880. "", // pszOID
  881. L"", // pwszName
  882. 0, // dwLength
  883. 0, NULL // ExtraInfo
  884. };
  885. // Please update the following if you add a new entry to the RDNAttrTable in
  886. // oidinfo.cpp with a longer pwszName
  887. #define MAX_X500_KEY_LEN 64
  888. //+-------------------------------------------------------------------------
  889. // Checks if character needs to be quoted
  890. //
  891. // Defined in RFC1779
  892. //--------------------------------------------------------------------------
  893. static inline BOOL IsQuotedW(WCHAR wc)
  894. {
  895. return IsInStrW(L",+=\"\n<>#;", wc);
  896. }
  897. //+-------------------------------------------------------------------------
  898. // Checks if "decoded" unicode RDN value needs to be quoted
  899. //--------------------------------------------------------------------------
  900. static BOOL IsQuotedUnicodeRDNValue(PCERT_RDN_VALUE_BLOB pValue)
  901. {
  902. LPCWSTR pwszValue = (LPCWSTR) pValue->pbData;
  903. DWORD cchValue = pValue->cbData / sizeof(WCHAR);
  904. if (0 == cchValue)
  905. return TRUE;
  906. // First or Last character is whitespace
  907. if (IsSpaceW(pwszValue[0]) || IsSpaceW(pwszValue[cchValue - 1]))
  908. return TRUE;
  909. for ( ; cchValue > 0; cchValue--, pwszValue++)
  910. if (IsQuotedW(*pwszValue))
  911. return TRUE;
  912. return FALSE;
  913. }
  914. //+-------------------------------------------------------------------------
  915. // Get the first dwValueType from the attribute's ordered list that is
  916. // an acceptable type for the input attribute character string.
  917. //
  918. // If no type is acceptable, update the *pdwErrLocation with the first
  919. // bad character position using the last type in the list.
  920. //--------------------------------------------------------------------------
  921. static DWORD GetUnicodeValueType(
  922. IN PCCRYPT_OID_INFO pX500Info,
  923. IN LPCWSTR pwszAttr,
  924. IN DWORD cchAttr,
  925. IN DWORD dwUnicodeFlags,
  926. OUT DWORD *pdwErrLocation
  927. )
  928. {
  929. DWORD dwValueType;
  930. const DWORD *pdwValueType;
  931. DWORD cValueType;
  932. DWORD dwErr = (DWORD) E_UNEXPECTED;
  933. DWORD i;
  934. pdwValueType = (DWORD *) pX500Info->ExtraInfo.pbData;
  935. cValueType = pX500Info->ExtraInfo.cbData / sizeof(DWORD);
  936. // Need at least two entries: a dwValueType and a 0 terminator. Otherwise,
  937. // use default value types.
  938. if (2 > cValueType || 0 == pdwValueType[0]) {
  939. pdwValueType = rgdwDefaultValueType;
  940. cValueType = sizeof(rgdwDefaultValueType) / sizeof(DWORD);
  941. }
  942. *pdwErrLocation = 0;
  943. for (i = 0; i < cValueType && 0 != (dwValueType = pdwValueType[i]); i++) {
  944. if (CERT_RDN_UNICODE_STRING == dwValueType) {
  945. if (dwUnicodeFlags & CERT_RDN_ENABLE_T61_UNICODE_FLAG) {
  946. DWORD j;
  947. BOOL fT61;
  948. fT61 = TRUE;
  949. for (j = 0; j < cchAttr; j++) {
  950. if (pwszAttr[j] > 0xFF) {
  951. fT61 = FALSE;
  952. break;
  953. }
  954. }
  955. if (fT61)
  956. return CERT_RDN_T61_STRING;
  957. }
  958. if (dwUnicodeFlags & CERT_RDN_ENABLE_UTF8_UNICODE_FLAG)
  959. return CERT_RDN_UTF8_STRING;
  960. else
  961. return CERT_RDN_UNICODE_STRING;
  962. }
  963. dwErr = CheckUnicodeValueType(
  964. dwValueType,
  965. pwszAttr,
  966. cchAttr,
  967. pdwErrLocation
  968. );
  969. if (0 == dwErr)
  970. return dwValueType;
  971. }
  972. assert(dwErr);
  973. SetLastError(dwErr);
  974. return 0;
  975. }
  976. //+-------------------------------------------------------------------------
  977. // Get an acceptable dwValueType associated with the OID for the input
  978. // attribute character string.
  979. //
  980. // If no type is acceptable, update the *pdwErrLocation with the indices
  981. // of the RDN, RDNAttribute, and character string.
  982. //--------------------------------------------------------------------------
  983. static DWORD GetUnicodeX500OIDValueType(
  984. IN LPCSTR pszObjId,
  985. IN LPCWSTR pwszAttr,
  986. IN DWORD cchAttr,
  987. IN DWORD dwRDNIndex,
  988. IN DWORD dwAttrIndex,
  989. IN DWORD dwUnicodeFlags,
  990. OUT DWORD *pdwErrLocation
  991. )
  992. {
  993. PCCRYPT_OID_INFO pX500Info;
  994. DWORD dwValueType;
  995. assert(pszObjId);
  996. if (NULL == pszObjId)
  997. pszObjId = "";
  998. // Attempt to find the OID in the table. If OID isn't found,
  999. // use default
  1000. if (NULL == (pX500Info = CryptFindOIDInfo(
  1001. CRYPT_OID_INFO_OID_KEY,
  1002. (void *) pszObjId,
  1003. CRYPT_RDN_ATTR_OID_GROUP_ID
  1004. )))
  1005. pX500Info = &DefaultX500Info;
  1006. if (0 == (dwValueType = GetUnicodeValueType(
  1007. pX500Info,
  1008. pwszAttr,
  1009. cchAttr,
  1010. dwUnicodeFlags,
  1011. pdwErrLocation
  1012. ))) {
  1013. // Include the dwRDNIndex and dwAttrIndex in the error location.
  1014. assert(dwRDNIndex <= CERT_UNICODE_RDN_ERR_INDEX_MASK);
  1015. assert(dwAttrIndex <= CERT_UNICODE_ATTR_ERR_INDEX_MASK);
  1016. *pdwErrLocation |=
  1017. ((dwRDNIndex & CERT_UNICODE_RDN_ERR_INDEX_MASK) <<
  1018. CERT_UNICODE_RDN_ERR_INDEX_SHIFT) |
  1019. ((dwAttrIndex & CERT_UNICODE_ATTR_ERR_INDEX_MASK) <<
  1020. CERT_UNICODE_ATTR_ERR_INDEX_SHIFT);
  1021. }
  1022. return dwValueType;
  1023. }
  1024. //+-------------------------------------------------------------------------
  1025. // Set/Free/Get CERT_RDN_ATTR. The values are unicode.
  1026. //--------------------------------------------------------------------------
  1027. static BOOL SetUnicodeRDNAttribute(
  1028. IN PCERT_RDN_ATTR pSrcRDNAttr,
  1029. IN DWORD dwRDNIndex,
  1030. IN DWORD dwAttrIndex,
  1031. IN DWORD dwFlags,
  1032. IN OUT PCERT_RDN_ATTR pDstRDNAttr,
  1033. OUT DWORD *pdwErrLocation
  1034. )
  1035. {
  1036. BOOL fResult;
  1037. DWORD dwValueType = pSrcRDNAttr->dwValueType;
  1038. PCERT_RDN_VALUE_BLOB pSrcValue;
  1039. LPCWSTR pwszAttr;
  1040. DWORD cchAttr;
  1041. DWORD dwErr;
  1042. DWORD dwUnicodeFlags;
  1043. BOOL fDisableCheckType;
  1044. dwUnicodeFlags = 0;
  1045. if ((dwFlags & CRYPT_UNICODE_NAME_ENCODE_ENABLE_T61_UNICODE_FLAG) ||
  1046. (dwValueType & CERT_RDN_ENABLE_T61_UNICODE_FLAG))
  1047. dwUnicodeFlags |= CERT_RDN_ENABLE_T61_UNICODE_FLAG;
  1048. if ((dwFlags & CRYPT_UNICODE_NAME_ENCODE_ENABLE_UTF8_UNICODE_FLAG) ||
  1049. (dwValueType & CERT_RDN_ENABLE_UTF8_UNICODE_FLAG))
  1050. dwUnicodeFlags |= CERT_RDN_ENABLE_UTF8_UNICODE_FLAG;
  1051. fDisableCheckType =
  1052. (0 != (dwFlags & CRYPT_UNICODE_NAME_ENCODE_DISABLE_CHECK_TYPE_FLAG) ||
  1053. 0 != (dwValueType & CERT_RDN_DISABLE_CHECK_TYPE_FLAG));
  1054. dwValueType &= CERT_RDN_TYPE_MASK;
  1055. *pdwErrLocation = 0;
  1056. if (CERT_RDN_ENCODED_BLOB == dwValueType ||
  1057. CERT_RDN_OCTET_STRING == dwValueType) {
  1058. // No unicode conversion on this type
  1059. memcpy(pDstRDNAttr, pSrcRDNAttr, sizeof(CERT_RDN_ATTR));
  1060. return TRUE;
  1061. }
  1062. pSrcValue = &pSrcRDNAttr->Value;
  1063. pwszAttr = pSrcValue->pbData ? (LPCWSTR) pSrcValue->pbData : L"";
  1064. cchAttr = (DWORD)( pSrcValue->cbData ?
  1065. pSrcValue->cbData / sizeof(WCHAR) : wcslen(pwszAttr) );
  1066. if (0 == dwValueType) {
  1067. if (0 == (dwValueType = GetUnicodeX500OIDValueType(
  1068. pSrcRDNAttr->pszObjId,
  1069. pwszAttr,
  1070. cchAttr,
  1071. dwRDNIndex,
  1072. dwAttrIndex,
  1073. dwUnicodeFlags,
  1074. pdwErrLocation
  1075. ))) goto GetValueTypeError;
  1076. } else if (!fDisableCheckType) {
  1077. if (0 != (dwErr = CheckUnicodeValueType(
  1078. dwValueType,
  1079. pwszAttr,
  1080. cchAttr,
  1081. pdwErrLocation
  1082. ))) {
  1083. // Include the dwRDNIndex and dwAttrIndex in the error location.
  1084. assert(dwRDNIndex <= CERT_UNICODE_RDN_ERR_INDEX_MASK);
  1085. assert(dwAttrIndex <= CERT_UNICODE_ATTR_ERR_INDEX_MASK);
  1086. *pdwErrLocation |=
  1087. ((dwRDNIndex & CERT_UNICODE_RDN_ERR_INDEX_MASK) <<
  1088. CERT_UNICODE_RDN_ERR_INDEX_SHIFT) |
  1089. ((dwAttrIndex & CERT_UNICODE_ATTR_ERR_INDEX_MASK) <<
  1090. CERT_UNICODE_ATTR_ERR_INDEX_SHIFT);
  1091. goto InvalidUnicodeValueType;
  1092. }
  1093. }
  1094. pDstRDNAttr->pszObjId = pSrcRDNAttr->pszObjId;
  1095. pDstRDNAttr->dwValueType = dwValueType;
  1096. if (!SetUnicodeRDNAttributeValue(
  1097. dwValueType,
  1098. pSrcValue,
  1099. TRUE, // fDisableCheckType
  1100. &pDstRDNAttr->Value,
  1101. NULL // OPTIONAL pdwErrLocation
  1102. )) goto SetUnicodeRDNAttributeValueError;
  1103. fResult = TRUE;
  1104. CommonReturn:
  1105. return fResult;
  1106. ErrorReturn:
  1107. fResult = FALSE;
  1108. goto CommonReturn;
  1109. TRACE_ERROR(GetValueTypeError)
  1110. SET_ERROR_VAR(InvalidUnicodeValueType, dwErr)
  1111. TRACE_ERROR(SetUnicodeRDNAttributeValueError)
  1112. }
  1113. static void FreeUnicodeRDNAttribute(
  1114. IN OUT PCERT_RDN_ATTR pRDNAttr
  1115. )
  1116. {
  1117. FreeUnicodeRDNAttributeValue(pRDNAttr->dwValueType, &pRDNAttr->Value);
  1118. }
  1119. static BOOL GetUnicodeRDNAttribute(
  1120. IN PCERT_RDN_ATTR pSrcRDNAttr,
  1121. IN DWORD dwFlags,
  1122. OUT PCERT_RDN_ATTR pDstRDNAttr,
  1123. IN OUT BYTE **ppbExtra,
  1124. IN OUT LONG *plRemainExtra
  1125. )
  1126. {
  1127. LONG lAlignExtra;
  1128. DWORD cbObjId;
  1129. DWORD dwValueType;
  1130. PCERT_RDN_VALUE_BLOB pDstValue;
  1131. // Get Object Identifier length
  1132. if (pSrcRDNAttr->pszObjId)
  1133. cbObjId = strlen(pSrcRDNAttr->pszObjId) + 1;
  1134. else
  1135. cbObjId = 0;
  1136. dwValueType = pSrcRDNAttr->dwValueType;
  1137. lAlignExtra = INFO_LEN_ALIGN(cbObjId);
  1138. *plRemainExtra -= lAlignExtra;
  1139. if (*plRemainExtra >= 0) {
  1140. if(cbObjId) {
  1141. pDstRDNAttr->pszObjId = (LPSTR) *ppbExtra;
  1142. memcpy(*ppbExtra, pSrcRDNAttr->pszObjId, cbObjId);
  1143. } else
  1144. pDstRDNAttr->pszObjId = NULL;
  1145. *ppbExtra += lAlignExtra;
  1146. pDstRDNAttr->dwValueType = dwValueType;
  1147. pDstValue = &pDstRDNAttr->Value;
  1148. } else
  1149. pDstValue = NULL;
  1150. return GetUnicodeRDNAttributeValue(
  1151. dwValueType,
  1152. &pSrcRDNAttr->Value,
  1153. dwFlags,
  1154. pDstValue,
  1155. ppbExtra,
  1156. plRemainExtra
  1157. );
  1158. }
  1159. //+-------------------------------------------------------------------------
  1160. // Decode the "UNICODE" Name Info
  1161. //--------------------------------------------------------------------------
  1162. BOOL WINAPI UnicodeNameInfoDecodeExCallback(
  1163. IN void *pvDecodeInfo,
  1164. IN DWORD dwFlags,
  1165. IN OPTIONAL PCRYPT_DECODE_PARA pDecodePara,
  1166. OUT OPTIONAL void *pvStructInfo,
  1167. IN OUT LONG *plRemainExtra
  1168. )
  1169. {
  1170. BOOL fResult;
  1171. PCERT_NAME_INFO pNameInfo = (PCERT_NAME_INFO) pvDecodeInfo;
  1172. PCERT_NAME_INFO pInfo = (PCERT_NAME_INFO) pvStructInfo;
  1173. BYTE *pbExtra;
  1174. LONG lRemainExtra = *plRemainExtra;
  1175. LONG lAlignExtra;
  1176. DWORD cRDN, cAttr;
  1177. PCERT_RDN pSrcRDN, pDstRDN;
  1178. PCERT_RDN_ATTR pSrcAttr, pDstAttr;
  1179. // for lRemainExtra < 0, LENGTH_ONLY calculation
  1180. lRemainExtra -= sizeof(CERT_NAME_INFO);
  1181. if (lRemainExtra < 0)
  1182. pbExtra = NULL;
  1183. else
  1184. pbExtra = (BYTE *) pInfo + sizeof(CERT_NAME_INFO);
  1185. cRDN = pNameInfo->cRDN;
  1186. pSrcRDN = pNameInfo->rgRDN;
  1187. lAlignExtra = INFO_LEN_ALIGN(cRDN * sizeof(CERT_RDN));
  1188. lRemainExtra -= lAlignExtra;
  1189. if (lRemainExtra >= 0) {
  1190. pInfo->cRDN = cRDN;
  1191. pDstRDN = (PCERT_RDN) pbExtra;
  1192. pInfo->rgRDN = pDstRDN;
  1193. pbExtra += lAlignExtra;
  1194. } else
  1195. pDstRDN = NULL;
  1196. // Array of RDNs
  1197. for (; cRDN > 0; cRDN--, pSrcRDN++, pDstRDN++) {
  1198. cAttr = pSrcRDN->cRDNAttr;
  1199. pSrcAttr = pSrcRDN->rgRDNAttr;
  1200. lAlignExtra = INFO_LEN_ALIGN(cAttr * sizeof(CERT_RDN_ATTR));
  1201. lRemainExtra -= lAlignExtra;
  1202. if (lRemainExtra >= 0) {
  1203. pDstRDN->cRDNAttr = cAttr;
  1204. pDstAttr = (PCERT_RDN_ATTR) pbExtra;
  1205. pDstRDN->rgRDNAttr = pDstAttr;
  1206. pbExtra += lAlignExtra;
  1207. } else
  1208. pDstAttr = NULL;
  1209. // Array of attribute/values
  1210. for (; cAttr > 0; cAttr--, pSrcAttr++, pDstAttr++)
  1211. // We're now ready to get the attribute/value stuff
  1212. if (!GetUnicodeRDNAttribute(pSrcAttr, dwFlags,
  1213. pDstAttr, &pbExtra, &lRemainExtra))
  1214. goto DecodeError;
  1215. }
  1216. fResult = TRUE;
  1217. CommonReturn:
  1218. *plRemainExtra = lRemainExtra;
  1219. return fResult;
  1220. ErrorReturn:
  1221. fResult = FALSE;
  1222. goto CommonReturn;
  1223. TRACE_ERROR(DecodeError)
  1224. }
  1225. BOOL WINAPI UnicodeNameInfoDecodeEx(
  1226. IN DWORD dwCertEncodingType,
  1227. IN LPCSTR lpszStructType,
  1228. IN const BYTE *pbEncoded,
  1229. IN DWORD cbEncoded,
  1230. IN DWORD dwFlags,
  1231. IN OPTIONAL PCRYPT_DECODE_PARA pDecodePara,
  1232. OUT OPTIONAL void *pvStructInfo,
  1233. IN OUT DWORD *pcbStructInfo
  1234. )
  1235. {
  1236. return NestedDecodeAndAllocInfoEx(
  1237. dwCertEncodingType,
  1238. X509_NAME,
  1239. pbEncoded,
  1240. cbEncoded,
  1241. dwFlags,
  1242. pDecodePara,
  1243. UnicodeNameInfoDecodeExCallback,
  1244. pvStructInfo,
  1245. pcbStructInfo
  1246. );
  1247. }
  1248. //+-------------------------------------------------------------------------
  1249. // Encode the "UNICODE" Name Info
  1250. //--------------------------------------------------------------------------
  1251. static void FreeUnicodeNameInfo(
  1252. PCERT_NAME_INFO pInfo
  1253. )
  1254. {
  1255. PCERT_RDN pRDN = pInfo->rgRDN;
  1256. if (pRDN) {
  1257. DWORD cRDN = pInfo->cRDN;
  1258. for ( ; cRDN > 0; cRDN--, pRDN++) {
  1259. PCERT_RDN_ATTR pAttr = pRDN->rgRDNAttr;
  1260. if (pAttr) {
  1261. DWORD cAttr = pRDN->cRDNAttr;
  1262. for ( ; cAttr > 0; cAttr--, pAttr++)
  1263. FreeUnicodeRDNAttribute(pAttr);
  1264. PkiFree(pRDN->rgRDNAttr);
  1265. }
  1266. }
  1267. PkiFree(pInfo->rgRDN);
  1268. }
  1269. }
  1270. static BOOL SetUnicodeNameInfo(
  1271. IN PCERT_NAME_INFO pSrcInfo,
  1272. IN DWORD dwFlags,
  1273. OUT PCERT_NAME_INFO pDstInfo,
  1274. OUT DWORD *pdwErrLocation
  1275. )
  1276. {
  1277. BOOL fResult;
  1278. DWORD cRDN, cAttr;
  1279. DWORD i, j;
  1280. PCERT_RDN pSrcRDN;
  1281. PCERT_RDN_ATTR pSrcAttr;
  1282. PCERT_RDN pDstRDN = NULL;
  1283. PCERT_RDN_ATTR pDstAttr = NULL;
  1284. *pdwErrLocation = 0;
  1285. cRDN = pSrcInfo->cRDN;
  1286. pSrcRDN = pSrcInfo->rgRDN;
  1287. pDstInfo->cRDN = cRDN;
  1288. pDstInfo->rgRDN = NULL;
  1289. if (cRDN > 0) {
  1290. if (NULL == (pDstRDN = (PCERT_RDN) PkiZeroAlloc(
  1291. cRDN * sizeof(CERT_RDN))))
  1292. goto OutOfMemory;
  1293. pDstInfo->rgRDN = pDstRDN;
  1294. }
  1295. // Array of RDNs
  1296. for (i = 0; i < cRDN; i++, pSrcRDN++, pDstRDN++) {
  1297. cAttr = pSrcRDN->cRDNAttr;
  1298. pSrcAttr = pSrcRDN->rgRDNAttr;
  1299. pDstRDN->cRDNAttr = cAttr;
  1300. if (cAttr > 0) {
  1301. if (NULL == (pDstAttr = (PCERT_RDN_ATTR) PkiZeroAlloc(cAttr *
  1302. sizeof(CERT_RDN_ATTR))))
  1303. goto OutOfMemory;
  1304. pDstRDN->rgRDNAttr = pDstAttr;
  1305. }
  1306. // Array of attribute/values
  1307. for (j = 0; j < cAttr; j++, pSrcAttr++, pDstAttr++) {
  1308. // We're now ready to convert the unicode string
  1309. if (!SetUnicodeRDNAttribute(pSrcAttr, i, j, dwFlags, pDstAttr,
  1310. pdwErrLocation))
  1311. goto SetUnicodeRDNAttributeError;
  1312. }
  1313. }
  1314. fResult = TRUE;
  1315. CommonReturn:
  1316. return fResult;
  1317. ErrorReturn:
  1318. fResult = FALSE;
  1319. goto CommonReturn;
  1320. TRACE_ERROR(OutOfMemory)
  1321. TRACE_ERROR(SetUnicodeRDNAttributeError)
  1322. }
  1323. BOOL WINAPI UnicodeNameInfoEncodeEx(
  1324. IN DWORD dwCertEncodingType,
  1325. IN LPCSTR lpszStructType,
  1326. IN PCERT_NAME_INFO pInfo,
  1327. IN DWORD dwFlags,
  1328. IN OPTIONAL PCRYPT_ENCODE_PARA pEncodePara,
  1329. OUT OPTIONAL void *pvEncoded,
  1330. IN OUT DWORD *pcbEncoded
  1331. )
  1332. {
  1333. BOOL fResult;
  1334. CERT_NAME_INFO DstInfo;
  1335. DWORD dwErrLocation;
  1336. if (!SetUnicodeNameInfo(pInfo, dwFlags, &DstInfo, &dwErrLocation)) {
  1337. if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
  1338. *((void **) pvEncoded) = NULL;
  1339. *pcbEncoded = dwErrLocation;
  1340. fResult = FALSE;
  1341. goto CommonReturn;
  1342. }
  1343. fResult = CryptEncodeObjectEx(
  1344. dwCertEncodingType,
  1345. X509_NAME,
  1346. &DstInfo,
  1347. dwFlags,
  1348. pEncodePara,
  1349. pvEncoded,
  1350. pcbEncoded
  1351. );
  1352. CommonReturn:
  1353. FreeUnicodeNameInfo(&DstInfo);
  1354. return fResult;
  1355. }
  1356. static BOOL WINAPI UnicodeNameInfoEncode(
  1357. IN DWORD dwCertEncodingType,
  1358. IN LPCSTR lpszStructType,
  1359. IN PCERT_NAME_INFO pInfo,
  1360. OUT OPTIONAL BYTE *pbEncoded,
  1361. IN OUT DWORD *pcbEncoded
  1362. )
  1363. {
  1364. BOOL fResult;
  1365. CERT_NAME_INFO DstInfo;
  1366. DWORD dwErrLocation;
  1367. if (!SetUnicodeNameInfo(pInfo, 0, &DstInfo, &dwErrLocation)) {
  1368. *pcbEncoded = dwErrLocation;
  1369. fResult = FALSE;
  1370. goto CommonReturn;
  1371. }
  1372. fResult = CryptEncodeObject(
  1373. dwCertEncodingType,
  1374. X509_NAME,
  1375. &DstInfo,
  1376. pbEncoded,
  1377. pcbEncoded
  1378. );
  1379. CommonReturn:
  1380. FreeUnicodeNameInfo(&DstInfo);
  1381. return fResult;
  1382. }
  1383. static void PutStrW(LPCWSTR pwszPut, LPWSTR *ppwsz, DWORD *pcwsz,
  1384. DWORD *pcwszOut, BOOL fQuote = FALSE)
  1385. {
  1386. WCHAR wc;
  1387. while (wc = *pwszPut++) {
  1388. if (L'\"' == wc && fQuote)
  1389. PutStrW(L"\"", ppwsz, pcwsz, pcwszOut, FALSE);
  1390. if (*pcwsz != 1) {
  1391. if (*pcwsz) {
  1392. **ppwsz = wc;
  1393. *ppwsz += 1;
  1394. *pcwsz -= 1;
  1395. }
  1396. *pcwszOut += 1;
  1397. }
  1398. // else
  1399. // Always reserve space for the NULL terminator.
  1400. }
  1401. }
  1402. static void PutOIDStrW(
  1403. IN DWORD dwStrType,
  1404. IN LPCSTR pszObjId,
  1405. IN OUT LPWSTR *ppwsz,
  1406. IN OUT DWORD *pcwsz,
  1407. IN OUT DWORD *pcwszOut
  1408. )
  1409. {
  1410. // Eliminate the upper flags before switching
  1411. switch (dwStrType & 0xFFFF) {
  1412. case CERT_X500_NAME_STR:
  1413. {
  1414. PCCRYPT_OID_INFO pX500Info;
  1415. if (pX500Info = CryptFindOIDInfo(
  1416. CRYPT_OID_INFO_OID_KEY,
  1417. (void *) pszObjId,
  1418. CRYPT_RDN_ATTR_OID_GROUP_ID
  1419. )) {
  1420. if (*pX500Info->pwszName) {
  1421. PutStrW(pX500Info->pwszName, ppwsz, pcwsz,
  1422. pcwszOut);
  1423. PutStrW(L"=", ppwsz, pcwsz, pcwszOut);
  1424. return;
  1425. }
  1426. }
  1427. PutStrW(L"OID.", ppwsz, pcwsz, pcwszOut);
  1428. }
  1429. // Fall through
  1430. case CERT_OID_NAME_STR:
  1431. {
  1432. int cchWideChar;
  1433. cchWideChar = MultiByteToWideChar(
  1434. CP_ACP,
  1435. 0, // dwFlags
  1436. pszObjId,
  1437. -1, // null terminated
  1438. *ppwsz,
  1439. *pcwsz) - 1;
  1440. if (cchWideChar > 0) {
  1441. if (*pcwsz) {
  1442. assert(*pcwsz > (DWORD)cchWideChar);
  1443. *pcwsz -= cchWideChar;
  1444. *ppwsz += cchWideChar;
  1445. }
  1446. *pcwszOut += cchWideChar;
  1447. }
  1448. PutStrW(L"=", ppwsz, pcwsz, pcwszOut);
  1449. }
  1450. break;
  1451. case CERT_SIMPLE_NAME_STR:
  1452. default:
  1453. break;
  1454. }
  1455. }
  1456. static void PutHexW(
  1457. IN PCERT_RDN_VALUE_BLOB pValue,
  1458. IN OUT LPWSTR *ppwsz,
  1459. IN OUT DWORD *pcwsz,
  1460. IN OUT DWORD *pcwszOut
  1461. )
  1462. {
  1463. WCHAR wszHex[3];
  1464. BYTE *pb = pValue->pbData;
  1465. DWORD cb = pValue->cbData;
  1466. PutStrW(L"#", ppwsz, pcwsz, pcwszOut);
  1467. wszHex[2] = L'\0';
  1468. for ( ; cb > 0; cb--, pb++) {
  1469. int b;
  1470. b = (*pb >> 4) & 0x0F;
  1471. wszHex[0] = (WCHAR)( (b <= 9) ? b + L'0' : (b - 10) + L'A');
  1472. b = *pb & 0x0F;
  1473. wszHex[1] = (WCHAR)( (b <= 9) ? b + L'0' : (b - 10) + L'A');
  1474. PutStrW(wszHex, ppwsz, pcwsz, pcwszOut);
  1475. }
  1476. }
  1477. static void ReverseNameInfo(
  1478. IN PCERT_NAME_INFO pInfo
  1479. )
  1480. {
  1481. DWORD cRDN;
  1482. PCERT_RDN pLo;
  1483. PCERT_RDN pHi;
  1484. CERT_RDN Tmp;
  1485. cRDN = pInfo->cRDN;
  1486. if (0 == cRDN)
  1487. return;
  1488. pLo = pInfo->rgRDN;
  1489. pHi = pInfo->rgRDN + cRDN - 1;
  1490. for ( ; pLo < pHi; pHi--, pLo++) {
  1491. Tmp = *pHi;
  1492. *pHi = *pLo;
  1493. *pLo = Tmp;
  1494. }
  1495. }
  1496. //+-------------------------------------------------------------------------
  1497. // Convert the decoded certificate name info to a null terminated WCHAR
  1498. // string.
  1499. //
  1500. // Note, if CERT_NAME_STR_REVERSE_FLAG is set, reverses the decoded
  1501. // name info RDNs
  1502. //--------------------------------------------------------------------------
  1503. static DWORD WINAPI CertNameInfoToStrW(
  1504. IN DWORD dwCertEncodingType,
  1505. IN PCERT_NAME_INFO pInfo,
  1506. IN DWORD dwStrType,
  1507. OUT OPTIONAL LPWSTR pwsz,
  1508. IN DWORD cwsz
  1509. )
  1510. {
  1511. DWORD cwszOut = 0;
  1512. LPCWSTR pwszRDNSeparator;
  1513. LPCWSTR pwszMultiValueSeparator;
  1514. BOOL fEnableQuoting;
  1515. if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
  1516. pwszRDNSeparator = L"; ";
  1517. else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
  1518. pwszRDNSeparator = L"\r\n";
  1519. else
  1520. pwszRDNSeparator = L", ";
  1521. if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
  1522. pwszMultiValueSeparator = L" ";
  1523. else
  1524. pwszMultiValueSeparator = L" + ";
  1525. if (dwStrType & CERT_NAME_STR_NO_QUOTING_FLAG)
  1526. fEnableQuoting = FALSE;
  1527. else
  1528. fEnableQuoting = TRUE;
  1529. if (pwsz == NULL)
  1530. cwsz = 0;
  1531. if (pInfo) {
  1532. DWORD cRDN;
  1533. PCERT_RDN pRDN;
  1534. if (dwStrType & CERT_NAME_STR_REVERSE_FLAG)
  1535. ReverseNameInfo(pInfo);
  1536. cRDN = pInfo->cRDN;
  1537. pRDN = pInfo->rgRDN;
  1538. if (0 == cRDN)
  1539. SetLastError((DWORD) CRYPT_E_NOT_FOUND);
  1540. for ( ; cRDN > 0; cRDN--, pRDN++) {
  1541. DWORD cAttr = pRDN->cRDNAttr;
  1542. PCERT_RDN_ATTR pAttr = pRDN->rgRDNAttr;
  1543. for ( ; cAttr > 0; cAttr--, pAttr++) {
  1544. BOOL fQuote;
  1545. PutOIDStrW(dwStrType, pAttr->pszObjId, &pwsz, &cwsz, &cwszOut);
  1546. if (CERT_RDN_ENCODED_BLOB == pAttr->dwValueType ||
  1547. CERT_RDN_OCTET_STRING == pAttr->dwValueType)
  1548. PutHexW(&pAttr->Value, &pwsz, &cwsz, &cwszOut);
  1549. else {
  1550. fQuote = fEnableQuoting && IsQuotedUnicodeRDNValue(
  1551. &pAttr->Value);
  1552. if (fQuote)
  1553. PutStrW(L"\"", &pwsz, &cwsz, &cwszOut);
  1554. PutStrW((LPCWSTR) pAttr->Value.pbData, &pwsz, &cwsz,
  1555. &cwszOut, fQuote);
  1556. if (fQuote)
  1557. PutStrW(L"\"", &pwsz, &cwsz, &cwszOut);
  1558. }
  1559. if (cAttr > 1)
  1560. PutStrW(pwszMultiValueSeparator, &pwsz, &cwsz, &cwszOut);
  1561. }
  1562. if (cRDN > 1)
  1563. PutStrW(pwszRDNSeparator, &pwsz, &cwsz, &cwszOut);
  1564. }
  1565. }
  1566. if (cwsz != 0) {
  1567. // Always NULL terminate
  1568. *pwsz = L'\0';
  1569. }
  1570. return cwszOut + 1;
  1571. }
  1572. //+-------------------------------------------------------------------------
  1573. // Convert the certificate name blob to a null terminated WCHAR string.
  1574. //--------------------------------------------------------------------------
  1575. DWORD
  1576. WINAPI
  1577. CertNameToStrW(
  1578. IN DWORD dwCertEncodingType,
  1579. IN PCERT_NAME_BLOB pName,
  1580. IN DWORD dwStrType,
  1581. OUT OPTIONAL LPWSTR pwsz,
  1582. IN DWORD cwsz
  1583. )
  1584. {
  1585. DWORD cwszOut;
  1586. PCERT_NAME_INFO pInfo;
  1587. pInfo = (PCERT_NAME_INFO) AllocAndDecodeObject(
  1588. dwCertEncodingType,
  1589. X509_UNICODE_NAME,
  1590. pName->pbData,
  1591. pName->cbData,
  1592. (dwStrType & CERT_NAME_STR_DISABLE_IE4_UTF8_FLAG) ?
  1593. CRYPT_UNICODE_NAME_DECODE_DISABLE_IE4_UTF8_FLAG : 0
  1594. );
  1595. // Note, decoded name info RDNs may be reversed
  1596. cwszOut = CertNameInfoToStrW(
  1597. dwCertEncodingType,
  1598. pInfo,
  1599. dwStrType,
  1600. pwsz,
  1601. cwsz
  1602. );
  1603. PkiFree(pInfo);
  1604. return cwszOut;
  1605. }
  1606. //+-------------------------------------------------------------------------
  1607. // Convert the Unicode string to Ascii
  1608. //--------------------------------------------------------------------------
  1609. static DWORD ConvertUnicodeStringToAscii(
  1610. IN LPWSTR pwsz,
  1611. IN DWORD cwsz,
  1612. OUT OPTIONAL LPSTR psz,
  1613. IN DWORD csz
  1614. )
  1615. {
  1616. DWORD cszOut = 0;
  1617. if (psz == NULL)
  1618. csz = 0;
  1619. if (pwsz) {
  1620. int cchMultiByte;
  1621. cchMultiByte = WideCharToMultiByte(
  1622. CP_ACP,
  1623. 0, // dwFlags
  1624. pwsz,
  1625. -1, // Null terminated
  1626. psz,
  1627. (int) csz,
  1628. NULL, // lpDefaultChar
  1629. NULL // lpfUsedDefaultChar
  1630. );
  1631. if (cchMultiByte < 1)
  1632. cszOut = 0;
  1633. else
  1634. // Subtract off the trailing null terminator
  1635. cszOut = (DWORD) cchMultiByte - 1;
  1636. }
  1637. if (csz != 0) {
  1638. // Always NULL terminate
  1639. *(psz + cszOut) = '\0';
  1640. }
  1641. return cszOut + 1;
  1642. }
  1643. //+-------------------------------------------------------------------------
  1644. // Convert the certificate name blob to a null terminated char string.
  1645. //--------------------------------------------------------------------------
  1646. DWORD
  1647. WINAPI
  1648. CertNameToStrA(
  1649. IN DWORD dwCertEncodingType,
  1650. IN PCERT_NAME_BLOB pName,
  1651. IN DWORD dwStrType,
  1652. OUT OPTIONAL LPSTR psz,
  1653. IN DWORD csz
  1654. )
  1655. {
  1656. DWORD cszOut;
  1657. LPWSTR pwsz = NULL;
  1658. DWORD cwsz;
  1659. cwsz = CertNameToStrW(
  1660. dwCertEncodingType,
  1661. pName,
  1662. dwStrType,
  1663. NULL, // pwsz
  1664. 0 // cwsz
  1665. );
  1666. if (pwsz = (LPWSTR) PkiNonzeroAlloc(cwsz * sizeof(WCHAR)))
  1667. CertNameToStrW(
  1668. dwCertEncodingType,
  1669. pName,
  1670. dwStrType,
  1671. pwsz,
  1672. cwsz
  1673. );
  1674. cszOut = ConvertUnicodeStringToAscii(pwsz, cwsz, psz, csz);
  1675. PkiFree(pwsz);
  1676. return cszOut;
  1677. }
  1678. //+-------------------------------------------------------------------------
  1679. // Map the attribute key (for example "CN") to its Object Identifier
  1680. // (for example, "2.5.4.3").
  1681. //
  1682. // The input pwcKey isn't NULL terminated. cchKey > 0.
  1683. //
  1684. // Returns NULL if unable to find a matching attribute key.
  1685. //--------------------------------------------------------------------------
  1686. static LPCSTR X500KeyToOID(IN LPCWSTR pwcKey, IN DWORD cchKey)
  1687. {
  1688. PCCRYPT_OID_INFO pX500Info;
  1689. WCHAR wszKey[MAX_X500_KEY_LEN + 1];
  1690. if (cchKey > MAX_X500_KEY_LEN)
  1691. return NULL;
  1692. assert(cchKey > 0);
  1693. // Null terminate the input Key
  1694. memcpy(wszKey, pwcKey, cchKey * sizeof(WCHAR));
  1695. wszKey[cchKey] = L'\0';
  1696. if (pX500Info = CryptFindOIDInfo(
  1697. CRYPT_OID_INFO_NAME_KEY,
  1698. wszKey,
  1699. CRYPT_RDN_ATTR_OID_GROUP_ID
  1700. )) {
  1701. if (*pX500Info->pszOID)
  1702. return pX500Info->pszOID;
  1703. }
  1704. return NULL;
  1705. }
  1706. //+-------------------------------------------------------------------------
  1707. // Checks if a digit
  1708. //--------------------------------------------------------------------------
  1709. static inline BOOL IsDigitA(char c)
  1710. {
  1711. return c >= '0' && c <= '9';
  1712. }
  1713. #define X500_OID_PREFIX_A "OID."
  1714. #define X500_OID_PREFIX_LEN strlen(X500_OID_PREFIX_A)
  1715. #define NO_LOCALE MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
  1716. //+-------------------------------------------------------------------------
  1717. // Check for the case insensitive leading "OID." If present, skip past
  1718. // it. Check that the remaining string contains only digits or a dot (".").
  1719. // Also, don't allow consecutive dots.
  1720. //
  1721. // Returns NULL for an invalid OID.
  1722. //--------------------------------------------------------------------------
  1723. static LPCSTR GetX500OID(IN LPCSTR pszObjId)
  1724. {
  1725. LPCSTR psz;
  1726. char c;
  1727. BOOL fDot;
  1728. if (strlen(pszObjId) > X500_OID_PREFIX_LEN &&
  1729. 2 == CompareStringA(NO_LOCALE, NORM_IGNORECASE,
  1730. X500_OID_PREFIX_A, X500_OID_PREFIX_LEN,
  1731. pszObjId, X500_OID_PREFIX_LEN))
  1732. pszObjId += X500_OID_PREFIX_LEN;
  1733. // Verify the OID to have only digits and dots
  1734. psz = pszObjId;
  1735. fDot = FALSE;
  1736. while (c = *psz++) {
  1737. if (c == '.') {
  1738. if (fDot)
  1739. return NULL;
  1740. fDot = TRUE;
  1741. } else {
  1742. if (!IsDigitA(c))
  1743. return NULL;
  1744. fDot = FALSE;
  1745. }
  1746. }
  1747. return pszObjId;
  1748. }
  1749. //+-------------------------------------------------------------------------
  1750. // Convert the the hex string, for example, #AB01, to binary.
  1751. //
  1752. // The input string is assumed to have the leading #. Ignores embedded
  1753. // whitespace.
  1754. //
  1755. // The returned binary is allocated in pValue->pbData.
  1756. //--------------------------------------------------------------------------
  1757. static BOOL GetAndAllocHexW(
  1758. IN LPCWSTR pwszToken,
  1759. IN DWORD cchToken,
  1760. OUT PCERT_RDN_VALUE_BLOB pValue
  1761. )
  1762. {
  1763. BOOL fResult;
  1764. BYTE *pb;
  1765. DWORD cb;
  1766. BOOL fUpperNibble;
  1767. pValue->pbData = NULL;
  1768. pValue->cbData = 0;
  1769. // Advance past #
  1770. cchToken--;
  1771. pwszToken++;
  1772. if (0 == cchToken)
  1773. goto NoHex;
  1774. if (NULL == (pb = (BYTE *) PkiNonzeroAlloc(cchToken / 2 + 1)))
  1775. goto OutOfMemory;
  1776. pValue->pbData = pb;
  1777. fUpperNibble = TRUE;
  1778. cb = 0;
  1779. while (cchToken--) {
  1780. BYTE b;
  1781. WCHAR wc = *pwszToken++;
  1782. // only convert ascii hex characters 0..9, a..f, A..F
  1783. // ignore whitespace
  1784. if (wc >= L'0' && wc <= L'9')
  1785. b = (BYTE) (wc - L'0');
  1786. else if (wc >= L'a' && wc <= L'f')
  1787. b = (BYTE) (10 + wc - L'a');
  1788. else if (wc >= L'A' && wc <= L'F')
  1789. b = (BYTE) (10 + wc - L'A');
  1790. else if (IsSpaceW(wc))
  1791. continue;
  1792. else
  1793. goto InvalidHex;
  1794. if (fUpperNibble) {
  1795. *pb = (BYTE)( b << 4 );
  1796. cb++;
  1797. fUpperNibble = FALSE;
  1798. } else {
  1799. *pb = (BYTE)( *pb | b);
  1800. pb++;
  1801. fUpperNibble = TRUE;
  1802. }
  1803. }
  1804. if (cb == 0) {
  1805. PkiFree(pValue->pbData);
  1806. pValue->pbData = NULL;
  1807. }
  1808. pValue->cbData = cb;
  1809. fResult = TRUE;
  1810. CommonReturn:
  1811. return fResult;
  1812. ErrorReturn:
  1813. fResult = FALSE;
  1814. PkiFree(pValue->pbData);
  1815. pValue->pbData = NULL;
  1816. goto CommonReturn;
  1817. TRACE_ERROR(OutOfMemory)
  1818. SET_ERROR(NoHex, CRYPT_E_INVALID_X500_STRING)
  1819. SET_ERROR(InvalidHex, CRYPT_E_INVALID_X500_STRING)
  1820. }
  1821. #define X500_QUOTED_FLAG 0x1
  1822. #define X500_EMBEDDED_QUOTE_FLAG 0x2
  1823. //+-------------------------------------------------------------------------
  1824. // Get the next key or value token.
  1825. //
  1826. // Handles quoted tokens.
  1827. //
  1828. // Upon return *ppwsz points at the delimiter or error location
  1829. //--------------------------------------------------------------------------
  1830. static BOOL GetX500Token(
  1831. IN OUT LPCWSTR *ppwsz,
  1832. IN LPCWSTR pwszDelimiter,
  1833. IN BOOL fEnableQuoting,
  1834. OUT LPCWSTR *ppwszToken,
  1835. OUT DWORD *pcchToken,
  1836. OUT DWORD *pdwFlags
  1837. )
  1838. {
  1839. BOOL fResult;
  1840. LPCWSTR pwsz = *ppwsz;
  1841. LPCWSTR pwszStart = NULL;
  1842. LPCWSTR pwszEnd = NULL;
  1843. DWORD dwQuote = 0; // 1 - after leading ", 2 - after trailing "
  1844. *pdwFlags = 0;
  1845. while (TRUE) {
  1846. WCHAR wc = *pwsz;
  1847. if (0 == dwQuote) {
  1848. // No quotes so far. Or quoting not enabled.
  1849. if (fEnableQuoting && L'\"' == wc) {
  1850. if (NULL == pwszStart) {
  1851. pwszStart = pwsz + 1;
  1852. dwQuote = 1;
  1853. *pdwFlags |= X500_QUOTED_FLAG;
  1854. } else
  1855. // Quote after non whitespace
  1856. goto ErrorReturn;
  1857. } else {
  1858. if (L'\0' == wc || IsInStrW(pwszDelimiter, wc)) {
  1859. // Hit a delimiter (including the null terminator)
  1860. if (pwszStart)
  1861. *pcchToken = (DWORD)(pwszEnd - pwszStart) + 1;
  1862. else
  1863. *pcchToken = 0;
  1864. break;
  1865. }
  1866. if (!IsSpaceW(wc)) {
  1867. pwszEnd = pwsz;
  1868. if (NULL == pwszStart)
  1869. pwszStart = pwsz;
  1870. }
  1871. }
  1872. } else if (1 == dwQuote) {
  1873. // After first quote
  1874. if (L'\0' == wc) {
  1875. // Point to first quote
  1876. pwsz = pwszStart - 1;
  1877. goto ErrorReturn;
  1878. } else if (L'\"' == wc) {
  1879. if (L'\"' == *(pwsz + 1)) {
  1880. *pdwFlags |= X500_EMBEDDED_QUOTE_FLAG;
  1881. // Skip double quote
  1882. pwsz++;
  1883. } else {
  1884. *pcchToken = (DWORD)(pwsz - pwszStart);
  1885. dwQuote++;
  1886. }
  1887. }
  1888. } else {
  1889. // After second quote
  1890. if (L'\0' == wc || IsInStrW(pwszDelimiter, wc))
  1891. break;
  1892. else if (!IsSpaceW(wc))
  1893. goto ErrorReturn;
  1894. }
  1895. pwsz++;
  1896. }
  1897. fResult = TRUE;
  1898. CommonReturn:
  1899. *ppwszToken = pwszStart;
  1900. *ppwsz = pwsz;
  1901. return fResult;
  1902. ErrorReturn:
  1903. pwszStart = NULL;
  1904. *pcchToken = 0;
  1905. fResult = FALSE;
  1906. goto CommonReturn;
  1907. }
  1908. //+-------------------------------------------------------------------------
  1909. // Convert the null terminated X500 WCHAR string to an encoded
  1910. // certificate name.
  1911. //--------------------------------------------------------------------------
  1912. BOOL
  1913. WINAPI
  1914. CertStrToNameW(
  1915. IN DWORD dwCertEncodingType,
  1916. IN LPCWSTR pwszX500,
  1917. IN DWORD dwStrType,
  1918. IN OPTIONAL void *pvReserved,
  1919. OUT BYTE *pbEncoded,
  1920. IN OUT DWORD *pcbEncoded,
  1921. OUT OPTIONAL LPCWSTR *ppwszError
  1922. )
  1923. {
  1924. typedef struct _X500_ATTR_AUX {
  1925. LPSTR pszAllocObjId;
  1926. LPCWSTR pwszValue;
  1927. BYTE *pbAllocValue;
  1928. BOOL fNewRDN;
  1929. } X500_ATTR_AUX, *PX500_ATTR_AUX;
  1930. #define X500_ATTR_ALLOC_COUNT 20
  1931. BOOL fResult;
  1932. CERT_NAME_INFO NameInfo;
  1933. PCERT_RDN pRDN = NULL;
  1934. PCERT_RDN_ATTR pAttr = NULL;
  1935. PX500_ATTR_AUX pAux = NULL;
  1936. DWORD cRDN = 0;
  1937. DWORD cAttr = 0;
  1938. DWORD iRDN;
  1939. DWORD iAttr;
  1940. DWORD cAllocAttr;
  1941. BOOL fNewRDN;
  1942. DWORD dwValueType;
  1943. WCHAR wszSeparators[8];
  1944. BOOL fEnableQuoting;
  1945. LPCWSTR pwszError = NULL;
  1946. LPCWSTR pwszStartX500 = pwszX500;
  1947. dwValueType = 0;
  1948. if (dwStrType & CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG)
  1949. dwValueType |= CERT_RDN_ENABLE_T61_UNICODE_FLAG;
  1950. if (dwStrType & CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG)
  1951. dwValueType |= CERT_RDN_ENABLE_UTF8_UNICODE_FLAG;
  1952. // Check for an empty Name.
  1953. if (NULL == pwszX500 || L'\0' == *pwszX500) {
  1954. NameInfo.cRDN = 0;
  1955. NameInfo.rgRDN = NULL;
  1956. if (ppwszError)
  1957. *ppwszError = NULL;
  1958. return CryptEncodeObject(
  1959. dwCertEncodingType,
  1960. X509_NAME,
  1961. &NameInfo,
  1962. pbEncoded,
  1963. pcbEncoded
  1964. );
  1965. }
  1966. if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
  1967. wcscpy(wszSeparators, L";");
  1968. else if (dwStrType & CERT_NAME_STR_COMMA_FLAG)
  1969. wcscpy(wszSeparators, L",");
  1970. else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
  1971. wcscpy(wszSeparators, L"\r\n");
  1972. else
  1973. wcscpy(wszSeparators, L",;");
  1974. if (!(dwStrType & CERT_NAME_STR_NO_PLUS_FLAG))
  1975. wcscat(wszSeparators, L"+");
  1976. if (dwStrType & CERT_NAME_STR_NO_QUOTING_FLAG)
  1977. fEnableQuoting = FALSE;
  1978. else
  1979. fEnableQuoting = TRUE;
  1980. // Eliminate the upper flags before switching
  1981. switch (dwStrType & 0xFFFF) {
  1982. case 0:
  1983. case CERT_OID_NAME_STR:
  1984. case CERT_X500_NAME_STR:
  1985. break;
  1986. case CERT_SIMPLE_NAME_STR:
  1987. default:
  1988. goto InvalidArg;
  1989. }
  1990. // Do initial allocations of Attrs, and Auxs
  1991. if (NULL == (pAttr = (PCERT_RDN_ATTR) PkiNonzeroAlloc(
  1992. sizeof(CERT_RDN_ATTR) * X500_ATTR_ALLOC_COUNT)) ||
  1993. NULL == (pAux = (PX500_ATTR_AUX) PkiNonzeroAlloc(
  1994. sizeof(X500_ATTR_AUX) * X500_ATTR_ALLOC_COUNT)))
  1995. goto OutOfMemory;
  1996. cAllocAttr = X500_ATTR_ALLOC_COUNT;
  1997. fNewRDN = TRUE;
  1998. while (TRUE) {
  1999. LPCWSTR pwszToken;
  2000. DWORD cchToken;
  2001. DWORD dwTokenFlags;
  2002. LPCSTR pszObjId;
  2003. // Get the key token
  2004. if (!GetX500Token(
  2005. &pwszX500,
  2006. L"=", // pwszDelimiter
  2007. FALSE, // fEnableQuoting
  2008. &pwszToken,
  2009. &cchToken,
  2010. &dwTokenFlags
  2011. )) {
  2012. pwszError = pwszX500;
  2013. goto X500KeyTokenError;
  2014. }
  2015. if (0 == cchToken) {
  2016. if (*pwszX500 == L'\0')
  2017. break;
  2018. else {
  2019. pwszError = pwszX500;
  2020. goto EmptyX500KeyError;
  2021. }
  2022. } else if (*pwszX500 == L'\0') {
  2023. pwszError = pwszToken;
  2024. goto NoX500KeyEqualError;
  2025. }
  2026. if (cAttr >= cAllocAttr) {
  2027. PCERT_RDN_ATTR pNewAttr;
  2028. PX500_ATTR_AUX pNewAux;
  2029. assert(cAttr == cAllocAttr);
  2030. if (NULL == (pNewAttr = (PCERT_RDN_ATTR) PkiRealloc(pAttr,
  2031. sizeof(CERT_RDN_ATTR) *
  2032. (cAllocAttr + X500_ATTR_ALLOC_COUNT))))
  2033. goto OutOfMemory;
  2034. pAttr = pNewAttr;
  2035. if (NULL == (pNewAux = (PX500_ATTR_AUX) PkiRealloc(pAux,
  2036. sizeof(X500_ATTR_AUX) *
  2037. (cAllocAttr + X500_ATTR_ALLOC_COUNT))))
  2038. goto OutOfMemory;
  2039. pAux = pNewAux;
  2040. cAllocAttr += X500_ATTR_ALLOC_COUNT;
  2041. }
  2042. iAttr = cAttr;
  2043. cAttr++;
  2044. memset(&pAttr[iAttr], 0, sizeof(CERT_RDN_ATTR));
  2045. memset(&pAux[iAttr], 0, sizeof(X500_ATTR_AUX));
  2046. pAux[iAttr].fNewRDN = fNewRDN;
  2047. if (fNewRDN)
  2048. cRDN++;
  2049. // Convert the Key token to an OID
  2050. pszObjId = X500KeyToOID(pwszToken, cchToken);
  2051. if (NULL == pszObjId) {
  2052. // Convert to ascii and null terminate
  2053. LPSTR pszAllocObjId;
  2054. DWORD i;
  2055. // Convert from unicode to ascii and null terminate
  2056. if (NULL == (pszAllocObjId = (LPSTR) PkiNonzeroAlloc(
  2057. cchToken + 1)))
  2058. goto OutOfMemory;
  2059. pAux[iAttr].pszAllocObjId = pszAllocObjId;
  2060. for (i = 0; i < cchToken; i++)
  2061. pszAllocObjId[i] = (char) (pwszToken[i] & 0xFF);
  2062. pszAllocObjId[cchToken] = '\0';
  2063. // Skips by leading OID. and validates
  2064. pszObjId = GetX500OID(pszAllocObjId);
  2065. if (NULL == pszObjId) {
  2066. pwszError = pwszToken;
  2067. goto InvalidX500Key;
  2068. }
  2069. }
  2070. pAttr[iAttr].pszObjId = (LPSTR) pszObjId;
  2071. pAttr[iAttr].dwValueType = dwValueType;
  2072. // Advance past the Key's "=" delimiter
  2073. pwszX500++;
  2074. // Get the value token
  2075. if (!GetX500Token(
  2076. &pwszX500,
  2077. wszSeparators,
  2078. fEnableQuoting,
  2079. &pwszToken,
  2080. &cchToken,
  2081. &dwTokenFlags
  2082. )) {
  2083. pwszError = pwszX500;
  2084. goto X500ValueTokenError;
  2085. }
  2086. if (cchToken) {
  2087. if (*pwszToken == L'#' && 0 == (dwTokenFlags & X500_QUOTED_FLAG)) {
  2088. // Convert ascii hex to binary
  2089. if (!GetAndAllocHexW(pwszToken, cchToken,
  2090. &pAttr[iAttr].Value)) {
  2091. pwszError = pwszToken;
  2092. goto ConvertHexError;
  2093. }
  2094. pAttr[iAttr].dwValueType = CERT_RDN_OCTET_STRING;
  2095. pAux[iAttr].pbAllocValue = pAttr[iAttr].Value.pbData;
  2096. } else if (dwTokenFlags & X500_EMBEDDED_QUOTE_FLAG) {
  2097. // Realloc and remove the double "'s
  2098. LPWSTR pwszAlloc;
  2099. DWORD cchAlloc;
  2100. DWORD i;
  2101. if (NULL == (pwszAlloc = (LPWSTR) PkiNonzeroAlloc(
  2102. cchToken * sizeof(WCHAR))))
  2103. goto OutOfMemory;
  2104. pAux[iAttr].pbAllocValue = (BYTE *) pwszAlloc;
  2105. cchAlloc = 0;
  2106. for (i = 0; i < cchToken; i++) {
  2107. pwszAlloc[cchAlloc++] = pwszToken[i];
  2108. if (pwszToken[i] == L'\"')
  2109. i++;
  2110. }
  2111. assert(cchAlloc < cchToken);
  2112. pAttr[iAttr].Value.pbData = (BYTE *) pwszAlloc;
  2113. pAttr[iAttr].Value.cbData = cchAlloc * sizeof(WCHAR);
  2114. } else {
  2115. pAttr[iAttr].Value.pbData = (BYTE *) pwszToken;
  2116. pAttr[iAttr].Value.cbData = cchToken * sizeof(WCHAR);
  2117. }
  2118. pAux[iAttr].pwszValue = pwszToken;
  2119. }
  2120. fNewRDN = TRUE;
  2121. if (*pwszX500 == L'\0')
  2122. break;
  2123. else if (*pwszX500 == L'+')
  2124. fNewRDN = FALSE;
  2125. // Advance past the value's delimiter
  2126. pwszX500++;
  2127. }
  2128. if (0 == cRDN) {
  2129. pwszError = pwszStartX500;
  2130. goto NoRDNError;
  2131. }
  2132. // Allocate array of RDNs and update
  2133. if (NULL == (pRDN = (PCERT_RDN) PkiNonzeroAlloc(sizeof(CERT_RDN) * cRDN)))
  2134. goto OutOfMemory;
  2135. iRDN = 0;
  2136. for (iAttr = 0; iAttr < cAttr; iAttr++) {
  2137. if (pAux[iAttr].fNewRDN) {
  2138. assert(iRDN < cRDN);
  2139. pRDN[iRDN].cRDNAttr = 1;
  2140. pRDN[iRDN].rgRDNAttr = &pAttr[iAttr];
  2141. iRDN++;
  2142. } else {
  2143. assert(iRDN > 0);
  2144. pRDN[iRDN - 1].cRDNAttr++;
  2145. }
  2146. }
  2147. assert(iRDN == cRDN);
  2148. NameInfo.cRDN = cRDN;
  2149. NameInfo.rgRDN = pRDN;
  2150. if (dwStrType & CERT_NAME_STR_REVERSE_FLAG)
  2151. ReverseNameInfo(&NameInfo);
  2152. // Encode the above built name
  2153. fResult = UnicodeNameInfoEncode(
  2154. dwCertEncodingType,
  2155. X509_UNICODE_NAME,
  2156. &NameInfo,
  2157. pbEncoded,
  2158. pcbEncoded
  2159. );
  2160. if (!fResult) {
  2161. DWORD dwErr = GetLastError();
  2162. if ((DWORD) CRYPT_E_INVALID_NUMERIC_STRING == dwErr ||
  2163. (DWORD) CRYPT_E_INVALID_PRINTABLE_STRING == dwErr ||
  2164. (DWORD) CRYPT_E_INVALID_IA5_STRING == dwErr) {
  2165. // *pcbEncoded contains the location of the error
  2166. PCERT_RDN_ATTR pErrAttr;
  2167. DWORD iValue;
  2168. if (dwStrType & CERT_NAME_STR_REVERSE_FLAG) {
  2169. // Reverse back to get the correct location of the error
  2170. // relative to the input string
  2171. ReverseNameInfo(&NameInfo);
  2172. fResult = UnicodeNameInfoEncode(
  2173. dwCertEncodingType,
  2174. X509_UNICODE_NAME,
  2175. &NameInfo,
  2176. pbEncoded,
  2177. pcbEncoded
  2178. );
  2179. if (fResult)
  2180. goto UnexpectedReverseEncodeSuccess;
  2181. dwErr = GetLastError();
  2182. if (!( (DWORD) CRYPT_E_INVALID_NUMERIC_STRING == dwErr ||
  2183. (DWORD) CRYPT_E_INVALID_PRINTABLE_STRING == dwErr ||
  2184. (DWORD) CRYPT_E_INVALID_IA5_STRING == dwErr))
  2185. goto UnexpectedReverseEncodeError;
  2186. }
  2187. iValue = GET_CERT_UNICODE_VALUE_ERR_INDEX(*pcbEncoded);
  2188. iRDN = GET_CERT_UNICODE_RDN_ERR_INDEX(*pcbEncoded);
  2189. iAttr = GET_CERT_UNICODE_ATTR_ERR_INDEX(*pcbEncoded);
  2190. *pcbEncoded = 0;
  2191. assert(iRDN < cRDN);
  2192. assert(iAttr < pRDN[iRDN].cRDNAttr);
  2193. pErrAttr = &pRDN[iRDN].rgRDNAttr[iAttr];
  2194. assert(pErrAttr->dwValueType != CERT_RDN_OCTET_STRING);
  2195. // Index from beginning of pAttr
  2196. iAttr = (DWORD)(pErrAttr - pAttr);
  2197. assert(iAttr < cAttr);
  2198. assert(iValue < pAttr[iAttr].Value.cbData / sizeof(WCHAR));
  2199. pwszError = pAux[iAttr].pwszValue;
  2200. assert(pwszError);
  2201. if (pAux[iAttr].pbAllocValue) {
  2202. // Adjust for embedded quotes where the the second quote
  2203. // was removed above before encoding
  2204. DWORD i = iValue;
  2205. assert(pAux[iAttr].pbAllocValue == pAttr[iAttr].Value.pbData);
  2206. LPCWSTR pwszValue = (LPCWSTR) pAttr[iAttr].Value.pbData;
  2207. for ( ; i > 0; i--, pwszValue++)
  2208. if (*pwszValue == L'\"')
  2209. iValue++;
  2210. }
  2211. pwszError += iValue;
  2212. }
  2213. }
  2214. CommonReturn:
  2215. while (cAttr--) {
  2216. PkiFree(pAux[cAttr].pszAllocObjId);
  2217. PkiFree(pAux[cAttr].pbAllocValue);
  2218. }
  2219. PkiFree(pRDN);
  2220. PkiFree(pAttr);
  2221. PkiFree(pAux);
  2222. if (ppwszError)
  2223. *ppwszError = pwszError;
  2224. return fResult;
  2225. ErrorReturn:
  2226. fResult = FALSE;
  2227. goto CommonReturn;
  2228. SET_ERROR(InvalidArg, E_INVALIDARG)
  2229. TRACE_ERROR(OutOfMemory)
  2230. SET_ERROR(X500KeyTokenError, CRYPT_E_INVALID_X500_STRING)
  2231. SET_ERROR(EmptyX500KeyError, CRYPT_E_INVALID_X500_STRING)
  2232. SET_ERROR(NoX500KeyEqualError, CRYPT_E_INVALID_X500_STRING)
  2233. SET_ERROR(InvalidX500Key, CRYPT_E_INVALID_X500_STRING)
  2234. SET_ERROR(X500ValueTokenError, CRYPT_E_INVALID_X500_STRING)
  2235. SET_ERROR(ConvertHexError, CRYPT_E_INVALID_X500_STRING)
  2236. SET_ERROR(NoRDNError, CRYPT_E_INVALID_X500_STRING)
  2237. SET_ERROR(UnexpectedReverseEncodeSuccess, E_UNEXPECTED)
  2238. TRACE_ERROR(UnexpectedReverseEncodeError)
  2239. }
  2240. //+-------------------------------------------------------------------------
  2241. // Convert the null terminated X500 char string to an encoded
  2242. // certificate name.
  2243. //--------------------------------------------------------------------------
  2244. BOOL
  2245. WINAPI
  2246. CertStrToNameA(
  2247. IN DWORD dwCertEncodingType,
  2248. IN LPCSTR pszX500,
  2249. IN DWORD dwStrType,
  2250. IN OPTIONAL void *pvReserved,
  2251. OUT BYTE *pbEncoded,
  2252. IN OUT DWORD *pcbEncoded,
  2253. OUT OPTIONAL LPCSTR *ppszError
  2254. )
  2255. {
  2256. BOOL fResult;
  2257. LPWSTR pwszX500 = NULL;
  2258. LPCWSTR pwszError = NULL;
  2259. assert(pszX500);
  2260. if (NULL == (pwszX500 = MkWStr((LPSTR) pszX500)))
  2261. goto ErrorReturn;
  2262. fResult = CertStrToNameW(
  2263. dwCertEncodingType,
  2264. pwszX500,
  2265. dwStrType,
  2266. pvReserved,
  2267. pbEncoded,
  2268. pcbEncoded,
  2269. &pwszError
  2270. );
  2271. if (ppszError) {
  2272. // Update multi byte error location
  2273. if (pwszError) {
  2274. // Default to beginning of string
  2275. *ppszError = pszX500;
  2276. if (pwszError > pwszX500) {
  2277. // After beginning of string. There should be at least 2
  2278. // characters.
  2279. //
  2280. // Need to convert pwszX500 .. pwszError - 1 back to multi byte
  2281. // to get the correct multi byte pointer.
  2282. int cchError = strlen(pszX500) - 1; // exclude error char
  2283. LPSTR pszError;
  2284. DWORD dwSaveLastError = GetLastError();
  2285. assert(cchError);
  2286. if (pszError = (LPSTR) PkiNonzeroAlloc(cchError)) {
  2287. // Convert up through the previous multibyte character
  2288. cchError = WideCharToMultiByte(
  2289. CP_ACP,
  2290. 0, // dwFlags
  2291. pwszX500,
  2292. (int)(pwszError - pwszX500),
  2293. pszError,
  2294. cchError,
  2295. NULL, // lpDefaultChar
  2296. NULL // lpfUsedDefaultChar
  2297. );
  2298. if (cchError > 0)
  2299. *ppszError = pszX500 + cchError;
  2300. PkiFree(pszError);
  2301. }
  2302. SetLastError(dwSaveLastError);
  2303. }
  2304. } else
  2305. *ppszError = NULL;
  2306. }
  2307. CommonReturn:
  2308. FreeWStr(pwszX500);
  2309. return fResult;
  2310. ErrorReturn:
  2311. fResult = FALSE;
  2312. *pcbEncoded = 0;
  2313. if (ppszError)
  2314. *ppszError = NULL;
  2315. goto CommonReturn;
  2316. }
  2317. //==========================================================================
  2318. // CertGetNameStrW support functions
  2319. //==========================================================================
  2320. //+-------------------------------------------------------------------------
  2321. // Returns pointer to allocated CERT_NAME_INFO by decoding the name blob.
  2322. //
  2323. // Returns NULL if cRDN == 0
  2324. //--------------------------------------------------------------------------
  2325. static PCERT_NAME_INFO AllocAndGetNameInfo(
  2326. IN DWORD dwCertEncodingType,
  2327. IN PCERT_NAME_BLOB pName,
  2328. IN DWORD dwFlags
  2329. )
  2330. {
  2331. PCERT_NAME_INFO pInfo;
  2332. assert(pName);
  2333. if (0 == pName->cbData)
  2334. return NULL;
  2335. if (NULL == (pInfo = (PCERT_NAME_INFO) AllocAndDecodeObject(
  2336. dwCertEncodingType,
  2337. X509_UNICODE_NAME,
  2338. pName->pbData,
  2339. pName->cbData,
  2340. (dwFlags & CERT_NAME_DISABLE_IE4_UTF8_FLAG) ?
  2341. CRYPT_UNICODE_NAME_DECODE_DISABLE_IE4_UTF8_FLAG : 0
  2342. )))
  2343. return NULL;
  2344. if (0 == pInfo->cRDN) {
  2345. PkiFree(pInfo);
  2346. return NULL;
  2347. } else
  2348. return pInfo;
  2349. }
  2350. //+-------------------------------------------------------------------------
  2351. // Returns pointer to allocated CERT_NAME_INFO by decoding either the
  2352. // Subject or Issuer field in the certificate. CERT_NAME_ISSUER_FLAG is
  2353. // set to select the Issuer.
  2354. //
  2355. // Returns NULL if cRDN == 0
  2356. //--------------------------------------------------------------------------
  2357. static PCERT_NAME_INFO AllocAndGetCertNameInfo(
  2358. IN PCCERT_CONTEXT pCertContext,
  2359. IN DWORD dwFlags
  2360. )
  2361. {
  2362. PCERT_NAME_BLOB pName;
  2363. if (dwFlags & CERT_NAME_ISSUER_FLAG)
  2364. pName = &pCertContext->pCertInfo->Issuer;
  2365. else
  2366. pName = &pCertContext->pCertInfo->Subject;
  2367. return AllocAndGetNameInfo(pCertContext->dwCertEncodingType, pName,
  2368. dwFlags);
  2369. }
  2370. //+-------------------------------------------------------------------------
  2371. // Table of Subject and Issuer Alternative Name extension OIDs
  2372. //--------------------------------------------------------------------------
  2373. static const LPCSTR rgpszSubjectAltOID[] = {
  2374. szOID_SUBJECT_ALT_NAME2,
  2375. szOID_SUBJECT_ALT_NAME
  2376. };
  2377. #define NUM_SUBJECT_ALT_OID (sizeof(rgpszSubjectAltOID) / \
  2378. sizeof(rgpszSubjectAltOID[0]))
  2379. static const LPCSTR rgpszIssuerAltOID[] = {
  2380. szOID_ISSUER_ALT_NAME2,
  2381. szOID_ISSUER_ALT_NAME
  2382. };
  2383. #define NUM_ISSUER_ALT_OID (sizeof(rgpszIssuerAltOID) / \
  2384. sizeof(rgpszIssuerAltOID[0]))
  2385. //+-------------------------------------------------------------------------
  2386. // Returns pointer to allocated CERT_ALT_NAME_INFO by decoding either the
  2387. // Subject or Issuer Alternative Extension. CERT_NAME_ISSUER_FLAG is
  2388. // set to select the Issuer.
  2389. //
  2390. // Returns NULL if extension not found or cAltEntry == 0
  2391. //--------------------------------------------------------------------------
  2392. static PCERT_ALT_NAME_INFO AllocAndGetAltNameInfo(
  2393. IN PCCERT_CONTEXT pCertContext,
  2394. IN DWORD dwFlags
  2395. )
  2396. {
  2397. DWORD cAltOID;
  2398. const LPCSTR *ppszAltOID;
  2399. PCERT_EXTENSION pExt;
  2400. PCERT_ALT_NAME_INFO pInfo;
  2401. if (dwFlags & CERT_NAME_ISSUER_FLAG) {
  2402. cAltOID = NUM_ISSUER_ALT_OID;
  2403. ppszAltOID = rgpszIssuerAltOID;
  2404. } else {
  2405. cAltOID = NUM_SUBJECT_ALT_OID;
  2406. ppszAltOID = rgpszSubjectAltOID;
  2407. }
  2408. // Try to find an alternative name extension
  2409. pExt = NULL;
  2410. for ( ; cAltOID > 0; cAltOID--, ppszAltOID++) {
  2411. if (pExt = CertFindExtension(
  2412. *ppszAltOID,
  2413. pCertContext->pCertInfo->cExtension,
  2414. pCertContext->pCertInfo->rgExtension
  2415. ))
  2416. break;
  2417. }
  2418. if (NULL == pExt)
  2419. return NULL;
  2420. if (NULL == (pInfo = (PCERT_ALT_NAME_INFO) AllocAndDecodeObject(
  2421. pCertContext->dwCertEncodingType,
  2422. X509_ALTERNATE_NAME,
  2423. pExt->Value.pbData,
  2424. pExt->Value.cbData,
  2425. 0 // dwFlags
  2426. )))
  2427. return NULL;
  2428. if (0 == pInfo->cAltEntry) {
  2429. PkiFree(pInfo);
  2430. return NULL;
  2431. } else
  2432. return pInfo;
  2433. }
  2434. //+-------------------------------------------------------------------------
  2435. // Returns pointer to allocated CERT_NAME_INFO by decoding the first
  2436. // Directory Name choice (if it exists) in the decoded CERT_ALT_NAME_INFO.
  2437. //
  2438. // Returns NULL if no Directory Name choice or cRDN == 0.
  2439. //--------------------------------------------------------------------------
  2440. static PCERT_NAME_INFO AllocAndGetAltDirNameInfo(
  2441. IN DWORD dwCertEncodingType,
  2442. IN PCERT_ALT_NAME_INFO pAltNameInfo,
  2443. IN DWORD dwFlags
  2444. )
  2445. {
  2446. DWORD cEntry;
  2447. PCERT_ALT_NAME_ENTRY pEntry;
  2448. if (NULL == pAltNameInfo)
  2449. return NULL;
  2450. cEntry = pAltNameInfo->cAltEntry;
  2451. pEntry = pAltNameInfo->rgAltEntry;
  2452. for ( ; cEntry > 0; cEntry--, pEntry++) {
  2453. if (CERT_ALT_NAME_DIRECTORY_NAME == pEntry->dwAltNameChoice) {
  2454. return AllocAndGetNameInfo(dwCertEncodingType,
  2455. &pEntry->DirectoryName, dwFlags);
  2456. }
  2457. }
  2458. return NULL;
  2459. }
  2460. //+-------------------------------------------------------------------------
  2461. // First, returns pointer to allocated CERT_ALT_NAME_INFO by decoding either
  2462. // the Subject or Issuer Alternative Extension. CERT_NAME_ISSUER_FLAG is
  2463. // set to select the Issuer. Returns NULL if extension not found or
  2464. // cAltEntry == 0
  2465. //
  2466. // Then, if able to find the extension, returns pointer to allocated
  2467. // CERT_NAME_INFO by decoding the first Directory Name choice (if it exists)
  2468. // in the decoded CERT_ALT_NAME_INFO. Returns NULL if no Directory Name
  2469. // choice or cRDN == 0.
  2470. //--------------------------------------------------------------------------
  2471. static PCERT_NAME_INFO AllocAndGetAltDirNameInfo(
  2472. IN PCCERT_CONTEXT pCertContext,
  2473. IN DWORD dwFlags,
  2474. OUT PCERT_ALT_NAME_INFO *ppAltNameInfo
  2475. )
  2476. {
  2477. PCERT_ALT_NAME_INFO pAltNameInfo;
  2478. *ppAltNameInfo = pAltNameInfo = AllocAndGetAltNameInfo(pCertContext,
  2479. dwFlags);
  2480. if (NULL == pAltNameInfo)
  2481. return NULL;
  2482. return AllocAndGetAltDirNameInfo(pCertContext->dwCertEncodingType,
  2483. pAltNameInfo, dwFlags);
  2484. }
  2485. //+-------------------------------------------------------------------------
  2486. // Copy name string. Ensure its NULL terminated.
  2487. //--------------------------------------------------------------------------
  2488. static void CopyNameStringW(
  2489. IN LPCWSTR pwszSrc,
  2490. OUT OPTIONAL LPWSTR pwszNameString,
  2491. IN DWORD cchNameString,
  2492. OUT DWORD *pcwszOut
  2493. )
  2494. {
  2495. PutStrW(pwszSrc, &pwszNameString, &cchNameString, pcwszOut);
  2496. if (cchNameString != 0)
  2497. // Always NULL terminate
  2498. *pwszNameString = L'\0';
  2499. *pcwszOut += 1;
  2500. }
  2501. //+-------------------------------------------------------------------------
  2502. // Table of ordered RDN attributes to search for when formatting
  2503. // SIMPLE_DISPLAY_TYPE
  2504. //--------------------------------------------------------------------------
  2505. static const LPCSTR rgpszSimpleDisplayAttrOID[] = {
  2506. szOID_COMMON_NAME,
  2507. szOID_ORGANIZATIONAL_UNIT_NAME,
  2508. szOID_ORGANIZATION_NAME,
  2509. szOID_RSA_emailAddr,
  2510. NULL // any
  2511. };
  2512. #define NUM_SIMPLE_DISPLAY_ATTR_OID (sizeof(rgpszSimpleDisplayAttrOID) / \
  2513. sizeof(rgpszSimpleDisplayAttrOID[0]))
  2514. //+-------------------------------------------------------------------------
  2515. // Table of ordered RDN attributes to search for when formatting
  2516. // EMAIL_TYPE
  2517. //--------------------------------------------------------------------------
  2518. static const LPCSTR rgpszEmailAttrOID[] = {
  2519. szOID_RSA_emailAddr
  2520. };
  2521. #define NUM_EMAIL_ATTR_OID (sizeof(rgpszEmailAttrOID) / \
  2522. sizeof(rgpszEmailAttrOID[0]))
  2523. //+-------------------------------------------------------------------------
  2524. // Table of ordered RDN attributes to search for when formatting
  2525. // DNS_TYPE
  2526. //--------------------------------------------------------------------------
  2527. static const LPCSTR rgpszDNSAttrOID[] = {
  2528. szOID_COMMON_NAME
  2529. };
  2530. #define NUM_DNS_ATTR_OID (sizeof(rgpszDNSAttrOID) / \
  2531. sizeof(rgpszDNSAttrOID[0]))
  2532. // Largest number from above tables
  2533. #define MAX_ATTR_OID NUM_SIMPLE_DISPLAY_ATTR_OID
  2534. // PCERT_NAME_INFO table count and indices
  2535. #define NAME_INFO_CNT 2
  2536. #define CERT_NAME_INFO_INDEX 0
  2537. #define ALT_DIR_NAME_INFO_INDEX 1
  2538. //+-------------------------------------------------------------------------
  2539. // Iterate through the list of attributes specified in rgpszAttrOID
  2540. // and iterate through the table of decoded names specified in rgpNameInfo
  2541. // and find the first occurrence of the attribute.
  2542. //--------------------------------------------------------------------------
  2543. static BOOL GetAttrStringW(
  2544. IN DWORD cAttrOID,
  2545. IN const LPCSTR *rgpszAttrOID,
  2546. IN PCERT_NAME_INFO rgpNameInfo[NAME_INFO_CNT],
  2547. OUT OPTIONAL LPWSTR pwszNameString,
  2548. IN DWORD cchNameString,
  2549. OUT DWORD *pcwszOut
  2550. )
  2551. {
  2552. DWORD iOID;
  2553. PCERT_RDN_ATTR rgpFoundAttr[MAX_ATTR_OID];
  2554. DWORD iInfo;
  2555. assert(cAttrOID > 0 && cAttrOID <= MAX_ATTR_OID);
  2556. for (iOID = 0; iOID < cAttrOID; iOID++)
  2557. rgpFoundAttr[iOID] = NULL;
  2558. for (iInfo = 0; iInfo < NAME_INFO_CNT; iInfo++) {
  2559. PCERT_NAME_INFO pInfo;
  2560. DWORD cRDN;
  2561. if (NULL == (pInfo = rgpNameInfo[iInfo]))
  2562. continue;
  2563. // Search RDNs in reverse order
  2564. for (cRDN = pInfo->cRDN; cRDN > 0; cRDN--) {
  2565. PCERT_RDN pRDN = &pInfo->rgRDN[cRDN - 1];
  2566. DWORD cAttr = pRDN->cRDNAttr;
  2567. PCERT_RDN_ATTR pAttr = pRDN->rgRDNAttr;
  2568. for ( ; cAttr > 0; cAttr--, pAttr++) {
  2569. if (CERT_RDN_ENCODED_BLOB == pAttr->dwValueType ||
  2570. CERT_RDN_OCTET_STRING == pAttr->dwValueType)
  2571. continue;
  2572. for (iOID = 0; iOID < cAttrOID; iOID++) {
  2573. if (NULL == rgpFoundAttr[iOID] &&
  2574. (NULL == rgpszAttrOID[iOID] ||
  2575. 0 == strcmp(rgpszAttrOID[iOID],
  2576. pAttr->pszObjId))) {
  2577. rgpFoundAttr[iOID] = pAttr;
  2578. if (0 == iOID)
  2579. goto FoundAttr;
  2580. else
  2581. break;
  2582. }
  2583. }
  2584. }
  2585. }
  2586. }
  2587. // iOID == 0 was already found above
  2588. assert(NULL == rgpFoundAttr[0]);
  2589. for (iOID = 1; iOID < cAttrOID; iOID++) {
  2590. if (rgpFoundAttr[iOID])
  2591. break;
  2592. }
  2593. if (iOID >= cAttrOID)
  2594. return FALSE;
  2595. FoundAttr:
  2596. assert(iOID < cAttrOID && rgpFoundAttr[iOID]);
  2597. CopyNameStringW((LPCWSTR) rgpFoundAttr[iOID]->Value.pbData, pwszNameString,
  2598. cchNameString, pcwszOut);
  2599. return TRUE;
  2600. }
  2601. //+-------------------------------------------------------------------------
  2602. // Attempt to find the specified choice in the decoded alternative name
  2603. // extension.
  2604. //--------------------------------------------------------------------------
  2605. static BOOL GetAltNameUnicodeStringChoiceW(
  2606. IN DWORD dwAltNameChoice,
  2607. IN PCERT_ALT_NAME_INFO pAltNameInfo,
  2608. OUT OPTIONAL LPWSTR pwszNameString,
  2609. IN DWORD cchNameString,
  2610. OUT DWORD *pcwszOut
  2611. )
  2612. {
  2613. DWORD cEntry;
  2614. PCERT_ALT_NAME_ENTRY pEntry;
  2615. if (NULL == pAltNameInfo)
  2616. return FALSE;
  2617. cEntry = pAltNameInfo->cAltEntry;
  2618. pEntry = pAltNameInfo->rgAltEntry;
  2619. for ( ; cEntry > 0; cEntry--, pEntry++) {
  2620. if (dwAltNameChoice == pEntry->dwAltNameChoice) {
  2621. // pwszRfc822Name union choice is the same as
  2622. // pwszDNSName and pwszURL.
  2623. CopyNameStringW(pEntry->pwszRfc822Name, pwszNameString,
  2624. cchNameString, pcwszOut);
  2625. return TRUE;
  2626. }
  2627. }
  2628. return FALSE;
  2629. }
  2630. //+-------------------------------------------------------------------------
  2631. // Attempt to find an OTHER_NAME choice in the decoded alternative name
  2632. // extension whose pszObjId == szOID_NT_PRINCIPAL_NAME.
  2633. //
  2634. // The UPN OtherName Value blob is decoded as a X509_UNICODE_ANY_STRING.
  2635. //--------------------------------------------------------------------------
  2636. static BOOL GetAltNameUPNW(
  2637. IN PCERT_ALT_NAME_INFO pAltNameInfo,
  2638. OUT OPTIONAL LPWSTR pwszNameString,
  2639. IN DWORD cchNameString,
  2640. OUT DWORD *pcwszOut
  2641. )
  2642. {
  2643. DWORD cEntry;
  2644. PCERT_ALT_NAME_ENTRY pEntry;
  2645. if (NULL == pAltNameInfo)
  2646. return FALSE;
  2647. cEntry = pAltNameInfo->cAltEntry;
  2648. pEntry = pAltNameInfo->rgAltEntry;
  2649. for ( ; cEntry > 0; cEntry--, pEntry++) {
  2650. if (CERT_ALT_NAME_OTHER_NAME == pEntry->dwAltNameChoice &&
  2651. 0 == strcmp(pEntry->pOtherName->pszObjId,
  2652. szOID_NT_PRINCIPAL_NAME)) {
  2653. PCERT_NAME_VALUE pNameValue;
  2654. if (pNameValue = (PCERT_NAME_VALUE) AllocAndDecodeObject(
  2655. X509_ASN_ENCODING,
  2656. X509_UNICODE_ANY_STRING,
  2657. pEntry->pOtherName->Value.pbData,
  2658. pEntry->pOtherName->Value.cbData,
  2659. 0 // dwFlags
  2660. )) {
  2661. BOOL fIsStr = IS_CERT_RDN_CHAR_STRING(pNameValue->dwValueType);
  2662. if (fIsStr)
  2663. CopyNameStringW((LPWSTR) pNameValue->Value.pbData,
  2664. pwszNameString, cchNameString, pcwszOut);
  2665. PkiFree(pNameValue);
  2666. if (fIsStr)
  2667. return TRUE;
  2668. }
  2669. }
  2670. }
  2671. return FALSE;
  2672. }
  2673. //+-------------------------------------------------------------------------
  2674. // Get the subject or issuer name from the certificate and
  2675. // according to the specified format type, convert to a null terminated
  2676. // WCHAR string.
  2677. //
  2678. // CERT_NAME_ISSUER_FLAG can be set to get the issuer's name. Otherwise,
  2679. // gets the subject's name.
  2680. //--------------------------------------------------------------------------
  2681. DWORD
  2682. WINAPI
  2683. CertGetNameStringW(
  2684. IN PCCERT_CONTEXT pCertContext,
  2685. IN DWORD dwType,
  2686. IN DWORD dwFlags,
  2687. IN void *pvTypePara,
  2688. OUT OPTIONAL LPWSTR pwszNameString,
  2689. IN DWORD cchNameString
  2690. )
  2691. {
  2692. DWORD cwszOut = 0;
  2693. PCERT_NAME_INFO rgpNameInfo[NAME_INFO_CNT] = { NULL, NULL };
  2694. PCERT_ALT_NAME_INFO pAltNameInfo = NULL;
  2695. DWORD i;
  2696. DWORD dwStrType;
  2697. DWORD dwCertEncodingType;
  2698. if (NULL == pwszNameString)
  2699. cchNameString = 0;
  2700. switch (dwType) {
  2701. case CERT_NAME_EMAIL_TYPE:
  2702. pAltNameInfo = AllocAndGetAltNameInfo(pCertContext, dwFlags);
  2703. if (GetAltNameUnicodeStringChoiceW(
  2704. CERT_ALT_NAME_RFC822_NAME,
  2705. pAltNameInfo,
  2706. pwszNameString,
  2707. cchNameString,
  2708. &cwszOut
  2709. )) goto CommonReturn;
  2710. rgpNameInfo[CERT_NAME_INFO_INDEX] = AllocAndGetCertNameInfo(
  2711. pCertContext, dwFlags);
  2712. if (!GetAttrStringW(
  2713. NUM_EMAIL_ATTR_OID,
  2714. rgpszEmailAttrOID,
  2715. rgpNameInfo,
  2716. pwszNameString,
  2717. cchNameString,
  2718. &cwszOut
  2719. )) goto NoEmail;
  2720. break;
  2721. case CERT_NAME_DNS_TYPE:
  2722. pAltNameInfo = AllocAndGetAltNameInfo(pCertContext, dwFlags);
  2723. if (GetAltNameUnicodeStringChoiceW(
  2724. CERT_ALT_NAME_DNS_NAME,
  2725. pAltNameInfo,
  2726. pwszNameString,
  2727. cchNameString,
  2728. &cwszOut
  2729. )) goto CommonReturn;
  2730. rgpNameInfo[CERT_NAME_INFO_INDEX] = AllocAndGetCertNameInfo(
  2731. pCertContext, dwFlags);
  2732. if (!GetAttrStringW(
  2733. NUM_DNS_ATTR_OID,
  2734. rgpszDNSAttrOID,
  2735. rgpNameInfo,
  2736. pwszNameString,
  2737. cchNameString,
  2738. &cwszOut
  2739. )) goto NoDNS;
  2740. break;
  2741. case CERT_NAME_URL_TYPE:
  2742. pAltNameInfo = AllocAndGetAltNameInfo(pCertContext, dwFlags);
  2743. if (!GetAltNameUnicodeStringChoiceW(
  2744. CERT_ALT_NAME_URL,
  2745. pAltNameInfo,
  2746. pwszNameString,
  2747. cchNameString,
  2748. &cwszOut
  2749. )) goto NoURL;
  2750. break;
  2751. case CERT_NAME_UPN_TYPE:
  2752. pAltNameInfo = AllocAndGetAltNameInfo(pCertContext, dwFlags);
  2753. if (!GetAltNameUPNW(
  2754. pAltNameInfo,
  2755. pwszNameString,
  2756. cchNameString,
  2757. &cwszOut
  2758. )) goto NoUPN;
  2759. break;
  2760. case CERT_NAME_RDN_TYPE:
  2761. dwStrType = pvTypePara ? *((DWORD *) pvTypePara) : 0;
  2762. if (dwStrType & CERT_NAME_STR_DISABLE_IE4_UTF8_FLAG)
  2763. dwFlags |= CERT_NAME_DISABLE_IE4_UTF8_FLAG;
  2764. dwCertEncodingType = pCertContext->dwCertEncodingType;
  2765. if (rgpNameInfo[CERT_NAME_INFO_INDEX] = AllocAndGetCertNameInfo(
  2766. pCertContext, dwFlags))
  2767. // Note, decoded name info RDNs may be reversed
  2768. cwszOut = CertNameInfoToStrW(
  2769. dwCertEncodingType,
  2770. rgpNameInfo[CERT_NAME_INFO_INDEX],
  2771. dwStrType,
  2772. pwszNameString,
  2773. cchNameString
  2774. );
  2775. else if (rgpNameInfo[ALT_DIR_NAME_INFO_INDEX] =
  2776. AllocAndGetAltDirNameInfo(pCertContext, dwFlags,
  2777. &pAltNameInfo))
  2778. // Note, decoded name info RDNs may be reversed
  2779. cwszOut = CertNameInfoToStrW(
  2780. dwCertEncodingType,
  2781. rgpNameInfo[ALT_DIR_NAME_INFO_INDEX],
  2782. dwStrType,
  2783. pwszNameString,
  2784. cchNameString
  2785. );
  2786. else
  2787. goto NoRDN;
  2788. break;
  2789. case CERT_NAME_ATTR_TYPE:
  2790. rgpNameInfo[CERT_NAME_INFO_INDEX] = AllocAndGetCertNameInfo(
  2791. pCertContext, dwFlags);
  2792. rgpNameInfo[ALT_DIR_NAME_INFO_INDEX] = AllocAndGetAltDirNameInfo(
  2793. pCertContext, dwFlags, &pAltNameInfo);
  2794. if (!GetAttrStringW(
  2795. 1, // cAttrOID
  2796. (const LPCSTR *) &pvTypePara,
  2797. rgpNameInfo,
  2798. pwszNameString,
  2799. cchNameString,
  2800. &cwszOut
  2801. )) goto NoAttr;
  2802. break;
  2803. case CERT_NAME_FRIENDLY_DISPLAY_TYPE:
  2804. {
  2805. DWORD cbData = 0;
  2806. CertGetCertificateContextProperty(
  2807. pCertContext,
  2808. CERT_FRIENDLY_NAME_PROP_ID,
  2809. NULL, // pvData
  2810. &cbData
  2811. );
  2812. // Need at least one character, plus the null terminator
  2813. if (cbData >= sizeof(WCHAR) * 2) {
  2814. LPWSTR pwszFriendlyName;
  2815. // Ensure the Friendly name is null terminated.
  2816. if (pwszFriendlyName = (LPWSTR) PkiZeroAlloc(
  2817. cbData + sizeof(WCHAR) * 2)) {
  2818. BOOL fResult;
  2819. fResult = CertGetCertificateContextProperty(
  2820. pCertContext,
  2821. CERT_FRIENDLY_NAME_PROP_ID,
  2822. pwszFriendlyName,
  2823. &cbData
  2824. );
  2825. if (fResult)
  2826. CopyNameStringW(
  2827. pwszFriendlyName,
  2828. pwszNameString,
  2829. cchNameString,
  2830. &cwszOut
  2831. );
  2832. PkiFree(pwszFriendlyName);
  2833. if (fResult)
  2834. goto CommonReturn;
  2835. }
  2836. }
  2837. }
  2838. // Fall through
  2839. case CERT_NAME_SIMPLE_DISPLAY_TYPE:
  2840. rgpNameInfo[CERT_NAME_INFO_INDEX] = AllocAndGetCertNameInfo(
  2841. pCertContext, dwFlags);
  2842. rgpNameInfo[ALT_DIR_NAME_INFO_INDEX] = AllocAndGetAltDirNameInfo(
  2843. pCertContext, dwFlags, &pAltNameInfo);
  2844. if (GetAttrStringW(
  2845. NUM_SIMPLE_DISPLAY_ATTR_OID,
  2846. rgpszSimpleDisplayAttrOID,
  2847. rgpNameInfo,
  2848. pwszNameString,
  2849. cchNameString,
  2850. &cwszOut
  2851. )) goto CommonReturn;
  2852. if (!GetAltNameUnicodeStringChoiceW(
  2853. CERT_ALT_NAME_RFC822_NAME,
  2854. pAltNameInfo,
  2855. pwszNameString,
  2856. cchNameString,
  2857. &cwszOut
  2858. )) goto NoSimpleDisplay;
  2859. break;
  2860. default:
  2861. goto InvalidType;
  2862. }
  2863. CommonReturn:
  2864. for (i = 0; i < NAME_INFO_CNT; i++)
  2865. PkiFree(rgpNameInfo[i]);
  2866. PkiFree(pAltNameInfo);
  2867. return cwszOut;
  2868. ErrorReturn:
  2869. if (0 != cchNameString)
  2870. // Always NULL terminate
  2871. *pwszNameString = L'\0';
  2872. cwszOut = 1;
  2873. goto CommonReturn;
  2874. SET_ERROR(NoEmail, CRYPT_E_NOT_FOUND)
  2875. SET_ERROR(NoDNS, CRYPT_E_NOT_FOUND)
  2876. SET_ERROR(NoURL, CRYPT_E_NOT_FOUND)
  2877. SET_ERROR(NoUPN, CRYPT_E_NOT_FOUND)
  2878. SET_ERROR(NoRDN, CRYPT_E_NOT_FOUND)
  2879. SET_ERROR(NoAttr, CRYPT_E_NOT_FOUND)
  2880. SET_ERROR(NoSimpleDisplay, CRYPT_E_NOT_FOUND)
  2881. SET_ERROR(InvalidType, E_INVALIDARG)
  2882. }
  2883. //+-------------------------------------------------------------------------
  2884. // Get the subject or issuer name from the certificate and
  2885. // according to the specified format type, convert to a null terminated
  2886. // char string.
  2887. //
  2888. // CERT_NAME_ISSUER_FLAG can be set to get the issuer's name. Otherwise,
  2889. // gets the subject's name.
  2890. //--------------------------------------------------------------------------
  2891. DWORD
  2892. WINAPI
  2893. CertGetNameStringA(
  2894. IN PCCERT_CONTEXT pCertContext,
  2895. IN DWORD dwType,
  2896. IN DWORD dwFlags,
  2897. IN void *pvTypePara,
  2898. OUT OPTIONAL LPSTR pszNameString,
  2899. IN DWORD cchNameString
  2900. )
  2901. {
  2902. DWORD cszOut;
  2903. LPWSTR pwsz = NULL;
  2904. DWORD cwsz;
  2905. cwsz = CertGetNameStringW(
  2906. pCertContext,
  2907. dwType,
  2908. dwFlags,
  2909. pvTypePara,
  2910. NULL, // pwsz
  2911. 0 // cwsz
  2912. );
  2913. if (pwsz = (LPWSTR) PkiNonzeroAlloc(cwsz * sizeof(WCHAR)))
  2914. CertGetNameStringW(
  2915. pCertContext,
  2916. dwType,
  2917. dwFlags,
  2918. pvTypePara,
  2919. pwsz,
  2920. cwsz
  2921. );
  2922. cszOut = ConvertUnicodeStringToAscii(pwsz, cwsz, pszNameString,
  2923. cchNameString);
  2924. PkiFree(pwsz);
  2925. return cszOut;
  2926. }