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.

2390 lines
64 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1997
  6. //
  7. // File: pkserv.cxx
  8. //
  9. // Contents: Server side public key support for Kerberos
  10. //
  11. //
  12. // History: 24-Nov-1997 MikeSw Created
  13. //
  14. //------------------------------------------------------------------------
  15. #include "kdcsvr.hxx"
  16. #include <wininet.h> // for SECURITY_FLAG_xxx
  17. #include <sclogon.h> // ScHelperXXX
  18. #include <cryptui.h> // for CryptUiXXX
  19. #include <certca.h> // for CA*XXX
  20. #define FILENO FILENO_PKSERV
  21. //
  22. // This is the cert store containing the CTL used to verify client certificates
  23. //
  24. HCERTSTORE KdcCertStore = NULL;
  25. HCRYPTPROV KdcClientProvider = NULL;
  26. PCCERT_CONTEXT GlobalKdcCert = NULL;
  27. HANDLE KdcCertStoreChangeEvent = NULL;
  28. TimeStamp KdcLastChangeEventTime;
  29. RTL_CRITICAL_SECTION KdcGlobalCertCritSect;
  30. BOOLEAN KdcGlobalCertCritSectInitialized = FALSE;
  31. HANDLE KdcCertStoreWait = NULL;
  32. BOOLEAN KdcPKIInitialized = FALSE;
  33. BOOLEAN Kdc3DesSupported = TRUE;
  34. HANDLE KdcCaNotificationHandle = NULL;
  35. #define KDC_ROOT_STORE L"ROOT"
  36. #define KDC_PRIVATE_MY_STORE L"MY"
  37. #define MAX_TEMPLATE_NAME_VALUE_SIZE 80 // sizeof (CERT_NAME_VALUE) + wcslen(SmartcardLogon)
  38. KERB_OBJECT_ID KdcSignatureAlg[10];
  39. NTSTATUS
  40. KdcGetKdcCertificate(PCCERT_CONTEXT *KdcCert);
  41. //+-------------------------------------------------------------------------
  42. //
  43. // Function: VerifyScLogonEku
  44. //
  45. // Synopsis:
  46. //
  47. // Effects:
  48. //
  49. // Arguments: IN: A certificate context
  50. //
  51. // Requires: TRUE is the certificate has a smart card logon EKU; or its template
  52. // name is DomainController
  53. //
  54. // Returns:
  55. //
  56. // Notes:
  57. //
  58. //
  59. //--------------------------------------------------------------------------
  60. BOOL
  61. VerifyScLogonEku(
  62. IN PCCERT_CONTEXT pCertContext,
  63. IN BOOLEAN KdcCertificate
  64. )
  65. {
  66. BOOL fDCCert=FALSE;
  67. CERT_EXTENSION *pExtension = NULL;
  68. DWORD cbSize = 0;
  69. DWORD dwIndex = 0;
  70. PCERT_NAME_VALUE pTemplateName = NULL;
  71. CERT_ENHKEY_USAGE *pEnhKeyUsage=NULL;
  72. if(NULL == (pCertContext->pCertInfo))
  73. goto Cleanup;
  74. //find the EKU extension
  75. pExtension =CertFindExtension(szOID_ENHANCED_KEY_USAGE,
  76. pCertContext->pCertInfo->cExtension,
  77. pCertContext->pCertInfo->rgExtension);
  78. if(pExtension)
  79. {
  80. if(CryptDecodeObject(X509_ASN_ENCODING,
  81. X509_ENHANCED_KEY_USAGE,
  82. pExtension->Value.pbData,
  83. pExtension->Value.cbData,
  84. 0,
  85. NULL,
  86. &cbSize))
  87. {
  88. pEnhKeyUsage=(CERT_ENHKEY_USAGE *)MIDL_user_allocate(cbSize);
  89. if(pEnhKeyUsage)
  90. {
  91. if(CryptDecodeObject(X509_ASN_ENCODING,
  92. X509_ENHANCED_KEY_USAGE,
  93. pExtension->Value.pbData,
  94. pExtension->Value.cbData,
  95. 0,
  96. pEnhKeyUsage,
  97. &cbSize))
  98. {
  99. for(dwIndex=0; dwIndex < pEnhKeyUsage->cUsageIdentifier; dwIndex++)
  100. {
  101. if(0 == strcmp(szOID_KP_SMARTCARD_LOGON,
  102. (pEnhKeyUsage->rgpszUsageIdentifier)[dwIndex]))
  103. {
  104. //we find it
  105. fDCCert=TRUE;
  106. break;
  107. }
  108. }
  109. }
  110. }
  111. }
  112. }
  113. //
  114. //check if we have found it via the enhanced key usage extension
  115. //
  116. if (( fDCCert ) ||
  117. (!KdcCertificate && !fDCCert))
  118. {
  119. goto Cleanup;
  120. }
  121. //
  122. // For DC certificates, its also OK to have the W2K certtype extension in
  123. // place of the sclogon oid - this doesn't apply to client certificates,
  124. // however.
  125. //
  126. //find the V1 template extension
  127. pExtension =CertFindExtension(szOID_ENROLL_CERTTYPE_EXTENSION,
  128. pCertContext->pCertInfo->cExtension,
  129. pCertContext->pCertInfo->rgExtension);
  130. if(pExtension == NULL)
  131. goto Cleanup;
  132. cbSize=0;
  133. if(!CryptDecodeObject(X509_ASN_ENCODING,
  134. X509_UNICODE_ANY_STRING,
  135. pExtension->Value.pbData,
  136. pExtension->Value.cbData,
  137. 0,
  138. NULL,
  139. &cbSize))
  140. goto Cleanup;
  141. pTemplateName = (CERT_NAME_VALUE *)MIDL_user_allocate(cbSize);
  142. if(NULL == pTemplateName)
  143. goto Cleanup;
  144. if(!CryptDecodeObject(X509_ASN_ENCODING,
  145. X509_UNICODE_ANY_STRING,
  146. pExtension->Value.pbData,
  147. pExtension->Value.cbData,
  148. 0,
  149. pTemplateName,
  150. &cbSize))
  151. goto Cleanup;
  152. if(wcscmp((LPWSTR) pTemplateName->Value.pbData, wszCERTTYPE_DC) != 0)
  153. goto Cleanup;
  154. fDCCert=TRUE;
  155. Cleanup:
  156. if(pEnhKeyUsage)
  157. MIDL_user_free(pEnhKeyUsage);
  158. if(pTemplateName)
  159. MIDL_user_free(pTemplateName);
  160. return fDCCert;
  161. }
  162. //+-------------------------------------------------------------------------
  163. //
  164. // Function: KdcCheckCertificate
  165. //
  166. // Synopsis: a helper routine to verify the certificate. It will check
  167. // CRLs, CTLs
  168. //
  169. // Effects:
  170. //
  171. // Arguments:
  172. // CertContext - the certificate to check
  173. // EmbeddedUPNOk - returns TRUE if the certificate can
  174. // be translated to a user by looking at the
  175. // subject name.
  176. // returns FALSE if the certificate must be
  177. // mapped by looking in the user's mapped certificate
  178. // ds attribute.
  179. //
  180. // Requires:
  181. //
  182. // Returns:
  183. //
  184. // Notes:
  185. //
  186. //
  187. //--------------------------------------------------------------------------
  188. KERBERR
  189. KdcCheckCertificate(
  190. IN PCCERT_CONTEXT CertContext,
  191. IN OUT PKERB_EXT_ERROR pExtendedError,
  192. IN OUT OPTIONAL PCERT_CHAIN_POLICY_STATUS FinalChainStatus,
  193. IN BOOLEAN KdcCert
  194. )
  195. {
  196. KERBERR KerbErr = KDC_ERR_NONE;
  197. CERT_CHAIN_PARA ChainParameters = {0};
  198. LPSTR Usage = (KdcCert ? KERB_PKINIT_KDC_CERT_TYPE : KERB_PKINIT_CLIENT_CERT_TYPE);
  199. PCCERT_CHAIN_CONTEXT ChainContext = NULL;
  200. CERT_CHAIN_POLICY_STATUS PolicyStatus ={0};
  201. ChainParameters.cbSize = sizeof(CERT_CHAIN_PARA);
  202. ChainParameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  203. ChainParameters.RequestedUsage.Usage.cUsageIdentifier = 1;
  204. ChainParameters.RequestedUsage.Usage.rgpszUsageIdentifier = &Usage;
  205. if (!CertGetCertificateChain(
  206. HCCE_LOCAL_MACHINE,
  207. CertContext,
  208. NULL, // evaluate at current time
  209. NULL, // no additional stores
  210. &ChainParameters,
  211. CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
  212. NULL, // reserved
  213. &ChainContext
  214. ))
  215. {
  216. D_DebugLog((DEB_WARN,"Failed to verify certificate chain: %0x%x\n",GetLastError()));
  217. KerbErr = KDC_ERR_CLIENT_NOT_TRUSTED;
  218. goto Cleanup;
  219. }
  220. else
  221. {
  222. CERT_CHAIN_POLICY_PARA ChainPolicy;
  223. ZeroMemory(&ChainPolicy, sizeof(ChainPolicy));
  224. ChainPolicy.cbSize = sizeof(ChainPolicy);
  225. ZeroMemory(&PolicyStatus, sizeof(PolicyStatus));
  226. PolicyStatus.cbSize = sizeof(PolicyStatus);
  227. PolicyStatus.lChainIndex = -1;
  228. PolicyStatus.lElementIndex = -1;
  229. if (!CertVerifyCertificateChainPolicy(
  230. CERT_CHAIN_POLICY_NT_AUTH,
  231. ChainContext,
  232. &ChainPolicy,
  233. &PolicyStatus))
  234. {
  235. D_DebugLog((DEB_WARN,"CertVerifyCertificateChainPolicy failure: %0x%x\n", GetLastError()));
  236. KerbErr = KDC_ERR_CLIENT_NOT_TRUSTED;
  237. goto Cleanup;
  238. }
  239. if( PolicyStatus.dwError != S_OK )
  240. {
  241. D_DebugLog((DEB_WARN,"CertVerifyCertificateChainPolicy - Chain Status failure: %0x%x\n",PolicyStatus.dwError));
  242. KerbErr = KDC_ERR_CLIENT_NOT_TRUSTED;
  243. goto Cleanup;
  244. }
  245. //
  246. // Verify that the sclogon oid is in the client certificate, alternately
  247. // that the sclogon oid or template name are in kdc certificates.
  248. //
  249. if (!VerifyScLogonEku( CertContext, KdcCert))
  250. {
  251. DebugLog((DEB_ERROR, "Cert missing SCLogon EKU\n"));
  252. PolicyStatus.dwError = (DWORD) CERT_E_WRONG_USAGE;
  253. KerbErr = KDC_ERR_CLIENT_NOT_TRUSTED;
  254. goto Cleanup;
  255. }
  256. }
  257. Cleanup:
  258. if (PolicyStatus.dwError != S_OK)
  259. {
  260. FILL_EXT_ERROR_EX(pExtendedError, PolicyStatus.dwError,FILENO,__LINE__);
  261. if (ARGUMENT_PRESENT(FinalChainStatus))
  262. {
  263. RtlCopyMemory(
  264. FinalChainStatus,
  265. &PolicyStatus,
  266. sizeof(CERT_CHAIN_POLICY_STATUS)
  267. );
  268. }
  269. }
  270. if (ChainContext != NULL)
  271. {
  272. CertFreeCertificateChain(ChainContext);
  273. }
  274. return(KerbErr);
  275. }
  276. //+-------------------------------------------------------------------------
  277. //
  278. // Function: KdcVerifyClientCertName
  279. //
  280. // Synopsis: Verifies that the mapping of a client's cert name matches
  281. // the mapping of the client name from the AS request
  282. //
  283. // Effects:
  284. //
  285. // Arguments:
  286. //
  287. // Requires:
  288. //
  289. // Returns:
  290. //
  291. // Notes:
  292. //
  293. //
  294. //--------------------------------------------------------------------------
  295. KERBERR
  296. KdcVerifyClientCertName(
  297. IN PCCERT_CONTEXT ClientCert,
  298. IN PKDC_TICKET_INFO ClientTicketInfo
  299. )
  300. {
  301. UNICODE_STRING NameString = {0};
  302. UNICODE_STRING ClientRealm = {0};
  303. PKERB_INTERNAL_NAME ClientName = NULL;
  304. KDC_TICKET_INFO TicketInfo = {0};
  305. BOOLEAN ClientReferral = FALSE;
  306. KERBERR KerbErr = KDC_ERR_NONE;
  307. KERB_EXT_ERROR ExtendedError;
  308. //
  309. // Get the client name from the cert
  310. //
  311. if(STATUS_SUCCESS != KerbGetPrincipalNameFromCertificate(ClientCert, &NameString))
  312. {
  313. KerbErr = KRB_ERR_GENERIC;
  314. goto Cleanup;
  315. }
  316. D_DebugLog((DEB_TRACE,"Email name from certificate is %wZ\n",&NameString));
  317. KerbErr = KerbConvertStringToKdcName(
  318. &ClientName,
  319. &NameString
  320. );
  321. if (!KERB_SUCCESS(KerbErr))
  322. {
  323. goto Cleanup;
  324. }
  325. ClientName->NameType = KRB_NT_ENTERPRISE_PRINCIPAL;
  326. //
  327. // Now crack the name & see if it refers to us
  328. //
  329. //
  330. // Normalize the client name.
  331. //
  332. KerbErr = KdcNormalize(
  333. ClientName,
  334. NULL,
  335. NULL,
  336. NULL,
  337. KDC_NAME_CLIENT | KDC_NAME_FOLLOW_REFERRALS | KDC_NAME_CHECK_GC,
  338. FALSE, // do not restrict user accounts (user2user)
  339. &ClientReferral,
  340. &ClientRealm,
  341. &TicketInfo,
  342. &ExtendedError,
  343. NULL, // no user handle
  344. 0L, // no fields to fetch
  345. 0L, // no extended fields
  346. NULL, // no user all
  347. NULL // no group membership
  348. );
  349. if (!KERB_SUCCESS(KerbErr) )
  350. {
  351. DebugLog((DEB_ERROR,"Failed to normalize name "));
  352. KerbPrintKdcName(DEB_ERROR,ClientName);
  353. goto Cleanup;
  354. }
  355. //
  356. // If this is a referral, return an error and the true realm name
  357. // of the client
  358. //
  359. if (ClientReferral)
  360. {
  361. KerbErr = KDC_ERR_WRONG_REALM;
  362. DebugLog((DEB_WARN,"Client tried to logon to account in another realm\n"));
  363. goto Cleanup;
  364. }
  365. //
  366. // Verify the client cert matches the client
  367. //
  368. if (TicketInfo.UserId != ClientTicketInfo->UserId)
  369. {
  370. DebugLog((DEB_ERROR,"Cert name doesn't match user name: %wZ, %wZ\n",
  371. &NameString, &ClientTicketInfo->AccountName));
  372. KerbErr = KDC_ERR_CLIENT_NAME_MISMATCH;
  373. goto Cleanup;
  374. }
  375. Cleanup:
  376. KerbFreeString( &NameString);
  377. KerbFreeKdcName( &ClientName );
  378. FreeTicketInfo( &TicketInfo );
  379. return(KerbErr);
  380. }
  381. //+-------------------------------------------------------------------------
  382. //
  383. // Function: KdcConvertNameString
  384. //
  385. // Synopsis: Converts the cr-lf to , in a dn
  386. //
  387. // Effects:
  388. //
  389. // Arguments:
  390. //
  391. // Requires:
  392. //
  393. // Returns:
  394. //
  395. // Notes:
  396. //
  397. //
  398. //--------------------------------------------------------------------------
  399. void
  400. KdcConvertNameString(
  401. IN PUNICODE_STRING Name,
  402. IN WCHAR ReplacementChar
  403. )
  404. {
  405. PWCHAR Comma1, Comma2;
  406. //
  407. // Scan through the name, converting "\r\n" to the replacement char. This
  408. // should be done by the CertNameToStr APIs, but that won't happen for
  409. // a while.
  410. //
  411. Comma1 = Comma2 = Name->Buffer ;
  412. while ( *Comma2 )
  413. {
  414. *Comma1 = *Comma2 ;
  415. if ( *Comma2 == L'\r' )
  416. {
  417. if ( *(Comma2 + 1) == L'\n' )
  418. {
  419. *Comma1 = ReplacementChar;
  420. Comma2++ ;
  421. }
  422. }
  423. Comma1++;
  424. Comma2++;
  425. }
  426. *Comma1 = L'\0';
  427. Name->Length = (USHORT) wcslen( Name->Buffer ) * sizeof( WCHAR );
  428. }
  429. //+-------------------------------------------------------------------------
  430. //
  431. // Function: KdcFreePkiAuditInfo
  432. //
  433. // Synopsis: Free KDC_PKI_AUDIT_INFO
  434. //
  435. // Effects:
  436. //
  437. // Arguments:
  438. //
  439. // Requires:
  440. //
  441. // Returns:
  442. //
  443. // Notes:
  444. //
  445. //
  446. //---------------------------------------------------------------------------
  447. VOID
  448. KdcFreePkiAuditInfo(
  449. IN PKDC_PKI_AUDIT_INFO AuditInfo
  450. )
  451. {
  452. KerbFreeString( &AuditInfo->CertIssuerName );
  453. KerbFreeString( &AuditInfo->CertSerialNumber );
  454. KerbFreeString( &AuditInfo->CertThumbprint );
  455. }
  456. //+-------------------------------------------------------------------------
  457. //
  458. // Function: KdcFillPkiAuditInfo
  459. //
  460. // Synopsis: Gets the cert hash, issuer, etc for a cert.
  461. //
  462. // Effects:
  463. //
  464. // Arguments:
  465. //
  466. // Requires:
  467. //
  468. // Returns: TRUE if it does, false if it doesn't
  469. //
  470. // Notes:
  471. //
  472. //
  473. //--------------------------------------------------------------------------
  474. NTSTATUS
  475. KdcFillPkiAuditInfo(
  476. IN PCCERT_CONTEXT Cert,
  477. IN OUT PKDC_PKI_AUDIT_INFO AuditInfo
  478. )
  479. {
  480. NTSTATUS Status = STATUS_SUCCESS;
  481. Status = KerbCreateUnicodeStringFromBlob(
  482. Cert->pCertInfo->SerialNumber.pbData,
  483. Cert->pCertInfo->SerialNumber.cbData,
  484. &AuditInfo->CertSerialNumber,
  485. FALSE
  486. );
  487. if (!NT_SUCCESS( Status ))
  488. {
  489. DebugLog((DEB_ERROR, "KerbCreateUnicodeStringFromBlob failed\n"));
  490. goto Cleanup;
  491. }
  492. Status = KerbGetCertificateHashString(
  493. Cert,
  494. &AuditInfo->CertThumbprint
  495. );
  496. if (!NT_SUCCESS( Status ))
  497. {
  498. DebugLog((DEB_ERROR, "KerbGetCertificateHashString failed\n"));
  499. goto Cleanup;
  500. }
  501. Status = KerbGetCertificateIssuer(
  502. Cert,
  503. &AuditInfo->CertIssuerName
  504. );
  505. if (!NT_SUCCESS( Status ))
  506. {
  507. DebugLog((DEB_ERROR, "KerbGetCertificateIssuer failed\n"));
  508. goto Cleanup;
  509. }
  510. Cleanup:
  511. if (!NT_SUCCESS( Status ))
  512. {
  513. KdcFreePkiAuditInfo( AuditInfo );
  514. }
  515. return Status;
  516. }
  517. //+-------------------------------------------------------------------------
  518. //
  519. // Function: KdcCheckForEtype
  520. //
  521. // Synopsis: Checks if a client supports a particular etype
  522. //
  523. // Effects:
  524. //
  525. // Arguments:
  526. //
  527. // Requires:
  528. //
  529. // Returns: TRUE if it does, false if it doesn't
  530. //
  531. // Notes:
  532. //
  533. //
  534. //--------------------------------------------------------------------------
  535. BOOLEAN
  536. KdcCheckForEtype(
  537. IN PKERB_CRYPT_LIST CryptList,
  538. IN ULONG Etype
  539. )
  540. {
  541. PKERB_CRYPT_LIST List = CryptList;
  542. while (List != NULL)
  543. {
  544. if ((ULONG) List->value == Etype)
  545. {
  546. return(TRUE);
  547. }
  548. List=List->next;
  549. }
  550. return(FALSE);
  551. }
  552. //+-------------------------------------------------------------------------
  553. //
  554. // Function: KdcCheckPkinitPreAuthData
  555. //
  556. // Synopsis:
  557. //
  558. // Effects:
  559. //
  560. // Arguments:
  561. //
  562. // Requires:
  563. //
  564. // Returns:
  565. //
  566. // Notes:
  567. //
  568. //
  569. //--------------------------------------------------------------------------
  570. KERBERR
  571. KdcCheckPkinitPreAuthData(
  572. IN PKDC_TICKET_INFO ClientTicketInfo,
  573. IN SAMPR_HANDLE UserHandle,
  574. IN OPTIONAL PKERB_PA_DATA_LIST PreAuthData,
  575. IN PKERB_KDC_REQUEST_BODY ClientRequest,
  576. OUT PKERB_PA_DATA_LIST * OutputPreAuthData,
  577. OUT PULONG Nonce,
  578. OUT PKERB_ENCRYPTION_KEY EncryptionKey,
  579. OUT PUNICODE_STRING TransitedRealm,
  580. OUT PKDC_PKI_AUDIT_INFO PkiAuditInfo,
  581. OUT PKERB_EXT_ERROR pExtendedError
  582. )
  583. {
  584. NTSTATUS Status;
  585. KERBERR KerbErr = KDC_ERR_NONE;
  586. PKERB_PA_PK_AS_REQ PkAsReq = NULL;
  587. PKERB_PA_PK_AS_REQ2 PkAsReq2 = NULL;
  588. PKERB_CERTIFICATE UserCert = NULL;
  589. PCCERT_CONTEXT CertContext = NULL;
  590. PCCERT_CONTEXT KdcCert = NULL;
  591. HCRYPTKEY ClientKey = NULL;
  592. PBYTE PackedAuthenticator = NULL;
  593. ULONG PackedAuthenticatorSize;
  594. PBYTE PackedKeyPack = NULL;
  595. ULONG PackedKeyPackSize;
  596. PBYTE SignedKeyPack = NULL;
  597. ULONG SignedKeyPackSize;
  598. PKERB_SIGNATURE Signature = NULL;
  599. PKERB_PK_AUTHENTICATOR PkAuthenticator = NULL;
  600. CERT_CHAIN_POLICY_STATUS FinalChainStatus = {0};
  601. UNICODE_STRING ClientKdcName = {0};
  602. ULONG ClientKdcNameType;
  603. LARGE_INTEGER ClientTime;
  604. LARGE_INTEGER CurrentTime;
  605. PULONG EtypeArray = NULL;
  606. ULONG EtypeCount = 0;
  607. ULONG CommonEtype;
  608. KERB_SIGNED_REPLY_KEY_PACKAGE KeyPack = {0};
  609. KERB_REPLY_KEY_PACKAGE ReplyKey = {0};
  610. HCRYPTPROV KdcProvider = NULL;
  611. BOOL FreeProvider = FALSE;
  612. #define KERB_PK_MAX_SIGNATURE_SIZE 128
  613. BYTE PkSignature[KERB_PK_MAX_SIGNATURE_SIZE];
  614. ULONG PkSignatureLength = KERB_PK_MAX_SIGNATURE_SIZE;
  615. ULONG RequiredSize = 0;
  616. PBYTE EncryptedKeyPack = NULL;
  617. PKERB_PA_DATA_LIST PackedPkAsRep = NULL;
  618. PBYTE PackedKey = NULL;
  619. ULONG PackedKeySize = 0;
  620. KERB_ENCRYPTION_KEY TempKey = {0};
  621. PKERB_CERTIFICATE_LIST CertList = NULL;
  622. CRYPT_ALGORITHM_IDENTIFIER CryptAlg = {0};
  623. PKERB_AUTH_PACKAGE AuthPack = NULL;
  624. BOOLEAN Used3Des = FALSE;
  625. //
  626. // Prepare the output variables
  627. //
  628. *OutputPreAuthData = NULL;
  629. RtlZeroMemory(
  630. EncryptionKey,
  631. sizeof(KERB_ENCRYPTION_KEY)
  632. );
  633. *Nonce = 0;
  634. //
  635. // If we don't do this preauth, return such
  636. //
  637. Status = KdcGetKdcCertificate(&KdcCert);
  638. if (!NT_SUCCESS(Status))
  639. {
  640. //
  641. // Log an event
  642. //
  643. ReportServiceEvent(
  644. EVENTLOG_ERROR_TYPE,
  645. KDCEVENT_NO_KDC_CERTIFICATE,
  646. 0,
  647. NULL,
  648. 0
  649. );
  650. FILL_EXT_ERROR_EX(pExtendedError, STATUS_PKINIT_FAILURE, FILENO, __LINE__);
  651. return(KDC_ERR_PADATA_TYPE_NOSUPP);
  652. }
  653. GetSystemTimeAsFileTime((PFILETIME) &CurrentTime );
  654. //
  655. // First, unpack the outer KRB-PA-PK-AS-REQ
  656. //
  657. KerbErr = KerbUnpackData(
  658. PreAuthData->value.preauth_data.value,
  659. PreAuthData->value.preauth_data.length,
  660. KERB_PA_PK_AS_REQ_PDU,
  661. (PVOID *) &PkAsReq
  662. );
  663. if (!KERB_SUCCESS(KerbErr))
  664. {
  665. //
  666. // Try the older variation
  667. //
  668. KerbErr = KerbUnpackData(
  669. PreAuthData->value.preauth_data.value,
  670. PreAuthData->value.preauth_data.length,
  671. KERB_PA_PK_AS_REQ2_PDU,
  672. (PVOID *) &PkAsReq2
  673. );
  674. if (!KERB_SUCCESS(KerbErr))
  675. {
  676. DebugLog((DEB_ERROR,"Failed to unpack PA-PK-AS-REQ(2): 0x%x\n",KerbErr));
  677. goto Cleanup;
  678. }
  679. }
  680. if (PkAsReq != NULL)
  681. {
  682. //
  683. // Verify the signature
  684. //
  685. Status = ScHelperVerifyPkcsMessage(
  686. NULL,
  687. KdcClientProvider,
  688. PkAsReq->signed_auth_pack.value,
  689. PkAsReq->signed_auth_pack.length,
  690. PackedAuthenticator,
  691. &PackedAuthenticatorSize,
  692. NULL // don't return certificate context
  693. );
  694. if ((Status != ERROR_MORE_DATA) && (Status != STATUS_SUCCESS))
  695. {
  696. DebugLog((DEB_ERROR,"Failed to verify message: %x\n",Status));
  697. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  698. KerbErr = KRB_AP_ERR_MODIFIED;
  699. goto Cleanup;
  700. }
  701. PackedAuthenticator = (PBYTE) MIDL_user_allocate(PackedAuthenticatorSize);
  702. if (PackedAuthenticator == NULL)
  703. {
  704. KerbErr = KRB_ERR_GENERIC;
  705. goto Cleanup;
  706. }
  707. Status = ScHelperVerifyPkcsMessage(
  708. NULL,
  709. KdcClientProvider,
  710. PkAsReq->signed_auth_pack.value,
  711. PkAsReq->signed_auth_pack.length,
  712. PackedAuthenticator,
  713. &PackedAuthenticatorSize,
  714. &CertContext
  715. );
  716. if (Status != STATUS_SUCCESS)
  717. {
  718. DebugLog((DEB_ERROR,"Failed to verify message: %x\n",Status));
  719. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  720. KerbErr = KRB_AP_ERR_MODIFIED;
  721. goto Cleanup;
  722. }
  723. //
  724. // Unpack the auth package
  725. //
  726. KerbErr = KerbUnpackData(
  727. PackedAuthenticator,
  728. PackedAuthenticatorSize,
  729. KERB_AUTH_PACKAGE_PDU,
  730. (PVOID *)&AuthPack
  731. );
  732. if (!KERB_SUCCESS(KerbErr))
  733. {
  734. goto Cleanup;
  735. }
  736. PkAuthenticator = &AuthPack->pk_authenticator;
  737. }
  738. else
  739. {
  740. DsysAssert(PkAsReq2 != NULL);
  741. //
  742. // Get the user certificate & verify
  743. //
  744. if ((PkAsReq2->bit_mask & user_certs_present) == 0)
  745. {
  746. DebugLog((DEB_ERROR,"Client tried to use pkinit w/o client cert\n"));
  747. KerbErr = KDC_ERR_BADOPTION;
  748. goto Cleanup;
  749. }
  750. //
  751. // Just use the first of the certificates
  752. //
  753. UserCert = &PkAsReq2->user_certs->value;
  754. //
  755. // We only handle x509 certificates
  756. //
  757. if (UserCert->cert_type != KERB_CERTIFICATE_TYPE_X509)
  758. {
  759. DebugLog((DEB_ERROR,"User supplied bad cert type: %d\n",UserCert->cert_type));
  760. KerbErr = KDC_ERR_BADOPTION;
  761. goto Cleanup;
  762. }
  763. //
  764. // Decode the certificate.
  765. //
  766. CertContext = CertCreateCertificateContext(
  767. X509_ASN_ENCODING,
  768. UserCert->cert_data.value,
  769. UserCert->cert_data.length
  770. );
  771. if (CertContext == NULL)
  772. {
  773. Status = GetLastError();
  774. DebugLog((DEB_ERROR,"Failed to create certificate context: 0x%x\n",Status));
  775. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  776. KerbErr = KRB_ERR_GENERIC;
  777. goto Cleanup;
  778. }
  779. //
  780. // Verify the authenticator
  781. //
  782. Signature = &PkAsReq2->signed_auth_pack.auth_package_signature;
  783. //
  784. // Now import the key from the certificate
  785. //
  786. if (!CryptImportPublicKeyInfo(
  787. KdcClientProvider,
  788. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  789. &CertContext->pCertInfo->SubjectPublicKeyInfo,
  790. &ClientKey
  791. ))
  792. {
  793. DebugLog((DEB_ERROR,"Failed to import public key: 0x%x\n",GetLastError()));
  794. FILL_EXT_ERROR(pExtendedError, GetLastError(), FILENO, __LINE__);
  795. KerbErr = KRB_ERR_GENERIC;
  796. goto Cleanup;
  797. }
  798. //
  799. // Encode the data to be verified
  800. //
  801. KerbErr = KerbPackData(
  802. &PkAsReq2->signed_auth_pack.auth_package,
  803. KERB_AUTH_PACKAGE_PDU,
  804. &PackedAuthenticatorSize,
  805. &PackedAuthenticator
  806. );
  807. if (!KERB_SUCCESS(KerbErr))
  808. {
  809. goto Cleanup;
  810. }
  811. //
  812. // Verify the signature on the message
  813. //
  814. if (!KerbCompareObjectIds(
  815. Signature->signature_algorithm.algorithm,
  816. KdcSignatureAlg
  817. ))
  818. {
  819. DebugLog((DEB_ERROR,"Unsupported signature algorithm (not MD5)\n"));
  820. KerbErr = KDC_ERR_SUMTYPE_NOSUPP;
  821. goto Cleanup;
  822. }
  823. Status = ScHelperVerifyMessage(
  824. NULL, // no logon info
  825. KdcClientProvider,
  826. CertContext,
  827. KERB_PKINIT_SIGNATURE_ALG,
  828. PackedAuthenticator,
  829. PackedAuthenticatorSize,
  830. Signature->pkcs_signature.value,
  831. Signature->pkcs_signature.length / 8 // because it is a bit string
  832. );
  833. if (!NT_SUCCESS(Status))
  834. {
  835. DebugLog((DEB_ERROR,"Failed to verify message: 0x%x\n",Status));
  836. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  837. KerbErr = KDC_ERR_INVALID_SIG;
  838. goto Cleanup;
  839. }
  840. //
  841. // Now check the information in the authenticator itself.
  842. //
  843. PkAuthenticator = &PkAsReq2->signed_auth_pack.auth_package.pk_authenticator;
  844. }
  845. //
  846. // Fill in the audit information for the certificate - this is non-fatal, though...
  847. //
  848. KerbErr = KdcFillPkiAuditInfo(
  849. CertContext,
  850. PkiAuditInfo
  851. );
  852. if (!KERB_SUCCESS( KerbErr ))
  853. {
  854. DebugLog((DEB_ERROR, "Failed to build audit information %x\n", KerbErr));
  855. DsysAssert(FALSE);
  856. }
  857. //
  858. // Call a helper routine to verify the certificate. It will check
  859. // CRLs, CTLs,
  860. //
  861. KerbErr = KdcCheckCertificate(
  862. CertContext,
  863. pExtendedError,
  864. &FinalChainStatus,
  865. FALSE // not a kdc certificate
  866. );
  867. if (!KERB_SUCCESS(KerbErr))
  868. {
  869. //
  870. // Dumb this down for release?
  871. //
  872. KdcReportBadClientCertificate(
  873. &ClientTicketInfo->AccountName,
  874. &FinalChainStatus,
  875. sizeof(FinalChainStatus) - sizeof(void*),
  876. pExtendedError->status
  877. );
  878. DebugLog((DEB_ERROR,"Failed to check CLIENT certificate: 0x%x\n",KerbErr));
  879. goto Cleanup;
  880. }
  881. //
  882. // Verify the cert is for the right client
  883. //
  884. KerbErr = KdcVerifyClientCertName(
  885. CertContext,
  886. ClientTicketInfo
  887. );
  888. if (!KERB_SUCCESS(KerbErr))
  889. {
  890. DebugLog((DEB_ERROR,"KDC failed to verify client's identity from cert\n"));
  891. goto Cleanup;
  892. }
  893. #ifdef later
  894. //
  895. // BUG 455112: this code breaks MIT KDCs, which can't handle a strange
  896. // x.500 name in the transited field. So, for NT5, disable the code
  897. //
  898. //
  899. // Put the issuer name in as a transited realm, as it is invovled in
  900. // the authentication decision.
  901. //
  902. TransitedLength = CertNameToStr( CertContext->dwCertEncodingType,
  903. &CertContext->pCertInfo->Issuer,
  904. dwNameToStrFlags,
  905. NULL,
  906. 0 );
  907. if ( TransitedLength == 0 )
  908. {
  909. D_DebugLog((DEB_ERROR,"Failed to get issuer name: 0x%x\n",GetLastError()));
  910. KerbErr = KRB_ERR_GENERIC;
  911. goto Cleanup;
  912. }
  913. TransitedRealm->MaximumLength = (USHORT) TransitedLength * sizeof(WCHAR) + sizeof(WCHAR);
  914. TransitedRealm->Length = (USHORT) TransitedLength * sizeof(WCHAR);
  915. TransitedRealm->Buffer = (LPWSTR) MIDL_user_allocate( TransitedRealm->MaximumLength );
  916. if ( TransitedRealm->Buffer == NULL )
  917. {
  918. KerbErr = KRB_ERR_GENERIC;
  919. goto Cleanup;
  920. }
  921. TransitedLength = CertNameToStr( CertContext->dwCertEncodingType,
  922. &CertContext->pCertInfo->Issuer,
  923. dwNameToStrFlags,
  924. TransitedRealm->Buffer,
  925. TransitedLength );
  926. if ( TransitedLength == 0 )
  927. {
  928. D_DebugLog((DEB_ERROR,"Failed to get issuer name: 0x%x\n",GetLastError()));
  929. FILL_EXT_ERROR(pExtendedError, GetLastError(), FILENO, __LINE__);
  930. KerbErr = KRB_ERR_GENERIC;
  931. goto Cleanup;
  932. }
  933. //
  934. // Convert the "." to "/"
  935. //
  936. KdcConvertNameString(
  937. TransitedRealm,
  938. L'/'
  939. );
  940. #endif // later
  941. //
  942. // Verify the realm name is correct
  943. //
  944. if (!SecData.IsOurRealm(
  945. &PkAuthenticator->kdc_realm
  946. ))
  947. {
  948. DebugLog((DEB_ERROR,"Client used wrong realm in PK authenticator: %s\n",
  949. PkAuthenticator->kdc_realm
  950. ));
  951. KerbErr = KDC_ERR_S_PRINCIPAL_UNKNOWN;
  952. goto Cleanup;
  953. }
  954. //
  955. // Verify the service realm and kdc name is correct
  956. //
  957. KerbErr = KerbConvertPrincipalNameToString(
  958. &ClientKdcName,
  959. &ClientKdcNameType,
  960. &PkAuthenticator->kdc_name
  961. );
  962. if (!KERB_SUCCESS(KerbErr))
  963. {
  964. goto Cleanup;
  965. }
  966. if (!RtlEqualUnicodeString(
  967. SecData.KdcFullServiceKdcName(),
  968. &ClientKdcName,
  969. TRUE))
  970. {
  971. if (!RtlEqualUnicodeString(
  972. SecData.KdcFullServiceDnsName(),
  973. &ClientKdcName,
  974. TRUE))
  975. {
  976. if (!RtlEqualUnicodeString(
  977. SecData.KdcFullServiceName(),
  978. &ClientKdcName,
  979. TRUE))
  980. {
  981. DebugLog((DEB_ERROR,"Client provided KDC name is wrong: %wZ\n",
  982. &ClientKdcName));
  983. KerbErr = KDC_ERR_KDC_NAME_MISMATCH;
  984. goto Cleanup;
  985. }
  986. }
  987. }
  988. //
  989. // Now verify the time
  990. //
  991. KerbConvertGeneralizedTimeToLargeInt(
  992. &ClientTime,
  993. &PkAuthenticator->client_time,
  994. PkAuthenticator->cusec
  995. );
  996. if (!KerbCheckTimeSkew(
  997. &CurrentTime,
  998. &ClientTime,
  999. &SkewTime))
  1000. {
  1001. KerbErr = KRB_AP_ERR_SKEW;
  1002. goto Cleanup;
  1003. }
  1004. *Nonce = PkAuthenticator->nonce;
  1005. //
  1006. // Generate a temporary key. First find a good encryption type
  1007. //
  1008. KerbErr = KerbConvertCryptListToArray(
  1009. &EtypeArray,
  1010. &EtypeCount,
  1011. ClientRequest->encryption_type
  1012. );
  1013. if (!KERB_SUCCESS(KerbErr))
  1014. {
  1015. goto Cleanup;
  1016. }
  1017. Status = CDFindCommonCSystem(
  1018. EtypeCount,
  1019. EtypeArray,
  1020. &CommonEtype
  1021. );
  1022. if (!NT_SUCCESS(Status))
  1023. {
  1024. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  1025. goto Cleanup;
  1026. }
  1027. KerbErr = KerbMakeKey(
  1028. CommonEtype,
  1029. EncryptionKey
  1030. );
  1031. if (!KERB_SUCCESS(KerbErr))
  1032. {
  1033. goto Cleanup;
  1034. }
  1035. //
  1036. // Build the return structure
  1037. //
  1038. PackedPkAsRep = (PKERB_PA_DATA_LIST) MIDL_user_allocate(sizeof(KERB_PA_DATA_LIST));
  1039. if (PackedPkAsRep == NULL)
  1040. {
  1041. KerbErr = KRB_ERR_GENERIC;
  1042. goto Cleanup;
  1043. }
  1044. RtlZeroMemory(
  1045. PackedPkAsRep,
  1046. sizeof(KERB_PA_DATA_LIST)
  1047. );
  1048. PackedPkAsRep->next = NULL;
  1049. PackedPkAsRep->value.preauth_data_type = KRB5_PADATA_PK_AS_REP;
  1050. //
  1051. // Success. Now build the reply
  1052. //
  1053. if (PkAsReq2 != NULL)
  1054. {
  1055. KERB_PA_PK_AS_REP2 Reply = {0};
  1056. //
  1057. // Create the reply key package
  1058. //
  1059. //
  1060. // Create the reply key package, which contains the key used to encrypt
  1061. // the AS_REPLY.
  1062. //
  1063. KeyPack.reply_key_package.nonce = *Nonce;
  1064. KeyPack.reply_key_package.reply_key = *EncryptionKey;
  1065. KerbErr = KerbPackData(
  1066. &KeyPack.reply_key_package,
  1067. KERB_REPLY_KEY_PACKAGE2_PDU,
  1068. &PackedKeyPackSize,
  1069. &PackedKeyPack
  1070. );
  1071. if (!KERB_SUCCESS(KerbErr))
  1072. {
  1073. goto Cleanup;
  1074. }
  1075. //
  1076. // Acquire a crypt context for the private key of the certificate
  1077. //
  1078. if (!CryptAcquireCertificatePrivateKey(
  1079. KdcCert,
  1080. 0, // no flags
  1081. NULL, // reserved
  1082. &KdcProvider,
  1083. NULL, // no key spec
  1084. &FreeProvider
  1085. ))
  1086. {
  1087. DebugLog((DEB_ERROR,"Failed to acquire KDC certificate private key: 0x%x\n",GetLastError()));
  1088. FILL_EXT_ERROR(pExtendedError, GetLastError(), FILENO, __LINE__);
  1089. KerbErr = KRB_ERR_GENERIC;
  1090. goto Cleanup;
  1091. }
  1092. //
  1093. // Now, to sign the reply key package
  1094. //
  1095. Status = ScHelperSignMessage(
  1096. NULL, // no pin
  1097. NULL, // no logon info
  1098. KdcProvider,
  1099. KERB_PKINIT_SIGNATURE_ALG,
  1100. PackedKeyPack,
  1101. PackedKeyPackSize,
  1102. PkSignature,
  1103. &PkSignatureLength
  1104. );
  1105. if (!NT_SUCCESS(Status))
  1106. {
  1107. DebugLog((DEB_ERROR,"Failed to sign keypack: 0x%x\n",Status));
  1108. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1109. KerbErr = KRB_AP_ERR_MODIFIED;
  1110. goto Cleanup;
  1111. }
  1112. //
  1113. // Copy the temporary signature into the return structure
  1114. //
  1115. KeyPack.reply_key_signature.pkcs_signature.length = PkSignatureLength * 8; // because it is a bit string
  1116. KeyPack.reply_key_signature.pkcs_signature.value = PkSignature;
  1117. KeyPack.reply_key_signature.signature_algorithm.algorithm = KdcSignatureAlg;
  1118. //
  1119. // Now marshall the signed key package
  1120. //
  1121. KerbErr = KerbPackData(
  1122. &KeyPack,
  1123. KERB_SIGNED_REPLY_KEY_PACKAGE_PDU,
  1124. &SignedKeyPackSize,
  1125. &SignedKeyPack
  1126. );
  1127. if (!KERB_SUCCESS(KerbErr))
  1128. {
  1129. goto Cleanup;
  1130. }
  1131. //
  1132. // Just encrypt the key package
  1133. //
  1134. PackedKey = SignedKeyPack;
  1135. PackedKeySize = SignedKeyPackSize;
  1136. //
  1137. // Zero these out so we don't free them twice
  1138. //
  1139. SignedKeyPack = NULL;
  1140. SignedKeyPackSize = 0;
  1141. //
  1142. // Compute the size of the encrypted temp key
  1143. //
  1144. //
  1145. ChangeCryptAlg2:
  1146. if (Kdc3DesSupported && KdcCheckForEtype(ClientRequest->encryption_type, KERB_PKINIT_SEAL_ETYPE))
  1147. {
  1148. Used3Des = TRUE;
  1149. CryptAlg.pszObjId = KERB_PKINIT_SEAL_OID;
  1150. }
  1151. else
  1152. {
  1153. CryptAlg.pszObjId = KERB_PKINIT_EXPORT_SEAL_OID;
  1154. if (!KdcCheckForEtype(ClientRequest->encryption_type, KERB_PKINIT_EXPORT_SEAL_ETYPE))
  1155. {
  1156. DebugLog((DEB_WARN,"Client doesn't claim to support exportable pkinit encryption type %d\n",
  1157. KERB_PKINIT_EXPORT_SEAL_ETYPE));
  1158. }
  1159. }
  1160. RequiredSize = 0;
  1161. Status = ScHelperEncryptMessage(
  1162. NULL,
  1163. KdcClientProvider,
  1164. CertContext,
  1165. &CryptAlg,
  1166. PackedKey,
  1167. PackedKeySize,
  1168. NULL,
  1169. (PULONG) &RequiredSize
  1170. );
  1171. if ((Status != ERROR_MORE_DATA) && (Status != STATUS_SUCCESS))
  1172. {
  1173. //
  1174. // 3des is only supported on domestic builds with the
  1175. // strong cryptography pack installed.
  1176. //
  1177. if ((Status == NTE_BAD_ALGID) && (Used3Des))
  1178. {
  1179. Kdc3DesSupported = FALSE;
  1180. goto ChangeCryptAlg2;
  1181. }
  1182. DebugLog((DEB_ERROR,"Failed to encrypt message: %x\n",Status));
  1183. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1184. KerbErr = KRB_AP_ERR_MODIFIED;
  1185. goto Cleanup;
  1186. }
  1187. //
  1188. // Allocate the output size
  1189. //
  1190. EncryptedKeyPack = (PBYTE) MIDL_user_allocate(RequiredSize);
  1191. if (EncryptedKeyPack == NULL)
  1192. {
  1193. KerbErr = KRB_ERR_GENERIC;
  1194. goto Cleanup;
  1195. }
  1196. //
  1197. // Really do the encryption
  1198. //
  1199. Status = ScHelperEncryptMessage(
  1200. NULL,
  1201. KdcClientProvider,
  1202. CertContext,
  1203. &CryptAlg,
  1204. PackedKey,
  1205. PackedKeySize,
  1206. EncryptedKeyPack,
  1207. &RequiredSize
  1208. );
  1209. if (!NT_SUCCESS(Status))
  1210. {
  1211. DebugLog((DEB_ERROR,"Failed to encrypt message: %x\n",Status));
  1212. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1213. KerbErr = KRB_AP_ERR_MODIFIED;
  1214. goto Cleanup;
  1215. }
  1216. //
  1217. // Create the cert list for the reply
  1218. //
  1219. KerbErr = KerbCreateCertificateList(
  1220. &CertList,
  1221. KdcCert
  1222. );
  1223. if (!KERB_SUCCESS(KerbErr))
  1224. {
  1225. goto Cleanup;
  1226. }
  1227. //
  1228. // We will be returning the KDC cert as well as a package containing
  1229. // a temporary key
  1230. //
  1231. Reply.bit_mask |= KERB_PA_PK_AS_REP2_kdc_cert_present;
  1232. //
  1233. // Now, to finish the reply, we need a handle to the KDCs certificate
  1234. //
  1235. Reply.kdc_cert = (KERB_PA_PK_AS_REP2_kdc_cert) CertList;
  1236. Reply.temp_key_package.choice = pkinit_enveloped_data_chosen;
  1237. Reply.temp_key_package.u.pkinit_enveloped_data.length = (int) RequiredSize;
  1238. Reply.temp_key_package.u.pkinit_enveloped_data.value = EncryptedKeyPack;
  1239. KerbErr = KerbPackData(
  1240. &Reply,
  1241. KERB_PA_PK_AS_REP2_PDU,
  1242. (PULONG) &PackedPkAsRep->value.preauth_data.length,
  1243. &PackedPkAsRep->value.preauth_data.value
  1244. );
  1245. if (!KERB_SUCCESS(KerbErr))
  1246. {
  1247. goto Cleanup;
  1248. }
  1249. }
  1250. else
  1251. {
  1252. KERB_PA_PK_AS_REP Reply = {0};
  1253. //
  1254. // Create the reply key package
  1255. //
  1256. //
  1257. // Create the reply key package, which contains the key used to encrypt
  1258. // the AS_REPLY.
  1259. //
  1260. ReplyKey.nonce = *Nonce;
  1261. ReplyKey.reply_key = *EncryptionKey;
  1262. KerbErr = KerbPackData(
  1263. &ReplyKey,
  1264. KERB_REPLY_KEY_PACKAGE_PDU,
  1265. &PackedKeyPackSize,
  1266. &PackedKeyPack
  1267. );
  1268. if (!KERB_SUCCESS(KerbErr))
  1269. {
  1270. goto Cleanup;
  1271. }
  1272. //
  1273. // Acquire a crypt context for the private key of the certificate
  1274. //
  1275. if (!CryptAcquireCertificatePrivateKey(
  1276. KdcCert,
  1277. 0, // no flags
  1278. NULL, // reserved
  1279. &KdcProvider,
  1280. NULL, // no key spec
  1281. &FreeProvider
  1282. ))
  1283. {
  1284. DebugLog((DEB_ERROR,"Failed to acquire KDC certificate private key: 0x%x\n",GetLastError()));
  1285. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1286. KerbErr = KRB_ERR_GENERIC;
  1287. goto Cleanup;
  1288. }
  1289. //
  1290. // Now, to sign the reply key package
  1291. //
  1292. CryptAlg.pszObjId = KERB_PKINIT_SIGNATURE_OID;
  1293. Status = ScHelperSignPkcsMessage(
  1294. NULL, // no pin
  1295. NULL, // no logon info
  1296. KdcProvider,
  1297. KdcCert,
  1298. &CryptAlg,
  1299. CRYPT_MESSAGE_SILENT_KEYSET_FLAG, // dwSignMessageFlags
  1300. PackedKeyPack,
  1301. PackedKeyPackSize,
  1302. SignedKeyPack,
  1303. &SignedKeyPackSize
  1304. );
  1305. if ((Status != ERROR_MORE_DATA) && (Status != STATUS_SUCCESS))
  1306. {
  1307. DebugLog((DEB_ERROR,"Failed to encrypt message: %x\n",Status));
  1308. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1309. KerbErr = KRB_AP_ERR_MODIFIED;
  1310. goto Cleanup;
  1311. }
  1312. SignedKeyPack = (PBYTE) MIDL_user_allocate(SignedKeyPackSize);
  1313. if (SignedKeyPack == NULL)
  1314. {
  1315. KerbErr = KRB_ERR_GENERIC;
  1316. goto Cleanup;
  1317. }
  1318. Status = ScHelperSignPkcsMessage(
  1319. NULL, // no pin
  1320. NULL, // no logon info
  1321. KdcProvider,
  1322. KdcCert,
  1323. &CryptAlg,
  1324. CRYPT_MESSAGE_SILENT_KEYSET_FLAG, // dwSignMessageFlags
  1325. PackedKeyPack,
  1326. PackedKeyPackSize,
  1327. SignedKeyPack,
  1328. &SignedKeyPackSize
  1329. );
  1330. if (Status != STATUS_SUCCESS)
  1331. {
  1332. DebugLog((DEB_ERROR,"Failed to sign pkcs message: 0x%x\n",Status));
  1333. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1334. KerbErr = KRB_ERR_GENERIC;
  1335. goto Cleanup;
  1336. }
  1337. //
  1338. // Now encrypt the content
  1339. //
  1340. //
  1341. // Compute the size of the encrypted temp key
  1342. //
  1343. //
  1344. ChangeCryptAlg:
  1345. if (Kdc3DesSupported && KdcCheckForEtype(ClientRequest->encryption_type, KERB_PKINIT_SEAL_ETYPE))
  1346. {
  1347. Used3Des = TRUE;
  1348. CryptAlg.pszObjId = KERB_PKINIT_SEAL_OID;
  1349. }
  1350. else
  1351. {
  1352. CryptAlg.pszObjId = KERB_PKINIT_EXPORT_SEAL_OID;
  1353. if (!KdcCheckForEtype(ClientRequest->encryption_type, KERB_PKINIT_EXPORT_SEAL_ETYPE))
  1354. {
  1355. DebugLog((DEB_WARN,"Client doesn't claim to support exportable pkinit encryption type %d\n",
  1356. KERB_PKINIT_EXPORT_SEAL_ETYPE));
  1357. }
  1358. }
  1359. RequiredSize = 0;
  1360. Status = ScHelperEncryptMessage(
  1361. NULL,
  1362. KdcClientProvider,
  1363. CertContext,
  1364. &CryptAlg,
  1365. SignedKeyPack,
  1366. SignedKeyPackSize,
  1367. NULL,
  1368. (PULONG) &RequiredSize
  1369. );
  1370. if ((Status != ERROR_MORE_DATA) && (Status != STATUS_SUCCESS))
  1371. {
  1372. //
  1373. // 3des is only supported on domestic builds with the
  1374. // strong cryptography pack installed.
  1375. //
  1376. if ((Status == NTE_BAD_ALGID) && (Used3Des))
  1377. {
  1378. Kdc3DesSupported = FALSE;
  1379. goto ChangeCryptAlg;
  1380. }
  1381. DebugLog((DEB_ERROR,"Failed to encrypt message (crypto mismatch?): %x\n",Status));
  1382. FILL_EXT_ERROR_EX(pExtendedError, Status, FILENO, __LINE__);
  1383. KerbErr = KRB_AP_ERR_MODIFIED;
  1384. goto Cleanup;
  1385. }
  1386. //
  1387. // Allocate the output size
  1388. //
  1389. EncryptedKeyPack = (PBYTE) MIDL_user_allocate(RequiredSize);
  1390. if (EncryptedKeyPack == NULL)
  1391. {
  1392. KerbErr = KRB_ERR_GENERIC;
  1393. goto Cleanup;
  1394. }
  1395. //
  1396. // Really do the encryption
  1397. //
  1398. Status = ScHelperEncryptMessage(
  1399. NULL,
  1400. KdcClientProvider,
  1401. CertContext,
  1402. &CryptAlg,
  1403. SignedKeyPack,
  1404. SignedKeyPackSize,
  1405. EncryptedKeyPack,
  1406. &RequiredSize
  1407. );
  1408. if (!NT_SUCCESS(Status))
  1409. {
  1410. DebugLog((DEB_ERROR,"Failed to encrypt message: %x\n",Status));
  1411. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1412. KerbErr = KRB_AP_ERR_MODIFIED;
  1413. goto Cleanup;
  1414. }
  1415. Reply.u.key_package.value = EncryptedKeyPack;
  1416. Reply.u.key_package.length = RequiredSize;
  1417. Reply.choice = pkinit_enveloped_data_chosen;
  1418. KerbErr = KerbPackData(
  1419. &Reply,
  1420. KERB_PA_PK_AS_REP_PDU,
  1421. (PULONG) &PackedPkAsRep->value.preauth_data.length,
  1422. &PackedPkAsRep->value.preauth_data.value
  1423. );
  1424. if (!KERB_SUCCESS(KerbErr))
  1425. {
  1426. goto Cleanup;
  1427. }
  1428. }
  1429. *OutputPreAuthData = PackedPkAsRep;
  1430. PackedPkAsRep = NULL;
  1431. Cleanup:
  1432. if (FreeProvider)
  1433. {
  1434. CryptReleaseContext(
  1435. KdcProvider,
  1436. 0
  1437. );
  1438. }
  1439. if (PkAsReq != NULL)
  1440. {
  1441. KerbFreeData(
  1442. KERB_PA_PK_AS_REQ_PDU,
  1443. PkAsReq
  1444. );
  1445. }
  1446. if (PkAsReq2 != NULL)
  1447. {
  1448. KerbFreeData(
  1449. KERB_PA_PK_AS_REQ2_PDU,
  1450. PkAsReq2
  1451. );
  1452. }
  1453. if (SignedKeyPack != NULL)
  1454. {
  1455. KdcFreeEncodedData(SignedKeyPack);
  1456. }
  1457. if (PackedKeyPack != NULL)
  1458. {
  1459. KdcFreeEncodedData(PackedKeyPack);
  1460. }
  1461. if (PackedAuthenticator != NULL)
  1462. {
  1463. KdcFreeEncodedData(PackedAuthenticator);
  1464. }
  1465. if (ClientKey != NULL)
  1466. {
  1467. CryptDestroyKey(ClientKey);
  1468. }
  1469. if (CertContext != NULL)
  1470. {
  1471. CertFreeCertificateContext(CertContext);
  1472. }
  1473. if(KdcCert)
  1474. {
  1475. CertFreeCertificateContext(KdcCert);
  1476. }
  1477. if (EncryptedKeyPack != NULL)
  1478. {
  1479. MIDL_user_free(EncryptedKeyPack);
  1480. }
  1481. if (EtypeArray != NULL)
  1482. {
  1483. MIDL_user_free(EtypeArray);
  1484. }
  1485. KerbFreeCertificateList(
  1486. CertList
  1487. );
  1488. KerbFreeKey(&TempKey);
  1489. if (PackedKey != NULL)
  1490. {
  1491. MIDL_user_free(PackedKey);
  1492. }
  1493. if (PackedPkAsRep != NULL)
  1494. {
  1495. if (PackedPkAsRep->value.preauth_data.value != NULL)
  1496. {
  1497. MIDL_user_free(PackedPkAsRep->value.preauth_data.value);
  1498. }
  1499. MIDL_user_free(PackedPkAsRep);
  1500. }
  1501. KerbFreeString(&ClientKdcName);
  1502. return(KerbErr);
  1503. }
  1504. //+-------------------------------------------------------------------------
  1505. //
  1506. // Function: KdcMyStoreWaitHandler
  1507. //
  1508. // Synopsis: Retrieves a copy of the KDC cert
  1509. //
  1510. // Effects:
  1511. //
  1512. // Arguments:
  1513. //
  1514. // Requires:
  1515. //
  1516. // Returns:
  1517. //
  1518. // Notes:
  1519. //
  1520. //
  1521. //--------------------------------------------------------------------------
  1522. VOID
  1523. KdcMyStoreWaitHandler(
  1524. PVOID pVoid,
  1525. BOOLEAN fTimeout
  1526. )
  1527. {
  1528. PCCERT_CONTEXT Certificate = NULL, OldCertificate = NULL, Candidate = NULL;
  1529. CERT_CHAIN_POLICY_STATUS FinalChainStatus = {0};
  1530. KERB_EXT_ERROR DummyError;
  1531. KERBERR KerbErr;
  1532. BOOLEAN Found = FALSE;
  1533. ULONG PropertySize = 0;
  1534. // Diagnostic: When's the last time this event fired?
  1535. GetSystemTimeAsFileTime((PFILETIME) &KdcLastChangeEventTime);
  1536. //
  1537. // This was triggered by a timeout, so disable the store notification
  1538. // for now...
  1539. //
  1540. if (fTimeout)
  1541. {
  1542. if (!CertControlStore(
  1543. KdcCertStore, // in, the store to be controlled
  1544. 0, // in, not used.
  1545. CERT_STORE_CTRL_CANCEL_NOTIFY,
  1546. &KdcCertStoreChangeEvent
  1547. ))
  1548. {
  1549. D_DebugLog((DEB_ERROR, "CertControlStore (cancel notify) failed - %x\n", GetLastError()));
  1550. }
  1551. }
  1552. D_DebugLog((DEB_T_PKI, "Triggering KdcMyStoreWaitHandler()\n"));
  1553. //
  1554. // Resync store
  1555. //
  1556. CertControlStore(
  1557. KdcCertStore, // in, the store to be controlled
  1558. 0, // in, not used.
  1559. CERT_STORE_CTRL_RESYNC, // in, control action type
  1560. NULL // Just resync store
  1561. );
  1562. RtlEnterCriticalSection(&KdcGlobalCertCritSect);
  1563. // Our my store changed, so we need to find the cert again.
  1564. if(GlobalKdcCert)
  1565. {
  1566. OldCertificate = CertDuplicateCertificateContext(GlobalKdcCert);
  1567. KerbErr = KdcCheckCertificate(
  1568. GlobalKdcCert,
  1569. &DummyError,
  1570. &FinalChainStatus,
  1571. TRUE // this is a kdc certificate
  1572. );
  1573. if (!KERB_SUCCESS(KerbErr))
  1574. {
  1575. CertFreeCertificateContext(GlobalKdcCert);
  1576. GlobalKdcCert = NULL;
  1577. }
  1578. else
  1579. {
  1580. // certificate is good!
  1581. // However, it may have been deleted, so
  1582. // verify its existance
  1583. while ((Certificate = CertEnumCertificatesInStore(
  1584. KdcCertStore,
  1585. Certificate)) != NULL)
  1586. {
  1587. if (CertCompareCertificate(
  1588. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1589. GlobalKdcCert->pCertInfo,
  1590. Certificate->pCertInfo
  1591. ))
  1592. {
  1593. Found = TRUE;
  1594. break; // still there
  1595. }
  1596. }
  1597. if (NULL != Certificate)
  1598. {
  1599. CertFreeCertificateContext(Certificate);
  1600. Certificate = NULL;
  1601. }
  1602. if (Found)
  1603. {
  1604. goto Rearm;
  1605. }
  1606. CertFreeCertificateContext(GlobalKdcCert);
  1607. GlobalKdcCert = NULL;
  1608. }
  1609. }
  1610. if (NULL == GlobalKdcCert)
  1611. {
  1612. //
  1613. // Enumerate all the certificates looking for the one we want
  1614. //
  1615. while ((Certificate = CertEnumCertificatesInStore(
  1616. KdcCertStore,
  1617. Certificate)) != NULL)
  1618. {
  1619. CERT_CHAIN_POLICY_STATUS TempStatus;
  1620. //
  1621. // Check to see if the certificate is the one we want
  1622. //
  1623. if (!CertGetCertificateContextProperty(
  1624. Certificate,
  1625. CERT_KEY_PROV_INFO_PROP_ID,
  1626. NULL, // no data
  1627. &PropertySize))
  1628. {
  1629. continue;
  1630. }
  1631. //
  1632. // Make sure the cert we selected was "good"
  1633. //
  1634. KerbErr = KdcCheckCertificate(
  1635. Certificate,
  1636. &DummyError,
  1637. &TempStatus,
  1638. TRUE // this is a kdc certificate
  1639. );
  1640. if (!KERB_SUCCESS(KerbErr))
  1641. {
  1642. //
  1643. // Hack - lots of times we can't find a CRL, but we have a "mostly"
  1644. // valid certificate.
  1645. //
  1646. if (TempStatus.dwError == CRYPT_E_REVOCATION_OFFLINE)
  1647. {
  1648. if ( Candidate != NULL )
  1649. {
  1650. CertFreeCertificateContext(Candidate);
  1651. }
  1652. Candidate = CertDuplicateCertificateContext(Certificate);
  1653. D_DebugLog((DEB_ERROR, "Revocation offline - using somewhat good certificate\n"));
  1654. }
  1655. continue;
  1656. }
  1657. break;
  1658. }
  1659. }
  1660. // Couldn't find a good certificate!
  1661. if (NULL == Certificate)
  1662. {
  1663. //
  1664. // Keep the old one... We might just be getting an offline CA
  1665. //
  1666. if (OldCertificate != NULL || Candidate != NULL)
  1667. {
  1668. if (OldCertificate)
  1669. {
  1670. D_DebugLog((DEB_T_PKI, "Re-using old certificate\n"));
  1671. GlobalKdcCert = OldCertificate;
  1672. OldCertificate = NULL;
  1673. }
  1674. else
  1675. {
  1676. GlobalKdcCert = Candidate;
  1677. Candidate = NULL;
  1678. }
  1679. ReportServiceEvent(
  1680. EVENTLOG_WARNING_TYPE,
  1681. KDCEVENT_INVALID_KDC_CERTIFICATE,
  1682. sizeof(FinalChainStatus) - sizeof(void*), // don't need ptr.
  1683. &FinalChainStatus,
  1684. 0
  1685. );
  1686. }
  1687. else
  1688. //
  1689. // Never had one...
  1690. //
  1691. {
  1692. DebugLog((DEB_ERROR, "No valid KDC certificate was available\n"));
  1693. GlobalKdcCert = NULL;
  1694. }
  1695. }
  1696. else
  1697. {
  1698. D_DebugLog((DEB_T_PKI, "Picked new KDC certificate\n"));
  1699. GlobalKdcCert = Certificate;
  1700. }
  1701. Rearm:
  1702. if (OldCertificate != NULL)
  1703. {
  1704. CertFreeCertificateContext(OldCertificate);
  1705. }
  1706. if (Candidate != NULL)
  1707. {
  1708. CertFreeCertificateContext(Candidate);
  1709. }
  1710. RtlLeaveCriticalSection(&KdcGlobalCertCritSect);
  1711. //
  1712. // This was moved here because of race conditions associated w/ my store
  1713. // chain building, where the event was getting fired rapidly, leading
  1714. // us to loose notification, and thus- the re-arm.
  1715. //
  1716. CertControlStore(
  1717. KdcCertStore, // in, the store to be controlled
  1718. 0, // in, not used.
  1719. CERT_STORE_CTRL_NOTIFY_CHANGE, // in, control action type
  1720. &KdcCertStoreChangeEvent // in, the handle of the event
  1721. );
  1722. }
  1723. //+-------------------------------------------------------------------------
  1724. //
  1725. // Function: KdcGetKdcCertificate
  1726. //
  1727. // Synopsis: Retrieves a copy of the KDC cert
  1728. //
  1729. // Effects:
  1730. //
  1731. // Arguments:
  1732. //
  1733. // Requires:
  1734. //
  1735. // Returns:
  1736. //
  1737. // Notes:
  1738. //
  1739. //
  1740. //--------------------------------------------------------------------------
  1741. NTSTATUS
  1742. KdcGetKdcCertificate(
  1743. PCCERT_CONTEXT *KdcCert
  1744. )
  1745. {
  1746. NTSTATUS Status = STATUS_SUCCESS;
  1747. if(!KdcGlobalCertCritSectInitialized)
  1748. {
  1749. return STATUS_OBJECT_NAME_NOT_FOUND;
  1750. }
  1751. RtlEnterCriticalSection(&KdcGlobalCertCritSect);
  1752. if (GlobalKdcCert == NULL)
  1753. {
  1754. DebugLog((DEB_WARN,"Unable to find KDC certificate in KDC store\n"));
  1755. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1756. goto Cleanup;
  1757. }
  1758. // Increment the ref count, so if we change certs while the caller of this
  1759. // is still using this cert, we won't delete it out from under.
  1760. *KdcCert = CertDuplicateCertificateContext(GlobalKdcCert);
  1761. if(*KdcCert == NULL)
  1762. {
  1763. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1764. goto Cleanup;
  1765. }
  1766. Cleanup:
  1767. RtlLeaveCriticalSection(&KdcGlobalCertCritSect);
  1768. return(Status);
  1769. }
  1770. //+-------------------------------------------------------------------------
  1771. //
  1772. // Function: KdcInitializeCerts
  1773. //
  1774. // Synopsis: Initializes data for cert handling
  1775. //
  1776. // Effects:
  1777. //
  1778. // Arguments:
  1779. //
  1780. // Requires:
  1781. //
  1782. // Returns:
  1783. //
  1784. // Notes:
  1785. //
  1786. //
  1787. //--------------------------------------------------------------------------
  1788. NTSTATUS
  1789. KdcInitializeCerts(
  1790. VOID
  1791. )
  1792. {
  1793. NTSTATUS Status = STATUS_SUCCESS;
  1794. ULONG Index;
  1795. LPSTR TempString = NULL, StringCopy = NULL, EndPtr = NULL;
  1796. ULONG TenHours;
  1797. TenHours = (ULONG) 1000 * 60 * 60 * 10;
  1798. Status = RtlInitializeCriticalSection(&KdcGlobalCertCritSect);
  1799. if (!NT_SUCCESS(Status))
  1800. {
  1801. goto Cleanup;
  1802. }
  1803. KdcGlobalCertCritSectInitialized = TRUE;
  1804. if (!CryptAcquireContext(
  1805. &KdcClientProvider,
  1806. NULL, // default container
  1807. NULL,
  1808. PROV_RSA_FULL,
  1809. CRYPT_VERIFYCONTEXT
  1810. ))
  1811. {
  1812. Status = GetLastError();
  1813. DebugLog((DEB_ERROR,"Failed to acquire client crypt context: 0x%x\n",Status));
  1814. goto Cleanup;
  1815. }
  1816. //
  1817. // Open the KDC store to get the KDC cert
  1818. //
  1819. KdcCertStore = CertOpenStore(
  1820. CERT_STORE_PROV_SYSTEM_W,
  1821. 0, // no encoding
  1822. NULL, // no provider
  1823. CERT_STORE_OPEN_EXISTING_FLAG |
  1824. CERT_STORE_NO_CRYPT_RELEASE_FLAG |
  1825. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  1826. KDC_PRIVATE_MY_STORE
  1827. );
  1828. if (KdcCertStore == NULL)
  1829. {
  1830. Status = GetLastError();
  1831. DebugLog((DEB_ERROR,"Failed to open %ws store: 0x%x\n", KDC_PRIVATE_MY_STORE,Status));
  1832. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1833. goto Cleanup;
  1834. }
  1835. // Create an auto-reset event that is to be signaled when
  1836. // the my store is changed. This event is initialized to Signaled
  1837. // so that on first call to get a cert, we assume the my store is changed
  1838. // and do all the work.
  1839. KdcCertStoreChangeEvent = CreateEvent(
  1840. NULL,
  1841. FALSE,
  1842. FALSE,
  1843. NULL);
  1844. if(NULL == KdcCertStoreChangeEvent)
  1845. {
  1846. Status = GetLastError();
  1847. goto Cleanup;
  1848. }
  1849. if (! RegisterWaitForSingleObject(&KdcCertStoreWait,
  1850. KdcCertStoreChangeEvent,
  1851. KdcMyStoreWaitHandler,
  1852. NULL,
  1853. TenHours,
  1854. WT_EXECUTEDEFAULT
  1855. ))
  1856. {
  1857. Status = GetLastError();
  1858. goto Cleanup;
  1859. }
  1860. // Arm the cert store for change notification
  1861. // CERT_CONTROL_STORE_NOTIFY_CHANGE.
  1862. if(!CertControlStore(
  1863. KdcCertStore, // The store to be controlled
  1864. 0, // Not used
  1865. CERT_STORE_CTRL_NOTIFY_CHANGE, // Control action type
  1866. &KdcCertStoreChangeEvent)) // Points to the event handle.
  1867. // When a change is detected,
  1868. // a signal is written to the
  1869. // space pointed to by
  1870. // hHandle.
  1871. {
  1872. // Notification is not avaialble, so kill the Event
  1873. Status = GetLastError();
  1874. goto Cleanup;
  1875. }
  1876. //
  1877. // Initialize the object IDs
  1878. //
  1879. Index = 0;
  1880. StringCopy = (LPSTR) MIDL_user_allocate(strlen(KERB_PKINIT_SIGNATURE_OID)+1);
  1881. if (StringCopy == NULL)
  1882. {
  1883. Status = STATUS_INSUFFICIENT_RESOURCES;
  1884. goto Cleanup;
  1885. }
  1886. //
  1887. // Scan the string for every '.' separated number
  1888. //
  1889. strcpy(
  1890. StringCopy,
  1891. KERB_PKINIT_SIGNATURE_OID
  1892. );
  1893. TempString = StringCopy;
  1894. EndPtr = TempString;
  1895. while (TempString != NULL)
  1896. {
  1897. ULONG Temp;
  1898. while (*EndPtr != '\0' && *EndPtr != '.')
  1899. {
  1900. EndPtr++;
  1901. }
  1902. if (*EndPtr == '.')
  1903. {
  1904. *EndPtr = '\0';
  1905. EndPtr++;
  1906. }
  1907. else
  1908. {
  1909. EndPtr = NULL;
  1910. }
  1911. sscanf(TempString,"%u",&Temp);
  1912. KdcSignatureAlg[Index].value = (USHORT) Temp;
  1913. KdcSignatureAlg[Index].next = &KdcSignatureAlg[Index+1];
  1914. Index++;
  1915. TempString = EndPtr;
  1916. }
  1917. DsysAssert(Index != 0);
  1918. KdcSignatureAlg[Index-1].next = NULL;
  1919. MIDL_user_free(StringCopy);
  1920. StringCopy = NULL;
  1921. Cleanup:
  1922. if (!NT_SUCCESS(Status))
  1923. {
  1924. KdcCleanupCerts(FALSE);
  1925. }
  1926. return(Status);
  1927. }
  1928. //+-------------------------------------------------------------------------
  1929. //
  1930. // Function: KdcCleanupCerts
  1931. //
  1932. // Synopsis: Cleans up data associated with certificate handling
  1933. //
  1934. // Effects:
  1935. //
  1936. // Arguments:
  1937. //
  1938. // Requires:
  1939. //
  1940. // Returns:
  1941. //
  1942. // Notes:
  1943. //
  1944. //
  1945. //--------------------------------------------------------------------------
  1946. VOID
  1947. KdcCleanupCerts(
  1948. IN BOOLEAN CleanupScavenger
  1949. )
  1950. {
  1951. HANDLE WaitHandle;
  1952. //
  1953. // Pete code used to hold the critsec in the callback.
  1954. //
  1955. if(KdcCertStoreWait)
  1956. {
  1957. WaitHandle = (HANDLE) InterlockedExchangePointer(&KdcCertStoreWait,NULL);
  1958. UnregisterWaitEx(WaitHandle, INVALID_HANDLE_VALUE);
  1959. }
  1960. if(KdcGlobalCertCritSectInitialized)
  1961. {
  1962. RtlEnterCriticalSection(&KdcGlobalCertCritSect);
  1963. }
  1964. if (GlobalKdcCert != NULL)
  1965. {
  1966. CertFreeCertificateContext(
  1967. GlobalKdcCert
  1968. );
  1969. GlobalKdcCert = NULL;
  1970. }
  1971. if (KdcCertStore != NULL)
  1972. {
  1973. CertCloseStore(
  1974. KdcCertStore,
  1975. CERT_CLOSE_STORE_FORCE_FLAG
  1976. );
  1977. KdcCertStore = NULL;
  1978. }
  1979. if(KdcCertStoreChangeEvent)
  1980. {
  1981. CloseHandle(KdcCertStoreChangeEvent);
  1982. KdcCertStoreChangeEvent = NULL;
  1983. }
  1984. if (KdcClientProvider != NULL)
  1985. {
  1986. CryptReleaseContext(
  1987. KdcClientProvider,
  1988. 0 // no flags
  1989. );
  1990. KdcClientProvider = NULL;
  1991. }
  1992. if(KdcGlobalCertCritSectInitialized)
  1993. {
  1994. RtlLeaveCriticalSection(&KdcGlobalCertCritSect);
  1995. RtlDeleteCriticalSection(&KdcGlobalCertCritSect);
  1996. KdcGlobalCertCritSectInitialized = FALSE;
  1997. }
  1998. }