Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

15538 lines
368 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 <esent.h>
  18. #include "dbtable.h"
  19. #include "resource.h"
  20. #include "cscom.h"
  21. #include "csprop.h"
  22. #include "elog.h"
  23. #include "certlog.h"
  24. #include "csdisp.h"
  25. #include "cscsp.h"
  26. #include <certca.h>
  27. #include <esent.h>
  28. #include <winldap.h>
  29. #include "csldap.h"
  30. #include "cainfop.h"
  31. #define __dwFILE__ __dwFILE_CERTSRV_PKCS_CPP__
  32. CSURLTEMPLATE *g_paRevURL = NULL;
  33. DWORD g_caRevURL = 0;
  34. CSURLTEMPLATE *g_paCACertURL = NULL;
  35. DWORD g_caCACertURL = 0;
  36. BSTR g_strDomainDN = NULL;
  37. BSTR g_strConfigDN = NULL;
  38. WCHAR *g_pwszKRAPublishURL = NULL;
  39. WCHAR *g_pwszAIACrossCertPublishURL = NULL;
  40. WCHAR *g_pwszRootTrustCrossCertPublishURL = NULL;
  41. // Note on Renewal and Key reuse:
  42. //
  43. // Cert Indexes, Key Indexes and CRL Name Indexes are all zero based.
  44. //
  45. // One CRL is issued by this CA for each unique key. Each CRL covers all of
  46. // the certs issued by this CA for one key, even though the key may have been
  47. // used by multiple renewal certs.
  48. //
  49. // The database IssuerNameID PROPTYPE_LONG column holds the Key Index in the
  50. // top 16 bits and the Cert Index in the bottom 16 bits. This allows a pair of
  51. // query restrictions to reduce the result row set to those revoked certs
  52. // that will be placed into a single CRL.
  53. //
  54. // When Cert File, Key Container, CRL File or DS Object name templates include
  55. // an Index Suffix, an empty string suffix, "", is used when the index is zero.
  56. // Otherwise the Suffix is "(%u)", where the index itself is passed to wsprintf
  57. // to construct the %u field.
  58. //
  59. // Cert Indexes increment each time the CA cert is renewed. Because 16 bit
  60. // Cert Indexes are stored in the database, a CA may have up to 64k certs,
  61. // and be renewed a maximum of 64k-1 times.
  62. //
  63. // The Cert File Name Suffix is built from the Cert Index.
  64. //
  65. // Key Indexes: The original installed CA cert uses a Key Index of 0.
  66. // If a renewal cert uses the same key as any previous cert used by this CA,
  67. // the Key Index for the new CA cert is taken from the previous CA cert.
  68. // If a renewal cert uses a new Key, the Cert Index is used for the Key Index.
  69. // The primary reason sequential Key Indexes are not used for new keys is that
  70. // too much context information is required to determine the next Key Index --
  71. // which is particularly difficult to obtain when performing PFX restore.
  72. //
  73. // The Key Container Name Suffix is built from the Key Index.
  74. //
  75. //
  76. // CRL Indexes: same as Key Index.
  77. // CRL File Name Suffix: same as Key Container Name Suffix.
  78. //
  79. // Example: Cert CertName Key KeyName CRL CRLName
  80. // Index Suffix Index Suffix Index Suffix
  81. // Original Install 0 "" 0 "" 0 ""
  82. //
  83. // Renew, new Key 1 "(1)" 1 "(1)" 1 "(1)"
  84. // *Renew, reuse Key 2 "(2)" 1 "(1)" 1 "(1)"
  85. // *Renew, reuse Key 3 "(3)" 1 "(1)" 1 "(1)"
  86. //
  87. // Renew, new Key 4 "(4)" 4 "(4)" 4 "(4)"
  88. // *Renew, reuse Key 5 "(5)" 4 "(4)" 4 "(4)"
  89. //
  90. // Renew, new Key 6 "(6)" 6 "(6)" 6 "(6)"
  91. // *Renew, reuse Key 7 "(7)" 6 "(6)" 6 "(6)"
  92. //
  93. //
  94. // CCertRequest::GetCACertificate can be used to fetch Certs and CRLs by Index.
  95. // This API always accepts a Cert Index.
  96. //
  97. // When fetching a certificate: If the Cert Index is valid, the appropriate
  98. // certificate or chain is returned, even if it is expired or revoked.
  99. //
  100. // When fetching a CRL: If the Cert Index is valid AND if the Cert Index
  101. // MATCHES the Key Index for the indexed Cert, the appropriate CRL is returned.
  102. // This means that an error will be returned when requesting CRLs associated
  103. // with entries in the above table that reused keys (marked with an asterisk
  104. // in the first column). The nearest previous unmarked entry's CRL covers
  105. // revocations for the marked entries.
  106. //
  107. //
  108. // CCertServer{Policy,Exit}::GetCertificateProperty can be used to fetch
  109. // information about Certs and CRLs. This API allows an optional numeric
  110. // suffix on the property name, as in "RawCRL.3". The suffix is always
  111. // interpreted as a Cert Index.
  112. //
  113. // wszPROPCERTCOUNT: Returns total CA Cert count, including expired and
  114. // revoked certs. No numeric Cert Index suffix is allowed.
  115. //
  116. // wszPROPRAWCACERTIFICATE: Returns the Cert for the passed Cert Index.
  117. // Returns the Cert for the most recent Cert Index if no Cert Index is
  118. // specified. Expired and revoked certs are still retrievable.
  119. //
  120. // wszPROPCERTSTATE: Returns the Cert State for the passed Cert Index.
  121. // Returns the Cert State for the most recent Cert Index if no Cert Index is
  122. // specified.
  123. // Values for wszPROPCERTSTATE (see certadm.h):
  124. // CA_DISP_REVOKED // This Cert has been revoked.
  125. // CA_DISP_VALID // This Cert is still valid
  126. // CA_DISP_INVALID // This Cert has expired.
  127. // CA_DISP_ERROR // Cert unavailable (placehholder in registry?)
  128. //
  129. // wszPROPCERTSUFFIX: Returns the Cert FileName Suffix for the passed Cert
  130. // Index. Returns the Cert FileName Suffix for the most recent Cert Index if
  131. // no Cert Index is specified.
  132. //
  133. // wszPROPRAWCRL: Returns the CRL for the passed Cert Index. As with
  134. // CCertRequest::GetCACertificate, it is an error to fetch a CRL for a Cert
  135. // that reused keys. In the above table, only "RawCRL.0", "RawCRL.1",
  136. // "RawCRL.4", "RawCRL.6" & "RawCRL" are allowed. "RawCRL" will fetch the most
  137. // recent CRL. Use the wszPROPCRLSTATE with a numeric Cert Index suffix to
  138. // determine which CRLs are valid to fetch. CA_DISP_ERROR indicates the
  139. // CRL cannot be fetched. CA_DISP_REVOKED and CA_DISP_INVALID CRLs are still
  140. // retrievable via this method call.
  141. //
  142. // All of the other CRL-related property fetches are supported for all valid
  143. // Cert Index values:
  144. //
  145. // wszPROPCRLINDEX: Returns the CRL Index value for the passed Cert Index.
  146. // Returns the CRL Index value for the most recent Cert Index if no Cert Index
  147. // is specified.
  148. //
  149. // wszPROPCRLSTATE: Returns the CRL State for the passed Cert Index.
  150. // Returns the CRL State for the most recent Cert Index if no Cert Index is
  151. // specified.
  152. // Values for wszPROPCRLSTATE (see certadm.h):
  153. // CA_DISP_REVOKED // All unexpired certs using this Cert's CRL have been
  154. // // revoked.
  155. // CA_DISP_VALID // This Cert is still publishing CRLs as needed.
  156. // CA_DISP_INVALID // All certs using this Cert's CRL are expired.
  157. // CA_DISP_ERROR // This Cert's CRL is managed by another Cert.
  158. //
  159. // wszPROPCRLSUFFIX: Returns the CRL FileName Suffix for the passed Cert Index.
  160. // Returns the CRL FileName Suffix for the most recent Cert Index if no Cert
  161. // Index is specified.
  162. CACTX *g_aCAContext; // allocated array of CACTXs
  163. CACTX *g_pCAContextCurrent; // current CACTX is last g_aCAContext element
  164. CACROSSCTX *g_aCACrossForward; // allocated array of CACROSSCTXs; root CA only
  165. CACROSSCTX *g_aCACrossBackward; // allocated array of CACROSSCTXs; root CA only
  166. typedef struct _KRACTX
  167. {
  168. DWORD Flags;
  169. HRESULT hrVerifyStatus;
  170. CERT_CONTEXT const *pccKRA;
  171. BSTR strKRAHash;
  172. } KRACTX;
  173. KRACTX *g_aKRAContext;
  174. DWORD g_cKRACertsRoundRobin = 0;
  175. DWORD g_cCAKeys; // Total number of unique CA keys managed by this CA
  176. DWORD g_cCACerts; // Total number of CA certs managed by this CA
  177. DWORD g_cKRACerts; // Total number of KRA certs loaded by this CA
  178. BOOL g_fcritsecCAXchg = FALSE;
  179. CRITICAL_SECTION g_critsecCAXchg;
  180. CAXCHGCTX *g_aCAXchgContext; // allocated array of CAXCHGCTXs
  181. CAXCHGCTX *g_pCAXchgContextCurrent; // current CAXCHGCTX is last element
  182. DWORD g_cCAXchgCerts; // number of CA Xchg certs managed by this CA
  183. HCERTSTORE g_hStoreCAXchg = NULL;
  184. DWORD g_dwXchgProvType;
  185. WCHAR *g_pwszXchgProvName = NULL;
  186. ALG_ID g_XchgidAlg;
  187. BOOL g_fXchgMachineKeyset;
  188. DWORD g_dwXchgKeySize;
  189. DWORD g_dwVerifyCertFlags;
  190. LONG g_lValidityPeriodCount = dwVALIDITYPERIODCOUNTDEFAULT_STANDALONE;
  191. enum ENUM_PERIOD g_enumValidityPeriod = dwVALIDITYPERIODENUMDEFAULT;
  192. enum ENUM_PERIOD g_enumCAXchgValidityPeriod = dwCAXCHGVALIDITYPERIODENUMDEFAULT;
  193. LONG g_lCAXchgValidityPeriodCount = dwCAXCHGVALIDITYPERIODCOUNTDEFAULT;
  194. enum ENUM_PERIOD g_enumCAXchgOverlapPeriod = dwCAXCHGOVERLAPPERIODENUMDEFAULT;
  195. LONG g_lCAXchgOverlapPeriodCount = dwCAXCHGOVERLAPPERIODCOUNTDEFAULT;
  196. typedef enum {
  197. ST_COUNTRY = 0,
  198. ST_ORGANIZATION,
  199. ST_ORGANIZATIONALUNIT,
  200. ST_COMMONNAME,
  201. ST_LOCALITY,
  202. ST_STATEORPROVINCE,
  203. ST_TITLE,
  204. ST_GIVENNAME,
  205. ST_INITIALS,
  206. ST_SURNAME,
  207. ST_DOMAINCOMPONENT,
  208. ST_EMAIL,
  209. ST_STREETADDRESS,
  210. ST_UNSTRUCTUREDNAME,
  211. ST_UNSTRUCTUREDADDRESS,
  212. ST_DEVICESERIALNUMBER,
  213. ST_NULL
  214. };
  215. typedef struct _SUBJECTTABLE
  216. {
  217. WCHAR const *pwszPropName;
  218. CHAR const *pszObjId;
  219. WCHAR const * const *apwszAttributeName;
  220. DWORD cchMax;
  221. DWORD dwValueType;
  222. DWORD dwSubjectTableIndex;
  223. DWORD dwSubjectTemplateIndex;
  224. } SUBJECTTABLE;
  225. WCHAR const *apwszAttrCountry[] = {
  226. wszATTRCOUNTRY1,
  227. wszATTRCOUNTRY2,
  228. TEXT(szOID_COUNTRY_NAME),
  229. NULL
  230. };
  231. WCHAR const *apwszAttrOrg[] = {
  232. wszATTRORG1,
  233. wszATTRORG2,
  234. wszATTRORG3,
  235. TEXT(szOID_ORGANIZATION_NAME),
  236. NULL
  237. };
  238. WCHAR const *apwszAttrOrgUnit[] = {
  239. wszATTRORGUNIT1,
  240. wszATTRORGUNIT2,
  241. wszATTRORGUNIT3,
  242. wszATTRORGUNIT4,
  243. TEXT(szOID_ORGANIZATIONAL_UNIT_NAME),
  244. NULL
  245. };
  246. WCHAR const *apwszAttrCommonName[] = {
  247. wszATTRCOMMONNAME1,
  248. wszATTRCOMMONNAME2,
  249. TEXT(szOID_COMMON_NAME),
  250. NULL
  251. };
  252. WCHAR const *apwszAttrLocality[] = {
  253. wszATTRLOCALITY1,
  254. wszATTRLOCALITY2,
  255. TEXT(szOID_LOCALITY_NAME),
  256. NULL
  257. };
  258. WCHAR const *apwszAttrState[] = {
  259. wszATTRSTATE1,
  260. wszATTRSTATE2,
  261. wszATTRSTATE3,
  262. TEXT(szOID_STATE_OR_PROVINCE_NAME),
  263. NULL
  264. };
  265. WCHAR const *apwszAttrTitle[] = {
  266. wszATTRTITLE1,
  267. wszATTRTITLE2,
  268. TEXT(szOID_TITLE),
  269. NULL
  270. };
  271. WCHAR const *apwszAttrGivenName[] = {
  272. wszATTRGIVENNAME1,
  273. wszATTRGIVENNAME2,
  274. TEXT(szOID_GIVEN_NAME),
  275. NULL
  276. };
  277. WCHAR const *apwszAttrInitials[] = {
  278. wszATTRINITIALS1,
  279. wszATTRINITIALS2,
  280. TEXT(szOID_INITIALS),
  281. NULL
  282. };
  283. WCHAR const *apwszAttrSurName[] = {
  284. wszATTRSURNAME1,
  285. wszATTRSURNAME2,
  286. TEXT(szOID_SUR_NAME),
  287. NULL
  288. };
  289. WCHAR const *apwszAttrDomComp[] = {
  290. wszATTRDOMAINCOMPONENT1,
  291. wszATTRDOMAINCOMPONENT2,
  292. TEXT(szOID_DOMAIN_COMPONENT),
  293. NULL
  294. };
  295. WCHAR const *apwszAttrEMail[] = {
  296. wszATTREMAIL1,
  297. wszATTREMAIL2,
  298. TEXT(szOID_RSA_emailAddr),
  299. NULL
  300. };
  301. WCHAR const *apwszAttrStreetAddr[] = {
  302. wszATTRSTREETADDRESS1,
  303. wszATTRSTREETADDRESS2,
  304. TEXT(szOID_STREET_ADDRESS),
  305. NULL
  306. };
  307. WCHAR const *apwszAttrUnstructName[] = {
  308. wszATTRUNSTRUCTUREDNAME1,
  309. TEXT(szOID_RSA_unstructName),
  310. NULL
  311. };
  312. WCHAR const *apwszAttrUnstructAddr[] = {
  313. wszATTRUNSTRUCTUREDADDRESS1,
  314. TEXT(szOID_RSA_unstructAddr),
  315. NULL
  316. };
  317. WCHAR const *apwszAttrDeviceSerialNumber[] = {
  318. wszATTRDEVICESERIALNUMBER1,
  319. TEXT(szOID_DEVICE_SERIAL_NUMBER),
  320. NULL
  321. };
  322. SUBJECTTABLE pkcs_subject[] =
  323. {
  324. {
  325. // "Country",
  326. g_wszPropSubjectCountry,
  327. szOID_COUNTRY_NAME,
  328. apwszAttrCountry,
  329. cchCOUNTRYNAMEMAX,
  330. CERT_RDN_PRINTABLE_STRING,
  331. ST_COUNTRY,
  332. MAXDWORD,
  333. },
  334. {
  335. // "Organization",
  336. g_wszPropSubjectOrganization,
  337. szOID_ORGANIZATION_NAME,
  338. apwszAttrOrg,
  339. cchORGANIZATIONNAMEMAX,
  340. CERT_RDN_PRINTABLE_STRING,
  341. ST_ORGANIZATION,
  342. MAXDWORD,
  343. },
  344. {
  345. // "OrganizationalUnit",
  346. g_wszPropSubjectOrgUnit,
  347. szOID_ORGANIZATIONAL_UNIT_NAME,
  348. apwszAttrOrgUnit,
  349. cchORGANIZATIONALUNITNAMEMAX,
  350. CERT_RDN_PRINTABLE_STRING,
  351. ST_ORGANIZATIONALUNIT,
  352. MAXDWORD,
  353. },
  354. {
  355. // "CommonName",
  356. g_wszPropSubjectCommonName,
  357. szOID_COMMON_NAME,
  358. apwszAttrCommonName,
  359. cchCOMMONNAMEMAX,
  360. CERT_RDN_PRINTABLE_STRING,
  361. ST_COMMONNAME,
  362. MAXDWORD,
  363. },
  364. {
  365. // "Locality",
  366. g_wszPropSubjectLocality,
  367. szOID_LOCALITY_NAME,
  368. apwszAttrLocality,
  369. cchLOCALITYMANAMEMAX,
  370. CERT_RDN_PRINTABLE_STRING,
  371. ST_LOCALITY,
  372. MAXDWORD,
  373. },
  374. {
  375. // "StateOrProvince",
  376. g_wszPropSubjectState,
  377. szOID_STATE_OR_PROVINCE_NAME,
  378. apwszAttrState,
  379. cchSTATEORPROVINCENAMEMAX,
  380. CERT_RDN_PRINTABLE_STRING,
  381. ST_STATEORPROVINCE,
  382. MAXDWORD,
  383. },
  384. {
  385. // "Title",
  386. g_wszPropSubjectTitle,
  387. szOID_TITLE,
  388. apwszAttrTitle,
  389. cchTITLEMAX,
  390. CERT_RDN_PRINTABLE_STRING,
  391. ST_TITLE,
  392. MAXDWORD,
  393. },
  394. {
  395. // "GivenName",
  396. g_wszPropSubjectGivenName,
  397. szOID_GIVEN_NAME,
  398. apwszAttrGivenName,
  399. cchGIVENNAMEMAX,
  400. CERT_RDN_PRINTABLE_STRING,
  401. ST_GIVENNAME,
  402. MAXDWORD,
  403. },
  404. {
  405. // "Initials",
  406. g_wszPropSubjectInitials,
  407. szOID_INITIALS,
  408. apwszAttrInitials,
  409. cchINITIALSMAX,
  410. CERT_RDN_PRINTABLE_STRING,
  411. ST_INITIALS,
  412. MAXDWORD,
  413. },
  414. {
  415. // "SurName",
  416. g_wszPropSubjectSurName,
  417. szOID_SUR_NAME,
  418. apwszAttrSurName,
  419. cchSURNAMEMAX,
  420. CERT_RDN_PRINTABLE_STRING,
  421. ST_SURNAME,
  422. MAXDWORD,
  423. },
  424. {
  425. // "DomainComponent",
  426. g_wszPropSubjectDomainComponent,
  427. szOID_DOMAIN_COMPONENT,
  428. apwszAttrDomComp,
  429. cchDOMAINCOMPONENTMAX,
  430. CERT_RDN_PRINTABLE_STRING,
  431. ST_DOMAINCOMPONENT,
  432. MAXDWORD,
  433. },
  434. {
  435. // "EMail",
  436. g_wszPropSubjectEMail,
  437. szOID_RSA_emailAddr,
  438. apwszAttrEMail,
  439. cchEMAILMAX,
  440. CERT_RDN_PRINTABLE_STRING,
  441. ST_EMAIL,
  442. MAXDWORD,
  443. },
  444. {
  445. // "StreetAddress",
  446. g_wszPropSubjectStreetAddress,
  447. szOID_STREET_ADDRESS,
  448. apwszAttrStreetAddr,
  449. cchSTREETADDRESSMAX,
  450. CERT_RDN_PRINTABLE_STRING,
  451. ST_STREETADDRESS,
  452. MAXDWORD,
  453. },
  454. {
  455. // "UnstructuredName",
  456. g_wszPropSubjectUnstructuredName,
  457. szOID_RSA_unstructName,
  458. apwszAttrUnstructName,
  459. cchUNSTRUCTUREDNAMEMAX,
  460. CERT_RDN_PRINTABLE_STRING,
  461. ST_UNSTRUCTUREDNAME,
  462. MAXDWORD,
  463. },
  464. {
  465. // "UnstructuredAddress",
  466. g_wszPropSubjectUnstructuredAddress,
  467. szOID_RSA_unstructAddr,
  468. apwszAttrUnstructAddr,
  469. cchUNSTRUCTUREDADDRESSMAX,
  470. CERT_RDN_PRINTABLE_STRING,
  471. ST_UNSTRUCTUREDADDRESS,
  472. MAXDWORD,
  473. },
  474. {
  475. // "DeviceSerialNumber",
  476. g_wszPropSubjectDeviceSerialNumber,
  477. szOID_DEVICE_SERIAL_NUMBER,
  478. apwszAttrDeviceSerialNumber,
  479. cchDEVICESERIALNUMBERMAX,
  480. CERT_RDN_PRINTABLE_STRING,
  481. ST_DEVICESERIALNUMBER,
  482. MAXDWORD,
  483. },
  484. {
  485. NULL,
  486. NULL,
  487. NULL,
  488. 0,
  489. 0,
  490. ST_NULL,
  491. MAXDWORD,
  492. },
  493. };
  494. #define CSUBJECTTABLE (sizeof(pkcs_subject) / sizeof(pkcs_subject[0]))
  495. SUBJECTTABLE const *pkcs_apSubject[CSUBJECTTABLE];
  496. SUBJECTTABLE const **pkcs_ppSubjectLast;
  497. BOOL pkcsfSubjectTemplate = FALSE;
  498. WCHAR const g_wszCNXchgSuffix[] = wszCNXCHGSUFFIX;
  499. VOID
  500. pkcsSetDistinguishedName(
  501. IN ICertDBRow *prow,
  502. IN DWORD dwTable,
  503. IN CERT_NAME_BLOB const *pSubject)
  504. {
  505. DWORD cwc;
  506. WCHAR awcName[CCH_DBMAXTEXT_DN + 1];
  507. HRESULT hr;
  508. CSASSERT(PROPTABLE_REQUEST == dwTable || PROPTABLE_CERTIFICATE == dwTable);
  509. cwc = CertNameToStr(
  510. X509_ASN_ENCODING,
  511. const_cast<CERT_NAME_BLOB *>(pSubject),
  512. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  513. awcName,
  514. ARRAYSIZE(awcName));
  515. if (0 != cwc && L'\0' != awcName[0])
  516. {
  517. #if DBG_CERTSRV
  518. DWORD ReqId;
  519. prow->GetRowId(&ReqId);
  520. DBGPRINT((
  521. DBG_SS_CERTSRVI,
  522. "%ws DN(%u): '%ws'\n",
  523. PROPTABLE_REQUEST == dwTable? L"Request" : L"Certificate",
  524. ReqId,
  525. awcName));
  526. #endif
  527. if (wcslen(awcName) == ARRAYSIZE(awcName) - 1)
  528. {
  529. DBGPRINT((
  530. DBG_SS_CERTSRV,
  531. "pkcsSetDistinguishedName: possible DN truncation: %u chars: '%ws'\n",
  532. ARRAYSIZE(awcName) - 1,
  533. awcName));
  534. }
  535. hr = prow->SetProperty(
  536. g_wszPropSubjectDistinguishedName,
  537. PROPTYPE_STRING | PROPCALLER_SERVER | dwTable,
  538. MAXDWORD,
  539. (BYTE const *) awcName);
  540. _PrintIfError(hr, "SetProperty(DN)");
  541. }
  542. }
  543. WCHAR const *
  544. PKCSMapAttributeName(
  545. OPTIONAL IN WCHAR const *pwszAttributeName,
  546. OPTIONAL IN CHAR const *pszObjId,
  547. OUT DWORD *pdwIndex,
  548. OUT DWORD *pcchMax)
  549. {
  550. SUBJECTTABLE const *pSubjectTable;
  551. WCHAR const *pwszPropName = NULL;
  552. for (pSubjectTable = pkcs_subject; ; pSubjectTable++)
  553. {
  554. WCHAR const * const *ppwsz;
  555. if (NULL == pSubjectTable->pwszPropName)
  556. {
  557. goto error;
  558. }
  559. if (NULL != pwszAttributeName)
  560. {
  561. for (ppwsz = pSubjectTable->apwszAttributeName;
  562. NULL != *ppwsz;
  563. ppwsz++)
  564. {
  565. if (0 == mylstrcmpiS(pwszAttributeName, *ppwsz))
  566. {
  567. break;
  568. }
  569. }
  570. if (NULL != *ppwsz ||
  571. 0 == mylstrcmpiS(pwszAttributeName, pSubjectTable->pwszPropName))
  572. {
  573. break;
  574. }
  575. }
  576. if (NULL != pszObjId &&
  577. 0 == strcmp(pszObjId, pSubjectTable->pszObjId))
  578. {
  579. break;
  580. }
  581. }
  582. CSASSERT(NULL != pSubjectTable->pwszPropName);
  583. pwszPropName = pSubjectTable->pwszPropName;
  584. *pdwIndex = pSubjectTable->dwSubjectTableIndex;
  585. *pcchMax = pSubjectTable->cchMax;
  586. error:
  587. return(pwszPropName);
  588. }
  589. HRESULT
  590. pkcsFindCAContext(
  591. IN DWORD iCert, // MAXDWORD -> use current
  592. IN DWORD iKey, // MAXDWORD -> use current
  593. OUT CACTX **ppCAContext)
  594. {
  595. HRESULT hr = E_INVALIDARG;
  596. DWORD i;
  597. CACTX *pCAContext;
  598. *ppCAContext = NULL;
  599. // Lookup is either by cert index OR by key index, but not both or neither
  600. CSASSERT((MAXDWORD == iCert) ^ (MAXDWORD == iKey));
  601. if (MAXDWORD != iCert)
  602. {
  603. if ((~_16BITMASK & iCert) || iCert >= g_cCACerts)
  604. {
  605. _JumpError(hr, error, "bad cert index");
  606. }
  607. *ppCAContext = &g_aCAContext[iCert];
  608. CSASSERT(iCert == (*ppCAContext)->iCert);
  609. }
  610. else
  611. {
  612. CSASSERT(MAXDWORD != iKey);
  613. if ((~_16BITMASK & iKey) || iKey >= g_cCAKeys)
  614. {
  615. _JumpError(hr, error, "bad key index");
  616. }
  617. for (i = g_cCACerts; ; i--)
  618. {
  619. if (0 == i)
  620. {
  621. _JumpError(hr, error, "key index not found");
  622. }
  623. pCAContext = &g_aCAContext[i - 1];
  624. if (iKey == pCAContext->iKey)
  625. {
  626. *ppCAContext = pCAContext;
  627. break;
  628. }
  629. }
  630. }
  631. hr = S_OK; // found it!
  632. error:
  633. return(hr);
  634. }
  635. // Returns Cert Index in *piCert on success.
  636. //
  637. // returned in *piCert:
  638. // If iCert input value is not MAXDWORD, validate & return iCert.
  639. // If iCert input value is MAXDWORD, return the most current Cert Index.
  640. HRESULT
  641. PKCSMapCertIndex(
  642. IN DWORD iCert,
  643. OUT DWORD *piCert,
  644. OUT DWORD *pState)
  645. {
  646. HRESULT hr;
  647. CACTX *pCAContext;
  648. DBGCODE(DWORD iCertSave = iCert);
  649. *pState = CA_DISP_ERROR;
  650. if (MAXDWORD == iCert)
  651. {
  652. iCert = g_cCACerts - 1;
  653. }
  654. if (iCert >= g_cCACerts)
  655. {
  656. hr = E_INVALIDARG;
  657. _JumpError(hr, error, "bad CertIndex");
  658. }
  659. pCAContext = &g_aCAContext[iCert];
  660. hr = PKCSVerifyCAState(pCAContext);
  661. _PrintIfError(hr, "PKCSVerifyCAState");
  662. *pState = CA_DISP_VALID;
  663. if (CTXF_CERTMISSING & pCAContext->Flags)
  664. {
  665. *pState = CA_DISP_ERROR;
  666. }
  667. else
  668. if (CTXF_REVOKED & pCAContext->Flags)
  669. {
  670. *pState = CA_DISP_REVOKED;
  671. }
  672. else
  673. if (CTXF_EXPIRED & pCAContext->Flags)
  674. {
  675. *pState = CA_DISP_INVALID;
  676. }
  677. *piCert = iCert;
  678. hr = S_OK;
  679. error:
  680. DBGPRINT((
  681. DBG_SS_CERTSRVI,
  682. "PKCSMapCertIndex(%u) --> %u, s=%u, hr=%x\n",
  683. iCertSave,
  684. *piCert,
  685. *pState,
  686. hr));
  687. return(hr);
  688. }
  689. VOID
  690. pkcsVerifyCACrossState(
  691. IN OUT CACROSSCTX *pCACross)
  692. {
  693. HRESULT hr;
  694. if (0 == pCACross->Flags && NULL != pCACross->pccCACross)
  695. {
  696. hr = myVerifyCertContext(
  697. pCACross->pccCACross, // pCert
  698. 0, // dwFlags
  699. 0, // cUsageOids
  700. NULL, // apszUsageOids
  701. HCCE_LOCAL_MACHINE, // hChainEngine
  702. NULL, // hAdditionalStore
  703. NULL); // ppwszMissingIssuer
  704. pCACross->hrVerifyStatus = hr;
  705. if (S_OK != hr)
  706. {
  707. _PrintError2(hr, "myVerifyCertContext", CRYPT_E_REVOCATION_OFFLINE);
  708. if (CERT_E_UNTRUSTEDROOT == hr || TRUST_E_CERT_SIGNATURE == hr)
  709. {
  710. hr = S_OK;
  711. }
  712. else
  713. if (CERT_E_EXPIRED == hr)
  714. {
  715. pCACross->Flags |= CTXF_EXPIRED;
  716. }
  717. else if (CRYPT_E_REVOKED == hr || CERT_E_REVOKED == hr)
  718. {
  719. pCACross->Flags |= CTXF_REVOKED;
  720. }
  721. else if (CRYPT_E_REVOCATION_OFFLINE == hr)
  722. {
  723. HRESULT hr2;
  724. DWORD dwState;
  725. hr2 = GetSetupStatus(NULL, &dwState);
  726. if ((S_OK == hr2 && (SETUP_CREATEDB_FLAG & dwState)) ||
  727. CERTLOG_WARNING > g_dwLogLevel)
  728. {
  729. hr = S_OK;
  730. }
  731. }
  732. else if (CRYPT_E_NO_REVOCATION_CHECK == hr)
  733. {
  734. if (CERTLOG_VERBOSE > g_dwLogLevel)
  735. {
  736. hr = S_OK;
  737. }
  738. }
  739. _JumpIfError(hr, error, "myVerifyCertContext");
  740. }
  741. }
  742. error:
  743. ;
  744. }
  745. // Returns Cert Index in *piCert on success.
  746. //
  747. // returned in *piCert:
  748. // If iCert input value is not MAXDWORD, validate & return iCert.
  749. // If iCert input value is MAXDWORD, return the most current Cert Index.
  750. HRESULT
  751. pkcsMapCrossCertIndex(
  752. IN BOOL fForward,
  753. IN DWORD iCert,
  754. OUT DWORD *piCert,
  755. OUT DWORD *pState)
  756. {
  757. HRESULT hr;
  758. CACROSSCTX *pCACross;
  759. DBGCODE(DWORD iCertSave = iCert);
  760. *pState = CA_DISP_ERROR;
  761. if (MAXDWORD == iCert)
  762. {
  763. iCert = g_cCACerts - 1;
  764. }
  765. if (iCert >= g_cCACerts)
  766. {
  767. hr = E_INVALIDARG;
  768. _JumpError(hr, error, "bad CertIndex");
  769. }
  770. pCACross = fForward? g_aCACrossForward : g_aCACrossBackward;
  771. if (NULL != pCACross)
  772. {
  773. pCACross += iCert;
  774. if (NULL != pCACross->pccCACross)
  775. {
  776. pkcsVerifyCACrossState(pCACross);
  777. *pState = CA_DISP_VALID;
  778. if (CTXF_CERTMISSING & pCACross->Flags)
  779. {
  780. *pState = CA_DISP_ERROR;
  781. }
  782. else
  783. if (CTXF_REVOKED & pCACross->Flags)
  784. {
  785. *pState = CA_DISP_REVOKED;
  786. }
  787. else
  788. if (CTXF_EXPIRED & pCACross->Flags)
  789. {
  790. *pState = CA_DISP_INVALID;
  791. }
  792. }
  793. }
  794. *piCert = iCert;
  795. hr = S_OK;
  796. error:
  797. DBGPRINT((
  798. DBG_SS_CERTSRVI,
  799. "PKCSMapCrossCertIndex(%u) --> %u, s=%u, hr=%x\n",
  800. iCertSave,
  801. *piCert,
  802. *pState,
  803. hr));
  804. return(hr);
  805. }
  806. // Returns Cert Index in *piCert and CRL Index in *piCRL on success.
  807. //
  808. // returned in *piCert:
  809. // If iCert input value is not MAXDWORD, validate iCert. Look up the newest
  810. // Cert Index that uses the same key as the passed iCert.
  811. // If iCert input value is MAXDWORD, return the most current Cert Index.
  812. //
  813. // returned in *piCRL:
  814. // CRL index (same as Key Index)
  815. //
  816. HRESULT
  817. PKCSMapCRLIndex(
  818. IN DWORD iCert,
  819. OUT DWORD *piCert, // returns newest iCert w/matching iKey for passed iCert
  820. OUT DWORD *piCRL,
  821. OUT DWORD *pState)
  822. {
  823. HRESULT hr;
  824. CACTX *pCAContext;
  825. CACTX *pCAContextNewest;
  826. DWORD i;
  827. DBGCODE(DWORD iCertSave = iCert);
  828. hr = PKCSMapCertIndex(iCert, piCert, pState);
  829. _JumpIfError(hr, error, "PKCSMapCertIndex");
  830. // Now we know *piCert is a valid Cert Index:
  831. pCAContext = &g_aCAContext[*piCert];
  832. *piCRL = pCAContext->iKey;
  833. // find the newest iCert with matching iKey
  834. for (i = *piCert + 1; i < g_cCACerts; i++)
  835. {
  836. if (*piCRL != g_aCAContext[i].iKey)
  837. {
  838. break;
  839. }
  840. *piCert = i;
  841. }
  842. pCAContextNewest = &g_aCAContext[*piCert];
  843. if (CTXF_CRLZOMBIE & pCAContext->Flags)
  844. {
  845. *pState = CA_DISP_VALID;
  846. }
  847. else
  848. if (pCAContext->iCert != pCAContext->iKey)
  849. {
  850. *pState = CA_DISP_ERROR;
  851. }
  852. else
  853. if ((CTXF_EXPIRED & pCAContext->Flags) &&
  854. 0 == (CTXF_SKIPCRL & pCAContextNewest->Flags))
  855. {
  856. *pState = CA_DISP_VALID;
  857. }
  858. hr = S_OK;
  859. error:
  860. DBGPRINT((
  861. DBG_SS_CERTSRVI,
  862. "PKCSMapCRLIndex(%u) --> %u, iCRL=%u, s=%u, hr=%x\n",
  863. iCertSave,
  864. *piCert,
  865. *piCRL,
  866. *pState,
  867. hr));
  868. return(hr);
  869. }
  870. HRESULT
  871. PKCSGetCACertStatusCode(
  872. IN DWORD iCert,
  873. OUT HRESULT *phrCAStatusCode)
  874. {
  875. HRESULT hr;
  876. DWORD State;
  877. *phrCAStatusCode = E_FAIL;
  878. hr = PKCSMapCertIndex(iCert, &iCert, &State);
  879. _JumpIfError(hr, error, "PKCSMapCertIndex");
  880. *phrCAStatusCode = g_aCAContext[iCert].hrVerifyStatus;
  881. hr = S_OK;
  882. error:
  883. return(hr);
  884. }
  885. HRESULT
  886. PKCSGetCAState(
  887. IN LONG PropId, // CR_PROP_*
  888. OUT BYTE *pb)
  889. {
  890. HRESULT hr = S_OK;
  891. DWORD i;
  892. for (i = 0; i < g_cCACerts; i++)
  893. {
  894. DWORD State;
  895. switch (PropId)
  896. {
  897. DWORD iCert;
  898. DWORD iCRL;
  899. case CR_PROP_CAFORWARDCROSSCERTSTATE:
  900. case CR_PROP_CABACKWARDCROSSCERTSTATE:
  901. hr = pkcsMapCrossCertIndex(
  902. CR_PROP_CAFORWARDCROSSCERTSTATE == PropId,
  903. i,
  904. &iCert,
  905. &State);
  906. _JumpIfError(hr, error, "pkcsMapCrossCertIndex");
  907. break;
  908. case CR_PROP_CACERTSTATE:
  909. case CR_PROP_CACERTVERSION:
  910. hr = PKCSMapCertIndex(i, &iCert, &State);
  911. _JumpIfError(hr, error, "PKCSMapCertIndex");
  912. break;
  913. case CR_PROP_CRLSTATE:
  914. hr = PKCSMapCRLIndex(i, &iCert, &iCRL, &State);
  915. _JumpIfError(hr, error, "PKCSMapCRLIndex");
  916. break;
  917. default:
  918. hr = E_INVALIDARG;
  919. _JumpError(hr, error, "PropId");
  920. break;
  921. }
  922. CSASSERT(0 == (~0xff & State));
  923. *pb++ = (BYTE) State;
  924. }
  925. error:
  926. return(hr);
  927. }
  928. HRESULT
  929. PKCSGetCAVersion(
  930. OUT DWORD *pdw)
  931. {
  932. HRESULT hr;
  933. DWORD i;
  934. for (i = 0; i < g_cCACerts; i++)
  935. {
  936. DWORD State;
  937. DWORD iCert;
  938. hr = PKCSMapCertIndex(i, &iCert, &State);
  939. _JumpIfError(hr, error, "PKCSMapCertIndex");
  940. // Now we know iCert is a valid Cert Index:
  941. *pdw++ = g_aCAContext[iCert].NameId;
  942. }
  943. hr = S_OK;
  944. error:
  945. return(hr);
  946. }
  947. inline DWORD
  948. MapHRESULTToKRADisposition(
  949. IN HRESULT hr)
  950. {
  951. switch(hr)
  952. {
  953. case CERT_E_EXPIRED: return KRA_DISP_EXPIRED;
  954. case CRYPT_E_NOT_FOUND: return KRA_DISP_NOTFOUND;
  955. case CERT_E_REVOKED:
  956. case CRYPT_E_REVOKED: return KRA_DISP_REVOKED;
  957. case S_OK: return KRA_DISP_VALID;
  958. case CERT_E_UNTRUSTEDROOT:
  959. case CERT_E_CHAINING: return KRA_DISP_UNTRUSTED;
  960. case ERROR_NOT_FOUND: return KRA_DISP_NOTLOADED;
  961. default: return KRA_DISP_INVALID;
  962. }
  963. }
  964. HRESULT
  965. PKCSGetKRAState(
  966. IN DWORD cKRA,
  967. OUT BYTE *pb)
  968. {
  969. HRESULT hr = S_OK;
  970. DWORD dwCount;
  971. HCERTSTORE hKRAStore = NULL;
  972. CERT_CONTEXT const *pCertContext = NULL;
  973. hKRAStore = CertOpenStore(
  974. CERT_STORE_PROV_SYSTEM_W,
  975. X509_ASN_ENCODING,
  976. NULL, // hProv
  977. CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG,
  978. wszKRA_CERTSTORE);
  979. if (NULL == hKRAStore)
  980. {
  981. hr = myHLastError();
  982. _JumpError(hr, error, "CertOpenStore KRA");
  983. }
  984. for (dwCount = 0; dwCount < cKRA; dwCount++)
  985. {
  986. hr = myFindCACertByHashIndex(
  987. hKRAStore,
  988. g_wszSanitizedName,
  989. CSRH_CAKRACERT,
  990. dwCount,
  991. NULL,
  992. &pCertContext);
  993. if (S_OK == hr)
  994. {
  995. hr = myVerifyKRACertContext(pCertContext, g_dwVerifyCertFlags);
  996. // check if the CA is using this cert (was able to load it last
  997. // time it started)
  998. if (S_OK == hr)
  999. {
  1000. hr = ERROR_NOT_FOUND;
  1001. if (NULL != g_aKRAContext)
  1002. {
  1003. DWORD iKRALoaded;
  1004. for (iKRALoaded = 0; iKRALoaded < g_cKRACerts; iKRALoaded++)
  1005. {
  1006. if (myAreCertContextBlobsSame(
  1007. pCertContext,
  1008. g_aKRAContext[iKRALoaded].pccKRA))
  1009. {
  1010. // the CA loaded this KRA cert
  1011. hr = g_aKRAContext[iKRALoaded].hrVerifyStatus;
  1012. break;
  1013. }
  1014. }
  1015. }
  1016. }
  1017. }
  1018. CSASSERT(0 == (~0xff & MapHRESULTToKRADisposition(hr)));
  1019. pb[dwCount] = (BYTE)MapHRESULTToKRADisposition(hr);
  1020. hr = S_OK;
  1021. CertFreeCertificateContext(pCertContext);
  1022. pCertContext = NULL;
  1023. }
  1024. error:
  1025. if (NULL != pCertContext)
  1026. {
  1027. CertFreeCertificateContext(pCertContext);
  1028. }
  1029. if (NULL != hKRAStore)
  1030. {
  1031. CertCloseStore(hKRAStore, CERT_CLOSE_STORE_CHECK_FLAG);
  1032. }
  1033. return hr;
  1034. }
  1035. HRESULT
  1036. pkcsSetRequestNameInfo(
  1037. IN ICertDBRow *prow,
  1038. IN CERT_NAME_BLOB const *pSubject,
  1039. OPTIONAL IN WCHAR const *pwszCNSuffix,
  1040. IN BOOL fReorderLikeRDNs,
  1041. IN OUT DWORD *pdwRequestFlags,
  1042. OUT BOOL *pfSubjectNameSet)
  1043. {
  1044. HRESULT hr;
  1045. CERT_RDN *prdn;
  1046. CERT_RDN *prdnEnd;
  1047. CERT_NAME_INFO *pNameInfo = NULL;
  1048. WCHAR const *pwszPropName;
  1049. DWORD cbNameInfo;
  1050. DWORD dwIndex;
  1051. DWORD cchMax;
  1052. BYTE afSubjectTable[CSUBJECTTABLE]; // see PKCSParseAttributes note
  1053. *pfSubjectNameSet = FALSE;
  1054. ZeroMemory(afSubjectTable, sizeof(afSubjectTable));
  1055. CSASSERT(CSExpr(0 == FALSE));
  1056. hr = prow->SetProperty(
  1057. g_wszPropSubjectRawName,
  1058. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  1059. pSubject->cbData,
  1060. pSubject->pbData);
  1061. _JumpIfError(hr, error, "SetProperty");
  1062. pkcsSetDistinguishedName(prow, PROPTABLE_REQUEST, pSubject);
  1063. if (!myDecodeName(
  1064. X509_ASN_ENCODING,
  1065. X509_UNICODE_NAME,
  1066. pSubject->pbData,
  1067. pSubject->cbData,
  1068. CERTLIB_USE_LOCALALLOC,
  1069. &pNameInfo,
  1070. &cbNameInfo))
  1071. {
  1072. hr = myHLastError();
  1073. _JumpError(hr, error, "myDecodeName");
  1074. }
  1075. if (ENUM_TELETEX_ON == (ENUM_TELETEX_MASK & g_fForceTeletex))
  1076. {
  1077. *pdwRequestFlags |= CR_FLG_FORCETELETEX;
  1078. }
  1079. if (ENUM_TELETEX_UTF8 & g_fForceTeletex)
  1080. {
  1081. *pdwRequestFlags |= CR_FLG_FORCEUTF8;
  1082. }
  1083. if (fReorderLikeRDNs)
  1084. {
  1085. DWORD dwSubjectTemplateIndex = 0;
  1086. for (
  1087. prdn = pNameInfo->rgRDN, prdnEnd = &prdn[pNameInfo->cRDN];
  1088. fReorderLikeRDNs && prdn < prdnEnd;
  1089. prdn++)
  1090. {
  1091. if (1 != prdn->cRDNAttr)
  1092. {
  1093. fReorderLikeRDNs = FALSE;
  1094. break;
  1095. }
  1096. pwszPropName = PKCSMapAttributeName(
  1097. NULL,
  1098. prdn->rgRDNAttr[0].pszObjId,
  1099. &dwIndex,
  1100. &cchMax);
  1101. if (NULL != pwszPropName)
  1102. {
  1103. DBGPRINT((
  1104. DBG_SS_CERTSRVI,
  1105. "dwSubjectTemplateIndex: %x -> %x\n",
  1106. dwSubjectTemplateIndex,
  1107. pkcs_subject[dwIndex].dwSubjectTemplateIndex));
  1108. if (MAXDWORD == pkcs_subject[dwIndex].dwSubjectTemplateIndex ||
  1109. dwSubjectTemplateIndex >
  1110. pkcs_subject[dwIndex].dwSubjectTemplateIndex)
  1111. {
  1112. fReorderLikeRDNs = FALSE;
  1113. break;
  1114. }
  1115. dwSubjectTemplateIndex =
  1116. pkcs_subject[dwIndex].dwSubjectTemplateIndex;
  1117. }
  1118. }
  1119. }
  1120. for (
  1121. prdn = pNameInfo->rgRDN, prdnEnd = &prdn[pNameInfo->cRDN];
  1122. prdn < prdnEnd;
  1123. prdn++)
  1124. {
  1125. CERT_RDN_ATTR *prdna;
  1126. CERT_RDN_ATTR *prdnaEnd;
  1127. for (
  1128. prdna = prdn->rgRDNAttr, prdnaEnd = &prdna[prdn->cRDNAttr];
  1129. prdna < prdnaEnd;
  1130. prdna++)
  1131. {
  1132. switch (prdna->dwValueType)
  1133. {
  1134. case CERT_RDN_PRINTABLE_STRING:
  1135. case CERT_RDN_UNICODE_STRING:
  1136. case CERT_RDN_TELETEX_STRING:
  1137. case CERT_RDN_IA5_STRING:
  1138. case CERT_RDN_UTF8_STRING:
  1139. break;
  1140. default:
  1141. continue;
  1142. }
  1143. if (NULL == prdna->Value.pbData ||
  1144. sizeof(WCHAR) > prdna->Value.cbData ||
  1145. ((sizeof(WCHAR) - 1) & prdna->Value.cbData) ||
  1146. L'\0' == *(WCHAR *) prdna->Value.pbData ||
  1147. L'\0' != *(WCHAR *) &prdna->Value.pbData[prdna->Value.cbData])
  1148. {
  1149. continue;
  1150. }
  1151. if (CERT_RDN_TELETEX_STRING == prdna->dwValueType &&
  1152. ENUM_TELETEX_AUTO == (ENUM_TELETEX_MASK & g_fForceTeletex))
  1153. {
  1154. *pdwRequestFlags |= CR_FLG_FORCETELETEX;
  1155. }
  1156. pwszPropName = PKCSMapAttributeName(
  1157. NULL,
  1158. prdna->pszObjId,
  1159. &dwIndex,
  1160. &cchMax);
  1161. if (NULL != pwszPropName)
  1162. {
  1163. BOOL fCN;
  1164. // CAPI null-terminates strings
  1165. CSASSERT(
  1166. sizeof(WCHAR) * wcslen((WCHAR const *) prdna->Value.pbData) ==
  1167. prdna->Value.cbData);
  1168. fCN = 0 == strcmp(szOID_COMMON_NAME, prdna->pszObjId);
  1169. hr = PropSetAttributeProperty(
  1170. prow,
  1171. afSubjectTable[dwIndex], // fConcatenateRDNs
  1172. fReorderLikeRDNs,
  1173. PROPTABLE_REQUEST,
  1174. cchMax,
  1175. fCN? pwszCNSuffix : NULL,
  1176. pwszPropName,
  1177. (WCHAR const *) prdna->Value.pbData);
  1178. if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) == hr)
  1179. {
  1180. hr = CERTSRV_E_BAD_REQUESTSUBJECT;
  1181. }
  1182. _JumpIfError(hr, error, "PropSetAttributeProperty");
  1183. afSubjectTable[dwIndex] = TRUE;
  1184. *pfSubjectNameSet = TRUE;
  1185. if (fCN)
  1186. {
  1187. pwszCNSuffix = NULL;
  1188. }
  1189. }
  1190. }
  1191. }
  1192. hr = S_OK;
  1193. error:
  1194. if (NULL != pNameInfo)
  1195. {
  1196. LocalFree(pNameInfo);
  1197. }
  1198. return(hr);
  1199. }
  1200. HRESULT
  1201. PKCSSetRequestFlags(
  1202. IN ICertDBRow *prow,
  1203. IN BOOL fSet,
  1204. IN DWORD dwChange)
  1205. {
  1206. HRESULT hr;
  1207. DWORD dwOld;
  1208. DWORD dwNew;
  1209. DWORD cb;
  1210. cb = sizeof(dwOld);
  1211. hr = prow->GetProperty(
  1212. g_wszPropRequestFlags,
  1213. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  1214. NULL,
  1215. &cb,
  1216. (BYTE *) &dwOld);
  1217. _JumpIfError(hr, error, "GetProperty");
  1218. if (fSet)
  1219. {
  1220. dwNew = dwOld | dwChange;
  1221. }
  1222. else
  1223. {
  1224. dwNew = dwOld & ~dwChange;
  1225. }
  1226. if (dwOld != dwNew)
  1227. {
  1228. hr = prow->SetProperty(
  1229. g_wszPropRequestFlags,
  1230. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  1231. sizeof(dwNew),
  1232. (BYTE const *) &dwNew);
  1233. _JumpIfError(hr, error, "SetProperty(RequestFlags)");
  1234. }
  1235. error:
  1236. return(hr);
  1237. }
  1238. HRESULT
  1239. pkcsSetAttributeProperty(
  1240. IN ICertDBRow *prow,
  1241. IN WCHAR const *pwszName,
  1242. IN WCHAR const *pwszValue,
  1243. IN DWORD dwTable,
  1244. IN BYTE afSubjectTable[],
  1245. OUT BOOL *pfSubjectModified,
  1246. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf)
  1247. {
  1248. HRESULT hr;
  1249. WCHAR const *pwszPropName;
  1250. DWORD dwIndex;
  1251. DWORD cwcMax;
  1252. BOOL fConcatenateRDNs;
  1253. *pfSubjectModified = FALSE;
  1254. if (NULL != pfEnrollOnBehalfOf)
  1255. {
  1256. *pfEnrollOnBehalfOf = FALSE;
  1257. }
  1258. pwszPropName = NULL;
  1259. cwcMax = MAXDWORD;
  1260. dwIndex = 0;
  1261. if (CRLF_ALLOW_REQUEST_ATTRIBUTE_SUBJECT & g_dwCRLFlags)
  1262. {
  1263. // See if the attribute name can be mapped to a standard property.
  1264. pwszPropName = PKCSMapAttributeName(pwszName, NULL, &dwIndex, &cwcMax);
  1265. }
  1266. if (NULL != pwszPropName)
  1267. {
  1268. fConcatenateRDNs = afSubjectTable[dwIndex];
  1269. afSubjectTable[dwIndex] = TRUE;
  1270. *pfSubjectModified = TRUE;
  1271. }
  1272. else
  1273. {
  1274. pwszPropName = pwszName;
  1275. fConcatenateRDNs = FALSE;
  1276. dwTable = PROPTABLE_ATTRIBUTE;
  1277. if (0 == mylstrcmpiS(pwszPropName, g_wszPropRequesterName))
  1278. {
  1279. if (NULL == pfEnrollOnBehalfOf)
  1280. {
  1281. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1282. _JumpError(hr, error, "NULL pfEnrollOnBehalfOf");
  1283. }
  1284. *pfEnrollOnBehalfOf = TRUE;
  1285. dwTable = PROPTABLE_REQUEST;
  1286. }
  1287. }
  1288. hr = PropSetAttributeProperty(
  1289. prow,
  1290. fConcatenateRDNs,
  1291. FALSE, // fPrependNewValue
  1292. dwTable,
  1293. cwcMax,
  1294. NULL, // pwszSuffix
  1295. pwszPropName,
  1296. pwszValue);
  1297. _JumpIfError(hr, error, "PropSetAttributeProperty");
  1298. error:
  1299. return(hr);
  1300. }
  1301. // Note on Request Attribute and Subject RDN processing:
  1302. //
  1303. // Subject RDN strings and Request Attributes may be set several ways, in
  1304. // the following order. Subsequent changes overwrite earlier changes, so the
  1305. // order implies precedence:
  1306. //
  1307. // - Subject in the inner PKCS10 (if no PKCS10 subject, then use the Subject
  1308. // in the PKCS7 renewal cert)
  1309. // - the next outer PKCS7 or CMC Attributes
  1310. // - ...
  1311. // - the most outer PKCS7 or CMC Attributes
  1312. // - Request Attribute string passed with the request when first submitted
  1313. // - Policy Module may set subject RDNs in the certificate table
  1314. // - ICertAdmin::SetAttributes' Request Attribute string (if request pending)
  1315. //
  1316. // "PKCS7 or CMC Attributes" means either of the following:
  1317. // 1) Authenticated Attributes associated with a (non-CMC) PKCS7 signer info.
  1318. // 2) Tagged Attributes and/or RegInfo Control Attributes in a CMC request.
  1319. //
  1320. // None of the secured attributes listed in the registry (which is set to
  1321. // wszzDEFAULTSIGNEDATTRIBUTES by default) may be set unless the source is
  1322. // PKCS7 or CMC Attributes.
  1323. //
  1324. // The original request attribute string is stored in the RequestAttributes
  1325. // column in the request table. It is never modified after that. Individual
  1326. // request attribute values are parsed out of this string (when the request is
  1327. // submitted and when ICertAdmin::SetAttributes is called) and stored in a
  1328. // Subject RDN column of the request or certificate table if the attribute
  1329. // name matches an alias for a Subject RDN, or in a unique row in the
  1330. // attribute table otherwise.
  1331. //
  1332. // Individual Subject RDNs may be specified multiple times (multiple "OU",
  1333. // "CN", strings). If all of the RDNs were set from the same source,
  1334. // they must be concatenated, but if some RDNs were specified from one source,
  1335. // then modified by another source, the previous set of RDNs should be
  1336. // overwritten by the new ones. If the original Request Attribute string
  1337. // specified "CN:foo\nOU:ou2\nCN:bar", the two CN strings should be
  1338. // concatenated. If one or more CN values are also specified later by a
  1339. // single call to ICertAdmin::SetAttributes, the original CN values should be
  1340. // overwritten by the new value(s).
  1341. //
  1342. // It is possible to have the CN strings specified by one source and the OU
  1343. // strings specified by another.
  1344. //
  1345. // Before the policy module gets control, all Subject RDN changes are written
  1346. // to the Request table. Just before dispatching to the policy module, the
  1347. // Request Subject RDNs are copied to the Certificate Table RDNs. The policy
  1348. // module may modify the Certificate Table RDNs only.
  1349. //
  1350. // If the request is made pending, ICertAdmin::SetAttributes may be used to
  1351. // modify request attributes and Certificate Table RDNs.
  1352. //
  1353. // The certificate Subject is constructed from the Certificate Table RDNs.
  1354. HRESULT
  1355. PKCSParseAttributes(
  1356. IN ICertDBRow *prow,
  1357. IN WCHAR const *pwszAttributes,
  1358. IN BOOL fRegInfo,
  1359. IN BOOL fPending,
  1360. IN DWORD dwRDNTable,
  1361. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf)
  1362. {
  1363. HRESULT hr;
  1364. WCHAR *pwszDup = NULL;
  1365. WCHAR *pwszBuf;
  1366. WCHAR const *pwszName;
  1367. WCHAR const *pwszValue;
  1368. DWORD iSecuredAttribute;
  1369. BYTE afSubjectTable[CSUBJECTTABLE]; // see PKCSParseAttributes note
  1370. WCHAR *pwszNameAlloc = NULL;
  1371. WCHAR *pwszValueAlloc = NULL;
  1372. BOOL fSubjectModified = FALSE;
  1373. static WCHAR const s_wszzPendingAttributes[] =
  1374. wszPROPCERTTEMPLATE
  1375. L"\0";
  1376. if (NULL != pfEnrollOnBehalfOf)
  1377. {
  1378. *pfEnrollOnBehalfOf = FALSE;
  1379. }
  1380. if (NULL == pwszAttributes)
  1381. {
  1382. hr = S_OK;
  1383. goto error; // silently ignore empty string
  1384. }
  1385. hr = myDupString(pwszAttributes, &pwszDup);
  1386. _JumpIfError(hr, error, "myDupString");
  1387. pwszBuf = pwszDup;
  1388. ZeroMemory(afSubjectTable, sizeof(afSubjectTable));
  1389. CSASSERT(CSExpr(0 == FALSE));
  1390. for (;;)
  1391. {
  1392. hr = myParseNextAttribute(&pwszBuf, fRegInfo, &pwszName, &pwszValue);
  1393. if (S_FALSE == hr)
  1394. {
  1395. break;
  1396. }
  1397. _JumpIfError(hr, error, "myParseNextAttribute");
  1398. if (fRegInfo)
  1399. {
  1400. if (NULL != pwszNameAlloc)
  1401. {
  1402. LocalFree(pwszNameAlloc);
  1403. pwszNameAlloc = NULL;
  1404. }
  1405. if (NULL != pwszValueAlloc)
  1406. {
  1407. LocalFree(pwszValueAlloc);
  1408. pwszValueAlloc = NULL;
  1409. }
  1410. hr = myUncanonicalizeURLParm(pwszName, &pwszNameAlloc);
  1411. _JumpIfError(hr, error, "myUncanonicalizeURLParm");
  1412. hr = myUncanonicalizeURLParm(pwszValue, &pwszValueAlloc);
  1413. _JumpIfError(hr, error, "myUncanonicalizeURLParm");
  1414. pwszName = pwszNameAlloc;
  1415. pwszValue = pwszValueAlloc;
  1416. }
  1417. iSecuredAttribute = MAXDWORD;
  1418. if (!fRegInfo)
  1419. {
  1420. // Only set the attribute if it's not one of the attributes
  1421. // that is required to be secure.
  1422. iSecuredAttribute = CRLIsStringInList(
  1423. pwszName,
  1424. g_wszzSecuredAttributes);
  1425. }
  1426. if (fPending && MAXDWORD == iSecuredAttribute)
  1427. {
  1428. // Only set the attribute if it's not one of the attributes
  1429. // that is disallowed for pending requests.
  1430. iSecuredAttribute = CRLIsStringInList(
  1431. pwszName,
  1432. s_wszzPendingAttributes);
  1433. }
  1434. if (MAXDWORD == iSecuredAttribute)
  1435. {
  1436. BOOL fEnrollOnBehalfOf = FALSE;
  1437. BOOL fSubjectModifiedT = FALSE;
  1438. hr = pkcsSetAttributeProperty(
  1439. prow,
  1440. pwszName,
  1441. pwszValue,
  1442. dwRDNTable,
  1443. afSubjectTable,
  1444. &fSubjectModified,
  1445. NULL != pfEnrollOnBehalfOf? &fEnrollOnBehalfOf : NULL);
  1446. _JumpIfError(hr, error, "PKCSSetRequestFlags");
  1447. if (fSubjectModifiedT)
  1448. {
  1449. fSubjectModified = TRUE;
  1450. }
  1451. if (fEnrollOnBehalfOf)
  1452. {
  1453. *pfEnrollOnBehalfOf = TRUE;
  1454. }
  1455. }
  1456. }
  1457. if (fSubjectModified)
  1458. {
  1459. hr = PKCSSetRequestFlags(prow, FALSE, CR_FLG_SUBJECTUNMODIFIED);
  1460. _JumpIfError(hr, error, "PKCSSetRequestFlags");
  1461. }
  1462. hr = S_OK;
  1463. error:
  1464. if (NULL != pwszNameAlloc)
  1465. {
  1466. LocalFree(pwszNameAlloc);
  1467. }
  1468. if (NULL != pwszValueAlloc)
  1469. {
  1470. LocalFree(pwszValueAlloc);
  1471. }
  1472. if (NULL != pwszDup)
  1473. {
  1474. LocalFree(pwszDup);
  1475. }
  1476. return(hr);
  1477. }
  1478. HRESULT
  1479. pkcsSetAltSubjectNameExtension(
  1480. IN ICertDBRow *prow,
  1481. IN DWORD ExtFlags,
  1482. IN CERT_EXTENSION const *rgExtension,
  1483. IN DWORD cExtension,
  1484. IN DWORD cAltSubjectExtension)
  1485. {
  1486. HRESULT hr = S_OK;
  1487. CERT_ALT_NAME_INFO **apInfo = NULL;
  1488. DWORD i;
  1489. DWORD j;
  1490. DWORD cInfo = 0;
  1491. DWORD cb;
  1492. CERT_ALT_NAME_INFO ResultInfo;
  1493. DWORD cbResult;
  1494. BYTE *pbResult = NULL;
  1495. ResultInfo.cAltEntry = 0;
  1496. ResultInfo.rgAltEntry = NULL;
  1497. apInfo = (CERT_ALT_NAME_INFO **) LocalAlloc(
  1498. LMEM_FIXED,
  1499. sizeof(CERT_ALT_NAME_INFO *) * cAltSubjectExtension);
  1500. if (NULL == apInfo)
  1501. {
  1502. hr = E_OUTOFMEMORY;
  1503. _JumpError(hr, error, "LocalAlloc");
  1504. }
  1505. // Decode all AltNames
  1506. for (i = 0; i < cExtension; i++)
  1507. {
  1508. // This is an OID, generated by capi2, so we don't need to
  1509. // do a case-insensitive comparison
  1510. if (0 == strcmp(rgExtension[i].pszObjId, szOID_SUBJECT_ALT_NAME2))
  1511. {
  1512. CSASSERT(cInfo < cAltSubjectExtension);
  1513. // Decode to plain text
  1514. if (!myDecodeObject(
  1515. X509_ASN_ENCODING,
  1516. X509_ALTERNATE_NAME,
  1517. rgExtension[i].Value.pbData,
  1518. rgExtension[i].Value.cbData,
  1519. CERTLIB_USE_LOCALALLOC,
  1520. (VOID **) &apInfo[cInfo],
  1521. &cb))
  1522. {
  1523. hr = myHLastError();
  1524. _JumpError(hr, error, "myDecodeObject");
  1525. }
  1526. if (rgExtension[i].fCritical)
  1527. {
  1528. ExtFlags |= EXTENSION_CRITICAL_FLAG;
  1529. }
  1530. ResultInfo.cAltEntry += apInfo[cInfo]->cAltEntry;
  1531. cInfo++;
  1532. }
  1533. }
  1534. CSASSERT(cInfo == cAltSubjectExtension);
  1535. ResultInfo.rgAltEntry = (CERT_ALT_NAME_ENTRY *) LocalAlloc(
  1536. LMEM_FIXED,
  1537. ResultInfo.cAltEntry * sizeof(CERT_ALT_NAME_ENTRY));
  1538. if (NULL == ResultInfo.rgAltEntry)
  1539. {
  1540. hr = E_OUTOFMEMORY;
  1541. _JumpIfError(hr, error, "LocalAlloc");
  1542. }
  1543. j = 0;
  1544. for (i = 0; i < cInfo; i++)
  1545. {
  1546. CopyMemory(
  1547. &ResultInfo.rgAltEntry[j],
  1548. apInfo[i]->rgAltEntry,
  1549. apInfo[i]->cAltEntry * sizeof(CERT_ALT_NAME_ENTRY));
  1550. j += apInfo[i]->cAltEntry;
  1551. }
  1552. if (!myEncodeObject(
  1553. X509_ASN_ENCODING,
  1554. X509_ALTERNATE_NAME,
  1555. &ResultInfo,
  1556. 0,
  1557. CERTLIB_USE_LOCALALLOC,
  1558. &pbResult,
  1559. &cbResult))
  1560. {
  1561. hr = myHLastError();
  1562. _JumpError(hr, error, "myEncodeObject");
  1563. }
  1564. hr = PropSetExtension(
  1565. prow,
  1566. PROPTYPE_BINARY | PROPCALLER_REQUEST,
  1567. TEXT(szOID_SUBJECT_ALT_NAME2),
  1568. ExtFlags,
  1569. cbResult,
  1570. pbResult);
  1571. _JumpIfError(hr, error, "PropSetExtension");
  1572. error:
  1573. if (NULL != apInfo)
  1574. {
  1575. for (i = 0; i < cInfo; i++)
  1576. {
  1577. if (NULL != apInfo[i])
  1578. {
  1579. LocalFree(apInfo[i]);
  1580. }
  1581. }
  1582. LocalFree(apInfo);
  1583. }
  1584. if (NULL != ResultInfo.rgAltEntry)
  1585. {
  1586. LocalFree(ResultInfo.rgAltEntry);
  1587. }
  1588. if (NULL != pbResult)
  1589. {
  1590. LocalFree(pbResult);
  1591. }
  1592. return(hr);
  1593. }
  1594. // Scan extension array, and merge all the AltSubjectName Extensions into one.
  1595. HRESULT
  1596. pkcsSetExtensions(
  1597. IN ICertDBRow *prow,
  1598. IN DWORD ExtFlags,
  1599. IN CERT_EXTENSION const *rgExtension,
  1600. IN DWORD cExtension)
  1601. {
  1602. HRESULT hr;
  1603. WCHAR *pwszObjId = NULL;
  1604. CERT_EXTENSION const *pExt;
  1605. CERT_EXTENSION const *pExtEnd;
  1606. DWORD cAltSubjectExtension = 0;
  1607. pExtEnd = &rgExtension[cExtension];
  1608. for (pExt = rgExtension; pExt < pExtEnd; pExt++)
  1609. {
  1610. DWORD ExtFlagsT;
  1611. if (EXTENSION_ORIGIN_RENEWALCERT == (EXTENSION_ORIGIN_MASK & ExtFlags))
  1612. {
  1613. char const * const *ppszObjId;
  1614. static char const * const apszObjIdFilter[] = {
  1615. szOID_CERTSRV_CA_VERSION,
  1616. szOID_AUTHORITY_INFO_ACCESS,
  1617. szOID_CRL_DIST_POINTS,
  1618. szOID_AUTHORITY_KEY_IDENTIFIER2,
  1619. szOID_SUBJECT_KEY_IDENTIFIER,
  1620. NULL
  1621. };
  1622. for (ppszObjId = apszObjIdFilter; NULL != *ppszObjId; ppszObjId++)
  1623. {
  1624. if (0 == strcmp(*ppszObjId, pExt->pszObjId))
  1625. {
  1626. break;
  1627. }
  1628. }
  1629. if (NULL != *ppszObjId) // if in list
  1630. {
  1631. continue; // skip this extension
  1632. }
  1633. }
  1634. else
  1635. if (EXTENSION_ORIGIN_CACERT == (EXTENSION_ORIGIN_MASK & ExtFlags))
  1636. {
  1637. char const * const *ppszObjId;
  1638. static char const * const apszObjIdAllowed[] = {
  1639. szOID_SUBJECT_KEY_IDENTIFIER,
  1640. NULL
  1641. };
  1642. for (ppszObjId = apszObjIdAllowed; NULL != *ppszObjId; ppszObjId++)
  1643. {
  1644. if (0 == strcmp(*ppszObjId, pExt->pszObjId))
  1645. {
  1646. break;
  1647. }
  1648. }
  1649. if (NULL == *ppszObjId) // if not in list
  1650. {
  1651. continue; // skip this extension
  1652. }
  1653. }
  1654. if (NULL != pwszObjId)
  1655. {
  1656. LocalFree(pwszObjId);
  1657. pwszObjId = NULL;
  1658. }
  1659. if (!myConvertSzToWsz(&pwszObjId, pExt->pszObjId, -1))
  1660. {
  1661. hr = E_OUTOFMEMORY;
  1662. _JumpError(hr, error, "myConvertSzToWsz(ObjId)");
  1663. }
  1664. ExtFlagsT = ExtFlags;
  1665. if (pExt->fCritical)
  1666. {
  1667. ExtFlagsT |= EXTENSION_CRITICAL_FLAG;
  1668. }
  1669. // AltSubjectName needs to be merged, so we do that later.
  1670. // This is an OID, generated by capi2, so we don't need to
  1671. // do a case-insensitive comparison.
  1672. if (0 == lstrcmp(pwszObjId, TEXT(szOID_SUBJECT_ALT_NAME2)))
  1673. {
  1674. cAltSubjectExtension++;
  1675. continue;
  1676. }
  1677. hr = PropSetExtension(
  1678. prow,
  1679. PROPTYPE_BINARY | PROPCALLER_REQUEST,
  1680. pwszObjId,
  1681. ExtFlagsT,
  1682. pExt->Value.cbData,
  1683. pExt->Value.pbData);
  1684. _JumpIfError(hr, error, "PropSetExtension");
  1685. DBGPRINT((
  1686. DBG_SS_CERTSRVI,
  1687. "PropSetExtension(%ws, f=%x, cb=%x, pb=%x)\n",
  1688. pwszObjId,
  1689. ExtFlagsT,
  1690. pExt->Value.cbData,
  1691. pExt->Value.pbData));
  1692. }
  1693. if (0 != cAltSubjectExtension)
  1694. {
  1695. hr = pkcsSetAltSubjectNameExtension(
  1696. prow,
  1697. ExtFlags,
  1698. rgExtension,
  1699. cExtension,
  1700. cAltSubjectExtension);
  1701. _JumpIfError(hr, error, "pkcsSetAltSubjectNameExtension");
  1702. }
  1703. hr = S_OK;
  1704. error:
  1705. if (NULL != pwszObjId)
  1706. {
  1707. LocalFree(pwszObjId);
  1708. }
  1709. return(hr);
  1710. }
  1711. HRESULT
  1712. pkcsSetOSVersion(
  1713. IN ICertDBRow *prow,
  1714. IN CRYPT_ATTR_BLOB *pAttrBlob)
  1715. {
  1716. HRESULT hr;
  1717. CERT_NAME_VALUE *pOSVersionString = NULL;
  1718. BSTR strVersion = NULL;
  1719. DWORD cb;
  1720. if (!myDecodeObject(
  1721. X509_ASN_ENCODING,
  1722. X509_ANY_STRING,
  1723. pAttrBlob->pbData,
  1724. pAttrBlob->cbData,
  1725. CERTLIB_USE_LOCALALLOC,
  1726. (VOID **) &pOSVersionString,
  1727. &cb))
  1728. {
  1729. hr = myHLastError();
  1730. _JumpError(hr, error, "myDecodeObject");
  1731. }
  1732. if (NULL != pOSVersionString)
  1733. {
  1734. if (!IS_CERT_RDN_CHAR_STRING(pOSVersionString->dwValueType))
  1735. {
  1736. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1737. _JumpError(hr, error, "version string is numeric data");
  1738. }
  1739. // If it's an 8 bit string, convert it to UNICODE
  1740. if (CERT_RDN_UNIVERSAL_STRING > pOSVersionString->dwValueType)
  1741. {
  1742. // Pass byte count in to allocate enough characters for
  1743. // the converted Unicode string
  1744. strVersion = SysAllocStringLen(
  1745. NULL,
  1746. pOSVersionString->Value.cbData);
  1747. // This is expected to be only numbers and '.'s,
  1748. if (NULL == strVersion)
  1749. {
  1750. hr = E_OUTOFMEMORY;
  1751. _JumpError(hr, error, "SysAllocStringLen");
  1752. }
  1753. mbstowcs(
  1754. strVersion,
  1755. (char const *) pOSVersionString->Value.pbData,
  1756. pOSVersionString->Value.cbData);
  1757. }
  1758. else if (CERT_RDN_BMP_STRING == pOSVersionString->dwValueType ||
  1759. CERT_RDN_UNICODE_STRING == pOSVersionString->dwValueType)
  1760. {
  1761. strVersion = SysAllocStringLen(
  1762. (WCHAR *) pOSVersionString->Value.pbData,
  1763. pOSVersionString->Value.cbData/sizeof(WCHAR));
  1764. if (NULL == strVersion)
  1765. {
  1766. hr = E_OUTOFMEMORY;
  1767. _JumpError(hr, error, "SysAllocStringLen");
  1768. }
  1769. }
  1770. else
  1771. {
  1772. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1773. _JumpError(hr, error, "unknown string type");
  1774. }
  1775. hr = prow->SetProperty(
  1776. g_wszPropRequestOSVersion,
  1777. PROPTYPE_STRING |
  1778. PROPCALLER_SERVER |
  1779. PROPTABLE_ATTRIBUTE,
  1780. SysStringByteLen(strVersion),
  1781. (BYTE *) strVersion);
  1782. _JumpIfError(hr, error, "SetProperty");
  1783. }
  1784. hr = S_OK;
  1785. error:
  1786. if (NULL != strVersion)
  1787. {
  1788. SysFreeString(strVersion);
  1789. }
  1790. if (NULL != pOSVersionString)
  1791. {
  1792. LocalFree(pOSVersionString);
  1793. }
  1794. return(hr);
  1795. }
  1796. HRESULT
  1797. pkcsSetCSPProvider(
  1798. IN ICertDBRow *prow,
  1799. IN CRYPT_ATTR_BLOB *pAttrBlob)
  1800. {
  1801. HRESULT hr;
  1802. CRYPT_CSP_PROVIDER *pccp = NULL;
  1803. hr = myDecodeCSPProviderAttribute(
  1804. pAttrBlob->pbData,
  1805. pAttrBlob->cbData,
  1806. &pccp);
  1807. _JumpIfError(hr, error, "myDecodeCSPProviderAttribute");
  1808. if (NULL != pccp->pwszProviderName && L'\0' != *pccp->pwszProviderName)
  1809. {
  1810. hr = prow->SetProperty(
  1811. g_wszPropRequestCSPProvider,
  1812. PROPTYPE_STRING |
  1813. PROPCALLER_SERVER |
  1814. PROPTABLE_ATTRIBUTE,
  1815. MAXDWORD,
  1816. (BYTE const *) pccp->pwszProviderName);
  1817. _JumpIfError(hr, error, "SetProperty");
  1818. }
  1819. hr = S_OK;
  1820. error:
  1821. if (NULL != pccp)
  1822. {
  1823. LocalFree(pccp);
  1824. }
  1825. return(hr);
  1826. }
  1827. HRESULT
  1828. pkcsSetExtensionsFromAttributeBlob(
  1829. IN ICertDBRow *prow,
  1830. IN DWORD ExtFlags,
  1831. IN CRYPT_ATTRIBUTE const *pAttrib)
  1832. {
  1833. HRESULT hr;
  1834. CRYPT_ATTR_BLOB *pAttrBlob;
  1835. CERT_NAME_VALUE *pNameInfo = NULL;
  1836. CERT_EXTENSIONS *pCertExtensions = NULL;
  1837. DWORD cb;
  1838. pAttrBlob = pAttrib->rgValue;
  1839. for (;;)
  1840. {
  1841. if (NULL != pCertExtensions)
  1842. {
  1843. LocalFree(pCertExtensions);
  1844. pCertExtensions = NULL;
  1845. }
  1846. if (myDecodeObject(
  1847. X509_ASN_ENCODING,
  1848. X509_EXTENSIONS,
  1849. pAttrBlob->pbData,
  1850. pAttrBlob->cbData,
  1851. CERTLIB_USE_LOCALALLOC,
  1852. (VOID **) &pCertExtensions,
  1853. &cb))
  1854. {
  1855. break; // success
  1856. }
  1857. hr = myHLastError();
  1858. // if we already decoded the attribute as a T61 string, or if it is
  1859. // not a PKCS 9.14 attribute, fail -- we don't know what it contains.
  1860. if (NULL != pNameInfo ||
  1861. 0 != strcmp(pAttrib->pszObjId, szOID_RSA_certExtensions))
  1862. {
  1863. _JumpError(hr, error, "myDecodeObject");
  1864. }
  1865. // Decode the attribute as a T61 string. Some implementations wrap the
  1866. // PKCS 9.14 extension array in an extra level of encoding as a Teletex
  1867. // string.
  1868. if (!myDecodeObject(
  1869. X509_ASN_ENCODING,
  1870. X509_ANY_STRING,
  1871. pAttrBlob->pbData,
  1872. pAttrBlob->cbData,
  1873. CERTLIB_USE_LOCALALLOC,
  1874. (VOID **) &pNameInfo,
  1875. &cb))
  1876. {
  1877. hr = myHLastError();
  1878. _JumpError(hr, error, "myDecodeObject");
  1879. }
  1880. // Loop again and try to decode the raw name blob as X509_EXTENSIONS.
  1881. pAttrBlob = &pNameInfo->Value;
  1882. }
  1883. hr = pkcsSetExtensions(
  1884. prow,
  1885. EXTENSION_DISABLE_FLAG | ExtFlags,
  1886. pCertExtensions->rgExtension,
  1887. pCertExtensions->cExtension);
  1888. _JumpIfError(hr, error, "pkcsSetExtensions(attributes)");
  1889. error:
  1890. if (NULL != pNameInfo)
  1891. {
  1892. LocalFree(pNameInfo);
  1893. }
  1894. if (NULL != pCertExtensions)
  1895. {
  1896. LocalFree(pCertExtensions);
  1897. }
  1898. return(hr);
  1899. }
  1900. HRESULT
  1901. PKCSGetProperty(
  1902. IN ICertDBRow *prow,
  1903. IN WCHAR const *pwszPropName,
  1904. IN DWORD Flags,
  1905. OPTIONAL OUT DWORD *pcbData,
  1906. OUT BYTE **ppbData)
  1907. {
  1908. HRESULT hr;
  1909. BYTE *pbData = NULL;
  1910. DWORD cbData;
  1911. if (NULL != pcbData)
  1912. {
  1913. *pcbData = 0;
  1914. }
  1915. *ppbData = NULL;
  1916. cbData = 0;
  1917. hr = prow->GetProperty(pwszPropName, Flags, NULL, &cbData, pbData);
  1918. _JumpIfError2(hr, error, "GetProperty", CERTSRV_E_PROPERTY_EMPTY);
  1919. pbData = (BYTE *) LocalAlloc(LMEM_FIXED, cbData);
  1920. if (NULL == pbData)
  1921. {
  1922. hr = E_OUTOFMEMORY;
  1923. _JumpError(hr, error, "LocalAlloc");
  1924. }
  1925. hr = prow->GetProperty(pwszPropName, Flags, NULL, &cbData, pbData);
  1926. _JumpIfError(hr, error, "GetProperty");
  1927. if (NULL != pcbData)
  1928. {
  1929. *pcbData = cbData;
  1930. }
  1931. *ppbData = pbData;
  1932. pbData = NULL;
  1933. error:
  1934. if (NULL != pbData)
  1935. {
  1936. LocalFree(pbData);
  1937. }
  1938. return(hr);
  1939. }
  1940. VOID
  1941. pkcsFreePublicKeyInfo(
  1942. IN OUT CERT_PUBLIC_KEY_INFO *pPublicKeyInfo)
  1943. {
  1944. if (NULL != pPublicKeyInfo->Algorithm.pszObjId)
  1945. {
  1946. LocalFree(pPublicKeyInfo->Algorithm.pszObjId);
  1947. }
  1948. if (NULL != pPublicKeyInfo->Algorithm.Parameters.pbData)
  1949. {
  1950. LocalFree(pPublicKeyInfo->Algorithm.Parameters.pbData);
  1951. }
  1952. if (NULL != pPublicKeyInfo->PublicKey.pbData)
  1953. {
  1954. LocalFree(pPublicKeyInfo->PublicKey.pbData);
  1955. }
  1956. ZeroMemory(pPublicKeyInfo, sizeof(*pPublicKeyInfo));
  1957. }
  1958. HRESULT
  1959. pkcsGetPublicKeyInfo(
  1960. IN ICertDBRow *prow,
  1961. OUT CERT_PUBLIC_KEY_INFO *pPublicKeyInfo)
  1962. {
  1963. HRESULT hr;
  1964. WCHAR *pwszObjId = NULL;
  1965. ZeroMemory(pPublicKeyInfo, sizeof(*pPublicKeyInfo));
  1966. hr = PKCSGetProperty(
  1967. prow,
  1968. g_wszPropCertificatePublicKeyAlgorithm,
  1969. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  1970. NULL,
  1971. (BYTE **) &pwszObjId);
  1972. _JumpIfError(hr, error, "PKCSGetProperty");
  1973. if (!myConvertWszToSz(&pPublicKeyInfo->Algorithm.pszObjId, pwszObjId, -1))
  1974. {
  1975. hr = E_OUTOFMEMORY;
  1976. _JumpError(hr, error, "myConvertWszToSz(AlgObjId)");
  1977. }
  1978. hr = PKCSGetProperty(
  1979. prow,
  1980. g_wszPropCertificateRawPublicKeyAlgorithmParameters,
  1981. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  1982. &pPublicKeyInfo->Algorithm.Parameters.cbData,
  1983. &pPublicKeyInfo->Algorithm.Parameters.pbData);
  1984. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  1985. {
  1986. _JumpIfError(hr, error, "PKCSGetProperty");
  1987. }
  1988. hr = PKCSGetProperty(
  1989. prow,
  1990. g_wszPropCertificateRawPublicKey,
  1991. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  1992. &pPublicKeyInfo->PublicKey.cbData,
  1993. &pPublicKeyInfo->PublicKey.pbData);
  1994. _JumpIfError(hr, error, "PKCSGetProperty");
  1995. error:
  1996. if (S_OK != hr)
  1997. {
  1998. pkcsFreePublicKeyInfo(pPublicKeyInfo);
  1999. }
  2000. if (NULL != pwszObjId)
  2001. {
  2002. LocalFree(pwszObjId);
  2003. }
  2004. return(hr);
  2005. }
  2006. VOID
  2007. pkcsLogKRACertError(
  2008. IN DWORD LogMsg,
  2009. IN DWORD iHash,
  2010. OPTIONAL IN CERT_CONTEXT const *pcc,
  2011. IN HRESULT hrLog)
  2012. {
  2013. HRESULT hr;
  2014. WCHAR awc[cwcDWORDSPRINTF];
  2015. WCHAR *pwszName = NULL;
  2016. WCHAR const *pwszError = NULL;
  2017. WCHAR const *apwsz[3];
  2018. wsprintf(awc, L"%u", iHash);
  2019. apwsz[0] = awc;
  2020. if (NULL != pcc)
  2021. {
  2022. hr = myCertNameToStr(
  2023. X509_ASN_ENCODING,
  2024. &pcc->pCertInfo->Subject,
  2025. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  2026. &pwszName);
  2027. _PrintIfError(hr, "myCertNameToStr");
  2028. }
  2029. apwsz[1] = NULL != pwszName? pwszName : L"";
  2030. pwszError = myGetErrorMessageText(hrLog, TRUE);
  2031. apwsz[2] = NULL != pwszError? pwszError : L"";
  2032. LogEvent(EVENTLOG_ERROR_TYPE, LogMsg, ARRAYSIZE(apwsz), apwsz);
  2033. //error:
  2034. if (NULL != pwszName)
  2035. {
  2036. LocalFree(pwszName);
  2037. }
  2038. if (NULL != pwszError)
  2039. {
  2040. LocalFree(const_cast<WCHAR *>(pwszError));
  2041. }
  2042. }
  2043. HRESULT
  2044. pkcsCryptGetDefaultProvider(
  2045. DWORD dwProvType,
  2046. DWORD dwFlags,
  2047. WCHAR **ppwszProvName)
  2048. {
  2049. HRESULT hr;
  2050. DWORD cb;
  2051. *ppwszProvName = NULL;
  2052. cb = 0;
  2053. for (;;)
  2054. {
  2055. if (!CryptGetDefaultProvider(
  2056. dwProvType,
  2057. NULL, // pdwReserved
  2058. dwFlags,
  2059. *ppwszProvName,
  2060. &cb))
  2061. {
  2062. hr = myHLastError();
  2063. _JumpError(hr, error, "CryptGetDefaultProvider");
  2064. }
  2065. if (NULL != *ppwszProvName)
  2066. {
  2067. break;
  2068. }
  2069. *ppwszProvName = (WCHAR *) LocalAlloc(LMEM_FIXED, cb);
  2070. if (NULL == *ppwszProvName)
  2071. {
  2072. hr = E_OUTOFMEMORY;
  2073. _JumpError(hr, error, "LocalAlloc");
  2074. }
  2075. }
  2076. hr = S_OK;
  2077. error:
  2078. return(hr);
  2079. }
  2080. HRESULT
  2081. pkcsEncryptPrivateKey(
  2082. IN BYTE *pbDecrypted,
  2083. IN DWORD cbDecrypted,
  2084. IN OUT CERTSRV_RESULT_CONTEXT *pResult) // CoTaskMem*
  2085. {
  2086. HRESULT hr;
  2087. DWORD i;
  2088. DWORD iKRACert;
  2089. DWORD cwc;
  2090. CERT_CONTEXT const **rgKRACerts = NULL;
  2091. WCHAR *pwszKRAHashes = NULL;
  2092. DWORD *rgKRAIndexes = NULL;
  2093. DWORD cKRAUsed;
  2094. KRACTX *pKRAContext;
  2095. BOOL fInvalidated;
  2096. DWORD iKRAStart;
  2097. WCHAR *pwszProviderName = NULL;
  2098. static bool fUseCAProv = true;
  2099. if (NULL != pResult->pbArchivedKey || NULL != pResult->pwszKRAHashes)
  2100. {
  2101. hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
  2102. _JumpError(hr, error, "multiple archived keys");
  2103. }
  2104. CSASSERT(
  2105. NULL != g_aKRAContext &&
  2106. 0 != g_cKRACerts &&
  2107. 0 != g_cKRACertsRoundRobin);
  2108. rgKRAIndexes = (DWORD *) LocalAlloc(
  2109. LMEM_FIXED,
  2110. g_cKRACertsRoundRobin * sizeof(rgKRAIndexes[0]));
  2111. if (NULL == rgKRAIndexes)
  2112. {
  2113. hr = E_OUTOFMEMORY;
  2114. _JumpError(hr, error, "LocalAlloc");
  2115. }
  2116. if (!CryptGenRandom(
  2117. g_pCAContextCurrent->hProvCA,
  2118. sizeof(iKRAStart),
  2119. (BYTE *) &iKRAStart))
  2120. {
  2121. hr = myHLastError();
  2122. _JumpError(hr, error, "CryptGenRandom");
  2123. }
  2124. cwc = 0;
  2125. fInvalidated = FALSE;
  2126. for (
  2127. cKRAUsed = 0, i = 0;
  2128. cKRAUsed < g_cKRACertsRoundRobin && i < g_cKRACerts;
  2129. i++)
  2130. {
  2131. iKRACert = (iKRAStart + i) % g_cKRACerts;
  2132. pKRAContext = &g_aKRAContext[iKRACert];
  2133. if (S_OK != pKRAContext->hrVerifyStatus)
  2134. {
  2135. continue;
  2136. }
  2137. hr = myVerifyKRACertContext(pKRAContext->pccKRA, g_dwVerifyCertFlags);
  2138. if (S_OK != hr)
  2139. {
  2140. _PrintError(hr, "myVerifyKRACertContext");
  2141. pKRAContext->hrVerifyStatus = hr;
  2142. if (CERT_E_EXPIRED == hr)
  2143. {
  2144. pKRAContext->Flags |= CTXF_EXPIRED;
  2145. }
  2146. else
  2147. // Assume revoked for other errors
  2148. // if (CRYPT_E_REVOKED == hr || CERT_E_REVOKED == hr)
  2149. {
  2150. pKRAContext->Flags |= CTXF_REVOKED;
  2151. }
  2152. pkcsLogKRACertError(
  2153. MSG_E_INVALID_KRA_CERT,
  2154. iKRACert,
  2155. pKRAContext->pccKRA,
  2156. hr);
  2157. fInvalidated = TRUE;
  2158. continue;
  2159. }
  2160. cwc += wcslen(pKRAContext->strKRAHash) + 1;
  2161. rgKRAIndexes[cKRAUsed] = iKRACert;
  2162. cKRAUsed++;
  2163. }
  2164. if (0 == cKRAUsed || g_cKRACertsRoundRobin > cKRAUsed)
  2165. {
  2166. if (fInvalidated)
  2167. {
  2168. LogEvent(EVENTLOG_ERROR_TYPE, MSG_E_TOO_MANY_KRA_INVALID, 0, NULL);
  2169. }
  2170. hr = CERTSRV_E_NO_VALID_KRA;
  2171. _JumpError(hr, error, "too many invalid KRA certs");
  2172. }
  2173. rgKRACerts = (CERT_CONTEXT const **) LocalAlloc(
  2174. LMEM_FIXED,
  2175. cKRAUsed * sizeof(rgKRACerts[0]));
  2176. if (NULL == rgKRACerts)
  2177. {
  2178. hr = E_OUTOFMEMORY;
  2179. _JumpError(hr, error, "LocalAlloc");
  2180. }
  2181. pwszKRAHashes = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  2182. if (NULL == pwszKRAHashes)
  2183. {
  2184. hr = E_OUTOFMEMORY;
  2185. _JumpError(hr, error, "LocalAlloc");
  2186. }
  2187. pwszKRAHashes[0] = L'\0';
  2188. for (i = 0; i < cKRAUsed; i++)
  2189. {
  2190. pKRAContext = &g_aKRAContext[rgKRAIndexes[i]];
  2191. rgKRACerts[i] = pKRAContext->pccKRA;
  2192. if (0 != i)
  2193. {
  2194. wcscat(pwszKRAHashes, L"\n");
  2195. }
  2196. wcscat(pwszKRAHashes, pKRAContext->strKRAHash);
  2197. }
  2198. CSASSERT(wcslen(pwszKRAHashes) + 1 == cwc);
  2199. if (CRLF_REVCHECK_IGNORE_OFFLINE & g_KRAFlags)
  2200. {
  2201. fUseCAProv = false;
  2202. }
  2203. hr = myCryptEncryptMessage(
  2204. g_XchgidAlg,
  2205. cKRAUsed, // cCertRecipient
  2206. rgKRACerts, // rgCertRecipient
  2207. pbDecrypted,
  2208. cbDecrypted,
  2209. fUseCAProv? g_pCAContextCurrent->hProvCA : NULL,
  2210. &pResult->pbArchivedKey,
  2211. &pResult->cbArchivedKey);
  2212. if (FAILED(hr) && fUseCAProv)
  2213. {
  2214. // Failed to use the CA HCRYPTPROV, fall back to default
  2215. hr = pkcsCryptGetDefaultProvider(
  2216. PROV_RSA_FULL,
  2217. CRYPT_MACHINE_DEFAULT,
  2218. &pwszProviderName);
  2219. _JumpIfError(hr, error, "pkcsCryptGetDefaultProvider");
  2220. hr = LogEvent(
  2221. EVENTLOG_WARNING_TYPE,
  2222. MSG_E_USE_DEFAULT_CA_XCHG_CSP,
  2223. 1, // cpwsz
  2224. &pwszProviderName); // apwsz
  2225. _PrintIfError(hr, "LogEvent");
  2226. fUseCAProv = false;
  2227. hr = myCryptEncryptMessage(
  2228. g_XchgidAlg,
  2229. cKRAUsed, // cCertRecipient
  2230. rgKRACerts, // rgCertRecipient
  2231. pbDecrypted,
  2232. cbDecrypted,
  2233. NULL,
  2234. &pResult->pbArchivedKey,
  2235. &pResult->cbArchivedKey);
  2236. }
  2237. _JumpIfError(hr, error, "myCryptEncryptMessage");
  2238. pResult->pwszKRAHashes = pwszKRAHashes;
  2239. pwszKRAHashes = NULL;
  2240. error:
  2241. if (NULL != pwszProviderName)
  2242. {
  2243. LocalFree(pwszProviderName);
  2244. }
  2245. if (NULL != rgKRAIndexes)
  2246. {
  2247. LocalFree(rgKRAIndexes);
  2248. }
  2249. if (NULL != pwszKRAHashes)
  2250. {
  2251. LocalFree(pwszKRAHashes);
  2252. }
  2253. if (NULL != rgKRACerts)
  2254. {
  2255. LocalFree(rgKRACerts);
  2256. }
  2257. return(hr);
  2258. }
  2259. // PKCSArchivePrivateKey -- archive a private key
  2260. //
  2261. // Description of Algorithm:
  2262. // -------------------------
  2263. //
  2264. // Client constructs request:
  2265. // CryptExportKey(NULL, NULL, PRIVATEKEYBLOB, ...)
  2266. // CryptEncryptMessage(CALG_3DES, &CAExchangeCert, ...)
  2267. //
  2268. // Server decrypts and verifies key in request:
  2269. // CryptDecryptMessage(..., &PrivateKeyBlob)
  2270. //
  2271. // Server imports decrypted key into temporary key container:
  2272. // CryptAcquireContext(
  2273. // &hProv,
  2274. // pwszTempKeyContainerName,
  2275. // NULL,
  2276. // PROV_RSA_FULL,
  2277. // CRYPT_NEWKEYSET)
  2278. // CryptImportKey(PrivateKeyBlob, &PrivateKey)
  2279. // CryptDestroyKey(PrivateKey)
  2280. // CryptReleaseContext()
  2281. //
  2282. // Server validates key for encryption:
  2283. // CryptAcquireContext(
  2284. // &hProv,
  2285. // pwszTempKeyContainerName,
  2286. // NULL,
  2287. // PROV_RSA_FULL,
  2288. // 0)
  2289. // CryptImportPublicKeyInfo(RequestPublicKey, &PublicKey)
  2290. // CryptGenKey(hProv, CALC_RC4, CRYPT_EXPORTABLE, &SymmetricKey)
  2291. // CryptGenRandom(hProv, ...)
  2292. // CryptEncrypt(SymmetricKey, ..)
  2293. // CryptExportKey(SymmetricKey, PublicKey, SIMPLEBLOB, &SymmetricKeyBlob)
  2294. // CryptDestroyKey(SymmetricKey)
  2295. //
  2296. // CryptGetUserKey(hProv, AT_KEYEXCHANGE, &PrivateKey)
  2297. // CryptImportKey(hProv, SymmetricKeyBlob, PrivateKey, ..., &SymmetricKey)
  2298. // CryptDecrypt(SymmetricKey, ...)
  2299. //
  2300. // CryptExportPublicKeyInfo(hProv, AT_KEYEXCHANGE, &ExportedPublicKey)
  2301. // CertComparePublicKeyInfo(ExportedPublicKey, RequestPublicKey)
  2302. // memcmp(RandomCleartext, DecryptedClearText)
  2303. // CryptDestroyKey(all keys)
  2304. // CryptReleaseContext()
  2305. //
  2306. // Server verifies request public key matches decrypted public key:
  2307. // CryptExportPublicKeyInfo(
  2308. // hProv,
  2309. // AT_KEYEXCHANGE,
  2310. // &PublicKeyBlobFromDecryptedPrivateKey)
  2311. // CertComparePublicKeyInfo(
  2312. // PublicKeyBlobFromDecryptedPrivateKe,
  2313. // PublicKeyBlobFromRequest),
  2314. //
  2315. // Server deletes temporary key container:
  2316. // CryptAcquireContext(
  2317. // &hProv,
  2318. // pwszTempKeyContainerName,
  2319. // NULL,
  2320. // PROV_RSA_FULL,
  2321. // CRYPT_DELETEKEYSET)
  2322. //
  2323. // Server encrypts key to one or more KRA certs:
  2324. // CryptEncryptMessage(CALG_3DES, KRACertCount, &KRACertArray, ...)
  2325. HRESULT
  2326. PKCSArchivePrivateKey(
  2327. IN ICertDBRow *prow,
  2328. IN BOOL fV1Cert,
  2329. IN BOOL fOverwrite,
  2330. IN CRYPT_ATTR_BLOB const *pBlobEncrypted,
  2331. OPTIONAL IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  2332. {
  2333. HRESULT hr;
  2334. BYTE *pbDecrypted = NULL;
  2335. DWORD cbDecrypted;
  2336. DWORD iCertSig;
  2337. BYTE *pbCert; // do not free!
  2338. DWORD cbCert;
  2339. DWORD cb;
  2340. CERT_PUBLIC_KEY_INFO PublicKeyInfo;
  2341. WCHAR *pwszUserName = NULL;
  2342. BYTE *pbKeyHash = NULL;
  2343. DWORD cbKeyHash;
  2344. CERTSRV_RESULT_CONTEXT tempResultContext;
  2345. BOOL fSigningKey = FALSE;
  2346. ZeroMemory(&tempResultContext, sizeof(tempResultContext));
  2347. ZeroMemory(&PublicKeyInfo, sizeof(PublicKeyInfo));
  2348. cbDecrypted = 0;
  2349. cbKeyHash = 0;
  2350. if (0 == g_cKRACerts || g_cKRACertsRoundRobin > g_cKRACerts)
  2351. {
  2352. hr = CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED;
  2353. _JumpError(hr, error, "not enough KRA certs loaded");
  2354. }
  2355. if (NULL != pResult)
  2356. {
  2357. if (NULL == pResult->pbKeyHashIn)
  2358. {
  2359. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2360. _JumpError(hr, error, "missing encrypted key hash");
  2361. }
  2362. hr = myCalculateKeyArchivalHash(
  2363. pBlobEncrypted->pbData,
  2364. pBlobEncrypted->cbData,
  2365. &pbKeyHash,
  2366. &cbKeyHash);
  2367. _JumpIfError(hr, error, "myCalculateKeyArchivalHash");
  2368. if (pResult->cbKeyHashIn != cbKeyHash ||
  2369. 0 != memcmp(pResult->pbKeyHashIn, pbKeyHash, cbKeyHash))
  2370. {
  2371. hr = NTE_BAD_KEY;
  2372. _JumpError(hr, error, "key hash mismatch");
  2373. }
  2374. hr = PKCSSetRequestFlags(prow, TRUE, CR_FLG_VALIDENCRYPTEDKEYHASH);
  2375. _JumpIfError(hr, error, "PKCSSetRequestFlags");
  2376. }
  2377. hr = prow->GetProperty(
  2378. g_wszPropRequestRawArchivedKey,
  2379. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2380. NULL,
  2381. &cb,
  2382. NULL);
  2383. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  2384. {
  2385. if (S_OK == hr && !fOverwrite)
  2386. {
  2387. hr = HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS);
  2388. }
  2389. _JumpIfError2(
  2390. hr,
  2391. error,
  2392. "GetProperty",
  2393. HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS));
  2394. }
  2395. hr = PKCSGetProperty(
  2396. prow,
  2397. g_wszPropRequesterName,
  2398. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2399. NULL,
  2400. (BYTE **) &pwszUserName);
  2401. _JumpIfError(hr, error, "PKCSGetProperty");
  2402. if (NULL == g_hStoreCAXchg)
  2403. {
  2404. hr = PKCSGetCAXchgCert(0, pwszUserName, &iCertSig, &pbCert, &cbCert);
  2405. _JumpIfError(hr, error, "PKCSGetCAXchgCert");
  2406. }
  2407. CSASSERT(NULL != g_hStoreCAXchg);
  2408. hr = myCryptDecryptMessage(
  2409. g_hStoreCAXchg,
  2410. pBlobEncrypted->pbData,
  2411. pBlobEncrypted->cbData,
  2412. CERTLIB_USE_LOCALALLOC,
  2413. &pbDecrypted,
  2414. &cbDecrypted);
  2415. _JumpIfError(hr, error, "myCryptDecryptMessage");
  2416. DBGDUMPHEX((DBG_SS_CERTSRVI, DH_PRIVATEDATA, pbDecrypted, cbDecrypted));
  2417. hr = pkcsGetPublicKeyInfo(prow, &PublicKeyInfo);
  2418. _JumpIfError(hr, error, "pkcsGetPublicKeyInfo");
  2419. hr = myValidateKeyBlob(
  2420. pbDecrypted,
  2421. cbDecrypted,
  2422. &PublicKeyInfo,
  2423. fV1Cert,
  2424. &fSigningKey,
  2425. NULL);
  2426. _JumpIfError(hr, error, "myValidateKeyBlob");
  2427. if (fSigningKey && 0 == (KRAF_ENABLEARCHIVEALL & g_KRAFlags))
  2428. {
  2429. if (NULL != pResult)
  2430. {
  2431. pResult->dwResultFlags |= CRCF_ARCHIVESIGNINGKEYERROR;
  2432. }
  2433. hr = NTE_BAD_KEY_STATE;
  2434. _JumpError(hr, error, "fSigningKey");
  2435. }
  2436. hr = pkcsEncryptPrivateKey(
  2437. pbDecrypted,
  2438. cbDecrypted,
  2439. NULL != pResult? pResult : &tempResultContext);
  2440. _JumpIfError(hr, error, "pkcsEncryptPrivateKey");
  2441. // if a key import, save to database
  2442. if (NULL == pResult)
  2443. {
  2444. hr = prow->SetProperty(
  2445. g_wszPropRequestRawArchivedKey,
  2446. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2447. tempResultContext.cbArchivedKey,
  2448. tempResultContext.pbArchivedKey);
  2449. _JumpIfError(hr, error, "SetProperty(ArchivedKey)");
  2450. hr = prow->SetProperty(
  2451. g_wszPropRequestKeyRecoveryHashes,
  2452. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2453. MAXDWORD,
  2454. (BYTE const *) tempResultContext.pwszKRAHashes);
  2455. _JumpIfError(hr, error, "SetProperty(KRAHashes)");
  2456. }
  2457. if (NULL != pResult && NULL == pResult->pbKeyHashOut)
  2458. {
  2459. pResult->pbKeyHashOut = pbKeyHash;
  2460. pResult->cbKeyHashOut = cbKeyHash;
  2461. pbKeyHash = NULL;
  2462. }
  2463. {
  2464. CertSrv::CAuditEvent audit(SE_AUDITID_CERTSRV_KEYARCHIVED, g_dwAuditFilter);
  2465. DWORD dwRequestID = 0;
  2466. cb = sizeof(DWORD);
  2467. if (audit.IsEventEnabled())
  2468. {
  2469. hr = prow->GetProperty(
  2470. g_wszPropRequestRequestID,
  2471. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2472. NULL,
  2473. &cb,
  2474. (BYTE *)&dwRequestID);
  2475. _JumpIfError(hr, error, "Report");
  2476. hr = audit.AddData(dwRequestID); // %1 request ID
  2477. _JumpIfError(hr, error, "CAuditEvent::AddData");
  2478. hr = audit.AddData(pwszUserName); // %2 requester
  2479. _JumpIfError(hr, error, "CAuditEvent::AddData");
  2480. // %3 KRA hashes
  2481. hr = audit.AddData(
  2482. (NULL != pResult? pResult : &tempResultContext)->pwszKRAHashes);
  2483. _JumpIfError(hr, error, "CAuditEvent::AddData");
  2484. hr = audit.Report();
  2485. _JumpIfError(hr, error, "Report");
  2486. }
  2487. }
  2488. error:
  2489. if (S_OK != hr && NULL != pResult)
  2490. {
  2491. pResult->dwResultFlags |= CRCF_KEYARCHIVALERROR;
  2492. }
  2493. pkcsFreePublicKeyInfo(&PublicKeyInfo);
  2494. if (NULL != pbDecrypted)
  2495. {
  2496. SecureZeroMemory(pbDecrypted, cbDecrypted); // Private Key Material!
  2497. LocalFree(pbDecrypted);
  2498. }
  2499. if (NULL != pwszUserName)
  2500. {
  2501. LocalFree(pwszUserName);
  2502. }
  2503. if (NULL != pbKeyHash)
  2504. {
  2505. LocalFree(pbKeyHash);
  2506. }
  2507. ReleaseResult(&tempResultContext);
  2508. return(hr);
  2509. }
  2510. HRESULT
  2511. pkcsSaveRequestWithoutArchivedKey(
  2512. IN ICertDBRow *prow,
  2513. IN DWORD cbIn,
  2514. IN BYTE const *pbIn)
  2515. {
  2516. HRESULT hr;
  2517. HCRYPTMSG hMsg = NULL;
  2518. DWORD cSigner;
  2519. DWORD iSigner;
  2520. DWORD i;
  2521. DWORD cb;
  2522. BYTE *pbWithoutKey = NULL;
  2523. DWORD cbWithoutKey;
  2524. CRYPT_ATTRIBUTES *pAttrib = NULL;
  2525. BOOL fKeyDeleted = FALSE;
  2526. hMsg = CryptMsgOpenToDecode(
  2527. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  2528. 0, // dwFlags
  2529. 0, // dwMsgType
  2530. NULL, // hCryptProv
  2531. NULL, // pRecipientInfo
  2532. NULL); // pStreamInfo
  2533. if (NULL == hMsg)
  2534. {
  2535. hr = myHLastError();
  2536. _JumpError(hr, error, "CryptMsgOpenToDecode");
  2537. }
  2538. if (!CryptMsgUpdate(hMsg, pbIn, cbIn, TRUE))
  2539. {
  2540. hr = myHLastError();
  2541. _JumpError(hr, error, "CryptMsgUpdate");
  2542. }
  2543. cb = sizeof(cSigner);
  2544. if (!CryptMsgGetParam(
  2545. hMsg,
  2546. CMSG_SIGNER_COUNT_PARAM,
  2547. 0,
  2548. &cSigner,
  2549. &cb))
  2550. {
  2551. hr = myHLastError();
  2552. _JumpError(hr, error, "CryptMsgGetParam(signer count)");
  2553. }
  2554. DBGPRINT((DBG_SS_CERTSRV, "cSigner=%u\n", cSigner));
  2555. for (iSigner = 0; iSigner < cSigner; iSigner++)
  2556. {
  2557. hr = myCryptMsgGetParam(
  2558. hMsg,
  2559. CMSG_SIGNER_UNAUTH_ATTR_PARAM,
  2560. iSigner, // dwIndex
  2561. CERTLIB_USE_LOCALALLOC,
  2562. (VOID **) &pAttrib,
  2563. &cb);
  2564. _PrintIfError2(hr, "myCryptMsgGetParam(content)", hr);
  2565. if (S_FALSE == hr)
  2566. {
  2567. continue;
  2568. }
  2569. _JumpIfError(hr, error, "myCryptMsgGetParam(content)");
  2570. DBGPRINT((
  2571. DBG_SS_CERTSRV,
  2572. "iSigner=%u, cAttr=%u\n",
  2573. iSigner,
  2574. pAttrib->cAttr));
  2575. // Loop through deleting attributes from the end to avoid invalidated
  2576. // indexes, which may result from deleting earlier attributes.
  2577. for (i = 0; i < pAttrib->cAttr; i++)
  2578. {
  2579. CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA DelPara;
  2580. DWORD iAttr = pAttrib->cAttr - i - 1;
  2581. DBGPRINT((
  2582. DBG_SS_CERTSRV,
  2583. "iSigner=%u, iAttr=%u %hs\n",
  2584. iSigner,
  2585. iAttr,
  2586. pAttrib->rgAttr[iAttr].pszObjId));
  2587. if (0 == strcmp(
  2588. pAttrib->rgAttr[iAttr].pszObjId,
  2589. szOID_ARCHIVED_KEY_ATTR))
  2590. {
  2591. ZeroMemory(&DelPara, sizeof(DelPara));
  2592. DelPara.cbSize = sizeof(DelPara);
  2593. DelPara.dwSignerIndex = iSigner;
  2594. DelPara.dwUnauthAttrIndex = iAttr;
  2595. DBGPRINT((
  2596. DBG_SS_CERTSRV,
  2597. "Delete Key(signer=%u, attrib=%u)\n",
  2598. DelPara.dwSignerIndex,
  2599. DelPara.dwUnauthAttrIndex));
  2600. if (!CryptMsgControl(
  2601. hMsg,
  2602. 0,
  2603. CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR,
  2604. &DelPara))
  2605. {
  2606. hr = myHLastError();
  2607. _PrintError(hr, "CryptMsgControl");
  2608. }
  2609. fKeyDeleted = TRUE;
  2610. }
  2611. }
  2612. LocalFree(pAttrib);
  2613. pAttrib = NULL;
  2614. }
  2615. if (!fKeyDeleted)
  2616. {
  2617. hr = S_FALSE;
  2618. _JumpError(hr, error, "no Encrypted Key attribute");
  2619. }
  2620. hr = myCryptMsgGetParam(
  2621. hMsg,
  2622. CMSG_ENCODED_MESSAGE,
  2623. 0, // dwIndex
  2624. CERTLIB_USE_LOCALALLOC,
  2625. (VOID **) &pbWithoutKey,
  2626. &cbWithoutKey);
  2627. _JumpIfError(hr, error, "myCryptMsgGetParam(content)");
  2628. hr = prow->SetProperty(
  2629. g_wszPropRequestRawRequest,
  2630. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2631. cbWithoutKey,
  2632. pbWithoutKey);
  2633. _JumpIfError(hr, error, "SetProperty(request)");
  2634. error:
  2635. if (NULL != pAttrib)
  2636. {
  2637. LocalFree(pAttrib);
  2638. }
  2639. if (NULL != pbWithoutKey)
  2640. {
  2641. LocalFree(pbWithoutKey);
  2642. }
  2643. if (NULL != hMsg)
  2644. {
  2645. CryptMsgClose(hMsg);
  2646. }
  2647. return(hr);
  2648. }
  2649. #define PSA_DISALLOW_EXTENSIONS 0x00000001
  2650. #define PSA_DISALLOW_NAMEVALUEPAIRS 0x00000002
  2651. #define PSA_DISALLOW_ARCHIVEDKEY 0x00000004
  2652. HRESULT
  2653. pkcsSetAttributes(
  2654. IN ICertDBRow *prow,
  2655. IN DWORD ExtFlags,
  2656. IN DWORD dwDisallowFlags,
  2657. IN CRYPT_ATTRIBUTE const *rgAttrib,
  2658. IN DWORD cAttrib,
  2659. IN DWORD cbRequest,
  2660. OPTIONAL IN BYTE const *pbRequest,
  2661. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf,
  2662. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  2663. {
  2664. HRESULT hr;
  2665. CRYPT_ATTRIBUTE const *pAttrib;
  2666. CRYPT_ATTRIBUTE const *pAttribEnd;
  2667. DWORD i;
  2668. BYTE afSubjectTable[CSUBJECTTABLE]; // see PKCSParseAttributes note
  2669. CRYPT_DATA_BLOB *pBlob = NULL;
  2670. BOOL fSubjectModified = FALSE;
  2671. ZeroMemory(afSubjectTable, sizeof(afSubjectTable));
  2672. CSASSERT(CSExpr(0 == FALSE));
  2673. if (NULL != pfEnrollOnBehalfOf)
  2674. {
  2675. *pfEnrollOnBehalfOf = FALSE;
  2676. }
  2677. pAttribEnd = &rgAttrib[cAttrib];
  2678. for (pAttrib = rgAttrib; pAttrib < pAttribEnd; pAttrib++)
  2679. {
  2680. if (0 == strcmp(pAttrib->pszObjId, szOID_OS_VERSION))
  2681. {
  2682. if (1 != pAttrib->cValue)
  2683. {
  2684. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2685. _JumpError(hr, error, "Attribute Value count != 1");
  2686. }
  2687. hr = pkcsSetOSVersion(prow, pAttrib->rgValue);
  2688. _JumpIfError(hr, error, "pkcsSetOSVersion");
  2689. }
  2690. else
  2691. if (0 == strcmp(pAttrib->pszObjId, szOID_ENROLLMENT_CSP_PROVIDER))
  2692. {
  2693. // Check to see if we have a CSPPROVIDER attribute. We use this in
  2694. // the policy module to determine if xenroll generated the request,
  2695. // so we can behave differently for old xenroll requests (put the
  2696. // UPN in the subject to avoid enrollment loops)
  2697. if (1 != pAttrib->cValue)
  2698. {
  2699. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2700. _JumpError(hr, error, "Attribute Value count != 1");
  2701. }
  2702. hr = pkcsSetCSPProvider(prow, pAttrib->rgValue);
  2703. _JumpIfError(hr, error, "pkcsSetCSPProvider");
  2704. }
  2705. else
  2706. if (0 == strcmp(pAttrib->pszObjId, szOID_ENCRYPTED_KEY_HASH))
  2707. {
  2708. DWORD cb;
  2709. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2710. if (NULL != pResult->pbKeyHashIn || NULL != pBlob)
  2711. {
  2712. _JumpError(hr, error, "Multiple key hashes");
  2713. }
  2714. if (1 != pAttrib->cValue)
  2715. {
  2716. _JumpError(hr, error, "Attribute Value count != 1");
  2717. }
  2718. if (!myDecodeObject(
  2719. X509_ASN_ENCODING,
  2720. X509_OCTET_STRING,
  2721. pAttrib->rgValue[0].pbData,
  2722. pAttrib->rgValue[0].cbData,
  2723. CERTLIB_USE_LOCALALLOC,
  2724. (VOID **) &pBlob,
  2725. &cb))
  2726. {
  2727. hr = myHLastError();
  2728. _JumpError(hr, error, "myDecodeObject");
  2729. }
  2730. pResult->pbKeyHashIn = (BYTE *) LocalAlloc(
  2731. LMEM_FIXED,
  2732. pBlob->cbData);
  2733. if (NULL == pResult->pbKeyHashIn)
  2734. {
  2735. hr = E_OUTOFMEMORY;
  2736. _JumpError(hr, error, "LocalAlloc");
  2737. }
  2738. CopyMemory(pResult->pbKeyHashIn, pBlob->pbData, pBlob->cbData);
  2739. pResult->cbKeyHashIn = pBlob->cbData;
  2740. }
  2741. else
  2742. if (0 == strcmp(pAttrib->pszObjId, szOID_ARCHIVED_KEY_ATTR))
  2743. {
  2744. // Pull encrypted private key out of the attribute for archival.
  2745. //
  2746. // Save request in database without private key now, to keep the
  2747. // error path from saving the request later *with* the key.
  2748. if (NULL != pbRequest)
  2749. {
  2750. hr = pkcsSaveRequestWithoutArchivedKey(
  2751. prow,
  2752. cbRequest,
  2753. pbRequest);
  2754. _PrintIfError(hr, "pkcsSaveRequestWithoutArchivedKey");
  2755. if (S_OK == hr)
  2756. {
  2757. pResult->fRequestSavedWithoutKey = TRUE;
  2758. }
  2759. }
  2760. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2761. if (PSA_DISALLOW_ARCHIVEDKEY & dwDisallowFlags)
  2762. {
  2763. hr = CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL;
  2764. _JumpError(hr, error, "archived key disallowed");
  2765. }
  2766. if (1 != pAttrib->cValue)
  2767. {
  2768. _JumpError(hr, error, "Attribute Value count != 1");
  2769. }
  2770. hr = PKCSArchivePrivateKey(
  2771. prow,
  2772. FALSE,
  2773. FALSE,
  2774. &pAttrib->rgValue[0],
  2775. pResult);
  2776. _JumpIfError(hr, error, "PKCSArchivePrivateKey");
  2777. }
  2778. else
  2779. if (0 == strcmp(pAttrib->pszObjId, szOID_CERT_EXTENSIONS) ||
  2780. 0 == strcmp(pAttrib->pszObjId, szOID_RSA_certExtensions))
  2781. {
  2782. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2783. if (PSA_DISALLOW_EXTENSIONS & dwDisallowFlags)
  2784. {
  2785. _JumpError(hr, error, "extensions disallowed");
  2786. }
  2787. if (1 != pAttrib->cValue)
  2788. {
  2789. _JumpError(hr, error, "Attribute Value count != 1");
  2790. }
  2791. hr = pkcsSetExtensionsFromAttributeBlob(
  2792. prow,
  2793. ExtFlags,
  2794. pAttrib);
  2795. _JumpIfError(hr, error, "pkcsSetExtensionsFromAttributeBlob");
  2796. }
  2797. else
  2798. if (0 == strcmp(pAttrib->pszObjId, szOID_ENROLLMENT_NAME_VALUE_PAIR))
  2799. {
  2800. // Can't apply name value pair attributes to a renewal or CMC
  2801. if (PSA_DISALLOW_NAMEVALUEPAIRS & dwDisallowFlags)
  2802. {
  2803. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2804. _JumpError(hr, error, "name/value pairs disallowed");
  2805. }
  2806. for (i = 0; i < pAttrib->cValue; i++)
  2807. {
  2808. CRYPT_ENROLLMENT_NAME_VALUE_PAIR *pInfo = NULL;
  2809. DWORD cbInfo = 0;
  2810. CRYPT_ATTR_BLOB const *pvalue = &pAttrib->rgValue[i];
  2811. if (!myDecodeNameValuePair(
  2812. X509_ASN_ENCODING,
  2813. pvalue->pbData,
  2814. pvalue->cbData,
  2815. CERTLIB_USE_LOCALALLOC,
  2816. &pInfo,
  2817. &cbInfo))
  2818. {
  2819. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2820. _JumpError(hr, error, "myDecodeNameValuePair");
  2821. // if the attribute name & value are both non-empty ...
  2822. }
  2823. BOOL fEnrollOnBehalfOf = FALSE;
  2824. BOOL fSubjectModifiedT = FALSE;
  2825. hr = pkcsSetAttributeProperty(
  2826. prow,
  2827. pInfo->pwszName,
  2828. pInfo->pwszValue,
  2829. PROPTABLE_REQUEST,
  2830. afSubjectTable,
  2831. &fSubjectModified,
  2832. NULL != pfEnrollOnBehalfOf? &fEnrollOnBehalfOf : NULL);
  2833. if (fSubjectModifiedT)
  2834. {
  2835. fSubjectModified = TRUE;
  2836. }
  2837. if (fEnrollOnBehalfOf)
  2838. {
  2839. *pfEnrollOnBehalfOf = TRUE;
  2840. }
  2841. if (NULL != pInfo)
  2842. {
  2843. LocalFree(pInfo);
  2844. }
  2845. _JumpIfError(hr, error, "pkcsSetAttributeProperty");
  2846. }
  2847. }
  2848. else
  2849. {
  2850. DBGPRINT((
  2851. DBG_SS_CERTSRVI,
  2852. "Skipping authenticated attribute %hs\n",
  2853. pAttrib->pszObjId));
  2854. }
  2855. }
  2856. if (fSubjectModified)
  2857. {
  2858. hr = PKCSSetRequestFlags(prow, FALSE, CR_FLG_SUBJECTUNMODIFIED);
  2859. _JumpIfError(hr, error, "PKCSSetRequestFlags");
  2860. }
  2861. hr = S_OK;
  2862. error:
  2863. if (NULL != pBlob)
  2864. {
  2865. LocalFree(pBlob);
  2866. }
  2867. return(hr);
  2868. }
  2869. HRESULT
  2870. pkcsVerifyCertContext(
  2871. OPTIONAL IN FILETIME const *pft,
  2872. IN BOOL fTimeOnly,
  2873. IN CERT_CONTEXT const *pcc)
  2874. {
  2875. HRESULT hr;
  2876. FILETIME ft;
  2877. if (NULL == pft)
  2878. {
  2879. GetSystemTimeAsFileTime(&ft);
  2880. pft = &ft;
  2881. }
  2882. if (0 > CompareFileTime(pft, &pcc->pCertInfo->NotBefore))
  2883. {
  2884. hr = CERT_E_EXPIRED;
  2885. _JumpError(hr, error, "cert not yet valid");
  2886. }
  2887. if (0 < CompareFileTime(pft, &pcc->pCertInfo->NotAfter))
  2888. {
  2889. hr = CERT_E_EXPIRED;
  2890. _JumpError(hr, error, "cert is expired");
  2891. }
  2892. if (!fTimeOnly)
  2893. {
  2894. hr = myVerifyCertContext(
  2895. pcc, // pCert
  2896. g_dwVerifyCertFlags, // dwFlags
  2897. 0, // cUsageOids
  2898. NULL, // apszUsageOids
  2899. HCCE_LOCAL_MACHINE, // hChainEngine
  2900. NULL, // hAdditionalStore
  2901. NULL); // ppwszMissingIssuer
  2902. _JumpIfError(hr, error, "myVerifyCertContext");
  2903. }
  2904. hr = S_OK;
  2905. error:
  2906. return(hr);
  2907. }
  2908. HRESULT
  2909. pkcsSetValidityPeriod(
  2910. IN ICertDBRow *prow,
  2911. IN CACTX *pCAContext,
  2912. OPTIONAL IN FILETIME const *pftNotBefore,
  2913. OPTIONAL IN FILETIME const *pftNotAfter,
  2914. IN LONG lValidityPeriodCount,
  2915. IN enum ENUM_PERIOD enumValidityPeriod)
  2916. {
  2917. HRESULT hr;
  2918. FILETIME ftNotBefore;
  2919. FILETIME ftNotAfter;
  2920. LONGLONG delta;
  2921. GetSystemTimeAsFileTime(&ftNotBefore);
  2922. hr = pkcsVerifyCertContext(&ftNotBefore, TRUE, pCAContext->pccCA);
  2923. _JumpIfErrorStr(hr, error, "pkcsVerifyCertContext", L"CA cert invalid");
  2924. if (NULL != pftNotBefore && NULL != pftNotAfter)
  2925. {
  2926. ftNotBefore = *pftNotBefore; // Caller already computed tome stamps
  2927. ftNotAfter = *pftNotAfter;
  2928. }
  2929. else
  2930. {
  2931. ftNotAfter = ftNotBefore;
  2932. // Set start date to the current time minus clock skew. But ensure the
  2933. // new cert's start date is not before the CA certificate's start date.
  2934. delta = g_dwClockSkewMinutes * CVT_MINUTES;
  2935. myAddToFileTime(&ftNotBefore, -delta * CVT_BASE);
  2936. if (0 > CompareFileTime(
  2937. &ftNotBefore,
  2938. &pCAContext->pccCA->pCertInfo->NotBefore))
  2939. {
  2940. ftNotBefore = pCAContext->pccCA->pCertInfo->NotBefore;
  2941. }
  2942. // Set the end date to the start date plus the registry-configured
  2943. // validity period. Then clamp the new cert's end date to the CA
  2944. // certificate's end date.
  2945. myMakeExprDateTime(
  2946. &ftNotAfter,
  2947. lValidityPeriodCount,
  2948. enumValidityPeriod);
  2949. if (0 < CompareFileTime(
  2950. &ftNotAfter,
  2951. &pCAContext->pccCA->pCertInfo->NotAfter))
  2952. {
  2953. ftNotAfter = pCAContext->pccCA->pCertInfo->NotAfter;
  2954. if (CERTLOG_VERBOSE <= g_dwLogLevel)
  2955. {
  2956. DWORD dwRequestId;
  2957. WCHAR const *apwsz[2];
  2958. WCHAR awc[cwcDWORDSPRINTF];
  2959. prow->GetRowId(&dwRequestId);
  2960. wsprintf(awc, L"%u", dwRequestId);
  2961. apwsz[0] = g_wszCommonName;
  2962. apwsz[1] = awc;
  2963. LogEvent(
  2964. EVENTLOG_WARNING_TYPE,
  2965. MSG_CLAMPED_BY_CA_CERT,
  2966. ARRAYSIZE(apwsz),
  2967. apwsz);
  2968. }
  2969. }
  2970. }
  2971. hr = prow->SetProperty(
  2972. g_wszPropCertificateNotBeforeDate,
  2973. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  2974. sizeof(ftNotBefore),
  2975. (BYTE *) &ftNotBefore);
  2976. _JumpIfError(hr, error, "pkcsSetValidityPeriod:SetProperty");
  2977. hr = prow->SetProperty(
  2978. g_wszPropCertificateNotAfterDate,
  2979. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  2980. sizeof(ftNotAfter),
  2981. (BYTE *) &ftNotAfter);
  2982. _JumpIfError(hr, error, "pkcsSetValidityPeriod:SetProperty");
  2983. error:
  2984. return(hr);
  2985. }
  2986. HRESULT
  2987. pkcsSetServerExtension(
  2988. IN ICertDBRow *prow,
  2989. IN WCHAR const *pwszObjId,
  2990. IN DWORD cbExt,
  2991. OPTIONAL IN BYTE const *pbExt)
  2992. {
  2993. HRESULT hr;
  2994. BYTE *pbOld = NULL;
  2995. DWORD cbOld;
  2996. DWORD ExtFlags;
  2997. ExtFlags = 0;
  2998. if (NULL == pbExt)
  2999. {
  3000. CSASSERT(0 == cbExt);
  3001. hr = PropGetExtension(
  3002. prow,
  3003. PROPTYPE_BINARY | PROPCALLER_SERVER,
  3004. pwszObjId,
  3005. &ExtFlags,
  3006. &cbOld,
  3007. &pbOld);
  3008. if (S_OK != hr)
  3009. {
  3010. ExtFlags = 0;
  3011. }
  3012. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  3013. {
  3014. ExtFlags |= EXTENSION_DISABLE_FLAG;
  3015. }
  3016. }
  3017. if (NULL != pbExt || (EXTENSION_DISABLE_FLAG & ExtFlags))
  3018. {
  3019. ExtFlags &= ~EXTENSION_ORIGIN_MASK;
  3020. ExtFlags |= EXTENSION_ORIGIN_SERVER;
  3021. hr = PropSetExtension(
  3022. prow,
  3023. PROPTYPE_BINARY | PROPCALLER_SERVER,
  3024. pwszObjId,
  3025. ExtFlags,
  3026. cbExt,
  3027. pbExt);
  3028. _JumpIfError(hr, error, "PropSetExtension");
  3029. }
  3030. hr = S_OK;
  3031. error:
  3032. if (NULL != pbOld)
  3033. {
  3034. LocalFree(pbOld);
  3035. }
  3036. return(hr);
  3037. }
  3038. HRESULT
  3039. pkcsSetPublicKeyProperties(
  3040. IN ICertDBRow *prow,
  3041. IN CERT_PUBLIC_KEY_INFO const *pSubjectPublicKeyInfo)
  3042. {
  3043. HRESULT hr;
  3044. WCHAR *pwszObjId = NULL;
  3045. CERT_EXTENSION ext;
  3046. DWORD ExtFlags;
  3047. DWORD dwCaller;
  3048. DWORD cbitKey;
  3049. ext.Value.pbData = NULL;
  3050. // Public Key size must be a multiple of 8 bits.
  3051. if (0 != pSubjectPublicKeyInfo->PublicKey.cUnusedBits)
  3052. {
  3053. hr = NTE_BAD_KEY;
  3054. _JumpError(hr, error, "PublicKey.cUnusedBits");
  3055. }
  3056. hr = prow->SetProperty(
  3057. g_wszPropCertificateRawPublicKey,
  3058. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3059. pSubjectPublicKeyInfo->PublicKey.cbData,
  3060. pSubjectPublicKeyInfo->PublicKey.pbData);
  3061. _JumpIfError(hr, error, "SetProperty");
  3062. cbitKey = CertGetPublicKeyLength(
  3063. X509_ASN_ENCODING,
  3064. const_cast<CERT_PUBLIC_KEY_INFO *>(pSubjectPublicKeyInfo));
  3065. hr = prow->SetProperty(
  3066. g_wszPropCertificatePublicKeyLength,
  3067. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3068. sizeof(cbitKey),
  3069. (BYTE const *) &cbitKey);
  3070. _JumpIfError(hr, error, "SetProperty(KeyLength)");
  3071. if (!myConvertSzToWsz(
  3072. &pwszObjId,
  3073. pSubjectPublicKeyInfo->Algorithm.pszObjId,
  3074. -1))
  3075. {
  3076. hr = E_OUTOFMEMORY;
  3077. _JumpError(hr, error, "myConvertSzToWsz(AlgObjId)");
  3078. }
  3079. hr = prow->SetProperty(
  3080. g_wszPropCertificatePublicKeyAlgorithm,
  3081. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3082. MAXDWORD,
  3083. (BYTE const *) pwszObjId);
  3084. _JumpIfError(hr, error, "SetProperty");
  3085. if (NULL != pSubjectPublicKeyInfo->Algorithm.Parameters.pbData)
  3086. {
  3087. hr = prow->SetProperty(
  3088. g_wszPropCertificateRawPublicKeyAlgorithmParameters,
  3089. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3090. pSubjectPublicKeyInfo->Algorithm.Parameters.cbData,
  3091. pSubjectPublicKeyInfo->Algorithm.Parameters.pbData);
  3092. _JumpIfError(hr, error, "SetProperty");
  3093. }
  3094. // Subject Key Identifier extension:
  3095. hr = PropGetExtension(
  3096. prow,
  3097. PROPTYPE_BINARY | PROPCALLER_SERVER,
  3098. TEXT(szOID_SUBJECT_KEY_IDENTIFIER),
  3099. &ExtFlags,
  3100. &ext.Value.cbData,
  3101. &ext.Value.pbData);
  3102. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  3103. {
  3104. _JumpIfError(hr, error, "PropGetExtension");
  3105. dwCaller = PROPCALLER_REQUEST;
  3106. ExtFlags &= ~EXTENSION_DISABLE_FLAG;
  3107. }
  3108. else
  3109. {
  3110. dwCaller = PROPCALLER_SERVER;
  3111. ExtFlags = EXTENSION_ORIGIN_SERVER;
  3112. hr = myCreateSubjectKeyIdentifierExtension(
  3113. pSubjectPublicKeyInfo,
  3114. &ext.Value.pbData,
  3115. &ext.Value.cbData);
  3116. _JumpIfError(hr, error, "myCreateSubjectKeyIdentifierExtension");
  3117. }
  3118. hr = PropSetExtension(
  3119. prow,
  3120. PROPTYPE_BINARY | dwCaller,
  3121. TEXT(szOID_SUBJECT_KEY_IDENTIFIER),
  3122. ExtFlags,
  3123. ext.Value.cbData,
  3124. ext.Value.pbData);
  3125. _JumpIfError(hr, error, "PropSetExtension");
  3126. error:
  3127. if (NULL != ext.Value.pbData)
  3128. {
  3129. LocalFree(ext.Value.pbData);
  3130. }
  3131. if (NULL != pwszObjId)
  3132. {
  3133. LocalFree(pwszObjId);
  3134. }
  3135. return(hr);
  3136. }
  3137. HRESULT
  3138. pkcsParsePKCS10Request(
  3139. IN DWORD DBGCODE(dwFlags),
  3140. IN ICertDBRow *prow,
  3141. IN DWORD cbRequest,
  3142. IN BYTE const *pbRequest,
  3143. IN CERT_CONTEXT const *pSigningAuthority,
  3144. OUT BOOL *pfRenewal,
  3145. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  3146. {
  3147. HRESULT hr;
  3148. DWORD cbCertInfo;
  3149. CERT_REQUEST_INFO *pRequestInfo = NULL;
  3150. CRYPT_ATTRIBUTE const *pAttrib;
  3151. CRYPT_ATTRIBUTE const *pAttribEnd;
  3152. CRYPT_ATTR_BLOB *pAttrBlob;
  3153. CERT_CONTEXT const *pOldCert = NULL;
  3154. DWORD dwRequestFlags = 0;
  3155. BOOL fRenewal = FALSE;
  3156. BOOL fSubjectNameSet;
  3157. BOOL fReorderLikeRDNs;
  3158. CSASSERT(CR_IN_PKCS10 == (CR_IN_FORMATMASK & dwFlags));
  3159. CSASSERT(
  3160. CR_IN_PKCS10 == (CR_IN_FORMATMASK & pResult->dwFlagsTop) ||
  3161. CR_IN_PKCS7 == (CR_IN_FORMATMASK & pResult->dwFlagsTop) ||
  3162. CR_IN_CMC == (CR_IN_FORMATMASK & pResult->dwFlagsTop));
  3163. if (!myDecodeObject(
  3164. X509_ASN_ENCODING,
  3165. X509_CERT_REQUEST_TO_BE_SIGNED,
  3166. pbRequest,
  3167. cbRequest,
  3168. CERTLIB_USE_LOCALALLOC,
  3169. (VOID **) &pRequestInfo,
  3170. &cbCertInfo))
  3171. {
  3172. hr = myHLastError();
  3173. _JumpError(hr, error, "myDecodeObject");
  3174. }
  3175. // verify with the public key passed in the PKCS10
  3176. if (!CryptVerifyCertificateSignature(
  3177. NULL,
  3178. X509_ASN_ENCODING,
  3179. const_cast<BYTE *>(pbRequest),
  3180. cbRequest,
  3181. &pRequestInfo->SubjectPublicKeyInfo))
  3182. {
  3183. hr = myHLastError();
  3184. _PrintError3(
  3185. hr,
  3186. "CryptVerifyCertificateSignature",
  3187. E_INVALIDARG,
  3188. CRYPT_E_ASN1_BADTAG);
  3189. if (CR_IN_CMC == (CR_IN_FORMATMASK & pResult->dwFlagsTop))
  3190. {
  3191. if (E_INVALIDARG == hr) // NULL signature?
  3192. {
  3193. CRYPT_DATA_BLOB Blob;
  3194. Blob.cbData = cbRequest;
  3195. Blob.pbData = const_cast<BYTE *>(pbRequest);
  3196. if (!CryptVerifyCertificateSignatureEx(
  3197. NULL, // hCryptProv
  3198. X509_ASN_ENCODING,
  3199. CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB,
  3200. &Blob,
  3201. CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL,
  3202. NULL, // pvIssuer
  3203. 0, // dwFlags
  3204. NULL)) // pvReserved
  3205. {
  3206. HRESULT hr2 = myHLastError();
  3207. _PrintError(hr2, "CryptVerifyCertificateSignatureEx");
  3208. pResult->dwResultFlags |= CRCF_SIGNATUREERROR;
  3209. }
  3210. else
  3211. {
  3212. hr = S_OK;
  3213. }
  3214. }
  3215. }
  3216. if (E_INVALIDARG == hr || CRYPT_E_ASN1_BADTAG == hr)
  3217. {
  3218. hr = NTE_BAD_SIGNATURE;
  3219. }
  3220. _JumpIfError(hr, error, "CryptVerifyCertificateSignature");
  3221. }
  3222. // handle renewal certificate extensions BEFORE processing the rest of
  3223. // the request attributes (which may also contain extensions)
  3224. pAttribEnd = &pRequestInfo->rgAttribute[pRequestInfo->cAttribute];
  3225. for (pAttrib = pRequestInfo->rgAttribute; pAttrib < pAttribEnd; pAttrib++)
  3226. {
  3227. if (0 == strcmp(pAttrib->pszObjId, szOID_RENEWAL_CERTIFICATE))
  3228. {
  3229. hr = CERTSRV_E_BAD_RENEWAL_CERT_ATTRIBUTE;
  3230. if (fRenewal)
  3231. {
  3232. _JumpError(hr, error, "Multiple renewal certs!");
  3233. }
  3234. if (CR_IN_PKCS7 != (CR_IN_FORMATMASK & pResult->dwFlagsTop) &&
  3235. CR_IN_CMC != (CR_IN_FORMATMASK & pResult->dwFlagsTop))
  3236. {
  3237. _JumpError(hr, error, "renewal cert must be in PKCS7 or CMC");
  3238. }
  3239. if (1 != pAttrib->cValue)
  3240. {
  3241. _JumpError(hr, error, "Attribute Value count != 1");
  3242. }
  3243. pAttrBlob = pAttrib->rgValue;
  3244. pOldCert = CertCreateCertificateContext(
  3245. X509_ASN_ENCODING,
  3246. pAttrBlob->pbData,
  3247. pAttrBlob->cbData);
  3248. if (NULL == pOldCert)
  3249. {
  3250. _JumpError(hr, error, "CertCreateCertificateContext");
  3251. }
  3252. // The old raw certificate, and the signer of the PKCS7 must match!
  3253. if (NULL == pSigningAuthority ||
  3254. !myAreCertContextBlobsSame(pSigningAuthority, pOldCert))
  3255. {
  3256. _JumpError(hr, error, "myAreCertContextBlobsSame");
  3257. }
  3258. // This is a renewal, mark it as such.
  3259. hr = prow->SetProperty(
  3260. g_wszPropRequestRawOldCertificate,
  3261. PROPTYPE_BINARY |
  3262. PROPCALLER_SERVER |
  3263. PROPTABLE_REQUEST,
  3264. pAttrBlob->cbData,
  3265. pAttrBlob->pbData);
  3266. _JumpIfError(hr, error, "SetProperty(old cert)");
  3267. hr = pkcsSetExtensions(
  3268. prow,
  3269. EXTENSION_ORIGIN_RENEWALCERT | EXTENSION_DISABLE_FLAG,
  3270. pOldCert->pCertInfo->rgExtension,
  3271. pOldCert->pCertInfo->cExtension);
  3272. _JumpIfError(hr, error, "pkcsSetExtensions(old cert)");
  3273. fRenewal = TRUE;
  3274. if (CertComparePublicKeyInfo(
  3275. X509_ASN_ENCODING,
  3276. &pRequestInfo->SubjectPublicKeyInfo,
  3277. &pOldCert->pCertInfo->SubjectPublicKeyInfo))
  3278. {
  3279. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  3280. DWORD cbHash;
  3281. cbHash = sizeof(abHash);
  3282. if (!CertGetCertificateContextProperty(
  3283. pOldCert,
  3284. CERT_SHA1_HASH_PROP_ID,
  3285. abHash,
  3286. &cbHash))
  3287. {
  3288. hr = myHLastError();
  3289. _JumpError(hr, error, "CertGetCertificateContextProperty");
  3290. }
  3291. hr = MultiByteIntegerToBstr(
  3292. TRUE,
  3293. cbHash,
  3294. abHash,
  3295. &pResult->strRenewalCertHash);
  3296. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  3297. }
  3298. }
  3299. }
  3300. // handle certificate extensions/known atributes
  3301. hr = pkcsSetAttributes(
  3302. prow,
  3303. EXTENSION_ORIGIN_REQUEST,
  3304. PSA_DISALLOW_ARCHIVEDKEY,
  3305. pRequestInfo->rgAttribute,
  3306. pRequestInfo->cAttribute,
  3307. 0,
  3308. NULL,
  3309. NULL,
  3310. pResult);
  3311. _JumpIfError(hr, error, "pkcsSetAttributes(PKCS10)");
  3312. // If an XEnroll request, reverse the order of similar adjacent RDNs
  3313. fReorderLikeRDNs = FALSE;
  3314. if (0 == (CRLF_DISABLE_RDN_REORDER & g_dwCRLFlags))
  3315. {
  3316. DWORD cb;
  3317. hr = prow->GetProperty(
  3318. g_wszPropRequestOSVersion,
  3319. PROPTYPE_STRING |
  3320. PROPCALLER_SERVER |
  3321. PROPTABLE_ATTRIBUTE,
  3322. NULL,
  3323. &cb,
  3324. NULL);
  3325. _PrintIfError(hr, "GetProperty");
  3326. if (S_OK == hr && 0 != cb)
  3327. {
  3328. fReorderLikeRDNs = TRUE;
  3329. }
  3330. }
  3331. hr = pkcsSetRequestNameInfo(
  3332. prow,
  3333. &pRequestInfo->Subject,
  3334. NULL, // pwszCNSuffix
  3335. fReorderLikeRDNs,
  3336. &dwRequestFlags,
  3337. &fSubjectNameSet);
  3338. _JumpIfError(hr, error, "pkcsSetRequestNameInfo");
  3339. if (fSubjectNameSet)
  3340. {
  3341. dwRequestFlags |= CR_FLG_SUBJECTUNMODIFIED;
  3342. }
  3343. if (fRenewal)
  3344. {
  3345. if (!fSubjectNameSet)
  3346. {
  3347. CSASSERT(NULL != pOldCert);
  3348. CSASSERT(NULL != pOldCert->pCertInfo);
  3349. hr = pkcsSetRequestNameInfo(
  3350. prow,
  3351. &pOldCert->pCertInfo->Subject,
  3352. NULL, // pwszCNSuffix
  3353. FALSE, // fReorderLikeRDNs
  3354. &dwRequestFlags,
  3355. &fSubjectNameSet);
  3356. _JumpIfError(hr, error, "pkcsSetRequestNameInfo");
  3357. }
  3358. dwRequestFlags |= CR_FLG_RENEWAL;
  3359. }
  3360. hr = prow->SetProperty(
  3361. g_wszPropRequestFlags,
  3362. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3363. sizeof(dwRequestFlags),
  3364. (BYTE const *) &dwRequestFlags);
  3365. _JumpIfError(hr, error, "SetProperty(RequestFlags)");
  3366. hr = pkcsSetPublicKeyProperties(prow, &pRequestInfo->SubjectPublicKeyInfo);
  3367. _JumpIfError(hr, error, "pkcsSetPublicKeyProperties");
  3368. hr = PKCSSetServerProperties(
  3369. prow,
  3370. NULL, // use default signing context
  3371. NULL, // pftNotBefore
  3372. NULL, // pftNotAfter
  3373. g_lValidityPeriodCount,
  3374. g_enumValidityPeriod);
  3375. _JumpIfError(hr, error, "PKCSSetServerProperties");
  3376. if (NULL != pfRenewal)
  3377. {
  3378. *pfRenewal = fRenewal;
  3379. }
  3380. error:
  3381. if (NULL != pOldCert)
  3382. {
  3383. CertFreeCertificateContext(pOldCert);
  3384. }
  3385. if (NULL != pRequestInfo)
  3386. {
  3387. LocalFree(pRequestInfo);
  3388. }
  3389. return(hr);
  3390. }
  3391. HRESULT
  3392. PKCSVerifyChallengeString(
  3393. IN ICertDBRow *prow)
  3394. {
  3395. HRESULT hr;
  3396. DWORD cb;
  3397. WCHAR wszPassed[MAX_PATH];
  3398. WCHAR wszExpected[MAX_PATH];
  3399. cb = sizeof(wszExpected);
  3400. hr = prow->GetProperty(
  3401. g_wszPropExpectedChallenge,
  3402. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_ATTRIBUTE,
  3403. NULL,
  3404. &cb,
  3405. (BYTE *) wszExpected);
  3406. if (S_OK != hr || L'\0' == wszExpected[0])
  3407. {
  3408. hr = S_OK; // no challenge expected
  3409. goto error;
  3410. }
  3411. cb = sizeof(wszPassed);
  3412. hr = prow->GetProperty(
  3413. g_wszPropChallenge,
  3414. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_ATTRIBUTE,
  3415. NULL,
  3416. &cb,
  3417. (BYTE *) wszPassed);
  3418. if (S_OK != hr)
  3419. {
  3420. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD);
  3421. _JumpError(hr, error, "Missing Challenge String");
  3422. }
  3423. if (0 != wcscmp(wszExpected, wszPassed))
  3424. {
  3425. CONSOLEPRINT2((
  3426. DBG_SS_CERTSRV,
  3427. "Challenge: passed(%ws) expected(%ws)\n",
  3428. wszPassed,
  3429. wszExpected));
  3430. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD);
  3431. _JumpError(hr, error, "Invalid Challenge String");
  3432. }
  3433. hr = prow->SetProperty(
  3434. g_wszPropExpectedChallenge,
  3435. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_ATTRIBUTE,
  3436. 0,
  3437. NULL);
  3438. _PrintIfError(hr, "SetProperty");
  3439. hr = S_OK;
  3440. error:
  3441. return(hr);
  3442. }
  3443. HRESULT
  3444. pkcsParseKeyGenRequest(
  3445. IN DWORD DBGCODE(dwFlags),
  3446. IN ICertDBRow *prow,
  3447. IN DWORD cbRequest,
  3448. IN BYTE const *pbRequest,
  3449. IN OUT CERTSRV_RESULT_CONTEXT * /* pResult */ )
  3450. {
  3451. HRESULT hr;
  3452. DWORD cbKeyGenRequest;
  3453. CERT_KEYGEN_REQUEST_INFO *pKeyGenRequest = NULL;
  3454. DWORD dwRequestFlags;
  3455. CSASSERT(CR_IN_KEYGEN == (CR_IN_FORMATMASK & dwFlags));
  3456. // Decode KeyGenRequest structure
  3457. if (!myDecodeKeyGenRequest(
  3458. pbRequest,
  3459. cbRequest,
  3460. CERTLIB_USE_LOCALALLOC,
  3461. &pKeyGenRequest,
  3462. &cbKeyGenRequest))
  3463. {
  3464. hr = myHLastError();
  3465. _JumpError(hr, error, "myDecodeKeyGen");
  3466. }
  3467. // verify with the public key passed in the PKCS10
  3468. if (!CryptVerifyCertificateSignature(
  3469. NULL,
  3470. X509_ASN_ENCODING,
  3471. (BYTE *) pbRequest,
  3472. cbRequest,
  3473. &pKeyGenRequest->SubjectPublicKeyInfo))
  3474. {
  3475. hr = myHLastError();
  3476. _JumpError(hr, error, "CryptVerifyCertificateSignature");
  3477. }
  3478. hr = pkcsSetPublicKeyProperties(
  3479. prow,
  3480. &pKeyGenRequest->SubjectPublicKeyInfo);
  3481. _JumpIfError(hr, error, "pkcsSetPublicKeyProperties");
  3482. hr = PKCSSetServerProperties(
  3483. prow,
  3484. NULL, // use default signing context
  3485. NULL, // pftNotBefore
  3486. NULL, // pftNotAfter
  3487. g_lValidityPeriodCount,
  3488. g_enumValidityPeriod);
  3489. _JumpIfError(hr, error, "PKCSSetServerProperties");
  3490. hr = prow->SetProperty(
  3491. g_wszPropExpectedChallenge,
  3492. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_ATTRIBUTE,
  3493. MAXDWORD,
  3494. (BYTE *) pKeyGenRequest->pwszChallengeString);
  3495. _JumpIfError(hr, error, "SetProperty");
  3496. dwRequestFlags = 0;
  3497. switch (ENUM_TELETEX_MASK & g_fForceTeletex)
  3498. {
  3499. case ENUM_TELETEX_ON:
  3500. case ENUM_TELETEX_AUTO:
  3501. dwRequestFlags |= CR_FLG_FORCETELETEX;
  3502. break;
  3503. }
  3504. if (ENUM_TELETEX_UTF8 & g_fForceTeletex)
  3505. {
  3506. dwRequestFlags |= CR_FLG_FORCEUTF8;
  3507. }
  3508. hr = prow->SetProperty(
  3509. g_wszPropRequestFlags,
  3510. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3511. sizeof(dwRequestFlags),
  3512. (BYTE const *) &dwRequestFlags);
  3513. _JumpIfError(hr, error, "SetProperty(RequestFlags)");
  3514. error:
  3515. if (NULL != pKeyGenRequest)
  3516. {
  3517. LocalFree(pKeyGenRequest);
  3518. }
  3519. return(hr);
  3520. }
  3521. // Validate the certificate:
  3522. // Signed by CA Certificate
  3523. // issuer name == CA Certificate subject
  3524. // NotBefore >= CA Certificate NotBefore
  3525. // NotAfter <= CA Certificate NotAfter
  3526. // if KEYID2 issuer KeyId set: == CA Certificate KeyId
  3527. // if KEYID2 issuer Name set: == CA Certificate Issuer
  3528. // if KEYID2 issuer Serial Number set: == CA Certificate serial number
  3529. HRESULT
  3530. pkcsVerifyCertIssuer(
  3531. IN CERT_CONTEXT const *pCert,
  3532. IN CACTX const *pCAContext)
  3533. {
  3534. HRESULT hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3535. CERT_INFO const *pCertInfo = pCert->pCertInfo;
  3536. CERT_INFO const *pCACertInfo;
  3537. CERT_EXTENSION const *pExt;
  3538. CERT_EXTENSION const *pExtEnd;
  3539. CERT_AUTHORITY_KEY_ID2_INFO *pkeyAuth = NULL;
  3540. DWORD cbkeyAuth;
  3541. CERT_NAME_BLOB const *pName;
  3542. CSASSERT(NULL != pCAContext);
  3543. if (NULL == pCAContext->pccCA)
  3544. {
  3545. hr = NTE_BAD_SIGNATURE;
  3546. _JumpError2(hr, error, "pCAContext->pccCA", hr);
  3547. }
  3548. pCACertInfo = pCAContext->pccCA->pCertInfo;
  3549. // verify with the CA cert's public key
  3550. if (!CryptVerifyCertificateSignature(
  3551. NULL,
  3552. X509_ASN_ENCODING,
  3553. pCert->pbCertEncoded,
  3554. pCert->cbCertEncoded,
  3555. const_cast<CERT_PUBLIC_KEY_INFO *>(
  3556. &pCACertInfo->SubjectPublicKeyInfo)))
  3557. {
  3558. hr = myHLastError();
  3559. _JumpError2(hr, error, "CryptVerifyCertificateSignature", hr);
  3560. }
  3561. // Check Issuer name:
  3562. if (!myAreBlobsSame(
  3563. pCACertInfo->Subject.pbData,
  3564. pCACertInfo->Subject.cbData,
  3565. pCertInfo->Issuer.pbData,
  3566. pCertInfo->Issuer.cbData))
  3567. {
  3568. _JumpError(hr, error, "Bad Issuer Name");
  3569. }
  3570. // Check that NotBefore >= CA Certificate NotBefore
  3571. if (0 > CompareFileTime(&pCertInfo->NotBefore, &pCACertInfo->NotBefore))
  3572. {
  3573. _JumpError(hr, error, "NotBefore too early");
  3574. }
  3575. // Check that NotAfter <= CA Certificate NotAfter
  3576. if (0 < CompareFileTime(&pCertInfo->NotAfter, &pCACertInfo->NotAfter))
  3577. {
  3578. _JumpError(hr, error, "NotAfter too late");
  3579. }
  3580. pExtEnd = &pCert->pCertInfo->rgExtension[pCert->pCertInfo->cExtension];
  3581. for (pExt = pCert->pCertInfo->rgExtension; pExt < pExtEnd; pExt++)
  3582. {
  3583. if (0 == strcmp(pExt->pszObjId, szOID_AUTHORITY_KEY_IDENTIFIER2))
  3584. {
  3585. if (!myDecodeObject(
  3586. X509_ASN_ENCODING,
  3587. X509_AUTHORITY_KEY_ID2,
  3588. pExt->Value.pbData,
  3589. pExt->Value.cbData,
  3590. CERTLIB_USE_LOCALALLOC,
  3591. (VOID **) &pkeyAuth,
  3592. &cbkeyAuth))
  3593. {
  3594. hr = myHLastError();
  3595. _JumpError(hr, error, "myDecodeObject");
  3596. }
  3597. // Check Issuer KeyId:
  3598. if (NULL != pCAContext->IssuerKeyId.pbData &&
  3599. NULL != pkeyAuth->KeyId.pbData &&
  3600. !myAreBlobsSame(
  3601. pCAContext->IssuerKeyId.pbData,
  3602. pCAContext->IssuerKeyId.cbData,
  3603. pkeyAuth->KeyId.pbData,
  3604. pkeyAuth->KeyId.cbData))
  3605. {
  3606. _JumpError(hr, error, "Bad AuthorityKeyId KeyId");
  3607. }
  3608. // Check Issuer name:
  3609. if (1 == pkeyAuth->AuthorityCertIssuer.cAltEntry &&
  3610. CERT_ALT_NAME_DIRECTORY_NAME ==
  3611. pkeyAuth->AuthorityCertIssuer.rgAltEntry[0].dwAltNameChoice)
  3612. {
  3613. pName = &pkeyAuth->AuthorityCertIssuer.rgAltEntry[0].DirectoryName;
  3614. if (NULL != pName->pbData &&
  3615. !myAreBlobsSame(
  3616. pCACertInfo->Issuer.pbData,
  3617. pCACertInfo->Issuer.cbData,
  3618. pName->pbData,
  3619. pName->cbData))
  3620. {
  3621. _JumpError(hr, error, "Bad AuthorityKeyId Issuer Name");
  3622. }
  3623. }
  3624. // Check Issuer SerialNumber:
  3625. if (NULL != pkeyAuth->AuthorityCertSerialNumber.pbData &&
  3626. !myAreSerialNumberBlobsSame(
  3627. &pCACertInfo->SerialNumber,
  3628. &pkeyAuth->AuthorityCertSerialNumber))
  3629. {
  3630. _JumpError(hr, error, "Bad AuthorityKeyId Issuer Serial Number");
  3631. }
  3632. break;
  3633. }
  3634. }
  3635. hr = S_OK;
  3636. error:
  3637. if (NULL != pkeyAuth)
  3638. {
  3639. LocalFree(pkeyAuth);
  3640. }
  3641. return(hr);
  3642. }
  3643. HRESULT
  3644. PKCSVerifyIssuedCertificate(
  3645. IN CERT_CONTEXT const *pCert,
  3646. OUT CACTX **ppCAContext)
  3647. {
  3648. HRESULT hr;
  3649. DWORD i;
  3650. CACTX *pCAContext;
  3651. *ppCAContext = NULL;
  3652. CSASSERT(0 != g_cCACerts);
  3653. hr = S_OK;
  3654. for (i = g_cCACerts; i > 0; i--)
  3655. {
  3656. pCAContext = &g_aCAContext[i - 1];
  3657. hr = pkcsVerifyCertIssuer(pCert, pCAContext);
  3658. if (S_OK == hr)
  3659. {
  3660. *ppCAContext = pCAContext;
  3661. break;
  3662. }
  3663. if (HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY) != hr)
  3664. {
  3665. _PrintError2(hr, "pkcsVerifyCertIssuer", NTE_BAD_SIGNATURE);
  3666. }
  3667. }
  3668. //error:
  3669. return(hr);
  3670. }
  3671. HRESULT
  3672. pkcsSetCertHash(
  3673. IN ICertDBRow *prow,
  3674. IN CERT_CONTEXT const *pcc)
  3675. {
  3676. HRESULT hr;
  3677. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  3678. DWORD cbHash;
  3679. BSTR strHash = NULL;
  3680. cbHash = sizeof(abHash);
  3681. if (!CertGetCertificateContextProperty(
  3682. pcc,
  3683. CERT_SHA1_HASH_PROP_ID,
  3684. abHash,
  3685. &cbHash))
  3686. {
  3687. hr = myHLastError();
  3688. _JumpError(hr, error, "CertGetCertificateContextProperty");
  3689. }
  3690. hr = MultiByteIntegerToBstr(TRUE, cbHash, abHash, &strHash);
  3691. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  3692. hr = prow->SetProperty(
  3693. g_wszPropCertificateHash,
  3694. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3695. MAXDWORD,
  3696. (BYTE const *) strHash);
  3697. _JumpIfError(hr, error, "SetProperty");
  3698. error:
  3699. if (NULL != strHash)
  3700. {
  3701. SysFreeString(strHash);
  3702. }
  3703. return(hr);
  3704. }
  3705. HRESULT
  3706. pkcsSetCertAndKeyHashes(
  3707. IN ICertDBRow *prow,
  3708. IN CERT_CONTEXT const *pcc)
  3709. {
  3710. HRESULT hr;
  3711. BYTE *pbHash = NULL;
  3712. DWORD cbHash;
  3713. BSTR strHash = NULL;
  3714. hr = pkcsSetCertHash(prow, pcc);
  3715. _JumpIfError(hr, error, "pkcsSetCertHash");
  3716. hr = myGetPublicKeyHash(
  3717. pcc->pCertInfo,
  3718. &pcc->pCertInfo->SubjectPublicKeyInfo,
  3719. &pbHash,
  3720. &cbHash);
  3721. _JumpIfError(hr, error, "myGetPublicKeyHash");
  3722. hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strHash);
  3723. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  3724. hr = prow->SetProperty(
  3725. g_wszPropCertificateSubjectKeyIdentifier,
  3726. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3727. MAXDWORD,
  3728. (BYTE const *) strHash);
  3729. _JumpIfError(hr, error, "SetProperty");
  3730. error:
  3731. if (NULL != strHash)
  3732. {
  3733. SysFreeString(strHash);
  3734. }
  3735. if (NULL != pbHash)
  3736. {
  3737. LocalFree(pbHash);
  3738. }
  3739. return(hr);
  3740. }
  3741. HRESULT
  3742. pkcsSetTemplateProperty(
  3743. IN ICertDBRow *prow,
  3744. IN CERT_CONTEXT const *pCert)
  3745. {
  3746. HRESULT hr;
  3747. CERT_EXTENSION const *pExt;
  3748. CERT_NAME_VALUE *pName = NULL;
  3749. CERT_TEMPLATE_EXT *pTemplate = NULL;
  3750. DWORD cb;
  3751. WCHAR const *pwszTemplate = NULL;
  3752. WCHAR *pwszObjId = NULL;
  3753. // look for v2 template extension
  3754. pExt = CertFindExtension(
  3755. szOID_CERTIFICATE_TEMPLATE,
  3756. pCert->pCertInfo->cExtension,
  3757. pCert->pCertInfo->rgExtension);
  3758. if (NULL != pExt)
  3759. {
  3760. if (!myDecodeObject(
  3761. X509_ASN_ENCODING,
  3762. X509_CERTIFICATE_TEMPLATE,
  3763. pExt->Value.pbData,
  3764. pExt->Value.cbData,
  3765. CERTLIB_USE_LOCALALLOC,
  3766. (VOID **) &pTemplate,
  3767. &cb))
  3768. {
  3769. hr = myHLastError();
  3770. _JumpError(hr, error, "Policy:myDecodeObject");
  3771. }
  3772. if (!myConvertSzToWsz(&pwszObjId, pTemplate->pszObjId, -1))
  3773. {
  3774. hr = E_OUTOFMEMORY;
  3775. _JumpError(hr, error, "Policy:myConvertSzToBstr");
  3776. }
  3777. pwszTemplate = pwszObjId;
  3778. }
  3779. else
  3780. {
  3781. // look for v1 template extension
  3782. pExt = CertFindExtension(
  3783. szOID_ENROLL_CERTTYPE_EXTENSION,
  3784. pCert->pCertInfo->cExtension,
  3785. pCert->pCertInfo->rgExtension);
  3786. if (NULL != pExt)
  3787. {
  3788. if (!myDecodeObject(
  3789. X509_ASN_ENCODING,
  3790. X509_UNICODE_ANY_STRING,
  3791. pExt->Value.pbData,
  3792. pExt->Value.cbData,
  3793. CERTLIB_USE_LOCALALLOC,
  3794. (VOID **) &pName,
  3795. &cb))
  3796. {
  3797. hr = myHLastError();
  3798. _JumpError(hr, error, "Policy:myDecodeObject");
  3799. }
  3800. pwszTemplate = (WCHAR const *) pName->Value.pbData;
  3801. }
  3802. }
  3803. if (NULL != pwszTemplate)
  3804. {
  3805. hr = prow->SetProperty(
  3806. wszPROPCERTIFICATETEMPLATE,
  3807. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3808. MAXDWORD,
  3809. (BYTE const *) pwszTemplate);
  3810. _JumpIfError(hr, error, "SetProperty");
  3811. }
  3812. hr = S_OK;
  3813. error:
  3814. if (NULL != pName)
  3815. {
  3816. LocalFree(pName);
  3817. }
  3818. if (NULL != pTemplate)
  3819. {
  3820. LocalFree(pTemplate);
  3821. }
  3822. if (NULL != pwszObjId)
  3823. {
  3824. LocalFree(pwszObjId);
  3825. }
  3826. return(hr);
  3827. }
  3828. HRESULT
  3829. pkcsSetRevocationFields(
  3830. IN ICertDBRow *prow)
  3831. {
  3832. HRESULT hr;
  3833. DWORD DBDisposition;
  3834. DWORD Reason;
  3835. WCHAR *pwszMachineRequesterName = NULL;
  3836. WCHAR const *pwszDisposition = NULL;
  3837. DBDisposition = DB_DISP_REVOKED;
  3838. hr = prow->SetProperty(
  3839. g_wszPropRequestDisposition,
  3840. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3841. sizeof(DBDisposition),
  3842. (BYTE *) &DBDisposition);
  3843. _JumpIfError(hr, error, "SetProperty");
  3844. hr = PropSetRequestTimeProperty(prow, g_wszPropRequestRevokedWhen);
  3845. _JumpIfError(hr, error, "PropSetRequestTimeProperty");
  3846. hr = PropSetRequestTimeProperty(
  3847. prow,
  3848. g_wszPropRequestRevokedEffectiveWhen);
  3849. _JumpIfError(hr, error, "PropSetRequestTimeProperty");
  3850. Reason = CRL_REASON_UNSPECIFIED;
  3851. hr = prow->SetProperty(
  3852. g_wszPropRequestRevokedReason,
  3853. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3854. sizeof(Reason),
  3855. (BYTE const *) &Reason);
  3856. _JumpIfError(hr, error, "SetProperty");
  3857. hr = myGetComputerObjectName(NameSamCompatible, &pwszMachineRequesterName);
  3858. if (S_OK != hr)
  3859. {
  3860. _PrintError(hr, "myGetComputerObjectName");
  3861. hr = myGetUserNameEx(NameSamCompatible, &pwszMachineRequesterName);
  3862. _JumpIfError(hr, error, "myGetUserNameEx");
  3863. }
  3864. pwszDisposition = CoreBuildDispositionString(
  3865. g_pwszRevokedBy,
  3866. pwszMachineRequesterName,
  3867. NULL,
  3868. NULL,
  3869. NULL,
  3870. S_OK,
  3871. FALSE);
  3872. if (NULL == pwszDisposition)
  3873. {
  3874. pwszDisposition = g_pwszRevokedBy;
  3875. }
  3876. hr = prow->SetProperty(
  3877. g_wszPropRequestDispositionMessage,
  3878. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3879. MAXDWORD,
  3880. (BYTE const *) pwszDisposition);
  3881. _JumpIfError(hr, error, "SetProperty");
  3882. error:
  3883. if (NULL != pwszMachineRequesterName)
  3884. {
  3885. LocalFree(pwszMachineRequesterName);
  3886. }
  3887. if (NULL != pwszDisposition && pwszDisposition != g_pwszRevokedBy)
  3888. {
  3889. LocalFree(const_cast<WCHAR *>(pwszDisposition));
  3890. }
  3891. return(hr);
  3892. }
  3893. HRESULT
  3894. PKCSParseImportedCertificate(
  3895. IN ICertDBRow *prow,
  3896. IN BOOL fCrossCert, // else random imported cert
  3897. IN DWORD Disposition,
  3898. OPTIONAL IN CACTX const *pCAContext,
  3899. IN CERT_CONTEXT const *pCert)
  3900. {
  3901. HRESULT hr;
  3902. CERT_INFO const *pCertInfo = pCert->pCertInfo;
  3903. DWORD dwRequestFlags = 0;
  3904. BOOL fSubjectNameSet;
  3905. HRESULT ErrCode = S_OK;
  3906. BSTR strSerialNumber = NULL;
  3907. // set raw cert property in the db
  3908. hr = prow->SetProperty(
  3909. g_wszPropRawCertificate,
  3910. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3911. pCert->cbCertEncoded,
  3912. pCert->pbCertEncoded);
  3913. _JumpIfError(hr, error, "SetProperty");
  3914. // set extensions
  3915. hr = pkcsSetExtensions(
  3916. prow,
  3917. EXTENSION_ORIGIN_IMPORTEDCERT,
  3918. pCertInfo->rgExtension,
  3919. pCertInfo->cExtension);
  3920. _JumpIfError(hr, error, "pkcsSetExtensions");
  3921. // set request name info
  3922. hr = pkcsSetRequestNameInfo(
  3923. prow,
  3924. &pCertInfo->Subject,
  3925. NULL, // pwszCNSuffix
  3926. FALSE, // fReorderLikeRDNs
  3927. &dwRequestFlags,
  3928. &fSubjectNameSet);
  3929. _JumpIfError(hr, error, "pkcsSetRequestNameInfo");
  3930. hr = pkcsSetPublicKeyProperties(prow, &pCertInfo->SubjectPublicKeyInfo);
  3931. _JumpIfError(hr, error, "pkcsSetPublicKeyProperties");
  3932. hr = prow->CopyRequestNames();
  3933. _JumpIfError(hr, error, "CopyRequestNames");
  3934. hr = pkcsSetCertAndKeyHashes(prow, pCert);
  3935. _JumpIfError(hr, error, "pkcsSetCertAndKeyHashes");
  3936. hr = prow->SetProperty(
  3937. g_wszPropCertificateNotBeforeDate,
  3938. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3939. sizeof(pCertInfo->NotBefore),
  3940. (BYTE *) &pCertInfo->NotBefore);
  3941. _JumpIfError(hr, error, "SetProperty");
  3942. hr = prow->SetProperty(
  3943. g_wszPropCertificateNotAfterDate,
  3944. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3945. sizeof(pCertInfo->NotAfter),
  3946. (BYTE *) &pCertInfo->NotAfter);
  3947. _JumpIfError(hr, error, "SetProperty");
  3948. hr = prow->SetProperty(
  3949. g_wszPropSubjectRawName,
  3950. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3951. pCertInfo->Subject.cbData,
  3952. pCertInfo->Subject.pbData);
  3953. _JumpIfError(hr, error, "SetProperty");
  3954. // set distinguished name
  3955. pkcsSetDistinguishedName(prow, PROPTABLE_CERTIFICATE, &pCertInfo->Subject);
  3956. if (fCrossCert)
  3957. {
  3958. dwRequestFlags |= CR_FLG_CACROSSCERT;
  3959. }
  3960. hr = prow->SetProperty(
  3961. g_wszPropRequestFlags,
  3962. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3963. sizeof(dwRequestFlags),
  3964. (BYTE const *) &dwRequestFlags);
  3965. _JumpIfError(hr, error, "SetProperty(RequestFlags)");
  3966. // set disposition issued
  3967. hr = prow->SetProperty(
  3968. g_wszPropRequestDisposition,
  3969. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3970. sizeof(Disposition),
  3971. (BYTE const *) &Disposition);
  3972. _JumpIfError(hr, error, "SetProperty(disposition)");
  3973. if (DB_DISP_REVOKED == Disposition)
  3974. {
  3975. hr = pkcsSetRevocationFields(prow);
  3976. _JumpIfError(hr, error, "pkcsSetRevocationFields");
  3977. }
  3978. // set disposition status code
  3979. hr = prow->SetProperty(
  3980. g_wszPropRequestStatusCode,
  3981. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3982. sizeof(ErrCode),
  3983. (BYTE const *) &ErrCode);
  3984. _JumpIfError(hr, error, "SetProperty(status code)");
  3985. if (NULL != pCAContext)
  3986. {
  3987. hr = prow->SetProperty(
  3988. g_wszPropCertificateIssuerNameID,
  3989. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3990. sizeof(pCAContext->NameId),
  3991. (BYTE *) &pCAContext->NameId);
  3992. _JumpIfError(hr, error, "SetProperty");
  3993. }
  3994. hr = PropSetRequestTimeProperty(prow, g_wszPropRequestSubmittedWhen);
  3995. _JumpIfError(hr, error, "PropSetRequestTimeProperty");
  3996. hr = PropSetRequestTimeProperty(prow, g_wszPropRequestResolvedWhen);
  3997. _JumpIfError(hr, error, "PropSetRequestTimeProperty");
  3998. hr = pkcsSetTemplateProperty(prow, pCert);
  3999. _JumpIfError(hr, error, "pkcsSetTemplateProperty");
  4000. // Convert serial number to string and set in DB
  4001. hr = MultiByteIntegerToBstr(
  4002. FALSE,
  4003. pCertInfo->SerialNumber.cbData,
  4004. pCertInfo->SerialNumber.pbData,
  4005. &strSerialNumber);
  4006. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  4007. hr = prow->SetProperty(
  4008. g_wszPropCertificateSerialNumber,
  4009. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  4010. MAXDWORD,
  4011. (BYTE *) strSerialNumber);
  4012. _JumpIfError(hr, error, "SetProperty");
  4013. error:
  4014. if (NULL != strSerialNumber)
  4015. {
  4016. SysFreeString(strSerialNumber);
  4017. }
  4018. return(hr);
  4019. }
  4020. // Return TRUE if Data and Cert references apply to the specified CMC message
  4021. BOOL
  4022. pkcsCMCReferenceMatch(
  4023. IN DWORD DataReference, // nested CMC message Body Part Id
  4024. IN DWORD CertReference, // PKCS10 Cert Request Body Part Id
  4025. IN DWORD dwCmcDataReference,
  4026. IN DWORD cCertReference,
  4027. IN DWORD const *rgdwCertReference)
  4028. {
  4029. BOOL fMatch = FALSE;
  4030. DWORD i;
  4031. if (MAXDWORD != DataReference && dwCmcDataReference == DataReference)
  4032. {
  4033. fMatch = TRUE;
  4034. }
  4035. else if (MAXDWORD != CertReference && 0 == dwCmcDataReference)
  4036. {
  4037. for (i = 0; i < cCertReference; i++)
  4038. {
  4039. if (rgdwCertReference[i] == CertReference)
  4040. {
  4041. fMatch = TRUE;
  4042. break;
  4043. }
  4044. }
  4045. }
  4046. return(fMatch);
  4047. }
  4048. HRESULT
  4049. pkcsSetCMCExtensions(
  4050. IN ICertDBRow *prow,
  4051. IN DWORD DataReference, // nested CMC message Body Part Id
  4052. IN DWORD CertReference, // PKCS10 Cert Request Body Part Id
  4053. IN BYTE const *pbData,
  4054. IN DWORD cbData)
  4055. {
  4056. HRESULT hr;
  4057. CMC_ADD_EXTENSIONS_INFO *pcmcExt = NULL;
  4058. DWORD cb;
  4059. // Decode CMC_ADD_EXTENSIONS_INFO from Attribute Blob
  4060. CSASSERT(NULL == pcmcExt);
  4061. if (!myDecodeObject(
  4062. X509_ASN_ENCODING,
  4063. CMC_ADD_EXTENSIONS,
  4064. pbData,
  4065. cbData,
  4066. CERTLIB_USE_LOCALALLOC,
  4067. (VOID **) &pcmcExt,
  4068. &cb))
  4069. {
  4070. hr = myHLastError();
  4071. _JumpError(hr, error, "myDecodeObject");
  4072. }
  4073. if (pkcsCMCReferenceMatch(
  4074. DataReference,
  4075. CertReference,
  4076. pcmcExt->dwCmcDataReference,
  4077. pcmcExt->cCertReference,
  4078. pcmcExt->rgdwCertReference))
  4079. {
  4080. hr = pkcsSetExtensions(
  4081. prow,
  4082. EXTENSION_ORIGIN_CMC | EXTENSION_DISABLE_FLAG,
  4083. pcmcExt->rgExtension,
  4084. pcmcExt->cExtension);
  4085. _JumpIfError(hr, error, "pkcsSetExtensions(request)");
  4086. }
  4087. hr = S_OK;
  4088. error:
  4089. if (NULL != pcmcExt)
  4090. {
  4091. LocalFree(pcmcExt);
  4092. }
  4093. return(hr);
  4094. }
  4095. HRESULT
  4096. pkcsSetCMCAttributes(
  4097. IN ICertDBRow *prow,
  4098. IN DWORD DataReference, // nested CMC message Body Part Id
  4099. IN DWORD CertReference, // PKCS10 Cert Request Body Part Id
  4100. IN BYTE const *pbData,
  4101. IN DWORD cbData,
  4102. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf,
  4103. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  4104. {
  4105. HRESULT hr;
  4106. CMC_ADD_ATTRIBUTES_INFO *pcmcAttrib = NULL;
  4107. DWORD cb;
  4108. if (NULL != pfEnrollOnBehalfOf)
  4109. {
  4110. *pfEnrollOnBehalfOf = FALSE;
  4111. }
  4112. // Decode CMC_ADD_ATTRIBUTES_INFO from Attribute Blob
  4113. CSASSERT(NULL == pcmcAttrib);
  4114. if (!myDecodeObject(
  4115. X509_ASN_ENCODING,
  4116. CMC_ADD_ATTRIBUTES,
  4117. pbData,
  4118. cbData,
  4119. CERTLIB_USE_LOCALALLOC,
  4120. (VOID **) &pcmcAttrib,
  4121. &cb))
  4122. {
  4123. hr = myHLastError();
  4124. _JumpError(hr, error, "myDecodeObject");
  4125. }
  4126. if (pkcsCMCReferenceMatch(
  4127. DataReference,
  4128. CertReference,
  4129. pcmcAttrib->dwCmcDataReference,
  4130. pcmcAttrib->cCertReference,
  4131. pcmcAttrib->rgdwCertReference))
  4132. {
  4133. hr = pkcsSetAttributes(
  4134. prow,
  4135. EXTENSION_ORIGIN_CMC,
  4136. PSA_DISALLOW_EXTENSIONS | PSA_DISALLOW_ARCHIVEDKEY,
  4137. pcmcAttrib->rgAttribute,
  4138. pcmcAttrib->cAttribute,
  4139. 0,
  4140. NULL,
  4141. pfEnrollOnBehalfOf,
  4142. pResult);
  4143. _JumpIfError(hr, error, "pkcsSetAttributes(CMC)");
  4144. }
  4145. hr = S_OK;
  4146. error:
  4147. if (NULL != pcmcAttrib)
  4148. {
  4149. LocalFree(pcmcAttrib);
  4150. }
  4151. return(hr);
  4152. }
  4153. // map "email_mail" to "email"
  4154. // map "email_*" to "*"?
  4155. // mail_firstName=Terry&mail_lastName=Cheung+CMC+Zero+2&mail_email=
  4156. // tcheung%40verisign%2Ecom&challenge=test&
  4157. HRESULT
  4158. pkcsSetCMCRegInfo(
  4159. IN ICertDBRow *prow,
  4160. IN BYTE const *pbOctet,
  4161. IN DWORD cbOctet,
  4162. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf)
  4163. {
  4164. HRESULT hr;
  4165. WCHAR *pwszRA = NULL;
  4166. if (NULL != pfEnrollOnBehalfOf)
  4167. {
  4168. *pfEnrollOnBehalfOf = FALSE;
  4169. }
  4170. hr = myDecodeCMCRegInfo(pbOctet, cbOctet, &pwszRA);
  4171. _JumpIfError(hr, error, "myDecodeCMCRegInfo");
  4172. hr = PKCSParseAttributes(
  4173. prow,
  4174. pwszRA,
  4175. TRUE,
  4176. FALSE,
  4177. PROPTABLE_REQUEST,
  4178. pfEnrollOnBehalfOf);
  4179. _JumpIfError(hr, error, "PKCSParseAttributes");
  4180. error:
  4181. if (NULL != pwszRA)
  4182. {
  4183. LocalFree(pwszRA);
  4184. }
  4185. return(hr);
  4186. }
  4187. HRESULT
  4188. pkcsSetTaggedAttributes(
  4189. IN ICertDBRow *prow,
  4190. IN DWORD DataReference, // nested CMC message Body Part Id
  4191. IN DWORD CertReference, // PKCS10 Cert Request Body Part Id
  4192. IN CMC_TAGGED_ATTRIBUTE const *pTaggedAttribute,
  4193. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf,
  4194. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  4195. {
  4196. HRESULT hr;
  4197. DWORD i;
  4198. CRYPT_ATTRIBUTE const *pAttribute = &pTaggedAttribute->Attribute;
  4199. DWORD cb;
  4200. BOOL fEnrollOnBehalfOf;
  4201. if (NULL != pfEnrollOnBehalfOf)
  4202. {
  4203. *pfEnrollOnBehalfOf = FALSE;
  4204. }
  4205. for (i = 0; i < pAttribute->cValue; i++)
  4206. {
  4207. if (0 == strcmp(szOID_CMC_ADD_EXTENSIONS, pAttribute->pszObjId))
  4208. {
  4209. hr = pkcsSetCMCExtensions(
  4210. prow,
  4211. DataReference,
  4212. CertReference,
  4213. pAttribute->rgValue[i].pbData,
  4214. pAttribute->rgValue[i].cbData);
  4215. _JumpIfError(hr, error, "pkcsSetCMCExtensions");
  4216. }
  4217. else
  4218. if (0 == strcmp(szOID_CMC_ADD_ATTRIBUTES, pAttribute->pszObjId))
  4219. {
  4220. fEnrollOnBehalfOf = FALSE;
  4221. hr = pkcsSetCMCAttributes(
  4222. prow,
  4223. DataReference,
  4224. CertReference,
  4225. pAttribute->rgValue[i].pbData,
  4226. pAttribute->rgValue[i].cbData,
  4227. NULL != pfEnrollOnBehalfOf? &fEnrollOnBehalfOf : NULL,
  4228. pResult);
  4229. _JumpIfError(hr, error, "pkcsSetCMCAttributes");
  4230. if (fEnrollOnBehalfOf)
  4231. {
  4232. CSASSERT(NULL != pfEnrollOnBehalfOf);
  4233. *pfEnrollOnBehalfOf = TRUE;
  4234. }
  4235. }
  4236. else
  4237. if (0 == strcmp(szOID_CMC_REG_INFO, pAttribute->pszObjId))
  4238. {
  4239. fEnrollOnBehalfOf = FALSE;
  4240. hr = pkcsSetCMCRegInfo(
  4241. prow,
  4242. pAttribute->rgValue[i].pbData,
  4243. pAttribute->rgValue[i].cbData,
  4244. NULL != pfEnrollOnBehalfOf? &fEnrollOnBehalfOf : NULL);
  4245. _JumpIfError(hr, error, "pkcsSetCMCRegInfo");
  4246. if (fEnrollOnBehalfOf)
  4247. {
  4248. CSASSERT(NULL != pfEnrollOnBehalfOf);
  4249. *pfEnrollOnBehalfOf = TRUE;
  4250. }
  4251. }
  4252. else
  4253. if (0 == strcmp(szOID_CMC_TRANSACTION_ID, pAttribute->pszObjId))
  4254. {
  4255. DWORD dwTransactionId;
  4256. cb = sizeof(dwTransactionId);
  4257. dwTransactionId = 0;
  4258. if (!CryptDecodeObject(
  4259. X509_ASN_ENCODING,
  4260. X509_INTEGER,
  4261. pAttribute->rgValue[i].pbData,
  4262. pAttribute->rgValue[i].cbData,
  4263. 0,
  4264. &dwTransactionId,
  4265. &cb))
  4266. {
  4267. hr = myHLastError();
  4268. _JumpError(hr, error, "CryptDecodeObject");
  4269. }
  4270. pResult->fTransactionId = TRUE;
  4271. pResult->dwTransactionId = dwTransactionId;
  4272. }
  4273. else
  4274. if (0 == strcmp(szOID_CMC_SENDER_NONCE, pAttribute->pszObjId))
  4275. {
  4276. CRYPT_DATA_BLOB *pBlob;
  4277. BYTE *pb;
  4278. if (!myDecodeObject(
  4279. X509_ASN_ENCODING,
  4280. X509_OCTET_STRING,
  4281. pAttribute->rgValue[i].pbData,
  4282. pAttribute->rgValue[i].cbData,
  4283. CERTLIB_USE_LOCALALLOC,
  4284. (VOID **) &pBlob,
  4285. &cb))
  4286. {
  4287. hr = myHLastError();
  4288. _JumpError(hr, error, "myDecodeObject");
  4289. }
  4290. pb = (BYTE *) LocalAlloc(LMEM_FIXED, pBlob->cbData);
  4291. if (NULL == pb)
  4292. {
  4293. hr = E_OUTOFMEMORY;
  4294. }
  4295. else
  4296. {
  4297. CopyMemory(pb, pBlob->pbData, pBlob->cbData);
  4298. if (NULL != pResult->pbSenderNonce)
  4299. {
  4300. LocalFree(pResult->pbSenderNonce);
  4301. }
  4302. pResult->pbSenderNonce = pb;
  4303. pResult->cbSenderNonce = pBlob->cbData;
  4304. hr = S_OK;
  4305. }
  4306. LocalFree(pBlob);
  4307. _JumpIfError(hr, error, "LocalAlloc");
  4308. }
  4309. else if (0 == (CRLF_IGNORE_UNKNOWN_CMC_ATTRIBUTES & g_dwCRLFlags))
  4310. {
  4311. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4312. _JumpError(hr, error, "unknown tagged attribute");
  4313. }
  4314. }
  4315. hr = S_OK;
  4316. error:
  4317. return(hr);
  4318. }
  4319. //+------------------------------------------------------------------------
  4320. // pkcsParseCMCRequest
  4321. //
  4322. // Crack a CMC request and dig the goodies out of it.
  4323. // Crack the contents of the CMC request recursively.
  4324. //-------------------------------------------------------------------------
  4325. HRESULT
  4326. pkcsParseCMCRequest(
  4327. IN ICertDBRow *prow,
  4328. IN DWORD cbIn,
  4329. IN BYTE const *pbIn,
  4330. OPTIONAL IN CERT_CONTEXT const *pCertSigner,
  4331. OPTIONAL OUT BOOL *pfRenewal,
  4332. OPTIONAL OUT BOOL *pfEnrollOnBehalfOf,
  4333. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  4334. {
  4335. HRESULT hr;
  4336. DWORD cb;
  4337. CMC_DATA_INFO *pcmcData = NULL;
  4338. DWORD i;
  4339. DWORD DataReference = MAXDWORD; // nested CMC message Body Part Id
  4340. DWORD CertReference = MAXDWORD; // PKCS10 Cert Request Body Part Id
  4341. if (NULL != pfRenewal)
  4342. {
  4343. *pfRenewal = FALSE;
  4344. }
  4345. if (NULL != pfEnrollOnBehalfOf)
  4346. {
  4347. *pfEnrollOnBehalfOf = FALSE;
  4348. }
  4349. if (!myDecodeObject(
  4350. X509_ASN_ENCODING,
  4351. CMC_DATA,
  4352. pbIn,
  4353. cbIn,
  4354. CERTLIB_USE_LOCALALLOC,
  4355. (VOID **) &pcmcData,
  4356. &cb))
  4357. {
  4358. hr = myHLastError();
  4359. _JumpError(hr, error, "myDecodeObject");
  4360. }
  4361. if (0 != pcmcData->cTaggedOtherMsg)
  4362. {
  4363. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4364. _JumpError(hr, error, "unknown other message");
  4365. }
  4366. // Process nested CMC messages
  4367. if (0 != pcmcData->cTaggedContentInfo)
  4368. {
  4369. CMC_TAGGED_CONTENT_INFO const *pTaggedContentInfo;
  4370. // Only handle one CMC message at a time for now.
  4371. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4372. if (1 < pcmcData->cTaggedContentInfo)
  4373. {
  4374. _JumpError(hr, error, "multiple nested CMC messages");
  4375. }
  4376. // Disallow CMC message recursion below a PKCS10 request.
  4377. if (0 != pcmcData->cTaggedRequest)
  4378. {
  4379. _JumpError(hr, error, "recursion below PKCS10 request");
  4380. }
  4381. // Recurse on the nested CMC message
  4382. pTaggedContentInfo = &pcmcData->rgTaggedContentInfo[0];
  4383. hr = PKCSParseRequest(
  4384. CR_IN_CMC | (~CR_IN_FORMATMASK & pResult->dwFlagsTop),
  4385. prow,
  4386. pTaggedContentInfo->EncodedContentInfo.cbData,
  4387. pTaggedContentInfo->EncodedContentInfo.pbData,
  4388. pCertSigner,
  4389. pfRenewal,
  4390. pResult);
  4391. _JumpIfError(hr, error, "PKCSParseRequest");
  4392. DataReference = pTaggedContentInfo->dwBodyPartID;
  4393. }
  4394. // Process nested PKCS10 requests
  4395. if (0 != pcmcData->cTaggedRequest)
  4396. {
  4397. CMC_TAGGED_REQUEST const *pTaggedRequest;
  4398. CMC_TAGGED_CERT_REQUEST const *pTaggedCertRequest;
  4399. // Only handle one request at a time for now.
  4400. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4401. if (1 < pcmcData->cTaggedRequest)
  4402. {
  4403. _JumpError(hr, error, "multiple PKCS10 requests");
  4404. }
  4405. pTaggedRequest = &pcmcData->rgTaggedRequest[0];
  4406. // The request must be a PKCS10 request
  4407. if (CMC_TAGGED_CERT_REQUEST_CHOICE !=
  4408. pTaggedRequest->dwTaggedRequestChoice)
  4409. {
  4410. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4411. _JumpError(hr, error, "recursion below PKCS10 request");
  4412. }
  4413. pTaggedCertRequest = pTaggedRequest->pTaggedCertRequest;
  4414. hr = PKCSParseRequest(
  4415. CR_IN_PKCS10 | (~CR_IN_FORMATMASK & pResult->dwFlagsTop),
  4416. prow,
  4417. pTaggedCertRequest->SignedCertRequest.cbData,
  4418. pTaggedCertRequest->SignedCertRequest.pbData,
  4419. pCertSigner,
  4420. pfRenewal,
  4421. pResult);
  4422. _JumpIfError(hr, error, "PKCSParseRequest");
  4423. CertReference = pTaggedCertRequest->dwBodyPartID;
  4424. }
  4425. // Process extensions and attributes
  4426. for (i = 0; i < pcmcData->cTaggedAttribute; i++)
  4427. {
  4428. hr = pkcsSetTaggedAttributes(
  4429. prow,
  4430. DataReference,
  4431. CertReference,
  4432. &pcmcData->rgTaggedAttribute[i],
  4433. pfEnrollOnBehalfOf,
  4434. pResult);
  4435. _JumpIfError(hr, error, "pkcsSetTaggedAttributes");
  4436. }
  4437. hr = S_OK;
  4438. error:
  4439. if (NULL != pcmcData)
  4440. {
  4441. LocalFree(pcmcData);
  4442. }
  4443. return(hr);
  4444. }
  4445. HRESULT
  4446. pkcsAppendPolicies(
  4447. IN ICertDBRow *prow,
  4448. IN WCHAR const *pwszPropName,
  4449. OPTIONAL IN WCHAR const *pwszzPolicies)
  4450. {
  4451. HRESULT hr;
  4452. WCHAR *pwszOld = NULL;
  4453. WCHAR *pwszNew = NULL;
  4454. WCHAR const *pwszIn;
  4455. WCHAR *pwsz;
  4456. DWORD cwc = 0;
  4457. DWORD cb;
  4458. hr = PKCSGetProperty(
  4459. prow,
  4460. pwszPropName,
  4461. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  4462. &cb,
  4463. (BYTE **) &pwszOld);
  4464. _PrintIfError2(hr, "PKCSGetProperty", hr);
  4465. if (S_OK != hr)
  4466. {
  4467. pwszOld = NULL;
  4468. }
  4469. if (NULL != pwszOld)
  4470. {
  4471. cwc = wcslen(pwszOld) + 1; // allow for \n separator
  4472. }
  4473. // pwszzPolicies == NULL means the cert is good for *all* policies.
  4474. // Store "*"
  4475. //
  4476. // *pwszzPolicies == L'\0' means the cert is good for *no* policies.
  4477. // Store "-"
  4478. if (NULL == pwszzPolicies)
  4479. {
  4480. pwszzPolicies = L"*\0";
  4481. }
  4482. else if (L'\0' == *pwszzPolicies)
  4483. {
  4484. pwszzPolicies = L"-\0";
  4485. }
  4486. for (pwszIn = pwszzPolicies; L'\0' != *pwszIn; pwszIn += wcslen(pwszIn) + 1)
  4487. ;
  4488. cwc += SAFE_SUBTRACT_POINTERS(pwszIn, pwszzPolicies);
  4489. pwszNew = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  4490. if (NULL == pwszNew)
  4491. {
  4492. hr = E_OUTOFMEMORY;
  4493. _JumpError(hr, error, "LocalAlloc");
  4494. }
  4495. pwsz = pwszNew;
  4496. if (NULL != pwszOld)
  4497. {
  4498. wcscpy(pwsz, pwszOld);
  4499. pwsz += wcslen(pwsz);
  4500. wcscpy(pwsz, L"\n");
  4501. pwsz++;
  4502. }
  4503. for (pwszIn = pwszzPolicies; L'\0' != *pwszIn; pwszIn += wcslen(pwszIn) + 1)
  4504. {
  4505. if (pwszIn != pwszzPolicies)
  4506. {
  4507. wcscpy(pwsz, L",");
  4508. pwsz++;
  4509. }
  4510. wcscpy(pwsz, pwszIn);
  4511. pwsz += wcslen(pwsz);
  4512. }
  4513. CSASSERT(&pwsz[1] == &pwszNew[cwc]);
  4514. hr = prow->SetProperty(
  4515. pwszPropName,
  4516. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  4517. MAXDWORD,
  4518. (BYTE const *) pwszNew);
  4519. _JumpIfError(hr, error, "SetProperty");
  4520. error:
  4521. if (NULL != pwszOld)
  4522. {
  4523. LocalFree(pwszOld);
  4524. }
  4525. if (NULL != pwszNew)
  4526. {
  4527. LocalFree(pwszNew);
  4528. }
  4529. return(hr);
  4530. }
  4531. //+------------------------------------------------------------------------
  4532. // pkcsParsePKCS7Request
  4533. //
  4534. // Crack a PKCS7 and dig the goodies out of it.
  4535. // Verify the signature of the 7 against the cert given in the 7.
  4536. // Crack the contents of the 7 recursively.
  4537. //-------------------------------------------------------------------------
  4538. HRESULT
  4539. pkcsParsePKCS7Request(
  4540. IN BOOL fTopLevel,
  4541. IN DWORD dwFlags,
  4542. IN ICertDBRow *prow,
  4543. IN DWORD cbIn,
  4544. IN BYTE const *pbIn,
  4545. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  4546. {
  4547. HRESULT hr;
  4548. BYTE *pbContents = NULL;
  4549. DWORD cbContents;
  4550. CERT_CONTEXT const *pCertSigner = NULL;
  4551. HCERTSTORE hStore = NULL;
  4552. HCRYPTMSG hMsg = NULL;
  4553. char *pszInnerContentObjId = NULL;
  4554. DWORD i;
  4555. BOOL fCMC;
  4556. BOOL fRenewal = FALSE;
  4557. char *apszEnrollOids[] = {szOID_ENROLLMENT_AGENT};
  4558. DWORD dwVerifyContextFlags;
  4559. DWORD dwMsgType;
  4560. DWORD cSigner;
  4561. DWORD cFirstSigner;
  4562. BOOL fFirstSigner;
  4563. DWORD cRecipient;
  4564. DWORD cb;
  4565. CMSG_CMS_SIGNER_INFO *pcsi = NULL;
  4566. DWORD dwDisallowFlags;
  4567. DWORD iElement;
  4568. WCHAR *pwszzIssuancePolicies = NULL;
  4569. WCHAR *pwszzApplicationPolicies = NULL;
  4570. WCHAR *pwszExtendedErrorInfo = NULL;
  4571. CERT_REQUEST_INFO *pRequest = NULL;
  4572. BOOL fEnrollOnBehalfOf;
  4573. CSASSERT(
  4574. CR_IN_PKCS7 == (CR_IN_FORMATMASK & dwFlags) ||
  4575. CR_IN_CMC == (CR_IN_FORMATMASK & dwFlags));
  4576. // Crack the 7 and verify the signature.
  4577. hr = myDecodePKCS7(
  4578. pbIn,
  4579. cbIn,
  4580. &pbContents,
  4581. &cbContents,
  4582. &dwMsgType,
  4583. &pszInnerContentObjId,
  4584. &cSigner,
  4585. &cRecipient,
  4586. &hStore,
  4587. &hMsg);
  4588. _JumpIfError(hr, error, "myDecodePKCS7");
  4589. if (CMSG_SIGNED != dwMsgType || 0 == cSigner)
  4590. {
  4591. hr = CRYPT_E_NO_SIGNER;
  4592. _JumpIfError(hr, error, "myDecodePKCS7(no signing cert)");
  4593. }
  4594. fCMC = NULL != pszInnerContentObjId &&
  4595. 0 == strcmp(pszInnerContentObjId, szOID_CT_PKI_DATA);
  4596. // Decode the contents.
  4597. if (fCMC)
  4598. {
  4599. if (CR_IN_CMC != (CR_IN_FORMATMASK & dwFlags))
  4600. {
  4601. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4602. _JumpError(hr, error, "dwFlags");
  4603. }
  4604. // CMC renewal requests may have one 'first' signer (non-NULL KeyId or
  4605. // Dummy signer) and one additional Issuer+Serial signer. If the
  4606. // request has the appropriate signatures, pass the cert to the lowest
  4607. // level to see if it really is a renewal request.
  4608. if (1 <= cSigner && 2 >= cSigner)
  4609. {
  4610. DWORD iCertSigner = MAXDWORD;
  4611. cFirstSigner = 0;
  4612. for (i = 0; i < cSigner; i++)
  4613. {
  4614. if (NULL != pcsi)
  4615. {
  4616. LocalFree(pcsi);
  4617. pcsi = NULL;
  4618. }
  4619. hr = myCryptMsgGetParam(
  4620. hMsg,
  4621. CMSG_CMS_SIGNER_INFO_PARAM,
  4622. i,
  4623. CERTLIB_USE_LOCALALLOC,
  4624. (VOID **) &pcsi,
  4625. &cb);
  4626. _JumpIfError(hr, error, "myCryptMsgGetParam");
  4627. fFirstSigner = FALSE;
  4628. if (CERT_ID_KEY_IDENTIFIER == pcsi->SignerId.dwIdChoice ||
  4629. (NULL != pcsi->HashEncryptionAlgorithm.pszObjId &&
  4630. 0 == strcmp(
  4631. szOID_PKIX_NO_SIGNATURE,
  4632. pcsi->HashEncryptionAlgorithm.pszObjId)))
  4633. {
  4634. fFirstSigner = TRUE;
  4635. cFirstSigner++;
  4636. }
  4637. else
  4638. {
  4639. if (MAXDWORD != iCertSigner)
  4640. {
  4641. iCertSigner = MAXDWORD; // must not be a renewal
  4642. break;
  4643. }
  4644. iCertSigner = i;
  4645. }
  4646. }
  4647. if (MAXDWORD != iCertSigner && 1 >= cFirstSigner)
  4648. {
  4649. iElement = iCertSigner;
  4650. if (!CryptMsgGetAndVerifySigner(
  4651. hMsg,
  4652. 0, // cSignerStore
  4653. NULL, // rghSignerStore
  4654. CMSG_USE_SIGNER_INDEX_FLAG,
  4655. &pCertSigner,
  4656. &iElement))
  4657. {
  4658. pResult->dwResultFlags |= CRCF_SIGNATUREERROR;
  4659. hr = myHLastError();
  4660. _JumpError(hr, error, "CryptMsgGetAndVerifySigner");
  4661. }
  4662. }
  4663. }
  4664. fEnrollOnBehalfOf = FALSE;
  4665. hr = pkcsParseCMCRequest(
  4666. prow,
  4667. cbContents,
  4668. pbContents,
  4669. pCertSigner,
  4670. &fRenewal,
  4671. &fEnrollOnBehalfOf,
  4672. pResult);
  4673. _JumpIfError(hr, error, "pkcsParseCMCRequest");
  4674. if (fEnrollOnBehalfOf)
  4675. {
  4676. pResult->fEnrollOnBehalfOf = TRUE;
  4677. }
  4678. }
  4679. else
  4680. {
  4681. if (CR_IN_PKCS7 != (CR_IN_FORMATMASK & dwFlags))
  4682. {
  4683. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4684. _JumpError(hr, error, "dwFlags");
  4685. }
  4686. // Expect only one signer for PKCS7 renewal requests. Pass the cert
  4687. // to the lowest level to see if it really is a renewal request.
  4688. iElement = 0;
  4689. if (!CryptMsgGetAndVerifySigner(
  4690. hMsg,
  4691. 0, // cSignerStore
  4692. NULL, // rghSignerStore
  4693. CMSG_USE_SIGNER_INDEX_FLAG,
  4694. &pCertSigner,
  4695. &iElement))
  4696. {
  4697. pResult->dwResultFlags |= CRCF_SIGNATUREERROR;
  4698. hr = myHLastError();
  4699. _JumpError(hr, error, "CryptMsgGetAndVerifySigner");
  4700. }
  4701. hr = PKCSParseRequest(
  4702. CR_IN_FORMATANY | (~CR_IN_FORMATMASK & pResult->dwFlagsTop),
  4703. prow,
  4704. cbContents,
  4705. pbContents,
  4706. pCertSigner,
  4707. &fRenewal,
  4708. pResult);
  4709. _JumpIfError(hr, error, "PKCSParseRequest");
  4710. }
  4711. // Loop through the signers, verifying signatures and saving attributes.
  4712. cFirstSigner = 0;
  4713. for (i = 0; i < cSigner; i++)
  4714. {
  4715. if (NULL != pcsi)
  4716. {
  4717. LocalFree(pcsi);
  4718. pcsi = NULL;
  4719. }
  4720. if (NULL != pwszzIssuancePolicies)
  4721. {
  4722. LocalFree(pwszzIssuancePolicies);
  4723. pwszzIssuancePolicies = NULL;
  4724. }
  4725. if (NULL != pwszzApplicationPolicies)
  4726. {
  4727. LocalFree(pwszzApplicationPolicies);
  4728. pwszzApplicationPolicies = NULL;
  4729. }
  4730. if (NULL != pwszExtendedErrorInfo)
  4731. {
  4732. LocalFree(pwszExtendedErrorInfo);
  4733. pwszExtendedErrorInfo = NULL;
  4734. }
  4735. if (NULL != pCertSigner)
  4736. {
  4737. CertFreeCertificateContext(pCertSigner);
  4738. pCertSigner = NULL;
  4739. }
  4740. hr = myCryptMsgGetParam(
  4741. hMsg,
  4742. CMSG_CMS_SIGNER_INFO_PARAM,
  4743. i,
  4744. CERTLIB_USE_LOCALALLOC,
  4745. (VOID **) &pcsi,
  4746. &cb);
  4747. if (S_OK != hr)
  4748. {
  4749. pResult->dwResultFlags |= CRCF_SIGNATUREERROR;
  4750. _JumpError(hr, error, "myCryptMsgGetParam");
  4751. }
  4752. fFirstSigner = FALSE;
  4753. if (fCMC &&
  4754. (CERT_ID_KEY_IDENTIFIER == pcsi->SignerId.dwIdChoice ||
  4755. (NULL != pcsi->HashEncryptionAlgorithm.pszObjId &&
  4756. 0 == strcmp(
  4757. szOID_PKIX_NO_SIGNATURE,
  4758. pcsi->HashEncryptionAlgorithm.pszObjId))))
  4759. {
  4760. CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA cvse;
  4761. fFirstSigner = TRUE;
  4762. ZeroMemory(&cvse, sizeof(cvse));
  4763. cvse.cbSize = sizeof(cvse);
  4764. cvse.dwSignerIndex = i;
  4765. if (CERT_ID_KEY_IDENTIFIER == pcsi->SignerId.dwIdChoice)
  4766. {
  4767. if (NULL == pRequest)
  4768. {
  4769. hr = myGetInnerPKCS10(
  4770. hMsg,
  4771. pszInnerContentObjId,
  4772. &pRequest);
  4773. _JumpIfError(hr, error, "myGetInnerPKCS10");
  4774. }
  4775. cvse.dwSignerType = CMSG_VERIFY_SIGNER_PUBKEY;
  4776. cvse.pvSigner = &pRequest->SubjectPublicKeyInfo;
  4777. }
  4778. else
  4779. {
  4780. cvse.dwSignerType = CMSG_VERIFY_SIGNER_NULL;
  4781. }
  4782. if (!CryptMsgControl(
  4783. hMsg,
  4784. 0, // dwFlags
  4785. CMSG_CTRL_VERIFY_SIGNATURE_EX,
  4786. &cvse))
  4787. {
  4788. pResult->dwResultFlags |= CRCF_SIGNATUREERROR;
  4789. hr = myHLastError();
  4790. _JumpError(hr, error, "CryptMsgControl(VerifySig)");
  4791. }
  4792. }
  4793. else
  4794. {
  4795. iElement = i;
  4796. if (!CryptMsgGetAndVerifySigner(
  4797. hMsg,
  4798. 0, // cSignerStore
  4799. NULL, // rghSignerStore
  4800. CMSG_USE_SIGNER_INDEX_FLAG,
  4801. &pCertSigner,
  4802. &iElement))
  4803. {
  4804. pResult->dwResultFlags |= CRCF_SIGNATUREERROR;
  4805. hr = myHLastError();
  4806. _JumpError(hr, error, "CryptMsgGetAndVerifySigner");
  4807. }
  4808. }
  4809. // Only enroll-on-behalf-of requests may contain Name, Value pairs.
  4810. // Only enroll-on-behalf-of requests and renewal requests may contain
  4811. // certificate extensions.
  4812. dwDisallowFlags = PSA_DISALLOW_ARCHIVEDKEY;
  4813. if (fRenewal)
  4814. {
  4815. dwDisallowFlags |= PSA_DISALLOW_NAMEVALUEPAIRS;
  4816. pResult->dwResultFlags |= CRCF_RENEWAL;
  4817. }
  4818. if (fCMC)
  4819. {
  4820. dwDisallowFlags |= PSA_DISALLOW_EXTENSIONS |
  4821. PSA_DISALLOW_NAMEVALUEPAIRS;
  4822. }
  4823. fEnrollOnBehalfOf = FALSE;
  4824. hr = pkcsSetAttributes(
  4825. prow,
  4826. EXTENSION_ORIGIN_PKCS7,
  4827. dwDisallowFlags,
  4828. pcsi->AuthAttrs.rgAttr,
  4829. pcsi->AuthAttrs.cAttr,
  4830. 0,
  4831. NULL,
  4832. &fEnrollOnBehalfOf,
  4833. pResult);
  4834. _JumpIfError(hr, error, "pkcsSetAttributes(Authenticated)");
  4835. if (fEnrollOnBehalfOf)
  4836. {
  4837. pResult->fEnrollOnBehalfOf = TRUE;
  4838. }
  4839. // Pull encrypted private key out of unauthenticated attributes
  4840. hr = pkcsSetAttributes(
  4841. prow,
  4842. EXTENSION_ORIGIN_PKCS7,
  4843. ((fTopLevel && fFirstSigner)? 0 : PSA_DISALLOW_ARCHIVEDKEY) |
  4844. PSA_DISALLOW_EXTENSIONS |
  4845. PSA_DISALLOW_NAMEVALUEPAIRS,
  4846. pcsi->UnauthAttrs.rgAttr,
  4847. pcsi->UnauthAttrs.cAttr,
  4848. cbIn,
  4849. fTopLevel? pbIn : NULL,
  4850. NULL,
  4851. pResult);
  4852. _JumpIfError(hr, error, "pkcsSetAttributes(UNauthenticated)");
  4853. if (fFirstSigner)
  4854. {
  4855. cFirstSigner++;
  4856. }
  4857. else
  4858. {
  4859. BOOL fEnrollmentAgent;
  4860. // This is a renewal request, an enroll-on-behalf-of request, a CMC
  4861. // request or just a request inside a PKCS 7 -- verify the cert
  4862. // chain for all signers. If enroll-on-behalf-of on an Enterprise
  4863. // CA (if requester name is set in the authenticated attributes),
  4864. // check the signing cert via NTAuth policy and check for
  4865. // szOID_ENROLLMENT_AGENT usage. NtAuth verification was added to
  4866. // control the ability of enroll-on-behalf agents to add usernames
  4867. // to the PKCS7 wrapper.
  4868. fEnrollmentAgent = pResult->fEnrollOnBehalfOf &&
  4869. #ifdef CERTSRV_EOBO_DCR_APPROVED
  4870. (CRLF_ENFORCE_ENROLLMENT_AGENT & g_dwCRLFlags);
  4871. #else
  4872. ((CRLF_ENFORCE_ENROLLMENT_AGENT & g_dwCRLFlags) ||
  4873. IsEnterpriseCA(g_CAType));
  4874. #endif
  4875. dwVerifyContextFlags = g_dwVerifyCertFlags;
  4876. if (pResult->fEnrollOnBehalfOf && IsEnterpriseCA(g_CAType))
  4877. {
  4878. dwVerifyContextFlags |= CA_VERIFY_FLAGS_NT_AUTH;
  4879. }
  4880. hr = myVerifyCertContextEx(
  4881. pCertSigner,
  4882. dwVerifyContextFlags,
  4883. 0, // dwmsTimeout
  4884. fEnrollmentAgent? ARRAYSIZE(apszEnrollOids) : 0,
  4885. fEnrollmentAgent? apszEnrollOids : NULL,
  4886. 0, // cIssuanceOids
  4887. NULL, // apszIssuanceOids
  4888. HCCE_LOCAL_MACHINE, // hChainEngine
  4889. NULL, // pft
  4890. hStore, // hAdditionalStore
  4891. NULL, // pfnCallback
  4892. NULL, // ppwszMissingIssuer
  4893. &pwszzIssuancePolicies,
  4894. &pwszzApplicationPolicies,
  4895. &pwszExtendedErrorInfo,
  4896. NULL); // pTrustStatus
  4897. if (S_OK != hr)
  4898. {
  4899. pResult->dwResultFlags |= CRCF_SIGNATUREERROR;
  4900. _JumpError(hr, error, "myVerifyCertContextEx");
  4901. }
  4902. if (NULL != pwszExtendedErrorInfo)
  4903. {
  4904. hr = myAppendString(
  4905. pwszExtendedErrorInfo,
  4906. L", ",
  4907. &pResult->pwszExtendedErrorInfo);
  4908. _JumpIfError(hr, error, "myAppendString");
  4909. }
  4910. if (fTopLevel)
  4911. {
  4912. // save Issuance Policies
  4913. hr = pkcsAppendPolicies(
  4914. prow,
  4915. wszPROPSIGNERPOLICIES,
  4916. pwszzIssuancePolicies);
  4917. _JumpIfError(hr, error, "pkcsAppendPolicies");
  4918. // save Application Policies
  4919. hr = pkcsAppendPolicies(
  4920. prow,
  4921. wszPROPSIGNERAPPLICATIONPOLICIES,
  4922. pwszzApplicationPolicies);
  4923. _JumpIfError(hr, error, "pkcsAppendPolicies");
  4924. }
  4925. }
  4926. }
  4927. if (pResult->fEnrollOnBehalfOf)
  4928. {
  4929. hr = PKCSSetRequestFlags(prow, TRUE, CR_FLG_ENROLLONBEHALFOF);
  4930. _JumpIfError(hr, error, "PKCSSetRequestFlags");
  4931. if (fCMC && cSigner == cFirstSigner)
  4932. {
  4933. pResult->dwResultFlags |= CRCF_SIGNATUREERROR;
  4934. hr = CRYPT_E_NO_TRUSTED_SIGNER;
  4935. _JumpError(hr, error, "No NTAuth signer");
  4936. }
  4937. }
  4938. if ((fCMC && 1 < cFirstSigner) || (!fCMC && 0 < cFirstSigner))
  4939. {
  4940. pResult->dwResultFlags |= CRCF_SIGNATUREERROR;
  4941. hr = NTE_BAD_SIGNATURE;
  4942. _JumpError(hr, error, "cFirstSigner");
  4943. }
  4944. error:
  4945. if (NULL != pRequest)
  4946. {
  4947. LocalFree(pRequest);
  4948. }
  4949. if (NULL != pcsi)
  4950. {
  4951. LocalFree(pcsi);
  4952. }
  4953. if (NULL != pwszzIssuancePolicies)
  4954. {
  4955. LocalFree(pwszzIssuancePolicies);
  4956. }
  4957. if (NULL != pwszzApplicationPolicies)
  4958. {
  4959. LocalFree(pwszzApplicationPolicies);
  4960. }
  4961. if (NULL != pwszExtendedErrorInfo)
  4962. {
  4963. LocalFree(pwszExtendedErrorInfo);
  4964. }
  4965. if (NULL != hMsg)
  4966. {
  4967. CryptMsgClose(hMsg);
  4968. }
  4969. if (NULL != pCertSigner)
  4970. {
  4971. CertFreeCertificateContext(pCertSigner);
  4972. }
  4973. if (NULL != hStore)
  4974. {
  4975. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  4976. }
  4977. if (NULL != pbContents)
  4978. {
  4979. LocalFree(pbContents);
  4980. }
  4981. if (NULL != pszInnerContentObjId)
  4982. {
  4983. LocalFree(pszInnerContentObjId);
  4984. }
  4985. return(hr);
  4986. }
  4987. typedef struct _REQUESTFORMATS
  4988. {
  4989. char const *pszFormat;
  4990. DWORD dwFlags;
  4991. } REQUESTFORMATS;
  4992. REQUESTFORMATS g_arf[] = {
  4993. { X509_CERT_REQUEST_TO_BE_SIGNED, CR_IN_PKCS10 },
  4994. { X509_KEYGEN_REQUEST_TO_BE_SIGNED, CR_IN_KEYGEN },
  4995. };
  4996. #define CREQUESTFORMATS ARRAYSIZE(g_arf)
  4997. HRESULT
  4998. pkcsCrackRequestType(
  4999. IN DWORD cbRequest,
  5000. IN BYTE const *pbRequest,
  5001. OUT DWORD *pdwFlags)
  5002. {
  5003. HRESULT hr = S_OK;
  5004. DWORD cb;
  5005. BYTE *pbDecoded = NULL;
  5006. REQUESTFORMATS const *prf;
  5007. REQUESTFORMATS const *prfEnd;
  5008. HCRYPTMSG hMsg = NULL;
  5009. char *pszInnerContentObjId = NULL;
  5010. prfEnd = &g_arf[CREQUESTFORMATS];
  5011. for (prf = g_arf; prf < prfEnd; prf++)
  5012. {
  5013. CSASSERT(NULL == pbDecoded);
  5014. if (myDecodeObject(
  5015. X509_ASN_ENCODING,
  5016. prf->pszFormat,
  5017. pbRequest,
  5018. cbRequest,
  5019. CERTLIB_USE_LOCALALLOC,
  5020. (VOID **) &pbDecoded,
  5021. &cb))
  5022. {
  5023. *pdwFlags = prf->dwFlags;
  5024. break;
  5025. }
  5026. hr = myHLastError();
  5027. CSASSERT(S_OK != hr);
  5028. }
  5029. if (prf >= prfEnd)
  5030. {
  5031. CSASSERT(S_OK != hr);
  5032. hr = myDecodePKCS7(
  5033. pbRequest,
  5034. cbRequest,
  5035. NULL, // ppbContents
  5036. NULL, // pcbContents
  5037. NULL, // pdwMsgType
  5038. &pszInnerContentObjId,
  5039. NULL, // pcSigner
  5040. NULL, // pcRecipient
  5041. NULL, // phStore
  5042. &hMsg);
  5043. _JumpIfError(hr, error, "myDecodePKCS7");
  5044. *pdwFlags = CR_IN_PKCS7; // default to renewal
  5045. if (NULL != pszInnerContentObjId &&
  5046. 0 == strcmp(pszInnerContentObjId, szOID_CT_PKI_DATA))
  5047. {
  5048. *pdwFlags = CR_IN_CMC;
  5049. }
  5050. }
  5051. hr = S_OK;
  5052. error:
  5053. if (NULL != hMsg)
  5054. {
  5055. CryptMsgClose(hMsg);
  5056. }
  5057. if (NULL != pszInnerContentObjId)
  5058. {
  5059. LocalFree(pszInnerContentObjId);
  5060. }
  5061. if (NULL != pbDecoded)
  5062. {
  5063. LocalFree(pbDecoded);
  5064. }
  5065. return(hr);
  5066. }
  5067. HRESULT
  5068. PKCSParseRequest(
  5069. IN DWORD dwFlags,
  5070. IN ICertDBRow *prow,
  5071. IN DWORD cbRequest,
  5072. IN BYTE const *pbRequest,
  5073. IN CERT_CONTEXT const *pSigningAuthority,
  5074. OPTIONAL OUT BOOL *pfRenewal,
  5075. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  5076. {
  5077. HRESULT hr;
  5078. if (NULL != pfRenewal)
  5079. {
  5080. *pfRenewal = FALSE;
  5081. }
  5082. if (CR_IN_FORMATANY == (CR_IN_FORMATMASK & dwFlags))
  5083. {
  5084. hr = pkcsCrackRequestType(cbRequest, pbRequest, &dwFlags);
  5085. _JumpIfError(hr, error, "pkcsCrackRequestType");
  5086. dwFlags |= ~CR_IN_FORMATMASK & pResult->dwFlagsTop;
  5087. // If this is the top level caller, store a more specific request type:
  5088. if (NULL == pfRenewal)
  5089. {
  5090. pResult->dwFlagsTop = dwFlags;
  5091. hr = prow->SetProperty(
  5092. g_wszPropRequestType,
  5093. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  5094. sizeof(dwFlags),
  5095. (BYTE const *) &dwFlags);
  5096. _JumpIfError(hr, error, "SetProperty(reqtype)");
  5097. }
  5098. }
  5099. switch (CR_IN_FORMATMASK & dwFlags)
  5100. {
  5101. case CR_IN_PKCS10:
  5102. hr = pkcsParsePKCS10Request(
  5103. dwFlags,
  5104. prow,
  5105. cbRequest,
  5106. pbRequest,
  5107. pSigningAuthority,
  5108. pfRenewal,
  5109. pResult);
  5110. _JumpIfError(hr, error, "pkcsParsePKCS10Request");
  5111. break;
  5112. case CR_IN_KEYGEN:
  5113. hr = pkcsParseKeyGenRequest(
  5114. dwFlags,
  5115. prow,
  5116. cbRequest,
  5117. pbRequest,
  5118. pResult);
  5119. _JumpIfError(hr, error, "pkcsParseKeyGenRequest");
  5120. break;
  5121. case CR_IN_CMC:
  5122. case CR_IN_PKCS7:
  5123. // PKCS7 requests can either be an 'enroll on behalf of', renewal
  5124. // request or a CMC request. We need to recursively unwrap it to
  5125. // process it.
  5126. hr = pkcsParsePKCS7Request(
  5127. NULL == pfRenewal, // fTopLevel
  5128. dwFlags,
  5129. prow,
  5130. cbRequest,
  5131. pbRequest,
  5132. pResult);
  5133. _JumpIfError(hr, error, "pkcsParsePKCS7Request");
  5134. break;
  5135. default:
  5136. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  5137. _JumpError(hr, error, "dwFlags");
  5138. }
  5139. error:
  5140. if (NULL == pfRenewal)
  5141. {
  5142. HRESULT hr2;
  5143. DWORD cbData;
  5144. hr2 = prow->GetProperty(
  5145. g_wszPropRequestRawRequest,
  5146. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  5147. NULL,
  5148. &cbData,
  5149. NULL);
  5150. if (S_OK != hr2)
  5151. {
  5152. hr2 = prow->SetProperty(
  5153. g_wszPropRequestRawRequest,
  5154. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  5155. cbRequest,
  5156. pbRequest);
  5157. _PrintIfError(hr2, "SetProperty(request)");
  5158. if (S_OK == hr)
  5159. {
  5160. hr = hr2;
  5161. }
  5162. }
  5163. }
  5164. return(hr);
  5165. }
  5166. HRESULT
  5167. PKCSGetCRLList(
  5168. IN BOOL fDelta,
  5169. IN DWORD iCert,
  5170. OUT WCHAR const * const **ppapwszCRLList)
  5171. {
  5172. HRESULT hr = E_INVALIDARG;
  5173. *ppapwszCRLList = NULL;
  5174. if (iCert < g_cCACerts)
  5175. {
  5176. CACTX *pCAContext = &g_aCAContext[iCert];
  5177. if (NULL == pCAContext->pccCA)
  5178. {
  5179. hr = S_FALSE;
  5180. goto error;
  5181. }
  5182. *ppapwszCRLList = fDelta?
  5183. pCAContext->papwszDeltaCRLFiles :
  5184. pCAContext->papwszCRLFiles;
  5185. if (NULL != *ppapwszCRLList)
  5186. {
  5187. hr = S_OK;
  5188. }
  5189. }
  5190. error:
  5191. return(hr);
  5192. }
  5193. HRESULT
  5194. pkcsBuildCRLList(
  5195. IN BOOL fDelta,
  5196. IN OUT CACTX *pCAContext,
  5197. OUT WCHAR ***ppapwszOut)
  5198. {
  5199. HRESULT hr;
  5200. DWORD PublishFlag = fDelta? CSURL_SERVERPUBLISHDELTA : CSURL_SERVERPUBLISH;
  5201. DWORD cFiles;
  5202. CSURLTEMPLATE const *pTemplate;
  5203. CSURLTEMPLATE const *pTemplateEnd;
  5204. cFiles = 0;
  5205. pTemplateEnd = &g_paRevURL[g_caRevURL];
  5206. for (pTemplate = g_paRevURL; pTemplate < pTemplateEnd; pTemplate++)
  5207. {
  5208. if (PublishFlag & pTemplate->Flags)
  5209. {
  5210. cFiles++;
  5211. }
  5212. }
  5213. *ppapwszOut = (WCHAR **) LocalAlloc(
  5214. LMEM_FIXED | LMEM_ZEROINIT,
  5215. (cFiles + 1) * sizeof((*ppapwszOut)[0]));
  5216. if (NULL == *ppapwszOut)
  5217. {
  5218. hr = E_OUTOFMEMORY;
  5219. _JumpError(hr, error, "LocalAlloc");
  5220. }
  5221. DBGPRINT((
  5222. DBG_SS_CERTSRVI,
  5223. "CRLList alloc[%u] = %x @%x\n",
  5224. cFiles,
  5225. *ppapwszOut,
  5226. ppapwszOut));
  5227. CSASSERT(NULL != g_strDomainDN && NULL != g_strConfigDN);
  5228. cFiles = 0;
  5229. for (pTemplate = g_paRevURL; pTemplate < pTemplateEnd; pTemplate++)
  5230. {
  5231. if (PublishFlag & pTemplate->Flags)
  5232. {
  5233. hr = myFormatCertsrvStringArray(
  5234. FALSE, // fURL
  5235. g_pwszServerName, // pwszServerName_p1_2
  5236. g_wszSanitizedName, // pwszSanitizedName_p3_7
  5237. pCAContext->iKey, // iCert_p4 -- use iKey!!
  5238. MAXDWORD, // iCertTarget_p4
  5239. g_strDomainDN, // pwszDomainDN_p5
  5240. g_strConfigDN, // pwszConfigDN_p6
  5241. pCAContext->iKey, // iCRL_p8
  5242. fDelta, // fDeltaCRL_p9
  5243. FALSE, // fDSAttrib_p10_11
  5244. 1, // cStrings
  5245. (LPCWSTR *) &pTemplate->pwszURL, // apwszStringsIn
  5246. &(*ppapwszOut)[cFiles]); // apwszStringsOut
  5247. _JumpIfError(hr, error, "myFormatCertsrvStringArray");
  5248. DBGPRINT((
  5249. DBG_SS_CERTSRVI,
  5250. "CRLList format[%u] = %x @%x (%ws)\n",
  5251. cFiles,
  5252. (*ppapwszOut)[cFiles],
  5253. &(*ppapwszOut)[cFiles],
  5254. (*ppapwszOut)[cFiles]));
  5255. cFiles++;
  5256. }
  5257. }
  5258. (*ppapwszOut)[cFiles] = NULL;
  5259. hr = S_OK;
  5260. error:
  5261. // Freeing the CACTX structure during shutdown will free orphaned CRL paths
  5262. return(hr);
  5263. }
  5264. HRESULT
  5265. pkcsBuildKeyAuthority2(
  5266. IN DWORD EditFlags,
  5267. IN CACTX const *pCAContext,
  5268. OUT CRYPT_OBJID_BLOB *pKeyAuthority2)
  5269. {
  5270. HRESULT hr = S_OK;
  5271. CERT_AUTHORITY_KEY_ID2_INFO keyAuth;
  5272. CERT_ALT_NAME_ENTRY AltNameEntry;
  5273. if (0 ==
  5274. ((EDITF_ENABLEAKIKEYID |
  5275. EDITF_ENABLEAKIISSUERNAME |
  5276. EDITF_ENABLEAKIISSUERSERIAL) & EditFlags))
  5277. {
  5278. goto error;
  5279. }
  5280. ZeroMemory(&keyAuth, sizeof(keyAuth));
  5281. // Issuer's KeyId:
  5282. if ((EDITF_ENABLEAKIKEYID & EditFlags) &&
  5283. NULL != pCAContext->IssuerKeyId.pbData)
  5284. {
  5285. keyAuth.KeyId = pCAContext->IssuerKeyId;
  5286. }
  5287. // The Issuer's Issuer name and the Issuer's SerialNumber combined
  5288. // should uniquely identify the Issuer cert.
  5289. // Issuer's Issuer name:
  5290. // -------- ------ ----
  5291. if (EDITF_ENABLEAKIISSUERNAME & EditFlags)
  5292. {
  5293. AltNameEntry.dwAltNameChoice = CERT_ALT_NAME_DIRECTORY_NAME;
  5294. AltNameEntry.DirectoryName = pCAContext->pccCA->pCertInfo->Issuer;
  5295. keyAuth.AuthorityCertIssuer.cAltEntry = 1;
  5296. keyAuth.AuthorityCertIssuer.rgAltEntry = &AltNameEntry;
  5297. }
  5298. // Issuer's SerialNumber:
  5299. if (EDITF_ENABLEAKIISSUERSERIAL & EditFlags)
  5300. {
  5301. keyAuth.AuthorityCertSerialNumber =
  5302. pCAContext->pccCA->pCertInfo->SerialNumber;
  5303. }
  5304. // put in Key Authority Info
  5305. if (!myEncodeKeyAuthority2(
  5306. X509_ASN_ENCODING,
  5307. &keyAuth,
  5308. CERTLIB_USE_LOCALALLOC,
  5309. &pKeyAuthority2->pbData,
  5310. &pKeyAuthority2->cbData))
  5311. {
  5312. hr = myHLastError();
  5313. _JumpError(hr, error, "myEncodeKeyAuthority2");
  5314. }
  5315. error:
  5316. return(hr);
  5317. }
  5318. HRESULT
  5319. pkcsBuildCDP(
  5320. IN DWORD Flags,
  5321. IN BOOL fDelta,
  5322. IN CACTX const *pCAContext,
  5323. OUT CRYPT_OBJID_BLOB *pCDP)
  5324. {
  5325. HRESULT hr;
  5326. DWORD i;
  5327. CSURLTEMPLATE const *pTemplate;
  5328. CSURLTEMPLATE const *pTemplateEnd;
  5329. CRL_DIST_POINTS_INFO CRLDistInfo;
  5330. CRL_DIST_POINT CRLDistPoint;
  5331. CERT_ALT_NAME_INFO *pAltInfo;
  5332. ZeroMemory(&CRLDistPoint, sizeof(CRLDistPoint));
  5333. pAltInfo = &CRLDistPoint.DistPointName.FullName;
  5334. pCDP->pbData = NULL;
  5335. pCDP->cbData = 0;
  5336. pTemplateEnd = g_paCACertURL;
  5337. if (0 != g_caRevURL)
  5338. {
  5339. pTemplateEnd = &g_paRevURL[g_caRevURL];
  5340. for (pTemplate = g_paRevURL; pTemplate < pTemplateEnd; pTemplate++)
  5341. {
  5342. if (Flags & pTemplate->Flags)
  5343. {
  5344. pAltInfo->cAltEntry++;
  5345. }
  5346. }
  5347. }
  5348. if (0 == pAltInfo->cAltEntry)
  5349. {
  5350. hr = S_FALSE;
  5351. goto error;
  5352. }
  5353. CRLDistInfo.cDistPoint = 1;
  5354. CRLDistInfo.rgDistPoint = &CRLDistPoint;
  5355. CRLDistPoint.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
  5356. pAltInfo->rgAltEntry = (CERT_ALT_NAME_ENTRY *) LocalAlloc(
  5357. LMEM_FIXED | LMEM_ZEROINIT,
  5358. pAltInfo->cAltEntry * sizeof(pAltInfo->rgAltEntry[0]));
  5359. if (NULL == pAltInfo->rgAltEntry)
  5360. {
  5361. hr = E_OUTOFMEMORY;
  5362. _JumpError(hr, error, "LocalAlloc");
  5363. }
  5364. CSASSERT(NULL != g_strDomainDN && NULL != g_strConfigDN);
  5365. i = 0;
  5366. for (pTemplate = g_paRevURL; pTemplate < pTemplateEnd; pTemplate++)
  5367. {
  5368. if (Flags & pTemplate->Flags)
  5369. {
  5370. hr = myFormatCertsrvStringArray(
  5371. TRUE, // fURL
  5372. g_pwszServerName, // pwszServerName_p1_2
  5373. g_wszSanitizedName, // pwszSanitizedName_p3_7
  5374. pCAContext->iCert, // iCert_p4
  5375. MAXDWORD, // iCertTarget_p4
  5376. g_strDomainDN, // pwszDomainDN_p5
  5377. g_strConfigDN, // pwszConfigDN_p6
  5378. pCAContext->iKey, // iCRL_p8
  5379. fDelta, // fDeltaCRL_p9
  5380. TRUE, // fDSAttrib_p10_11
  5381. 1, // cStrings
  5382. (LPCWSTR *) &pTemplate->pwszURL, // apwszStringsIn
  5383. &pAltInfo->rgAltEntry[i].pwszURL); // apwszStringsOut
  5384. _JumpIfError(hr, error, "myFormatCertsrvStringArray");
  5385. pAltInfo->rgAltEntry[i].dwAltNameChoice = CERT_ALT_NAME_URL;
  5386. i++;
  5387. }
  5388. }
  5389. CSASSERT(pAltInfo->cAltEntry == i);
  5390. if (!myEncodeObject(
  5391. X509_ASN_ENCODING,
  5392. X509_CRL_DIST_POINTS,
  5393. &CRLDistInfo,
  5394. 0,
  5395. CERTLIB_USE_LOCALALLOC,
  5396. &pCDP->pbData,
  5397. &pCDP->cbData))
  5398. {
  5399. hr = myHLastError();
  5400. _JumpIfError(hr, error, "myEncodeObject");
  5401. }
  5402. hr = S_OK;
  5403. error:
  5404. if (NULL != pAltInfo->rgAltEntry)
  5405. {
  5406. for (i = 0; i < pAltInfo->cAltEntry; i++)
  5407. {
  5408. if (NULL != pAltInfo->rgAltEntry[i].pwszURL)
  5409. {
  5410. LocalFree(pAltInfo->rgAltEntry[i].pwszURL);
  5411. }
  5412. }
  5413. LocalFree(pAltInfo->rgAltEntry);
  5414. }
  5415. return(hr);
  5416. }
  5417. HRESULT
  5418. pkcsBuildAIA(
  5419. IN DWORD Flags,
  5420. IN CACTX const *pCAContext,
  5421. OUT CRYPT_OBJID_BLOB *pAIA)
  5422. {
  5423. HRESULT hr;
  5424. DWORD cAIA;
  5425. DWORD i;
  5426. CSURLTEMPLATE const *pTemplate;
  5427. CSURLTEMPLATE const *pTemplateEnd;
  5428. CERT_AUTHORITY_INFO_ACCESS caio;
  5429. CERT_ACCESS_DESCRIPTION *pcad;
  5430. caio.cAccDescr = 0;
  5431. caio.rgAccDescr = NULL;
  5432. pAIA->pbData = NULL;
  5433. pAIA->cbData = 0;
  5434. cAIA = 0;
  5435. pTemplateEnd = g_paCACertURL;
  5436. if (0 != g_caRevURL)
  5437. {
  5438. pTemplateEnd = &g_paCACertURL[g_caCACertURL];
  5439. for (pTemplate = g_paCACertURL; pTemplate < pTemplateEnd; pTemplate++)
  5440. {
  5441. if (Flags & pTemplate->Flags)
  5442. {
  5443. cAIA++;
  5444. }
  5445. }
  5446. }
  5447. if (0 == cAIA)
  5448. {
  5449. hr = S_FALSE;
  5450. goto error;
  5451. }
  5452. caio.rgAccDescr = (CERT_ACCESS_DESCRIPTION *) LocalAlloc(
  5453. LMEM_FIXED | LMEM_ZEROINIT,
  5454. cAIA * sizeof(caio.rgAccDescr[0]));
  5455. if (NULL == caio.rgAccDescr)
  5456. {
  5457. hr = E_OUTOFMEMORY;
  5458. _JumpError(hr, error, "LocalAlloc");
  5459. }
  5460. CSASSERT(NULL != g_strDomainDN && NULL != g_strConfigDN);
  5461. for (pTemplate = g_paCACertURL; pTemplate < pTemplateEnd; pTemplate++)
  5462. {
  5463. if (Flags & pTemplate->Flags)
  5464. {
  5465. pcad = &caio.rgAccDescr[caio.cAccDescr];
  5466. pcad->pszAccessMethod = (CSURL_ADDTOCERTOCSP & pTemplate->Flags)?
  5467. szOID_PKIX_OCSP : szOID_PKIX_CA_ISSUERS;
  5468. pcad->AccessLocation.dwAltNameChoice = CERT_ALT_NAME_URL;
  5469. hr = myFormatCertsrvStringArray(
  5470. TRUE, // fURL
  5471. g_pwszServerName, // pwszServerName_p1_2
  5472. g_wszSanitizedName, // pwszSanitizedName_p3_7
  5473. pCAContext->iCert, // iCert_p4
  5474. MAXDWORD, // iCertTarget_p4
  5475. g_strDomainDN, // pwszDomainDN_p5
  5476. g_strConfigDN, // pwszConfigDN_p6
  5477. pCAContext->iKey, // iCRL_p8
  5478. FALSE, // fDeltaCRL_p9
  5479. TRUE, // fDSAttrib_p10_11
  5480. 1, // cStrings
  5481. (LPCWSTR *) &pTemplate->pwszURL, // apwszStringsIn
  5482. &pcad->AccessLocation.pwszURL); // apwszStringsOut
  5483. _JumpIfError(hr, error, "myFormatCertsrvStringArray");
  5484. caio.cAccDescr++;
  5485. }
  5486. }
  5487. CSASSERT(caio.cAccDescr == cAIA);
  5488. if (!myEncodeObject(
  5489. X509_ASN_ENCODING,
  5490. X509_AUTHORITY_INFO_ACCESS,
  5491. &caio,
  5492. 0,
  5493. CERTLIB_USE_LOCALALLOC,
  5494. &pAIA->pbData,
  5495. &pAIA->cbData))
  5496. {
  5497. hr = myHLastError();
  5498. _JumpIfError(hr, error, "myEncodeObject");
  5499. }
  5500. hr = S_OK;
  5501. error:
  5502. if (NULL != caio.rgAccDescr)
  5503. {
  5504. for (i = 0; i < caio.cAccDescr; i++)
  5505. {
  5506. pcad = &caio.rgAccDescr[i];
  5507. if (NULL != pcad->AccessLocation.pwszURL)
  5508. {
  5509. LocalFree(pcad->AccessLocation.pwszURL);
  5510. }
  5511. }
  5512. LocalFree(caio.rgAccDescr);
  5513. }
  5514. return(hr);
  5515. }
  5516. HRESULT
  5517. PKCSSetServerProperties(
  5518. IN ICertDBRow *prow,
  5519. OPTIONAL IN CACTX *pCAContext, // signing CACTX
  5520. OPTIONAL IN FILETIME const *pftNotBefore,
  5521. OPTIONAL IN FILETIME const *pftNotAfter,
  5522. IN LONG lValidityPeriodCount,
  5523. IN enum ENUM_PERIOD enumValidityPeriod)
  5524. {
  5525. HRESULT hr;
  5526. CRYPT_OBJID_BLOB aBlob[3];
  5527. CRYPT_OBJID_BLOB *pBlob;
  5528. DWORD i;
  5529. ZeroMemory(aBlob, sizeof(aBlob));
  5530. if (NULL == pCAContext)
  5531. {
  5532. pCAContext = g_pCAContextCurrent;
  5533. }
  5534. hr = pkcsBuildKeyAuthority2(g_CRLEditFlags, pCAContext, &aBlob[0]);
  5535. _JumpIfError(hr, error, "pkcsBuildKeyAuthority2");
  5536. hr = pkcsSetServerExtension(
  5537. prow,
  5538. TEXT(szOID_AUTHORITY_KEY_IDENTIFIER2),
  5539. aBlob[0].cbData,
  5540. aBlob[0].pbData);
  5541. _JumpIfError(hr, error, "pkcsSetServerExtension");
  5542. pBlob = &pCAContext->CDPCert;
  5543. if (pCAContext != g_pCAContextCurrent)
  5544. {
  5545. hr = pkcsBuildCDP(
  5546. CSURL_ADDTOCERTCDP,
  5547. FALSE, // fDelta
  5548. pCAContext,
  5549. &aBlob[1]);
  5550. _JumpIfError(hr, error, "pkcsBuildCDP");
  5551. pBlob = &aBlob[1];
  5552. }
  5553. hr = pkcsSetServerExtension(
  5554. prow,
  5555. TEXT(szOID_CRL_DIST_POINTS),
  5556. pBlob->cbData,
  5557. pBlob->pbData);
  5558. _JumpIfError(hr, error, "pkcsSetServerExtension");
  5559. pBlob = &pCAContext->AIACert;
  5560. if (pCAContext != g_pCAContextCurrent)
  5561. {
  5562. hr = pkcsBuildAIA(
  5563. CSURL_ADDTOCERTCDP | CSURL_ADDTOCERTOCSP,
  5564. pCAContext,
  5565. &aBlob[2]);
  5566. _JumpIfError(hr, error, "pkcsBuildAIA");
  5567. pBlob = &aBlob[2];
  5568. }
  5569. hr = pkcsSetServerExtension(
  5570. prow,
  5571. TEXT(szOID_AUTHORITY_INFO_ACCESS),
  5572. pBlob->cbData,
  5573. pBlob->pbData);
  5574. _JumpIfError(hr, error, "pkcsSetServerExtension");
  5575. hr = pkcsSetValidityPeriod(
  5576. prow,
  5577. pCAContext,
  5578. pftNotBefore,
  5579. pftNotAfter,
  5580. lValidityPeriodCount,
  5581. enumValidityPeriod);
  5582. _JumpIfError(hr, error, "pkcsSetValidityPeriod");
  5583. error:
  5584. for (i = 0; i < ARRAYSIZE(aBlob); i++)
  5585. {
  5586. if (NULL != aBlob[i].pbData)
  5587. {
  5588. LocalFree(aBlob[i].pbData);
  5589. }
  5590. }
  5591. return(hr);
  5592. }
  5593. // Find the newest cert with the matching key container name:
  5594. HRESULT
  5595. pkcsFindMatchingKeyContext(
  5596. OPTIONAL IN CERT_PUBLIC_KEY_INFO *pPublicKeyInfo,
  5597. IN DWORD iKey,
  5598. OUT CACTX **ppCAContext)
  5599. {
  5600. HRESULT hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  5601. DWORD i;
  5602. CACTX *pCAContext;
  5603. *ppCAContext = NULL;
  5604. for (i = g_cCACerts; i > 0; i--)
  5605. {
  5606. pCAContext = &g_aCAContext[i - 1];
  5607. if ((MAXDWORD != iKey && iKey == pCAContext->iKey) ||
  5608. (NULL != pCAContext->pccCA &&
  5609. NULL != pPublicKeyInfo &&
  5610. CertComparePublicKeyInfo(
  5611. X509_ASN_ENCODING,
  5612. pPublicKeyInfo,
  5613. &pCAContext->pccCA->pCertInfo->SubjectPublicKeyInfo)))
  5614. {
  5615. // by design, CertComparePublicKeyInfo doesn't set last error!
  5616. *ppCAContext = pCAContext;
  5617. hr = S_OK;
  5618. break;
  5619. }
  5620. }
  5621. return(hr);
  5622. }
  5623. HRESULT
  5624. pkcsLoadURLTemplates(
  5625. IN WCHAR const *pwszRegName,
  5626. OUT CSURLTEMPLATE **ppaURL,
  5627. OUT DWORD *pcaURL)
  5628. {
  5629. HRESULT hr;
  5630. WCHAR *pwszzTemplates = NULL;
  5631. WCHAR *pwsz;
  5632. DWORD cTemplate = 0;
  5633. CSURLTEMPLATE *pTemplate;
  5634. DWORD Flags;
  5635. WCHAR *pwsz2;
  5636. *ppaURL = NULL;
  5637. *pcaURL = 0;
  5638. // get (multiple) path templates
  5639. hr = myGetCertRegMultiStrValue(
  5640. g_wszSanitizedName,
  5641. NULL,
  5642. NULL,
  5643. pwszRegName,
  5644. &pwszzTemplates);
  5645. _JumpIfError(hr, error, "myGetCertRegStrValue");
  5646. for (pwsz = pwszzTemplates; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
  5647. {
  5648. Flags = _wtoi(pwsz);
  5649. pwsz2 = pwsz;
  5650. while (iswdigit(*pwsz2))
  5651. {
  5652. pwsz2++;
  5653. }
  5654. if (0 != Flags && pwsz2 > pwsz && L':' == *pwsz2)
  5655. {
  5656. cTemplate++;
  5657. }
  5658. }
  5659. if (0 != cTemplate)
  5660. {
  5661. *ppaURL = (CSURLTEMPLATE *) LocalAlloc(
  5662. LMEM_FIXED | LMEM_ZEROINIT,
  5663. cTemplate * sizeof((*ppaURL)[0]));
  5664. if (NULL == *ppaURL)
  5665. {
  5666. hr = E_OUTOFMEMORY;
  5667. _JumpError(hr, error, "LocalAlloc");
  5668. }
  5669. pTemplate = *ppaURL;
  5670. *pcaURL = cTemplate;
  5671. for (pwsz = pwszzTemplates; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
  5672. {
  5673. Flags = _wtoi(pwsz);
  5674. pwsz2 = pwsz;
  5675. while (iswdigit(*pwsz2))
  5676. {
  5677. pwsz2++;
  5678. }
  5679. if (0 != Flags && pwsz2 > pwsz && L':' == *pwsz2)
  5680. {
  5681. pTemplate->Flags = Flags;
  5682. hr = myDupString(&pwsz2[1], &pTemplate->pwszURL);
  5683. _JumpIfError(hr, error, "myDupString");
  5684. pTemplate++;
  5685. }
  5686. }
  5687. CSASSERT(pTemplate == &(*ppaURL)[*pcaURL]);
  5688. }
  5689. error:
  5690. if (NULL != pwszzTemplates)
  5691. {
  5692. LocalFree(pwszzTemplates);
  5693. }
  5694. return(hr);
  5695. }
  5696. VOID
  5697. pkcsFreeTemplates(
  5698. IN OUT CSURLTEMPLATE **ppaURL,
  5699. IN OUT DWORD *pcaURL)
  5700. {
  5701. CSURLTEMPLATE *pTemplate;
  5702. CSURLTEMPLATE *pTemplateEnd;
  5703. if (0 != *pcaURL && NULL != *ppaURL)
  5704. {
  5705. pTemplateEnd = &(*ppaURL)[*pcaURL];
  5706. for (pTemplate = *ppaURL; pTemplate < pTemplateEnd; pTemplate++)
  5707. {
  5708. if (NULL != pTemplate->pwszURL)
  5709. {
  5710. LocalFree(pTemplate->pwszURL);
  5711. }
  5712. }
  5713. LocalFree(*ppaURL);
  5714. *ppaURL = NULL;
  5715. }
  5716. }
  5717. HRESULT
  5718. pkcsGetCertFilename(
  5719. IN WCHAR const *pwszSanitizedName,
  5720. IN DWORD iCert,
  5721. IN DWORD iCertTarget,
  5722. OUT WCHAR **ppwszCertFile)
  5723. {
  5724. HRESULT hr;
  5725. WCHAR wszBuf[MAX_PATH];
  5726. WCHAR *pwszIndexedName = NULL;
  5727. DWORD cwc;
  5728. *ppwszCertFile = NULL;
  5729. hr = myAllocIndexedName(
  5730. pwszSanitizedName,
  5731. iCert,
  5732. iCertTarget,
  5733. &pwszIndexedName);
  5734. _JumpIfError(hr, error, "myAllocIndexedName");
  5735. cwc = GetEnvironmentVariable(L"SystemRoot", wszBuf, ARRAYSIZE(wszBuf));
  5736. if (0 == cwc)
  5737. {
  5738. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  5739. _JumpError(hr, error, "GetEnvironmentVariable");
  5740. }
  5741. if (ARRAYSIZE(wszBuf) < cwc)
  5742. {
  5743. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  5744. _JumpError(hr, error, "%SystemRoot%");
  5745. }
  5746. cwc = wcslen(wszBuf) +
  5747. WSZARRAYSIZE(L"\\System32\\" wszCERTENROLLSHAREPATH L"\\") +
  5748. wcslen(g_pwszServerName) +
  5749. WSZARRAYSIZE(L"_") +
  5750. wcslen(pwszIndexedName) +
  5751. WSZARRAYSIZE(L".crt") +
  5752. 1;
  5753. *ppwszCertFile = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  5754. if (NULL == *ppwszCertFile)
  5755. {
  5756. hr = E_OUTOFMEMORY;
  5757. _JumpError(hr, error, "LocalAlloc");
  5758. }
  5759. wcscpy(*ppwszCertFile, wszBuf);
  5760. wcscat(*ppwszCertFile, L"\\System32\\" wszCERTENROLLSHAREPATH L"\\");
  5761. wcscat(*ppwszCertFile, g_pwszServerName);
  5762. wcscat(*ppwszCertFile, L"_");
  5763. wcscat(*ppwszCertFile, pwszIndexedName);
  5764. wcscat(*ppwszCertFile, L".crt");
  5765. CSASSERT(1 + wcslen(*ppwszCertFile) == cwc);
  5766. error:
  5767. if (NULL != pwszIndexedName)
  5768. {
  5769. LocalFree(pwszIndexedName);
  5770. }
  5771. return(hr);
  5772. }
  5773. HRESULT
  5774. pkcsReloadMissingCertByHash(
  5775. IN WCHAR const *pwszSanitizedName,
  5776. IN DWORD dwRegHashChoice,
  5777. IN BYTE const *pbHashReg,
  5778. IN DWORD cbHashReg,
  5779. IN DWORD iHash,
  5780. IN WCHAR const *pwszStoreName)
  5781. {
  5782. HRESULT hr;
  5783. DWORD cbHash;
  5784. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  5785. BSTR strHash = NULL;
  5786. ICertDBRow *prow = NULL;
  5787. DWORD cbCert;
  5788. BYTE *pbCert = NULL;
  5789. WCHAR *pwszCertFile = NULL;
  5790. CERT_CONTEXT const *pcc = NULL;
  5791. HCERTSTORE hStore = NULL;
  5792. hr = MultiByteIntegerToBstr(TRUE, cbHashReg, pbHashReg, &strHash);
  5793. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  5794. DBGPRINT((
  5795. DBG_SS_CERTSRV,
  5796. "Reloading %wsContext[%u]\n %ws\n",
  5797. CSRH_CASIGCERT == dwRegHashChoice? L"CA" : L"KRA",
  5798. iHash,
  5799. strHash));
  5800. hr = g_pCertDB->OpenRow(
  5801. PROPOPEN_READONLY |
  5802. PROPOPEN_CERTHASH |
  5803. PROPTABLE_REQCERT,
  5804. 0,
  5805. strHash,
  5806. &prow);
  5807. _PrintIfErrorStr(hr, "OpenRow", strHash);
  5808. if (S_OK == hr)
  5809. {
  5810. hr = PKCSGetProperty(
  5811. prow,
  5812. g_wszPropRawCertificate,
  5813. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  5814. &cbCert,
  5815. (BYTE **) &pbCert);
  5816. _JumpIfError(hr, error, "PKCSGetProperty(cert)");
  5817. }
  5818. else if (CSRH_CASIGCERT != dwRegHashChoice)
  5819. {
  5820. _JumpError(hr, error, "OpenRow");
  5821. }
  5822. else
  5823. {
  5824. hr = pkcsGetCertFilename(
  5825. pwszSanitizedName,
  5826. iHash,
  5827. MAXDWORD, // iCertTarget
  5828. &pwszCertFile);
  5829. _JumpIfError(hr, error, "myGetCertFilename");
  5830. hr = DecodeFileW(pwszCertFile, &pbCert, &cbCert, CRYPT_STRING_ANY);
  5831. _JumpIfError(hr, error, "DecodeFileW");
  5832. }
  5833. pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
  5834. if (NULL == pcc)
  5835. {
  5836. hr = myHLastError();
  5837. _JumpError(hr, error, "CertCreateCertificateContext");
  5838. }
  5839. cbHash = sizeof(abHash);
  5840. if (!CertGetCertificateContextProperty(
  5841. pcc,
  5842. CERT_SHA1_HASH_PROP_ID,
  5843. abHash,
  5844. &cbHash))
  5845. {
  5846. hr = myHLastError();
  5847. _JumpError(hr, error, "CertGetCertificateContextProperty");
  5848. }
  5849. if (cbHash != cbHashReg || 0 != memcmp(abHash, pbHashReg, cbHash))
  5850. {
  5851. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  5852. _JumpError(hr, error, "wrong Cert");
  5853. }
  5854. hStore = CertOpenStore(
  5855. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  5856. X509_ASN_ENCODING,
  5857. NULL, // hProv
  5858. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  5859. pwszStoreName);
  5860. if (NULL == hStore)
  5861. {
  5862. hr = myHLastError();
  5863. _JumpErrorStr(hr, error, "CertOpenStore", pwszStoreName);
  5864. }
  5865. if (!CertAddCertificateContextToStore(
  5866. hStore,
  5867. pcc,
  5868. CERT_STORE_ADD_USE_EXISTING,
  5869. NULL))
  5870. {
  5871. hr = myHLastError();
  5872. _JumpError(hr, error, "CertAddCertificateContextToStore");
  5873. }
  5874. // Add as encoded blob to avoid all properties, key prov info, etc.
  5875. if (!CertAddEncodedCertificateToStore(
  5876. hStore,
  5877. X509_ASN_ENCODING,
  5878. pbCert,
  5879. cbCert,
  5880. CERT_STORE_ADD_REPLACE_EXISTING,
  5881. NULL)) // ppCertContext
  5882. {
  5883. hr = myHLastError();
  5884. _JumpError(hr, error, "CertAddEncodedCertificateToStore");
  5885. }
  5886. DBGPRINT((
  5887. DBG_SS_CERTSRV,
  5888. "Reloaded %wsContext[%u]\n",
  5889. CSRH_CASIGCERT == dwRegHashChoice? L"CA" : L"KRA",
  5890. iHash));
  5891. hr = S_OK;
  5892. error:
  5893. if (NULL != pcc)
  5894. {
  5895. CertFreeCertificateContext(pcc);
  5896. }
  5897. if (NULL != hStore)
  5898. {
  5899. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  5900. }
  5901. if (NULL != pwszCertFile)
  5902. {
  5903. LocalFree(pwszCertFile);
  5904. }
  5905. if (NULL != prow)
  5906. {
  5907. prow->Release();
  5908. }
  5909. if (NULL != pbCert)
  5910. {
  5911. LocalFree(pbCert);
  5912. }
  5913. if (NULL != strHash)
  5914. {
  5915. SysFreeString(strHash);
  5916. }
  5917. return(hr);
  5918. }
  5919. HRESULT
  5920. pkcsReloadMissingCAOrKRACert(
  5921. IN WCHAR const *pwszSanitizedName,
  5922. IN DWORD dwRegHashChoice,
  5923. IN DWORD iHash,
  5924. IN WCHAR const *pwszStoreName)
  5925. {
  5926. HRESULT hr;
  5927. BYTE *pbHashReg = NULL;
  5928. DWORD cbHashReg;
  5929. hr = myGetCARegHash(
  5930. pwszSanitizedName,
  5931. dwRegHashChoice,
  5932. iHash,
  5933. &pbHashReg,
  5934. &cbHashReg);
  5935. _JumpIfError(hr, error, "myGetCARegHash");
  5936. hr = pkcsReloadMissingCertByHash(
  5937. pwszSanitizedName,
  5938. dwRegHashChoice,
  5939. pbHashReg,
  5940. cbHashReg,
  5941. iHash,
  5942. pwszStoreName);
  5943. _JumpIfError(hr, error, "pkcsReloadMissingCertByHash");
  5944. error:
  5945. if (NULL != pbHashReg)
  5946. {
  5947. LocalFree(pbHashReg);
  5948. }
  5949. return(hr);
  5950. }
  5951. VOID
  5952. pkcsFreeBlobArray(
  5953. IN DWORD cBlob,
  5954. CERT_BLOB *rgBlob)
  5955. {
  5956. DWORD i;
  5957. for (i = 0; i < cBlob; i++)
  5958. {
  5959. if (NULL != rgBlob[i].pbData)
  5960. {
  5961. LocalFree(rgBlob[i].pbData);
  5962. }
  5963. }
  5964. LocalFree(rgBlob);
  5965. }
  5966. HRESULT
  5967. pkcsGetKRACertBlobs(
  5968. IN ICertDBRow *prow,
  5969. OUT DWORD *pcCertBlob,
  5970. OUT CERT_BLOB **prgCertBlob)
  5971. {
  5972. HRESULT hr;
  5973. WCHAR *pwszHashes = NULL;
  5974. WCHAR *pwsz;
  5975. DWORD cb;
  5976. DWORD cHash;
  5977. DWORD i;
  5978. CERT_BLOB *rgBlob = NULL;
  5979. HCERTSTORE hStore = NULL;
  5980. CRYPT_DATA_BLOB HashBlob;
  5981. DWORD cBlobLoaded;
  5982. CERT_CONTEXT const *pcc = NULL;
  5983. HashBlob.pbData = NULL;
  5984. cBlobLoaded = 0;
  5985. hr = PKCSGetProperty(
  5986. prow,
  5987. g_wszPropRequestKeyRecoveryHashes,
  5988. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  5989. &cb,
  5990. (BYTE **) &pwszHashes);
  5991. _JumpIfError(hr, error, "PKCSGetProperty(KRA hashes)");
  5992. cHash = 1;
  5993. pwsz = pwszHashes;
  5994. for (;;)
  5995. {
  5996. pwsz = wcschr(pwsz, L'\n');
  5997. if (NULL == pwsz)
  5998. {
  5999. break;
  6000. }
  6001. *pwsz++ = L'\0';
  6002. cHash++;
  6003. }
  6004. rgBlob = (CERT_BLOB *) LocalAlloc(
  6005. LMEM_FIXED | LMEM_ZEROINIT,
  6006. cHash * sizeof(rgBlob[0]));
  6007. if (NULL == rgBlob)
  6008. {
  6009. hr = E_OUTOFMEMORY;
  6010. _JumpError(hr, error, "LocalAlloc");
  6011. }
  6012. // open KRA store
  6013. hStore = CertOpenStore(
  6014. CERT_STORE_PROV_SYSTEM_W,
  6015. X509_ASN_ENCODING,
  6016. NULL, // hProv
  6017. CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG,
  6018. wszKRA_CERTSTORE);
  6019. if (NULL == hStore)
  6020. {
  6021. hr = myHLastError();
  6022. _JumpError(hr, error, "CertOpenStore");
  6023. }
  6024. pwsz = pwszHashes;
  6025. for (i = 0; i < cHash; i++)
  6026. {
  6027. BOOL fReloaded;
  6028. hr = WszToMultiByteInteger(
  6029. TRUE,
  6030. pwsz,
  6031. &HashBlob.cbData,
  6032. &HashBlob.pbData);
  6033. _JumpIfError(hr, error, "WszToMultiByteInteger");
  6034. fReloaded = FALSE;
  6035. for (;;)
  6036. {
  6037. pcc = CertFindCertificateInStore(
  6038. hStore,
  6039. X509_ASN_ENCODING,
  6040. 0,
  6041. CERT_FIND_HASH,
  6042. &HashBlob,
  6043. NULL);
  6044. if (fReloaded || NULL != pcc)
  6045. {
  6046. break;
  6047. }
  6048. hr = pkcsReloadMissingCertByHash(
  6049. g_wszSanitizedName,
  6050. CSRH_CAKRACERT,
  6051. HashBlob.pbData,
  6052. HashBlob.cbData,
  6053. i,
  6054. wszKRA_CERTSTORE);
  6055. _PrintIfError(hr, "pkcsReloadMissingCertByHash");
  6056. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  6057. hStore = CertOpenStore(
  6058. CERT_STORE_PROV_SYSTEM_W,
  6059. X509_ASN_ENCODING,
  6060. NULL, // hProv
  6061. CERT_SYSTEM_STORE_LOCAL_MACHINE |
  6062. CERT_STORE_READONLY_FLAG,
  6063. wszKRA_CERTSTORE);
  6064. if (NULL == hStore)
  6065. {
  6066. hr = myHLastError();
  6067. _JumpError(hr, error, "CertOpenStore");
  6068. }
  6069. fReloaded = TRUE;
  6070. }
  6071. if (NULL == pcc)
  6072. {
  6073. hr = myHLastError();
  6074. _PrintError(hr, "CertFindCertificateInStore");
  6075. }
  6076. else
  6077. {
  6078. rgBlob[cBlobLoaded].pbData = (BYTE *) LocalAlloc(
  6079. LMEM_FIXED,
  6080. pcc->cbCertEncoded);
  6081. if (NULL == rgBlob[cBlobLoaded].pbData)
  6082. {
  6083. hr = E_OUTOFMEMORY;
  6084. _JumpError(hr, error, "LocalAlloc");
  6085. }
  6086. rgBlob[cBlobLoaded].cbData = pcc->cbCertEncoded;
  6087. CopyMemory(
  6088. rgBlob[cBlobLoaded].pbData,
  6089. pcc->pbCertEncoded,
  6090. pcc->cbCertEncoded);
  6091. cBlobLoaded++;
  6092. CertFreeCertificateContext(pcc);
  6093. pcc = NULL;
  6094. }
  6095. pwsz += wcslen(pwsz) + 1;
  6096. LocalFree(HashBlob.pbData);
  6097. HashBlob.pbData = NULL;
  6098. }
  6099. *pcCertBlob = cBlobLoaded;
  6100. *prgCertBlob = rgBlob;
  6101. rgBlob = NULL;
  6102. error:
  6103. if (NULL != rgBlob)
  6104. {
  6105. pkcsFreeBlobArray(cBlobLoaded, rgBlob);
  6106. }
  6107. if (NULL != hStore)
  6108. {
  6109. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  6110. }
  6111. if (NULL != pcc)
  6112. {
  6113. CertFreeCertificateContext(pcc);
  6114. }
  6115. if (NULL != HashBlob.pbData)
  6116. {
  6117. LocalFree(HashBlob.pbData);
  6118. }
  6119. if (NULL != pwszHashes)
  6120. {
  6121. LocalFree(pwszHashes);
  6122. }
  6123. return(hr);
  6124. }
  6125. HRESULT
  6126. pkcsGetHashAsOctet(
  6127. IN ICertDBRow *prow,
  6128. OUT BYTE **ppbData,
  6129. OUT DWORD *pcbData)
  6130. {
  6131. HRESULT hr;
  6132. WCHAR *pwszHash = NULL;
  6133. DWORD cb;
  6134. CRYPT_DATA_BLOB Blob;
  6135. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  6136. BYTE *pbCert = NULL;
  6137. DWORD cbCert;
  6138. CERT_CONTEXT const *pcc = NULL;
  6139. *ppbData = NULL;
  6140. Blob.pbData = NULL;
  6141. hr = PKCSGetProperty(
  6142. prow,
  6143. g_wszPropCertificateHash,
  6144. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  6145. &cb,
  6146. (BYTE **) &pwszHash);
  6147. if (S_OK != hr)
  6148. {
  6149. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  6150. {
  6151. _JumpError(hr, error, "PKCSGetProperty(hash)");
  6152. }
  6153. hr = PKCSGetProperty(
  6154. prow,
  6155. g_wszPropRawCertificate,
  6156. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  6157. &cbCert,
  6158. &pbCert);
  6159. _JumpIfError(hr, error, "PKCSGetProperty(cert)");
  6160. pcc = CertCreateCertificateContext(
  6161. X509_ASN_ENCODING,
  6162. pbCert,
  6163. cbCert);
  6164. if (NULL == pcc)
  6165. {
  6166. hr = myHLastError();
  6167. _JumpError(hr, error, "CertCreateCertificateContext");
  6168. }
  6169. Blob.cbData = sizeof(abHash);
  6170. if (!CertGetCertificateContextProperty(
  6171. pcc,
  6172. CERT_SHA1_HASH_PROP_ID,
  6173. abHash,
  6174. &Blob.cbData))
  6175. {
  6176. hr = myHLastError();
  6177. _JumpError(hr, error, "CertGetCertificateContextProperty");
  6178. }
  6179. Blob.pbData = abHash;
  6180. }
  6181. else
  6182. {
  6183. hr = WszToMultiByteInteger(TRUE, pwszHash, &Blob.cbData, &Blob.pbData);
  6184. _JumpIfError(hr, error, "WszToMultiByteInteger");
  6185. }
  6186. if (!myEncodeObject(
  6187. X509_ASN_ENCODING,
  6188. X509_OCTET_STRING,
  6189. &Blob,
  6190. 0,
  6191. CERTLIB_USE_LOCALALLOC,
  6192. ppbData,
  6193. pcbData))
  6194. {
  6195. hr = myHLastError();
  6196. _JumpError(hr, error, "myEncodeObject");
  6197. }
  6198. hr = S_OK;
  6199. error:
  6200. if (NULL != pwszHash)
  6201. {
  6202. LocalFree(pwszHash);
  6203. }
  6204. if (NULL != Blob.pbData && abHash != Blob.pbData)
  6205. {
  6206. LocalFree(Blob.pbData);
  6207. }
  6208. if (NULL != pbCert)
  6209. {
  6210. LocalFree(pbCert);
  6211. }
  6212. if (NULL != pcc)
  6213. {
  6214. CertFreeCertificateContext(pcc);
  6215. }
  6216. return(hr);
  6217. }
  6218. VOID
  6219. AddCertBlobToArray(
  6220. IN CERT_CONTEXT const *pcc,
  6221. IN CERT_BLOB *rgCertBlobAll,
  6222. IN CERT_BLOB **ppCertBlob)
  6223. {
  6224. CERT_BLOB *pCertBlob = *ppCertBlob;
  6225. DWORD i;
  6226. DWORD cBlob;
  6227. cBlob = SAFE_SUBTRACT_POINTERS(pCertBlob, rgCertBlobAll);
  6228. for (i = 0; i < cBlob; i++)
  6229. {
  6230. if (rgCertBlobAll[i].cbData == pcc->cbCertEncoded &&
  6231. 0 == memcmp(
  6232. rgCertBlobAll[i].pbData,
  6233. pcc->pbCertEncoded,
  6234. pcc->cbCertEncoded))
  6235. {
  6236. DBGPRINT((
  6237. DBG_SS_CERTSRV,
  6238. "Duplicate Recovery Blob Cert[%u]\n",
  6239. i));
  6240. goto error;
  6241. }
  6242. }
  6243. DBGPRINT((
  6244. DBG_SS_CERTSRV,
  6245. "Adding Recovery Blob Cert[%u]\n",
  6246. cBlob));
  6247. pCertBlob->cbData = pcc->cbCertEncoded;
  6248. pCertBlob->pbData = pcc->pbCertEncoded;
  6249. pCertBlob++;
  6250. *ppCertBlob = pCertBlob;
  6251. error:
  6252. ;
  6253. }
  6254. HRESULT
  6255. PKCSGetArchivedKey(
  6256. IN DWORD dwRequestId,
  6257. OUT BYTE **ppbArchivedKey, // CoTaskMem*
  6258. OUT DWORD *pcbArchivedKey)
  6259. {
  6260. HRESULT hr;
  6261. ICertDBRow *prow = NULL;
  6262. BYTE *pbKey = NULL;
  6263. DWORD cbKey;
  6264. BYTE *pbCertUser = NULL;
  6265. DWORD cbCertUser;
  6266. HCRYPTMSG hMsg = NULL;
  6267. CACTX *pCAContext;
  6268. CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo;
  6269. CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo;
  6270. CERT_CONTEXT const *pccUser = NULL;
  6271. CERT_CHAIN_CONTEXT const *pCertChainContextUser = NULL;
  6272. CERT_CHAIN_PARA CertChainPara;
  6273. CERT_BLOB *rgCertBlobKRA = NULL;
  6274. DWORD cCertBlobKRA;
  6275. CERT_BLOB *rgCertBlobAll = NULL;
  6276. DWORD cCertBlobAll;
  6277. CERT_BLOB *pCertBlob;
  6278. CRYPT_ATTRIBUTE HashAttrib;
  6279. CRYPT_ATTR_BLOB HashAttribBlob;
  6280. DWORD i;
  6281. *ppbArchivedKey = NULL;
  6282. HashAttribBlob.pbData = NULL;
  6283. cCertBlobKRA = 0;
  6284. hr = g_pCertDB->OpenRow(
  6285. PROPOPEN_READONLY | PROPTABLE_REQCERT,
  6286. dwRequestId,
  6287. NULL,
  6288. &prow);
  6289. _JumpIfError(hr, error, "OpenRow");
  6290. hr = PKCSGetProperty(
  6291. prow,
  6292. g_wszPropRequestRawArchivedKey,
  6293. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  6294. &cbKey,
  6295. &pbKey);
  6296. _JumpIfError(hr, error, "PKCSGetProperty(key)");
  6297. hr = pkcsGetKRACertBlobs(prow, &cCertBlobKRA, &rgCertBlobKRA);
  6298. _JumpIfError(hr, error, "pkcsGetKRACertBlobs");
  6299. hr = pkcsGetHashAsOctet(
  6300. prow,
  6301. &HashAttribBlob.pbData,
  6302. &HashAttribBlob.cbData);
  6303. _JumpIfError(hr, error, "pkcsGetHashAsOctet");
  6304. HashAttrib.pszObjId = szOID_ARCHIVED_KEY_CERT_HASH;
  6305. HashAttrib.cValue = 1;
  6306. HashAttrib.rgValue = &HashAttribBlob;
  6307. hr = PKCSGetProperty(
  6308. prow,
  6309. g_wszPropRawCertificate,
  6310. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  6311. &cbCertUser,
  6312. &pbCertUser);
  6313. _JumpIfError(hr, error, "PKCSGetProperty(cert)");
  6314. pccUser = CertCreateCertificateContext(
  6315. X509_ASN_ENCODING,
  6316. pbCertUser,
  6317. cbCertUser);
  6318. if (NULL == pccUser)
  6319. {
  6320. hr = myHLastError();
  6321. _JumpError(hr, error, "CertCreateCertificateContext");
  6322. }
  6323. // build the user cert chain
  6324. ZeroMemory(&CertChainPara, sizeof(CertChainPara));
  6325. CertChainPara.cbSize = sizeof(CertChainPara);
  6326. if (!CertGetCertificateChain(
  6327. HCCE_LOCAL_MACHINE,
  6328. pccUser,
  6329. NULL,
  6330. NULL,
  6331. &CertChainPara,
  6332. 0,
  6333. NULL,
  6334. &pCertChainContextUser))
  6335. {
  6336. hr = myHLastError();
  6337. _JumpError(hr, error, "CertGetCertificateChain");
  6338. }
  6339. // make sure there is at least 1 simple chain
  6340. if (0 == pCertChainContextUser->cChain)
  6341. {
  6342. hr = E_INVALIDARG;
  6343. _JumpError(hr, error, "No user chain");
  6344. }
  6345. // Encode the encrypted key into a PKCS 7, signed by the current CA cert.
  6346. // Initialize the CMSG_SIGNER_ENCODE_INFO structure for one signer.
  6347. pCAContext = g_pCAContextCurrent;
  6348. cCertBlobAll = cCertBlobKRA +
  6349. pCAContext->cCACertChain +
  6350. pCertChainContextUser->rgpChain[0]->cElement;
  6351. rgCertBlobAll = (CERT_BLOB *) LocalAlloc(
  6352. LMEM_FIXED,
  6353. cCertBlobAll * sizeof(rgCertBlobAll[0]));
  6354. if (NULL == rgCertBlobAll)
  6355. {
  6356. hr = E_OUTOFMEMORY;
  6357. _JumpError(hr, error, "LocalAlloc");
  6358. }
  6359. pCertBlob = rgCertBlobAll;
  6360. CopyMemory(pCertBlob, rgCertBlobKRA, cCertBlobKRA * sizeof(pCertBlob[0]));
  6361. pCertBlob += cCertBlobKRA;
  6362. // Add the current CA cert chain
  6363. for (i = 0; i < pCAContext->cCACertChain; i++)
  6364. {
  6365. AddCertBlobToArray(
  6366. pCAContext->apCACertChain[i],
  6367. rgCertBlobAll,
  6368. &pCertBlob);
  6369. }
  6370. // Add the user cert chain
  6371. {
  6372. CERT_SIMPLE_CHAIN *pSimpleChain;
  6373. pSimpleChain = pCertChainContextUser->rgpChain[0];
  6374. for (i = 0; i < pSimpleChain->cElement; i++)
  6375. {
  6376. AddCertBlobToArray(
  6377. pSimpleChain->rgpElement[i]->pCertContext,
  6378. rgCertBlobAll,
  6379. &pCertBlob);
  6380. }
  6381. }
  6382. CSASSERT(pCertBlob <= &rgCertBlobAll[cCertBlobAll]);
  6383. DBGPRINT((
  6384. DBG_SS_CERTSRV,
  6385. "Recovery Certs: %u --> %u\n",
  6386. cCertBlobAll,
  6387. SAFE_SUBTRACT_POINTERS(pCertBlob, rgCertBlobAll)));
  6388. cCertBlobAll = SAFE_SUBTRACT_POINTERS(pCertBlob, rgCertBlobAll);
  6389. ZeroMemory(&SignerEncodeInfo, sizeof(SignerEncodeInfo));
  6390. SignerEncodeInfo.cbSize = sizeof(SignerEncodeInfo);
  6391. SignerEncodeInfo.pCertInfo = pCAContext->pccCA->pCertInfo;
  6392. SignerEncodeInfo.hCryptProv = pCAContext->hProvCA;
  6393. SignerEncodeInfo.dwKeySpec = AT_SIGNATURE;
  6394. SignerEncodeInfo.HashAlgorithm.pszObjId = szOID_OIWSEC_sha1;
  6395. SignerEncodeInfo.cAuthAttr = 1;
  6396. SignerEncodeInfo.rgAuthAttr = &HashAttrib;
  6397. //SignerEncodeInfo.cUnauthAttr = 0;
  6398. //SignerEncodeInfo.rgUnauthAttr = NULL;
  6399. //SignerEncodeInfo.HashEncryptionAlgorithm.pszObjId = ???;
  6400. // CERT_ID_SHA1_HASH is not yet implemented in CryptMsgOpenToEncode
  6401. //SignerEncodeInfo.SignerId.dwIdChoice = CERT_ID_SHA1_HASH;
  6402. //SignerEncodeInfo.SignerId.HashId.cbData = cb;
  6403. //SignerEncodeInfo.SignerId.HashId.pbData = abHash;
  6404. ZeroMemory(&SignedMsgEncodeInfo, sizeof(SignedMsgEncodeInfo));
  6405. SignedMsgEncodeInfo.cbSize = sizeof(SignedMsgEncodeInfo);
  6406. SignedMsgEncodeInfo.cSigners = 1;
  6407. SignedMsgEncodeInfo.rgSigners = &SignerEncodeInfo;
  6408. SignedMsgEncodeInfo.cCertEncoded = cCertBlobAll;
  6409. SignedMsgEncodeInfo.rgCertEncoded = rgCertBlobAll;
  6410. //SignedMsgEncodeInfo.cCrlEncoded = 0;
  6411. //SignedMsgEncodeInfo.rgCrlEncoded = NULL;
  6412. hMsg = CryptMsgOpenToEncode(
  6413. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  6414. 0, // dwFlags
  6415. CMSG_SIGNED, // dwMsgType
  6416. &SignedMsgEncodeInfo, // pvMsgEncodeInfo
  6417. NULL, // pszInnerContentObjID
  6418. NULL); // pStreamInfo
  6419. if (NULL == hMsg)
  6420. {
  6421. hr = myHLastError();
  6422. _JumpError(hr, error, "CryptMsgOpenToDecode");
  6423. }
  6424. if (!CryptMsgUpdate(hMsg, pbKey, cbKey, TRUE))
  6425. {
  6426. hr = myHLastError();
  6427. _JumpError(hr, error, "CryptMsgUpdate");
  6428. }
  6429. // Return the encoded and signed content.
  6430. // Use CMSG_CONTENT_PARAM to get the signed message.
  6431. hr = myCryptMsgGetParam(
  6432. hMsg,
  6433. CMSG_CONTENT_PARAM,
  6434. 0,
  6435. CERTLIB_USE_COTASKMEMALLOC,
  6436. (VOID **) ppbArchivedKey,
  6437. pcbArchivedKey);
  6438. _JumpIfError(hr, error, "myCryptMsgGetParam");
  6439. error:
  6440. if (pCertChainContextUser != NULL)
  6441. {
  6442. CertFreeCertificateChain(pCertChainContextUser);
  6443. }
  6444. if (NULL != pccUser)
  6445. {
  6446. CertFreeCertificateContext(pccUser);
  6447. }
  6448. if (NULL != hMsg)
  6449. {
  6450. CryptMsgClose(hMsg);
  6451. }
  6452. if (NULL != rgCertBlobKRA)
  6453. {
  6454. pkcsFreeBlobArray(cCertBlobKRA, rgCertBlobKRA);
  6455. }
  6456. if (NULL != rgCertBlobAll)
  6457. {
  6458. LocalFree(rgCertBlobAll);
  6459. }
  6460. if (NULL != HashAttribBlob.pbData)
  6461. {
  6462. LocalFree(HashAttribBlob.pbData);
  6463. }
  6464. if (NULL != pbKey)
  6465. {
  6466. LocalFree(pbKey);
  6467. }
  6468. if (NULL != pbCertUser)
  6469. {
  6470. LocalFree(pbCertUser);
  6471. }
  6472. if (NULL != prow)
  6473. {
  6474. prow->Release();
  6475. }
  6476. return(hr);
  6477. }
  6478. HRESULT
  6479. pkcsGetKeyContainerName(
  6480. IN CERT_CONTEXT const *pccCA,
  6481. OUT WCHAR **ppwszKeyContainerName)
  6482. {
  6483. HRESULT hr;
  6484. CRYPT_HASH_BLOB KeyIdentifier;
  6485. CRYPT_KEY_PROV_INFO *pkpi = NULL;
  6486. DWORD cb;
  6487. KeyIdentifier.pbData = NULL;
  6488. *ppwszKeyContainerName = NULL;
  6489. hr = myGetPublicKeyHash(
  6490. pccCA->pCertInfo,
  6491. &pccCA->pCertInfo->SubjectPublicKeyInfo,
  6492. &KeyIdentifier.pbData,
  6493. &KeyIdentifier.cbData);
  6494. _JumpIfError(hr, error, "myGetPublicKeyHash");
  6495. cb = 0;
  6496. for (;;)
  6497. {
  6498. if (!CryptGetKeyIdentifierProperty(
  6499. &KeyIdentifier,
  6500. CERT_KEY_PROV_INFO_PROP_ID,
  6501. CRYPT_KEYID_MACHINE_FLAG,
  6502. NULL, // pwszComputerName
  6503. NULL, // pvReserved
  6504. pkpi,
  6505. &cb))
  6506. {
  6507. hr = myHLastError();
  6508. _JumpError(hr, error, "Cert index");
  6509. }
  6510. if (NULL != pkpi)
  6511. {
  6512. break;
  6513. }
  6514. pkpi = (CRYPT_KEY_PROV_INFO *) LocalAlloc(LMEM_FIXED, cb);
  6515. if (NULL == pkpi)
  6516. {
  6517. hr = E_OUTOFMEMORY;
  6518. _JumpError(hr, error, "LocalAlloc");
  6519. }
  6520. }
  6521. hr = myDupString(pkpi->pwszContainerName, ppwszKeyContainerName);
  6522. _JumpIfError(hr, error, "myDupString");
  6523. error:
  6524. if (NULL != pkpi)
  6525. {
  6526. LocalFree(pkpi);
  6527. }
  6528. if (NULL != KeyIdentifier.pbData)
  6529. {
  6530. LocalFree(KeyIdentifier.pbData);
  6531. }
  6532. return(hr);
  6533. }
  6534. HRESULT
  6535. pkcsLoadCAContext(
  6536. IN WCHAR const *pwszSanitizedName,
  6537. IN WCHAR *pwszProvName,
  6538. IN DWORD dwProvType,
  6539. IN ALG_ID idAlg,
  6540. IN BOOL fMachineKeyset,
  6541. IN DWORD iHash,
  6542. IN OUT HCERTSTORE *phMyStore)
  6543. {
  6544. HRESULT hr;
  6545. HCRYPTPROV hProvCA = NULL;
  6546. char *pszObjIdSignatureAlgorithm = NULL;
  6547. WCHAR *pwszKeyContainerName = NULL;
  6548. CERT_CONTEXT const *pccCA = NULL;
  6549. DWORD cCACertChain;
  6550. CERT_CONTEXT const **apCACertChain = NULL;
  6551. CERT_CHAIN_CONTEXT const *pCertChainContext = NULL;
  6552. CERT_CHAIN_PARA CertChainPara;
  6553. CRYPT_KEY_PROV_INFO *pKey = NULL;
  6554. CACTX *pCAContext;
  6555. int i;
  6556. DWORD cbKey;
  6557. DWORD iCert;
  6558. DWORD iKey;
  6559. DWORD NameId;
  6560. BOOL fReloaded;
  6561. hr = myGetSigningOID(
  6562. NULL, // hProv
  6563. pwszProvName,
  6564. dwProvType,
  6565. idAlg,
  6566. &pszObjIdSignatureAlgorithm);
  6567. _JumpIfError(hr, error, "myGetSigningOID");
  6568. if (~_16BITMASK & iHash)
  6569. {
  6570. hr = E_INVALIDARG;
  6571. _JumpError(hr, error, "Cert index");
  6572. }
  6573. fReloaded = FALSE;
  6574. cCACertChain = 0;
  6575. for (;;)
  6576. {
  6577. hr = myFindCACertByHashIndex(
  6578. *phMyStore,
  6579. pwszSanitizedName,
  6580. CSRH_CASIGCERT,
  6581. iHash,
  6582. &NameId,
  6583. &pccCA);
  6584. iCert = iHash;
  6585. iKey = iCert;
  6586. if (S_OK == hr)
  6587. {
  6588. break;
  6589. }
  6590. // if no hash entry exists for this index, fake up a CA Context
  6591. // as a place holder.
  6592. if (S_FALSE == hr)
  6593. {
  6594. CSASSERT(MAXDWORD == NameId);
  6595. CSASSERT(NULL == pccCA);
  6596. break;
  6597. }
  6598. if (fReloaded || CRYPT_E_NOT_FOUND != hr)
  6599. {
  6600. _JumpError(hr, error, "myFindCACertByHashIndex");
  6601. }
  6602. _PrintError(hr, "myFindCACertByHashIndex");
  6603. // The CA cert is missing from the HKLM "my" store -- look it up in
  6604. // the DB or the CertEnroll directory, and put it back in the store.
  6605. hr = pkcsReloadMissingCAOrKRACert(
  6606. pwszSanitizedName,
  6607. CSRH_CASIGCERT,
  6608. iHash,
  6609. wszMY_CERTSTORE);
  6610. _JumpIfError(hr, error, "pkcsReloadMissingCAOrKRACert");
  6611. CertCloseStore(*phMyStore, CERT_CLOSE_STORE_CHECK_FLAG);
  6612. *phMyStore = CertOpenStore(
  6613. CERT_STORE_PROV_SYSTEM_W,
  6614. X509_ASN_ENCODING,
  6615. NULL, // hProv
  6616. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  6617. wszMY_CERTSTORE);
  6618. if (NULL == *phMyStore)
  6619. {
  6620. hr = myHLastError();
  6621. _JumpError(hr, error, "CertOpenStore");
  6622. }
  6623. fReloaded = TRUE;
  6624. }
  6625. CSASSERT(S_FALSE == hr || S_OK == hr);
  6626. if (S_OK == hr)
  6627. {
  6628. if (MAXDWORD != NameId && iCert != CANAMEIDTOICERT(NameId))
  6629. {
  6630. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  6631. DBGPRINT((
  6632. DBG_SS_CERTSRV,
  6633. "NameId=%u.%u iCert=%u\n",
  6634. CANAMEIDTOICERT(NameId),
  6635. CANAMEIDTOIKEY(NameId),
  6636. iCert));
  6637. _JumpError(hr, error, "bad iCert");
  6638. }
  6639. fReloaded = FALSE;
  6640. for (;;)
  6641. {
  6642. if (NULL != pwszKeyContainerName)
  6643. {
  6644. LocalFree(pwszKeyContainerName);
  6645. pwszKeyContainerName = NULL;
  6646. }
  6647. if (!fReloaded)
  6648. {
  6649. // get the private key provider info
  6650. if (!myCertGetCertificateContextProperty(
  6651. pccCA,
  6652. CERT_KEY_PROV_INFO_PROP_ID,
  6653. CERTLIB_USE_LOCALALLOC,
  6654. (VOID **) &pKey,
  6655. &cbKey))
  6656. {
  6657. hr = myHLastError();
  6658. if (CRYPT_E_NOT_FOUND != hr)
  6659. {
  6660. _JumpError(hr, error, "myCertGetCertificateContextProperty");
  6661. }
  6662. _PrintError(hr, "CertGetCertificateContextProperty");
  6663. // The Key Provider Info is missing -- use the sanitized
  6664. // name and key index to construct the key container name.
  6665. // If that key matches, we'll write out the new Key
  6666. // Provider Info below.
  6667. hr = myAllocIndexedName(
  6668. pwszSanitizedName,
  6669. MAXDWORD != NameId? CANAMEIDTOIKEY(NameId) : iCert,
  6670. MAXDWORD, // iCertTarget
  6671. &pwszKeyContainerName);
  6672. _JumpIfError(hr, error, "myAllocIndexedName");
  6673. }
  6674. else
  6675. {
  6676. hr = myDupString(pKey->pwszContainerName, &pwszKeyContainerName);
  6677. _JumpIfError(hr, error, "myDupString");
  6678. }
  6679. }
  6680. else
  6681. {
  6682. hr = pkcsGetKeyContainerName(pccCA, &pwszKeyContainerName);
  6683. _JumpIfError(hr, error, "pkcsGetKeyContainerName");
  6684. }
  6685. // test signing
  6686. hr = myValidateSigningKey(
  6687. pwszKeyContainerName,
  6688. pwszProvName,
  6689. dwProvType,
  6690. 0 != g_CryptSilent,
  6691. fMachineKeyset,
  6692. FALSE, // fForceSignatureTest
  6693. pccCA,
  6694. NULL, // pPublicKeyInfo
  6695. idAlg,
  6696. NULL, // pfSigningTestAttempted
  6697. NULL); // phProv
  6698. if (S_OK == hr)
  6699. {
  6700. break;
  6701. }
  6702. if (fReloaded)
  6703. {
  6704. _JumpError(hr, error, "myValidateSigningKey");
  6705. }
  6706. _PrintError(hr, "myValidateSigningKey");
  6707. fReloaded = TRUE;
  6708. }
  6709. // If the Key Provider Info is missing, write out new Key Provider Info
  6710. if (NULL == pKey)
  6711. {
  6712. CRYPT_KEY_PROV_INFO kpi;
  6713. ZeroMemory(&kpi, sizeof(kpi));
  6714. kpi.pwszContainerName = pwszKeyContainerName;
  6715. kpi.pwszProvName = pwszProvName;
  6716. kpi.dwProvType = dwProvType;
  6717. kpi.dwFlags = fMachineKeyset? CRYPT_MACHINE_KEYSET : 0;
  6718. kpi.dwKeySpec = AT_SIGNATURE;
  6719. if (!CertSetCertificateContextProperty(
  6720. pccCA,
  6721. CERT_KEY_PROV_INFO_PROP_ID,
  6722. 0,
  6723. &kpi))
  6724. {
  6725. hr = myHLastError();
  6726. _JumpError(hr, error, "CertSetCertificateContextProperty");
  6727. }
  6728. DBGPRINT((
  6729. DBG_SS_CERTSRV,
  6730. "Reloaded CAContext[%u] KeyProvInfo[%u]\n",
  6731. iCert,
  6732. iKey));
  6733. }
  6734. hr = pkcsFindMatchingKeyContext(
  6735. &pccCA->pCertInfo->SubjectPublicKeyInfo,
  6736. MAXDWORD,
  6737. &pCAContext);
  6738. if (S_OK != hr && MAXDWORD != NameId)
  6739. {
  6740. iKey = CANAMEIDTOIKEY(NameId);
  6741. if (iKey < iCert)
  6742. {
  6743. hr = pkcsFindMatchingKeyContext(NULL, iKey, &pCAContext);
  6744. _JumpIfError(hr, error, "pkcsFindMatchingKeyContext");
  6745. }
  6746. }
  6747. if (S_OK == hr)
  6748. {
  6749. iKey = pCAContext->iKey;
  6750. if (MAXDWORD != NameId && iKey != CANAMEIDTOIKEY(NameId))
  6751. {
  6752. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  6753. _JumpError(hr, error, "bad iKey");
  6754. }
  6755. if (NULL == pCAContext->pccCA)
  6756. {
  6757. CSASSERT(pCAContext->Flags & CTXF_CERTMISSING);
  6758. pCAContext->Flags |= CTXF_CRLZOMBIE;
  6759. }
  6760. else
  6761. {
  6762. // CRLs will be handled by the newest CA cert for this key.
  6763. // Turn off CRLs for older CA certs with this key.
  6764. CSASSERT(0 == (pCAContext->Flags & CTXF_CERTMISSING));
  6765. DBGPRINT((
  6766. DBG_SS_CERTSRVI,
  6767. "pkcsLoadCAContext(%u) DUPKEY, %u.%u: f=%x->%x\n",
  6768. iHash,
  6769. pCAContext->iCert,
  6770. pCAContext->iKey,
  6771. pCAContext->Flags,
  6772. pCAContext->Flags | CTXF_SKIPCRL));
  6773. pCAContext->Flags |= CTXF_SKIPCRL;
  6774. }
  6775. }
  6776. else
  6777. {
  6778. g_cCAKeys++; // this key has not previously been loaded
  6779. }
  6780. DBGPRINT((
  6781. DBG_SS_CERTSRV,
  6782. "CAContext[%u]: Key %u: %ws\n",
  6783. iCert,
  6784. iKey,
  6785. pwszKeyContainerName));
  6786. // get private key handler for later use if current CA
  6787. if (!myCertSrvCryptAcquireContext(
  6788. &hProvCA,
  6789. pwszKeyContainerName,
  6790. pwszProvName,
  6791. dwProvType,
  6792. g_CryptSilent,
  6793. fMachineKeyset))
  6794. {
  6795. hr = myHLastError();
  6796. _JumpErrorStr(
  6797. hr,
  6798. error,
  6799. "myCertSrvCryptAcquireContext",
  6800. pwszKeyContainerName);
  6801. }
  6802. // now try to figure out the chain
  6803. ZeroMemory(&CertChainPara, sizeof(CertChainPara));
  6804. CertChainPara.cbSize = sizeof(CertChainPara);
  6805. if (!CertGetCertificateChain(
  6806. HCCE_LOCAL_MACHINE,
  6807. pccCA,
  6808. NULL,
  6809. NULL,
  6810. &CertChainPara,
  6811. 0,
  6812. NULL,
  6813. &pCertChainContext))
  6814. {
  6815. hr = myHLastError();
  6816. goto error;
  6817. }
  6818. // make sure there is at least 1 simple chain
  6819. if (pCertChainContext->cChain == 0)
  6820. {
  6821. hr = E_INVALIDARG;
  6822. _JumpError(hr, error, "No valid trust chain could be formed");
  6823. }
  6824. // tell global how many elements we have in our chain
  6825. cCACertChain = pCertChainContext->rgpChain[0]->cElement;
  6826. // Allocate memory for global. Allocate one extra pointer to allow loop
  6827. // to assign NULL pointer in place in array. Leave the count set to the
  6828. // actual number of CA cert contexts, excluding the NULL pointer.
  6829. apCACertChain = (CERT_CONTEXT const **) LocalAlloc(
  6830. LMEM_FIXED,
  6831. (cCACertChain + 1) * sizeof(apCACertChain[0]));
  6832. if (NULL == apCACertChain)
  6833. {
  6834. hr = E_OUTOFMEMORY;
  6835. _JumpError(hr, error, "LocalAlloc");
  6836. }
  6837. // copy chain in reverse order: from parent to child
  6838. for (i = cCACertChain - 1; i >= 0; i--)
  6839. {
  6840. apCACertChain[i] = CertDuplicateCertificateContext(
  6841. pCertChainContext->rgpChain[0]->rgpElement[i]->pCertContext);
  6842. if (NULL == apCACertChain[i])
  6843. {
  6844. hr = myHLastError();
  6845. _JumpError(hr, error, "CertDuplicateCertificateContext");
  6846. }
  6847. }
  6848. }
  6849. for (i = 0; i < (int) g_cCACerts; i++)
  6850. {
  6851. if (iCert < g_aCAContext[i].iCert)
  6852. {
  6853. MoveMemory(
  6854. &g_aCAContext[i + 1],
  6855. &g_aCAContext[i],
  6856. (g_cCACerts - i) * sizeof(g_aCAContext[0]));
  6857. break;
  6858. }
  6859. }
  6860. g_cCACerts++;
  6861. pCAContext = &g_aCAContext[i];
  6862. ZeroMemory(pCAContext, sizeof(*pCAContext));
  6863. if (NULL == pccCA)
  6864. {
  6865. pCAContext->Flags |= CTXF_CERTMISSING | CTXF_SKIPCRL;
  6866. }
  6867. pCAContext->iCert = iCert;
  6868. pCAContext->iKey = iKey;
  6869. pCAContext->NameId = MAKECANAMEID(iCert, iKey);
  6870. pCAContext->hProvCA = hProvCA;
  6871. hProvCA = NULL;
  6872. pCAContext->pccCA = pccCA;
  6873. pccCA = NULL;
  6874. if (NULL != apCACertChain)
  6875. {
  6876. pCAContext->cCACertChain = cCACertChain;
  6877. pCAContext->apCACertChain = apCACertChain;
  6878. apCACertChain = NULL;
  6879. }
  6880. pCAContext->pszObjIdSignatureAlgorithm = pszObjIdSignatureAlgorithm;
  6881. pszObjIdSignatureAlgorithm = NULL;
  6882. pCAContext->pwszKeyContainerName = pwszKeyContainerName;
  6883. pwszKeyContainerName = NULL;
  6884. // Ignore failure from here on -- collected data is optional
  6885. if (NULL != pCAContext->pccCA)
  6886. {
  6887. hr = myGetPublicKeyHash(
  6888. pCAContext->pccCA->pCertInfo,
  6889. &pCAContext->pccCA->pCertInfo->SubjectPublicKeyInfo,
  6890. &pCAContext->IssuerKeyId.pbData,
  6891. &pCAContext->IssuerKeyId.cbData);
  6892. _PrintIfError(hr, "myGetPublicKeyHash");
  6893. if (0 == (CTXF_SKIPCRL & pCAContext->Flags))
  6894. {
  6895. hr = pkcsBuildKeyAuthority2(
  6896. g_CRLEditFlags,
  6897. pCAContext,
  6898. &pCAContext->KeyAuthority2CRL);
  6899. _PrintIfError(hr, "pkcsBuildKeyAuthority2");
  6900. hr = pkcsBuildCDP(
  6901. CSURL_ADDTOFRESHESTCRL,
  6902. TRUE, // fDelta
  6903. pCAContext,
  6904. &pCAContext->CDPCRLFreshest);
  6905. _PrintIfError(hr, "pkcsBuildCDP");
  6906. hr = pkcsBuildCDP(
  6907. CSURL_ADDTOCRLCDP,
  6908. FALSE, // fDelta
  6909. pCAContext,
  6910. &pCAContext->CDPCRLBase);
  6911. _PrintIfError(hr, "pkcsBuildCDP");
  6912. hr = pkcsBuildCDP(
  6913. CSURL_ADDTOCRLCDP,
  6914. TRUE, // fDelta
  6915. pCAContext,
  6916. &pCAContext->CDPCRLDelta);
  6917. _PrintIfError(hr, "pkcsBuildCDP");
  6918. hr = pkcsBuildCRLList(
  6919. FALSE,
  6920. pCAContext,
  6921. &pCAContext->papwszCRLFiles);
  6922. _JumpIfError(hr, error, "pkcsBuildCRLList");
  6923. hr = pkcsBuildCRLList(
  6924. TRUE,
  6925. pCAContext,
  6926. &pCAContext->papwszDeltaCRLFiles);
  6927. _JumpIfError(hr, error, "pkcsBuildCRLList");
  6928. }
  6929. }
  6930. hr = S_OK;
  6931. error:
  6932. if (NULL != hProvCA)
  6933. {
  6934. CryptReleaseContext(hProvCA, 0);
  6935. }
  6936. if (NULL != pszObjIdSignatureAlgorithm)
  6937. {
  6938. LocalFree(pszObjIdSignatureAlgorithm);
  6939. }
  6940. if (NULL != pwszKeyContainerName)
  6941. {
  6942. LocalFree(pwszKeyContainerName);
  6943. }
  6944. if (NULL != pKey)
  6945. {
  6946. LocalFree(pKey);
  6947. }
  6948. if (pCertChainContext != NULL)
  6949. {
  6950. CertFreeCertificateChain(pCertChainContext);
  6951. }
  6952. if (NULL != pccCA)
  6953. {
  6954. CertFreeCertificateContext(pccCA);
  6955. }
  6956. return(hr);
  6957. }
  6958. HRESULT
  6959. pkcsLoadCAContextArray(
  6960. IN WCHAR const *pwszSanitizedName)
  6961. {
  6962. HRESULT hr;
  6963. DWORD cCACerts;
  6964. HCERTSTORE hMyStore = NULL;
  6965. WCHAR *pwszProvName = NULL;
  6966. DWORD dwProvType;
  6967. ALG_ID idAlg;
  6968. BOOL fMachineKeyset;
  6969. DWORD iHash;
  6970. // get provider name
  6971. hr = myGetCertSrvCSP(
  6972. FALSE, // fEncryptionCSP
  6973. pwszSanitizedName,
  6974. &dwProvType,
  6975. &pwszProvName,
  6976. &idAlg,
  6977. &fMachineKeyset,
  6978. NULL); // pdwKeySize
  6979. _JumpIfError(hr, error, "myGetCertSrvCSP");
  6980. // open MY store
  6981. hMyStore = CertOpenStore(
  6982. CERT_STORE_PROV_SYSTEM_W,
  6983. X509_ASN_ENCODING,
  6984. NULL, // hProv
  6985. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  6986. wszMY_CERTSTORE);
  6987. if (NULL == hMyStore)
  6988. {
  6989. hr = myHLastError();
  6990. _JumpError(hr, error, "CertOpenStore");
  6991. }
  6992. // find & load CA certs, etc.
  6993. hr = myGetCARegHashCount(pwszSanitizedName, CSRH_CASIGCERT, &cCACerts);
  6994. if (S_OK == hr && 0 == cCACerts)
  6995. {
  6996. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  6997. }
  6998. _JumpIfError(hr, error, "myGetCARegHashCount");
  6999. g_aCAContext = (CACTX *) LocalAlloc(
  7000. LMEM_FIXED | LMEM_ZEROINIT,
  7001. cCACerts * sizeof(g_aCAContext[0]));
  7002. if (NULL == g_aCAContext)
  7003. {
  7004. hr = E_OUTOFMEMORY;
  7005. _JumpError(hr, error, "LocalAlloc");
  7006. }
  7007. for (iHash = 0; iHash < cCACerts; iHash++)
  7008. {
  7009. hr = pkcsLoadCAContext(
  7010. pwszSanitizedName,
  7011. pwszProvName,
  7012. dwProvType,
  7013. idAlg,
  7014. fMachineKeyset,
  7015. iHash,
  7016. &hMyStore);
  7017. if (S_FALSE == hr)
  7018. {
  7019. continue;
  7020. }
  7021. _JumpIfError(hr, error, "pkcsLoadCAContext");
  7022. }
  7023. g_pCAContextCurrent = &g_aCAContext[g_cCACerts - 1];
  7024. // Only build a Key Authority extension for the current CACTX -- it's the
  7025. // only one used to issue certs.
  7026. hr = pkcsBuildKeyAuthority2(
  7027. EDITF_ENABLEAKIKEYID |
  7028. EDITF_ENABLEAKIISSUERNAME |
  7029. EDITF_ENABLEAKIISSUERSERIAL,
  7030. g_pCAContextCurrent,
  7031. &g_pCAContextCurrent->KeyAuthority2Cert);
  7032. _PrintIfError(hr, "pkcsBuildKeyAuthority2");
  7033. // Only build a CDP extension for the current CACTX -- it's the
  7034. // only one used to issue certs.
  7035. hr = pkcsBuildCDP(
  7036. CSURL_ADDTOCERTCDP,
  7037. FALSE, // fDelta
  7038. g_pCAContextCurrent,
  7039. &g_pCAContextCurrent->CDPCert);
  7040. _PrintIfError(hr, "pkcsBuildCDP");
  7041. // Only build an AIA extension for the current CACTX -- it's the
  7042. // only one used to issue certs.
  7043. hr = pkcsBuildAIA(
  7044. CSURL_ADDTOCERTCDP | CSURL_ADDTOCERTOCSP,
  7045. g_pCAContextCurrent,
  7046. &g_pCAContextCurrent->AIACert);
  7047. _PrintIfError(hr, "pkcsBuildAIA");
  7048. hr = S_OK;
  7049. error:
  7050. if (NULL != pwszProvName)
  7051. {
  7052. LocalFree(pwszProvName);
  7053. }
  7054. if (NULL != hMyStore)
  7055. {
  7056. CertCloseStore(hMyStore, CERT_CLOSE_STORE_CHECK_FLAG);
  7057. }
  7058. return(hr);
  7059. }
  7060. BOOL
  7061. pkcsCompareBlob(
  7062. IN CERT_BLOB const *pBlob1,
  7063. IN CERT_BLOB const *pBlob2)
  7064. {
  7065. return(
  7066. pBlob1->cbData == pBlob2->cbData &&
  7067. 0 == memcmp(pBlob1->pbData, pBlob2->pbData, pBlob1->cbData));
  7068. }
  7069. HRESULT
  7070. pkcsAddInheritedExtension(
  7071. IN ICertDBRow *prow,
  7072. IN char const *pszObjId,
  7073. OPTIONAL IN CACTX const *pCAContext,
  7074. OPTIONAL IN CACTX const *pCAContextTarget,
  7075. OUT BOOL *pfAdded)
  7076. {
  7077. HRESULT hr;
  7078. CERT_EXTENSION const *pExt;
  7079. CERT_EXTENSION const *pExtTarget;
  7080. WCHAR *pwszObjId = NULL;
  7081. *pfAdded = FALSE;
  7082. if (NULL == pCAContext)
  7083. {
  7084. pCAContext = g_pCAContextCurrent;
  7085. }
  7086. pExt = CertFindExtension(
  7087. pszObjId,
  7088. pCAContext->pccCA->pCertInfo->cExtension,
  7089. pCAContext->pccCA->pCertInfo->rgExtension);
  7090. if (NULL != pCAContextTarget)
  7091. {
  7092. pExtTarget = CertFindExtension(
  7093. pszObjId,
  7094. pCAContextTarget->pccCA->pCertInfo->cExtension,
  7095. pCAContextTarget->pccCA->pCertInfo->rgExtension);
  7096. if ((NULL != pExt) ^ (NULL != pExtTarget))
  7097. {
  7098. hr = CERTSRV_E_INVALID_CA_CERTIFICATE;
  7099. _JumpError(hr, error, "target/source ext inconsistent");
  7100. }
  7101. if (NULL != pExt && !pkcsCompareBlob(&pExt->Value, &pExtTarget->Value))
  7102. {
  7103. hr = CERTSRV_E_INVALID_CA_CERTIFICATE;
  7104. _JumpError(hr, error, "target/source ext inconsistent");
  7105. }
  7106. }
  7107. if (NULL != pExt)
  7108. {
  7109. if (!myConvertSzToWsz(&pwszObjId, pszObjId, -1))
  7110. {
  7111. hr = E_OUTOFMEMORY;
  7112. _JumpError(hr, error, "myConvertSzToWsz(ObjId)");
  7113. }
  7114. hr = PropSetExtension(
  7115. prow,
  7116. PROPTYPE_BINARY | PROPCALLER_SERVER,
  7117. pwszObjId,
  7118. EXTENSION_ORIGIN_CACERT, // ExtFlags
  7119. pExt->Value.cbData,
  7120. pExt->Value.pbData);
  7121. _JumpIfError(hr, error, "PropSetExtension");
  7122. *pfAdded = TRUE;
  7123. }
  7124. hr = S_OK;
  7125. error:
  7126. if (NULL != pwszObjId)
  7127. {
  7128. LocalFree(pwszObjId);
  7129. }
  7130. return(hr);
  7131. }
  7132. HRESULT
  7133. pkcsAddCannedCertExtensions(
  7134. IN ICertDBRow *prow,
  7135. IN DWORD Flags,
  7136. OPTIONAL IN CACTX const *pCAContext,
  7137. OPTIONAL IN CACTX const *pCAContextTarget,
  7138. OUT char const **ppszObjIdExtError)
  7139. {
  7140. HRESULT hr;
  7141. CERT_EXTENSION aExt[5];
  7142. WCHAR const *apwszObjId[ARRAYSIZE(aExt)];
  7143. DWORD cExt = 0;
  7144. DWORD i;
  7145. BOOL fExtAdded;
  7146. char const *pszObjId = NULL;
  7147. static char *s_apszObjIdXchg[] =
  7148. {
  7149. szOID_KP_CA_EXCHANGE,
  7150. };
  7151. static char *s_apszObjIdAll[] =
  7152. {
  7153. szOID_ANY_CERT_POLICY,
  7154. };
  7155. ZeroMemory(aExt, sizeof(aExt));
  7156. if (NULL == pCAContext)
  7157. {
  7158. pCAContext = g_pCAContextCurrent;
  7159. }
  7160. // szOID_KEY_USAGE
  7161. {
  7162. CRYPT_BIT_BLOB KeyUsage;
  7163. BYTE abKeyUsage[1];
  7164. abKeyUsage[0] = (BYTE) (CRLF_USE_XCHG_CERT_TEMPLATE == Flags?
  7165. CERT_KEY_ENCIPHERMENT_KEY_USAGE : myCASIGN_KEY_USAGE);
  7166. KeyUsage.pbData = abKeyUsage;
  7167. KeyUsage.cbData = sizeof(abKeyUsage);
  7168. KeyUsage.cUnusedBits = 0;
  7169. if (!myEncodeKeyUsage(
  7170. X509_ASN_ENCODING,
  7171. &KeyUsage,
  7172. CERTLIB_USE_LOCALALLOC,
  7173. &aExt[cExt].Value.pbData,
  7174. &aExt[cExt].Value.cbData))
  7175. {
  7176. hr = myHLastError();
  7177. _JumpError(hr, error, "myEncodeKeyUsage");
  7178. }
  7179. apwszObjId[cExt] = TEXT(szOID_KEY_USAGE);
  7180. cExt++;
  7181. }
  7182. if (CRLF_USE_XCHG_CERT_TEMPLATE == Flags)
  7183. {
  7184. // szOID_ENHANCED_KEY_USAGE
  7185. {
  7186. CERT_ENHKEY_USAGE eku;
  7187. eku.cUsageIdentifier = ARRAYSIZE(s_apszObjIdXchg);
  7188. eku.rgpszUsageIdentifier = s_apszObjIdXchg;
  7189. if (!myEncodeObject(
  7190. X509_ASN_ENCODING,
  7191. X509_ENHANCED_KEY_USAGE,
  7192. &eku,
  7193. 0,
  7194. CERTLIB_USE_LOCALALLOC,
  7195. &aExt[cExt].Value.pbData,
  7196. &aExt[cExt].Value.cbData))
  7197. {
  7198. hr = myHLastError();
  7199. _JumpError(hr, error, "myEncodeObject");
  7200. }
  7201. apwszObjId[cExt] = TEXT(szOID_ENHANCED_KEY_USAGE);
  7202. cExt++;
  7203. }
  7204. // szOID_APPLICATION_CERT_POLICIES
  7205. {
  7206. CERT_POLICY_INFO acpi[ARRAYSIZE(s_apszObjIdXchg)];
  7207. CERT_POLICIES_INFO cps;
  7208. ZeroMemory(acpi, sizeof(acpi));
  7209. cps.cPolicyInfo = ARRAYSIZE(s_apszObjIdXchg);
  7210. cps.rgPolicyInfo = acpi;
  7211. for (i = 0; i < ARRAYSIZE(s_apszObjIdXchg); i++)
  7212. {
  7213. acpi[i].pszPolicyIdentifier = s_apszObjIdXchg[i];
  7214. }
  7215. if (!myEncodeObject(
  7216. X509_ASN_ENCODING,
  7217. X509_CERT_POLICIES,
  7218. &cps,
  7219. 0,
  7220. CERTLIB_USE_LOCALALLOC,
  7221. &aExt[cExt].Value.pbData,
  7222. &aExt[cExt].Value.cbData))
  7223. {
  7224. hr = myHLastError();
  7225. _JumpError(hr, error, "myEncodeObject");
  7226. }
  7227. apwszObjId[cExt] = TEXT(szOID_APPLICATION_CERT_POLICIES);
  7228. cExt++;
  7229. }
  7230. }
  7231. else
  7232. {
  7233. // szOID_ENHANCED_KEY_USAGE
  7234. pszObjId = szOID_ENHANCED_KEY_USAGE;
  7235. hr = pkcsAddInheritedExtension(
  7236. prow,
  7237. pszObjId,
  7238. pCAContext,
  7239. pCAContextTarget,
  7240. &fExtAdded);
  7241. _JumpIfError(hr, error, "pkcsAddInheritedExtension");
  7242. // szOID_APPLICATION_CERT_POLICIES
  7243. pszObjId = szOID_APPLICATION_CERT_POLICIES;
  7244. hr = pkcsAddInheritedExtension(
  7245. prow,
  7246. pszObjId,
  7247. pCAContext,
  7248. pCAContextTarget,
  7249. &fExtAdded);
  7250. _JumpIfError(hr, error, "pkcsAddInheritedExtension");
  7251. }
  7252. // szOID_CERT_POLICIES
  7253. pszObjId = szOID_CERT_POLICIES;
  7254. hr = pkcsAddInheritedExtension(
  7255. prow,
  7256. pszObjId,
  7257. pCAContext,
  7258. pCAContextTarget,
  7259. &fExtAdded);
  7260. _JumpIfError(hr, error, "pkcsAddInheritedExtension");
  7261. pszObjId = NULL;
  7262. if (CRLF_USE_XCHG_CERT_TEMPLATE != Flags && !fExtAdded)
  7263. {
  7264. CERT_POLICY_INFO acpi[ARRAYSIZE(s_apszObjIdAll)];
  7265. CERT_POLICIES_INFO cps;
  7266. ZeroMemory(acpi, sizeof(acpi));
  7267. cps.cPolicyInfo = ARRAYSIZE(s_apszObjIdAll);
  7268. cps.rgPolicyInfo = acpi;
  7269. for (i = 0; i < ARRAYSIZE(s_apszObjIdAll); i++)
  7270. {
  7271. acpi[i].pszPolicyIdentifier = s_apszObjIdAll[i];
  7272. }
  7273. if (!myEncodeObject(
  7274. X509_ASN_ENCODING,
  7275. X509_CERT_POLICIES,
  7276. &cps,
  7277. 0,
  7278. CERTLIB_USE_LOCALALLOC,
  7279. &aExt[cExt].Value.pbData,
  7280. &aExt[cExt].Value.cbData))
  7281. {
  7282. hr = myHLastError();
  7283. _JumpError(hr, error, "myEncodeObject");
  7284. }
  7285. apwszObjId[cExt] = TEXT(szOID_CERT_POLICIES);
  7286. cExt++;
  7287. }
  7288. if (CRLF_USE_XCHG_CERT_TEMPLATE != Flags)
  7289. {
  7290. // szOID_BASIC_CONSTRAINTS2
  7291. CERT_BASIC_CONSTRAINTS2_INFO Constraints;
  7292. Constraints.fCA = TRUE;
  7293. Constraints.fPathLenConstraint = FALSE;
  7294. Constraints.dwPathLenConstraint = 0;
  7295. if (!myEncodeObject(
  7296. X509_ASN_ENCODING,
  7297. X509_BASIC_CONSTRAINTS2,
  7298. &Constraints,
  7299. 0,
  7300. CERTLIB_USE_LOCALALLOC,
  7301. &aExt[cExt].Value.pbData,
  7302. &aExt[cExt].Value.cbData))
  7303. {
  7304. hr = myHLastError();
  7305. _JumpError(hr, error, "myEncodeObject");
  7306. }
  7307. aExt[cExt].fCritical = TRUE;
  7308. apwszObjId[cExt] = TEXT(szOID_BASIC_CONSTRAINTS2);
  7309. cExt++;
  7310. }
  7311. CSASSERT(cExt <= ARRAYSIZE(aExt));
  7312. hr = S_OK;
  7313. error:
  7314. *ppszObjIdExtError = pszObjId;
  7315. for (i = 0; i < ARRAYSIZE(aExt); i++)
  7316. {
  7317. if (NULL != aExt[i].Value.pbData)
  7318. {
  7319. HRESULT hr2;
  7320. hr2 = PropSetExtension(
  7321. prow,
  7322. PROPTYPE_BINARY | PROPCALLER_SERVER,
  7323. apwszObjId[i],
  7324. EXTENSION_ORIGIN_SERVER |
  7325. (aExt[i].fCritical? EXTENSION_CRITICAL_FLAG : 0),
  7326. aExt[i].Value.cbData,
  7327. aExt[i].Value.pbData);
  7328. _PrintIfErrorStr(hr2, "PropSetExtension", apwszObjId[i]);
  7329. if (S_OK == hr)
  7330. {
  7331. hr = hr2;
  7332. }
  7333. LocalFree(aExt[i].Value.pbData);
  7334. }
  7335. }
  7336. return(hr);
  7337. }
  7338. HRESULT
  7339. pkcsAddInternalCertExtensions(
  7340. IN ICertDBRow *prow,
  7341. IN BOOL fCrossCert, // else CA Xchg cert
  7342. IN WCHAR const *pwszTemplate,
  7343. OPTIONAL IN CACTX *pCAContext, // signing CACTX
  7344. OPTIONAL IN CACTX *pCAContextTarget, // target CACTX
  7345. OUT char const **ppszObjIdExtError)
  7346. {
  7347. HRESULT hr;
  7348. CERT_EXTENSION Ext;
  7349. HCERTTYPE hCertType = NULL;
  7350. CERT_EXTENSIONS *pExtensions = NULL;
  7351. WCHAR *pwszObjId = NULL;
  7352. DWORD Flags = fCrossCert?
  7353. CRLF_USE_CROSS_CERT_TEMPLATE : CRLF_USE_XCHG_CERT_TEMPLATE;
  7354. ZeroMemory(&Ext, sizeof(Ext));
  7355. *ppszObjIdExtError = NULL;
  7356. // szOID_ENROLL_CERTTYPE_EXTENSION
  7357. hr = myBuildCertTypeExtension(pwszTemplate, &Ext);
  7358. _JumpIfError(hr, error, "myBuildCertTypeExtension");
  7359. hr = PropSetExtension(
  7360. prow,
  7361. PROPTYPE_BINARY | PROPCALLER_SERVER,
  7362. TEXT(szOID_ENROLL_CERTTYPE_EXTENSION),
  7363. EXTENSION_ORIGIN_SERVER, // ExtFlags
  7364. Ext.Value.cbData,
  7365. Ext.Value.pbData);
  7366. _JumpIfError(hr, error, "PropSetExtension");
  7367. hr = S_FALSE;
  7368. if (!fCrossCert || (Flags & g_dwCRLFlags))
  7369. {
  7370. hr = CAFindCertTypeByName(
  7371. pwszTemplate,
  7372. NULL,
  7373. CT_FIND_LOCAL_SYSTEM |
  7374. CT_ENUM_MACHINE_TYPES |
  7375. CT_ENUM_USER_TYPES |
  7376. CT_FLAG_NO_CACHE_LOOKUP,
  7377. &hCertType);
  7378. }
  7379. if (S_OK != hr)
  7380. {
  7381. _PrintErrorStr2(hr, "CAFindCertTypeByName", pwszTemplate, S_FALSE);
  7382. if (Flags & g_dwCRLFlags)
  7383. {
  7384. _JumpIfError(hr, error, "PropSetExtension");
  7385. }
  7386. hr = pkcsAddCannedCertExtensions(
  7387. prow,
  7388. Flags,
  7389. pCAContext,
  7390. pCAContextTarget,
  7391. ppszObjIdExtError);
  7392. _JumpIfError(hr, error, "pkcsAddCannedCertExtensions");
  7393. }
  7394. else
  7395. {
  7396. BOOL fExtAdded;
  7397. if (Flags & g_dwCRLFlags)
  7398. {
  7399. hr = CACertTypeAccessCheckEx(
  7400. hCertType,
  7401. NULL,
  7402. CERTTYPE_ACCESS_CHECK_ENROLL);
  7403. if (E_ACCESSDENIED == hr)
  7404. {
  7405. // map E_ACCESSDENIED to a more meaningful error
  7406. hr = CERTSRV_E_TEMPLATE_DENIED;
  7407. }
  7408. _JumpIfError(hr, error, "CACertTypeAccessCheckEx");
  7409. }
  7410. hr = CAGetCertTypeExtensions(hCertType, &pExtensions);
  7411. _JumpIfError(hr, error, "CAGetCertTypeExtensions");
  7412. // szOID_CERT_POLICIES
  7413. hr = pkcsAddInheritedExtension(
  7414. prow,
  7415. szOID_CERT_POLICIES,
  7416. pCAContext,
  7417. pCAContextTarget,
  7418. &fExtAdded);
  7419. if (S_OK != hr)
  7420. {
  7421. *ppszObjIdExtError = szOID_CERT_POLICIES;
  7422. _JumpError(hr, error, "pkcsAddInheritedExtension");
  7423. }
  7424. if (NULL != pExtensions && 0 != pExtensions->cExtension)
  7425. {
  7426. CERT_EXTENSION *pExt;
  7427. CERT_EXTENSION *pExtEnd;
  7428. pExt = pExtensions->rgExtension;
  7429. pExtEnd = &pExt[pExtensions->cExtension];
  7430. for ( ; pExt < pExtEnd; pExt++)
  7431. {
  7432. if (NULL != pwszObjId)
  7433. {
  7434. LocalFree(pwszObjId);
  7435. pwszObjId = NULL;
  7436. }
  7437. if (!myConvertSzToWsz(&pwszObjId, pExt->pszObjId, -1))
  7438. {
  7439. hr = E_OUTOFMEMORY;
  7440. _JumpError(hr, error, "myConvertSzToWsz(ObjId)");
  7441. }
  7442. hr = PropSetExtension(
  7443. prow,
  7444. PROPTYPE_BINARY | PROPCALLER_SERVER,
  7445. pwszObjId,
  7446. EXTENSION_ORIGIN_SERVER |
  7447. (pExt->fCritical? EXTENSION_CRITICAL_FLAG : 0),
  7448. pExt->Value.cbData,
  7449. pExt->Value.pbData);
  7450. _JumpIfError(hr, error, "PropSetExtension");
  7451. }
  7452. }
  7453. if (CRLF_USE_XCHG_CERT_TEMPLATE == Flags)
  7454. {
  7455. hr = PKCSUpdateXchgValidityPeriods(hCertType);
  7456. _PrintIfError(hr, "PKCSUpdateXchgValidityPeriods");
  7457. }
  7458. }
  7459. hr = S_OK;
  7460. error:
  7461. if (NULL != Ext.Value.pbData)
  7462. {
  7463. LocalFree(Ext.Value.pbData);
  7464. }
  7465. if (NULL != pwszObjId)
  7466. {
  7467. LocalFree(pwszObjId);
  7468. }
  7469. if (NULL != hCertType)
  7470. {
  7471. if (NULL != pExtensions)
  7472. {
  7473. CAFreeCertTypeExtensions(hCertType, pExtensions);
  7474. }
  7475. CACloseCertType(hCertType);
  7476. }
  7477. return(hr);
  7478. }
  7479. HRESULT
  7480. pkcsAddCrossCertVersionExtension(
  7481. IN ICertDBRow *prow,
  7482. IN DWORD CrossCAVersion)
  7483. {
  7484. HRESULT hr;
  7485. BYTE *pbExt = NULL;
  7486. DWORD cbExt;
  7487. // Build the Cross CA Version extension
  7488. if (!myEncodeObject(
  7489. X509_ASN_ENCODING,
  7490. X509_INTEGER,
  7491. &CrossCAVersion,
  7492. 0,
  7493. CERTLIB_USE_LOCALALLOC,
  7494. &pbExt,
  7495. &cbExt))
  7496. {
  7497. hr = myHLastError();
  7498. _JumpError(hr, error, "myEncodeObject");
  7499. }
  7500. hr = PropSetExtension(
  7501. prow,
  7502. PROPTYPE_BINARY | PROPCALLER_SERVER,
  7503. TEXT(szOID_CERTSRV_CROSSCA_VERSION),
  7504. EXTENSION_ORIGIN_SERVER, // ExtFlags
  7505. cbExt,
  7506. pbExt);
  7507. _JumpIfError(hr, error, "PropSetExtension");
  7508. error:
  7509. if (NULL != pbExt)
  7510. {
  7511. LocalFree(pbExt);
  7512. }
  7513. return(hr);
  7514. }
  7515. HRESULT
  7516. pkcsCreateNewInternalCert(
  7517. IN ICertDBRow *prow,
  7518. IN CERT_NAME_BLOB const *pSubject,
  7519. IN HCRYPTPROV hProv,
  7520. OPTIONAL IN WCHAR const *pwszUserName,
  7521. IN BOOL fCrossCert, // else CA Xchg cert
  7522. OPTIONAL IN CACTX *pCAContext, // signing CACTX
  7523. OPTIONAL IN CACTX *pCAContextTarget,// target CACTX
  7524. OPTIONAL IN FILETIME const *pftNotBefore,
  7525. OPTIONAL IN FILETIME const *pftNotAfter,
  7526. OUT CERT_CONTEXT const **ppcc)
  7527. {
  7528. HRESULT hr;
  7529. HRESULT hr2;
  7530. BOOL fErrorLogged = FALSE;
  7531. DWORD dwRequestFlags;
  7532. WCHAR const *pwszTemplate;
  7533. BOOL fSubjectNameSet;
  7534. CERT_PUBLIC_KEY_INFO *pPubKey = NULL;
  7535. DWORD cb;
  7536. CERTTRANSBLOB ctbCert; // CoTaskMem*
  7537. CERTSRV_RESULT_CONTEXT Result;
  7538. WCHAR *pwszDisposition = NULL;
  7539. WCHAR *pwszDispositionCreateCert = NULL;
  7540. WCHAR *pwszMachineRequesterName = NULL;
  7541. char const *pszObjIdExtError = NULL;
  7542. ZeroMemory(&ctbCert, sizeof(ctbCert));
  7543. *ppcc = NULL;
  7544. dwRequestFlags = fCrossCert? CR_FLG_CACROSSCERT : CR_FLG_CAXCHGCERT;
  7545. pwszTemplate = fCrossCert? wszCERTTYPE_CROSS_CA : wszCERTTYPE_CA_EXCHANGE;
  7546. hr = myGetComputerObjectName(NameSamCompatible, &pwszMachineRequesterName);
  7547. if (S_OK != hr)
  7548. {
  7549. _PrintError(hr, "myGetComputerObjectName");
  7550. hr = myGetUserNameEx(NameSamCompatible, &pwszMachineRequesterName);
  7551. _JumpIfError(hr, error, "myGetUserNameEx");
  7552. }
  7553. if (NULL == pwszUserName)
  7554. {
  7555. pwszUserName = pwszMachineRequesterName;
  7556. }
  7557. hr = prow->SetProperty(
  7558. g_wszPropRequesterName,
  7559. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  7560. MAXDWORD,
  7561. (BYTE const *) pwszMachineRequesterName);
  7562. _JumpIfError(hr, error, "SetProperty");
  7563. hr = prow->SetProperty(
  7564. g_wszPropCallerName,
  7565. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  7566. MAXDWORD,
  7567. (BYTE const *) pwszUserName);
  7568. _JumpIfError(hr, error, "SetProperty");
  7569. hr = prow->SetProperty(
  7570. wszPROPCERTIFICATETEMPLATE,
  7571. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  7572. MAXDWORD,
  7573. (BYTE const *) pwszTemplate);
  7574. _JumpIfError(hr, error, "SetProperty");
  7575. if (!myCryptExportPublicKeyInfo(
  7576. hProv,
  7577. fCrossCert? AT_SIGNATURE : AT_KEYEXCHANGE,
  7578. CERTLIB_USE_LOCALALLOC,
  7579. &pPubKey,
  7580. &cb))
  7581. {
  7582. hr = myHLastError();
  7583. _JumpError(hr, error, "myCryptExportPublicKeyInfo");
  7584. }
  7585. hr = PropSetRequestTimeProperty(prow, g_wszPropRequestSubmittedWhen);
  7586. _JumpIfError(hr, error, "PropSetRequestTimeProperty");
  7587. hr = PropSetRequestTimeProperty(prow, g_wszPropRequestResolvedWhen);
  7588. _JumpIfError(hr, error, "PropSetRequestTimeProperty");
  7589. hr = CoreSetDisposition(prow, DB_DISP_ACTIVE);
  7590. _JumpIfError(hr, error, "CoreSetDisposition");
  7591. hr = pkcsSetRequestNameInfo(
  7592. prow,
  7593. pSubject,
  7594. fCrossCert? NULL : g_wszCNXchgSuffix,
  7595. FALSE, // fReorderLikeRDNs
  7596. &dwRequestFlags,
  7597. &fSubjectNameSet);
  7598. _JumpIfError(hr, error, "pkcsSetRequestNameInfo");
  7599. hr = prow->SetProperty(
  7600. g_wszPropRequestFlags,
  7601. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  7602. sizeof(dwRequestFlags),
  7603. (BYTE const *) &dwRequestFlags);
  7604. _JumpIfError(hr, error, "SetProperty(RequestFlags)");
  7605. CSASSERT(fSubjectNameSet);
  7606. hr = pkcsSetPublicKeyProperties(prow, pPubKey);
  7607. _JumpIfError(hr, error, "pkcsSetPublicKeyProperties");
  7608. hr = prow->CopyRequestNames();
  7609. _JumpIfError(hr, error, "CopyRequestNames");
  7610. hr = PKCSSetServerProperties(
  7611. prow,
  7612. pCAContext, // optional signing context
  7613. pftNotBefore,
  7614. pftNotAfter,
  7615. g_lCAXchgValidityPeriodCount,
  7616. g_enumCAXchgValidityPeriod);
  7617. _JumpIfError(hr, error, "PKCSSetServerProperties");
  7618. hr = pkcsAddInternalCertExtensions(
  7619. prow,
  7620. fCrossCert,
  7621. pwszTemplate,
  7622. pCAContext,
  7623. pCAContextTarget,
  7624. &pszObjIdExtError);
  7625. _JumpIfError(hr, error, "pkcsAddInternalCertExtensions");
  7626. ZeroMemory(&Result, sizeof(Result));
  7627. Result.pctbCert = &ctbCert;
  7628. hr = PKCSCreateCertificate(
  7629. prow,
  7630. DB_DISP_ISSUED,
  7631. FALSE, // fIncludeCRLs
  7632. fCrossCert,
  7633. pCAContext, // optional signing context
  7634. &fErrorLogged,
  7635. NULL, // ppCAContext
  7636. &pwszDispositionCreateCert,
  7637. &Result);
  7638. _JumpIfError(hr, error, "PKCSCreateCertificate");
  7639. *ppcc = CertCreateCertificateContext(
  7640. X509_ASN_ENCODING,
  7641. ctbCert.pb,
  7642. ctbCert.cb);
  7643. if (NULL == *ppcc)
  7644. {
  7645. hr = myHLastError();
  7646. _JumpError(hr, error, "CertCreateCertificateContext");
  7647. }
  7648. hr = S_OK;
  7649. error:
  7650. pwszDisposition = CoreBuildDispositionString(
  7651. g_pwszRequestedBy,
  7652. pwszUserName,
  7653. pwszDispositionCreateCert,
  7654. NULL,
  7655. NULL,
  7656. S_OK,
  7657. FALSE);
  7658. hr2 = CoreSetRequestDispositionFields(
  7659. prow,
  7660. hr,
  7661. S_OK == hr? DB_DISP_ISSUED : DB_DISP_DENIED,
  7662. pwszDisposition);
  7663. _PrintIfError(hr2, "CoreSetRequestDispositionFields");
  7664. if (S_OK == hr)
  7665. {
  7666. hr = hr2;
  7667. }
  7668. if (S_OK != hr && !fErrorLogged)
  7669. {
  7670. DWORD LogMsg;
  7671. WCHAR const *apwsz[3];
  7672. DWORD cpwsz;
  7673. WCHAR wszVersion[2 * cwcDWORDSPRINTF + 1];
  7674. cpwsz = 0;
  7675. LogMsg = MSG_E_CANNOT_CREATE_XCHG_CERT;
  7676. if (fCrossCert)
  7677. {
  7678. wszVersion[0] = L'\0';
  7679. if (NULL != pCAContext && NULL != pCAContextTarget)
  7680. {
  7681. wsprintf(
  7682. wszVersion, L"(%u-%u)",
  7683. pCAContext->iCert,
  7684. pCAContextTarget->iCert);
  7685. }
  7686. apwsz[cpwsz++] = wszVersion;
  7687. LogMsg = MSG_E_CANNOT_CREATE_CROSS_CERT;
  7688. if (NULL != pszObjIdExtError)
  7689. {
  7690. LogMsg = MSG_E_CROSS_CERT_EXTENSION_CONFLICT;
  7691. apwsz[cpwsz++] = myGetOIDNameA(pszObjIdExtError);
  7692. }
  7693. }
  7694. apwsz[cpwsz++] = NULL != pwszDisposition?
  7695. pwszDisposition : pwszDispositionCreateCert;
  7696. LogEventStringArrayHResult(
  7697. EVENTLOG_ERROR_TYPE,
  7698. LogMsg,
  7699. cpwsz,
  7700. apwsz,
  7701. hr);
  7702. }
  7703. if (NULL != pwszMachineRequesterName)
  7704. {
  7705. LocalFree(pwszMachineRequesterName);
  7706. }
  7707. if (NULL != pwszDisposition)
  7708. {
  7709. LocalFree(pwszDisposition);
  7710. }
  7711. if (NULL != pwszDispositionCreateCert)
  7712. {
  7713. LocalFree(pwszDispositionCreateCert);
  7714. }
  7715. if (NULL != ctbCert.pb)
  7716. {
  7717. CoTaskMemFree(ctbCert.pb);
  7718. }
  7719. if (NULL != pPubKey)
  7720. {
  7721. LocalFree(pPubKey);
  7722. }
  7723. return(hr);
  7724. }
  7725. HRESULT
  7726. pkcsFormXchgKeyContainerName(
  7727. IN DWORD dwRequestId,
  7728. OUT WCHAR **ppwszKeyContainer)
  7729. {
  7730. HRESULT hr;
  7731. DWORD cwcSuffix;
  7732. DWORD cwcName;
  7733. WCHAR wszSuffix[ARRAYSIZE(g_wszCNXchgSuffix) + 1 + cwcDWORDSPRINTF + 1];
  7734. WCHAR wszKeyContainer[MAX_PATH];
  7735. *ppwszKeyContainer = NULL;
  7736. cwcSuffix = wsprintf(wszSuffix, L"%ws(%u)", g_wszCNXchgSuffix, dwRequestId);
  7737. CSASSERT(ARRAYSIZE(wszSuffix) > cwcSuffix);
  7738. cwcName = wcslen(g_wszSanitizedName);
  7739. if (cwcName > MAX_PATH - cwcSuffix)
  7740. {
  7741. cwcName = MAX_PATH - cwcSuffix;
  7742. }
  7743. CSASSERT(ARRAYSIZE(wszKeyContainer) > cwcName);
  7744. wcscpy(wszKeyContainer, g_wszSanitizedName);
  7745. wcscpy(&wszKeyContainer[cwcName], wszSuffix);
  7746. hr = myDupString(wszKeyContainer, ppwszKeyContainer);
  7747. _JumpIfError(hr, error, "myDupString");
  7748. DBGPRINT((
  7749. DBG_SS_CERTSRV,
  7750. "pkcsFormXchgKeyContainerName: %ws\n",
  7751. *ppwszKeyContainer));
  7752. error:
  7753. return(hr);
  7754. }
  7755. VOID
  7756. pkcsDeleteKey(
  7757. OPTIONAL IN WCHAR const *pwszKeyContainer)
  7758. {
  7759. HRESULT hr;
  7760. HCRYPTPROV hProv;
  7761. if (NULL != pwszKeyContainer)
  7762. {
  7763. if (!CryptAcquireContext(
  7764. &hProv,
  7765. pwszKeyContainer,
  7766. g_pwszXchgProvName,
  7767. g_dwXchgProvType,
  7768. CRYPT_DELETEKEYSET |
  7769. g_CryptSilent |
  7770. (g_fXchgMachineKeyset? CRYPT_MACHINE_KEYSET : 0)))
  7771. {
  7772. hr = myHLastError();
  7773. _JumpError(hr, error, "CryptAcquireContext");
  7774. }
  7775. }
  7776. error:
  7777. ;
  7778. }
  7779. VOID
  7780. pkcsLoadCAXchgCSPInfo(
  7781. IN BOOL fSetDefaults)
  7782. {
  7783. HRESULT hr = S_FALSE;
  7784. if (NULL != g_pwszXchgProvName)
  7785. {
  7786. LocalFree(g_pwszXchgProvName);
  7787. g_pwszXchgProvName = NULL;
  7788. }
  7789. if (!fSetDefaults)
  7790. {
  7791. hr = myGetCertSrvCSP(
  7792. TRUE, // fEncryptionCSP
  7793. g_wszSanitizedName,
  7794. &g_dwXchgProvType,
  7795. &g_pwszXchgProvName,
  7796. &g_XchgidAlg,
  7797. &g_fXchgMachineKeyset,
  7798. &g_dwXchgKeySize);
  7799. if (S_OK != hr)
  7800. {
  7801. _PrintError(hr, "myGetCertSrvCSP(CAXchg)");
  7802. }
  7803. }
  7804. if (S_OK != hr)
  7805. {
  7806. g_dwXchgProvType = PROV_RSA_FULL;
  7807. g_pwszXchgProvName = NULL;
  7808. g_XchgidAlg = CALG_3DES;
  7809. g_fXchgMachineKeyset = TRUE;
  7810. g_dwXchgKeySize = 0;
  7811. }
  7812. if (0 == g_dwXchgKeySize)
  7813. {
  7814. g_dwXchgKeySize = 1024;
  7815. }
  7816. }
  7817. HRESULT
  7818. pkcsCreateNewCAXchgCert(
  7819. IN WCHAR const *pwszUserName)
  7820. {
  7821. HRESULT hr;
  7822. ICertDBRow *prow = NULL;
  7823. BOOL fErrorLogged = FALSE;
  7824. DWORD i;
  7825. CAXCHGCTX CAXchgContext;
  7826. CAXCHGCTX *rgCAXchgContext;
  7827. ZeroMemory(&CAXchgContext, sizeof(CAXchgContext));
  7828. hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, 0, NULL, &prow);
  7829. _JumpIfError(hr, error, "OpenRow");
  7830. prow->GetRowId(&CAXchgContext.ReqId);
  7831. hr = pkcsFormXchgKeyContainerName(
  7832. CAXchgContext.ReqId,
  7833. &CAXchgContext.pwszKeyContainerName);
  7834. _JumpIfError(hr, error, "pkcsFormXchgKeyContainerName");
  7835. for (i = 0; ; i++)
  7836. {
  7837. hr = myGenerateKeys(
  7838. CAXchgContext.pwszKeyContainerName,
  7839. g_pwszXchgProvName,
  7840. g_CryptSilent,
  7841. g_fXchgMachineKeyset,
  7842. AT_KEYEXCHANGE,
  7843. g_dwXchgProvType,
  7844. g_dwXchgKeySize,
  7845. &CAXchgContext.hProvCA);
  7846. if (S_OK == hr)
  7847. {
  7848. break;
  7849. }
  7850. _PrintErrorStr(hr, "myGenerateKeys", g_pwszXchgProvName);
  7851. LogEventHResult(
  7852. NULL == g_pwszXchgProvName?
  7853. EVENTLOG_ERROR_TYPE :
  7854. EVENTLOG_WARNING_TYPE,
  7855. NULL == g_pwszXchgProvName?
  7856. MSG_E_BAD_DEFAULT_CA_XCHG_CSP :
  7857. MSG_E_BAD_REGISTRY_CA_XCHG_CSP,
  7858. hr);
  7859. if (0 != i || NULL == g_pwszXchgProvName)
  7860. {
  7861. fErrorLogged = TRUE;
  7862. _JumpError(hr, error, "myGenerateKeys");
  7863. }
  7864. pkcsLoadCAXchgCSPInfo(TRUE); // switch to default CSP
  7865. }
  7866. if (0 != i)
  7867. {
  7868. hr = LogEvent(
  7869. EVENTLOG_WARNING_TYPE,
  7870. MSG_E_USE_DEFAULT_CA_XCHG_CSP,
  7871. 0, // cpwsz
  7872. NULL); // apwsz
  7873. _PrintIfError(hr, "LogEvent");
  7874. }
  7875. hr = mySetKeyContainerSecurity(CAXchgContext.hProvCA);
  7876. _JumpIfError(hr, error, "mySetKeyContainerSecurity");
  7877. hr = pkcsCreateNewInternalCert(
  7878. prow,
  7879. &g_pCAContextCurrent->pccCA->pCertInfo->Subject,
  7880. CAXchgContext.hProvCA,
  7881. pwszUserName,
  7882. FALSE, // fCrossCert
  7883. NULL, // use default signing CACTX
  7884. NULL, // pCAContextTarget
  7885. NULL, // pftNotBefore
  7886. NULL, // pftNotAfter
  7887. &CAXchgContext.pccCAXchg);
  7888. _JumpIfError(hr, error, "pkcsCreateNewInternalCert");
  7889. if (NULL == g_aCAXchgContext)
  7890. {
  7891. CSASSERT(0 == g_cCAXchgCerts);
  7892. rgCAXchgContext = (CAXCHGCTX *) LocalAlloc(
  7893. LMEM_FIXED,
  7894. sizeof(rgCAXchgContext[0]));
  7895. }
  7896. else
  7897. {
  7898. rgCAXchgContext = (CAXCHGCTX *) LocalReAlloc(
  7899. g_aCAXchgContext,
  7900. (g_cCAXchgCerts + 1) * sizeof(rgCAXchgContext[0]),
  7901. LMEM_MOVEABLE);
  7902. }
  7903. if (NULL == rgCAXchgContext)
  7904. {
  7905. hr = E_OUTOFMEMORY;
  7906. _JumpError(hr, error, "LocalAlloc/ReAlloc");
  7907. }
  7908. g_aCAXchgContext = rgCAXchgContext;
  7909. g_aCAXchgContext[g_cCAXchgCerts] = CAXchgContext;
  7910. g_pCAXchgContextCurrent = &g_aCAXchgContext[g_cCAXchgCerts];
  7911. g_cCAXchgCerts++;
  7912. ZeroMemory(&CAXchgContext, sizeof(CAXchgContext));
  7913. hr = S_OK;
  7914. error:
  7915. if (NULL != prow)
  7916. {
  7917. HRESULT hr2;
  7918. hr2 = prow->CommitTransaction(TRUE);
  7919. _PrintIfError(hr2, "CommitTransaction");
  7920. if (S_OK == hr)
  7921. {
  7922. hr = hr2;
  7923. }
  7924. if (S_OK != hr2)
  7925. {
  7926. hr2 = prow->CommitTransaction(FALSE);
  7927. _PrintIfError(hr2, "CommitTransaction");
  7928. }
  7929. prow->Release();
  7930. }
  7931. if (NULL != CAXchgContext.pccCAXchg)
  7932. {
  7933. CertFreeCertificateContext(CAXchgContext.pccCAXchg);
  7934. }
  7935. if (NULL != CAXchgContext.hProvCA)
  7936. {
  7937. CryptReleaseContext(CAXchgContext.hProvCA, 0);
  7938. pkcsDeleteKey(CAXchgContext.pwszKeyContainerName);
  7939. }
  7940. if (NULL != CAXchgContext.pwszKeyContainerName)
  7941. {
  7942. LocalFree(CAXchgContext.pwszKeyContainerName);
  7943. }
  7944. return(hr);
  7945. }
  7946. HRESULT
  7947. pkcsCreateNewCrossCert(
  7948. IN OUT CACROSSCTX *pCACross,
  7949. IN FILETIME const *pftNotBefore,
  7950. IN FILETIME const *pftNotAfter)
  7951. {
  7952. HRESULT hr;
  7953. ICertDBRow *prow = NULL;
  7954. WCHAR wszIndex[2 * cwcDWORDSPRINTF + 1];
  7955. CERT_INFO const *pCertInfoCATarget;
  7956. wsprintf(
  7957. wszIndex,
  7958. L"%u-%u",
  7959. pCACross->pCAContext->iCert,
  7960. pCACross->pCAContextTarget->iCert);
  7961. hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, 0, NULL, &prow);
  7962. _JumpIfErrorStr(hr, error, "OpenRow", wszIndex);
  7963. prow->GetRowId(&pCACross->ReqId);
  7964. pCertInfoCATarget = pCACross->pCAContextTarget->pccCA->pCertInfo;
  7965. hr = pkcsSetExtensions(
  7966. prow,
  7967. EXTENSION_ORIGIN_CACERT,
  7968. pCertInfoCATarget->rgExtension,
  7969. pCertInfoCATarget->cExtension);
  7970. _JumpIfError(hr, error, "pkcsSetExtensions(old cert)");
  7971. hr = pkcsAddCrossCertVersionExtension(
  7972. prow,
  7973. MAKECROSSCAVERSION(
  7974. pCACross->pCAContext->iCert,
  7975. pCACross->pCAContextTarget->iCert));
  7976. _JumpIfError(hr, error, "pkcsAddCrossCertExtensions");
  7977. hr = pkcsCreateNewInternalCert(
  7978. prow,
  7979. &pCertInfoCATarget->Subject,
  7980. pCACross->pCAContextTarget->hProvCA, // for the public key
  7981. NULL, // pwszUserName
  7982. TRUE, // fCrossCert
  7983. pCACross->pCAContext, // signing context
  7984. pCACross->pCAContextTarget, // target context
  7985. pftNotBefore,
  7986. pftNotAfter,
  7987. &pCACross->pccCACross);
  7988. _JumpIfErrorStr(hr, error, "pkcsCreateNewInternalCert", wszIndex);
  7989. error:
  7990. if (NULL != prow)
  7991. {
  7992. HRESULT hr2;
  7993. hr2 = prow->CommitTransaction(TRUE);
  7994. _PrintIfError(hr2, "CommitTransaction");
  7995. if (S_OK == hr)
  7996. {
  7997. hr = hr2;
  7998. }
  7999. if (S_OK != hr2)
  8000. {
  8001. hr2 = prow->CommitTransaction(FALSE);
  8002. _PrintIfError(hr2, "CommitTransaction");
  8003. }
  8004. prow->Release();
  8005. }
  8006. return(hr);
  8007. }
  8008. CERT_CONTEXT const *
  8009. pkcsFindCertificateInStore(
  8010. IN HCERTSTORE hStore,
  8011. IN CERT_CONTEXT const *pCert)
  8012. {
  8013. BYTE rgbHash[CBMAX_CRYPT_HASH_LEN];
  8014. CRYPT_DATA_BLOB HashBlob;
  8015. HashBlob.pbData = rgbHash;
  8016. HashBlob.cbData = sizeof(rgbHash);
  8017. if (!CertGetCertificateContextProperty(
  8018. pCert,
  8019. CERT_SHA1_HASH_PROP_ID,
  8020. rgbHash,
  8021. &HashBlob.cbData) ||
  8022. sizeof(rgbHash) != HashBlob.cbData)
  8023. {
  8024. return(NULL);
  8025. }
  8026. return(CertFindCertificateInStore(
  8027. hStore,
  8028. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,// dwCertEncodingType
  8029. 0, // dwFindFlags
  8030. CERT_FIND_SHA1_HASH,
  8031. (const void *) &HashBlob,
  8032. NULL)); // pPrevCertContext
  8033. }
  8034. HRESULT
  8035. pkcsWriteCertToStore(
  8036. IN WCHAR const *pwszStore,
  8037. IN BOOL fEnterprise,
  8038. IN BOOL fDelete,
  8039. IN CERT_CONTEXT const *pcc,
  8040. OUT LONG *plDisposition)
  8041. {
  8042. HRESULT hr;
  8043. HCERTSTORE hStore = NULL;
  8044. CERT_CONTEXT const *pccT;
  8045. *plDisposition = 0;
  8046. hStore = CertOpenStore(
  8047. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  8048. X509_ASN_ENCODING,
  8049. NULL, // hProv
  8050. fEnterprise?
  8051. CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE :
  8052. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  8053. pwszStore);
  8054. if (NULL == hStore)
  8055. {
  8056. hr = myHLastError();
  8057. _JumpError(hr, error, "CertOpenStore");
  8058. }
  8059. pccT = pkcsFindCertificateInStore(hStore, pcc);
  8060. if (NULL != pccT)
  8061. {
  8062. if (fDelete)
  8063. {
  8064. CertDeleteCertificateFromStore(pccT);
  8065. *plDisposition = -1;
  8066. }
  8067. else
  8068. {
  8069. // already added; do nothing
  8070. CertFreeCertificateContext(pccT);
  8071. }
  8072. }
  8073. else
  8074. {
  8075. if (!fDelete)
  8076. {
  8077. if (!CertAddCertificateContextToStore(
  8078. hStore,
  8079. pcc,
  8080. CERT_STORE_ADD_USE_EXISTING,
  8081. NULL))
  8082. {
  8083. hr = myHLastError();
  8084. _JumpError(hr, error, "CertAddCertificateContextToStore");
  8085. }
  8086. *plDisposition = 1;
  8087. }
  8088. else
  8089. {
  8090. // already deleted; do nothing
  8091. }
  8092. }
  8093. hr = S_OK;
  8094. error:
  8095. if (NULL != hStore)
  8096. {
  8097. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  8098. }
  8099. return(hr);
  8100. }
  8101. // if necessary, publish to System32\CertSrv\CertEnroll directory
  8102. // if necessary, publish to HKLM CA cert store
  8103. // if necessary, publish to crossCertificatePair in this CA's AIA object
  8104. HRESULT
  8105. pkcsPublishCrossCert(
  8106. IN OUT CACROSSCTX *pCACross,
  8107. IN BOOL fDelete)
  8108. {
  8109. HRESULT hr;
  8110. HRESULT hr2;
  8111. WCHAR *pwszFile = NULL;
  8112. LONG lDisposition;
  8113. hr = pkcsGetCertFilename(
  8114. g_wszSanitizedName,
  8115. pCACross->pCAContext->iCert,
  8116. pCACross->pCAContextTarget->iCert,
  8117. &pwszFile);
  8118. _JumpIfError(hr, error, "myGetCertFilename");
  8119. hr = CRLWriteToLockedFile(
  8120. pCACross->pccCACross->pbCertEncoded,
  8121. pCACross->pccCACross->cbCertEncoded,
  8122. fDelete,
  8123. pwszFile);
  8124. _PrintIfError(hr, "CRLWriteToLockedFile");
  8125. hr2 = pkcsWriteCertToStore(
  8126. wszCA_CERTSTORE,
  8127. FALSE, // fEnterprise
  8128. fDelete,
  8129. pCACross->pccCACross,
  8130. &lDisposition);
  8131. if (S_OK == hr)
  8132. {
  8133. hr = hr2; // return first error
  8134. }
  8135. _PrintIfError(hr2, "pkcsWriteCertToStore");
  8136. if (g_fUseDS)
  8137. {
  8138. // don't attempt to create the object, should already be there
  8139. hr = CorePublishCrossCertificate(
  8140. pCACross->ReqId,
  8141. pCACross->pccCACross,
  8142. FALSE, // fCreateDSObject
  8143. fDelete); // fDelete
  8144. if (S_OK == hr)
  8145. {
  8146. hr = hr2; // return first error
  8147. }
  8148. _JumpIfError(hr2, error, "CorePublishCrossCertificate");
  8149. }
  8150. _JumpIfError(hr, error, "pkcsPublishCrossCert");
  8151. error:
  8152. if (NULL != pwszFile)
  8153. {
  8154. LocalFree(pwszFile);
  8155. }
  8156. return(hr);
  8157. }
  8158. // Verify the cert matches the expected Cross cert contents:
  8159. // 1) verify timestamps meet expectations
  8160. // 2) Issuer and Subject both match CA binary subject
  8161. // 3) it is a CrossCA cert (v1 CrossCA template extension)
  8162. // 4) IssuerNameId matches source CA cert key index
  8163. // 5) SubjectKeyId matches target CA cert SubjectKeyId
  8164. HRESULT
  8165. pkcsVerifyCrossCertificate(
  8166. IN BYTE const *pbCert,
  8167. IN DWORD cbCert,
  8168. IN FILETIME const *pftNotBefore,
  8169. IN FILETIME const *pftNotAfter,
  8170. IN OUT CACROSSCTX *pCACross)
  8171. {
  8172. HRESULT hr;
  8173. CERT_CONTEXT const *pcc = NULL;
  8174. CERT_NAME_BLOB const *pSubject;
  8175. CERT_EXTENSION const *pExtCross;
  8176. CERT_EXTENSION const *pExt;
  8177. CERT_NAME_VALUE *pName = NULL;
  8178. CERT_AUTHORITY_KEY_ID2_INFO *pInfo = NULL;
  8179. CERT_BLOB *pSKIBlob = NULL;
  8180. DWORD cb;
  8181. CSASSERT(NULL == pCACross->pccCACross);
  8182. pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
  8183. if (NULL == pcc)
  8184. {
  8185. hr = myHLastError();
  8186. _JumpError(hr, error, "CertCreateCertificateContext");
  8187. }
  8188. // verify timestamps meet expectations
  8189. // verify Subject & Issuer match CA Subject
  8190. pSubject = &pCACross->pCAContext->pccCA->pCertInfo->Subject;
  8191. if (0 != CompareFileTime(pftNotBefore, &pcc->pCertInfo->NotBefore) ||
  8192. 0 != CompareFileTime(pftNotAfter, &pcc->pCertInfo->NotAfter) ||
  8193. !pkcsCompareBlob(pSubject, &pcc->pCertInfo->Subject) ||
  8194. !pkcsCompareBlob(pSubject, &pcc->pCertInfo->Issuer))
  8195. {
  8196. hr = CRYPT_E_NOT_FOUND;
  8197. _JumpError2(hr, error, "NotBefore/NotAfter/Subject/Issuer", hr);
  8198. }
  8199. // verify v1 CrossCA template extension
  8200. pExtCross = CertFindExtension(
  8201. szOID_ENROLL_CERTTYPE_EXTENSION,
  8202. pcc->pCertInfo->cExtension,
  8203. pcc->pCertInfo->rgExtension);
  8204. if (NULL == pExtCross)
  8205. {
  8206. hr = CRYPT_E_NOT_FOUND;
  8207. _JumpError(hr, error, "No Template");
  8208. }
  8209. if (!myDecodeObject(
  8210. X509_ASN_ENCODING,
  8211. X509_UNICODE_ANY_STRING,
  8212. pExtCross->Value.pbData,
  8213. pExtCross->Value.cbData,
  8214. CERTLIB_USE_LOCALALLOC,
  8215. (VOID **) &pName,
  8216. &cb))
  8217. {
  8218. hr = myHLastError();
  8219. _JumpError(hr, error, "Policy:myDecodeObject");
  8220. }
  8221. if (0 != LSTRCMPIS(
  8222. (WCHAR const *) pName->Value.pbData,
  8223. wszCERTTYPE_CROSS_CA))
  8224. {
  8225. hr = CRYPT_E_NOT_FOUND;
  8226. _JumpError(hr, error, "No Template");
  8227. }
  8228. // verify SKI matches target SKI
  8229. pExtCross = CertFindExtension(
  8230. szOID_SUBJECT_KEY_IDENTIFIER,
  8231. pcc->pCertInfo->cExtension,
  8232. pcc->pCertInfo->rgExtension);
  8233. pExt = CertFindExtension(
  8234. szOID_SUBJECT_KEY_IDENTIFIER,
  8235. pCACross->pCAContextTarget->pccCA->pCertInfo->cExtension,
  8236. pCACross->pCAContextTarget->pccCA->pCertInfo->rgExtension);
  8237. if (NULL == pExtCross ||
  8238. NULL == pExt ||
  8239. !pkcsCompareBlob(&pExtCross->Value, &pExt->Value))
  8240. {
  8241. hr = CRYPT_E_NOT_FOUND;
  8242. _JumpError(hr, error, "SKI");
  8243. }
  8244. // verify AKI KeyId matches source SKI
  8245. pExtCross = CertFindExtension(
  8246. szOID_AUTHORITY_KEY_IDENTIFIER2,
  8247. pcc->pCertInfo->cExtension,
  8248. pcc->pCertInfo->rgExtension);
  8249. pExt = CertFindExtension(
  8250. szOID_SUBJECT_KEY_IDENTIFIER,
  8251. pCACross->pCAContext->pccCA->pCertInfo->cExtension,
  8252. pCACross->pCAContext->pccCA->pCertInfo->rgExtension);
  8253. if (NULL == pExtCross || NULL == pExt)
  8254. {
  8255. hr = CRYPT_E_NOT_FOUND;
  8256. _JumpError(hr, error, "SKI");
  8257. }
  8258. if (!myDecodeObject(
  8259. X509_ASN_ENCODING,
  8260. X509_AUTHORITY_KEY_ID2,
  8261. pExtCross->Value.pbData,
  8262. pExtCross->Value.cbData,
  8263. CERTLIB_USE_LOCALALLOC,
  8264. (VOID **) &pInfo,
  8265. &cb))
  8266. {
  8267. hr = myHLastError();
  8268. _JumpIfError(hr, error, "Policy:myDecodeObject");
  8269. }
  8270. if (!myDecodeObject(
  8271. X509_ASN_ENCODING,
  8272. X509_OCTET_STRING,
  8273. pExt->Value.pbData,
  8274. pExt->Value.cbData,
  8275. CERTLIB_USE_LOCALALLOC,
  8276. (VOID **) &pSKIBlob,
  8277. &cb))
  8278. {
  8279. hr = myHLastError();
  8280. _JumpIfError(hr, error, "Policy:myDecodeObject");
  8281. }
  8282. if (!pkcsCompareBlob(pSKIBlob, &pInfo->KeyId))
  8283. {
  8284. hr = CRYPT_E_NOT_FOUND;
  8285. _JumpError(hr, error, "AKI");
  8286. }
  8287. pCACross->pccCACross = pcc;
  8288. pcc = NULL;
  8289. hr = S_OK;
  8290. error:
  8291. if (NULL != pSKIBlob)
  8292. {
  8293. LocalFree(pSKIBlob);
  8294. }
  8295. if (NULL != pName)
  8296. {
  8297. LocalFree(pName);
  8298. }
  8299. if (NULL != pInfo)
  8300. {
  8301. LocalFree(pInfo);
  8302. }
  8303. if (NULL != pcc)
  8304. {
  8305. CertFreeCertificateContext(pcc);
  8306. }
  8307. return(hr);
  8308. }
  8309. // Query for a cert matching the CA's Common Name AND
  8310. // IssuerNameId matches source CA cert key index
  8311. DWORD g_aColCross[] = {
  8312. #define ICOL_RAWCERTIFICATE 0
  8313. DTI_CERTIFICATETABLE | DTC_RAWCERTIFICATE,
  8314. };
  8315. HRESULT
  8316. pkcsLoadCrossCertFromDB(
  8317. IN OUT CACROSSCTX *pCACross,
  8318. IN FILETIME const *pftNotBefore,
  8319. IN FILETIME const *pftNotAfter)
  8320. {
  8321. HRESULT hr;
  8322. CERTVIEWRESTRICTION acvr[3];
  8323. CERTVIEWRESTRICTION *pcvr;
  8324. DWORD NameIdMin;
  8325. DWORD NameIdMax;
  8326. IEnumCERTDBRESULTROW *pView = NULL;
  8327. DWORD celtFetched;
  8328. DWORD i;
  8329. BOOL fEnd;
  8330. CERTDBRESULTROW aResult[1];
  8331. BOOL fResultActive = FALSE;
  8332. CSASSERT(NULL == pCACross->pccCACross);
  8333. // Set up restrictions as follows:
  8334. pcvr = acvr;
  8335. // CommonName == g_wszCommonName
  8336. pcvr->ColumnIndex = DTI_CERTIFICATETABLE | DTC_COMMONNAME;
  8337. pcvr->SeekOperator = CVR_SEEK_EQ;
  8338. pcvr->SortOrder = CVR_SORT_ASCEND;
  8339. pcvr->pbValue = (BYTE *) g_wszCommonName;
  8340. pcvr->cbValue = sizeof(WCHAR) * (wcslen(g_wszCommonName) + 1);
  8341. pcvr++;
  8342. // NameId >= MAKECANAMEID(iCert == 0, iKey)
  8343. NameIdMin = MAKECANAMEID(0, pCACross->pCAContext->iKey);
  8344. pcvr->ColumnIndex = DTI_CERTIFICATETABLE | DTC_CERTIFICATEISSUERNAMEID;
  8345. pcvr->SeekOperator = CVR_SEEK_GE;
  8346. pcvr->SortOrder = CVR_SORT_NONE;
  8347. pcvr->pbValue = (BYTE *) &NameIdMin;
  8348. pcvr->cbValue = sizeof(NameIdMin);
  8349. pcvr++;
  8350. // NameId <= MAKECANAMEID(iCert == _16BITMASK, iKey)
  8351. NameIdMax = MAKECANAMEID(_16BITMASK, pCACross->pCAContext->iKey);
  8352. pcvr->ColumnIndex = DTI_CERTIFICATETABLE | DTC_CERTIFICATEISSUERNAMEID;
  8353. pcvr->SeekOperator = CVR_SEEK_LE;
  8354. pcvr->SortOrder = CVR_SORT_NONE;
  8355. pcvr->pbValue = (BYTE *) &NameIdMax;
  8356. pcvr->cbValue = sizeof(NameIdMax);
  8357. pcvr++;
  8358. CSASSERT(ARRAYSIZE(acvr) == SAFE_SUBTRACT_POINTERS(pcvr, acvr));
  8359. celtFetched = 0;
  8360. hr = g_pCertDB->OpenView(
  8361. ARRAYSIZE(acvr),
  8362. acvr,
  8363. ARRAYSIZE(g_aColCross),
  8364. g_aColCross,
  8365. 0, // no worker thread
  8366. &pView);
  8367. _JumpIfError(hr, error, "OpenView");
  8368. fEnd = FALSE;
  8369. while (!fEnd)
  8370. {
  8371. hr = pView->Next(NULL, ARRAYSIZE(aResult), aResult, &celtFetched);
  8372. if (S_FALSE == hr)
  8373. {
  8374. fEnd = TRUE;
  8375. if (0 == celtFetched)
  8376. {
  8377. break;
  8378. }
  8379. hr = S_OK;
  8380. }
  8381. _JumpIfError(hr, error, "Next");
  8382. fResultActive = TRUE;
  8383. CSASSERT(ARRAYSIZE(aResult) >= celtFetched);
  8384. for (i = 0; i < celtFetched; i++)
  8385. {
  8386. CERTDBRESULTROW *pResult = &aResult[i];
  8387. CSASSERT(ARRAYSIZE(g_aColCross) == pResult->ccol);
  8388. if (NULL == pResult->acol[ICOL_RAWCERTIFICATE].pbValue)
  8389. {
  8390. continue;
  8391. }
  8392. CSASSERT(PROPTYPE_BINARY == (PROPTYPE_MASK & pResult->acol[ICOL_RAWCERTIFICATE].Type));
  8393. hr = pkcsVerifyCrossCertificate(
  8394. pResult->acol[ICOL_RAWCERTIFICATE].pbValue,
  8395. pResult->acol[ICOL_RAWCERTIFICATE].cbValue,
  8396. pftNotBefore,
  8397. pftNotAfter,
  8398. pCACross);
  8399. _PrintIfError2(hr, "pkcsVerifyCrossCertificate", hr);
  8400. if (S_OK == hr)
  8401. {
  8402. CSASSERT(NULL != pCACross->pccCACross);
  8403. fEnd = TRUE;
  8404. break;
  8405. }
  8406. }
  8407. pView->ReleaseResultRow(celtFetched, aResult);
  8408. fResultActive = FALSE;
  8409. }
  8410. hr = NULL != pCACross->pccCACross? S_OK : CRYPT_E_NOT_FOUND;
  8411. _JumpIfError(hr, error, "pCACross->pccCACross");
  8412. error:
  8413. if (NULL != pView)
  8414. {
  8415. if (fResultActive)
  8416. {
  8417. pView->ReleaseResultRow(celtFetched, aResult);
  8418. }
  8419. pView->Release();
  8420. }
  8421. return(hr);
  8422. }
  8423. #undef ICOL_RAWCERTIFICATE
  8424. HRESULT
  8425. pkcsLoadCrossCertFromFile(
  8426. IN OUT CACROSSCTX *pCACross,
  8427. IN FILETIME const *pftNotBefore,
  8428. IN FILETIME const *pftNotAfter)
  8429. {
  8430. HRESULT hr;
  8431. WCHAR *pwszFile = NULL;
  8432. BYTE *pbCert = NULL;
  8433. DWORD cbCert;
  8434. hr = pkcsGetCertFilename(
  8435. g_wszSanitizedName,
  8436. pCACross->pCAContext->iCert,
  8437. pCACross->pCAContextTarget->iCert,
  8438. &pwszFile);
  8439. _JumpIfError(hr, error, "myGetCertFilename");
  8440. hr = DecodeFileW(pwszFile, &pbCert, &cbCert, CRYPT_STRING_ANY);
  8441. _JumpIfError(hr, error, "DecodeFileW");
  8442. hr = pkcsVerifyCrossCertificate(
  8443. pbCert,
  8444. cbCert,
  8445. pftNotBefore,
  8446. pftNotAfter,
  8447. pCACross);
  8448. _JumpIfError(hr, error, "pkcsVerifyCrossCertificate");
  8449. error:
  8450. if (NULL != pwszFile)
  8451. {
  8452. LocalFree(pwszFile);
  8453. }
  8454. if (NULL != pbCert)
  8455. {
  8456. LocalFree(pbCert);
  8457. }
  8458. return(hr);
  8459. }
  8460. HRESULT
  8461. pkcsImportCAOrCrossOrKRACert(
  8462. IN CERT_CONTEXT const *pcc,
  8463. IN BOOL fCrossCert, // else CA or KRA cert
  8464. IN DWORD DBDisposition,
  8465. OPTIONAL IN CACTX const *pCAContext)
  8466. {
  8467. HRESULT hr;
  8468. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  8469. DWORD cbHash;
  8470. BSTR strHash = NULL;
  8471. ICertDBRow *prow = NULL;
  8472. WCHAR *pwszUserName = NULL;
  8473. DWORD cb;
  8474. BOOL fCommit = FALSE;
  8475. BOOL fCommitted = FALSE;
  8476. cbHash = sizeof(abHash);
  8477. if (!CertGetCertificateContextProperty(
  8478. pcc,
  8479. CERT_HASH_PROP_ID,
  8480. abHash,
  8481. &cbHash))
  8482. {
  8483. hr = myHLastError();
  8484. _JumpError(hr, error, "CertGetCertificateContextProperty");
  8485. }
  8486. hr = MultiByteIntegerToBstr(TRUE, cbHash, abHash, &strHash);
  8487. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  8488. // Import Cert if it doesn't already exist in DB:
  8489. hr = g_pCertDB->OpenRow(
  8490. PROPOPEN_CERTHASH | PROPTABLE_REQCERT,
  8491. 0,
  8492. strHash,
  8493. &prow);
  8494. if (S_OK != hr)
  8495. {
  8496. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  8497. {
  8498. _JumpError(hr, error, "OpenRow");
  8499. }
  8500. hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, 0, NULL, &prow);
  8501. _JumpIfError(hr, error, "OpenRow");
  8502. hr = PKCSParseImportedCertificate(
  8503. prow,
  8504. fCrossCert,
  8505. DBDisposition,
  8506. pCAContext,
  8507. pcc);
  8508. _JumpIfError(hr, error, "PKCSParseImportedCertificate");
  8509. fCommit = TRUE;
  8510. }
  8511. // Set requester name if missing
  8512. hr = prow->GetProperty(
  8513. g_wszPropRequesterName,
  8514. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  8515. NULL,
  8516. &cb,
  8517. NULL);
  8518. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  8519. {
  8520. hr = myGetComputerObjectName(NameSamCompatible, &pwszUserName);
  8521. if (S_OK != hr)
  8522. {
  8523. _PrintError(hr, "myGetComputerObjectName");
  8524. hr = myGetUserNameEx(NameSamCompatible, &pwszUserName);
  8525. _JumpIfError(hr, error, "myGetUserNameEx");
  8526. }
  8527. hr = prow->SetProperty(
  8528. g_wszPropRequesterName,
  8529. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  8530. MAXDWORD,
  8531. (BYTE const *) pwszUserName);
  8532. _JumpIfError(hr, error, "SetProperty");
  8533. hr = prow->SetProperty(
  8534. g_wszPropCallerName,
  8535. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  8536. MAXDWORD,
  8537. (BYTE const *) pwszUserName);
  8538. _JumpIfError(hr, error, "SetProperty");
  8539. fCommit = TRUE;
  8540. }
  8541. if (DB_DISP_REVOKED == DBDisposition)
  8542. {
  8543. DWORD DispositionOld;
  8544. cb = sizeof(DispositionOld);
  8545. hr = prow->GetProperty(
  8546. g_wszPropRequestDisposition,
  8547. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  8548. NULL,
  8549. &cb,
  8550. (BYTE *) &DispositionOld);
  8551. _JumpIfError(hr, error, "GetProperty(Disposition)");
  8552. CSASSERT(
  8553. DB_DISP_ISSUED == DispositionOld ||
  8554. DB_DISP_REVOKED == DispositionOld);
  8555. if (DB_DISP_ISSUED == DispositionOld)
  8556. {
  8557. fCommit = TRUE;
  8558. hr = pkcsSetRevocationFields(prow);
  8559. _JumpIfError(hr, error, "pkcsSetRevocationFields");
  8560. }
  8561. }
  8562. hr = prow->CommitTransaction(fCommit);
  8563. _JumpIfError(hr, error, "CommitTransaction");
  8564. fCommitted = TRUE;
  8565. hr = S_OK;
  8566. error:
  8567. if (NULL != prow)
  8568. {
  8569. if (S_OK != hr && !fCommitted)
  8570. {
  8571. HRESULT hr2 = prow->CommitTransaction(FALSE);
  8572. _PrintIfError(hr2, "CommitTransaction");
  8573. }
  8574. prow->Release();
  8575. }
  8576. if (NULL != pwszUserName)
  8577. {
  8578. LocalFree(pwszUserName);
  8579. }
  8580. if (NULL != strHash)
  8581. {
  8582. SysFreeString(strHash);
  8583. }
  8584. return(hr);
  8585. }
  8586. // If the row exists in the database, do not create a new Cross cert -- even if
  8587. // the attempt to create a cross cert failed. The row must be deleted to cause
  8588. // a new Cross cert creation attempt.
  8589. // If the cert exists in the row, load the cert context without validation.
  8590. HRESULT
  8591. pkcsLoadCrossCert(
  8592. IN OUT CACROSSCTX *pCACross,
  8593. IN FILETIME *pftNow,
  8594. IN BOOL fForward,
  8595. IN BOOL fRevoke)
  8596. {
  8597. HRESULT hr;
  8598. CACTX *pCAContextOld;
  8599. CACTX *pCAContextNew;
  8600. FILETIME const *pftNotBefore;
  8601. FILETIME const *pftNotAfter;
  8602. if (fForward)
  8603. {
  8604. pCAContextOld = pCACross->pCAContext;
  8605. pCAContextNew = pCACross->pCAContextTarget;
  8606. }
  8607. else
  8608. {
  8609. pCAContextOld = pCACross->pCAContextTarget;
  8610. pCAContextNew = pCACross->pCAContext;
  8611. }
  8612. if (NULL != pCAContextOld->pccCA && NULL != pCAContextNew->pccCA)
  8613. {
  8614. pftNotBefore = &pCAContextNew->pccCA->pCertInfo->NotBefore;
  8615. pftNotAfter = &pCAContextOld->pccCA->pCertInfo->NotAfter;
  8616. // Query for Cross cert -- see above criteria
  8617. hr = pkcsLoadCrossCertFromDB(pCACross, pftNotBefore, pftNotAfter);
  8618. _PrintIfError(hr, "pkcsLoadCrossCertFromDB");
  8619. // if not in DB, look in CertEnroll directory
  8620. if (NULL == pCACross->pccCACross)
  8621. {
  8622. hr = pkcsLoadCrossCertFromFile(pCACross, pftNotBefore, pftNotAfter);
  8623. _PrintIfError(hr, "pkcsLoadCrossCertFromFile");
  8624. }
  8625. // if not yet loaded or found, create a new one
  8626. if (NULL == pCACross->pccCACross)
  8627. {
  8628. // Only create a cross cert if:
  8629. // 1) neither CA cert is revoked -- if !fRevoke
  8630. // 2) old CA cert is not yet expired
  8631. // 3) overlap period exists
  8632. if (!fRevoke &&
  8633. 0 > CompareFileTime(pftNow, pftNotAfter) &&
  8634. 0 > CompareFileTime(pftNotBefore, pftNotAfter))
  8635. {
  8636. hr = pkcsCreateNewCrossCert(pCACross, pftNotBefore, pftNotAfter);
  8637. _JumpIfError(hr, error, "pkcsCreateNewCrossCert");
  8638. if (CERTLOG_TERSE <= g_dwLogLevel)
  8639. {
  8640. WCHAR const *apwsz[2];
  8641. WCHAR awc[2 * cwcDWORDSPRINTF + 2 + 1];
  8642. wsprintf(
  8643. awc,
  8644. L"(%u-%u)",
  8645. pCACross->pCAContext->iCert,
  8646. pCACross->pCAContextTarget->iCert);
  8647. apwsz[0] = g_wszCommonName;
  8648. apwsz[1] = awc;
  8649. LogEvent(
  8650. EVENTLOG_INFORMATION_TYPE,
  8651. MSG_CREATED_CROSS_CERT,
  8652. ARRAYSIZE(apwsz),
  8653. apwsz);
  8654. }
  8655. }
  8656. }
  8657. // if cert loaded:
  8658. if (NULL != pCACross->pccCACross)
  8659. {
  8660. HRESULT hr2;
  8661. pkcsVerifyCACrossState(pCACross);
  8662. hr = pkcsImportCAOrCrossOrKRACert(
  8663. pCACross->pccCACross,
  8664. TRUE, // fCrossCert
  8665. fRevoke? DB_DISP_REVOKED : DB_DISP_ISSUED,
  8666. pCACross->pCAContext);
  8667. _PrintIfError(hr, "pkcsImportCAOrCrossOrKRACert");
  8668. hr2 = pkcsPublishCrossCert(pCACross, fRevoke);
  8669. _PrintIfError(hr2, "pkcsPublishCrossCert");
  8670. if (S_OK == hr)
  8671. {
  8672. hr = hr2;
  8673. }
  8674. _JumpIfError(hr, error, "Import/Publish Cross Cert");
  8675. }
  8676. }
  8677. hr = S_OK;
  8678. error:
  8679. return(hr);
  8680. }
  8681. BOOL
  8682. pkcsShouldDelete(
  8683. IN CACTX const *pCAContext,
  8684. IN BOOL fRevokedOnly)
  8685. {
  8686. BOOL fDelete = FALSE;
  8687. if ((CTXF_REVOKED & pCAContext->Flags) &&
  8688. 0 == (CRLF_PRESERVE_REVOKED_CA_CERTS & g_dwCRLFlags))
  8689. {
  8690. fDelete = TRUE;
  8691. }
  8692. if (!fRevokedOnly &&
  8693. (CTXF_EXPIRED & pCAContext->Flags) &&
  8694. 0 == (CRLF_PRESERVE_EXPIRED_CA_CERTS & g_dwCRLFlags))
  8695. {
  8696. fDelete = TRUE;
  8697. }
  8698. return(fDelete);
  8699. }
  8700. HRESULT
  8701. pkcsLoadCrossCertArray()
  8702. {
  8703. HRESULT hr;
  8704. HRESULT hr2;
  8705. DWORD i;
  8706. FILETIME ftNow;
  8707. g_aCACrossForward = (CACROSSCTX *) LocalAlloc(
  8708. LMEM_FIXED | LMEM_ZEROINIT,
  8709. g_cCACerts * sizeof(g_aCACrossForward[0]));
  8710. if (NULL == g_aCACrossForward)
  8711. {
  8712. hr = E_OUTOFMEMORY;
  8713. _JumpError(hr, error, "LocalAlloc");
  8714. }
  8715. g_aCACrossBackward = (CACROSSCTX *) LocalAlloc(
  8716. LMEM_FIXED | LMEM_ZEROINIT,
  8717. g_cCACerts * sizeof(g_aCACrossBackward[0]));
  8718. if (NULL == g_aCACrossBackward)
  8719. {
  8720. hr = E_OUTOFMEMORY;
  8721. _JumpError(hr, error, "LocalAlloc");
  8722. }
  8723. GetSystemTimeAsFileTime(&ftNow);
  8724. hr = S_OK;
  8725. for (i = 0; i < g_cCACerts - 1; i++)
  8726. {
  8727. if (g_aCAContext[i].iKey != g_aCAContext[i + 1].iKey)
  8728. {
  8729. BOOL fRevoke;
  8730. fRevoke = pkcsShouldDelete(&g_aCAContext[i], TRUE) ||
  8731. pkcsShouldDelete(&g_aCAContext[i + 1], TRUE);
  8732. g_aCACrossForward[i].pCAContext = &g_aCAContext[i];
  8733. g_aCACrossForward[i].pCAContextTarget = &g_aCAContext[i + 1];
  8734. if (fRevoke)
  8735. {
  8736. g_aCACrossForward[i].Flags |= CTXF_REVOKED;
  8737. }
  8738. hr2 = pkcsLoadCrossCert(
  8739. &g_aCACrossForward[i],
  8740. &ftNow,
  8741. TRUE, // fForward
  8742. fRevoke);
  8743. _PrintIfError(hr2, "pkcsLoadCrossCert");
  8744. if (S_OK == hr)
  8745. {
  8746. hr = hr2;
  8747. }
  8748. g_aCACrossBackward[i + 1].pCAContext = &g_aCAContext[i + 1];
  8749. g_aCACrossBackward[i + 1].pCAContextTarget = &g_aCAContext[i];
  8750. if (fRevoke)
  8751. {
  8752. g_aCACrossBackward[i + 1].Flags |= CTXF_REVOKED;
  8753. }
  8754. hr2 = pkcsLoadCrossCert(
  8755. &g_aCACrossBackward[i + 1],
  8756. &ftNow,
  8757. FALSE, // fForward
  8758. fRevoke);
  8759. _PrintIfError(hr2, "pkcsLoadCrossCert");
  8760. if (S_OK == hr)
  8761. {
  8762. hr = hr2;
  8763. }
  8764. }
  8765. }
  8766. _JumpIfError(hr, error, "pkcsLoadCrossCert");
  8767. error:
  8768. return(hr);
  8769. }
  8770. HRESULT
  8771. pkcsImportCAContext(
  8772. IN CACTX const *pCAContext)
  8773. {
  8774. HRESULT hr;
  8775. HRESULT hr2;
  8776. DWORD i;
  8777. WCHAR *pwszCertFile = NULL;
  8778. BOOL fDelete;
  8779. CERT_CONTEXT const *pCert = NULL;
  8780. LONG lDisposition;
  8781. hr = S_OK;
  8782. CSASSERT(NULL != pCAContext->pccCA);
  8783. for (i = 0; i < pCAContext->cCACertChain; i++)
  8784. {
  8785. pCert = pCAContext->apCACertChain[i];
  8786. // If missing, save the cert to the database.
  8787. hr2 = pkcsImportCAOrCrossOrKRACert(
  8788. pCert,
  8789. FALSE, // fCrossCert
  8790. 0 == i? DB_DISP_CA_CERT : DB_DISP_CA_CERT_CHAIN,
  8791. pCAContext);
  8792. if (S_OK != hr2)
  8793. {
  8794. if (S_OK == hr)
  8795. {
  8796. hr = hr2; // return first error
  8797. }
  8798. _PrintError(hr2, "pkcsImportCAOrCrossOrKRACert");
  8799. continue;
  8800. }
  8801. }
  8802. hr2 = pkcsGetCertFilename(
  8803. g_wszSanitizedName,
  8804. pCAContext->iCert,
  8805. MAXDWORD, // iCertTarget
  8806. &pwszCertFile);
  8807. if (S_OK == hr)
  8808. {
  8809. hr = hr2; // return first error
  8810. }
  8811. _JumpIfError(hr2, error, "myGetCertFilename");
  8812. fDelete = pkcsShouldDelete(pCAContext, FALSE);
  8813. // If necessary, save/delete the cert to/from the CertEnroll directory.
  8814. hr2 = CRLWriteToLockedFile(
  8815. pCAContext->pccCA->pbCertEncoded,
  8816. pCAContext->pccCA->cbCertEncoded,
  8817. fDelete,
  8818. pwszCertFile);
  8819. if (S_OK == hr)
  8820. {
  8821. hr = hr2; // return first error
  8822. }
  8823. _PrintIfError(hr2, "CRLWriteToLockedFile");
  8824. // If necessary, add/delete the cert to/from the HKLM Machine CA store.
  8825. hr2 = pkcsWriteCertToStore(
  8826. wszCA_CERTSTORE,
  8827. FALSE, // fEnterprise
  8828. fDelete,
  8829. pCAContext->pccCA,
  8830. &lDisposition);
  8831. if (S_OK == hr)
  8832. {
  8833. hr = hr2; // return first error
  8834. }
  8835. _PrintIfError(hr2, "pkcsWriteCertToStore");
  8836. if (fDelete)
  8837. {
  8838. // If present, delete the cert from the HKLM Enterprise CA store.
  8839. hr2 = pkcsWriteCertToStore(
  8840. wszCA_CERTSTORE,
  8841. TRUE, // fEnterprise
  8842. TRUE, // fDelete
  8843. pCAContext->pccCA,
  8844. &lDisposition);
  8845. if (S_OK == hr)
  8846. {
  8847. hr = hr2; // return first error
  8848. }
  8849. _PrintIfError(hr2, "pkcsWriteCertToStore");
  8850. if (IsRootCA(g_CAType))
  8851. {
  8852. // If present, delete the cert from the HKLM Machine Root store.
  8853. hr2 = pkcsWriteCertToStore(
  8854. wszROOT_CERTSTORE,
  8855. FALSE, // fEnterprise
  8856. TRUE, // fDelete
  8857. pCAContext->pccCA,
  8858. &lDisposition);
  8859. if (S_OK == hr)
  8860. {
  8861. hr = hr2; // return first error
  8862. }
  8863. // If present, delete the cert from the HKLM Enterprise Root store.
  8864. hr2 = pkcsWriteCertToStore(
  8865. wszROOT_CERTSTORE,
  8866. TRUE, // fEnterprise
  8867. TRUE, // fDelete
  8868. pCAContext->pccCA,
  8869. &lDisposition);
  8870. if (S_OK == hr)
  8871. {
  8872. hr = hr2; // return first error
  8873. }
  8874. _PrintIfError(hr2, "pkcsWriteCertToStore");
  8875. }
  8876. }
  8877. else
  8878. {
  8879. // If executing with a DS available, expect group policy to supply the
  8880. // root cert. Log an event if we don't find the root cert in the HKLM
  8881. // Enterprise Root store.
  8882. if (g_fUseDS &&
  8883. NULL != pCert &&
  8884. CertCompareCertificateName(
  8885. X509_ASN_ENCODING,
  8886. &pCert->pCertInfo->Subject,
  8887. &pCert->pCertInfo->Issuer))
  8888. {
  8889. hr2 = pkcsWriteCertToStore(
  8890. wszROOT_CERTSTORE,
  8891. TRUE, // fEnterprise
  8892. FALSE, // fDelete
  8893. pCert,
  8894. &lDisposition);
  8895. _PrintIfError(hr2, "pkcsWriteCertToStore");
  8896. if (0 < lDisposition)
  8897. {
  8898. WCHAR awc[cwcDWORDSPRINTF];
  8899. WCHAR const *apwsz[1];
  8900. // Was missing -- probably not being sucked down from Group
  8901. // Policy's Root CA object query. Complain loudly.
  8902. wsprintf(awc, L"%u", pCAContext->iCert);
  8903. apwsz[0] = awc;
  8904. LogEvent(
  8905. EVENTLOG_WARNING_TYPE,
  8906. MSG_E_MISSING_POLICY_ROOT,
  8907. ARRAYSIZE(apwsz),
  8908. apwsz);
  8909. }
  8910. }
  8911. }
  8912. _JumpIfError(hr, error, "pkcsImportCAContext");
  8913. error:
  8914. if (NULL != pwszCertFile)
  8915. {
  8916. LocalFree(pwszCertFile);
  8917. }
  8918. return(hr);
  8919. }
  8920. HRESULT
  8921. pkcsImportCAContextArray()
  8922. {
  8923. HRESULT hr;
  8924. HRESULT hr2;
  8925. DWORD i;
  8926. WCHAR *pwszCertDir = NULL;
  8927. WCHAR *pwsz;
  8928. hr = pkcsGetCertFilename(g_wszSanitizedName, 0, MAXDWORD, &pwszCertDir);
  8929. _JumpIfError(hr, error, "myGetCertFilename");
  8930. pwsz = wcsrchr(pwszCertDir, L'\\');
  8931. CSASSERT(NULL != pwsz);
  8932. *pwsz = L'\0';
  8933. CreateDirectory(pwszCertDir, NULL); // in case it's missing
  8934. for (i = 0; i < g_cCACerts; i++)
  8935. {
  8936. CACTX *pCAContext = &g_aCAContext[i];
  8937. if (NULL == pCAContext->pccCA)
  8938. {
  8939. continue;
  8940. }
  8941. hr2 = pkcsImportCAContext(pCAContext);
  8942. if (S_OK != hr2)
  8943. {
  8944. _PrintError(hr2, "pkcsImportCAContext");
  8945. if (S_OK == hr)
  8946. {
  8947. hr = hr2; // return first error
  8948. }
  8949. }
  8950. }
  8951. error:
  8952. if (NULL != pwszCertDir)
  8953. {
  8954. LocalFree(pwszCertDir);
  8955. }
  8956. return(hr);
  8957. }
  8958. HRESULT
  8959. pkcsExpandURL(
  8960. IN WCHAR const *pwszURLTemplate,
  8961. IN BOOL fDSAttrib,
  8962. OUT WCHAR **ppwszURL)
  8963. {
  8964. HRESULT hr;
  8965. *ppwszURL = NULL;
  8966. CSASSERT(NULL != g_strDomainDN && NULL != g_strConfigDN);
  8967. hr = myFormatCertsrvStringArray(
  8968. FALSE, // fURL
  8969. g_pwszServerName, // pwszServerName_p1_2
  8970. g_wszSanitizedName, // pwszSanitizedName_p3_7
  8971. 0, // iCert_p4
  8972. MAXDWORD, // iCertTarget_p4
  8973. g_strDomainDN, // pwszDomainDN_p5
  8974. g_strConfigDN, // pwszConfigDN_p6
  8975. 0, // iCRL_p8
  8976. FALSE, // fDeltaCRL_p9
  8977. fDSAttrib, // fDSAttrib_p10_11
  8978. 1, // cStrings
  8979. &pwszURLTemplate, // apwszStringsIn
  8980. ppwszURL); // apwszStringsOut
  8981. _JumpIfError(hr, error, "myFormatCertsrvStringArray");
  8982. error:
  8983. return(hr);
  8984. }
  8985. HRESULT
  8986. pkcsObtainDSStore(
  8987. IN WCHAR const *pwszURLTemplate,
  8988. OUT HCERTSTORE *phCertStore)
  8989. {
  8990. HRESULT hr;
  8991. HCERTSTORE hEnterpriseStore;
  8992. WCHAR *pwszURL = NULL;
  8993. if (NULL == pwszURLTemplate || NULL == phCertStore)
  8994. {
  8995. hr = E_POINTER;
  8996. _JumpError(hr, error, "NULL parm");
  8997. }
  8998. *phCertStore = NULL;
  8999. hr = pkcsExpandURL(pwszURLTemplate, TRUE, &pwszURL);
  9000. _JumpIfError(hr, error, "pkcsExpandURL");
  9001. hEnterpriseStore = myUrlCertOpenStore(
  9002. CRYPT_WIRE_ONLY_RETRIEVAL |
  9003. CRYPT_RETRIEVE_MULTIPLE_OBJECTS |
  9004. CRYPT_LDAP_SIGN_RETRIEVAL,
  9005. pwszURL);
  9006. if (NULL == hEnterpriseStore)
  9007. {
  9008. hr = myHLastError();
  9009. _JumpError(hr, error, "myUrlCertOpenStore");
  9010. }
  9011. *phCertStore = hEnterpriseStore;
  9012. hr = S_OK;
  9013. error:
  9014. if (NULL != pwszURL)
  9015. {
  9016. LocalFree(pwszURL);
  9017. }
  9018. return(hr);
  9019. }
  9020. HRESULT
  9021. pkcsVerifyRootRevocationStatus(
  9022. IN OUT CACTX *pCAContext,
  9023. OUT BOOL *pfRevoked)
  9024. {
  9025. HRESULT hr;
  9026. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  9027. DWORD cb;
  9028. BSTR strHash = NULL;
  9029. ICertDBRow *prow = NULL;
  9030. DWORD Disposition;
  9031. *pfRevoked = FALSE;
  9032. cb = sizeof(abHash);
  9033. if (!CertGetCertificateContextProperty(
  9034. pCAContext->pccCA,
  9035. CERT_SHA1_HASH_PROP_ID,
  9036. abHash,
  9037. &cb))
  9038. {
  9039. hr = myHLastError();
  9040. _JumpError(hr, error, "CertGetCertificateContextProperty");
  9041. }
  9042. hr = MultiByteIntegerToBstr(TRUE, cb, abHash, &strHash);
  9043. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  9044. hr = g_pCertDB->OpenRow(
  9045. PROPOPEN_READONLY | PROPOPEN_CERTHASH | PROPTABLE_REQCERT,
  9046. 0,
  9047. strHash,
  9048. &prow);
  9049. _JumpIfError(hr, error, "OpenRow(xchg cert)");
  9050. cb = sizeof(Disposition);
  9051. hr = prow->GetProperty(
  9052. g_wszPropRequestDisposition,
  9053. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  9054. NULL,
  9055. &cb,
  9056. (BYTE *) &Disposition);
  9057. _JumpIfError(hr, error, "GetProperty(Disposition)");
  9058. if (DB_DISP_CA_CERT == Disposition)
  9059. {
  9060. DWORD Reason;
  9061. FILETIME ftRevoked;
  9062. FILETIME ftCurrent;
  9063. cb = sizeof(Reason);
  9064. hr = prow->GetProperty(
  9065. g_wszPropRequestRevokedReason,
  9066. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  9067. NULL,
  9068. &cb,
  9069. (BYTE *) &Reason);
  9070. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  9071. {
  9072. hr = S_OK;
  9073. goto error;
  9074. }
  9075. _JumpIfError(hr, error, "GetProperty(Reason)");
  9076. cb = sizeof(ftRevoked);
  9077. hr = prow->GetProperty(
  9078. g_wszPropRequestRevokedEffectiveWhen,
  9079. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  9080. NULL,
  9081. &cb,
  9082. (BYTE *) &ftRevoked);
  9083. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  9084. {
  9085. hr = S_OK;
  9086. goto error;
  9087. }
  9088. _JumpIfError(hr, error, "GetProperty(RevokedEffectiveWhen)");
  9089. GetSystemTimeAsFileTime(&ftCurrent);
  9090. if (0 >= CompareFileTime(&ftRevoked, &ftCurrent))
  9091. {
  9092. *pfRevoked = TRUE;
  9093. }
  9094. }
  9095. hr = S_OK;
  9096. error:
  9097. if (NULL != strHash)
  9098. {
  9099. SysFreeString(strHash);
  9100. }
  9101. if (NULL != prow)
  9102. {
  9103. prow->Release();
  9104. }
  9105. return(hr);
  9106. }
  9107. HRESULT
  9108. pkcsVerifySignatureCertContext(
  9109. IN OUT CACTX *pCAContext,
  9110. IN HCERTSTORE hNTAuthStore)
  9111. {
  9112. HRESULT hr;
  9113. WCHAR awc[cwcDWORDSPRINTF];
  9114. hr = myVerifyCertContext(
  9115. pCAContext->pccCA, // pCert
  9116. 0, // dwFlags
  9117. 0, // cUsageOids
  9118. NULL, // apszUsageOids
  9119. HCCE_LOCAL_MACHINE, // hChainEngine
  9120. NULL, // hAdditionalStore
  9121. NULL); // ppwszMissingIssuer
  9122. _PrintIfError2(hr, "myVerifyCertContext", CRYPT_E_REVOCATION_OFFLINE);
  9123. if (IsRootCA(g_CAType) &&
  9124. (S_OK == hr ||
  9125. CERT_E_UNTRUSTEDROOT == hr ||
  9126. CRYPT_E_REVOCATION_OFFLINE == hr ||
  9127. CRYPT_E_NO_REVOCATION_CHECK == hr))
  9128. {
  9129. HRESULT hr2;
  9130. BOOL fRevoked;
  9131. hr2 = pkcsVerifyRootRevocationStatus(pCAContext, &fRevoked);
  9132. _PrintIfError2(hr2, "pkcsVerifyRootRevocationStatus", CERTSRV_E_PROPERTY_EMPTY);
  9133. if (S_OK == hr2 && fRevoked)
  9134. {
  9135. hr = CRYPT_E_REVOKED;
  9136. _PrintError(hr, "pkcsVerifyRootRevocationStatus");
  9137. }
  9138. else
  9139. {
  9140. FILETIME ftCurrent;
  9141. GetSystemTimeAsFileTime(&ftCurrent);
  9142. if (0 < CompareFileTime(
  9143. &ftCurrent,
  9144. &pCAContext->pccCA->pCertInfo->NotAfter))
  9145. {
  9146. hr = CERT_E_EXPIRED;
  9147. _PrintError(hr, "CA certificate is expired");
  9148. }
  9149. }
  9150. }
  9151. pCAContext->hrVerifyStatus = hr;
  9152. if (S_OK != hr)
  9153. {
  9154. DWORD LogMsg = MAXDWORD;
  9155. DWORD dwLogTypeOld = EVENTLOG_INFORMATION_TYPE;
  9156. DWORD dwLogTypeCurrent = EVENTLOG_ERROR_TYPE;
  9157. if (CERT_E_EXPIRED == hr)
  9158. {
  9159. DBGCODE(DWORD f = pCAContext->Flags);
  9160. pCAContext->Flags |= CTXF_EXPIRED;
  9161. if (0 == (CRLF_PUBLISH_EXPIRED_CERT_CRLS & g_dwCRLFlags))
  9162. {
  9163. pCAContext->Flags |= CTXF_SKIPCRL;
  9164. }
  9165. DBGPRINT((
  9166. DBG_SS_CERTSRVI,
  9167. "pkcsVerifySignatureCertContext(%u.%u) EXPIRED, f=%x->%x, hr=%x\n",
  9168. pCAContext->iCert,
  9169. pCAContext->iKey,
  9170. f,
  9171. pCAContext->Flags,
  9172. hr));
  9173. LogMsg = MSG_E_CA_CERT_EXPIRED;
  9174. }
  9175. else if (CRYPT_E_REVOKED == hr || CERT_E_REVOKED == hr)
  9176. {
  9177. pCAContext->Flags |= CTXF_REVOKED | CTXF_SKIPCRL;
  9178. LogMsg = MSG_E_CA_CERT_REVOKED;
  9179. dwLogTypeOld = EVENTLOG_WARNING_TYPE;
  9180. }
  9181. else if (CRYPT_E_REVOCATION_OFFLINE == hr)
  9182. {
  9183. HRESULT hr2;
  9184. DWORD dwState;
  9185. hr2 = GetSetupStatus(NULL, &dwState);
  9186. if ((S_OK != hr2 || 0 == (SETUP_CREATEDB_FLAG & dwState)) &&
  9187. CERTLOG_WARNING <= g_dwLogLevel)
  9188. {
  9189. LogMsg = MSG_E_CA_CERT_REVOCATION_OFFLINE;
  9190. dwLogTypeCurrent = EVENTLOG_WARNING_TYPE;
  9191. }
  9192. else
  9193. {
  9194. hr = S_OK;
  9195. }
  9196. }
  9197. else if (CRYPT_E_NO_REVOCATION_CHECK == hr)
  9198. {
  9199. if (CERTLOG_VERBOSE <= g_dwLogLevel)
  9200. {
  9201. LogMsg = MSG_E_CA_CERT_REVOCATION_NOT_CHECKED;
  9202. dwLogTypeCurrent = EVENTLOG_WARNING_TYPE;
  9203. }
  9204. else
  9205. {
  9206. hr = S_OK;
  9207. }
  9208. }
  9209. else
  9210. {
  9211. LogMsg = MSG_E_CA_CHAIN;
  9212. }
  9213. if (S_OK != hr)
  9214. {
  9215. WCHAR const *apwsz[3];
  9216. WCHAR awchr[cwcHRESULTSTRING];
  9217. CSASSERT(MAXDWORD != LogMsg);
  9218. wsprintf(awc, L"%u", pCAContext->iCert);
  9219. apwsz[0] = g_wszCommonName;
  9220. apwsz[1] = myGetErrorMessageText(hr, TRUE);
  9221. if (NULL == apwsz[1])
  9222. {
  9223. apwsz[1] = myHResultToString(awchr, hr);
  9224. }
  9225. apwsz[2] = awc;
  9226. LogEvent(
  9227. pCAContext->iCert + 1 < g_cCACerts?
  9228. dwLogTypeOld : dwLogTypeCurrent,
  9229. LogMsg,
  9230. ARRAYSIZE(apwsz),
  9231. apwsz);
  9232. if (NULL != apwsz[1] && awchr != apwsz[1])
  9233. {
  9234. LocalFree(const_cast<WCHAR *>(apwsz[1]));
  9235. }
  9236. }
  9237. _JumpIfError(hr, error, "myVerifyCertContext");
  9238. }
  9239. // The CA's certificate looks good. We verify the CA's certificate
  9240. // is in the NTAuth store
  9241. if (NULL != hNTAuthStore)
  9242. {
  9243. CERT_CONTEXT const *pCertContext;
  9244. pCertContext = pkcsFindCertificateInStore(
  9245. hNTAuthStore,
  9246. pCAContext->pccCA);
  9247. if (NULL == pCertContext)
  9248. {
  9249. WCHAR const *apwsz[2];
  9250. wsprintf(awc, L"%u", pCAContext->iCert);
  9251. apwsz[0] = awc;
  9252. apwsz[1] = g_wszCommonName;
  9253. LogEvent(
  9254. EVENTLOG_WARNING_TYPE,
  9255. MSG_CA_CERT_NO_IN_AUTH,
  9256. ARRAYSIZE(apwsz),
  9257. apwsz);
  9258. }
  9259. if (NULL != pCertContext)
  9260. {
  9261. CertFreeCertificateContext(pCertContext);
  9262. }
  9263. }
  9264. error:
  9265. return(hr);
  9266. }
  9267. HRESULT
  9268. pkcsVerifySignatureCertContextArray()
  9269. {
  9270. HRESULT hr;
  9271. DWORD i;
  9272. HCERTSTORE hNTAuthStore = NULL;
  9273. CSASSERT(0 != g_cCACerts);
  9274. // We need to verify CA's certificates should be in the NTAuth store
  9275. // if the certificate is not yet expired or revoked
  9276. if (IsEnterpriseCA(g_CAType))
  9277. {
  9278. hr = pkcsObtainDSStore(g_wszLDAPNTAuthURLTemplate, &hNTAuthStore);
  9279. _PrintIfError(hr, "pkcsObtainDSStore");
  9280. if (NULL == hNTAuthStore)
  9281. {
  9282. WCHAR const *pwszCommonName = g_wszCommonName;
  9283. LogEvent(
  9284. EVENTLOG_WARNING_TYPE,
  9285. MSG_CA_CERT_NO_AUTH_STORE,
  9286. 1,
  9287. &pwszCommonName);
  9288. }
  9289. }
  9290. hr = S_OK;
  9291. for (i = 0; i < g_cCACerts; i++)
  9292. {
  9293. CACTX *pCAContext = &g_aCAContext[i];
  9294. if (NULL == pCAContext->pccCA)
  9295. {
  9296. continue;
  9297. }
  9298. // Ignore all errors except for the current CA (last array entry)
  9299. hr = pkcsVerifySignatureCertContext(pCAContext, hNTAuthStore);
  9300. _PrintIfError(hr, "pkcsVerifySignatureCertContext");
  9301. }
  9302. //error:
  9303. if (NULL != hNTAuthStore)
  9304. {
  9305. CertCloseStore(hNTAuthStore, 0);
  9306. }
  9307. return(hr);
  9308. }
  9309. HRESULT
  9310. PKCSVerifyCAState(
  9311. IN OUT CACTX *pCAContext)
  9312. {
  9313. HRESULT hr;
  9314. if (0 == (~CTXF_SKIPCRL & pCAContext->Flags) &&
  9315. NULL != pCAContext->pccCA)
  9316. {
  9317. hr = pkcsVerifySignatureCertContext(pCAContext, NULL);
  9318. _JumpIfError(hr, error, "pkcsVerifySignatureCertContext");
  9319. }
  9320. hr = pCAContext->hrVerifyStatus;
  9321. error:
  9322. return(hr);
  9323. }
  9324. HRESULT
  9325. pkcsVerifyDSCACert(
  9326. IN LDAP *pld)
  9327. {
  9328. HRESULT hr;
  9329. HCAINFO hCAInfo = NULL;
  9330. CERT_CONTEXT const *pDSCertContext = NULL;
  9331. CSASSERT(NULL != g_pCAContextCurrent && NULL != g_pCAContextCurrent->pccCA);
  9332. hr = CAFindByName(
  9333. g_pwszSanitizedDSName,
  9334. (LPCWSTR) pld,
  9335. CA_FIND_LOCAL_SYSTEM |
  9336. CA_FIND_INCLUDE_UNTRUSTED | // skip CA cert checking
  9337. CA_FLAG_SCOPE_IS_LDAP_HANDLE,
  9338. &hCAInfo);
  9339. _JumpIfErrorStr(hr, error, "CAFindByName", g_wszSanitizedName);
  9340. hr = CAGetCACertificate(hCAInfo, &pDSCertContext);
  9341. _JumpIfError(hr, error, "CAGetCACertificate");
  9342. if (!pDSCertContext ||
  9343. pDSCertContext->cbCertEncoded !=
  9344. g_pCAContextCurrent->pccCA->cbCertEncoded ||
  9345. 0 != memcmp(
  9346. pDSCertContext->pbCertEncoded,
  9347. g_pCAContextCurrent->pccCA->pbCertEncoded,
  9348. g_pCAContextCurrent->pccCA->cbCertEncoded))
  9349. {
  9350. // published cert is invalid or old, publish the current one
  9351. hr = CASetCACertificate(hCAInfo, g_pCAContextCurrent->pccCA);
  9352. _JumpIfError(hr, error, "CASetCACertificate");
  9353. hr = CAUpdateCA(hCAInfo);
  9354. _JumpIfError(hr, error, "CAUpdateCA");
  9355. {
  9356. CAuditEvent audit(SE_AUDITID_CERTSRV_PUBLISHCACERT, g_dwAuditFilter);
  9357. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  9358. DWORD cbHash;
  9359. cbHash = sizeof(abHash);
  9360. if (!CertGetCertificateContextProperty(
  9361. g_pCAContextCurrent->pccCA,
  9362. CERT_SHA1_HASH_PROP_ID,
  9363. abHash,
  9364. &cbHash))
  9365. {
  9366. hr = myHLastError();
  9367. _JumpError(hr, error, "CertGetCertificateContextProperty");
  9368. }
  9369. // %1 Certificate Hash
  9370. hr = audit.AddData(abHash, cbHash);
  9371. _JumpIfError(hr, error, "CAuditEvent::AddData");
  9372. hr = audit.AddData(g_pCAContextCurrent->pccCA->pCertInfo->NotBefore); // %2 Valid From
  9373. _JumpIfError(hr, error, "CAuditEvent::AddData");
  9374. hr = audit.AddData(g_pCAContextCurrent->pccCA->pCertInfo->NotAfter); //%3 Valid To
  9375. _JumpIfError(hr, error, "CAuditEvent::AddData");
  9376. hr = audit.Report();
  9377. _JumpIfError(hr, error, "CAuditEvent::Report");
  9378. }
  9379. }
  9380. hr = S_OK;
  9381. error:
  9382. if (NULL != hCAInfo)
  9383. {
  9384. CACloseCA(hCAInfo);
  9385. }
  9386. if (NULL != pDSCertContext)
  9387. {
  9388. CertFreeCertificateContext(pDSCertContext);
  9389. }
  9390. return(hr);
  9391. }
  9392. // Verify all of this CA's unexpired signature certs are in the DS.
  9393. // Republish any that aren't. Cleans up DS replication conflicts.
  9394. HRESULT
  9395. pkcsPublishCAContextArray(
  9396. IN LDAP *pld)
  9397. {
  9398. HRESULT hr;
  9399. HRESULT hr2;
  9400. DWORD i;
  9401. HCERTSTORE hAIAStore = NULL;
  9402. WCHAR *pwszDSError = NULL;
  9403. WCHAR *pwszURL = NULL;
  9404. WCHAR *pwszDN;
  9405. CSASSERT(0 != g_cCACerts);
  9406. // We need to verify each CA certificate is in the DS AIA store,
  9407. // if not yet expired or revoked
  9408. hr = pkcsObtainDSStore(g_wszzLDAPIssuerCertURLTemplate, &hAIAStore);
  9409. _JumpIfError(hr, error, "pkcsObtainDSStore");
  9410. CSASSERT(NULL != hAIAStore);
  9411. hr = pkcsExpandURL(g_wszzLDAPIssuerCertURLTemplate, FALSE, &pwszURL);
  9412. _JumpIfError(hr, error, "pkcsExpandURL");
  9413. pwszDN = pwszURL;
  9414. for (i = 0; i < 3; i++)
  9415. {
  9416. pwszDN = wcschr(pwszDN, L'/');
  9417. if (NULL == pwszDN)
  9418. {
  9419. hr = E_INVALIDARG;
  9420. _JumpError(hr, error, "bad pwszURL");
  9421. }
  9422. pwszDN++;
  9423. }
  9424. for (i = 0; i < g_cCACerts; i++)
  9425. {
  9426. CACTX *pCAContext = &g_aCAContext[i];
  9427. CERT_CONTEXT const *pcc;
  9428. BOOL fDelete;
  9429. DWORD dwDisposition;
  9430. WCHAR awc[cwcDWORDSPRINTF];
  9431. WCHAR const *apwsz[4];
  9432. if (NULL == pCAContext->pccCA)
  9433. {
  9434. continue;
  9435. }
  9436. // Ignore verify errors except for the current CA (last array entry)
  9437. fDelete = FALSE;
  9438. hr = PKCSVerifyCAState(pCAContext);
  9439. if (S_OK != hr)
  9440. {
  9441. _PrintError(hr, "PKCSVerifyCAState");
  9442. fDelete = pkcsShouldDelete(pCAContext, FALSE);
  9443. if (!fDelete)
  9444. {
  9445. continue; // don't publish/delete: (transient invalidity?)
  9446. }
  9447. }
  9448. pcc = pkcsFindCertificateInStore(hAIAStore, pCAContext->pccCA);
  9449. if (NULL != pcc)
  9450. {
  9451. CertFreeCertificateContext(pcc);
  9452. if (!fDelete)
  9453. {
  9454. continue; // don't publish if already published
  9455. }
  9456. }
  9457. else
  9458. {
  9459. if (fDelete)
  9460. {
  9461. continue; // don't delete if already deleted
  9462. }
  9463. }
  9464. if (NULL != pwszDSError)
  9465. {
  9466. LocalFree(pwszDSError);
  9467. pwszDSError = NULL;
  9468. }
  9469. hr2 = myLdapPublishCertToDS(
  9470. pld,
  9471. pCAContext->pccCA,
  9472. pwszDN,
  9473. wszDSCACERTATTRIBUTE,
  9474. LPC_CAOBJECT | LPC_CREATEOBJECT,
  9475. fDelete,
  9476. &dwDisposition,
  9477. &pwszDSError);
  9478. wsprintf(awc, L"%u", pCAContext->iCert);
  9479. apwsz[0] = awc;
  9480. apwsz[1] = pwszDN;
  9481. if (S_OK != hr2)
  9482. {
  9483. WCHAR const *pwszError = NULL;
  9484. WCHAR awchr[cwcHRESULTSTRING];
  9485. apwsz[2] = pwszDSError;
  9486. pwszError = myGetErrorMessageText(hr2, TRUE);
  9487. apwsz[3] = pwszError;
  9488. if (NULL == apwsz[3])
  9489. {
  9490. apwsz[3] = myHResultToString(awchr, hr2);
  9491. }
  9492. LogEvent(
  9493. EVENTLOG_WARNING_TYPE,
  9494. fDelete?
  9495. MSG_E_CANNOT_DELETE_INVALID_CA_CERT :
  9496. MSG_E_CANNOT_ADD_MISSING_CA_CERT,
  9497. ARRAYSIZE(apwsz),
  9498. apwsz);
  9499. if (NULL != pwszError)
  9500. {
  9501. LocalFree(const_cast<WCHAR *>(pwszError));
  9502. }
  9503. _PrintErrorStr(dwDisposition, "myLdapPublishCertToDS", pwszDSError);
  9504. if (fDelete)
  9505. {
  9506. _PrintErrorStr(hr2, "myLdapPublishCertToDS", L"Delete");
  9507. }
  9508. _PrintErrorStr(hr2, "myLdapPublishCertToDS", pwszDN);
  9509. }
  9510. else
  9511. {
  9512. DBGPRINT((
  9513. DBG_SS_CERTSRV,
  9514. fDelete?
  9515. "Deleted CA Cert[%u] from %ws\n" :
  9516. "Published CA Cert[%u] to %ws\n",
  9517. i,
  9518. pwszDN));
  9519. LogEvent(
  9520. EVENTLOG_INFORMATION_TYPE,
  9521. fDelete?
  9522. MSG_E_DELETED_INVALID_CA_CERT :
  9523. MSG_E_ADDED_MISSING_CA_CERT,
  9524. min(ARRAYSIZE(apwsz), 2),
  9525. apwsz);
  9526. }
  9527. }
  9528. _JumpIfError(hr, error, "pkcsPublishCAContextArray");
  9529. error:
  9530. if (NULL != pwszURL)
  9531. {
  9532. LocalFree(pwszURL);
  9533. }
  9534. if (NULL != pwszDSError)
  9535. {
  9536. LocalFree(pwszDSError);
  9537. }
  9538. if (NULL != hAIAStore)
  9539. {
  9540. CertCloseStore(hAIAStore, 0);
  9541. }
  9542. return(hr);
  9543. }
  9544. VOID
  9545. pkcsReleaseKRACertArray()
  9546. {
  9547. DWORD i;
  9548. if (NULL != g_aKRAContext)
  9549. {
  9550. for (i = 0; i < g_cKRACerts; i++)
  9551. {
  9552. if (NULL != g_aKRAContext[i].pccKRA)
  9553. {
  9554. CertFreeCertificateContext(g_aKRAContext[i].pccKRA);
  9555. }
  9556. if (NULL != g_aKRAContext[i].strKRAHash)
  9557. {
  9558. SysFreeString(g_aKRAContext[i].strKRAHash);
  9559. }
  9560. }
  9561. LocalFree(g_aKRAContext);
  9562. g_aKRAContext = NULL;
  9563. }
  9564. g_cKRACerts = 0;
  9565. }
  9566. HRESULT
  9567. pkcsLoadKRACertContext(
  9568. IN DWORD iHash,
  9569. IN OUT HCERTSTORE *phStore)
  9570. {
  9571. HRESULT hr;
  9572. CERT_CONTEXT const *pcc = NULL;
  9573. BSTR strHash = NULL;
  9574. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  9575. DWORD cbHash;
  9576. DWORD LogMsg = 0;
  9577. BOOL fReloaded;
  9578. KRACTX *pKRAContext;
  9579. DBGPRINT((DBG_SS_CERTSRV, "Loading KRA Cert[%u]:\n", iHash));
  9580. fReloaded = FALSE;
  9581. for (;;)
  9582. {
  9583. hr = myFindCACertByHashIndex(
  9584. *phStore,
  9585. g_wszSanitizedName,
  9586. CSRH_CAKRACERT,
  9587. iHash,
  9588. NULL, // pNameId
  9589. &pcc);
  9590. if (S_OK == hr)
  9591. {
  9592. break;
  9593. }
  9594. if (fReloaded || CRYPT_E_NOT_FOUND != hr)
  9595. {
  9596. _JumpError(hr, error, "myFindCACertByHashIndex");
  9597. }
  9598. _PrintError(hr, "myFindCACertByHashIndex");
  9599. // The KRA cert is missing from the HKLM "kra" store -- look it up in
  9600. // the DB, and put it back in the store.
  9601. hr = pkcsReloadMissingCAOrKRACert(
  9602. g_wszSanitizedName,
  9603. CSRH_CAKRACERT,
  9604. iHash,
  9605. wszKRA_CERTSTORE);
  9606. _JumpIfError(hr, error, "pkcsReloadMissingCAOrKRACert");
  9607. CertCloseStore(*phStore, CERT_CLOSE_STORE_CHECK_FLAG);
  9608. *phStore = CertOpenStore(
  9609. CERT_STORE_PROV_SYSTEM_W,
  9610. X509_ASN_ENCODING,
  9611. NULL, // hProv
  9612. CERT_SYSTEM_STORE_LOCAL_MACHINE |
  9613. CERT_STORE_READONLY_FLAG,
  9614. wszKRA_CERTSTORE);
  9615. if (NULL == *phStore)
  9616. {
  9617. hr = myHLastError();
  9618. _JumpError(hr, error, "CertOpenStore");
  9619. }
  9620. fReloaded = TRUE;
  9621. }
  9622. hr = pkcsImportCAOrCrossOrKRACert(pcc, FALSE, DB_DISP_KRA_CERT, NULL);
  9623. _JumpIfError(hr, error, "pkcsImportCAOrCrossOrKRACert");
  9624. cbHash = sizeof(abHash);
  9625. if (!CertGetCertificateContextProperty(
  9626. pcc,
  9627. CERT_SHA1_HASH_PROP_ID,
  9628. abHash,
  9629. &cbHash))
  9630. {
  9631. hr = myHLastError();
  9632. _JumpError(hr, error, "CertGetCertificateContextProperty");
  9633. }
  9634. hr = MultiByteIntegerToBstr(TRUE, cbHash, abHash, &strHash);
  9635. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  9636. pKRAContext = &g_aKRAContext[g_cKRACerts];
  9637. g_cKRACerts++;
  9638. pKRAContext->pccKRA = pcc;
  9639. pKRAContext->strKRAHash = strHash;
  9640. strHash = NULL;
  9641. pcc = NULL;
  9642. // Ignore failure from here on -- collected data is optional
  9643. hr = myVerifyKRACertContext(pKRAContext->pccKRA, g_dwVerifyCertFlags);
  9644. pKRAContext->hrVerifyStatus = hr;
  9645. if (S_OK != hr)
  9646. {
  9647. if (CERT_E_EXPIRED == hr)
  9648. {
  9649. pKRAContext->Flags |= CTXF_EXPIRED;
  9650. }
  9651. else
  9652. // Assume revoked for other errors
  9653. // if (CRYPT_E_REVOKED == hr || CERT_E_REVOKED == hr)
  9654. {
  9655. pKRAContext->Flags |= CTXF_REVOKED;
  9656. }
  9657. LogMsg = MSG_E_INVALID_KRA_CERT;
  9658. _JumpError(hr, error, "myVerifyKRACertContext");
  9659. }
  9660. hr = S_OK;
  9661. error:
  9662. if (S_OK != hr)
  9663. {
  9664. if (0 == LogMsg)
  9665. {
  9666. LogMsg = MSG_E_CANNOT_LOAD_KRA_CERT;
  9667. }
  9668. pkcsLogKRACertError(LogMsg, iHash, pcc, hr);
  9669. }
  9670. if (NULL != strHash)
  9671. {
  9672. SysFreeString(strHash);
  9673. }
  9674. if (NULL != pcc)
  9675. {
  9676. CertFreeCertificateContext(pcc);
  9677. }
  9678. return(hr);
  9679. }
  9680. HRESULT
  9681. pkcsLoadKRACertArray()
  9682. {
  9683. HRESULT hr;
  9684. DWORD iHash;
  9685. DWORD cKRACerts;
  9686. HCERTSTORE hStore = NULL;
  9687. DWORD LogMsg = 0;
  9688. DWORD cKRACertsValid;
  9689. WCHAR wszDword0[cwcDWORDSPRINTF];
  9690. WCHAR wszDword1[cwcDWORDSPRINTF];
  9691. if (!g_fAdvancedServer)
  9692. {
  9693. LogMsg = MSG_E_KRA_NOT_ADVANCED_SERVER;
  9694. hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
  9695. _JumpError(hr, error, "!g_fAdvancedServer");
  9696. }
  9697. wszDword0[0] = L'\0';
  9698. wszDword1[0] = L'\0';
  9699. // open KRA store
  9700. hStore = CertOpenStore(
  9701. CERT_STORE_PROV_SYSTEM_W,
  9702. X509_ASN_ENCODING,
  9703. NULL, // hProv
  9704. CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG,
  9705. wszKRA_CERTSTORE);
  9706. if (NULL == hStore)
  9707. {
  9708. hr = myHLastError();
  9709. _JumpError(hr, error, "CertOpenStore");
  9710. }
  9711. // find & load KRA certs
  9712. hr = myGetCARegHashCount(g_wszSanitizedName, CSRH_CAKRACERT, &cKRACerts);
  9713. if (S_OK == hr && 0 == cKRACerts)
  9714. {
  9715. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  9716. }
  9717. _JumpIfError(hr, error, "myGetCARegHashCount");
  9718. g_aKRAContext = (KRACTX *) LocalAlloc(
  9719. LMEM_FIXED | LMEM_ZEROINIT,
  9720. cKRACerts * sizeof(g_aKRAContext[0]));
  9721. if (NULL == g_aKRAContext)
  9722. {
  9723. hr = E_OUTOFMEMORY;
  9724. _JumpError(hr, error, "LocalAlloc");
  9725. }
  9726. cKRACertsValid = 0;
  9727. for (iHash = 0; iHash < cKRACerts; iHash++)
  9728. {
  9729. hr = pkcsLoadKRACertContext(iHash, &hStore);
  9730. _PrintIfError(hr, "pkcsLoadKRACertContext");
  9731. if (S_OK == hr)
  9732. {
  9733. cKRACertsValid++;
  9734. }
  9735. }
  9736. if (0 == cKRACertsValid || g_cKRACertsRoundRobin > cKRACertsValid)
  9737. {
  9738. wsprintf(wszDword0, L"%u", cKRACertsValid);
  9739. wsprintf(wszDword1, L"%u", g_cKRACertsRoundRobin);
  9740. LogMsg = MSG_E_TOO_FEW_VALID_KRA_CERTS;
  9741. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  9742. _JumpError(hr, error, "cKRACertsValid");
  9743. }
  9744. hr = S_OK;
  9745. error:
  9746. if (S_OK != hr)
  9747. {
  9748. if (MSG_E_TOO_FEW_VALID_KRA_CERTS == LogMsg)
  9749. {
  9750. WCHAR const *apwsz[2];
  9751. apwsz[0] = wszDword0;
  9752. apwsz[1] = wszDword1;
  9753. LogEvent(EVENTLOG_ERROR_TYPE, LogMsg, ARRAYSIZE(apwsz), apwsz);
  9754. }
  9755. else
  9756. {
  9757. if (0 == LogMsg)
  9758. {
  9759. LogMsg = MSG_E_LOADING_KRA_CERTS;
  9760. }
  9761. LogEventHResult(EVENTLOG_ERROR_TYPE, LogMsg, hr);
  9762. }
  9763. pkcsReleaseKRACertArray();
  9764. }
  9765. if (NULL != hStore)
  9766. {
  9767. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  9768. }
  9769. return(hr);
  9770. }
  9771. HRESULT
  9772. pkcsPatchDN(
  9773. IN HRESULT hrFail,
  9774. IN WCHAR const *pwszRegName,
  9775. IN OUT BSTR *pstrDSValue)
  9776. {
  9777. HRESULT hr;
  9778. WCHAR *pwszRegValue = NULL;
  9779. hr = myGetCertRegStrValue(
  9780. g_wszSanitizedName,
  9781. NULL,
  9782. NULL,
  9783. pwszRegName,
  9784. &pwszRegValue);
  9785. _PrintIfErrorStr(hr, "myGetCertRegStrValue", pwszRegName);
  9786. // If the DS DN was retrieved, make sure the registry matches
  9787. if (NULL != *pstrDSValue)
  9788. {
  9789. if (NULL == pwszRegValue || 0 != lstrcmp(*pstrDSValue, pwszRegValue))
  9790. {
  9791. // set reg value
  9792. hr = mySetCertRegStrValue(
  9793. g_wszSanitizedName,
  9794. NULL,
  9795. NULL,
  9796. pwszRegName,
  9797. *pstrDSValue);
  9798. _PrintIfErrorStr(hr, "mySetCertRegStrValue", pwszRegName);
  9799. }
  9800. }
  9801. // Else if the registry DN was retrieved, just use it
  9802. else
  9803. if (NULL != pwszRegValue && L'\0' != *pwszRegValue)
  9804. {
  9805. if (!myConvertWszToBstr(pstrDSValue, pwszRegValue, -1))
  9806. {
  9807. hr = E_OUTOFMEMORY;
  9808. _JumpError(hr, error, "myConvertWszToBstr");
  9809. }
  9810. }
  9811. // If neither DN was retrieved, fail if g_fUsedDS or alloc an empty string:
  9812. else
  9813. {
  9814. if (g_fUseDS)
  9815. {
  9816. hr = hrFail;
  9817. _JumpError(hr, error, "both DS and Reg NULL");
  9818. }
  9819. *pstrDSValue = SysAllocString(L"");
  9820. if (NULL == *pstrDSValue)
  9821. {
  9822. hr = E_OUTOFMEMORY;
  9823. _JumpError(hr, error, "SysAllocString");
  9824. }
  9825. }
  9826. hr = S_OK;
  9827. error:
  9828. if (NULL != pwszRegValue)
  9829. {
  9830. LocalFree(pwszRegValue);
  9831. }
  9832. return(hr);
  9833. }
  9834. HRESULT
  9835. pkcsGetAuthoritativeDomainDn(
  9836. IN WCHAR const *pwszCommonName,
  9837. OUT LDAP **ppld,
  9838. OUT BSTR *pstrDomainDN,
  9839. OUT BSTR *pstrConfigDN)
  9840. {
  9841. HRESULT hr;
  9842. HRESULT hr2;
  9843. // Get domain and config containers (%5, %6)
  9844. *ppld = NULL;
  9845. *pstrDomainDN = NULL;
  9846. *pstrConfigDN = NULL;
  9847. hr2 = S_OK;
  9848. if (g_fUseDS)
  9849. {
  9850. hr = myRobustLdapBindEx(
  9851. 0, // dwFlags1
  9852. RLBF_REQUIRE_SECURE_LDAP, // dwFlags2
  9853. LDAP_VERSION2, // uVersion
  9854. NULL, // pwszDomainName
  9855. ppld,
  9856. NULL); // ppwszForestDNSName
  9857. if (S_OK != hr)
  9858. {
  9859. _PrintError(hr, "myRobustLdapBindEx");
  9860. }
  9861. else
  9862. {
  9863. hr = myGetAuthoritativeDomainDn(*ppld, pstrDomainDN, pstrConfigDN);
  9864. _PrintIfError(hr, "myGetAuthoritativeDomainDn");
  9865. }
  9866. if (S_OK != hr)
  9867. {
  9868. LogEventStringHResult(
  9869. EVENTLOG_ERROR_TYPE,
  9870. MSG_E_DS_RETRY,
  9871. pwszCommonName,
  9872. hr);
  9873. }
  9874. hr2 = hr;
  9875. }
  9876. hr = pkcsPatchDN(hr2, wszREGDSCONFIGDN, pstrConfigDN);
  9877. _JumpIfError(hr, error, "pkcsPatchDN");
  9878. hr = pkcsPatchDN(hr2, wszREGDSDOMAINDN, pstrDomainDN);
  9879. _JumpIfError(hr, error, "pkcsPatchDN");
  9880. error:
  9881. return(hr);
  9882. }
  9883. HRESULT
  9884. PKCSSetup(
  9885. IN WCHAR const *pwszCommonName,
  9886. IN WCHAR const *pwszSanitizedName)
  9887. {
  9888. HRESULT hr;
  9889. LDAP *pld = NULL;
  9890. DWORD LogMsg = MAXDWORD;
  9891. BOOL fWarn = FALSE;
  9892. g_dwVerifyCertFlags = 0;
  9893. if (CRLF_REVCHECK_IGNORE_OFFLINE & g_dwCRLFlags)
  9894. {
  9895. g_dwVerifyCertFlags |= CA_VERIFY_FLAGS_IGNORE_OFFLINE;
  9896. }
  9897. if (CRLF_REVCHECK_IGNORE_NOREVCHECK & g_dwCRLFlags)
  9898. {
  9899. g_dwVerifyCertFlags |= CA_VERIFY_FLAGS_IGNORE_NOREVCHECK;
  9900. }
  9901. // set crypt handles and load certificate chain
  9902. __try
  9903. {
  9904. InitializeCriticalSection(&g_critsecCAXchg);
  9905. g_fcritsecCAXchg = TRUE;
  9906. hr = S_OK;
  9907. }
  9908. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  9909. {
  9910. }
  9911. hr = pkcsGetAuthoritativeDomainDn(
  9912. pwszCommonName,
  9913. &pld,
  9914. &g_strDomainDN,
  9915. &g_strConfigDN);
  9916. if (S_OK != hr)
  9917. {
  9918. LogMsg = MSG_E_NO_DS;
  9919. _JumpError(hr, error, "pkcsGetAuthoritativeDomainDn");
  9920. }
  9921. // get (multiple) CRL path templates
  9922. hr = pkcsLoadURLTemplates(
  9923. wszREGCRLPUBLICATIONURLS,
  9924. &g_paRevURL,
  9925. &g_caRevURL);
  9926. _PrintIfErrorStr(hr, "pkcsLoadURLTemplates", wszREGCRLPUBLICATIONURLS);
  9927. // get (multiple) CA Cert path templates
  9928. hr = pkcsLoadURLTemplates(
  9929. wszREGCACERTPUBLICATIONURLS,
  9930. &g_paCACertURL,
  9931. &g_caCACertURL);
  9932. _PrintIfErrorStr(hr, "pkcsLoadURLTemplates", wszREGCACERTPUBLICATIONURLS);
  9933. hr = DBOpen(pwszSanitizedName);
  9934. if (S_OK != hr)
  9935. {
  9936. LogMsg = MSG_E_DB_INIT_FAILED;
  9937. _JumpError(hr, error, "PKCSSetup:DBOpen");
  9938. }
  9939. hr = pkcsLoadCAContextArray(pwszSanitizedName);
  9940. if (S_OK != hr)
  9941. {
  9942. LogMsg = MSG_E_CA_CERT_INVALID;
  9943. _JumpError(hr, error, "pkcsLoadCAContextArray");
  9944. }
  9945. hr = pkcsVerifySignatureCertContextArray();
  9946. {
  9947. // Import the certs into the database even if there were errors.
  9948. // Import them after verifying them so we can delete revoked and
  9949. // expired CA certs from various locations.
  9950. HRESULT hr2 = pkcsImportCAContextArray();
  9951. _PrintIfError(hr2, "pkcsImportCAContextArray");
  9952. }
  9953. if (S_OK != hr)
  9954. {
  9955. LogMsg = MSG_E_CA_CERT_INVALID;
  9956. _JumpError(hr, error, "pkcsVerifySignatureCertContextArray");
  9957. }
  9958. if (0 != g_cKRACertsRoundRobin)
  9959. {
  9960. hr = pkcsLoadKRACertArray();
  9961. _PrintIfError(hr, "pkcsLoadKRACertArray");
  9962. }
  9963. hr = pkcsExpandURL(
  9964. g_wszzLDAPKRACertURLTemplate,
  9965. FALSE,
  9966. &g_pwszKRAPublishURL);
  9967. _JumpIfError(hr, error, "pkcsExpandURL");
  9968. hr = pkcsExpandURL(
  9969. g_wszzLDAPIssuerCertURLTemplate,
  9970. FALSE,
  9971. &g_pwszAIACrossCertPublishURL);
  9972. _JumpIfError(hr, error, "pkcsExpandURL");
  9973. hr = pkcsExpandURL(
  9974. g_wszLDAPRootTrustURLTemplate,
  9975. FALSE,
  9976. &g_pwszRootTrustCrossCertPublishURL);
  9977. _JumpIfError(hr, error, "pkcsExpandURL");
  9978. if (IsRootCA(g_CAType) &&
  9979. 0 == (CRLF_DISABLE_ROOT_CROSS_CERTS & g_dwCRLFlags))
  9980. {
  9981. hr = pkcsLoadCrossCertArray();
  9982. _PrintIfError(hr, "pkcsLoadCrossCertArray");
  9983. }
  9984. if (NULL != pld)
  9985. {
  9986. hr = pkcsVerifyDSCACert(pld);
  9987. _PrintIfError(hr, "pkcsVerifyDSCACert");
  9988. hr = pkcsPublishCAContextArray(pld);
  9989. _PrintIfError(hr, "pkcsPublishCAContextArray");
  9990. }
  9991. hr = S_OK;
  9992. error:
  9993. if (NULL != pld)
  9994. {
  9995. ldap_unbind(pld);
  9996. }
  9997. if (S_OK != hr)
  9998. {
  9999. if (MAXDWORD == LogMsg)
  10000. {
  10001. LogMsg = MSG_E_GENERIC_STARTUP_FAILURE;
  10002. }
  10003. PKCSTerminate();
  10004. LogEventStringHResult(
  10005. EVENTLOG_ERROR_TYPE,
  10006. LogMsg,
  10007. pwszCommonName,
  10008. hr);
  10009. if (fWarn)
  10010. {
  10011. hr = S_OK;
  10012. }
  10013. }
  10014. return(hr);
  10015. }
  10016. VOID
  10017. pkcsReleaseCACertificateChain(
  10018. CERT_CONTEXT const **apCACertChain,
  10019. DWORD cCACertChain)
  10020. {
  10021. DWORD i;
  10022. if (NULL != apCACertChain)
  10023. {
  10024. for (i = 0; i < cCACertChain; ++i)
  10025. {
  10026. CertFreeCertificateContext(apCACertChain[i]);
  10027. }
  10028. LocalFree(apCACertChain);
  10029. }
  10030. }
  10031. VOID
  10032. pkcsReleaseCAContext(
  10033. IN OUT CACTX *pCAContext)
  10034. {
  10035. pkcsReleaseCACertificateChain(
  10036. pCAContext->apCACertChain,
  10037. pCAContext->cCACertChain);
  10038. //pCAContext->apCACertChain = NULL;
  10039. //pCAContext->pccCA = NULL;
  10040. if (NULL != pCAContext->hProvCA)
  10041. {
  10042. CryptReleaseContext(pCAContext->hProvCA, 0);
  10043. }
  10044. if (NULL != pCAContext->IssuerKeyId.pbData)
  10045. {
  10046. LocalFree(pCAContext->IssuerKeyId.pbData);
  10047. }
  10048. if (NULL != pCAContext->pszObjIdSignatureAlgorithm)
  10049. {
  10050. LocalFree(pCAContext->pszObjIdSignatureAlgorithm);
  10051. }
  10052. if (NULL != pCAContext->KeyAuthority2Cert.pbData)
  10053. {
  10054. LocalFree(pCAContext->KeyAuthority2Cert.pbData);
  10055. }
  10056. if (NULL != pCAContext->KeyAuthority2CRL.pbData)
  10057. {
  10058. LocalFree(pCAContext->KeyAuthority2CRL.pbData);
  10059. }
  10060. if (NULL != pCAContext->CDPCert.pbData)
  10061. {
  10062. LocalFree(pCAContext->CDPCert.pbData);
  10063. }
  10064. if (NULL != pCAContext->CDPCRLFreshest.pbData)
  10065. {
  10066. LocalFree(pCAContext->CDPCRLFreshest.pbData);
  10067. }
  10068. if (NULL != pCAContext->CDPCRLBase.pbData)
  10069. {
  10070. LocalFree(pCAContext->CDPCRLBase.pbData);
  10071. }
  10072. if (NULL != pCAContext->CDPCRLDelta.pbData)
  10073. {
  10074. LocalFree(pCAContext->CDPCRLDelta.pbData);
  10075. }
  10076. if (NULL != pCAContext->AIACert.pbData)
  10077. {
  10078. LocalFree(pCAContext->AIACert.pbData);
  10079. }
  10080. if (NULL != pCAContext->pwszKeyContainerName)
  10081. {
  10082. LocalFree(pCAContext->pwszKeyContainerName);
  10083. }
  10084. if (NULL != pCAContext->papwszCRLFiles)
  10085. {
  10086. WCHAR **ppwsz;
  10087. for (ppwsz = pCAContext->papwszCRLFiles; NULL != *ppwsz; ppwsz++)
  10088. {
  10089. LocalFree(*ppwsz);
  10090. }
  10091. LocalFree(pCAContext->papwszCRLFiles);
  10092. }
  10093. if (NULL != pCAContext->papwszDeltaCRLFiles)
  10094. {
  10095. WCHAR **ppwsz;
  10096. for (ppwsz = pCAContext->papwszDeltaCRLFiles; NULL != *ppwsz; ppwsz++)
  10097. {
  10098. LocalFree(*ppwsz);
  10099. }
  10100. LocalFree(pCAContext->papwszDeltaCRLFiles);
  10101. }
  10102. }
  10103. VOID
  10104. pkcsReleaseCACrossContextArray(
  10105. IN OUT CACROSSCTX **prgCACross)
  10106. {
  10107. DWORD i;
  10108. CACROSSCTX *pCACross = *prgCACross;
  10109. if (NULL != pCACross)
  10110. {
  10111. for (i = 0; i < g_cCACerts; i++)
  10112. {
  10113. if (NULL != pCACross[i].pccCACross)
  10114. {
  10115. CertFreeCertificateContext(pCACross[i].pccCACross);
  10116. }
  10117. }
  10118. LocalFree(pCACross);
  10119. *prgCACross = NULL;
  10120. }
  10121. }
  10122. VOID
  10123. pkcsReleaseCAContextArray()
  10124. {
  10125. DWORD i;
  10126. pkcsReleaseCACrossContextArray(&g_aCACrossForward);
  10127. pkcsReleaseCACrossContextArray(&g_aCACrossBackward);
  10128. if (NULL != g_aCAContext)
  10129. {
  10130. for (i = 0; i < g_cCACerts; i++)
  10131. {
  10132. pkcsReleaseCAContext(&g_aCAContext[i]);
  10133. }
  10134. LocalFree(g_aCAContext);
  10135. g_aCAContext = NULL;
  10136. }
  10137. g_cCACerts = 0;
  10138. g_pCAContextCurrent = NULL;
  10139. }
  10140. // Trim off leading and trailing whitespace and separator characters
  10141. WCHAR *
  10142. pkcsTrimToken(
  10143. IN WCHAR *pwszIn,
  10144. IN WCHAR wchSeparator)
  10145. {
  10146. WCHAR *pwsz;
  10147. while (wchSeparator == *pwszIn || iswspace(*pwszIn))
  10148. {
  10149. pwszIn++;
  10150. }
  10151. pwsz = &pwszIn[wcslen(pwszIn)];
  10152. while (--pwsz >= pwszIn &&
  10153. (wchSeparator == *pwsz || iswspace(*pwsz)))
  10154. {
  10155. *pwsz = L'\0';
  10156. }
  10157. if (L'\0' == *pwszIn)
  10158. {
  10159. pwszIn = NULL;
  10160. }
  10161. return(pwszIn);
  10162. }
  10163. WCHAR *
  10164. PKCSSplitToken(
  10165. IN OUT WCHAR **ppwszIn,
  10166. IN WCHAR *pwcSeparator,
  10167. OUT BOOL *pfSplit)
  10168. {
  10169. WCHAR *pwszOut = NULL;
  10170. WCHAR *pwszNext = NULL;
  10171. BOOL fSplit = FALSE;
  10172. WCHAR *pwszIn;
  10173. WCHAR *pwsz;
  10174. pwszIn = *ppwszIn;
  10175. if (NULL != pwszIn)
  10176. {
  10177. pwszOut = pwszIn;
  10178. if (NULL != pwcSeparator)
  10179. {
  10180. pwsz = wcschr(pwszIn, *pwcSeparator);
  10181. if (NULL != pwsz)
  10182. {
  10183. *pwsz = L'\0';
  10184. pwszNext = pkcsTrimToken(&pwsz[1], *pwcSeparator);
  10185. pwszOut = pkcsTrimToken(pwszOut, *pwcSeparator);
  10186. fSplit = TRUE;
  10187. }
  10188. }
  10189. }
  10190. *ppwszIn = pwszNext;
  10191. *pfSplit = fSplit;
  10192. return(pwszOut);
  10193. }
  10194. HRESULT
  10195. PKCSSetSubjectTemplate(
  10196. IN WCHAR const *pwszzTemplate)
  10197. {
  10198. HRESULT hr;
  10199. WCHAR const *pwszz;
  10200. WCHAR const *pwszPropName;
  10201. SUBJECTTABLE const **ppSubject;
  10202. SUBJECTTABLE const **pps;
  10203. SUBJECTTABLE *pSubject;
  10204. DWORD dwIndex;
  10205. DWORD cchMax;
  10206. hr = E_INVALIDARG;
  10207. if (NULL == pwszzTemplate)
  10208. {
  10209. _JumpError(hr, error, "pwszzTemplate NULL");
  10210. }
  10211. ppSubject = pkcs_apSubject; // fill in this empty subject array with string matches
  10212. for (pwszz = pwszzTemplate; L'\0' != *pwszz; pwszz += wcslen(pwszz) + 1)
  10213. {
  10214. pwszPropName = PKCSMapAttributeName(pwszz, NULL, &dwIndex, &cchMax);
  10215. if (NULL == pwszPropName)
  10216. {
  10217. hr = E_INVALIDARG;
  10218. _JumpErrorStr(hr, error, "PKCSMapAttributeName", pwszz);
  10219. }
  10220. for (pSubject = pkcs_subject; ; pSubject++)
  10221. {
  10222. if (NULL == pSubject->pwszPropName)
  10223. {
  10224. _JumpError(hr, error, "pkcs_subject lookup");
  10225. }
  10226. if (0 == mylstrcmpiS(pwszPropName, pSubject->pwszPropName))
  10227. {
  10228. break;
  10229. }
  10230. }
  10231. for (pps = pkcs_apSubject; pps < ppSubject; pps++)
  10232. {
  10233. if (*pps == pSubject)
  10234. {
  10235. _JumpErrorStr(hr, error, "pkcs_subject duplicate", pwszz);
  10236. }
  10237. }
  10238. if (ppSubject >= &pkcs_apSubject[CSUBJECTTABLE])
  10239. {
  10240. _JumpError(hr, error, "pkcs_subject overflow");
  10241. }
  10242. pSubject->dwSubjectTemplateIndex = SAFE_SUBTRACT_POINTERS(
  10243. ppSubject,
  10244. pkcs_apSubject);
  10245. *ppSubject++ = pSubject;
  10246. DBGPRINT((
  10247. DBG_SS_CERTSRVI,
  10248. "Subject Template[%u] <== Subject[%u]: %hs -- %ws\n",
  10249. pSubject->dwSubjectTemplateIndex,
  10250. pSubject->dwSubjectTableIndex,
  10251. pSubject->pszObjId,
  10252. pSubject->pwszPropName));
  10253. }
  10254. CSASSERT(ppSubject <= &pkcs_apSubject[CSUBJECTTABLE]);
  10255. if (ppSubject == pkcs_apSubject)
  10256. {
  10257. _JumpError(hr, error, "pwszzTemplate empty");
  10258. }
  10259. pkcs_ppSubjectLast = ppSubject - 1;
  10260. pkcsfSubjectTemplate = TRUE;
  10261. hr = S_OK;
  10262. error:
  10263. return(hr);
  10264. }
  10265. HRESULT
  10266. pkcsSplitRDNComponents(
  10267. IN SUBJECTTABLE const *pSubjectTable,
  10268. IN OUT WCHAR *pwszRDN, // Parsing stomps string in-place
  10269. IN DWORD cAttrMax,
  10270. OUT DWORD *pcAttr,
  10271. OUT CERT_RDN_ATTR *rgAttr)
  10272. {
  10273. HRESULT hr;
  10274. DWORD cAttr;
  10275. DWORD i;
  10276. DWORD cwc;
  10277. WCHAR *pwszRemain;
  10278. WCHAR const *pwszToken;
  10279. WCHAR *pwszT;
  10280. BOOL fSplit;
  10281. *pcAttr = 0;
  10282. cAttr = 0;
  10283. if (NULL != pwszRDN)
  10284. {
  10285. // Allocate memory for each RDN component filled in:
  10286. pwszRemain = pwszRDN;
  10287. for (;;)
  10288. {
  10289. pwszToken = PKCSSplitToken(
  10290. &pwszRemain,
  10291. wszNAMESEPARATORDEFAULT,
  10292. &fSplit);
  10293. if (NULL == pwszToken)
  10294. {
  10295. break;
  10296. }
  10297. if (cAttr >= cAttrMax)
  10298. {
  10299. hr = CERTSRV_E_BAD_REQUESTSUBJECT;
  10300. _JumpError(hr, error, "Subject RDN overflow");
  10301. }
  10302. cwc = wcslen(pwszToken);
  10303. if (g_fEnforceRDNNameLengths && cwc > pSubjectTable->cchMax)
  10304. {
  10305. DBGPRINT((
  10306. DBG_SS_CERTSRV,
  10307. "RDN component too long: %u/%u: %ws[%u]=\"%ws\"\n",
  10308. cwc,
  10309. pSubjectTable->cchMax,
  10310. pSubjectTable->pwszPropName,
  10311. cAttr,
  10312. pwszToken));
  10313. hr = CERTSRV_E_BAD_REQUESTSUBJECT;
  10314. _JumpErrorStr(hr, error, "RDN component too long", pwszToken);
  10315. }
  10316. pwszT = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
  10317. if (NULL == pwszT)
  10318. {
  10319. hr = E_OUTOFMEMORY;
  10320. _JumpError(hr, error, "LocalAlloc(pwszToken)");
  10321. }
  10322. wcscpy(pwszT, pwszToken);
  10323. rgAttr[cAttr].pszObjId = (char *) pSubjectTable->pszObjId;
  10324. rgAttr[cAttr].dwValueType = CERT_RDN_ANY_TYPE; // 'best' encoding
  10325. rgAttr[cAttr].Value.pbData = (BYTE *) pwszT;
  10326. rgAttr[cAttr].Value.cbData = 0; // Indicate Unicode input
  10327. cAttr++;
  10328. }
  10329. }
  10330. *pcAttr = cAttr;
  10331. hr = S_OK;
  10332. error:
  10333. if (S_OK != hr)
  10334. {
  10335. for (i = 0; i < cAttr; i++)
  10336. {
  10337. LocalFree(rgAttr[i].Value.pbData);
  10338. }
  10339. }
  10340. return(hr);
  10341. }
  10342. #define CSUBJECTRDNMAX (4 * CSUBJECTTABLE)
  10343. HRESULT
  10344. pkcsEncodeSubjectName(
  10345. IN ICertDBRow *prow,
  10346. IN CERT_RDN_ATTR const *rgAttr,
  10347. IN DWORD cAttr,
  10348. OUT BYTE **ppbData,
  10349. OUT DWORD *pcbData)
  10350. {
  10351. HRESULT hr;
  10352. DWORD i;
  10353. DWORD cbprop;
  10354. DWORD dwRequestFlags;
  10355. DWORD dwFlags;
  10356. CERT_RDN rgRDN[CSUBJECTRDNMAX];
  10357. CERT_NAME_INFO nameinfo;
  10358. CSASSERT(ARRAYSIZE(rgRDN) >= cAttr);
  10359. for (i = 0; i < cAttr; i++)
  10360. {
  10361. rgRDN[i].cRDNAttr = 1;
  10362. rgRDN[i].rgRDNAttr = (CERT_RDN_ATTR *) &rgAttr[i];
  10363. }
  10364. nameinfo.cRDN = cAttr;
  10365. nameinfo.rgRDN = rgRDN;
  10366. cbprop = sizeof(dwRequestFlags);
  10367. hr = prow->GetProperty(
  10368. g_wszPropRequestFlags,
  10369. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  10370. NULL,
  10371. &cbprop,
  10372. (BYTE *) &dwRequestFlags);
  10373. _JumpIfError(hr, error, "GetProperty");
  10374. CSASSERT(sizeof(dwRequestFlags) == cbprop);
  10375. dwFlags = 0;
  10376. if (CR_FLG_FORCETELETEX & dwRequestFlags)
  10377. {
  10378. dwFlags |= CERT_RDN_ENABLE_T61_UNICODE_FLAG;
  10379. }
  10380. if (CR_FLG_FORCEUTF8 & dwRequestFlags)
  10381. {
  10382. dwFlags |= CERT_RDN_ENABLE_UTF8_UNICODE_FLAG;
  10383. }
  10384. if (!myEncodeName(
  10385. X509_ASN_ENCODING,
  10386. &nameinfo,
  10387. dwFlags,
  10388. CERTLIB_USE_LOCALALLOC,
  10389. ppbData,
  10390. pcbData))
  10391. {
  10392. hr = myHLastError();
  10393. _JumpError(hr, error, "myEncodeName");
  10394. }
  10395. error:
  10396. return(hr);
  10397. }
  10398. HRESULT
  10399. pkcsBuildSubjectFromNamesTable(
  10400. IN ICertDBRow *prow,
  10401. OUT CERT_NAME_BLOB *pSubject)
  10402. {
  10403. HRESULT hr;
  10404. DWORD cbData = 0;
  10405. DWORD i;
  10406. DWORD cAttr;
  10407. DWORD cAttrT;
  10408. CERT_RDN_ATTR rgAttr[CSUBJECTRDNMAX];
  10409. SUBJECTTABLE const * const *ppSubject;
  10410. WCHAR *pwszData = NULL;
  10411. pSubject->pbData = NULL;
  10412. CSASSERT(NULL != pkcs_ppSubjectLast);
  10413. cAttr = 0;
  10414. for (
  10415. ppSubject = pkcs_ppSubjectLast;
  10416. ppSubject >= pkcs_apSubject;
  10417. ppSubject--)
  10418. {
  10419. hr = PKCSGetProperty(
  10420. prow,
  10421. (*ppSubject)->pwszPropName,
  10422. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  10423. &cbData,
  10424. (BYTE **) &pwszData);
  10425. if (S_OK != hr)
  10426. {
  10427. continue;
  10428. }
  10429. if (0 != cbData)
  10430. {
  10431. // Allocates memory for each RDN component filled in:
  10432. hr = pkcsSplitRDNComponents(
  10433. *ppSubject,
  10434. pwszData,
  10435. ARRAYSIZE(rgAttr) - cAttr,
  10436. &cAttrT,
  10437. &rgAttr[cAttr]);
  10438. _JumpIfError(hr, error, "SplitRDNComponents");
  10439. cAttr += cAttrT;
  10440. }
  10441. LocalFree(pwszData);
  10442. pwszData = NULL;
  10443. }
  10444. // done building string of subject entries, time to encode
  10445. hr = pkcsEncodeSubjectName(
  10446. prow,
  10447. rgAttr,
  10448. cAttr,
  10449. &pSubject->pbData,
  10450. &pSubject->cbData);
  10451. _JumpIfError(hr, error, "pkcsEncodeSubjectName");
  10452. hr = prow->SetProperty(
  10453. g_wszPropSubjectRawName,
  10454. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  10455. pSubject->cbData,
  10456. pSubject->pbData);
  10457. _JumpIfError(hr, error, "SetProperty");
  10458. pkcsSetDistinguishedName(prow, PROPTABLE_CERTIFICATE, pSubject);
  10459. error:
  10460. for (i = 0; i < cAttr; i++)
  10461. {
  10462. LocalFree(rgAttr[i].Value.pbData);
  10463. }
  10464. if (NULL != pwszData)
  10465. {
  10466. LocalFree(pwszData);
  10467. }
  10468. return(hr);
  10469. }
  10470. HRESULT
  10471. pkcsCheck7f(
  10472. IN ICertDBRow *prow,
  10473. IN BYTE const *pbCert,
  10474. IN DWORD cbCert,
  10475. OUT BOOL *pfErrorLogged)
  10476. {
  10477. HRESULT hr;
  10478. WCHAR *pwszSubject = NULL;
  10479. WCHAR const *pwszSubject2;
  10480. WCHAR wszDword[cwcDWORDSPRINTF];
  10481. WCHAR wszRequestId[cwcDWORDSPRINTF];
  10482. WORD cString = 0;
  10483. WCHAR const *apwsz[4];
  10484. DWORD State;
  10485. DWORD Index1;
  10486. DWORD Index2;
  10487. DWORD cwcField;
  10488. WCHAR wszField[128];
  10489. DWORD cwcObjectId;
  10490. WCHAR wszObjectId[128];
  10491. WCHAR const *pwszObjectIdDescription = NULL;
  10492. WCHAR *wszBuf = NULL;
  10493. const DWORD dwDefaultBufSize = 2048 * sizeof(WCHAR);
  10494. *pfErrorLogged = FALSE;
  10495. cwcField = sizeof(wszField)/sizeof(wszField[0]);
  10496. cwcObjectId = sizeof(wszObjectId)/sizeof(wszObjectId[0]);
  10497. hr = myCheck7f(
  10498. pbCert,
  10499. cbCert,
  10500. FALSE,
  10501. &State,
  10502. &Index1,
  10503. &Index2,
  10504. &cwcField,
  10505. wszField,
  10506. &cwcObjectId,
  10507. wszObjectId,
  10508. &pwszObjectIdDescription); // Static: do not free!
  10509. _JumpIfError(hr, error, "myCheck7f");
  10510. if (CHECK7F_NONE != State)
  10511. {
  10512. DWORD ReqId;
  10513. wszBuf = (WCHAR *) LocalAlloc(LMEM_FIXED, dwDefaultBufSize);
  10514. if (NULL == wszBuf)
  10515. {
  10516. hr = E_OUTOFMEMORY;
  10517. _JumpError(hr, error, "LocalAlloc");
  10518. }
  10519. prow->GetRowId(&ReqId);
  10520. wsprintf(wszRequestId, L"%u", ReqId);
  10521. apwsz[cString++] = wszRequestId;
  10522. apwsz[cString++] = wszDword;
  10523. hr = PKCSGetProperty(
  10524. prow,
  10525. g_wszPropSubjectDistinguishedName,
  10526. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  10527. NULL,
  10528. (BYTE **) &pwszSubject);
  10529. pwszSubject2 = pwszSubject;
  10530. if (S_OK != hr)
  10531. {
  10532. _PrintError(hr, "GetProperty(DN)");
  10533. pwszSubject2 = g_pwszUnknownSubject;
  10534. }
  10535. apwsz[cString++] = pwszSubject2;
  10536. wcscpy(wszBuf, wszField);
  10537. if (0 != Index1)
  10538. {
  10539. wsprintf(
  10540. &wszBuf[wcslen(wszBuf)],
  10541. 0 != Index2? L"[%u,%u]" : L"[%u]",
  10542. Index1 - 1,
  10543. Index2 - 1);
  10544. }
  10545. if (0 != cwcObjectId)
  10546. {
  10547. wcscat(wszBuf, L" ObjectId=");
  10548. wcscat(wszBuf, wszObjectId);
  10549. }
  10550. if (NULL != pwszObjectIdDescription)
  10551. {
  10552. // If buffer too small, reallocate enough space for old buffer,
  10553. // OID description, () and trailing zero
  10554. DWORD dwBufLen = (wcslen(wszBuf)+wcslen(pwszObjectIdDescription)+3)*
  10555. sizeof(WCHAR);
  10556. if (dwDefaultBufSize < dwBufLen)
  10557. {
  10558. WCHAR *pTempBuf = (WCHAR *) LocalReAlloc(
  10559. wszBuf,
  10560. dwBufLen,
  10561. LMEM_MOVEABLE);
  10562. if (NULL == pTempBuf)
  10563. {
  10564. hr = E_OUTOFMEMORY;
  10565. _JumpError(hr, error, "LocalReAlloc");
  10566. }
  10567. wszBuf = pTempBuf;
  10568. }
  10569. wcscat(wszBuf, L" (");
  10570. wcscat(wszBuf, pwszObjectIdDescription);
  10571. wcscat(wszBuf, L")");
  10572. }
  10573. apwsz[cString++] = wszBuf;
  10574. hr = CERTSRV_E_ENCODING_LENGTH;
  10575. wsprintf(wszDword, L"0x%x", hr);
  10576. if (CERTLOG_ERROR <= g_dwLogLevel)
  10577. {
  10578. LogEvent(
  10579. EVENTLOG_ERROR_TYPE,
  10580. MSG_E_BADCERTLENGTHFIELD,
  10581. cString,
  10582. apwsz);
  10583. }
  10584. CONSOLEPRINT4((
  10585. DBG_SS_CERTSRV,
  10586. "CertSrv Request %u: rc=%x: Bad encoded length detected: %ws \"%ws\"\n",
  10587. ReqId,
  10588. hr,
  10589. wszBuf,
  10590. pwszSubject));
  10591. *pfErrorLogged = TRUE;
  10592. }
  10593. error:
  10594. if (NULL != pwszSubject)
  10595. {
  10596. LocalFree(pwszSubject);
  10597. }
  10598. if (NULL != wszBuf)
  10599. {
  10600. LocalFree(wszBuf);
  10601. }
  10602. return(hr);
  10603. }
  10604. HRESULT
  10605. pkcsCreateCertSerialNumber(
  10606. IN ICertDBRow *prow,
  10607. IN CACTX const *pCAContext,
  10608. OUT BSTR *pstrSerialNumber)
  10609. {
  10610. HRESULT hr;
  10611. DWORD dw;
  10612. USHORT us;
  10613. BYTE abRandom[8];
  10614. BYTE abSerial[max(
  10615. sizeof(dw) + sizeof(us) + sizeof(dw),
  10616. sizeof(dw) + sizeof(us) + sizeof(abRandom) + sizeof(dw) + sizeof(BYTE))];
  10617. BSTR strHighSerial = NULL;
  10618. BSTR strSerialNumber = NULL;
  10619. DWORD cbSerial;
  10620. BYTE *pb;
  10621. BOOL fCritSecEntered = FALSE;
  10622. //#define TEST_SPECIAL_SERIAL_NUMBERS
  10623. #ifdef TEST_SPECIAL_SERIAL_NUMBERS
  10624. BOOL fAddZeroByte = FALSE;
  10625. #endif
  10626. *pstrSerialNumber = NULL;
  10627. pb = abSerial;
  10628. prow->GetRowId(&dw);
  10629. CopyMemory(pb, &dw, sizeof(dw));
  10630. pb += sizeof(dw);
  10631. us = (USHORT) pCAContext->iCert;
  10632. CopyMemory(pb, &us, sizeof(us));
  10633. pb += sizeof(us);
  10634. if (MAXDWORD == g_dwHighSerial)
  10635. {
  10636. EnterCriticalSection(&g_critsecCAXchg);
  10637. fCritSecEntered = TRUE;
  10638. if (NULL == g_pbHighSerial)
  10639. {
  10640. if (!CryptGenRandom(
  10641. g_pCAContextCurrent->hProvCA,
  10642. ARRAYSIZE(abRandom),
  10643. abRandom))
  10644. {
  10645. hr = myHLastError();
  10646. _JumpError(hr, error, "CryptGenRandom");
  10647. }
  10648. g_pbHighSerial = (BYTE *) LocalAlloc(LMEM_FIXED, sizeof(abRandom));
  10649. if (NULL == g_pbHighSerial)
  10650. {
  10651. hr = E_OUTOFMEMORY;
  10652. _JumpError(hr, error, "LocalAlloc");
  10653. }
  10654. g_cbHighSerial = sizeof(abRandom);
  10655. CopyMemory(g_pbHighSerial, abRandom, sizeof(abRandom));
  10656. hr = MultiByteIntegerToBstr(
  10657. FALSE,
  10658. sizeof(abRandom),
  10659. abRandom,
  10660. &strHighSerial);
  10661. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  10662. hr = mySetCertRegStrValue(
  10663. g_wszSanitizedName,
  10664. NULL,
  10665. NULL,
  10666. g_wszRegHighSerial,
  10667. strHighSerial);
  10668. _JumpIfErrorStr(hr, error, "mySetCertRegStrValue", g_wszRegHighSerial);
  10669. g_dwHighSerial = 0;
  10670. }
  10671. if (fCritSecEntered)
  10672. {
  10673. LeaveCriticalSection(&g_critsecCAXchg);
  10674. fCritSecEntered = FALSE;
  10675. }
  10676. }
  10677. if (NULL != g_pbHighSerial)
  10678. {
  10679. DWORD cbLeft = sizeof(abSerial) - SAFE_SUBTRACT_POINTERS(pb, abSerial);
  10680. if (g_cbHighSerial > cbLeft)
  10681. {
  10682. g_cbHighSerial = cbLeft;
  10683. }
  10684. CopyMemory(pb, g_pbHighSerial, g_cbHighSerial);
  10685. pb += g_cbHighSerial;
  10686. }
  10687. else
  10688. if (0 != g_dwHighSerial)
  10689. {
  10690. if (!CryptGenRandom(
  10691. g_pCAContextCurrent->hProvCA,
  10692. ARRAYSIZE(abRandom),
  10693. abRandom))
  10694. {
  10695. hr = myHLastError();
  10696. _PrintError(hr, "CryptGenRandom");
  10697. memset(abRandom, g_dwHighSerial, sizeof(abRandom));
  10698. }
  10699. CopyMemory(pb, abRandom, sizeof(abRandom));
  10700. pb += sizeof(abRandom);
  10701. CopyMemory(pb, &dw, sizeof(dw));
  10702. pb += sizeof(dw);
  10703. *pb++ = (BYTE) g_dwHighSerial;
  10704. }
  10705. else
  10706. {
  10707. dw = GetTickCount();
  10708. CopyMemory(pb, &dw, sizeof(dw));
  10709. pb += sizeof(dw);
  10710. }
  10711. cbSerial = SAFE_SUBTRACT_POINTERS(pb, abSerial);
  10712. // Make sure the serial number doesn't overflow the buffer:
  10713. CSASSERT(sizeof(abSerial) >= cbSerial);
  10714. // IETF max serial number length is 20 bytes:
  10715. CSASSERT(20 >= cbSerial);
  10716. pb--;
  10717. if (0 == *pb)
  10718. {
  10719. *pb = 'a';
  10720. }
  10721. else if (0 == (0xf0 & *pb))
  10722. {
  10723. *pb |= 0x10; // make high nibble non-zero
  10724. }
  10725. *pb &= 0x7f; // Some clients can't handle negative serial numbers:
  10726. #ifdef TEST_SPECIAL_SERIAL_NUMBERS
  10727. if (1 & abSerial[0])
  10728. {
  10729. *pb |= 0x80; // Test negative serial numbers:
  10730. if (2 & abSerial[0])
  10731. {
  10732. *pb-- = 0; // Test high zero byte serial numbers:
  10733. *pb |= 0x80; // Test negative serial numbers:
  10734. fAddZeroByte = TRUE;
  10735. }
  10736. }
  10737. #endif
  10738. hr = MultiByteIntegerToBstr(FALSE, cbSerial, abSerial, &strSerialNumber);
  10739. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  10740. #ifdef TEST_SPECIAL_SERIAL_NUMBERS
  10741. if (fAddZeroByte)
  10742. {
  10743. BSTR str = NULL;
  10744. str = SysAllocStringLen(NULL, 2 + wcslen(strSerialNumber));
  10745. if (NULL != str)
  10746. {
  10747. wcscpy(str, L"00");
  10748. wcscat(str, strSerialNumber);
  10749. SysFreeString(strSerialNumber);
  10750. strSerialNumber = str;
  10751. }
  10752. }
  10753. #endif
  10754. *pstrSerialNumber = strSerialNumber;
  10755. strSerialNumber = NULL;
  10756. hr = S_OK;
  10757. error:
  10758. if (fCritSecEntered)
  10759. {
  10760. LeaveCriticalSection(&g_critsecCAXchg);
  10761. fCritSecEntered = FALSE;
  10762. }
  10763. if (NULL != strHighSerial)
  10764. {
  10765. SysFreeString(strHighSerial);
  10766. }
  10767. if (NULL != strSerialNumber)
  10768. {
  10769. SysFreeString(strSerialNumber);
  10770. }
  10771. return(hr);
  10772. }
  10773. HRESULT
  10774. PKCSVerifySubjectRDN(
  10775. OPTIONAL IN ICertDBRow *prow,
  10776. IN OUT WCHAR const **ppwszPropertyName,
  10777. OPTIONAL IN WCHAR const *pwszPropertyValue,
  10778. OUT BOOL *pfSubjectDot)
  10779. {
  10780. HRESULT hr;
  10781. WCHAR const *pwsz;
  10782. WCHAR const *pwszName = *ppwszPropertyName;
  10783. WCHAR wszPrefix[ARRAYSIZE(wszPROPSUBJECTDOT)];
  10784. SUBJECTTABLE const *pSubjectTable;
  10785. DWORD i;
  10786. DWORD cAttr = 0;
  10787. CERT_RDN_ATTR rgAttr[CSUBJECTRDNMAX];
  10788. WCHAR *pwszValue = NULL;
  10789. DWORD cbData;
  10790. BYTE *pbData = NULL;
  10791. hr = S_OK;
  10792. *pfSubjectDot = FALSE;
  10793. // Check to see if the request is for L"Subject.".
  10794. pwsz = wcschr(pwszName, L'.');
  10795. if (NULL != pwsz &&
  10796. SAFE_SUBTRACT_POINTERS(pwsz, pwszName) + 2 == ARRAYSIZE(wszPrefix))
  10797. {
  10798. pwsz++; // skip past L'.'
  10799. CopyMemory(
  10800. wszPrefix,
  10801. pwszName,
  10802. (SAFE_SUBTRACT_POINTERS(pwsz, pwszName) * sizeof(WCHAR)));
  10803. wszPrefix[ARRAYSIZE(wszPrefix) - 1] = L'\0';
  10804. if (0 == LSTRCMPIS(wszPrefix, wszPROPSUBJECTDOT))
  10805. {
  10806. pwszName = pwsz;
  10807. if (L'\0' == *pwszName)
  10808. {
  10809. *pfSubjectDot = TRUE;
  10810. }
  10811. }
  10812. }
  10813. pSubjectTable = NULL;
  10814. if (!*pfSubjectDot)
  10815. {
  10816. for (pSubjectTable = pkcs_subject; ; pSubjectTable++)
  10817. {
  10818. WCHAR const * const *ppwsz;
  10819. if (NULL == pSubjectTable->pwszPropName)
  10820. {
  10821. goto error;
  10822. }
  10823. // Check for matching full name without "Subject." prefix:
  10824. pwsz = wcschr(pSubjectTable->pwszPropName, L'.');
  10825. if (NULL != pwsz && 0 == mylstrcmpiS(pwszName, &pwsz[1]))
  10826. {
  10827. break;
  10828. }
  10829. // Check for matching OID or abbreviated name:
  10830. for (
  10831. ppwsz = pSubjectTable->apwszAttributeName;
  10832. NULL != *ppwsz;
  10833. ppwsz++)
  10834. {
  10835. if (0 == mylstrcmpiS(pwszName, *ppwsz))
  10836. {
  10837. break;
  10838. }
  10839. }
  10840. if (NULL != *ppwsz)
  10841. {
  10842. *ppwszPropertyName = pSubjectTable->pwszPropName;
  10843. break;
  10844. }
  10845. }
  10846. }
  10847. // It's a valid Certificate Table Subject RDN. Call pkcsSplitRDNComponents
  10848. // to split the string into individual RDN components and optionally
  10849. // enforce each component is under the maximum length.
  10850. DBGPRINT((
  10851. DBG_SS_CERTSRVI,
  10852. "PKCSVerifySubjectRDN(%ws) --> '%ws'\n",
  10853. *ppwszPropertyName,
  10854. pwszName));
  10855. if (NULL != prow)
  10856. {
  10857. if (!*pfSubjectDot && NULL != pwszPropertyValue)
  10858. {
  10859. pwszValue = (WCHAR *) LocalAlloc(
  10860. LMEM_FIXED,
  10861. (wcslen(pwszPropertyValue) + 1) * sizeof(WCHAR));
  10862. if (NULL == pwszValue)
  10863. {
  10864. hr = E_OUTOFMEMORY;
  10865. _JumpError(hr, error, "LocalAlloc");
  10866. }
  10867. wcscpy(pwszValue, pwszPropertyValue);
  10868. CSASSERT(NULL != pSubjectTable);
  10869. hr = pkcsSplitRDNComponents(
  10870. pSubjectTable,
  10871. pwszValue,
  10872. ARRAYSIZE(rgAttr),
  10873. &cAttr,
  10874. rgAttr);
  10875. _JumpIfError(hr, error, "SplitRDNComponents");
  10876. // Call myEncodeName merely to test for valid string data.
  10877. // Some RDN OIDs are restricted to IA5 strings.
  10878. hr = pkcsEncodeSubjectName(prow, rgAttr, cAttr, &pbData, &cbData);
  10879. _JumpIfError(hr, error, "pkcsEncodeSubjectName");
  10880. }
  10881. hr = PKCSSetRequestFlags(prow, FALSE, CR_FLG_SUBJECTUNMODIFIED);
  10882. _JumpIfError(hr, error, "PKCSSetRequestFlags");
  10883. }
  10884. error:
  10885. for (i = 0; i < cAttr; i++)
  10886. {
  10887. LocalFree(rgAttr[i].Value.pbData);
  10888. }
  10889. if (NULL != pbData)
  10890. {
  10891. LocalFree(pbData);
  10892. }
  10893. if (NULL != pwszValue)
  10894. {
  10895. LocalFree(pwszValue);
  10896. }
  10897. return(hr);
  10898. }
  10899. HRESULT
  10900. PKCSDeleteAllSubjectRDNs(
  10901. IN ICertDBRow *prow,
  10902. IN DWORD Flags)
  10903. {
  10904. HRESULT hr;
  10905. SUBJECTTABLE const *pSubjectTable;
  10906. for (pSubjectTable = pkcs_subject; ; pSubjectTable++)
  10907. {
  10908. if (NULL == pSubjectTable->pwszPropName)
  10909. {
  10910. break;
  10911. }
  10912. hr = prow->SetProperty(pSubjectTable->pwszPropName, Flags, 0, NULL);
  10913. _JumpIfError(hr, error, "SetProperty");
  10914. }
  10915. hr = S_OK;
  10916. error:
  10917. return(hr);
  10918. }
  10919. HRESULT
  10920. pkcsVerifyEKUPolices(
  10921. IN CERT_CONTEXT const *pcc,
  10922. OPTIONAL IN WCHAR const *pwszzPolicies,
  10923. IN WCHAR const *pwszInvalidPoliciesPrefix,
  10924. OUT WCHAR **ppwszInvalidPolicies)
  10925. {
  10926. HRESULT hr;
  10927. CERT_ENHKEY_USAGE *pEKUs = NULL;
  10928. DWORD i;
  10929. WCHAR const *pwsz;
  10930. WCHAR *pwszObjId = NULL;
  10931. *ppwszInvalidPolicies = NULL;
  10932. if (NULL == pwszzPolicies)
  10933. {
  10934. hr = S_OK;
  10935. goto error;
  10936. }
  10937. hr = myCertGetEnhancedKeyUsage(
  10938. pcc,
  10939. CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
  10940. &pEKUs);
  10941. if (CRYPT_E_NOT_FOUND == hr)
  10942. {
  10943. hr = S_OK;
  10944. goto error;
  10945. }
  10946. _JumpIfError(hr, error, "myCertGetEnhancedKeyUsage");
  10947. for (i = 0; i < pEKUs->cUsageIdentifier; i++)
  10948. {
  10949. CSASSERT(NULL == pwszObjId);
  10950. if (!myConvertSzToWsz(
  10951. &pwszObjId,
  10952. pEKUs->rgpszUsageIdentifier[i],
  10953. -1))
  10954. {
  10955. hr = E_OUTOFMEMORY;
  10956. _JumpError(hr, error, "myConvertSzToWsz(ObjId)");
  10957. }
  10958. for (pwsz = pwszzPolicies; ; pwsz += wcslen(pwsz) + 1)
  10959. {
  10960. if (L'\0' == *pwsz)
  10961. {
  10962. hr = myAppendString(pwszObjId, L", ", ppwszInvalidPolicies);
  10963. _JumpIfError(hr, error, "myAppendString");
  10964. hr = CERT_E_INVALID_POLICY;
  10965. _PrintErrorStr(hr, "Chain invalidates policy", pwszObjId);
  10966. break;
  10967. }
  10968. if (0 == lstrcmp(pwsz, pwszObjId))
  10969. {
  10970. break;
  10971. }
  10972. }
  10973. LocalFree(pwszObjId);
  10974. pwszObjId = NULL;
  10975. }
  10976. if (NULL != *ppwszInvalidPolicies)
  10977. {
  10978. HRESULT hr2;
  10979. hr2 = myPrependString(pwszInvalidPoliciesPrefix, L" ", ppwszInvalidPolicies);
  10980. _PrintIfError(hr2, "myPrependString");
  10981. }
  10982. _JumpIfErrorStr(
  10983. hr,
  10984. error,
  10985. "Chain invalidates policy",
  10986. *ppwszInvalidPolicies);
  10987. error:
  10988. if (NULL != pEKUs)
  10989. {
  10990. LocalFree(pEKUs);
  10991. }
  10992. if (NULL != pwszObjId)
  10993. {
  10994. LocalFree(pwszObjId);
  10995. }
  10996. return(hr);
  10997. }
  10998. HRESULT
  10999. pkcsVerifyIssuedPolices(
  11000. IN CERT_CONTEXT const *pcc,
  11001. IN CHAR const *pszObjId,
  11002. OPTIONAL IN WCHAR const *pwszzPolicies,
  11003. IN WCHAR const *pwszInvalidPoliciesPrefix,
  11004. OUT WCHAR **ppwszInvalidPolicies)
  11005. {
  11006. HRESULT hr;
  11007. CERT_EXTENSION const *pExt;
  11008. CERT_POLICIES_INFO *pcpsi = NULL;
  11009. DWORD cb;
  11010. DWORD i;
  11011. WCHAR const *pwsz;
  11012. WCHAR *pwszObjId = NULL;
  11013. *ppwszInvalidPolicies = NULL;
  11014. if (NULL == pwszzPolicies)
  11015. {
  11016. hr = S_OK;
  11017. goto error;
  11018. }
  11019. pExt = CertFindExtension(
  11020. pszObjId,
  11021. pcc->pCertInfo->cExtension,
  11022. pcc->pCertInfo->rgExtension);
  11023. if (NULL == pExt)
  11024. {
  11025. hr = CRYPT_E_NOT_FOUND;
  11026. goto error;
  11027. }
  11028. if (!myDecodeObject(
  11029. X509_ASN_ENCODING,
  11030. X509_CERT_POLICIES,
  11031. pExt->Value.pbData,
  11032. pExt->Value.cbData,
  11033. CERTLIB_USE_LOCALALLOC,
  11034. (VOID **) &pcpsi,
  11035. &cb))
  11036. {
  11037. hr = myHLastError();
  11038. _JumpError(hr, error, "myDecodeObject");
  11039. }
  11040. hr = S_OK;
  11041. for (i = 0; i < pcpsi->cPolicyInfo; i++)
  11042. {
  11043. CSASSERT(NULL == pwszObjId);
  11044. if (!myConvertSzToWsz(
  11045. &pwszObjId,
  11046. pcpsi->rgPolicyInfo[i].pszPolicyIdentifier,
  11047. -1))
  11048. {
  11049. hr = E_OUTOFMEMORY;
  11050. _JumpError(hr, error, "myConvertSzToWsz(ObjId)");
  11051. }
  11052. for (pwsz = pwszzPolicies; ; pwsz += wcslen(pwsz) + 1)
  11053. {
  11054. if (L'\0' == *pwsz)
  11055. {
  11056. hr = myAppendString(pwszObjId, L", ", ppwszInvalidPolicies);
  11057. _JumpIfError(hr, error, "myAppendString");
  11058. hr = CERT_E_INVALID_POLICY;
  11059. _PrintErrorStr(hr, "Chain invalidates policy", pwszObjId);
  11060. break;
  11061. }
  11062. if (0 == lstrcmp(pwsz, pwszObjId))
  11063. {
  11064. break;
  11065. }
  11066. }
  11067. LocalFree(pwszObjId);
  11068. pwszObjId = NULL;
  11069. }
  11070. if (NULL != *ppwszInvalidPolicies)
  11071. {
  11072. HRESULT hr2;
  11073. hr2 = myPrependString(pwszInvalidPoliciesPrefix, L" ", ppwszInvalidPolicies);
  11074. _PrintIfError(hr2, "myPrependString");
  11075. }
  11076. _JumpIfErrorStr(
  11077. hr,
  11078. error,
  11079. "Chain invalidates policy",
  11080. *ppwszInvalidPolicies);
  11081. error:
  11082. if (NULL != pcpsi)
  11083. {
  11084. LocalFree(pcpsi);
  11085. }
  11086. if (NULL != pwszObjId)
  11087. {
  11088. LocalFree(pwszObjId);
  11089. }
  11090. return(hr);
  11091. }
  11092. int _cdecl
  11093. fnRDNSort(
  11094. IN VOID const *pvrdn1,
  11095. IN VOID const *pvrdn2)
  11096. {
  11097. CERT_RDN_ATTR const *prdna1 = &((CERT_RDN const *) pvrdn1)->rgRDNAttr[0];
  11098. CERT_RDN_ATTR const *prdna2 = &((CERT_RDN const *) pvrdn2)->rgRDNAttr[0];
  11099. int r;
  11100. r = strcmp(prdna1->pszObjId, prdna2->pszObjId);
  11101. if (0 == r)
  11102. {
  11103. r = prdna1->dwValueType - prdna2->dwValueType;
  11104. if (0 == r)
  11105. {
  11106. r = prdna1->Value.cbData - prdna2->Value.cbData;
  11107. if (0 == r)
  11108. {
  11109. r = mylstrcmpiL(
  11110. (WCHAR const *) prdna1->Value.pbData,
  11111. (WCHAR const *) prdna2->Value.pbData);
  11112. }
  11113. }
  11114. }
  11115. return(r);
  11116. }
  11117. HRESULT
  11118. pkcsGetSortedName(
  11119. IN CERT_NAME_BLOB const *pName,
  11120. OUT WCHAR **ppwszName)
  11121. {
  11122. HRESULT hr;
  11123. DWORD i;
  11124. CERT_NAME_INFO *pNameInfo = NULL;
  11125. CERT_NAME_INFO NameInfo;
  11126. CERT_RDN *prdn;
  11127. CERT_RDN_ATTR *rgrdna = NULL;
  11128. CERT_RDN_ATTR *prdna;
  11129. CERT_NAME_BLOB NameBlob;
  11130. DWORD cb;
  11131. *ppwszName = NULL;
  11132. NameInfo.rgRDN = NULL;
  11133. NameBlob.pbData = NULL;
  11134. if (!myDecodeName(
  11135. X509_ASN_ENCODING,
  11136. X509_UNICODE_NAME,
  11137. pName->pbData,
  11138. pName->cbData,
  11139. CERTLIB_USE_LOCALALLOC,
  11140. &pNameInfo,
  11141. &cb))
  11142. {
  11143. hr = myHLastError();
  11144. _JumpError(hr, error, "myDecodeName");
  11145. }
  11146. NameInfo.cRDN = 0;
  11147. for (i = 0; i < pNameInfo->cRDN; i++)
  11148. {
  11149. NameInfo.cRDN += pNameInfo->rgRDN[i].cRDNAttr;
  11150. }
  11151. NameInfo.rgRDN = (CERT_RDN *) LocalAlloc(
  11152. LMEM_FIXED,
  11153. NameInfo.cRDN * sizeof(NameInfo.rgRDN[0]));
  11154. if (NULL == NameInfo.rgRDN)
  11155. {
  11156. hr = E_OUTOFMEMORY;
  11157. _JumpError(hr, error, "LocalAlloc");
  11158. }
  11159. rgrdna = (CERT_RDN_ATTR *) LocalAlloc(
  11160. LMEM_FIXED,
  11161. NameInfo.cRDN * sizeof(rgrdna[0]));
  11162. if (NULL == rgrdna)
  11163. {
  11164. hr = E_OUTOFMEMORY;
  11165. _JumpError(hr, error, "LocalAlloc");
  11166. }
  11167. prdn = NameInfo.rgRDN;
  11168. prdna = rgrdna;
  11169. for (i = 0; i < pNameInfo->cRDN; i++)
  11170. {
  11171. CERT_RDN const *prdnT = &pNameInfo->rgRDN[i];
  11172. DWORD j;
  11173. for (j = 0; j < prdnT->cRDNAttr; j++)
  11174. {
  11175. prdn->cRDNAttr = 1;
  11176. prdn->rgRDNAttr = prdna;
  11177. *prdna = prdnT->rgRDNAttr[j];
  11178. prdn++;
  11179. prdna++;
  11180. }
  11181. }
  11182. qsort(NameInfo.rgRDN, NameInfo.cRDN, sizeof(NameInfo.rgRDN[0]), fnRDNSort);
  11183. if (!myEncodeName(
  11184. X509_ASN_ENCODING,
  11185. &NameInfo,
  11186. CERT_RDN_ENABLE_UTF8_UNICODE_FLAG,
  11187. CERTLIB_USE_LOCALALLOC,
  11188. &NameBlob.pbData,
  11189. &NameBlob.cbData))
  11190. {
  11191. hr = myHLastError();
  11192. _JumpError(hr, error, "myEncodeName");
  11193. }
  11194. hr = myCertNameToStr(
  11195. X509_ASN_ENCODING,
  11196. &NameBlob,
  11197. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  11198. ppwszName);
  11199. _JumpIfError(hr, error, "myCertNameToStr");
  11200. error:
  11201. if (NULL != NameBlob.pbData)
  11202. {
  11203. LocalFree(NameBlob.pbData);
  11204. }
  11205. if (NULL != NameInfo.rgRDN)
  11206. {
  11207. LocalFree(NameInfo.rgRDN);
  11208. }
  11209. if (NULL != rgrdna)
  11210. {
  11211. LocalFree(rgrdna);
  11212. }
  11213. if (NULL != pNameInfo)
  11214. {
  11215. LocalFree(pNameInfo);
  11216. }
  11217. return(hr);
  11218. }
  11219. HRESULT
  11220. pkcsCompareNames(
  11221. IN CERT_NAME_BLOB const *pName1,
  11222. IN CERT_NAME_BLOB const *pName2,
  11223. OUT BOOL *pfMatch)
  11224. {
  11225. HRESULT hr;
  11226. WCHAR *pwszName1 = NULL;
  11227. WCHAR *pwszName2 = NULL;
  11228. *pfMatch = FALSE;
  11229. hr = pkcsGetSortedName(pName1, &pwszName1);
  11230. _JumpIfError(hr, error, "pkcsGetSortedName");
  11231. hr = pkcsGetSortedName(pName2, &pwszName2);
  11232. _JumpIfError(hr, error, "pkcsGetSortedName");
  11233. if (0 == mylstrcmpiL(pwszName1, pwszName2))
  11234. {
  11235. *pfMatch = TRUE;
  11236. }
  11237. hr = S_OK;
  11238. error:
  11239. if (NULL != pwszName1)
  11240. {
  11241. LocalFree(pwszName1);
  11242. }
  11243. if (NULL != pwszName2)
  11244. {
  11245. LocalFree(pwszName2);
  11246. }
  11247. return(hr);
  11248. }
  11249. HRESULT
  11250. pkcsEncodeSubjectCert(
  11251. IN ICertDBRow *prow,
  11252. IN CACTX const *pCAContext,
  11253. IN BOOL fCrossCert,
  11254. OUT BYTE **ppbEncoded, // CoTaskMem*
  11255. OUT DWORD *pcbEncoded,
  11256. OUT BOOL *pfErrorLogged,
  11257. OUT WCHAR **ppwszDispositionCreateCert)
  11258. {
  11259. HRESULT hr;
  11260. HRESULT hr2;
  11261. HRESULT hrValidate = S_OK;
  11262. BYTE *pbCertEncoded = NULL;
  11263. DWORD cbCertEncoded;
  11264. DWORD ExtFlags;
  11265. BSTR strSerialNumber = NULL;
  11266. IEnumCERTDBNAME *penum = NULL;
  11267. CERTDBNAME cdbn;
  11268. FILETIME ftNotBefore;
  11269. DWORD dwRequestFlags;
  11270. WCHAR *pwszSubject = NULL;
  11271. DWORD dwFlags;
  11272. CERT_INFO Cert;
  11273. CERT_EXTENSION *pExt = NULL;
  11274. DWORD cExt = INCREMENT_EXTENSIONS;
  11275. DWORD cbprop;
  11276. DWORD i;
  11277. CERT_CONTEXT const *pcc = NULL;
  11278. WCHAR *pwszzIssuancePolicies = NULL;
  11279. WCHAR *pwszzApplicationPolicies = NULL;
  11280. WCHAR *pwszInvalidIssuancePolicies = NULL;
  11281. WCHAR *pwszInvalidApplicationPolicies = NULL;
  11282. WCHAR *pwszExtendedErrorInfo = NULL;
  11283. CERT_TRUST_STATUS TrustStatus;
  11284. cdbn.pwszName = NULL;
  11285. *pfErrorLogged = FALSE;
  11286. *ppwszDispositionCreateCert = NULL;
  11287. // CERT
  11288. ZeroMemory(&Cert, sizeof(Cert));
  11289. pExt = (CERT_EXTENSION *) LocalAlloc(
  11290. LMEM_FIXED | LMEM_ZEROINIT,
  11291. cExt * sizeof(*pExt));
  11292. if (NULL == pExt)
  11293. {
  11294. hr = E_OUTOFMEMORY;
  11295. _JumpError(hr, error, "LocalAlloc");
  11296. }
  11297. Cert.dwVersion = CERT_V3;
  11298. hr = pkcsCreateCertSerialNumber(prow, pCAContext, &strSerialNumber);
  11299. _JumpIfError(hr, error, "pkcsCreateCertSerialNumber");
  11300. // convert to int
  11301. hr = WszToMultiByteInteger(
  11302. FALSE,
  11303. strSerialNumber,
  11304. &Cert.SerialNumber.cbData,
  11305. &Cert.SerialNumber.pbData);
  11306. _JumpIfError(hr, error, "WszToMultiByteInteger");
  11307. Cert.SignatureAlgorithm.pszObjId = pCAContext->pszObjIdSignatureAlgorithm;
  11308. Cert.Issuer = pCAContext->pccCA->pCertInfo->Subject;
  11309. cbprop = sizeof(Cert.NotBefore);
  11310. hr = prow->GetProperty(
  11311. g_wszPropCertificateNotBeforeDate,
  11312. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  11313. NULL,
  11314. &cbprop,
  11315. (BYTE *) &Cert.NotBefore);
  11316. _JumpIfError(hr, error, "GetProperty");
  11317. CSASSERT(sizeof(Cert.NotBefore) == cbprop);
  11318. cbprop = sizeof(Cert.NotAfter);
  11319. hr = prow->GetProperty(
  11320. g_wszPropCertificateNotAfterDate,
  11321. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  11322. NULL,
  11323. &cbprop,
  11324. (BYTE *) &Cert.NotAfter);
  11325. _JumpIfError(hr, error, "GetProperty");
  11326. CSASSERT(sizeof(Cert.NotAfter) == cbprop);
  11327. CSASSERT(NULL == Cert.Subject.pbData);
  11328. cbprop = sizeof(dwRequestFlags);
  11329. hr = prow->GetProperty(
  11330. g_wszPropRequestFlags,
  11331. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  11332. NULL,
  11333. &cbprop,
  11334. (BYTE *) &dwRequestFlags);
  11335. _JumpIfError(hr, error, "GetProperty");
  11336. if (!pkcsfSubjectTemplate ||
  11337. fCrossCert ||
  11338. ((CRLF_REBUILD_MODIFIED_SUBJECT_ONLY & g_dwCRLFlags) &&
  11339. (CR_FLG_SUBJECTUNMODIFIED & dwRequestFlags)))
  11340. {
  11341. hr = PKCSGetProperty(
  11342. prow,
  11343. g_wszPropSubjectRawName,
  11344. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  11345. &Cert.Subject.cbData,
  11346. &Cert.Subject.pbData);
  11347. if (S_OK == hr &&
  11348. 0 == Cert.Subject.cbData &&
  11349. NULL != Cert.Subject.pbData)
  11350. {
  11351. LocalFree(Cert.Subject.pbData);
  11352. Cert.Subject.pbData = NULL;
  11353. }
  11354. }
  11355. if (NULL == Cert.Subject.pbData)
  11356. {
  11357. hr = pkcsBuildSubjectFromNamesTable(prow, &Cert.Subject);
  11358. _JumpIfError(hr, error, "pkcsBuildSubjectFromNamesTable");
  11359. }
  11360. hr = myCertNameToStr(
  11361. X509_ASN_ENCODING,
  11362. &Cert.Subject,
  11363. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  11364. &pwszSubject);
  11365. _JumpIfError(hr, error, "myCertNameToStr");
  11366. if (!fCrossCert)
  11367. {
  11368. BOOL fMatch;
  11369. hr = pkcsCompareNames(&Cert.Issuer, &Cert.Subject, &fMatch);
  11370. _JumpIfError(hr, error, "pkcsCompareNames");
  11371. if (fMatch)
  11372. {
  11373. hr = CERTSRV_E_BAD_REQUESTSUBJECT;
  11374. _JumpError(hr, error, "Subject string matches Issuer");
  11375. }
  11376. }
  11377. // if the subject is empty, Subject Alt Name extension must be critical:
  11378. if (L'\0' == *pwszSubject)
  11379. {
  11380. BYTE *pbAltName = NULL;
  11381. DWORD cbAltName;
  11382. hr = PropGetExtension(
  11383. prow,
  11384. PROPTYPE_BINARY | PROPCALLER_SERVER,
  11385. TEXT(szOID_SUBJECT_ALT_NAME2),
  11386. &ExtFlags,
  11387. &cbAltName,
  11388. &pbAltName);
  11389. _PrintIfErrorStr(hr, "PropGetExtension", TEXT(szOID_SUBJECT_ALT_NAME2));
  11390. // Empty subject: Require a non-empty, non-disabled Subject Alt Name 2
  11391. // extension. An empty extension with a single empty entry can be
  11392. // constructed in four bytes. We don't attempt to detect multiple
  11393. // empty name entries.
  11394. if (S_OK == hr &&
  11395. NULL != pbAltName &&
  11396. 4 < cbAltName &&
  11397. 0 == (EXTENSION_DISABLE_FLAG & ExtFlags))
  11398. {
  11399. if (0 == (EXTENSION_CRITICAL_FLAG & ExtFlags))
  11400. {
  11401. ExtFlags |= EXTENSION_CRITICAL_FLAG;
  11402. hr = PropSetExtension(
  11403. prow,
  11404. PROPTYPE_BINARY | PROPCALLER_SERVER,
  11405. TEXT(szOID_SUBJECT_ALT_NAME2),
  11406. ExtFlags,
  11407. cbAltName,
  11408. pbAltName);
  11409. }
  11410. LocalFree(pbAltName);
  11411. _JumpIfError(hr, error, "PropSetExtension");
  11412. }
  11413. else
  11414. {
  11415. hr = CERTSRV_E_BAD_REQUESTSUBJECT;
  11416. _JumpError(hr, error, "empty Subject+missing/disabled SubjectAltName");
  11417. }
  11418. }
  11419. hr = pkcsGetPublicKeyInfo(prow, &Cert.SubjectPublicKeyInfo);
  11420. _JumpIfError(hr, error, "pkcsGetPublicKeyInfo");
  11421. Cert.rgExtension = pExt;
  11422. i = 0;
  11423. hr = prow->EnumCertDBName(CIE_TABLE_EXTENSIONS, &penum);
  11424. _JumpIfError(hr, error, "EnumCertDBName");
  11425. hr = CERTSRV_E_PROPERTY_EMPTY;
  11426. for (;;)
  11427. {
  11428. ULONG celtFetched;
  11429. if (cExt == i)
  11430. {
  11431. CERT_EXTENSION *pExtT;
  11432. // reached max, increse size
  11433. cExt += INCREMENT_EXTENSIONS;
  11434. pExtT = (CERT_EXTENSION *) LocalReAlloc(
  11435. pExt,
  11436. cExt * sizeof(*pExt),
  11437. LMEM_ZEROINIT | LMEM_MOVEABLE);
  11438. if (NULL == pExtT)
  11439. {
  11440. hr = E_OUTOFMEMORY;
  11441. _JumpError(hr, error, "LocalReAlloc");
  11442. }
  11443. pExt = pExtT;
  11444. Cert.rgExtension = pExt;
  11445. }
  11446. hr = penum->Next(1, &cdbn, &celtFetched);
  11447. if (S_FALSE == hr)
  11448. {
  11449. break;
  11450. }
  11451. _JumpIfError(hr, error, "Next");
  11452. CSASSERT(1 == celtFetched);
  11453. CSASSERT(NULL != cdbn.pwszName);
  11454. if (!myConvertWszToSz(
  11455. &Cert.rgExtension[i].pszObjId,
  11456. cdbn.pwszName,
  11457. -1))
  11458. {
  11459. hr = E_OUTOFMEMORY;
  11460. _JumpError(hr, error, "myConvertWszToSz(ExtObjId)");
  11461. }
  11462. hr = PropGetExtension(
  11463. prow,
  11464. PROPTYPE_BINARY | PROPCALLER_SERVER,
  11465. cdbn.pwszName,
  11466. &ExtFlags,
  11467. &Cert.rgExtension[i].Value.cbData,
  11468. &Cert.rgExtension[i].Value.pbData);
  11469. _JumpIfError(hr, error, "PropGetExtension");
  11470. DBGPRINT((
  11471. DBG_SS_CERTSRVI,
  11472. "pkcsEncodeSubjectCert: Ext=%ws, ExtFlags=%x, len=%x\n",
  11473. cdbn.pwszName,
  11474. ExtFlags,
  11475. Cert.rgExtension[i].Value.cbData));
  11476. Cert.rgExtension[i].fCritical =
  11477. (EXTENSION_CRITICAL_FLAG & ExtFlags)? TRUE : FALSE;
  11478. CoTaskMemFree(cdbn.pwszName);
  11479. cdbn.pwszName = NULL;
  11480. if (EXTENSION_DISABLE_FLAG & ExtFlags)
  11481. {
  11482. if (NULL != pExt[i].pszObjId)
  11483. {
  11484. LocalFree(pExt[i].pszObjId);
  11485. pExt[i].pszObjId = NULL;
  11486. }
  11487. if (NULL != pExt[i].Value.pbData)
  11488. {
  11489. LocalFree(pExt[i].Value.pbData);
  11490. pExt[i].Value.pbData = NULL;
  11491. }
  11492. continue;
  11493. }
  11494. i++;
  11495. }
  11496. Cert.cExtension = i;
  11497. // encode the cert contents
  11498. if (!myEncodeObject(
  11499. X509_ASN_ENCODING,
  11500. X509_CERT_TO_BE_SIGNED,
  11501. &Cert,
  11502. 0,
  11503. CERTLIB_USE_LOCALALLOC,
  11504. &pbCertEncoded,
  11505. &cbCertEncoded))
  11506. {
  11507. hr = myHLastError();
  11508. _JumpError(hr, error, "myEncodeObject");
  11509. }
  11510. // sign the cert, then encode the signed info
  11511. hr = myEncodeSignedContent(
  11512. pCAContext->hProvCA,
  11513. X509_ASN_ENCODING,
  11514. Cert.SignatureAlgorithm.pszObjId,
  11515. pbCertEncoded,
  11516. cbCertEncoded,
  11517. CERTLIB_USE_COTASKMEMALLOC,
  11518. ppbEncoded,
  11519. pcbEncoded); // use CoTaskMem*
  11520. _JumpIfError(hr, error, "myEncodeSignedContent");
  11521. pcc = CertCreateCertificateContext(
  11522. X509_ASN_ENCODING,
  11523. *ppbEncoded,
  11524. *pcbEncoded);
  11525. if (NULL == pcc)
  11526. {
  11527. hr = myHLastError();
  11528. _JumpError(hr, error, "CertCreateCertificateContext");
  11529. }
  11530. if (g_fCertEnrollCompatible)
  11531. {
  11532. hr = pkcsCheck7f(
  11533. prow,
  11534. *ppbEncoded,
  11535. *pcbEncoded,
  11536. pfErrorLogged);
  11537. if (S_OK != hr)
  11538. {
  11539. CoTaskMemFree(*ppbEncoded);
  11540. *ppbEncoded = NULL;
  11541. _JumpError(hr, error, "pkcsCheck7f");
  11542. }
  11543. }
  11544. ftNotBefore = pcc->pCertInfo->NotBefore;
  11545. myMakeExprDateTime(&ftNotBefore, g_dwClockSkewMinutes, ENUM_PERIOD_MINUTES);
  11546. dwFlags = g_dwVerifyCertFlags;
  11547. if (fCrossCert)
  11548. {
  11549. dwFlags |= CA_VERIFY_FLAGS_IGNORE_OFFLINE;
  11550. }
  11551. if (CRLF_IGNORE_INVALID_POLICIES & g_dwCRLFlags)
  11552. {
  11553. dwFlags |= CA_VERIFY_FLAGS_IGNORE_INVALID_POLICIES;
  11554. }
  11555. hr = myVerifyCertContextEx(
  11556. pcc, // pCert
  11557. dwFlags,
  11558. 0, // dwmsTimeout
  11559. 0, // cUsageOids
  11560. NULL, // apszUsageOids
  11561. 0, // cIssuanceOids
  11562. NULL, // apszIssuanceOids
  11563. HCCE_LOCAL_MACHINE, // hChainEngine
  11564. &ftNotBefore, // pft
  11565. NULL, // hAdditionalStore
  11566. NULL, // pfnCallback
  11567. NULL, // ppwszMissingIssuer
  11568. &pwszzIssuancePolicies,
  11569. &pwszzApplicationPolicies,
  11570. &pwszExtendedErrorInfo,
  11571. &TrustStatus);
  11572. _PrintIfError(hr, "myVerifyCertContextEx");
  11573. // Ignore old Crypt32 cross cert chain verification errors
  11574. if ((CERT_E_UNTRUSTEDROOT == hr || TRUST_E_CERT_SIGNATURE == hr) &&
  11575. (CRLF_IGNORE_CROSS_CERT_TRUST_ERROR & g_dwCRLFlags) &&
  11576. fCrossCert)
  11577. {
  11578. hr = S_OK;
  11579. }
  11580. hrValidate = hr;
  11581. if (S_OK == hrValidate)
  11582. {
  11583. hr = pkcsVerifyIssuedPolices(
  11584. pcc,
  11585. szOID_CERT_POLICIES,
  11586. pwszzIssuancePolicies,
  11587. g_pwszInvalidIssuancePolicies,
  11588. &pwszInvalidIssuancePolicies);
  11589. _PrintIfError(hr, "pkcsVerifyIssuedPolices");
  11590. if (CRYPT_E_NOT_FOUND == hr)
  11591. {
  11592. hr = S_OK; // ignore error if extension is not found
  11593. }
  11594. if (S_OK == hrValidate &&
  11595. 0 == (CRLF_IGNORE_INVALID_POLICIES & g_dwCRLFlags) &&
  11596. (CERT_TRUST_HAS_ISSUANCE_CHAIN_POLICY & TrustStatus.dwInfoStatus))
  11597. {
  11598. hrValidate = hr;
  11599. }
  11600. hr = pkcsVerifyIssuedPolices(
  11601. pcc,
  11602. szOID_APPLICATION_CERT_POLICIES,
  11603. pwszzApplicationPolicies,
  11604. g_pwszInvalidApplicationPolicies,
  11605. &pwszInvalidApplicationPolicies);
  11606. _PrintIfError(hr, "pkcsVerifyIssuedPolices(szOID_APPLICATION_CERT_POLICIES)");
  11607. if (CRYPT_E_NOT_FOUND == hr)
  11608. {
  11609. // application policies extension empty, fail over to EKU
  11610. hr = pkcsVerifyEKUPolices(
  11611. pcc,
  11612. pwszzApplicationPolicies,
  11613. g_pwszInvalidApplicationPolicies,
  11614. &pwszInvalidApplicationPolicies);
  11615. _PrintIfError(hr, "pkcsVerifyIssuedPolices(szOID_ENHANCED_KEY_USAGE)");
  11616. }
  11617. if (S_OK == hrValidate &&
  11618. 0 == (CRLF_IGNORE_INVALID_POLICIES & g_dwCRLFlags))
  11619. {
  11620. hrValidate = hr;
  11621. }
  11622. }
  11623. if (S_OK != hrValidate)
  11624. {
  11625. if (0 == (CRLF_SAVE_FAILED_CERTS & g_dwCRLFlags))
  11626. {
  11627. goto error;
  11628. }
  11629. }
  11630. hr = pkcsSetCertAndKeyHashes(prow, pcc);
  11631. _JumpIfError(hr, error, "pkcsSetCertAndKeyHashes");
  11632. hr = prow->SetProperty(
  11633. g_wszPropCertificateIssuerNameID,
  11634. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  11635. sizeof(pCAContext->NameId),
  11636. (BYTE *) &pCAContext->NameId);
  11637. _JumpIfError(hr, error, "SetProperty");
  11638. hr = prow->SetProperty(
  11639. g_wszPropCertificateSerialNumber,
  11640. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  11641. MAXDWORD,
  11642. (BYTE *) strSerialNumber);
  11643. _JumpIfError(hr, error, "SetProperty");
  11644. #ifdef TEST_SPECIAL_SERIAL_NUMBERS
  11645. if (L'0' == strSerialNumber[0] && L'0' == strSerialNumber[1])
  11646. {
  11647. hr = prow->SetProperty(
  11648. g_wszPropCertificateSerialNumber,
  11649. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  11650. MAXDWORD,
  11651. (BYTE *) &strSerialNumber[2]);
  11652. _JumpIfError(hr, error, "SetProperty");
  11653. }
  11654. #endif
  11655. error:
  11656. if (S_OK != hrValidate)
  11657. {
  11658. hr = hrValidate;
  11659. }
  11660. *ppwszDispositionCreateCert = pwszInvalidIssuancePolicies;
  11661. pwszInvalidIssuancePolicies = NULL;
  11662. if (NULL != pwszInvalidApplicationPolicies)
  11663. {
  11664. hr2 = myAppendString(
  11665. pwszInvalidApplicationPolicies,
  11666. L" ",
  11667. ppwszDispositionCreateCert);
  11668. _PrintIfError(hr2, "myAppendString");
  11669. }
  11670. if (NULL != pwszExtendedErrorInfo)
  11671. {
  11672. hr2 = myAppendString(
  11673. pwszExtendedErrorInfo,
  11674. L" ",
  11675. ppwszDispositionCreateCert);
  11676. _PrintIfError(hr2, "myAppendString");
  11677. }
  11678. if (NULL != pwszSubject)
  11679. {
  11680. LocalFree(pwszSubject);
  11681. }
  11682. if (NULL != pwszzIssuancePolicies)
  11683. {
  11684. LocalFree(pwszzIssuancePolicies);
  11685. }
  11686. if (NULL != pwszzApplicationPolicies)
  11687. {
  11688. LocalFree(pwszzApplicationPolicies);
  11689. }
  11690. if (NULL != pwszInvalidIssuancePolicies)
  11691. {
  11692. LocalFree(pwszInvalidIssuancePolicies);
  11693. }
  11694. if (NULL != pwszInvalidApplicationPolicies)
  11695. {
  11696. LocalFree(pwszInvalidApplicationPolicies);
  11697. }
  11698. if (NULL != pwszExtendedErrorInfo)
  11699. {
  11700. LocalFree(pwszExtendedErrorInfo);
  11701. }
  11702. if (NULL != pcc)
  11703. {
  11704. CertFreeCertificateContext(pcc);
  11705. }
  11706. if (NULL != pExt)
  11707. {
  11708. i = 0;
  11709. if (NULL != cdbn.pwszName)
  11710. {
  11711. CoTaskMemFree(cdbn.pwszName);
  11712. }
  11713. while (cExt != i)
  11714. {
  11715. if (NULL != pExt[i].pszObjId)
  11716. {
  11717. LocalFree(pExt[i].pszObjId);
  11718. }
  11719. if (NULL != pExt[i].Value.pbData)
  11720. {
  11721. LocalFree(pExt[i].Value.pbData);
  11722. }
  11723. i++;
  11724. }
  11725. LocalFree(pExt);
  11726. }
  11727. if (NULL != penum)
  11728. {
  11729. penum->Release();
  11730. }
  11731. if (NULL != Cert.SerialNumber.pbData)
  11732. {
  11733. LocalFree(Cert.SerialNumber.pbData);
  11734. }
  11735. if (NULL != Cert.Subject.pbData)
  11736. {
  11737. LocalFree(Cert.Subject.pbData);
  11738. }
  11739. pkcsFreePublicKeyInfo(&Cert.SubjectPublicKeyInfo);
  11740. if (NULL != pbCertEncoded)
  11741. {
  11742. LocalFree(pbCertEncoded);
  11743. }
  11744. if (NULL != strSerialNumber)
  11745. {
  11746. SysFreeString(strSerialNumber);
  11747. }
  11748. return(hr);
  11749. }
  11750. VOID
  11751. pkcsFreeCRLChain(
  11752. IN DWORD cCert,
  11753. OPTIONAL IN OUT CERT_BLOB *prgCertBlob,
  11754. OPTIONAL IN OUT CERT_CONTEXT const **rgCert,
  11755. IN DWORD cCRL,
  11756. OPTIONAL IN OUT CRL_BLOB *rgCRLBlob,
  11757. OPTIONAL IN OUT CRL_CONTEXT const **rgCRL)
  11758. {
  11759. DWORD i;
  11760. if (NULL != prgCertBlob)
  11761. {
  11762. LocalFree(prgCertBlob);
  11763. }
  11764. if (NULL != rgCert)
  11765. {
  11766. for (i = 0; i < cCert; i++)
  11767. {
  11768. if (NULL != rgCert[i])
  11769. {
  11770. CertFreeCertificateContext(rgCert[i]);
  11771. }
  11772. }
  11773. LocalFree(rgCert);
  11774. }
  11775. if (NULL != rgCRLBlob)
  11776. {
  11777. LocalFree(rgCRLBlob);
  11778. }
  11779. if (NULL != rgCRL)
  11780. {
  11781. for (i = 0; i < cCRL; i++)
  11782. {
  11783. if (NULL != rgCRL[i])
  11784. {
  11785. CertFreeCRLContext(rgCRL[i]);
  11786. }
  11787. }
  11788. LocalFree(rgCRL);
  11789. }
  11790. }
  11791. // Build the CA's cert chain and collect all paremt CA CRLs.
  11792. // Add in the optional passed leaf cert and the CA's CRLs.
  11793. // This ensures that the chain includes at least this CA's correct cert & CRLs.
  11794. HRESULT
  11795. pkcsBuildCRLChain(
  11796. OPTIONAL IN CACTX *pCAContext,
  11797. OPTIONAL IN BYTE const *pbCertLeaf,
  11798. IN DWORD cbCertLeaf,
  11799. IN BOOL fIncludeCRLs,
  11800. OUT DWORD *pcCert,
  11801. OPTIONAL OUT CERT_BLOB **prgCertBlob,
  11802. OUT CERT_CONTEXT const ***prgCert,
  11803. OUT DWORD *pcCRLBlob,
  11804. OPTIONAL OUT CRL_BLOB **prgCRLBlob,
  11805. OUT CRL_CONTEXT const ***prgCRL)
  11806. {
  11807. HRESULT hr;
  11808. CERT_CHAIN_PARA ChainParams;
  11809. CERT_CHAIN_CONTEXT const *pChainContext = NULL;
  11810. DWORD cElement;
  11811. CERT_CHAIN_ELEMENT **rgpElement;
  11812. DWORD cCert = 0;
  11813. CERT_CONTEXT const **rgpCert = NULL;
  11814. CERT_CONTEXT const *pccCertLeaf = NULL;
  11815. CERT_BLOB *rgCertBlob = NULL;
  11816. DWORD cCRL = 0;
  11817. CRL_CONTEXT const **rgpCRL = NULL;
  11818. CRL_BLOB *rgCRLBlob = NULL;
  11819. DWORD i;
  11820. DWORD iCert;
  11821. DWORD iCRL;
  11822. if (NULL != prgCertBlob)
  11823. {
  11824. *prgCertBlob = NULL;
  11825. }
  11826. *prgCert = NULL;
  11827. if (NULL != prgCRLBlob)
  11828. {
  11829. *prgCRLBlob = NULL;
  11830. }
  11831. *prgCRL = NULL;
  11832. if (NULL != pbCertLeaf)
  11833. {
  11834. pccCertLeaf = CertCreateCertificateContext(
  11835. X509_ASN_ENCODING,
  11836. pbCertLeaf,
  11837. cbCertLeaf);
  11838. if (NULL == pccCertLeaf)
  11839. {
  11840. hr = myHLastError();
  11841. _JumpError(hr, error, "CertCreateCertificateContext");
  11842. }
  11843. }
  11844. CSASSERT(NULL != pCAContext || NULL != pccCertLeaf);
  11845. if (NULL == pCAContext || fIncludeCRLs)
  11846. {
  11847. // Get the CA cert chain and parent CA CRLs:
  11848. ZeroMemory(&ChainParams, sizeof(ChainParams));
  11849. ChainParams.cbSize = sizeof(ChainParams);
  11850. //ChainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  11851. //ChainParams.RequestedUsage.Usage.cUsageIdentifier = 0;
  11852. //ChainParams.RequestedUsage.Usage.rgpszUsageIdentifier = NULL;
  11853. if (!CertGetCertificateChain(
  11854. HCCE_LOCAL_MACHINE, // hChainEngine
  11855. NULL != pCAContext?
  11856. pCAContext->pccCA : pccCertLeaf,
  11857. NULL, // pTime
  11858. NULL, // hAdditionalStore
  11859. &ChainParams, // pChainPara
  11860. CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
  11861. NULL, // pvReserved
  11862. &pChainContext)) // ppChainContext
  11863. {
  11864. hr = myHLastError();
  11865. _JumpError(hr, error, "CertGetCertificateChain");
  11866. }
  11867. if (0 == pChainContext->cChain ||
  11868. 0 == pChainContext->rgpChain[0]->cElement)
  11869. {
  11870. hr = CRYPT_E_NOT_FOUND;
  11871. _JumpError(hr, error, "No chain");
  11872. }
  11873. cElement = pChainContext->rgpChain[0]->cElement;
  11874. rgpElement = pChainContext->rgpChain[0]->rgpElement;
  11875. }
  11876. else
  11877. {
  11878. cElement = pCAContext->cCACertChain;
  11879. rgpElement = NULL;
  11880. }
  11881. cCert = cElement;
  11882. cCRL = 2 * (cCert + 1); // Worst case. *Always* include this CA's CRLs
  11883. if (NULL != pbCertLeaf)
  11884. {
  11885. cCert++;
  11886. }
  11887. rgpCert = (CERT_CONTEXT const **) LocalAlloc(
  11888. LMEM_FIXED | LMEM_ZEROINIT,
  11889. cCert * sizeof(rgpCert[0]));
  11890. if (NULL == rgpCert)
  11891. {
  11892. hr = E_OUTOFMEMORY;
  11893. _JumpError(hr, error, "LocalAlloc");
  11894. }
  11895. if (fIncludeCRLs)
  11896. {
  11897. rgpCRL = (CRL_CONTEXT const **) LocalAlloc(
  11898. LMEM_FIXED | LMEM_ZEROINIT,
  11899. cCRL * sizeof(rgpCRL[0]));
  11900. if (NULL == rgpCRL)
  11901. {
  11902. hr = E_OUTOFMEMORY;
  11903. _JumpError(hr, error, "LocalAlloc");
  11904. }
  11905. }
  11906. iCert = 0;
  11907. iCRL = 0;
  11908. // Add parent CA certs and CRLs:
  11909. if (NULL == pCAContext || fIncludeCRLs)
  11910. {
  11911. for (i = 0; i < cElement; i++)
  11912. {
  11913. CSASSERT(NULL != rgpElement);
  11914. CERT_CHAIN_ELEMENT const *pElement = rgpElement[i];
  11915. CERT_REVOCATION_INFO *pRevocationInfo;
  11916. rgpCert[iCert] = CertDuplicateCertificateContext(
  11917. pElement->pCertContext);
  11918. if (NULL != rgpCert[iCert])
  11919. {
  11920. iCert++;
  11921. }
  11922. pRevocationInfo = pElement->pRevocationInfo;
  11923. if (fIncludeCRLs &&
  11924. NULL != pRevocationInfo &&
  11925. CCSIZEOF_STRUCT(CERT_REVOCATION_INFO, pCrlInfo) <=
  11926. pRevocationInfo->cbSize &&
  11927. NULL != pRevocationInfo->pCrlInfo)
  11928. {
  11929. CERT_REVOCATION_CRL_INFO *pCrlInfo;
  11930. pCrlInfo = pRevocationInfo->pCrlInfo;
  11931. if (NULL != pCrlInfo)
  11932. {
  11933. if (NULL != pCrlInfo->pBaseCrlContext)
  11934. {
  11935. rgpCRL[iCRL] = CertDuplicateCRLContext(
  11936. pCrlInfo->pBaseCrlContext);
  11937. if (NULL != rgpCRL[iCRL])
  11938. {
  11939. iCRL++;
  11940. }
  11941. }
  11942. if (NULL != pCrlInfo->pDeltaCrlContext)
  11943. {
  11944. rgpCRL[iCRL] = CertDuplicateCRLContext(
  11945. pCrlInfo->pDeltaCrlContext);
  11946. if (NULL != rgpCRL[iCRL])
  11947. {
  11948. iCRL++;
  11949. }
  11950. }
  11951. }
  11952. }
  11953. }
  11954. }
  11955. else
  11956. {
  11957. for (i = 0; i < pCAContext->cCACertChain; i++)
  11958. {
  11959. rgpCert[iCert] = CertDuplicateCertificateContext(
  11960. pCAContext->apCACertChain[i]);
  11961. if (NULL != rgpCert[iCert])
  11962. {
  11963. iCert++;
  11964. }
  11965. }
  11966. }
  11967. if (NULL != pCAContext)
  11968. {
  11969. // Add issued cert at the end -- optional Leaf cert:
  11970. if (NULL != pbCertLeaf)
  11971. {
  11972. for (i = 0; i < iCert; i++)
  11973. {
  11974. if (cbCertLeaf == rgpCert[i]->cbCertEncoded &&
  11975. 0 == memcmp(
  11976. pbCertLeaf,
  11977. rgpCert[i]->pbCertEncoded,
  11978. cbCertLeaf))
  11979. {
  11980. break;
  11981. }
  11982. }
  11983. if (i == iCert) // if not found in existing array
  11984. {
  11985. rgpCert[iCert] = CertDuplicateCertificateContext(pccCertLeaf);
  11986. if (NULL != rgpCert[iCert])
  11987. {
  11988. iCert++;
  11989. }
  11990. }
  11991. }
  11992. // Add current CA's Base and delta CRLs:
  11993. if (fIncludeCRLs)
  11994. {
  11995. hr = CRLGetCRL(
  11996. pCAContext->iKey,
  11997. FALSE, // fDelta
  11998. &rgpCRL[iCRL],
  11999. NULL); // pdwCRLPublishFlags
  12000. _JumpIfError(hr, error, "CRLGetCRL(base)"); // Base CRL must exist
  12001. iCRL++;
  12002. hr = CRLGetCRL(
  12003. pCAContext->iKey,
  12004. TRUE, // fDelta
  12005. &rgpCRL[iCRL],
  12006. NULL); // pdwCRLPublishFlags
  12007. _PrintIfError(hr, "CRLGetCRL(delta)"); // Delta CRL might not exist
  12008. if (S_OK == hr)
  12009. {
  12010. iCRL++;
  12011. }
  12012. }
  12013. }
  12014. CSASSERT(iCert <= cCert);
  12015. CSASSERT(iCRL <= cCRL);
  12016. if (NULL != prgCertBlob)
  12017. {
  12018. rgCertBlob = (CERT_BLOB *) LocalAlloc(
  12019. LMEM_FIXED,
  12020. iCert * sizeof(rgCertBlob[0]));
  12021. if (NULL == rgCertBlob)
  12022. {
  12023. hr = E_OUTOFMEMORY;
  12024. _JumpError(hr, error, "LocalAlloc");
  12025. }
  12026. for (i = 0; i < iCert; i++)
  12027. {
  12028. rgCertBlob[i].cbData = rgpCert[i]->cbCertEncoded;
  12029. rgCertBlob[i].pbData = rgpCert[i]->pbCertEncoded;
  12030. }
  12031. }
  12032. if (NULL != prgCRLBlob && 0 != iCRL)
  12033. {
  12034. rgCRLBlob = (CERT_BLOB *) LocalAlloc(
  12035. LMEM_FIXED,
  12036. iCRL * sizeof(rgCRLBlob[0]));
  12037. if (NULL == rgCRLBlob)
  12038. {
  12039. hr = E_OUTOFMEMORY;
  12040. _JumpError(hr, error, "LocalAlloc");
  12041. }
  12042. for (i = 0; i < iCRL; i++)
  12043. {
  12044. rgCRLBlob[i].cbData = rgpCRL[i]->cbCrlEncoded;
  12045. rgCRLBlob[i].pbData = rgpCRL[i]->pbCrlEncoded;
  12046. }
  12047. }
  12048. *pcCert = iCert;
  12049. *prgCert = rgpCert;
  12050. rgpCert = NULL;
  12051. if (NULL != prgCertBlob)
  12052. {
  12053. *prgCertBlob = rgCertBlob;
  12054. rgCertBlob = NULL;
  12055. }
  12056. *pcCRLBlob = iCRL;
  12057. *prgCRL = rgpCRL;
  12058. rgpCRL = NULL;
  12059. if (NULL != prgCRLBlob)
  12060. {
  12061. *prgCRLBlob = rgCRLBlob;
  12062. rgCRLBlob = NULL;
  12063. }
  12064. hr = S_OK;
  12065. error:
  12066. pkcsFreeCRLChain(cCert, rgCertBlob, rgpCert, cCRL, rgCRLBlob, rgpCRL);
  12067. if (NULL != pccCertLeaf)
  12068. {
  12069. CertFreeCertificateContext(pccCertLeaf);
  12070. }
  12071. if (NULL != pChainContext)
  12072. {
  12073. CertFreeCertificateChain(pChainContext);
  12074. }
  12075. return(hr);
  12076. }
  12077. HRESULT
  12078. pkcsRetrieveKeyHashFromRequest(
  12079. IN ICertDBRow *prow,
  12080. OUT BYTE **ppbKeyHashOut,
  12081. OUT DWORD *pcbKeyHashOut)
  12082. {
  12083. HRESULT hr;
  12084. HCRYPTMSG hMsg = NULL;
  12085. char *pszInnerContentObjId = NULL;
  12086. BYTE *pbRequest = NULL;
  12087. DWORD cbRequest;
  12088. BYTE *pbContent = NULL;
  12089. DWORD cbContent;
  12090. CMC_ADD_ATTRIBUTES_INFO *pcmcAttrib = NULL;
  12091. DWORD cb;
  12092. CRYPT_ATTRIBUTE const *pAttrib;
  12093. CRYPT_ATTRIBUTE const *pAttribEnd;
  12094. CRYPT_DATA_BLOB *pBlob = NULL;
  12095. CMC_DATA_INFO *pcmcData = NULL;
  12096. DWORD i;
  12097. DWORD DataReference = MAXDWORD; // nested CMC message Body Part Id
  12098. DWORD CertReference = MAXDWORD; // PKCS10 Cert Request Body Part Id
  12099. *ppbKeyHashOut = NULL;
  12100. hr = PKCSGetProperty(
  12101. prow,
  12102. g_wszPropRequestRawRequest,
  12103. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  12104. &cbRequest,
  12105. (BYTE **) &pbRequest);
  12106. _JumpIfError(hr, error, "PKCSGetProperty(xchg cert)");
  12107. hr = myDecodePKCS7(
  12108. pbRequest,
  12109. cbRequest,
  12110. &pbContent,
  12111. &cbContent,
  12112. NULL, // pdwMsgType
  12113. &pszInnerContentObjId,
  12114. NULL, // pcSigner
  12115. NULL, // pcRecipient
  12116. NULL, // phStore
  12117. &hMsg);
  12118. _JumpIfError(hr, error, "myDecodePKCS7");
  12119. if (!myDecodeObject(
  12120. X509_ASN_ENCODING,
  12121. CMC_DATA,
  12122. pbContent,
  12123. cbContent,
  12124. CERTLIB_USE_LOCALALLOC,
  12125. (VOID **) &pcmcData,
  12126. &cb))
  12127. {
  12128. hr = myHLastError();
  12129. _JumpError(hr, error, "myDecodeObject");
  12130. }
  12131. if (1 == pcmcData->cTaggedRequest)
  12132. {
  12133. CertReference = pcmcData->rgTaggedRequest[0].pTaggedCertRequest->dwBodyPartID;
  12134. }
  12135. // Process extensions and attributes
  12136. for (i = 0; i < pcmcData->cTaggedAttribute; i++)
  12137. {
  12138. if (0 != strcmp(
  12139. szOID_CMC_ADD_ATTRIBUTES,
  12140. pcmcData->rgTaggedAttribute[i].Attribute.pszObjId))
  12141. {
  12142. continue;
  12143. }
  12144. // Decode CMC_ADD_ATTRIBUTES_INFO from Attribute Blob
  12145. if (NULL != pcmcAttrib)
  12146. {
  12147. LocalFree(pcmcAttrib);
  12148. pcmcAttrib = NULL;
  12149. }
  12150. if (!myDecodeObject(
  12151. X509_ASN_ENCODING,
  12152. CMC_ADD_ATTRIBUTES,
  12153. pcmcData->rgTaggedAttribute[i].Attribute.rgValue[0].pbData,
  12154. pcmcData->rgTaggedAttribute[i].Attribute.rgValue[0].cbData,
  12155. CERTLIB_USE_LOCALALLOC,
  12156. (VOID **) &pcmcAttrib,
  12157. &cb))
  12158. {
  12159. hr = myHLastError();
  12160. _JumpError(hr, error, "myDecodeObject");
  12161. }
  12162. if (!pkcsCMCReferenceMatch(
  12163. DataReference,
  12164. CertReference,
  12165. pcmcAttrib->dwCmcDataReference,
  12166. pcmcAttrib->cCertReference,
  12167. pcmcAttrib->rgdwCertReference))
  12168. {
  12169. continue;
  12170. }
  12171. pAttrib = pcmcAttrib->rgAttribute;
  12172. if (NULL == pAttrib)
  12173. {
  12174. continue;
  12175. }
  12176. pAttribEnd = &pAttrib[pcmcAttrib->cAttribute];
  12177. for ( ; pAttrib < pAttribEnd; pAttrib++)
  12178. {
  12179. if (0 != strcmp(pAttrib->pszObjId, szOID_ENCRYPTED_KEY_HASH))
  12180. {
  12181. continue;
  12182. }
  12183. if (NULL != pBlob)
  12184. {
  12185. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  12186. _JumpError(hr, error, "Multiple encrypted key hashes");
  12187. }
  12188. if (1 != pAttrib->cValue)
  12189. {
  12190. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  12191. _JumpError(hr, error, "Attribute Value count != 1");
  12192. }
  12193. if (!myDecodeObject(
  12194. X509_ASN_ENCODING,
  12195. X509_OCTET_STRING,
  12196. pAttrib->rgValue[0].pbData,
  12197. pAttrib->rgValue[0].cbData,
  12198. CERTLIB_USE_LOCALALLOC,
  12199. (VOID **) &pBlob,
  12200. &cb))
  12201. {
  12202. hr = myHLastError();
  12203. _JumpError(hr, error, "myDecodeObject");
  12204. }
  12205. *ppbKeyHashOut = (BYTE *) LocalAlloc(
  12206. LMEM_FIXED,
  12207. pBlob->cbData);
  12208. if (NULL == *ppbKeyHashOut)
  12209. {
  12210. hr = E_OUTOFMEMORY;
  12211. _JumpError(hr, error, "LocalAlloc");
  12212. }
  12213. CopyMemory(*ppbKeyHashOut, pBlob->pbData, pBlob->cbData);
  12214. *pcbKeyHashOut = pBlob->cbData;
  12215. }
  12216. }
  12217. if (NULL == pBlob)
  12218. {
  12219. hr = CRYPT_E_NOT_FOUND;
  12220. _JumpError(hr, error, "No encrypted key hash");
  12221. }
  12222. hr = S_OK;
  12223. error:
  12224. if (NULL != pBlob)
  12225. {
  12226. LocalFree(pBlob);
  12227. }
  12228. if (NULL != pcmcData)
  12229. {
  12230. LocalFree(pcmcData);
  12231. }
  12232. if (NULL != pcmcAttrib)
  12233. {
  12234. LocalFree(pcmcAttrib);
  12235. }
  12236. if (NULL != pbContent)
  12237. {
  12238. LocalFree(pbContent);
  12239. }
  12240. if (NULL != pbRequest)
  12241. {
  12242. LocalFree(pbRequest);
  12243. }
  12244. if (NULL != pszInnerContentObjId)
  12245. {
  12246. LocalFree(pszInnerContentObjId);
  12247. }
  12248. if (NULL != hMsg)
  12249. {
  12250. CryptMsgClose(hMsg);
  12251. }
  12252. return(hr);
  12253. }
  12254. // Build a PKCS7 CMC response
  12255. HRESULT
  12256. PKCSEncodeFullResponse(
  12257. OPTIONAL IN ICertDBRow *prow,
  12258. IN CERTSRV_RESULT_CONTEXT *pResult,
  12259. IN HRESULT hrRequest,
  12260. IN WCHAR *pwszDispositionString,
  12261. OPTIONAL IN CACTX *pCAContext,
  12262. OPTIONAL IN BYTE const *pbCertLeaf,
  12263. IN DWORD cbCertLeaf,
  12264. IN BOOL fIncludeCRLs,
  12265. OUT BYTE **ppbResponse, // CoTaskMem*
  12266. OUT DWORD *pcbResponse)
  12267. {
  12268. HRESULT hr;
  12269. CMC_RESPONSE_INFO Response;
  12270. CMC_STATUS_INFO Status;
  12271. BYTE *pbContent = NULL;
  12272. DWORD cbContent;
  12273. DWORD dwBodyPartIdOfRequest = 1;
  12274. DWORD dwCMCDataReference = 0;
  12275. DWORD dwBodyPartId = 1;
  12276. CMC_TAGGED_ATTRIBUTE aTaggedAttribute[5];
  12277. DWORD ita = 0;
  12278. CRYPT_ATTRIBUTE aAttr[2];
  12279. DWORD iAttr = 0;
  12280. CRYPT_ATTR_BLOB aAttrBlob[7];
  12281. DWORD iblob = 0;
  12282. CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo;
  12283. CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo;
  12284. CMC_PEND_INFO PendInfo;
  12285. DWORD ReqId;
  12286. DWORD dwRequestFlags;
  12287. DWORD cb;
  12288. DWORD i;
  12289. HCRYPTMSG hMsg = NULL;
  12290. CERT_CONTEXT const **prgCert = NULL;
  12291. CRL_CONTEXT const **prgCRL = NULL;
  12292. CHAR szNonce[(11 + 1) + (8 + 1) * 3];
  12293. ZeroMemory(aAttrBlob, sizeof(aAttrBlob));
  12294. ZeroMemory(&Status, sizeof(Status));
  12295. ZeroMemory(&Response, sizeof(Response));
  12296. ZeroMemory(&SignedMsgEncodeInfo, sizeof(SignedMsgEncodeInfo));
  12297. SignedMsgEncodeInfo.cbSize = sizeof(SignedMsgEncodeInfo);
  12298. SignedMsgEncodeInfo.cSigners = 1;
  12299. SignedMsgEncodeInfo.rgSigners = &SignerEncodeInfo;
  12300. //SignedMsgEncodeInfo.cCertEncoded = 0;
  12301. //SignedMsgEncodeInfo.rgCertEncoded = NULL;
  12302. //SignedMsgEncodeInfo.cCrlEncoded = 0;
  12303. //SignedMsgEncodeInfo.rgCrlEncoded = NULL;
  12304. Status.cBodyList = 1;
  12305. Status.dwOtherInfoChoice = CMC_OTHER_INFO_NO_CHOICE;
  12306. Status.rgdwBodyList = &dwBodyPartIdOfRequest;
  12307. Status.pwszStatusString = pwszDispositionString;
  12308. switch (*pResult->pdwDisposition)
  12309. {
  12310. case CR_DISP_ISSUED:
  12311. case CR_DISP_ISSUED_OUT_OF_BAND:
  12312. case CR_DISP_REVOKED: // map revoked to CMC_STATUS_FAILED?
  12313. Status.dwStatus = CMC_STATUS_SUCCESS;
  12314. break;
  12315. case CR_DISP_UNDER_SUBMISSION:
  12316. Status.dwStatus = CMC_STATUS_PENDING;
  12317. Status.dwOtherInfoChoice = CMC_OTHER_INFO_PEND_CHOICE;
  12318. Status.pPendInfo = &PendInfo;
  12319. CSASSERT(NULL != prow);
  12320. prow->GetRowId(&ReqId);
  12321. PendInfo.PendToken.cbData = sizeof(ReqId);
  12322. PendInfo.PendToken.pbData = (BYTE *) &ReqId;
  12323. cb = sizeof(PendInfo.PendTime);
  12324. hr = prow->GetProperty(
  12325. g_wszPropRequestSubmittedWhen,
  12326. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  12327. NULL,
  12328. &cb,
  12329. (BYTE *) &PendInfo.PendTime);
  12330. _JumpIfError(hr, error, "GetProperty");
  12331. break;
  12332. //case CR_DISP_INCOMPLETE:
  12333. //case CR_DISP_ERROR:
  12334. //case CR_DISP_DENIED:
  12335. default:
  12336. Status.dwStatus = CMC_STATUS_FAILED;
  12337. if (NULL != prow)
  12338. {
  12339. cb = sizeof(hrRequest);
  12340. hr = prow->GetProperty(
  12341. g_wszPropRequestStatusCode,
  12342. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  12343. NULL,
  12344. &cb,
  12345. (BYTE *) &hrRequest);
  12346. _JumpIfError(hr, error, "GetProperty(status code)");
  12347. }
  12348. switch (hrRequest)
  12349. {
  12350. case CERTSRV_E_BAD_REQUESTSUBJECT:
  12351. Status.dwFailInfo = CMC_FAIL_BAD_REQUEST;
  12352. Status.dwOtherInfoChoice = CMC_OTHER_INFO_FAIL_CHOICE;
  12353. break;
  12354. }
  12355. break;
  12356. }
  12357. // Encode control attributes for Status, Transaction Id, Sender and
  12358. // Recipient Nonces and Issued Cert Hash.
  12359. ZeroMemory(aTaggedAttribute, sizeof(aTaggedAttribute));
  12360. // Status:
  12361. if (!myEncodeObject(
  12362. X509_ASN_ENCODING,
  12363. CMC_STATUS,
  12364. &Status,
  12365. 0,
  12366. CERTLIB_USE_LOCALALLOC,
  12367. &aAttrBlob[iblob].pbData,
  12368. &aAttrBlob[iblob].cbData))
  12369. {
  12370. hr = myHLastError();
  12371. _JumpError(hr, error, "myEncodeObject");
  12372. }
  12373. aTaggedAttribute[ita].dwBodyPartID = dwBodyPartId++;
  12374. aTaggedAttribute[ita].Attribute.pszObjId = szOID_CMC_STATUS_INFO;
  12375. aTaggedAttribute[ita].Attribute.cValue = 1;
  12376. aTaggedAttribute[ita].Attribute.rgValue = &aAttrBlob[iblob];
  12377. iblob++;
  12378. ita++;
  12379. // Transaction Id:
  12380. if (pResult->fTransactionId)
  12381. {
  12382. if (!myEncodeObject(
  12383. X509_ASN_ENCODING,
  12384. X509_INTEGER,
  12385. &pResult->dwTransactionId,
  12386. 0,
  12387. CERTLIB_USE_LOCALALLOC,
  12388. &aAttrBlob[iblob].pbData,
  12389. &aAttrBlob[iblob].cbData))
  12390. {
  12391. hr = myHLastError();
  12392. _JumpError(hr, error, "myEncodeObject");
  12393. }
  12394. aTaggedAttribute[ita].dwBodyPartID = dwBodyPartId++;
  12395. aTaggedAttribute[ita].Attribute.pszObjId = szOID_CMC_TRANSACTION_ID;
  12396. aTaggedAttribute[ita].Attribute.cValue = 1;
  12397. aTaggedAttribute[ita].Attribute.rgValue = &aAttrBlob[iblob];
  12398. iblob++;
  12399. ita++;
  12400. }
  12401. if (NULL != pResult->pbSenderNonce && 0 != pResult->cbSenderNonce)
  12402. {
  12403. CRYPT_DATA_BLOB Blob;
  12404. FILETIME ft;
  12405. DWORD dw;
  12406. DWORD cch;
  12407. // Recipient Nonce:
  12408. Blob.pbData = const_cast<BYTE *>(pResult->pbSenderNonce);
  12409. Blob.cbData = pResult->cbSenderNonce;
  12410. if (!myEncodeObject(
  12411. X509_ASN_ENCODING,
  12412. X509_OCTET_STRING,
  12413. &Blob,
  12414. 0,
  12415. CERTLIB_USE_LOCALALLOC,
  12416. &aAttrBlob[iblob].pbData,
  12417. &aAttrBlob[iblob].cbData))
  12418. {
  12419. hr = myHLastError();
  12420. _JumpError(hr, error, "myEncodeObject");
  12421. }
  12422. aTaggedAttribute[ita].dwBodyPartID = dwBodyPartId++;
  12423. aTaggedAttribute[ita].Attribute.pszObjId = szOID_CMC_RECIPIENT_NONCE;
  12424. aTaggedAttribute[ita].Attribute.cValue = 1;
  12425. aTaggedAttribute[ita].Attribute.rgValue = &aAttrBlob[iblob];
  12426. iblob++;
  12427. ita++;
  12428. // Sender Nonce:
  12429. GetSystemTimeAsFileTime(&ft);
  12430. dw = GetTickCount();
  12431. cch = sprintf(
  12432. szNonce,
  12433. "%u %08lx %08lx-%08lx",
  12434. *pResult->pdwRequestId,
  12435. dw,
  12436. ft.dwHighDateTime,
  12437. ft.dwLowDateTime);
  12438. CSASSERT(ARRAYSIZE(szNonce) > cch);
  12439. Blob.pbData = (BYTE *) szNonce;
  12440. Blob.cbData = cch;
  12441. if (!myEncodeObject(
  12442. X509_ASN_ENCODING,
  12443. X509_OCTET_STRING,
  12444. &Blob,
  12445. 0,
  12446. CERTLIB_USE_LOCALALLOC,
  12447. &aAttrBlob[iblob].pbData,
  12448. &aAttrBlob[iblob].cbData))
  12449. {
  12450. hr = myHLastError();
  12451. _JumpError(hr, error, "myEncodeObject");
  12452. }
  12453. aTaggedAttribute[ita].dwBodyPartID = dwBodyPartId++;
  12454. aTaggedAttribute[ita].Attribute.pszObjId = szOID_CMC_SENDER_NONCE;
  12455. aTaggedAttribute[ita].Attribute.cValue = 1;
  12456. aTaggedAttribute[ita].Attribute.rgValue = &aAttrBlob[iblob];
  12457. iblob++;
  12458. ita++;
  12459. }
  12460. // Issued Cert Hash:
  12461. if (NULL != pbCertLeaf)
  12462. {
  12463. CSASSERT(NULL != prow);
  12464. hr = pkcsGetHashAsOctet(
  12465. prow,
  12466. &aAttrBlob[iblob].pbData,
  12467. &aAttrBlob[iblob].cbData);
  12468. _JumpIfError(hr, error, "pkcsGetHashAsOctet");
  12469. aAttr[iAttr].pszObjId = szOID_ISSUED_CERT_HASH;
  12470. aAttr[iAttr].cValue = 1;
  12471. aAttr[iAttr].rgValue = &aAttrBlob[iblob];
  12472. iblob++;
  12473. iAttr++;
  12474. }
  12475. dwRequestFlags = 0;
  12476. if (NULL != prow)
  12477. {
  12478. cb = sizeof(dwRequestFlags);
  12479. hr = prow->GetProperty(
  12480. g_wszPropRequestFlags,
  12481. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  12482. NULL,
  12483. &cb,
  12484. (BYTE *) &dwRequestFlags);
  12485. if (S_OK != hr)
  12486. {
  12487. _PrintError(hr, "GetProperty");
  12488. dwRequestFlags = 0;
  12489. }
  12490. }
  12491. // Computed hash of private key encrypted to this CA, for client
  12492. // confirmation.
  12493. if (CR_FLG_VALIDENCRYPTEDKEYHASH & dwRequestFlags)
  12494. {
  12495. CRYPT_DATA_BLOB Blob;
  12496. if (NULL == pResult->pbKeyHashOut)
  12497. {
  12498. hr = pkcsRetrieveKeyHashFromRequest(
  12499. prow,
  12500. &pResult->pbKeyHashOut,
  12501. &pResult->cbKeyHashOut);
  12502. _JumpIfError(hr, error, "pkcsRetrieveKeyHashFromRequest");
  12503. }
  12504. Blob.pbData = pResult->pbKeyHashOut;
  12505. Blob.cbData = pResult->cbKeyHashOut;
  12506. if (!myEncodeObject(
  12507. X509_ASN_ENCODING,
  12508. X509_OCTET_STRING,
  12509. &Blob,
  12510. 0,
  12511. CERTLIB_USE_LOCALALLOC,
  12512. &aAttrBlob[iblob].pbData,
  12513. &aAttrBlob[iblob].cbData))
  12514. {
  12515. hr = myHLastError();
  12516. _JumpError(hr, error, "myEncodeObject");
  12517. }
  12518. aAttr[iAttr].pszObjId = szOID_ENCRYPTED_KEY_HASH;
  12519. aAttr[iAttr].cValue = 1;
  12520. aAttr[iAttr].rgValue = &aAttrBlob[iblob];
  12521. iblob++;
  12522. iAttr++;
  12523. }
  12524. if (0 != iAttr)
  12525. {
  12526. hr = BuildCMCAttributes(
  12527. iAttr, // cAttribute
  12528. aAttr, // rgAttribute
  12529. dwCMCDataReference,
  12530. dwBodyPartIdOfRequest,
  12531. dwBodyPartId++,
  12532. &aTaggedAttribute[ita],
  12533. &aAttrBlob[iblob]);
  12534. _JumpIfError(hr, error, "BuildCMCAttributes");
  12535. iblob++;
  12536. ita++;
  12537. }
  12538. CSASSERT(ARRAYSIZE(aTaggedAttribute) >= ita);
  12539. CSASSERT(ARRAYSIZE(aAttr) >= iAttr);
  12540. CSASSERT(ARRAYSIZE(aAttrBlob) >= iblob);
  12541. Response.cTaggedAttribute = ita;
  12542. Response.rgTaggedAttribute = aTaggedAttribute;
  12543. if (!myEncodeObject(
  12544. X509_ASN_ENCODING,
  12545. CMC_RESPONSE,
  12546. &Response,
  12547. 0,
  12548. CERTLIB_USE_LOCALALLOC,
  12549. &pbContent,
  12550. &cbContent))
  12551. {
  12552. hr = myHLastError();
  12553. _JumpError(hr, error, "myEncodeObject");
  12554. }
  12555. if (NULL == pCAContext)
  12556. {
  12557. pCAContext = g_pCAContextCurrent;
  12558. }
  12559. ZeroMemory(&SignerEncodeInfo, sizeof(SignerEncodeInfo));
  12560. SignerEncodeInfo.cbSize = sizeof(SignerEncodeInfo);
  12561. SignerEncodeInfo.pCertInfo = pCAContext->pccCA->pCertInfo;
  12562. SignerEncodeInfo.hCryptProv = pCAContext->hProvCA;
  12563. SignerEncodeInfo.dwKeySpec = AT_SIGNATURE;
  12564. SignerEncodeInfo.HashAlgorithm.pszObjId = szOID_OIWSEC_sha1;
  12565. //SignerEncodeInfo.pvHashAuxInfo = NULL;
  12566. //SignerEncodeInfo.cAuthAttr = 0;
  12567. //SignerEncodeInfo.rgAuthAttr = NULL;
  12568. //SignerEncodeInfo.cUnauthAttr = 0;
  12569. //SignerEncodeInfo.rgUnauthAttr = NULL;
  12570. if (NULL != pbCertLeaf)
  12571. {
  12572. hr = pkcsBuildCRLChain(
  12573. pCAContext,
  12574. pbCertLeaf,
  12575. cbCertLeaf,
  12576. fIncludeCRLs,
  12577. &SignedMsgEncodeInfo.cCertEncoded,
  12578. &SignedMsgEncodeInfo.rgCertEncoded,
  12579. &prgCert,
  12580. &SignedMsgEncodeInfo.cCrlEncoded,
  12581. &SignedMsgEncodeInfo.rgCrlEncoded,
  12582. &prgCRL);
  12583. _JumpIfError(hr, error, "pkcsBuildCRLChain");
  12584. }
  12585. hMsg = CryptMsgOpenToEncode(
  12586. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  12587. CMSG_CMS_ENCAPSULATED_CONTENT_FLAG, // dwFlags
  12588. CMSG_SIGNED,
  12589. &SignedMsgEncodeInfo,
  12590. szOID_CT_PKI_RESPONSE,
  12591. NULL); // pStreamInfo
  12592. if (NULL == hMsg)
  12593. {
  12594. hr = myHLastError();
  12595. _JumpError(hr, error, "CryptMsgOpenToEncode");
  12596. }
  12597. if (!CryptMsgUpdate(hMsg, pbContent, cbContent, TRUE))
  12598. {
  12599. hr = myHLastError();
  12600. _JumpError(hr, error, "CryptMsgUpdate");
  12601. }
  12602. // Return the encoded and signed content.
  12603. // Use CMSG_CONTENT_PARAM to get the signed message.
  12604. hr = myCryptMsgGetParam(
  12605. hMsg,
  12606. CMSG_CONTENT_PARAM,
  12607. 0,
  12608. CERTLIB_USE_COTASKMEMALLOC,
  12609. (VOID **) ppbResponse,
  12610. pcbResponse);
  12611. _JumpIfError(hr, error, "myCryptMsgGetParam");
  12612. if (CRLF_LOG_FULL_RESPONSE & g_dwCRLFlags)
  12613. {
  12614. mydbgDumpHex(DBG_SS_ERROR, 0, *ppbResponse, *pcbResponse);
  12615. }
  12616. error:
  12617. pkcsFreeCRLChain(
  12618. SignedMsgEncodeInfo.cCertEncoded,
  12619. SignedMsgEncodeInfo.rgCertEncoded,
  12620. prgCert,
  12621. SignedMsgEncodeInfo.cCrlEncoded,
  12622. SignedMsgEncodeInfo.rgCrlEncoded,
  12623. prgCRL);
  12624. for (i = 0; i < ARRAYSIZE(aAttrBlob); i++)
  12625. {
  12626. if (NULL != aAttrBlob[i].pbData)
  12627. {
  12628. LocalFree(aAttrBlob[i].pbData);
  12629. }
  12630. }
  12631. if (NULL != hMsg)
  12632. {
  12633. CryptMsgClose(hMsg);
  12634. }
  12635. if (NULL != pbContent)
  12636. {
  12637. LocalFree(pbContent);
  12638. }
  12639. return(hr);
  12640. }
  12641. // Build a PKCS7 NULL signature with encapsulated certs
  12642. HRESULT
  12643. pkcsEncodeCertChain(
  12644. OPTIONAL IN CACTX *pCAContext,
  12645. OPTIONAL IN BYTE const *pbCertLeaf,
  12646. IN DWORD cbCertLeaf,
  12647. IN BYTE const *pbToBeSigned,
  12648. IN DWORD cbToBeSigned,
  12649. IN BOOL fIncludeCRLs,
  12650. OUT BYTE **ppbCertChain, // CoTaskMem*
  12651. OUT DWORD *pcbCertChain)
  12652. {
  12653. HRESULT hr;
  12654. CRYPT_SIGN_MESSAGE_PARA csmp;
  12655. CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm = { szOID_OIWSEC_sha1, 0, 0 };
  12656. // init csmp for empty signature
  12657. ZeroMemory(&csmp, sizeof(csmp));
  12658. csmp.cbSize = sizeof(csmp);
  12659. csmp.dwMsgEncodingType = PKCS_7_ASN_ENCODING;
  12660. //csmp.pSigningCert = NULL;
  12661. csmp.HashAlgorithm = DigestAlgorithm;
  12662. //csmp.cMsgCert = 0;
  12663. //csmp.rgpMsgCert = NULL;
  12664. //csmp.cMsgCrl = 0;
  12665. //csmp.rgpMsgCrl = NULL;
  12666. hr = pkcsBuildCRLChain(
  12667. pCAContext,
  12668. pbCertLeaf,
  12669. cbCertLeaf,
  12670. fIncludeCRLs,
  12671. &csmp.cMsgCert,
  12672. NULL,
  12673. &csmp.rgpMsgCert,
  12674. &csmp.cMsgCrl,
  12675. NULL,
  12676. &csmp.rgpMsgCrl);
  12677. _JumpIfError(hr, error, "pkcsBuildCRLChain");
  12678. if (!myCryptSignMessage(
  12679. &csmp,
  12680. pbToBeSigned,
  12681. cbToBeSigned,
  12682. CERTLIB_USE_COTASKMEMALLOC,
  12683. ppbCertChain,
  12684. pcbCertChain))
  12685. {
  12686. hr = myHLastError();
  12687. _JumpError(hr, error, "myCryptSignMessage");
  12688. }
  12689. hr = S_OK;
  12690. error:
  12691. pkcsFreeCRLChain(
  12692. csmp.cMsgCert,
  12693. NULL,
  12694. csmp.rgpMsgCert,
  12695. csmp.cMsgCrl,
  12696. NULL,
  12697. csmp.rgpMsgCrl);
  12698. return(hr);
  12699. }
  12700. HRESULT
  12701. PKCSGetCACert(
  12702. IN LONG PropId, // CR_PROP_*
  12703. IN DWORD iCert,
  12704. OUT BYTE **ppbCACert,
  12705. OUT DWORD *pcbCACert)
  12706. {
  12707. HRESULT hr;
  12708. DWORD State;
  12709. CERT_CONTEXT const *pcc = NULL;
  12710. CACROSSCTX *pCACross;
  12711. switch (PropId)
  12712. {
  12713. case CR_PROP_CAFORWARDCROSSCERT:
  12714. case CR_PROP_CABACKWARDCROSSCERT:
  12715. hr = pkcsMapCrossCertIndex(
  12716. CR_PROP_CAFORWARDCROSSCERT == PropId,
  12717. iCert,
  12718. &iCert,
  12719. &State);
  12720. _JumpIfError(hr, error, "pkcsMapCrossCertIndex");
  12721. // Now we know iCert is a valid Cross Cert Index:
  12722. pCACross = CR_PROP_CAFORWARDCROSSCERT == PropId?
  12723. g_aCACrossForward : g_aCACrossBackward;
  12724. if (NULL != pCACross)
  12725. {
  12726. pcc = pCACross[iCert].pccCACross;
  12727. }
  12728. break;
  12729. case CR_PROP_CASIGCERT:
  12730. hr = PKCSMapCertIndex(iCert, &iCert, &State);
  12731. _JumpIfError(hr, error, "PKCSMapCertIndex");
  12732. // Now we know iCert is a valid Cert Index:
  12733. pcc = g_aCAContext[iCert].pccCA;
  12734. break;
  12735. default:
  12736. hr = E_INVALIDARG;
  12737. _JumpError(hr, error, "PropId");
  12738. break;
  12739. }
  12740. if (NULL == pcc)
  12741. {
  12742. hr = E_INVALIDARG;
  12743. _JumpError(hr, error, "invalid cert");
  12744. }
  12745. *pcbCACert = pcc->cbCertEncoded;
  12746. *ppbCACert = pcc->pbCertEncoded;
  12747. hr = S_OK;
  12748. error:
  12749. return(hr);
  12750. }
  12751. HRESULT
  12752. PKCSGetCAChain(
  12753. IN DWORD iCert,
  12754. IN BOOL fIncludeCRLs,
  12755. OUT BYTE **ppbCAChain, // CoTaskMem*
  12756. OUT DWORD *pcbCAChain)
  12757. {
  12758. HRESULT hr;
  12759. DWORD State;
  12760. CACTX *pCAContext;
  12761. hr = PKCSMapCertIndex(iCert, &iCert, &State);
  12762. _JumpIfError(hr, error, "PKCSMapCertIndex");
  12763. // Now we know iCert is a valid Cert Index:
  12764. pCAContext = &g_aCAContext[iCert];
  12765. if (NULL == pCAContext->pccCA)
  12766. {
  12767. hr = E_INVALIDARG;
  12768. _JumpError(hr, error, "invalid cert");
  12769. }
  12770. hr = pkcsEncodeCertChain(
  12771. pCAContext,
  12772. NULL, // pbCertLeaf
  12773. 0, // cbCertLeaf
  12774. pCAContext->pccCA->pbCertEncoded, // pbToBeSigned
  12775. pCAContext->pccCA->cbCertEncoded, // cbToBeSigned
  12776. fIncludeCRLs,
  12777. ppbCAChain, // CoTaskMem*
  12778. pcbCAChain);
  12779. _JumpIfError(hr, error, "PKCSEncodeCertChain");
  12780. error:
  12781. return(hr);
  12782. }
  12783. HRESULT
  12784. pkcsAcquireKey(
  12785. OPTIONAL IN WCHAR const *pwszKeyContainer,
  12786. OUT HCRYPTPROV *phProv)
  12787. {
  12788. HRESULT hr;
  12789. *phProv = NULL;
  12790. if (!CryptAcquireContext(
  12791. phProv,
  12792. pwszKeyContainer,
  12793. g_pwszXchgProvName,
  12794. g_dwXchgProvType,
  12795. g_CryptSilent |
  12796. (g_fXchgMachineKeyset? CRYPT_MACHINE_KEYSET : 0)))
  12797. {
  12798. hr = myHLastError();
  12799. _JumpError(hr, error, "CryptAcquireContext");
  12800. }
  12801. hr = S_OK;
  12802. error:
  12803. return(hr);
  12804. }
  12805. HRESULT
  12806. pkcsSyncRegTimePeriod(
  12807. IN WCHAR const *pwszRegPeriodCount,
  12808. IN WCHAR const *pwszRegPeriodString,
  12809. IN OUT enum ENUM_PERIOD *penumCAXchgValidityPeriod,
  12810. IN OUT LONG *plCAXchgValidityPeriodCount,
  12811. IN FILETIME const *pft)
  12812. {
  12813. HRESULT hr;
  12814. DWORD cPeriodUnits;
  12815. PERIODUNITS *rgPeriodUnits = NULL;
  12816. hr = caTranslateFileTimePeriodToPeriodUnits(
  12817. pft,
  12818. FALSE, // fExact
  12819. &cPeriodUnits,
  12820. &rgPeriodUnits);
  12821. _JumpIfError(hr, error, "caTranslateFileTimePeriodToPeriodUnits");
  12822. CSASSERT(0 < cPeriodUnits);
  12823. if (rgPeriodUnits[0].lCount != *plCAXchgValidityPeriodCount ||
  12824. rgPeriodUnits[0].enumPeriod != *penumCAXchgValidityPeriod)
  12825. {
  12826. WCHAR const *pwszPeriodString;
  12827. *plCAXchgValidityPeriodCount = rgPeriodUnits[0].lCount;
  12828. *penumCAXchgValidityPeriod = rgPeriodUnits[0].enumPeriod;
  12829. hr = myTranslateUnlocalizedPeriodString(
  12830. rgPeriodUnits[0].enumPeriod,
  12831. &pwszPeriodString);
  12832. _JumpIfError(hr, error, "myTranslateUnlocalizedPeriodString");
  12833. // CA xchg cert period string
  12834. hr = mySetCertRegStrValue(
  12835. g_wszSanitizedName,
  12836. NULL,
  12837. NULL,
  12838. pwszRegPeriodString,
  12839. pwszPeriodString);
  12840. _JumpIfErrorStr(hr, error, "mySetCertRegStrValue", pwszRegPeriodString);
  12841. // CA xchg cert period count
  12842. hr = mySetCertRegDWValue(
  12843. g_wszSanitizedName,
  12844. NULL,
  12845. NULL,
  12846. pwszRegPeriodCount,
  12847. *plCAXchgValidityPeriodCount);
  12848. _JumpIfErrorStr(hr, error, "mySetCertRegDWValue", pwszRegPeriodCount);
  12849. }
  12850. hr = S_OK;
  12851. error:
  12852. if (NULL != rgPeriodUnits)
  12853. {
  12854. LocalFree(rgPeriodUnits);
  12855. }
  12856. return(hr);
  12857. }
  12858. // Set validity & overlap periods from template; update registry if it differs.
  12859. // enum ENUM_PERIOD g_enumCAXchgValidityPeriod
  12860. // LONG g_lCAXchgValidityPeriodCount
  12861. //
  12862. // enum ENUM_PERIOD g_enumCAXchgOverlapPeriod
  12863. // LONG g_lCAXchgOverlapPeriodCount
  12864. HRESULT
  12865. PKCSUpdateXchgValidityPeriods(
  12866. OPTIONAL IN HCERTTYPE hCertType)
  12867. {
  12868. HRESULT hr;
  12869. HCERTTYPE hCertTypeT = NULL;
  12870. FILETIME ftExpiration;
  12871. FILETIME ftOverlap;
  12872. if (NULL == hCertType)
  12873. {
  12874. hr = CAFindCertTypeByName(
  12875. wszCERTTYPE_CA_EXCHANGE,
  12876. NULL,
  12877. CT_FIND_LOCAL_SYSTEM |
  12878. CT_ENUM_MACHINE_TYPES |
  12879. CT_ENUM_USER_TYPES |
  12880. CT_FLAG_NO_CACHE_LOOKUP,
  12881. &hCertTypeT);
  12882. _JumpIfErrorStr(hr, error, "CAFindCertTypeByName", wszCERTTYPE_CA_EXCHANGE);
  12883. hCertType = hCertTypeT;
  12884. }
  12885. hr = CAGetCertTypeExpiration(
  12886. hCertType,
  12887. &ftExpiration,
  12888. &ftOverlap);
  12889. _JumpIfError(hr, error, "CAGetCertTypeExpiration");
  12890. hr = pkcsSyncRegTimePeriod(
  12891. g_wszRegCAXchgValidityPeriodCount,
  12892. g_wszRegCAXchgValidityPeriodString,
  12893. &g_enumCAXchgValidityPeriod,
  12894. &g_lCAXchgValidityPeriodCount,
  12895. &ftExpiration);
  12896. _JumpIfError(hr, error, "pkcsSyncRegTimePeriod");
  12897. hr = pkcsSyncRegTimePeriod(
  12898. g_wszRegCAXchgOverlapPeriodCount,
  12899. g_wszRegCAXchgOverlapPeriodString,
  12900. &g_enumCAXchgOverlapPeriod,
  12901. &g_lCAXchgOverlapPeriodCount,
  12902. &ftOverlap);
  12903. _JumpIfError(hr, error, "pkcsSyncRegTimePeriod");
  12904. error:
  12905. if (NULL != hCertTypeT)
  12906. {
  12907. CACloseCertType(hCertTypeT);
  12908. }
  12909. return(hr);
  12910. }
  12911. VOID
  12912. pkcsReleaseCAXchgContext(
  12913. IN OUT CAXCHGCTX *pCAXchgContext)
  12914. {
  12915. if (NULL != pCAXchgContext->hProvCA)
  12916. {
  12917. CryptReleaseContext(pCAXchgContext->hProvCA, 0);
  12918. pCAXchgContext->hProvCA = NULL;
  12919. }
  12920. if (NULL != pCAXchgContext->pccCAXchg)
  12921. {
  12922. CertFreeCertificateContext(pCAXchgContext->pccCAXchg);
  12923. pCAXchgContext->pccCAXchg = NULL;
  12924. }
  12925. if (NULL != pCAXchgContext->pwszKeyContainerName)
  12926. {
  12927. LocalFree(pCAXchgContext->pwszKeyContainerName);
  12928. pCAXchgContext->pwszKeyContainerName = NULL;
  12929. }
  12930. }
  12931. VOID
  12932. pkcsReleaseCAXchgContextArray()
  12933. {
  12934. DWORD i;
  12935. if (NULL != g_aCAXchgContext)
  12936. {
  12937. for (i = 0; i < g_cCAXchgCerts; i++)
  12938. {
  12939. pkcsReleaseCAXchgContext(&g_aCAXchgContext[i]);
  12940. }
  12941. LocalFree(g_aCAXchgContext);
  12942. g_aCAXchgContext = NULL;
  12943. }
  12944. g_cCAXchgCerts = 0;
  12945. g_pCAContextCurrent = NULL;
  12946. }
  12947. HRESULT
  12948. pkcsLoadCAXchgContext(
  12949. IN DWORD iHash)
  12950. {
  12951. HRESULT hr;
  12952. CAXCHGCTX *pCAXchgContext;
  12953. DWORD dwRequestFlags;
  12954. DWORD NameId;
  12955. HCRYPTPROV hProv = NULL;
  12956. WCHAR *pwszKeyContainer = NULL;
  12957. BYTE *pbHash = NULL;
  12958. DWORD cbHash;
  12959. BYTE *pbCert = NULL;
  12960. DWORD cbCert;
  12961. DWORD cb;
  12962. BSTR strHash = NULL;
  12963. ICertDBRow *prow = NULL;
  12964. DWORD dwRequestId;
  12965. CERT_CONTEXT const *pcc = NULL;
  12966. BOOL fDeleteKey = FALSE;
  12967. DWORD i;
  12968. hr = myGetCARegHash(
  12969. g_wszSanitizedName,
  12970. CSRH_CAXCHGCERT,
  12971. iHash,
  12972. &pbHash,
  12973. &cbHash);
  12974. _JumpIfError2(hr, error, "myGetCARegHash", S_FALSE);
  12975. hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strHash);
  12976. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  12977. DBGPRINT((
  12978. DBG_SS_CERTSRV,
  12979. "Reloading Xchg CAContext[%u]:\n %ws\n",
  12980. iHash,
  12981. strHash));
  12982. hr = g_pCertDB->OpenRow(
  12983. PROPOPEN_READONLY | PROPOPEN_CERTHASH | PROPTABLE_REQCERT,
  12984. 0,
  12985. strHash,
  12986. &prow);
  12987. _JumpIfError(hr, error, "OpenRow(xchg cert)");
  12988. prow->GetRowId(&dwRequestId);
  12989. hr = pkcsFormXchgKeyContainerName(dwRequestId, &pwszKeyContainer);
  12990. _JumpIfError(hr, error, "pkcsFormXchgKeyContainerName");
  12991. cb = sizeof(dwRequestFlags);
  12992. hr = prow->GetProperty(
  12993. g_wszPropRequestFlags,
  12994. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  12995. NULL,
  12996. &cb,
  12997. (BYTE *) &dwRequestFlags);
  12998. _JumpIfError(hr, error, "GetProperty(RequestFlags)");
  12999. if (0 == (CR_FLG_CAXCHGCERT & dwRequestFlags))
  13000. {
  13001. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  13002. _JumpError(hr, error, "Not a CA Xchg cert");
  13003. }
  13004. cb = sizeof(NameId);
  13005. hr = prow->GetProperty(
  13006. g_wszPropCertificateIssuerNameID,
  13007. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  13008. NULL,
  13009. &cb,
  13010. (BYTE *) &NameId);
  13011. _JumpIfError(hr, error, "GetProperty");
  13012. hr = PKCSGetProperty(
  13013. prow,
  13014. g_wszPropRawCertificate,
  13015. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  13016. &cbCert,
  13017. (BYTE **) &pbCert);
  13018. _JumpIfError(hr, error, "PKCSGetProperty(xchg cert)");
  13019. pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
  13020. if (NULL == pcc)
  13021. {
  13022. hr = myHLastError();
  13023. _JumpError(hr, error, "CertCreateCertificateContext");
  13024. }
  13025. for (i = 0; ; i++)
  13026. {
  13027. hr = pkcsAcquireKey(pwszKeyContainer, &hProv);
  13028. _PrintIfErrorStr(hr, "pkcsAcquireKey", g_pwszXchgProvName);
  13029. if (S_OK == hr)
  13030. {
  13031. hr = myValidateKeyForEncrypting(
  13032. hProv,
  13033. &pcc->pCertInfo->SubjectPublicKeyInfo,
  13034. CALG_3DES);
  13035. _PrintIfErrorStr(hr, "myValidateKeyForEncrypting", g_pwszXchgProvName);
  13036. }
  13037. if (S_OK == hr)
  13038. {
  13039. break;
  13040. }
  13041. LogEventHResult(
  13042. NULL == g_pwszXchgProvName?
  13043. EVENTLOG_ERROR_TYPE :
  13044. EVENTLOG_WARNING_TYPE,
  13045. NULL == g_pwszXchgProvName?
  13046. MSG_E_BAD_DEFAULT_CA_XCHG_CSP :
  13047. MSG_E_BAD_REGISTRY_CA_XCHG_CSP,
  13048. hr);
  13049. if (0 != i || NULL == g_pwszXchgProvName)
  13050. {
  13051. fDeleteKey = TRUE;
  13052. _JumpError(hr, error, "pkcsAcquireKey/myValidateKeyForEncrypting");
  13053. }
  13054. pkcsLoadCAXchgCSPInfo(TRUE); // switch to default CSP
  13055. }
  13056. if (0 != i)
  13057. {
  13058. hr = LogEvent(
  13059. EVENTLOG_WARNING_TYPE,
  13060. MSG_E_USE_DEFAULT_CA_XCHG_CSP,
  13061. 0, // cpwsz
  13062. NULL); // apwsz
  13063. _PrintIfError(hr, "LogEvent");
  13064. }
  13065. hr = pkcsVerifyCertContext(NULL, FALSE, pcc);
  13066. if (S_OK != hr)
  13067. {
  13068. fDeleteKey = TRUE;
  13069. _JumpErrorStr(hr, error, "pkcsVerifyCertContext", L"CAXchg cert invalid");
  13070. }
  13071. pCAXchgContext = &g_aCAXchgContext[g_cCAXchgCerts];
  13072. ZeroMemory(pCAXchgContext, sizeof(*pCAXchgContext));
  13073. pCAXchgContext->ReqId = dwRequestId;
  13074. pCAXchgContext->pccCAXchg = pcc;
  13075. pcc = NULL;
  13076. pCAXchgContext->hProvCA = hProv;
  13077. hProv = NULL;
  13078. pCAXchgContext->pwszKeyContainerName = pwszKeyContainer;
  13079. pwszKeyContainer = NULL;
  13080. pCAXchgContext->iCertSig = CANAMEIDTOICERT(NameId);
  13081. g_cCAXchgCerts++;
  13082. hr = S_OK;
  13083. error:
  13084. if (NULL != hProv)
  13085. {
  13086. CryptReleaseContext(hProv, 0);
  13087. }
  13088. if (fDeleteKey)
  13089. {
  13090. pkcsDeleteKey(pwszKeyContainer);
  13091. }
  13092. if (NULL != prow)
  13093. {
  13094. prow->Release();
  13095. }
  13096. if (NULL != pbCert)
  13097. {
  13098. LocalFree(pbCert);
  13099. }
  13100. if (NULL != pcc)
  13101. {
  13102. CertFreeCertificateContext(pcc);
  13103. }
  13104. if (NULL != pwszKeyContainer)
  13105. {
  13106. LocalFree(pwszKeyContainer);
  13107. }
  13108. if (NULL != pbHash)
  13109. {
  13110. LocalFree(pbHash);
  13111. }
  13112. if (NULL != strHash)
  13113. {
  13114. SysFreeString(strHash);
  13115. }
  13116. return(hr);
  13117. }
  13118. HRESULT
  13119. pkcsLoadCAXchgContextArray(
  13120. OUT BOOL *pfIncompleteLoad)
  13121. {
  13122. HRESULT hr;
  13123. DWORD cCAXchgCerts;
  13124. DWORD iHash;
  13125. DWORD i;
  13126. // get provider name, etc.
  13127. pkcsLoadCAXchgCSPInfo(FALSE);
  13128. // find & load CA Xchg certs, etc.
  13129. *pfIncompleteLoad = TRUE;
  13130. hr = myGetCARegHashCount(
  13131. g_wszSanitizedName,
  13132. CSRH_CAXCHGCERT,
  13133. &cCAXchgCerts);
  13134. if (S_OK == hr && 0 == cCAXchgCerts)
  13135. {
  13136. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  13137. }
  13138. _JumpIfError(hr, error, "myGetCARegHashCount");
  13139. g_aCAXchgContext = (CAXCHGCTX *) LocalAlloc(
  13140. LMEM_FIXED | LMEM_ZEROINIT,
  13141. cCAXchgCerts * sizeof(g_aCAXchgContext[0]));
  13142. if (NULL == g_aCAXchgContext)
  13143. {
  13144. hr = E_OUTOFMEMORY;
  13145. _JumpError(hr, error, "LocalAlloc");
  13146. }
  13147. for (iHash = 0; iHash < cCAXchgCerts; iHash++)
  13148. {
  13149. hr = pkcsLoadCAXchgContext(iHash);
  13150. _PrintIfError(hr, "pkcsLoadCAXchgContext");
  13151. }
  13152. if (0 == g_cCAXchgCerts)
  13153. {
  13154. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  13155. _JumpError(hr, error, "g_cCAXchgCerts");
  13156. }
  13157. g_pCAXchgContextCurrent = &g_aCAXchgContext[0];
  13158. for (i = 1; i < g_cCAXchgCerts; i++)
  13159. {
  13160. if (0 < CompareFileTime(
  13161. &g_aCAXchgContext[i].pccCAXchg->pCertInfo->NotAfter,
  13162. &g_pCAXchgContextCurrent->pccCAXchg->pCertInfo->NotAfter))
  13163. {
  13164. g_pCAXchgContextCurrent = &g_aCAXchgContext[i];
  13165. }
  13166. }
  13167. if (cCAXchgCerts == g_cCAXchgCerts)
  13168. {
  13169. *pfIncompleteLoad = FALSE;
  13170. }
  13171. hr = S_OK;
  13172. error:
  13173. if (S_OK != hr)
  13174. {
  13175. if (NULL != g_aCAXchgContext)
  13176. {
  13177. LocalFree(g_aCAXchgContext);
  13178. g_aCAXchgContext = NULL;
  13179. }
  13180. g_cCAXchgCerts = 0;
  13181. g_pCAXchgContextCurrent = NULL;
  13182. }
  13183. return(hr);
  13184. }
  13185. HRESULT
  13186. pkcsUpdateCAXchgStoreAndRegistry(
  13187. IN BOOL fUpdateRegistry)
  13188. {
  13189. HRESULT hr;
  13190. DWORD i;
  13191. DWORD iHash;
  13192. CAXCHGCTX *pCAXchgContext;
  13193. HCERTSTORE hStore = NULL;
  13194. CERT_KEY_CONTEXT ckc;
  13195. CERT_CONTEXT const *pccStore = NULL;
  13196. hStore = CertOpenStore(
  13197. CERT_STORE_PROV_MEMORY,
  13198. X509_ASN_ENCODING,
  13199. NULL, // hProv
  13200. 0, // dwFlags
  13201. NULL); // pvPara
  13202. if (NULL == hStore)
  13203. {
  13204. hr = myHLastError();
  13205. _JumpError(hr, error, "CertOpenStore");
  13206. }
  13207. if (fUpdateRegistry)
  13208. {
  13209. hr = myDeleteCertRegValue(
  13210. g_wszSanitizedName,
  13211. NULL,
  13212. NULL,
  13213. g_wszRegCAXchgCertHash);
  13214. _PrintIfError(hr, "myDeleteCertRegValue");
  13215. }
  13216. ZeroMemory(&ckc, sizeof(ckc));
  13217. ckc.cbSize = sizeof(ckc);
  13218. ckc.dwKeySpec = AT_KEYEXCHANGE;
  13219. iHash = 0;
  13220. for (i = 0; i < g_cCAXchgCerts; i++)
  13221. {
  13222. pCAXchgContext = &g_aCAXchgContext[i];
  13223. if (CTXF_EXPIRED & pCAXchgContext->Flags)
  13224. {
  13225. continue;
  13226. }
  13227. // Add as encoded blob to avoid all properties, key prov info, etc.
  13228. if (!CertAddEncodedCertificateToStore(
  13229. hStore,
  13230. X509_ASN_ENCODING,
  13231. pCAXchgContext->pccCAXchg->pbCertEncoded,
  13232. pCAXchgContext->pccCAXchg->cbCertEncoded,
  13233. CERT_STORE_ADD_REPLACE_EXISTING,
  13234. &pccStore)) // ppCertContext
  13235. {
  13236. hr = myHLastError();
  13237. _JumpError(hr, error, "CertAddEncodedCertificateToStore");
  13238. }
  13239. ckc.hCryptProv = pCAXchgContext->hProvCA;
  13240. if (!CertSetCertificateContextProperty(
  13241. pccStore,
  13242. CERT_KEY_CONTEXT_PROP_ID,
  13243. CERT_STORE_NO_CRYPT_RELEASE_FLAG,
  13244. &ckc))
  13245. {
  13246. hr = myHLastError();
  13247. _JumpError(hr, error, "CertSetCertificateContextProperty");
  13248. }
  13249. CertFreeCertificateContext(pccStore);
  13250. pccStore = NULL;
  13251. DBGPRINT((
  13252. DBG_SS_CERTSRV,
  13253. "Add to CA Xchg memory store: '%ws'\n",
  13254. pCAXchgContext->pwszKeyContainerName));
  13255. if (fUpdateRegistry)
  13256. {
  13257. hr = mySetCARegHash(
  13258. g_wszSanitizedName,
  13259. CSRH_CAXCHGCERT,
  13260. iHash,
  13261. pCAXchgContext->pccCAXchg);
  13262. if (S_OK != hr)
  13263. {
  13264. _PrintError(hr, "mySetCARegHash");
  13265. continue;
  13266. }
  13267. }
  13268. iHash++;
  13269. }
  13270. if (NULL != g_hStoreCAXchg)
  13271. {
  13272. CertCloseStore(g_hStoreCAXchg, CERT_CLOSE_STORE_CHECK_FLAG);
  13273. }
  13274. g_hStoreCAXchg = hStore;
  13275. hStore = NULL;
  13276. hr = S_OK;
  13277. error:
  13278. if (NULL != pccStore)
  13279. {
  13280. CertFreeCertificateContext(pccStore);
  13281. }
  13282. if (NULL != hStore)
  13283. {
  13284. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  13285. }
  13286. return(hr);
  13287. }
  13288. HRESULT
  13289. PKCSIsRevoked(
  13290. IN DWORD RequestId,
  13291. OPTIONAL IN WCHAR const *pwszSerialNumber,
  13292. OUT LONG *pRevocationReason,
  13293. OUT LONG *pDisposition)
  13294. {
  13295. HRESULT hr;
  13296. ICertDBRow *prow = NULL;
  13297. BYTE *pbHash = NULL;
  13298. DWORD cbHash;
  13299. BSTR strHash = NULL;
  13300. DWORD Disposition;
  13301. DWORD cbProp;
  13302. FILETIME ftRevoked;
  13303. FILETIME ftCurrent;
  13304. *pRevocationReason = CRL_REASON_UNSPECIFIED;
  13305. *pDisposition = CA_DISP_INVALID;
  13306. hr = g_pCertDB->OpenRow(
  13307. PROPOPEN_READONLY | PROPTABLE_REQCERT,
  13308. RequestId,
  13309. pwszSerialNumber,
  13310. &prow);
  13311. _PrintIfErrorStr2(hr, "OpenRow", pwszSerialNumber, CERTSRV_E_PROPERTY_EMPTY);
  13312. if (CERTSRV_E_PROPERTY_EMPTY == hr && NULL != pwszSerialNumber)
  13313. {
  13314. _PrintErrorStr2(
  13315. hr,
  13316. "OpenRow(serial)",
  13317. pwszSerialNumber,
  13318. CERTSRV_E_PROPERTY_EMPTY);
  13319. hr = WszToMultiByteInteger(TRUE, pwszSerialNumber, &cbHash, &pbHash);
  13320. _JumpIfError(hr, error, "WszToMultiByteInteger");
  13321. hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strHash);
  13322. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  13323. hr = g_pCertDB->OpenRow(
  13324. PROPOPEN_READONLY |
  13325. PROPOPEN_CERTHASH |
  13326. PROPTABLE_REQCERT,
  13327. RequestId,
  13328. strHash,
  13329. &prow);
  13330. _PrintIfErrorStr2(hr, "OpenRow", strHash, CERTSRV_E_PROPERTY_EMPTY);
  13331. }
  13332. if (S_OK != hr)
  13333. {
  13334. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  13335. {
  13336. hr = S_OK; // disposition indicates cert is invalid
  13337. }
  13338. goto error;
  13339. }
  13340. cbProp = sizeof(Disposition);
  13341. hr = prow->GetProperty(
  13342. g_wszPropRequestDisposition,
  13343. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  13344. NULL,
  13345. &cbProp,
  13346. (BYTE *) &Disposition);
  13347. _JumpIfError(hr, error, "GetProperty(Disposition)");
  13348. if (DB_DISP_ISSUED == Disposition ||
  13349. (DB_DISP_CA_CERT == Disposition && IsRootCA(g_CAType)))
  13350. {
  13351. *pDisposition = CA_DISP_VALID;
  13352. goto error;
  13353. }
  13354. if (DB_DISP_REVOKED != Disposition)
  13355. {
  13356. goto error;
  13357. }
  13358. cbProp = sizeof(ftRevoked);
  13359. hr = prow->GetProperty(
  13360. g_wszPropRequestRevokedEffectiveWhen,
  13361. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  13362. NULL,
  13363. &cbProp,
  13364. (BYTE *) &ftRevoked);
  13365. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  13366. {
  13367. *pDisposition = CA_DISP_VALID;
  13368. hr = S_OK;
  13369. goto error;
  13370. }
  13371. _JumpIfError(hr, error, "GetProperty(RevokedEffectiveWhen)");
  13372. GetSystemTimeAsFileTime(&ftCurrent);
  13373. if (0 < CompareFileTime(&ftRevoked, &ftCurrent))
  13374. {
  13375. *pDisposition = CA_DISP_VALID;
  13376. goto error;
  13377. }
  13378. cbProp = sizeof(*pRevocationReason);
  13379. hr = prow->GetProperty(
  13380. g_wszPropRequestRevokedReason,
  13381. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  13382. NULL,
  13383. &cbProp,
  13384. (BYTE *) pRevocationReason);
  13385. _JumpIfError(hr, error, "GetProperty(RevokedReason)");
  13386. *pDisposition = CA_DISP_REVOKED;
  13387. error:
  13388. if (NULL != pbHash)
  13389. {
  13390. LocalFree(pbHash);
  13391. }
  13392. if (NULL != strHash)
  13393. {
  13394. SysFreeString(strHash);
  13395. }
  13396. if (NULL != prow)
  13397. {
  13398. prow->Release();
  13399. }
  13400. return(hr);
  13401. }
  13402. HRESULT
  13403. PKCSGetCAXchgCert(
  13404. IN DWORD iCert,
  13405. IN WCHAR const *pwszUserName,
  13406. OUT DWORD *piCertSig,
  13407. OUT BYTE **ppbCACert,
  13408. OUT DWORD *pcbCACert)
  13409. {
  13410. HRESULT hr;
  13411. BOOL fNewCert = FALSE;
  13412. BOOL fIncompleteLoad = FALSE;
  13413. FILETIME ft;
  13414. BOOL fCritSecEntered = FALSE;
  13415. *ppbCACert = NULL;
  13416. if (MAXDWORD != iCert && 0 != iCert)
  13417. {
  13418. hr = E_INVALIDARG;
  13419. _JumpError(hr, error, "bad Xchg CertIndex");
  13420. }
  13421. EnterCriticalSection(&g_critsecCAXchg);
  13422. fCritSecEntered = TRUE;
  13423. hr = S_OK;
  13424. __try
  13425. {
  13426. if (NULL == g_pCAXchgContextCurrent ||
  13427. NULL == g_pCAXchgContextCurrent->pccCAXchg)
  13428. {
  13429. hr = pkcsLoadCAXchgContextArray(&fIncompleteLoad);
  13430. _PrintIfError(hr, "pkcsLoadCAXchgContextArray");
  13431. if (S_OK != hr)
  13432. {
  13433. fNewCert = TRUE;
  13434. }
  13435. }
  13436. if (NULL != g_pCAXchgContextCurrent &&
  13437. NULL != g_pCAXchgContextCurrent->pccCAXchg)
  13438. {
  13439. CERT_INFO const *pCertInfo = g_pCAXchgContextCurrent->pccCAXchg->pCertInfo;
  13440. GetSystemTimeAsFileTime(&ft);
  13441. if (0 < CompareFileTime(&ft, &pCertInfo->NotAfter))
  13442. {
  13443. g_pCAXchgContextCurrent->Flags |= CTXF_EXPIRED;
  13444. hr = CERT_E_EXPIRED;
  13445. _PrintError(hr, "CA Xchg certificate is expired -- delete key");
  13446. pkcsDeleteKey(g_pCAXchgContextCurrent->pwszKeyContainerName);
  13447. fNewCert = TRUE;
  13448. }
  13449. else
  13450. if (0 > CompareFileTime(&ft, &pCertInfo->NotBefore))
  13451. {
  13452. hr = CERT_E_EXPIRED;
  13453. _PrintError(hr, "CA Xchg certificate not yet valid");
  13454. fNewCert = TRUE;
  13455. }
  13456. else
  13457. {
  13458. myMakeExprDateTime(
  13459. &ft,
  13460. g_lCAXchgOverlapPeriodCount,
  13461. g_enumCAXchgOverlapPeriod);
  13462. if (0 < CompareFileTime(&ft, &pCertInfo->NotAfter))
  13463. {
  13464. hr = CERT_E_EXPIRED;
  13465. _PrintError(hr, "CA Xchg certificate expires too soon");
  13466. fNewCert = TRUE;
  13467. }
  13468. else
  13469. {
  13470. hr = pkcsVerifyCertIssuer(
  13471. g_pCAXchgContextCurrent->pccCAXchg,
  13472. g_pCAContextCurrent);
  13473. if (S_OK != hr)
  13474. {
  13475. _PrintError(hr, "CA Xchg cert not issued by current CA");
  13476. fNewCert = TRUE;
  13477. }
  13478. else
  13479. {
  13480. LONG RevocationReason;
  13481. LONG Disposition;
  13482. hr = PKCSIsRevoked(
  13483. g_pCAXchgContextCurrent->ReqId,
  13484. NULL, // pwszSerialNumber
  13485. &RevocationReason,
  13486. &Disposition);
  13487. if (S_OK != hr)
  13488. {
  13489. _PrintError(hr, "PKCSIsRevoked");
  13490. fNewCert = TRUE;
  13491. }
  13492. else
  13493. if (CA_DISP_VALID != Disposition)
  13494. {
  13495. hr = CRYPT_E_REVOKED;
  13496. _PrintError(hr, "revoked or bad CA Xchg certificate");
  13497. fNewCert = TRUE;
  13498. }
  13499. }
  13500. }
  13501. }
  13502. }
  13503. if (fNewCert)
  13504. {
  13505. hr = pkcsCreateNewCAXchgCert(pwszUserName);
  13506. _LeaveIfError(hr, "pkcsCreateNewCAXchgCert");
  13507. }
  13508. hr = pkcsUpdateCAXchgStoreAndRegistry(fNewCert || fIncompleteLoad);
  13509. _LeaveIfError(hr, "pkcsUpdateCAXchgStoreAndRegistry");
  13510. // It's safe to return the cert blob memory pointer because the CA
  13511. // Exchange cert contexts aren't released until shutdown.
  13512. *piCertSig = g_pCAXchgContextCurrent->iCertSig;
  13513. *pcbCACert = g_pCAXchgContextCurrent->pccCAXchg->cbCertEncoded;
  13514. *ppbCACert = g_pCAXchgContextCurrent->pccCAXchg->pbCertEncoded;
  13515. hr = S_OK;
  13516. }
  13517. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  13518. {
  13519. }
  13520. error:
  13521. if (fCritSecEntered)
  13522. {
  13523. LeaveCriticalSection(&g_critsecCAXchg);
  13524. }
  13525. return(hr);
  13526. }
  13527. HRESULT
  13528. PKCSGetCAXchgChain(
  13529. IN DWORD iCert,
  13530. IN WCHAR const *pwszUserName,
  13531. IN BOOL fIncludeCRLs,
  13532. OUT BYTE **ppbCAChain, // CoTaskMem*
  13533. OUT DWORD *pcbCAChain)
  13534. {
  13535. HRESULT hr;
  13536. BYTE *pbCACert;
  13537. DWORD cbCACert;
  13538. CACTX *pCAContext;
  13539. hr = PKCSGetCAXchgCert(iCert, pwszUserName, &iCert, &pbCACert, &cbCACert);
  13540. _JumpIfError(hr, error, "PKCSGetCAXchgCert");
  13541. // iCert now indexes the signature cert that signed the current Xchg cert
  13542. pCAContext = &g_aCAContext[iCert];
  13543. if (NULL == pCAContext->pccCA)
  13544. {
  13545. hr = E_INVALIDARG;
  13546. _JumpError(hr, error, "invalid cert");
  13547. }
  13548. hr = pkcsEncodeCertChain(
  13549. pCAContext,
  13550. pbCACert, // pbCertLeaf
  13551. cbCACert, // cbCertLeaf
  13552. pbCACert, // pbToBeSigned
  13553. cbCACert, // cbToBeSigned
  13554. fIncludeCRLs,
  13555. ppbCAChain, // CoTaskMem*
  13556. pcbCAChain);
  13557. _JumpIfError(hr, error, "PKCSEncodeCertChain");
  13558. error:
  13559. return(hr);
  13560. }
  13561. VOID
  13562. PKCSTerminate(VOID)
  13563. {
  13564. pkcsReleaseCAContextArray();
  13565. pkcsReleaseCAXchgContextArray();
  13566. if (NULL != g_hStoreCAXchg)
  13567. {
  13568. CertCloseStore(g_hStoreCAXchg, CERT_CLOSE_STORE_CHECK_FLAG);
  13569. g_hStoreCAXchg = NULL;
  13570. }
  13571. pkcsLoadCAXchgCSPInfo(TRUE);
  13572. pkcsReleaseKRACertArray();
  13573. pkcsFreeTemplates(&g_paRevURL, &g_caRevURL);
  13574. pkcsFreeTemplates(&g_paCACertURL, &g_caCACertURL);
  13575. if (NULL != g_pwszKRAPublishURL)
  13576. {
  13577. LocalFree(g_pwszKRAPublishURL);
  13578. g_pwszKRAPublishURL = NULL;
  13579. }
  13580. if (NULL != g_pwszAIACrossCertPublishURL)
  13581. {
  13582. LocalFree(g_pwszAIACrossCertPublishURL);
  13583. g_pwszAIACrossCertPublishURL = NULL;
  13584. }
  13585. if (NULL != g_pwszRootTrustCrossCertPublishURL)
  13586. {
  13587. LocalFree(g_pwszRootTrustCrossCertPublishURL);
  13588. g_pwszRootTrustCrossCertPublishURL = NULL;
  13589. }
  13590. if (NULL != g_strDomainDN)
  13591. {
  13592. SysFreeString(g_strDomainDN);
  13593. g_strDomainDN = NULL;
  13594. }
  13595. if (NULL != g_strConfigDN)
  13596. {
  13597. SysFreeString(g_strConfigDN);
  13598. g_strConfigDN = NULL;
  13599. }
  13600. if (g_fcritsecCAXchg)
  13601. {
  13602. DeleteCriticalSection(&g_critsecCAXchg);
  13603. g_fcritsecCAXchg = FALSE;
  13604. }
  13605. }
  13606. // PKCSCreateCertificate -- Create certificate & build PKCS 7 or Full Response.
  13607. //
  13608. // If pResult->pctbCert is non-NULL and pResult->pctbCert->pb is NULL:
  13609. // CR_IN_NEW:
  13610. // Build, store and return cert
  13611. // Use current CA Context
  13612. // Build and return PKCS 7 or Full Response
  13613. //
  13614. // If pResult->pctbCert is non-NULL and pResult->pctbCert->pb is non-NULL:
  13615. // CR_IN_RETRIEVEPENDING:
  13616. // Use passed cert
  13617. // Find matching CA Context
  13618. // Build and return PKCS 7 or Full Response
  13619. //
  13620. // If pResult->pctbCert is NULL:
  13621. // CR_IN_RESUBMIT:
  13622. // Build and store cert -- don't return cert
  13623. // Use current CA Context
  13624. // Don't build or return PKCS 7 or Full Response
  13625. HRESULT
  13626. PKCSCreateCertificate(
  13627. IN ICertDBRow *prow,
  13628. IN DWORD Disposition,
  13629. IN BOOL fIncludeCRLs,
  13630. IN BOOL fCrossCert,
  13631. OPTIONAL IN CACTX *pCAContext, // signing CACTX
  13632. OUT BOOL *pfErrorLogged,
  13633. OPTIONAL OUT CACTX **ppCAContext,
  13634. OPTIONAL OUT WCHAR **ppwszDispositionCreateCert,
  13635. IN OUT CERTSRV_RESULT_CONTEXT *pResult) // CoTaskMem*
  13636. {
  13637. HRESULT hr;
  13638. BYTE *pbCert = NULL;
  13639. DWORD cbCert;
  13640. BYTE *pbCertChain = NULL;
  13641. DWORD cbCertChain;
  13642. BOOL fCreated = FALSE;
  13643. CERT_CONTEXT const *pcc = NULL;
  13644. *pfErrorLogged = FALSE;
  13645. if (NULL != ppCAContext)
  13646. {
  13647. *ppCAContext = NULL;
  13648. }
  13649. if (NULL != ppwszDispositionCreateCert)
  13650. {
  13651. *ppwszDispositionCreateCert = NULL;
  13652. }
  13653. CSASSERT(NULL == pResult->pctbCertChain || NULL == pResult->pctbCertChain->pb);
  13654. CSASSERT(NULL == pResult->pctbFullResponse || NULL == pResult->pctbFullResponse->pb);
  13655. cbCertChain = 0;
  13656. if (NULL != pResult->pctbCert && NULL != pResult->pctbCert->pb)
  13657. {
  13658. CSASSERT(NULL == pCAContext);
  13659. CSASSERT(NULL == ppwszDispositionCreateCert);
  13660. pbCert = pResult->pctbCert->pb;
  13661. cbCert = pResult->pctbCert->cb;
  13662. pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
  13663. if (NULL == pcc)
  13664. {
  13665. hr = myHLastError();
  13666. _JumpError(hr, error, "CertCreateCertificateContext");
  13667. }
  13668. pCAContext = NULL;
  13669. if (DB_DISP_CA_CERT != Disposition &&
  13670. DB_DISP_CA_CERT_CHAIN != Disposition)
  13671. {
  13672. hr = PKCSVerifyIssuedCertificate(pcc, &pCAContext);
  13673. _JumpIfError(hr, error, "PKCSVerifyIssuedCertificate");
  13674. }
  13675. }
  13676. else
  13677. {
  13678. CSASSERT(NULL != ppwszDispositionCreateCert);
  13679. if (NULL == pCAContext)
  13680. {
  13681. pCAContext = g_pCAContextCurrent;
  13682. }
  13683. cbCert = 0;
  13684. hr = pkcsEncodeSubjectCert(
  13685. prow,
  13686. pCAContext,
  13687. fCrossCert,
  13688. &pbCert, // CoTaskMem*
  13689. &cbCert,
  13690. pfErrorLogged,
  13691. ppwszDispositionCreateCert);
  13692. if (S_OK == hr ||
  13693. ((CRLF_SAVE_FAILED_CERTS & g_dwCRLFlags) &&
  13694. NULL != pbCert &&
  13695. 0 != cbCert))
  13696. {
  13697. HRESULT hr2;
  13698. hr2 = prow->SetProperty(
  13699. g_wszPropRawCertificate,
  13700. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  13701. cbCert,
  13702. pbCert);
  13703. if (S_OK == hr)
  13704. {
  13705. hr = hr2;
  13706. }
  13707. _JumpIfError(hr2, error, "SetProperty");
  13708. }
  13709. _JumpIfError(hr, error, "pkcsEncodeSubjectCert");
  13710. fCreated = TRUE;
  13711. }
  13712. if (NULL != pResult->pctbCertChain)
  13713. {
  13714. hr = pkcsEncodeCertChain(
  13715. pCAContext,
  13716. pbCert, // pbCertLeaf
  13717. cbCert, // cbCertLeaf
  13718. pbCert, // pbToBeSigned
  13719. cbCert, // cbToBeSigned
  13720. fIncludeCRLs,
  13721. &pbCertChain, // CoTaskMem*
  13722. &cbCertChain);
  13723. _JumpIfError(hr, error, "pkcsEncodeCertChain");
  13724. }
  13725. if (fCreated && NULL != pResult->pctbCert)
  13726. {
  13727. pResult->pctbCert->pb = pbCert;
  13728. pResult->pctbCert->cb = cbCert;
  13729. pbCert = NULL;
  13730. }
  13731. if (NULL != pResult->pctbCertChain)
  13732. {
  13733. pResult->pctbCertChain->pb = pbCertChain;
  13734. pResult->pctbCertChain->cb = cbCertChain;
  13735. pbCertChain = NULL;
  13736. }
  13737. if (NULL != ppCAContext)
  13738. {
  13739. *ppCAContext = pCAContext;
  13740. }
  13741. hr = S_OK;
  13742. error:
  13743. if (NULL != pcc)
  13744. {
  13745. CertFreeCertificateContext(pcc);
  13746. }
  13747. if (fCreated && NULL != pbCert)
  13748. {
  13749. CoTaskMemFree(pbCert);
  13750. }
  13751. if (fCreated && NULL != pbCertChain)
  13752. {
  13753. CoTaskMemFree(pbCertChain);
  13754. }
  13755. CSASSERT(
  13756. NULL == pResult->pctbCertChain ||
  13757. ((S_OK == hr) ^ (NULL == pResult->pctbCertChain->pb)));
  13758. return(hr);
  13759. }
  13760. HRESULT
  13761. PKCSGetKRACert(
  13762. IN DWORD iCert,
  13763. OUT BYTE **ppbCert,
  13764. OUT DWORD *pcbCert)
  13765. {
  13766. HRESULT hr = S_OK;
  13767. if (MAXDWORD == iCert)
  13768. {
  13769. iCert = g_cKRACerts - 1;
  13770. }
  13771. if (iCert >= g_cKRACerts || NULL == g_aKRAContext)
  13772. {
  13773. hr = E_INVALIDARG;
  13774. _JumpError(hr, error, "bad CertIndex");
  13775. }
  13776. *pcbCert = g_aKRAContext[iCert].pccKRA->cbCertEncoded;
  13777. *ppbCert = g_aKRAContext[iCert].pccKRA->pbCertEncoded;
  13778. error:
  13779. return(hr);
  13780. }