Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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