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.

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