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.

733 lines
20 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 2001 - 2001
  6. //
  7. // File: testutil.cpp
  8. // Contents: Test Utility API Prototypes and Definitions
  9. //
  10. // History: 29-Jan-01 philh created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include <windows.h>
  14. #include <assert.h>
  15. #include "testutil.h"
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <memory.h>
  20. #include <time.h>
  21. #include <stddef.h>
  22. #define TESTUTIL_MAX_EXT_CNT 30
  23. #define TESTUTIL_MAX_ATTR_CNT 30
  24. //+-------------------------------------------------------------------------
  25. // Error output routines
  26. //--------------------------------------------------------------------------
  27. VOID
  28. PrintErr(
  29. IN LPCSTR pszMsg,
  30. IN LONG lErr
  31. )
  32. {
  33. printf("%s failed => 0x%x (%d) \n", pszMsg, lErr, lErr);
  34. }
  35. VOID
  36. PrintLastError(
  37. IN LPCSTR pszMsg
  38. )
  39. {
  40. DWORD dwErr = GetLastError();
  41. printf("%s failed => 0x%x (%d) \n", pszMsg, dwErr, dwErr);
  42. }
  43. //+-------------------------------------------------------------------------
  44. // Test allocation and free routines
  45. //--------------------------------------------------------------------------
  46. LPVOID
  47. TestAlloc(
  48. IN size_t cbBytes
  49. )
  50. {
  51. LPVOID pv;
  52. pv = malloc(cbBytes);
  53. if (pv == NULL)
  54. PrintErr("TestAlloc", (LONG) GetLastError());
  55. return pv;
  56. }
  57. VOID
  58. TestFree(
  59. IN LPVOID pv
  60. )
  61. {
  62. if (pv)
  63. free(pv);
  64. }
  65. CRYPT_DECODE_PARA TestDecodePara = {
  66. offsetof(CRYPT_DECODE_PARA, pfnFree) + sizeof(TestDecodePara.pfnFree),
  67. TestAlloc,
  68. TestFree
  69. };
  70. //+-------------------------------------------------------------------------
  71. // Allocate and convert a multi-byte string to a wide string. TestFree()
  72. // must be called to free the returned wide string.
  73. //--------------------------------------------------------------------------
  74. LPWSTR
  75. AllocAndSzToWsz(
  76. IN LPCSTR psz
  77. )
  78. {
  79. size_t cb;
  80. LPWSTR pwsz = NULL;
  81. if (-1 == (cb = mbstowcs( NULL, psz, strlen(psz))))
  82. goto bad_param;
  83. cb += 1; // terminating NULL
  84. if (NULL == (pwsz = (LPWSTR)TestAlloc( cb * sizeof(WCHAR)))) {
  85. PrintLastError("AllocAndSzToWsz");
  86. goto failed;
  87. }
  88. if (-1 == mbstowcs( pwsz, psz, cb))
  89. goto bad_param;
  90. goto common_return;
  91. bad_param:
  92. printf("failed => Bad AllocAndSzToWsz");
  93. failed:
  94. if (pwsz) {
  95. TestFree(pwsz);
  96. pwsz = NULL;
  97. }
  98. common_return:
  99. return pwsz;
  100. }
  101. //+-------------------------------------------------------------------------
  102. // Conversions functions between encoded OID and the dot string
  103. // representation
  104. //--------------------------------------------------------------------------
  105. #define MAX_OID_STRING_LEN 0x80
  106. #define MAX_ENCODED_OID_LEN 0x80
  107. // Encoded Attribute
  108. //
  109. // Attribute ::= SEQUENCE {
  110. // type EncodedObjectID,
  111. // values AttributeSetValue
  112. // } --#public--
  113. //
  114. // AttributeSetValue ::= SET OF NOCOPYANY
  115. BOOL
  116. EncodedOIDToDot(
  117. IN PCRYPT_DER_BLOB pEncodedOIDBlob,
  118. OUT CHAR rgszOID[MAX_OID_STRING_LEN]
  119. )
  120. {
  121. BOOL fResult;
  122. DWORD cbOID = pEncodedOIDBlob->cbData;
  123. const BYTE *pbOID = pEncodedOIDBlob->pbData;
  124. BYTE rgbEncodedAttr[MAX_ENCODED_OID_LEN];
  125. PCRYPT_ATTRIBUTE pAttr = NULL;
  126. DWORD cbAttr;
  127. // Convert the OID into an encoded Attribute that we can
  128. // decode to get the OID string.
  129. if (0 == cbOID || MAX_OID_STRING_LEN - 6 < cbOID) {
  130. strcpy(rgszOID, "Invalid OID length");
  131. return FALSE;
  132. }
  133. rgbEncodedAttr[0] = MINASN1_TAG_SEQ;
  134. rgbEncodedAttr[1] = (BYTE) (2 + cbOID + 2);
  135. rgbEncodedAttr[2] = MINASN1_TAG_OID;
  136. rgbEncodedAttr[3] = (BYTE) cbOID;
  137. memcpy(&rgbEncodedAttr[4], pbOID, cbOID);
  138. rgbEncodedAttr[4 + cbOID + 0] = MINASN1_TAG_SET;
  139. rgbEncodedAttr[4 + cbOID + 1] = 0;
  140. if (!CryptDecodeObjectEx(
  141. X509_ASN_ENCODING,
  142. PKCS_ATTRIBUTE,
  143. rgbEncodedAttr,
  144. 2 + 2 + cbOID + 2,
  145. CRYPT_DECODE_NOCOPY_FLAG | CRYPT_DECODE_ALLOC_FLAG,
  146. &TestDecodePara,
  147. (void *) &pAttr,
  148. &cbAttr
  149. )) {
  150. strcpy(rgszOID, "Decode OID failed");
  151. return FALSE;
  152. }
  153. if (strlen(pAttr->pszObjId) >= MAX_OID_STRING_LEN) {
  154. strcpy(rgszOID, "Invalid OID length");
  155. fResult = FALSE;
  156. } else {
  157. strcpy(rgszOID, pAttr->pszObjId);
  158. fResult = TRUE;
  159. }
  160. TestFree(pAttr);
  161. return fResult;
  162. }
  163. const BYTE rgbSeqTag[] = {MINASN1_TAG_SEQ, 0};
  164. const BYTE rgbOIDTag[] = {MINASN1_TAG_OID, 0};
  165. const MINASN1_EXTRACT_VALUE_PARA rgExtractAttrPara[] = {
  166. // 0 - Attribute ::= SEQUENCE {
  167. MINASN1_STEP_INTO_VALUE_OP, 0, rgbSeqTag,
  168. // 1 - type EncodedObjectID,
  169. MINASN1_RETURN_CONTENT_BLOB_FLAG | MINASN1_STEP_OVER_VALUE_OP,
  170. 0, rgbOIDTag,
  171. };
  172. #define ATTR_VALUE_COUNT \
  173. (sizeof(rgExtractAttrPara) / sizeof(rgExtractAttrPara[0]))
  174. BOOL
  175. DotToEncodedOID(
  176. IN LPCSTR pszOID,
  177. OUT BYTE rgbEncodedOID[MAX_ENCODED_OID_LEN],
  178. OUT DWORD *pcbEncodedOID
  179. )
  180. {
  181. BOOL fResult;
  182. CRYPT_ATTRIBUTE Attr;
  183. BYTE rgbEncoded[512];
  184. DWORD cbEncoded;
  185. CRYPT_DER_BLOB rgValueBlob[1];
  186. DWORD cValue;
  187. DWORD i;
  188. BYTE *pb;
  189. DWORD cb;
  190. // Encode an Attribute that only has the OID.
  191. Attr.pszObjId = (LPSTR) pszOID;
  192. Attr.cValue = 0;
  193. Attr.rgValue = NULL;
  194. cbEncoded = sizeof(rgbEncoded);
  195. if (!CryptEncodeObject(
  196. X509_ASN_ENCODING,
  197. PKCS_ATTRIBUTE,
  198. &Attr,
  199. rgbEncoded,
  200. &cbEncoded
  201. )) {
  202. printf("\n");
  203. printf("Asn1Encode(%s)", pszOID);
  204. PrintLastError("");
  205. goto ErrorReturn;
  206. }
  207. cValue = ATTR_VALUE_COUNT;
  208. if (0 >= MinAsn1ExtractValues(
  209. rgbEncoded,
  210. cbEncoded,
  211. &cValue,
  212. rgExtractAttrPara,
  213. 1,
  214. rgValueBlob
  215. )) {
  216. printf("Unable to encode OID: %s\n", pszOID);
  217. goto ErrorReturn;
  218. }
  219. pb = rgValueBlob[0].pbData;
  220. cb = rgValueBlob[0].cbData;
  221. if (0 == cb || MAX_ENCODED_OID_LEN < cb) {
  222. printf("Invalid length for OID: %s\n", pszOID);
  223. goto ErrorReturn;
  224. }
  225. memcpy(rgbEncodedOID, pb, cb);
  226. *pcbEncodedOID = cb;
  227. fResult = TRUE;
  228. CommonReturn:
  229. return fResult;
  230. ErrorReturn:
  231. fResult = FALSE;
  232. *pcbEncodedOID = 0;
  233. goto CommonReturn;
  234. }
  235. //+-------------------------------------------------------------------------
  236. // Functions to print bytes
  237. //--------------------------------------------------------------------------
  238. VOID
  239. PrintBytes(
  240. IN PCRYPT_DER_BLOB pBlob
  241. )
  242. {
  243. DWORD cb = pBlob->cbData;
  244. BYTE *pb = pBlob->pbData;
  245. if (0 == cb) {
  246. printf(" No Bytes\n");
  247. return;
  248. }
  249. for (; 0 < cb; cb--, pb++)
  250. printf(" %02X", *pb);
  251. printf("\n");
  252. }
  253. #define CROW 16
  254. VOID
  255. PrintMultiLineBytes(
  256. IN LPCSTR pszHdr,
  257. IN PCRYPT_DER_BLOB pBlob
  258. )
  259. {
  260. DWORD cbSize = pBlob->cbData;
  261. BYTE *pb = pBlob->pbData;
  262. DWORD cb, i;
  263. if (cbSize == 0) {
  264. printf("%s No Bytes\n", pszHdr);
  265. return;
  266. }
  267. while (cbSize > 0)
  268. {
  269. printf("%s", pszHdr);
  270. cb = min(CROW, cbSize);
  271. cbSize -= cb;
  272. for (i = 0; i<cb; i++)
  273. printf(" %02X", pb[i]);
  274. for (i = cb; i<CROW; i++)
  275. printf(" ");
  276. printf(" '");
  277. for (i = 0; i<cb; i++)
  278. if (pb[i] >= 0x20 && pb[i] <= 0x7f)
  279. printf("%c", pb[i]);
  280. else
  281. printf(".");
  282. pb += cb;
  283. printf("'\n");
  284. }
  285. }
  286. //+-------------------------------------------------------------------------
  287. // Allocate and read an encoded DER blob from a file
  288. //--------------------------------------------------------------------------
  289. BOOL
  290. ReadDERFromFile(
  291. IN LPCSTR pszFileName,
  292. OUT PBYTE *ppbDER,
  293. OUT PDWORD pcbDER
  294. )
  295. {
  296. BOOL fRet;
  297. HANDLE hFile = 0;
  298. PBYTE pbDER = NULL;
  299. DWORD cbDER;
  300. DWORD cbRead;
  301. if( INVALID_HANDLE_VALUE == (hFile = CreateFile( pszFileName, GENERIC_READ,
  302. FILE_SHARE_READ | FILE_SHARE_WRITE,
  303. NULL, OPEN_EXISTING, 0, NULL))) {
  304. printf( "can't open %s\n", pszFileName);
  305. goto ErrorReturn;
  306. }
  307. cbDER = GetFileSize( hFile, NULL);
  308. if (cbDER == 0) {
  309. printf( "empty file %s\n", pszFileName);
  310. goto ErrorReturn;
  311. }
  312. if (NULL == (pbDER = (PBYTE)TestAlloc(cbDER))) {
  313. printf( "can't alloc %d bytes\n", cbDER);
  314. goto ErrorReturn;
  315. }
  316. if (!ReadFile( hFile, pbDER, cbDER, &cbRead, NULL) ||
  317. (cbRead != cbDER)) {
  318. printf( "can't read %s\n", pszFileName);
  319. goto ErrorReturn;
  320. }
  321. *ppbDER = pbDER;
  322. *pcbDER = cbDER;
  323. fRet = TRUE;
  324. CommonReturn:
  325. if (hFile)
  326. CloseHandle(hFile);
  327. return fRet;
  328. ErrorReturn:
  329. if (pbDER)
  330. TestFree(pbDER);
  331. *ppbDER = NULL;
  332. *pcbDER = 0;
  333. fRet = FALSE;
  334. goto CommonReturn;
  335. }
  336. //+-------------------------------------------------------------------------
  337. // Write an encoded DER blob to a file
  338. //--------------------------------------------------------------------------
  339. BOOL
  340. WriteDERToFile(
  341. IN LPCSTR pszFileName,
  342. IN PBYTE pbDER,
  343. IN DWORD cbDER
  344. )
  345. {
  346. BOOL fResult;
  347. // Write the Encoded Blob to the file
  348. HANDLE hFile;
  349. hFile = CreateFile(pszFileName,
  350. GENERIC_WRITE,
  351. 0, // fdwShareMode
  352. NULL, // lpsa
  353. CREATE_ALWAYS,
  354. 0, // fdwAttrsAndFlags
  355. 0); // TemplateFile
  356. if (INVALID_HANDLE_VALUE == hFile) {
  357. fResult = FALSE;
  358. PrintLastError("WriteDERToFile::CreateFile");
  359. } else {
  360. DWORD dwBytesWritten;
  361. if (!(fResult = WriteFile(
  362. hFile,
  363. pbDER,
  364. cbDER,
  365. &dwBytesWritten,
  366. NULL // lpOverlapped
  367. )))
  368. PrintLastError("WriteDERToFile::WriteFile");
  369. CloseHandle(hFile);
  370. }
  371. return fResult;
  372. }
  373. //+-------------------------------------------------------------------------
  374. // Display functions
  375. //--------------------------------------------------------------------------
  376. VOID
  377. DisplayCert(
  378. IN CRYPT_DER_BLOB rgCertBlob[MINASN1_CERT_BLOB_CNT],
  379. IN BOOL fVerbose
  380. )
  381. {
  382. if (0 != rgCertBlob[MINASN1_CERT_VERSION_IDX].cbData) {
  383. printf("Version:");
  384. PrintBytes(&rgCertBlob[MINASN1_CERT_VERSION_IDX]);
  385. }
  386. printf("Subject:");
  387. DisplayName(&rgCertBlob[MINASN1_CERT_SUBJECT_IDX]);
  388. printf("Issuer:");
  389. DisplayName(&rgCertBlob[MINASN1_CERT_ISSUER_IDX]);
  390. printf("SerialNumber:");
  391. PrintBytes(&rgCertBlob[MINASN1_CERT_SERIAL_NUMBER_IDX]);
  392. printf("NotBefore:\n");
  393. PrintMultiLineBytes(" ", &rgCertBlob[MINASN1_CERT_NOT_BEFORE_IDX]);
  394. printf("NotAfter:\n");
  395. PrintMultiLineBytes(" ", &rgCertBlob[MINASN1_CERT_NOT_AFTER_IDX]);
  396. if (0 != rgCertBlob[MINASN1_CERT_ISSUER_UNIQUE_ID_IDX].cbData) {
  397. printf("IssuerUniqueId:\n");
  398. PrintMultiLineBytes(" ",
  399. &rgCertBlob[MINASN1_CERT_ISSUER_UNIQUE_ID_IDX]);
  400. }
  401. if (0 != rgCertBlob[MINASN1_CERT_SUBJECT_UNIQUE_ID_IDX].cbData) {
  402. printf("SubjectUniqueId:\n");
  403. PrintMultiLineBytes(" ",
  404. &rgCertBlob[MINASN1_CERT_SUBJECT_UNIQUE_ID_IDX]);
  405. }
  406. if (fVerbose) {
  407. CRYPT_DER_BLOB rgPubKeyInfoBlob[MINASN1_PUBKEY_INFO_BLOB_CNT];
  408. CRYPT_DER_BLOB rgPubKeyAlgIdBlob[MINASN1_ALGID_BLOB_CNT];
  409. CRYPT_DER_BLOB rgSignAlgIdBlob[MINASN1_ALGID_BLOB_CNT];
  410. if (0 >= MinAsn1ParsePublicKeyInfo(
  411. &rgCertBlob[MINASN1_CERT_PUBKEY_INFO_IDX],
  412. rgPubKeyInfoBlob
  413. ) ||
  414. 0 >= MinAsn1ParseAlgorithmIdentifier(
  415. &rgPubKeyInfoBlob[MINASN1_PUBKEY_INFO_ALGID_IDX],
  416. rgPubKeyAlgIdBlob
  417. ))
  418. printf("PublicKeyInfo: parse failed\n");
  419. else {
  420. CHAR rgszOID[MAX_OID_STRING_LEN];
  421. CRYPT_DER_BLOB rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_BLOB_CNT];
  422. EncodedOIDToDot(&rgPubKeyAlgIdBlob[MINASN1_ALGID_OID_IDX],
  423. rgszOID);
  424. printf("PublicKeyInfo.Algorithm: %s\n", rgszOID);
  425. if (0 != rgPubKeyAlgIdBlob[MINASN1_ALGID_PARA_IDX].cbData) {
  426. printf("PublicKeyInfo.Algorithm.Parameters:\n");
  427. PrintMultiLineBytes(" ",
  428. &rgPubKeyAlgIdBlob[MINASN1_ALGID_PARA_IDX]);
  429. }
  430. if (0 >= MinAsn1ParseRSAPublicKey(
  431. &rgPubKeyInfoBlob[MINASN1_PUBKEY_INFO_PUBKEY_IDX],
  432. rgRSAPubKeyBlob
  433. )) {
  434. printf("PublicKeyInfo.PublicKey:\n");
  435. PrintMultiLineBytes(" ",
  436. &rgPubKeyInfoBlob[MINASN1_PUBKEY_INFO_PUBKEY_IDX]);
  437. } else {
  438. DWORD dwByteLen;
  439. dwByteLen =
  440. rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_MODULUS_IDX].cbData;
  441. if (0 < dwByteLen && 0 == rgRSAPubKeyBlob[
  442. MINASN1_RSA_PUBKEY_MODULUS_IDX].pbData[0])
  443. dwByteLen--;
  444. printf("PublicKeyInfo.RSAPublicKey.BitLength: %d\n",
  445. dwByteLen * 8);
  446. printf("PublicKeyInfo.RSAPublicKey.Modulus:\n");
  447. PrintMultiLineBytes(" ",
  448. &rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_MODULUS_IDX]);
  449. printf("PublicKeyInfo.RSAPublicKey.Exponent:");
  450. PrintBytes(&rgRSAPubKeyBlob[MINASN1_RSA_PUBKEY_EXPONENT_IDX]);
  451. }
  452. }
  453. if ( 0 >= MinAsn1ParseAlgorithmIdentifier(
  454. &rgCertBlob[MINASN1_CERT_SIGN_ALGID_IDX],
  455. rgSignAlgIdBlob
  456. ))
  457. printf("SignatureAlgorithm: parse failed\n");
  458. else {
  459. CHAR rgszOID[MAX_OID_STRING_LEN];
  460. EncodedOIDToDot(&rgSignAlgIdBlob[MINASN1_ALGID_OID_IDX],
  461. rgszOID);
  462. printf("Signature.Algorithm: %s\n", rgszOID);
  463. if (0 != rgSignAlgIdBlob[MINASN1_ALGID_PARA_IDX].cbData) {
  464. printf("Signature.Algorithm.Parameters:\n");
  465. PrintMultiLineBytes(" ",
  466. &rgSignAlgIdBlob[MINASN1_ALGID_PARA_IDX]);
  467. }
  468. }
  469. printf("Signature.Content\n");
  470. PrintMultiLineBytes(" ", &rgCertBlob[MINASN1_CERT_SIGNATURE_IDX]);
  471. DisplayExts(&rgCertBlob[MINASN1_CERT_EXTS_IDX]);
  472. }
  473. }
  474. VOID
  475. DisplayName(
  476. IN PCRYPT_DER_BLOB pNameValueBlob
  477. )
  478. {
  479. WCHAR wszName[512];
  480. CertNameToStrW(
  481. X509_ASN_ENCODING,
  482. pNameValueBlob,
  483. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  484. wszName,
  485. 512
  486. );
  487. printf(" <%S>\n", wszName);
  488. }
  489. VOID
  490. DisplayExts(
  491. IN PCRYPT_DER_BLOB pExtsValueBlob
  492. )
  493. {
  494. DWORD cExt;
  495. DWORD i;
  496. CRYPT_DER_BLOB rgrgExtBlob[TESTUTIL_MAX_EXT_CNT][MINASN1_EXT_BLOB_CNT];
  497. if (0 == pExtsValueBlob->cbData)
  498. return;
  499. cExt = TESTUTIL_MAX_EXT_CNT;
  500. if (0 >= MinAsn1ParseExtensions(
  501. pExtsValueBlob,
  502. &cExt,
  503. rgrgExtBlob
  504. )) {
  505. printf("Extensions: parse failed\n");
  506. return;
  507. }
  508. for (i = 0; i < cExt; i++) {
  509. CHAR rgszOID[MAX_OID_STRING_LEN];
  510. EncodedOIDToDot(&rgrgExtBlob[i][MINASN1_EXT_OID_IDX], rgszOID);
  511. printf("Extension[%d] %s Critical: ", i, rgszOID);
  512. if (0 != rgrgExtBlob[i][MINASN1_EXT_CRITICAL_IDX].cbData &&
  513. 0 != rgrgExtBlob[i][MINASN1_EXT_CRITICAL_IDX].pbData[0])
  514. printf("TRUE\n");
  515. else
  516. printf("FALSE\n");
  517. PrintMultiLineBytes(" ", &rgrgExtBlob[i][MINASN1_EXT_VALUE_IDX]);
  518. }
  519. }
  520. VOID
  521. DisplayCTL(
  522. IN PCRYPT_DER_BLOB pEncodedContentBlob,
  523. IN BOOL fVerbose
  524. )
  525. {
  526. CRYPT_DER_BLOB rgCTLBlob[MINASN1_CTL_BLOB_CNT];
  527. if (0 >= MinAsn1ParseCTL(
  528. pEncodedContentBlob,
  529. rgCTLBlob
  530. )) {
  531. printf("CTL: parse failed\n");
  532. return;
  533. }
  534. if (0 != rgCTLBlob[MINASN1_CTL_VERSION_IDX].cbData) {
  535. printf("Version:");
  536. PrintBytes(&rgCTLBlob[MINASN1_CTL_VERSION_IDX]);
  537. }
  538. printf("SubjectUsage:\n");
  539. PrintMultiLineBytes(" ", &rgCTLBlob[MINASN1_CTL_SUBJECT_USAGE_IDX]);
  540. if (0 != rgCTLBlob[MINASN1_CTL_LIST_ID_IDX].cbData) {
  541. printf("ListIdentifier:\n");
  542. PrintMultiLineBytes(" ", &rgCTLBlob[MINASN1_CTL_LIST_ID_IDX]);
  543. }
  544. if (0 != rgCTLBlob[MINASN1_CTL_SEQUENCE_NUMBER_IDX].cbData) {
  545. printf("SequenceNumber:");
  546. PrintBytes(&rgCTLBlob[MINASN1_CTL_SEQUENCE_NUMBER_IDX]);
  547. }
  548. printf("ThisUpdate:\n");
  549. PrintMultiLineBytes(" ", &rgCTLBlob[MINASN1_CTL_THIS_UPDATE_IDX]);
  550. if (0 != rgCTLBlob[MINASN1_CTL_NEXT_UPDATE_IDX].cbData) {
  551. printf("NextUpdate:\n");
  552. PrintMultiLineBytes(" ", &rgCTLBlob[MINASN1_CTL_NEXT_UPDATE_IDX]);
  553. }
  554. printf("SubjectAlgorithmIdentifier:\n");
  555. PrintMultiLineBytes(" ", &rgCTLBlob[MINASN1_CTL_SUBJECT_ALGID_IDX]);
  556. if (fVerbose)
  557. DisplayExts(&rgCTLBlob[MINASN1_CTL_EXTS_IDX]);
  558. if (0 != rgCTLBlob[MINASN1_CTL_SUBJECTS_IDX].cbData) {
  559. DWORD cbEncoded;
  560. const BYTE *pbEncoded;
  561. DWORD i;
  562. printf("\n");
  563. // Advance past the Subjects' outer tag and length
  564. if (0 >= MinAsn1ExtractContent(
  565. rgCTLBlob[MINASN1_CTL_SUBJECTS_IDX].pbData,
  566. rgCTLBlob[MINASN1_CTL_SUBJECTS_IDX].cbData,
  567. &cbEncoded,
  568. &pbEncoded
  569. )) {
  570. printf("Subjects: parse failed\n");
  571. return;
  572. }
  573. // Loop through the encoded subjects
  574. for (i = 0; 0 != cbEncoded; i++) {
  575. LONG cbSubject;
  576. CRYPT_DER_BLOB rgCTLSubjectBlob[MINASN1_CTL_SUBJECT_BLOB_CNT];
  577. printf("---- Subject[%d] ----\n", i);
  578. cbSubject = MinAsn1ParseCTLSubject(
  579. pbEncoded,
  580. cbEncoded,
  581. rgCTLSubjectBlob
  582. );
  583. if (0 >= cbSubject) {
  584. printf("Subject: parse failed\n");
  585. return;
  586. }
  587. printf("Identifier:\n");
  588. PrintMultiLineBytes(" ",
  589. &rgCTLSubjectBlob[MINASN1_CTL_SUBJECT_ID_IDX]);
  590. if (fVerbose) {
  591. DisplayAttrs("",
  592. &rgCTLSubjectBlob[MINASN1_CTL_SUBJECT_ATTRS_IDX]);
  593. printf("\n");
  594. }
  595. pbEncoded += cbSubject;
  596. cbEncoded -= cbSubject;
  597. }
  598. }
  599. }
  600. VOID
  601. DisplayAttrs(
  602. IN LPCSTR pszHdr,
  603. IN PCRYPT_DER_BLOB pAttrsValueBlob
  604. )
  605. {
  606. DWORD cAttr;
  607. DWORD i;
  608. CRYPT_DER_BLOB rgrgAttrBlob[TESTUTIL_MAX_ATTR_CNT][MINASN1_ATTR_BLOB_CNT];
  609. if (0 == pAttrsValueBlob->cbData)
  610. return;
  611. cAttr = TESTUTIL_MAX_ATTR_CNT;
  612. if (0 >= MinAsn1ParseAttributes(
  613. pAttrsValueBlob,
  614. &cAttr,
  615. rgrgAttrBlob
  616. )) {
  617. printf("%sAttributes: parse failed\n", pszHdr);
  618. return;
  619. }
  620. for (i = 0; i < cAttr; i++) {
  621. CHAR rgszOID[MAX_OID_STRING_LEN];
  622. EncodedOIDToDot(&rgrgAttrBlob[i][MINASN1_ATTR_OID_IDX], rgszOID);
  623. printf("%sAttribute[%d] %s:\n", pszHdr, i, rgszOID);
  624. PrintMultiLineBytes(" ", &rgrgAttrBlob[i][MINASN1_ATTR_VALUE_IDX]);
  625. }
  626. }