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.

991 lines
30 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1996
  6. //
  7. // File: tx500str.cpp
  8. //
  9. // Contents: X500 Certificate Name String API Tests
  10. //
  11. // See Usage() for list of test options.
  12. //
  13. //
  14. // Functions: main
  15. //
  16. // History: 18-Feb-97 philh created
  17. //
  18. //--------------------------------------------------------------------------
  19. #include <windows.h>
  20. #include <assert.h>
  21. #include "wincrypt.h"
  22. #include "certtest.h"
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <malloc.h>
  27. #include <memory.h>
  28. #include <time.h>
  29. #define ALL_STR_TYPES 0xFFFFFFFF
  30. static BOOL fVerbose = FALSE;
  31. static void FormatAndParseCertNames(
  32. IN LPCSTR pszCertFilename,
  33. IN DWORD dwStrType,
  34. IN BOOL fSubject
  35. );
  36. static void GetCertNameFromFile(
  37. IN LPCSTR pszCertFilename,
  38. IN DWORD dwGetNameStringType,
  39. IN LPSTR pszAttrOID,
  40. IN DWORD dwStrType,
  41. IN BOOL fSubject,
  42. IN DWORD dwExpectedErr
  43. );
  44. static void ParseX500Name(
  45. IN LPCSTR pszName,
  46. IN DWORD dwStrType,
  47. IN DWORD dwExpectedErr,
  48. IN int iExpectedErrOffset
  49. );
  50. static void ParsePredefinedX500Names();
  51. #define CROW 8
  52. void PrintWords(LPCSTR pszHdr, WORD *pw, DWORD cwSize)
  53. {
  54. ULONG cw, i;
  55. while (cwSize > 0)
  56. {
  57. printf("%s", pszHdr);
  58. cw = min(CROW, cwSize);
  59. cwSize -= cw;
  60. for (i = 0; i<cw; i++)
  61. printf(" %04X", pw[i]);
  62. for (i = cw; i<CROW; i++)
  63. printf(" ");
  64. printf(" '");
  65. for (i = 0; i<cw; i++)
  66. if (pw[i] >= 0x20 && pw[i] <= 0x7f)
  67. printf("%C", pw[i]);
  68. else
  69. printf(".");
  70. pw += cw;
  71. printf("'\n");
  72. }
  73. }
  74. static void Usage(void)
  75. {
  76. int i;
  77. printf("Usage: tx500str [options]\n");
  78. printf("Options are:\n");
  79. printf(" -h - This message\n");
  80. printf(" -n<X500 Name> - For example \"CN=Joe Cool, O=Microsoft\"\n");
  81. printf(" -e<number> - Expected Error\n");
  82. printf(" -o<number> - Expected Error Offset\n");
  83. printf(" -c<Cert Filename> - Read encoded cert file for names\n");
  84. printf(" -S - Format cert's Subject (default)\n");
  85. printf(" -I - Format cert's Issuer\n");
  86. printf(" -f<number> - Name string formatting type\n");
  87. printf(" -fAll - Name string formatting (All types)\n");
  88. printf(" -v - Verbose\n");
  89. printf(" -g - CertGetNameString(SIMPLE_DISPLAY)\n");
  90. printf(" -g<number> - CertGetNameString type\n");
  91. printf(" -a<OID> - Attribute OID, for example, -a2.5.4.3\n");
  92. printf("\n");
  93. printf("Default: Cycle through predefined list of X500 test names\n");
  94. }
  95. int _cdecl main(int argc, char * argv[])
  96. {
  97. LPSTR pszName = NULL;
  98. LPSTR pszCertFilename = NULL;
  99. DWORD dwStrType = 0;
  100. DWORD dwExpectedErr = 0;
  101. int iExpectedErrOffset = -1;
  102. BOOL fSubject = TRUE;
  103. BOOL fGetCertName = FALSE;
  104. DWORD dwGetNameStringType = CERT_NAME_SIMPLE_DISPLAY_TYPE;
  105. LPSTR pszAttrOID = NULL;
  106. while (--argc>0)
  107. {
  108. if (**++argv == '-')
  109. {
  110. switch(argv[0][1])
  111. {
  112. case 'c':
  113. pszCertFilename = argv[0]+2;
  114. if (*pszCertFilename == '\0') {
  115. printf("Need to specify filename\n");
  116. goto BadUsage;
  117. }
  118. break;
  119. case 'n':
  120. pszName = argv[0]+2;
  121. if (*pszName == '\0') {
  122. printf("Need to specify X500 name\n");
  123. goto BadUsage;
  124. }
  125. break;
  126. case 'f':
  127. if (argv[0][2]) {
  128. if (0 == _stricmp(argv[0]+2, "ALL"))
  129. dwStrType = ALL_STR_TYPES;
  130. else
  131. dwStrType = (DWORD) strtoul(argv[0]+2, NULL, 0);
  132. } else {
  133. printf("Need to specify -fALL or -f<number>\n");
  134. goto BadUsage;
  135. }
  136. break;
  137. case 'e':
  138. if (argv[0][2])
  139. dwExpectedErr = (DWORD) strtoul(argv[0]+2, NULL, 0);
  140. else {
  141. printf("Need to specify -e<number>\n");
  142. goto BadUsage;
  143. }
  144. break;
  145. case 'o':
  146. if (argv[0][2])
  147. iExpectedErrOffset = strtol(argv[0]+2, NULL, 0);
  148. else {
  149. printf("Need to specify -o<number>\n");
  150. goto BadUsage;
  151. }
  152. break;
  153. case 'v':
  154. fVerbose = TRUE;
  155. break;
  156. case 'S':
  157. fSubject = TRUE;
  158. break;
  159. case 'I':
  160. fSubject = FALSE;
  161. break;
  162. case 'g':
  163. fGetCertName = TRUE;
  164. if (argv[0][2])
  165. dwGetNameStringType = (DWORD) strtoul(argv[0]+2, NULL, 0);
  166. break;
  167. case 'a':
  168. pszAttrOID = argv[0]+2;
  169. break;
  170. case 'h':
  171. default:
  172. goto BadUsage;
  173. }
  174. } else
  175. goto BadUsage;
  176. }
  177. printf("command line: %s\n", GetCommandLine());
  178. if (pszName) {
  179. printf("Parsing ");
  180. ParseX500Name(
  181. pszName,
  182. dwStrType,
  183. dwExpectedErr,
  184. iExpectedErrOffset
  185. );
  186. } else if (pszCertFilename) {
  187. printf("Reading encoded certificate file: %s\n", pszCertFilename);
  188. if (fGetCertName)
  189. GetCertNameFromFile(
  190. pszCertFilename,
  191. dwGetNameStringType,
  192. pszAttrOID,
  193. dwStrType,
  194. fSubject,
  195. dwExpectedErr
  196. );
  197. else
  198. FormatAndParseCertNames(
  199. pszCertFilename,
  200. dwStrType,
  201. fSubject
  202. );
  203. } else {
  204. printf("Parsing predefined X500 test names\n", pszName);
  205. ParsePredefinedX500Names();
  206. }
  207. CommonReturn:
  208. return 0;
  209. BadUsage:
  210. Usage();
  211. goto CommonReturn;
  212. }
  213. static void *TestDecodeObject(
  214. IN LPCSTR lpszStructType,
  215. IN const BYTE *pbEncoded,
  216. IN DWORD cbEncoded
  217. )
  218. {
  219. DWORD cbInfo;
  220. void *pvInfo;
  221. // Set to bogus value. pvInfo == NULL, should cause it to be ignored.
  222. cbInfo = 0x12345678;
  223. CryptDecodeObject(
  224. dwCertEncodingType,
  225. lpszStructType,
  226. pbEncoded,
  227. cbEncoded,
  228. 0, // dwFlags
  229. NULL, // pvInfo
  230. &cbInfo
  231. );
  232. if (cbInfo == 0) {
  233. if ((DWORD_PTR) lpszStructType <= 0xFFFF)
  234. printf("CryptDecodeObject(StructType: %d, pvInfo == NULL)",
  235. (DWORD)(DWORD_PTR) lpszStructType);
  236. else
  237. printf("CryptDecodeObject(StructType: %s, pvInfo == NULL)",
  238. lpszStructType);
  239. PrintLastError("");
  240. return NULL;
  241. }
  242. if (NULL == (pvInfo = TestAlloc(cbInfo)))
  243. return NULL;
  244. if (!CryptDecodeObject(
  245. dwCertEncodingType,
  246. lpszStructType,
  247. pbEncoded,
  248. cbEncoded,
  249. 0, // dwFlags
  250. pvInfo,
  251. &cbInfo
  252. )) {
  253. if ((DWORD_PTR) lpszStructType <= 0xFFFF)
  254. printf("CryptDecodeObject(StructType: %d)",
  255. (DWORD)(DWORD_PTR) lpszStructType);
  256. else
  257. printf("CryptDecodeObject(StructType: %s)",
  258. lpszStructType);
  259. PrintLastError("");
  260. TestFree(pvInfo);
  261. return NULL;
  262. }
  263. return pvInfo;
  264. }
  265. static BOOL DecodeName(BYTE *pbEncoded, DWORD cbEncoded, DWORD dwStrType)
  266. {
  267. BOOL fResult;
  268. PCERT_NAME_INFO pInfo = NULL;
  269. DWORD i,j;
  270. PCERT_RDN pRDN;
  271. PCERT_RDN_ATTR pAttr;
  272. CERT_NAME_BLOB Name;
  273. DWORD cwsz;
  274. LPWSTR pwsz;
  275. if (NULL == (pInfo = (PCERT_NAME_INFO) TestDecodeObject(
  276. X509_NAME,
  277. pbEncoded,
  278. cbEncoded
  279. ))) goto ErrorReturn;
  280. for (i = 0, pRDN = pInfo->rgRDN; i < pInfo->cRDN; i++, pRDN++) {
  281. for (j = 0, pAttr = pRDN->rgRDNAttr; j < pRDN->cRDNAttr; j++, pAttr++) {
  282. LPSTR pszObjId = pAttr->pszObjId;
  283. if (pszObjId == NULL)
  284. pszObjId = "<NULL OBJID>";
  285. printf(" [%d,%d] %s ValueType: %d\n",
  286. i, j, pszObjId, pAttr->dwValueType);
  287. if (pAttr->Value.cbData)
  288. PrintBytes(" ", pAttr->Value.pbData, pAttr->Value.cbData);
  289. else
  290. printf(" NO Value Bytes\n");
  291. }
  292. }
  293. if (dwStrType == 0xFFFFFFFF)
  294. goto GoodReturn;
  295. Name.pbData = pbEncoded;
  296. Name.cbData = cbEncoded;
  297. if (0 == (dwStrType & 0xFFFF))
  298. dwStrType |= CERT_X500_NAME_STR;
  299. cwsz = CertNameToStrW(
  300. dwCertEncodingType,
  301. &Name,
  302. dwStrType,
  303. NULL, // pwsz
  304. 0); // cwsz
  305. if (pwsz = (LPWSTR) TestAlloc(cwsz * sizeof(WCHAR))) {
  306. CertNameToStrW(
  307. dwCertEncodingType,
  308. &Name,
  309. dwStrType,
  310. pwsz,
  311. cwsz);
  312. printf(" %S\n", pwsz);
  313. TestFree(pwsz);
  314. }
  315. GoodReturn:
  316. fResult = TRUE;
  317. goto CommonReturn;
  318. ErrorReturn:
  319. fResult = FALSE;
  320. CommonReturn:
  321. if (pInfo)
  322. TestFree(pInfo);
  323. return fResult;
  324. }
  325. static void ParseUnicodeX500Name(
  326. IN LPCWSTR pwszName,
  327. IN DWORD dwStrFlags
  328. )
  329. {
  330. BOOL fResult;
  331. DWORD i;
  332. BYTE *pbEncoded;
  333. DWORD cbEncoded;
  334. CERT_NAME_BLOB Name;
  335. DWORD cwsz;
  336. LPWSTR pwsz;
  337. printf("Unicode name::\n");
  338. PrintWords(" ", (WORD *) pwszName, wcslen(pwszName));
  339. fResult = CertStrToNameW(
  340. dwCertEncodingType,
  341. pwszName,
  342. dwStrFlags | 0, // dwStrType
  343. NULL, // pvReserved
  344. NULL, // pbEncoded
  345. &cbEncoded,
  346. NULL // pwszError
  347. );
  348. if (!fResult) {
  349. PrintLastError("CertStrToNameW");
  350. return;
  351. }
  352. if (NULL == (pbEncoded = (BYTE *) TestAlloc(cbEncoded)))
  353. return;
  354. if (!CertStrToNameW(
  355. dwCertEncodingType,
  356. pwszName,
  357. dwStrFlags | 0, // dwStrType
  358. NULL, // pvReserved
  359. pbEncoded,
  360. &cbEncoded,
  361. NULL // pwszError
  362. ))
  363. PrintLastError("CertStrToNameW");
  364. else if (fVerbose)
  365. DecodeName(pbEncoded, cbEncoded, 0xFFFFFFFF);
  366. // Decode name to see if we come up with what was passed in
  367. Name.pbData = pbEncoded;
  368. Name.cbData = cbEncoded;
  369. cwsz = CertNameToStrW(
  370. dwCertEncodingType,
  371. &Name,
  372. dwStrFlags | CERT_X500_NAME_STR,
  373. NULL, // pwsz
  374. 0); // cwsz
  375. if (pwsz = (LPWSTR) TestAlloc(cwsz * sizeof(WCHAR))) {
  376. cwsz = CertNameToStrW(
  377. dwCertEncodingType,
  378. &Name,
  379. dwStrFlags | CERT_X500_NAME_STR,
  380. pwsz,
  381. cwsz);
  382. cwsz--;
  383. if (cwsz != wcslen(pwszName)) {
  384. printf(" failed => CertNameToStrW length of %d != %d\n",
  385. cwsz, wcslen(pwszName));
  386. PrintWords(" ", (WORD *) pwsz, cwsz);
  387. } else if (0 != memcmp(pwsz, pwszName, cwsz * sizeof(WCHAR))) {
  388. printf(" failed => CertNameToStrW didn't match input\n");
  389. PrintWords(" ", (WORD *) pwsz, cwsz);
  390. }
  391. TestFree(pwsz);
  392. }
  393. TestFree(pbEncoded);
  394. }
  395. typedef struct _X500_NAMES {
  396. LPCSTR pszName;
  397. DWORD dwStrType;
  398. DWORD dwErr; // 0 => expect success
  399. int iErrOffset; // -1 => expect NULL pszError
  400. } X500_NAMES, *PX500_NAMES;
  401. // 1 2 3 4 5 6
  402. // 0123456789012345678901234567890123456789012345678901234567890
  403. static const X500_NAMES rgX500Names[] = {
  404. "CN=Joe Cool", 0, 0, -1,
  405. "CN=Joe Cool;", 0, 0, -1,
  406. "CN=Joe Cool,", 0, 0, -1,
  407. "CN=Joe Cool+ ", 0, 0, -1,
  408. "Cn=Joe Cool+T= + ", 0, 0, -1,
  409. "cn=Joe Cool+t= , ", 0, 0, -1,
  410. "cn=\"Joe Cool ,;+\"\"-#\t<>=\"", 0, 0, -1,
  411. "cN=Joe Cool + T = Programmer; OU= Micro , OiD.1.2.3.4=#01 02", 0, 0, -1,
  412. " 1.2.3.4 = # 0123456789abcdef 13 + SN = wow", 0, 0, -1,
  413. "1.2.3.4=\"# 0123456789abcdef 13 string not octet\" + oid.1.2.3.4.1=#0123456789abcdef13 + SN = wow", 0, 0, -1,
  414. "oiD.1.2.3.4.5=#12\t34 \t45 \t 78;1.2.3=#45; 1.2.3.1=#87", 0, 0, -1,
  415. "C=US; L=Internet; St=Washington + Street=Microsoft Way", 0, 0, -1,
  416. "C=U#; L=Internet; Street=Microsoft Way", 0,
  417. (DWORD) CRYPT_E_INVALID_PRINTABLE_STRING, 3,
  418. "[email protected]", 0, 0, -1,
  419. "Email=joe\xB0[email protected]", 0,
  420. (DWORD) CRYPT_E_INVALID_IA5_STRING, 9,
  421. "C=US; OU=Microsoft; St=Way + L= Internet + Email=joe\xB0[email protected]",
  422. 0, (DWORD) CRYPT_E_INVALID_IA5_STRING, 53,
  423. "C=US; OU=Microsoft; St=Way + L= Internet + [email protected]",
  424. 0, 0, -1,
  425. "Email=\"\"\"Cool\"\" Guy\xB0@microsoft.com\"",
  426. 0, (DWORD) CRYPT_E_INVALID_IA5_STRING, 19,
  427. "C=US; OU=Microsoft; St=Way + L= Internet + Email=\"\"\"Cool\"\" Guy\xB0@microsoft.com\"",
  428. 0, (DWORD) CRYPT_E_INVALID_IA5_STRING, 64,
  429. "C=US; OU=Microsoft; St=Way + L= Internet + Email=\"\"\"Cool\"\" [email protected]\"",
  430. 0, 0, -1,
  431. "T = Numeric ; 2.5.4.24=0123456789 0123456789", 0, 0, -1,
  432. "T = Bad Numeric ; 2.5.4.24=0123456789abcdef 0123456789",
  433. 0, (DWORD) CRYPT_E_INVALID_NUMERIC_STRING, 37,
  434. " CN = \" Joe \"\"Cool\"\"\" ", 0, 0, -1,
  435. " CN = \" Joe \"\"Cool\"\" \" ;T=quoted lead and trail spaces ",
  436. 0, 0, -1,
  437. "CN = Joe \"Cool\" ", (DWORD) CERT_NAME_STR_NO_QUOTING_FLAG, 0, -1,
  438. "CN=Joe \"\"Cool\"\" ", 0, (DWORD) CRYPT_E_INVALID_X500_STRING, 7,
  439. " CN = \"Joe \"\"Cool\"\" ", 0, (DWORD) CRYPT_E_INVALID_X500_STRING, 9,
  440. "CM=Joe Cool", 0, (DWORD) CRYPT_E_INVALID_X500_STRING, 0,
  441. "Cn=Joe Cool, Ox=wrong",
  442. 0, (DWORD) CRYPT_E_INVALID_X500_STRING, 13,
  443. "OID.1.2=#01 02 g", 0, (DWORD) CRYPT_E_INVALID_X500_STRING, 8,
  444. "1.2=# ; T= empty ascii hex", 0, (DWORD) CRYPT_E_INVALID_X500_STRING, 4,
  445. "OID.1.2=#00; OID.1..3.1=#01; T=Consecutive dots",
  446. 0, (DWORD) CRYPT_E_INVALID_X500_STRING, 13,
  447. "1.2=#f; T= Odd ascii hex", 0, 0, -1,
  448. "1.2=#12e; T= Odd ascii hex", 0, 0, -1,
  449. "CN = Joe, Cool ; OU = Microsoft, xyz; T=CERT_NAME_STR_SEMICOLON_FLAG",
  450. CERT_NAME_STR_SEMICOLON_FLAG, 0, -1,
  451. "CN = Joe, Cool ; OU = Microsoft, xyz",
  452. 0, (DWORD) CRYPT_E_INVALID_X500_STRING, 10,
  453. "CN = Joe; Cool , OU = Microsoft; xyz, T=CERT_NAME_STR_COMMA_FLAG",
  454. CERT_NAME_STR_COMMA_FLAG, 0, -1,
  455. "CN = Joe; Cool , OU = Microsoft; xyz",
  456. 0, (DWORD) CRYPT_E_INVALID_X500_STRING, 10,
  457. "CN = Joe, Cool ; More stuff \n OU = Microsoft; xyz \nT=CERT_NAME_STR_CRLF_FLAG",
  458. CERT_NAME_STR_CRLF_FLAG, 0, -1,
  459. "CN = Joe, Cool ; More stuff \n OU = Microsoft; xyz",
  460. 0, (DWORD) CRYPT_E_INVALID_X500_STRING, 10,
  461. "CN = Joe Cool + more cool ; L= Wa + more local; T=CERT_NAME_STR_NO_PLUS_FLAG",
  462. CERT_NAME_STR_NO_PLUS_FLAG, 0, -1,
  463. "CN = Joe Cool + more cool ; L= Wa + more local;",
  464. 0, (DWORD) CRYPT_E_INVALID_X500_STRING, 16,
  465. "CN = Joe Cool , OU = Microsoft xyz T=IgnoredEqualDelimiter",
  466. 0, 0, -1,
  467. "CN = Joe Cool; T=CERT_SIMPLE_NAME_STR",
  468. CERT_SIMPLE_NAME_STR, (DWORD) E_INVALIDARG, -1,
  469. "CN=xyz; =; T=EmptyX500Key",
  470. 0, (DWORD) CRYPT_E_INVALID_X500_STRING, 8,
  471. "O", 0, (DWORD) CRYPT_E_INVALID_X500_STRING, 0,
  472. "", 0, 0, -1
  473. };
  474. #define NX500NAMES (sizeof(rgX500Names) / sizeof(rgX500Names[0]))
  475. static void ParsePredefinedX500Names()
  476. {
  477. // Note, fffe and ffff aren't valid UTF8 characters
  478. LPWSTR pwszUnicodeName =
  479. L"DC=microsoft, "
  480. L"DC=com, "
  481. L"DC=\x0001 \x0002 \x007e \x007f, "
  482. L"DC=\x0080 \x0081 \x07fe \x07ff, "
  483. L"DC=\x0800 \x0801 \xfffc \xfffd, "
  484. L"CN=UNICODE, "
  485. L"OID.1.2.3.1=\x0001 \x0002 \x007e \x007f, "
  486. L"OID.1.2.3.2=\x0080 \x0081 \x07fe \x07ff, "
  487. L"OID.1.2.3.3=\x0800 \x0801 \xfffc \xfffd"
  488. ;
  489. WCHAR rgwszUnicode[3 + 1 + 0xFFFC + 1 + 1 + 1];
  490. DWORD i;
  491. DWORD j;
  492. wcscpy(rgwszUnicode, L"CN=\"");
  493. j = 4;
  494. for (i = 1; i <= 0xFF; i++) {
  495. rgwszUnicode[j++] = (WCHAR) i;
  496. if ((WCHAR) i == L'\"')
  497. rgwszUnicode[j++] = L'\"';
  498. }
  499. for (i = 0x7E0; i <= 0x820; i++)
  500. rgwszUnicode[j++] = (WCHAR) i;
  501. for (i = 0xFFE0; i <= 0xFFFD; i++)
  502. rgwszUnicode[j++] = (WCHAR) i;
  503. rgwszUnicode[j] = L'\0';
  504. wcscat(rgwszUnicode, L"\"");
  505. for (i = 0; i < NX500NAMES; i++)
  506. ParseX500Name(
  507. rgX500Names[i].pszName,
  508. rgX500Names[i].dwStrType,
  509. rgX500Names[i].dwErr,
  510. rgX500Names[i].iErrOffset
  511. );
  512. for (i = 0; i < NX500NAMES; i++)
  513. ParseX500Name(
  514. rgX500Names[i].pszName,
  515. rgX500Names[i].dwStrType | CERT_NAME_STR_REVERSE_FLAG,
  516. rgX500Names[i].dwErr,
  517. rgX500Names[i].iErrOffset
  518. );
  519. ParseUnicodeX500Name(pwszUnicodeName, 0);
  520. ParseUnicodeX500Name(pwszUnicodeName,
  521. CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG);
  522. ParseUnicodeX500Name(pwszUnicodeName,
  523. CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG |
  524. CERT_NAME_STR_DISABLE_IE4_UTF8_FLAG);
  525. ParseUnicodeX500Name(pwszUnicodeName,
  526. CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG);
  527. ParseUnicodeX500Name(pwszUnicodeName,
  528. CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG |
  529. CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG);
  530. ParseUnicodeX500Name(rgwszUnicode, 0);
  531. ParseUnicodeX500Name(rgwszUnicode,
  532. CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG);
  533. ParseUnicodeX500Name(rgwszUnicode,
  534. CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG |
  535. CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG);
  536. }
  537. static void ParseX500Name(
  538. IN LPCSTR pszName,
  539. IN DWORD dwStrType,
  540. IN DWORD dwExpectedErr,
  541. IN int iExpectedErrOffset
  542. )
  543. {
  544. BOOL fResult;
  545. DWORD i;
  546. BYTE *pbEncoded;
  547. DWORD cbEncoded;
  548. LPCSTR pszError;
  549. printf("<%s>\n", pszName);
  550. fResult = CertStrToNameA(
  551. dwCertEncodingType,
  552. pszName,
  553. dwStrType,
  554. NULL, // pvReserved
  555. NULL, // pbEncoded
  556. &cbEncoded,
  557. &pszError
  558. );
  559. if (!fResult) {
  560. DWORD dwErr = GetLastError();
  561. if (0 == dwExpectedErr)
  562. printf(" failed => unexpected error %d 0x%x\n", dwErr, dwErr);
  563. else if (dwErr != dwExpectedErr)
  564. printf(" failed => expected error %d 0x%x got %d 0x%x\n",
  565. dwExpectedErr, dwExpectedErr, dwErr, dwErr);
  566. if (pszError) {
  567. int iErrOffset = (int)(INT_PTR) (pszError - pszName);
  568. LPSTR pszNameErr = (LPSTR) _alloca(iErrOffset + 1 + 1);
  569. memcpy(pszNameErr, pszName, iErrOffset + 1);
  570. pszNameErr[iErrOffset + 1] = '\0';
  571. printf(" Error at offset %d <%s\n", iErrOffset, pszNameErr);
  572. if (iExpectedErrOffset < 0)
  573. printf(" failed => unexpected error offset\n");
  574. else if (iExpectedErrOffset != iErrOffset)
  575. printf(" failed => expected error offset %d\n",
  576. iExpectedErrOffset);
  577. } else if (iExpectedErrOffset >= 0)
  578. printf(" failed => expected error offset %d\n",
  579. iExpectedErrOffset);
  580. } else if (dwExpectedErr)
  581. printf(" failed => expected error %d 0x%x\n",
  582. dwExpectedErr, dwExpectedErr);
  583. else {
  584. if (NULL == (pbEncoded = (BYTE *) TestAlloc(cbEncoded)))
  585. return;
  586. if (!CertStrToNameA(
  587. dwCertEncodingType,
  588. pszName,
  589. dwStrType,
  590. NULL, // pvReserved
  591. pbEncoded,
  592. &cbEncoded,
  593. &pszError
  594. ))
  595. PrintLastError("CertStrToName");
  596. else {
  597. if (pszError != NULL)
  598. printf(" failed => expected NULL pszError\n");
  599. if (fVerbose)
  600. DecodeName(pbEncoded, cbEncoded, dwStrType);
  601. }
  602. TestFree(pbEncoded);
  603. }
  604. }
  605. static LPWSTR NameToStr(
  606. IN PCERT_NAME_BLOB pName,
  607. IN DWORD dwStrType
  608. )
  609. {
  610. DWORD cwsz;
  611. LPWSTR pwsz;
  612. cwsz = CertNameToStrW(
  613. dwCertEncodingType,
  614. pName,
  615. dwStrType,
  616. NULL, // pwsz
  617. 0); // cwsz
  618. if (cwsz <= 1) {
  619. PrintLastError("CertNameToStr");
  620. return NULL;
  621. }
  622. if (pwsz = (LPWSTR) TestAlloc(cwsz * sizeof(WCHAR))) {
  623. cwsz = CertNameToStrW(
  624. dwCertEncodingType,
  625. pName,
  626. dwStrType,
  627. pwsz,
  628. cwsz);
  629. }
  630. return pwsz;
  631. }
  632. static BOOL StrToName(
  633. IN LPCWSTR pwszName,
  634. IN DWORD dwStrType,
  635. OUT PCERT_NAME_BLOB pName
  636. )
  637. {
  638. BOOL fResult;
  639. LPCWSTR pwszError;
  640. memset(pName, 0, sizeof(*pName));
  641. fResult = CertStrToNameW(
  642. dwCertEncodingType,
  643. pwszName,
  644. dwStrType,
  645. NULL, // pvReserved
  646. NULL, // pbEncoded
  647. &pName->cbData,
  648. &pwszError
  649. );
  650. if (!fResult) {
  651. PrintLastError("CertStrToNameW");
  652. if (pwszError) {
  653. int iErrOffset = (int)(INT_PTR) (pwszError - pwszName);
  654. LPWSTR pwszNameErr = (LPWSTR) _alloca((iErrOffset + 1 + 1) * 2);
  655. memcpy(pwszNameErr, pwszName, (iErrOffset + 1) * 2);
  656. pwszNameErr[iErrOffset + 1] = L'\0';
  657. printf("Error at <%S\n", pwszNameErr);
  658. }
  659. return FALSE;
  660. }
  661. if (NULL == (pName->pbData = (BYTE *) TestAlloc(pName->cbData)))
  662. return FALSE;
  663. fResult = CertStrToNameW(
  664. dwCertEncodingType,
  665. pwszName,
  666. dwStrType,
  667. NULL, // pvReserved
  668. pName->pbData,
  669. &pName->cbData,
  670. NULL // pwszError
  671. );
  672. if (!fResult) {
  673. PrintLastError("CertStrToNameW");
  674. TestFree(pName->pbData);
  675. pName->pbData = NULL;
  676. return FALSE;
  677. }
  678. return TRUE;
  679. }
  680. static void FormatAndParseName(
  681. IN PCERT_NAME_BLOB pName,
  682. IN DWORD dwStrType
  683. )
  684. {
  685. LPWSTR pwszName = NULL;
  686. CERT_NAME_BLOB Name2;
  687. memset(&Name2, 0, sizeof(Name2));
  688. LPWSTR pwszName2 = NULL;
  689. pwszName = NameToStr(pName, dwStrType);
  690. if (NULL == pwszName)
  691. goto ErrorReturn;
  692. printf("<%S>\n", pwszName);
  693. if (!StrToName(pwszName, dwStrType, &Name2))
  694. goto ErrorReturn;
  695. pwszName2 = NameToStr(&Name2, dwStrType);
  696. if (NULL == pwszName2)
  697. goto ErrorReturn;
  698. if (wcslen(pwszName) != wcslen(pwszName2) ||
  699. 0 != wcscmp(pwszName, pwszName2)) {
  700. printf("failed => re-formatted name mismatch\n");
  701. printf("Re-formatted::\n");
  702. printf("<%S>\n", pwszName2);
  703. }
  704. if (pName->cbData != Name2.cbData ||
  705. 0 != memcmp(pName->pbData, Name2.pbData, Name2.cbData)) {
  706. printf("failed => re-encoded name mismatch\n");
  707. printf("Input::\n");
  708. PrintBytes(" ", pName->pbData, pName->cbData);
  709. DecodeName(pName->pbData, pName->cbData, 0xFFFFFFFF);
  710. printf("Re-encoded::\n");
  711. PrintBytes(" ", Name2.pbData, Name2.cbData);
  712. DecodeName(Name2.pbData, Name2.cbData, 0xFFFFFFFF);
  713. }
  714. ErrorReturn:
  715. if (pwszName)
  716. TestFree(pwszName);
  717. if (pwszName2)
  718. TestFree(pwszName2);
  719. if (Name2.pbData)
  720. TestFree(Name2.pbData);
  721. }
  722. static void FormatAndParseCertNames(
  723. IN LPCSTR pszCertFilename,
  724. IN DWORD dwStrType,
  725. IN BOOL fSubject
  726. )
  727. {
  728. CERT_BLOB Cert;
  729. PCCERT_CONTEXT pCertContext = NULL;
  730. PCERT_NAME_BLOB pName;
  731. static DWORD rgdwStrType[] = {
  732. CERT_OID_NAME_STR,
  733. CERT_X500_NAME_STR,
  734. CERT_OID_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG |
  735. CERT_NAME_STR_NO_QUOTING_FLAG,
  736. CERT_X500_NAME_STR | CERT_NAME_STR_NO_QUOTING_FLAG |
  737. CERT_NAME_STR_CRLF_FLAG,
  738. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  739. CERT_X500_NAME_STR | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG |
  740. CERT_NAME_STR_DISABLE_IE4_UTF8_FLAG,
  741. CERT_X500_NAME_STR | CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG,
  742. 0
  743. };
  744. DWORD *pdwStrType;
  745. if (!ReadDERFromFile(pszCertFilename, &Cert.pbData, &Cert.cbData))
  746. return;
  747. if (NULL == (pCertContext = CertCreateCertificateContext(
  748. dwCertEncodingType, Cert.pbData, Cert.cbData))) {
  749. PrintLastError("CertCreateCertificateContext");
  750. goto ErrorReturn;
  751. }
  752. if (fSubject) {
  753. printf("Subject::\n");
  754. pName = &pCertContext->pCertInfo->Subject;
  755. } else {
  756. printf("Issuer::\n");
  757. pName = &pCertContext->pCertInfo->Issuer;
  758. }
  759. if (fVerbose)
  760. DecodeName(pName->pbData, pName->cbData, 0xFFFFFFFF);
  761. if (dwStrType != 0xFFFFFFFF) {
  762. if (dwStrType == 0)
  763. dwStrType = CERT_X500_NAME_STR;
  764. FormatAndParseName(pName, dwStrType);
  765. } else {
  766. pdwStrType = rgdwStrType;
  767. while (dwStrType = *pdwStrType++) {
  768. FormatAndParseName(pName, dwStrType);
  769. printf("\n");
  770. }
  771. }
  772. ErrorReturn:
  773. CertFreeCertificateContext(pCertContext);
  774. TestFree(Cert.pbData);
  775. }
  776. static void GetCertNameFromFile(
  777. IN LPCSTR pszCertFilename,
  778. IN DWORD dwGetNameStringType,
  779. IN LPSTR pszAttrOID,
  780. IN DWORD dwStrType,
  781. IN BOOL fSubject,
  782. IN DWORD dwExpectedErr
  783. )
  784. {
  785. CERT_BLOB Cert;
  786. PCCERT_CONTEXT pCertContext = NULL;
  787. LPWSTR pwsz = NULL;
  788. LPSTR psz = NULL;
  789. DWORD cch;
  790. DWORD dwFlags;
  791. void *pvTypePara;
  792. dwFlags = dwGetNameStringType & 0xFFFF0000;
  793. dwGetNameStringType &= 0x0000FFFF;
  794. switch (dwGetNameStringType) {
  795. case CERT_NAME_RDN_TYPE:
  796. pvTypePara = &dwStrType;
  797. break;
  798. case CERT_NAME_ATTR_TYPE:
  799. pvTypePara = pszAttrOID;
  800. break;
  801. default:
  802. pvTypePara = NULL;
  803. }
  804. if (!ReadDERFromFile(pszCertFilename, &Cert.pbData, &Cert.cbData))
  805. return;
  806. if (NULL == (pCertContext = CertCreateCertificateContext(
  807. dwCertEncodingType, Cert.pbData, Cert.cbData))) {
  808. PrintLastError("CertCreateCertificateContext");
  809. goto ErrorReturn;
  810. }
  811. if (fSubject) {
  812. printf("Unicode Subject::\n");
  813. dwFlags |= 0;
  814. } else {
  815. printf("Unicode Issuer::\n");
  816. dwFlags |= CERT_NAME_ISSUER_FLAG;
  817. }
  818. cch = CertGetNameStringW(
  819. pCertContext,
  820. dwGetNameStringType,
  821. dwFlags,
  822. pvTypePara,
  823. NULL, // pwsz
  824. 0); // cch
  825. if (cch <= 1) {
  826. DWORD dwErr = GetLastError();
  827. printf(" CertGetNameStringW returned empty string\n");
  828. if (0 == dwExpectedErr)
  829. printf(" failed => unexpected error %d 0x%x\n", dwErr, dwErr);
  830. else if (dwErr != dwExpectedErr)
  831. printf(" failed => expected error %d 0x%x got %d 0x%x\n",
  832. dwExpectedErr, dwExpectedErr, dwErr, dwErr);
  833. } else if (dwExpectedErr)
  834. printf(" failed => expected error %d 0x%x\n",
  835. dwExpectedErr, dwExpectedErr);
  836. else if (pwsz = (LPWSTR) TestAlloc(cch * sizeof(WCHAR))) {
  837. cch = CertGetNameStringW(
  838. pCertContext,
  839. dwGetNameStringType,
  840. dwFlags,
  841. pvTypePara,
  842. pwsz,
  843. cch);
  844. printf(" <%S>\n", pwsz);
  845. }
  846. if (!fVerbose)
  847. goto CommonReturn;
  848. if (fSubject) {
  849. printf("ASCII Subject::\n");
  850. dwFlags = 0;
  851. } else {
  852. printf("ASCII Issuer::\n");
  853. dwFlags = CERT_NAME_ISSUER_FLAG;
  854. }
  855. cch = CertGetNameStringA(
  856. pCertContext,
  857. dwGetNameStringType,
  858. dwFlags,
  859. pvTypePara,
  860. NULL, // psz
  861. 0); // cch
  862. if (cch <= 1) {
  863. DWORD dwErr = GetLastError();
  864. printf(" CertGetNameStringA returned empty string\n");
  865. if (0 == dwExpectedErr)
  866. printf(" failed => unexpected error %d 0x%x\n", dwErr, dwErr);
  867. else if (dwErr != dwExpectedErr)
  868. printf(" failed => expected error %d 0x%x got %d 0x%x\n",
  869. dwExpectedErr, dwExpectedErr, dwErr, dwErr);
  870. } else if (dwExpectedErr)
  871. printf(" failed => expected error %d 0x%x\n",
  872. dwExpectedErr, dwExpectedErr);
  873. else if (psz = (LPSTR) TestAlloc(cch)) {
  874. cch = CertGetNameStringA(
  875. pCertContext,
  876. dwGetNameStringType,
  877. dwFlags,
  878. pvTypePara,
  879. psz,
  880. cch);
  881. printf(" <%s>\n", psz);
  882. }
  883. CommonReturn:
  884. ErrorReturn:
  885. CertFreeCertificateContext(pCertContext);
  886. TestFree(Cert.pbData);
  887. TestFree(pwsz);
  888. TestFree(psz);
  889. }