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.

11799 lines
268 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: pkcs.cpp
  7. //
  8. // Contents: Cert Server Extension interfaces -- PKCS implementation
  9. //
  10. //---------------------------------------------------------------------------
  11. #include <pch.cpp>
  12. #pragma hdrstop
  13. #include <stdio.h>
  14. #include <time.h>
  15. #define SECURITY_WIN32
  16. #include <security.h>
  17. #include "resource.h"
  18. #include "cscom.h"
  19. #include "csprop.h"
  20. #include "elog.h"
  21. #include "certlog.h"
  22. #include "csdisp.h"
  23. #include "cscsp.h"
  24. #include <certca.h>
  25. #include <esent.h>
  26. #include <winldap.h>
  27. #include "csldap.h"
  28. #include "cainfop.h"
  29. #define __dwFILE__ __dwFILE_CERTSRV_PKCS_CPP_
  30. CSURLTEMPLATE *g_paRevURL = NULL;
  31. DWORD g_caRevURL = 0;
  32. CSURLTEMPLATE *g_paCACertURL = NULL;
  33. DWORD g_caCACertURL = 0;
  34. BSTR g_strDomainDN = NULL;
  35. BSTR g_strConfigDN = NULL;
  36. WCHAR *g_pwszKRAPublishURL = NULL;
  37. WCHAR *g_pwszAIACrossCertPublishURL = NULL;
  38. WCHAR *g_pwszRootTrustCrossCertPublishURL = NULL;
  39. // Note on Renewal and Key reuse:
  40. //
  41. // Cert Indexes, Key Indexes and CRL Name Indexes are all zero based.
  42. //
  43. // One CRL is issued by this CA for each unique key. Each CRL covers all of
  44. // the certs issued by this CA for one key, even though the key may have been
  45. // used by multiple renewal certs.
  46. //
  47. // The database IssuerNameID PROPTYPE_LONG column holds the Key Index in the
  48. // top 16 bits and the Cert Index in the bottom 16 bits. This allows a pair of
  49. // query restrictions to reduce the result row set to those revoked certs
  50. // that will be placed into a single CRL.
  51. //
  52. // When Cert File, Key Container, CRL File or DS Object name templates include
  53. // an Index Suffix, an empty string suffix, "", is used when the index is zero.
  54. // Otherwise the Suffix is "(%u)", where the index itself is passed to wsprintf
  55. // to construct the %u field.
  56. //
  57. // Cert Indexes increment each time the CA cert is renewed. Because 16 bit
  58. // Cert Indexes are stored in the database, a CA may have up to 64k certs,
  59. // and be renewed a maximum of 64k-1 times.
  60. //
  61. // The Cert File Name Suffix is built from the Cert Index.
  62. //
  63. // Key Indexes: The original installed CA cert uses a Key Index of 0.
  64. // If a renewal cert uses the same key as any previous cert used by this CA,
  65. // the Key Index for the new CA cert is taken from the previous CA cert.
  66. // If a renewal cert uses a new Key, the Cert Index is used for the Key Index.
  67. // The primary reason sequential Key Indexes are not used for new keys is that
  68. // too much context information is required to determine the next Key Index --
  69. // which is particularly difficult to obtain when performing PFX restore.
  70. //
  71. // The Key Container Name Suffix is built from the Key Index.
  72. //
  73. //
  74. // CRL Indexes: same as Key Index.
  75. // CRL File Name Suffix: same as Key Container Name Suffix.
  76. //
  77. // Example: Cert CertName Key KeyName CRL CRLName
  78. // Index Suffix Index Suffix Index Suffix
  79. // Original Install 0 "" 0 "" 0 ""
  80. //
  81. // Renew, new Key 1 "(1)" 1 "(1)" 1 "(1)"
  82. // *Renew, reuse Key 2 "(2)" 1 "(1)" 1 "(1)"
  83. // *Renew, reuse Key 3 "(3)" 1 "(1)" 1 "(1)"
  84. //
  85. // Renew, new Key 4 "(4)" 4 "(4)" 4 "(4)"
  86. // *Renew, reuse Key 5 "(5)" 4 "(4)" 4 "(4)"
  87. //
  88. // Renew, new Key 6 "(6)" 6 "(6)" 6 "(6)"
  89. // *Renew, reuse Key 7 "(7)" 6 "(6)" 6 "(6)"
  90. //
  91. //
  92. // CCertRequest::GetCACertificate can be used to fetch Certs and CRLs by Index.
  93. // This API always accepts a Cert Index.
  94. //
  95. // When fetching a certificate: If the Cert Index is valid, the appropriate
  96. // certificate or chain is returned, even if it is expired or revoked.
  97. //
  98. // When fetching a CRL: If the Cert Index is valid AND if the Cert Index
  99. // MATCHES the Key Index for the indexed Cert, the appropriate CRL is returned.
  100. // This means that an error will be returned when requesting CRLs associated
  101. // with entries in the above table that reused keys (marked with an asterisk
  102. // in the first column). The nearest previous unmarked entry's CRL covers
  103. // revocations for the marked entries.
  104. //
  105. //
  106. // CCertServer{Policy,Exit}::GetCertificateProperty can be used to fetch
  107. // information about Certs and CRLs. This API allows an optional numeric
  108. // suffix on the property name, as in "RawCRL.3". The suffix is always
  109. // interpreted as a Cert Index.
  110. //
  111. // wszPROPCERTCOUNT: Returns total CA Cert count, including expired and
  112. // revoked certs. No numeric Cert Index suffix is allowed.
  113. //
  114. // wszPROPRAWCACERTIFICATE: Returns the Cert for the passed Cert Index.
  115. // Returns the Cert for the most recent Cert Index if no Cert Index is
  116. // specified. Expired and revoked certs are still retrievable.
  117. //
  118. // wszPROPCERTSTATE: Returns the Cert State for the passed Cert Index.
  119. // Returns the Cert State for the most recent Cert Index if no Cert Index is
  120. // specified.
  121. // Values for wszPROPCERTSTATE (see certadm.h):
  122. // CA_DISP_REVOKED // This Cert has been revoked.
  123. // CA_DISP_VALID // This Cert is still valid
  124. // CA_DISP_INVALID // This Cert has expired.
  125. // CA_DISP_ERROR // Cert unavailable (placehholder in registry?)
  126. //
  127. // wszPROPCERTSUFFIX: Returns the Cert FileName Suffix for the passed Cert
  128. // Index. Returns the Cert FileName Suffix for the most recent Cert Index if
  129. // no Cert Index is specified.
  130. //
  131. // wszPROPRAWCRL: Returns the CRL for the passed Cert Index. As with
  132. // CCertRequest::GetCACertificate, it is an error to fetch a CRL for a Cert
  133. // that reused keys. In the above table, only "RawCRL.0", "RawCRL.1",
  134. // "RawCRL.4", "RawCRL.6" & "RawCRL" are allowed. "RawCRL" will fetch the most
  135. // recent CRL. Use the wszPROPCRLSTATE with a numeric Cert Index suffix to
  136. // determine which CRLs are valid to fetch. CA_DISP_ERROR indicates the
  137. // CRL cannot be fetched. CA_DISP_REVOKED and CA_DISP_INVALID CRLs are still
  138. // retrievable via this method call.
  139. //
  140. // All of the other CRL-related property fetches are supported for all valid
  141. // Cert Index values:
  142. //
  143. // wszPROPCRLINDEX: Returns the CRL Index value for the passed Cert Index.
  144. // Returns the CRL Index value for the most recent Cert Index if no Cert Index
  145. // is specified.
  146. //
  147. // wszPROPCRLSTATE: Returns the CRL State for the passed Cert Index.
  148. // Returns the CRL State for the most recent Cert Index if no Cert Index is
  149. // specified.
  150. // Values for wszPROPCRLSTATE (see certadm.h):
  151. // CA_DISP_REVOKED // All unexpired certs using this Cert's CRL have been
  152. // // revoked.
  153. // CA_DISP_VALID // This Cert is still publishing CRLs as needed.
  154. // CA_DISP_INVALID // All certs using this Cert's CRL are expired.
  155. // CA_DISP_ERROR // This Cert's CRL is managed by another Cert.
  156. //
  157. // wszPROPCRLSUFFIX: Returns the CRL FileName Suffix for the passed Cert Index.
  158. // Returns the CRL FileName Suffix for the most recent Cert Index if no Cert
  159. // Index is specified.
  160. CACTX *g_aCAContext; // allocated array of CACTXs
  161. CACTX *g_pCAContextCurrent; // current CACTX is last g_aCAContext element
  162. CERT_CONTEXT const **g_rgKRACerts = NULL;
  163. BSTR *g_rgstrKRAHashes = NULL;
  164. DWORD g_cKRAHashes = 0;
  165. DWORD g_cKRACertsRoundRobin = 0;
  166. DWORD g_iKRACerts; // Next KRA cert to be used by this CA
  167. HRESULT g_hrKRALoad = S_OK;
  168. DWORD g_cCAKeys; // Total number of unique CA keys managed by this CA
  169. DWORD g_cCACerts; // Total number of CA certs managed by this CA
  170. DWORD g_cKRACerts; // Total number of KRA certs used by this CA
  171. CAXCHGCTX *g_aCAXchgContext; // allocated array of CAXCHGCTXs
  172. CAXCHGCTX *g_pCAXchgContextCurrent; // current CAXCHGCTX is last element
  173. DWORD g_cCAXchgCerts; // number of CA Xchg certs managed by this CA
  174. HCERTSTORE g_hStoreCAXchg = NULL;
  175. DWORD g_dwXchgProvType;
  176. WCHAR *g_pwszXchgProvName = NULL;
  177. ALG_ID g_XchgidAlg;
  178. BOOL g_fXchgMachineKeyset;
  179. DWORD g_dwXchgKeySize;
  180. LONG g_lValidityPeriodCount = dwVALIDITYPERIODCOUNTDEFAULT_STANDALONE;
  181. enum ENUM_PERIOD g_enumValidityPeriod = dwVALIDITYPERIODENUMDEFAULT;
  182. enum ENUM_PERIOD g_enumCAXchgValidityPeriod = dwCAXCHGVALIDITYPERIODENUMDEFAULT;
  183. LONG g_lCAXchgValidityPeriodCount = dwCAXCHGVALIDITYPERIODCOUNTDEFAULT;
  184. enum ENUM_PERIOD g_enumCAXchgOverlapPeriod = dwCAXCHGOVERLAPPERIODENUMDEFAULT;
  185. LONG g_lCAXchgOverlapPeriodCount = dwCAXCHGOVERLAPPERIODCOUNTDEFAULT;
  186. typedef enum {
  187. ST_COUNTRY = 0,
  188. ST_ORGANIZATION,
  189. ST_ORGANIZATIONALUNIT,
  190. ST_COMMONNAME,
  191. ST_LOCALITY,
  192. ST_STATEORPROVINCE,
  193. ST_TITLE,
  194. ST_GIVENNAME,
  195. ST_INITIALS,
  196. ST_SURNAME,
  197. ST_DOMAINCOMPONENT,
  198. ST_EMAIL,
  199. ST_STREETADDRESS,
  200. ST_UNSTRUCTUREDNAME,
  201. ST_UNSTRUCTUREDADDRESS,
  202. ST_DEVICESERIALNUMBER,
  203. ST_NULL
  204. };
  205. typedef struct _SUBJECTTABLE
  206. {
  207. WCHAR const *pwszPropName;
  208. CHAR const *pszObjId;
  209. WCHAR const * const *apwszAttributeName;
  210. DWORD cchMax;
  211. DWORD dwValueType;
  212. DWORD dwSubjectTableValue;
  213. } SUBJECTTABLE;
  214. WCHAR const *apwszAttrCountry[] = {
  215. wszATTRCOUNTRY1,
  216. wszATTRCOUNTRY2,
  217. TEXT(szOID_COUNTRY_NAME),
  218. NULL
  219. };
  220. WCHAR const *apwszAttrOrg[] = {
  221. wszATTRORG1,
  222. wszATTRORG2,
  223. wszATTRORG3,
  224. TEXT(szOID_ORGANIZATION_NAME),
  225. NULL
  226. };
  227. WCHAR const *apwszAttrOrgUnit[] = {
  228. wszATTRORGUNIT1,
  229. wszATTRORGUNIT2,
  230. wszATTRORGUNIT3,
  231. wszATTRORGUNIT4,
  232. TEXT(szOID_ORGANIZATIONAL_UNIT_NAME),
  233. NULL
  234. };
  235. WCHAR const *apwszAttrCommonName[] = {
  236. wszATTRCOMMONNAME1,
  237. wszATTRCOMMONNAME2,
  238. TEXT(szOID_COMMON_NAME),
  239. NULL
  240. };
  241. WCHAR const *apwszAttrLocality[] = {
  242. wszATTRLOCALITY1,
  243. wszATTRLOCALITY2,
  244. TEXT(szOID_LOCALITY_NAME),
  245. NULL
  246. };
  247. WCHAR const *apwszAttrState[] = {
  248. wszATTRSTATE1,
  249. wszATTRSTATE2,
  250. wszATTRSTATE3,
  251. TEXT(szOID_STATE_OR_PROVINCE_NAME),
  252. NULL
  253. };
  254. WCHAR const *apwszAttrTitle[] = {
  255. wszATTRTITLE1,
  256. wszATTRTITLE2,
  257. TEXT(szOID_TITLE),
  258. NULL
  259. };
  260. WCHAR const *apwszAttrGivenName[] = {
  261. wszATTRGIVENNAME1,
  262. wszATTRGIVENNAME2,
  263. TEXT(szOID_GIVEN_NAME),
  264. NULL
  265. };
  266. WCHAR const *apwszAttrInitials[] = {
  267. wszATTRINITIALS1,
  268. wszATTRINITIALS2,
  269. TEXT(szOID_INITIALS),
  270. NULL
  271. };
  272. WCHAR const *apwszAttrSurName[] = {
  273. wszATTRSURNAME1,
  274. wszATTRSURNAME2,
  275. TEXT(szOID_SUR_NAME),
  276. NULL
  277. };
  278. WCHAR const *apwszAttrDomComp[] = {
  279. wszATTRDOMAINCOMPONENT1,
  280. wszATTRDOMAINCOMPONENT2,
  281. TEXT(szOID_DOMAIN_COMPONENT),
  282. NULL
  283. };
  284. WCHAR const *apwszAttrEMail[] = {
  285. wszATTREMAIL1,
  286. wszATTREMAIL2,
  287. TEXT(szOID_RSA_emailAddr),
  288. NULL
  289. };
  290. WCHAR const *apwszAttrStreetAddr[] = {
  291. wszATTRSTREETADDRESS1,
  292. wszATTRSTREETADDRESS2,
  293. TEXT(szOID_STREET_ADDRESS),
  294. NULL
  295. };
  296. WCHAR const *apwszAttrUnstructName[] = {
  297. wszATTRUNSTRUCTUREDNAME1,
  298. TEXT(szOID_RSA_unstructName),
  299. NULL
  300. };
  301. WCHAR const *apwszAttrUnstructAddr[] = {
  302. wszATTRUNSTRUCTUREDADDRESS1,
  303. TEXT(szOID_RSA_unstructAddr),
  304. NULL
  305. };
  306. WCHAR const *apwszAttrDeviceSerialNumber[] = {
  307. wszATTRDEVICESERIALNUMBER1,
  308. TEXT(szOID_DEVICE_SERIAL_NUMBER),
  309. NULL
  310. };
  311. SUBJECTTABLE const pkcs_subject[] =
  312. {
  313. {
  314. // "Country",
  315. g_wszPropSubjectCountry,
  316. szOID_COUNTRY_NAME,
  317. apwszAttrCountry,
  318. cchCOUNTRYNAMEMAX,
  319. CERT_RDN_PRINTABLE_STRING,
  320. ST_COUNTRY,
  321. },
  322. {
  323. // "Organization",
  324. g_wszPropSubjectOrganization,
  325. szOID_ORGANIZATION_NAME,
  326. apwszAttrOrg,
  327. cchORGANIZATIONNAMEMAX,
  328. CERT_RDN_PRINTABLE_STRING,
  329. ST_ORGANIZATION,
  330. },
  331. {
  332. // "OrganizationalUnit",
  333. g_wszPropSubjectOrgUnit,
  334. szOID_ORGANIZATIONAL_UNIT_NAME,
  335. apwszAttrOrgUnit,
  336. cchORGANIZATIONALUNITNAMEMAX,
  337. CERT_RDN_PRINTABLE_STRING,
  338. ST_ORGANIZATIONALUNIT,
  339. },
  340. {
  341. // "CommonName",
  342. g_wszPropSubjectCommonName,
  343. szOID_COMMON_NAME,
  344. apwszAttrCommonName,
  345. cchCOMMONNAMEMAX,
  346. CERT_RDN_PRINTABLE_STRING,
  347. ST_COMMONNAME,
  348. },
  349. {
  350. // "Locality",
  351. g_wszPropSubjectLocality,
  352. szOID_LOCALITY_NAME,
  353. apwszAttrLocality,
  354. cchLOCALITYMANAMEMAX,
  355. CERT_RDN_PRINTABLE_STRING,
  356. ST_LOCALITY,
  357. },
  358. {
  359. // "StateOrProvince",
  360. g_wszPropSubjectState,
  361. szOID_STATE_OR_PROVINCE_NAME,
  362. apwszAttrState,
  363. cchSTATEORPROVINCENAMEMAX,
  364. CERT_RDN_PRINTABLE_STRING,
  365. ST_STATEORPROVINCE,
  366. },
  367. {
  368. // "Title",
  369. g_wszPropSubjectTitle,
  370. szOID_TITLE,
  371. apwszAttrTitle,
  372. cchTITLEMAX,
  373. CERT_RDN_PRINTABLE_STRING,
  374. ST_TITLE,
  375. },
  376. {
  377. // "GivenName",
  378. g_wszPropSubjectGivenName,
  379. szOID_GIVEN_NAME,
  380. apwszAttrGivenName,
  381. cchGIVENNAMEMAX,
  382. CERT_RDN_PRINTABLE_STRING,
  383. ST_GIVENNAME,
  384. },
  385. {
  386. // "Initials",
  387. g_wszPropSubjectInitials,
  388. szOID_INITIALS,
  389. apwszAttrInitials,
  390. cchINITIALSMAX,
  391. CERT_RDN_PRINTABLE_STRING,
  392. ST_INITIALS,
  393. },
  394. {
  395. // "SurName",
  396. g_wszPropSubjectSurName,
  397. szOID_SUR_NAME,
  398. apwszAttrSurName,
  399. cchSURNAMEMAX,
  400. CERT_RDN_PRINTABLE_STRING,
  401. ST_SURNAME,
  402. },
  403. {
  404. // "DomainComponent",
  405. g_wszPropSubjectDomainComponent,
  406. szOID_DOMAIN_COMPONENT,
  407. apwszAttrDomComp,
  408. cchDOMAINCOMPONENTMAX,
  409. CERT_RDN_PRINTABLE_STRING,
  410. ST_DOMAINCOMPONENT,
  411. },
  412. {
  413. // "EMail",
  414. g_wszPropSubjectEMail,
  415. szOID_RSA_emailAddr,
  416. apwszAttrEMail,
  417. cchEMAILMAX,
  418. CERT_RDN_PRINTABLE_STRING,
  419. ST_EMAIL,
  420. },
  421. {
  422. // "StreetAddress",
  423. g_wszPropSubjectStreetAddress,
  424. szOID_STREET_ADDRESS,
  425. apwszAttrStreetAddr,
  426. cchSTREETADDRESSMAX,
  427. CERT_RDN_PRINTABLE_STRING,
  428. ST_STREETADDRESS,
  429. },
  430. {
  431. // "UnstructuredName",
  432. g_wszPropSubjectUnstructuredName,
  433. szOID_RSA_unstructName,
  434. apwszAttrUnstructName,
  435. cchUNSTRUCTUREDNAMEMAX,
  436. CERT_RDN_PRINTABLE_STRING,
  437. ST_UNSTRUCTUREDNAME,
  438. },
  439. {
  440. // "UnstructuredAddress",
  441. g_wszPropSubjectUnstructuredAddress,
  442. szOID_RSA_unstructAddr,
  443. apwszAttrUnstructAddr,
  444. cchUNSTRUCTUREDADDRESSMAX,
  445. CERT_RDN_PRINTABLE_STRING,
  446. ST_UNSTRUCTUREDADDRESS,
  447. },
  448. {
  449. // "DeviceSerialNumber",
  450. g_wszPropSubjectDeviceSerialNumber,
  451. szOID_DEVICE_SERIAL_NUMBER,
  452. apwszAttrDeviceSerialNumber,
  453. cchDEVICESERIALNUMBERMAX,
  454. CERT_RDN_PRINTABLE_STRING,
  455. ST_DEVICESERIALNUMBER,
  456. },
  457. {
  458. NULL,
  459. NULL,
  460. NULL,
  461. 0,
  462. 0,
  463. ST_NULL,
  464. },
  465. };
  466. #define CSUBJECTTABLE (sizeof(pkcs_subject) / sizeof(pkcs_subject[0]))
  467. SUBJECTTABLE const *pkcs_apSubject[CSUBJECTTABLE];
  468. SUBJECTTABLE const **pkcs_ppSubjectLast;
  469. BOOL pkcsfSubjectTemplate = FALSE;
  470. WCHAR const g_wszCNXchgSuffix[] = wszCNXCHGSUFFIX;
  471. WCHAR const g_wszNTAuth[]=L"ldap:///CN=Public Key Services,CN=Services,%s?cACertificate?one?cn=NTAuthCertificates";
  472. #define SHA1_HASH_LENGTH 20
  473. VOID
  474. pkcsSetDistinguishedName(
  475. IN ICertDBRow *prow,
  476. IN DWORD dwTable,
  477. IN CERT_NAME_BLOB const *pSubject)
  478. {
  479. DWORD cwc;
  480. WCHAR awcName[CCH_DBMAXTEXT_DN + 1];
  481. HRESULT hr;
  482. CSASSERT(PROPTABLE_REQUEST == dwTable || PROPTABLE_CERTIFICATE == dwTable);
  483. cwc = CertNameToStr(
  484. X509_ASN_ENCODING,
  485. const_cast<CERT_NAME_BLOB *>(pSubject),
  486. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  487. awcName,
  488. ARRAYSIZE(awcName));
  489. if (0 != cwc && L'\0' != awcName[0])
  490. {
  491. #if DBG_CERTSRV
  492. DWORD ReqId;
  493. prow->GetRowId(&ReqId);
  494. DBGPRINT((
  495. DBG_SS_CERTSRVI,
  496. "%ws DN(%u): '%ws'\n",
  497. PROPTABLE_REQUEST == dwTable? L"Request" : L"Certificate",
  498. ReqId,
  499. awcName));
  500. #endif
  501. if (wcslen(awcName) == ARRAYSIZE(awcName) - 1)
  502. {
  503. DBGPRINT((
  504. DBG_SS_CERTSRV,
  505. "pkcsSetDistinguishedName: possible DN truncation: %u chars: '%ws'\n",
  506. ARRAYSIZE(awcName) - 1,
  507. awcName));
  508. }
  509. hr = prow->SetProperty(
  510. g_wszPropSubjectDistinguishedName,
  511. PROPTYPE_STRING | PROPCALLER_SERVER | dwTable,
  512. MAXDWORD,
  513. (BYTE const *) awcName);
  514. _PrintIfError(hr, "SetProperty(DN)");
  515. }
  516. }
  517. WCHAR const *
  518. PKCSMapAttributeName(
  519. OPTIONAL IN WCHAR const *pwszAttributeName,
  520. OPTIONAL IN CHAR const *pszObjId,
  521. OUT DWORD *pdwIndex,
  522. OUT DWORD *pcchMax)
  523. {
  524. SUBJECTTABLE const *pSubjectTable;
  525. WCHAR const *pwszPropName = NULL;
  526. for (pSubjectTable = pkcs_subject; ; pSubjectTable++)
  527. {
  528. WCHAR const * const *ppwsz;
  529. if (NULL == pSubjectTable->pwszPropName)
  530. {
  531. goto error;
  532. }
  533. if (NULL != pwszAttributeName)
  534. {
  535. for (ppwsz = pSubjectTable->apwszAttributeName;
  536. NULL != *ppwsz;
  537. ppwsz++)
  538. {
  539. if (0 == lstrcmpi(pwszAttributeName, *ppwsz))
  540. {
  541. break;
  542. }
  543. }
  544. if (NULL != *ppwsz ||
  545. 0 == lstrcmpi(pwszAttributeName, pSubjectTable->pwszPropName))
  546. {
  547. break;
  548. }
  549. }
  550. if (NULL != pszObjId &&
  551. 0 == strcmp(pszObjId, pSubjectTable->pszObjId))
  552. {
  553. break;
  554. }
  555. }
  556. CSASSERT(NULL != pSubjectTable->pwszPropName);
  557. pwszPropName = pSubjectTable->pwszPropName;
  558. *pdwIndex = pSubjectTable->dwSubjectTableValue;
  559. *pcchMax = pSubjectTable->cchMax;
  560. error:
  561. return(pwszPropName);
  562. }
  563. HRESULT
  564. pkcsFindCAContext(
  565. IN DWORD iCert, // MAXDWORD -> use current
  566. IN DWORD iKey, // MAXDWORD -> use current
  567. OUT CACTX **ppCAContext)
  568. {
  569. HRESULT hr = E_INVALIDARG;
  570. DWORD i;
  571. CACTX *pCAContext;
  572. *ppCAContext = NULL;
  573. // Lookup is either by cert index OR by key index, but not both or neither
  574. CSASSERT((MAXDWORD == iCert) ^ (MAXDWORD == iKey));
  575. if (MAXDWORD != iCert)
  576. {
  577. if ((~_16BITMASK & iCert) || iCert >= g_cCACerts)
  578. {
  579. _JumpError(hr, error, "bad cert index");
  580. }
  581. *ppCAContext = &g_aCAContext[iCert];
  582. CSASSERT(iCert == (*ppCAContext)->iCert);
  583. }
  584. else
  585. {
  586. CSASSERT(MAXDWORD != iKey);
  587. if ((~_16BITMASK & iKey) || iKey >= g_cCAKeys)
  588. {
  589. _JumpError(hr, error, "bad key index");
  590. }
  591. for (i = g_cCACerts; ; i--)
  592. {
  593. if (0 == i)
  594. {
  595. _JumpError(hr, error, "key index not found");
  596. }
  597. pCAContext = &g_aCAContext[i - 1];
  598. if (iKey == pCAContext->iKey)
  599. {
  600. *ppCAContext = pCAContext;
  601. break;
  602. }
  603. }
  604. }
  605. hr = S_OK; // found it!
  606. error:
  607. return(hr);
  608. }
  609. // Returns Cert Index in *piCert on success.
  610. //
  611. // returned in *piCert:
  612. // If iCert input value is not MAXDWORD, validate & return iCert.
  613. // If iCert input value is MAXDWORD, return the most current Cert Index.
  614. HRESULT
  615. PKCSMapCertIndex(
  616. IN DWORD iCert,
  617. OUT DWORD *piCert,
  618. OUT DWORD *pState)
  619. {
  620. HRESULT hr;
  621. CACTX *pCAContext;
  622. DBGCODE(DWORD iCertSave = iCert);
  623. *pState = CA_DISP_ERROR;
  624. if (MAXDWORD == iCert)
  625. {
  626. iCert = g_cCACerts - 1;
  627. }
  628. if (iCert >= g_cCACerts)
  629. {
  630. hr = E_INVALIDARG;
  631. _JumpError(hr, error, "bad CertIndex");
  632. }
  633. pCAContext = &g_aCAContext[iCert];
  634. PKCSVerifyCAState(pCAContext);
  635. *pState = CA_DISP_VALID;
  636. if (CTXF_CERTMISSING & pCAContext->Flags)
  637. {
  638. *pState = CA_DISP_ERROR;
  639. }
  640. else
  641. if (CTXF_REVOKED & pCAContext->Flags)
  642. {
  643. *pState = CA_DISP_REVOKED;
  644. }
  645. else
  646. if (CTXF_EXPIRED & pCAContext->Flags)
  647. {
  648. *pState = CA_DISP_INVALID;
  649. }
  650. *piCert = iCert;
  651. hr = S_OK;
  652. error:
  653. DBGPRINT((
  654. DBG_SS_CERTSRVI,
  655. "PKCSMapCertIndex(%u) --> %u, s=%u, hr=%x\n",
  656. iCertSave,
  657. *piCert,
  658. *pState,
  659. hr));
  660. return(hr);
  661. }
  662. // Returns Cert Index in *piCert and CRL Index in *piCRL on success.
  663. //
  664. // returned in *piCert:
  665. // If iCert input value is not MAXDWORD, validate iCert. Look up the newest
  666. // Cert Index that uses the same key as the passed iCert.
  667. // If iCert input value is MAXDWORD, return the most current Cert Index.
  668. //
  669. // returned in *piCRL:
  670. // CRL index (same as Key Index)
  671. //
  672. HRESULT
  673. PKCSMapCRLIndex(
  674. IN DWORD iCert,
  675. OUT DWORD *piCert, // returns newest iCert w/matching iKey for passed iCert
  676. OUT DWORD *piCRL,
  677. OUT DWORD *pState)
  678. {
  679. HRESULT hr;
  680. CACTX *pCAContext;
  681. CACTX *pCAContextNewest;
  682. DWORD i;
  683. DBGCODE(DWORD iCertSave = iCert);
  684. hr = PKCSMapCertIndex(iCert, piCert, pState);
  685. _JumpIfError(hr, error, "PKCSMapCertIndex");
  686. // Now we know *piCert is a valid Cert Index:
  687. pCAContext = &g_aCAContext[*piCert];
  688. *piCRL = pCAContext->iKey;
  689. // find the newest iCert with matching iKey
  690. for (i = *piCert + 1; i < g_cCACerts; i++)
  691. {
  692. if (*piCRL == g_aCAContext[i].iKey)
  693. {
  694. *piCert = i;
  695. }
  696. }
  697. pCAContextNewest = &g_aCAContext[*piCert];
  698. if (CTXF_CRLZOMBIE & pCAContext->Flags)
  699. {
  700. *pState = CA_DISP_VALID;
  701. }
  702. else
  703. if (pCAContext->iCert != pCAContext->iKey)
  704. {
  705. *pState = CA_DISP_ERROR;
  706. }
  707. else
  708. if (CTXF_EXPIRED == ((CTXF_EXPIRED | CTXF_SKIPCRL) & pCAContextNewest->Flags))
  709. {
  710. *pState = CA_DISP_VALID;
  711. }
  712. hr = S_OK;
  713. error:
  714. DBGPRINT((
  715. DBG_SS_CERTSRVI,
  716. "PKCSMapCRLIndex(%u) --> %u, iCRL=%u, s=%u, hr=%x\n",
  717. iCertSave,
  718. *piCert,
  719. *piCRL,
  720. *pState,
  721. hr));
  722. return(hr);
  723. }
  724. HRESULT
  725. PKCSGetCACertStatusCode(
  726. IN DWORD iCert,
  727. OUT HRESULT *phrCAStatusCode)
  728. {
  729. HRESULT hr;
  730. DWORD State;
  731. *phrCAStatusCode = E_FAIL;
  732. hr = PKCSMapCertIndex(iCert, &iCert, &State);
  733. _JumpIfError(hr, error, "PKCSMapCertIndex");
  734. *phrCAStatusCode = g_aCAContext[iCert].hrVerifyStatus;
  735. hr = S_OK;
  736. error:
  737. return(hr);
  738. }
  739. HRESULT
  740. PKCSGetCAState(
  741. IN BOOL fCertState,
  742. OUT BYTE *pb)
  743. {
  744. HRESULT hr;
  745. DWORD i;
  746. for (i = 0; i < g_cCACerts; i++)
  747. {
  748. DWORD iCert;
  749. DWORD iCRL;
  750. DWORD State;
  751. if (fCertState)
  752. {
  753. hr = PKCSMapCertIndex(i, &iCert, &State);
  754. _JumpIfError(hr, error, "PKCSMapCertIndex");
  755. }
  756. else
  757. {
  758. hr = PKCSMapCRLIndex(i, &iCert, &iCRL, &State);
  759. _JumpIfError(hr, error, "PKCSMapCRLIndex");
  760. }
  761. CSASSERT(0 == (~0xff & State));
  762. *pb++ = (BYTE) State;
  763. }
  764. error:
  765. return(hr);
  766. }
  767. inline DWORD MapHRESULTToKRADisposition(HRESULT hr)
  768. {
  769. switch(hr)
  770. {
  771. case CERT_E_EXPIRED: return KRA_DISP_EXPIRED;
  772. case CRYPT_E_NOT_FOUND: return KRA_DISP_NOTFOUND;
  773. case CRYPT_E_REVOKED: return KRA_DISP_REVOKED;
  774. case S_OK: return KRA_DISP_VALID;
  775. case CERT_E_UNTRUSTEDROOT:
  776. case CERT_E_CHAINING: return KRA_DISP_UNTRUSTED;
  777. case ERROR_NOT_FOUND: return KRA_DISP_NOTLOADED;
  778. default: return KRA_DISP_INVALID;
  779. }
  780. }
  781. HRESULT
  782. PKCSGetKRAState(
  783. IN DWORD cKRA,
  784. OUT BYTE *pb)
  785. {
  786. HRESULT hr = S_OK;
  787. DWORD dwCount = 0, dwUsedCount;
  788. HCERTSTORE hKRAStore = NULL;
  789. CERT_CONTEXT const *pCertContext = NULL;
  790. hKRAStore = CertOpenStore(
  791. CERT_STORE_PROV_SYSTEM_W,
  792. X509_ASN_ENCODING,
  793. NULL, // hProv
  794. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  795. wszKRA_CERTSTORE);
  796. _JumpIfError(hr, error, "CertOpenStore KRA");
  797. for (dwCount = 0, dwUsedCount = 0; dwCount < cKRA; dwCount++)
  798. {
  799. hr = myFindCACertByHashIndex(
  800. hKRAStore,
  801. g_wszSanitizedName,
  802. CSRH_CAKRACERT,
  803. dwCount,
  804. NULL,
  805. &pCertContext);
  806. if (S_OK == hr)
  807. {
  808. hr = myVerifyKRACertContext(
  809. pCertContext,
  810. (CRLF_REVCHECK_IGNORE_OFFLINE & g_dwCRLFlags)?
  811. CA_VERIFY_FLAGS_IGNORE_OFFLINE : 0);
  812. // check if the CA is using this cert (was able to
  813. // load it last time it started)
  814. if(S_OK==hr)
  815. {
  816. hr = ERROR_NOT_FOUND;
  817. for(dwUsedCount=0; dwUsedCount< g_cKRACerts; dwUsedCount++)
  818. {
  819. if(CertCompareCertificate(
  820. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  821. pCertContext->pCertInfo,
  822. g_rgKRACerts[dwUsedCount]->pCertInfo))
  823. {
  824. // the CA is using this KRA cert
  825. hr = S_OK;
  826. break;
  827. }
  828. }
  829. }
  830. }
  831. CSASSERT(0 == (~0xff & MapHRESULTToKRADisposition(hr)));
  832. pb[dwCount] = (BYTE)MapHRESULTToKRADisposition(hr);
  833. hr = S_OK;
  834. CertFreeCertificateContext(pCertContext);
  835. pCertContext = NULL;
  836. }
  837. error:
  838. if(NULL != pCertContext)
  839. {
  840. CertFreeCertificateContext(pCertContext);
  841. }
  842. if (NULL != hKRAStore)
  843. {
  844. CertCloseStore(hKRAStore, CERT_CLOSE_STORE_CHECK_FLAG);
  845. }
  846. return hr;
  847. }
  848. HRESULT
  849. pkcsSetRequestNameInfo(
  850. IN ICertDBRow *prow,
  851. IN CERT_NAME_BLOB const *pSubject,
  852. OPTIONAL IN WCHAR const *pwszCNSuffix,
  853. IN OUT DWORD *pdwRequestFlags,
  854. OUT BOOL *pfSubjectNameSet)
  855. {
  856. HRESULT hr;
  857. CERT_RDN *prdn;
  858. CERT_RDN *prdnEnd;
  859. CERT_NAME_INFO *pNameInfo = NULL;
  860. WCHAR const *pwszPropName;
  861. DWORD cbNameInfo;
  862. DWORD dwIndex;
  863. DWORD cchMax;
  864. BYTE afSubjectTable[CSUBJECTTABLE]; // see PKCSParseAttributes note
  865. SUBJECTTABLE const *pSubjectTable;
  866. *pfSubjectNameSet = FALSE;
  867. ZeroMemory(&afSubjectTable, sizeof(afSubjectTable));
  868. CSASSERT(0 == FALSE);
  869. hr = prow->SetProperty(
  870. g_wszPropSubjectRawName,
  871. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  872. pSubject->cbData,
  873. pSubject->pbData);
  874. _JumpIfError(hr, error, "SetProperty");
  875. pkcsSetDistinguishedName(prow, PROPTABLE_REQUEST, pSubject);
  876. if (!myDecodeName(
  877. X509_ASN_ENCODING,
  878. X509_UNICODE_NAME,
  879. pSubject->pbData,
  880. pSubject->cbData,
  881. CERTLIB_USE_LOCALALLOC,
  882. &pNameInfo,
  883. &cbNameInfo))
  884. {
  885. hr = myHLastError();
  886. _JumpError(hr, error, "myDecodeName");
  887. }
  888. if (ENUM_TELETEX_ON == (ENUM_TELETEX_MASK & g_fForceTeletex))
  889. {
  890. *pdwRequestFlags |= CR_FLG_FORCETELETEX;
  891. }
  892. if (ENUM_TELETEX_UTF8 & g_fForceTeletex)
  893. {
  894. *pdwRequestFlags |= CR_FLG_FORCEUTF8;
  895. }
  896. for (
  897. prdn = pNameInfo->rgRDN, prdnEnd = &prdn[pNameInfo->cRDN];
  898. prdn < prdnEnd;
  899. prdn++)
  900. {
  901. CERT_RDN_ATTR *prdna;
  902. CERT_RDN_ATTR *prdnaEnd;
  903. for (
  904. prdna = prdn->rgRDNAttr, prdnaEnd = &prdna[prdn->cRDNAttr];
  905. prdna < prdnaEnd;
  906. prdna++)
  907. {
  908. CSASSERT(
  909. prdna->dwValueType == CERT_RDN_PRINTABLE_STRING ||
  910. prdna->dwValueType == CERT_RDN_UNICODE_STRING ||
  911. prdna->dwValueType == CERT_RDN_TELETEX_STRING ||
  912. prdna->dwValueType == CERT_RDN_IA5_STRING ||
  913. prdna->dwValueType == CERT_RDN_UTF8_STRING);
  914. if (NULL == prdna->Value.pbData ||
  915. sizeof(WCHAR) > prdna->Value.cbData ||
  916. L'\0' == *(WCHAR *) prdna->Value.pbData)
  917. {
  918. continue;
  919. }
  920. if (CERT_RDN_TELETEX_STRING == prdna->dwValueType &&
  921. ENUM_TELETEX_AUTO == (ENUM_TELETEX_MASK & g_fForceTeletex))
  922. {
  923. *pdwRequestFlags |= CR_FLG_FORCETELETEX;
  924. }
  925. pwszPropName = PKCSMapAttributeName(
  926. NULL,
  927. prdna->pszObjId,
  928. &dwIndex,
  929. &cchMax);
  930. if (NULL != pwszPropName)
  931. {
  932. BOOL fCN;
  933. // CAPI null-terminates strings
  934. CSASSERT(
  935. sizeof(WCHAR) * wcslen((WCHAR const *) prdna->Value.pbData) ==
  936. prdna->Value.cbData);
  937. fCN = 0 == strcmp(szOID_COMMON_NAME, prdna->pszObjId);
  938. hr = PropSetAttributeProperty(
  939. prow,
  940. afSubjectTable[dwIndex], // fConcatenateRDNs
  941. PROPTABLE_REQUEST,
  942. cchMax,
  943. fCN? pwszCNSuffix : NULL,
  944. pwszPropName,
  945. (WCHAR const *) prdna->Value.pbData);
  946. if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) == hr)
  947. {
  948. hr = CERTSRV_E_BAD_REQUESTSUBJECT;
  949. }
  950. _JumpIfError(hr, error, "PropSetAttributeProperty");
  951. afSubjectTable[dwIndex] = TRUE;
  952. *pfSubjectNameSet = TRUE;
  953. if (fCN)
  954. {
  955. pwszCNSuffix = NULL;
  956. }
  957. }
  958. }
  959. }
  960. hr = S_OK;
  961. error:
  962. if (NULL != pNameInfo)
  963. {
  964. LocalFree(pNameInfo);
  965. }
  966. return(hr);
  967. }
  968. HRESULT
  969. PKCSSetRequestFlags(
  970. IN ICertDBRow *prow,
  971. IN BOOL fSet,
  972. IN DWORD dwChange)
  973. {
  974. HRESULT hr;
  975. DWORD dwOld;
  976. DWORD dwNew;
  977. DWORD cb;
  978. cb = sizeof(dwOld);
  979. hr = prow->GetProperty(
  980. g_wszPropRequestFlags,
  981. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  982. &cb,
  983. (BYTE *) &dwOld);
  984. _JumpIfError(hr, error, "GetProperty");
  985. if (fSet)
  986. {
  987. dwNew = dwOld | dwChange;
  988. }
  989. else
  990. {
  991. dwNew = dwOld & ~dwChange;
  992. }
  993. if (dwOld != dwNew)
  994. {
  995. hr = prow->SetProperty(
  996. g_wszPropRequestFlags,
  997. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  998. sizeof(dwNew),
  999. (BYTE const *) &dwNew);
  1000. _JumpIfError(hr, error, "SetProperty(RequestFlags)");
  1001. }
  1002. error:
  1003. return(hr);
  1004. }
  1005. HRESULT
  1006. pkcsSetAttributeProperty(
  1007. IN ICertDBRow *prow,
  1008. IN WCHAR const *pwszName,
  1009. IN WCHAR const *pwszValue,
  1010. IN DWORD dwTable,
  1011. IN BYTE afSubjectTable[],
  1012. OUT BOOL *pfSubjectModified,
  1013. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf)
  1014. {
  1015. HRESULT hr;
  1016. WCHAR const *pwszPropName;
  1017. DWORD dwIndex;
  1018. DWORD cwcMax;
  1019. BOOL fConcatenateRDNs;
  1020. *pfSubjectModified = FALSE;
  1021. if (NULL != pfEnrollOnBehalfOf)
  1022. {
  1023. *pfEnrollOnBehalfOf = FALSE;
  1024. }
  1025. // See if the attribute name can be mapped to a standard property.
  1026. pwszPropName = PKCSMapAttributeName(pwszName, NULL, &dwIndex, &cwcMax);
  1027. if (NULL != pwszPropName)
  1028. {
  1029. fConcatenateRDNs = afSubjectTable[dwIndex];
  1030. afSubjectTable[dwIndex] = TRUE;
  1031. *pfSubjectModified = TRUE;
  1032. }
  1033. else
  1034. {
  1035. pwszPropName = pwszName;
  1036. cwcMax = MAXDWORD;
  1037. fConcatenateRDNs = FALSE;
  1038. dwTable = PROPTABLE_ATTRIBUTE;
  1039. if (0 == lstrcmpi(g_wszPropRequesterName, pwszPropName))
  1040. {
  1041. if (NULL == pfEnrollOnBehalfOf)
  1042. {
  1043. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1044. _JumpError(hr, error, "NULL pfEnrollOnBehalfOf");
  1045. }
  1046. *pfEnrollOnBehalfOf = TRUE;
  1047. dwTable = PROPTABLE_REQUEST;
  1048. }
  1049. }
  1050. hr = PropSetAttributeProperty(
  1051. prow,
  1052. fConcatenateRDNs,
  1053. dwTable,
  1054. cwcMax,
  1055. NULL, // pwszSuffix
  1056. pwszPropName,
  1057. pwszValue);
  1058. _JumpIfError(hr, error, "PropSetAttributeProperty");
  1059. error:
  1060. return(hr);
  1061. }
  1062. // Note on Request Attribute and Subject RDN processing:
  1063. //
  1064. // Subject RDN strings and Request Attributes may be set several ways, in
  1065. // the following order. Subsequent changes overwrite earlier changes, so the
  1066. // order implies precedence:
  1067. //
  1068. // - Subject in the inner PKCS10 (if no PKCS10 subject, then use the Subject
  1069. // in the PKCS7 renewal cert)
  1070. // - the next outer PKCS7 or CMC Attributes
  1071. // - ...
  1072. // - the most outer PKCS7 or CMC Attributes
  1073. // - Request Attribute string passed with the request when first submitted
  1074. // - Policy Module may set subject RDNs in the certificate table
  1075. // - ICertAdmin::SetAttributes' Request Attribute string (if request pending)
  1076. //
  1077. // "PKCS7 or CMC Attributes" means either of the following:
  1078. // 1) Authenticated Attributes associated with a (non-CMC) PKCS7 signer info.
  1079. // 2) Tagged Attributes and/or RegInfo Control Attributes in a CMC request.
  1080. //
  1081. // None of the secured attributes listed in the registry (which is set to
  1082. // wszzDEFAULTSIGNEDATTRIBUTES by default) may be set unless the source is
  1083. // PKCS7 or CMC Attributes.
  1084. //
  1085. // The original request attribute string is stored in the RequestAttributes
  1086. // column in the request table. It is never modified after that. Individual
  1087. // request attribute values are parsed out of this string (when the request is
  1088. // submitted and when ICertAdmin::SetAttributes is called) and stored in a
  1089. // Subject RDN column of the request or certificate table if the attribute
  1090. // name matches an alias for a Subject RDN, or in a unique row in the
  1091. // attribute table otherwise.
  1092. //
  1093. // Individual Subject RDNs may be specified multiple times (multiple "OU",
  1094. // "CN", strings). If all of the RDNs were set from the same source,
  1095. // they must be concatenated, but if some RDNs were specified from one source,
  1096. // then modified by another source, the previous set of RDNs should be
  1097. // overwritten by the new ones. If the original Request Attribute string
  1098. // specified "CN:foo\nOU:ou2\nCN:bar", the two CN strings should be
  1099. // concatenated. If one or more CN values are also specified later by a
  1100. // single call to ICertAdmin::SetAttributes, the original CN values should be
  1101. // overwritten by the new value(s).
  1102. //
  1103. // It is possible to have the CN strings specified by one source and the OU
  1104. // strings specified by another.
  1105. //
  1106. // Before the policy module gets control, all Subject RDN changes are written
  1107. // to the Request table. Just before dispatching to the policy module, the
  1108. // Request Subject RDNs are copied to the Certificate Table RDNs. The policy
  1109. // module may modify the Certificate Table RDNs only.
  1110. //
  1111. // If the request is made pending, ICertAdmin::SetAttributes may be used to
  1112. // modify request attributes and Certificate Table RDNs.
  1113. //
  1114. // The certificate Subject is constructed from the Certificate Table RDNs.
  1115. HRESULT
  1116. PKCSParseAttributes(
  1117. IN ICertDBRow *prow,
  1118. IN WCHAR const *pwszAttributes,
  1119. IN BOOL fRegInfo,
  1120. IN DWORD dwRDNTable,
  1121. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf)
  1122. {
  1123. HRESULT hr;
  1124. WCHAR *pwszDup = NULL;
  1125. WCHAR *pwszBuf;
  1126. WCHAR const *pwszName;
  1127. WCHAR const *pwszValue;
  1128. WCHAR const *pwszSecuredAttr;
  1129. BYTE afSubjectTable[CSUBJECTTABLE]; // see PKCSParseAttributes note
  1130. WCHAR *pwszNameAlloc = NULL;
  1131. WCHAR *pwszValueAlloc = NULL;
  1132. BOOL fSubjectModified = FALSE;
  1133. if (NULL != pfEnrollOnBehalfOf)
  1134. {
  1135. *pfEnrollOnBehalfOf = FALSE;
  1136. }
  1137. if (NULL == pwszAttributes)
  1138. {
  1139. hr = S_OK;
  1140. goto error; // silently ignore empty string
  1141. }
  1142. hr = myDupString(pwszAttributes, &pwszDup);
  1143. _JumpIfError(hr, error, "myDupString");
  1144. pwszBuf = pwszDup;
  1145. ZeroMemory(&afSubjectTable, sizeof(afSubjectTable));
  1146. CSASSERT(0 == FALSE);
  1147. while (TRUE)
  1148. {
  1149. hr = myParseNextAttribute(&pwszBuf, fRegInfo, &pwszName, &pwszValue);
  1150. if (S_FALSE == hr)
  1151. {
  1152. break;
  1153. }
  1154. _JumpIfError(hr, error, "myParseNextAttribute");
  1155. if (fRegInfo)
  1156. {
  1157. if (NULL != pwszNameAlloc)
  1158. {
  1159. LocalFree(pwszNameAlloc);
  1160. pwszNameAlloc = NULL;
  1161. }
  1162. if (NULL != pwszValueAlloc)
  1163. {
  1164. LocalFree(pwszValueAlloc);
  1165. pwszValueAlloc = NULL;
  1166. }
  1167. hr = myUncanonicalizeURLParm(pwszName, &pwszNameAlloc);
  1168. _JumpIfError(hr, error, "myUncanonicalizeURLParm");
  1169. hr = myUncanonicalizeURLParm(pwszValue, &pwszValueAlloc);
  1170. _JumpIfError(hr, error, "myUncanonicalizeURLParm");
  1171. pwszName = pwszNameAlloc;
  1172. pwszValue = pwszValueAlloc;
  1173. }
  1174. if (!fRegInfo)
  1175. {
  1176. // Only set the attribute if it's not one of the attributes
  1177. // that is required to be secure.
  1178. for (pwszSecuredAttr = g_wszzSecuredAttributes;
  1179. NULL != pwszSecuredAttr && L'\0' != *pwszSecuredAttr;
  1180. pwszSecuredAttr += wcslen(pwszSecuredAttr) + 1)
  1181. {
  1182. if (0 == lstrcmpi(pwszSecuredAttr, pwszName))
  1183. {
  1184. break;
  1185. }
  1186. }
  1187. }
  1188. if (fRegInfo || NULL == pwszSecuredAttr || L'\0' == *pwszSecuredAttr)
  1189. {
  1190. BOOL fEnrollOnBehalfOf = FALSE;
  1191. BOOL fSubjectModifiedT = FALSE;
  1192. hr = pkcsSetAttributeProperty(
  1193. prow,
  1194. pwszName,
  1195. pwszValue,
  1196. dwRDNTable,
  1197. afSubjectTable,
  1198. &fSubjectModified,
  1199. NULL != pfEnrollOnBehalfOf? &fEnrollOnBehalfOf : NULL);
  1200. _JumpIfError(hr, error, "PKCSSetRequestFlags");
  1201. if (fSubjectModifiedT)
  1202. {
  1203. fSubjectModified = TRUE;
  1204. }
  1205. if (fEnrollOnBehalfOf)
  1206. {
  1207. *pfEnrollOnBehalfOf = TRUE;
  1208. }
  1209. }
  1210. }
  1211. if (fSubjectModified)
  1212. {
  1213. hr = PKCSSetRequestFlags(prow, FALSE, CR_FLG_SUBJECTUNMODIFIED);
  1214. _JumpIfError(hr, error, "PKCSSetRequestFlags");
  1215. }
  1216. hr = S_OK;
  1217. error:
  1218. if (NULL != pwszNameAlloc)
  1219. {
  1220. LocalFree(pwszNameAlloc);
  1221. }
  1222. if (NULL != pwszValueAlloc)
  1223. {
  1224. LocalFree(pwszValueAlloc);
  1225. }
  1226. if (NULL != pwszDup)
  1227. {
  1228. LocalFree(pwszDup);
  1229. }
  1230. return(hr);
  1231. }
  1232. HRESULT
  1233. pkcsSetAltSubjectNameExtension(
  1234. IN ICertDBRow *prow,
  1235. IN DWORD ExtFlags,
  1236. IN CERT_EXTENSION const *rgExtension,
  1237. IN DWORD cExtension,
  1238. IN DWORD cAltSubjectExtension)
  1239. {
  1240. HRESULT hr = S_OK;
  1241. CERT_ALT_NAME_INFO **apInfo = NULL;
  1242. DWORD i;
  1243. DWORD j;
  1244. DWORD cInfo = 0;
  1245. DWORD cb;
  1246. CERT_ALT_NAME_INFO ResultInfo;
  1247. DWORD cbResult;
  1248. BYTE *pbResult = NULL;
  1249. ResultInfo.cAltEntry = 0;
  1250. ResultInfo.rgAltEntry = NULL;
  1251. apInfo = (CERT_ALT_NAME_INFO **) LocalAlloc(
  1252. LMEM_FIXED,
  1253. sizeof(CERT_ALT_NAME_INFO *) * cAltSubjectExtension);
  1254. if (NULL == apInfo)
  1255. {
  1256. hr = E_OUTOFMEMORY;
  1257. _JumpError(hr, error, "LocalAlloc");
  1258. }
  1259. // Decode all AltNames
  1260. for (i = 0; i < cExtension; i++)
  1261. {
  1262. // This is an OID, generated by capi2, so we don't need to
  1263. // do a case-insensitive comparison
  1264. if (0 == strcmp(rgExtension[i].pszObjId, szOID_SUBJECT_ALT_NAME2))
  1265. {
  1266. CSASSERT(cInfo < cAltSubjectExtension);
  1267. // Decode to plain text
  1268. if (!myDecodeObject(
  1269. X509_ASN_ENCODING,
  1270. X509_ALTERNATE_NAME,
  1271. rgExtension[i].Value.pbData,
  1272. rgExtension[i].Value.cbData,
  1273. CERTLIB_USE_LOCALALLOC,
  1274. (VOID **) &apInfo[cInfo],
  1275. &cb))
  1276. {
  1277. hr = myHLastError();
  1278. _JumpError(hr, error, "myDecodeObject");
  1279. }
  1280. if (rgExtension[i].fCritical)
  1281. {
  1282. ExtFlags |= EXTENSION_CRITICAL_FLAG;
  1283. }
  1284. ResultInfo.cAltEntry += apInfo[cInfo]->cAltEntry;
  1285. cInfo++;
  1286. }
  1287. }
  1288. CSASSERT(cInfo == cAltSubjectExtension);
  1289. ResultInfo.rgAltEntry = (CERT_ALT_NAME_ENTRY *) LocalAlloc(
  1290. LMEM_FIXED,
  1291. ResultInfo.cAltEntry * sizeof(CERT_ALT_NAME_ENTRY));
  1292. if (NULL == ResultInfo.rgAltEntry)
  1293. {
  1294. hr = E_OUTOFMEMORY;
  1295. _JumpIfError(hr, error, "LocalAlloc");
  1296. }
  1297. j = 0;
  1298. for (i = 0; i < cInfo; i++)
  1299. {
  1300. CopyMemory(
  1301. &ResultInfo.rgAltEntry[j],
  1302. apInfo[i]->rgAltEntry,
  1303. apInfo[i]->cAltEntry * sizeof(CERT_ALT_NAME_ENTRY));
  1304. j += apInfo[i]->cAltEntry;
  1305. }
  1306. if (!myEncodeObject(
  1307. X509_ASN_ENCODING,
  1308. X509_ALTERNATE_NAME,
  1309. &ResultInfo,
  1310. 0,
  1311. CERTLIB_USE_LOCALALLOC,
  1312. &pbResult,
  1313. &cbResult))
  1314. {
  1315. hr = myHLastError();
  1316. _JumpError(hr, error, "myEncodeObject");
  1317. }
  1318. hr = PropSetExtension(
  1319. prow,
  1320. PROPTYPE_BINARY | PROPCALLER_REQUEST,
  1321. TEXT(szOID_SUBJECT_ALT_NAME2),
  1322. ExtFlags,
  1323. cbResult,
  1324. pbResult);
  1325. _JumpIfError(hr, error, "PropSetExtension");
  1326. error:
  1327. if (NULL != apInfo)
  1328. {
  1329. for (i = 0; i < cInfo; i++)
  1330. {
  1331. if (NULL != apInfo[i])
  1332. {
  1333. LocalFree(apInfo[i]);
  1334. }
  1335. }
  1336. LocalFree(apInfo);
  1337. }
  1338. if (NULL != ResultInfo.rgAltEntry)
  1339. {
  1340. LocalFree(ResultInfo.rgAltEntry);
  1341. }
  1342. if (NULL != pbResult)
  1343. {
  1344. LocalFree(pbResult);
  1345. }
  1346. return(hr);
  1347. }
  1348. // Scan extension array, and merge all the AltSubjectName Extensions into one.
  1349. HRESULT
  1350. pkcsSetExtensions(
  1351. IN ICertDBRow *prow,
  1352. IN DWORD ExtFlags,
  1353. IN CERT_EXTENSION const *rgExtension,
  1354. IN DWORD cExtension)
  1355. {
  1356. HRESULT hr;
  1357. WCHAR *pwszObjId = NULL;
  1358. CERT_EXTENSION const *pExt;
  1359. CERT_EXTENSION const *pExtEnd;
  1360. DWORD cAltSubjectExtension = 0;
  1361. pExtEnd = &rgExtension[cExtension];
  1362. for (pExt = rgExtension; pExt < pExtEnd; pExt++)
  1363. {
  1364. DWORD ExtFlagsT;
  1365. if (EXTENSION_ORIGIN_RENEWALCERT == (EXTENSION_ORIGIN_MASK & ExtFlags))
  1366. {
  1367. char const * const *ppszObjId;
  1368. static char const * const apszObjIdFilter[] = {
  1369. szOID_CERTSRV_CA_VERSION,
  1370. szOID_AUTHORITY_INFO_ACCESS,
  1371. szOID_CRL_DIST_POINTS,
  1372. szOID_AUTHORITY_KEY_IDENTIFIER2,
  1373. szOID_SUBJECT_KEY_IDENTIFIER,
  1374. NULL
  1375. };
  1376. for (ppszObjId = apszObjIdFilter; NULL != *ppszObjId; ppszObjId++)
  1377. {
  1378. if (0 == strcmp(*ppszObjId, pExt->pszObjId))
  1379. {
  1380. break;
  1381. }
  1382. }
  1383. if (NULL != *ppszObjId)
  1384. {
  1385. continue; // skip this extension
  1386. }
  1387. }
  1388. if (NULL != pwszObjId)
  1389. {
  1390. LocalFree(pwszObjId);
  1391. pwszObjId = NULL;
  1392. }
  1393. if (!ConvertSzToWsz(&pwszObjId, pExt->pszObjId, -1))
  1394. {
  1395. hr = E_OUTOFMEMORY;
  1396. _JumpError(hr, error, "ConvertSzToWsz(ObjId)");
  1397. }
  1398. ExtFlagsT = ExtFlags;
  1399. if (pExt->fCritical)
  1400. {
  1401. ExtFlagsT |= EXTENSION_CRITICAL_FLAG;
  1402. }
  1403. // AltSubjectName needs to be merged, so we do that later.
  1404. // This is an OID, generated by capi2, so we don't need to
  1405. // do a case-insensitive comparison.
  1406. if (0 == lstrcmp(pwszObjId, TEXT(szOID_SUBJECT_ALT_NAME2)))
  1407. {
  1408. cAltSubjectExtension++;
  1409. continue;
  1410. }
  1411. hr = PropSetExtension(
  1412. prow,
  1413. PROPTYPE_BINARY | PROPCALLER_REQUEST,
  1414. pwszObjId,
  1415. ExtFlagsT,
  1416. pExt->Value.cbData,
  1417. pExt->Value.pbData);
  1418. _JumpIfError(hr, error, "PropSetExtension");
  1419. DBGPRINT((
  1420. DBG_SS_CERTSRVI,
  1421. "PropSetExtension(%ws, f=%x, cb=%x, pb=%x)\n",
  1422. pwszObjId,
  1423. ExtFlagsT,
  1424. pExt->Value.cbData,
  1425. pExt->Value.pbData));
  1426. }
  1427. if (0 != cAltSubjectExtension)
  1428. {
  1429. hr = pkcsSetAltSubjectNameExtension(
  1430. prow,
  1431. ExtFlags,
  1432. rgExtension,
  1433. cExtension,
  1434. cAltSubjectExtension);
  1435. _JumpIfError(hr, error, "pkcsSetAltSubjectNameExtension");
  1436. }
  1437. hr = S_OK;
  1438. error:
  1439. if (NULL != pwszObjId)
  1440. {
  1441. LocalFree(pwszObjId);
  1442. }
  1443. return(hr);
  1444. }
  1445. HRESULT
  1446. pkcsSetOSVersion(
  1447. IN ICertDBRow *prow,
  1448. IN CRYPT_ATTR_BLOB *pAttrBlob)
  1449. {
  1450. HRESULT hr;
  1451. CERT_NAME_VALUE *pOSVersionString = NULL;
  1452. BSTR strVersion = NULL;
  1453. DWORD cb;
  1454. if (!myDecodeObject(
  1455. X509_ASN_ENCODING,
  1456. X509_ANY_STRING,
  1457. pAttrBlob->pbData,
  1458. pAttrBlob->cbData,
  1459. CERTLIB_USE_LOCALALLOC,
  1460. (VOID **) &pOSVersionString,
  1461. &cb))
  1462. {
  1463. hr = myHLastError();
  1464. _JumpError(hr, error, "myDecodeObject");
  1465. }
  1466. if (NULL != pOSVersionString)
  1467. {
  1468. if (!IS_CERT_RDN_CHAR_STRING(pOSVersionString->dwValueType))
  1469. {
  1470. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1471. _JumpError(hr, error, "version string is numeric data");
  1472. }
  1473. // If it's an 8 bit string, convert it to UNICODE
  1474. if (CERT_RDN_UNIVERSAL_STRING > pOSVersionString->dwValueType)
  1475. {
  1476. // Pass byte count in to allocate enough characters for
  1477. // the converted Unicode string
  1478. strVersion = SysAllocStringLen(
  1479. NULL,
  1480. pOSVersionString->Value.cbData);
  1481. // This is expected to be only numbers and '.'s,
  1482. if (NULL == strVersion)
  1483. {
  1484. hr = E_OUTOFMEMORY;
  1485. _JumpError(hr, error, "SysAllocStringLen");
  1486. }
  1487. mbstowcs(
  1488. strVersion,
  1489. (char const *) pOSVersionString->Value.pbData,
  1490. pOSVersionString->Value.cbData);
  1491. }
  1492. else if (CERT_RDN_BMP_STRING == pOSVersionString->dwValueType ||
  1493. CERT_RDN_UNICODE_STRING == pOSVersionString->dwValueType)
  1494. {
  1495. strVersion = SysAllocStringLen(
  1496. (WCHAR *) pOSVersionString->Value.pbData,
  1497. pOSVersionString->Value.cbData/sizeof(WCHAR));
  1498. if (NULL == strVersion)
  1499. {
  1500. hr = E_OUTOFMEMORY;
  1501. _JumpError(hr, error, "SysAllocStringLen");
  1502. }
  1503. }
  1504. else
  1505. {
  1506. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1507. _JumpError(hr, error, "unknown string type");
  1508. }
  1509. hr = prow->SetProperty(
  1510. g_wszPropRequestOSVersion,
  1511. PROPTYPE_STRING |
  1512. PROPCALLER_SERVER |
  1513. PROPTABLE_ATTRIBUTE,
  1514. SysStringByteLen(strVersion),
  1515. (BYTE *) strVersion);
  1516. _JumpIfError(hr, error, "SetProperty");
  1517. }
  1518. hr = S_OK;
  1519. error:
  1520. if (NULL != strVersion)
  1521. {
  1522. SysFreeString(strVersion);
  1523. }
  1524. if (NULL != pOSVersionString)
  1525. {
  1526. LocalFree(pOSVersionString);
  1527. }
  1528. return(hr);
  1529. }
  1530. HRESULT
  1531. pkcsSetCSPProvider(
  1532. IN ICertDBRow *prow,
  1533. IN CRYPT_ATTR_BLOB *pAttrBlob)
  1534. {
  1535. HRESULT hr;
  1536. CRYPT_CSP_PROVIDER *pccp = NULL;
  1537. hr = myDecodeCSPProviderAttribute(
  1538. pAttrBlob->pbData,
  1539. pAttrBlob->cbData,
  1540. &pccp);
  1541. _JumpIfError(hr, error, "myDecodeCSPProviderAttribute");
  1542. if (NULL != pccp->pwszProviderName && L'\0' != *pccp->pwszProviderName)
  1543. {
  1544. hr = prow->SetProperty(
  1545. g_wszPropRequestCSPProvider,
  1546. PROPTYPE_STRING |
  1547. PROPCALLER_SERVER |
  1548. PROPTABLE_ATTRIBUTE,
  1549. MAXDWORD,
  1550. (BYTE const *) pccp->pwszProviderName);
  1551. _JumpIfError(hr, error, "SetProperty");
  1552. }
  1553. hr = S_OK;
  1554. error:
  1555. if (NULL != pccp)
  1556. {
  1557. LocalFree(pccp);
  1558. }
  1559. return(hr);
  1560. }
  1561. HRESULT
  1562. pkcsSetExtensionsFromAttributeBlob(
  1563. IN ICertDBRow *prow,
  1564. IN DWORD ExtFlags,
  1565. IN CRYPT_ATTRIBUTE const *pAttrib)
  1566. {
  1567. HRESULT hr;
  1568. CRYPT_ATTR_BLOB *pAttrBlob;
  1569. CERT_NAME_VALUE *pNameInfo = NULL;
  1570. CERT_EXTENSIONS *pCertExtensions = NULL;
  1571. DWORD cb;
  1572. pAttrBlob = pAttrib->rgValue;
  1573. while (TRUE)
  1574. {
  1575. if (NULL != pCertExtensions)
  1576. {
  1577. LocalFree(pCertExtensions);
  1578. pCertExtensions = NULL;
  1579. }
  1580. if (myDecodeObject(
  1581. X509_ASN_ENCODING,
  1582. X509_EXTENSIONS,
  1583. pAttrBlob->pbData,
  1584. pAttrBlob->cbData,
  1585. CERTLIB_USE_LOCALALLOC,
  1586. (VOID **) &pCertExtensions,
  1587. &cb))
  1588. {
  1589. break; // success
  1590. }
  1591. hr = myHLastError();
  1592. // if we already decoded the attribute as a T61 string, or if it is
  1593. // not a PKCS 9.14 attribute, fail -- we don't know what it contains.
  1594. if (NULL != pNameInfo ||
  1595. 0 != strcmp(pAttrib->pszObjId, szOID_RSA_certExtensions))
  1596. {
  1597. _JumpError(hr, error, "myDecodeObject");
  1598. }
  1599. // Decode the attribute as a T61 string. Some implementations wrap the
  1600. // PKCS 9.14 extension array in an extra level of encoding as a Teletex
  1601. // string.
  1602. if (!myDecodeObject(
  1603. X509_ASN_ENCODING,
  1604. X509_ANY_STRING,
  1605. pAttrBlob->pbData,
  1606. pAttrBlob->cbData,
  1607. CERTLIB_USE_LOCALALLOC,
  1608. (VOID **) &pNameInfo,
  1609. &cb))
  1610. {
  1611. hr = myHLastError();
  1612. _JumpError(hr, error, "myDecodeObject");
  1613. }
  1614. // Loop again and try to decode the raw name blob as X509_EXTENSIONS.
  1615. pAttrBlob = &pNameInfo->Value;
  1616. }
  1617. hr = pkcsSetExtensions(
  1618. prow,
  1619. EXTENSION_DISABLE_FLAG | ExtFlags,
  1620. pCertExtensions->rgExtension,
  1621. pCertExtensions->cExtension);
  1622. _JumpIfError(hr, error, "pkcsSetExtensions(attributes)");
  1623. error:
  1624. if (NULL != pNameInfo)
  1625. {
  1626. LocalFree(pNameInfo);
  1627. }
  1628. if (NULL != pCertExtensions)
  1629. {
  1630. LocalFree(pCertExtensions);
  1631. }
  1632. return(hr);
  1633. }
  1634. HRESULT
  1635. PKCSGetProperty(
  1636. IN ICertDBRow *prow,
  1637. IN WCHAR const *pwszPropName,
  1638. IN DWORD Flags,
  1639. OPTIONAL OUT DWORD *pcbData,
  1640. OUT BYTE **ppbData)
  1641. {
  1642. HRESULT hr;
  1643. BYTE *pbData = NULL;
  1644. DWORD cbData;
  1645. if (NULL != pcbData)
  1646. {
  1647. *pcbData = 0;
  1648. }
  1649. *ppbData = NULL;
  1650. cbData = 0;
  1651. hr = prow->GetProperty(pwszPropName, Flags, &cbData, pbData);
  1652. _JumpIfError2(hr, error, "GetProperty", CERTSRV_E_PROPERTY_EMPTY);
  1653. pbData = (BYTE *) LocalAlloc(LMEM_FIXED, cbData);
  1654. if (NULL == pbData)
  1655. {
  1656. hr = E_OUTOFMEMORY;
  1657. _JumpError(hr, error, "LocalAlloc");
  1658. }
  1659. hr = prow->GetProperty(pwszPropName, Flags, &cbData, pbData);
  1660. _JumpIfError(hr, error, "GetProperty");
  1661. if (NULL != pcbData)
  1662. {
  1663. *pcbData = cbData;
  1664. }
  1665. *ppbData = pbData;
  1666. pbData = NULL;
  1667. error:
  1668. if (NULL != pbData)
  1669. {
  1670. LocalFree(pbData);
  1671. }
  1672. return(hr);
  1673. }
  1674. VOID
  1675. pkcsFreePublicKeyInfo(
  1676. IN OUT CERT_PUBLIC_KEY_INFO *pPublicKeyInfo)
  1677. {
  1678. if (NULL != pPublicKeyInfo->Algorithm.pszObjId)
  1679. {
  1680. LocalFree(pPublicKeyInfo->Algorithm.pszObjId);
  1681. }
  1682. if (NULL != pPublicKeyInfo->Algorithm.Parameters.pbData)
  1683. {
  1684. LocalFree(pPublicKeyInfo->Algorithm.Parameters.pbData);
  1685. }
  1686. if (NULL != pPublicKeyInfo->PublicKey.pbData)
  1687. {
  1688. LocalFree(pPublicKeyInfo->PublicKey.pbData);
  1689. }
  1690. ZeroMemory(pPublicKeyInfo, sizeof(*pPublicKeyInfo));
  1691. }
  1692. HRESULT
  1693. pkcsGetPublicKeyInfo(
  1694. IN ICertDBRow *prow,
  1695. OUT CERT_PUBLIC_KEY_INFO *pPublicKeyInfo)
  1696. {
  1697. HRESULT hr;
  1698. WCHAR *pwszObjId = NULL;
  1699. ZeroMemory(pPublicKeyInfo, sizeof(*pPublicKeyInfo));
  1700. hr = PKCSGetProperty(
  1701. prow,
  1702. g_wszPropCertificatePublicKeyAlgorithm,
  1703. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  1704. NULL,
  1705. (BYTE **) &pwszObjId);
  1706. _JumpIfError(hr, error, "PKCSGetProperty");
  1707. if (!ConvertWszToSz(&pPublicKeyInfo->Algorithm.pszObjId, pwszObjId, -1))
  1708. {
  1709. hr = E_OUTOFMEMORY;
  1710. _JumpError(hr, error, "ConvertWszToSz(AlgObjId)");
  1711. }
  1712. hr = PKCSGetProperty(
  1713. prow,
  1714. g_wszPropCertificateRawPublicKeyAlgorithmParameters,
  1715. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  1716. &pPublicKeyInfo->Algorithm.Parameters.cbData,
  1717. &pPublicKeyInfo->Algorithm.Parameters.pbData);
  1718. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  1719. {
  1720. _JumpIfError(hr, error, "PKCSGetProperty");
  1721. }
  1722. hr = PKCSGetProperty(
  1723. prow,
  1724. g_wszPropCertificateRawPublicKey,
  1725. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  1726. &pPublicKeyInfo->PublicKey.cbData,
  1727. &pPublicKeyInfo->PublicKey.pbData);
  1728. _JumpIfError(hr, error, "PKCSGetProperty");
  1729. error:
  1730. if (S_OK != hr)
  1731. {
  1732. pkcsFreePublicKeyInfo(pPublicKeyInfo);
  1733. }
  1734. if (NULL != pwszObjId)
  1735. {
  1736. LocalFree(pwszObjId);
  1737. }
  1738. return(hr);
  1739. }
  1740. HRESULT
  1741. pkcsEncryptPrivateKey(
  1742. IN BYTE *pbDecrypted,
  1743. IN DWORD cbDecrypted,
  1744. OUT BYTE **ppbEncrypted,
  1745. OUT DWORD *pcbEncrypted,
  1746. OUT WCHAR **ppwszKRAHashes)
  1747. {
  1748. HRESULT hr;
  1749. DWORD i;
  1750. DWORD iKRACert;
  1751. DWORD cwc;
  1752. WCHAR *pwszKRAHashes = NULL;
  1753. CERT_CONTEXT const **rgKRACerts = NULL;
  1754. static bool fUseCAProv = true;
  1755. *ppbEncrypted = NULL;
  1756. *ppwszKRAHashes = NULL;
  1757. CSASSERT(
  1758. NULL != g_rgKRACerts &&
  1759. 0 != g_cKRACerts &&
  1760. 0 != g_cKRACertsRoundRobin &&
  1761. NULL != g_rgstrKRAHashes);
  1762. for (cwc = 0, i = 0; i < g_cKRACertsRoundRobin; i++)
  1763. {
  1764. iKRACert = (g_iKRACerts + i) % g_cKRACerts;
  1765. cwc += wcslen(g_rgstrKRAHashes[iKRACert]) + 1;
  1766. }
  1767. pwszKRAHashes = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  1768. if (NULL == pwszKRAHashes)
  1769. {
  1770. hr = E_OUTOFMEMORY;
  1771. _JumpError(hr, error, "LocalAlloc");
  1772. }
  1773. rgKRACerts = (CERT_CONTEXT const **) LocalAlloc(
  1774. LMEM_FIXED,
  1775. g_cKRACertsRoundRobin * sizeof(rgKRACerts[0]));
  1776. if (NULL == rgKRACerts)
  1777. {
  1778. hr = E_OUTOFMEMORY;
  1779. _JumpError(hr, error, "LocalAlloc");
  1780. }
  1781. pwszKRAHashes[0] = L'\0';
  1782. for (i = 0; i < g_cKRACertsRoundRobin; i++)
  1783. {
  1784. iKRACert = (g_iKRACerts + i) % g_cKRACerts;
  1785. rgKRACerts[i] = g_rgKRACerts[iKRACert];
  1786. if (0 != i)
  1787. {
  1788. wcscat(pwszKRAHashes, L"\n");
  1789. }
  1790. wcscat(pwszKRAHashes, g_rgstrKRAHashes[iKRACert]);
  1791. }
  1792. CSASSERT(wcslen(pwszKRAHashes) + 1 == cwc);
  1793. hr = myCryptEncryptMessage(
  1794. CALG_3DES,
  1795. g_cKRACertsRoundRobin, // cCertRecipient
  1796. rgKRACerts, // rgCertRecipient
  1797. pbDecrypted,
  1798. cbDecrypted,
  1799. fUseCAProv? g_pCAContextCurrent->hProvCA : NULL,
  1800. ppbEncrypted,
  1801. pcbEncrypted);
  1802. if (FAILED(hr) && fUseCAProv)
  1803. {
  1804. // Failed to use the CA HCRYPTPROV, fall back to
  1805. // default
  1806. fUseCAProv = false;
  1807. hr = myCryptEncryptMessage(
  1808. CALG_3DES,
  1809. g_cKRACertsRoundRobin, // cCertRecipient
  1810. rgKRACerts, // rgCertRecipient
  1811. pbDecrypted,
  1812. cbDecrypted,
  1813. NULL,
  1814. ppbEncrypted,
  1815. pcbEncrypted);
  1816. }
  1817. _JumpIfError(hr, error, "myCryptEncryptMessage");
  1818. *ppwszKRAHashes = pwszKRAHashes;
  1819. pwszKRAHashes = NULL;
  1820. error:
  1821. if (NULL != pwszKRAHashes)
  1822. {
  1823. LocalFree(pwszKRAHashes);
  1824. }
  1825. if (NULL != rgKRACerts)
  1826. {
  1827. LocalFree(rgKRACerts);
  1828. }
  1829. return(hr);
  1830. }
  1831. HRESULT
  1832. PKCSArchivePrivateKey(
  1833. IN ICertDBRow *prow,
  1834. IN BOOL fV1Cert,
  1835. IN BOOL fOverwrite,
  1836. IN CRYPT_ATTR_BLOB const *pBlobEncrypted,
  1837. OPTIONAL IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  1838. {
  1839. HRESULT hr;
  1840. BYTE *pbDecrypted = NULL;
  1841. DWORD cbDecrypted;
  1842. BYTE *pbEncrypted = NULL;
  1843. DWORD cbEncrypted;
  1844. DWORD iCertSig;
  1845. BYTE *pbCert; // do not free!
  1846. DWORD cbCert;
  1847. WCHAR *pwszKRAHashes = NULL;
  1848. CERT_PUBLIC_KEY_INFO PublicKeyInfo;
  1849. WCHAR *pwszUserName = NULL;
  1850. DWORD cb;
  1851. BYTE *pbKeyHash = NULL;
  1852. DWORD cbKeyHash;
  1853. ZeroMemory(&PublicKeyInfo, sizeof(PublicKeyInfo));
  1854. if (0 == g_cKRACerts)
  1855. {
  1856. if (0 == g_cKRAHashes)
  1857. {
  1858. hr = CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED;
  1859. }
  1860. else
  1861. {
  1862. hr = CERTSRV_E_NO_VALID_KRA;
  1863. }
  1864. _JumpError(hr, error, "no KRA encryption certs");
  1865. }
  1866. if (NULL != pResult)
  1867. {
  1868. if (NULL == pResult->pbKeyHashIn)
  1869. {
  1870. if (0 == (CRLF_ACCEPT_OLDRFC_CMC & g_dwCRLFlags))
  1871. {
  1872. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1873. _JumpError(hr, error, "missing encrypted key hash");
  1874. }
  1875. }
  1876. else
  1877. {
  1878. hr = myCalculateKeyArchivalHash(
  1879. pBlobEncrypted->pbData,
  1880. pBlobEncrypted->cbData,
  1881. &pbKeyHash,
  1882. &cbKeyHash);
  1883. _JumpIfError(hr, error, "myCalculateKeyArchivalHash");
  1884. if (pResult->cbKeyHashIn != cbKeyHash ||
  1885. 0 != memcmp(pResult->pbKeyHashIn, pbKeyHash, cbKeyHash))
  1886. {
  1887. hr = S_OK;
  1888. _JumpError(S_FALSE, error, "Ignoring key: hash mismatch");
  1889. }
  1890. }
  1891. }
  1892. hr = prow->GetProperty(
  1893. g_wszPropRequestRawArchivedKey,
  1894. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  1895. &cb,
  1896. NULL);
  1897. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  1898. {
  1899. if (S_OK == hr && !fOverwrite)
  1900. {
  1901. hr = HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS);
  1902. }
  1903. _JumpIfError2(
  1904. hr,
  1905. error,
  1906. "GetProperty",
  1907. HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS));
  1908. }
  1909. hr = PKCSGetProperty(
  1910. prow,
  1911. g_wszPropRequesterName,
  1912. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  1913. NULL,
  1914. (BYTE **) &pwszUserName);
  1915. _JumpIfError(hr, error, "PKCSGetProperty");
  1916. if (NULL == g_hStoreCAXchg)
  1917. {
  1918. hr = PKCSGetCAXchgCert(0, pwszUserName, &iCertSig, &pbCert, &cbCert);
  1919. _JumpIfError(hr, error, "PKCSGetCAXchgCert");
  1920. }
  1921. CSASSERT(NULL != g_hStoreCAXchg);
  1922. hr = myCryptDecryptMessage(
  1923. g_hStoreCAXchg,
  1924. pBlobEncrypted->pbData,
  1925. pBlobEncrypted->cbData,
  1926. CERTLIB_USE_LOCALALLOC,
  1927. &pbDecrypted,
  1928. &cbDecrypted);
  1929. _JumpIfError(hr, error, "myCryptDecryptMessage");
  1930. DBGDUMPHEX((DBG_SS_CERTSRVI, 0, pbDecrypted, cbDecrypted));
  1931. hr = pkcsGetPublicKeyInfo(prow, &PublicKeyInfo);
  1932. _JumpIfError(hr, error, "pkcsGetPublicKeyInfo");
  1933. hr = myValidateKeyBlob(
  1934. pbDecrypted,
  1935. cbDecrypted,
  1936. &PublicKeyInfo,
  1937. fV1Cert,
  1938. NULL);
  1939. _JumpIfError(hr, error, "myValidateKeyBlob");
  1940. hr = pkcsEncryptPrivateKey(
  1941. pbDecrypted,
  1942. cbDecrypted,
  1943. &pbEncrypted,
  1944. &cbEncrypted,
  1945. &pwszKRAHashes);
  1946. _JumpIfError(hr, error, "pkcsEncryptPrivateKey");
  1947. hr = prow->SetProperty(
  1948. g_wszPropRequestRawArchivedKey,
  1949. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  1950. cbEncrypted,
  1951. pbEncrypted);
  1952. _JumpIfError(hr, error, "PKCSArchivePrivateKey:SetProperty");
  1953. hr = prow->SetProperty(
  1954. g_wszPropRequestKeyRecoveryHashes,
  1955. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  1956. MAXDWORD,
  1957. (BYTE const *) pwszKRAHashes);
  1958. _JumpIfError(hr, error, "SetProperty");
  1959. if (NULL != pResult && NULL == pResult->pbKeyHashOut)
  1960. {
  1961. pResult->pbKeyHashOut = pbKeyHash;
  1962. pResult->cbKeyHashOut = cbKeyHash;
  1963. pbKeyHash = NULL;
  1964. }
  1965. {
  1966. CertSrv::CAuditEvent audit(SE_AUDITID_CERTSRV_KEYARCHIVED, g_dwAuditFilter);
  1967. DWORD dwRequestID = 0;
  1968. DWORD cb = sizeof(DWORD);
  1969. if (audit.IsEventEnabled())
  1970. {
  1971. hr = prow->GetProperty(
  1972. g_wszPropRequestRequestID,
  1973. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  1974. &cb,
  1975. (BYTE *)&dwRequestID);
  1976. _JumpIfError(hr, error, "Report");
  1977. hr = audit.AddData(dwRequestID); // %1 request ID
  1978. _JumpIfError(hr, error, "CAuditEvent::AddData");
  1979. hr = audit.AddData(pwszUserName); // %2 requester
  1980. _JumpIfError(hr, error, "CAuditEvent::AddData");
  1981. hr = audit.AddData(pwszKRAHashes);// %3 KRA hashes
  1982. _JumpIfError(hr, error, "CAuditEvent::AddData");
  1983. hr = audit.Report();
  1984. _JumpIfError(hr, error, "Report");
  1985. }
  1986. }
  1987. error:
  1988. pkcsFreePublicKeyInfo(&PublicKeyInfo);
  1989. if (NULL != pbDecrypted)
  1990. {
  1991. ZeroMemory(pbDecrypted, cbDecrypted); // Private Key Material!
  1992. LocalFree(pbDecrypted);
  1993. }
  1994. if (NULL != pbEncrypted)
  1995. {
  1996. LocalFree(pbEncrypted);
  1997. }
  1998. if (NULL != pwszKRAHashes)
  1999. {
  2000. LocalFree(pwszKRAHashes);
  2001. }
  2002. if (NULL != pwszUserName)
  2003. {
  2004. LocalFree(pwszUserName);
  2005. }
  2006. if (NULL != pbKeyHash)
  2007. {
  2008. LocalFree(pbKeyHash);
  2009. }
  2010. return(hr);
  2011. }
  2012. HRESULT
  2013. pkcsSaveRequestWithoutArchivedKey(
  2014. IN ICertDBRow *prow,
  2015. IN DWORD cbIn,
  2016. IN BYTE const *pbIn)
  2017. {
  2018. HRESULT hr;
  2019. HCRYPTMSG hMsg = NULL;
  2020. DWORD cSigner;
  2021. DWORD iSigner;
  2022. DWORD i;
  2023. DWORD cb;
  2024. BYTE *pbWithoutKey = NULL;
  2025. DWORD cbWithoutKey;
  2026. CRYPT_ATTRIBUTES *pAttrib = NULL;
  2027. BOOL fKeyDeleted = FALSE;
  2028. hMsg = CryptMsgOpenToDecode(
  2029. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  2030. 0, // dwFlags
  2031. 0, // dwMsgType
  2032. NULL, // hCryptProv
  2033. NULL, // pRecipientInfo
  2034. NULL); // pStreamInfo
  2035. if (NULL == hMsg)
  2036. {
  2037. hr = myHLastError();
  2038. _JumpError(hr, error, "CryptMsgOpenToDecode");
  2039. }
  2040. if (!CryptMsgUpdate(hMsg, pbIn, cbIn, TRUE))
  2041. {
  2042. hr = myHLastError();
  2043. _JumpError(hr, error, "CryptMsgUpdate");
  2044. }
  2045. cb = sizeof(cSigner);
  2046. if (!CryptMsgGetParam(
  2047. hMsg,
  2048. CMSG_SIGNER_COUNT_PARAM,
  2049. 0,
  2050. &cSigner,
  2051. &cb))
  2052. {
  2053. hr = myHLastError();
  2054. _JumpError(hr, error, "CryptMsgGetParam(signer count)");
  2055. }
  2056. DBGPRINT((DBG_SS_CERTSRV, "cSigner=%u\n", cSigner));
  2057. for (iSigner = 0; iSigner < cSigner; iSigner++)
  2058. {
  2059. hr = myCryptMsgGetParam(
  2060. hMsg,
  2061. CMSG_SIGNER_UNAUTH_ATTR_PARAM,
  2062. iSigner, // dwIndex
  2063. CERTLIB_USE_LOCALALLOC,
  2064. (VOID **) &pAttrib,
  2065. &cb);
  2066. _PrintIfError2(hr, "myCryptMsgGetParam(content)", hr);
  2067. if (S_FALSE == hr)
  2068. {
  2069. continue;
  2070. }
  2071. _JumpIfError(hr, error, "myCryptMsgGetParam(content)");
  2072. DBGPRINT((
  2073. DBG_SS_CERTSRV,
  2074. "iSigner=%u, cAttr=%u\n",
  2075. iSigner,
  2076. pAttrib->cAttr));
  2077. // Loop through deleting attributes from the end to avoid invalidated
  2078. // indexes, which may result from deleting earlier attributes.
  2079. for (i = 0; i < pAttrib->cAttr; i++)
  2080. {
  2081. CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA DelPara;
  2082. DWORD iAttr = pAttrib->cAttr - i - 1;
  2083. DBGPRINT((
  2084. DBG_SS_CERTSRV,
  2085. "iSigner=%u, iAttr=%u %hs\n",
  2086. iSigner,
  2087. iAttr,
  2088. pAttrib->rgAttr[iAttr].pszObjId));
  2089. if (0 == strcmp(
  2090. pAttrib->rgAttr[iAttr].pszObjId,
  2091. szOID_ARCHIVED_KEY_ATTR))
  2092. {
  2093. ZeroMemory(&DelPara, sizeof(DelPara));
  2094. DelPara.cbSize = sizeof(DelPara);
  2095. DelPara.dwSignerIndex = iSigner;
  2096. DelPara.dwUnauthAttrIndex = iAttr;
  2097. DBGPRINT((
  2098. DBG_SS_CERTSRV,
  2099. "Delete Key(signer=%u, attrib=%u)\n",
  2100. DelPara.dwSignerIndex,
  2101. DelPara.dwUnauthAttrIndex));
  2102. if (!CryptMsgControl(
  2103. hMsg,
  2104. 0,
  2105. CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR,
  2106. &DelPara))
  2107. {
  2108. hr = myHLastError();
  2109. _PrintError(hr, "CryptMsgControl");
  2110. }
  2111. fKeyDeleted = TRUE;
  2112. }
  2113. }
  2114. LocalFree(pAttrib);
  2115. pAttrib = NULL;
  2116. }
  2117. if (!fKeyDeleted)
  2118. {
  2119. hr = S_FALSE;
  2120. _JumpError(hr, error, "no Encrypted Key attribute");
  2121. }
  2122. hr = myCryptMsgGetParam(
  2123. hMsg,
  2124. CMSG_ENCODED_MESSAGE,
  2125. 0, // dwIndex
  2126. CERTLIB_USE_LOCALALLOC,
  2127. (VOID **) &pbWithoutKey,
  2128. &cbWithoutKey);
  2129. _JumpIfError(hr, error, "myCryptMsgGetParam(content)");
  2130. hr = prow->SetProperty(
  2131. g_wszPropRequestRawRequest,
  2132. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2133. cbWithoutKey,
  2134. pbWithoutKey);
  2135. _JumpIfError(hr, error, "SetProperty(request)");
  2136. error:
  2137. if (NULL != pAttrib)
  2138. {
  2139. LocalFree(pAttrib);
  2140. }
  2141. if (NULL != pbWithoutKey)
  2142. {
  2143. LocalFree(pbWithoutKey);
  2144. }
  2145. if (NULL != hMsg)
  2146. {
  2147. CryptMsgClose(hMsg);
  2148. }
  2149. return(hr);
  2150. }
  2151. #define PSA_DISALLOW_EXTENSIONS 0x00000001
  2152. #define PSA_DISALLOW_NAMEVALUEPAIRS 0x00000002
  2153. #define PSA_DISALLOW_ARCHIVEDKEY 0x00000004
  2154. HRESULT
  2155. pkcsSetAttributes(
  2156. IN ICertDBRow *prow,
  2157. IN DWORD ExtFlags,
  2158. IN DWORD dwDisallowFlags,
  2159. IN CRYPT_ATTRIBUTE const *rgAttrib,
  2160. IN DWORD cAttrib,
  2161. IN DWORD cbRequest,
  2162. OPTIONAL IN BYTE const *pbRequest,
  2163. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf,
  2164. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  2165. {
  2166. HRESULT hr;
  2167. CRYPT_ATTRIBUTE const *pAttrib;
  2168. CRYPT_ATTRIBUTE const *pAttribEnd;
  2169. DWORD i;
  2170. BYTE afSubjectTable[CSUBJECTTABLE]; // see PKCSParseAttributes note
  2171. CRYPT_DATA_BLOB *pBlob = NULL;
  2172. BOOL fSubjectModified = FALSE;
  2173. ZeroMemory(&afSubjectTable, sizeof(afSubjectTable));
  2174. CSASSERT(0 == FALSE);
  2175. if (NULL != pfEnrollOnBehalfOf)
  2176. {
  2177. *pfEnrollOnBehalfOf = FALSE;
  2178. }
  2179. pAttribEnd = &rgAttrib[cAttrib];
  2180. for (pAttrib = rgAttrib; pAttrib < pAttribEnd; pAttrib++)
  2181. {
  2182. if (0 == strcmp(pAttrib->pszObjId, szOID_OS_VERSION))
  2183. {
  2184. if (1 != pAttrib->cValue)
  2185. {
  2186. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2187. _JumpError(hr, error, "Attribute Value count != 1");
  2188. }
  2189. hr = pkcsSetOSVersion(prow, pAttrib->rgValue);
  2190. _JumpIfError(hr, error, "pkcsSetOSVersion");
  2191. }
  2192. else
  2193. if (0 == strcmp(pAttrib->pszObjId, szOID_ENROLLMENT_CSP_PROVIDER))
  2194. {
  2195. // Check to see if we have a CSPPROVIDER attribute. We use this in
  2196. // the policy module to determine if xenroll generated the request,
  2197. // so we can behave differently for old xenroll requests (put the
  2198. // UPN in the subject to avoid enrollment loops)
  2199. if (1 != pAttrib->cValue)
  2200. {
  2201. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2202. _JumpError(hr, error, "Attribute Value count != 1");
  2203. }
  2204. hr = pkcsSetCSPProvider(prow, pAttrib->rgValue);
  2205. _JumpIfError(hr, error, "pkcsSetCSPProvider");
  2206. }
  2207. else
  2208. if (0 == strcmp(pAttrib->pszObjId, szOID_ENCRYPTED_KEY_HASH))
  2209. {
  2210. DWORD cb;
  2211. if (NULL != pResult->pbKeyHashIn || NULL != pBlob)
  2212. {
  2213. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2214. _JumpError(hr, error, "Multiple key hashes");
  2215. }
  2216. if (1 != pAttrib->cValue)
  2217. {
  2218. _JumpError(hr, error, "Attribute Value count != 1");
  2219. }
  2220. if (!myDecodeObject(
  2221. X509_ASN_ENCODING,
  2222. X509_OCTET_STRING,
  2223. pAttrib->rgValue[0].pbData,
  2224. pAttrib->rgValue[0].cbData,
  2225. CERTLIB_USE_LOCALALLOC,
  2226. (VOID **) &pBlob,
  2227. &cb))
  2228. {
  2229. hr = myHLastError();
  2230. _JumpError(hr, error, "myDecodeObject");
  2231. }
  2232. pResult->pbKeyHashIn = (BYTE *) LocalAlloc(
  2233. LMEM_FIXED,
  2234. pBlob->cbData);
  2235. if (NULL == pResult->pbKeyHashIn)
  2236. {
  2237. hr = E_OUTOFMEMORY;
  2238. _JumpError(hr, error, "LocalAlloc");
  2239. }
  2240. CopyMemory(pResult->pbKeyHashIn, pBlob->pbData, pBlob->cbData);
  2241. pResult->cbKeyHashIn = pBlob->cbData;
  2242. }
  2243. else
  2244. if (0 == strcmp(pAttrib->pszObjId, szOID_ARCHIVED_KEY_ATTR))
  2245. {
  2246. // Pull encrypted private key out of the attribute for archival.
  2247. //
  2248. // Save request in database without private key now, to keep the
  2249. // error path from saving the request later *with* the key.
  2250. if (NULL != pbRequest)
  2251. {
  2252. hr = pkcsSaveRequestWithoutArchivedKey(
  2253. prow,
  2254. cbRequest,
  2255. pbRequest);
  2256. _PrintIfError(hr, "pkcsSaveRequestWithoutArchivedKey");
  2257. if (S_OK == hr)
  2258. {
  2259. pResult->fKeyArchived = TRUE;
  2260. }
  2261. }
  2262. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2263. if (PSA_DISALLOW_ARCHIVEDKEY & dwDisallowFlags)
  2264. {
  2265. hr = CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL;
  2266. _JumpError(hr, error, "archived key disallowed");
  2267. }
  2268. if (1 != pAttrib->cValue)
  2269. {
  2270. _JumpError(hr, error, "Attribute Value count != 1");
  2271. }
  2272. hr = PKCSArchivePrivateKey(
  2273. prow,
  2274. FALSE,
  2275. FALSE,
  2276. &pAttrib->rgValue[0],
  2277. pResult);
  2278. _JumpIfError(hr, error, "PKCSArchivePrivateKey");
  2279. }
  2280. else
  2281. if (0 == strcmp(pAttrib->pszObjId, szOID_CERT_EXTENSIONS) ||
  2282. 0 == strcmp(pAttrib->pszObjId, szOID_RSA_certExtensions))
  2283. {
  2284. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2285. if (PSA_DISALLOW_EXTENSIONS & dwDisallowFlags)
  2286. {
  2287. _JumpError(hr, error, "extensions disallowed");
  2288. }
  2289. if (1 != pAttrib->cValue)
  2290. {
  2291. _JumpError(hr, error, "Attribute Value count != 1");
  2292. }
  2293. hr = pkcsSetExtensionsFromAttributeBlob(
  2294. prow,
  2295. ExtFlags,
  2296. pAttrib);
  2297. _JumpIfError(hr, error, "pkcsSetExtensionsFromAttributeBlob");
  2298. }
  2299. else
  2300. if (0 == strcmp(pAttrib->pszObjId, szOID_ENROLLMENT_NAME_VALUE_PAIR))
  2301. {
  2302. // Can't apply name value pair attributes to a renewal or CMC
  2303. if (PSA_DISALLOW_NAMEVALUEPAIRS & dwDisallowFlags)
  2304. {
  2305. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2306. _JumpError(hr, error, "name/value pairs disallowed");
  2307. }
  2308. for (i = 0; i < pAttrib->cValue; i++)
  2309. {
  2310. CRYPT_ENROLLMENT_NAME_VALUE_PAIR *pInfo = NULL;
  2311. DWORD cbInfo = 0;
  2312. CRYPT_ATTR_BLOB const *pvalue = &pAttrib->rgValue[i];
  2313. WCHAR const *pwszPropName;
  2314. BOOL fConcatenateRDNs;
  2315. DWORD dwIndex;
  2316. DWORD cchMax;
  2317. DWORD dwTable;
  2318. if (!myDecodeNameValuePair(
  2319. X509_ASN_ENCODING,
  2320. pvalue->pbData,
  2321. pvalue->cbData,
  2322. CERTLIB_USE_LOCALALLOC,
  2323. &pInfo,
  2324. &cbInfo))
  2325. {
  2326. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2327. _JumpError(hr, error, "myDecodeNameValuePair");
  2328. // if the attribute name & value are both non-empty ...
  2329. }
  2330. BOOL fEnrollOnBehalfOf = FALSE;
  2331. BOOL fSubjectModifiedT = FALSE;
  2332. hr = pkcsSetAttributeProperty(
  2333. prow,
  2334. pInfo->pwszName,
  2335. pInfo->pwszValue,
  2336. PROPTABLE_REQUEST,
  2337. afSubjectTable,
  2338. &fSubjectModified,
  2339. NULL != pfEnrollOnBehalfOf? &fEnrollOnBehalfOf : NULL);
  2340. if (fSubjectModifiedT)
  2341. {
  2342. fSubjectModified = TRUE;
  2343. }
  2344. if (fEnrollOnBehalfOf)
  2345. {
  2346. *pfEnrollOnBehalfOf = TRUE;
  2347. }
  2348. if (NULL != pInfo)
  2349. {
  2350. LocalFree(pInfo);
  2351. }
  2352. _JumpIfError(hr, error, "pkcsSetAttributeProperty");
  2353. }
  2354. }
  2355. else
  2356. {
  2357. DBGPRINT((
  2358. DBG_SS_CERTSRVI,
  2359. "Skipping authenticated attribute %hs\n",
  2360. pAttrib->pszObjId));
  2361. }
  2362. }
  2363. if (fSubjectModified)
  2364. {
  2365. hr = PKCSSetRequestFlags(prow, FALSE, CR_FLG_SUBJECTUNMODIFIED);
  2366. _JumpIfError(hr, error, "PKCSSetRequestFlags");
  2367. }
  2368. hr = S_OK;
  2369. error:
  2370. if (NULL != pBlob)
  2371. {
  2372. LocalFree(pBlob);
  2373. }
  2374. return(hr);
  2375. }
  2376. HRESULT
  2377. pkcsVerifyCertContext(
  2378. OPTIONAL IN FILETIME const *pft,
  2379. IN BOOL fTimeOnly,
  2380. IN CERT_CONTEXT const *pcc)
  2381. {
  2382. HRESULT hr;
  2383. FILETIME ft;
  2384. if (NULL == pft)
  2385. {
  2386. GetSystemTimeAsFileTime(&ft);
  2387. pft = &ft;
  2388. }
  2389. if (0 > CompareFileTime(pft, &pcc->pCertInfo->NotBefore))
  2390. {
  2391. hr = CERT_E_EXPIRED;
  2392. _JumpError(hr, error, "cert not yet valid");
  2393. }
  2394. if (0 < CompareFileTime(pft, &pcc->pCertInfo->NotAfter))
  2395. {
  2396. hr = CERT_E_EXPIRED;
  2397. _JumpError(hr, error, "cert is expired");
  2398. }
  2399. if (!fTimeOnly)
  2400. {
  2401. hr = myVerifyCertContext(
  2402. pcc, // pCert
  2403. (CRLF_REVCHECK_IGNORE_OFFLINE & g_dwCRLFlags)?
  2404. CA_VERIFY_FLAGS_IGNORE_OFFLINE : 0, // dwFlags
  2405. 0, // cUsageOids
  2406. NULL, // apszUsageOids
  2407. HCCE_LOCAL_MACHINE, // hChainEngine
  2408. NULL, // hAdditionalStore
  2409. NULL); // ppwszMissingIssuer
  2410. _JumpIfError(hr, error, "myVerifyCertContext");
  2411. }
  2412. hr = S_OK;
  2413. error:
  2414. return(hr);
  2415. }
  2416. HRESULT
  2417. pkcsSetValidityPeriod(
  2418. IN ICertDBRow *prow,
  2419. IN LONG lValidityPeriodCount,
  2420. IN enum ENUM_PERIOD enumValidityPeriod)
  2421. {
  2422. HRESULT hr;
  2423. FILETIME ftNotBefore;
  2424. FILETIME ftNotAfter;
  2425. LONGLONG delta;
  2426. CACTX *pCAContext = g_pCAContextCurrent;
  2427. GetSystemTimeAsFileTime(&ftNotBefore);
  2428. hr = pkcsVerifyCertContext(&ftNotBefore, TRUE, pCAContext->pccCA);
  2429. _JumpIfErrorStr(hr, error, "pkcsVerifyCertContext", L"CA cert expired");
  2430. ftNotAfter = ftNotBefore;
  2431. // Set the start date to the current time minus clock skew. But ensure the
  2432. // new cert's start date is not before the CA certificate's start date.
  2433. delta = g_dwClockSkewMinutes * CVT_MINUTES;
  2434. myAddToFileTime(&ftNotBefore, -delta * CVT_BASE);
  2435. if (0 > CompareFileTime(
  2436. &ftNotBefore,
  2437. &pCAContext->pccCA->pCertInfo->NotBefore))
  2438. {
  2439. ftNotBefore = pCAContext->pccCA->pCertInfo->NotBefore;
  2440. }
  2441. hr = prow->SetProperty(
  2442. g_wszPropCertificateNotBeforeDate,
  2443. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  2444. sizeof(ftNotBefore),
  2445. (BYTE *) &ftNotBefore);
  2446. _JumpIfError(hr, error, "pkcsSetValidityPeriod:SetProperty");
  2447. // Set the end date to the start date plus the registry-configured
  2448. // validity period. Then clamp the new cert's end date to the CA
  2449. // certificate's end date.
  2450. myMakeExprDateTime(&ftNotAfter, lValidityPeriodCount, enumValidityPeriod);
  2451. if (0 < CompareFileTime(
  2452. &ftNotAfter,
  2453. &pCAContext->pccCA->pCertInfo->NotAfter))
  2454. {
  2455. ftNotAfter = pCAContext->pccCA->pCertInfo->NotAfter;
  2456. }
  2457. hr = prow->SetProperty(
  2458. g_wszPropCertificateNotAfterDate,
  2459. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  2460. sizeof(ftNotAfter),
  2461. (BYTE *) &ftNotAfter);
  2462. _JumpIfError(hr, error, "pkcsSetValidityPeriod:SetProperty");
  2463. error:
  2464. return(hr);
  2465. }
  2466. HRESULT
  2467. pkcsSetServerExtension(
  2468. IN ICertDBRow *prow,
  2469. IN WCHAR const *pwszObjId,
  2470. IN DWORD cbExt,
  2471. IN BYTE const *pbExt)
  2472. {
  2473. HRESULT hr;
  2474. BYTE *pbOld = NULL;
  2475. DWORD cbOld;
  2476. DWORD ExtFlags;
  2477. ExtFlags = 0;
  2478. if (NULL == pbExt)
  2479. {
  2480. CSASSERT(0 == cbExt);
  2481. hr = PropGetExtension(
  2482. prow,
  2483. PROPTYPE_BINARY | PROPCALLER_SERVER,
  2484. pwszObjId,
  2485. &ExtFlags,
  2486. &cbOld,
  2487. &pbOld);
  2488. if (S_OK != hr)
  2489. {
  2490. ExtFlags = 0;
  2491. }
  2492. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  2493. {
  2494. ExtFlags |= EXTENSION_DISABLE_FLAG;
  2495. }
  2496. }
  2497. if (NULL != pbExt || (EXTENSION_DISABLE_FLAG & ExtFlags))
  2498. {
  2499. ExtFlags &= ~EXTENSION_ORIGIN_MASK;
  2500. ExtFlags |= EXTENSION_ORIGIN_SERVER;
  2501. hr = PropSetExtension(
  2502. prow,
  2503. PROPTYPE_BINARY | PROPCALLER_SERVER,
  2504. pwszObjId,
  2505. ExtFlags,
  2506. cbExt,
  2507. pbExt);
  2508. _JumpIfError(hr, error, "PropSetExtension");
  2509. }
  2510. hr = S_OK;
  2511. error:
  2512. if (NULL != pbOld)
  2513. {
  2514. LocalFree(pbOld);
  2515. }
  2516. return(hr);
  2517. }
  2518. HRESULT
  2519. PKCSSetServerProperties(
  2520. IN ICertDBRow *prow,
  2521. IN LONG lValidityPeriodCount,
  2522. IN enum ENUM_PERIOD enumValidityPeriod)
  2523. {
  2524. HRESULT hr;
  2525. CACTX *pCAContext = g_pCAContextCurrent;
  2526. hr = pkcsSetServerExtension(
  2527. prow,
  2528. TEXT(szOID_AUTHORITY_KEY_IDENTIFIER2),
  2529. pCAContext->KeyAuthority2Cert.cbData,
  2530. pCAContext->KeyAuthority2Cert.pbData);
  2531. _JumpIfError(hr, error, "pkcsSetServerExtension");
  2532. hr = pkcsSetServerExtension(
  2533. prow,
  2534. TEXT(szOID_CRL_DIST_POINTS),
  2535. pCAContext->CDPCert.cbData,
  2536. pCAContext->CDPCert.pbData);
  2537. _JumpIfError(hr, error, "pkcsSetServerExtension");
  2538. hr = pkcsSetServerExtension(
  2539. prow,
  2540. TEXT(szOID_AUTHORITY_INFO_ACCESS),
  2541. pCAContext->AIACert.cbData,
  2542. pCAContext->AIACert.pbData);
  2543. _JumpIfError(hr, error, "pkcsSetServerExtension");
  2544. hr = pkcsSetValidityPeriod(prow, lValidityPeriodCount, enumValidityPeriod);
  2545. _JumpIfError(hr, error, "pkcsSetValidityPeriod");
  2546. error:
  2547. return(hr);
  2548. }
  2549. HRESULT
  2550. pkcsSetPublicKeyProperties(
  2551. IN ICertDBRow *prow,
  2552. IN CERT_PUBLIC_KEY_INFO const *pSubjectPublicKeyInfo)
  2553. {
  2554. HRESULT hr;
  2555. WCHAR *pwszExtensionName;
  2556. WCHAR *pwszObjId = NULL;
  2557. CACTX *pCAContext = g_pCAContextCurrent;
  2558. CERT_EXTENSION ext;
  2559. DWORD ExtFlags;
  2560. DWORD dwCaller;
  2561. DWORD cbitKey;
  2562. ext.Value.pbData = NULL;
  2563. // Public Key size must be a multiple of 8 bits.
  2564. if (0 != pSubjectPublicKeyInfo->PublicKey.cUnusedBits)
  2565. {
  2566. hr = NTE_BAD_KEY;
  2567. _JumpError(hr, error, "PublicKey.cUnusedBits");
  2568. }
  2569. hr = prow->SetProperty(
  2570. g_wszPropCertificateRawPublicKey,
  2571. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  2572. pSubjectPublicKeyInfo->PublicKey.cbData,
  2573. pSubjectPublicKeyInfo->PublicKey.pbData);
  2574. _JumpIfError(hr, error, "SetProperty");
  2575. cbitKey = CertGetPublicKeyLength(
  2576. X509_ASN_ENCODING,
  2577. const_cast<CERT_PUBLIC_KEY_INFO *>(pSubjectPublicKeyInfo));
  2578. hr = prow->SetProperty(
  2579. g_wszPropCertificatePublicKeyLength,
  2580. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  2581. sizeof(cbitKey),
  2582. (BYTE const *) &cbitKey);
  2583. _JumpIfError(hr, error, "SetProperty(KeyLength)");
  2584. if (!ConvertSzToWsz(
  2585. &pwszObjId,
  2586. pSubjectPublicKeyInfo->Algorithm.pszObjId,
  2587. -1))
  2588. {
  2589. hr = E_OUTOFMEMORY;
  2590. _JumpError(hr, error, "ConvertSzToWsz(AlgObjId)");
  2591. }
  2592. hr = prow->SetProperty(
  2593. g_wszPropCertificatePublicKeyAlgorithm,
  2594. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  2595. MAXDWORD,
  2596. (BYTE const *) pwszObjId);
  2597. _JumpIfError(hr, error, "SetProperty");
  2598. if (NULL != pSubjectPublicKeyInfo->Algorithm.Parameters.pbData)
  2599. {
  2600. hr = prow->SetProperty(
  2601. g_wszPropCertificateRawPublicKeyAlgorithmParameters,
  2602. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  2603. pSubjectPublicKeyInfo->Algorithm.Parameters.cbData,
  2604. pSubjectPublicKeyInfo->Algorithm.Parameters.pbData);
  2605. _JumpIfError(hr, error, "SetProperty");
  2606. }
  2607. // Subject Key Identifier extension:
  2608. hr = PropGetExtension(
  2609. prow,
  2610. PROPTYPE_BINARY | PROPCALLER_SERVER,
  2611. TEXT(szOID_SUBJECT_KEY_IDENTIFIER),
  2612. &ExtFlags,
  2613. &ext.Value.cbData,
  2614. &ext.Value.pbData);
  2615. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  2616. {
  2617. _JumpIfError(hr, error, "PropGetExtension");
  2618. dwCaller = PROPCALLER_REQUEST;
  2619. ExtFlags &= ~EXTENSION_DISABLE_FLAG;
  2620. }
  2621. else
  2622. {
  2623. dwCaller = PROPCALLER_SERVER;
  2624. ExtFlags = EXTENSION_ORIGIN_SERVER;
  2625. hr = myCreateSubjectKeyIdentifierExtension(
  2626. pSubjectPublicKeyInfo,
  2627. &ext.Value.pbData,
  2628. &ext.Value.cbData);
  2629. _JumpIfError(hr, error, "myCreateSubjectKeyIdentifierExtension");
  2630. }
  2631. hr = PropSetExtension(
  2632. prow,
  2633. PROPTYPE_BINARY | dwCaller,
  2634. TEXT(szOID_SUBJECT_KEY_IDENTIFIER),
  2635. ExtFlags,
  2636. ext.Value.cbData,
  2637. ext.Value.pbData);
  2638. _JumpIfError(hr, error, "PropSetExtension");
  2639. error:
  2640. if (NULL != ext.Value.pbData)
  2641. {
  2642. LocalFree(ext.Value.pbData);
  2643. }
  2644. if (NULL != pwszObjId)
  2645. {
  2646. LocalFree(pwszObjId);
  2647. }
  2648. return(hr);
  2649. }
  2650. HRESULT
  2651. pkcsParsePKCS10Request(
  2652. IN DWORD dwFlags,
  2653. IN ICertDBRow *prow,
  2654. IN DWORD cbRequest,
  2655. IN BYTE const *pbRequest,
  2656. IN CERT_CONTEXT const *pSigningAuthority,
  2657. OUT BOOL *pfRenewal,
  2658. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  2659. {
  2660. HRESULT hr;
  2661. DWORD cbCertInfo;
  2662. CERT_REQUEST_INFO *pRequestInfo = NULL;
  2663. CRYPT_ATTRIBUTE const *pAttrib;
  2664. CRYPT_ATTRIBUTE const *pAttribEnd;
  2665. CRYPT_ATTR_BLOB *pAttrBlob;
  2666. CERT_CONTEXT const *pOldCert = NULL;
  2667. DWORD dwRequestFlags = 0;
  2668. BOOL fRenewal = FALSE;
  2669. BOOL fSubjectNameSet;
  2670. CSASSERT(CR_IN_PKCS10 == (CR_IN_FORMATMASK & dwFlags));
  2671. CSASSERT(
  2672. CR_IN_PKCS10 == (CR_IN_FORMATMASK & pResult->dwFlagsTop) ||
  2673. CR_IN_PKCS7 == (CR_IN_FORMATMASK & pResult->dwFlagsTop) ||
  2674. CR_IN_CMC == (CR_IN_FORMATMASK & pResult->dwFlagsTop));
  2675. if (!myDecodeObject(
  2676. X509_ASN_ENCODING,
  2677. X509_CERT_REQUEST_TO_BE_SIGNED,
  2678. pbRequest,
  2679. cbRequest,
  2680. CERTLIB_USE_LOCALALLOC,
  2681. (VOID **) &pRequestInfo,
  2682. &cbCertInfo))
  2683. {
  2684. hr = myHLastError();
  2685. _JumpError(hr, error, "myDecodeObject");
  2686. }
  2687. // verify with the public key passed in the PKCS10
  2688. if (!CryptVerifyCertificateSignature(
  2689. NULL,
  2690. X509_ASN_ENCODING,
  2691. const_cast<BYTE *>(pbRequest),
  2692. cbRequest,
  2693. &pRequestInfo->SubjectPublicKeyInfo))
  2694. {
  2695. hr = myHLastError();
  2696. _PrintError3(
  2697. hr,
  2698. "CryptVerifyCertificateSignature",
  2699. E_INVALIDARG,
  2700. CRYPT_E_ASN1_BADTAG);
  2701. if (CR_IN_CMC == (CR_IN_FORMATMASK & pResult->dwFlagsTop))
  2702. {
  2703. if (E_INVALIDARG == hr) // NULL signature?
  2704. {
  2705. CRYPT_DATA_BLOB Blob;
  2706. Blob.cbData = cbRequest;
  2707. Blob.pbData = const_cast<BYTE *>(pbRequest);
  2708. if (!CryptVerifyCertificateSignatureEx(
  2709. NULL, // hCryptProv
  2710. X509_ASN_ENCODING,
  2711. CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB,
  2712. &Blob,
  2713. CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL,
  2714. NULL, // pvIssuer
  2715. 0, // dwFlags
  2716. NULL)) // pvReserved
  2717. {
  2718. HRESULT hr2 = myHLastError();
  2719. _PrintError(hr2, "CryptVerifyCertificateSignatureEx");
  2720. }
  2721. else
  2722. {
  2723. hr = S_OK;
  2724. }
  2725. }
  2726. else if ((CRLF_ACCEPT_OLDRFC_CMC & g_dwCRLFlags) &&
  2727. CRYPT_E_ASN1_BADTAG == hr) // No signature?
  2728. {
  2729. hr = S_OK;
  2730. }
  2731. }
  2732. if (E_INVALIDARG == hr || CRYPT_E_ASN1_BADTAG == hr)
  2733. {
  2734. hr = NTE_BAD_SIGNATURE;
  2735. }
  2736. _JumpIfError(hr, error, "CryptVerifyCertificateSignature");
  2737. }
  2738. // handle renewal certificate extensions BEFORE processing the rest of
  2739. // the request attributes (which may also contain extensions)
  2740. pAttribEnd = &pRequestInfo->rgAttribute[pRequestInfo->cAttribute];
  2741. for (pAttrib = pRequestInfo->rgAttribute; pAttrib < pAttribEnd; pAttrib++)
  2742. {
  2743. if (0 == strcmp(pAttrib->pszObjId, szOID_RENEWAL_CERTIFICATE))
  2744. {
  2745. hr = CERTSRV_E_BAD_RENEWAL_CERT_ATTRIBUTE;
  2746. if (fRenewal)
  2747. {
  2748. _JumpError(hr, error, "Multiple renewal certs!");
  2749. }
  2750. if (CR_IN_PKCS7 != (CR_IN_FORMATMASK & pResult->dwFlagsTop) &&
  2751. CR_IN_CMC != (CR_IN_FORMATMASK & pResult->dwFlagsTop))
  2752. {
  2753. _JumpError(hr, error, "renewal cert must be in PKCS7 or CMC");
  2754. }
  2755. if (1 != pAttrib->cValue)
  2756. {
  2757. _JumpError(hr, error, "Attribute Value count != 1");
  2758. }
  2759. pAttrBlob = pAttrib->rgValue;
  2760. pOldCert = CertCreateCertificateContext(
  2761. X509_ASN_ENCODING,
  2762. pAttrBlob->pbData,
  2763. pAttrBlob->cbData);
  2764. if (NULL == pOldCert)
  2765. {
  2766. _JumpError(hr, error, "CertCreateCertificateContext");
  2767. }
  2768. // The old raw certificate, and the signer of the PKCS7 must match!
  2769. if (NULL == pSigningAuthority ||
  2770. !CertCompareCertificate(
  2771. pSigningAuthority->dwCertEncodingType,
  2772. pSigningAuthority->pCertInfo,
  2773. pOldCert->pCertInfo))
  2774. {
  2775. _JumpError(hr, error, "CertCompareCertificate");
  2776. }
  2777. // This is a renewal, mark it as such.
  2778. hr = prow->SetProperty(
  2779. g_wszPropRequestRawOldCertificate,
  2780. PROPTYPE_BINARY |
  2781. PROPCALLER_SERVER |
  2782. PROPTABLE_REQUEST,
  2783. pAttrBlob->cbData,
  2784. pAttrBlob->pbData);
  2785. _JumpIfError(hr, error, "SetProperty(old cert)");
  2786. hr = pkcsSetExtensions(
  2787. prow,
  2788. EXTENSION_ORIGIN_RENEWALCERT | EXTENSION_DISABLE_FLAG,
  2789. pOldCert->pCertInfo->rgExtension,
  2790. pOldCert->pCertInfo->cExtension);
  2791. _JumpIfError(hr, error, "pkcsSetExtensions(old cert)");
  2792. fRenewal = TRUE;
  2793. }
  2794. }
  2795. // handle certificate extensions/known atributes
  2796. hr = pkcsSetAttributes(
  2797. prow,
  2798. EXTENSION_ORIGIN_REQUEST,
  2799. PSA_DISALLOW_ARCHIVEDKEY,
  2800. pRequestInfo->rgAttribute,
  2801. pRequestInfo->cAttribute,
  2802. 0,
  2803. NULL,
  2804. NULL,
  2805. pResult);
  2806. _JumpIfError(hr, error, "pkcsSetAttributes(PKCS10)");
  2807. hr = pkcsSetRequestNameInfo(
  2808. prow,
  2809. &pRequestInfo->Subject,
  2810. NULL, // pwszCNSuffix
  2811. &dwRequestFlags,
  2812. &fSubjectNameSet);
  2813. _JumpIfError(hr, error, "pkcsSetRequestNameInfo");
  2814. if (fSubjectNameSet)
  2815. {
  2816. dwRequestFlags |= CR_FLG_SUBJECTUNMODIFIED;
  2817. }
  2818. if (fRenewal)
  2819. {
  2820. if (!fSubjectNameSet)
  2821. {
  2822. CSASSERT(NULL != pOldCert);
  2823. CSASSERT(NULL != pOldCert->pCertInfo);
  2824. hr = pkcsSetRequestNameInfo(
  2825. prow,
  2826. &pOldCert->pCertInfo->Subject,
  2827. NULL, // pwszCNSuffix
  2828. &dwRequestFlags,
  2829. &fSubjectNameSet);
  2830. _JumpIfError(hr, error, "pkcsSetRequestNameInfo");
  2831. }
  2832. dwRequestFlags |= CR_FLG_RENEWAL;
  2833. }
  2834. hr = prow->SetProperty(
  2835. g_wszPropRequestFlags,
  2836. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2837. sizeof(dwRequestFlags),
  2838. (BYTE const *) &dwRequestFlags);
  2839. _JumpIfError(hr, error, "SetProperty(RequestFlags)");
  2840. hr = pkcsSetPublicKeyProperties(prow, &pRequestInfo->SubjectPublicKeyInfo);
  2841. _JumpIfError(hr, error, "pkcsSetPublicKeyProperties");
  2842. hr = PKCSSetServerProperties(
  2843. prow,
  2844. g_lValidityPeriodCount,
  2845. g_enumValidityPeriod);
  2846. _JumpIfError(hr, error, "PKCSSetServerProperties");
  2847. if (NULL != pfRenewal)
  2848. {
  2849. *pfRenewal = fRenewal;
  2850. }
  2851. error:
  2852. if (NULL != pOldCert)
  2853. {
  2854. CertFreeCertificateContext(pOldCert);
  2855. }
  2856. if (NULL != pRequestInfo)
  2857. {
  2858. LocalFree(pRequestInfo);
  2859. }
  2860. return(hr);
  2861. }
  2862. HRESULT
  2863. PKCSVerifyChallengeString(
  2864. IN ICertDBRow *prow)
  2865. {
  2866. HRESULT hr;
  2867. DWORD cb;
  2868. WCHAR wszPassed[MAX_PATH];
  2869. WCHAR wszExpected[MAX_PATH];
  2870. cb = sizeof(wszExpected);
  2871. hr = prow->GetProperty(
  2872. g_wszPropExpectedChallenge,
  2873. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_ATTRIBUTE,
  2874. &cb,
  2875. (BYTE *) wszExpected);
  2876. if (S_OK != hr || L'\0' == wszExpected[0])
  2877. {
  2878. hr = S_OK; // no challenge expected
  2879. goto error;
  2880. }
  2881. cb = sizeof(wszPassed);
  2882. hr = prow->GetProperty(
  2883. g_wszPropChallenge,
  2884. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_ATTRIBUTE,
  2885. &cb,
  2886. (BYTE *) wszPassed);
  2887. if (S_OK != hr)
  2888. {
  2889. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD);
  2890. _JumpError(hr, error, "Missing Challenge String");
  2891. }
  2892. if (0 != wcscmp(wszExpected, wszPassed))
  2893. {
  2894. CONSOLEPRINT2((
  2895. DBG_SS_CERTSRV,
  2896. "Challenge: passed(%ws) expected(%ws)\n",
  2897. wszPassed,
  2898. wszExpected));
  2899. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD);
  2900. _JumpError(hr, error, "Invalid Challenge String");
  2901. }
  2902. hr = prow->SetProperty(
  2903. g_wszPropExpectedChallenge,
  2904. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_ATTRIBUTE,
  2905. 0,
  2906. NULL);
  2907. _PrintIfError(hr, "SetProperty");
  2908. hr = S_OK;
  2909. error:
  2910. return(hr);
  2911. }
  2912. HRESULT
  2913. pkcsParseKeyGenRequest(
  2914. IN DWORD dwFlags,
  2915. IN ICertDBRow *prow,
  2916. IN DWORD cbRequest,
  2917. IN BYTE const *pbRequest,
  2918. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  2919. {
  2920. HRESULT hr;
  2921. DWORD cbKeyGenRequest;
  2922. CERT_KEYGEN_REQUEST_INFO *pKeyGenRequest = NULL;
  2923. DWORD dwRequestFlags;
  2924. CSASSERT(CR_IN_KEYGEN == (CR_IN_FORMATMASK & dwFlags));
  2925. // Decode KeyGenRequest structure
  2926. if (!myDecodeKeyGenRequest(
  2927. pbRequest,
  2928. cbRequest,
  2929. CERTLIB_USE_LOCALALLOC,
  2930. &pKeyGenRequest,
  2931. &cbKeyGenRequest))
  2932. {
  2933. hr = myHLastError();
  2934. _JumpError(hr, error, "myDecodeKeyGen");
  2935. }
  2936. // verify with the public key passed in the PKCS10
  2937. if (!CryptVerifyCertificateSignature(
  2938. NULL,
  2939. X509_ASN_ENCODING,
  2940. (BYTE *) pbRequest,
  2941. cbRequest,
  2942. &pKeyGenRequest->SubjectPublicKeyInfo))
  2943. {
  2944. hr = myHLastError();
  2945. _JumpError(hr, error, "CryptVerifyCertificateSignature");
  2946. }
  2947. hr = pkcsSetPublicKeyProperties(
  2948. prow,
  2949. &pKeyGenRequest->SubjectPublicKeyInfo);
  2950. _JumpIfError(hr, error, "pkcsSetPublicKeyProperties");
  2951. hr = PKCSSetServerProperties(
  2952. prow,
  2953. g_lValidityPeriodCount,
  2954. g_enumValidityPeriod);
  2955. _JumpIfError(hr, error, "PKCSSetServerProperties");
  2956. hr = prow->SetProperty(
  2957. g_wszPropExpectedChallenge,
  2958. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_ATTRIBUTE,
  2959. MAXDWORD,
  2960. (BYTE *) pKeyGenRequest->pwszChallengeString);
  2961. _JumpIfError(hr, error, "SetProperty");
  2962. dwRequestFlags = 0;
  2963. switch (ENUM_TELETEX_MASK & g_fForceTeletex)
  2964. {
  2965. case ENUM_TELETEX_ON:
  2966. case ENUM_TELETEX_AUTO:
  2967. dwRequestFlags |= CR_FLG_FORCETELETEX;
  2968. break;
  2969. }
  2970. if (ENUM_TELETEX_UTF8 & g_fForceTeletex)
  2971. {
  2972. dwRequestFlags |= CR_FLG_FORCEUTF8;
  2973. }
  2974. hr = prow->SetProperty(
  2975. g_wszPropRequestFlags,
  2976. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2977. sizeof(dwRequestFlags),
  2978. (BYTE const *) &dwRequestFlags);
  2979. _JumpIfError(hr, error, "SetProperty(RequestFlags)");
  2980. error:
  2981. if (NULL != pKeyGenRequest)
  2982. {
  2983. LocalFree(pKeyGenRequest);
  2984. }
  2985. return(hr);
  2986. }
  2987. // Validate the certificate:
  2988. // Signed by CA Certificate
  2989. // issuer name == CA Certificate subject
  2990. // NotBefore >= CA Certificate NotBefore
  2991. // NotAfter <= CA Certificate NotAfter
  2992. // if KEYID2 issuer KeyId set: == CA Certificate KeyId
  2993. // if KEYID2 issuer Name set: == CA Certificate Issuer
  2994. // if KEYID2 issuer Serial Number set: == CA Certificate serial number
  2995. HRESULT
  2996. pkcsVerifyCertIssuer(
  2997. IN CERT_CONTEXT const *pCert,
  2998. IN CACTX const *pCAContext)
  2999. {
  3000. HRESULT hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3001. CERT_INFO const *pCertInfo = pCert->pCertInfo;
  3002. CERT_INFO const *pCACertInfo = pCAContext->pccCA->pCertInfo;
  3003. CERT_EXTENSION const *pExt;
  3004. CERT_EXTENSION const *pExtEnd;
  3005. CERT_AUTHORITY_KEY_ID2_INFO *pkeyAuth = NULL;
  3006. DWORD cbkeyAuth;
  3007. CERT_NAME_BLOB const *pName;
  3008. // verify with the CA cert's public key
  3009. if (!CryptVerifyCertificateSignature(
  3010. NULL,
  3011. X509_ASN_ENCODING,
  3012. pCert->pbCertEncoded,
  3013. pCert->cbCertEncoded,
  3014. const_cast<CERT_PUBLIC_KEY_INFO *>(
  3015. &pCACertInfo->SubjectPublicKeyInfo)))
  3016. {
  3017. hr = myHLastError();
  3018. _JumpError2(
  3019. hr,
  3020. error,
  3021. "CryptVerifyCertificateSignature",
  3022. NTE_BAD_SIGNATURE);
  3023. }
  3024. // Check Issuer name:
  3025. if (!myAreBlobsSame(
  3026. pCACertInfo->Subject.pbData,
  3027. pCACertInfo->Subject.cbData,
  3028. pCertInfo->Issuer.pbData,
  3029. pCertInfo->Issuer.cbData))
  3030. {
  3031. _JumpError(hr, error, "Bad Issuer Name");
  3032. }
  3033. // Check that NotBefore >= CA Certificate NotBefore
  3034. if (0 > CompareFileTime(&pCertInfo->NotBefore, &pCACertInfo->NotBefore))
  3035. {
  3036. _JumpError(hr, error, "NotBefore too early");
  3037. }
  3038. // Check that NotAfter <= CA Certificate NotAfter
  3039. if (0 < CompareFileTime(&pCertInfo->NotAfter, &pCACertInfo->NotAfter))
  3040. {
  3041. _JumpError(hr, error, "NotAfter too late");
  3042. }
  3043. pExtEnd = &pCert->pCertInfo->rgExtension[pCert->pCertInfo->cExtension];
  3044. for (pExt = pCert->pCertInfo->rgExtension; pExt < pExtEnd; pExt++)
  3045. {
  3046. if (0 == strcmp(pExt->pszObjId, szOID_AUTHORITY_KEY_IDENTIFIER2))
  3047. {
  3048. if (!myDecodeObject(
  3049. X509_ASN_ENCODING,
  3050. X509_AUTHORITY_KEY_ID2,
  3051. pExt->Value.pbData,
  3052. pExt->Value.cbData,
  3053. CERTLIB_USE_LOCALALLOC,
  3054. (VOID **) &pkeyAuth,
  3055. &cbkeyAuth))
  3056. {
  3057. hr = myHLastError();
  3058. _JumpError(hr, error, "myDecodeObject");
  3059. }
  3060. // Check Issuer KeyId:
  3061. if (NULL != pCAContext->IssuerKeyId.pbData &&
  3062. NULL != pkeyAuth->KeyId.pbData &&
  3063. !myAreBlobsSame(
  3064. pCAContext->IssuerKeyId.pbData,
  3065. pCAContext->IssuerKeyId.cbData,
  3066. pkeyAuth->KeyId.pbData,
  3067. pkeyAuth->KeyId.cbData))
  3068. {
  3069. _JumpError(hr, error, "Bad AuthorityKeyId KeyId");
  3070. }
  3071. // Check Issuer name:
  3072. if (1 == pkeyAuth->AuthorityCertIssuer.cAltEntry &&
  3073. CERT_ALT_NAME_DIRECTORY_NAME ==
  3074. pkeyAuth->AuthorityCertIssuer.rgAltEntry[0].dwAltNameChoice)
  3075. {
  3076. pName = &pkeyAuth->AuthorityCertIssuer.rgAltEntry[0].DirectoryName;
  3077. if (NULL != pName->pbData &&
  3078. !myAreBlobsSame(
  3079. pCACertInfo->Issuer.pbData,
  3080. pCACertInfo->Issuer.cbData,
  3081. pName->pbData,
  3082. pName->cbData))
  3083. {
  3084. _JumpError(hr, error, "Bad AuthorityKeyId Issuer Name");
  3085. }
  3086. }
  3087. // Check Issuer SerialNumber:
  3088. if (NULL != pkeyAuth->AuthorityCertSerialNumber.pbData &&
  3089. !myAreSerialNumberBlobsSame(
  3090. &pCACertInfo->SerialNumber,
  3091. &pkeyAuth->AuthorityCertSerialNumber))
  3092. {
  3093. _JumpError(hr, error, "Bad AuthorityKeyId Issuer Serial Number");
  3094. }
  3095. break;
  3096. }
  3097. }
  3098. hr = S_OK;
  3099. error:
  3100. if (NULL != pkeyAuth)
  3101. {
  3102. LocalFree(pkeyAuth);
  3103. }
  3104. return(hr);
  3105. }
  3106. HRESULT
  3107. PKCSVerifyIssuedCertificate(
  3108. IN CERT_CONTEXT const *pCert,
  3109. OUT CACTX **ppCAContext)
  3110. {
  3111. HRESULT hr;
  3112. DWORD i;
  3113. CACTX *pCAContext;
  3114. *ppCAContext = NULL;
  3115. CSASSERT(0 != g_cCACerts);
  3116. for (i = g_cCACerts; i > 0; i--)
  3117. {
  3118. pCAContext = &g_aCAContext[i - 1];
  3119. hr = pkcsVerifyCertIssuer(pCert, pCAContext);
  3120. if (S_OK == hr)
  3121. {
  3122. *ppCAContext = pCAContext;
  3123. break;
  3124. }
  3125. _PrintError2(hr, "pkcsVerifyCertIssuer", NTE_BAD_SIGNATURE);
  3126. }
  3127. //error:
  3128. return(hr);
  3129. }
  3130. HRESULT
  3131. pkcsSetCertHash(
  3132. IN ICertDBRow *prow,
  3133. IN CERT_CONTEXT const *pcc)
  3134. {
  3135. HRESULT hr;
  3136. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  3137. DWORD cbHash;
  3138. BSTR strHash = NULL;
  3139. CACTX *pCAContext = g_pCAContextCurrent;
  3140. cbHash = sizeof(abHash);
  3141. if (!CertGetCertificateContextProperty(
  3142. pcc,
  3143. CERT_SHA1_HASH_PROP_ID,
  3144. abHash,
  3145. &cbHash))
  3146. {
  3147. hr = myHLastError();
  3148. _JumpError(hr, error, "CertGetCertificateContextProperty");
  3149. }
  3150. hr = MultiByteIntegerToBstr(TRUE, cbHash, abHash, &strHash);
  3151. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  3152. hr = prow->SetProperty(
  3153. g_wszPropCertificateHash,
  3154. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3155. MAXDWORD,
  3156. (BYTE const *) strHash);
  3157. _JumpIfError(hr, error, "SetProperty");
  3158. error:
  3159. if (NULL != strHash)
  3160. {
  3161. SysFreeString(strHash);
  3162. }
  3163. return(hr);
  3164. }
  3165. HRESULT
  3166. pkcsSetCertAndKeyHashes(
  3167. IN ICertDBRow *prow,
  3168. IN CERT_CONTEXT const *pcc)
  3169. {
  3170. HRESULT hr;
  3171. BYTE *pbHash = NULL;
  3172. DWORD cbHash;
  3173. BSTR strHash = NULL;
  3174. hr = pkcsSetCertHash(prow, pcc);
  3175. _JumpIfError(hr, error, "pkcsSetCertHash");
  3176. hr = myGetPublicKeyHash(
  3177. pcc->pCertInfo,
  3178. &pcc->pCertInfo->SubjectPublicKeyInfo,
  3179. &pbHash,
  3180. &cbHash);
  3181. _JumpIfError(hr, error, "myGetPublicKeyHash");
  3182. hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strHash);
  3183. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  3184. hr = prow->SetProperty(
  3185. g_wszPropCertificateSubjectKeyIdentifier,
  3186. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3187. MAXDWORD,
  3188. (BYTE const *) strHash);
  3189. _JumpIfError(hr, error, "SetProperty");
  3190. error:
  3191. if (NULL != strHash)
  3192. {
  3193. SysFreeString(strHash);
  3194. }
  3195. if (NULL != pbHash)
  3196. {
  3197. LocalFree(pbHash);
  3198. }
  3199. return(hr);
  3200. }
  3201. HRESULT
  3202. PKCSParseImportedCertificate(
  3203. IN DWORD Disposition,
  3204. IN ICertDBRow *prow,
  3205. OPTIONAL IN CACTX const *pCAContext,
  3206. IN CERT_CONTEXT const *pCert)
  3207. {
  3208. HRESULT hr;
  3209. CERT_INFO const *pCertInfo = pCert->pCertInfo;
  3210. DWORD dwRequestFlags = 0;
  3211. BOOL fSubjectNameSet;
  3212. HRESULT ErrCode = S_OK;
  3213. BSTR strSerialNumber = NULL;
  3214. // set raw cert property in the db
  3215. hr = prow->SetProperty(
  3216. g_wszPropRawCertificate,
  3217. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3218. pCert->cbCertEncoded,
  3219. pCert->pbCertEncoded);
  3220. _JumpIfError(hr, error, "SetProperty");
  3221. // set extensions
  3222. hr = pkcsSetExtensions(
  3223. prow,
  3224. EXTENSION_ORIGIN_IMPORTEDCERT,
  3225. pCertInfo->rgExtension,
  3226. pCertInfo->cExtension);
  3227. _JumpIfError(hr, error, "pkcsSetExtensions");
  3228. // set request name info
  3229. hr = pkcsSetRequestNameInfo(
  3230. prow,
  3231. &pCertInfo->Subject,
  3232. NULL, // pwszCNSuffix
  3233. &dwRequestFlags,
  3234. &fSubjectNameSet);
  3235. _JumpIfError(hr, error, "pkcsSetRequestNameInfo");
  3236. hr = pkcsSetPublicKeyProperties(prow, &pCertInfo->SubjectPublicKeyInfo);
  3237. _JumpIfError(hr, error, "pkcsSetPublicKeyProperties");
  3238. hr = prow->CopyRequestNames();
  3239. _JumpIfError(hr, error, "CopyRequestNames");
  3240. hr = pkcsSetCertAndKeyHashes(prow, pCert);
  3241. _JumpIfError(hr, error, "pkcsSetCertAndKeyHashes");
  3242. hr = prow->SetProperty(
  3243. g_wszPropCertificateNotBeforeDate,
  3244. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3245. sizeof(pCertInfo->NotBefore),
  3246. (BYTE *) &pCertInfo->NotBefore);
  3247. _JumpIfError(hr, error, "SetProperty");
  3248. hr = prow->SetProperty(
  3249. g_wszPropCertificateNotAfterDate,
  3250. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3251. sizeof(pCertInfo->NotAfter),
  3252. (BYTE *) &pCertInfo->NotAfter);
  3253. _JumpIfError(hr, error, "SetProperty");
  3254. hr = prow->SetProperty(
  3255. g_wszPropSubjectRawName,
  3256. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3257. pCertInfo->Subject.cbData,
  3258. pCertInfo->Subject.pbData);
  3259. _JumpIfError(hr, error, "SetProperty");
  3260. // set distinguished name
  3261. pkcsSetDistinguishedName(
  3262. prow,
  3263. PROPTABLE_CERTIFICATE,
  3264. &pCertInfo->Subject);
  3265. // set disposition issued
  3266. hr = prow->SetProperty(
  3267. g_wszPropRequestDisposition,
  3268. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3269. sizeof(Disposition),
  3270. (BYTE const *) &Disposition);
  3271. _JumpIfError(hr, error, "SetProperty(disposition)");
  3272. // set disposition status code
  3273. hr = prow->SetProperty(
  3274. g_wszPropRequestStatusCode,
  3275. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3276. sizeof(ErrCode),
  3277. (BYTE const *) &ErrCode);
  3278. _JumpIfError(hr, error, "SetProperty(status code)");
  3279. if (NULL != pCAContext)
  3280. {
  3281. hr = prow->SetProperty(
  3282. g_wszPropCertificateIssuerNameID,
  3283. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3284. sizeof(pCAContext->NameId),
  3285. (BYTE *) &pCAContext->NameId);
  3286. _JumpIfError(hr, error, "SetProperty");
  3287. }
  3288. hr = PropSetRequestTimeProperty(prow, g_wszPropRequestResolvedWhen);
  3289. _JumpIfError(hr, error, "PropSetRequestTimeProperty");
  3290. // Convert serial number to string and set in DB
  3291. hr = MultiByteIntegerToBstr(
  3292. FALSE,
  3293. pCertInfo->SerialNumber.cbData,
  3294. pCertInfo->SerialNumber.pbData,
  3295. &strSerialNumber);
  3296. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  3297. hr = prow->SetProperty(
  3298. g_wszPropCertificateSerialNumber,
  3299. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3300. MAXDWORD,
  3301. (BYTE *) strSerialNumber);
  3302. _JumpIfError(hr, error, "SetProperty");
  3303. error:
  3304. if (NULL != strSerialNumber)
  3305. {
  3306. SysFreeString(strSerialNumber);
  3307. }
  3308. return(hr);
  3309. }
  3310. // Return TRUE if Data and Cert references apply to the specified CMC message
  3311. BOOL
  3312. pkcsCMCReferenceMatch(
  3313. IN DWORD DataReference, // nested CMC message Body Part Id
  3314. IN DWORD CertReference, // PKCS10 Cert Request Body Part Id
  3315. IN DWORD dwCmcDataReference,
  3316. IN DWORD cCertReference,
  3317. IN DWORD const *rgdwCertReference)
  3318. {
  3319. BOOL fMatch = FALSE;
  3320. DWORD i;
  3321. if (MAXDWORD != DataReference && dwCmcDataReference == DataReference)
  3322. {
  3323. fMatch = TRUE;
  3324. }
  3325. else if (MAXDWORD != CertReference && 0 == dwCmcDataReference)
  3326. {
  3327. for (i = 0; i < cCertReference; i++)
  3328. {
  3329. if (rgdwCertReference[i] == CertReference)
  3330. {
  3331. fMatch = TRUE;
  3332. break;
  3333. }
  3334. }
  3335. }
  3336. return(fMatch);
  3337. }
  3338. HRESULT
  3339. pkcsSetCMCExtensions(
  3340. IN ICertDBRow *prow,
  3341. IN DWORD DataReference, // nested CMC message Body Part Id
  3342. IN DWORD CertReference, // PKCS10 Cert Request Body Part Id
  3343. IN BYTE const *pbData,
  3344. IN DWORD cbData)
  3345. {
  3346. HRESULT hr;
  3347. CMC_ADD_EXTENSIONS_INFO *pcmcExt = NULL;
  3348. DWORD cb;
  3349. // Decode CMC_ADD_EXTENSIONS_INFO from Attribute Blob
  3350. CSASSERT(NULL == pcmcExt);
  3351. if (!myDecodeObject(
  3352. X509_ASN_ENCODING,
  3353. CMC_ADD_EXTENSIONS,
  3354. pbData,
  3355. cbData,
  3356. CERTLIB_USE_LOCALALLOC,
  3357. (VOID **) &pcmcExt,
  3358. &cb))
  3359. {
  3360. hr = myHLastError();
  3361. _JumpError(hr, error, "myDecodeObject");
  3362. }
  3363. if (pkcsCMCReferenceMatch(
  3364. DataReference,
  3365. CertReference,
  3366. pcmcExt->dwCmcDataReference,
  3367. pcmcExt->cCertReference,
  3368. pcmcExt->rgdwCertReference))
  3369. {
  3370. hr = pkcsSetExtensions(
  3371. prow,
  3372. EXTENSION_ORIGIN_CMC | EXTENSION_DISABLE_FLAG,
  3373. pcmcExt->rgExtension,
  3374. pcmcExt->cExtension);
  3375. _JumpIfError(hr, error, "pkcsSetExtensions(request)");
  3376. }
  3377. hr = S_OK;
  3378. error:
  3379. if (NULL != pcmcExt)
  3380. {
  3381. LocalFree(pcmcExt);
  3382. }
  3383. return(hr);
  3384. }
  3385. HRESULT
  3386. pkcsSetCMCAttributes(
  3387. IN ICertDBRow *prow,
  3388. IN DWORD DataReference, // nested CMC message Body Part Id
  3389. IN DWORD CertReference, // PKCS10 Cert Request Body Part Id
  3390. IN BYTE const *pbData,
  3391. IN DWORD cbData,
  3392. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf,
  3393. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  3394. {
  3395. HRESULT hr;
  3396. CMC_ADD_ATTRIBUTES_INFO *pcmcAttrib = NULL;
  3397. DWORD cb;
  3398. if (NULL != pfEnrollOnBehalfOf)
  3399. {
  3400. *pfEnrollOnBehalfOf = FALSE;
  3401. }
  3402. // Decode CMC_ADD_ATTRIBUTES_INFO from Attribute Blob
  3403. CSASSERT(NULL == pcmcAttrib);
  3404. if (!myDecodeObject(
  3405. X509_ASN_ENCODING,
  3406. CMC_ADD_ATTRIBUTES,
  3407. pbData,
  3408. cbData,
  3409. CERTLIB_USE_LOCALALLOC,
  3410. (VOID **) &pcmcAttrib,
  3411. &cb))
  3412. {
  3413. hr = myHLastError();
  3414. _JumpError(hr, error, "myDecodeObject");
  3415. }
  3416. if (pkcsCMCReferenceMatch(
  3417. DataReference,
  3418. CertReference,
  3419. pcmcAttrib->dwCmcDataReference,
  3420. pcmcAttrib->cCertReference,
  3421. pcmcAttrib->rgdwCertReference))
  3422. {
  3423. hr = pkcsSetAttributes(
  3424. prow,
  3425. EXTENSION_ORIGIN_CMC,
  3426. PSA_DISALLOW_EXTENSIONS | PSA_DISALLOW_ARCHIVEDKEY,
  3427. pcmcAttrib->rgAttribute,
  3428. pcmcAttrib->cAttribute,
  3429. 0,
  3430. NULL,
  3431. pfEnrollOnBehalfOf,
  3432. pResult);
  3433. _JumpIfError(hr, error, "pkcsSetAttributes(CMC)");
  3434. }
  3435. hr = S_OK;
  3436. error:
  3437. if (NULL != pcmcAttrib)
  3438. {
  3439. LocalFree(pcmcAttrib);
  3440. }
  3441. return(hr);
  3442. }
  3443. // map "email_mail" to "email"
  3444. // map "email_*" to "*"?
  3445. // mail_firstName=Terry&mail_lastName=Cheung+CMC+Zero+2&mail_email=
  3446. // tcheung%40verisign%2Ecom&challenge=test&
  3447. HRESULT
  3448. pkcsSetCMCRegInfo(
  3449. IN ICertDBRow *prow,
  3450. IN BYTE const *pbOctet,
  3451. IN DWORD cbOctet,
  3452. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf)
  3453. {
  3454. HRESULT hr;
  3455. WCHAR *pwszRA = NULL;
  3456. if (NULL != pfEnrollOnBehalfOf)
  3457. {
  3458. *pfEnrollOnBehalfOf = FALSE;
  3459. }
  3460. hr = myDecodeCMCRegInfo(pbOctet, cbOctet, &pwszRA);
  3461. _JumpIfError(hr, error, "myDecodeCMCRegInfo");
  3462. hr = PKCSParseAttributes(
  3463. prow,
  3464. pwszRA,
  3465. TRUE,
  3466. PROPTABLE_REQUEST,
  3467. pfEnrollOnBehalfOf);
  3468. _JumpIfError(hr, error, "PKCSParseAttributes");
  3469. error:
  3470. if (NULL != pwszRA)
  3471. {
  3472. LocalFree(pwszRA);
  3473. }
  3474. return(hr);
  3475. }
  3476. HRESULT
  3477. pkcsSetTaggedAttributes(
  3478. IN ICertDBRow *prow,
  3479. IN DWORD DataReference, // nested CMC message Body Part Id
  3480. IN DWORD CertReference, // PKCS10 Cert Request Body Part Id
  3481. IN CMC_TAGGED_ATTRIBUTE const *pTaggedAttribute,
  3482. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf,
  3483. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  3484. {
  3485. HRESULT hr;
  3486. DWORD i;
  3487. CRYPT_ATTRIBUTE const *pAttribute = &pTaggedAttribute->Attribute;
  3488. DWORD cb;
  3489. BOOL fEnrollOnBehalfOf;
  3490. if (NULL != pfEnrollOnBehalfOf)
  3491. {
  3492. *pfEnrollOnBehalfOf = FALSE;
  3493. }
  3494. for (i = 0; i < pAttribute->cValue; i++)
  3495. {
  3496. if (0 == strcmp(szOID_CMC_ADD_EXTENSIONS, pAttribute->pszObjId))
  3497. {
  3498. hr = pkcsSetCMCExtensions(
  3499. prow,
  3500. DataReference,
  3501. CertReference,
  3502. pAttribute->rgValue[i].pbData,
  3503. pAttribute->rgValue[i].cbData);
  3504. _JumpIfError(hr, error, "pkcsSetCMCExtensions");
  3505. }
  3506. else
  3507. if (0 == strcmp(szOID_CMC_ADD_ATTRIBUTES, pAttribute->pszObjId))
  3508. {
  3509. fEnrollOnBehalfOf = FALSE;
  3510. hr = pkcsSetCMCAttributes(
  3511. prow,
  3512. DataReference,
  3513. CertReference,
  3514. pAttribute->rgValue[i].pbData,
  3515. pAttribute->rgValue[i].cbData,
  3516. NULL != pfEnrollOnBehalfOf? &fEnrollOnBehalfOf : NULL,
  3517. pResult);
  3518. _JumpIfError(hr, error, "pkcsSetCMCAttributes");
  3519. if (fEnrollOnBehalfOf)
  3520. {
  3521. CSASSERT(NULL != pfEnrollOnBehalfOf);
  3522. *pfEnrollOnBehalfOf = TRUE;
  3523. }
  3524. }
  3525. else
  3526. if (0 == strcmp(szOID_CMC_REG_INFO, pAttribute->pszObjId))
  3527. {
  3528. fEnrollOnBehalfOf = FALSE;
  3529. hr = pkcsSetCMCRegInfo(
  3530. prow,
  3531. pAttribute->rgValue[i].pbData,
  3532. pAttribute->rgValue[i].cbData,
  3533. NULL != pfEnrollOnBehalfOf? &fEnrollOnBehalfOf : NULL);
  3534. _JumpIfError(hr, error, "pkcsSetCMCRegInfo");
  3535. if (fEnrollOnBehalfOf)
  3536. {
  3537. CSASSERT(NULL != pfEnrollOnBehalfOf);
  3538. *pfEnrollOnBehalfOf = TRUE;
  3539. }
  3540. }
  3541. else
  3542. if (0 == strcmp(szOID_CMC_TRANSACTION_ID, pAttribute->pszObjId))
  3543. {
  3544. DWORD dwTransactionId;
  3545. cb = sizeof(dwTransactionId);
  3546. dwTransactionId = 0;
  3547. if (!CryptDecodeObject(
  3548. X509_ASN_ENCODING,
  3549. X509_INTEGER,
  3550. pAttribute->rgValue[i].pbData,
  3551. pAttribute->rgValue[i].cbData,
  3552. 0,
  3553. &dwTransactionId,
  3554. &cb))
  3555. {
  3556. hr = myHLastError();
  3557. _JumpError(hr, error, "CryptDecodeObject");
  3558. }
  3559. pResult->fTransactionId = TRUE;
  3560. pResult->dwTransactionId = dwTransactionId;
  3561. }
  3562. else
  3563. if (0 == strcmp(szOID_CMC_SENDER_NONCE, pAttribute->pszObjId))
  3564. {
  3565. CRYPT_DATA_BLOB *pBlob;
  3566. BYTE *pb;
  3567. if (!myDecodeObject(
  3568. X509_ASN_ENCODING,
  3569. X509_OCTET_STRING,
  3570. pAttribute->rgValue[i].pbData,
  3571. pAttribute->rgValue[i].cbData,
  3572. CERTLIB_USE_LOCALALLOC,
  3573. (VOID **) &pBlob,
  3574. &cb))
  3575. {
  3576. hr = myHLastError();
  3577. _JumpError(hr, error, "myDecodeObject");
  3578. }
  3579. pb = (BYTE *) LocalAlloc(LMEM_FIXED, pBlob->cbData);
  3580. if (NULL == pb)
  3581. {
  3582. hr = E_OUTOFMEMORY;
  3583. }
  3584. else
  3585. {
  3586. CopyMemory(pb, pBlob->pbData, pBlob->cbData);
  3587. if (NULL != pResult->pbSenderNonce)
  3588. {
  3589. LocalFree(pResult->pbSenderNonce);
  3590. }
  3591. pResult->pbSenderNonce = pb;
  3592. pResult->cbSenderNonce = pBlob->cbData;
  3593. hr = S_OK;
  3594. }
  3595. LocalFree(pBlob);
  3596. _JumpIfError(hr, error, "LocalAlloc");
  3597. }
  3598. else if (0 == (CRLF_IGNORE_UNKNOWN_CMC_ATTRIBUTES & g_dwCRLFlags))
  3599. {
  3600. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3601. _JumpError(hr, error, "unknown tagged attribute");
  3602. }
  3603. }
  3604. hr = S_OK;
  3605. error:
  3606. return(hr);
  3607. }
  3608. //+------------------------------------------------------------------------
  3609. // pkcsParseCMCRequest
  3610. //
  3611. // Crack a CMC request and dig the goodies out of it.
  3612. // Crack the contents of the CMC request recursively.
  3613. //-------------------------------------------------------------------------
  3614. HRESULT
  3615. pkcsParseCMCRequest(
  3616. IN ICertDBRow *prow,
  3617. IN DWORD cbIn,
  3618. IN BYTE const *pbIn,
  3619. OPTIONAL IN CERT_CONTEXT const *pCertSigner,
  3620. OPTIONAL OUT BOOL *pfRenewal,
  3621. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf,
  3622. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  3623. {
  3624. HRESULT hr;
  3625. DWORD cb;
  3626. CMC_DATA_INFO const *pcmcData = NULL;
  3627. DWORD i;
  3628. DWORD DataReference = MAXDWORD; // nested CMC message Body Part Id
  3629. DWORD CertReference = MAXDWORD; // PKCS10 Cert Request Body Part Id
  3630. if (NULL != pfRenewal)
  3631. {
  3632. *pfRenewal = FALSE;
  3633. }
  3634. if (NULL != pfEnrollOnBehalfOf)
  3635. {
  3636. *pfEnrollOnBehalfOf = FALSE;
  3637. }
  3638. if (!myDecodeObject(
  3639. X509_ASN_ENCODING,
  3640. CMC_DATA,
  3641. pbIn,
  3642. cbIn,
  3643. CERTLIB_USE_LOCALALLOC,
  3644. (VOID **) &pcmcData,
  3645. &cb))
  3646. {
  3647. hr = myHLastError();
  3648. _JumpError(hr, error, "myDecodeObject");
  3649. }
  3650. if (0 != pcmcData->cTaggedOtherMsg)
  3651. {
  3652. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3653. _JumpError(hr, error, "unknown other message");
  3654. }
  3655. // Process nested CMC messages
  3656. if (0 != pcmcData->cTaggedContentInfo)
  3657. {
  3658. CMC_TAGGED_CONTENT_INFO const *pTaggedContentInfo;
  3659. // Only handle one CMC message at a time for now.
  3660. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3661. if (1 < pcmcData->cTaggedContentInfo)
  3662. {
  3663. _JumpError(hr, error, "multiple nested CMC messages");
  3664. }
  3665. // Disallow CMC message recursion below a PKCS10 request.
  3666. if (0 != pcmcData->cTaggedRequest)
  3667. {
  3668. _JumpError(hr, error, "recursion below PKCS10 request");
  3669. }
  3670. // Recurse on the nested CMC message
  3671. pTaggedContentInfo = &pcmcData->rgTaggedContentInfo[0];
  3672. hr = PKCSParseRequest(
  3673. CR_IN_CMC | (~CR_IN_FORMATMASK & pResult->dwFlagsTop),
  3674. prow,
  3675. pTaggedContentInfo->EncodedContentInfo.cbData,
  3676. pTaggedContentInfo->EncodedContentInfo.pbData,
  3677. pCertSigner,
  3678. pfRenewal,
  3679. pResult);
  3680. _JumpIfError(hr, error, "PKCSParseRequest");
  3681. DataReference = pTaggedContentInfo->dwBodyPartID;
  3682. }
  3683. // Process nested PKCS10 requests
  3684. if (0 != pcmcData->cTaggedRequest)
  3685. {
  3686. CMC_TAGGED_REQUEST const *pTaggedRequest;
  3687. CMC_TAGGED_CERT_REQUEST const *pTaggedCertRequest;
  3688. // Only handle one request at a time for now.
  3689. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3690. if (1 < pcmcData->cTaggedRequest)
  3691. {
  3692. _JumpError(hr, error, "multiple PKCS10 requests");
  3693. }
  3694. pTaggedRequest = &pcmcData->rgTaggedRequest[0];
  3695. // The request must be a PKCS10 request
  3696. if (CMC_TAGGED_CERT_REQUEST_CHOICE !=
  3697. pTaggedRequest->dwTaggedRequestChoice)
  3698. {
  3699. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3700. _JumpError(hr, error, "recursion below PKCS10 request");
  3701. }
  3702. pTaggedCertRequest = pTaggedRequest->pTaggedCertRequest;
  3703. hr = PKCSParseRequest(
  3704. CR_IN_PKCS10 | (~CR_IN_FORMATMASK & pResult->dwFlagsTop),
  3705. prow,
  3706. pTaggedCertRequest->SignedCertRequest.cbData,
  3707. pTaggedCertRequest->SignedCertRequest.pbData,
  3708. pCertSigner,
  3709. pfRenewal,
  3710. pResult);
  3711. _JumpIfError(hr, error, "PKCSParseRequest");
  3712. CertReference = pTaggedCertRequest->dwBodyPartID;
  3713. }
  3714. // Process extensions and attributes
  3715. for (i = 0; i < pcmcData->cTaggedAttribute; i++)
  3716. {
  3717. hr = pkcsSetTaggedAttributes(
  3718. prow,
  3719. DataReference,
  3720. CertReference,
  3721. &pcmcData->rgTaggedAttribute[i],
  3722. pfEnrollOnBehalfOf,
  3723. pResult);
  3724. _JumpIfError(hr, error, "pkcsSetTaggedAttributes");
  3725. }
  3726. hr = S_OK;
  3727. error:
  3728. if (NULL != pcmcData)
  3729. {
  3730. LocalFree((VOID *) pcmcData);
  3731. }
  3732. return(hr);
  3733. }
  3734. HRESULT
  3735. pkcsAppendPolicies(
  3736. IN ICertDBRow *prow,
  3737. IN WCHAR const *pwszPropName,
  3738. OPTIONAL IN WCHAR const *pwszzPolicies)
  3739. {
  3740. HRESULT hr;
  3741. WCHAR *pwszOld = NULL;
  3742. WCHAR *pwszNew = NULL;
  3743. WCHAR const *pwszIn;
  3744. WCHAR *pwsz;
  3745. DWORD cwc = 0;
  3746. DWORD cb;
  3747. hr = PKCSGetProperty(
  3748. prow,
  3749. pwszPropName,
  3750. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3751. &cb,
  3752. (BYTE **) &pwszOld);
  3753. _PrintIfError2(hr, "PKCSGetProperty", hr);
  3754. if (S_OK != hr)
  3755. {
  3756. pwszOld = NULL;
  3757. }
  3758. if (NULL != pwszOld)
  3759. {
  3760. cwc = wcslen(pwszOld) + 1; // allow for \n separator
  3761. }
  3762. if (NULL == pwszzPolicies || L'\0' == *pwszzPolicies)
  3763. {
  3764. pwszzPolicies = L"-\0";
  3765. }
  3766. for (pwszIn = pwszzPolicies; L'\0' != *pwszIn; pwszIn += wcslen(pwszIn) + 1)
  3767. ;
  3768. cwc += SAFE_SUBTRACT_POINTERS(pwszIn, pwszzPolicies);
  3769. pwszNew = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  3770. if (NULL == pwszNew)
  3771. {
  3772. hr = E_OUTOFMEMORY;
  3773. _JumpError(hr, error, "LocalAlloc");
  3774. }
  3775. pwsz = pwszNew;
  3776. if (NULL != pwszOld)
  3777. {
  3778. wcscpy(pwsz, pwszOld);
  3779. pwsz += wcslen(pwsz);
  3780. wcscpy(pwsz, L"\n");
  3781. pwsz++;
  3782. }
  3783. for (pwszIn = pwszzPolicies; L'\0' != *pwszIn; pwszIn += wcslen(pwszIn) + 1)
  3784. {
  3785. if (pwszIn != pwszzPolicies)
  3786. {
  3787. wcscpy(pwsz, L",");
  3788. pwsz++;
  3789. }
  3790. wcscpy(pwsz, pwszIn);
  3791. pwsz += wcslen(pwsz);
  3792. }
  3793. CSASSERT(&pwsz[1] == &pwszNew[cwc]);
  3794. hr = prow->SetProperty(
  3795. pwszPropName,
  3796. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3797. MAXDWORD,
  3798. (BYTE const *) pwszNew);
  3799. _JumpIfError(hr, error, "SetProperty");
  3800. error:
  3801. if (NULL != pwszOld)
  3802. {
  3803. LocalFree(pwszOld);
  3804. }
  3805. if (NULL != pwszNew)
  3806. {
  3807. LocalFree(pwszNew);
  3808. }
  3809. return(hr);
  3810. }
  3811. //+------------------------------------------------------------------------
  3812. // pkcsParsePKCS7Request
  3813. //
  3814. // Crack a PKCS7 and dig the goodies out of it.
  3815. // Verify the signature of the 7 against the cert given in the 7.
  3816. // Crack the contents of the 7 recursively.
  3817. //-------------------------------------------------------------------------
  3818. HRESULT
  3819. pkcsParsePKCS7Request(
  3820. IN BOOL fTopLevel,
  3821. IN DWORD dwFlags,
  3822. IN ICertDBRow *prow,
  3823. IN DWORD cbIn,
  3824. IN BYTE const *pbIn,
  3825. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  3826. {
  3827. HRESULT hr;
  3828. BYTE *pbContents = NULL;
  3829. DWORD cbContents;
  3830. CERT_CONTEXT const *pCertSigner = NULL;
  3831. HCERTSTORE hStore = NULL;
  3832. HCRYPTMSG hMsg = NULL;
  3833. char *pszInnerContentObjId = NULL;
  3834. DWORD i;
  3835. BOOL fCMC;
  3836. BOOL fRenewal = FALSE;
  3837. DWORD cbAttrib;
  3838. char *apszEnrollOids[] = {szOID_ENROLLMENT_AGENT};
  3839. DWORD dwVerifyContextFlags;
  3840. DWORD dwMsgType;
  3841. DWORD cSigner;
  3842. DWORD cFirstSigner;
  3843. BOOL fFirstSigner;
  3844. DWORD cRecipient;
  3845. DWORD cb;
  3846. CMSG_CMS_SIGNER_INFO *pcsi = NULL;
  3847. DWORD dwDisallowFlags;
  3848. DWORD iElement;
  3849. WCHAR *pwszzIssuancePolicies = NULL;
  3850. WCHAR *pwszzApplicationPolicies = NULL;
  3851. CERT_REQUEST_INFO *pRequest = NULL;
  3852. BOOL fEnrollOnBehalfOf;
  3853. CSASSERT(
  3854. CR_IN_PKCS7 == (CR_IN_FORMATMASK & dwFlags) ||
  3855. CR_IN_CMC == (CR_IN_FORMATMASK & dwFlags));
  3856. // Crack the 7 and verify the signature.
  3857. hr = myDecodePKCS7(
  3858. pbIn,
  3859. cbIn,
  3860. &pbContents,
  3861. &cbContents,
  3862. &dwMsgType,
  3863. &pszInnerContentObjId,
  3864. &cSigner,
  3865. &cRecipient,
  3866. &hStore,
  3867. &hMsg);
  3868. _JumpIfError(hr, error, "myDecodePKCS7");
  3869. if (CMSG_SIGNED != dwMsgType || 0 == cSigner)
  3870. {
  3871. hr = CRYPT_E_NO_SIGNER;
  3872. _JumpIfError(hr, error, "myDecodePKCS7(no signing cert)");
  3873. }
  3874. #define szOID_CT_PKI_DATA_OLDRFC "1.3.6.1.5.5.7.5.2" // BUGBUG: temporary!
  3875. fCMC = NULL != pszInnerContentObjId &&
  3876. (0 == strcmp(pszInnerContentObjId, szOID_CT_PKI_DATA) ||
  3877. (0 == strcmp(pszInnerContentObjId, szOID_CT_PKI_DATA_OLDRFC) &&
  3878. (CRLF_ACCEPT_OLDRFC_CMC & g_dwCRLFlags)));
  3879. // Decode the contents.
  3880. if (fCMC)
  3881. {
  3882. if (CR_IN_CMC != (CR_IN_FORMATMASK & dwFlags))
  3883. {
  3884. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3885. _JumpError(hr, error, "dwFlags");
  3886. }
  3887. // CMC renewal requests may have one 'first' signer (non-NULL KeyId or
  3888. // Dummy signer) and one additional Issuer+Serial signer. If the
  3889. // request has the appropriate signatures, pass the cert to the lowest
  3890. // level to see if it really is a renewal request.
  3891. if (1 <= cSigner && 2 >= cSigner)
  3892. {
  3893. DWORD iCertSigner = MAXDWORD;
  3894. cFirstSigner = 0;
  3895. for (i = 0; i < cSigner; i++)
  3896. {
  3897. if (NULL != pcsi)
  3898. {
  3899. LocalFree(pcsi);
  3900. pcsi = NULL;
  3901. }
  3902. hr = myCryptMsgGetParam(
  3903. hMsg,
  3904. CMSG_CMS_SIGNER_INFO_PARAM,
  3905. i,
  3906. CERTLIB_USE_LOCALALLOC,
  3907. (VOID **) &pcsi,
  3908. &cb);
  3909. _JumpIfError(hr, error, "myCryptMsgGetParam");
  3910. fFirstSigner = FALSE;
  3911. if (CERT_ID_KEY_IDENTIFIER == pcsi->SignerId.dwIdChoice ||
  3912. (NULL != pcsi->HashEncryptionAlgorithm.pszObjId &&
  3913. 0 == strcmp(
  3914. szOID_PKIX_NO_SIGNATURE,
  3915. pcsi->HashEncryptionAlgorithm.pszObjId)))
  3916. {
  3917. fFirstSigner = TRUE;
  3918. }
  3919. else if ((CRLF_ACCEPT_OLDRFC_CMC & g_dwCRLFlags) &&
  3920. CERT_ID_ISSUER_SERIAL_NUMBER == pcsi->SignerId.dwIdChoice)
  3921. {
  3922. hr = myIsFirstSigner(
  3923. &pcsi->SignerId.IssuerSerialNumber.Issuer,
  3924. &fFirstSigner);
  3925. _JumpIfError(hr, error, "myIsFirstSigner");
  3926. }
  3927. if (fFirstSigner)
  3928. {
  3929. cFirstSigner++;
  3930. }
  3931. else
  3932. {
  3933. if (MAXDWORD != iCertSigner)
  3934. {
  3935. iCertSigner = MAXDWORD; // must not be a renewal
  3936. break;
  3937. }
  3938. iCertSigner = i;
  3939. }
  3940. }
  3941. if (MAXDWORD != iCertSigner && 1 >= cFirstSigner)
  3942. {
  3943. iElement = iCertSigner;
  3944. if (!CryptMsgGetAndVerifySigner(
  3945. hMsg,
  3946. 0, // cSignerStore
  3947. NULL, // rghSignerStore
  3948. CMSG_USE_SIGNER_INDEX_FLAG,
  3949. &pCertSigner,
  3950. &iElement))
  3951. {
  3952. hr = myHLastError();
  3953. _JumpError(hr, error, "CryptMsgGetAndVerifySigner");
  3954. }
  3955. }
  3956. }
  3957. fEnrollOnBehalfOf = FALSE;
  3958. hr = pkcsParseCMCRequest(
  3959. prow,
  3960. cbContents,
  3961. pbContents,
  3962. pCertSigner,
  3963. &fRenewal,
  3964. &fEnrollOnBehalfOf,
  3965. pResult);
  3966. _JumpIfError(hr, error, "pkcsParseCMCRequest");
  3967. if (fEnrollOnBehalfOf)
  3968. {
  3969. pResult->fEnrollOnBehalfOf = TRUE;
  3970. }
  3971. if (0 == strcmp(pszInnerContentObjId, szOID_CT_PKI_DATA_OLDRFC))
  3972. {
  3973. hr = PKCSSetRequestFlags(prow, TRUE, CR_FLG_OLDRFCCMC);
  3974. _JumpIfError(hr, error, "PKCSSetRequestFlags");
  3975. }
  3976. }
  3977. else
  3978. {
  3979. if (CR_IN_PKCS7 != (CR_IN_FORMATMASK & dwFlags))
  3980. {
  3981. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3982. _JumpError(hr, error, "dwFlags");
  3983. }
  3984. // Expect only one signer for PKCS7 renewal requests. Pass the cert
  3985. // to the lowest level to see if it really is a renewal request.
  3986. iElement = 0;
  3987. if (!CryptMsgGetAndVerifySigner(
  3988. hMsg,
  3989. 0, // cSignerStore
  3990. NULL, // rghSignerStore
  3991. CMSG_USE_SIGNER_INDEX_FLAG,
  3992. &pCertSigner,
  3993. &iElement))
  3994. {
  3995. hr = myHLastError();
  3996. _JumpError(hr, error, "CryptMsgGetAndVerifySigner");
  3997. }
  3998. hr = PKCSParseRequest(
  3999. CR_IN_FORMATANY | (~CR_IN_FORMATMASK & pResult->dwFlagsTop),
  4000. prow,
  4001. cbContents,
  4002. pbContents,
  4003. pCertSigner,
  4004. &fRenewal,
  4005. pResult);
  4006. _JumpIfError(hr, error, "PKCSParseRequest");
  4007. }
  4008. // Loop through the signers, verifying signatures and saving attributes.
  4009. cFirstSigner = 0;
  4010. for (i = 0; i < cSigner; i++)
  4011. {
  4012. BOOL fNTAuth;
  4013. BOOL fEnrollOnBehalfOf;
  4014. if (NULL != pcsi)
  4015. {
  4016. LocalFree(pcsi);
  4017. pcsi = NULL;
  4018. }
  4019. if (NULL != pwszzIssuancePolicies)
  4020. {
  4021. LocalFree(pwszzIssuancePolicies);
  4022. pwszzIssuancePolicies = NULL;
  4023. }
  4024. if (NULL != pwszzApplicationPolicies)
  4025. {
  4026. LocalFree(pwszzApplicationPolicies);
  4027. pwszzApplicationPolicies = NULL;
  4028. }
  4029. if (NULL != pCertSigner)
  4030. {
  4031. CertFreeCertificateContext(pCertSigner);
  4032. pCertSigner = NULL;
  4033. }
  4034. hr = myCryptMsgGetParam(
  4035. hMsg,
  4036. CMSG_CMS_SIGNER_INFO_PARAM,
  4037. i,
  4038. CERTLIB_USE_LOCALALLOC,
  4039. (VOID **) &pcsi,
  4040. &cb);
  4041. _JumpIfError(hr, error, "myCryptMsgGetParam");
  4042. fFirstSigner = FALSE;
  4043. if (fCMC &&
  4044. (CERT_ID_KEY_IDENTIFIER == pcsi->SignerId.dwIdChoice ||
  4045. (NULL != pcsi->HashEncryptionAlgorithm.pszObjId &&
  4046. 0 == strcmp(
  4047. szOID_PKIX_NO_SIGNATURE,
  4048. pcsi->HashEncryptionAlgorithm.pszObjId))))
  4049. {
  4050. CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA cvse;
  4051. fFirstSigner = TRUE;
  4052. ZeroMemory(&cvse, sizeof(cvse));
  4053. cvse.cbSize = sizeof(cvse);
  4054. cvse.dwSignerIndex = i;
  4055. if (CERT_ID_KEY_IDENTIFIER == pcsi->SignerId.dwIdChoice)
  4056. {
  4057. if (NULL == pRequest)
  4058. {
  4059. hr = myGetInnerPKCS10(
  4060. hMsg,
  4061. pszInnerContentObjId,
  4062. &pRequest);
  4063. _JumpIfError(hr, error, "myGetInnerPKCS10");
  4064. }
  4065. cvse.dwSignerType = CMSG_VERIFY_SIGNER_PUBKEY;
  4066. cvse.pvSigner = &pRequest->SubjectPublicKeyInfo;
  4067. }
  4068. else
  4069. {
  4070. cvse.dwSignerType = CMSG_VERIFY_SIGNER_NULL;
  4071. }
  4072. if (!CryptMsgControl(
  4073. hMsg,
  4074. 0, // dwFlags
  4075. CMSG_CTRL_VERIFY_SIGNATURE_EX,
  4076. &cvse))
  4077. {
  4078. hr = myHLastError();
  4079. _JumpError(hr, error, "CryptMsgControl(VerifySig)");
  4080. }
  4081. }
  4082. else
  4083. {
  4084. if (fCMC &&
  4085. (CRLF_ACCEPT_OLDRFC_CMC & g_dwCRLFlags) &&
  4086. CERT_ID_ISSUER_SERIAL_NUMBER == pcsi->SignerId.dwIdChoice)
  4087. {
  4088. hr = myIsFirstSigner(
  4089. &pcsi->SignerId.IssuerSerialNumber.Issuer,
  4090. &fFirstSigner);
  4091. _JumpIfError(hr, error, "myIsFirstSigner");
  4092. }
  4093. iElement = i;
  4094. if (!CryptMsgGetAndVerifySigner(
  4095. hMsg,
  4096. 0, // cSignerStore
  4097. NULL, // rghSignerStore
  4098. CMSG_USE_SIGNER_INDEX_FLAG,
  4099. &pCertSigner,
  4100. &iElement))
  4101. {
  4102. hr = myHLastError();
  4103. _JumpError(hr, error, "CryptMsgGetAndVerifySigner");
  4104. }
  4105. }
  4106. // Only enroll-on-behalf-of requests may contain Name, Value pairs.
  4107. // Only enroll-on-behalf-of requests and renewal requests may contain
  4108. // certificate extensions.
  4109. dwDisallowFlags = PSA_DISALLOW_ARCHIVEDKEY;
  4110. if (fRenewal)
  4111. {
  4112. dwDisallowFlags |= PSA_DISALLOW_NAMEVALUEPAIRS;
  4113. }
  4114. if (fCMC)
  4115. {
  4116. dwDisallowFlags |= PSA_DISALLOW_EXTENSIONS |
  4117. PSA_DISALLOW_NAMEVALUEPAIRS;
  4118. }
  4119. fEnrollOnBehalfOf = FALSE;
  4120. hr = pkcsSetAttributes(
  4121. prow,
  4122. EXTENSION_ORIGIN_PKCS7,
  4123. dwDisallowFlags,
  4124. pcsi->AuthAttrs.rgAttr,
  4125. pcsi->AuthAttrs.cAttr,
  4126. 0,
  4127. NULL,
  4128. &fEnrollOnBehalfOf,
  4129. pResult);
  4130. _JumpIfError(hr, error, "pkcsSetAttributes(Authenticated)");
  4131. if (fEnrollOnBehalfOf)
  4132. {
  4133. pResult->fEnrollOnBehalfOf = TRUE;
  4134. }
  4135. // Pull encrypted private key out of unauthenticated attributes
  4136. hr = pkcsSetAttributes(
  4137. prow,
  4138. EXTENSION_ORIGIN_PKCS7,
  4139. ((fTopLevel && fFirstSigner)? 0 : PSA_DISALLOW_ARCHIVEDKEY) |
  4140. PSA_DISALLOW_EXTENSIONS |
  4141. PSA_DISALLOW_NAMEVALUEPAIRS,
  4142. pcsi->UnauthAttrs.rgAttr,
  4143. pcsi->UnauthAttrs.cAttr,
  4144. cbIn,
  4145. fTopLevel? pbIn : NULL,
  4146. NULL,
  4147. pResult);
  4148. _JumpIfError(hr, error, "pkcsSetAttributes(UNauthenticated)");
  4149. if (fFirstSigner)
  4150. {
  4151. cFirstSigner++;
  4152. }
  4153. else
  4154. {
  4155. // This is a renewal request, an enroll-on-behalf-of request, a CMC
  4156. // request or just a request inside a PKCS 7 -- verify the cert
  4157. // chain for all signers. If enroll-on-behalf-of on an Enterprise
  4158. // CA (if requester name is set in the authenticated attributes),
  4159. // check the signing cert via NTAuth policy and check for
  4160. // szOID_ENROLLMENT_AGENT usage. NtAuth verification was added to
  4161. // control the ability of enroll-on-behalf agents to add usernames
  4162. // to the PKCS7 wrapper.
  4163. fNTAuth = pResult->fEnrollOnBehalfOf && IsEnterpriseCA(g_CAType);
  4164. dwVerifyContextFlags = 0;
  4165. if (CRLF_REVCHECK_IGNORE_OFFLINE & g_dwCRLFlags)
  4166. {
  4167. dwVerifyContextFlags |= CA_VERIFY_FLAGS_IGNORE_OFFLINE;
  4168. }
  4169. if (fNTAuth)
  4170. {
  4171. dwVerifyContextFlags |= CA_VERIFY_FLAGS_NT_AUTH;
  4172. }
  4173. hr = myVerifyCertContextEx(
  4174. pCertSigner,
  4175. dwVerifyContextFlags,
  4176. (DWORD)(fNTAuth? ARRAYSIZE(apszEnrollOids) : 0),
  4177. fNTAuth? apszEnrollOids : NULL,
  4178. HCCE_LOCAL_MACHINE, // hChainEngine
  4179. NULL, // pft
  4180. hStore, // hAdditionalStore
  4181. NULL, // ppwszMissingIssuer
  4182. &pwszzIssuancePolicies,
  4183. &pwszzApplicationPolicies);
  4184. _JumpIfError(hr, error, "myVerifyCertContextEx");
  4185. if (fTopLevel)
  4186. {
  4187. // save Issuance Policies
  4188. hr = pkcsAppendPolicies(
  4189. prow,
  4190. wszPROPSIGNERPOLICIES,
  4191. pwszzIssuancePolicies);
  4192. _JumpIfError(hr, error, "pkcsAppendPolicies");
  4193. // save Application Policies
  4194. hr = pkcsAppendPolicies(
  4195. prow,
  4196. wszPROPSIGNERAPPLICATIONPOLICIES,
  4197. pwszzApplicationPolicies);
  4198. _JumpIfError(hr, error, "pkcsAppendPolicies");
  4199. }
  4200. }
  4201. }
  4202. if (pResult->fEnrollOnBehalfOf)
  4203. {
  4204. hr = PKCSSetRequestFlags(prow, TRUE, CR_FLG_ENROLLONBEHALFOF);
  4205. _JumpIfError(hr, error, "PKCSSetRequestFlags");
  4206. if (fCMC && cSigner == cFirstSigner)
  4207. {
  4208. hr = CRYPT_E_NO_TRUSTED_SIGNER;
  4209. _JumpError(hr, error, "No NTAuth signer");
  4210. }
  4211. }
  4212. if ((fCMC && 1 < cFirstSigner) || (!fCMC && 0 < cFirstSigner))
  4213. {
  4214. hr = NTE_BAD_SIGNATURE;
  4215. _JumpError(hr, error, "cFirstSigner");
  4216. }
  4217. error:
  4218. if (NULL != pRequest)
  4219. {
  4220. LocalFree(pRequest);
  4221. }
  4222. if (NULL != pcsi)
  4223. {
  4224. LocalFree(pcsi);
  4225. }
  4226. if (NULL != pwszzIssuancePolicies)
  4227. {
  4228. LocalFree(pwszzIssuancePolicies);
  4229. }
  4230. if (NULL != pwszzApplicationPolicies)
  4231. {
  4232. LocalFree(pwszzApplicationPolicies);
  4233. }
  4234. if (NULL != hMsg)
  4235. {
  4236. CryptMsgClose(hMsg);
  4237. }
  4238. if (NULL != pCertSigner)
  4239. {
  4240. CertFreeCertificateContext(pCertSigner);
  4241. }
  4242. if (NULL != hStore)
  4243. {
  4244. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  4245. }
  4246. if (NULL != pbContents)
  4247. {
  4248. LocalFree(pbContents);
  4249. }
  4250. if (NULL != pszInnerContentObjId)
  4251. {
  4252. LocalFree(pszInnerContentObjId);
  4253. }
  4254. return(hr);
  4255. }
  4256. typedef struct _REQUESTFORMATS
  4257. {
  4258. char const *pszFormat;
  4259. DWORD dwFlags;
  4260. } REQUESTFORMATS;
  4261. REQUESTFORMATS g_arf[] = {
  4262. { X509_CERT_REQUEST_TO_BE_SIGNED, CR_IN_PKCS10 },
  4263. { X509_KEYGEN_REQUEST_TO_BE_SIGNED, CR_IN_KEYGEN },
  4264. };
  4265. #define CREQUESTFORMATS ARRAYSIZE(g_arf)
  4266. HRESULT
  4267. pkcsCrackRequestType(
  4268. IN DWORD cbRequest,
  4269. IN BYTE const *pbRequest,
  4270. OUT DWORD *pdwFlags)
  4271. {
  4272. HRESULT hr;
  4273. DWORD cb;
  4274. BYTE *pbDecoded = NULL;
  4275. REQUESTFORMATS const *prf;
  4276. REQUESTFORMATS const *prfEnd;
  4277. HCRYPTMSG hMsg = NULL;
  4278. char *pszInnerContentObjId = NULL;
  4279. prfEnd = &g_arf[CREQUESTFORMATS];
  4280. for (prf = g_arf; prf < prfEnd; prf++)
  4281. {
  4282. CSASSERT(NULL == pbDecoded);
  4283. if (myDecodeObject(
  4284. X509_ASN_ENCODING,
  4285. prf->pszFormat,
  4286. pbRequest,
  4287. cbRequest,
  4288. CERTLIB_USE_LOCALALLOC,
  4289. (VOID **) &pbDecoded,
  4290. &cb))
  4291. {
  4292. *pdwFlags = prf->dwFlags;
  4293. break;
  4294. }
  4295. hr = myHLastError();
  4296. CSASSERT(S_OK != hr);
  4297. }
  4298. if (prf >= prfEnd)
  4299. {
  4300. CSASSERT(S_OK != hr);
  4301. hr = myDecodePKCS7(
  4302. pbRequest,
  4303. cbRequest,
  4304. NULL, // ppbContents
  4305. NULL, // pcbContents
  4306. NULL, // pdwMsgType
  4307. &pszInnerContentObjId,
  4308. NULL, // pcSigner
  4309. NULL, // pcRecipient
  4310. NULL, // phStore
  4311. &hMsg);
  4312. _JumpIfError(hr, error, "myDecodePKCS7");
  4313. *pdwFlags = CR_IN_PKCS7; // default to renewal
  4314. if (NULL != pszInnerContentObjId &&
  4315. (0 == strcmp(pszInnerContentObjId, szOID_CT_PKI_DATA) ||
  4316. 0 == strcmp(pszInnerContentObjId, szOID_CT_PKI_DATA_OLDRFC)))
  4317. {
  4318. *pdwFlags = CR_IN_CMC;
  4319. }
  4320. }
  4321. hr = S_OK;
  4322. error:
  4323. if (NULL != hMsg)
  4324. {
  4325. CryptMsgClose(hMsg);
  4326. }
  4327. if (NULL != pszInnerContentObjId)
  4328. {
  4329. LocalFree(pszInnerContentObjId);
  4330. }
  4331. if (NULL != pbDecoded)
  4332. {
  4333. LocalFree(pbDecoded);
  4334. }
  4335. return(hr);
  4336. }
  4337. HRESULT
  4338. PKCSParseRequest(
  4339. IN DWORD dwFlags,
  4340. IN ICertDBRow *prow,
  4341. IN DWORD cbRequest,
  4342. IN BYTE const *pbRequest,
  4343. IN CERT_CONTEXT const *pSigningAuthority,
  4344. OPTIONAL OUT BOOL *pfRenewal,
  4345. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  4346. {
  4347. HRESULT hr;
  4348. if (NULL != pfRenewal)
  4349. {
  4350. *pfRenewal = FALSE;
  4351. }
  4352. if (CR_IN_FORMATANY == (CR_IN_FORMATMASK & dwFlags))
  4353. {
  4354. hr = pkcsCrackRequestType(cbRequest, pbRequest, &dwFlags);
  4355. _JumpIfError(hr, error, "pkcsCrackRequestType");
  4356. dwFlags |= ~CR_IN_FORMATMASK & pResult->dwFlagsTop;
  4357. // If this is the top level caller, store a more specific request type:
  4358. if (NULL == pfRenewal)
  4359. {
  4360. pResult->dwFlagsTop = dwFlags;
  4361. hr = prow->SetProperty(
  4362. g_wszPropRequestType,
  4363. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  4364. sizeof(dwFlags),
  4365. (BYTE const *) &dwFlags);
  4366. _JumpIfError(hr, error, "SetProperty(reqtype)");
  4367. }
  4368. }
  4369. switch (CR_IN_FORMATMASK & dwFlags)
  4370. {
  4371. case CR_IN_PKCS10:
  4372. hr = pkcsParsePKCS10Request(
  4373. dwFlags,
  4374. prow,
  4375. cbRequest,
  4376. pbRequest,
  4377. pSigningAuthority,
  4378. pfRenewal,
  4379. pResult);
  4380. _JumpIfError(hr, error, "pkcsParsePKCS10Request");
  4381. break;
  4382. case CR_IN_KEYGEN:
  4383. hr = pkcsParseKeyGenRequest(
  4384. dwFlags,
  4385. prow,
  4386. cbRequest,
  4387. pbRequest,
  4388. pResult);
  4389. _JumpIfError(hr, error, "pkcsParseKeyGenRequest");
  4390. break;
  4391. case CR_IN_CMC:
  4392. case CR_IN_PKCS7:
  4393. // PKCS7 requests can either be an 'enroll on behalf of', renewal
  4394. // request or a CMC request. We need to recursively unwrap it to
  4395. // process it.
  4396. hr = pkcsParsePKCS7Request(
  4397. NULL == pfRenewal, // fTopLevel
  4398. dwFlags,
  4399. prow,
  4400. cbRequest,
  4401. pbRequest,
  4402. pResult);
  4403. _JumpIfError(hr, error, "pkcsParsePKCS7Request");
  4404. break;
  4405. default:
  4406. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4407. _JumpError(hr, error, "dwFlags");
  4408. }
  4409. error:
  4410. if (NULL == pfRenewal)
  4411. {
  4412. HRESULT hr2;
  4413. DWORD cbData;
  4414. hr2 = prow->GetProperty(
  4415. g_wszPropRequestRawRequest,
  4416. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  4417. &cbData,
  4418. NULL);
  4419. if (S_OK != hr2)
  4420. {
  4421. hr2 = prow->SetProperty(
  4422. g_wszPropRequestRawRequest,
  4423. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  4424. cbRequest,
  4425. pbRequest);
  4426. _PrintIfError(hr2, "SetProperty(request)");
  4427. if (S_OK == hr)
  4428. {
  4429. hr = hr2;
  4430. }
  4431. }
  4432. }
  4433. return(hr);
  4434. }
  4435. HRESULT
  4436. PKCSGetCRLList(
  4437. IN BOOL fDelta,
  4438. IN DWORD iCert,
  4439. OUT WCHAR const * const **ppapwszCRLList)
  4440. {
  4441. HRESULT hr = E_INVALIDARG;
  4442. *ppapwszCRLList = NULL;
  4443. if (iCert < g_cCACerts)
  4444. {
  4445. CACTX *pCAContext = &g_aCAContext[iCert];
  4446. if (NULL == pCAContext->pccCA)
  4447. {
  4448. hr = S_FALSE;
  4449. goto error;
  4450. }
  4451. *ppapwszCRLList = fDelta?
  4452. pCAContext->papwszDeltaCRLFiles :
  4453. pCAContext->papwszCRLFiles;
  4454. if (NULL != *ppapwszCRLList)
  4455. {
  4456. hr = S_OK;
  4457. }
  4458. }
  4459. error:
  4460. return(hr);
  4461. }
  4462. HRESULT
  4463. pkcsBuildCRLList(
  4464. IN BOOL fDelta,
  4465. IN OUT CACTX *pCAContext,
  4466. OUT WCHAR ***ppapwszOut)
  4467. {
  4468. HRESULT hr;
  4469. DWORD cFiles;
  4470. CSURLTEMPLATE const *pTemplate;
  4471. CSURLTEMPLATE const *pTemplateEnd;
  4472. cFiles = 0;
  4473. pTemplateEnd = &g_paRevURL[g_caRevURL];
  4474. for (pTemplate = g_paRevURL; pTemplate < pTemplateEnd; pTemplate++)
  4475. {
  4476. if (CSURL_SERVERPUBLISH & pTemplate->Flags)
  4477. {
  4478. cFiles++;
  4479. }
  4480. }
  4481. *ppapwszOut = (WCHAR **) LocalAlloc(
  4482. LMEM_FIXED | LMEM_ZEROINIT,
  4483. (cFiles + 1) * sizeof((*ppapwszOut)[0]));
  4484. if (NULL == *ppapwszOut)
  4485. {
  4486. hr = E_OUTOFMEMORY;
  4487. _JumpError(hr, error, "LocalAlloc");
  4488. }
  4489. DBGPRINT((
  4490. DBG_SS_CERTSRVI,
  4491. "CRLList alloc[%u] = %x @%x\n",
  4492. cFiles,
  4493. *ppapwszOut,
  4494. ppapwszOut));
  4495. CSASSERT(NULL != g_strDomainDN && NULL != g_strConfigDN);
  4496. cFiles = 0;
  4497. for (pTemplate = g_paRevURL; pTemplate < pTemplateEnd; pTemplate++)
  4498. {
  4499. if (CSURL_SERVERPUBLISH & pTemplate->Flags)
  4500. {
  4501. hr = myFormatCertsrvStringArray(
  4502. FALSE, // fURL
  4503. g_pwszServerName, // pwszServerName_p1_2
  4504. g_wszSanitizedName, // pwszSanitizedName_p3_7
  4505. pCAContext->iKey, // iCert_p4 -- use iKey!!
  4506. g_strDomainDN, // pwszDomainDN_p5
  4507. g_strConfigDN, // pwszConfigDN_p6
  4508. pCAContext->iKey, // iCRL_p8
  4509. fDelta, // fDeltaCRL_p9
  4510. FALSE, // fDSAttrib_p10_11
  4511. 1, // cStrings
  4512. (LPCWSTR *) &pTemplate->pwszURL, // apwszStringsIn
  4513. &(*ppapwszOut)[cFiles]); // apwszStringsOut
  4514. _JumpIfError(hr, error, "myFormatCertsrvStringArray");
  4515. DBGPRINT((
  4516. DBG_SS_CERTSRVI,
  4517. "CRLList format[%u] = %x @%x (%ws)\n",
  4518. cFiles,
  4519. (*ppapwszOut)[cFiles],
  4520. &(*ppapwszOut)[cFiles],
  4521. (*ppapwszOut)[cFiles]));
  4522. cFiles++;
  4523. }
  4524. }
  4525. (*ppapwszOut)[cFiles] = NULL;
  4526. hr = S_OK;
  4527. error:
  4528. // Freeing the CACTX structure during shutdown will free orphaned CRL paths
  4529. return(hr);
  4530. }
  4531. HRESULT
  4532. pkcsBuildKeyAuthority2(
  4533. IN DWORD EditFlags,
  4534. IN CACTX const *pCAContext,
  4535. OUT CRYPT_OBJID_BLOB *pKeyAuthority2)
  4536. {
  4537. HRESULT hr = S_OK;
  4538. CERT_AUTHORITY_KEY_ID2_INFO keyAuth;
  4539. CERT_ALT_NAME_ENTRY AltNameEntry;
  4540. if (0 ==
  4541. ((EDITF_ENABLEAKIKEYID |
  4542. EDITF_ENABLEAKIISSUERNAME |
  4543. EDITF_ENABLEAKIISSUERSERIAL) & EditFlags))
  4544. {
  4545. goto error;
  4546. }
  4547. ZeroMemory(&keyAuth, sizeof(keyAuth));
  4548. // Issuer's KeyId:
  4549. if ((EDITF_ENABLEAKIKEYID & EditFlags) &&
  4550. NULL != pCAContext->IssuerKeyId.pbData)
  4551. {
  4552. keyAuth.KeyId = pCAContext->IssuerKeyId;
  4553. }
  4554. // The Issuer's Issuer name and the Issuer's SerialNumber combined
  4555. // should uniquely identify the Issuer cert.
  4556. // Issuer's Issuer name:
  4557. // -------- ------ ----
  4558. if (EDITF_ENABLEAKIISSUERNAME & EditFlags)
  4559. {
  4560. AltNameEntry.dwAltNameChoice = CERT_ALT_NAME_DIRECTORY_NAME;
  4561. AltNameEntry.DirectoryName = pCAContext->pccCA->pCertInfo->Issuer;
  4562. keyAuth.AuthorityCertIssuer.cAltEntry = 1;
  4563. keyAuth.AuthorityCertIssuer.rgAltEntry = &AltNameEntry;
  4564. }
  4565. // Issuer's SerialNumber:
  4566. if (EDITF_ENABLEAKIISSUERSERIAL & EditFlags)
  4567. {
  4568. keyAuth.AuthorityCertSerialNumber =
  4569. pCAContext->pccCA->pCertInfo->SerialNumber;
  4570. }
  4571. // put in Key Authority Info
  4572. if (!myEncodeKeyAuthority2(
  4573. X509_ASN_ENCODING,
  4574. &keyAuth,
  4575. CERTLIB_USE_LOCALALLOC,
  4576. &pKeyAuthority2->pbData,
  4577. &pKeyAuthority2->cbData))
  4578. {
  4579. hr = myHLastError();
  4580. _JumpError(hr, error, "myEncodeKeyAuthority2");
  4581. }
  4582. error:
  4583. return(hr);
  4584. }
  4585. HRESULT
  4586. pkcsBuildCDP(
  4587. IN DWORD Flags,
  4588. IN BOOL fDelta,
  4589. IN CACTX const *pCAContext,
  4590. OUT CRYPT_OBJID_BLOB *pCDP)
  4591. {
  4592. HRESULT hr;
  4593. DWORD i;
  4594. CSURLTEMPLATE const *pTemplate;
  4595. CSURLTEMPLATE const *pTemplateEnd;
  4596. CRL_DIST_POINTS_INFO CRLDistInfo;
  4597. CRL_DIST_POINT CRLDistPoint;
  4598. CERT_ALT_NAME_INFO *pAltInfo;
  4599. ZeroMemory(&CRLDistPoint, sizeof(CRLDistPoint));
  4600. pAltInfo = &CRLDistPoint.DistPointName.FullName;
  4601. pCDP->pbData = NULL;
  4602. pCDP->cbData = 0;
  4603. if (0 != g_caRevURL)
  4604. {
  4605. pTemplateEnd = &g_paRevURL[g_caRevURL];
  4606. for (pTemplate = g_paRevURL; pTemplate < pTemplateEnd; pTemplate++)
  4607. {
  4608. if (Flags & pTemplate->Flags)
  4609. {
  4610. pAltInfo->cAltEntry++;
  4611. }
  4612. }
  4613. }
  4614. if (0 == pAltInfo->cAltEntry)
  4615. {
  4616. hr = S_FALSE;
  4617. goto error;
  4618. }
  4619. CRLDistInfo.cDistPoint = 1;
  4620. CRLDistInfo.rgDistPoint = &CRLDistPoint;
  4621. CRLDistPoint.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
  4622. pAltInfo->rgAltEntry = (CERT_ALT_NAME_ENTRY *) LocalAlloc(
  4623. LMEM_FIXED | LMEM_ZEROINIT,
  4624. pAltInfo->cAltEntry * sizeof(pAltInfo->rgAltEntry[0]));
  4625. if (NULL == pAltInfo->rgAltEntry)
  4626. {
  4627. hr = E_OUTOFMEMORY;
  4628. _JumpError(hr, error, "LocalAlloc");
  4629. }
  4630. CSASSERT(NULL != g_strDomainDN && NULL != g_strConfigDN);
  4631. i = 0;
  4632. for (pTemplate = g_paRevURL; pTemplate < pTemplateEnd; pTemplate++)
  4633. {
  4634. if (Flags & pTemplate->Flags)
  4635. {
  4636. hr = myFormatCertsrvStringArray(
  4637. TRUE, // fURL
  4638. g_pwszServerName, // pwszServerName_p1_2
  4639. g_wszSanitizedName, // pwszSanitizedName_p3_7
  4640. pCAContext->iCert, // iCert_p4
  4641. g_strDomainDN, // pwszDomainDN_p5
  4642. g_strConfigDN, // pwszConfigDN_p6
  4643. pCAContext->iKey, // iCRL_p8
  4644. fDelta, // fDeltaCRL_p9
  4645. TRUE, // fDSAttrib_p10_11
  4646. 1, // cStrings
  4647. (LPCWSTR *) &pTemplate->pwszURL, // apwszStringsIn
  4648. &pAltInfo->rgAltEntry[i].pwszURL); // apwszStringsOut
  4649. _JumpIfError(hr, error, "myFormatCertsrvStringArray");
  4650. pAltInfo->rgAltEntry[i].dwAltNameChoice = CERT_ALT_NAME_URL;
  4651. i++;
  4652. }
  4653. }
  4654. CSASSERT(pAltInfo->cAltEntry == i);
  4655. if (!myEncodeObject(
  4656. X509_ASN_ENCODING,
  4657. X509_CRL_DIST_POINTS,
  4658. &CRLDistInfo,
  4659. 0,
  4660. CERTLIB_USE_LOCALALLOC,
  4661. &pCDP->pbData,
  4662. &pCDP->cbData))
  4663. {
  4664. hr = myHLastError();
  4665. _JumpIfError(hr, error, "myEncodeObject");
  4666. }
  4667. hr = S_OK;
  4668. error:
  4669. if (NULL != pAltInfo->rgAltEntry)
  4670. {
  4671. for (i = 0; i < pAltInfo->cAltEntry; i++)
  4672. {
  4673. if (NULL != pAltInfo->rgAltEntry[i].pwszURL)
  4674. {
  4675. LocalFree(pAltInfo->rgAltEntry[i].pwszURL);
  4676. }
  4677. }
  4678. LocalFree(pAltInfo->rgAltEntry);
  4679. }
  4680. return(hr);
  4681. }
  4682. HRESULT
  4683. pkcsBuildAIA(
  4684. IN DWORD Flags,
  4685. IN CACTX const *pCAContext,
  4686. OUT CRYPT_OBJID_BLOB *pAIA)
  4687. {
  4688. HRESULT hr;
  4689. DWORD cAIA;
  4690. DWORD i;
  4691. CSURLTEMPLATE const *pTemplate;
  4692. CSURLTEMPLATE const *pTemplateEnd;
  4693. CERT_AUTHORITY_INFO_ACCESS caio;
  4694. CERT_ACCESS_DESCRIPTION *pcad;
  4695. caio.cAccDescr = 0;
  4696. caio.rgAccDescr = NULL;
  4697. pAIA->pbData = NULL;
  4698. pAIA->cbData = 0;
  4699. cAIA = 0;
  4700. if (0 != g_caRevURL)
  4701. {
  4702. pTemplateEnd = &g_paCACertURL[g_caCACertURL];
  4703. for (pTemplate = g_paCACertURL; pTemplate < pTemplateEnd; pTemplate++)
  4704. {
  4705. if (Flags & pTemplate->Flags)
  4706. {
  4707. cAIA++;
  4708. }
  4709. }
  4710. }
  4711. if (0 == cAIA)
  4712. {
  4713. hr = S_FALSE;
  4714. goto error;
  4715. }
  4716. caio.rgAccDescr = (CERT_ACCESS_DESCRIPTION *) LocalAlloc(
  4717. LMEM_FIXED | LMEM_ZEROINIT,
  4718. cAIA * sizeof(caio.rgAccDescr[0]));
  4719. if (NULL == caio.rgAccDescr)
  4720. {
  4721. hr = E_OUTOFMEMORY;
  4722. _JumpError(hr, error, "LocalAlloc");
  4723. }
  4724. CSASSERT(NULL != g_strDomainDN && NULL != g_strConfigDN);
  4725. for (pTemplate = g_paCACertURL; pTemplate < pTemplateEnd; pTemplate++)
  4726. {
  4727. if (Flags & pTemplate->Flags)
  4728. {
  4729. pcad = &caio.rgAccDescr[caio.cAccDescr];
  4730. pcad->pszAccessMethod = (CSURL_ADDTOCERTOCSP & pTemplate->Flags)?
  4731. szOID_PKIX_OCSP : szOID_PKIX_CA_ISSUERS;
  4732. pcad->AccessLocation.dwAltNameChoice = CERT_ALT_NAME_URL;
  4733. hr = myFormatCertsrvStringArray(
  4734. TRUE, // fURL
  4735. g_pwszServerName, // pwszServerName_p1_2
  4736. g_wszSanitizedName, // pwszSanitizedName_p3_7
  4737. pCAContext->iCert, // iCert_p4
  4738. g_strDomainDN, // pwszDomainDN_p5
  4739. g_strConfigDN, // pwszConfigDN_p6
  4740. pCAContext->iKey, // iCRL_p8
  4741. FALSE, // fDeltaCRL_p9
  4742. TRUE, // fDSAttrib_p10_11
  4743. 1, // cStrings
  4744. (LPCWSTR *) &pTemplate->pwszURL, // apwszStringsIn
  4745. &pcad->AccessLocation.pwszURL); // apwszStringsOut
  4746. _JumpIfError(hr, error, "myFormatCertsrvStringArray");
  4747. caio.cAccDescr++;
  4748. }
  4749. }
  4750. CSASSERT(caio.cAccDescr == cAIA);
  4751. if (!myEncodeObject(
  4752. X509_ASN_ENCODING,
  4753. X509_AUTHORITY_INFO_ACCESS,
  4754. &caio,
  4755. 0,
  4756. CERTLIB_USE_LOCALALLOC,
  4757. &pAIA->pbData,
  4758. &pAIA->cbData))
  4759. {
  4760. hr = myHLastError();
  4761. _JumpIfError(hr, error, "myEncodeObject");
  4762. }
  4763. hr = S_OK;
  4764. error:
  4765. if (NULL != caio.rgAccDescr)
  4766. {
  4767. for (i = 0; i < caio.cAccDescr; i++)
  4768. {
  4769. pcad = &caio.rgAccDescr[i];
  4770. if (NULL != pcad->AccessLocation.pwszURL)
  4771. {
  4772. LocalFree(pcad->AccessLocation.pwszURL);
  4773. }
  4774. }
  4775. LocalFree(caio.rgAccDescr);
  4776. }
  4777. return(hr);
  4778. }
  4779. // Find the newest cert with the matching key container name:
  4780. HRESULT
  4781. pkcsFindMatchingKeyContext(
  4782. OPTIONAL IN CERT_PUBLIC_KEY_INFO *pPublicKeyInfo,
  4783. IN DWORD iKey,
  4784. OUT CACTX **ppCAContext)
  4785. {
  4786. HRESULT hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  4787. DWORD i;
  4788. CACTX *pCAContext;
  4789. *ppCAContext = NULL;
  4790. for (i = g_cCACerts; i > 0; i--)
  4791. {
  4792. pCAContext = &g_aCAContext[i - 1];
  4793. if ((MAXDWORD != iKey && iKey == pCAContext->iKey) ||
  4794. (NULL != pCAContext->pccCA &&
  4795. NULL != pPublicKeyInfo &&
  4796. CertComparePublicKeyInfo(
  4797. X509_ASN_ENCODING,
  4798. pPublicKeyInfo,
  4799. &pCAContext->pccCA->pCertInfo->SubjectPublicKeyInfo)))
  4800. {
  4801. // by design, CertComparePublicKeyInfo doesn't set last error!
  4802. *ppCAContext = pCAContext;
  4803. hr = S_OK;
  4804. break;
  4805. }
  4806. }
  4807. return(hr);
  4808. }
  4809. HRESULT
  4810. pkcsLoadTemplates(
  4811. IN WCHAR const *pwszRegName,
  4812. OUT CSURLTEMPLATE **ppaURL,
  4813. OUT DWORD *pcaURL)
  4814. {
  4815. HRESULT hr;
  4816. WCHAR *pwszzTemplates = NULL;
  4817. WCHAR *pwsz;
  4818. DWORD cTemplate = 0;
  4819. CSURLTEMPLATE *pTemplate;
  4820. DWORD Flags;
  4821. WCHAR *pwsz2;
  4822. *ppaURL = NULL;
  4823. *pcaURL = 0;
  4824. // get (multiple) path templates
  4825. hr = myGetCertRegMultiStrValue(
  4826. g_wszSanitizedName,
  4827. NULL,
  4828. NULL,
  4829. pwszRegName,
  4830. &pwszzTemplates);
  4831. _JumpIfError(hr, error, "myGetCertRegStrValue");
  4832. for (pwsz = pwszzTemplates; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
  4833. {
  4834. Flags = _wtoi(pwsz);
  4835. pwsz2 = pwsz;
  4836. while (iswdigit(*pwsz2))
  4837. {
  4838. pwsz2++;
  4839. }
  4840. if (0 != Flags && pwsz2 > pwsz && L':' == *pwsz2)
  4841. {
  4842. cTemplate++;
  4843. }
  4844. }
  4845. if (0 != cTemplate)
  4846. {
  4847. *ppaURL = (CSURLTEMPLATE *) LocalAlloc(
  4848. LMEM_FIXED | LMEM_ZEROINIT,
  4849. cTemplate * sizeof((*ppaURL)[0]));
  4850. if (NULL == *ppaURL)
  4851. {
  4852. hr = E_OUTOFMEMORY;
  4853. _JumpError(hr, error, "LocalAlloc");
  4854. }
  4855. pTemplate = *ppaURL;
  4856. *pcaURL = cTemplate;
  4857. for (pwsz = pwszzTemplates; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
  4858. {
  4859. Flags = _wtoi(pwsz);
  4860. pwsz2 = pwsz;
  4861. while (iswdigit(*pwsz2))
  4862. {
  4863. pwsz2++;
  4864. }
  4865. if (0 != Flags && pwsz2 > pwsz && L':' == *pwsz2)
  4866. {
  4867. pTemplate->Flags = Flags;
  4868. hr = myDupString(&pwsz2[1], &pTemplate->pwszURL);
  4869. _JumpIfError(hr, error, "myDupString");
  4870. pTemplate++;
  4871. }
  4872. }
  4873. CSASSERT(pTemplate == &(*ppaURL)[*pcaURL]);
  4874. }
  4875. error:
  4876. if (NULL != pwszzTemplates)
  4877. {
  4878. LocalFree(pwszzTemplates);
  4879. }
  4880. return(hr);
  4881. }
  4882. VOID
  4883. pkcsFreeTemplates(
  4884. IN OUT CSURLTEMPLATE **ppaURL,
  4885. IN OUT DWORD *pcaURL)
  4886. {
  4887. CSURLTEMPLATE *pTemplate;
  4888. CSURLTEMPLATE *pTemplateEnd;
  4889. if (0 != *pcaURL && NULL != *ppaURL)
  4890. {
  4891. pTemplateEnd = &(*ppaURL)[*pcaURL];
  4892. for (pTemplate = *ppaURL; pTemplate < pTemplateEnd; pTemplate++)
  4893. {
  4894. if (NULL != pTemplate->pwszURL)
  4895. {
  4896. LocalFree(pTemplate->pwszURL);
  4897. }
  4898. }
  4899. LocalFree(*ppaURL);
  4900. *ppaURL = NULL;
  4901. }
  4902. }
  4903. HRESULT
  4904. pkcsGetCertFilename(
  4905. IN WCHAR const *pwszSanitizedName,
  4906. IN DWORD iCert,
  4907. OUT WCHAR **ppwszCertFile)
  4908. {
  4909. HRESULT hr;
  4910. WCHAR wszBuf[MAX_PATH];
  4911. WCHAR *pwszIndexedName = NULL;
  4912. DWORD cwc;
  4913. *ppwszCertFile = NULL;
  4914. hr = myAllocIndexedName(
  4915. pwszSanitizedName,
  4916. iCert,
  4917. &pwszIndexedName);
  4918. _JumpIfError(hr, error, "myAllocIndexedName");
  4919. if (0 == GetEnvironmentVariable(L"SystemRoot", wszBuf, ARRAYSIZE(wszBuf)))
  4920. {
  4921. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  4922. _JumpError(hr, error, "GetEnvironmentVariable");
  4923. }
  4924. cwc = wcslen(wszBuf) +
  4925. WSZARRAYSIZE(L"\\System32\\" wszCERTENROLLSHAREPATH L"\\") +
  4926. wcslen(g_pwszServerName) +
  4927. WSZARRAYSIZE(L"_") +
  4928. wcslen(pwszIndexedName) +
  4929. WSZARRAYSIZE(L".crt") +
  4930. 1;
  4931. *ppwszCertFile = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  4932. if (NULL == *ppwszCertFile)
  4933. {
  4934. hr = E_OUTOFMEMORY;
  4935. _JumpError(hr, error, "LocalAlloc");
  4936. }
  4937. wcscpy(*ppwszCertFile, wszBuf);
  4938. wcscat(*ppwszCertFile, L"\\System32\\" wszCERTENROLLSHAREPATH L"\\");
  4939. wcscat(*ppwszCertFile, g_pwszServerName);
  4940. wcscat(*ppwszCertFile, L"_");
  4941. wcscat(*ppwszCertFile, pwszIndexedName);
  4942. wcscat(*ppwszCertFile, L".crt");
  4943. CSASSERT(1 + wcslen(*ppwszCertFile) == cwc);
  4944. error:
  4945. if (NULL != pwszIndexedName)
  4946. {
  4947. LocalFree(pwszIndexedName);
  4948. }
  4949. return(hr);
  4950. }
  4951. HRESULT
  4952. pkcsReloadMissingCertByHash(
  4953. IN HCERTSTORE hStore,
  4954. IN WCHAR const *pwszSanitizedName,
  4955. IN DWORD dwRegHashChoice,
  4956. IN BYTE const *pbHashReg,
  4957. IN DWORD cbHashReg,
  4958. IN DWORD iHash)
  4959. {
  4960. HRESULT hr;
  4961. DWORD cbHash;
  4962. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  4963. BSTR strHash = NULL;
  4964. ICertDBRow *prow = NULL;
  4965. DWORD cbCert;
  4966. BYTE *pbCert = NULL;
  4967. WCHAR *pwszCertFile = NULL;
  4968. CERT_CONTEXT const *pcc = NULL;
  4969. hr = MultiByteIntegerToBstr(TRUE, cbHashReg, pbHashReg, &strHash);
  4970. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  4971. DBGPRINT((
  4972. DBG_SS_CERTSRV,
  4973. "Reloading %wsContext[%u]\n %ws\n",
  4974. CSRH_CASIGCERT == dwRegHashChoice? L"CA" : L"KRA",
  4975. iHash,
  4976. strHash));
  4977. hr = g_pCertDB->OpenRow(
  4978. PROPOPEN_READONLY |
  4979. PROPOPEN_CERTHASH |
  4980. PROPTABLE_REQCERT,
  4981. 0,
  4982. strHash,
  4983. &prow);
  4984. _PrintIfErrorStr(hr, "OpenRow", strHash);
  4985. if (S_OK == hr)
  4986. {
  4987. hr = PKCSGetProperty(
  4988. prow,
  4989. g_wszPropRawCertificate,
  4990. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  4991. &cbCert,
  4992. (BYTE **) &pbCert);
  4993. _JumpIfError(hr, error, "PKCSGetProperty(cert)");
  4994. }
  4995. else if (CSRH_CASIGCERT != dwRegHashChoice)
  4996. {
  4997. _JumpError(hr, error, "OpenRow");
  4998. }
  4999. else
  5000. {
  5001. hr = pkcsGetCertFilename(
  5002. pwszSanitizedName,
  5003. iHash,
  5004. &pwszCertFile);
  5005. _JumpIfError(hr, error, "myGetCertFilename");
  5006. hr = DecodeFileW(pwszCertFile, &pbCert, &cbCert, CRYPT_STRING_ANY);
  5007. _JumpIfError(hr, error, "DecodeFileW");
  5008. }
  5009. pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
  5010. if (NULL == pcc)
  5011. {
  5012. hr = myHLastError();
  5013. _JumpError(hr, error, "CertCreateCertificateContext");
  5014. }
  5015. cbHash = sizeof(abHash);
  5016. if (!CertGetCertificateContextProperty(
  5017. pcc,
  5018. CERT_SHA1_HASH_PROP_ID,
  5019. abHash,
  5020. &cbHash))
  5021. {
  5022. hr = myHLastError();
  5023. _JumpError(hr, error, "CertGetCertificateContextProperty");
  5024. }
  5025. if (cbHash != cbHashReg || 0 != memcmp(abHash, pbHashReg, cbHash))
  5026. {
  5027. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  5028. _JumpError(hr, error, "wrong Cert");
  5029. }
  5030. // Add as encoded blob to avoid all properties, key prov info, etc.
  5031. if (!CertAddEncodedCertificateToStore(
  5032. hStore,
  5033. X509_ASN_ENCODING,
  5034. pbCert,
  5035. cbCert,
  5036. CERT_STORE_ADD_REPLACE_EXISTING,
  5037. NULL)) // ppCertContext
  5038. {
  5039. hr = myHLastError();
  5040. _JumpError(hr, error, "CertAddEncodedCertificateToStore");
  5041. }
  5042. DBGPRINT((
  5043. DBG_SS_CERTSRV,
  5044. "Reloaded %wsContext[%u]\n",
  5045. CSRH_CASIGCERT == dwRegHashChoice? L"CA" : L"KRA",
  5046. iHash));
  5047. hr = S_OK;
  5048. error:
  5049. if (NULL != pcc)
  5050. {
  5051. CertFreeCertificateContext(pcc);
  5052. }
  5053. if (NULL != pwszCertFile)
  5054. {
  5055. LocalFree(pwszCertFile);
  5056. }
  5057. if (NULL != prow)
  5058. {
  5059. prow->Release();
  5060. }
  5061. if (NULL != pbCert)
  5062. {
  5063. LocalFree(pbCert);
  5064. }
  5065. if (NULL != strHash)
  5066. {
  5067. SysFreeString(strHash);
  5068. }
  5069. return(hr);
  5070. }
  5071. HRESULT
  5072. pkcsReloadMissingCAOrKRACert(
  5073. IN HCERTSTORE hStore,
  5074. IN WCHAR const *pwszSanitizedName,
  5075. IN DWORD dwRegHashChoice,
  5076. IN DWORD iHash)
  5077. {
  5078. HRESULT hr;
  5079. BYTE *pbHashReg = NULL;
  5080. DWORD cbHashReg;
  5081. hr = myGetCARegHash(
  5082. pwszSanitizedName,
  5083. dwRegHashChoice,
  5084. iHash,
  5085. &pbHashReg,
  5086. &cbHashReg);
  5087. _JumpIfError(hr, error, "myGetCARegHash");
  5088. hr = pkcsReloadMissingCertByHash(
  5089. hStore,
  5090. pwszSanitizedName,
  5091. dwRegHashChoice,
  5092. pbHashReg,
  5093. cbHashReg,
  5094. iHash);
  5095. _JumpIfError(hr, error, "pkcsReloadMissingCertByHash");
  5096. error:
  5097. if (NULL != pbHashReg)
  5098. {
  5099. LocalFree(pbHashReg);
  5100. }
  5101. return(hr);
  5102. }
  5103. VOID
  5104. pkcsFreeBlobArray(
  5105. IN DWORD cBlob,
  5106. CERT_BLOB *rgBlob)
  5107. {
  5108. DWORD i;
  5109. for (i = 0; i < cBlob; i++)
  5110. {
  5111. if (NULL != rgBlob[cBlob].pbData)
  5112. {
  5113. LocalFree(rgBlob[i].pbData);
  5114. }
  5115. }
  5116. LocalFree(rgBlob);
  5117. }
  5118. HRESULT
  5119. pkcsGetKRACertBlobs(
  5120. IN ICertDBRow *prow,
  5121. OUT DWORD *pcCertBlob,
  5122. OUT CERT_BLOB **prgCertBlob)
  5123. {
  5124. HRESULT hr;
  5125. WCHAR *pwszHashes = NULL;
  5126. WCHAR *pwsz;
  5127. DWORD cb;
  5128. DWORD cHash;
  5129. DWORD i;
  5130. CERT_BLOB *rgBlob = NULL;
  5131. HCERTSTORE hStore = NULL;
  5132. CRYPT_DATA_BLOB HashBlob;
  5133. DWORD cBlobLoaded;
  5134. CERT_CONTEXT const *pcc = NULL;
  5135. HashBlob.pbData = NULL;
  5136. hr = PKCSGetProperty(
  5137. prow,
  5138. g_wszPropRequestKeyRecoveryHashes,
  5139. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  5140. &cb,
  5141. (BYTE **) &pwszHashes);
  5142. _JumpIfError(hr, error, "PKCSGetProperty(KRA hashes)");
  5143. cHash = 1;
  5144. pwsz = pwszHashes;
  5145. while (TRUE)
  5146. {
  5147. pwsz = wcschr(pwsz, L'\n');
  5148. if (NULL == pwsz)
  5149. {
  5150. break;
  5151. }
  5152. *pwsz++ = L'\0';
  5153. cHash++;
  5154. }
  5155. cBlobLoaded = 0;
  5156. rgBlob = (CERT_BLOB *) LocalAlloc(
  5157. LMEM_FIXED | LMEM_ZEROINIT,
  5158. cHash * sizeof(rgBlob[0]));
  5159. if (NULL == rgBlob)
  5160. {
  5161. hr = E_OUTOFMEMORY;
  5162. _JumpError(hr, error, "LocalAlloc");
  5163. }
  5164. // open KRA store
  5165. hStore = CertOpenStore(
  5166. CERT_STORE_PROV_SYSTEM_W,
  5167. X509_ASN_ENCODING,
  5168. NULL, // hProv
  5169. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  5170. wszKRA_CERTSTORE);
  5171. if (NULL == hStore)
  5172. {
  5173. hr = myHLastError();
  5174. _JumpError(hr, error, "CertOpenStore");
  5175. }
  5176. pwsz = pwszHashes;
  5177. for (i = 0; i < cHash; i++)
  5178. {
  5179. BOOL fReloaded;
  5180. hr = WszToMultiByteInteger(
  5181. TRUE,
  5182. pwsz,
  5183. &HashBlob.cbData,
  5184. &HashBlob.pbData);
  5185. _JumpIfError(hr, error, "WszToMultiByteInteger");
  5186. fReloaded = FALSE;
  5187. while (TRUE)
  5188. {
  5189. pcc = CertFindCertificateInStore(
  5190. hStore,
  5191. X509_ASN_ENCODING,
  5192. 0,
  5193. CERT_FIND_HASH,
  5194. &HashBlob,
  5195. NULL);
  5196. if (fReloaded || NULL != pcc)
  5197. {
  5198. break;
  5199. }
  5200. hr = pkcsReloadMissingCertByHash(
  5201. hStore,
  5202. g_wszSanitizedName,
  5203. CSRH_CAKRACERT,
  5204. HashBlob.pbData,
  5205. HashBlob.cbData,
  5206. i);
  5207. _PrintIfError(hr, "pkcsReloadMissingCertByHash");
  5208. fReloaded = TRUE;
  5209. }
  5210. if (NULL == pcc)
  5211. {
  5212. hr = myHLastError();
  5213. _PrintError(hr, "CertFindCertificateInStore");
  5214. }
  5215. else
  5216. {
  5217. rgBlob[cBlobLoaded].pbData = (BYTE *) LocalAlloc(
  5218. LMEM_FIXED,
  5219. pcc->cbCertEncoded);
  5220. if (NULL == rgBlob[cBlobLoaded].pbData)
  5221. {
  5222. hr = E_OUTOFMEMORY;
  5223. _JumpError(hr, error, "LocalAlloc");
  5224. }
  5225. rgBlob[cBlobLoaded].cbData = pcc->cbCertEncoded;
  5226. CopyMemory(
  5227. rgBlob[cBlobLoaded].pbData,
  5228. pcc->pbCertEncoded,
  5229. pcc->cbCertEncoded);
  5230. cBlobLoaded++;
  5231. CertFreeCertificateContext(pcc);
  5232. pcc = NULL;
  5233. }
  5234. pwsz += wcslen(pwsz) + 1;
  5235. LocalFree(HashBlob.pbData);
  5236. HashBlob.pbData = NULL;
  5237. }
  5238. *pcCertBlob = cBlobLoaded;
  5239. *prgCertBlob = rgBlob;
  5240. rgBlob = NULL;
  5241. error:
  5242. if (NULL != rgBlob)
  5243. {
  5244. pkcsFreeBlobArray(cBlobLoaded, rgBlob);
  5245. }
  5246. if (NULL != hStore)
  5247. {
  5248. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  5249. }
  5250. if (NULL != pcc)
  5251. {
  5252. CertFreeCertificateContext(pcc);
  5253. }
  5254. if (NULL != HashBlob.pbData)
  5255. {
  5256. LocalFree(HashBlob.pbData);
  5257. }
  5258. if (NULL != pwszHashes)
  5259. {
  5260. LocalFree(pwszHashes);
  5261. }
  5262. return(hr);
  5263. }
  5264. HRESULT
  5265. pkcsGetHashAsOctet(
  5266. IN ICertDBRow *prow,
  5267. OUT BYTE **ppbData,
  5268. OUT DWORD *pcbData)
  5269. {
  5270. HRESULT hr;
  5271. WCHAR *pwszHash = NULL;
  5272. DWORD cb;
  5273. CRYPT_DATA_BLOB Blob;
  5274. DWORD cbHash;
  5275. *ppbData = NULL;
  5276. Blob.pbData = NULL;
  5277. hr = PKCSGetProperty(
  5278. prow,
  5279. g_wszPropCertificateHash,
  5280. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  5281. &cb,
  5282. (BYTE **) &pwszHash);
  5283. _JumpIfError(hr, error, "PKCSGetProperty(hash)");
  5284. hr = WszToMultiByteInteger(TRUE, pwszHash, &Blob.cbData, &Blob.pbData);
  5285. _JumpIfError(hr, error, "WszToMultiByteInteger");
  5286. if (!myEncodeObject(
  5287. X509_ASN_ENCODING,
  5288. X509_OCTET_STRING,
  5289. &Blob,
  5290. 0,
  5291. CERTLIB_USE_LOCALALLOC,
  5292. ppbData,
  5293. pcbData))
  5294. {
  5295. hr = myHLastError();
  5296. _JumpError(hr, error, "myEncodeObject");
  5297. }
  5298. hr = S_OK;
  5299. error:
  5300. if (NULL != pwszHash)
  5301. {
  5302. LocalFree(pwszHash);
  5303. }
  5304. if (NULL != Blob.pbData)
  5305. {
  5306. LocalFree(Blob.pbData);
  5307. }
  5308. return(hr);
  5309. }
  5310. VOID
  5311. AddCertBlobToArray(
  5312. IN CERT_CONTEXT const *pcc,
  5313. IN CERT_BLOB *rgCertBlobAll,
  5314. IN CERT_BLOB **ppCertBlob)
  5315. {
  5316. CERT_BLOB *pCertBlob = *ppCertBlob;
  5317. DWORD i;
  5318. DWORD cBlob;
  5319. cBlob = SAFE_SUBTRACT_POINTERS(pCertBlob, rgCertBlobAll);
  5320. for (i = 0; i < cBlob; i++)
  5321. {
  5322. if (rgCertBlobAll[i].cbData == pcc->cbCertEncoded &&
  5323. 0 == memcmp(
  5324. rgCertBlobAll[i].pbData,
  5325. pcc->pbCertEncoded,
  5326. pcc->cbCertEncoded))
  5327. {
  5328. DBGPRINT((
  5329. DBG_SS_CERTSRV,
  5330. "Duplicate Recovery Blob Cert[%u]\n",
  5331. i));
  5332. goto error;
  5333. }
  5334. }
  5335. DBGPRINT((
  5336. DBG_SS_CERTSRV,
  5337. "Adding Recovery Blob Cert[%u]\n",
  5338. cBlob));
  5339. pCertBlob->cbData = pcc->cbCertEncoded;
  5340. pCertBlob->pbData = pcc->pbCertEncoded;
  5341. pCertBlob++;
  5342. *ppCertBlob = pCertBlob;
  5343. error:
  5344. ;
  5345. }
  5346. HRESULT
  5347. PKCSGetArchivedKey(
  5348. IN DWORD dwRequestId,
  5349. OUT BYTE **ppbArchivedKey, // CoTaskMem*
  5350. OUT DWORD *pcbArchivedKey)
  5351. {
  5352. HRESULT hr;
  5353. ICertDBRow *prow = NULL;
  5354. BYTE *pbKey = NULL;
  5355. DWORD cbKey;
  5356. BYTE *pbCertUser = NULL;
  5357. DWORD cbCertUser;
  5358. DWORD cb;
  5359. HCRYPTMSG hMsg = NULL;
  5360. CACTX *pCAContext;
  5361. CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo;
  5362. CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo;
  5363. CERT_CONTEXT const *pccUser = NULL;
  5364. CERT_CHAIN_CONTEXT const *pCertChainContextUser = NULL;
  5365. CERT_CHAIN_PARA CertChainPara;
  5366. CERT_BLOB *rgCertBlobKRA = NULL;
  5367. DWORD cCertBlobKRA;
  5368. CERT_BLOB *rgCertBlobAll = NULL;
  5369. DWORD cCertBlobAll;
  5370. CERT_BLOB *pCertBlob;
  5371. CRYPT_ATTRIBUTE HashAttrib;
  5372. CRYPT_ATTR_BLOB HashAttribBlob;
  5373. DWORD i;
  5374. *ppbArchivedKey = NULL;
  5375. HashAttribBlob.pbData = NULL;
  5376. hr = g_pCertDB->OpenRow(
  5377. PROPOPEN_READONLY | PROPTABLE_REQCERT,
  5378. dwRequestId,
  5379. NULL,
  5380. &prow);
  5381. _JumpIfError(hr, error, "OpenRow");
  5382. hr = PKCSGetProperty(
  5383. prow,
  5384. g_wszPropRequestRawArchivedKey,
  5385. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  5386. &cbKey,
  5387. &pbKey);
  5388. _JumpIfError(hr, error, "PKCSGetProperty(key)");
  5389. hr = pkcsGetKRACertBlobs(prow, &cCertBlobKRA, &rgCertBlobKRA);
  5390. _JumpIfError(hr, error, "pkcsGetKRACertBlobs");
  5391. hr = pkcsGetHashAsOctet(
  5392. prow,
  5393. &HashAttribBlob.pbData,
  5394. &HashAttribBlob.cbData);
  5395. _JumpIfError(hr, error, "pkcsGetHashAsOctet");
  5396. HashAttrib.pszObjId = szOID_ARCHIVED_KEY_CERT_HASH;
  5397. HashAttrib.cValue = 1;
  5398. HashAttrib.rgValue = &HashAttribBlob;
  5399. hr = PKCSGetProperty(
  5400. prow,
  5401. g_wszPropRawCertificate,
  5402. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  5403. &cbCertUser,
  5404. &pbCertUser);
  5405. _JumpIfError(hr, error, "PKCSGetProperty(cert)");
  5406. pccUser = CertCreateCertificateContext(
  5407. X509_ASN_ENCODING,
  5408. pbCertUser,
  5409. cbCertUser);
  5410. if (NULL == pccUser)
  5411. {
  5412. hr = myHLastError();
  5413. _JumpError(hr, error, "CertCreateCertificateContext");
  5414. }
  5415. // build the user cert chain
  5416. ZeroMemory(&CertChainPara, sizeof(CertChainPara));
  5417. CertChainPara.cbSize = sizeof(CertChainPara);
  5418. if (!CertGetCertificateChain(
  5419. HCCE_LOCAL_MACHINE,
  5420. pccUser,
  5421. NULL,
  5422. NULL,
  5423. &CertChainPara,
  5424. 0,
  5425. NULL,
  5426. &pCertChainContextUser))
  5427. {
  5428. hr = myHLastError();
  5429. _JumpError(hr, error, "CertGetCertificateChain");
  5430. }
  5431. // make sure there is at least 1 simple chain
  5432. if (0 == pCertChainContextUser->cChain)
  5433. {
  5434. hr = E_INVALIDARG;
  5435. _JumpError(hr, error, "No user chain");
  5436. }
  5437. // Encode the encrypted key into a PKCS 7, signed by the current CA cert.
  5438. // Initialize the CMSG_SIGNER_ENCODE_INFO structure for one signer.
  5439. pCAContext = g_pCAContextCurrent;
  5440. cCertBlobAll = cCertBlobKRA +
  5441. pCAContext->cCACertChain +
  5442. pCertChainContextUser->rgpChain[0]->cElement;
  5443. rgCertBlobAll = (CERT_BLOB *) LocalAlloc(
  5444. LMEM_FIXED,
  5445. cCertBlobAll * sizeof(rgCertBlobAll[0]));
  5446. if (NULL == rgCertBlobAll)
  5447. {
  5448. hr = E_OUTOFMEMORY;
  5449. _JumpError(hr, error, "LocalAlloc");
  5450. }
  5451. pCertBlob = rgCertBlobAll;
  5452. CopyMemory(pCertBlob, rgCertBlobKRA, cCertBlobKRA * sizeof(pCertBlob[0]));
  5453. pCertBlob += cCertBlobKRA;
  5454. // Add the current CA cert chain
  5455. for (i = 0; i < pCAContext->cCACertChain; i++)
  5456. {
  5457. AddCertBlobToArray(
  5458. pCAContext->apCACertChain[i],
  5459. rgCertBlobAll,
  5460. &pCertBlob);
  5461. }
  5462. // Add the user cert chain
  5463. {
  5464. CERT_SIMPLE_CHAIN *pSimpleChain;
  5465. pSimpleChain = pCertChainContextUser->rgpChain[0];
  5466. for (i = 0; i < pSimpleChain->cElement; i++)
  5467. {
  5468. AddCertBlobToArray(
  5469. pSimpleChain->rgpElement[i]->pCertContext,
  5470. rgCertBlobAll,
  5471. &pCertBlob);
  5472. }
  5473. }
  5474. CSASSERT(pCertBlob <= &rgCertBlobAll[cCertBlobAll]);
  5475. DBGPRINT((
  5476. DBG_SS_CERTSRV,
  5477. "Recovery Certs: %u --> %u\n",
  5478. cCertBlobAll,
  5479. SAFE_SUBTRACT_POINTERS(pCertBlob, rgCertBlobAll)));
  5480. cCertBlobAll = SAFE_SUBTRACT_POINTERS(pCertBlob, rgCertBlobAll);
  5481. ZeroMemory(&SignerEncodeInfo, sizeof(SignerEncodeInfo));
  5482. SignerEncodeInfo.cbSize = sizeof(SignerEncodeInfo);
  5483. SignerEncodeInfo.pCertInfo = pCAContext->pccCA->pCertInfo;
  5484. SignerEncodeInfo.hCryptProv = pCAContext->hProvCA;
  5485. SignerEncodeInfo.dwKeySpec = AT_SIGNATURE;
  5486. SignerEncodeInfo.HashAlgorithm.pszObjId = szOID_OIWSEC_sha1;
  5487. SignerEncodeInfo.cAuthAttr = 1;
  5488. SignerEncodeInfo.rgAuthAttr = &HashAttrib;
  5489. //SignerEncodeInfo.cUnauthAttr = 0;
  5490. //SignerEncodeInfo.rgUnauthAttr = NULL;
  5491. //SignerEncodeInfo.HashEncryptionAlgorithm.pszObjId = ???;
  5492. // CERT_ID_SHA1_HASH is not yet implemented in CryptMsgOpenToEncode
  5493. //SignerEncodeInfo.SignerId.dwIdChoice = CERT_ID_SHA1_HASH;
  5494. //SignerEncodeInfo.SignerId.HashId.cbData = cb;
  5495. //SignerEncodeInfo.SignerId.HashId.pbData = abHash;
  5496. ZeroMemory(&SignedMsgEncodeInfo, sizeof(SignedMsgEncodeInfo));
  5497. SignedMsgEncodeInfo.cbSize = sizeof(SignedMsgEncodeInfo);
  5498. SignedMsgEncodeInfo.cSigners = 1;
  5499. SignedMsgEncodeInfo.rgSigners = &SignerEncodeInfo;
  5500. SignedMsgEncodeInfo.cCertEncoded = cCertBlobAll;
  5501. SignedMsgEncodeInfo.rgCertEncoded = rgCertBlobAll;
  5502. //SignedMsgEncodeInfo.cCrlEncoded = 0;
  5503. //SignedMsgEncodeInfo.rgCrlEncoded = NULL;
  5504. hMsg = CryptMsgOpenToEncode(
  5505. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  5506. 0, // dwFlags
  5507. CMSG_SIGNED, // dwMsgType
  5508. &SignedMsgEncodeInfo, // pvMsgEncodeInfo
  5509. NULL, // pszInnerContentObjID
  5510. NULL); // pStreamInfo
  5511. if (NULL == hMsg)
  5512. {
  5513. hr = myHLastError();
  5514. _JumpError(hr, error, "CryptMsgOpenToDecode");
  5515. }
  5516. if (!CryptMsgUpdate(hMsg, pbKey, cbKey, TRUE))
  5517. {
  5518. hr = myHLastError();
  5519. _JumpError(hr, error, "CryptMsgUpdate");
  5520. }
  5521. // Return the encoded and signed content.
  5522. // Use CMSG_CONTENT_PARAM to get the signed message.
  5523. hr = myCryptMsgGetParam(
  5524. hMsg,
  5525. CMSG_CONTENT_PARAM,
  5526. 0,
  5527. CERTLIB_USE_COTASKMEMALLOC,
  5528. (VOID **) ppbArchivedKey,
  5529. pcbArchivedKey);
  5530. _JumpIfError(hr, error, "myCryptMsgGetParam");
  5531. error:
  5532. if (pCertChainContextUser != NULL)
  5533. {
  5534. CertFreeCertificateChain(pCertChainContextUser);
  5535. }
  5536. if (NULL != pccUser)
  5537. {
  5538. CertFreeCertificateContext(pccUser);
  5539. }
  5540. if (NULL != hMsg)
  5541. {
  5542. CryptMsgClose(hMsg);
  5543. }
  5544. if (NULL != rgCertBlobKRA)
  5545. {
  5546. pkcsFreeBlobArray(cCertBlobKRA, rgCertBlobKRA);
  5547. }
  5548. if (NULL != rgCertBlobAll)
  5549. {
  5550. LocalFree(rgCertBlobAll);
  5551. }
  5552. if (NULL != HashAttribBlob.pbData)
  5553. {
  5554. LocalFree(HashAttribBlob.pbData);
  5555. }
  5556. if (NULL != pbKey)
  5557. {
  5558. LocalFree(pbKey);
  5559. }
  5560. if (NULL != pbCertUser)
  5561. {
  5562. LocalFree(pbCertUser);
  5563. }
  5564. if (NULL != prow)
  5565. {
  5566. prow->Release();
  5567. }
  5568. return(hr);
  5569. }
  5570. HRESULT
  5571. pkcsGetKeyContainerName(
  5572. IN CERT_CONTEXT const *pccCA,
  5573. OUT WCHAR **ppwszKeyContainerName)
  5574. {
  5575. HRESULT hr;
  5576. CRYPT_HASH_BLOB KeyIdentifier;
  5577. CRYPT_KEY_PROV_INFO *pkpi = NULL;
  5578. DWORD cb;
  5579. KeyIdentifier.pbData = NULL;
  5580. *ppwszKeyContainerName = NULL;
  5581. hr = myGetPublicKeyHash(
  5582. pccCA->pCertInfo,
  5583. &pccCA->pCertInfo->SubjectPublicKeyInfo,
  5584. &KeyIdentifier.pbData,
  5585. &KeyIdentifier.cbData);
  5586. _JumpIfError(hr, error, "myGetPublicKeyHash");
  5587. cb = 0;
  5588. while (TRUE)
  5589. {
  5590. if (!CryptGetKeyIdentifierProperty(
  5591. &KeyIdentifier,
  5592. CERT_KEY_PROV_INFO_PROP_ID,
  5593. CRYPT_KEYID_MACHINE_FLAG,
  5594. NULL, // pwszComputerName
  5595. NULL, // pvReserved
  5596. pkpi,
  5597. &cb))
  5598. {
  5599. hr = myHLastError();
  5600. _JumpError(hr, error, "Cert index");
  5601. }
  5602. if (NULL != pkpi)
  5603. {
  5604. break;
  5605. }
  5606. pkpi = (CRYPT_KEY_PROV_INFO *) LocalAlloc(LMEM_FIXED, cb);
  5607. if (NULL == pkpi)
  5608. {
  5609. hr = E_OUTOFMEMORY;
  5610. _JumpError(hr, error, "LocalAlloc");
  5611. }
  5612. }
  5613. hr = myDupString(pkpi->pwszContainerName, ppwszKeyContainerName);
  5614. _JumpIfError(hr, error, "myDupString");
  5615. error:
  5616. if (NULL != pkpi)
  5617. {
  5618. LocalFree(pkpi);
  5619. }
  5620. if (NULL != KeyIdentifier.pbData)
  5621. {
  5622. LocalFree(KeyIdentifier.pbData);
  5623. }
  5624. return(hr);
  5625. }
  5626. HRESULT
  5627. pkcsLoadCAContext(
  5628. IN WCHAR const *pwszSanitizedName,
  5629. IN WCHAR *pwszProvName,
  5630. IN DWORD dwProvType,
  5631. IN ALG_ID idAlg,
  5632. IN BOOL fMachineKeyset,
  5633. IN DWORD iHash,
  5634. IN HCERTSTORE hMyStore)
  5635. {
  5636. HRESULT hr;
  5637. HCRYPTPROV hProvCA = NULL;
  5638. char *pszObjIdSignatureAlgorithm = NULL;
  5639. WCHAR *pwszKeyContainerName = NULL;
  5640. CERT_CONTEXT const *pccCA = NULL;
  5641. DWORD cCACertChain;
  5642. CERT_CONTEXT const **apCACertChain = NULL;
  5643. CERT_CHAIN_CONTEXT const *pCertChainContext = NULL;
  5644. CERT_CHAIN_PARA CertChainPara;
  5645. CRYPT_KEY_PROV_INFO *pKey = NULL;
  5646. CACTX *pCAContext;
  5647. DWORD i;
  5648. DWORD cbKey;
  5649. DWORD iCert;
  5650. DWORD iKey;
  5651. DWORD NameId;
  5652. BOOL fReloaded;
  5653. hr = myGetSigningOID(
  5654. NULL, // hProv
  5655. pwszProvName,
  5656. dwProvType,
  5657. idAlg,
  5658. &pszObjIdSignatureAlgorithm);
  5659. _JumpIfError(hr, error, "myGetSigningOID");
  5660. if (~_16BITMASK & iHash)
  5661. {
  5662. hr = E_INVALIDARG;
  5663. _JumpError(hr, error, "Cert index");
  5664. }
  5665. fReloaded = FALSE;
  5666. while (TRUE)
  5667. {
  5668. hr = myFindCACertByHashIndex(
  5669. hMyStore,
  5670. pwszSanitizedName,
  5671. CSRH_CASIGCERT,
  5672. iHash,
  5673. &NameId,
  5674. &pccCA);
  5675. iCert = iHash;
  5676. iKey = iCert;
  5677. if (S_OK == hr)
  5678. {
  5679. break;
  5680. }
  5681. // if no hash entry exists for this index, fake up a CA Context
  5682. // as a place holder.
  5683. if (S_FALSE == hr)
  5684. {
  5685. CSASSERT(MAXDWORD == NameId);
  5686. CSASSERT(NULL == pccCA);
  5687. break;
  5688. }
  5689. if (fReloaded || CRYPT_E_NOT_FOUND != hr)
  5690. {
  5691. _JumpError(hr, error, "myFindCACertByHashIndex");
  5692. }
  5693. _PrintError(hr, "myFindCACertByHashIndex");
  5694. // The CA cert is missing from the HKLM "my" store -- look it up in
  5695. // the DB or the CertEnroll directory, and put it back in the store.
  5696. hr = pkcsReloadMissingCAOrKRACert(
  5697. hMyStore,
  5698. pwszSanitizedName,
  5699. CSRH_CASIGCERT,
  5700. iHash);
  5701. _JumpIfError(hr, error, "pkcsReloadMissingCAOrKRACert");
  5702. fReloaded = TRUE;
  5703. }
  5704. CSASSERT(S_FALSE == hr || S_OK == hr);
  5705. if (S_OK == hr)
  5706. {
  5707. if (MAXDWORD != NameId && iCert != CANAMEIDTOICERT(NameId))
  5708. {
  5709. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  5710. DBGPRINT((
  5711. DBG_SS_CERTSRV,
  5712. "NameId=%u.%u iCert=%u\n",
  5713. CANAMEIDTOICERT(NameId),
  5714. CANAMEIDTOIKEY(NameId),
  5715. iCert));
  5716. _JumpError(hr, error, "bad iCert");
  5717. }
  5718. fReloaded = FALSE;
  5719. while (TRUE)
  5720. {
  5721. if (NULL != pwszKeyContainerName)
  5722. {
  5723. LocalFree(pwszKeyContainerName);
  5724. pwszKeyContainerName = NULL;
  5725. }
  5726. if (!fReloaded)
  5727. {
  5728. // get the private key provider info
  5729. if (!myCertGetCertificateContextProperty(
  5730. pccCA,
  5731. CERT_KEY_PROV_INFO_PROP_ID,
  5732. CERTLIB_USE_LOCALALLOC,
  5733. (VOID **) &pKey,
  5734. &cbKey))
  5735. {
  5736. hr = myHLastError();
  5737. if (CRYPT_E_NOT_FOUND != hr)
  5738. {
  5739. _JumpError(hr, error, "myCertGetCertificateContextProperty");
  5740. }
  5741. _PrintError(hr, "CertGetCertificateContextProperty");
  5742. // The Key Provider Info is missing -- use the sanitized
  5743. // name and key index to construct the key container name.
  5744. // If that key matches, we'll write out the new Key
  5745. // Provider Info below.
  5746. hr = myAllocIndexedName(
  5747. pwszSanitizedName,
  5748. MAXDWORD != NameId? CANAMEIDTOIKEY(NameId) : iCert,
  5749. &pwszKeyContainerName);
  5750. _JumpIfError(hr, error, "myAllocIndexedName");
  5751. }
  5752. else
  5753. {
  5754. hr = myDupString(pKey->pwszContainerName, &pwszKeyContainerName);
  5755. _JumpIfError(hr, error, "myDupString");
  5756. }
  5757. }
  5758. else
  5759. {
  5760. hr = pkcsGetKeyContainerName(pccCA, &pwszKeyContainerName);
  5761. _JumpIfError(hr, error, "pkcsGetKeyContainerName");
  5762. }
  5763. // signing testing
  5764. hr = myValidateHashForSigning(
  5765. pwszKeyContainerName,
  5766. pwszProvName,
  5767. dwProvType,
  5768. fMachineKeyset,
  5769. &pccCA->pCertInfo->SubjectPublicKeyInfo,
  5770. idAlg);
  5771. if (S_OK == hr)
  5772. {
  5773. break;
  5774. }
  5775. if (fReloaded)
  5776. {
  5777. _JumpError(hr, error, "myValidateHashForSigning");
  5778. }
  5779. _PrintError(hr, "myValidateHashForSigning");
  5780. fReloaded = TRUE;
  5781. }
  5782. // If the Key Provider Info is missing, write out new Key Provider Info
  5783. if (NULL == pKey)
  5784. {
  5785. CRYPT_KEY_PROV_INFO kpi;
  5786. ZeroMemory(&kpi, sizeof(kpi));
  5787. kpi.pwszContainerName = pwszKeyContainerName;
  5788. kpi.pwszProvName = pwszProvName;
  5789. kpi.dwProvType = dwProvType;
  5790. kpi.dwFlags = fMachineKeyset? CRYPT_MACHINE_KEYSET : 0;
  5791. kpi.dwKeySpec = AT_SIGNATURE;
  5792. if (!CertSetCertificateContextProperty(
  5793. pccCA,
  5794. CERT_KEY_PROV_INFO_PROP_ID,
  5795. 0,
  5796. &kpi))
  5797. {
  5798. hr = myHLastError();
  5799. _JumpError(hr, error, "CertSetCertificateContextProperty");
  5800. }
  5801. DBGPRINT((
  5802. DBG_SS_CERTSRV,
  5803. "Reloaded CAContext[%u] KeyProvInfo[%u]\n",
  5804. iCert,
  5805. iKey));
  5806. }
  5807. hr = pkcsFindMatchingKeyContext(
  5808. &pccCA->pCertInfo->SubjectPublicKeyInfo,
  5809. MAXDWORD,
  5810. &pCAContext);
  5811. if (S_OK != hr && MAXDWORD != NameId)
  5812. {
  5813. iKey = CANAMEIDTOIKEY(NameId);
  5814. if (iKey < iCert)
  5815. {
  5816. hr = pkcsFindMatchingKeyContext(NULL, iKey, &pCAContext);
  5817. _JumpIfError(hr, error, "pkcsFindMatchingKeyContext");
  5818. }
  5819. }
  5820. if (S_OK == hr)
  5821. {
  5822. iKey = pCAContext->iKey;
  5823. if (MAXDWORD != NameId && iKey != CANAMEIDTOIKEY(NameId))
  5824. {
  5825. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  5826. _JumpError(hr, error, "bad iKey");
  5827. }
  5828. if (NULL == pCAContext->pccCA)
  5829. {
  5830. CSASSERT(pCAContext->Flags & CTXF_CERTMISSING);
  5831. pCAContext->Flags |= CTXF_CRLZOMBIE;
  5832. }
  5833. else
  5834. {
  5835. CSASSERT(0 == (pCAContext->Flags & CTXF_CERTMISSING));
  5836. pCAContext->Flags |= CTXF_SKIPCRL;
  5837. }
  5838. }
  5839. else
  5840. {
  5841. g_cCAKeys++; // this key has not previously been loaded
  5842. }
  5843. DBGPRINT((
  5844. DBG_SS_CERTSRV,
  5845. "CAContext[%u]: Key %u: %ws\n",
  5846. iCert,
  5847. iKey,
  5848. pwszKeyContainerName));
  5849. // get private key handler for later use if current CA
  5850. if (!myCertSrvCryptAcquireContext(
  5851. &hProvCA,
  5852. pwszKeyContainerName,
  5853. pwszProvName,
  5854. dwProvType,
  5855. g_fCryptSilent? CRYPT_SILENT : 0,
  5856. fMachineKeyset))
  5857. {
  5858. hr = myHLastError();
  5859. _JumpErrorStr(
  5860. hr,
  5861. error,
  5862. "myCertSrvCryptAcquireContext",
  5863. pwszKeyContainerName);
  5864. }
  5865. // now try to figure out the chain
  5866. ZeroMemory(&CertChainPara, sizeof(CertChainPara));
  5867. CertChainPara.cbSize = sizeof(CertChainPara);
  5868. if (!CertGetCertificateChain(
  5869. HCCE_LOCAL_MACHINE,
  5870. pccCA,
  5871. NULL,
  5872. NULL,
  5873. &CertChainPara,
  5874. 0,
  5875. NULL,
  5876. &pCertChainContext))
  5877. {
  5878. hr = myHLastError();
  5879. goto error;
  5880. }
  5881. // make sure there is at least 1 simple chain
  5882. if (pCertChainContext->cChain == 0)
  5883. {
  5884. hr = E_INVALIDARG;
  5885. _JumpError(hr, error, "No valid trust chain could be formed");
  5886. }
  5887. // tell global how many elements we have in our chain
  5888. cCACertChain = pCertChainContext->rgpChain[0]->cElement;
  5889. // Allocate memory for global. Allocate one extra pointer to allow loop
  5890. // to assign NULL pointer in place in array. Leave the count set to the
  5891. // actual number of CA cert contexts, excluding the NULL pointer.
  5892. apCACertChain = (CERT_CONTEXT const **) LocalAlloc(
  5893. LMEM_FIXED,
  5894. (cCACertChain + 1) * sizeof(apCACertChain[0]));
  5895. if (NULL == apCACertChain)
  5896. {
  5897. hr = E_OUTOFMEMORY;
  5898. _JumpError(hr, error, "LocalAlloc");
  5899. }
  5900. // copy chain in reverse order: from parent to child
  5901. {
  5902. int i;
  5903. for (i = cCACertChain - 1; i >= 0; i--)
  5904. {
  5905. apCACertChain[i] = CertDuplicateCertificateContext(
  5906. pCertChainContext->rgpChain[0]->rgpElement[i]->pCertContext);
  5907. if (NULL == apCACertChain[i])
  5908. {
  5909. hr = myHLastError();
  5910. _JumpError(hr, error, "CertDuplicateCertificateContext");
  5911. }
  5912. }
  5913. }
  5914. }
  5915. for (i = 0; i < g_cCACerts; i++)
  5916. {
  5917. if (iCert < g_aCAContext[i].iCert)
  5918. {
  5919. MoveMemory(
  5920. &g_aCAContext[i + 1],
  5921. &g_aCAContext[i],
  5922. (g_cCACerts - i) * sizeof(g_aCAContext[0]));
  5923. break;
  5924. }
  5925. }
  5926. g_cCACerts++;
  5927. pCAContext = &g_aCAContext[i];
  5928. ZeroMemory(pCAContext, sizeof(*pCAContext));
  5929. if (NULL == pccCA)
  5930. {
  5931. pCAContext->Flags |= CTXF_CERTMISSING | CTXF_SKIPCRL;
  5932. }
  5933. pCAContext->iCert = iCert;
  5934. pCAContext->iKey = iKey;
  5935. pCAContext->NameId = MAKECANAMEID(iCert, iKey);
  5936. pCAContext->hProvCA = hProvCA;
  5937. hProvCA = NULL;
  5938. pCAContext->pccCA = pccCA;
  5939. pccCA = NULL;
  5940. if (NULL != apCACertChain)
  5941. {
  5942. pCAContext->cCACertChain = cCACertChain;
  5943. pCAContext->apCACertChain = apCACertChain;
  5944. apCACertChain = NULL;
  5945. }
  5946. pCAContext->pszObjIdSignatureAlgorithm = pszObjIdSignatureAlgorithm;
  5947. pszObjIdSignatureAlgorithm = NULL;
  5948. pCAContext->pwszKeyContainerName = pwszKeyContainerName;
  5949. pwszKeyContainerName = NULL;
  5950. // Ignore failure from here on -- collected data is optional
  5951. if (NULL != pCAContext->pccCA)
  5952. {
  5953. hr = myGetPublicKeyHash(
  5954. pCAContext->pccCA->pCertInfo,
  5955. &pCAContext->pccCA->pCertInfo->SubjectPublicKeyInfo,
  5956. &pCAContext->IssuerKeyId.pbData,
  5957. &pCAContext->IssuerKeyId.cbData);
  5958. _PrintIfError(hr, "myGetPublicKeyHash");
  5959. if (0 == (CTXF_SKIPCRL & pCAContext->Flags))
  5960. {
  5961. hr = pkcsBuildKeyAuthority2(
  5962. g_CRLEditFlags,
  5963. pCAContext,
  5964. &pCAContext->KeyAuthority2CRL);
  5965. _PrintIfError(hr, "pkcsBuildKeyAuthority2");
  5966. hr = pkcsBuildCDP(
  5967. CSURL_ADDTOFRESHESTCRL,
  5968. TRUE,
  5969. pCAContext,
  5970. &pCAContext->CDPCRLFreshest);
  5971. _PrintIfError(hr, "pkcsBuildCDP");
  5972. hr = pkcsBuildCDP(
  5973. CSURL_ADDTOCRLCDP,
  5974. FALSE,
  5975. pCAContext,
  5976. &pCAContext->CDPCRLBase);
  5977. _PrintIfError(hr, "pkcsBuildCDP");
  5978. hr = pkcsBuildCDP(
  5979. CSURL_ADDTOCRLCDP,
  5980. TRUE,
  5981. pCAContext,
  5982. &pCAContext->CDPCRLDelta);
  5983. _PrintIfError(hr, "pkcsBuildCDP");
  5984. hr = pkcsBuildCRLList(
  5985. FALSE,
  5986. pCAContext,
  5987. &pCAContext->papwszCRLFiles);
  5988. _JumpIfError(hr, error, "pkcsBuildCRLList");
  5989. hr = pkcsBuildCRLList(
  5990. TRUE,
  5991. pCAContext,
  5992. &pCAContext->papwszDeltaCRLFiles);
  5993. _JumpIfError(hr, error, "pkcsBuildCRLList");
  5994. }
  5995. }
  5996. hr = S_OK;
  5997. error:
  5998. if (NULL != hProvCA)
  5999. {
  6000. CryptReleaseContext(hProvCA, 0);
  6001. }
  6002. if (NULL != pszObjIdSignatureAlgorithm)
  6003. {
  6004. LocalFree(pszObjIdSignatureAlgorithm);
  6005. }
  6006. if (NULL != pwszKeyContainerName)
  6007. {
  6008. LocalFree(pwszKeyContainerName);
  6009. }
  6010. if (NULL != pKey)
  6011. {
  6012. LocalFree(pKey);
  6013. }
  6014. if (pCertChainContext != NULL)
  6015. {
  6016. CertFreeCertificateChain(pCertChainContext);
  6017. }
  6018. if (NULL != pccCA)
  6019. {
  6020. CertFreeCertificateContext(pccCA);
  6021. }
  6022. return(hr);
  6023. }
  6024. HRESULT
  6025. pkcsLoadCAContextArray(
  6026. IN WCHAR const *pwszCommonName,
  6027. IN WCHAR const *pwszSanitizedName)
  6028. {
  6029. HRESULT hr;
  6030. DWORD cCACerts;
  6031. HCERTSTORE hMyStore = NULL;
  6032. WCHAR *pwszProvName = NULL;
  6033. DWORD dwProvType;
  6034. ALG_ID idAlg;
  6035. BOOL fMachineKeyset;
  6036. DWORD iHash;
  6037. // get provider name
  6038. hr = myGetCertSrvCSP(
  6039. FALSE, // fEncryptionCSP
  6040. pwszSanitizedName,
  6041. &dwProvType,
  6042. &pwszProvName,
  6043. &idAlg,
  6044. &fMachineKeyset,
  6045. NULL); // pdwKeySize
  6046. _JumpIfError(hr, error, "myGetCertSrvCSP");
  6047. // open MY store
  6048. hMyStore = CertOpenStore(
  6049. CERT_STORE_PROV_SYSTEM_W,
  6050. X509_ASN_ENCODING,
  6051. NULL, // hProv
  6052. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  6053. wszMY_CERTSTORE);
  6054. if (NULL == hMyStore)
  6055. {
  6056. hr = myHLastError();
  6057. _JumpError(hr, error, "CertOpenStore");
  6058. }
  6059. // find & load CA certs, etc.
  6060. hr = myGetCARegHashCount(pwszSanitizedName, CSRH_CASIGCERT, &cCACerts);
  6061. if (S_OK == hr && 0 == cCACerts)
  6062. {
  6063. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  6064. }
  6065. _JumpIfError(hr, error, "myGetCARegHashCount");
  6066. g_aCAContext = (CACTX *) LocalAlloc(
  6067. LMEM_FIXED | LMEM_ZEROINIT,
  6068. cCACerts * sizeof(g_aCAContext[0]));
  6069. if (NULL == g_aCAContext)
  6070. {
  6071. hr = E_OUTOFMEMORY;
  6072. _JumpError(hr, error, "LocalAlloc");
  6073. }
  6074. for (iHash = 0; iHash < cCACerts; iHash++)
  6075. {
  6076. hr = pkcsLoadCAContext(
  6077. pwszSanitizedName,
  6078. pwszProvName,
  6079. dwProvType,
  6080. idAlg,
  6081. fMachineKeyset,
  6082. iHash,
  6083. hMyStore);
  6084. if (S_FALSE == hr)
  6085. {
  6086. continue;
  6087. }
  6088. _JumpIfError(hr, error, "pkcsLoadCAContext");
  6089. }
  6090. g_pCAContextCurrent = &g_aCAContext[g_cCACerts - 1];
  6091. // Only build a Key Authority extension for the current CACTX -- it's the
  6092. // only one used to issue certs.
  6093. hr = pkcsBuildKeyAuthority2(
  6094. EDITF_ENABLEAKIKEYID |
  6095. EDITF_ENABLEAKIISSUERNAME |
  6096. EDITF_ENABLEAKIISSUERSERIAL,
  6097. g_pCAContextCurrent,
  6098. &g_pCAContextCurrent->KeyAuthority2Cert);
  6099. _PrintIfError(hr, "pkcsBuildKeyAuthority2");
  6100. // Only build a CDP extension for the current CACTX -- it's the
  6101. // only one used to issue certs.
  6102. hr = pkcsBuildCDP(
  6103. CSURL_ADDTOCERTCDP,
  6104. FALSE,
  6105. g_pCAContextCurrent,
  6106. &g_pCAContextCurrent->CDPCert);
  6107. _PrintIfError(hr, "pkcsBuildCDP");
  6108. // Only build a CDP extension for the current CACTX -- it's the
  6109. // only one used to issue certs.
  6110. hr = pkcsBuildAIA(
  6111. CSURL_ADDTOCERTCDP | CSURL_ADDTOCERTOCSP,
  6112. g_pCAContextCurrent,
  6113. &g_pCAContextCurrent->AIACert);
  6114. _PrintIfError(hr, "pkcsBuildAIA");
  6115. hr = S_OK;
  6116. error:
  6117. if (NULL != pwszProvName)
  6118. {
  6119. LocalFree(pwszProvName);
  6120. }
  6121. if (NULL != hMyStore)
  6122. {
  6123. CertCloseStore(hMyStore, CERT_CLOSE_STORE_CHECK_FLAG);
  6124. }
  6125. return(hr);
  6126. }
  6127. HRESULT
  6128. pkcsImportCAOrKRACert(
  6129. IN CERT_CONTEXT const *pcc,
  6130. IN DWORD DBDisposition,
  6131. OPTIONAL IN CACTX const *pCAContext)
  6132. {
  6133. HRESULT hr;
  6134. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  6135. DWORD cbHash;
  6136. BSTR strHash = NULL;
  6137. ICertDBRow *prow = NULL;
  6138. WCHAR *pwszUserName = NULL;
  6139. DWORD cb;
  6140. BOOL fCommit = FALSE;
  6141. BOOL fCommitted = FALSE;
  6142. cbHash = sizeof(abHash);
  6143. if (!CertGetCertificateContextProperty(
  6144. pcc,
  6145. CERT_HASH_PROP_ID,
  6146. abHash,
  6147. &cbHash))
  6148. {
  6149. hr = myHLastError();
  6150. _JumpError(hr, error, "CertGetCertificateContextProperty");
  6151. }
  6152. hr = MultiByteIntegerToBstr(TRUE, cbHash, abHash, &strHash);
  6153. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  6154. // Import Cert if it doesn't already exist in DB:
  6155. hr = g_pCertDB->OpenRow(
  6156. PROPOPEN_CERTHASH | PROPTABLE_REQCERT,
  6157. 0,
  6158. strHash,
  6159. &prow);
  6160. if (S_OK != hr)
  6161. {
  6162. CSASSERT(CERTSRV_E_PROPERTY_EMPTY == hr);
  6163. hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, 0, NULL, &prow);
  6164. _JumpIfError(hr, error, "OpenRow");
  6165. hr = PKCSParseImportedCertificate(
  6166. DBDisposition,
  6167. prow,
  6168. pCAContext,
  6169. pcc);
  6170. _JumpIfError(hr, error, "PKCSParseImportedCertificate");
  6171. fCommit = TRUE;
  6172. }
  6173. // Set requester name if missing
  6174. hr = prow->GetProperty(
  6175. g_wszPropRequesterName,
  6176. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  6177. &cb,
  6178. NULL);
  6179. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  6180. {
  6181. hr = myGetComputerObjectName(NameSamCompatible, &pwszUserName);
  6182. if (S_OK != hr)
  6183. {
  6184. _PrintError(hr, "myGetComputerObjectName");
  6185. hr = myGetUserNameEx(NameSamCompatible, &pwszUserName);
  6186. _JumpIfError(hr, error, "myGetUserNameEx");
  6187. }
  6188. hr = prow->SetProperty(
  6189. g_wszPropRequesterName,
  6190. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  6191. MAXDWORD,
  6192. (BYTE const *) pwszUserName);
  6193. _JumpIfError(hr, error, "SetProperty");
  6194. hr = prow->SetProperty(
  6195. g_wszPropCallerName,
  6196. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  6197. MAXDWORD,
  6198. (BYTE const *) pwszUserName);
  6199. _JumpIfError(hr, error, "SetProperty");
  6200. fCommit = TRUE;
  6201. }
  6202. hr = prow->CommitTransaction(fCommit);
  6203. _JumpIfError(hr, error, "CommitTransaction");
  6204. fCommitted = TRUE;
  6205. hr = S_OK;
  6206. error:
  6207. if (NULL != prow)
  6208. {
  6209. if (S_OK != hr && !fCommitted)
  6210. {
  6211. HRESULT hr2 = prow->CommitTransaction(FALSE);
  6212. _PrintIfError(hr2, "CommitTransaction");
  6213. }
  6214. prow->Release();
  6215. }
  6216. if (NULL != pwszUserName)
  6217. {
  6218. LocalFree(pwszUserName);
  6219. }
  6220. if (NULL != strHash)
  6221. {
  6222. SysFreeString(strHash);
  6223. }
  6224. return(hr);
  6225. }
  6226. HRESULT
  6227. pkcsImportCAContext(
  6228. IN CACTX const *pCAContext)
  6229. {
  6230. HRESULT hr;
  6231. HRESULT hr2;
  6232. DWORD i;
  6233. hr = S_OK;
  6234. for (i = 0; i < pCAContext->cCACertChain; i++)
  6235. {
  6236. CERT_CONTEXT const *pCert = pCAContext->apCACertChain[i];
  6237. hr2 = pkcsImportCAOrKRACert(
  6238. pCert,
  6239. 0 == i? DB_DISP_CA_CERT : DB_DISP_CA_CERT_CHAIN,
  6240. pCAContext);
  6241. if (S_OK != hr2)
  6242. {
  6243. if (S_OK == hr)
  6244. {
  6245. hr = hr2; // return first error
  6246. }
  6247. _PrintError(hr2, "pkcsImportCAOrKRACert");
  6248. continue;
  6249. }
  6250. }
  6251. _JumpIfError(hr, error, "pkcsImportCAOrKRACert");
  6252. error:
  6253. return(hr);
  6254. }
  6255. HRESULT
  6256. pkcsImportCAContextArray()
  6257. {
  6258. HRESULT hr = S_OK;
  6259. HRESULT hr2;
  6260. DWORD i;
  6261. for (i = 0; i < g_cCACerts; i++)
  6262. {
  6263. CACTX *pCAContext = &g_aCAContext[i];
  6264. if (NULL == pCAContext->pccCA)
  6265. {
  6266. continue;
  6267. }
  6268. hr2 = pkcsImportCAContext(pCAContext);
  6269. if (S_OK != hr2)
  6270. {
  6271. _PrintError(hr2, "pkcsImportCAContext");
  6272. if (S_OK == hr)
  6273. {
  6274. hr = hr2; // return first error
  6275. }
  6276. }
  6277. }
  6278. //error:
  6279. return(hr);
  6280. }
  6281. PCCERT_CONTEXT pkcsFindCertificateInOtherStore(
  6282. IN HCERTSTORE hOtherStore,
  6283. IN PCCERT_CONTEXT pCert
  6284. )
  6285. {
  6286. BYTE rgbHash[SHA1_HASH_LENGTH];
  6287. CRYPT_DATA_BLOB HashBlob;
  6288. HashBlob.pbData = rgbHash;
  6289. HashBlob.cbData = SHA1_HASH_LENGTH;
  6290. if (!CertGetCertificateContextProperty(
  6291. pCert,
  6292. CERT_SHA1_HASH_PROP_ID,
  6293. rgbHash,
  6294. &HashBlob.cbData
  6295. ) || SHA1_HASH_LENGTH != HashBlob.cbData)
  6296. return NULL;
  6297. return CertFindCertificateInStore(
  6298. hOtherStore,
  6299. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, // dwCertEncodingType
  6300. 0, // dwFindFlags
  6301. CERT_FIND_SHA1_HASH,
  6302. (const void *) &HashBlob,
  6303. NULL //pPrevCertContext
  6304. );
  6305. }
  6306. HRESULT pkcsObtainNTAuthStore(IN HCERTSTORE *phCertStore)
  6307. {
  6308. HRESULT hr=E_INVALIDARG;
  6309. HCERTSTORE hEnterpriseStore = NULL;
  6310. LPWSTR pwszLdapStore=NULL;
  6311. if((NULL==phCertStore) || (NULL==g_strConfigDN))
  6312. _JumpError(hr, error, "LocalAlloc for pwazLdapStore");
  6313. *phCertStore=NULL;
  6314. pwszLdapStore = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*(wcslen(g_strConfigDN)+wcslen(g_wszNTAuth)));
  6315. if(pwszLdapStore == NULL)
  6316. {
  6317. hr = E_OUTOFMEMORY;
  6318. _JumpError(hr, error, "LocalAlloc for pwazLdapStore");
  6319. }
  6320. wsprintf(pwszLdapStore,
  6321. g_wszNTAuth,
  6322. g_strConfigDN);
  6323. hEnterpriseStore = CertOpenStore(CERT_STORE_PROV_LDAP,
  6324. 0,
  6325. 0,
  6326. CERT_STORE_READONLY_FLAG | CERT_LDAP_STORE_SIGN_FLAG,
  6327. pwszLdapStore);
  6328. if(NULL == hEnterpriseStore)
  6329. {
  6330. hr=myHLastError();
  6331. _JumpError(hr, error, "CertOpenStore");
  6332. }
  6333. *phCertStore=hEnterpriseStore;
  6334. hr = S_OK;
  6335. error:
  6336. if(pwszLdapStore)
  6337. LocalFree(pwszLdapStore);
  6338. return hr;
  6339. }
  6340. HRESULT
  6341. pkcsVerifySignatureCertContext(
  6342. IN WCHAR const * pwszCommonName,
  6343. IN HCERTSTORE hNTAuthStore,
  6344. IN DWORD dwCAIndex,
  6345. IN OUT CACTX *pCAContext,
  6346. OUT DWORD *pLogMsg,
  6347. OUT BOOL *pfWarn)
  6348. {
  6349. HRESULT hr;
  6350. WCHAR awc[11];
  6351. WCHAR const *apwsz[2];
  6352. PCCERT_CONTEXT pCertContext = NULL;
  6353. *pLogMsg = 0;
  6354. *pfWarn = FALSE;
  6355. hr = myVerifyCertContext(
  6356. pCAContext->pccCA, // pCert
  6357. 0, // dwFlags
  6358. 0, // cUsageOids
  6359. NULL, // apszUsageOids
  6360. HCCE_LOCAL_MACHINE, // hChainEngine
  6361. NULL, // hAdditionalStore
  6362. NULL); // ppwszMissingIssuer
  6363. pCAContext->hrVerifyStatus = hr;
  6364. if (S_OK != hr)
  6365. {
  6366. _PrintError2(hr, "myVerifyCertContext", CRYPT_E_REVOCATION_OFFLINE);
  6367. if (CERT_E_EXPIRED == hr)
  6368. {
  6369. pCAContext->Flags |= CTXF_EXPIRED;
  6370. if (0 == (CRLF_PUBLISH_EXPIRED_CERT_CRLS & g_dwCRLFlags))
  6371. {
  6372. pCAContext->Flags |= CTXF_SKIPCRL;
  6373. }
  6374. *pLogMsg = MSG_E_CA_CERT_EXPIRED;
  6375. }
  6376. else if (CRYPT_E_REVOKED == hr)
  6377. {
  6378. pCAContext->Flags |= CTXF_REVOKED | CTXF_SKIPCRL;
  6379. *pLogMsg = MSG_E_CA_CERT_REVOKED;
  6380. }
  6381. else if (CRYPT_E_REVOCATION_OFFLINE == hr)
  6382. {
  6383. DWORD dwState;
  6384. hr = GetSetupStatus(NULL, &dwState);
  6385. if ((S_OK != hr || 0 == (SETUP_CREATEDB_FLAG & dwState)) &&
  6386. CERTLOG_WARNING <= g_dwLogLevel)
  6387. {
  6388. *pLogMsg = MSG_E_CA_CERT_REVOCATION_OFFLINE;
  6389. *pfWarn = TRUE;
  6390. }
  6391. else
  6392. {
  6393. hr = S_OK;
  6394. }
  6395. }
  6396. else if (CRYPT_E_NO_REVOCATION_CHECK == hr)
  6397. {
  6398. if (CERTLOG_VERBOSE <= g_dwLogLevel)
  6399. {
  6400. *pLogMsg = MSG_E_CA_CERT_REVOCATION_NOT_CHECKED;
  6401. *pfWarn = TRUE;
  6402. }
  6403. else
  6404. {
  6405. hr = S_OK;
  6406. }
  6407. }
  6408. else
  6409. {
  6410. *pLogMsg = MSG_E_CA_CHAIN;
  6411. }
  6412. _JumpIfError(hr, error, "myVerifyCertContext");
  6413. }
  6414. //the CA's certificate looks good. We verify the CA's
  6415. //certificate is in the NTAuth store
  6416. if(hNTAuthStore)
  6417. {
  6418. if(NULL == (pCertContext=pkcsFindCertificateInOtherStore(
  6419. hNTAuthStore,
  6420. pCAContext->pccCA)))
  6421. {
  6422. wsprintf(awc, L"%u", dwCAIndex);
  6423. apwsz[0] = awc;
  6424. apwsz[1] = pwszCommonName;
  6425. LogEvent(EVENTLOG_WARNING_TYPE, MSG_CA_CERT_NO_IN_AUTH, ARRAYSIZE(apwsz), apwsz);
  6426. }
  6427. if(pCertContext)
  6428. CertFreeCertificateContext(pCertContext);
  6429. }
  6430. error:
  6431. return(hr);
  6432. }
  6433. HRESULT
  6434. pkcsVerifySignatureCertContextArray(
  6435. IN WCHAR const * pwszCommonName,
  6436. OUT DWORD *pLogMsg,
  6437. OUT BOOL *pfWarn)
  6438. {
  6439. HRESULT hr;
  6440. DWORD i;
  6441. WCHAR const *apwsz[1];
  6442. HCERTSTORE hNTAuthStore=NULL;
  6443. CSASSERT(0 != g_cCACerts);
  6444. //we need to verify CA's certificates should be in
  6445. //the NTAuth store if the certificate is not yet expired or revoked
  6446. if(IsEnterpriseCA(g_CAType))
  6447. {
  6448. pkcsObtainNTAuthStore(&hNTAuthStore);
  6449. if(NULL == hNTAuthStore)
  6450. {
  6451. apwsz[0] = pwszCommonName;
  6452. LogEvent(EVENTLOG_WARNING_TYPE, MSG_CA_CERT_NO_AUTH_STORE, ARRAYSIZE(apwsz), apwsz);
  6453. }
  6454. }
  6455. for (i = 0; i < g_cCACerts; i++)
  6456. {
  6457. CACTX *pCAContext = &g_aCAContext[i];
  6458. if (NULL == pCAContext->pccCA)
  6459. {
  6460. continue;
  6461. }
  6462. // Ignore all errors except for the current CA (last entry in array)
  6463. hr = pkcsVerifySignatureCertContext(
  6464. pwszCommonName,
  6465. hNTAuthStore,
  6466. i,
  6467. pCAContext,
  6468. pLogMsg,
  6469. pfWarn);
  6470. }
  6471. if(hNTAuthStore)
  6472. CertCloseStore(hNTAuthStore, 0);
  6473. return(hr);
  6474. }
  6475. VOID
  6476. PKCSVerifyCAState(
  6477. IN OUT CACTX *pCAContext)
  6478. {
  6479. HRESULT hr;
  6480. if (0 == pCAContext->Flags && NULL != pCAContext->pccCA)
  6481. {
  6482. DWORD LogMsg = MAXDWORD;
  6483. BOOL fWarn = FALSE;
  6484. hr = pkcsVerifySignatureCertContext(NULL, NULL, 0, pCAContext, &LogMsg, &fWarn);
  6485. if (S_OK != hr)
  6486. {
  6487. CSASSERT(MAXDWORD != LogMsg);
  6488. LogEventStringHResult(
  6489. fWarn? EVENTLOG_WARNING_TYPE : EVENTLOG_ERROR_TYPE,
  6490. LogMsg,
  6491. g_wszCommonName,
  6492. hr);
  6493. }
  6494. }
  6495. }
  6496. HRESULT
  6497. pkcsVerifyDSCACert(
  6498. IN LDAP *pld)
  6499. {
  6500. HRESULT hr;
  6501. HCAINFO hCAInfo = NULL;
  6502. PCCERT_CONTEXT pDSCertContext = NULL;
  6503. // BUGBUG: verify all of this CA's unexpired signature certs are in the DS.
  6504. // Republish any that aren't. Cleans up DS replication conflicts.
  6505. CSASSERT(g_pCAContextCurrent && g_pCAContextCurrent->pccCA);
  6506. hr = CAFindByName(
  6507. g_wszSanitizedName,
  6508. NULL,
  6509. CA_FIND_LOCAL_SYSTEM |
  6510. CA_FIND_INCLUDE_UNTRUSTED, // this will cause findbyname to skip
  6511. &hCAInfo); // ca cert checking
  6512. _JumpIfErrorStr(hr, error, "CAFindByName", g_wszSanitizedName);
  6513. hr = CAGetCACertificate(hCAInfo, &pDSCertContext);
  6514. _JumpIfError(hr, error, "CAGetCACertificate");
  6515. if(!pDSCertContext ||
  6516. pDSCertContext->cbCertEncoded !=
  6517. g_pCAContextCurrent->pccCA->cbCertEncoded ||
  6518. 0 != memcmp(pDSCertContext->pbCertEncoded,
  6519. g_pCAContextCurrent->pccCA->pbCertEncoded,
  6520. g_pCAContextCurrent->pccCA->cbCertEncoded))
  6521. {
  6522. // published cert is invalid or old, publish the current one
  6523. hr = CASetCACertificate(
  6524. hCAInfo,
  6525. g_pCAContextCurrent->pccCA);
  6526. _JumpIfError(hr, error, "CASetCACertificate");
  6527. hr = CAUpdateCA(hCAInfo);
  6528. _JumpIfError(hr, error, "CAUpdateCA");
  6529. {
  6530. CAuditEvent audit(SE_AUDITID_CERTSRV_PUBLISHCACERT, g_dwAuditFilter);
  6531. hr = audit.AddData( // %1 Certificate Hash
  6532. g_pCAContextCurrent->pccCA->pCertInfo->SerialNumber.pbData,
  6533. g_pCAContextCurrent->pccCA->pCertInfo->SerialNumber.cbData);
  6534. _JumpIfError(hr, error, "CAuditEvent::AddData");
  6535. hr = audit.AddData(g_pCAContextCurrent->pccCA->pCertInfo->NotBefore); // %2 Valid From
  6536. _JumpIfError(hr, error, "CAuditEvent::AddData");
  6537. hr = audit.AddData(g_pCAContextCurrent->pccCA->pCertInfo->NotAfter); //%3 Valid To
  6538. _JumpIfError(hr, error, "CAuditEvent::AddData");
  6539. hr = audit.Report();
  6540. _JumpIfError(hr, error, "CAuditEvent::Report");
  6541. }
  6542. }
  6543. hr = S_OK;
  6544. error:
  6545. if(hCAInfo)
  6546. {
  6547. CACloseCA(hCAInfo);
  6548. }
  6549. if(pDSCertContext)
  6550. {
  6551. CertFreeCertificateContext(pDSCertContext);
  6552. }
  6553. return(hr);
  6554. }
  6555. VOID
  6556. pkcsReleaseKRACertArray()
  6557. {
  6558. DWORD i;
  6559. if (NULL != g_rgKRACerts)
  6560. {
  6561. for (i = 0; i < g_cKRACerts; i++)
  6562. {
  6563. if (NULL != g_rgKRACerts[i])
  6564. {
  6565. CertFreeCertificateContext(g_rgKRACerts[i]);
  6566. }
  6567. }
  6568. LocalFree(g_rgKRACerts);
  6569. g_rgKRACerts = NULL;
  6570. }
  6571. if (NULL != g_rgstrKRAHashes)
  6572. {
  6573. for (i = 0; i < g_cKRACerts; i++)
  6574. {
  6575. if (NULL != g_rgstrKRAHashes[i])
  6576. {
  6577. SysFreeString(g_rgstrKRAHashes[i]);
  6578. }
  6579. }
  6580. LocalFree(g_rgstrKRAHashes);
  6581. g_rgstrKRAHashes = NULL;
  6582. }
  6583. g_cKRACerts = 0;
  6584. g_hrKRALoad = S_OK;
  6585. }
  6586. VOID
  6587. pkcsLogKRACertError(
  6588. IN DWORD LogMsg,
  6589. IN DWORD iHash,
  6590. OPTIONAL IN CERT_CONTEXT const *pcc,
  6591. IN HRESULT hrLog)
  6592. {
  6593. HRESULT hr;
  6594. WCHAR awc[11];
  6595. WCHAR *pwszName = NULL;
  6596. WCHAR const *pwszError = NULL;
  6597. WCHAR const *apwsz[3];
  6598. wsprintf(awc, L"%u", iHash);
  6599. apwsz[0] = awc;
  6600. if (NULL != pcc)
  6601. {
  6602. hr = myCertNameToStr(
  6603. X509_ASN_ENCODING,
  6604. &pcc->pCertInfo->Subject,
  6605. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  6606. &pwszName);
  6607. _PrintIfError(hr, "myCertNameToStr");
  6608. }
  6609. apwsz[1] = NULL != pwszName? pwszName : L"";
  6610. pwszError = myGetErrorMessageText(hrLog, TRUE);
  6611. apwsz[2] = NULL != pwszError? pwszError : L"";
  6612. LogEvent(EVENTLOG_ERROR_TYPE, LogMsg, ARRAYSIZE(apwsz), apwsz);
  6613. //error:
  6614. if (NULL != pwszName)
  6615. {
  6616. LocalFree(pwszName);
  6617. }
  6618. if (NULL != pwszError)
  6619. {
  6620. LocalFree(const_cast<WCHAR *>(pwszError));
  6621. }
  6622. }
  6623. HRESULT
  6624. pkcsLoadKRACertContext(
  6625. IN DWORD iHash,
  6626. IN HCERTSTORE hStore)
  6627. {
  6628. HRESULT hr;
  6629. CERT_CONTEXT const *pcc = NULL;
  6630. BSTR strHash = NULL;
  6631. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  6632. DWORD cbHash;
  6633. DWORD LogMsg = 0;
  6634. BOOL fReloaded;
  6635. DBGPRINT((DBG_SS_CERTSRV, "Loading KRA Cert[%u]:\n", iHash));
  6636. fReloaded = FALSE;
  6637. while (TRUE)
  6638. {
  6639. hr = myFindCACertByHashIndex(
  6640. hStore,
  6641. g_wszSanitizedName,
  6642. CSRH_CAKRACERT,
  6643. iHash,
  6644. NULL, // pNameId
  6645. &pcc);
  6646. if (S_OK == hr)
  6647. {
  6648. break;
  6649. }
  6650. if (fReloaded || CRYPT_E_NOT_FOUND != hr)
  6651. {
  6652. _JumpError(hr, error, "myFindCACertByHashIndex");
  6653. }
  6654. _PrintError(hr, "myFindCACertByHashIndex");
  6655. // The KRA cert is missing from the HKLM "kra" store -- look it up in
  6656. // the DB, and put it back in the store.
  6657. hr = pkcsReloadMissingCAOrKRACert(
  6658. hStore,
  6659. g_wszSanitizedName,
  6660. CSRH_CAKRACERT,
  6661. iHash);
  6662. _JumpIfError(hr, error, "pkcsReloadMissingCAOrKRACert");
  6663. fReloaded = TRUE;
  6664. }
  6665. hr = myVerifyKRACertContext(
  6666. pcc,
  6667. (CRLF_REVCHECK_IGNORE_OFFLINE & g_dwCRLFlags)?
  6668. CA_VERIFY_FLAGS_IGNORE_OFFLINE : 0);
  6669. if (S_OK != hr)
  6670. {
  6671. LogMsg = MSG_E_INVALID_KRA_CERT;
  6672. _JumpErrorStr(hr, error, "myVerifyKRACertContext", L"KRA cert invalid");
  6673. }
  6674. hr = pkcsImportCAOrKRACert(pcc, DB_DISP_KRA_CERT, NULL);
  6675. _JumpIfError(hr, error, "pkcsReloadMissingCAOrKRACert");
  6676. cbHash = sizeof(abHash);
  6677. if (!CertGetCertificateContextProperty(
  6678. pcc,
  6679. CERT_SHA1_HASH_PROP_ID,
  6680. abHash,
  6681. &cbHash))
  6682. {
  6683. hr = myHLastError();
  6684. _JumpError(hr, error, "CertGetCertificateContextProperty");
  6685. }
  6686. hr = MultiByteIntegerToBstr(TRUE, cbHash, abHash, &strHash);
  6687. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  6688. g_rgstrKRAHashes[g_cKRACerts] = strHash;
  6689. g_rgKRACerts[g_cKRACerts] = pcc;
  6690. g_cKRACerts++;
  6691. strHash = NULL;
  6692. pcc = NULL;
  6693. hr = S_OK;
  6694. error:
  6695. if (S_OK != hr)
  6696. {
  6697. if (0 == LogMsg)
  6698. {
  6699. LogMsg = MSG_E_CANNOT_LOAD_KRA_CERT;
  6700. }
  6701. pkcsLogKRACertError(LogMsg, iHash, pcc, hr);
  6702. }
  6703. if (NULL != strHash)
  6704. {
  6705. SysFreeString(strHash);
  6706. }
  6707. if (NULL != pcc)
  6708. {
  6709. CertFreeCertificateContext(pcc);
  6710. }
  6711. return(hr);
  6712. }
  6713. HRESULT
  6714. pkcsLoadKRACertArray()
  6715. {
  6716. HRESULT hr;
  6717. DWORD iHash;
  6718. DWORD i;
  6719. HCERTSTORE hStore = NULL;
  6720. DWORD LogMsg = 0;
  6721. if (!g_fAdvancedServer)
  6722. {
  6723. LogMsg = MSG_E_KRA_NOT_ADVANCED_SERVER;
  6724. hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
  6725. _JumpError(hr, error, "!g_fAdvancedServer");
  6726. }
  6727. // open KRA store
  6728. hStore = CertOpenStore(
  6729. CERT_STORE_PROV_SYSTEM_W,
  6730. X509_ASN_ENCODING,
  6731. NULL, // hProv
  6732. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  6733. wszKRA_CERTSTORE);
  6734. if (NULL == hStore)
  6735. {
  6736. hr = myHLastError();
  6737. _JumpError(hr, error, "CertOpenStore");
  6738. }
  6739. // find & load KRA certs
  6740. hr = myGetCARegHashCount(g_wszSanitizedName, CSRH_CAKRACERT, &g_cKRAHashes);
  6741. if (S_OK == hr && 0 == g_cKRAHashes)
  6742. {
  6743. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  6744. }
  6745. _JumpIfError(hr, error, "myGetCARegHashCount");
  6746. g_rgKRACerts = (CERT_CONTEXT const **) LocalAlloc(
  6747. LMEM_FIXED | LMEM_ZEROINIT,
  6748. g_cKRAHashes * sizeof(g_rgKRACerts[0]));
  6749. if (NULL == g_rgKRACerts)
  6750. {
  6751. hr = E_OUTOFMEMORY;
  6752. _JumpError(hr, error, "LocalAlloc");
  6753. }
  6754. g_rgstrKRAHashes = (BSTR *) LocalAlloc(
  6755. LMEM_FIXED | LMEM_ZEROINIT,
  6756. g_cKRAHashes * sizeof(g_rgstrKRAHashes[0]));
  6757. if (NULL == g_rgstrKRAHashes)
  6758. {
  6759. hr = E_OUTOFMEMORY;
  6760. _JumpError(hr, error, "LocalAlloc");
  6761. }
  6762. for (iHash = 0; iHash < g_cKRAHashes; iHash++)
  6763. {
  6764. hr = pkcsLoadKRACertContext(iHash, hStore);
  6765. if (S_OK != hr)
  6766. {
  6767. _PrintError(hr, "pkcsLoadKRACertContext");
  6768. g_hrKRALoad = hr;
  6769. }
  6770. }
  6771. if (0 == g_cKRACerts)
  6772. {
  6773. LogMsg = MSG_E_NO_VALID_KRA_CERTS;
  6774. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  6775. _JumpError(hr, error, "g_cKRACerts == 0");
  6776. }
  6777. g_iKRACerts = 0;
  6778. if (g_cKRACerts > g_cKRACertsRoundRobin)
  6779. {
  6780. srand((unsigned) time(NULL));
  6781. g_iKRACerts = rand() % g_cKRACerts;
  6782. }
  6783. else
  6784. {
  6785. g_cKRACertsRoundRobin = g_cKRACerts;
  6786. }
  6787. hr = S_OK;
  6788. error:
  6789. if (S_OK != hr)
  6790. {
  6791. if (0 == LogMsg)
  6792. {
  6793. LogMsg = MSG_E_LOADING_KRA_CERTS;
  6794. }
  6795. LogEventHResult(EVENTLOG_ERROR_TYPE, LogMsg, hr);
  6796. pkcsReleaseKRACertArray();
  6797. }
  6798. if (NULL != hStore)
  6799. {
  6800. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  6801. }
  6802. return(hr);
  6803. }
  6804. HRESULT
  6805. pkcsExpandURL(
  6806. IN WCHAR const *pwszURLTemplate,
  6807. OUT WCHAR **ppwszURL)
  6808. {
  6809. HRESULT hr;
  6810. *ppwszURL = NULL;
  6811. CSASSERT(NULL != g_strDomainDN && NULL != g_strConfigDN);
  6812. hr = myFormatCertsrvStringArray(
  6813. FALSE, // fURL
  6814. g_pwszServerName, // pwszServerName_p1_2
  6815. g_wszSanitizedName, // pwszSanitizedName_p3_7
  6816. 0, // iCert_p4
  6817. g_strDomainDN, // pwszDomainDN_p5
  6818. g_strConfigDN, // pwszConfigDN_p6
  6819. 0, // iCRL_p8
  6820. FALSE, // fDeltaCRL_p9
  6821. FALSE, // fDSAttrib_p10_11
  6822. 1, // cStrings
  6823. &pwszURLTemplate, // apwszStringsIn
  6824. ppwszURL); // apwszStringsOut
  6825. _JumpIfError(hr, error, "myFormatCertsrvStringArray");
  6826. error:
  6827. return(hr);
  6828. }
  6829. HRESULT
  6830. pkcsPatchDN(
  6831. IN HRESULT hrFail,
  6832. IN WCHAR const *pwszRegName,
  6833. IN OUT BSTR *pstrDSValue)
  6834. {
  6835. HRESULT hr;
  6836. WCHAR *pwszRegValue = NULL;
  6837. hr = myGetCertRegStrValue(
  6838. g_wszSanitizedName,
  6839. NULL,
  6840. NULL,
  6841. pwszRegName,
  6842. &pwszRegValue);
  6843. _PrintIfErrorStr(hr, "myGetCertRegStrValue", pwszRegName);
  6844. if (NULL != *pstrDSValue)
  6845. {
  6846. if (NULL == pwszRegValue || 0 != lstrcmp(*pstrDSValue, pwszRegValue))
  6847. {
  6848. // set reg value
  6849. hr = mySetCertRegStrValue(
  6850. g_wszSanitizedName,
  6851. NULL,
  6852. NULL,
  6853. pwszRegName,
  6854. *pstrDSValue);
  6855. _PrintIfErrorStr(hr, "mySetCertRegStrValue", pwszRegName);
  6856. }
  6857. }
  6858. else
  6859. {
  6860. if (NULL == pwszRegValue || L'\0' == *pwszRegValue)
  6861. {
  6862. hr = hrFail;
  6863. _JumpError(hr, error, "both DS and Reg NULL");
  6864. }
  6865. if (!ConvertWszToBstr(pstrDSValue, pwszRegValue, -1))
  6866. {
  6867. hr = E_OUTOFMEMORY;
  6868. _JumpError(hr, error, "ConvertWszToBstr");
  6869. }
  6870. }
  6871. hr = S_OK;
  6872. error:
  6873. if (NULL != pwszRegValue)
  6874. {
  6875. LocalFree(pwszRegValue);
  6876. }
  6877. return(hr);
  6878. }
  6879. HRESULT
  6880. pkcsGetAuthoritativeDomainDn(
  6881. IN WCHAR const *pwszCommonName,
  6882. OUT LDAP **ppld,
  6883. OUT BSTR *pstrDomainDN,
  6884. OUT BSTR *pstrConfigDN)
  6885. {
  6886. HRESULT hr;
  6887. WCHAR *pwszConfigDN = NULL;
  6888. WCHAR *pwszDomainDN = NULL;
  6889. // Get domain and config containers (%5, %6)
  6890. *ppld = NULL;
  6891. *pstrDomainDN = NULL;
  6892. *pstrConfigDN = NULL;
  6893. if (g_fUseDS)
  6894. {
  6895. HRESULT hr2;
  6896. hr = myRobustLdapBind(ppld, FALSE);
  6897. if (S_OK != hr)
  6898. {
  6899. _PrintError(hr, "myRobustLdapBind");
  6900. }
  6901. else
  6902. {
  6903. hr = myGetAuthoritativeDomainDn(*ppld, pstrDomainDN, pstrConfigDN);
  6904. _PrintIfError(hr, "myGetAuthoritativeDomainDn");
  6905. }
  6906. if (S_OK != hr)
  6907. {
  6908. LogEventStringHResult(
  6909. EVENTLOG_ERROR_TYPE,
  6910. MSG_E_DS_RETRY,
  6911. pwszCommonName,
  6912. hr);
  6913. }
  6914. hr2 = hr;
  6915. hr = pkcsPatchDN(hr2, wszREGDSCONFIGDN, pstrConfigDN);
  6916. _JumpIfError(hr, error, "pkcsPatchDN");
  6917. hr = pkcsPatchDN(hr2, wszREGDSDOMAINDN, pstrDomainDN);
  6918. _JumpIfError(hr, error, "pkcsPatchDN");
  6919. }
  6920. else
  6921. {
  6922. *pstrDomainDN = SysAllocString(L"");
  6923. *pstrConfigDN = SysAllocString(L"");
  6924. if (NULL == *pstrDomainDN || NULL == *pstrConfigDN)
  6925. {
  6926. hr = E_OUTOFMEMORY;
  6927. _JumpError(hr, error, "SysAllocString");
  6928. }
  6929. }
  6930. hr = S_OK;
  6931. error:
  6932. return(hr);
  6933. }
  6934. HRESULT
  6935. PKCSSetup(
  6936. IN WCHAR const *pwszCommonName,
  6937. IN WCHAR const *pwszSanitizedName)
  6938. {
  6939. HRESULT hr;
  6940. LDAP *pld = NULL;
  6941. DWORD LogMsg = MAXDWORD;
  6942. BOOL fWarn = FALSE;
  6943. // set crypt handles and load certificate chain
  6944. hr = pkcsGetAuthoritativeDomainDn(
  6945. pwszCommonName,
  6946. &pld,
  6947. &g_strDomainDN,
  6948. &g_strConfigDN);
  6949. if (S_OK != hr)
  6950. {
  6951. LogMsg = MSG_E_NO_DS;
  6952. _JumpError(hr, error, "pkcsGetAuthoritativeDomainDn");
  6953. }
  6954. // get (multiple) CRL path templates
  6955. hr = pkcsLoadTemplates(
  6956. wszREGCRLPUBLICATIONURLS,
  6957. &g_paRevURL,
  6958. &g_caRevURL);
  6959. _PrintIfErrorStr(hr, "pkcsLoadTemplates", wszREGCRLPUBLICATIONURLS);
  6960. // get (multiple) CA Cert path templates
  6961. hr = pkcsLoadTemplates(
  6962. wszREGCACERTPUBLICATIONURLS,
  6963. &g_paCACertURL,
  6964. &g_caCACertURL);
  6965. _PrintIfErrorStr(hr, "pkcsLoadTemplates", wszREGCACERTPUBLICATIONURLS);
  6966. hr = DBOpen(pwszSanitizedName);
  6967. if (S_OK != hr)
  6968. {
  6969. LogMsg = MSG_E_DB_INIT_FAILED;
  6970. _JumpError(hr, error, "PKCSSetup:DBOpen");
  6971. }
  6972. hr = pkcsLoadCAContextArray(pwszCommonName, pwszSanitizedName);
  6973. if (S_OK != hr)
  6974. {
  6975. LogMsg = MSG_E_CA_CHAIN;
  6976. _JumpError(hr, error, "pkcsLoadCAContextArray");
  6977. }
  6978. hr = pkcsImportCAContextArray();
  6979. _PrintIfError(hr, "pkcsImportCAContextArray");
  6980. hr = pkcsVerifySignatureCertContextArray(pwszCommonName, &LogMsg, &fWarn);
  6981. _JumpIfError(hr, error, "pkcsVerifySignatureCertContextArray");
  6982. if (0 != g_cKRACertsRoundRobin)
  6983. {
  6984. hr = pkcsLoadKRACertArray();
  6985. _PrintIfError(hr, "pkcsLoadKRACertArray");
  6986. }
  6987. hr = pkcsExpandURL(g_wszzLDAPKRACertURLTemplate, &g_pwszKRAPublishURL);
  6988. _JumpIfError(hr, error, "pkcsExpandURL");
  6989. hr = pkcsExpandURL(
  6990. g_wszzLDAPIssuerCertURLTemplate,
  6991. &g_pwszAIACrossCertPublishURL);
  6992. _JumpIfError(hr, error, "pkcsExpandURL");
  6993. hr = pkcsExpandURL(
  6994. g_wszLDAPRootTrustURLTemplate,
  6995. &g_pwszRootTrustCrossCertPublishURL);
  6996. _JumpIfError(hr, error, "pkcsExpandURL");
  6997. if (NULL != pld)
  6998. {
  6999. hr = pkcsVerifyDSCACert(pld);
  7000. _PrintIfError(hr, "pkcsVerifyDSCACert");
  7001. }
  7002. hr = S_OK;
  7003. error:
  7004. if (NULL != pld)
  7005. {
  7006. ldap_unbind(pld);
  7007. }
  7008. if (S_OK != hr)
  7009. {
  7010. CSASSERT(MAXDWORD != LogMsg);
  7011. if (!fWarn)
  7012. {
  7013. PKCSTerminate();
  7014. }
  7015. LogEventStringHResult(
  7016. fWarn? EVENTLOG_WARNING_TYPE : EVENTLOG_ERROR_TYPE,
  7017. LogMsg,
  7018. pwszCommonName,
  7019. hr);
  7020. if (fWarn)
  7021. {
  7022. hr = S_OK;
  7023. }
  7024. }
  7025. return(hr);
  7026. }
  7027. VOID
  7028. pkcsReleaseCACertificateChain(
  7029. CERT_CONTEXT const **apCACertChain,
  7030. DWORD cCACertChain)
  7031. {
  7032. DWORD i;
  7033. if (NULL != apCACertChain)
  7034. {
  7035. for (i = 0; i < cCACertChain; ++i)
  7036. {
  7037. CertFreeCertificateContext(apCACertChain[i]);
  7038. }
  7039. LocalFree(apCACertChain);
  7040. }
  7041. }
  7042. VOID
  7043. pkcsReleaseCAContext(
  7044. IN OUT CACTX *pCAContext)
  7045. {
  7046. pkcsReleaseCACertificateChain(
  7047. pCAContext->apCACertChain,
  7048. pCAContext->cCACertChain);
  7049. //pCAContext->apCACertChain = NULL;
  7050. //pCAContext->pccCA = NULL;
  7051. if (NULL != pCAContext->hProvCA)
  7052. {
  7053. CryptReleaseContext(pCAContext->hProvCA, 0);
  7054. }
  7055. if (NULL != pCAContext->IssuerKeyId.pbData)
  7056. {
  7057. LocalFree(pCAContext->IssuerKeyId.pbData);
  7058. }
  7059. if (NULL != pCAContext->pszObjIdSignatureAlgorithm)
  7060. {
  7061. LocalFree(pCAContext->pszObjIdSignatureAlgorithm);
  7062. }
  7063. if (NULL != pCAContext->KeyAuthority2Cert.pbData)
  7064. {
  7065. LocalFree(pCAContext->KeyAuthority2Cert.pbData);
  7066. }
  7067. if (NULL != pCAContext->KeyAuthority2CRL.pbData)
  7068. {
  7069. LocalFree(pCAContext->KeyAuthority2CRL.pbData);
  7070. }
  7071. if (NULL != pCAContext->CDPCert.pbData)
  7072. {
  7073. LocalFree(pCAContext->CDPCert.pbData);
  7074. }
  7075. if (NULL != pCAContext->CDPCRLFreshest.pbData)
  7076. {
  7077. LocalFree(pCAContext->CDPCRLFreshest.pbData);
  7078. }
  7079. if (NULL != pCAContext->CDPCRLBase.pbData)
  7080. {
  7081. LocalFree(pCAContext->CDPCRLBase.pbData);
  7082. }
  7083. if (NULL != pCAContext->CDPCRLDelta.pbData)
  7084. {
  7085. LocalFree(pCAContext->CDPCRLDelta.pbData);
  7086. }
  7087. if (NULL != pCAContext->AIACert.pbData)
  7088. {
  7089. LocalFree(pCAContext->AIACert.pbData);
  7090. }
  7091. if (NULL != pCAContext->pwszKeyContainerName)
  7092. {
  7093. LocalFree(pCAContext->pwszKeyContainerName);
  7094. }
  7095. if (NULL != pCAContext->papwszCRLFiles)
  7096. {
  7097. WCHAR **ppwsz;
  7098. for (ppwsz = pCAContext->papwszCRLFiles; NULL != *ppwsz; ppwsz++)
  7099. {
  7100. LocalFree(*ppwsz);
  7101. }
  7102. LocalFree(pCAContext->papwszCRLFiles);
  7103. }
  7104. if (NULL != pCAContext->papwszDeltaCRLFiles)
  7105. {
  7106. WCHAR **ppwsz;
  7107. for (ppwsz = pCAContext->papwszDeltaCRLFiles; NULL != *ppwsz; ppwsz++)
  7108. {
  7109. LocalFree(*ppwsz);
  7110. }
  7111. LocalFree(pCAContext->papwszDeltaCRLFiles);
  7112. }
  7113. }
  7114. VOID
  7115. pkcsReleaseCAContextArray()
  7116. {
  7117. DWORD i;
  7118. if (NULL != g_aCAContext)
  7119. {
  7120. for (i = 0; i < g_cCACerts; i++)
  7121. {
  7122. pkcsReleaseCAContext(&g_aCAContext[i]);
  7123. }
  7124. LocalFree(g_aCAContext);
  7125. g_aCAContext = NULL;
  7126. }
  7127. g_cCACerts = 0;
  7128. g_pCAContextCurrent = NULL;
  7129. }
  7130. // Trim off leading and trailing whitespace and separator characters
  7131. WCHAR *
  7132. pkcsTrimToken(
  7133. IN WCHAR *pwszIn,
  7134. IN WCHAR wchSeparator)
  7135. {
  7136. WCHAR *pwsz;
  7137. while (wchSeparator == *pwszIn || iswspace(*pwszIn))
  7138. {
  7139. pwszIn++;
  7140. }
  7141. pwsz = &pwszIn[wcslen(pwszIn)];
  7142. while (--pwsz >= pwszIn &&
  7143. (wchSeparator == *pwsz || iswspace(*pwsz)))
  7144. {
  7145. *pwsz = L'\0';
  7146. }
  7147. if (L'\0' == *pwszIn)
  7148. {
  7149. pwszIn = NULL;
  7150. }
  7151. return(pwszIn);
  7152. }
  7153. WCHAR *
  7154. PKCSSplitToken(
  7155. IN OUT WCHAR **ppwszIn,
  7156. IN WCHAR *pwcSeparator,
  7157. OUT BOOL *pfSplit)
  7158. {
  7159. WCHAR *pwszOut = NULL;
  7160. WCHAR *pwszNext = NULL;
  7161. BOOL fSplit = FALSE;
  7162. WCHAR *pwszIn;
  7163. WCHAR *pwsz;
  7164. pwszIn = *ppwszIn;
  7165. if (NULL != pwszIn)
  7166. {
  7167. pwszOut = pwszIn;
  7168. if (NULL != pwcSeparator)
  7169. {
  7170. pwsz = wcschr(pwszIn, *pwcSeparator);
  7171. if (NULL != pwsz)
  7172. {
  7173. *pwsz = L'\0';
  7174. pwszNext = pkcsTrimToken(&pwsz[1], *pwcSeparator);
  7175. pwszOut = pkcsTrimToken(pwszOut, *pwcSeparator);
  7176. fSplit = TRUE;
  7177. }
  7178. }
  7179. }
  7180. *ppwszIn = pwszNext;
  7181. *pfSplit = fSplit;
  7182. return(pwszOut);
  7183. }
  7184. HRESULT
  7185. PKCSSetSubjectTemplate(
  7186. IN WCHAR const *pwszzTemplate)
  7187. {
  7188. HRESULT hr;
  7189. BOOL fSplit;
  7190. WCHAR const *pwszz;
  7191. WCHAR const *pwszPropName;
  7192. BSTR bstrToken;
  7193. SUBJECTTABLE const **ppSubject;
  7194. SUBJECTTABLE const **pps;
  7195. SUBJECTTABLE const *pSubject;
  7196. DWORD dwIndex;
  7197. DWORD cchMax;
  7198. hr = E_INVALIDARG;
  7199. if (NULL == pwszzTemplate)
  7200. {
  7201. _JumpError(hr, error, "pwszzTemplate NULL");
  7202. }
  7203. ppSubject = pkcs_apSubject; // fill in this empty subject array with string matches
  7204. for (pwszz = pwszzTemplate; L'\0' != *pwszz; pwszz += wcslen(pwszz) + 1)
  7205. {
  7206. pwszPropName = PKCSMapAttributeName(pwszz, NULL, &dwIndex, &cchMax);
  7207. if (NULL == pwszPropName)
  7208. {
  7209. hr = E_INVALIDARG;
  7210. _JumpErrorStr(hr, error, "PKCSMapAttributeName", pwszz);
  7211. }
  7212. for (pSubject = pkcs_subject; ; pSubject++)
  7213. {
  7214. if (NULL == pSubject->pwszPropName)
  7215. {
  7216. _JumpError(hr, error, "pkcs_subject lookup");
  7217. }
  7218. if (0 == lstrcmpi(pSubject->pwszPropName, pwszPropName))
  7219. {
  7220. break;
  7221. }
  7222. }
  7223. for (pps = pkcs_apSubject; pps < ppSubject; pps++)
  7224. {
  7225. if (*pps == pSubject)
  7226. {
  7227. _JumpErrorStr(hr, error, "pkcs_subject duplicate", pwszz);
  7228. }
  7229. }
  7230. if (ppSubject >= &pkcs_apSubject[CSUBJECTTABLE])
  7231. {
  7232. _JumpError(hr, error, "pkcs_subject overflow");
  7233. }
  7234. DBGPRINT((
  7235. DBG_SS_CERTSRVI,
  7236. "Subject Template[%u]: %hs -- %ws\n",
  7237. SAFE_SUBTRACT_POINTERS(ppSubject, pkcs_apSubject),
  7238. pSubject->pszObjId,
  7239. pSubject->pwszPropName));
  7240. *ppSubject++ = pSubject;
  7241. }
  7242. CSASSERT(ppSubject <= &pkcs_apSubject[CSUBJECTTABLE]);
  7243. if (ppSubject == pkcs_apSubject)
  7244. {
  7245. _JumpError(hr, error, "pwszzTemplate empty");
  7246. }
  7247. pkcs_ppSubjectLast = ppSubject - 1;
  7248. pkcsfSubjectTemplate = TRUE;
  7249. hr = S_OK;
  7250. error:
  7251. return(hr);
  7252. }
  7253. HRESULT
  7254. pkcsSplitRDNComponents(
  7255. IN SUBJECTTABLE const *pSubjectTable,
  7256. IN OUT WCHAR *pwszRDN, // Parsing stomps string in-place
  7257. IN DWORD cAttrMax,
  7258. OUT DWORD *pcAttr,
  7259. OUT CERT_RDN_ATTR *rgAttr)
  7260. {
  7261. HRESULT hr;
  7262. DWORD cAttr;
  7263. DWORD i;
  7264. DWORD cwc;
  7265. WCHAR *pwszRemain;
  7266. WCHAR const *pwszToken;
  7267. WCHAR *pwszT;
  7268. BOOL fSplit;
  7269. *pcAttr = 0;
  7270. cAttr = 0;
  7271. if (NULL != pwszRDN)
  7272. {
  7273. // Allocate memory for each RDN component filled in:
  7274. pwszRemain = pwszRDN;
  7275. while (TRUE)
  7276. {
  7277. pwszToken = PKCSSplitToken(
  7278. &pwszRemain,
  7279. wszNAMESEPARATORDEFAULT,
  7280. &fSplit);
  7281. if (NULL == pwszToken)
  7282. {
  7283. break;
  7284. }
  7285. if (cAttr >= cAttrMax)
  7286. {
  7287. hr = CERTSRV_E_BAD_REQUESTSUBJECT;
  7288. _JumpError(hr, error, "Subject RDN overflow");
  7289. }
  7290. cwc = wcslen(pwszToken);
  7291. if (g_fEnforceRDNNameLengths && cwc > pSubjectTable->cchMax)
  7292. {
  7293. DBGPRINT((
  7294. DBG_SS_CERTSRV,
  7295. "RDN component too long: %u/%u: %ws[%u]=\"%ws\"\n",
  7296. cwc,
  7297. pSubjectTable->cchMax,
  7298. pSubjectTable->pwszPropName,
  7299. cAttr,
  7300. pwszToken));
  7301. hr = CERTSRV_E_BAD_REQUESTSUBJECT;
  7302. _JumpErrorStr(hr, error, "RDN component too long", pwszToken);
  7303. }
  7304. pwszT = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
  7305. if (NULL == pwszT)
  7306. {
  7307. hr = E_OUTOFMEMORY;
  7308. _JumpError(hr, error, "LocalAlloc(pwszToken)");
  7309. }
  7310. wcscpy(pwszT, pwszToken);
  7311. rgAttr[cAttr].pszObjId = (char *) pSubjectTable->pszObjId;
  7312. rgAttr[cAttr].dwValueType = CERT_RDN_ANY_TYPE; // 'best' encoding
  7313. rgAttr[cAttr].Value.pbData = (BYTE *) pwszT;
  7314. rgAttr[cAttr].Value.cbData = 0; // Indicate Unicode input
  7315. cAttr++;
  7316. }
  7317. }
  7318. *pcAttr = cAttr;
  7319. hr = S_OK;
  7320. error:
  7321. if (S_OK != hr)
  7322. {
  7323. for (i = 0; i < cAttr; i++)
  7324. {
  7325. LocalFree(rgAttr[i].Value.pbData);
  7326. }
  7327. }
  7328. return(hr);
  7329. }
  7330. #define CSUBJECTRDNMAX (4 * CSUBJECTTABLE)
  7331. HRESULT
  7332. pkcsEncodeSubjectName(
  7333. IN ICertDBRow *prow,
  7334. IN CERT_RDN_ATTR const *rgAttr,
  7335. IN DWORD cAttr,
  7336. OUT BYTE **ppbData,
  7337. OUT DWORD *pcbData)
  7338. {
  7339. HRESULT hr;
  7340. DWORD i;
  7341. DWORD cbprop;
  7342. DWORD dwRequestFlags;
  7343. DWORD dwFlags;
  7344. CERT_RDN rgRDN[CSUBJECTRDNMAX];
  7345. CERT_NAME_INFO nameinfo;
  7346. CSASSERT(ARRAYSIZE(rgRDN) >= cAttr);
  7347. for (i = 0; i < cAttr; i++)
  7348. {
  7349. rgRDN[i].cRDNAttr = 1;
  7350. rgRDN[i].rgRDNAttr = (CERT_RDN_ATTR *) &rgAttr[i];
  7351. }
  7352. nameinfo.cRDN = cAttr;
  7353. nameinfo.rgRDN = rgRDN;
  7354. cbprop = sizeof(dwRequestFlags);
  7355. hr = prow->GetProperty(
  7356. g_wszPropRequestFlags,
  7357. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  7358. &cbprop,
  7359. (BYTE *) &dwRequestFlags);
  7360. _JumpIfError(hr, error, "GetProperty");
  7361. CSASSERT(sizeof(dwRequestFlags) == cbprop);
  7362. dwFlags = 0;
  7363. if (CR_FLG_FORCETELETEX & dwRequestFlags)
  7364. {
  7365. dwFlags |= CERT_RDN_ENABLE_T61_UNICODE_FLAG;
  7366. }
  7367. if (CR_FLG_FORCEUTF8 & dwRequestFlags)
  7368. {
  7369. dwFlags |= CERT_RDN_ENABLE_UTF8_UNICODE_FLAG;
  7370. }
  7371. if (!myEncodeName(
  7372. X509_ASN_ENCODING,
  7373. &nameinfo,
  7374. dwFlags,
  7375. CERTLIB_USE_LOCALALLOC,
  7376. ppbData,
  7377. pcbData))
  7378. {
  7379. hr = myHLastError();
  7380. _JumpError(hr, error, "myEncodeName");
  7381. }
  7382. error:
  7383. return(hr);
  7384. }
  7385. HRESULT
  7386. pkcsBuildSubjectFromNamesTable(
  7387. IN ICertDBRow *prow,
  7388. OUT CERT_NAME_BLOB *pSubject)
  7389. {
  7390. HRESULT hr;
  7391. DWORD cbData = 0;
  7392. DWORD i;
  7393. DWORD cAttr;
  7394. DWORD cAttrT;
  7395. CERT_RDN_ATTR rgAttr[CSUBJECTRDNMAX];
  7396. SUBJECTTABLE const * const *ppSubject;
  7397. WCHAR *pwszData = NULL;
  7398. pSubject->pbData = NULL;
  7399. CSASSERT(NULL != pkcs_ppSubjectLast);
  7400. cAttr = 0;
  7401. for (
  7402. ppSubject = pkcs_ppSubjectLast;
  7403. ppSubject >= pkcs_apSubject;
  7404. ppSubject--)
  7405. {
  7406. hr = PKCSGetProperty(
  7407. prow,
  7408. (*ppSubject)->pwszPropName,
  7409. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  7410. &cbData,
  7411. (BYTE **) &pwszData);
  7412. if (S_OK != hr)
  7413. {
  7414. continue;
  7415. }
  7416. if (0 != cbData)
  7417. {
  7418. // Allocates memory for each RDN component filled in:
  7419. hr = pkcsSplitRDNComponents(
  7420. *ppSubject,
  7421. pwszData,
  7422. ARRAYSIZE(rgAttr) - cAttr,
  7423. &cAttrT,
  7424. &rgAttr[cAttr]);
  7425. _JumpIfError(hr, error, "SplitRDNComponents");
  7426. cAttr += cAttrT;
  7427. }
  7428. LocalFree(pwszData);
  7429. pwszData = NULL;
  7430. }
  7431. // done building string of subject entries, time to encode
  7432. hr = pkcsEncodeSubjectName(
  7433. prow,
  7434. rgAttr,
  7435. cAttr,
  7436. &pSubject->pbData,
  7437. &pSubject->cbData);
  7438. _JumpIfError(hr, error, "pkcsEncodeSubjectName");
  7439. hr = prow->SetProperty(
  7440. g_wszPropSubjectRawName,
  7441. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  7442. pSubject->cbData,
  7443. pSubject->pbData);
  7444. _JumpIfError(hr, error, "SetProperty");
  7445. pkcsSetDistinguishedName(prow, PROPTABLE_CERTIFICATE, pSubject);
  7446. error:
  7447. for (i = 0; i < cAttr; i++)
  7448. {
  7449. LocalFree(rgAttr[i].Value.pbData);
  7450. }
  7451. if (NULL != pwszData)
  7452. {
  7453. LocalFree(pwszData);
  7454. }
  7455. return(hr);
  7456. }
  7457. HRESULT
  7458. pkcsCheck7f(
  7459. IN ICertDBRow *prow,
  7460. IN BYTE const *pbCert,
  7461. IN DWORD cbCert,
  7462. OUT BOOL *pfErrorLogged)
  7463. {
  7464. HRESULT hr;
  7465. DWORD cbProp;
  7466. WCHAR awcSubject[1024];
  7467. WCHAR wszDword[2+8+1];
  7468. WCHAR wszRequestId[11+1];
  7469. WCHAR const *pwszDword;
  7470. WORD cString = 0;
  7471. WCHAR const *apwsz[4];
  7472. DWORD State;
  7473. DWORD Index1;
  7474. DWORD Index2;
  7475. DWORD cwcField;
  7476. WCHAR wszField[128];
  7477. DWORD cwcObjectId;
  7478. WCHAR wszObjectId[128];
  7479. WCHAR const *pwszObjectIdDescription = NULL;
  7480. WCHAR *wszBuf=NULL;
  7481. const DWORD dwDefaultBufSize = 2048*sizeof(WCHAR);
  7482. *pfErrorLogged = FALSE;
  7483. cwcField = sizeof(wszField)/sizeof(wszField[0]);
  7484. cwcObjectId = sizeof(wszObjectId)/sizeof(wszObjectId[0]);
  7485. hr = myCheck7f(
  7486. pbCert,
  7487. cbCert,
  7488. FALSE,
  7489. &State,
  7490. &Index1,
  7491. &Index2,
  7492. &cwcField,
  7493. wszField,
  7494. &cwcObjectId,
  7495. wszObjectId,
  7496. &pwszObjectIdDescription); // Static: do not free!
  7497. _JumpIfError(hr, error, "myCheck7f");
  7498. if (CHECK7F_NONE != State)
  7499. {
  7500. DWORD ReqId;
  7501. wszBuf = (WCHAR*)LocalAlloc(LMEM_FIXED, dwDefaultBufSize);
  7502. if (NULL == wszBuf)
  7503. {
  7504. hr = E_OUTOFMEMORY;
  7505. _JumpError(hr, error, "LocalAlloc");
  7506. }
  7507. prow->GetRowId(&ReqId);
  7508. wsprintf(wszRequestId, L"%u", ReqId);
  7509. apwsz[cString++] = wszRequestId;
  7510. apwsz[cString++] = wszDword;
  7511. cbProp = sizeof(awcSubject);
  7512. hr = prow->GetProperty(
  7513. g_wszPropSubjectDistinguishedName,
  7514. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  7515. &cbProp,
  7516. (BYTE *) awcSubject);
  7517. if (S_OK != hr)
  7518. {
  7519. _PrintError(hr, "GetProperty(DN)");
  7520. wcscpy(awcSubject, L"???");
  7521. }
  7522. apwsz[cString++] = awcSubject;
  7523. wcscpy(wszBuf, wszField);
  7524. if (0 != Index1)
  7525. {
  7526. wsprintf(
  7527. &wszBuf[wcslen(wszBuf)],
  7528. 0 != Index2? L"[%u,%u]" : L"[%u]",
  7529. Index1 - 1,
  7530. Index2 - 1);
  7531. }
  7532. if (0 != cwcObjectId)
  7533. {
  7534. wcscat(wszBuf, L" ObjectId=");
  7535. wcscat(wszBuf, wszObjectId);
  7536. }
  7537. if (NULL != pwszObjectIdDescription)
  7538. {
  7539. // If buffer too small, reallocate enough space for old buffer,
  7540. // OID description, () and trailing zero
  7541. DWORD dwBufLen = (wcslen(wszBuf)+wcslen(pwszObjectIdDescription)+3)*
  7542. sizeof(WCHAR);
  7543. if(dwDefaultBufSize<dwBufLen)
  7544. {
  7545. WCHAR *pTempBuf = (WCHAR*)LocalReAlloc(
  7546. wszBuf,
  7547. dwBufLen,
  7548. LMEM_MOVEABLE);
  7549. if(NULL == pTempBuf)
  7550. {
  7551. hr = E_OUTOFMEMORY;
  7552. _JumpError(hr, error, "LocalReAlloc");
  7553. }
  7554. wszBuf = pTempBuf;
  7555. }
  7556. wcscat(wszBuf, L" (");
  7557. wcscat(wszBuf, pwszObjectIdDescription);
  7558. wcscat(wszBuf, L")");
  7559. }
  7560. apwsz[cString++] = wszBuf;
  7561. hr = CERTSRV_E_ENCODING_LENGTH;
  7562. wsprintf(wszDword, L"0x%x", hr);
  7563. if (CERTLOG_ERROR <= g_dwLogLevel)
  7564. {
  7565. LogEvent(
  7566. EVENTLOG_ERROR_TYPE,
  7567. MSG_E_BADCERTLENGTHFIELD,
  7568. cString,
  7569. apwsz);
  7570. }
  7571. CONSOLEPRINT4((
  7572. DBG_SS_CERTSRV,
  7573. "CertSrv Request %u: rc=%x: Bad encoded length detected: %ws \"%ws\"\n",
  7574. ReqId,
  7575. hr,
  7576. wszBuf,
  7577. awcSubject));
  7578. *pfErrorLogged = TRUE;
  7579. }
  7580. error:
  7581. if (NULL != wszBuf)
  7582. {
  7583. LocalFree(wszBuf);
  7584. }
  7585. return(hr);
  7586. }
  7587. HRESULT
  7588. pkcsCreateCertSerialNumber(
  7589. IN ICertDBRow *prow,
  7590. IN CACTX const *pCAContext,
  7591. OUT BSTR *pstrSerialNumber)
  7592. {
  7593. HRESULT hr;
  7594. DWORD dw;
  7595. USHORT us;
  7596. BYTE abRandom[8];
  7597. BYTE abSerial[max(
  7598. sizeof(dw) + sizeof(us) + sizeof(dw),
  7599. sizeof(dw) + sizeof(us) + sizeof(abRandom) + sizeof(dw) + sizeof(BYTE))];
  7600. BSTR strSerialNumber = NULL;
  7601. DWORD cbSerial;
  7602. BYTE *pb;
  7603. DWORD cb;
  7604. //#define TEST_SPECIAL_SERIAL_NUMBERS
  7605. #ifdef TEST_SPECIAL_SERIAL_NUMBERS
  7606. BOOL fAddZeroByte = FALSE;
  7607. #endif
  7608. *pstrSerialNumber = NULL;
  7609. pb = abSerial;
  7610. prow->GetRowId(&dw);
  7611. CopyMemory(pb, &dw, sizeof(dw));
  7612. pb += sizeof(dw);
  7613. us = (USHORT) pCAContext->iCert;
  7614. CopyMemory(pb, &us, sizeof(us));
  7615. pb += sizeof(us);
  7616. if (0 != g_dwHighSerial)
  7617. {
  7618. if (!CryptGenRandom(
  7619. g_pCAContextCurrent->hProvCA,
  7620. ARRAYSIZE(abRandom),
  7621. abRandom))
  7622. {
  7623. hr = myHLastError();
  7624. _PrintError(hr, "CryptGenRandom");
  7625. memset(abRandom, g_dwHighSerial, sizeof(abRandom));
  7626. }
  7627. CopyMemory(pb, abRandom, sizeof(abRandom));
  7628. pb += sizeof(abRandom);
  7629. CopyMemory(pb, &dw, sizeof(dw));
  7630. pb += sizeof(dw);
  7631. *pb++ = (BYTE) g_dwHighSerial;
  7632. }
  7633. else
  7634. {
  7635. dw = GetTickCount();
  7636. CopyMemory(pb, &dw, sizeof(dw));
  7637. pb += sizeof(dw);
  7638. }
  7639. cbSerial = SAFE_SUBTRACT_POINTERS(pb, abSerial);
  7640. // Make sure the sreial number doesn't overflow the buffer:
  7641. CSASSERT(sizeof(abSerial) >= cbSerial);
  7642. // IETF max serial number length is 20 bytes:
  7643. CSASSERT(20 >= cbSerial);
  7644. pb--;
  7645. if (0 == *pb)
  7646. {
  7647. *pb = 'a';
  7648. }
  7649. else if (0 == (0xf0 & *pb))
  7650. {
  7651. *pb |= 0x10; // make high nibble non-zero
  7652. }
  7653. *pb &= 0x7f; // Some clients can't handle negative serial numbers:
  7654. #ifdef TEST_SPECIAL_SERIAL_NUMBERS
  7655. if (1 & abSerial[0])
  7656. {
  7657. *pb |= 0x80; // Test negative serial numbers:
  7658. if (2 & abSerial[0])
  7659. {
  7660. *pb-- = 0; // Test high zero byte serial numbers:
  7661. *pb |= 0x80; // Test negative serial numbers:
  7662. fAddZeroByte = TRUE;
  7663. }
  7664. }
  7665. #endif
  7666. hr = MultiByteIntegerToBstr(FALSE, cbSerial, abSerial, &strSerialNumber);
  7667. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  7668. #ifdef TEST_SPECIAL_SERIAL_NUMBERS
  7669. if (fAddZeroByte)
  7670. {
  7671. BSTR str = NULL;
  7672. str = SysAllocStringLen(NULL, 2 + wcslen(strSerialNumber));
  7673. if (NULL != str)
  7674. {
  7675. wcscpy(str, L"00");
  7676. wcscat(str, strSerialNumber);
  7677. SysFreeString(strSerialNumber);
  7678. strSerialNumber = str;
  7679. }
  7680. }
  7681. #endif
  7682. *pstrSerialNumber = strSerialNumber;
  7683. strSerialNumber = NULL;
  7684. hr = S_OK;
  7685. error:
  7686. if (NULL != strSerialNumber)
  7687. {
  7688. SysFreeString(strSerialNumber);
  7689. }
  7690. return(hr);
  7691. }
  7692. HRESULT
  7693. PKCSVerifySubjectRDN(
  7694. IN ICertDBRow *prow,
  7695. IN WCHAR const *pwszPropertyName,
  7696. OPTIONAL IN WCHAR const *pwszPropertyValue,
  7697. OUT BOOL *pfSubjectDot)
  7698. {
  7699. HRESULT hr;
  7700. WCHAR const *pwsz;
  7701. WCHAR const *pwszName = pwszPropertyName;
  7702. WCHAR wszPrefix[ARRAYSIZE(wszPROPSUBJECTDOT)];
  7703. SUBJECTTABLE const *pSubjectTable;
  7704. DWORD i;
  7705. DWORD cAttr = 0;
  7706. CERT_RDN_ATTR rgAttr[CSUBJECTRDNMAX];
  7707. WCHAR *pwszValue = NULL;
  7708. DWORD cbData;
  7709. BYTE *pbData = NULL;
  7710. hr = S_OK;
  7711. *pfSubjectDot = FALSE;
  7712. // Check to see if the request is for L"Subject.".
  7713. pwsz = wcschr(pwszName, L'.');
  7714. if (NULL != pwsz &&
  7715. SAFE_SUBTRACT_POINTERS(pwsz, pwszName) + 2 == ARRAYSIZE(wszPrefix))
  7716. {
  7717. pwsz++; // skip past L'.'
  7718. CopyMemory(
  7719. wszPrefix,
  7720. pwszName,
  7721. (SAFE_SUBTRACT_POINTERS(pwsz, pwszName) * sizeof(WCHAR)));
  7722. wszPrefix[ARRAYSIZE(wszPrefix) - 1] = L'\0';
  7723. if (0 == lstrcmpi(wszPrefix, wszPROPSUBJECTDOT))
  7724. {
  7725. pwszName = pwsz;
  7726. if (L'\0' == *pwszName)
  7727. {
  7728. *pfSubjectDot = TRUE;
  7729. }
  7730. }
  7731. }
  7732. if (!*pfSubjectDot)
  7733. {
  7734. for (pSubjectTable = pkcs_subject; ; pSubjectTable++)
  7735. {
  7736. WCHAR const * const *ppwsz;
  7737. if (NULL == pSubjectTable->pwszPropName)
  7738. {
  7739. goto error;
  7740. }
  7741. // Check for matching full name without "Subject." prefix:
  7742. pwsz = wcschr(pSubjectTable->pwszPropName, L'.');
  7743. if (NULL != pwsz && 0 == lstrcmpi(pwszName, &pwsz[1]))
  7744. {
  7745. break;
  7746. }
  7747. // Check for matching OID:
  7748. if (!iswdigit(*pwszName))
  7749. {
  7750. continue;
  7751. }
  7752. for (
  7753. ppwsz = pSubjectTable->apwszAttributeName;
  7754. NULL != *ppwsz;
  7755. ppwsz++)
  7756. {
  7757. if (*pwszName == **ppwsz && 0 == lstrcmp(pwszName, *ppwsz))
  7758. {
  7759. break;
  7760. }
  7761. }
  7762. if (NULL != *ppwsz)
  7763. {
  7764. break;
  7765. }
  7766. }
  7767. }
  7768. // It's a valid Certificate Table Subject RDN. Call pkcsSplitRDNComponents
  7769. // to split the string into individual RDN components and optionally
  7770. // enforce each component is under the maximum length.
  7771. DBGPRINT((
  7772. DBG_SS_CERTSRVI,
  7773. "PKCSVerifySubjectRDN(%ws) --> '%ws'\n",
  7774. pwszPropertyName,
  7775. pwszName));
  7776. if (!*pfSubjectDot && NULL != pwszPropertyValue)
  7777. {
  7778. pwszValue = (WCHAR *) LocalAlloc(
  7779. LMEM_FIXED,
  7780. (wcslen(pwszPropertyValue) + 1) * sizeof(WCHAR));
  7781. if (NULL == pwszValue)
  7782. {
  7783. hr = E_OUTOFMEMORY;
  7784. _JumpError(hr, error, "LocalAlloc");
  7785. }
  7786. wcscpy(pwszValue, pwszPropertyValue);
  7787. hr = pkcsSplitRDNComponents(
  7788. pSubjectTable,
  7789. pwszValue,
  7790. ARRAYSIZE(rgAttr),
  7791. &cAttr,
  7792. rgAttr);
  7793. _JumpIfError(hr, error, "SplitRDNComponents");
  7794. // Call myEncodeName merely to test for valid string data.
  7795. // Some RDN OIDs are restricted to IA5 strings.
  7796. hr = pkcsEncodeSubjectName(prow, rgAttr, cAttr, &pbData, &cbData);
  7797. _JumpIfError(hr, error, "pkcsEncodeSubjectName");
  7798. }
  7799. hr = PKCSSetRequestFlags(prow, FALSE, CR_FLG_SUBJECTUNMODIFIED);
  7800. _JumpIfError(hr, error, "PKCSSetRequestFlags");
  7801. error:
  7802. for (i = 0; i < cAttr; i++)
  7803. {
  7804. LocalFree(rgAttr[i].Value.pbData);
  7805. }
  7806. if (NULL != pbData)
  7807. {
  7808. LocalFree(pbData);
  7809. }
  7810. if (NULL != pwszValue)
  7811. {
  7812. LocalFree(pwszValue);
  7813. }
  7814. return(hr);
  7815. }
  7816. HRESULT
  7817. PKCSDeleteAllSubjectRDNs(
  7818. IN ICertDBRow *prow,
  7819. IN DWORD Flags)
  7820. {
  7821. HRESULT hr;
  7822. SUBJECTTABLE const *pSubjectTable;
  7823. WCHAR const *pwszPropName = NULL;
  7824. for (pSubjectTable = pkcs_subject; ; pSubjectTable++)
  7825. {
  7826. if (NULL == pSubjectTable->pwszPropName)
  7827. {
  7828. break;
  7829. }
  7830. hr = prow->SetProperty(pSubjectTable->pwszPropName, Flags, 0, NULL);
  7831. _JumpIfError(hr, error, "SetProperty");
  7832. }
  7833. hr = S_OK;
  7834. error:
  7835. return(hr);
  7836. }
  7837. HRESULT
  7838. pkcsverifyIssuedPolices(
  7839. IN CERT_CONTEXT const *pcc,
  7840. IN CHAR const *pszObjId,
  7841. OPTIONAL IN WCHAR const *pwszzPolicies)
  7842. {
  7843. HRESULT hr;
  7844. CERT_EXTENSION const *pExt;
  7845. CERT_POLICIES_INFO *pcpsi = NULL;
  7846. DWORD cb;
  7847. DWORD i;
  7848. WCHAR const *pwsz;
  7849. WCHAR *pwszObjId = NULL;
  7850. if (NULL == pwszzPolicies)
  7851. {
  7852. hr = S_OK;
  7853. goto error;
  7854. }
  7855. pExt = CertFindExtension(
  7856. pszObjId,
  7857. pcc->pCertInfo->cExtension,
  7858. pcc->pCertInfo->rgExtension);
  7859. if (NULL == pExt)
  7860. {
  7861. hr = S_OK;
  7862. goto error;
  7863. }
  7864. if (!myDecodeObject(
  7865. X509_ASN_ENCODING,
  7866. X509_CERT_POLICIES,
  7867. pExt->Value.pbData,
  7868. pExt->Value.cbData,
  7869. CERTLIB_USE_LOCALALLOC,
  7870. (VOID **) &pcpsi,
  7871. &cb))
  7872. {
  7873. hr = myHLastError();
  7874. _JumpError(hr, error, "myDecodeObject");
  7875. }
  7876. for (i = 0; i < pcpsi->cPolicyInfo; i++)
  7877. {
  7878. CSASSERT(NULL == pwszObjId);
  7879. if (!myConvertSzToWsz(
  7880. &pwszObjId,
  7881. pcpsi->rgPolicyInfo[i].pszPolicyIdentifier,
  7882. -1))
  7883. {
  7884. hr = E_OUTOFMEMORY;
  7885. _JumpError(hr, error, "myConvertSzToWsz(ObjId)");
  7886. }
  7887. for (pwsz = pwszzPolicies; ; pwsz += wcslen(pwsz) + 1)
  7888. {
  7889. if (L'\0' == *pwsz)
  7890. {
  7891. hr = CERT_E_INVALID_POLICY;
  7892. _JumpErrorStr(hr, error, "Chain invalidates policy", pwszObjId);
  7893. }
  7894. if (0 == lstrcmp(pwsz, pwszObjId))
  7895. {
  7896. break;
  7897. }
  7898. }
  7899. LocalFree(pwszObjId);
  7900. pwszObjId = NULL;
  7901. }
  7902. hr = S_OK;
  7903. error:
  7904. if (NULL != pcpsi)
  7905. {
  7906. LocalFree(pcpsi);
  7907. }
  7908. if (NULL != pwszObjId)
  7909. {
  7910. LocalFree(pwszObjId);
  7911. }
  7912. return(hr);
  7913. }
  7914. HRESULT
  7915. pkcsEncodeSubjectCert(
  7916. IN ICertDBRow *prow,
  7917. IN CACTX const *pCAContext,
  7918. OUT BYTE **ppbEncoded, // CoTaskMem*
  7919. OUT DWORD *pcbEncoded,
  7920. OUT BOOL *pfErrorLogged)
  7921. {
  7922. HRESULT hr;
  7923. HRESULT hrValidate = S_OK;
  7924. BYTE *pbCertEncoded = NULL;
  7925. DWORD cbCertEncoded;
  7926. DWORD ExtFlags;
  7927. BSTR strSerialNumber = NULL;
  7928. IEnumCERTDBNAME *penum = NULL;
  7929. CERTDBNAME cdbn;
  7930. FILETIME ftNotBefore;
  7931. DWORD dwRequestFlags;
  7932. WCHAR *pwszIssuer = NULL;
  7933. WCHAR *pwszSubject = NULL;
  7934. CERT_INFO Cert;
  7935. CERT_EXTENSION *pExt = NULL;
  7936. DWORD cExt = INCREMENT_EXTENSIONS;
  7937. DWORD cbprop;
  7938. DWORD i;
  7939. CHAR *pChar;
  7940. CHAR szObjId[MAX_PATH];
  7941. BYTE *pb;
  7942. CERT_CONTEXT const *pcc = NULL;
  7943. WCHAR *pwszzIssuancePolicies = NULL;
  7944. WCHAR *pwszzApplicationPolicies = NULL;
  7945. cdbn.pwszName = NULL;
  7946. *pfErrorLogged = FALSE;
  7947. // CERT
  7948. ZeroMemory(&Cert, sizeof(Cert));
  7949. pExt = (CERT_EXTENSION *) LocalAlloc(
  7950. LMEM_FIXED | LMEM_ZEROINIT,
  7951. cExt * sizeof(*pExt));
  7952. if (NULL == pExt)
  7953. {
  7954. hr = E_OUTOFMEMORY;
  7955. _JumpError(hr, error, "LocalAlloc");
  7956. }
  7957. Cert.dwVersion = CERT_V3;
  7958. hr = pkcsCreateCertSerialNumber(prow, pCAContext, &strSerialNumber);
  7959. _JumpIfError(hr, error, "pkcsCreateCertSerialNumber");
  7960. // convert to int
  7961. hr = WszToMultiByteInteger(
  7962. FALSE,
  7963. strSerialNumber,
  7964. &Cert.SerialNumber.cbData,
  7965. &Cert.SerialNumber.pbData);
  7966. _JumpIfError(hr, error, "WszToMultiByteInteger");
  7967. Cert.SignatureAlgorithm.pszObjId = pCAContext->pszObjIdSignatureAlgorithm;
  7968. Cert.Issuer = pCAContext->pccCA->pCertInfo->Subject;
  7969. cbprop = sizeof(Cert.NotBefore);
  7970. hr = prow->GetProperty(
  7971. g_wszPropCertificateNotBeforeDate,
  7972. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  7973. &cbprop,
  7974. (BYTE *) &Cert.NotBefore);
  7975. _JumpIfError(hr, error, "GetProperty");
  7976. CSASSERT(sizeof(Cert.NotBefore) == cbprop);
  7977. cbprop = sizeof(Cert.NotAfter);
  7978. hr = prow->GetProperty(
  7979. g_wszPropCertificateNotAfterDate,
  7980. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  7981. &cbprop,
  7982. (BYTE *) &Cert.NotAfter);
  7983. _JumpIfError(hr, error, "GetProperty");
  7984. CSASSERT(sizeof(Cert.NotAfter) == cbprop);
  7985. CSASSERT(NULL == Cert.Subject.pbData);
  7986. cbprop = sizeof(dwRequestFlags);
  7987. hr = prow->GetProperty(
  7988. g_wszPropRequestFlags,
  7989. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  7990. &cbprop,
  7991. (BYTE *) &dwRequestFlags);
  7992. _JumpIfError(hr, error, "GetProperty");
  7993. if (!pkcsfSubjectTemplate ||
  7994. ((CRLF_REBUILD_MODIFIED_SUBJECT_ONLY & g_dwCRLFlags) &&
  7995. (CR_FLG_SUBJECTUNMODIFIED & dwRequestFlags)))
  7996. {
  7997. hr = PKCSGetProperty(
  7998. prow,
  7999. g_wszPropSubjectRawName,
  8000. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  8001. &Cert.Subject.cbData,
  8002. &Cert.Subject.pbData);
  8003. if (S_OK == hr &&
  8004. 0 == Cert.Subject.cbData &&
  8005. NULL != Cert.Subject.pbData)
  8006. {
  8007. LocalFree(Cert.Subject.pbData);
  8008. Cert.Subject.pbData = NULL;
  8009. }
  8010. }
  8011. if (NULL == Cert.Subject.pbData)
  8012. {
  8013. hr = pkcsBuildSubjectFromNamesTable(prow, &Cert.Subject);
  8014. _JumpIfError(hr, error, "pkcsBuildSubjectFromNamesTable");
  8015. }
  8016. if (CertCompareCertificateName(
  8017. X509_ASN_ENCODING,
  8018. &Cert.Issuer,
  8019. &Cert.Subject))
  8020. {
  8021. hr = CERTSRV_E_BAD_REQUESTSUBJECT;
  8022. _JumpError(hr, error, "Subject matches Issuer");
  8023. }
  8024. hr = myCertNameToStr(
  8025. X509_ASN_ENCODING,
  8026. &Cert.Issuer,
  8027. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  8028. &pwszIssuer);
  8029. _JumpIfError(hr, error, "myCertNameToStr");
  8030. hr = myCertNameToStr(
  8031. X509_ASN_ENCODING,
  8032. &Cert.Subject,
  8033. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  8034. &pwszSubject);
  8035. _JumpIfError(hr, error, "myCertNameToStr");
  8036. if (0 == lstrcmpi(pwszIssuer, pwszSubject))
  8037. {
  8038. hr = CERTSRV_E_BAD_REQUESTSUBJECT;
  8039. _JumpError(hr, error, "Subject string matches Issuer");
  8040. }
  8041. hr = pkcsGetPublicKeyInfo(prow, &Cert.SubjectPublicKeyInfo);
  8042. _JumpIfError(hr, error, "pkcsGetPublicKeyInfo");
  8043. Cert.rgExtension = pExt;
  8044. i = 0;
  8045. hr = prow->EnumCertDBName(CIE_TABLE_EXTENSIONS, &penum);
  8046. _JumpIfError(hr, error, "EnumCertDBName");
  8047. hr = CERTSRV_E_PROPERTY_EMPTY;
  8048. while (TRUE)
  8049. {
  8050. ULONG celtFetched;
  8051. if (cExt == i)
  8052. {
  8053. CERT_EXTENSION *pExtT;
  8054. // reached max, increse size
  8055. cExt += INCREMENT_EXTENSIONS;
  8056. pExtT = (CERT_EXTENSION *) LocalReAlloc(
  8057. pExt,
  8058. cExt * sizeof(*pExt),
  8059. LMEM_ZEROINIT | LMEM_MOVEABLE);
  8060. if (NULL == pExtT)
  8061. {
  8062. hr = E_OUTOFMEMORY;
  8063. _JumpError(hr, error, "LocalReAlloc");
  8064. }
  8065. pExt = pExtT;
  8066. Cert.rgExtension = pExt;
  8067. }
  8068. hr = penum->Next(1, &cdbn, &celtFetched);
  8069. if (S_FALSE == hr)
  8070. {
  8071. break;
  8072. }
  8073. _JumpIfError(hr, error, "Next");
  8074. CSASSERT(1 == celtFetched);
  8075. CSASSERT(NULL != cdbn.pwszName);
  8076. if (!ConvertWszToSz(
  8077. &Cert.rgExtension[i].pszObjId,
  8078. cdbn.pwszName,
  8079. -1))
  8080. {
  8081. hr = E_OUTOFMEMORY;
  8082. _JumpError(hr, error, "ConvertWszToSz(ExtObjId)");
  8083. }
  8084. hr = PropGetExtension(
  8085. prow,
  8086. PROPTYPE_BINARY | PROPCALLER_SERVER,
  8087. cdbn.pwszName,
  8088. &ExtFlags,
  8089. &Cert.rgExtension[i].Value.cbData,
  8090. &Cert.rgExtension[i].Value.pbData);
  8091. _JumpIfError(hr, error, "PropGetExtension");
  8092. DBGPRINT((
  8093. DBG_SS_CERTSRVI,
  8094. "pkcsEncodeSubjectCert: Ext=%ws, ExtFlags=%x, len=%x\n",
  8095. cdbn.pwszName,
  8096. ExtFlags,
  8097. Cert.rgExtension[i].Value.cbData));
  8098. Cert.rgExtension[i].fCritical =
  8099. (EXTENSION_CRITICAL_FLAG & ExtFlags)? TRUE : FALSE;
  8100. CoTaskMemFree(cdbn.pwszName);
  8101. cdbn.pwszName = NULL;
  8102. if (EXTENSION_DISABLE_FLAG & ExtFlags)
  8103. {
  8104. if (NULL != pExt[i].pszObjId)
  8105. {
  8106. LocalFree(pExt[i].pszObjId);
  8107. pExt[i].pszObjId = NULL;
  8108. }
  8109. if (NULL != pExt[i].Value.pbData)
  8110. {
  8111. LocalFree(pExt[i].Value.pbData);
  8112. pExt[i].Value.pbData = NULL;
  8113. }
  8114. continue;
  8115. }
  8116. i++;
  8117. }
  8118. Cert.cExtension = i;
  8119. // encode the cert contents
  8120. if (!myEncodeObject(
  8121. X509_ASN_ENCODING,
  8122. X509_CERT_TO_BE_SIGNED,
  8123. &Cert,
  8124. 0,
  8125. CERTLIB_USE_LOCALALLOC,
  8126. &pbCertEncoded,
  8127. &cbCertEncoded))
  8128. {
  8129. hr = myHLastError();
  8130. _JumpError(hr, error, "myEncodeObject");
  8131. }
  8132. // sign the cert, then encode the signed info
  8133. hr = myEncodeSignedContent(
  8134. pCAContext->hProvCA,
  8135. X509_ASN_ENCODING,
  8136. Cert.SignatureAlgorithm.pszObjId,
  8137. pbCertEncoded,
  8138. cbCertEncoded,
  8139. CERTLIB_USE_COTASKMEMALLOC,
  8140. ppbEncoded,
  8141. pcbEncoded); // use CoTaskMem*
  8142. _JumpIfError(hr, error, "myEncodeSignedContent");
  8143. pcc = CertCreateCertificateContext(
  8144. X509_ASN_ENCODING,
  8145. *ppbEncoded,
  8146. *pcbEncoded);
  8147. if (NULL == pcc)
  8148. {
  8149. hr = myHLastError();
  8150. _JumpError(hr, error, "CertCreateCertificateContext");
  8151. }
  8152. if (g_fCertEnrollCompatible)
  8153. {
  8154. hr = pkcsCheck7f(
  8155. prow,
  8156. *ppbEncoded,
  8157. *pcbEncoded,
  8158. pfErrorLogged);
  8159. if (S_OK != hr)
  8160. {
  8161. CoTaskMemFree(*ppbEncoded);
  8162. *ppbEncoded = NULL;
  8163. _JumpError(hr, error, "pkcsCheck7f");
  8164. }
  8165. }
  8166. ftNotBefore = pcc->pCertInfo->NotBefore;
  8167. myMakeExprDateTime(&ftNotBefore, g_dwClockSkewMinutes, ENUM_PERIOD_MINUTES);
  8168. hr = myVerifyCertContextEx(
  8169. pcc, // pCert
  8170. (CRLF_REVCHECK_IGNORE_OFFLINE & g_dwCRLFlags)?
  8171. CA_VERIFY_FLAGS_IGNORE_OFFLINE : 0,
  8172. // dwFlags
  8173. 0, // cUsageOids
  8174. NULL, // apszUsageOids
  8175. HCCE_LOCAL_MACHINE, // hChainEngine
  8176. &ftNotBefore, // pft
  8177. NULL, // hAdditionalStore
  8178. NULL, // ppwszMissingIssuer
  8179. &pwszzIssuancePolicies,
  8180. &pwszzApplicationPolicies);
  8181. _PrintIfError(hr, "myVerifyCertContextEx");
  8182. if (S_OK != hr)
  8183. {
  8184. if (0 == (CRLF_SAVE_FAILED_CERTS & g_dwCRLFlags))
  8185. {
  8186. goto error;
  8187. }
  8188. hrValidate = hr;
  8189. }
  8190. if (S_OK == hrValidate &&
  8191. 0 == (CRLF_IGNORE_INVALID_POLICIES & g_dwCRLFlags))
  8192. {
  8193. hr = pkcsverifyIssuedPolices(
  8194. pcc,
  8195. szOID_CERT_POLICIES,
  8196. pwszzIssuancePolicies);
  8197. _PrintIfError(hr, "pkcsverifyIssuedPolices");
  8198. if (S_OK != hr)
  8199. {
  8200. if (0 == (CRLF_SAVE_FAILED_CERTS & g_dwCRLFlags))
  8201. {
  8202. goto error;
  8203. }
  8204. if (S_OK == hrValidate)
  8205. {
  8206. hrValidate = hr;
  8207. }
  8208. }
  8209. hr = pkcsverifyIssuedPolices(
  8210. pcc,
  8211. szOID_APPLICATION_CERT_POLICIES,
  8212. pwszzApplicationPolicies);
  8213. _PrintIfError(hr, "pkcsverifyIssuedPolices");
  8214. if (S_OK != hr)
  8215. {
  8216. if (0 == (CRLF_SAVE_FAILED_CERTS & g_dwCRLFlags))
  8217. {
  8218. goto error;
  8219. }
  8220. if (S_OK == hrValidate)
  8221. {
  8222. hrValidate = hr;
  8223. }
  8224. }
  8225. }
  8226. hr = pkcsSetCertAndKeyHashes(prow, pcc);
  8227. _JumpIfError(hr, error, "pkcsSetCertAndKeyHashes");
  8228. hr = prow->SetProperty(
  8229. g_wszPropCertificateIssuerNameID,
  8230. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  8231. sizeof(pCAContext->NameId),
  8232. (BYTE *) &pCAContext->NameId);
  8233. _JumpIfError(hr, error, "SetProperty");
  8234. hr = prow->SetProperty(
  8235. g_wszPropCertificateSerialNumber,
  8236. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  8237. MAXDWORD,
  8238. (BYTE *) strSerialNumber);
  8239. _JumpIfError(hr, error, "SetProperty");
  8240. #ifdef TEST_SPECIAL_SERIAL_NUMBERS
  8241. if (L'0' == strSerialNumber[0] && L'0' == strSerialNumber[1])
  8242. {
  8243. hr = prow->SetProperty(
  8244. g_wszPropCertificateSerialNumber,
  8245. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  8246. MAXDWORD,
  8247. (BYTE *) &strSerialNumber[2]);
  8248. _JumpIfError(hr, error, "SetProperty");
  8249. }
  8250. #endif
  8251. error:
  8252. if (S_OK != hrValidate)
  8253. {
  8254. hr = hrValidate;
  8255. }
  8256. if (NULL != pwszIssuer)
  8257. {
  8258. LocalFree(pwszIssuer);
  8259. }
  8260. if (NULL != pwszSubject)
  8261. {
  8262. LocalFree(pwszSubject);
  8263. }
  8264. if (NULL != pwszzIssuancePolicies)
  8265. {
  8266. LocalFree(pwszzIssuancePolicies);
  8267. }
  8268. if (NULL != pwszzApplicationPolicies)
  8269. {
  8270. LocalFree(pwszzApplicationPolicies);
  8271. }
  8272. if (NULL != pcc)
  8273. {
  8274. CertFreeCertificateContext(pcc);
  8275. }
  8276. if (NULL != pExt)
  8277. {
  8278. i = 0;
  8279. if (NULL != cdbn.pwszName)
  8280. {
  8281. CoTaskMemFree(cdbn.pwszName);
  8282. }
  8283. while (cExt != i)
  8284. {
  8285. if (NULL != pExt[i].pszObjId)
  8286. {
  8287. LocalFree(pExt[i].pszObjId);
  8288. }
  8289. if (NULL != pExt[i].Value.pbData)
  8290. {
  8291. LocalFree(pExt[i].Value.pbData);
  8292. }
  8293. i++;
  8294. }
  8295. LocalFree(pExt);
  8296. }
  8297. if (NULL != penum)
  8298. {
  8299. penum->Release();
  8300. }
  8301. if (NULL != Cert.SerialNumber.pbData)
  8302. {
  8303. LocalFree(Cert.SerialNumber.pbData);
  8304. }
  8305. if (NULL != Cert.Subject.pbData)
  8306. {
  8307. LocalFree(Cert.Subject.pbData);
  8308. }
  8309. pkcsFreePublicKeyInfo(&Cert.SubjectPublicKeyInfo);
  8310. if (NULL != pbCertEncoded)
  8311. {
  8312. LocalFree(pbCertEncoded);
  8313. }
  8314. if (NULL != strSerialNumber)
  8315. {
  8316. SysFreeString(strSerialNumber);
  8317. }
  8318. return(hr);
  8319. }
  8320. VOID
  8321. pkcsFreeCRLChain(
  8322. IN DWORD cCert,
  8323. OPTIONAL IN OUT CERT_BLOB *prgCertBlob,
  8324. OPTIONAL IN OUT CERT_CONTEXT const **rgCert,
  8325. IN DWORD cCRL,
  8326. OPTIONAL IN OUT CRL_BLOB *rgCRLBlob,
  8327. OPTIONAL IN OUT CRL_CONTEXT const **rgCRL)
  8328. {
  8329. DWORD i;
  8330. if (NULL != prgCertBlob)
  8331. {
  8332. LocalFree(prgCertBlob);
  8333. }
  8334. if (NULL != rgCert)
  8335. {
  8336. for (i = 0; i < cCert; i++)
  8337. {
  8338. if (NULL != rgCert[i])
  8339. {
  8340. CertFreeCertificateContext(rgCert[i]);
  8341. }
  8342. }
  8343. LocalFree(rgCert);
  8344. }
  8345. if (NULL != rgCRLBlob)
  8346. {
  8347. LocalFree(rgCRLBlob);
  8348. }
  8349. if (NULL != rgCRL)
  8350. {
  8351. for (i = 0; i < cCRL; i++)
  8352. {
  8353. if (NULL != rgCRL[i])
  8354. {
  8355. CertFreeCRLContext(rgCRL[i]);
  8356. }
  8357. }
  8358. LocalFree(rgCRL);
  8359. }
  8360. }
  8361. // Build the CA's cert chain and collect all paremt CA CRLs.
  8362. // Add in the optional passed leaf cert and the CA's CRLs.
  8363. // This ensures that the chain includes at least this CA's correct cert & CRLs.
  8364. HRESULT
  8365. pkcsBuildCRLChain(
  8366. OPTIONAL IN CACTX *pCAContext,
  8367. OPTIONAL IN BYTE const *pbCertLeaf,
  8368. IN DWORD cbCertLeaf,
  8369. IN BOOL fIncludeCRLs,
  8370. OUT DWORD *pcCert,
  8371. OPTIONAL OUT CERT_BLOB **prgCertBlob,
  8372. OUT CERT_CONTEXT const ***prgCert,
  8373. OUT DWORD *pcCRLBlob,
  8374. OPTIONAL OUT CRL_BLOB **prgCRLBlob,
  8375. OUT CRL_CONTEXT const ***prgCRL)
  8376. {
  8377. HRESULT hr;
  8378. CERT_CHAIN_PARA ChainParams;
  8379. CERT_CHAIN_CONTEXT const *pChainContext = NULL;
  8380. DWORD cElement;
  8381. CERT_CHAIN_ELEMENT **rgpElement;
  8382. DWORD cCert;
  8383. CERT_CONTEXT const **rgpCert = NULL;
  8384. CERT_CONTEXT const *pccCertLeaf = NULL;
  8385. CERT_BLOB *rgCertBlob = NULL;
  8386. DWORD cCRL;
  8387. CRL_CONTEXT const **rgpCRL = NULL;
  8388. CRL_BLOB *rgCRLBlob = NULL;
  8389. DWORD i;
  8390. DWORD iCert;
  8391. DWORD iCRL;
  8392. if (NULL != prgCertBlob)
  8393. {
  8394. *prgCertBlob = NULL;
  8395. }
  8396. *prgCert = NULL;
  8397. if (NULL != prgCRLBlob)
  8398. {
  8399. *prgCRLBlob = NULL;
  8400. }
  8401. *prgCRL = NULL;
  8402. if (NULL != pbCertLeaf)
  8403. {
  8404. pccCertLeaf = CertCreateCertificateContext(
  8405. X509_ASN_ENCODING,
  8406. pbCertLeaf,
  8407. cbCertLeaf);
  8408. if (NULL == pccCertLeaf)
  8409. {
  8410. hr = myHLastError();
  8411. _JumpError(hr, error, "CertCreateCertificateContext");
  8412. }
  8413. }
  8414. CSASSERT(NULL != pCAContext || NULL != pccCertLeaf);
  8415. if (NULL == pCAContext || fIncludeCRLs)
  8416. {
  8417. // Get the CA cert chain and parent CA CRLs:
  8418. ZeroMemory(&ChainParams, sizeof(ChainParams));
  8419. ChainParams.cbSize = sizeof(ChainParams);
  8420. //ChainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  8421. //ChainParams.RequestedUsage.Usage.cUsageIdentifier = 0;
  8422. //ChainParams.RequestedUsage.Usage.rgpszUsageIdentifier = NULL;
  8423. if (!CertGetCertificateChain(
  8424. HCCE_LOCAL_MACHINE, // hChainEngine
  8425. NULL != pCAContext?
  8426. pCAContext->pccCA : pccCertLeaf,
  8427. NULL, // pTime
  8428. NULL, // hAdditionalStore
  8429. &ChainParams, // pChainPara
  8430. CERT_CHAIN_REVOCATION_CHECK_END_CERT |
  8431. CERT_CHAIN_REVOCATION_CHECK_CHAIN,
  8432. NULL, // pvReserved
  8433. &pChainContext)) // ppChainContext
  8434. {
  8435. hr = myHLastError();
  8436. _JumpError(hr, error, "CertGetCertificateChain");
  8437. }
  8438. if (0 == pChainContext->cChain ||
  8439. 0 == pChainContext->rgpChain[0]->cElement)
  8440. {
  8441. hr = CRYPT_E_NOT_FOUND;
  8442. _JumpError(hr, error, "No chain");
  8443. }
  8444. cElement = pChainContext->rgpChain[0]->cElement;
  8445. rgpElement = pChainContext->rgpChain[0]->rgpElement;
  8446. }
  8447. else
  8448. {
  8449. cElement = pCAContext->cCACertChain;
  8450. }
  8451. cCert = cElement;
  8452. cCRL = 2 * (cCert + 1); // Worst case. *Always* include this CA's CRLs
  8453. if (NULL != pbCertLeaf)
  8454. {
  8455. cCert++;
  8456. }
  8457. rgpCert = (CERT_CONTEXT const **) LocalAlloc(
  8458. LMEM_FIXED | LMEM_ZEROINIT,
  8459. cCert * sizeof(rgpCert[0]));
  8460. if (NULL == rgpCert)
  8461. {
  8462. hr = E_OUTOFMEMORY;
  8463. _JumpError(hr, error, "LocalAlloc");
  8464. }
  8465. if (fIncludeCRLs)
  8466. {
  8467. rgpCRL = (CRL_CONTEXT const **) LocalAlloc(
  8468. LMEM_FIXED | LMEM_ZEROINIT,
  8469. cCRL * sizeof(rgpCRL[0]));
  8470. if (NULL == rgpCRL)
  8471. {
  8472. hr = E_OUTOFMEMORY;
  8473. _JumpError(hr, error, "LocalAlloc");
  8474. }
  8475. }
  8476. iCert = 0;
  8477. iCRL = 0;
  8478. // Add parent CA certs and CRLs:
  8479. if (NULL == pCAContext || fIncludeCRLs)
  8480. {
  8481. for (i = 0; i < cElement; i++)
  8482. {
  8483. CERT_CHAIN_ELEMENT const *pElement = rgpElement[i];
  8484. CERT_REVOCATION_INFO *pRevocationInfo;
  8485. rgpCert[iCert] = CertDuplicateCertificateContext(
  8486. pElement->pCertContext);
  8487. if (NULL != rgpCert[iCert])
  8488. {
  8489. iCert++;
  8490. }
  8491. pRevocationInfo = pElement->pRevocationInfo;
  8492. if (fIncludeCRLs &&
  8493. NULL != pRevocationInfo &&
  8494. CCSIZEOF_STRUCT(CERT_REVOCATION_INFO, pCrlInfo) <=
  8495. pRevocationInfo->cbSize &&
  8496. NULL != pRevocationInfo->pCrlInfo)
  8497. {
  8498. CERT_REVOCATION_CRL_INFO *pCrlInfo;
  8499. pCrlInfo = pRevocationInfo->pCrlInfo;
  8500. if (NULL != pCrlInfo)
  8501. {
  8502. if (NULL != pCrlInfo->pBaseCrlContext)
  8503. {
  8504. rgpCRL[iCRL] = CertDuplicateCRLContext(
  8505. pCrlInfo->pBaseCrlContext);
  8506. if (NULL != rgpCRL[iCRL])
  8507. {
  8508. iCRL++;
  8509. }
  8510. }
  8511. if (NULL != pCrlInfo->pDeltaCrlContext)
  8512. {
  8513. rgpCRL[iCRL] = CertDuplicateCRLContext(
  8514. pCrlInfo->pDeltaCrlContext);
  8515. if (NULL != rgpCRL[iCRL])
  8516. {
  8517. iCRL++;
  8518. }
  8519. }
  8520. }
  8521. }
  8522. }
  8523. }
  8524. else
  8525. {
  8526. for (i = 0; i < pCAContext->cCACertChain; i++)
  8527. {
  8528. rgpCert[iCert] = CertDuplicateCertificateContext(
  8529. pCAContext->apCACertChain[i]);
  8530. if (NULL != rgpCert[iCert])
  8531. {
  8532. iCert++;
  8533. }
  8534. }
  8535. }
  8536. if (NULL != pCAContext)
  8537. {
  8538. // Add issued cert at the end -- optional Leaf cert:
  8539. if (NULL != pbCertLeaf)
  8540. {
  8541. for (i = 0; i < iCert; i++)
  8542. {
  8543. if (cbCertLeaf == rgpCert[i]->cbCertEncoded &&
  8544. 0 == memcmp(
  8545. pbCertLeaf,
  8546. rgpCert[i]->pbCertEncoded,
  8547. cbCertLeaf))
  8548. {
  8549. break;
  8550. }
  8551. }
  8552. if (i == iCert) // if not found in existing array
  8553. {
  8554. rgpCert[iCert] = CertDuplicateCertificateContext(pccCertLeaf);
  8555. if (NULL != rgpCert[iCert])
  8556. {
  8557. iCert++;
  8558. }
  8559. }
  8560. }
  8561. // Add current CA's Base and delta CRLs:
  8562. if (fIncludeCRLs)
  8563. {
  8564. hr = CRLGetCRL(
  8565. pCAContext->iKey,
  8566. FALSE, // fDelta
  8567. &rgpCRL[iCRL],
  8568. NULL); // pdwCRLPublishFlags
  8569. _JumpIfError(hr, error, "CRLGetCRL(base)"); // Base CRL must exist
  8570. iCRL++;
  8571. hr = CRLGetCRL(
  8572. pCAContext->iKey,
  8573. TRUE, // fDelta
  8574. &rgpCRL[iCRL],
  8575. NULL); // pdwCRLPublishFlags
  8576. _PrintIfError(hr, "CRLGetCRL(delta)"); // Delta CRL might not exist
  8577. if (S_OK == hr)
  8578. {
  8579. iCRL++;
  8580. }
  8581. }
  8582. }
  8583. CSASSERT(iCert <= cCert);
  8584. CSASSERT(iCRL <= cCRL);
  8585. if (NULL != prgCertBlob)
  8586. {
  8587. rgCertBlob = (CERT_BLOB *) LocalAlloc(
  8588. LMEM_FIXED,
  8589. iCert * sizeof(rgCertBlob[0]));
  8590. if (NULL == rgCertBlob)
  8591. {
  8592. hr = E_OUTOFMEMORY;
  8593. _JumpError(hr, error, "LocalAlloc");
  8594. }
  8595. for (i = 0; i < iCert; i++)
  8596. {
  8597. rgCertBlob[i].cbData = rgpCert[i]->cbCertEncoded;
  8598. rgCertBlob[i].pbData = rgpCert[i]->pbCertEncoded;
  8599. }
  8600. }
  8601. if (NULL != prgCRLBlob && 0 != iCRL)
  8602. {
  8603. rgCRLBlob = (CERT_BLOB *) LocalAlloc(
  8604. LMEM_FIXED,
  8605. iCRL * sizeof(rgCRLBlob[0]));
  8606. if (NULL == rgCRLBlob)
  8607. {
  8608. hr = E_OUTOFMEMORY;
  8609. _JumpError(hr, error, "LocalAlloc");
  8610. }
  8611. for (i = 0; i < iCRL; i++)
  8612. {
  8613. rgCRLBlob[i].cbData = rgpCRL[i]->cbCrlEncoded;
  8614. rgCRLBlob[i].pbData = rgpCRL[i]->pbCrlEncoded;
  8615. }
  8616. }
  8617. *pcCert = iCert;
  8618. *prgCert = rgpCert;
  8619. rgpCert = NULL;
  8620. if (NULL != prgCertBlob)
  8621. {
  8622. *prgCertBlob = rgCertBlob;
  8623. rgCertBlob = NULL;
  8624. }
  8625. *pcCRLBlob = iCRL;
  8626. *prgCRL = rgpCRL;
  8627. rgpCRL = NULL;
  8628. if (NULL != prgCRLBlob)
  8629. {
  8630. *prgCRLBlob = rgCRLBlob;
  8631. rgCRLBlob = NULL;
  8632. }
  8633. hr = S_OK;
  8634. error:
  8635. pkcsFreeCRLChain(cCert, rgCertBlob, rgpCert, cCRL, rgCRLBlob, rgpCRL);
  8636. if (NULL != pccCertLeaf)
  8637. {
  8638. CertFreeCertificateContext(pccCertLeaf);
  8639. }
  8640. if (NULL != pChainContext)
  8641. {
  8642. CertFreeCertificateChain(pChainContext);
  8643. }
  8644. return(hr);
  8645. }
  8646. // Build a PKCS7 CMC response
  8647. HRESULT
  8648. PKCSEncodeFullResponse(
  8649. OPTIONAL IN ICertDBRow *prow,
  8650. IN CERTSRV_RESULT_CONTEXT const *pResult,
  8651. IN HRESULT hrRequest,
  8652. IN WCHAR *pwszDispositionString,
  8653. OPTIONAL IN CACTX *pCAContext,
  8654. OPTIONAL IN BYTE const *pbCertLeaf,
  8655. IN DWORD cbCertLeaf,
  8656. IN BOOL fIncludeCRLs,
  8657. OUT BYTE **ppbResponse, // CoTaskMem*
  8658. OUT DWORD *pcbResponse)
  8659. {
  8660. HRESULT hr;
  8661. CMC_RESPONSE_INFO Response;
  8662. CMC_STATUS_INFO Status;
  8663. BYTE *pbContent = NULL;
  8664. DWORD cbContent;
  8665. DWORD dwBodyPartIdOfRequest = 1;
  8666. DWORD dwCMCDataReference = 0;
  8667. DWORD dwBodyPartId = 1;
  8668. CMC_TAGGED_ATTRIBUTE aTaggedAttribute[5];
  8669. DWORD ita = 0;
  8670. CRYPT_ATTRIBUTE aAttr[2];
  8671. DWORD iAttr = 0;
  8672. CRYPT_ATTR_BLOB aAttrBlob[7];
  8673. DWORD iblob = 0;
  8674. CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo;
  8675. CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo;
  8676. CMC_PEND_INFO PendInfo;
  8677. DWORD ReqId;
  8678. DWORD dwRequestFlags;
  8679. DWORD cb;
  8680. DWORD i;
  8681. HCRYPTMSG hMsg = NULL;
  8682. CERT_CONTEXT const **prgCert = NULL;
  8683. CRL_CONTEXT const **prgCRL = NULL;
  8684. CHAR szNonce[(11 + 1) + (8 + 1) * 3];
  8685. ZeroMemory(aAttrBlob, sizeof(aAttrBlob));
  8686. ZeroMemory(&Status, sizeof(Status));
  8687. ZeroMemory(&Response, sizeof(Response));
  8688. ZeroMemory(&SignedMsgEncodeInfo, sizeof(SignedMsgEncodeInfo));
  8689. SignedMsgEncodeInfo.cbSize = sizeof(SignedMsgEncodeInfo);
  8690. SignedMsgEncodeInfo.cSigners = 1;
  8691. SignedMsgEncodeInfo.rgSigners = &SignerEncodeInfo;
  8692. //SignedMsgEncodeInfo.cCertEncoded = 0;
  8693. //SignedMsgEncodeInfo.rgCertEncoded = NULL;
  8694. //SignedMsgEncodeInfo.cCrlEncoded = 0;
  8695. //SignedMsgEncodeInfo.rgCrlEncoded = NULL;
  8696. Status.cBodyList = 1;
  8697. Status.dwOtherInfoChoice = CMC_OTHER_INFO_NO_CHOICE;
  8698. Status.rgdwBodyList = &dwBodyPartIdOfRequest;
  8699. Status.pwszStatusString = pwszDispositionString;
  8700. switch (*pResult->pdwDisposition)
  8701. {
  8702. case CR_DISP_ISSUED:
  8703. case CR_DISP_ISSUED_OUT_OF_BAND:
  8704. case CR_DISP_REVOKED: // map revoked to CMC_STATUS_FAILED?
  8705. Status.dwStatus = CMC_STATUS_SUCCESS;
  8706. break;
  8707. case CR_DISP_UNDER_SUBMISSION:
  8708. Status.dwStatus = CMC_STATUS_PENDING;
  8709. Status.dwOtherInfoChoice = CMC_OTHER_INFO_PEND_CHOICE;
  8710. Status.pPendInfo = &PendInfo;
  8711. CSASSERT(NULL != prow);
  8712. prow->GetRowId(&ReqId);
  8713. PendInfo.PendToken.cbData = sizeof(ReqId);
  8714. PendInfo.PendToken.pbData = (BYTE *) &ReqId;
  8715. cb = sizeof(PendInfo.PendTime);
  8716. hr = prow->GetProperty(
  8717. g_wszPropRequestSubmittedWhen,
  8718. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  8719. &cb,
  8720. (BYTE *) &PendInfo.PendTime);
  8721. _JumpIfError(hr, error, "GetProperty");
  8722. break;
  8723. //case CR_DISP_INCOMPLETE:
  8724. //case CR_DISP_ERROR:
  8725. //case CR_DISP_DENIED:
  8726. default:
  8727. Status.dwStatus = CMC_STATUS_FAILED;
  8728. if (NULL != prow)
  8729. {
  8730. cb = sizeof(hrRequest);
  8731. hr = prow->GetProperty(
  8732. g_wszPropRequestStatusCode,
  8733. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  8734. &cb,
  8735. (BYTE *) &hrRequest);
  8736. _JumpIfError(hr, error, "GetProperty(status code)");
  8737. }
  8738. switch (hrRequest)
  8739. {
  8740. case CERTSRV_E_BAD_REQUESTSUBJECT:
  8741. Status.dwFailInfo = CMC_FAIL_BAD_REQUEST;
  8742. Status.dwOtherInfoChoice = CMC_OTHER_INFO_FAIL_CHOICE;
  8743. break;
  8744. }
  8745. break;
  8746. }
  8747. // Encode control attributes for Status, Transaction Id, Sender and
  8748. // Recipient Nonces and Issued Cert Hash.
  8749. ZeroMemory(aTaggedAttribute, sizeof(aTaggedAttribute));
  8750. // Status:
  8751. if (!myEncodeObject(
  8752. X509_ASN_ENCODING,
  8753. CMC_STATUS,
  8754. &Status,
  8755. 0,
  8756. CERTLIB_USE_LOCALALLOC,
  8757. &aAttrBlob[iblob].pbData,
  8758. &aAttrBlob[iblob].cbData))
  8759. {
  8760. hr = myHLastError();
  8761. _JumpError(hr, error, "myEncodeObject");
  8762. }
  8763. aTaggedAttribute[ita].dwBodyPartID = dwBodyPartId++;
  8764. aTaggedAttribute[ita].Attribute.pszObjId = szOID_CMC_STATUS_INFO;
  8765. aTaggedAttribute[ita].Attribute.cValue = 1;
  8766. aTaggedAttribute[ita].Attribute.rgValue = &aAttrBlob[iblob];
  8767. iblob++;
  8768. ita++;
  8769. // Transaction Id:
  8770. if (pResult->fTransactionId)
  8771. {
  8772. if (!myEncodeObject(
  8773. X509_ASN_ENCODING,
  8774. X509_INTEGER,
  8775. &pResult->dwTransactionId,
  8776. 0,
  8777. CERTLIB_USE_LOCALALLOC,
  8778. &aAttrBlob[iblob].pbData,
  8779. &aAttrBlob[iblob].cbData))
  8780. {
  8781. hr = myHLastError();
  8782. _JumpError(hr, error, "myEncodeObject");
  8783. }
  8784. aTaggedAttribute[ita].dwBodyPartID = dwBodyPartId++;
  8785. aTaggedAttribute[ita].Attribute.pszObjId = szOID_CMC_TRANSACTION_ID;
  8786. aTaggedAttribute[ita].Attribute.cValue = 1;
  8787. aTaggedAttribute[ita].Attribute.rgValue = &aAttrBlob[iblob];
  8788. iblob++;
  8789. ita++;
  8790. }
  8791. if (NULL != pResult->pbSenderNonce && 0 != pResult->cbSenderNonce)
  8792. {
  8793. CRYPT_DATA_BLOB Blob;
  8794. FILETIME ft;
  8795. DWORD dw;
  8796. DWORD cch;
  8797. // Recipient Nonce:
  8798. Blob.pbData = const_cast<BYTE *>(pResult->pbSenderNonce);
  8799. Blob.cbData = pResult->cbSenderNonce;
  8800. if (!myEncodeObject(
  8801. X509_ASN_ENCODING,
  8802. X509_OCTET_STRING,
  8803. &Blob,
  8804. 0,
  8805. CERTLIB_USE_LOCALALLOC,
  8806. &aAttrBlob[iblob].pbData,
  8807. &aAttrBlob[iblob].cbData))
  8808. {
  8809. hr = myHLastError();
  8810. _JumpError(hr, error, "myEncodeObject");
  8811. }
  8812. aTaggedAttribute[ita].dwBodyPartID = dwBodyPartId++;
  8813. aTaggedAttribute[ita].Attribute.pszObjId = szOID_CMC_RECIPIENT_NONCE;
  8814. aTaggedAttribute[ita].Attribute.cValue = 1;
  8815. aTaggedAttribute[ita].Attribute.rgValue = &aAttrBlob[iblob];
  8816. iblob++;
  8817. ita++;
  8818. // Sender Nonce:
  8819. GetSystemTimeAsFileTime(&ft);
  8820. dw = GetTickCount();
  8821. cch = sprintf(
  8822. szNonce,
  8823. "%u %08lx %08lx-%08lx",
  8824. *pResult->pdwRequestId,
  8825. dw,
  8826. ft.dwHighDateTime,
  8827. ft.dwLowDateTime);
  8828. CSASSERT(ARRAYSIZE(szNonce) > cch);
  8829. Blob.pbData = (BYTE *) szNonce;
  8830. Blob.cbData = cch;
  8831. if (!myEncodeObject(
  8832. X509_ASN_ENCODING,
  8833. X509_OCTET_STRING,
  8834. &Blob,
  8835. 0,
  8836. CERTLIB_USE_LOCALALLOC,
  8837. &aAttrBlob[iblob].pbData,
  8838. &aAttrBlob[iblob].cbData))
  8839. {
  8840. hr = myHLastError();
  8841. _JumpError(hr, error, "myEncodeObject");
  8842. }
  8843. aTaggedAttribute[ita].dwBodyPartID = dwBodyPartId++;
  8844. aTaggedAttribute[ita].Attribute.pszObjId = szOID_CMC_SENDER_NONCE;
  8845. aTaggedAttribute[ita].Attribute.cValue = 1;
  8846. aTaggedAttribute[ita].Attribute.rgValue = &aAttrBlob[iblob];
  8847. iblob++;
  8848. ita++;
  8849. }
  8850. // Issued Cert Hash:
  8851. if (NULL != pbCertLeaf)
  8852. {
  8853. CSASSERT(NULL != prow);
  8854. hr = pkcsGetHashAsOctet(
  8855. prow,
  8856. &aAttrBlob[iblob].pbData,
  8857. &aAttrBlob[iblob].cbData);
  8858. _JumpIfError(hr, error, "pkcsGetHashAsOctet");
  8859. aAttr[iAttr].pszObjId = szOID_ISSUED_CERT_HASH;
  8860. aAttr[iAttr].cValue = 1;
  8861. aAttr[iAttr].rgValue = &aAttrBlob[iblob];
  8862. iblob++;
  8863. iAttr++;
  8864. }
  8865. // Computed hash of private key encrypted to this CA, for client
  8866. // confirmation.
  8867. if (NULL != pResult->pbKeyHashOut)
  8868. {
  8869. CRYPT_DATA_BLOB Blob;
  8870. Blob.pbData = pResult->pbKeyHashOut;
  8871. Blob.cbData = pResult->cbKeyHashOut;
  8872. if (!myEncodeObject(
  8873. X509_ASN_ENCODING,
  8874. X509_OCTET_STRING,
  8875. &Blob,
  8876. 0,
  8877. CERTLIB_USE_LOCALALLOC,
  8878. &aAttrBlob[iblob].pbData,
  8879. &aAttrBlob[iblob].cbData))
  8880. {
  8881. hr = myHLastError();
  8882. _JumpError(hr, error, "myEncodeObject");
  8883. }
  8884. aAttr[iAttr].pszObjId = szOID_ENCRYPTED_KEY_HASH;
  8885. aAttr[iAttr].cValue = 1;
  8886. aAttr[iAttr].rgValue = &aAttrBlob[iblob];
  8887. iblob++;
  8888. iAttr++;
  8889. }
  8890. if (0 != iAttr)
  8891. {
  8892. hr = BuildCMCAttributes(
  8893. iAttr, // cAttribute
  8894. aAttr, // rgAttribute
  8895. dwCMCDataReference,
  8896. dwBodyPartIdOfRequest,
  8897. dwBodyPartId++,
  8898. &aTaggedAttribute[ita],
  8899. &aAttrBlob[iblob]);
  8900. _JumpIfError(hr, error, "BuildCMCAttributes");
  8901. iblob++;
  8902. ita++;
  8903. }
  8904. CSASSERT(ARRAYSIZE(aTaggedAttribute) >= ita);
  8905. CSASSERT(ARRAYSIZE(aAttr) >= iAttr);
  8906. CSASSERT(ARRAYSIZE(aAttrBlob) >= iblob);
  8907. Response.cTaggedAttribute = ita;
  8908. Response.rgTaggedAttribute = aTaggedAttribute;
  8909. if (!myEncodeObject(
  8910. X509_ASN_ENCODING,
  8911. CMC_RESPONSE,
  8912. &Response,
  8913. 0,
  8914. CERTLIB_USE_LOCALALLOC,
  8915. &pbContent,
  8916. &cbContent))
  8917. {
  8918. hr = myHLastError();
  8919. _JumpError(hr, error, "myEncodeObject");
  8920. }
  8921. if (NULL == pCAContext)
  8922. {
  8923. pCAContext = g_pCAContextCurrent;
  8924. }
  8925. ZeroMemory(&SignerEncodeInfo, sizeof(SignerEncodeInfo));
  8926. SignerEncodeInfo.cbSize = sizeof(SignerEncodeInfo);
  8927. SignerEncodeInfo.pCertInfo = pCAContext->pccCA->pCertInfo;
  8928. SignerEncodeInfo.hCryptProv = pCAContext->hProvCA;
  8929. SignerEncodeInfo.dwKeySpec = AT_SIGNATURE;
  8930. SignerEncodeInfo.HashAlgorithm.pszObjId = szOID_OIWSEC_sha1;
  8931. //SignerEncodeInfo.pvHashAuxInfo = NULL;
  8932. //SignerEncodeInfo.cAuthAttr = 0;
  8933. //SignerEncodeInfo.rgAuthAttr = NULL;
  8934. //SignerEncodeInfo.cUnauthAttr = 0;
  8935. //SignerEncodeInfo.rgUnauthAttr = NULL;
  8936. if (NULL != pbCertLeaf)
  8937. {
  8938. hr = pkcsBuildCRLChain(
  8939. pCAContext,
  8940. pbCertLeaf,
  8941. cbCertLeaf,
  8942. fIncludeCRLs,
  8943. &SignedMsgEncodeInfo.cCertEncoded,
  8944. &SignedMsgEncodeInfo.rgCertEncoded,
  8945. &prgCert,
  8946. &SignedMsgEncodeInfo.cCrlEncoded,
  8947. &SignedMsgEncodeInfo.rgCrlEncoded,
  8948. &prgCRL);
  8949. _JumpIfError(hr, error, "pkcsBuildCRLChain");
  8950. }
  8951. dwRequestFlags = 0;
  8952. if (NULL != prow)
  8953. {
  8954. cb = sizeof(dwRequestFlags);
  8955. hr = prow->GetProperty(
  8956. g_wszPropRequestFlags,
  8957. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  8958. &cb,
  8959. (BYTE *) &dwRequestFlags);
  8960. _JumpIfError(hr, error, "GetProperty");
  8961. }
  8962. #define szOID_CT_PKI_RESPONSE_OLDRFC "1.3.6.1.5.5.7.5.3" // BUGBUG: temporary!
  8963. hMsg = CryptMsgOpenToEncode(
  8964. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  8965. CMSG_CMS_ENCAPSULATED_CONTENT_FLAG, // dwFlags
  8966. CMSG_SIGNED,
  8967. &SignedMsgEncodeInfo,
  8968. (CR_FLG_OLDRFCCMC & dwRequestFlags)?
  8969. szOID_CT_PKI_RESPONSE_OLDRFC :
  8970. szOID_CT_PKI_RESPONSE,
  8971. NULL); // pStreamInfo
  8972. if (NULL == hMsg)
  8973. {
  8974. hr = myHLastError();
  8975. _JumpError(hr, error, "CryptMsgOpenToEncode");
  8976. }
  8977. if (!CryptMsgUpdate(hMsg, pbContent, cbContent, TRUE))
  8978. {
  8979. hr = myHLastError();
  8980. _JumpError(hr, error, "CryptMsgUpdate");
  8981. }
  8982. // Return the encoded and signed content.
  8983. // Use CMSG_CONTENT_PARAM to get the signed message.
  8984. hr = myCryptMsgGetParam(
  8985. hMsg,
  8986. CMSG_CONTENT_PARAM,
  8987. 0,
  8988. CERTLIB_USE_COTASKMEMALLOC,
  8989. (VOID **) ppbResponse,
  8990. pcbResponse);
  8991. _JumpIfError(hr, error, "myCryptMsgGetParam");
  8992. error:
  8993. pkcsFreeCRLChain(
  8994. SignedMsgEncodeInfo.cCertEncoded,
  8995. SignedMsgEncodeInfo.rgCertEncoded,
  8996. prgCert,
  8997. SignedMsgEncodeInfo.cCrlEncoded,
  8998. SignedMsgEncodeInfo.rgCrlEncoded,
  8999. prgCRL);
  9000. for (i = 0; i < ARRAYSIZE(aAttrBlob); i++)
  9001. {
  9002. if (NULL != aAttrBlob[i].pbData)
  9003. {
  9004. LocalFree(aAttrBlob[i].pbData);
  9005. }
  9006. }
  9007. if (NULL != hMsg)
  9008. {
  9009. CryptMsgClose(hMsg);
  9010. }
  9011. if (NULL != pbContent)
  9012. {
  9013. LocalFree(pbContent);
  9014. }
  9015. return(hr);
  9016. }
  9017. // Build a PKCS7 NULL signature with encapsulated certs
  9018. HRESULT
  9019. pkcsEncodeCertChain(
  9020. OPTIONAL IN CACTX *pCAContext,
  9021. OPTIONAL IN BYTE const *pbCertLeaf,
  9022. IN DWORD cbCertLeaf,
  9023. IN BYTE const *pbToBeSigned,
  9024. IN DWORD cbToBeSigned,
  9025. IN BOOL fIncludeCRLs,
  9026. OUT BYTE **ppbCertChain, // CoTaskMem*
  9027. OUT DWORD *pcbCertChain)
  9028. {
  9029. HRESULT hr;
  9030. CRYPT_SIGN_MESSAGE_PARA csmp;
  9031. CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm = { szOID_OIWSEC_sha1, 0, 0 };
  9032. // init csmp for empty signature
  9033. ZeroMemory(&csmp, sizeof(csmp));
  9034. csmp.cbSize = sizeof(csmp);
  9035. csmp.dwMsgEncodingType = PKCS_7_ASN_ENCODING;
  9036. //csmp.pSigningCert = NULL;
  9037. csmp.HashAlgorithm = DigestAlgorithm;
  9038. //csmp.cMsgCert = 0;
  9039. //csmp.rgpMsgCert = NULL;
  9040. //csmp.cMsgCrl = 0;
  9041. //csmp.rgpMsgCrl = NULL;
  9042. hr = pkcsBuildCRLChain(
  9043. pCAContext,
  9044. pbCertLeaf,
  9045. cbCertLeaf,
  9046. fIncludeCRLs,
  9047. &csmp.cMsgCert,
  9048. NULL,
  9049. &csmp.rgpMsgCert,
  9050. &csmp.cMsgCrl,
  9051. NULL,
  9052. &csmp.rgpMsgCrl);
  9053. _JumpIfError(hr, error, "pkcsBuildCRLChain");
  9054. if (!myCryptSignMessage(
  9055. &csmp,
  9056. pbToBeSigned,
  9057. cbToBeSigned,
  9058. CERTLIB_USE_COTASKMEMALLOC,
  9059. ppbCertChain,
  9060. pcbCertChain))
  9061. {
  9062. hr = myHLastError();
  9063. _JumpError(hr, error, "myCryptSignMessage");
  9064. }
  9065. hr = S_OK;
  9066. error:
  9067. pkcsFreeCRLChain(
  9068. csmp.cMsgCert,
  9069. NULL,
  9070. csmp.rgpMsgCert,
  9071. csmp.cMsgCrl,
  9072. NULL,
  9073. csmp.rgpMsgCrl);
  9074. return(hr);
  9075. }
  9076. HRESULT
  9077. PKCSGetCACert(
  9078. IN DWORD iCert,
  9079. OUT BYTE **ppbCACert,
  9080. OUT DWORD *pcbCACert)
  9081. {
  9082. HRESULT hr;
  9083. DWORD State;
  9084. CACTX *pCAContext;
  9085. hr = PKCSMapCertIndex(iCert, &iCert, &State);
  9086. _JumpIfError(hr, error, "PKCSMapCertIndex");
  9087. // Now we know iCert is a valid Cert Index:
  9088. pCAContext = &g_aCAContext[iCert];
  9089. if (NULL == pCAContext->pccCA)
  9090. {
  9091. hr = E_INVALIDARG;
  9092. _JumpError(hr, error, "invalid cert");
  9093. }
  9094. *pcbCACert = pCAContext->pccCA->cbCertEncoded;
  9095. *ppbCACert = pCAContext->pccCA->pbCertEncoded;
  9096. error:
  9097. return(hr);
  9098. }
  9099. HRESULT
  9100. PKCSGetCAChain(
  9101. IN DWORD iCert,
  9102. IN BOOL fIncludeCRLs,
  9103. OUT BYTE **ppbCAChain, // CoTaskMem*
  9104. OUT DWORD *pcbCAChain)
  9105. {
  9106. HRESULT hr;
  9107. DWORD State;
  9108. CACTX *pCAContext;
  9109. hr = PKCSMapCertIndex(iCert, &iCert, &State);
  9110. _JumpIfError(hr, error, "PKCSMapCertIndex");
  9111. // Now we know iCert is a valid Cert Index:
  9112. pCAContext = &g_aCAContext[iCert];
  9113. if (NULL == pCAContext->pccCA)
  9114. {
  9115. hr = E_INVALIDARG;
  9116. _JumpError(hr, error, "invalid cert");
  9117. }
  9118. hr = pkcsEncodeCertChain(
  9119. pCAContext,
  9120. NULL, // pbCertLeaf
  9121. 0, // cbCertLeaf
  9122. pCAContext->pccCA->pbCertEncoded, // pbToBeSigned
  9123. pCAContext->pccCA->cbCertEncoded, // cbToBeSigned
  9124. fIncludeCRLs,
  9125. ppbCAChain, // CoTaskMem*
  9126. pcbCAChain);
  9127. _JumpIfError(hr, error, "PKCSEncodeCertChain");
  9128. error:
  9129. return(hr);
  9130. }
  9131. HRESULT
  9132. pkcsFormXchgKeyContainerName(
  9133. IN DWORD dwRequestId,
  9134. OUT WCHAR **ppwszKeyContainer)
  9135. {
  9136. HRESULT hr;
  9137. DWORD cwcSuffix;
  9138. DWORD cwcName;
  9139. WCHAR wszSuffix[32];
  9140. WCHAR wszKeyContainer[MAX_PATH];
  9141. *ppwszKeyContainer = NULL;
  9142. cwcSuffix = wsprintf(wszSuffix, L"%ws(%u)", g_wszCNXchgSuffix, dwRequestId);
  9143. CSASSERT(ARRAYSIZE(wszSuffix) > cwcSuffix);
  9144. cwcName = wcslen(g_wszSanitizedName);
  9145. if (cwcName > MAX_PATH - cwcSuffix)
  9146. {
  9147. cwcName = MAX_PATH - cwcSuffix;
  9148. }
  9149. CSASSERT(ARRAYSIZE(wszKeyContainer) > cwcName);
  9150. wcscpy(wszKeyContainer, g_wszSanitizedName);
  9151. wcscpy(&wszKeyContainer[cwcName], wszSuffix);
  9152. hr = myDupString(wszKeyContainer, ppwszKeyContainer);
  9153. _JumpIfError(hr, error, "myDupString");
  9154. DBGPRINT((
  9155. DBG_SS_CERTSRV,
  9156. "pkcsFormXchgKeyContainerName: %ws\n",
  9157. *ppwszKeyContainer));
  9158. error:
  9159. return(hr);
  9160. }
  9161. HRESULT
  9162. pkcsAcquireKey(
  9163. OPTIONAL IN WCHAR const *pwszKeyContainer,
  9164. OUT HCRYPTPROV *phProv)
  9165. {
  9166. HRESULT hr;
  9167. *phProv = NULL;
  9168. if (!CryptAcquireContext(
  9169. phProv,
  9170. pwszKeyContainer,
  9171. g_pwszXchgProvName,
  9172. g_dwXchgProvType,
  9173. g_fXchgMachineKeyset? CRYPT_MACHINE_KEYSET : 0))
  9174. {
  9175. hr = myHLastError();
  9176. _JumpError(hr, error, "CryptAcquireContext");
  9177. }
  9178. hr = S_OK;
  9179. error:
  9180. return(hr);
  9181. }
  9182. VOID
  9183. pkcsDeleteKey(
  9184. OPTIONAL IN WCHAR const *pwszKeyContainer)
  9185. {
  9186. HRESULT hr;
  9187. HCRYPTPROV hProv;
  9188. if (NULL != pwszKeyContainer)
  9189. {
  9190. if (!CryptAcquireContext(
  9191. &hProv,
  9192. pwszKeyContainer,
  9193. g_pwszXchgProvName,
  9194. g_dwXchgProvType,
  9195. CRYPT_DELETEKEYSET |
  9196. (g_fXchgMachineKeyset? CRYPT_MACHINE_KEYSET : 0)))
  9197. {
  9198. hr = myHLastError();
  9199. _JumpError(hr, error, "CryptAcquireContext");
  9200. }
  9201. }
  9202. error:
  9203. ;
  9204. }
  9205. VOID
  9206. pkcsLoadCAXchgCSPInfo(
  9207. IN BOOL fSetDefaults)
  9208. {
  9209. HRESULT hr = S_FALSE;
  9210. if (NULL != g_pwszXchgProvName)
  9211. {
  9212. LocalFree(g_pwszXchgProvName);
  9213. g_pwszXchgProvName = NULL;
  9214. }
  9215. if (!fSetDefaults)
  9216. {
  9217. hr = myGetCertSrvCSP(
  9218. TRUE, // fEncryptionCSP
  9219. g_wszSanitizedName,
  9220. &g_dwXchgProvType,
  9221. &g_pwszXchgProvName,
  9222. &g_XchgidAlg,
  9223. &g_fXchgMachineKeyset,
  9224. &g_dwXchgKeySize);
  9225. if (S_OK != hr)
  9226. {
  9227. _PrintError(hr, "myGetCertSrvCSP(CAXchg)");
  9228. }
  9229. }
  9230. if (S_OK != hr)
  9231. {
  9232. g_dwXchgProvType = PROV_RSA_FULL;
  9233. g_pwszXchgProvName = NULL;
  9234. g_XchgidAlg = CALG_3DES;
  9235. g_fXchgMachineKeyset = TRUE;
  9236. g_dwXchgKeySize = 0;
  9237. }
  9238. if (0 == g_dwXchgKeySize)
  9239. {
  9240. g_dwXchgKeySize = 1024;
  9241. }
  9242. }
  9243. HRESULT
  9244. pkcsCreateNewCAXchgCert(
  9245. IN WCHAR const *pwszUserName)
  9246. {
  9247. HRESULT hr;
  9248. ICertDBRow *prow = NULL;
  9249. DWORD dwRequestFlags = CR_FLG_CAXCHGCERT;
  9250. BOOL fSubjectNameSet;
  9251. BOOL fErrorLogged;
  9252. CERT_PUBLIC_KEY_INFO *pPubKey = NULL;
  9253. DWORD cb;
  9254. CAXCHGCTX CAXchgContext;
  9255. CAXCHGCTX *rgCAXchgContext;
  9256. CERT_EXTENSION aExt[4];
  9257. DWORD cExt;
  9258. DWORD i;
  9259. CERTTRANSBLOB ctbCert; // CoTaskMem*
  9260. CERTSRV_RESULT_CONTEXT Result;
  9261. WCHAR *pwszDisposition = NULL;
  9262. WCHAR *pwszMachineRequesterName = NULL;
  9263. BOOL fCommitted = FALSE;
  9264. static char *s_apszObjId[] =
  9265. {
  9266. szOID_KP_CA_EXCHANGE,
  9267. };
  9268. ZeroMemory(&CAXchgContext, sizeof(CAXchgContext));
  9269. ZeroMemory(&aExt, sizeof(aExt));
  9270. ZeroMemory(&ctbCert, sizeof(ctbCert));
  9271. hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, 0, NULL, &prow);
  9272. _JumpIfError(hr, error, "OpenRow");
  9273. prow->GetRowId(&CAXchgContext.ReqId);
  9274. hr = myGetComputerObjectName(NameSamCompatible, &pwszMachineRequesterName);
  9275. if (S_OK != hr)
  9276. {
  9277. _PrintError(hr, "myGetComputerObjectName");
  9278. hr = myGetUserNameEx(NameSamCompatible, &pwszMachineRequesterName);
  9279. _JumpIfError(hr, error, "myGetUserNameEx");
  9280. }
  9281. hr = prow->SetProperty(
  9282. g_wszPropRequesterName,
  9283. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  9284. MAXDWORD,
  9285. (BYTE const *) pwszMachineRequesterName);
  9286. _JumpIfError(hr, error, "SetProperty");
  9287. hr = prow->SetProperty(
  9288. g_wszPropCallerName,
  9289. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  9290. MAXDWORD,
  9291. (BYTE const *) pwszUserName);
  9292. _JumpIfError(hr, error, "SetProperty");
  9293. hr = prow->SetProperty(
  9294. wszPROPCERTIFICATETEMPLATE,
  9295. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  9296. MAXDWORD,
  9297. (BYTE const *) wszCERTTYPE_CA_EXCHANGE);
  9298. _JumpIfError(hr, error, "SetProperty");
  9299. hr = pkcsFormXchgKeyContainerName(
  9300. CAXchgContext.ReqId,
  9301. &CAXchgContext.pwszKeyContainerName);
  9302. _JumpIfError(hr, error, "pkcsFormXchgKeyContainerName");
  9303. for (i = 0; ; i++)
  9304. {
  9305. hr = myGenerateKeys(
  9306. CAXchgContext.pwszKeyContainerName,
  9307. g_pwszXchgProvName,
  9308. g_fXchgMachineKeyset,
  9309. AT_KEYEXCHANGE,
  9310. g_dwXchgProvType,
  9311. g_dwXchgKeySize,
  9312. &CAXchgContext.hProvCA);
  9313. if (S_OK == hr)
  9314. {
  9315. break;
  9316. }
  9317. _PrintErrorStr(hr, "myGenerateKeys", g_pwszXchgProvName);
  9318. LogEventHResult(
  9319. EVENTLOG_ERROR_TYPE,
  9320. NULL == g_pwszXchgProvName?
  9321. MSG_E_BAD_DEFAULT_CA_XCHG_CSP :
  9322. MSG_E_BAD_REGISTRY_CA_XCHG_CSP,
  9323. hr);
  9324. if (0 != i || NULL == g_pwszXchgProvName)
  9325. {
  9326. _JumpError(hr, error, "myGenerateKeys");
  9327. }
  9328. pkcsLoadCAXchgCSPInfo(TRUE); // switch to default CSP
  9329. }
  9330. if (0 != i)
  9331. {
  9332. hr = LogEvent(
  9333. EVENTLOG_WARNING_TYPE,
  9334. MSG_E_USE_DEFAULT_CA_XCHG_CSP,
  9335. 0, // cpwsz
  9336. NULL); // apwsz
  9337. _PrintIfError(hr, "LogEvent");
  9338. }
  9339. if (!myCryptExportPublicKeyInfo(
  9340. CAXchgContext.hProvCA,
  9341. AT_KEYEXCHANGE,
  9342. CERTLIB_USE_LOCALALLOC,
  9343. &pPubKey,
  9344. &cb))
  9345. {
  9346. hr = myHLastError();
  9347. _JumpError(hr, error, "myCryptExportPublicKeyInfo");
  9348. }
  9349. hr = PropSetRequestTimeProperty(prow, g_wszPropRequestSubmittedWhen);
  9350. _JumpIfError(hr, error, "PropSetRequestTimeProperty");
  9351. hr = CoreSetDisposition(prow, DB_DISP_ACTIVE);
  9352. _JumpIfError(hr, error, "CoreSetDisposition");
  9353. hr = pkcsSetRequestNameInfo(
  9354. prow,
  9355. &g_pCAContextCurrent->pccCA->pCertInfo->Subject,
  9356. g_wszCNXchgSuffix,
  9357. &dwRequestFlags,
  9358. &fSubjectNameSet);
  9359. _JumpIfError(hr, error, "pkcsSetRequestNameInfo");
  9360. hr = prow->SetProperty(
  9361. g_wszPropRequestFlags,
  9362. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  9363. sizeof(dwRequestFlags),
  9364. (BYTE const *) &dwRequestFlags);
  9365. _JumpIfError(hr, error, "SetProperty(RequestFlags)");
  9366. CSASSERT(fSubjectNameSet);
  9367. hr = pkcsSetPublicKeyProperties(prow, pPubKey);
  9368. _JumpIfError(hr, error, "pkcsSetPublicKeyProperties");
  9369. hr = prow->CopyRequestNames();
  9370. _JumpIfError(hr, error, "CopyRequestNames");
  9371. hr = PKCSSetServerProperties(
  9372. prow,
  9373. g_lCAXchgValidityPeriodCount,
  9374. g_enumCAXchgValidityPeriod);
  9375. _JumpIfError(hr, error, "PKCSSetServerProperties");
  9376. cExt = 0;
  9377. // szOID_KEY_USAGE
  9378. {
  9379. CRYPT_BIT_BLOB KeyUsage;
  9380. BYTE abKeyUsage[1] =
  9381. { CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_KEY_AGREEMENT_KEY_USAGE };
  9382. KeyUsage.pbData = abKeyUsage;
  9383. KeyUsage.cbData = sizeof(abKeyUsage);
  9384. KeyUsage.cUnusedBits = 0;
  9385. if (!myEncodeKeyUsage(
  9386. X509_ASN_ENCODING,
  9387. &KeyUsage,
  9388. CERTLIB_USE_LOCALALLOC,
  9389. &aExt[cExt].Value.pbData,
  9390. &aExt[cExt].Value.cbData))
  9391. {
  9392. hr = myHLastError();
  9393. _JumpError(hr, error, "myEncodeKeyUsage");
  9394. }
  9395. }
  9396. hr = PropSetExtension(
  9397. prow,
  9398. PROPTYPE_BINARY | PROPCALLER_SERVER,
  9399. TEXT(szOID_KEY_USAGE),
  9400. 0, // ExtFlags
  9401. aExt[cExt].Value.cbData,
  9402. aExt[cExt].Value.pbData);
  9403. _JumpIfError(hr, error, "PropSetExtension");
  9404. cExt++;
  9405. // szOID_ENHANCED_KEY_USAGE
  9406. {
  9407. CERT_ENHKEY_USAGE eku;
  9408. eku.cUsageIdentifier = ARRAYSIZE(s_apszObjId);
  9409. eku.rgpszUsageIdentifier = s_apszObjId;
  9410. if (!myEncodeObject(
  9411. X509_ASN_ENCODING,
  9412. X509_ENHANCED_KEY_USAGE,
  9413. &eku,
  9414. 0,
  9415. CERTLIB_USE_LOCALALLOC,
  9416. &aExt[cExt].Value.pbData,
  9417. &aExt[cExt].Value.cbData))
  9418. {
  9419. hr = myHLastError();
  9420. _JumpError(hr, error, "myEncodeObject");
  9421. }
  9422. }
  9423. hr = PropSetExtension(
  9424. prow,
  9425. PROPTYPE_BINARY | PROPCALLER_SERVER,
  9426. TEXT(szOID_ENHANCED_KEY_USAGE),
  9427. 0, // ExtFlags
  9428. aExt[cExt].Value.cbData,
  9429. aExt[cExt].Value.pbData);
  9430. _JumpIfError(hr, error, "PropSetExtension");
  9431. cExt++;
  9432. // szOID_APPLICATION_CERT_POLICIES
  9433. {
  9434. CERT_POLICY_INFO acpi[ARRAYSIZE(s_apszObjId)];
  9435. CERT_POLICIES_INFO cps;
  9436. ZeroMemory(&acpi, sizeof(acpi));
  9437. cps.cPolicyInfo = ARRAYSIZE(s_apszObjId);
  9438. cps.rgPolicyInfo = acpi;
  9439. for (i = 0; i < ARRAYSIZE(s_apszObjId); i++)
  9440. {
  9441. acpi[i].pszPolicyIdentifier = s_apszObjId[i];
  9442. }
  9443. if (!myEncodeObject(
  9444. X509_ASN_ENCODING,
  9445. X509_CERT_POLICIES,
  9446. &cps,
  9447. 0,
  9448. CERTLIB_USE_LOCALALLOC,
  9449. &aExt[cExt].Value.pbData,
  9450. &aExt[cExt].Value.cbData))
  9451. {
  9452. hr = myHLastError();
  9453. _JumpError(hr, error, "myEncodeObject");
  9454. }
  9455. }
  9456. hr = PropSetExtension(
  9457. prow,
  9458. PROPTYPE_BINARY | PROPCALLER_SERVER,
  9459. TEXT(szOID_APPLICATION_CERT_POLICIES),
  9460. 0, // ExtFlags
  9461. aExt[cExt].Value.cbData,
  9462. aExt[cExt].Value.pbData);
  9463. _JumpIfError(hr, error, "PropSetExtension");
  9464. cExt++;
  9465. // szOID_ENROLL_CERTTYPE_EXTENSION
  9466. hr = myBuildCertTypeExtension(wszCERTTYPE_CA_EXCHANGE, &aExt[cExt]);
  9467. _JumpIfError(hr, error, "myBuildCertTypeExtension");
  9468. hr = PropSetExtension(
  9469. prow,
  9470. PROPTYPE_BINARY | PROPCALLER_SERVER,
  9471. TEXT(szOID_ENROLL_CERTTYPE_EXTENSION),
  9472. 0, // ExtFlags
  9473. aExt[cExt].Value.cbData,
  9474. aExt[cExt].Value.pbData);
  9475. _JumpIfError(hr, error, "PropSetExtension");
  9476. cExt++;
  9477. CSASSERT(cExt == ARRAYSIZE(aExt));
  9478. ZeroMemory(&Result, sizeof(Result));
  9479. Result.pctbCert = &ctbCert;
  9480. hr = PKCSCreateCertificate(
  9481. prow,
  9482. DB_DISP_ISSUED,
  9483. FALSE,
  9484. &fErrorLogged,
  9485. NULL,
  9486. &Result);
  9487. _JumpIfError(hr, error, "PKCSCreateCertificate");
  9488. CAXchgContext.pccCA = CertCreateCertificateContext(
  9489. X509_ASN_ENCODING,
  9490. ctbCert.pb,
  9491. ctbCert.cb);
  9492. if (NULL == CAXchgContext.pccCA)
  9493. {
  9494. hr = myHLastError();
  9495. _JumpError(hr, error, "CertCreateCertificateContext");
  9496. }
  9497. if (NULL == g_aCAXchgContext)
  9498. {
  9499. CSASSERT(0 == g_cCAXchgCerts);
  9500. rgCAXchgContext = (CAXCHGCTX *) LocalAlloc(
  9501. LMEM_FIXED,
  9502. sizeof(rgCAXchgContext[0]));
  9503. }
  9504. else
  9505. {
  9506. rgCAXchgContext = (CAXCHGCTX *) LocalReAlloc(
  9507. g_aCAXchgContext,
  9508. (g_cCAXchgCerts + 1) * sizeof(rgCAXchgContext[0]),
  9509. LMEM_MOVEABLE);
  9510. }
  9511. if (NULL == rgCAXchgContext)
  9512. {
  9513. hr = E_OUTOFMEMORY;
  9514. _JumpError(hr, error, "LocalAlloc/ReAlloc");
  9515. }
  9516. g_aCAXchgContext = rgCAXchgContext;
  9517. g_aCAXchgContext[g_cCAXchgCerts] = CAXchgContext;
  9518. pwszDisposition = CoreBuildDispositionString(
  9519. g_pwszRequestedBy,
  9520. pwszUserName,
  9521. NULL,
  9522. NULL,
  9523. S_OK,
  9524. FALSE);
  9525. hr = CoreSetRequestDispositionFields(
  9526. prow,
  9527. S_OK,
  9528. DB_DISP_ISSUED,
  9529. pwszDisposition);
  9530. _JumpIfError(hr, error, "CoreSetRequestDispositionFields");
  9531. hr = prow->CommitTransaction(TRUE);
  9532. _JumpIfError(hr, error, "CommitTransaction");
  9533. fCommitted = TRUE;
  9534. g_pCAXchgContextCurrent = &g_aCAXchgContext[g_cCAXchgCerts];
  9535. g_cCAXchgCerts++;
  9536. ZeroMemory(&CAXchgContext, sizeof(CAXchgContext));
  9537. error:
  9538. if (NULL != pwszMachineRequesterName)
  9539. {
  9540. LocalFree(pwszMachineRequesterName);
  9541. }
  9542. if (NULL != pwszDisposition)
  9543. {
  9544. LocalFree(pwszDisposition);
  9545. }
  9546. for (i = 0; i < ARRAYSIZE(aExt); i++)
  9547. {
  9548. if (NULL != aExt[i].Value.pbData)
  9549. {
  9550. LocalFree(aExt[i].Value.pbData);
  9551. }
  9552. }
  9553. if (NULL != prow)
  9554. {
  9555. if (S_OK != hr && !fCommitted)
  9556. {
  9557. HRESULT hr2 = prow->CommitTransaction(FALSE);
  9558. _PrintIfError(hr2, "CommitTransaction");
  9559. }
  9560. prow->Release();
  9561. }
  9562. if (NULL != ctbCert.pb)
  9563. {
  9564. CoTaskMemFree(ctbCert.pb);
  9565. }
  9566. if (NULL != pPubKey)
  9567. {
  9568. LocalFree(pPubKey);
  9569. }
  9570. if (NULL != CAXchgContext.pccCA)
  9571. {
  9572. CertFreeCertificateContext(CAXchgContext.pccCA);
  9573. }
  9574. if (NULL != CAXchgContext.hProvCA)
  9575. {
  9576. CryptReleaseContext(CAXchgContext.hProvCA, 0);
  9577. pkcsDeleteKey(CAXchgContext.pwszKeyContainerName);
  9578. }
  9579. if (NULL != CAXchgContext.pwszKeyContainerName)
  9580. {
  9581. LocalFree(CAXchgContext.pwszKeyContainerName);
  9582. }
  9583. return(hr);
  9584. }
  9585. VOID
  9586. pkcsReleaseCAXchgContext(
  9587. IN OUT CAXCHGCTX *pCAXchgContext)
  9588. {
  9589. if (NULL != pCAXchgContext->hProvCA)
  9590. {
  9591. CryptReleaseContext(pCAXchgContext->hProvCA, 0);
  9592. pCAXchgContext->hProvCA = NULL;
  9593. }
  9594. if (NULL != pCAXchgContext->pccCA)
  9595. {
  9596. CertFreeCertificateContext(pCAXchgContext->pccCA);
  9597. pCAXchgContext->pccCA = NULL;
  9598. }
  9599. if (NULL != pCAXchgContext->pwszKeyContainerName)
  9600. {
  9601. LocalFree(pCAXchgContext->pwszKeyContainerName);
  9602. pCAXchgContext->pwszKeyContainerName = NULL;
  9603. }
  9604. }
  9605. VOID
  9606. pkcsReleaseCAXchgContextArray()
  9607. {
  9608. DWORD i;
  9609. if (NULL != g_aCAXchgContext)
  9610. {
  9611. for (i = 0; i < g_cCAXchgCerts; i++)
  9612. {
  9613. pkcsReleaseCAXchgContext(&g_aCAXchgContext[i]);
  9614. }
  9615. LocalFree(g_aCAXchgContext);
  9616. g_aCAXchgContext = NULL;
  9617. }
  9618. g_cCAXchgCerts = 0;
  9619. g_pCAContextCurrent = NULL;
  9620. }
  9621. HRESULT
  9622. pkcsLoadCAXchgContext(
  9623. IN DWORD iHash)
  9624. {
  9625. HRESULT hr;
  9626. CAXCHGCTX *pCAXchgContext;
  9627. DWORD dwRequestFlags;
  9628. DWORD NameId;
  9629. HCRYPTPROV hProv = NULL;
  9630. WCHAR *pwszKeyContainer = NULL;
  9631. WCHAR *pwszHash = NULL;
  9632. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  9633. BYTE *pbHash = NULL;
  9634. DWORD cbHash;
  9635. BYTE *pbCert = NULL;
  9636. DWORD cbCert;
  9637. DWORD cb;
  9638. BSTR strHash = NULL;
  9639. ICertDBRow *prow = NULL;
  9640. DWORD dwRequestId;
  9641. CERT_CONTEXT const *pcc = NULL;
  9642. BOOL fDeleteKey = FALSE;
  9643. DWORD i;
  9644. hr = myGetCARegHash(
  9645. g_wszSanitizedName,
  9646. CSRH_CAXCHGCERT,
  9647. iHash,
  9648. &pbHash,
  9649. &cbHash);
  9650. _JumpIfError2(hr, error, "myGetCARegHash", S_FALSE);
  9651. hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strHash);
  9652. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  9653. DBGPRINT((
  9654. DBG_SS_CERTSRV,
  9655. "Reloading Xchg CAContext[%u]:\n %ws\n",
  9656. iHash,
  9657. strHash));
  9658. hr = g_pCertDB->OpenRow(
  9659. PROPOPEN_READONLY | PROPOPEN_CERTHASH | PROPTABLE_REQCERT,
  9660. 0,
  9661. strHash,
  9662. &prow);
  9663. _JumpIfError(hr, error, "OpenRow(xchg cert)");
  9664. prow->GetRowId(&dwRequestId);
  9665. hr = pkcsFormXchgKeyContainerName(dwRequestId, &pwszKeyContainer);
  9666. _JumpIfError(hr, error, "pkcsFormXchgKeyContainerName");
  9667. cb = sizeof(dwRequestFlags);
  9668. hr = prow->GetProperty(
  9669. g_wszPropRequestFlags,
  9670. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  9671. &cb,
  9672. (BYTE *) &dwRequestFlags);
  9673. _JumpIfError(hr, error, "GetProperty(RequestFlags)");
  9674. if (0 == (CR_FLG_CAXCHGCERT & dwRequestFlags))
  9675. {
  9676. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  9677. _JumpError(hr, error, "Not a CA Xchg cert");
  9678. }
  9679. cb = sizeof(NameId);
  9680. hr = prow->GetProperty(
  9681. g_wszPropCertificateIssuerNameID,
  9682. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  9683. &cb,
  9684. (BYTE *) &NameId);
  9685. _JumpIfError(hr, error, "GetProperty");
  9686. hr = PKCSGetProperty(
  9687. prow,
  9688. g_wszPropRawCertificate,
  9689. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  9690. &cbCert,
  9691. (BYTE **) &pbCert);
  9692. _JumpIfError(hr, error, "PKCSGetProperty(xchg cert)");
  9693. pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
  9694. if (NULL == pcc)
  9695. {
  9696. hr = myHLastError();
  9697. _JumpError(hr, error, "CertCreateCertificateContext");
  9698. }
  9699. for (i = 0; ; i++)
  9700. {
  9701. hr = pkcsAcquireKey(pwszKeyContainer, &hProv);
  9702. _PrintIfErrorStr(hr, "pkcsAcquireKey", g_pwszXchgProvName);
  9703. if (S_OK == hr)
  9704. {
  9705. hr = myValidateKeyForEncrypting(
  9706. hProv,
  9707. &pcc->pCertInfo->SubjectPublicKeyInfo,
  9708. CALG_3DES);
  9709. _PrintIfErrorStr(hr, "myValidateKeyForEncrypting", g_pwszXchgProvName);
  9710. }
  9711. if (S_OK == hr)
  9712. {
  9713. break;
  9714. }
  9715. LogEventHResult(
  9716. EVENTLOG_ERROR_TYPE,
  9717. NULL == g_pwszXchgProvName?
  9718. MSG_E_BAD_DEFAULT_CA_XCHG_CSP :
  9719. MSG_E_BAD_REGISTRY_CA_XCHG_CSP,
  9720. hr);
  9721. if (0 != i || NULL == g_pwszXchgProvName)
  9722. {
  9723. fDeleteKey = TRUE;
  9724. _JumpError(hr, error, "pkcsAcquireKey/myValidateKeyForEncrypting");
  9725. }
  9726. pkcsLoadCAXchgCSPInfo(TRUE); // switch to default CSP
  9727. }
  9728. if (0 != i)
  9729. {
  9730. hr = LogEvent(
  9731. EVENTLOG_WARNING_TYPE,
  9732. MSG_E_USE_DEFAULT_CA_XCHG_CSP,
  9733. 0, // cpwsz
  9734. NULL); // apwsz
  9735. _PrintIfError(hr, "LogEvent");
  9736. }
  9737. hr = pkcsVerifyCertContext(NULL, FALSE, pcc);
  9738. if (S_OK != hr)
  9739. {
  9740. fDeleteKey = TRUE;
  9741. _JumpErrorStr(hr, error, "pkcsVerifyCertContext", L"CAXchg cert invalid");
  9742. }
  9743. pCAXchgContext = &g_aCAXchgContext[g_cCAXchgCerts];
  9744. ZeroMemory(pCAXchgContext, sizeof(*pCAXchgContext));
  9745. pCAXchgContext->ReqId = dwRequestId;
  9746. pCAXchgContext->pccCA = pcc;
  9747. pcc = NULL;
  9748. pCAXchgContext->hProvCA = hProv;
  9749. hProv = NULL;
  9750. pCAXchgContext->pwszKeyContainerName = pwszKeyContainer;
  9751. pwszKeyContainer = NULL;
  9752. pCAXchgContext->iCertSig = CANAMEIDTOICERT(NameId);
  9753. g_cCAXchgCerts++;
  9754. hr = S_OK;
  9755. error:
  9756. if (NULL != hProv)
  9757. {
  9758. CryptReleaseContext(hProv, 0);
  9759. }
  9760. if (fDeleteKey)
  9761. {
  9762. pkcsDeleteKey(pwszKeyContainer);
  9763. }
  9764. if (NULL != prow)
  9765. {
  9766. prow->Release();
  9767. }
  9768. if (NULL != pbCert)
  9769. {
  9770. LocalFree(pbCert);
  9771. }
  9772. if (NULL != pcc)
  9773. {
  9774. CertFreeCertificateContext(pcc);
  9775. }
  9776. if (NULL != pwszKeyContainer)
  9777. {
  9778. LocalFree(pwszKeyContainer);
  9779. }
  9780. if (NULL != pbHash)
  9781. {
  9782. LocalFree(pbHash);
  9783. }
  9784. if (NULL != strHash)
  9785. {
  9786. SysFreeString(strHash);
  9787. }
  9788. return(hr);
  9789. }
  9790. HRESULT
  9791. pkcsLoadCAXchgContextArray(
  9792. OUT BOOL *pfIncompleteLoad)
  9793. {
  9794. HRESULT hr;
  9795. DWORD cCAXchgCerts;
  9796. DWORD iHash;
  9797. DWORD i;
  9798. // get provider name, etc.
  9799. pkcsLoadCAXchgCSPInfo(FALSE);
  9800. // find & load CA Xchg certs, etc.
  9801. *pfIncompleteLoad = TRUE;
  9802. hr = myGetCARegHashCount(
  9803. g_wszSanitizedName,
  9804. CSRH_CAXCHGCERT,
  9805. &cCAXchgCerts);
  9806. if (S_OK == hr && 0 == cCAXchgCerts)
  9807. {
  9808. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  9809. }
  9810. _JumpIfError(hr, error, "myGetCARegHashCount");
  9811. g_aCAXchgContext = (CAXCHGCTX *) LocalAlloc(
  9812. LMEM_FIXED | LMEM_ZEROINIT,
  9813. cCAXchgCerts * sizeof(g_aCAXchgContext[0]));
  9814. if (NULL == g_aCAXchgContext)
  9815. {
  9816. hr = E_OUTOFMEMORY;
  9817. _JumpError(hr, error, "LocalAlloc");
  9818. }
  9819. for (iHash = 0; iHash < cCAXchgCerts; iHash++)
  9820. {
  9821. hr = pkcsLoadCAXchgContext(iHash);
  9822. _PrintIfError(hr, "pkcsLoadCAXchgContext");
  9823. }
  9824. if (0 == g_cCAXchgCerts)
  9825. {
  9826. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  9827. _JumpError(hr, error, "g_cCAXchgCerts");
  9828. }
  9829. g_pCAXchgContextCurrent = &g_aCAXchgContext[0];
  9830. for (i = 1; i < g_cCAXchgCerts; i++)
  9831. {
  9832. if (0 < CompareFileTime(
  9833. &g_aCAXchgContext[i].pccCA->pCertInfo->NotAfter,
  9834. &g_pCAXchgContextCurrent->pccCA->pCertInfo->NotAfter))
  9835. {
  9836. g_pCAXchgContextCurrent = &g_aCAXchgContext[i];
  9837. }
  9838. }
  9839. if (cCAXchgCerts == g_cCAXchgCerts)
  9840. {
  9841. *pfIncompleteLoad = FALSE;
  9842. }
  9843. hr = S_OK;
  9844. error:
  9845. if (S_OK != hr)
  9846. {
  9847. if (NULL != g_aCAXchgContext)
  9848. {
  9849. LocalFree(g_aCAXchgContext);
  9850. g_aCAXchgContext = NULL;
  9851. }
  9852. g_cCAXchgCerts = 0;
  9853. g_pCAXchgContextCurrent = NULL;
  9854. }
  9855. return(hr);
  9856. }
  9857. HRESULT
  9858. pkcsUpdateCAXchgStoreAndRegistry(
  9859. IN BOOL fUpdateRegistry)
  9860. {
  9861. HRESULT hr;
  9862. DWORD i;
  9863. DWORD iHash;
  9864. CAXCHGCTX *pCAXchgContext;
  9865. HCERTSTORE hStore = NULL;
  9866. CERT_KEY_CONTEXT ckc;
  9867. CERT_CONTEXT const *pccStore = NULL;
  9868. hStore = CertOpenStore(
  9869. CERT_STORE_PROV_MEMORY,
  9870. X509_ASN_ENCODING,
  9871. NULL, // hProv
  9872. 0, // dwFlags
  9873. NULL); // pvPara
  9874. if (NULL == hStore)
  9875. {
  9876. hr = myHLastError();
  9877. _JumpError(hr, error, "CertOpenStore");
  9878. }
  9879. if (fUpdateRegistry)
  9880. {
  9881. hr = myDeleteCertRegValue(
  9882. g_wszSanitizedName,
  9883. NULL,
  9884. NULL,
  9885. g_wszRegCAXchgCertHash);
  9886. _PrintIfError(hr, "myDeleteCertRegValue");
  9887. }
  9888. ZeroMemory(&ckc, sizeof(ckc));
  9889. ckc.cbSize = sizeof(ckc);
  9890. ckc.dwKeySpec = AT_KEYEXCHANGE;
  9891. iHash = 0;
  9892. for (i = 0; i < g_cCAXchgCerts; i++)
  9893. {
  9894. pCAXchgContext = &g_aCAXchgContext[i];
  9895. if (CTXF_EXPIRED & pCAXchgContext->Flags)
  9896. {
  9897. continue;
  9898. }
  9899. // Add as encoded blob to avoid all properties, key prov info, etc.
  9900. if (!CertAddEncodedCertificateToStore(
  9901. hStore,
  9902. X509_ASN_ENCODING,
  9903. pCAXchgContext->pccCA->pbCertEncoded,
  9904. pCAXchgContext->pccCA->cbCertEncoded,
  9905. CERT_STORE_ADD_REPLACE_EXISTING,
  9906. &pccStore)) // ppCertContext
  9907. {
  9908. hr = myHLastError();
  9909. _JumpError(hr, error, "CertAddEncodedCertificateToStore");
  9910. }
  9911. ckc.hCryptProv = pCAXchgContext->hProvCA;
  9912. if (!CertSetCertificateContextProperty(
  9913. pccStore,
  9914. CERT_KEY_CONTEXT_PROP_ID,
  9915. CERT_STORE_NO_CRYPT_RELEASE_FLAG,
  9916. &ckc))
  9917. {
  9918. hr = myHLastError();
  9919. _JumpError(hr, error, "CertSetCertificateContextProperty");
  9920. }
  9921. CertFreeCertificateContext(pccStore);
  9922. pccStore = NULL;
  9923. DBGPRINT((
  9924. DBG_SS_CERTSRV,
  9925. "Add to CA Xchg memory store: '%ws'\n",
  9926. pCAXchgContext->pwszKeyContainerName));
  9927. if (fUpdateRegistry)
  9928. {
  9929. hr = mySetCARegHash(
  9930. g_wszSanitizedName,
  9931. CSRH_CAXCHGCERT,
  9932. iHash,
  9933. pCAXchgContext->pccCA);
  9934. if (S_OK != hr)
  9935. {
  9936. _PrintError(hr, "mySetCARegHash");
  9937. continue;
  9938. }
  9939. }
  9940. iHash++;
  9941. }
  9942. if (NULL != g_hStoreCAXchg)
  9943. {
  9944. CertCloseStore(g_hStoreCAXchg, CERT_CLOSE_STORE_CHECK_FLAG);
  9945. }
  9946. g_hStoreCAXchg = hStore;
  9947. hStore = NULL;
  9948. hr = S_OK;
  9949. error:
  9950. if (NULL != pccStore)
  9951. {
  9952. CertFreeCertificateContext(pccStore);
  9953. }
  9954. if (NULL != hStore)
  9955. {
  9956. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  9957. }
  9958. return(hr);
  9959. }
  9960. HRESULT
  9961. PKCSIsRevoked(
  9962. IN DWORD RequestId,
  9963. OPTIONAL IN WCHAR const *pwszSerialNumber,
  9964. OUT LONG *pRevocationReason,
  9965. OUT LONG *pDisposition)
  9966. {
  9967. HRESULT hr;
  9968. ICertDBRow *prow = NULL;
  9969. BYTE *pbHash = NULL;
  9970. DWORD cbHash;
  9971. BSTR strHash = NULL;
  9972. DWORD Disposition;
  9973. DWORD cbProp;
  9974. FILETIME ftRevoked;
  9975. FILETIME ftCurrent;
  9976. *pRevocationReason = CRL_REASON_UNSPECIFIED;
  9977. *pDisposition = CA_DISP_INVALID;
  9978. hr = g_pCertDB->OpenRow(
  9979. PROPOPEN_READONLY | PROPTABLE_REQCERT,
  9980. RequestId,
  9981. pwszSerialNumber,
  9982. &prow);
  9983. _PrintIfErrorStr2(hr, "OpenRow", pwszSerialNumber, CERTSRV_E_PROPERTY_EMPTY);
  9984. if (CERTSRV_E_PROPERTY_EMPTY == hr && NULL != pwszSerialNumber)
  9985. {
  9986. _PrintErrorStr2(
  9987. hr,
  9988. "OpenRow(serial)",
  9989. pwszSerialNumber,
  9990. CERTSRV_E_PROPERTY_EMPTY);
  9991. hr = WszToMultiByteInteger(TRUE, pwszSerialNumber, &cbHash, &pbHash);
  9992. _JumpIfError(hr, error, "WszToMultiByteInteger");
  9993. hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strHash);
  9994. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  9995. hr = g_pCertDB->OpenRow(
  9996. PROPOPEN_READONLY |
  9997. PROPOPEN_CERTHASH |
  9998. PROPTABLE_REQCERT,
  9999. RequestId,
  10000. strHash,
  10001. &prow);
  10002. _PrintIfErrorStr2(hr, "OpenRow", strHash, CERTSRV_E_PROPERTY_EMPTY);
  10003. }
  10004. if (S_OK != hr)
  10005. {
  10006. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  10007. {
  10008. hr = S_OK; // disposition indicates cert is invalid
  10009. }
  10010. goto error;
  10011. }
  10012. cbProp = sizeof(Disposition);
  10013. hr = prow->GetProperty(
  10014. g_wszPropRequestDisposition,
  10015. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  10016. &cbProp,
  10017. (BYTE *) &Disposition);
  10018. _JumpIfError(hr, error, "GetProperty(Disposition)");
  10019. if (DB_DISP_ISSUED == Disposition ||
  10020. (DB_DISP_CA_CERT == Disposition && IsRootCA(g_CAType)))
  10021. {
  10022. *pDisposition = CA_DISP_VALID;
  10023. goto error;
  10024. }
  10025. if (DB_DISP_REVOKED != Disposition)
  10026. {
  10027. goto error;
  10028. }
  10029. cbProp = sizeof(ftRevoked);
  10030. hr = prow->GetProperty(
  10031. g_wszPropRequestRevokedEffectiveWhen,
  10032. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  10033. &cbProp,
  10034. (BYTE *) &ftRevoked);
  10035. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  10036. {
  10037. *pDisposition = CA_DISP_VALID;
  10038. hr = S_OK;
  10039. goto error;
  10040. }
  10041. _JumpIfError(hr, error, "GetProperty(RevokedEffectiveWhen)");
  10042. GetSystemTimeAsFileTime(&ftCurrent);
  10043. if (0 < CompareFileTime(&ftRevoked, &ftCurrent))
  10044. {
  10045. *pDisposition = CA_DISP_VALID;
  10046. goto error;
  10047. }
  10048. cbProp = sizeof(*pRevocationReason);
  10049. hr = prow->GetProperty(
  10050. g_wszPropRequestRevokedReason,
  10051. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  10052. &cbProp,
  10053. (BYTE *) pRevocationReason);
  10054. _JumpIfError(hr, error, "GetProperty(RevokedReason)");
  10055. *pDisposition = CA_DISP_REVOKED;
  10056. error:
  10057. if (NULL != pbHash)
  10058. {
  10059. LocalFree(pbHash);
  10060. }
  10061. if (NULL != strHash)
  10062. {
  10063. SysFreeString(strHash);
  10064. }
  10065. if (NULL != prow)
  10066. {
  10067. prow->Release();
  10068. }
  10069. return(hr);
  10070. }
  10071. HRESULT
  10072. PKCSGetCAXchgCert(
  10073. IN DWORD iCert,
  10074. IN WCHAR const *pwszUserName,
  10075. OUT DWORD *piCertSig,
  10076. OUT BYTE **ppbCACert,
  10077. OUT DWORD *pcbCACert)
  10078. {
  10079. HRESULT hr;
  10080. DWORD State;
  10081. BOOL fNewCert = FALSE;
  10082. BOOL fIncompleteLoad = FALSE;
  10083. FILETIME ft;
  10084. if (MAXDWORD != iCert && 0 != iCert)
  10085. {
  10086. hr = E_INVALIDARG;
  10087. _JumpError(hr, error, "bad Xchg CertIndex");
  10088. }
  10089. if (NULL == g_pCAXchgContextCurrent ||
  10090. NULL == g_pCAXchgContextCurrent->pccCA)
  10091. {
  10092. hr = pkcsLoadCAXchgContextArray(&fIncompleteLoad);
  10093. _PrintIfError(hr, "pkcsLoadCAXchgContextArray");
  10094. if (S_OK != hr)
  10095. {
  10096. fNewCert = TRUE;
  10097. }
  10098. }
  10099. if (NULL != g_pCAXchgContextCurrent &&
  10100. NULL != g_pCAXchgContextCurrent->pccCA)
  10101. {
  10102. CERT_INFO const *pCertInfo = g_pCAXchgContextCurrent->pccCA->pCertInfo;
  10103. GetSystemTimeAsFileTime(&ft);
  10104. if (0 < CompareFileTime(&ft, &pCertInfo->NotAfter))
  10105. {
  10106. g_pCAXchgContextCurrent->Flags |= CTXF_EXPIRED;
  10107. hr = CERT_E_EXPIRED;
  10108. _PrintError(hr, "CA Xchg certificate is expired -- delete key");
  10109. pkcsDeleteKey(g_pCAXchgContextCurrent->pwszKeyContainerName);
  10110. fNewCert = TRUE;
  10111. }
  10112. else
  10113. if (0 > CompareFileTime(&ft, &pCertInfo->NotBefore))
  10114. {
  10115. hr = CERT_E_EXPIRED;
  10116. _PrintError(hr, "CA Xchg certificate not yet valid");
  10117. fNewCert = TRUE;
  10118. }
  10119. else
  10120. {
  10121. myMakeExprDateTime(
  10122. &ft,
  10123. g_lCAXchgOverlapPeriodCount,
  10124. g_enumCAXchgOverlapPeriod);
  10125. if (0 < CompareFileTime(&ft, &pCertInfo->NotAfter))
  10126. {
  10127. hr = CERT_E_EXPIRED;
  10128. _PrintError(hr, "CA Xchg certificate expires too soon");
  10129. fNewCert = TRUE;
  10130. }
  10131. else
  10132. {
  10133. hr = pkcsVerifyCertIssuer(
  10134. g_pCAXchgContextCurrent->pccCA,
  10135. g_pCAContextCurrent);
  10136. if (S_OK != hr)
  10137. {
  10138. _PrintError(hr, "CA Xchg cert not issued by current CA");
  10139. fNewCert = TRUE;
  10140. }
  10141. else
  10142. {
  10143. LONG RevocationReason;
  10144. LONG Disposition;
  10145. hr = PKCSIsRevoked(
  10146. g_pCAXchgContextCurrent->ReqId,
  10147. NULL, // pwszSerialNumber
  10148. &RevocationReason,
  10149. &Disposition);
  10150. if (S_OK != hr)
  10151. {
  10152. _PrintError(hr, "PKCSIsRevoked");
  10153. fNewCert = TRUE;
  10154. }
  10155. else
  10156. if (CA_DISP_VALID != Disposition)
  10157. {
  10158. hr = CRYPT_E_REVOKED;
  10159. _PrintError(hr, "revoked or bad CA Xchg certificate");
  10160. fNewCert = TRUE;
  10161. }
  10162. }
  10163. }
  10164. }
  10165. }
  10166. if (fNewCert)
  10167. {
  10168. hr = pkcsCreateNewCAXchgCert(pwszUserName);
  10169. _JumpIfError(hr, error, "pkcsCreateNewCAXchgCert");
  10170. }
  10171. hr = pkcsUpdateCAXchgStoreAndRegistry(fNewCert || fIncompleteLoad);
  10172. _JumpIfError(hr, error, "pkcsUpdateCAXchgStoreAndRegistry");
  10173. *piCertSig = g_pCAXchgContextCurrent->iCertSig;
  10174. *pcbCACert = g_pCAXchgContextCurrent->pccCA->cbCertEncoded;
  10175. *ppbCACert = g_pCAXchgContextCurrent->pccCA->pbCertEncoded;
  10176. hr = S_OK;
  10177. error:
  10178. return(hr);
  10179. }
  10180. HRESULT
  10181. PKCSGetCAXchgChain(
  10182. IN DWORD iCert,
  10183. IN WCHAR const *pwszUserName,
  10184. IN BOOL fIncludeCRLs,
  10185. OUT BYTE **ppbCAChain, // CoTaskMem*
  10186. OUT DWORD *pcbCAChain)
  10187. {
  10188. HRESULT hr;
  10189. BYTE *pbCACert;
  10190. DWORD cbCACert;
  10191. CACTX *pCAContext;
  10192. hr = PKCSGetCAXchgCert(iCert, pwszUserName, &iCert, &pbCACert, &cbCACert);
  10193. _JumpIfError(hr, error, "PKCSGetCAXchgCert");
  10194. // iCert now indexes the signature cert that signed the current Xchg cert
  10195. pCAContext = &g_aCAContext[iCert];
  10196. if (NULL == pCAContext->pccCA)
  10197. {
  10198. hr = E_INVALIDARG;
  10199. _JumpError(hr, error, "invalid cert");
  10200. }
  10201. hr = pkcsEncodeCertChain(
  10202. pCAContext,
  10203. pbCACert, // pbCertLeaf
  10204. cbCACert, // cbCertLeaf
  10205. pbCACert, // pbToBeSigned
  10206. cbCACert, // cbToBeSigned
  10207. fIncludeCRLs,
  10208. ppbCAChain, // CoTaskMem*
  10209. pcbCAChain);
  10210. _JumpIfError(hr, error, "PKCSEncodeCertChain");
  10211. error:
  10212. return(hr);
  10213. }
  10214. VOID
  10215. PKCSTerminate(VOID)
  10216. {
  10217. pkcsReleaseCAContextArray();
  10218. pkcsReleaseCAXchgContextArray();
  10219. if (NULL != g_hStoreCAXchg)
  10220. {
  10221. CertCloseStore(g_hStoreCAXchg, CERT_CLOSE_STORE_CHECK_FLAG);
  10222. g_hStoreCAXchg = NULL;
  10223. }
  10224. pkcsLoadCAXchgCSPInfo(TRUE);
  10225. pkcsReleaseKRACertArray();
  10226. pkcsFreeTemplates(&g_paRevURL, &g_caRevURL);
  10227. pkcsFreeTemplates(&g_paCACertURL, &g_caCACertURL);
  10228. if (NULL != g_pwszKRAPublishURL)
  10229. {
  10230. LocalFree(g_pwszKRAPublishURL);
  10231. g_pwszKRAPublishURL = NULL;
  10232. }
  10233. if (NULL != g_pwszAIACrossCertPublishURL)
  10234. {
  10235. LocalFree(g_pwszAIACrossCertPublishURL);
  10236. g_pwszAIACrossCertPublishURL = NULL;
  10237. }
  10238. if (NULL != g_pwszRootTrustCrossCertPublishURL)
  10239. {
  10240. LocalFree(g_pwszRootTrustCrossCertPublishURL);
  10241. g_pwszRootTrustCrossCertPublishURL = NULL;
  10242. }
  10243. if (NULL != g_strDomainDN)
  10244. {
  10245. SysFreeString(g_strDomainDN);
  10246. g_strDomainDN = NULL;
  10247. }
  10248. if (NULL != g_strConfigDN)
  10249. {
  10250. SysFreeString(g_strConfigDN);
  10251. g_strConfigDN = NULL;
  10252. }
  10253. }
  10254. // PKCSCreateCertificate -- Create certificate & build PKCS 7 or Full Response.
  10255. //
  10256. // If pResult->pctbCert is non-NULL and pResult->pctbCert->pb is NULL:
  10257. // CR_IN_NEW:
  10258. // Build, store and return cert
  10259. // Use current CA Context
  10260. // Build and return PKCS 7 or Full Response
  10261. //
  10262. // If pResult->pctbCert is non-NULL and pResult->pctbCert->pb is non-NULL:
  10263. // CR_IN_RETRIEVEPENDING:
  10264. // Use passed cert
  10265. // Find matching CA Context
  10266. // Build and return PKCS 7 or Full Response
  10267. //
  10268. // If pResult->pctbCert is NULL:
  10269. // CR_IN_RESUBMIT:
  10270. // Build and store cert -- don't return cert
  10271. // Use current CA Context
  10272. // Don't build or return PKCS 7 or Full Response
  10273. HRESULT
  10274. PKCSCreateCertificate(
  10275. IN ICertDBRow *prow,
  10276. IN DWORD Disposition,
  10277. IN BOOL fIncludeCRLs,
  10278. OUT BOOL *pfErrorLogged,
  10279. OPTIONAL OUT CACTX **ppCAContext,
  10280. IN OUT CERTSRV_RESULT_CONTEXT *pResult) // CoTaskMem*
  10281. {
  10282. HRESULT hr;
  10283. BYTE *pbCert = NULL;
  10284. DWORD cbCert;
  10285. BYTE *pbCertChain = NULL;
  10286. DWORD cbCertChain;
  10287. DWORD cCert;
  10288. BOOL fCreated = FALSE;
  10289. DWORD i;
  10290. CACTX *pCAContext;
  10291. CERT_CONTEXT const *pcc = NULL;
  10292. if (NULL != ppCAContext)
  10293. {
  10294. *ppCAContext = NULL;
  10295. }
  10296. *pfErrorLogged = FALSE;
  10297. CSASSERT(NULL == pResult->pctbCertChain || NULL == pResult->pctbCertChain->pb);
  10298. CSASSERT(NULL == pResult->pctbFullResponse || NULL == pResult->pctbFullResponse->pb);
  10299. if (NULL != pResult->pctbCert && NULL != pResult->pctbCert->pb)
  10300. {
  10301. pbCert = pResult->pctbCert->pb;
  10302. cbCert = pResult->pctbCert->cb;
  10303. pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
  10304. if (NULL == pcc)
  10305. {
  10306. hr = myHLastError();
  10307. _JumpError(hr, error, "CertCreateCertificateContext");
  10308. }
  10309. pCAContext = NULL;
  10310. if (DB_DISP_CA_CERT != Disposition &&
  10311. DB_DISP_CA_CERT_CHAIN != Disposition)
  10312. {
  10313. hr = PKCSVerifyIssuedCertificate(pcc, &pCAContext);
  10314. _JumpIfError(hr, error, "PKCSVerifyIssuedCertificate");
  10315. }
  10316. }
  10317. else
  10318. {
  10319. pCAContext = g_pCAContextCurrent;
  10320. cbCert = 0;
  10321. hr = pkcsEncodeSubjectCert(
  10322. prow,
  10323. pCAContext,
  10324. &pbCert, // CoTaskMem*
  10325. &cbCert,
  10326. pfErrorLogged);
  10327. _JumpIfError(hr, error, "pkcsEncodeSubjectCert");
  10328. fCreated = TRUE;
  10329. hr = prow->SetProperty(
  10330. g_wszPropRawCertificate,
  10331. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  10332. cbCert,
  10333. pbCert);
  10334. _JumpIfError(hr, error, "SetProperty");
  10335. }
  10336. if (NULL != pResult->pctbCertChain)
  10337. {
  10338. hr = pkcsEncodeCertChain(
  10339. pCAContext,
  10340. pbCert, // pbCertLeaf
  10341. cbCert, // cbCertLeaf
  10342. pbCert, // pbToBeSigned
  10343. cbCert, // cbToBeSigned
  10344. fIncludeCRLs,
  10345. &pbCertChain, // CoTaskMem*
  10346. &cbCertChain);
  10347. _JumpIfError(hr, error, "pkcsEncodeCertChain");
  10348. }
  10349. if (fCreated && NULL != pResult->pctbCert)
  10350. {
  10351. pResult->pctbCert->pb = pbCert;
  10352. pResult->pctbCert->cb = cbCert;
  10353. pbCert = NULL;
  10354. }
  10355. if (NULL != pResult->pctbCertChain)
  10356. {
  10357. pResult->pctbCertChain->pb = pbCertChain;
  10358. pResult->pctbCertChain->cb = cbCertChain;
  10359. pbCertChain = NULL;
  10360. }
  10361. if (NULL != ppCAContext)
  10362. {
  10363. *ppCAContext = pCAContext;
  10364. }
  10365. hr = S_OK;
  10366. error:
  10367. if (NULL != pcc)
  10368. {
  10369. CertFreeCertificateContext(pcc);
  10370. }
  10371. if (fCreated && NULL != pbCert)
  10372. {
  10373. CoTaskMemFree(pbCert);
  10374. }
  10375. if (fCreated && NULL != pbCertChain)
  10376. {
  10377. CoTaskMemFree(pbCertChain);
  10378. }
  10379. CSASSERT(
  10380. NULL == pResult->pctbCertChain ||
  10381. ((S_OK == hr) ^ (NULL == pResult->pctbCertChain->pb)));
  10382. return(hr);
  10383. }
  10384. HRESULT
  10385. PKCSGetKRACert(
  10386. IN DWORD iCert,
  10387. OUT BYTE **ppbCert,
  10388. OUT DWORD *pcbCert)
  10389. {
  10390. HRESULT hr = S_OK;
  10391. DWORD State;
  10392. if (MAXDWORD == iCert)
  10393. {
  10394. iCert = g_iKRACerts;
  10395. }
  10396. if (iCert >= g_cKRACerts)
  10397. {
  10398. hr = E_INVALIDARG;
  10399. _JumpError(hr, error, "bad CertIndex");
  10400. }
  10401. *pcbCert = g_rgKRACerts[iCert]->cbCertEncoded;
  10402. *ppbCert = g_rgKRACerts[iCert]->pbCertEncoded;
  10403. error:
  10404. return(hr);
  10405. }