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.

3077 lines
75 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: pkauth.cxx
  8. //
  9. // Contents: Routines for supporting public-key authentication
  10. //
  11. //
  12. // History: 14-October-1997 Created MikeSw
  13. //
  14. //------------------------------------------------------------------------
  15. #include <kerb.hxx>
  16. #include <kerbp.h>
  17. //#ifndef WIN32_CHICAGO
  18. extern "C"
  19. {
  20. #include <stdlib.h>
  21. #include <cryptdll.h>
  22. }
  23. //#endif // WIN32_CHICAGO
  24. #ifdef RETAIL_LOG_SUPPORT
  25. static TCHAR THIS_FILE[]=TEXT(__FILE__);
  26. #endif
  27. KERB_OBJECT_ID KerbSignatureAlg[10];
  28. #define KERB_SCLOGON_DOMAIN_SUFFIX L"-sclogon"
  29. #define KERB_SCLOGON_DOMAIN_SUFFIX_SIZE (sizeof(KERB_SCLOGON_DOMAIN_SUFFIX) - sizeof(WCHAR))
  30. #ifndef SHA1DIGESTLEN
  31. #define SHA1DIGESTLEN 20
  32. #endif
  33. NTSTATUS
  34. KerbInitializeHProvFromCert(
  35. IN PKERB_PUBLIC_KEY_CREDENTIALS PkCreds
  36. );
  37. //+-------------------------------------------------------------------------
  38. //
  39. // Function: KerbComparePublicKeyCreds
  40. //
  41. // Synopsis: Verfies a certificate is valid for the specified usage
  42. //
  43. // Effects:
  44. //
  45. // Arguments:
  46. //
  47. // Requires:
  48. //
  49. // Returns:
  50. //
  51. // Notes:
  52. //
  53. //
  54. //--------------------------------------------------------------------------
  55. BOOL
  56. KerbComparePublicKeyCreds(
  57. IN PKERB_PUBLIC_KEY_CREDENTIALS PkCreds1,
  58. IN PKERB_PUBLIC_KEY_CREDENTIALS PkCreds2
  59. )
  60. {
  61. return CertCompareCertificate(
  62. X509_ASN_ENCODING,
  63. PkCreds1->CertContext->pCertInfo,
  64. PkCreds2->CertContext->pCertInfo
  65. );
  66. // more later?
  67. //return (fRet);
  68. }
  69. //+-------------------------------------------------------------------------
  70. //
  71. // Function: KerbCheckCertificate
  72. //
  73. // Synopsis: Verfies a certificate is valid for the specified usage
  74. //
  75. // Effects:
  76. //
  77. // Arguments:
  78. //
  79. // Requires:
  80. //
  81. // Returns:
  82. //
  83. // Notes:
  84. //
  85. //
  86. //--------------------------------------------------------------------------
  87. NTSTATUS
  88. KerbCheckCertificate(
  89. IN PCCERT_CONTEXT CertContext,
  90. IN LPSTR Usage,
  91. IN BOOLEAN LocalLogon // AllowRevocationCheckFailure
  92. )
  93. {
  94. NTSTATUS Status = STATUS_SUCCESS;
  95. CERT_CHAIN_PARA ChainParameters = {0};
  96. PCCERT_CHAIN_CONTEXT ChainContext = NULL;
  97. ChainParameters.cbSize = sizeof(CERT_CHAIN_PARA);
  98. ChainParameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  99. ChainParameters.RequestedUsage.Usage.cUsageIdentifier = 1;
  100. ChainParameters.RequestedUsage.Usage.rgpszUsageIdentifier = &Usage;
  101. if (!CertGetCertificateChain(
  102. HCCE_LOCAL_MACHINE,
  103. CertContext,
  104. NULL, // evaluate at current time
  105. NULL, // no additional stores
  106. &ChainParameters,
  107. (LocalLogon?
  108. CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY|CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT:
  109. CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT),
  110. NULL, // reserved
  111. &ChainContext
  112. ))
  113. {
  114. DebugLog((DEB_WARN,"Failed to verify certificate chain: %0x%x\n",GetLastError()));
  115. Status = STATUS_PKINIT_FAILURE;
  116. }
  117. else
  118. {
  119. CERT_CHAIN_POLICY_PARA ChainPolicy;
  120. CERT_CHAIN_POLICY_STATUS PolicyStatus;
  121. ZeroMemory(&ChainPolicy, sizeof(ChainPolicy));
  122. ChainPolicy.cbSize = sizeof(ChainPolicy);
  123. if (LocalLogon)
  124. {
  125. ChainPolicy.dwFlags = CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS;
  126. }
  127. ZeroMemory(&PolicyStatus, sizeof(PolicyStatus));
  128. PolicyStatus.cbSize = sizeof(PolicyStatus);
  129. PolicyStatus.lChainIndex = -1;
  130. PolicyStatus.lElementIndex = -1;
  131. if (!CertVerifyCertificateChainPolicy(
  132. CERT_CHAIN_POLICY_BASE,
  133. ChainContext,
  134. &ChainPolicy,
  135. &PolicyStatus))
  136. {
  137. DebugLog((DEB_WARN,"CertVerifyCertificateChainPolicy failure: %0x%x\n", GetLastError()));
  138. Status = STATUS_PKINIT_FAILURE;
  139. }
  140. if(PolicyStatus.dwError != S_OK)
  141. {
  142. DebugLog((DEB_WARN,"CertVerifyCertificateChainPolicy - Chain Status failure: %0x%x\n",PolicyStatus.dwError));
  143. KerbReportPkinitError(
  144. PolicyStatus.dwError,
  145. CertContext
  146. );
  147. Status = STATUS_PKINIT_FAILURE;
  148. }
  149. }
  150. if (ChainContext != NULL)
  151. {
  152. CertFreeCertificateChain(ChainContext);
  153. }
  154. return(Status);
  155. }
  156. //+-------------------------------------------------------------------------
  157. //
  158. // Function: KerbVerifyPkAsReply
  159. //
  160. // Synopsis: Verifies the reply from the KDC and retrieves the
  161. // ticket encryption key
  162. //
  163. // Effects:
  164. //
  165. // Arguments:
  166. //
  167. // Requires:
  168. //
  169. // Returns:
  170. //
  171. // Notes:
  172. //
  173. //
  174. //--------------------------------------------------------------------------
  175. NTSTATUS
  176. KerbVerifyPkAsReply(
  177. IN PKERB_PA_DATA_LIST InputPaData,
  178. IN PKERB_PRIMARY_CREDENTIAL Credentials,
  179. IN ULONG Nonce,
  180. OUT PKERB_ENCRYPTION_KEY EncryptionKey,
  181. OUT PBOOLEAN Done
  182. )
  183. {
  184. NTSTATUS Status = STATUS_SUCCESS;
  185. KERBERR KerbErr = KDC_ERR_NONE;
  186. PKERB_PA_PK_AS_REP Reply = NULL;
  187. PCCERT_CONTEXT KdcCertContext = NULL;
  188. PBYTE EncodedKeyPackage = NULL;
  189. ULONG KeyPackageSize = 0;
  190. PKERB_SIGNED_REPLY_KEY_PACKAGE KeyPackage = NULL;
  191. PKERB_REPLY_KEY_PACKAGE ReplyKeyPackage = NULL;
  192. PBYTE PackedKeyPack = NULL;
  193. ULONG PackedKeyPackSize = 0;
  194. HCRYPTKEY PrivateKey = NULL;
  195. PKERB_ENCRYPTION_KEY TempKey = NULL;
  196. HCRYPTPROV KdcProvider = NULL;
  197. BOOLEAN InitializedPkCreds = FALSE;
  198. NTSTATUS TokenStatus = STATUS_SUCCESS;
  199. HANDLE ImpersonationToken = NULL;
  200. *Done = TRUE;
  201. //
  202. // Unpack the request
  203. //
  204. KerbErr = KerbUnpackData(
  205. InputPaData->value.preauth_data.value,
  206. InputPaData->value.preauth_data.length,
  207. KERB_PA_PK_AS_REP_PDU,
  208. (PVOID *) &Reply
  209. );
  210. if (!KERB_SUCCESS(KerbErr))
  211. {
  212. Status = STATUS_INSUFFICIENT_RESOURCES;
  213. goto Cleanup;
  214. }
  215. if (Reply->choice != key_package_chosen)
  216. {
  217. Status = STATUS_INVALID_PARAMETER;
  218. goto Cleanup;
  219. }
  220. //
  221. // Now we need to verify the signature on the message
  222. //
  223. //
  224. // Make sure the csp data is available
  225. //
  226. if ((Credentials->PublicKeyCreds->InitializationInfo & CSP_DATA_INITIALIZED) == 0)
  227. {
  228. Status = KerbInitializePkCreds(
  229. Credentials->PublicKeyCreds
  230. );
  231. if (!NT_SUCCESS(Status))
  232. {
  233. goto Cleanup;
  234. }
  235. InitializedPkCreds = TRUE;
  236. }
  237. else if ((Credentials->PublicKeyCreds->InitializationInfo & CONTEXT_INITIALIZED_WITH_CRED_MAN_CREDS) != 0)
  238. {
  239. // need to set the PIN and this function does that
  240. Status = KerbInitializeHProvFromCert(
  241. Credentials->PublicKeyCreds
  242. );
  243. if (!NT_SUCCESS(Status))
  244. {
  245. goto Cleanup;
  246. }
  247. }
  248. //
  249. // Decode the contents as an encrypted data buffer
  250. //
  251. Status = __ScHelperDecryptMessage(
  252. &Credentials->PublicKeyCreds->Pin,
  253. Credentials->PublicKeyCreds->CspData,
  254. Credentials->PublicKeyCreds->hProv,
  255. Credentials->PublicKeyCreds->CertContext,
  256. Reply->u.key_package.value,
  257. Reply->u.key_package.length,
  258. EncodedKeyPackage,
  259. &KeyPackageSize
  260. );
  261. if ((Status != STATUS_BUFFER_TOO_SMALL) && (Status != STATUS_SUCCESS))
  262. {
  263. DebugLog((DEB_ERROR,"Failed to decrypt pkcs message: %x\n",Status));
  264. goto Cleanup;
  265. }
  266. EncodedKeyPackage = (PBYTE) KerbAllocate(KeyPackageSize);
  267. if (EncodedKeyPackage == NULL)
  268. {
  269. Status = STATUS_INSUFFICIENT_RESOURCES;
  270. goto Cleanup;
  271. }
  272. Status = __ScHelperDecryptMessage(
  273. &Credentials->PublicKeyCreds->Pin,
  274. Credentials->PublicKeyCreds->CspData,
  275. Credentials->PublicKeyCreds->hProv,
  276. Credentials->PublicKeyCreds->CertContext,
  277. Reply->u.key_package.value,
  278. Reply->u.key_package.length,
  279. EncodedKeyPackage,
  280. &KeyPackageSize
  281. );
  282. if (Status != STATUS_SUCCESS)
  283. {
  284. DebugLog((DEB_ERROR,"Failed to decrypt pkcs message: %x\n",Status));
  285. goto Cleanup;
  286. }
  287. //
  288. // Verify the signature
  289. //
  290. Status = ScHelperVerifyPkcsMessage(
  291. Credentials->PublicKeyCreds->CspData,
  292. NULL, // we don't care which CSP is used for the verification
  293. EncodedKeyPackage,
  294. KeyPackageSize,
  295. PackedKeyPack,
  296. &PackedKeyPackSize,
  297. NULL // don't return certificate context
  298. );
  299. if ((Status != STATUS_BUFFER_TOO_SMALL) && (Status != STATUS_SUCCESS))
  300. {
  301. DebugLog((DEB_ERROR,"Failed to verify message: %x\n",Status));
  302. goto Cleanup;
  303. }
  304. PackedKeyPack = (PBYTE) MIDL_user_allocate(PackedKeyPackSize);
  305. if (PackedKeyPack == NULL)
  306. {
  307. KerbErr = KRB_ERR_GENERIC;
  308. Status = STATUS_INSUFFICIENT_RESOURCES;
  309. goto Cleanup;
  310. }
  311. Status = ScHelperVerifyPkcsMessage(
  312. Credentials->PublicKeyCreds->CspData,
  313. NULL, // we don't care which CSP is used for the verification
  314. EncodedKeyPackage,
  315. KeyPackageSize,
  316. PackedKeyPack,
  317. &PackedKeyPackSize,
  318. &KdcCertContext
  319. );
  320. if (Status != STATUS_SUCCESS)
  321. {
  322. DebugLog((DEB_ERROR,"Failed to verify message: %x\n",Status));
  323. goto Cleanup;
  324. }
  325. KerbErr = KerbUnpackData(
  326. PackedKeyPack,
  327. PackedKeyPackSize,
  328. KERB_REPLY_KEY_PACKAGE_PDU,
  329. (PVOID *) &ReplyKeyPackage
  330. );
  331. if (!KERB_SUCCESS(KerbErr))
  332. {
  333. D_DebugLog((DEB_ERROR,"Failed to unpack reply key package\n"));
  334. Status = KerbMapKerbError(KerbErr);
  335. goto Cleanup;
  336. }
  337. if (Nonce != (ULONG) ReplyKeyPackage->nonce)
  338. {
  339. D_DebugLog((DEB_ERROR,"Returned nonce is not correct: 0x%x instead of 0x%x. %ws, line %d\n",
  340. ReplyKeyPackage->nonce, Nonce, THIS_FILE, __LINE__ ));
  341. Status = STATUS_LOGON_FAILURE;
  342. goto Cleanup;
  343. }
  344. //
  345. // Finally, copy the encryption key out and return it.
  346. //
  347. if (!KERB_SUCCESS(KerbDuplicateKey(
  348. EncryptionKey,
  349. &ReplyKeyPackage->reply_key
  350. )))
  351. {
  352. Status = STATUS_INSUFFICIENT_RESOURCES;
  353. goto Cleanup;
  354. }
  355. //
  356. // Verify the certificate
  357. //
  358. // If we're impersonating, revert, and save off old token. This keeps us from
  359. // going recursive.
  360. //
  361. // Are we impersonating?
  362. //
  363. TokenStatus = NtOpenThreadToken(
  364. NtCurrentThread(),
  365. TOKEN_QUERY | TOKEN_IMPERSONATE,
  366. TRUE,
  367. &ImpersonationToken
  368. );
  369. if( NT_SUCCESS(TokenStatus) )
  370. {
  371. RevertToSelf();
  372. }
  373. else if (TokenStatus != STATUS_NO_TOKEN)
  374. {
  375. Status = TokenStatus;
  376. goto Cleanup;
  377. }
  378. Status = KerbCheckCertificate(
  379. KdcCertContext,
  380. KERB_PKINIT_KDC_CERT_TYPE,
  381. FALSE // don't allow revocation failures
  382. );
  383. //
  384. // re-impersonate
  385. //
  386. if( ImpersonationToken != NULL ) {
  387. //
  388. // put the thread token back if we were impersonating.
  389. //
  390. SetThreadToken( NULL, ImpersonationToken );
  391. NtClose( ImpersonationToken );
  392. }
  393. if (!NT_SUCCESS(Status))
  394. {
  395. DebugLog((DEB_ERROR,"Failed to verify KDC certificate: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  396. goto Cleanup;
  397. }
  398. Cleanup:
  399. //
  400. // If we initialized these, reset them
  401. //
  402. if (InitializedPkCreds)
  403. {
  404. KerbReleasePkCreds(
  405. NULL,
  406. Credentials->PublicKeyCreds
  407. );
  408. }
  409. if (Reply != NULL)
  410. {
  411. KerbFreeData(
  412. KERB_PA_PK_AS_REP_PDU,
  413. Reply
  414. );
  415. }
  416. if (KdcCertContext != NULL)
  417. {
  418. CertFreeCertificateContext(KdcCertContext);
  419. }
  420. if (KeyPackage != NULL)
  421. {
  422. KerbFreeData(
  423. KERB_SIGNED_REPLY_KEY_PACKAGE_PDU,
  424. KeyPackage
  425. );
  426. }
  427. if (ReplyKeyPackage != NULL)
  428. {
  429. KerbFreeData(
  430. KERB_REPLY_KEY_PACKAGE_PDU,
  431. ReplyKeyPackage
  432. );
  433. }
  434. if (PackedKeyPack != NULL)
  435. {
  436. MIDL_user_free(PackedKeyPack);
  437. }
  438. if (PrivateKey != NULL)
  439. {
  440. CryptDestroyKey(PrivateKey);
  441. }
  442. if (TempKey != NULL)
  443. {
  444. KerbFreeData(
  445. KERB_ENCRYPTION_KEY_PDU,
  446. TempKey
  447. );
  448. }
  449. if (KdcProvider != NULL)
  450. {
  451. CryptReleaseContext(
  452. KdcProvider,
  453. 0 // no flags
  454. );
  455. }
  456. if (EncodedKeyPackage != NULL)
  457. {
  458. KerbFree(EncodedKeyPackage);
  459. }
  460. return(Status);
  461. }
  462. //+-------------------------------------------------------------------------
  463. //
  464. // Function: KerbGetUserCertificates
  465. //
  466. // Synopsis: Gets a list of the user certificates
  467. //
  468. // Effects:
  469. //
  470. // Arguments: Credentials - client's credentials containing certificate
  471. // Certficates - receives list of certificates.
  472. //
  473. // Requires:
  474. //
  475. // Returns:
  476. //
  477. // Notes:
  478. //
  479. //
  480. //--------------------------------------------------------------------------
  481. NTSTATUS
  482. KerbGetUserCertificates(
  483. IN PKERB_PRIMARY_CREDENTIAL Credentials,
  484. OUT PKERB_CERTIFICATE_LIST * Certificates
  485. )
  486. {
  487. NTSTATUS Status = STATUS_SUCCESS;
  488. if (!KERB_SUCCESS(KerbCreateCertificateList(
  489. Certificates,
  490. Credentials->PublicKeyCreds->CertContext
  491. )))
  492. {
  493. Status = STATUS_INSUFFICIENT_RESOURCES;
  494. goto Cleanup;
  495. }
  496. Cleanup:
  497. return(Status);
  498. }
  499. #if 0 // could not find any users - markpu - 04/19/2001 - will remove later
  500. //+-------------------------------------------------------------------------
  501. //
  502. // Function: KerbGetTrustedCertifiers
  503. //
  504. // Synopsis: Gets the list of trusted certifiers for this machine
  505. //
  506. // Effects:
  507. //
  508. // Arguments:
  509. //
  510. // Requires:
  511. //
  512. // Returns:
  513. //
  514. // Notes:
  515. //
  516. //
  517. //--------------------------------------------------------------------------
  518. NTSTATUS
  519. KerbGetTrustedCertifiers(
  520. IN PKERB_PRIMARY_CREDENTIAL Credentials,
  521. OUT PKERB_CERTIFIER_LIST * Certifiers
  522. )
  523. {
  524. NTSTATUS Status = STATUS_SUCCESS;
  525. PKERB_CERTIFIER_LIST ListEntry = NULL;
  526. //
  527. // Build a dummy list entry
  528. //
  529. ListEntry = (PKERB_CERTIFIER_LIST) KerbAllocate(sizeof(KERB_CERTIFIER_LIST));
  530. if (ListEntry == NULL)
  531. {
  532. Status = STATUS_INSUFFICIENT_RESOURCES;
  533. goto Cleanup;
  534. }
  535. if (!KERB_SUCCESS(KerbConvertStringToPrincipalName(
  536. &ListEntry->value,
  537. &KerbGlobalKdcServiceName,
  538. KRB_NT_PRINCIPAL
  539. )))
  540. {
  541. Status = STATUS_INSUFFICIENT_RESOURCES;
  542. goto Cleanup;
  543. }
  544. *Certifiers = ListEntry;
  545. ListEntry = NULL;
  546. Cleanup:
  547. if (ListEntry != NULL)
  548. {
  549. KerbFreePrincipalName( &ListEntry->value );
  550. KerbFree(ListEntry);
  551. }
  552. return(Status);
  553. }
  554. #endif
  555. //+-------------------------------------------------------------------------
  556. //
  557. // Function: KerbFreePKCreds
  558. //
  559. // Synopsis: Frees the public key creds
  560. //
  561. // Effects:
  562. //
  563. // Arguments:
  564. //
  565. // Requires:
  566. //
  567. // Returns:
  568. //
  569. // Notes:
  570. //
  571. //
  572. //--------------------------------------------------------------------------
  573. VOID
  574. KerbFreePKCreds(
  575. IN PKERB_PUBLIC_KEY_CREDENTIALS PkCreds
  576. )
  577. {
  578. if (NULL != PkCreds)
  579. {
  580. if (((PkCreds->InitializationInfo & CSP_DATA_INITIALIZED) != 0) &&
  581. ((PkCreds->InitializationInfo & (CONTEXT_INITIALIZED_WITH_CRED_MAN_CREDS | CONTEXT_INITIALIZED_WITH_ACH)) == 0))
  582. {
  583. __ScHelperRelease(
  584. PkCreds->CspData
  585. );
  586. PkCreds->InitializationInfo &= ~CSP_DATA_INITIALIZED;
  587. }
  588. if (PkCreds->hProv != NULL)
  589. {
  590. CryptReleaseContext(PkCreds->hProv, 0);
  591. PkCreds->hProv = NULL;
  592. }
  593. if (PkCreds->CertContext != NULL)
  594. {
  595. CertFreeCertificateContext(PkCreds->CertContext);
  596. PkCreds->CertContext = NULL;
  597. }
  598. KerbFreeString(&PkCreds->Pin);
  599. KerbFree(PkCreds);
  600. }
  601. }
  602. //+-------------------------------------------------------------------------
  603. //
  604. // Function: KerbInitializeHProvFromCert
  605. //
  606. // Synopsis: Initializes the out parameter phProv by getting the key
  607. // prov info from the cert context and acquiring a CSP context
  608. // given this information.
  609. //
  610. // Effects:
  611. //
  612. // Arguments:
  613. //
  614. // Requires:
  615. //
  616. // Returns:
  617. //
  618. // Notes:
  619. //
  620. //
  621. //--------------------------------------------------------------------------
  622. NTSTATUS
  623. KerbInitializeHProvFromCert(
  624. IN PKERB_PUBLIC_KEY_CREDENTIALS PkCreds
  625. )
  626. {
  627. ULONG cPin;
  628. LPWSTR pwszPin = NULL;
  629. LPSTR pszPin = NULL;
  630. NTSTATUS Status = STATUS_SUCCESS;
  631. if (!CryptAcquireCertificatePrivateKey(
  632. PkCreds->CertContext,
  633. CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_SILENT,
  634. NULL,
  635. &PkCreds->hProv,
  636. NULL,
  637. NULL
  638. ))
  639. {
  640. DebugLog((DEB_ERROR,
  641. "CryptAcquireCertificatePrivateKey failed - %x\n",
  642. GetLastError()));
  643. Status = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  644. goto Cleanup;
  645. }
  646. //
  647. // Convert the pin to ANSI, but only for creds acquired by ACH, as the
  648. // credman isn't "allowed" to cache pins anymore..
  649. //
  650. if (( PkCreds->InitializationInfo & CONTEXT_INITIALIZED_WITH_ACH ) != 0)
  651. {
  652. if (0 == PkCreds->Pin.Length)
  653. {
  654. Status = STATUS_LOGON_FAILURE;
  655. goto Cleanup;
  656. }
  657. pwszPin = (LPWSTR)KerbAllocate(PkCreds->Pin.Length + sizeof(WCHAR));
  658. if (NULL == pwszPin)
  659. {
  660. Status = STATUS_INSUFFICIENT_RESOURCES;
  661. goto Cleanup;
  662. }
  663. RtlCopyMemory(pwszPin, PkCreds->Pin.Buffer, PkCreds->Pin.Length);
  664. pwszPin[PkCreds->Pin.Length / sizeof(WCHAR)] = L'\0';
  665. cPin = WideCharToMultiByte(
  666. GetACP(),
  667. 0,
  668. pwszPin,
  669. -1,
  670. NULL,
  671. 0,
  672. NULL,
  673. NULL);
  674. pszPin = (LPSTR)KerbAllocate((cPin + 1) * sizeof(CHAR));
  675. if (NULL == pszPin)
  676. {
  677. Status = STATUS_INSUFFICIENT_RESOURCES;
  678. goto Cleanup;
  679. }
  680. cPin = WideCharToMultiByte(
  681. GetACP(),
  682. 0,
  683. pwszPin,
  684. -1,
  685. pszPin,
  686. cPin,
  687. NULL,
  688. NULL);
  689. if (!CryptSetProvParam(
  690. PkCreds->hProv,
  691. PP_KEYEXCHANGE_PIN,
  692. (LPBYTE)pszPin,
  693. 0
  694. ))
  695. {
  696. Status = STATUS_LOGON_FAILURE;
  697. goto Cleanup;
  698. }
  699. }
  700. Cleanup:
  701. if (NULL != pwszPin)
  702. {
  703. KerbFree(pwszPin);
  704. }
  705. if (NULL != pszPin)
  706. {
  707. KerbFree(pszPin);
  708. }
  709. return Status;
  710. }
  711. //+-------------------------------------------------------------------------
  712. //
  713. // Function: KerbInitializePkCreds
  714. //
  715. // Synopsis: Initializes or re-initailizes the smart card data in
  716. // the public key creds
  717. //
  718. // Effects:
  719. //
  720. // Arguments:
  721. //
  722. // Requires:
  723. //
  724. // Returns:
  725. //
  726. // Notes:
  727. //
  728. //
  729. //--------------------------------------------------------------------------
  730. NTSTATUS
  731. KerbInitializePkCreds(
  732. IN PKERB_PUBLIC_KEY_CREDENTIALS PkCreds
  733. )
  734. {
  735. NTSTATUS Status = STATUS_SUCCESS;
  736. if ((PkCreds->InitializationInfo & CSP_DATA_INITIALIZED) == 0)
  737. {
  738. //
  739. // check if we are using cred man creds (already have a cert context)
  740. //
  741. if (((PkCreds->InitializationInfo & CONTEXT_INITIALIZED_WITH_CRED_MAN_CREDS) == 0) &&
  742. ((PkCreds->InitializationInfo & CONTEXT_INITIALIZED_WITH_ACH) == 0))
  743. {
  744. Status = __ScHelperInitializeContext(
  745. PkCreds->CspData,
  746. PkCreds->CspDataLength
  747. );
  748. if (!NT_SUCCESS(Status))
  749. {
  750. DebugLog((DEB_ERROR,"ScHelperInitializeContext failed- %x\n", Status));
  751. goto Cleanup;
  752. }
  753. PkCreds->InitializationInfo |= CSP_DATA_INITIALIZED;
  754. }
  755. else
  756. {
  757. if (PkCreds->CertContext == NULL)
  758. {
  759. D_DebugLog((DEB_ERROR,"Using cred man creds but cert context is NULL.\n"));
  760. Status = STATUS_INVALID_PARAMETER;
  761. goto Cleanup;
  762. }
  763. PkCreds->InitializationInfo |= CSP_DATA_INITIALIZED;
  764. }
  765. }
  766. if (PkCreds->CertContext == NULL)
  767. {
  768. Status = __ScHelperGetCertFromLogonInfo(
  769. PkCreds->CspData,
  770. &PkCreds->Pin,
  771. &PkCreds->CertContext
  772. );
  773. if (Status != STATUS_SUCCESS)
  774. {
  775. DebugLog((DEB_ERROR,"Failed to get cert from logon info: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  776. if (NT_SUCCESS(Status))
  777. {
  778. Status = STATUS_LOGON_FAILURE;
  779. }
  780. goto Cleanup;
  781. }
  782. }
  783. Cleanup:
  784. if (!NT_SUCCESS(Status))
  785. {
  786. if (((PkCreds->InitializationInfo & CSP_DATA_INITIALIZED) != 0) &&
  787. ((PkCreds->InitializationInfo & ( CONTEXT_INITIALIZED_WITH_CRED_MAN_CREDS | CONTEXT_INITIALIZED_WITH_ACH)) == 0))
  788. {
  789. __ScHelperRelease(
  790. PkCreds->CspData
  791. );
  792. PkCreds->InitializationInfo &= ~CSP_DATA_INITIALIZED;
  793. }
  794. }
  795. return(Status);
  796. }
  797. //+-------------------------------------------------------------------------
  798. //
  799. // Function: KerbReleasePkCreds
  800. //
  801. // Synopsis: Releaes smart-card resources in the public key creds.
  802. //
  803. // Effects:
  804. //
  805. // Arguments:
  806. //
  807. // Requires:
  808. //
  809. // Returns:
  810. //
  811. // Notes:
  812. //
  813. //
  814. //--------------------------------------------------------------------------
  815. VOID
  816. KerbReleasePkCreds(
  817. IN OPTIONAL PKERB_LOGON_SESSION LogonSession,
  818. IN OPTIONAL PKERB_PUBLIC_KEY_CREDENTIALS PkCreds
  819. )
  820. {
  821. if (ARGUMENT_PRESENT(LogonSession))
  822. {
  823. KerbWriteLockLogonSessions(
  824. LogonSession
  825. );
  826. PkCreds = LogonSession->PrimaryCredentials.PublicKeyCreds;
  827. }
  828. KerbFreePKCreds(PkCreds);
  829. if (ARGUMENT_PRESENT(LogonSession))
  830. {
  831. LogonSession->PrimaryCredentials.PublicKeyCreds = NULL;
  832. KerbUnlockLogonSessions(
  833. LogonSession
  834. );
  835. }
  836. }
  837. //+-------------------------------------------------------------------------
  838. //
  839. // Function: KerbComputePkAuthenticatorSignature
  840. //
  841. // Synopsis: Computes the signature of the PK authenticator by
  842. // marshalling the authenticator, checksumming it, then
  843. // encrypting the checksum with the public key, more or less
  844. //
  845. // Effects:
  846. //
  847. // Arguments: AuthPackage - authenticator to sign
  848. // Credentials - Client's credentials (containing keys)
  849. // Signature - receives signature
  850. //
  851. // Requires:
  852. //
  853. // Returns:
  854. //
  855. // Notes:
  856. //
  857. //
  858. //--------------------------------------------------------------------------
  859. NTSTATUS
  860. KerbComputePkAuthenticatorSignature(
  861. IN PKERB_AUTH_PACKAGE AuthPackage,
  862. IN PKERB_PRIMARY_CREDENTIAL Credentials,
  863. OUT PKERB_SIGNATURE Signature
  864. )
  865. {
  866. NTSTATUS Status = STATUS_SUCCESS;
  867. KERBERR KerbErr = KDC_ERR_NONE;
  868. PBYTE PackedAuthenticator = NULL;
  869. ULONG PackedAuthenticatorSize;
  870. BOOLEAN InitializedPkCreds = FALSE;
  871. PUNICODE_STRING TmpPin = NULL;
  872. #define KERB_PK_MAX_SIGNATURE_SIZE 128
  873. BYTE PkSignature[KERB_PK_MAX_SIGNATURE_SIZE];
  874. ULONG PkSignatureLength = KERB_PK_MAX_SIGNATURE_SIZE;
  875. RtlZeroMemory(
  876. Signature,
  877. sizeof(KERB_SIGNATURE)
  878. );
  879. //
  880. // First marshall the auth package
  881. //
  882. KerbErr = KerbPackData(
  883. AuthPackage,
  884. KERB_AUTH_PACKAGE_PDU,
  885. &PackedAuthenticatorSize,
  886. &PackedAuthenticator
  887. );
  888. if (!KERB_SUCCESS(KerbErr))
  889. {
  890. Status = STATUS_INSUFFICIENT_RESOURCES;
  891. goto Cleanup;
  892. }
  893. //
  894. // Make sure the csp data is available
  895. //
  896. if ((Credentials->PublicKeyCreds->InitializationInfo & CSP_DATA_INITIALIZED) == 0)
  897. {
  898. Status = KerbInitializePkCreds(
  899. Credentials->PublicKeyCreds
  900. );
  901. if (!NT_SUCCESS(Status))
  902. {
  903. goto Cleanup;
  904. }
  905. InitializedPkCreds = TRUE;
  906. }
  907. else if (((Credentials->PublicKeyCreds->InitializationInfo
  908. & (CONTEXT_INITIALIZED_WITH_CRED_MAN_CREDS | CONTEXT_INITIALIZED_WITH_ACH)) != 0))
  909. {
  910. // need to set the PIN and this function does that
  911. Status = KerbInitializeHProvFromCert(
  912. Credentials->PublicKeyCreds
  913. );
  914. if (!NT_SUCCESS(Status))
  915. {
  916. goto Cleanup;
  917. }
  918. }
  919. // Initialize the PIN for ScHelperSignPkcs routines.
  920. if (((Credentials->PublicKeyCreds->InitializationInfo & CONTEXT_INITIALIZED_WITH_CRED_MAN_CREDS) == 0) &&
  921. (Credentials->PublicKeyCreds->Pin.Buffer != NULL))
  922. {
  923. TmpPin = &Credentials->PublicKeyCreds->Pin;
  924. }
  925. //
  926. // Now generate the checksum
  927. //
  928. Status = __ScHelperSignMessage(
  929. TmpPin,
  930. Credentials->PublicKeyCreds->CspData,
  931. Credentials->PublicKeyCreds->hProv,
  932. KERB_PKINIT_SIGNATURE_ALG,
  933. PackedAuthenticator,
  934. PackedAuthenticatorSize,
  935. PkSignature,
  936. &PkSignatureLength
  937. );
  938. if (!NT_SUCCESS(Status))
  939. {
  940. DebugLog((DEB_ERROR,"Failed to sign message with card: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  941. goto Cleanup;
  942. }
  943. //
  944. // Build the signature
  945. //
  946. Signature->signature_algorithm.algorithm = KerbSignatureAlg;
  947. //
  948. // Copy the temporary signature into the return structure
  949. //
  950. Signature->pkcs_signature.length = PkSignatureLength * 8; // because it is a bit string
  951. Signature->pkcs_signature.value = (PBYTE) KerbAllocate( PkSignatureLength );
  952. if (Signature->pkcs_signature.value == NULL)
  953. {
  954. Status = STATUS_INSUFFICIENT_RESOURCES;
  955. goto Cleanup;
  956. }
  957. RtlCopyMemory(
  958. Signature->pkcs_signature.value,
  959. PkSignature,
  960. PkSignatureLength
  961. );
  962. Status = STATUS_SUCCESS;
  963. Cleanup:
  964. if (InitializedPkCreds)
  965. {
  966. KerbReleasePkCreds(
  967. NULL,
  968. Credentials->PublicKeyCreds
  969. );
  970. }
  971. if (PackedAuthenticator != NULL)
  972. {
  973. MIDL_user_free(PackedAuthenticator);
  974. }
  975. return(Status);
  976. }
  977. NTSTATUS
  978. KerbGetProvParamWrapper(
  979. IN PUNICODE_STRING pPin,
  980. IN PBYTE pbLogonInfo,
  981. IN OPTIONAL HCRYPTPROV hProv,
  982. DWORD dwParam,
  983. BYTE*pbData,
  984. DWORD *pdwDataLen,
  985. DWORD dwFlags
  986. )
  987. {
  988. NTSTATUS Status = STATUS_SUCCESS;
  989. if (NULL != hProv)
  990. {
  991. if (!CryptGetProvParam(
  992. hProv,
  993. dwParam,
  994. pbData,
  995. pdwDataLen,
  996. dwFlags
  997. ))
  998. {
  999. DebugLog((DEB_ERROR, "Failure in SC subsytem - %x\n",GetLastError()));
  1000. Status = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1001. goto Cleanup;
  1002. }
  1003. }
  1004. else
  1005. {
  1006. Status = __ScHelperGetProvParam(
  1007. pPin,
  1008. pbLogonInfo,
  1009. dwParam,
  1010. pbData,
  1011. pdwDataLen,
  1012. dwFlags
  1013. );
  1014. if (!NT_SUCCESS(Status))
  1015. {
  1016. DebugLog((DEB_ERROR, "Failure in SC subsytem - %x\n",Status));
  1017. }
  1018. }
  1019. Cleanup:
  1020. return Status;
  1021. }
  1022. //+-------------------------------------------------------------------------
  1023. //
  1024. // Function: KerbGetSmartCardAlgorithms
  1025. //
  1026. // Synopsis: Gets the supported encryption types from the
  1027. // smart card provider
  1028. //
  1029. // Effects:
  1030. //
  1031. // Arguments:
  1032. //
  1033. // Requires:
  1034. //
  1035. // Returns:
  1036. //
  1037. // Notes:
  1038. //
  1039. //
  1040. //--------------------------------------------------------------------------
  1041. NTSTATUS
  1042. KerbGetSmartCardAlgorithms(
  1043. IN PKERB_PRIMARY_CREDENTIAL Credentials,
  1044. OUT PKERB_CRYPT_LIST * CryptList
  1045. )
  1046. {
  1047. NTSTATUS Status = STATUS_SUCCESS;
  1048. PROV_ENUMALGS Data;
  1049. ULONG DataSize;
  1050. ULONG Flags = CRYPT_FIRST;
  1051. #define KERB_SUPPORTED_PK_CRYPT_COUNT 2
  1052. ULONG CryptTypes[KERB_SUPPORTED_PK_CRYPT_COUNT];
  1053. ULONG CryptCount = 0;
  1054. //
  1055. // Enumerate through to get the encrypt types
  1056. //
  1057. while (1)
  1058. {
  1059. DataSize = sizeof(Data);
  1060. Status = KerbGetProvParamWrapper(
  1061. &Credentials->PublicKeyCreds->Pin,
  1062. Credentials->PublicKeyCreds->CspData,
  1063. Credentials->PublicKeyCreds->hProv,
  1064. PP_ENUMALGS,
  1065. (BYTE *) &Data,
  1066. &DataSize,
  1067. Flags
  1068. );
  1069. if (Status == STATUS_NO_MORE_ENTRIES)
  1070. {
  1071. Status = STATUS_SUCCESS;
  1072. break;
  1073. }
  1074. if (!NT_SUCCESS(Status))
  1075. {
  1076. DebugLog((DEB_ERROR,"GetProvPram failed: 0x%x\n", Status));
  1077. return(Status);
  1078. }
  1079. //
  1080. // Reset the flags to enumerate though
  1081. //
  1082. Flags = 0; // CRYPT_NEXT
  1083. //
  1084. // Check if it is an encryption algorithm. We only want
  1085. // to know about 3des and RC4
  1086. //
  1087. if (GET_ALG_CLASS(Data.aiAlgid) == ALG_CLASS_DATA_ENCRYPT)
  1088. {
  1089. //
  1090. // Check the type
  1091. //
  1092. if (GET_ALG_TYPE(Data.aiAlgid) == ALG_TYPE_BLOCK)
  1093. {
  1094. //
  1095. // Check for 3des
  1096. //
  1097. if (GET_ALG_SID(Data.aiAlgid) == ALG_SID_3DES)
  1098. {
  1099. //
  1100. // Add it to the list.
  1101. //
  1102. CryptTypes[CryptCount++] = KERB_ETYPE_DES_EDE3_CBC_ENV;
  1103. }
  1104. else if (GET_ALG_SID(Data.aiAlgid) == ALG_SID_RC2)
  1105. {
  1106. //
  1107. // Add it to the list.
  1108. //
  1109. CryptTypes[CryptCount++] = KERB_ETYPE_RC2_CBC_ENV;
  1110. }
  1111. }
  1112. }
  1113. if (CryptCount == KERB_SUPPORTED_PK_CRYPT_COUNT)
  1114. {
  1115. break;
  1116. }
  1117. }
  1118. //
  1119. // Now, if there are any crypt types, convert them.
  1120. //
  1121. if (CryptCount != 0)
  1122. {
  1123. KERBERR KerbErr;
  1124. KerbErr = KerbConvertArrayToCryptList(
  1125. CryptList,
  1126. CryptTypes,
  1127. CryptCount
  1128. );
  1129. return(KerbMapKerbError(KerbErr));
  1130. }
  1131. else
  1132. {
  1133. //
  1134. // We needed one of these, so bail now.
  1135. //
  1136. DebugLog((DEB_ERROR,"Smart card doesn't support rc2 or 3des for logon - failing out.\n"));
  1137. return(STATUS_CRYPTO_SYSTEM_INVALID);
  1138. }
  1139. }
  1140. //+-------------------------------------------------------------------------
  1141. //
  1142. // Function: KerbBuildPkinitPreAuthData
  1143. //
  1144. // Synopsis: Builds the pre-auth data for a PK-INIT AS request
  1145. //
  1146. // Effects:
  1147. //
  1148. // Arguments: Credentials - Credentials to use for this request
  1149. // InputPaData - Any PA data returned from DC on previous
  1150. // call
  1151. // TimeSkew - Known time skew with KDC
  1152. // ServiceName - Name for which we are requesting a ticket
  1153. // RealmName - name of realm in which we are requesting a ticket
  1154. // PreAuthData - receives new PA data
  1155. // Done - if returned as TRUE, then routine need not be called
  1156. // again
  1157. //
  1158. // Requires:
  1159. //
  1160. // Returns:
  1161. //
  1162. // Notes:
  1163. //
  1164. //
  1165. //--------------------------------------------------------------------------
  1166. NTSTATUS
  1167. KerbBuildPkinitPreauthData(
  1168. IN PKERB_PRIMARY_CREDENTIAL Credentials,
  1169. IN OPTIONAL PKERB_PA_DATA_LIST InputPaData,
  1170. IN PTimeStamp TimeSkew,
  1171. IN PKERB_INTERNAL_NAME ServiceName,
  1172. IN PUNICODE_STRING RealmName,
  1173. IN ULONG Nonce,
  1174. OUT PKERB_PA_DATA_LIST * PreAuthData,
  1175. OUT PKERB_ENCRYPTION_KEY EncryptionKey,
  1176. OUT PKERB_CRYPT_LIST * CryptList,
  1177. OUT PBOOLEAN Done
  1178. )
  1179. {
  1180. NTSTATUS Status = STATUS_SUCCESS;
  1181. KERB_PA_PK_AS_REQ Request = {0};
  1182. KERB_AUTH_PACKAGE AuthPack = {0};
  1183. PKERB_PA_DATA_LIST ListElement = NULL;
  1184. ULONG PackedRequestSize = 0;
  1185. PBYTE PackedRequest = NULL;
  1186. PBYTE PackedAuthPack = NULL;
  1187. ULONG PackedAuthPackSize = 0;
  1188. PBYTE SignedAuthPack = NULL;
  1189. ULONG SignedAuthPackSize = 0;
  1190. TimeStamp TimeNow;
  1191. KERBERR KerbErr;
  1192. BOOLEAN InitializedPkCreds = FALSE;
  1193. CRYPT_ALGORITHM_IDENTIFIER CryptAlg = {0};
  1194. PUNICODE_STRING TmpPin = NULL;
  1195. HANDLE ClientTokenHandle = NULL;
  1196. BOOLEAN Impersonating = FALSE;
  1197. //
  1198. // If we're using credman, we'll need to impersonate any time we make these calls.
  1199. //
  1200. if ( Credentials->PublicKeyCreds->InitializationInfo & CONTEXT_INITIALIZED_WITH_CRED_MAN_CREDS )
  1201. {
  1202. Status = LsaFunctions->OpenTokenByLogonId(
  1203. &Credentials->PublicKeyCreds->LogonId,
  1204. &ClientTokenHandle
  1205. );
  1206. if (!NT_SUCCESS(Status))
  1207. {
  1208. D_DebugLog((DEB_ERROR,"Unable to get the client token handle.\n"));
  1209. goto Cleanup;
  1210. }
  1211. if(!SetThreadToken(NULL, ClientTokenHandle))
  1212. {
  1213. D_DebugLog((DEB_ERROR,"Unable to impersonate the client token handle.\n"));
  1214. Status = STATUS_CANNOT_IMPERSONATE;
  1215. goto Cleanup;
  1216. }
  1217. Impersonating = TRUE;
  1218. }
  1219. //
  1220. // If there is any input, check to see if we succeeded the last time
  1221. // around
  1222. //
  1223. if (ARGUMENT_PRESENT(InputPaData))
  1224. {
  1225. Status = KerbVerifyPkAsReply(
  1226. InputPaData,
  1227. Credentials,
  1228. Nonce,
  1229. EncryptionKey,
  1230. Done
  1231. );
  1232. goto Cleanup;
  1233. }
  1234. //
  1235. // Make sure the csp data is available
  1236. //
  1237. if ((Credentials->PublicKeyCreds->InitializationInfo & CSP_DATA_INITIALIZED) == 0)
  1238. {
  1239. Status = KerbInitializePkCreds(
  1240. Credentials->PublicKeyCreds
  1241. );
  1242. if (!NT_SUCCESS(Status))
  1243. {
  1244. goto Cleanup;
  1245. }
  1246. InitializedPkCreds = TRUE;
  1247. }
  1248. else if (((Credentials->PublicKeyCreds->InitializationInfo
  1249. & (CONTEXT_INITIALIZED_WITH_CRED_MAN_CREDS | CONTEXT_INITIALIZED_WITH_ACH)) != 0))
  1250. {
  1251. // need to set the PIN and this function does that
  1252. Status = KerbInitializeHProvFromCert(
  1253. Credentials->PublicKeyCreds
  1254. );
  1255. if (!NT_SUCCESS(Status))
  1256. {
  1257. goto Cleanup;
  1258. }
  1259. }
  1260. // Initialize the PIN for ScHelperSignPkcs routines.
  1261. if (((Credentials->PublicKeyCreds->InitializationInfo & CONTEXT_INITIALIZED_WITH_CRED_MAN_CREDS) == 0) &&
  1262. (Credentials->PublicKeyCreds->Pin.Buffer != NULL))
  1263. {
  1264. TmpPin = &Credentials->PublicKeyCreds->Pin;
  1265. }
  1266. Status = KerbGetSmartCardAlgorithms(
  1267. Credentials,
  1268. CryptList
  1269. );
  1270. if (!NT_SUCCESS(Status))
  1271. {
  1272. DebugLog((DEB_ERROR,"Failed to get crypt list for smart card: 0x%x\n",
  1273. Status));
  1274. goto Cleanup;
  1275. }
  1276. //
  1277. // Do the new pa-pk-as-req
  1278. //
  1279. //
  1280. // Now comes the hard part - the PK authenticator
  1281. //
  1282. //
  1283. // First the KDC name
  1284. //
  1285. if (!KERB_SUCCESS(
  1286. KerbConvertKdcNameToPrincipalName(
  1287. &AuthPack.pk_authenticator.kdc_name,
  1288. ServiceName
  1289. )))
  1290. {
  1291. Status = STATUS_SUCCESS;
  1292. goto Cleanup;
  1293. }
  1294. //
  1295. // Then the realm
  1296. //
  1297. if (!KERB_SUCCESS(
  1298. KerbConvertUnicodeStringToRealm(
  1299. &AuthPack.pk_authenticator.kdc_realm,
  1300. RealmName)))
  1301. {
  1302. Status = STATUS_SUCCESS;
  1303. goto Cleanup;
  1304. }
  1305. //
  1306. // Now the time
  1307. //
  1308. GetSystemTimeAsFileTime((PFILETIME) &TimeNow);
  1309. #ifndef WIN32_CHICAGO
  1310. TimeNow.QuadPart += TimeSkew->QuadPart;
  1311. #else // !WIN32_CHICAGO
  1312. TimeNow += *TimeSkew;
  1313. #endif // WIN32_CHICAGO
  1314. KerbConvertLargeIntToGeneralizedTimeWrapper(
  1315. &AuthPack.pk_authenticator.client_time,
  1316. &AuthPack.pk_authenticator.cusec,
  1317. &TimeNow);
  1318. //
  1319. // And finally the nonce
  1320. //
  1321. AuthPack.pk_authenticator.nonce = Nonce;
  1322. //
  1323. // Pack up the auth pack so we can sign it
  1324. //
  1325. KerbErr = KerbPackData(
  1326. &AuthPack,
  1327. KERB_AUTH_PACKAGE_PDU,
  1328. &PackedAuthPackSize,
  1329. &PackedAuthPack
  1330. );
  1331. if (!KERB_SUCCESS(KerbErr))
  1332. {
  1333. DebugLog((DEB_ERROR,"Failed to pack auth package\n"));
  1334. Status = KerbMapKerbError(KerbErr);
  1335. goto Cleanup;
  1336. }
  1337. //
  1338. // Now sign it.
  1339. //
  1340. //
  1341. // Now generate the checksum
  1342. //
  1343. CryptAlg.pszObjId = KERB_PKINIT_SIGNATURE_OID;
  1344. Status = __ScHelperSignPkcsMessage(
  1345. TmpPin,
  1346. Credentials->PublicKeyCreds->CspData,
  1347. Credentials->PublicKeyCreds->hProv,
  1348. Credentials->PublicKeyCreds->CertContext,
  1349. &CryptAlg,
  1350. CRYPT_MESSAGE_SILENT_KEYSET_FLAG, // dwSignMessageFlags
  1351. PackedAuthPack,
  1352. PackedAuthPackSize,
  1353. SignedAuthPack,
  1354. &SignedAuthPackSize
  1355. );
  1356. if ((Status != STATUS_BUFFER_TOO_SMALL) && (Status != STATUS_SUCCESS))
  1357. {
  1358. DebugLog((DEB_ERROR,"Failed to sign message: %x\n",Status));
  1359. goto Cleanup;
  1360. }
  1361. SignedAuthPack = (PBYTE) MIDL_user_allocate(SignedAuthPackSize);
  1362. if (SignedAuthPack == NULL)
  1363. {
  1364. KerbErr = KRB_ERR_GENERIC;
  1365. goto Cleanup;
  1366. }
  1367. Status = __ScHelperSignPkcsMessage(
  1368. TmpPin,
  1369. Credentials->PublicKeyCreds->CspData,
  1370. Credentials->PublicKeyCreds->hProv,
  1371. Credentials->PublicKeyCreds->CertContext,
  1372. &CryptAlg,
  1373. CRYPT_MESSAGE_SILENT_KEYSET_FLAG, // dwSignMessageFlags
  1374. PackedAuthPack,
  1375. PackedAuthPackSize,
  1376. SignedAuthPack,
  1377. &SignedAuthPackSize
  1378. );
  1379. if (Status != STATUS_SUCCESS)
  1380. {
  1381. DebugLog((DEB_ERROR,"Failed to sign pkcs message: 0x%x\n",Status));
  1382. goto Cleanup;
  1383. }
  1384. Request.signed_auth_pack.value = SignedAuthPack;
  1385. Request.signed_auth_pack.length = SignedAuthPackSize;
  1386. //
  1387. // Marshall the request
  1388. //
  1389. if (!KERB_SUCCESS(KerbPackData(
  1390. &Request,
  1391. KERB_PA_PK_AS_REQ_PDU,
  1392. &PackedRequestSize,
  1393. &PackedRequest)))
  1394. {
  1395. Status = STATUS_INSUFFICIENT_RESOURCES;
  1396. goto Cleanup;
  1397. }
  1398. ListElement = (PKERB_PA_DATA_LIST) KerbAllocate(sizeof(KERB_PA_DATA_LIST));
  1399. if (ListElement == NULL)
  1400. {
  1401. Status = STATUS_INSUFFICIENT_RESOURCES;
  1402. goto Cleanup;
  1403. }
  1404. ListElement->value.preauth_data_type = KRB5_PADATA_PK_AS_REP;
  1405. ListElement->value.preauth_data.value = PackedRequest;
  1406. ListElement->value.preauth_data.length = PackedRequestSize;
  1407. PackedRequest = NULL;
  1408. ListElement->next = *PreAuthData;
  1409. *PreAuthData = ListElement;
  1410. ListElement = NULL;
  1411. Cleanup:
  1412. KerbFreeRealm(
  1413. &AuthPack.pk_authenticator.kdc_realm
  1414. );
  1415. KerbFreePrincipalName(
  1416. &AuthPack.pk_authenticator.kdc_name
  1417. );
  1418. if (ListElement != NULL)
  1419. {
  1420. KerbFree(ListElement);
  1421. }
  1422. if (PackedRequest != NULL)
  1423. {
  1424. MIDL_user_free(PackedRequest);
  1425. }
  1426. if (PackedAuthPack != NULL)
  1427. {
  1428. MIDL_user_free(PackedAuthPack);
  1429. }
  1430. if (SignedAuthPack != NULL)
  1431. {
  1432. MIDL_user_free(SignedAuthPack);
  1433. }
  1434. if ( Impersonating )
  1435. {
  1436. RevertToSelf();
  1437. CloseHandle(ClientTokenHandle);
  1438. }
  1439. if (InitializedPkCreds)
  1440. {
  1441. KerbReleasePkCreds(
  1442. NULL,
  1443. Credentials->PublicKeyCreds
  1444. );
  1445. }
  1446. return(Status);
  1447. }
  1448. //+-------------------------------------------------------------------------
  1449. //
  1450. // Function: KerbCreateSmartCardLogonSessionFromCertContext
  1451. //
  1452. // Synopsis: Creats a logon session from the cert context and passed in
  1453. // data. Retrieves the email name from the certificate.
  1454. //
  1455. // This function is for use with LogonUser when a marshalled
  1456. // smart card cert is passed in the user name and the PIN is
  1457. // passed as the password.
  1458. //
  1459. // Effects:
  1460. //
  1461. // Arguments:
  1462. //
  1463. // Requires:
  1464. //
  1465. // Returns:
  1466. //
  1467. // Notes:
  1468. //
  1469. //
  1470. //--------------------------------------------------------------------------
  1471. NTSTATUS
  1472. KerbCreateSmartCardLogonSessionFromCertContext(
  1473. IN PCERT_CONTEXT *ppCertContext,
  1474. IN PLUID pLogonId,
  1475. IN PUNICODE_STRING pAuthorityName,
  1476. IN PUNICODE_STRING pPin,
  1477. IN PUCHAR pCspData,
  1478. IN ULONG CspDataLength,
  1479. OUT PKERB_LOGON_SESSION *ppLogonSession,
  1480. OUT PUNICODE_STRING pAccountName
  1481. )
  1482. {
  1483. PKERB_LOGON_SESSION pLogonSession = NULL;
  1484. PKERB_PUBLIC_KEY_CREDENTIALS PkCredentials = NULL;
  1485. ULONG cbPkCreds = 0;
  1486. NTSTATUS Status = STATUS_SUCCESS;
  1487. //
  1488. // Get the client name from the cert.
  1489. // Place it in the return location
  1490. //
  1491. Status = KerbGetPrincipalNameFromCertificate(*ppCertContext, pAccountName);
  1492. if (!NT_SUCCESS(Status))
  1493. {
  1494. goto Cleanup;
  1495. }
  1496. //
  1497. // Create a normal logon session. We willa add the public-key information
  1498. // later
  1499. //
  1500. Status = KerbCreateLogonSession(
  1501. pLogonId,
  1502. pAccountName,
  1503. pAuthorityName,
  1504. NULL, // no password
  1505. NULL, // no old password
  1506. 0, // no flags
  1507. Interactive, // logon type
  1508. &pLogonSession
  1509. );
  1510. if (!NT_SUCCESS(Status))
  1511. {
  1512. goto Cleanup;
  1513. }
  1514. //
  1515. // Now create the public key credentials to be put in the logon
  1516. // session.
  1517. //
  1518. cbPkCreds = sizeof(KERB_PUBLIC_KEY_CREDENTIALS);
  1519. if ((NULL != pCspData) && (0 != CspDataLength))
  1520. {
  1521. cbPkCreds += CspDataLength;
  1522. }
  1523. PkCredentials = (PKERB_PUBLIC_KEY_CREDENTIALS) KerbAllocate(cbPkCreds);
  1524. if (PkCredentials == NULL)
  1525. {
  1526. Status = STATUS_INSUFFICIENT_RESOURCES;
  1527. goto Cleanup;
  1528. }
  1529. PkCredentials->CertContext = *ppCertContext;
  1530. *ppCertContext = NULL;
  1531. Status = KerbDuplicateString(
  1532. &PkCredentials->Pin,
  1533. pPin
  1534. );
  1535. if (!NT_SUCCESS(Status))
  1536. {
  1537. goto Cleanup;
  1538. }
  1539. //
  1540. // Copy in the CSP data for later use
  1541. //
  1542. if ((NULL != pCspData) && (0 != CspDataLength))
  1543. {
  1544. PkCredentials->CspDataLength = CspDataLength;
  1545. RtlCopyMemory(
  1546. PkCredentials->CspData,
  1547. pCspData,
  1548. CspDataLength
  1549. );
  1550. PkCredentials->InitializationInfo |= CSP_DATA_INITIALIZED;
  1551. }
  1552. else
  1553. {
  1554. PkCredentials->InitializationInfo |= CSP_DATA_INITIALIZED | CONTEXT_INITIALIZED_WITH_ACH;
  1555. }
  1556. KerbWriteLockLogonSessions(pLogonSession);
  1557. pLogonSession->PrimaryCredentials.PublicKeyCreds = PkCredentials;
  1558. pLogonSession->LogonSessionFlags |= KERB_LOGON_SMARTCARD;
  1559. PkCredentials = NULL;
  1560. KerbUnlockLogonSessions(pLogonSession);
  1561. *ppLogonSession = pLogonSession;
  1562. pLogonSession = NULL;
  1563. Cleanup:
  1564. if (*ppCertContext != NULL)
  1565. {
  1566. CertFreeCertificateContext(*ppCertContext);
  1567. }
  1568. KerbFreePKCreds(PkCredentials);
  1569. if (pLogonSession != NULL)
  1570. {
  1571. KerbReferenceLogonSessionByPointer(pLogonSession, TRUE);
  1572. KerbDereferenceLogonSession(pLogonSession);
  1573. KerbDereferenceLogonSession(pLogonSession);
  1574. }
  1575. return Status;
  1576. }
  1577. //+-------------------------------------------------------------------------
  1578. //
  1579. // Function: KerbMapCertChainError
  1580. //
  1581. // Synopsis: We don't have good winerrors for chaining //
  1582. // Effects:
  1583. //
  1584. // Arguments:
  1585. //
  1586. // Requires:
  1587. //
  1588. // Returns:
  1589. //
  1590. // Notes:
  1591. //
  1592. //
  1593. //--------------------------------------------------------------------------
  1594. NTSTATUS
  1595. KerbMapClientCertChainError(ULONG ChainStatus)
  1596. {
  1597. NTSTATUS Status;
  1598. switch(ChainStatus)
  1599. {
  1600. case CRYPT_E_REVOKED:
  1601. Status = STATUS_SMARTCARD_CERT_REVOKED;
  1602. break;
  1603. case CERT_E_EXPIRED:
  1604. Status = STATUS_SMARTCARD_CERT_EXPIRED;
  1605. break;
  1606. case CERT_E_UNTRUSTEDCA:
  1607. case CERT_E_UNTRUSTEDROOT:
  1608. Status = STATUS_ISSUING_CA_UNTRUSTED;
  1609. break;
  1610. case CRYPT_E_REVOCATION_OFFLINE:
  1611. Status = STATUS_REVOCATION_OFFLINE_C;
  1612. break;
  1613. // W2k or old whistler DC
  1614. case ERROR_NOT_SUPPORTED:
  1615. default:
  1616. Status = STATUS_PKINIT_CLIENT_FAILURE;
  1617. }
  1618. return Status;
  1619. }
  1620. //+-------------------------------------------------------------------------
  1621. //
  1622. // Function: KerbCreateSmardCardLogonSession
  1623. //
  1624. // Synopsis: Creats a logon session from the smart card logon info. It
  1625. // creates a certificate context from the logon information,
  1626. // retrieves the email name from the certificate, and then
  1627. // uses that to create a context.
  1628. //
  1629. // Effects:
  1630. //
  1631. // Arguments:
  1632. //
  1633. // Requires:
  1634. //
  1635. // Returns:
  1636. //
  1637. // Notes:
  1638. //
  1639. //
  1640. //--------------------------------------------------------------------------
  1641. NTSTATUS
  1642. KerbCreateSmartCardLogonSession(
  1643. IN PVOID ProtocolSubmitBuffer,
  1644. IN PVOID ClientBufferBase,
  1645. IN ULONG SubmitBufferSize,
  1646. IN SECURITY_LOGON_TYPE LogonType,
  1647. OUT PKERB_LOGON_SESSION *ReturnedLogonSession,
  1648. OUT PLUID ReturnedLogonId,
  1649. OUT PUNICODE_STRING AccountName,
  1650. OUT PUNICODE_STRING AuthorityName
  1651. )
  1652. {
  1653. PCERT_CONTEXT CertContext = NULL;
  1654. NTSTATUS Status = STATUS_SUCCESS;
  1655. PKERB_SMART_CARD_LOGON LogonInfo = (PKERB_SMART_CARD_LOGON) ProtocolSubmitBuffer;
  1656. LUID LogonId = {0};
  1657. BOOLEAN InitializedContext = FALSE;
  1658. //
  1659. // We were passed a blob of data. First we need to update the pointers
  1660. // to be in this address space
  1661. //
  1662. RELOCATE_ONE(&LogonInfo->Pin);
  1663. LogonInfo->CspData = LogonInfo->CspData - (ULONG_PTR) ClientBufferBase + (ULONG_PTR) LogonInfo;
  1664. //
  1665. // Make sure it all fits in our address space
  1666. //
  1667. if ((LogonInfo->CspDataLength + LogonInfo->CspData) >
  1668. ((PUCHAR) ProtocolSubmitBuffer + SubmitBufferSize))
  1669. {
  1670. Status = STATUS_INVALID_PARAMETER;
  1671. goto Cleanup;
  1672. }
  1673. //
  1674. // First, initialize the crypt context
  1675. //
  1676. Status = __ScHelperInitializeContext(
  1677. LogonInfo->CspData,
  1678. LogonInfo->CspDataLength
  1679. );
  1680. if (!NT_SUCCESS(Status))
  1681. {
  1682. DebugLog((DEB_ERROR,"Failed to initialize context from csp data: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1683. goto Cleanup;
  1684. }
  1685. InitializedContext = TRUE;
  1686. //
  1687. // The first thing to do is to convert the CSP data into a certificate
  1688. // context
  1689. //
  1690. Status = __ScHelperGetCertFromLogonInfo(
  1691. LogonInfo->CspData,
  1692. &LogonInfo->Pin,
  1693. (PCCERT_CONTEXT*)&CertContext
  1694. );
  1695. if (Status != STATUS_SUCCESS)
  1696. {
  1697. DebugLog((DEB_ERROR,"Failed to get cert from logon info: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1698. if (NT_SUCCESS(Status))
  1699. {
  1700. Status = STATUS_LOGON_FAILURE;
  1701. }
  1702. goto Cleanup;
  1703. }
  1704. RtlInitUnicodeString(
  1705. AuthorityName,
  1706. NULL
  1707. );
  1708. //
  1709. // Now we have just about everything to create a logon session
  1710. //
  1711. Status = NtAllocateLocallyUniqueId( &LogonId );
  1712. if (!NT_SUCCESS(Status))
  1713. {
  1714. DebugLog((DEB_ERROR,"Failed to allocate locally unique ID: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1715. goto Cleanup;
  1716. }
  1717. //
  1718. // For win95, if there is a logon session in our list, remove it.
  1719. // This is generated from the logon session dumped in the registry.
  1720. // But, we are about to do a new logon. Get rid of the old logon.
  1721. // If the new one does not succeed, too bad. But, that's by design.
  1722. //
  1723. #ifdef WIN32_CHICAGO
  1724. LsaApLogonTerminated(&LogonId);
  1725. #endif // WIN32_CHICAGO
  1726. Status = KerbCreateSmartCardLogonSessionFromCertContext(
  1727. &CertContext,
  1728. &LogonId,
  1729. AuthorityName,
  1730. &LogonInfo->Pin,
  1731. LogonInfo->CspData,
  1732. LogonInfo->CspDataLength,
  1733. ReturnedLogonSession,
  1734. AccountName
  1735. );
  1736. if (!NT_SUCCESS(Status))
  1737. {
  1738. goto Cleanup;
  1739. }
  1740. LogonInfo->CspDataLength = 0;
  1741. *ReturnedLogonId = LogonId;
  1742. Cleanup:
  1743. if (InitializedContext && LogonInfo->CspDataLength != 0)
  1744. {
  1745. __ScHelperRelease(
  1746. LogonInfo->CspData
  1747. );
  1748. }
  1749. return(Status);
  1750. }
  1751. //+-------------------------------------------------------------------------
  1752. //
  1753. // Function: KerbGetCertificateName
  1754. //
  1755. // Synopsis: Gets a name from a certificate name blob. The name is:
  1756. // subject@issuer
  1757. //
  1758. // Effects:
  1759. //
  1760. // Arguments:
  1761. //
  1762. // Requires:
  1763. //
  1764. // Returns:
  1765. //
  1766. // Notes:
  1767. //
  1768. //
  1769. //--------------------------------------------------------------------------
  1770. NTSTATUS
  1771. KerbGetCertificateName(
  1772. OUT PUNICODE_STRING Name,
  1773. IN PCERT_INFO Certificate
  1774. )
  1775. {
  1776. NTSTATUS Status = STATUS_SUCCESS;
  1777. ULONG IssuerLength;
  1778. ULONG SubjectLength;
  1779. RtlInitUnicodeString(
  1780. Name,
  1781. NULL
  1782. );
  1783. //
  1784. // First find the size of the name. The lengths include the
  1785. // null terminators.
  1786. //
  1787. SubjectLength = CertNameToStr(
  1788. X509_ASN_ENCODING,
  1789. &Certificate->Subject,
  1790. CERT_X500_NAME_STR,
  1791. NULL,
  1792. 0
  1793. );
  1794. if (SubjectLength == 0)
  1795. {
  1796. DebugLog((DEB_ERROR,"Failed to convert name: %0x%x. %ws, line %d\n",GetLastError(), THIS_FILE, __LINE__));
  1797. Status = STATUS_PKINIT_FAILURE;
  1798. goto Cleanup;
  1799. }
  1800. IssuerLength = CertNameToStr(
  1801. X509_ASN_ENCODING,
  1802. &Certificate->Issuer,
  1803. CERT_X500_NAME_STR,
  1804. NULL,
  1805. 0
  1806. );
  1807. if (IssuerLength == 0)
  1808. {
  1809. DebugLog((DEB_ERROR,"Failed to convert name: %0x%x. %ws, line %d\n",GetLastError(), THIS_FILE, __LINE__));
  1810. Status = STATUS_PKINIT_FAILURE;
  1811. goto Cleanup;
  1812. }
  1813. //
  1814. // Remove the null terminator from one name, but leave space for a
  1815. // ":" in the middle
  1816. //
  1817. Name->Buffer = (LPWSTR) KerbAllocate((SubjectLength + IssuerLength) * sizeof(WCHAR));
  1818. if (Name->Buffer == NULL)
  1819. {
  1820. Status = STATUS_INSUFFICIENT_RESOURCES;
  1821. goto Cleanup;
  1822. }
  1823. //
  1824. // Now get the name itself
  1825. //
  1826. SubjectLength = CertNameToStr(
  1827. X509_ASN_ENCODING,
  1828. &Certificate->Subject,
  1829. CERT_X500_NAME_STR,
  1830. Name->Buffer,
  1831. SubjectLength
  1832. );
  1833. if (SubjectLength == 0)
  1834. {
  1835. DebugLog((DEB_ERROR,"Failed to convert name: %0x%x. %ws, line %d\n",GetLastError(), THIS_FILE, __LINE__));
  1836. KerbFree(Name->Buffer);
  1837. Name->Buffer = NULL;
  1838. Status = STATUS_PKINIT_FAILURE;
  1839. goto Cleanup;
  1840. }
  1841. //
  1842. // Put an "@" in the middle so it is recognized by MSV as a UPN (just in case)
  1843. //
  1844. Name->Buffer[SubjectLength-1] = L'@';
  1845. IssuerLength = CertNameToStr(
  1846. X509_ASN_ENCODING,
  1847. &Certificate->Issuer,
  1848. CERT_X500_NAME_STR,
  1849. Name->Buffer + SubjectLength,
  1850. IssuerLength
  1851. );
  1852. if (IssuerLength == 0)
  1853. {
  1854. DebugLog((DEB_ERROR,"Failed to convert name: %0x%x. %ws, line %d\n",GetLastError(), THIS_FILE, __LINE__));
  1855. KerbFree(Name->Buffer);
  1856. Name->Buffer = NULL;
  1857. Status = STATUS_PKINIT_FAILURE;
  1858. goto Cleanup;
  1859. }
  1860. RtlInitUnicodeString(
  1861. Name,
  1862. Name->Buffer
  1863. );
  1864. Cleanup:
  1865. return(Status);
  1866. }
  1867. NTSTATUS
  1868. KerbGetCertificateHash(
  1869. OUT LPBYTE pCertHash,
  1870. IN ULONG cbCertHash,
  1871. IN PCCERT_CONTEXT pCertContext
  1872. )
  1873. {
  1874. ULONG cbHash = cbCertHash;
  1875. if ( CertGetCertificateContextProperty(
  1876. pCertContext,
  1877. CERT_SHA1_HASH_PROP_ID,
  1878. pCertHash,
  1879. &cbHash
  1880. ) == FALSE )
  1881. {
  1882. return( STATUS_PKINIT_FAILURE );
  1883. }
  1884. return( STATUS_SUCCESS );
  1885. }
  1886. //+-------------------------------------------------------------------------
  1887. //
  1888. // Function: KerbLookupSmartCardCachedLogon
  1889. //
  1890. // Synopsis: Looks up a cached smart card logon in the MSV cache
  1891. //
  1892. // Effects:
  1893. //
  1894. // Arguments:
  1895. //
  1896. // Requires:
  1897. //
  1898. // Returns:
  1899. //
  1900. // Notes: Free ValidationInfor with LocalFree
  1901. //
  1902. //
  1903. //--------------------------------------------------------------------------
  1904. BOOLEAN
  1905. KerbLookupSmartCardCachedLogon(
  1906. IN PCCERT_CONTEXT Certificate,
  1907. OUT PNETLOGON_VALIDATION_SAM_INFO4 * ValidationInfo,
  1908. OUT PKERB_MESSAGE_BUFFER SupplementalCreds
  1909. )
  1910. {
  1911. NTSTATUS Status = STATUS_SUCCESS;
  1912. UNICODE_STRING IssuerName = {0};
  1913. PMSV1_0_CACHE_LOOKUP_REQUEST CacheRequest = NULL;
  1914. PMSV1_0_CACHE_LOOKUP_RESPONSE CacheResponse = NULL;
  1915. UNICODE_STRING MsvPackageName = CONSTANT_UNICODE_STRING(TEXT(MSV1_0_PACKAGE_NAME));
  1916. NTSTATUS SubStatus = STATUS_SUCCESS;
  1917. ULONG OutputBufferSize = 0;
  1918. ULONG RequestSize = 0;
  1919. BOOLEAN Result = FALSE;
  1920. SupplementalCreds->BufferSize = 0;
  1921. SupplementalCreds->Buffer = NULL;
  1922. RequestSize = sizeof( MSV1_0_CACHE_LOOKUP_REQUEST ) +
  1923. SHA1DIGESTLEN -
  1924. sizeof( UCHAR );
  1925. CacheRequest = (PMSV1_0_CACHE_LOOKUP_REQUEST) KerbAllocate( RequestSize );
  1926. if ( CacheRequest == NULL )
  1927. {
  1928. return( FALSE );
  1929. }
  1930. *ValidationInfo = NULL;
  1931. //
  1932. // Get the issuer & subject name from the cert. These will be used as
  1933. // user name & domain name for the lookup
  1934. //
  1935. Status = KerbGetCertificateName(
  1936. &IssuerName,
  1937. Certificate->pCertInfo
  1938. );
  1939. if (NT_SUCCESS(Status))
  1940. {
  1941. Status = KerbGetCertificateHash(
  1942. CacheRequest->CredentialSubmitBuffer,
  1943. SHA1DIGESTLEN,
  1944. Certificate
  1945. );
  1946. }
  1947. if (!NT_SUCCESS(Status))
  1948. {
  1949. goto Cleanup;
  1950. }
  1951. CacheRequest->MessageType = MsV1_0CacheLookup;
  1952. CacheRequest->UserName = IssuerName;
  1953. CacheRequest->CredentialType = MSV1_0_CACHE_LOOKUP_CREDTYPE_RAW;
  1954. CacheRequest->CredentialInfoLength = SHA1DIGESTLEN;
  1955. //
  1956. // Leave the domain name portion blank.
  1957. //
  1958. //
  1959. // Call MSV1_0 to do the work
  1960. //
  1961. Status = LsaFunctions->CallPackage(
  1962. &MsvPackageName,
  1963. CacheRequest,
  1964. RequestSize,
  1965. (PVOID *) &CacheResponse,
  1966. &OutputBufferSize,
  1967. &SubStatus
  1968. );
  1969. if (!NT_SUCCESS(Status) || !NT_SUCCESS(SubStatus))
  1970. {
  1971. DebugLog((DEB_ERROR,"Failed to lookup cache credentials: 0x%x, 0x%x. %ws, line %d\n",Status, SubStatus, THIS_FILE, __LINE__));
  1972. goto Cleanup;
  1973. }
  1974. if (OutputBufferSize < sizeof(MSV1_0_CACHE_LOOKUP_RESPONSE))
  1975. {
  1976. DebugLog((DEB_ERROR,"Invalid response from cache lookup - return too small: %d bytes. %ws, line %d\n",
  1977. OutputBufferSize, THIS_FILE, __LINE__ ));
  1978. //
  1979. // Free it here so we don't do too much freeing in the cleanup portion
  1980. //
  1981. //
  1982. // BUG 455634: Do we need to free the internals as well (we do in cleanup)?
  1983. //
  1984. LsaFunctions->FreeReturnBuffer(CacheResponse);
  1985. CacheResponse = NULL;
  1986. goto Cleanup;
  1987. }
  1988. if (CacheResponse->MessageType != MsV1_0CacheLookup)
  1989. {
  1990. DebugLog((DEB_ERROR,"Wrong message type from cache lookup: %d. %ws, line %d\n",
  1991. CacheResponse->MessageType, THIS_FILE, __LINE__ ));
  1992. //
  1993. // Free it here so we don't do too much freeing in the cleanup portion
  1994. //
  1995. //
  1996. // BUG 455634: Do we need to free the internals as well (we do in cleanup)?
  1997. //
  1998. LsaFunctions->FreeReturnBuffer(CacheResponse);
  1999. CacheResponse = NULL;
  2000. goto Cleanup;
  2001. }
  2002. *ValidationInfo = (PNETLOGON_VALIDATION_SAM_INFO4) CacheResponse->ValidationInformation;
  2003. CacheResponse->ValidationInformation = NULL;
  2004. SupplementalCreds->Buffer = (PBYTE) CacheResponse->SupplementalCacheData;
  2005. SupplementalCreds->BufferSize = CacheResponse->SupplementalCacheDataLength;
  2006. CacheResponse->SupplementalCacheData = NULL;
  2007. Result = TRUE;
  2008. Cleanup:
  2009. if (CacheRequest != NULL)
  2010. {
  2011. KerbFree(CacheRequest);
  2012. }
  2013. if (CacheResponse != NULL)
  2014. {
  2015. //
  2016. // At this point we know it was a valid cache response, so we can
  2017. // free the validation info if it is present.
  2018. //
  2019. //
  2020. // BUG 455634: Why do we use LocalFree for the internal stuff?
  2021. //
  2022. if (CacheResponse->ValidationInformation != NULL)
  2023. {
  2024. LocalFree(CacheResponse->ValidationInformation);
  2025. }
  2026. if (CacheResponse->SupplementalCacheData != NULL)
  2027. {
  2028. LocalFree(CacheResponse->SupplementalCacheData);
  2029. }
  2030. LsaFunctions->FreeReturnBuffer(CacheResponse);
  2031. }
  2032. KerbFreeString(&IssuerName);
  2033. return(Result);
  2034. }
  2035. //+-------------------------------------------------------------------------
  2036. //
  2037. // Function: KerbDoLocalSmartCardLogon
  2038. //
  2039. // Synopsis: Performs a local logon with the smart card by validating the
  2040. // card and PIN & then trying to map the name locally
  2041. //
  2042. // Effects:
  2043. //
  2044. // Arguments:
  2045. //
  2046. // Requires:
  2047. //
  2048. // Returns:
  2049. //
  2050. // Notes:
  2051. //
  2052. //
  2053. //--------------------------------------------------------------------------
  2054. NTSTATUS
  2055. KerbDoLocalSmartCardLogon(
  2056. IN PKERB_LOGON_SESSION LogonSession,
  2057. OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
  2058. OUT PVOID *NewTokenInformation,
  2059. OUT PULONG ProfileBufferLength,
  2060. OUT PVOID * ProfileBuffer,
  2061. OUT PSECPKG_PRIMARY_CRED PrimaryCredentials,
  2062. OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY * CachedCredentials,
  2063. IN OUT PNETLOGON_VALIDATION_SAM_INFO4 * Validation4
  2064. )
  2065. {
  2066. NTSTATUS Status = STATUS_SUCCESS;
  2067. #ifndef WIN32_CHICAGO
  2068. PPACTYPE Pac = NULL;
  2069. PPAC_INFO_BUFFER LogonInfo = NULL;
  2070. PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo = NULL;
  2071. PNETLOGON_VALIDATION_SAM_INFO4 MsvValidationInfo = NULL;
  2072. PNETLOGON_VALIDATION_SAM_INFO3 PacValidationInfo = NULL;
  2073. PLSA_TOKEN_INFORMATION_V2 TokenInformation = NULL;
  2074. KERB_MESSAGE_BUFFER SupplementalCreds = {0};
  2075. #endif // !WIN32_CHICAGO
  2076. PKERB_INTERNAL_NAME ClientName = NULL;
  2077. PKERB_PUBLIC_KEY_CREDENTIALS PkCreds;
  2078. PBYTE DecryptedCreds = NULL;
  2079. ULONG DecryptedCredSize = 0;
  2080. *Validation4 = NULL;
  2081. PkCreds = LogonSession->PrimaryCredentials.PublicKeyCreds;
  2082. //
  2083. // First, verify the card. This will verify the certificate as well
  2084. // as verify the PIN & that the ceritifcate matches the private key on
  2085. // the card.
  2086. //
  2087. if ((PkCreds->InitializationInfo & CSP_DATA_INITIALIZED) == 0)
  2088. {
  2089. Status = KerbInitializePkCreds(
  2090. PkCreds
  2091. );
  2092. if (!NT_SUCCESS(Status))
  2093. {
  2094. goto Cleanup;
  2095. }
  2096. }
  2097. //
  2098. // Now build a PAC for the user
  2099. //
  2100. if (!KERB_SUCCESS(KerbConvertStringToKdcName(
  2101. &ClientName,
  2102. &LogonSession->PrimaryCredentials.UserName
  2103. )))
  2104. {
  2105. Status = STATUS_INSUFFICIENT_RESOURCES;
  2106. goto Cleanup;
  2107. }
  2108. #ifndef WIN32_CHICAGO
  2109. //
  2110. // First check for a cached logon entry
  2111. //
  2112. if (KerbLookupSmartCardCachedLogon(
  2113. PkCreds->CertContext,
  2114. &MsvValidationInfo,
  2115. &SupplementalCreds))
  2116. {
  2117. ValidationInfo = (PNETLOGON_VALIDATION_SAM_INFO3) MsvValidationInfo;
  2118. ValidationInfo->UserFlags |= LOGON_CACHED_ACCOUNT;
  2119. //
  2120. // Strip the domain postfix
  2121. //
  2122. if (ValidationInfo->LogonDomainName.Length >= KERB_SCLOGON_DOMAIN_SUFFIX_SIZE)
  2123. {
  2124. ValidationInfo->LogonDomainName.Length -= KERB_SCLOGON_DOMAIN_SUFFIX_SIZE;
  2125. }
  2126. if ((SupplementalCreds.Buffer != NULL) &&
  2127. (SupplementalCreds.BufferSize != 0))
  2128. {
  2129. DecryptedCredSize = SupplementalCreds.BufferSize;
  2130. DecryptedCreds = (PBYTE) MIDL_user_allocate(DecryptedCredSize);
  2131. if (DecryptedCreds == NULL)
  2132. {
  2133. Status = STATUS_INSUFFICIENT_RESOURCES;
  2134. goto Cleanup;
  2135. }
  2136. }
  2137. }
  2138. else
  2139. {
  2140. //
  2141. // Look for a name mapping
  2142. //
  2143. Status = KerbCreatePacForKerbClient(
  2144. &Pac,
  2145. ClientName,
  2146. &LogonSession->PrimaryCredentials.DomainName,
  2147. NULL
  2148. );
  2149. if (!NT_SUCCESS(Status))
  2150. {
  2151. goto Cleanup;
  2152. }
  2153. //
  2154. // Find the SAM validation info
  2155. //
  2156. LogonInfo = PAC_Find(
  2157. Pac,
  2158. PAC_LOGON_INFO,
  2159. NULL
  2160. );
  2161. if (LogonInfo == NULL)
  2162. {
  2163. DebugLog((DEB_ERROR,"Failed to find logon info! %ws, line %d\n", THIS_FILE, __LINE__));
  2164. Status = STATUS_INVALID_PARAMETER;
  2165. goto Cleanup;
  2166. }
  2167. //
  2168. // Now unmarshall the validation info
  2169. //
  2170. Status = PAC_UnmarshallValidationInfo(
  2171. &PacValidationInfo,
  2172. LogonInfo->Data,
  2173. LogonInfo->cbBufferSize
  2174. );
  2175. if (!NT_SUCCESS(Status))
  2176. {
  2177. DebugLog((DEB_ERROR,"Failed to unmarshall validation info: 0x%x. %ws, line %d\n",
  2178. Status, THIS_FILE, __LINE__));
  2179. goto Cleanup;
  2180. }
  2181. ValidationInfo = PacValidationInfo;
  2182. }
  2183. Status = __ScHelperVerifyCardAndCreds(
  2184. &PkCreds->Pin,
  2185. PkCreds->CertContext,
  2186. PkCreds->CspData,
  2187. SupplementalCreds.Buffer,
  2188. SupplementalCreds.BufferSize,
  2189. DecryptedCreds,
  2190. &DecryptedCredSize
  2191. );
  2192. if (!NT_SUCCESS(Status))
  2193. {
  2194. DebugLog((DEB_ERROR,"Failed to verify card: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2195. goto Cleanup;
  2196. }
  2197. //
  2198. // If we have any encrypted credentials, decode them here for return.
  2199. //
  2200. if (DecryptedCredSize != 0)
  2201. {
  2202. Status = PAC_UnmarshallCredentials(
  2203. CachedCredentials,
  2204. DecryptedCreds,
  2205. DecryptedCredSize
  2206. );
  2207. if (!NT_SUCCESS(Status))
  2208. {
  2209. goto Cleanup;
  2210. }
  2211. }
  2212. //
  2213. // Check to see if this is a non-user account. If so, don't allow the logon
  2214. //
  2215. if ((ValidationInfo->ExpansionRoom[SAMINFO_USER_ACCOUNT_CONTROL] & USER_MACHINE_ACCOUNT_MASK) != 0)
  2216. {
  2217. DebugLog((DEB_ERROR,"Logons to non-user accounts not allowed. UserAccountControl = 0x%x\n",
  2218. ValidationInfo->ExpansionRoom[SAMINFO_USER_ACCOUNT_CONTROL] ));
  2219. Status = STATUS_LOGON_TYPE_NOT_GRANTED;
  2220. goto Cleanup;
  2221. }
  2222. //
  2223. // Now we need to build a LSA_TOKEN_INFORMATION_V2 from the validation
  2224. // information
  2225. //
  2226. Status = KerbMakeTokenInformationV2(
  2227. ValidationInfo,
  2228. FALSE, // not local system
  2229. &TokenInformation
  2230. );
  2231. if (!NT_SUCCESS(Status))
  2232. {
  2233. DebugLog((DEB_ERROR,"Failed to make token informatin v2: 0x%x\n",
  2234. Status));
  2235. goto Cleanup;
  2236. }
  2237. //
  2238. // Allocate the client profile
  2239. //
  2240. Status = KerbAllocateInteractiveProfile(
  2241. (PKERB_INTERACTIVE_PROFILE *) ProfileBuffer,
  2242. ProfileBufferLength,
  2243. ValidationInfo,
  2244. LogonSession,
  2245. NULL,
  2246. NULL
  2247. );
  2248. if (!KERB_SUCCESS(Status))
  2249. {
  2250. goto Cleanup;
  2251. }
  2252. //
  2253. // Build the primary credential. We let someone else fill in the
  2254. // password.
  2255. //
  2256. PrimaryCredentials->LogonId = LogonSession->LogonId;
  2257. Status = KerbDuplicateString(
  2258. &PrimaryCredentials->DownlevelName,
  2259. &ValidationInfo->EffectiveName
  2260. );
  2261. if (!NT_SUCCESS(Status))
  2262. {
  2263. goto Cleanup;
  2264. }
  2265. Status = KerbDuplicateString(
  2266. &PrimaryCredentials->DomainName,
  2267. &ValidationInfo->LogonDomainName
  2268. );
  2269. if (!NT_SUCCESS(Status))
  2270. {
  2271. goto Cleanup;
  2272. }
  2273. Status = KerbDuplicateSid(
  2274. &PrimaryCredentials->UserSid,
  2275. TokenInformation->User.User.Sid
  2276. );
  2277. if (!NT_SUCCESS(Status))
  2278. {
  2279. goto Cleanup;
  2280. }
  2281. PrimaryCredentials->Flags = 0;
  2282. *Validation4 = MsvValidationInfo;
  2283. MsvValidationInfo = NULL;
  2284. *NewTokenInformation = TokenInformation;
  2285. *TokenInformationType = LsaTokenInformationV2;
  2286. #endif // !WIN32_CHICAGO
  2287. Cleanup:
  2288. if (PacValidationInfo != NULL)
  2289. {
  2290. MIDL_user_free(PacValidationInfo);
  2291. }
  2292. KerbFreeKdcName(
  2293. &ClientName
  2294. );
  2295. if (MsvValidationInfo != NULL)
  2296. {
  2297. LocalFree(MsvValidationInfo);
  2298. }
  2299. if (SupplementalCreds.Buffer != NULL)
  2300. {
  2301. //
  2302. // BUG 455634: this should be freed a better way
  2303. //
  2304. LocalFree(SupplementalCreds.Buffer);
  2305. }
  2306. #ifndef WIN32_CHICAGO
  2307. if (Pac != NULL)
  2308. {
  2309. MIDL_user_free(Pac);
  2310. }
  2311. if (!NT_SUCCESS(Status))
  2312. {
  2313. if (TokenInformation != NULL)
  2314. {
  2315. KerbFree( TokenInformation );
  2316. }
  2317. if (*ProfileBuffer != NULL)
  2318. {
  2319. LsaFunctions->FreeClientBuffer(NULL, *ProfileBuffer);
  2320. *ProfileBuffer = NULL;
  2321. }
  2322. KerbFreeString(
  2323. &PrimaryCredentials->DownlevelName
  2324. );
  2325. KerbFreeString(
  2326. &PrimaryCredentials->DomainName
  2327. );
  2328. if (PrimaryCredentials->UserSid != NULL)
  2329. {
  2330. KerbFree(PrimaryCredentials->UserSid);
  2331. PrimaryCredentials->UserSid = NULL;
  2332. }
  2333. }
  2334. #endif // WIN32_CHICAGO
  2335. return(Status);
  2336. }
  2337. //+-------------------------------------------------------------------------
  2338. //
  2339. // Function: KerbCacheSmartCardLogon
  2340. //
  2341. // Synopsis:
  2342. //
  2343. // Effects:
  2344. //
  2345. // Arguments:
  2346. //
  2347. // Requires:
  2348. //
  2349. // Returns:
  2350. //
  2351. // Notes:
  2352. //
  2353. //
  2354. //--------------------------------------------------------------------------
  2355. VOID
  2356. KerbCacheSmartCardLogon(
  2357. IN PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo,
  2358. IN OPTIONAL PUNICODE_STRING DnsDomainName,
  2359. IN OPTIONAL PUNICODE_STRING UPN,
  2360. IN PKERB_LOGON_SESSION LogonSession,
  2361. IN OPTIONAL PSECPKG_SUPPLEMENTAL_CRED_ARRAY CachedCredentials
  2362. )
  2363. {
  2364. NTSTATUS Status;
  2365. UNICODE_STRING IssuerName = {0};
  2366. UNICODE_STRING DomainName = {0};
  2367. UNICODE_STRING TempLogonDomainName = {0};
  2368. UNICODE_STRING LogonDomainName = {0};
  2369. BYTE CertificateHash[ SHA1DIGESTLEN ];
  2370. UNICODE_STRING CertificateHashString;
  2371. ULONG EncodedCredSize = 0;
  2372. PBYTE EncodedCreds = NULL;
  2373. ULONG EncryptedCredSize = 0;
  2374. PBYTE EncryptedCreds = NULL;
  2375. BOOLEAN LogonSessionLocked = FALSE;
  2376. BOOLEAN InitializedPkCreds = FALSE;
  2377. //
  2378. // Build the temporary logon domain name that indicates this is a
  2379. // smart card logon.
  2380. //
  2381. TempLogonDomainName.MaximumLength =
  2382. TempLogonDomainName.Length =
  2383. ValidationInfo->LogonDomainName.Length + KERB_SCLOGON_DOMAIN_SUFFIX_SIZE;
  2384. TempLogonDomainName.Buffer = (LPWSTR) MIDL_user_allocate(TempLogonDomainName.Length);
  2385. if (TempLogonDomainName.Buffer == NULL)
  2386. {
  2387. goto Cleanup;
  2388. }
  2389. //
  2390. // Create the new name
  2391. //
  2392. RtlCopyMemory(
  2393. TempLogonDomainName.Buffer,
  2394. ValidationInfo->LogonDomainName.Buffer,
  2395. ValidationInfo->LogonDomainName.Length
  2396. );
  2397. RtlCopyMemory(
  2398. ((PUCHAR) TempLogonDomainName.Buffer) + ValidationInfo->LogonDomainName.Length,
  2399. KERB_SCLOGON_DOMAIN_SUFFIX,
  2400. KERB_SCLOGON_DOMAIN_SUFFIX_SIZE
  2401. );
  2402. LogonDomainName = ValidationInfo->LogonDomainName;
  2403. ValidationInfo->LogonDomainName = TempLogonDomainName;
  2404. //
  2405. // Get the name under which to store this.
  2406. //
  2407. KerbReadLockLogonSessions(LogonSession);
  2408. LogonSessionLocked = TRUE;
  2409. Status = KerbGetCertificateName(
  2410. &IssuerName,
  2411. LogonSession->PrimaryCredentials.PublicKeyCreds->CertContext->pCertInfo
  2412. );
  2413. if ( Status == STATUS_SUCCESS )
  2414. {
  2415. Status = KerbGetCertificateHash(
  2416. CertificateHash,
  2417. SHA1DIGESTLEN,
  2418. LogonSession->PrimaryCredentials.PublicKeyCreds->CertContext
  2419. );
  2420. }
  2421. if (!NT_SUCCESS(Status))
  2422. {
  2423. goto Cleanup;
  2424. }
  2425. CertificateHashString.Length = SHA1DIGESTLEN;
  2426. CertificateHashString.Buffer = (LPWSTR)CertificateHash;
  2427. CertificateHashString.MaximumLength = SHA1DIGESTLEN;
  2428. if (ARGUMENT_PRESENT(CachedCredentials))
  2429. {
  2430. ScHelper_RandomCredBits RandomBits;
  2431. Status = PAC_EncodeCredentialData(
  2432. CachedCredentials,
  2433. &EncodedCreds,
  2434. &EncodedCredSize
  2435. );
  2436. if (!NT_SUCCESS(Status))
  2437. {
  2438. goto Cleanup;
  2439. }
  2440. if ((LogonSession->PrimaryCredentials.PublicKeyCreds->InitializationInfo & CSP_DATA_INITIALIZED) == 0)
  2441. {
  2442. Status = KerbInitializePkCreds(
  2443. LogonSession->PrimaryCredentials.PublicKeyCreds
  2444. );
  2445. if (!NT_SUCCESS(Status))
  2446. {
  2447. goto Cleanup;
  2448. }
  2449. InitializedPkCreds = TRUE;
  2450. }
  2451. Status = __ScHelperGenRandBits(
  2452. LogonSession->PrimaryCredentials.PublicKeyCreds->CspData,
  2453. &RandomBits
  2454. );
  2455. if (!NT_SUCCESS(Status))
  2456. {
  2457. DebugLog((DEB_ERROR,"Failed to generate random bits: 0x%x\n",Status));
  2458. goto Cleanup;
  2459. }
  2460. Status = __ScHelperEncryptCredentials(
  2461. &LogonSession->PrimaryCredentials.PublicKeyCreds->Pin,
  2462. LogonSession->PrimaryCredentials.PublicKeyCreds->CertContext,
  2463. &RandomBits,
  2464. LogonSession->PrimaryCredentials.PublicKeyCreds->CspData,
  2465. EncodedCreds,
  2466. EncodedCredSize,
  2467. NULL,
  2468. &EncryptedCredSize
  2469. );
  2470. if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL))
  2471. {
  2472. DebugLog((DEB_ERROR,"Failed to encrypt creds: 0x%x\n",Status));
  2473. goto Cleanup;
  2474. }
  2475. EncryptedCreds = (PBYTE) KerbAllocate(EncryptedCredSize);
  2476. if (EncryptedCreds == NULL)
  2477. {
  2478. Status = STATUS_INSUFFICIENT_RESOURCES;
  2479. goto Cleanup;
  2480. }
  2481. //
  2482. // Do the real encryption
  2483. //
  2484. Status = __ScHelperEncryptCredentials(
  2485. &LogonSession->PrimaryCredentials.PublicKeyCreds->Pin,
  2486. LogonSession->PrimaryCredentials.PublicKeyCreds->CertContext,
  2487. &RandomBits,
  2488. LogonSession->PrimaryCredentials.PublicKeyCreds->CspData,
  2489. EncodedCreds,
  2490. EncodedCredSize,
  2491. EncryptedCreds,
  2492. &EncryptedCredSize
  2493. );
  2494. if (Status != STATUS_SUCCESS)
  2495. {
  2496. DebugLog((DEB_ERROR,"Failed to encrypt creds: 0x%x\n",Status));
  2497. goto Cleanup;
  2498. }
  2499. }
  2500. KerbUnlockLogonSessions(LogonSession);
  2501. LogonSessionLocked = FALSE;
  2502. KerbCacheLogonInformation(
  2503. &IssuerName, // used as username
  2504. &DomainName, // blank - no domain
  2505. &CertificateHashString, // password is certificate hash,
  2506. DnsDomainName,
  2507. NULL, //UPN,
  2508. FALSE,
  2509. 0, // no flags
  2510. ValidationInfo,
  2511. EncryptedCreds,
  2512. EncryptedCredSize
  2513. );
  2514. Cleanup:
  2515. if (InitializedPkCreds)
  2516. {
  2517. KerbFreePKCreds(
  2518. LogonSession->PrimaryCredentials.PublicKeyCreds
  2519. );
  2520. }
  2521. if (LogonSessionLocked)
  2522. {
  2523. KerbUnlockLogonSessions(LogonSession);
  2524. }
  2525. KerbFreeString(&IssuerName);
  2526. KerbFreeString(&TempLogonDomainName);
  2527. //
  2528. // Restore the original logon domain name
  2529. //
  2530. if (LogonDomainName.Buffer != NULL)
  2531. {
  2532. ValidationInfo->LogonDomainName = LogonDomainName;
  2533. }
  2534. if (EncodedCreds != NULL)
  2535. {
  2536. MIDL_user_free(EncodedCreds);
  2537. }
  2538. }
  2539. //+-------------------------------------------------------------------------
  2540. //
  2541. // Function: KerbInitializePkinit
  2542. //
  2543. // Synopsis: Inializes structures needed for PKINIT
  2544. //
  2545. // Effects:
  2546. //
  2547. // Arguments:
  2548. //
  2549. // Requires:
  2550. //
  2551. // Returns:
  2552. //
  2553. // Notes:
  2554. //
  2555. //
  2556. //--------------------------------------------------------------------------
  2557. NTSTATUS
  2558. KerbInitializePkinit(
  2559. VOID
  2560. )
  2561. {
  2562. ULONG Index;
  2563. LPSTR StringCopy = NULL, TempString = NULL,EndPtr = NULL;
  2564. //
  2565. // Initialize the object IDs
  2566. //
  2567. Index = 0;
  2568. StringCopy = (LPSTR) KerbAllocate((ULONG) strlen(KERB_PKINIT_SIGNATURE_OID)+1);
  2569. if (StringCopy == NULL)
  2570. {
  2571. return( STATUS_INSUFFICIENT_RESOURCES);
  2572. }
  2573. //
  2574. // Scan the string for every '.' separated number
  2575. //
  2576. strcpy(
  2577. StringCopy,
  2578. KERB_PKINIT_SIGNATURE_OID
  2579. );
  2580. TempString = StringCopy;
  2581. EndPtr = TempString;
  2582. while (TempString != NULL)
  2583. {
  2584. ULONG Temp;
  2585. while (*EndPtr != '\0' && *EndPtr != '.')
  2586. {
  2587. EndPtr++;
  2588. }
  2589. if (*EndPtr == '.')
  2590. {
  2591. *EndPtr = '\0';
  2592. EndPtr++;
  2593. }
  2594. else
  2595. {
  2596. EndPtr = NULL;
  2597. }
  2598. if (0 == sscanf(TempString,"%u",&Temp))
  2599. {
  2600. return STATUS_INSUFFICIENT_RESOURCES;
  2601. }
  2602. KerbSignatureAlg[Index].value = (USHORT) Temp;
  2603. KerbSignatureAlg[Index].next = &KerbSignatureAlg[Index+1];
  2604. Index++;
  2605. TempString = EndPtr;
  2606. }
  2607. DsysAssert(Index != 0);
  2608. KerbSignatureAlg[Index-1].next = NULL;
  2609. KerbFree(StringCopy);
  2610. TempString = NULL;
  2611. return(STATUS_SUCCESS);
  2612. }