Source code of Windows XP (NT5)
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.

2117 lines
44 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: certgen.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include <pch.cpp>
  11. #pragma hdrstop
  12. #include <conio.h>
  13. #include "encode.h"
  14. #include "rsa.h"
  15. #include "md5.h"
  16. #include <wincrypt.h>
  17. #include <certsrv.h>
  18. #include <certca.h>
  19. #include <csdisp.h>
  20. #include "csprop.h"
  21. #define MSTOSEC(ms) (((ms) + 1000 - 1)/1000)
  22. DWORD g_crdnMax;
  23. HCRYPTPROV g_hMe = NULL;
  24. WCHAR g_wszTestKey[] = L"CertGen_TestKey";
  25. static unsigned char MD5_PRELUDE[] = {
  26. 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,
  27. 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00,
  28. 0x04, 0x10
  29. };
  30. BYTE g_CAPIPrivateKey[1000];
  31. DWORD g_cbPrivateKey;
  32. //LPBSAFE_PRV_KEY g_pRSAPrivateKey;
  33. DWORD g_cbRSAPrivateKey;
  34. LPBSAFE_PUB_KEY g_pRSAPublicKey;
  35. DWORD g_cbRSAPublicKey;
  36. WCHAR *g_pwszConfig = NULL;
  37. typedef struct {
  38. DWORD magic; // Should always be RSA2
  39. DWORD bitlen; // bit size of key
  40. DWORD pubexp; // public exponent
  41. } EXPORT_PRV_KEY;
  42. BOOL g_fRPC = FALSE;
  43. BOOL g_fRenewal = FALSE;
  44. BOOL g_fSave = FALSE;
  45. BOOL g_fPrintProperties = FALSE;
  46. BOOL g_fDebug = FALSE;
  47. BOOL g_fIgnoreAccessDenied = FALSE;
  48. BOOL g_fTime = FALSE;
  49. BOOL g_fIgnoreError = FALSE;
  50. BOOL g_fAllowDups = FALSE;
  51. BOOL g_fShowTime = FALSE;
  52. LONG g_IntervalCount;
  53. DWORD g_MaximumCount = MAXDWORD;
  54. DWORD g_DispatchFlags = DISPSETUP_COMFIRST;
  55. BOOL IsCharPrintableString(TCHAR chChar);
  56. WCHAR wszUsage[] =
  57. TEXT("Usage: CertGen [options]\n")
  58. TEXT("Options are:\n")
  59. TEXT(" -a - ignore denied requests\n")
  60. TEXT(" -c # - generate # certs\n")
  61. TEXT(" -config server\\CAName - specify CA config string\n")
  62. TEXT(" -renewal - generate renewal requests\n")
  63. TEXT(" -rpc - use RPC to connect to server\n")
  64. TEXT(" -r - put request/cert/chain info into test.req/test.crt/testchain.crt\n")
  65. TEXT(" -t # - print time statistics every # certs\n")
  66. TEXT(" -p - print properties from cert created\n")
  67. TEXT(" -i - don't stop on request errors\n")
  68. TEXT(" -z - allow duplicate subject name components\n")
  69. TEXT(" -m - print start/end time\n")
  70. ;
  71. HRESULT
  72. SeedRNG(void)
  73. {
  74. HRESULT hr;
  75. unsigned int seed;
  76. if (!CryptGenRandom(g_hMe, sizeof(seed), (BYTE *) &seed))
  77. {
  78. hr = myHLastError();
  79. _JumpError(hr, error, "CryptGenRandom");
  80. }
  81. srand(seed);
  82. hr = S_OK;
  83. error:
  84. return(hr);
  85. }
  86. HRESULT
  87. GenerateString(
  88. DWORD cnt,
  89. BYTE *pbStr)
  90. {
  91. HRESULT hr;
  92. DWORD i;
  93. BYTE *pb;
  94. hr = SeedRNG();
  95. _JumpIfError(hr, error, "SeedRNG");
  96. pb = pbStr;
  97. for (i = 0; i < cnt; i++)
  98. {
  99. do
  100. {
  101. *pb = rand() % 0x7f;
  102. } while (!IsCharPrintableString(*pb));
  103. pb++;
  104. }
  105. *pb = '\0';
  106. // Turn leading and trailing Blanks into '.' characters?
  107. if (g_fAllowDups && 0 < cnt)
  108. {
  109. if (' ' == *pbStr)
  110. {
  111. *pbStr = '.';
  112. }
  113. pb--;
  114. if (' ' == *pb)
  115. {
  116. *pb = '.';
  117. }
  118. }
  119. error:
  120. return(hr);
  121. }
  122. void
  123. FreeLocalMemory(
  124. NAMETABLE *pNameTable)
  125. {
  126. NAMEENTRY *pNameEntry = NULL;
  127. DWORD i;
  128. pNameEntry = pNameTable->pNameEntry;
  129. for (i = 0; i < pNameTable->cnt; i++)
  130. {
  131. if (NULL != pNameEntry->pbData)
  132. {
  133. LocalFree(pNameEntry->pbData);
  134. }
  135. pNameEntry++;
  136. }
  137. LocalFree(pNameTable->pNameEntry);
  138. }
  139. HRESULT
  140. GenerateNameTable(
  141. NAMETABLE *pNameTable)
  142. {
  143. HRESULT hr;
  144. NAMEENTRY *pNameEntryAlloc = NULL;
  145. NAMEENTRY *pNameEntry;
  146. DWORD cbString;
  147. BYTE *pbString;
  148. DWORD i;
  149. DWORD j;
  150. DWORD cRetry;
  151. hr = SeedRNG();
  152. _JumpIfError(hr, error, "SeedRNG");
  153. pNameTable->cnt = rand() % g_crdnMax; // 0 is Ok
  154. if (1 < g_fPrintProperties)
  155. {
  156. wprintf(L"NumEntries = %u\n", pNameTable->cnt);
  157. }
  158. for (i = 0; i < g_crdnSubject; i++)
  159. {
  160. g_ardnSubject[i].cbRemain = g_ardnSubject[i].cbMaxConcatenated;
  161. }
  162. pNameEntryAlloc = (NAMEENTRY *) LocalAlloc(
  163. LMEM_FIXED | LMEM_ZEROINIT,
  164. pNameTable->cnt * sizeof(NAMEENTRY));
  165. if (NULL == pNameEntryAlloc)
  166. {
  167. hr = E_OUTOFMEMORY;
  168. _JumpError(hr, error, "LocalAlloc");
  169. }
  170. pNameTable->pNameEntry = pNameEntryAlloc;
  171. for (i = 0; i < pNameTable->cnt; i++)
  172. {
  173. RDNENTRY *prdne;
  174. pNameEntry = &pNameTable->pNameEntry[i];
  175. for (cRetry = 0; !g_fAllowDups || cRetry < 2 * pNameTable->cnt; cRetry++)
  176. {
  177. pNameEntry->iRDN = rand() % g_crdnSubject;
  178. prdne = &g_ardnSubject[pNameEntry->iRDN];
  179. if (g_fAllowDups)
  180. {
  181. if (2 > prdne->cbRemain)
  182. {
  183. continue; // Skip if less than 2 characters left
  184. }
  185. }
  186. else
  187. {
  188. for (j = 0; j < i; j++)
  189. {
  190. if (pNameEntry->iRDN == pNameTable->pNameEntry[j].iRDN)
  191. {
  192. break;
  193. }
  194. }
  195. if (j < i)
  196. {
  197. continue; // Skip if a disallowed duplicate
  198. }
  199. }
  200. break;
  201. }
  202. if (g_fAllowDups && cRetry >= 2 * pNameTable->cnt)
  203. {
  204. if (1 < g_fPrintProperties)
  205. {
  206. wprintf(L"Reducing NumEntries = %u --> %i\n", pNameTable->cnt, i);
  207. }
  208. pNameTable->cnt = i; // too many retries -- reduce count & quit
  209. break;
  210. }
  211. pNameEntry->pszObjId = prdne->pszObjId;
  212. pNameEntry->BerTag = prdne->BerTag;
  213. assert(2 <= prdne->cbRemain);
  214. do
  215. {
  216. cbString = rand() % min(prdne->cbMaxString, prdne->cbRemain);
  217. } while (0 == cbString);
  218. // Reduce remaining count by length of string plus separator: "\n"
  219. if (1 < g_fPrintProperties)
  220. {
  221. wprintf(
  222. L" RDN(%u): %hs=%u/%u/%u/",
  223. i,
  224. prdne->pszShortName,
  225. cbString,
  226. prdne->cbMaxString,
  227. prdne->cbRemain);
  228. }
  229. prdne->cbRemain -= cbString;
  230. if (0 < prdne->cbRemain)
  231. {
  232. prdne->cbRemain--;
  233. }
  234. // Limit each string to (prdne->cbMaxString + 1) chars, including
  235. // trailing '\0':
  236. assert(cbString <= prdne->cbMaxString); // leave room for '\0' in DB
  237. pbString = (BYTE *) LocalAlloc(LMEM_FIXED, cbString + 1);
  238. if (NULL == pbString)
  239. {
  240. hr = E_OUTOFMEMORY;
  241. _JumpError(hr, error, "LocalAlloc");
  242. }
  243. hr = GenerateString(cbString, pbString);
  244. _JumpIfError(hr, error, "GenerateString");
  245. if (1 < g_fPrintProperties)
  246. {
  247. wprintf(L"%u: \"%hs\"\n", prdne->cbRemain, pbString);
  248. }
  249. pNameEntry->cbData = cbString;
  250. pNameEntry->pbData = pbString;
  251. }
  252. pNameEntryAlloc = NULL;
  253. error:
  254. if (NULL != pNameEntryAlloc)
  255. {
  256. FreeLocalMemory(pNameTable);
  257. }
  258. return(hr);
  259. }
  260. HRESULT
  261. GenerateTestNameTable(
  262. NAMETABLE *pNameTable)
  263. {
  264. HRESULT hr;
  265. NAMEENTRY *pNameEntryAlloc = NULL;
  266. NAMEENTRY *pNameEntry;
  267. DWORD cbString;
  268. BYTE *pbString;
  269. DWORD i;
  270. DWORD j;
  271. char szTest[2];
  272. pNameEntryAlloc = (NAMEENTRY *) LocalAlloc(
  273. LMEM_FIXED | LMEM_ZEROINIT,
  274. sizeof(NAMEENTRY) * g_crdnSubject);
  275. if (NULL == pNameEntryAlloc)
  276. {
  277. hr = E_OUTOFMEMORY;
  278. _JumpError(hr, error, "LocalAlloc");
  279. }
  280. pNameTable->cnt = g_crdnSubject;
  281. pNameTable->pNameEntry = pNameEntryAlloc;
  282. szTest[0] = 'a';
  283. szTest[1] = '\0';
  284. for (i = 0; i < g_crdnSubject; i++)
  285. {
  286. pNameEntry = &pNameTable->pNameEntry[i];
  287. pNameEntry->pszObjId = g_ardnSubject[i].pszObjId;
  288. pNameEntry->BerTag = g_ardnSubject[i].BerTag;
  289. pbString = (BYTE *) LocalAlloc(LMEM_FIXED, sizeof(szTest));
  290. if (NULL == pbString)
  291. {
  292. hr = E_OUTOFMEMORY;
  293. _JumpError(hr, error, "LocalAlloc");
  294. }
  295. CopyMemory(pbString, szTest, sizeof(szTest));
  296. pNameEntry->cbData = sizeof(szTest) - 1;
  297. pNameEntry->pbData = pbString;
  298. if ('z' == szTest[0])
  299. {
  300. szTest[0] = 'a';
  301. }
  302. else
  303. {
  304. szTest[0]++;
  305. }
  306. }
  307. pNameEntryAlloc = NULL;
  308. hr = S_OK;
  309. error:
  310. if (NULL != pNameEntryAlloc)
  311. {
  312. FreeLocalMemory(pNameTable);
  313. }
  314. return(hr);
  315. }
  316. BOOL
  317. PreparePrivateKeyForImport(
  318. IN BYTE *pbBlob,
  319. IN DWORD cbBlob,
  320. OUT BSAFE_PRV_KEY *pPriKey,
  321. IN OUT DWORD *pcbPriKey,
  322. OUT BSAFE_PUB_KEY *pPubKey,
  323. IN OUT DWORD *pcbPubKey)
  324. {
  325. EXPORT_PRV_KEY *pExportKey = (EXPORT_PRV_KEY *) pbBlob;
  326. DWORD cbHalfModLen;
  327. DWORD cbPub;
  328. DWORD cbPri;
  329. BYTE *pbIn;
  330. BYTE *pbOut;
  331. if (RSA2 != pExportKey->magic)
  332. {
  333. return(FALSE);
  334. }
  335. cbHalfModLen = pExportKey->bitlen / 16;
  336. cbPub = sizeof(BSAFE_PUB_KEY) + (cbHalfModLen + sizeof(DWORD)) * 2;
  337. cbPri = sizeof(BSAFE_PRV_KEY) + (cbHalfModLen + sizeof(DWORD)) * 10;
  338. if (NULL == pPriKey || NULL == pPubKey)
  339. {
  340. *pcbPubKey = cbPub;
  341. *pcbPriKey = cbPri;
  342. return(TRUE);
  343. }
  344. if (*pcbPubKey < cbPub || *pcbPriKey < cbPri)
  345. {
  346. *pcbPubKey = cbPub;
  347. *pcbPriKey = cbPri;
  348. return(FALSE);
  349. }
  350. else
  351. {
  352. // form the public key
  353. ZeroMemory(pPubKey, *pcbPubKey);
  354. pPubKey->magic = RSA1;
  355. pPubKey->keylen = (cbHalfModLen + sizeof(DWORD)) * 2;
  356. pPubKey->bitlen = pExportKey->bitlen;
  357. pPubKey->datalen = cbHalfModLen * 2 - 1;
  358. pPubKey->pubexp = pExportKey->pubexp;
  359. pbIn = pbBlob + sizeof(EXPORT_PRV_KEY);
  360. pbOut = (BYTE *) pPubKey + sizeof(BSAFE_PUB_KEY);
  361. CopyMemory(pbOut, pbIn, cbHalfModLen * 2);
  362. // form the private key
  363. ZeroMemory(pPriKey, *pcbPriKey);
  364. pPriKey->magic = pExportKey->magic;
  365. pPriKey->keylen = (cbHalfModLen + sizeof(DWORD)) * 2;
  366. pPriKey->bitlen = pExportKey->bitlen;
  367. pPriKey->datalen = cbHalfModLen * 2 - 1;
  368. pPriKey->pubexp = pExportKey->pubexp;
  369. pbOut = (BYTE *) pPriKey + sizeof(BSAFE_PRV_KEY);
  370. CopyMemory(pbOut, pbIn, cbHalfModLen * 2);
  371. pbOut += (cbHalfModLen + sizeof(DWORD)) * 2;
  372. pbIn += cbHalfModLen * 2;
  373. CopyMemory(pbOut, pbIn, cbHalfModLen);
  374. pbOut += cbHalfModLen + sizeof(DWORD);
  375. pbIn += cbHalfModLen;
  376. CopyMemory(pbOut, pbIn, cbHalfModLen);
  377. pbOut += cbHalfModLen + sizeof(DWORD);
  378. pbIn += cbHalfModLen;
  379. CopyMemory(pbOut, pbIn, cbHalfModLen);
  380. pbOut += cbHalfModLen + sizeof(DWORD);
  381. pbIn += cbHalfModLen;
  382. CopyMemory(pbOut, pbIn, cbHalfModLen);
  383. pbOut += cbHalfModLen + sizeof(DWORD);
  384. pbIn += cbHalfModLen;
  385. CopyMemory(pbOut, pbIn, cbHalfModLen);
  386. pbOut += cbHalfModLen + sizeof(DWORD);
  387. pbIn += cbHalfModLen;
  388. CopyMemory(pbOut, pbIn, cbHalfModLen * 2);
  389. }
  390. *pcbPubKey = cbPub;
  391. *pcbPriKey = cbPri;
  392. return(TRUE);
  393. }
  394. HRESULT
  395. GetPrivateKeyStuff(
  396. PctPrivateKey **ppKey)
  397. {
  398. HRESULT hr;
  399. BYTE *pbData;
  400. PctPrivateKey *pKey = NULL;
  401. HCRYPTKEY hKey = NULL;
  402. if (!CryptAcquireContext(
  403. &g_hMe,
  404. g_wszTestKey,
  405. MS_DEF_PROV,
  406. PROV_RSA_FULL,
  407. CRYPT_DELETEKEYSET))
  408. {
  409. hr = myHLastError();
  410. _PrintError(hr, "CryptAcquireContext");
  411. }
  412. if (!CryptAcquireContext(
  413. &g_hMe,
  414. g_wszTestKey,
  415. MS_DEF_PROV,
  416. PROV_RSA_FULL,
  417. CRYPT_NEWKEYSET))
  418. {
  419. hr = myHLastError();
  420. _JumpError(hr, error, "CryptAcquireContext");
  421. }
  422. if (!CryptGetUserKey(g_hMe, AT_SIGNATURE, &hKey))
  423. {
  424. hr = myHLastError();
  425. _PrintError2(hr, "CryptGetUserKey", hr);
  426. if (!CryptGenKey(g_hMe, AT_SIGNATURE, CRYPT_EXPORTABLE, &hKey))
  427. {
  428. hr = myHLastError();
  429. _JumpError(hr, error, "CryptGenKey");
  430. }
  431. }
  432. g_cbPrivateKey = sizeof(g_CAPIPrivateKey);
  433. if (!CryptExportKey(
  434. hKey,
  435. 0,
  436. PRIVATEKEYBLOB,
  437. 0L,
  438. &g_CAPIPrivateKey[0],
  439. &g_cbPrivateKey))
  440. {
  441. hr = myHLastError();
  442. _JumpError(hr, error, "CryptExportKey");
  443. }
  444. pbData = &g_CAPIPrivateKey[sizeof(BLOBHEADER)];
  445. if (!PreparePrivateKeyForImport(
  446. pbData,
  447. g_cbPrivateKey - sizeof(BLOBHEADER),
  448. NULL,
  449. &g_cbRSAPrivateKey,
  450. NULL,
  451. &g_cbRSAPublicKey))
  452. {
  453. hr = NTE_BAD_KEY;
  454. _JumpError(hr, error, "PreparePrivateKeyForImport");
  455. }
  456. pKey = (PctPrivateKey *) LocalAlloc(
  457. LMEM_FIXED,
  458. g_cbRSAPrivateKey + sizeof(PctPrivateKey));
  459. g_pRSAPublicKey = (BSAFE_PUB_KEY *) LocalAlloc(
  460. LMEM_FIXED,
  461. g_cbRSAPublicKey);
  462. if (pKey == NULL || g_pRSAPublicKey == NULL)
  463. {
  464. hr = E_OUTOFMEMORY;
  465. _JumpError(hr, error, "LocalAlloc");
  466. }
  467. pKey->cbKey = g_cbRSAPrivateKey;
  468. if (!PreparePrivateKeyForImport(
  469. pbData,
  470. g_cbPrivateKey - sizeof(BLOBHEADER),
  471. (BSAFE_PRV_KEY *) pKey->pKey,
  472. &g_cbRSAPrivateKey,
  473. g_pRSAPublicKey,
  474. &g_cbRSAPublicKey))
  475. {
  476. hr = NTE_BAD_KEY;
  477. _JumpError(hr, error, "PreparePrivateKeyForImport");
  478. }
  479. hr = S_OK;
  480. error:
  481. if (NULL != hKey)
  482. {
  483. CryptDestroyKey(hKey);
  484. }
  485. *ppKey = pKey;
  486. return(hr);
  487. }
  488. VOID
  489. ReverseMemCopy(
  490. OUT BYTE *pbDest,
  491. IN BYTE const *pbSource,
  492. IN DWORD cb)
  493. {
  494. BYTE *pb;
  495. pb = pbDest + cb - 1;
  496. do
  497. {
  498. *pb-- = *pbSource++;
  499. } while (pb >= pbDest);
  500. }
  501. BOOL WINAPI
  502. SigRSAMD5Sign(
  503. IN BYTE *pbData,
  504. IN DWORD cbData,
  505. OUT BYTE *pbSigned,
  506. OUT DWORD *pcbSigned,
  507. IN PctPrivateKey const *pKey)
  508. {
  509. MD5_CTX DigCtx;
  510. BSAFE_PRV_KEY *pk = (BSAFE_PRV_KEY *) pKey->pKey;
  511. BYTE LocalBuffer[300];
  512. BYTE LocalOutput[300];
  513. DWORD cb;
  514. //DumpHex(pbData, cbData);
  515. if (pk->datalen > sizeof(LocalBuffer))
  516. {
  517. return(FALSE);
  518. }
  519. // Generate the checksum
  520. MD5Init(&DigCtx);
  521. MD5Update(&DigCtx, pbData, cbData);
  522. MD5Final(&DigCtx);
  523. FillMemory(LocalBuffer, pk->keylen, 0);
  524. ReverseMemCopy(LocalBuffer, DigCtx.digest, 16);
  525. ReverseMemCopy(LocalBuffer + 16, MD5_PRELUDE, sizeof(MD5_PRELUDE));
  526. cb = sizeof(MD5_PRELUDE) + 16;
  527. LocalBuffer[cb++] = 0;
  528. while (cb < pk->datalen - 1)
  529. {
  530. LocalBuffer[cb++] = 0xff;
  531. }
  532. // Make into pkcs block type 1
  533. LocalBuffer[pk->datalen - 1] = 1;
  534. *pcbSigned = pk->datalen + 1;
  535. if (!BSafeDecPrivate(pk, LocalBuffer, LocalOutput))
  536. {
  537. return(FALSE);
  538. }
  539. ReverseMemCopy(pbSigned, LocalOutput, *pcbSigned);
  540. //DumpHex(pbSigned, *pcbSigned);
  541. return(TRUE);
  542. }
  543. long
  544. EncodeSubjectPubKeyInfo(
  545. IN PctPrivateKey const *pKey,
  546. OUT BYTE *pbBuffer)
  547. {
  548. BYTE *pbEncoded;
  549. LONG cbResult;
  550. LONG cbResultHeader;
  551. LONG PkResult;
  552. LONG PkResultHeader;
  553. BYTE *pbSave;
  554. BYTE *pbBitString;
  555. BYTE *pbBitStringBase;
  556. BYTE *pbTop;
  557. DWORD EstimatedLength;
  558. BSAFE_PRV_KEY *pk = (BSAFE_PRV_KEY *) pKey->pKey;
  559. // Encode public key now...
  560. EstimatedLength = pk->datalen + 32;
  561. pbEncoded = pbBuffer;
  562. cbResultHeader = EncodeHeader(pbEncoded, EstimatedLength);
  563. pbEncoded += cbResultHeader;
  564. pbTop = pbEncoded;
  565. cbResult = EncodeAlgorithm(pbEncoded, ALGTYPE_KEYEXCH_RSA_MD5);
  566. if (0 > cbResult)
  567. {
  568. return(-1);
  569. }
  570. pbEncoded += cbResult;
  571. // now, serialize the rsa key data:
  572. pbBitString = (BYTE *) LocalAlloc(LMEM_FIXED, EstimatedLength);
  573. if (NULL == pbBitString)
  574. {
  575. return(-1);
  576. }
  577. pbBitStringBase = pbBitString;
  578. // Encode the Sequence header, public key base and exponent as integers
  579. PkResultHeader = EncodeHeader(pbBitString, EstimatedLength);
  580. pbBitString += PkResultHeader;
  581. pbSave = pbBitString;
  582. PkResult = EncodeInteger(pbBitString, (BYTE *) (pk + 1), pk->keylen);
  583. pbBitString += PkResult;
  584. PkResult = EncodeInteger(pbBitString, (BYTE *) &pk->pubexp, sizeof(DWORD));
  585. pbBitString += PkResult;
  586. // Rewrite the bitstring header with an accurate length.
  587. PkResult = EncodeHeader(
  588. pbBitStringBase,
  589. SAFE_SUBTRACT_POINTERS(pbBitString, pbSave));
  590. // Encode the public key sequence as a raw bitstring, and free the memory.
  591. cbResult = EncodeBitString(
  592. pbEncoded,
  593. pbBitStringBase,
  594. SAFE_SUBTRACT_POINTERS(pbBitString, pbBitStringBase));
  595. pbEncoded += cbResult;
  596. LocalFree(pbBitStringBase);
  597. // Rewrite the header with an accurate length.
  598. cbResult = EncodeHeader(pbBuffer, SAFE_SUBTRACT_POINTERS(pbEncoded, pbTop));
  599. return(cbResult + SAFE_SUBTRACT_POINTERS(pbEncoded, pbTop));
  600. }
  601. #if 0
  602. a0 <len> BER_OPTIONAL | 0 -- Request Attributes
  603. 30 <len> BER_SEQUENCE
  604. 06 <len> BER_OBJECT_ID -- szOID_CERT_EXTENSIONS
  605. 31 <len> BER_SET
  606. 30 <len> BER_SEQUENCE
  607. 30 <len> BER_SEQUENCE (extension[0])
  608. 06 <len> BER_OBJECT_ID
  609. 01 <len> BER_BOOL (Optional)
  610. 04 <len> BER_OCTET_STRING
  611. 30 <len> BER_SEQUENCE (extension[1])
  612. 06 <len> BER_OBJECT_ID
  613. 04 <len> BER_OCTET_STRING
  614. 30 <len> BER_SEQUENCE (extension[2])
  615. 06 <len> BER_OBJECT_ID
  616. 04 <len> BER_OCTET_STRING
  617. #endif
  618. long
  619. AllocEncodeUnicodeString(
  620. IN WCHAR const *pwszCertType,
  621. OUT BYTE **ppbOut)
  622. {
  623. BYTE *pb = NULL;
  624. LONG cb;
  625. cb = EncodeUnicodeString(NULL, pwszCertType);
  626. pb = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
  627. if (NULL == pb)
  628. {
  629. cb = -1;
  630. goto error;
  631. }
  632. *ppbOut = pb;
  633. EncodeUnicodeString(pb, pwszCertType);
  634. error:
  635. return(cb);
  636. }
  637. long
  638. AllocEncodeExtensionArray(
  639. IN DWORD cExt,
  640. IN CERT_EXTENSION const *aExt,
  641. OUT BYTE **ppbExtensions)
  642. {
  643. BYTE *pb;
  644. DWORD i;
  645. LONG cb;
  646. LONG cbExtTotal;
  647. LONG acbLen[3];
  648. LONG *acbExt = NULL;
  649. *ppbExtensions = NULL;
  650. acbExt = (LONG *) LocalAlloc(LMEM_FIXED, cExt * sizeof(acbExt[0]));
  651. if (NULL == acbExt)
  652. {
  653. cbExtTotal = -1;
  654. _JumpError(-1, error, "LocalAlloc");
  655. }
  656. // Construct size from the bottom up.
  657. cbExtTotal = 0;
  658. for (i = 0; i < cExt; i++)
  659. {
  660. // BER_OBJECT_ID: Extension OID
  661. cb = EncodeObjId(NULL, aExt[i].pszObjId);
  662. if (-1 == cb)
  663. {
  664. _JumpError(-1, error, "EncodeObjId");
  665. }
  666. acbExt[i] = cb;
  667. if (aExt[i].fCritical)
  668. {
  669. // BER_BOOL: fCritical
  670. acbExt[i] += 1 + EncodeLength(NULL, 1);
  671. acbExt[i]++; // boolean value
  672. }
  673. // BER_OCTET_STRING: Extension octet string value
  674. acbExt[i] += 1 + EncodeLength(NULL, aExt[i].Value.cbData);
  675. acbExt[i] += aExt[i].Value.cbData; // octet string
  676. // BER_SEQUENCE: Extension Sequence
  677. cbExtTotal += 1 + EncodeLength(NULL, acbExt[i]);
  678. cbExtTotal += acbExt[i];
  679. }
  680. // BER_SEQUENCE: Extension Array Sequence
  681. acbLen[2] = cbExtTotal;
  682. cbExtTotal += 1 + EncodeLength(NULL, cbExtTotal);
  683. // BER_SET: Attribute Value
  684. acbLen[1] = cbExtTotal;
  685. cbExtTotal += 1 + EncodeLength(NULL, cbExtTotal);
  686. // BER_OBJECT_ID: Attribute OID
  687. cb = EncodeObjId(NULL, szOID_CERT_EXTENSIONS);
  688. if (-1 == cb)
  689. {
  690. _JumpError(-1, error, "EncodeObjId");
  691. }
  692. cbExtTotal += cb;
  693. // BER_SEQUENCE: Attribute Array Sequence
  694. acbLen[0] = cbExtTotal;
  695. cbExtTotal += 1 + EncodeLength(NULL, cbExtTotal);
  696. // Allocate memory and encode the extensions
  697. pb = (BYTE *) LocalAlloc(LMEM_FIXED, cbExtTotal);
  698. if (NULL == pb)
  699. {
  700. cbExtTotal = -1;
  701. _JumpError(-1, error, "LocalAlloc");
  702. }
  703. *ppbExtensions = pb;
  704. *pb++ = BER_SEQUENCE; // Attribute Array Sequence
  705. pb += EncodeLength(pb, acbLen[0]);
  706. pb += EncodeObjId(pb, szOID_CERT_EXTENSIONS);
  707. *pb++ = BER_SET; // Attribute Value
  708. pb += EncodeLength(pb, acbLen[1]);
  709. *pb++ = BER_SEQUENCE; // Extension Array Sequence
  710. pb += EncodeLength(pb, acbLen[2]);
  711. CSASSERT(*ppbExtensions + cbExtTotal >= pb);
  712. for (i = 0; i < cExt; i++)
  713. {
  714. CSASSERT(*ppbExtensions + cbExtTotal > pb);
  715. *pb++ = BER_SEQUENCE; // Extension Sequence
  716. pb += EncodeLength(pb, acbExt[i]);
  717. // BER_OBJECT_ID: Extension OID
  718. pb += EncodeObjId(pb, aExt[i].pszObjId);
  719. if (aExt[i].fCritical)
  720. {
  721. *pb++ = BER_BOOL; // fCritical
  722. pb += EncodeLength(pb, 1);
  723. *pb++ = 0xff;
  724. }
  725. *pb++ = BER_OCTET_STRING; // Extension octet string value
  726. pb += EncodeLength(pb, aExt[i].Value.cbData);
  727. CopyMemory(pb, aExt[i].Value.pbData, aExt[i].Value.cbData);
  728. pb += aExt[i].Value.cbData;
  729. }
  730. CSASSERT(*ppbExtensions + cbExtTotal == pb);
  731. error:
  732. if (NULL != acbExt)
  733. {
  734. LocalFree(acbExt);
  735. }
  736. return(cbExtTotal);
  737. }
  738. long
  739. EncodeExtensions(
  740. IN WCHAR const *pwszCertType,
  741. OUT BYTE **ppbExtensions)
  742. {
  743. LONG cbExt;
  744. BYTE *pbExt = NULL;
  745. CERT_EXTENSION aExt[1];
  746. DWORD cExt = 0;
  747. DWORD i;
  748. // Allocate memory and construct the CertType extension:
  749. aExt[cExt].pszObjId = szOID_ENROLL_CERTTYPE_EXTENSION;
  750. aExt[cExt].fCritical = FALSE;
  751. aExt[cExt].Value.cbData = AllocEncodeUnicodeString(
  752. pwszCertType,
  753. &aExt[cExt].Value.pbData);
  754. //DumpHex(aExt[cExt].Value.pbData, aExt[cExt].Value.cbData);
  755. cExt++;
  756. cbExt = AllocEncodeExtensionArray(cExt, aExt, ppbExtensions);
  757. if (-1 == cbExt)
  758. {
  759. _JumpError(-1, error, "AllocEncodeExtensionArray");
  760. }
  761. error:
  762. for (i = 0; i < cExt; i++)
  763. {
  764. if (NULL != aExt[i].Value.pbData)
  765. {
  766. LocalFree(aExt[i].Value.pbData);
  767. }
  768. }
  769. return(cbExt);
  770. }
  771. HRESULT
  772. EncodeRequest(
  773. IN PctPrivateKey const *pKey,
  774. IN NAMETABLE const *pNameTable,
  775. OUT BYTE **ppbRequest,
  776. OUT DWORD *pcbRequest)
  777. {
  778. HRESULT hr;
  779. BYTE *pbRequest0Alloc = NULL;
  780. BYTE *pbRequest1Alloc = NULL;
  781. BYTE *pbSigAlloc = NULL;
  782. BYTE *pbRequest0;
  783. BYTE *pbSave;
  784. BYTE *pbEncoded;
  785. BYTE *pbExt;
  786. LONG cbExt;
  787. LONG cbResult;
  788. LONG cbEncoded;
  789. BYTE bZero;
  790. LONG cbDN;
  791. DWORD cbRequest0;
  792. DWORD cbRequest1;
  793. LONG cbLenRequest;
  794. BSAFE_PRV_KEY *pk = (BSAFE_PRV_KEY *) pKey->pKey;
  795. cbExt = EncodeExtensions(L"User", &pbExt);
  796. if (-1 == cbExt)
  797. {
  798. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  799. _JumpError(hr, error, "EncodeExtensions");
  800. }
  801. //DumpHex(pbExt, cbExt);
  802. cbDN = EncodeDN(NULL, pNameTable);
  803. if (-1 == cbDN)
  804. {
  805. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  806. _JumpError(hr, error, "EncodeDN");
  807. }
  808. cbRequest0 = pk->datalen + 32 + cbDN + 16 + cbExt + 3;
  809. pbRequest0Alloc = (BYTE *) LocalAlloc(LMEM_FIXED, cbRequest0);
  810. if (NULL == pbRequest0Alloc)
  811. {
  812. hr = E_OUTOFMEMORY;
  813. _JumpError(hr, error, "LocalAlloc");
  814. }
  815. pbRequest0 = pbRequest0Alloc;
  816. pbEncoded = pbRequest0;
  817. // Encode BER_SEQUENCE: Version+Subject+Key+Attributes Sequence
  818. cbLenRequest = EncodeHeader(pbEncoded, cbRequest0);
  819. pbEncoded += cbLenRequest;
  820. pbSave = pbEncoded; // Save pointer past sequence length
  821. // Encode integer 0: Version 1 PKCS10
  822. bZero = (BYTE) CERT_REQUEST_V1;
  823. pbEncoded += EncodeInteger(pbEncoded, &bZero, sizeof(bZero));
  824. // Encode sequence of names
  825. cbResult = EncodeDN(pbEncoded, pNameTable);
  826. if (0 > cbResult)
  827. {
  828. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  829. _JumpError(hr, error, "EncodeDN");
  830. }
  831. pbEncoded += cbResult;
  832. cbResult = EncodeSubjectPubKeyInfo(pKey, pbEncoded);
  833. if (0 > cbResult)
  834. {
  835. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  836. _JumpError(hr, error, "EncodeSubjectPubKeyInfo");
  837. }
  838. pbEncoded += cbResult;
  839. // Encode attributes:
  840. // BER_OPTIONAL | 0: Attribute Field
  841. cbResult = EncodeAttributeHeader(pbEncoded, cbExt);
  842. pbEncoded += cbResult;
  843. CopyMemory(pbEncoded, pbExt, cbExt);
  844. pbEncoded += cbExt;
  845. // Encode BER_SEQUENCE: Version+Subject+Key+Attributes Sequence (again)
  846. cbEncoded = SAFE_SUBTRACT_POINTERS(pbEncoded, pbSave);
  847. cbResult = EncodeHeader(pbRequest0, cbEncoded);
  848. // If the header sequence length takes up less space than we anticipated,
  849. // add the difference to the base pointer and encode the header again,
  850. // right before the encoded data.
  851. if (cbResult != cbLenRequest)
  852. {
  853. CSASSERT(cbResult < cbLenRequest);
  854. pbRequest0 += cbLenRequest - cbResult;
  855. // Encode BER_SEQUENCE: Version+Subject+Key+Attributes Sequence (again)
  856. cbResult = EncodeHeader(pbRequest0, cbEncoded);
  857. }
  858. cbRequest0 = cbResult + SAFE_SUBTRACT_POINTERS(pbEncoded, pbSave);
  859. //DumpHex(pbRequest0, cbRequest0);
  860. // How much space do we need?
  861. cbRequest1 = cbRequest0 + pk->datalen + 32;
  862. pbRequest1Alloc = (BYTE *) LocalAlloc(LMEM_FIXED, cbRequest1);
  863. if (NULL == pbRequest1Alloc)
  864. {
  865. hr = E_OUTOFMEMORY;
  866. _JumpError(hr, error, "LocalAlloc");
  867. }
  868. pbEncoded = pbRequest1Alloc;
  869. // Encode BER_SEQUENCE: outer Request Sequence
  870. cbLenRequest = EncodeHeader(pbEncoded, cbRequest1);
  871. pbEncoded += cbLenRequest;
  872. pbSave = pbEncoded; // Save pointer past outer sequence length
  873. CopyMemory(pbEncoded, pbRequest0, cbRequest0);
  874. pbEncoded += cbRequest0;
  875. cbResult = EncodeAlgorithm(pbEncoded, ALGTYPE_SIG_RSA_MD5);
  876. pbEncoded += cbResult;
  877. //DumpHex(pbRequest1Alloc, cbRequest1);
  878. cbResult = pk->datalen + 16;
  879. pbSigAlloc = (BYTE *) LocalAlloc(LMEM_FIXED, cbResult);
  880. if (NULL == pbSigAlloc)
  881. {
  882. hr = E_OUTOFMEMORY;
  883. _JumpError(hr, error, "LocalAlloc");
  884. }
  885. if (!SigRSAMD5Sign(
  886. pbRequest0,
  887. cbRequest0,
  888. pbSigAlloc,
  889. (DWORD *) &cbResult,
  890. pKey))
  891. {
  892. hr = E_FAIL;
  893. _JumpError(hr, error, "SigRSAMD5Sign");
  894. }
  895. pbEncoded += EncodeBitString(pbEncoded, pbSigAlloc, cbResult);
  896. cbEncoded = SAFE_SUBTRACT_POINTERS(pbEncoded, pbSave);
  897. cbResult = EncodeHeader(pbRequest1Alloc, cbEncoded);
  898. cbRequest1 = cbResult + cbEncoded;
  899. if (cbResult != cbLenRequest)
  900. {
  901. if (cbResult > cbLenRequest)
  902. {
  903. // The chunk has actually grown from the estimate.
  904. BYTE *pbT;
  905. pbT = (BYTE *) LocalAlloc(LMEM_FIXED, cbRequest1);
  906. if (NULL == pbT)
  907. {
  908. hr = E_OUTOFMEMORY;
  909. _JumpError(hr, error, "LocalAlloc");
  910. }
  911. EncodeHeader(pbT, cbEncoded);
  912. CopyMemory(
  913. pbT + cbResult,
  914. pbSave,
  915. cbEncoded);
  916. LocalFree(pbRequest1Alloc);
  917. pbRequest1Alloc = pbT;
  918. }
  919. else
  920. {
  921. cbResult = EncodeHeader(pbRequest1Alloc, cbEncoded);
  922. MoveMemory(
  923. pbRequest1Alloc + cbResult,
  924. pbRequest1Alloc + cbLenRequest,
  925. cbEncoded);
  926. }
  927. }
  928. *ppbRequest = pbRequest1Alloc;
  929. *pcbRequest = cbRequest1;
  930. pbRequest1Alloc = NULL;
  931. //DumpHex(*ppbRequest, *pcbRequest);
  932. hr = S_OK;
  933. error:
  934. if (NULL != pbSigAlloc)
  935. {
  936. LocalFree(pbSigAlloc);
  937. }
  938. if (NULL != pbRequest1Alloc)
  939. {
  940. LocalFree(pbRequest1Alloc);
  941. }
  942. if (NULL != pbRequest0Alloc)
  943. {
  944. LocalFree(pbRequest0Alloc);
  945. }
  946. if (NULL != pbExt)
  947. {
  948. LocalFree(pbExt);
  949. }
  950. return(hr);
  951. }
  952. HRESULT
  953. GetAndCompareProperty(
  954. CERT_NAME_INFO *pNameInfo,
  955. char const *pszObjId,
  956. char const *pszValue,
  957. BYTE **pbProp,
  958. DWORD *pcbProp,
  959. BOOL *pfMatch)
  960. {
  961. HRESULT hr;
  962. CERT_RDN_ATTR *prdnaT;
  963. CERT_RDN *prdn;
  964. CERT_RDN *prdnEnd;
  965. *pfMatch = FALSE;
  966. prdnaT = NULL;
  967. for (
  968. prdn = pNameInfo->rgRDN, prdnEnd = &prdn[pNameInfo->cRDN];
  969. prdn < prdnEnd;
  970. prdn++)
  971. {
  972. CERT_RDN_ATTR *prdna;
  973. CERT_RDN_ATTR *prdnaEnd;
  974. for (
  975. prdna = prdn->rgRDNAttr, prdnaEnd = &prdna[prdn->cRDNAttr];
  976. prdna < prdnaEnd;
  977. prdna++)
  978. {
  979. if (0 == strcmp(prdna->pszObjId, pszObjId))
  980. {
  981. prdnaT = prdna;
  982. if (prdnaT->Value.cbData == strlen(pszValue) &&
  983. 0 == memcmp(pszValue, prdnaT->Value.pbData, prdnaT->Value.cbData))
  984. {
  985. *pfMatch = TRUE;
  986. }
  987. else if (g_fAllowDups)
  988. {
  989. continue;
  990. }
  991. prdn = prdnEnd; // exit outer for loop, too.
  992. break;
  993. }
  994. }
  995. }
  996. if (NULL == prdnaT)
  997. {
  998. hr = CERTSRV_E_PROPERTY_EMPTY;
  999. _JumpError2(hr, error, "Missing Property", CERTSRV_E_PROPERTY_EMPTY);
  1000. }
  1001. *pbProp = prdnaT->Value.pbData;
  1002. *pcbProp = prdnaT->Value.cbData;
  1003. hr = S_OK;
  1004. error:
  1005. return(hr);
  1006. }
  1007. HRESULT
  1008. CheckProperties(
  1009. DWORD ReqId,
  1010. NAMETABLE *pNameTable,
  1011. DWORD CertNumber,
  1012. CERT_NAME_INFO *pNameInfo)
  1013. {
  1014. HRESULT hr;
  1015. BYTE *pbProp;
  1016. DWORD cbProp;
  1017. DWORD i;
  1018. DWORD dwCount = 0;
  1019. BOOL fMatch;
  1020. if (g_fPrintProperties)
  1021. {
  1022. wprintf(
  1023. L"Properties for Certificate %u, RequestId %u:\n",
  1024. CertNumber,
  1025. ReqId);
  1026. }
  1027. for (i = 0; i < pNameTable->cnt; i++)
  1028. {
  1029. NAMEENTRY *pNameEntry;
  1030. RDNENTRY *prdn;
  1031. pNameEntry = &pNameTable->pNameEntry[i];
  1032. prdn = &g_ardnSubject[pNameEntry->iRDN];
  1033. hr = GetAndCompareProperty(
  1034. pNameInfo,
  1035. prdn->pszObjId,
  1036. (char const *) pNameEntry->pbData,
  1037. &pbProp,
  1038. &cbProp,
  1039. &fMatch);
  1040. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  1041. {
  1042. //_PrintError(hr, "GetAndCompareProperty");
  1043. pbProp = NULL;
  1044. hr = S_OK;
  1045. }
  1046. _JumpIfError(hr, error, "GetAndCompareProperty");
  1047. if (NULL != pbProp && !fMatch)
  1048. {
  1049. wprintf(
  1050. L"Property doesn't match: Expected %hs=\"%hs\", pbProp = \"%hs\"\n",
  1051. prdn->pszShortName,
  1052. pNameEntry->pbData,
  1053. pbProp);
  1054. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1055. _JumpError(hr, error, "GetAndCompareProperty: no match");
  1056. }
  1057. if (g_fPrintProperties)
  1058. {
  1059. DWORD ccol;
  1060. #define CCOL_OID 10
  1061. ccol = strlen(prdn->pszObjId) + 1;
  1062. if (ccol < CCOL_OID)
  1063. {
  1064. ccol = CCOL_OID - ccol;
  1065. }
  1066. else
  1067. {
  1068. ccol = 0;
  1069. }
  1070. wprintf(
  1071. L" %u: %hs: %*s%hs=%hs%hs%hs\n",
  1072. i,
  1073. prdn->pszObjId,
  1074. ccol,
  1075. "",
  1076. prdn->pszShortName,
  1077. NULL == pbProp? "" : "\"",
  1078. NULL == pbProp? " -- MISSING --" : (char const *) pbProp,
  1079. NULL == pbProp? "" : "\"");
  1080. }
  1081. }
  1082. if (g_fPrintProperties)
  1083. {
  1084. wprintf(L"\n");
  1085. }
  1086. hr = S_OK;
  1087. error:
  1088. return(hr);
  1089. }
  1090. HRESULT
  1091. EncodeRenewal(
  1092. IN BYTE const *pbRequest,
  1093. IN DWORD cbRequest,
  1094. OUT BYTE **ppbRenewal,
  1095. OUT DWORD *pcbRenewal)
  1096. {
  1097. HRESULT hr;
  1098. *ppbRenewal = (BYTE *) LocalAlloc(LMEM_FIXED, cbRequest);
  1099. if (NULL == *ppbRenewal)
  1100. {
  1101. hr = E_OUTOFMEMORY;
  1102. _JumpError(hr, error, "LocalAlloc");
  1103. }
  1104. CopyMemory(*ppbRenewal, pbRequest, cbRequest);
  1105. *pcbRenewal = cbRequest;
  1106. hr = S_OK;
  1107. error:
  1108. return(hr);
  1109. }
  1110. HRESULT
  1111. SubmitRequest(
  1112. OPTIONAL IN DISPATCHINTERFACE *pdiRequest,
  1113. IN DWORD Flags,
  1114. IN BYTE const *pbRequest,
  1115. IN DWORD cbRequest,
  1116. IN WCHAR const *pwszAttributes,
  1117. IN WCHAR const *pwszConfig,
  1118. OUT DWORD *pRequestIdOut,
  1119. OUT DWORD *pDisposition,
  1120. OUT HRESULT *phrLastStatus,
  1121. OUT WCHAR **ppwszDisposition,
  1122. OUT BYTE **ppbCert,
  1123. OUT DWORD *pcbCert)
  1124. {
  1125. HRESULT hr;
  1126. WCHAR *pwszRequest = NULL;
  1127. BSTR strCert = NULL;
  1128. BSTR strCertChain = NULL;
  1129. BSTR strDisposition = NULL;
  1130. BYTE *pbCert = NULL;
  1131. DWORD cbCert;
  1132. BYTE const *pbChain;
  1133. DWORD cbChain;
  1134. CERTSERVERENROLL *pcsEnroll = NULL;
  1135. WCHAR *pwszServer = NULL;
  1136. WCHAR *pwszAuthority = NULL;
  1137. WCHAR *pwszDisposition;
  1138. *phrLastStatus = S_OK;
  1139. *ppwszDisposition = NULL;
  1140. *ppbCert = NULL;
  1141. *pRequestIdOut = 0;
  1142. if (NULL == pdiRequest)
  1143. {
  1144. hr = mySplitConfigString(pwszConfig, &pwszServer, &pwszAuthority);
  1145. _JumpIfError(hr, error, "mySplitConfigString");
  1146. // CertServerSubmitRequest can only handle binary requests;
  1147. // pass the request in binary form, and pass Flags to so indicate.
  1148. hr = CertServerSubmitRequest(
  1149. CR_IN_BINARY | Flags,
  1150. pbRequest,
  1151. cbRequest,
  1152. pwszAttributes,
  1153. pwszServer,
  1154. pwszAuthority,
  1155. &pcsEnroll);
  1156. _JumpIfError(hr, error, "CertServerSubmitRequest");
  1157. *phrLastStatus = pcsEnroll->hrLastStatus;
  1158. _PrintIfError2(
  1159. *phrLastStatus,
  1160. "pcsEnroll->hrLastStatus Real Status",
  1161. HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  1162. pwszDisposition = pcsEnroll->pwszDispositionMessage;
  1163. *pDisposition = pcsEnroll->Disposition;
  1164. *pRequestIdOut = pcsEnroll->RequestId;
  1165. }
  1166. else
  1167. {
  1168. hr = myCryptBinaryToString(
  1169. pbRequest,
  1170. cbRequest,
  1171. CRYPT_STRING_BASE64REQUESTHEADER,
  1172. &pwszRequest);
  1173. _JumpIfError(hr, error, "myCryptBinaryToString");
  1174. if (g_fRPC)
  1175. {
  1176. Flags |= CR_IN_RPC;
  1177. }
  1178. hr = Request_Submit(
  1179. pdiRequest,
  1180. CR_IN_BASE64HEADER | Flags,
  1181. pwszRequest,
  1182. sizeof(WCHAR) * wcslen(pwszRequest),
  1183. pwszAttributes,
  1184. pwszConfig,
  1185. (LONG *) pDisposition);
  1186. if (S_OK != hr)
  1187. {
  1188. _PrintError2(
  1189. hr,
  1190. "Request_Submit",
  1191. HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  1192. // Collect the RequestId for potential error reporting:
  1193. Request_GetRequestId(pdiRequest, (LONG *) pRequestIdOut);
  1194. hr = Request_GetLastStatus(pdiRequest, phrLastStatus);
  1195. _JumpIfError(hr, error, "Request_GetLastStatus");
  1196. if (FAILED(*phrLastStatus))
  1197. {
  1198. hr = *phrLastStatus;
  1199. }
  1200. _JumpError2(
  1201. hr,
  1202. error,
  1203. "Request_GetLastStatus Real Status",
  1204. HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  1205. }
  1206. hr = Request_GetLastStatus(pdiRequest, phrLastStatus);
  1207. _JumpIfError(hr, error, "Request_GetLastStatus");
  1208. _PrintIfError(*phrLastStatus, "Request_GetLastStatus Real Status");
  1209. hr = Request_GetDispositionMessage(pdiRequest, &strDisposition);
  1210. _JumpIfError(hr, error, "Request_GetDispositionMessage");
  1211. hr = Request_GetRequestId(pdiRequest, (LONG *) pRequestIdOut);
  1212. _JumpIfError(hr, error, "Request_GetrequestId");
  1213. pwszDisposition = strDisposition;
  1214. }
  1215. if (CR_DISP_ISSUED == *pDisposition)
  1216. {
  1217. if (NULL == pdiRequest)
  1218. {
  1219. cbCert = pcsEnroll->cbCert;
  1220. pbCert = (BYTE *) LocalAlloc(LMEM_FIXED, cbCert);
  1221. if (NULL == pbCert)
  1222. {
  1223. hr = E_OUTOFMEMORY;
  1224. _JumpError(hr, error, "LocalAlloc");
  1225. }
  1226. CopyMemory(pbCert, pcsEnroll->pbCert, cbCert);
  1227. }
  1228. else
  1229. {
  1230. hr = Request_GetCertificate(
  1231. pdiRequest,
  1232. CR_OUT_BASE64HEADER,
  1233. &strCert);
  1234. _JumpIfError(hr, error, "Request_GetCertificate");
  1235. hr = myCryptStringToBinary(
  1236. strCert,
  1237. wcslen(strCert),
  1238. CRYPT_STRING_BASE64HEADER,
  1239. &pbCert,
  1240. &cbCert,
  1241. NULL,
  1242. NULL);
  1243. _JumpIfError(hr, error, "myCryptStringToBinary");
  1244. }
  1245. if (g_fSave)
  1246. {
  1247. hr = EncodeToFileW(
  1248. L"test.crt",
  1249. pbCert,
  1250. cbCert,
  1251. DECF_FORCEOVERWRITE | CRYPT_STRING_BINARY);
  1252. _JumpIfError(hr, error, "EncodeToFileW");
  1253. if (NULL == pdiRequest)
  1254. {
  1255. pbChain = pcsEnroll->pbCertChain;
  1256. cbChain = pcsEnroll->cbCertChain;
  1257. }
  1258. else
  1259. {
  1260. hr = Request_GetCertificate(
  1261. pdiRequest,
  1262. CR_OUT_BINARY | CR_OUT_CHAIN,
  1263. &strCertChain);
  1264. _JumpIfError(hr, error, "Request_GetCertificate");
  1265. pbChain = (BYTE const *) strCertChain;
  1266. cbChain = SysStringByteLen(strCertChain);
  1267. }
  1268. hr = EncodeToFileW(
  1269. L"testchain.crt",
  1270. pbChain,
  1271. cbChain,
  1272. DECF_FORCEOVERWRITE | CRYPT_STRING_BINARY);
  1273. _JumpIfError(hr, error, "EncodeToFileW");
  1274. }
  1275. }
  1276. if (NULL != pwszDisposition)
  1277. {
  1278. *ppwszDisposition = (WCHAR *) LocalAlloc(
  1279. LMEM_FIXED,
  1280. (wcslen(pwszDisposition) + 1) * sizeof(WCHAR));
  1281. if (NULL == *ppwszDisposition)
  1282. {
  1283. hr = E_OUTOFMEMORY;
  1284. _JumpError(hr, error, "LocalAlloc");
  1285. }
  1286. wcscpy(*ppwszDisposition, pwszDisposition);
  1287. }
  1288. *pcbCert = cbCert;
  1289. *ppbCert = pbCert;
  1290. pbCert = NULL;
  1291. hr = S_OK;
  1292. error:
  1293. if (NULL != pwszServer)
  1294. {
  1295. LocalFree(pwszServer);
  1296. }
  1297. if (NULL != pwszAuthority)
  1298. {
  1299. LocalFree(pwszAuthority);
  1300. }
  1301. if (NULL != pbCert)
  1302. {
  1303. LocalFree(pbCert);
  1304. }
  1305. if (NULL != pcsEnroll)
  1306. {
  1307. CertServerFreeMemory(pcsEnroll);
  1308. }
  1309. if (NULL != strCertChain)
  1310. {
  1311. SysFreeString(strCertChain);
  1312. }
  1313. if (NULL != strCert)
  1314. {
  1315. SysFreeString(strCert);
  1316. }
  1317. if (NULL != strDisposition)
  1318. {
  1319. SysFreeString(strDisposition);
  1320. }
  1321. if (NULL != pwszRequest)
  1322. {
  1323. LocalFree(pwszRequest);
  1324. }
  1325. return(hr);
  1326. }
  1327. HRESULT
  1328. TestOneRequest(
  1329. IN PctPrivateKey const *pKey,
  1330. OPTIONAL IN DISPATCHINTERFACE *pdiRequest,
  1331. IN WCHAR const *pwszConfig,
  1332. IN DWORD CertNumber,
  1333. OUT DWORD *pRequestId,
  1334. OUT DWORD *pTimeOneRequest)
  1335. {
  1336. HRESULT hr;
  1337. HRESULT hrLastStatus;
  1338. NAMETABLE NameTable;
  1339. BOOL fTableAllocated;
  1340. BYTE *pbRequest;
  1341. DWORD cbRequest;
  1342. BYTE *pbCert;
  1343. DWORD cbCert;
  1344. CERT_CONTEXT const *pCertContext;
  1345. DWORD RequestIdOut = 0;
  1346. DWORD Disposition;
  1347. WCHAR *pwszDisposition = NULL;
  1348. CERT_NAME_INFO *pNameInfo;
  1349. DWORD cbNameInfo;
  1350. CERT_INFO const *pCertInfo;
  1351. LONG Flags;
  1352. WCHAR wszAttributes[MAX_PATH];
  1353. fTableAllocated = FALSE;
  1354. pbRequest = NULL;
  1355. pbCert = NULL;
  1356. pCertContext = NULL;
  1357. pNameInfo = NULL;
  1358. if (g_fDebug)
  1359. {
  1360. hr = GenerateTestNameTable(&NameTable);
  1361. _JumpIfError(hr, error, "GenerateTestNameTable");
  1362. }
  1363. else
  1364. {
  1365. hr = GenerateNameTable(&NameTable);
  1366. _JumpIfError(hr, error, "GenerateNameTable");
  1367. }
  1368. fTableAllocated = TRUE;
  1369. hr = EncodeRequest(pKey, &NameTable, &pbRequest, &cbRequest);
  1370. _JumpIfError(hr, error, "EncodeRequest");
  1371. Flags = CR_IN_PKCS10;
  1372. if (g_fRenewal)
  1373. {
  1374. BYTE *pbTmp;
  1375. hr = EncodeRenewal(pbRequest, cbRequest, &pbTmp, &cbRequest);
  1376. _JumpIfError(hr, error, "EncodeRenewal");
  1377. LocalFree(pbRequest);
  1378. pbRequest = pbTmp;
  1379. Flags = CR_IN_PKCS7;
  1380. }
  1381. if (g_fSave)
  1382. {
  1383. hr = EncodeToFileW(
  1384. L"test.req",
  1385. pbRequest,
  1386. cbRequest,
  1387. DECF_FORCEOVERWRITE | CRYPT_STRING_BINARY);
  1388. _JumpIfError(hr, error, "EncodeToFileW");
  1389. }
  1390. *pTimeOneRequest = 0 - GetTickCount();
  1391. wsprintf(
  1392. wszAttributes,
  1393. L"\n"
  1394. L" attrib 1 end : value 1 end \t\r\n"
  1395. L"\tattrib 2 end:value_2_end\n"
  1396. L" \tattrib3:value-3-end\r\n"
  1397. L"Version:3\n"
  1398. L"RequestType:CertGen\n"
  1399. L"CertGenSequence:%u\n",
  1400. CertNumber);
  1401. hr = SubmitRequest(
  1402. pdiRequest,
  1403. Flags,
  1404. pbRequest,
  1405. cbRequest,
  1406. wszAttributes,
  1407. pwszConfig,
  1408. &RequestIdOut,
  1409. &Disposition,
  1410. &hrLastStatus,
  1411. &pwszDisposition,
  1412. &pbCert,
  1413. &cbCert);
  1414. *pTimeOneRequest += GetTickCount();
  1415. if (S_OK != hr)
  1416. {
  1417. _JumpError2(
  1418. hr,
  1419. error,
  1420. "SubmitRequest",
  1421. HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  1422. }
  1423. if (CR_DISP_ISSUED != Disposition)
  1424. {
  1425. hr = hrLastStatus;
  1426. if (S_OK == hr)
  1427. {
  1428. hr = E_FAIL;
  1429. }
  1430. wprintf(
  1431. L"SubmitRequest disposition=%x hr=%x (%ws)\n",
  1432. Disposition,
  1433. hr,
  1434. NULL == pwszDisposition? L"???" : pwszDisposition);
  1435. if (g_fIgnoreError)
  1436. {
  1437. hr = S_OK;
  1438. }
  1439. if (CR_DISP_DENIED == Disposition && g_fIgnoreAccessDenied)
  1440. {
  1441. hr = S_OK;
  1442. }
  1443. _JumpError(hr, error, "Cert not issued!");
  1444. }
  1445. pCertContext = CertCreateCertificateContext(
  1446. X509_ASN_ENCODING,
  1447. pbCert,
  1448. cbCert);
  1449. if (NULL == pCertContext)
  1450. {
  1451. hr = myHLastError();
  1452. _JumpError(hr, error, "CertCreateCertificateContext");
  1453. }
  1454. pCertInfo = pCertContext->pCertInfo;
  1455. if (!myDecodeName(
  1456. X509_ASN_ENCODING,
  1457. X509_NAME,
  1458. pCertInfo->Subject.pbData,
  1459. pCertInfo->Subject.cbData,
  1460. CERTLIB_USE_LOCALALLOC,
  1461. &pNameInfo,
  1462. &cbNameInfo))
  1463. {
  1464. hr = myHLastError();
  1465. _JumpError(hr, error, "myDecodeName");
  1466. }
  1467. hr = CheckProperties(RequestIdOut, &NameTable, CertNumber, pNameInfo);
  1468. _JumpIfError(hr, error, "CheckProperties");
  1469. error:
  1470. *pRequestId = RequestIdOut;
  1471. if (NULL != pwszDisposition)
  1472. {
  1473. LocalFree(pwszDisposition);
  1474. }
  1475. if (NULL != pNameInfo)
  1476. {
  1477. LocalFree(pNameInfo);
  1478. }
  1479. if (NULL != pCertContext)
  1480. {
  1481. CertFreeCertificateContext(pCertContext);
  1482. }
  1483. if (NULL != pbCert)
  1484. {
  1485. LocalFree(pbCert);
  1486. }
  1487. if (NULL != pbRequest)
  1488. {
  1489. LocalFree(pbRequest);
  1490. }
  1491. if (fTableAllocated)
  1492. {
  1493. FreeLocalMemory(&NameTable);
  1494. }
  1495. return(hr);
  1496. }
  1497. HRESULT
  1498. TestMain()
  1499. {
  1500. HRESULT hr;
  1501. PctPrivateKey *pKey = NULL;
  1502. DWORD TimeStartTest;
  1503. DWORD TimeStartLastN;
  1504. DWORD TimeRequestTotal = 0;
  1505. DWORD TimeRequestLastN = 0;
  1506. DWORD TimeElapsedTotal;
  1507. DWORD TotalCount = 0;
  1508. DISPATCHINTERFACE diRequest;
  1509. DISPATCHINTERFACE *pdiRequest = NULL;
  1510. BOOL fCoInit = FALSE;
  1511. DWORD RequestId = 0;
  1512. WCHAR const *pwszConfig;
  1513. BSTR strConfig = NULL;
  1514. g_crdnMax = g_crdnSubject;
  1515. hr = GetPrivateKeyStuff(&pKey);
  1516. _JumpIfError(hr, error, "GetPrivateKeyStuff");
  1517. hr = CoInitialize(NULL);
  1518. if (S_OK != hr && S_FALSE != hr)
  1519. {
  1520. _JumpError(hr, error, "CoInitialize");
  1521. }
  1522. fCoInit = TRUE;
  1523. if (1 >= g_fRPC)
  1524. {
  1525. hr = Request_Init(g_DispatchFlags, &diRequest);
  1526. _JumpIfError(hr, error, "Request_Init");
  1527. pdiRequest = &diRequest;
  1528. }
  1529. pwszConfig = g_pwszConfig;
  1530. if (NULL == pwszConfig)
  1531. {
  1532. hr = ConfigGetConfig(g_DispatchFlags, CC_LOCALACTIVECONFIG, &strConfig);
  1533. _JumpIfError(hr, error, "ConfigGetConfig");
  1534. pwszConfig = strConfig;
  1535. }
  1536. TimeStartLastN = TimeStartTest = GetTickCount();
  1537. while (TotalCount < g_MaximumCount)
  1538. {
  1539. DWORD TimeOneRequest;
  1540. DWORD TimeRequestEnd;
  1541. DWORD TimeElapsedLastN;
  1542. hr = TestOneRequest(
  1543. pKey,
  1544. pdiRequest,
  1545. pwszConfig,
  1546. TotalCount + 1,
  1547. &RequestId,
  1548. &TimeOneRequest);
  1549. if (S_OK != hr)
  1550. {
  1551. WCHAR const *pwszMsg;
  1552. pwszMsg = myGetErrorMessageText(hr, TRUE);
  1553. CONSOLEPRINT3((
  1554. DBG_SS_CERTREQ,
  1555. "RequestId %u: %hs%ws\n",
  1556. RequestId,
  1557. HRESULT_FROM_WIN32(ERROR_INVALID_DATA) == hr?
  1558. "Ignoring 7f length encoding: " : "",
  1559. NULL != pwszMsg? pwszMsg : L"Message retrieval Error"));
  1560. if (NULL != pwszMsg)
  1561. {
  1562. LocalFree(const_cast<WCHAR *>(pwszMsg));
  1563. }
  1564. }
  1565. if (HRESULT_FROM_WIN32(ERROR_INVALID_DATA) != hr || !g_fIgnoreError)
  1566. {
  1567. _JumpIfError(hr, error, "TestOneRequest");
  1568. }
  1569. TimeRequestEnd = GetTickCount();
  1570. TimeRequestTotal += TimeOneRequest;
  1571. TimeRequestLastN += TimeOneRequest;
  1572. TimeElapsedTotal = TimeRequestEnd - TimeStartTest;
  1573. TimeElapsedLastN = TimeRequestEnd - TimeStartLastN;
  1574. TotalCount++;
  1575. if (g_fTime)
  1576. {
  1577. if (0 == g_IntervalCount || 0 == (TotalCount % g_IntervalCount))
  1578. {
  1579. DWORD count;
  1580. count = g_IntervalCount;
  1581. if (0 == count)
  1582. {
  1583. count = TotalCount;
  1584. }
  1585. TimeElapsedLastN = TimeRequestEnd - TimeStartLastN;
  1586. wprintf(
  1587. L"RequestId %u: %u/%u Certs in %u/%u seconds (ave=%u/%u ms)\n",
  1588. RequestId,
  1589. count,
  1590. TotalCount,
  1591. MSTOSEC(TimeElapsedLastN),
  1592. MSTOSEC(TimeElapsedTotal),
  1593. TimeElapsedLastN/count,
  1594. TimeElapsedTotal/TotalCount);
  1595. if (0 != g_IntervalCount)
  1596. {
  1597. TimeRequestLastN = 0;
  1598. TimeStartLastN = GetTickCount();
  1599. }
  1600. }
  1601. }
  1602. }
  1603. error:
  1604. if (NULL != pKey)
  1605. {
  1606. LocalFree(pKey);
  1607. }
  1608. if (NULL != g_pRSAPublicKey)
  1609. {
  1610. LocalFree(g_pRSAPublicKey);
  1611. }
  1612. if (NULL != pdiRequest)
  1613. {
  1614. Request_Release(pdiRequest);
  1615. }
  1616. if (NULL != strConfig)
  1617. {
  1618. SysFreeString(strConfig);
  1619. }
  1620. if (fCoInit)
  1621. {
  1622. CoUninitialize();
  1623. }
  1624. if (0 != TotalCount)
  1625. {
  1626. wprintf(
  1627. L"\n%u Total Certificates in %u/%u seconds (request/elapsed time)\n",
  1628. TotalCount,
  1629. MSTOSEC(TimeRequestTotal),
  1630. MSTOSEC(TimeElapsedTotal));
  1631. wprintf(
  1632. L"Certificates required average of %u/%u milliseconds "
  1633. L"(request/elapsed time)\n",
  1634. TimeRequestTotal/TotalCount,
  1635. TimeElapsedTotal/TotalCount);
  1636. }
  1637. return(hr);
  1638. }
  1639. void
  1640. Usage(TCHAR *pwszError)
  1641. {
  1642. wprintf(L"%ws\n", pwszError);
  1643. wprintf(L"%ws\n", wszUsage);
  1644. exit(1);
  1645. }
  1646. extern "C" int __cdecl
  1647. wmain(int argc, WCHAR *argv[])
  1648. {
  1649. HRESULT hr;
  1650. while (1 < argc && ('-' == argv[1][0] || '/' == argv[1][0]))
  1651. {
  1652. WCHAR *pwsz = argv[1];
  1653. while (NULL != pwsz && *++pwsz != '\0')
  1654. {
  1655. switch (*pwsz)
  1656. {
  1657. case 'a':
  1658. case 'A':
  1659. g_fIgnoreAccessDenied++;
  1660. break;
  1661. case 'c':
  1662. case 'C':
  1663. if (0 == lstrcmpi(pwsz, L"config"))
  1664. {
  1665. if (1 >= argc)
  1666. {
  1667. Usage(TEXT("Missing -config argument"));
  1668. }
  1669. g_pwszConfig = argv[2];
  1670. }
  1671. else
  1672. {
  1673. if (2 >= argc || !iswdigit(argv[2][0]) || '\0' != pwsz[1])
  1674. {
  1675. Usage(TEXT("Missing numeric -c argument"));
  1676. }
  1677. g_MaximumCount = _wtoi(argv[2]);
  1678. }
  1679. argc--;
  1680. argv++;
  1681. pwsz = NULL;
  1682. break;
  1683. case 'd':
  1684. case 'D':
  1685. g_fDebug++;
  1686. break;
  1687. case 'i':
  1688. case 'I':
  1689. g_fIgnoreError++;
  1690. break;
  1691. case 'r':
  1692. case 'R':
  1693. if (0 == lstrcmpi(pwsz, L"renewal"))
  1694. {
  1695. g_fRenewal++;
  1696. pwsz = NULL;
  1697. }
  1698. else
  1699. if (0 == lstrcmpi(pwsz, L"rpc"))
  1700. {
  1701. g_fRPC++;
  1702. if (0 == lstrcmp(pwsz, L"RPC"))
  1703. {
  1704. g_fRPC++;
  1705. }
  1706. pwsz = NULL;
  1707. }
  1708. else
  1709. {
  1710. g_fSave++;
  1711. }
  1712. break;
  1713. case 'p':
  1714. case 'P':
  1715. g_fPrintProperties++;
  1716. break;
  1717. case 't':
  1718. case 'T':
  1719. g_fTime++;
  1720. g_IntervalCount = 10;
  1721. if (2 < argc && iswdigit(argv[2][0]))
  1722. {
  1723. if ('\0' != pwsz[1])
  1724. {
  1725. Usage(TEXT("Missing numeric -t argument"));
  1726. }
  1727. g_IntervalCount = _wtoi(argv[2]);
  1728. argc--;
  1729. argv++;
  1730. pwsz = NULL;
  1731. }
  1732. break;
  1733. case 'z':
  1734. case 'Z':
  1735. g_fAllowDups++;
  1736. g_crdnMax *= 5;
  1737. break;
  1738. case 'm':
  1739. case 'M':
  1740. g_fShowTime++;
  1741. break;
  1742. case 'h':
  1743. case 'H':
  1744. default:
  1745. Usage(TEXT("CertGen Usage"));
  1746. }
  1747. }
  1748. argc--;
  1749. argv++;
  1750. }
  1751. if (argc != 1)
  1752. {
  1753. Usage(TEXT("Extra arguments"));
  1754. }
  1755. if (g_fShowTime)
  1756. {
  1757. SYSTEMTIME st;
  1758. GetSystemTime(&st);
  1759. wprintf(L"Start time: %2i:%2i:%2i:%i\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
  1760. }
  1761. hr = TestMain();
  1762. if (g_fShowTime)
  1763. {
  1764. SYSTEMTIME st;
  1765. GetSystemTime(&st);
  1766. wprintf(L"End time: %2i:%2i:%2i:%i\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
  1767. wprintf(L"type any key to finish->");
  1768. _getch();
  1769. wprintf(L"\n");
  1770. }
  1771. myRegisterMemDump();
  1772. return((int) hr);
  1773. }
  1774. // We need this to include RSA library
  1775. extern "C" BOOL
  1776. GenRandom(ULONG huid, BYTE *pbBuffer, size_t dwLength)
  1777. {
  1778. wprintf(L"Error GenRandom called\n");
  1779. ExitProcess(0);
  1780. return(TRUE);
  1781. }