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

10029 lines
326 KiB

  1. /*
  2. Copyright (c) 1997, Microsoft Corporation, all rights reserved
  3. Description:
  4. PPP EAP TLS Authentication Protocol. Based on RFC xxxx.
  5. History:
  6. Oct 9, 1997: Vijay Baliga created original version.
  7. Notes:
  8. Server Client
  9. [Initial] [Initial]
  10. TLS Start
  11. [SentStart] ------------------>
  12. TLS client_hello
  13. <------------------ [SentHello]
  14. TLS server_hello
  15. TLS certificate
  16. TLS server_key_exchange
  17. TLS server_hello_done
  18. [SentHello] ------------------>
  19. TLS certificate
  20. TLS client_key_exchange
  21. TLS change_cipher_spec
  22. TLS finished
  23. <------------------ [SentFinished]
  24. TLS change_cipher_spec
  25. TLS finished
  26. [SentFinished] ------------------>
  27. NULL/TLS Alert
  28. <------------------ [RecdFinished]
  29. Success/Failure
  30. [SentResult] ------------------>
  31. [RecdResult]
  32. */
  33. #include <nt.h> // Required by windows.h
  34. #include <ntrtl.h> // Required by windows.h
  35. #include <nturtl.h> // Required by windows.h
  36. #include <windows.h> // Win32 base API's
  37. #include <shlwapi.h>
  38. #include <schannel.h>
  39. #include <rtutils.h> // For RTASSERT, TraceVprintfEx
  40. #include <issperr.h> // For SEC_E_OK
  41. #include <wintrust.h> // For WINTRUST_DATA
  42. #include <lmcons.h> // For UNLEN
  43. #include <rasauth.h> // Required by raseapif.h
  44. #include <raseapif.h> // For EAPCODE_Request
  45. #include <raserror.h> // For ERROR_PPP_INVALID_PACKET
  46. #include <mprlog.h> // For ROUTERLOG_CANT_GET_SERVER_CRED
  47. #include <stdio.h> // For sprintf
  48. #include <resource.h> // For IDS_CANT_VALIDATE_SERVER_TEXT
  49. #include <eaptypeid.h>
  50. #define SECURITY_WIN32
  51. #include <security.h> // For GetUserNameExA, CredHandle
  52. #define INCL_HOSTWIRE
  53. #define INCL_RASAUTHATTRIBUTES
  54. #include <ppputil.h> // For HostToWireFormat16, RasAuthAttributeInsert
  55. #define ALLOC_EAPTLS_GLOBALS
  56. #include <eaptls.h>
  57. //
  58. // Internal functions
  59. //
  60. void FreeCachedCredentials(EAPTLSCB * pEapTlsCb);
  61. void SetCachedCredentials (EAPTLSCB * pEapTlsCb);
  62. DWORD PeapCheckCookie ( PPEAPCB pPeapCb,
  63. PEAP_COOKIE *pCookie,
  64. DWORD cbCookie
  65. );
  66. DWORD PeapCreateCookie ( PPEAPCB pPeapCb,
  67. PBYTE * ppbCookie,
  68. DWORD * pcbCookie
  69. );
  70. DWORD PeapGetCredentials(
  71. IN VOID * pWorkBuf,
  72. OUT VOID ** ppCredentials);
  73. DWORD
  74. GetCredentialsFromUserProperties(
  75. EAPTLSCB *pUserProp,
  76. VOID **ppCredentials);
  77. DWORD CreatePEAPTLVStatusMessage ( PPEAPCB pPeapCb,
  78. PPP_EAP_PACKET * pPacket,
  79. DWORD cbPacket,
  80. BOOL fRequest,
  81. WORD wValue //Success or Failure
  82. );
  83. DWORD GetPEAPTLVStatusMessageValue ( PPEAPCB pPeapCb,
  84. PPP_EAP_PACKET * pPacket,
  85. WORD * pwValue
  86. );
  87. DWORD CreatePEAPTLVNAKMessage ( PPEAPCB pPeapCb,
  88. PPP_EAP_PACKET * pPacket,
  89. DWORD cbPacket
  90. );
  91. DWORD
  92. CreateOIDAttributes (
  93. IN EAPTLSCB * pEapTlsCb,
  94. PCERT_ENHKEY_USAGE pUsage,
  95. PCCERT_CHAIN_CONTEXT pCCertChainContext);
  96. BOOL fIsPEAPTLVMessage ( PPEAPCB pPeapCb,
  97. PPP_EAP_PACKET * pPacket
  98. );
  99. extern const DWORD g_adwHelp[];
  100. VOID
  101. ContextHelp(
  102. IN const DWORD* padwMap,
  103. IN HWND hWndDlg,
  104. IN UINT unMsg,
  105. IN WPARAM wParam,
  106. IN LPARAM lParam
  107. );
  108. /*
  109. Notes:
  110. g_szEapTlsCodeName[0..MAXEAPCODE] contains the names of the various
  111. EAP codes.
  112. */
  113. static CHAR* g_szEapTlsCodeName[] =
  114. {
  115. "Unknown",
  116. "Request",
  117. "Response",
  118. "Success",
  119. "Failure",
  120. };
  121. /*
  122. Notes:
  123. To protect us from denial of service attacks.
  124. */
  125. /*
  126. Notes:
  127. Configurable via registry values.
  128. */
  129. #define DEFAULT_MAX_BLOB_SIzE 0x4000
  130. DWORD g_dwMaxBlobSize = DEFAULT_MAX_BLOB_SIzE;
  131. //
  132. // Globals for peap test hook
  133. //
  134. #ifdef DBG
  135. HMODULE g_hTestHook = NULL;
  136. FARPROC TestHookPacketFromPeer = NULL;
  137. FARPROC TestHookPacketToPeer = NULL;
  138. FARPROC TestHookPacketFree = NULL;
  139. BOOL g_fHookInitialized = FALSE;
  140. #endif
  141. //
  142. // General globals
  143. //
  144. //
  145. BOOL g_fIgnoreNoRevocationCheck = FALSE;
  146. BOOL g_fIgnoreRevocationOffline = FALSE;
  147. BOOL g_fNoRootRevocationCheck = TRUE;
  148. BOOL g_fNoRevocationCheck = FALSE;
  149. //
  150. // Auth Type Used.
  151. //
  152. //EAPTLS
  153. #define EAPTLS_CACHEDCRED_FLAG_EAPTLS 0x00000001
  154. //PEAP
  155. #define EAPTLS_CACHEDCRED_FLAG_PEAP 0x00000002
  156. //EAPTLS_WITHIN_PEAP
  157. #define EAPTLS_CACHEDCRED_FLAG_PEAP_EAPTLS 0x00000004
  158. //
  159. // Wireless Specific
  160. //
  161. #define EAPTLS_CACHEDCRED_FLAG_8021x 0x00000008
  162. //
  163. // Server Side Flags.
  164. //
  165. #define EAPTLS_CACHEDCRED_FLAG_SERVER 0x00000010
  166. //
  167. // Using default creds.
  168. //
  169. #define EAPTLS_CACHEDCRED_FLAG_DEFAULT_CRED 0x00000020
  170. BOOL g_fCriticalSectionInitialized = FALSE;
  171. CRITICAL_SECTION g_csProtectCachedCredentials;
  172. //
  173. // Note: This list is not inherently protected.
  174. // the user of this list needs to protect this list.
  175. //
  176. typedef struct _EAPTLS_CACHED_CREDS
  177. {
  178. struct _EAPTLS_CACHED_CREDS * pNext;
  179. EAPTLS_HASH Hash; //Current hash
  180. DWORD dwCredFlags;
  181. CredHandle hCachedCredential;
  182. PCCERT_CONTEXT pcCachedCertContext;
  183. HCRYPTPROV hCachedProv;
  184. LUID AuthenticatedSessionLUID; //Session Id LUID
  185. //for a logged on user
  186. //used only on client
  187. } EAPTLS_CACHED_CREDS;
  188. //
  189. // List of cached credentials.
  190. //
  191. EAPTLS_CACHED_CREDS * g_pCachedCreds = NULL;
  192. //Peap Globals
  193. PPEAP_EAP_INFO g_pEapInfo = NULL;
  194. HANDLE g_hStoreChangeNotificationEvt = NULL;
  195. HANDLE g_hWaitonStoreChangeEvt = NULL;
  196. HCERTSTORE g_hLocalMachineStore = NULL;
  197. BOOL g_fChangeNotificationSetup = FALSE;
  198. DWORD RemoveNodeFromCachedCredList ( EAPTLS_CACHED_CREDS * pNode );
  199. /*
  200. *
  201. * Utility functions around the cached cred list.
  202. *
  203. *
  204. */
  205. VOID CALLBACK MachineStoreChangeNotification(
  206. PVOID lpParameter, // thread data
  207. BOOLEAN TimerOrWaitFired // reason
  208. )
  209. {
  210. EAPTLS_CACHED_CREDS * pNode = NULL;
  211. PCCERT_CONTEXT pCert = NULL;
  212. CRYPT_HASH_BLOB crypt_hash;
  213. DWORD cbData = sizeof(DWORD);
  214. //
  215. // There was a change in local machine store.
  216. // We dont have to check for TimerOrWaitFired
  217. // because the timeout is INFINITE.
  218. //
  219. EapTlsTrace ("MachineStoreChangeNotification");
  220. //
  221. //
  222. // Check to see if our cache is in sync.
  223. //
  224. //
  225. EnterCriticalSection ( &g_csProtectCachedCredentials );
  226. if(!CertControlStore(
  227. g_hLocalMachineStore,
  228. 0,
  229. CERT_STORE_CTRL_RESYNC,
  230. &g_hStoreChangeNotificationEvt)
  231. )
  232. {
  233. EapTlsTrace ("CertControlStore failed with error. 0x%x", GetLastError() );
  234. }
  235. else
  236. {
  237. pNode = g_pCachedCreds;
  238. //
  239. // For each item in our cached cred list, check to see
  240. // if we have the corresponding item in the cert storen
  241. // If we do have the item, check to see if that item has
  242. // been renewed. If it has been renewed, update the
  243. // hash in out cached cred list
  244. //
  245. //Check this out later.
  246. while ( pNode )
  247. {
  248. crypt_hash.cbData = pNode->Hash.cbHash;
  249. crypt_hash.pbData = pNode->Hash.pbHash;
  250. pCert = CertFindCertificateInStore(g_hLocalMachineStore,
  251. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  252. 0, CERT_FIND_HASH, (LPVOID)&crypt_hash, NULL);
  253. if ( !pCert )
  254. {
  255. //
  256. // We did not find the cert. So set the node as
  257. // unusable. And eventually delete it.
  258. //
  259. EapTlsTrace ("Configured Certificate is not in store. deleting the cached cred from list");
  260. RemoveNodeFromCachedCredList ( pNode );
  261. //Start over
  262. pNode = g_pCachedCreds;
  263. }
  264. else
  265. {
  266. //
  267. // Check to see if the cert has been archived
  268. //
  269. if(CertGetCertificateContextProperty(pCert,
  270. CERT_ARCHIVED_PROP_ID,
  271. NULL,
  272. &cbData ))
  273. {
  274. //
  275. // Certificate has been renewed.
  276. // Remove it from our cached cred list
  277. EapTlsTrace ("Configured Certificate is archived most likely because of renewal. deleting the cached cred from list");
  278. RemoveNodeFromCachedCredList ( pNode );
  279. pNode = g_pCachedCreds;
  280. }
  281. else
  282. {
  283. pNode = pNode->pNext;
  284. }
  285. CertFreeCertificateContext(pCert);
  286. pCert = NULL;
  287. }
  288. }
  289. }
  290. LeaveCriticalSection ( &g_csProtectCachedCredentials );
  291. }
  292. DWORD GetNewCachedCredListNode( EAPTLS_CACHED_CREDS ** ppNode )
  293. {
  294. DWORD dwRetCode = NO_ERROR;
  295. EapTlsTrace ( "GetNewCachedCredListNode");
  296. *ppNode =
  297. (EAPTLS_CACHED_CREDS *)LocalAlloc ( LPTR, sizeof(EAPTLS_CACHED_CREDS) );
  298. if ( NULL == *ppNode )
  299. {
  300. EapTlsTrace("Error allocating memory for cached cred node.");
  301. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  302. }
  303. (*ppNode)->pNext = NULL;
  304. return dwRetCode;
  305. }
  306. DWORD FreeCachedCredListNode ( EAPTLS_CACHED_CREDS * pNode )
  307. {
  308. DWORD dwRetCode = NO_ERROR;
  309. //
  310. // Free the cert context etc.
  311. //
  312. LocalFree ( pNode );
  313. pNode = NULL;
  314. return dwRetCode;
  315. }
  316. VOID ClearCachedCredList ()
  317. {
  318. EAPTLS_CACHED_CREDS * pCurNode = g_pCachedCreds;
  319. EapTlsTrace("RemoveNodeFromCachedCredList.");
  320. while ( pCurNode )
  321. {
  322. RemoveNodeFromCachedCredList ( pCurNode );
  323. pCurNode = g_pCachedCreds;
  324. }
  325. }
  326. //
  327. // Remove node from cached cred list. This is used on the
  328. // client side if auth fails.
  329. //
  330. DWORD RemoveNodeFromCachedCredList ( EAPTLS_CACHED_CREDS * pNode )
  331. {
  332. DWORD dwRetCode = NO_ERROR;
  333. SECURITY_STATUS Status;
  334. EAPTLS_CACHED_CREDS * pCurNode = g_pCachedCreds;
  335. EAPTLS_CACHED_CREDS * pPrevNode = NULL;
  336. EapTlsTrace("RemoveNodeFromCachedCredList.");
  337. //
  338. //Iterate the list and remove node.
  339. //
  340. while ( pCurNode )
  341. {
  342. if ( pCurNode == pNode )
  343. {
  344. //
  345. // Free all the stuff in the
  346. // node.
  347. //
  348. Status = FreeCredentialsHandle(&(pNode->hCachedCredential));
  349. if (SEC_E_OK != Status)
  350. {
  351. EapTlsTrace("FreeCredentialsHandle failed and returned 0x%x",
  352. Status);
  353. }
  354. if ( pNode->hCachedProv )
  355. {
  356. CryptReleaseContext(pNode->hCachedProv, 0);
  357. }
  358. if ( pNode->pcCachedCertContext )
  359. {
  360. CertFreeCertificateContext ( pNode->pcCachedCertContext );
  361. pNode->pcCachedCertContext = NULL;
  362. }
  363. if ( pPrevNode == NULL)
  364. {
  365. //
  366. //This is the head node being deleted
  367. //
  368. g_pCachedCreds = pCurNode->pNext;
  369. }
  370. else
  371. {
  372. pPrevNode->pNext = pCurNode->pNext;
  373. }
  374. FreeCachedCredListNode ( pNode );
  375. break;
  376. }
  377. pPrevNode = pCurNode;
  378. pCurNode = pCurNode->pNext;
  379. }
  380. return dwRetCode;
  381. }
  382. //
  383. // Find node in the cached cred list based on the control block.
  384. //
  385. EAPTLS_CACHED_CREDS * FindNodeInCachedCredList
  386. (
  387. EAPTLSCB * pEapTlsCb,
  388. BOOL fDefaultCachedCreds,
  389. BOOL fCheckThreadToken //We dont check thread token in case
  390. //of wiping out cached creds
  391. )
  392. {
  393. EAPTLS_CACHED_CREDS * pNode = g_pCachedCreds;
  394. DWORD dwFlags = 0;
  395. TOKEN_STATISTICS TokenStats;
  396. DWORD TokenStatsSize = 0;
  397. HANDLE CurrentThreadToken = NULL;
  398. BOOL fNodeFound = FALSE;
  399. if ( EAPTLSCB_FLAG_LOGON & pEapTlsCb->fFlags )
  400. {
  401. //
  402. // No cached credentials in case of winlogon scenario.
  403. // There are security implications. We can do this
  404. // iff we have a way to track logon/logoff which we
  405. // dont.
  406. //
  407. EapTlsTrace("Winlogon case. No cached credentials.");
  408. pNode = NULL;
  409. goto done;
  410. }
  411. // Create the Search flags
  412. dwFlags |= ( (pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER ) ?
  413. EAPTLS_CACHEDCRED_FLAG_SERVER :
  414. 0
  415. );
  416. dwFlags |= ( (pEapTlsCb->fFlags & EAPTLSCB_FLAG_8021X_AUTH )?
  417. EAPTLS_CACHEDCRED_FLAG_8021x:
  418. 0
  419. );
  420. dwFlags |= ( (pEapTlsCb->fFlags & EAPTLSCB_FLAG_USING_DEFAULT_CREDS)?
  421. EAPTLS_CACHEDCRED_FLAG_DEFAULT_CRED:
  422. 0
  423. );
  424. if ( (pEapTlsCb->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP ) )
  425. {
  426. dwFlags |= EAPTLS_CACHEDCRED_FLAG_PEAP;
  427. }
  428. else if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_HOSTED_INSIDE_PEAP )
  429. {
  430. dwFlags |= EAPTLS_CACHEDCRED_FLAG_PEAP_EAPTLS;
  431. }
  432. else
  433. {
  434. dwFlags |= EAPTLS_CACHEDCRED_FLAG_EAPTLS;
  435. }
  436. while ( pNode )
  437. {
  438. //
  439. // Check to see the following The hash of the
  440. //
  441. if ( fDefaultCachedCreds )
  442. {
  443. //
  444. // We dont have the hash in this case
  445. //
  446. dwFlags |= EAPTLS_CACHEDCRED_FLAG_DEFAULT_CRED;
  447. if ( pNode->dwCredFlags == dwFlags &&
  448. pEapTlsCb->pUserProp &&
  449. pNode->pcCachedCertContext
  450. )
  451. {
  452. fNodeFound = TRUE;
  453. }
  454. }
  455. else
  456. {
  457. if ( ( dwFlags & EAPTLS_CACHEDCRED_FLAG_PEAP ) &&
  458. !(dwFlags & EAPTLS_CACHEDCRED_FLAG_SERVER )
  459. )
  460. {
  461. //
  462. // If we're not a server and this is PEAP
  463. // cached cred then there is no client
  464. // cred and we should not search for
  465. // the hash
  466. if ( pNode->dwCredFlags == dwFlags )
  467. {
  468. fNodeFound = TRUE;
  469. }
  470. }
  471. else
  472. {
  473. if ( pNode->dwCredFlags == dwFlags &&
  474. pNode->Hash.cbHash &&
  475. pEapTlsCb->pUserProp &&
  476. ( !memcmp ( pNode->Hash.pbHash,
  477. pEapTlsCb->pUserProp->Hash.pbHash,
  478. pNode->Hash.cbHash
  479. )
  480. ) &&
  481. pNode->pcCachedCertContext
  482. )
  483. {
  484. fNodeFound = TRUE;
  485. }
  486. }
  487. }
  488. if ( fNodeFound )
  489. {
  490. //
  491. // We have a cred cached. If we're a client check to
  492. // see if the auth LUID is the same
  493. //
  494. if ( !( pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER) &&
  495. fCheckThreadToken
  496. )
  497. {
  498. //
  499. // Check to see if the thread token is the same.
  500. // User could have logged on/ logged off and
  501. // we dont want to use cached creds
  502. // in this case.
  503. //
  504. if ( ! OpenThreadToken(
  505. GetCurrentThread(),
  506. TOKEN_QUERY,
  507. TRUE,
  508. &CurrentThreadToken
  509. )
  510. )
  511. {
  512. EapTlsTrace("OpenThreadToken Failed with Error 0x%x", GetLastError() );
  513. pNode = NULL;
  514. goto done;
  515. }
  516. ZeroMemory ( &TokenStats, sizeof(TokenStats) );
  517. if ( !GetTokenInformation(
  518. CurrentThreadToken,
  519. TokenStatistics,
  520. &TokenStats,
  521. sizeof(TOKEN_STATISTICS),
  522. &TokenStatsSize
  523. )
  524. )
  525. {
  526. EapTlsTrace("OpenThreadToken Failed with Error 0x%x", GetLastError() );
  527. pNode=NULL;
  528. goto done;
  529. }
  530. if ( !( RtlEqualLuid(&(TokenStats.AuthenticationId), &(pNode->AuthenticatedSessionLUID) ) ) )
  531. {
  532. //
  533. // LUID is not the same. So free this cached cred from this list
  534. //
  535. RemoveNodeFromCachedCredList ( pNode );
  536. pNode=NULL;
  537. goto done;
  538. }
  539. }
  540. //Found the cached cred. So return the node back to the caller.
  541. goto done;
  542. }
  543. pNode = pNode->pNext;
  544. }
  545. done:
  546. if ( CurrentThreadToken )
  547. CloseHandle(CurrentThreadToken);
  548. return pNode;
  549. }
  550. //
  551. // Add node to cached cred list if it does not exist
  552. //
  553. //
  554. DWORD AddNodeToCachedCredList ( EAPTLSCB * pEapTlsCb )
  555. {
  556. DWORD dwRetCode = NO_ERROR;
  557. EAPTLS_CACHED_CREDS * pNode = NULL;
  558. TOKEN_STATISTICS TokenStats;
  559. DWORD TokenStatsSize = 0;
  560. HANDLE CurrentThreadToken = NULL;
  561. EapTlsTrace("AddNodeToCachedCredList.");
  562. if ( EAPTLSCB_FLAG_LOGON & pEapTlsCb->fFlags )
  563. {
  564. //
  565. // No cached credentials in case of winlogon scenario.
  566. // There are security implications. We can do this
  567. // iff we have a way to track logon/logoff which we
  568. // dont.
  569. //
  570. EapTlsTrace("Winlogon case.Not setting cached credentials.");
  571. goto done;
  572. }
  573. if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_MACHINE_AUTH )
  574. {
  575. pNode = FindNodeInCachedCredList ( pEapTlsCb, FALSE, FALSE );
  576. }
  577. else
  578. {
  579. pNode = FindNodeInCachedCredList ( pEapTlsCb, FALSE, TRUE );
  580. }
  581. if ( NULL != pNode )
  582. {
  583. EapTlsTrace ("Node already exists in cached cred list. Reducing the refcount.");
  584. pNode = NULL;
  585. goto done;
  586. }
  587. if ( !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER ) &&
  588. !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_MACHINE_AUTH)
  589. )
  590. {
  591. if ( ! OpenThreadToken(
  592. GetCurrentThread(),
  593. TOKEN_QUERY,
  594. TRUE,
  595. &CurrentThreadToken
  596. )
  597. )
  598. {
  599. dwRetCode = GetLastError();
  600. EapTlsTrace("OpenThreadToken Failed with Error 0x%x", dwRetCode );
  601. goto done;
  602. }
  603. ZeroMemory ( &TokenStats, sizeof(TokenStats) );
  604. if ( !GetTokenInformation(
  605. CurrentThreadToken,
  606. TokenStatistics,
  607. &TokenStats,
  608. sizeof(TOKEN_STATISTICS),
  609. &TokenStatsSize
  610. )
  611. )
  612. {
  613. dwRetCode = GetLastError();
  614. EapTlsTrace("OpenThreadToken Failed with Error 0x%x", dwRetCode );
  615. goto done;
  616. }
  617. }
  618. dwRetCode = GetNewCachedCredListNode( &pNode );
  619. if ( dwRetCode != NO_ERROR || ( pNode == NULL ) )
  620. {
  621. EapTlsTrace ("Error getting new cached cred list node.");
  622. goto done;
  623. }
  624. //
  625. // Set the fields in the node from EapTlsCB
  626. //
  627. pNode->dwCredFlags |= ( (pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER ) ?
  628. EAPTLS_CACHEDCRED_FLAG_SERVER :
  629. 0
  630. );
  631. pNode->dwCredFlags |= ( (pEapTlsCb->fFlags & EAPTLSCB_FLAG_8021X_AUTH )?
  632. EAPTLS_CACHEDCRED_FLAG_8021x:
  633. 0
  634. );
  635. pNode->dwCredFlags |= ( (pEapTlsCb->fFlags & EAPTLSCB_FLAG_USING_DEFAULT_CREDS)?
  636. EAPTLS_CACHEDCRED_FLAG_DEFAULT_CRED:
  637. 0
  638. );
  639. if ( (pEapTlsCb->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP ) )
  640. {
  641. pNode->dwCredFlags |= EAPTLS_CACHEDCRED_FLAG_PEAP;
  642. }
  643. else if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_HOSTED_INSIDE_PEAP )
  644. {
  645. pNode->dwCredFlags |= EAPTLS_CACHEDCRED_FLAG_PEAP_EAPTLS;
  646. }
  647. else
  648. {
  649. pNode->dwCredFlags |= EAPTLS_CACHEDCRED_FLAG_EAPTLS;
  650. }
  651. CopyMemory ( &(pNode->Hash),
  652. &(pEapTlsCb->pUserProp->Hash),
  653. sizeof(EAPTLS_HASH)
  654. );
  655. pNode->hCachedCredential = pEapTlsCb->hCredential;
  656. pNode->pcCachedCertContext = pEapTlsCb->pCertContext;
  657. pNode->hCachedProv = pEapTlsCb->hProv;
  658. if ( !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER ) )
  659. {
  660. CopyMemory (&( pNode->AuthenticatedSessionLUID),
  661. &(TokenStats.AuthenticationId),
  662. sizeof( pNode->AuthenticatedSessionLUID)
  663. );
  664. }
  665. if ( NULL == g_pCachedCreds )
  666. {
  667. g_pCachedCreds = pNode;
  668. }
  669. else
  670. {
  671. pNode->pNext = g_pCachedCreds;
  672. g_pCachedCreds = pNode;
  673. }
  674. done:
  675. if ( CurrentThreadToken )
  676. CloseHandle(CurrentThreadToken);
  677. return dwRetCode;
  678. }
  679. /*
  680. * This function encrypts the PIN
  681. *
  682. */
  683. DWORD EncryptData
  684. (
  685. IN PBYTE pbPlainData,
  686. IN DWORD cbPlainData,
  687. OUT PBYTE * ppEncData,
  688. OUT DWORD * pcbEncData
  689. )
  690. {
  691. DWORD dwRetCode = NO_ERROR;
  692. DATA_BLOB DataIn;
  693. DATA_BLOB DataOut;
  694. EapTlsTrace("EncryptData");
  695. if ( !pbPlainData || !cbPlainData )
  696. {
  697. dwRetCode = ERROR_INVALID_DATA;
  698. goto done;
  699. }
  700. ZeroMemory(&DataIn, sizeof(DataIn) );
  701. ZeroMemory(&DataOut, sizeof(DataOut) );
  702. *ppEncData = NULL;
  703. *pcbEncData = 0;
  704. DataIn.pbData = pbPlainData;
  705. DataIn.cbData = cbPlainData;
  706. if ( ! CryptProtectData ( &DataIn,
  707. EAPTLS_8021x_PIN_DATA_DESCR,
  708. NULL,
  709. NULL,
  710. NULL,
  711. CRYPTPROTECT_UI_FORBIDDEN|CRYPTPROTECT_LOCAL_MACHINE,
  712. &DataOut
  713. )
  714. )
  715. {
  716. dwRetCode = GetLastError();
  717. EapTlsTrace("CryptProtectData failed. Error: 0x%x", dwRetCode);
  718. goto done;
  719. }
  720. *ppEncData = DataOut.pbData;
  721. *pcbEncData = DataOut.cbData;
  722. done:
  723. EapTlsTrace("EncryptData done.");
  724. return dwRetCode;
  725. }
  726. /*
  727. * Decrypt the PIN here.
  728. */
  729. DWORD DecryptData
  730. (
  731. IN PBYTE pbEncData,
  732. IN DWORD cbEncData,
  733. OUT PBYTE * ppbPlainData,
  734. OUT DWORD * pcbPlainData
  735. )
  736. {
  737. DWORD dwRetCode = NO_ERROR;
  738. DATA_BLOB DataIn;
  739. DATA_BLOB DataOut;
  740. LPWSTR pDescrOut = NULL;
  741. EapTlsTrace("DecryptData");
  742. if ( !pbEncData || !cbEncData )
  743. {
  744. dwRetCode = ERROR_INVALID_DATA;
  745. goto done;
  746. }
  747. *ppbPlainData = 0;
  748. *pcbPlainData = 0;
  749. ZeroMemory(&DataIn, sizeof(DataIn));
  750. ZeroMemory(&DataOut, sizeof(DataOut));
  751. DataIn.pbData = pbEncData;
  752. DataIn.cbData = cbEncData;
  753. if ( !CryptUnprotectData( &DataIn,
  754. &pDescrOut,
  755. NULL,
  756. NULL,
  757. NULL,
  758. CRYPTPROTECT_UI_FORBIDDEN,
  759. &DataOut
  760. )
  761. )
  762. {
  763. dwRetCode = GetLastError();
  764. EapTlsTrace("CryptUnprotectData failed. Error: 0x%x", dwRetCode );
  765. goto done;
  766. }
  767. if ( lstrcmp( pDescrOut, EAPTLS_8021x_PIN_DATA_DESCR ) )
  768. {
  769. EapTlsTrace("Description of this data does not match expected value. Discarding data");
  770. dwRetCode = ERROR_INVALID_DATA;
  771. goto done;
  772. }
  773. *ppbPlainData = DataOut.pbData;
  774. *pcbPlainData = DataOut.cbData;
  775. done:
  776. EapTlsTrace("DecryptData done.");
  777. return dwRetCode;
  778. }
  779. /*
  780. Returns:
  781. TRUE: Packet is valid
  782. FALSE: Packet is badly formed
  783. Notes:
  784. Returns TRUE iff the EapTls packet *pPacket is correctly formed or pPacket
  785. is NULL.
  786. */
  787. BOOL
  788. FValidPacket(
  789. IN EAPTLS_PACKET* pPacket
  790. )
  791. {
  792. WORD wLength;
  793. BYTE bCode;
  794. if (NULL == pPacket)
  795. {
  796. return(TRUE);
  797. }
  798. wLength = WireToHostFormat16(pPacket->pbLength);
  799. bCode = pPacket->bCode;
  800. switch (bCode)
  801. {
  802. case EAPCODE_Request:
  803. case EAPCODE_Response:
  804. if (PPP_EAP_PACKET_HDR_LEN + 1 > wLength)
  805. {
  806. EapTlsTrace("EAP %s packet does not have Type octet",
  807. g_szEapTlsCodeName[bCode]);
  808. return(FALSE);
  809. }
  810. if (PPP_EAP_TLS != pPacket->bType)
  811. {
  812. // We are not concerned with this packet. It is not TLS.
  813. return(TRUE);
  814. }
  815. if (EAPTLS_PACKET_HDR_LEN > wLength)
  816. {
  817. EapTlsTrace("EAP TLS %s packet does not have Flags octet",
  818. g_szEapTlsCodeName[bCode]);
  819. return(FALSE);
  820. }
  821. if ((pPacket->bFlags & EAPTLS_PACKET_FLAG_LENGTH_INCL) &&
  822. EAPTLS_PACKET_HDR_LEN_MAX > wLength)
  823. {
  824. EapTlsTrace("EAP TLS %s packet with First fragment flag does "
  825. "not have TLS blob size octects",
  826. g_szEapTlsCodeName[bCode]);
  827. }
  828. break;
  829. case EAPCODE_Success:
  830. case EAPCODE_Failure:
  831. if (PPP_EAP_PACKET_HDR_LEN != wLength)
  832. {
  833. EapTlsTrace("EAP TLS %s packet has length %d",
  834. g_szEapTlsCodeName[bCode], wLength);
  835. return(FALSE);
  836. }
  837. break;
  838. default:
  839. EapTlsTrace("Invalid code in EAP packet: %d", bCode);
  840. return(FALSE);
  841. break;
  842. }
  843. return(TRUE);
  844. }
  845. /*
  846. Returns:
  847. VOID
  848. Notes:
  849. Print the contents of the EapTls packet *pPacket. pPacket can be NULL.
  850. fInput: TRUE iff we are receiving the packet
  851. */
  852. VOID
  853. PrintEapTlsPacket(
  854. IN EAPTLS_PACKET* pPacket,
  855. IN BOOL fInput
  856. )
  857. {
  858. BYTE bCode;
  859. WORD wLength;
  860. BOOL fLengthIncluded = FALSE;
  861. BOOL fMoreFragments = FALSE;
  862. BOOL fTlsStart = FALSE;
  863. DWORD dwType = 0;
  864. DWORD dwBlobLength = 0;
  865. if (NULL == pPacket)
  866. {
  867. return;
  868. }
  869. bCode = pPacket->bCode;
  870. if (bCode > MAXEAPCODE)
  871. {
  872. bCode = 0;
  873. }
  874. wLength = WireToHostFormat16(pPacket->pbLength);
  875. if ( FValidPacket(pPacket)
  876. && PPP_EAP_TLS == pPacket->bType
  877. && ( EAPCODE_Request == pPacket->bCode
  878. || EAPCODE_Response == pPacket->bCode))
  879. {
  880. fLengthIncluded = pPacket->bFlags & EAPTLS_PACKET_FLAG_LENGTH_INCL;
  881. fMoreFragments = pPacket->bFlags & EAPTLS_PACKET_FLAG_MORE_FRAGMENTS;
  882. fTlsStart = pPacket->bFlags & EAPTLS_PACKET_FLAG_TLS_START;
  883. dwType = pPacket->bType;
  884. if (fLengthIncluded)
  885. {
  886. dwBlobLength = WireToHostFormat32(pPacket->pbData);
  887. }
  888. }
  889. EapTlsTrace("%s %s (Code: %d) packet: Id: %d, Length: %d, Type: %d, "
  890. "TLS blob length: %d. Flags: %s%s%s",
  891. fInput ? ">> Received" : "<< Sending",
  892. g_szEapTlsCodeName[bCode], pPacket->bCode, pPacket->bId, wLength,
  893. dwType, dwBlobLength,
  894. fLengthIncluded ? "L" : "",
  895. fMoreFragments ? "M" : "",
  896. fTlsStart ? "S" : "");
  897. }
  898. /*
  899. Returns:
  900. Error codes only from winerror.h, raserror.h or mprerror.h
  901. Notes:
  902. RasEapGetInfo entry point called by the EAP-PPP engine.
  903. */
  904. DWORD
  905. RasEapGetInfo(
  906. IN DWORD dwEapTypeId,
  907. OUT PPP_EAP_INFO* pInfo
  908. )
  909. {
  910. DWORD dwErr = NO_ERROR;
  911. EapTlsTrace("RasEapGetInfo");
  912. RTASSERT(NULL != pInfo);
  913. if (PPP_EAP_TLS != dwEapTypeId
  914. #ifdef IMPL_PEAP
  915. && PPP_EAP_PEAP != dwEapTypeId
  916. #endif
  917. )
  918. {
  919. EapTlsTrace("EAP Type %d is not supported", dwEapTypeId);
  920. dwErr = ERROR_NOT_SUPPORTED;
  921. goto LDone;
  922. }
  923. ZeroMemory(pInfo, sizeof(PPP_EAP_INFO));
  924. if ( PPP_EAP_TLS == dwEapTypeId )
  925. {
  926. pInfo->dwEapTypeId = PPP_EAP_TLS;
  927. pInfo->RasEapInitialize = EapTlsInitialize;
  928. pInfo->RasEapBegin = EapTlsBegin;
  929. pInfo->RasEapEnd = EapTlsEnd;
  930. pInfo->RasEapMakeMessage = EapTlsMakeMessage;
  931. }
  932. else
  933. {
  934. pInfo->dwEapTypeId = PPP_EAP_PEAP;
  935. pInfo->RasEapInitialize = EapPeapInitialize;
  936. pInfo->RasEapBegin = EapPeapBegin;
  937. pInfo->RasEapEnd = EapPeapEnd;
  938. pInfo->RasEapMakeMessage = EapPeapMakeMessage;
  939. }
  940. LDone:
  941. return(dwErr);
  942. }
  943. //////////////////////////////////////////
  944. ////// Dialog procs for interactive UI
  945. //////////////////////////////////////////
  946. //// Server Configuration
  947. //
  948. BOOL
  949. ValidateServerInitDialog(
  950. IN HWND hWnd,
  951. IN LPARAM lParam
  952. )
  953. {
  954. EAPTLS_VALIDATE_SERVER * pValidateServer;
  955. SetWindowLongPtr(hWnd, DWLP_USER, lParam);
  956. pValidateServer = (EAPTLS_VALIDATE_SERVER *)lParam;
  957. //Set the Dialog Title
  958. SetWindowText( hWnd, pValidateServer->awszTitle );
  959. SetWindowText ( GetDlgItem(hWnd, IDC_MESSAGE),
  960. pValidateServer->awszWarning
  961. );
  962. if ( !pValidateServer->fShowCertDetails )
  963. {
  964. EnableWindow ( GetDlgItem(hWnd, IDC_BTN_VIEW_CERTIFICATE),
  965. FALSE
  966. );
  967. ShowWindow( GetDlgItem(hWnd, IDC_BTN_VIEW_CERTIFICATE),
  968. SW_HIDE
  969. );
  970. }
  971. return FALSE;
  972. }
  973. BOOL
  974. ValidateServerCommand(
  975. IN EAPTLS_VALIDATE_SERVER *pValidateServer,
  976. IN WORD wNotifyCode,
  977. IN WORD wId,
  978. IN HWND hWndDlg,
  979. IN HWND hWndCtrl
  980. )
  981. {
  982. BOOL fRetVal = FALSE;
  983. switch(wId)
  984. {
  985. case IDC_BTN_VIEW_CERTIFICATE:
  986. {
  987. HCERTSTORE hCertStore = NULL;
  988. PCCERT_CONTEXT pCertContext = NULL;
  989. CRYPT_HASH_BLOB chb;
  990. WCHAR szError[256];
  991. LoadString( GetHInstance(), IDS_NO_CERT_DETAILS,
  992. szError, 255);
  993. hCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM,
  994. 0,
  995. 0,
  996. CERT_STORE_READONLY_FLAG |CERT_SYSTEM_STORE_CURRENT_USER,
  997. L"CA"
  998. );
  999. if ( !hCertStore )
  1000. {
  1001. MessageBox ( hWndDlg,
  1002. szError,
  1003. pValidateServer->awszTitle,
  1004. MB_OK|MB_ICONSTOP
  1005. );
  1006. break;
  1007. }
  1008. chb.cbData = pValidateServer->Hash.cbHash;
  1009. chb.pbData = pValidateServer->Hash.pbHash;
  1010. pCertContext = CertFindCertificateInStore(
  1011. hCertStore,
  1012. 0,
  1013. 0,
  1014. CERT_FIND_HASH,
  1015. &chb,
  1016. 0);
  1017. if ( NULL == pCertContext )
  1018. {
  1019. MessageBox ( hWndDlg,
  1020. szError,
  1021. pValidateServer->awszTitle,
  1022. MB_OK|MB_ICONSTOP
  1023. );
  1024. if ( hCertStore )
  1025. CertCloseStore( hCertStore, CERT_CLOSE_STORE_FORCE_FLAG );
  1026. break;
  1027. }
  1028. //
  1029. // Show Cert detail
  1030. //
  1031. ShowCertDetails ( hWndDlg, hCertStore, pCertContext );
  1032. if ( pCertContext )
  1033. CertFreeCertificateContext(pCertContext);
  1034. if ( hCertStore )
  1035. CertCloseStore( hCertStore, CERT_CLOSE_STORE_FORCE_FLAG );
  1036. fRetVal = TRUE;
  1037. }
  1038. break;
  1039. case IDOK:
  1040. case IDCANCEL:
  1041. //
  1042. // Delete context from store
  1043. //
  1044. {
  1045. HCERTSTORE hCertStore = NULL;
  1046. PCCERT_CONTEXT pCertContext = NULL;
  1047. CRYPT_HASH_BLOB chb;
  1048. hCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM,
  1049. 0,
  1050. 0,
  1051. CERT_SYSTEM_STORE_CURRENT_USER,
  1052. L"CA"
  1053. );
  1054. if ( hCertStore )
  1055. {
  1056. chb.cbData = pValidateServer->Hash.cbHash;
  1057. chb.pbData = pValidateServer->Hash.pbHash;
  1058. pCertContext = CertFindCertificateInStore(
  1059. hCertStore,
  1060. 0,
  1061. 0,
  1062. CERT_FIND_HASH,
  1063. &chb,
  1064. 0);
  1065. if ( pCertContext )
  1066. CertDeleteCertificateFromStore(pCertContext);
  1067. CertCloseStore( hCertStore, CERT_CLOSE_STORE_FORCE_FLAG );
  1068. }
  1069. }
  1070. EndDialog(hWndDlg, wId);
  1071. fRetVal = TRUE;
  1072. break;
  1073. default:
  1074. break;
  1075. }
  1076. return fRetVal;
  1077. }
  1078. INT_PTR CALLBACK
  1079. ValidateServerDialogProc(
  1080. IN HWND hWnd,
  1081. IN UINT unMsg,
  1082. IN WPARAM wParam,
  1083. IN LPARAM lParam
  1084. )
  1085. {
  1086. EAPTLS_VALIDATE_SERVER * pValidateServer;
  1087. switch (unMsg)
  1088. {
  1089. case WM_INITDIALOG:
  1090. return(ValidateServerInitDialog(hWnd, lParam));
  1091. case WM_HELP:
  1092. case WM_CONTEXTMENU:
  1093. {
  1094. ContextHelp(g_adwHelp, hWnd, unMsg, wParam, lParam);
  1095. break;
  1096. }
  1097. case WM_COMMAND:
  1098. pValidateServer = (EAPTLS_VALIDATE_SERVER *)GetWindowLongPtr(hWnd, DWLP_USER);
  1099. return(ValidateServerCommand(pValidateServer,
  1100. HIWORD(wParam),
  1101. LOWORD(wParam),
  1102. hWnd,
  1103. (HWND)lParam)
  1104. );
  1105. }
  1106. return(FALSE);
  1107. }
  1108. /*
  1109. Returns:
  1110. Error codes only from winerror.h, raserror.h or mprerror.h
  1111. Notes:
  1112. */
  1113. DWORD
  1114. InvokeValidateServerDialog(
  1115. IN HWND hWndParent,
  1116. IN BYTE* pUIContextData,
  1117. IN DWORD dwSizeofUIContextData,
  1118. OUT BYTE** ppDataFromInteractiveUI,
  1119. OUT DWORD* pdwSizeOfDataFromInteractiveUI
  1120. )
  1121. {
  1122. INT_PTR nRet;
  1123. EAPTLS_VALIDATE_SERVER* pEapTlsValidateServer;
  1124. BYTE* pbResult = NULL;
  1125. DWORD dwSizeOfResult;
  1126. DWORD dwErr = NO_ERROR;
  1127. *ppDataFromInteractiveUI = NULL;
  1128. *pdwSizeOfDataFromInteractiveUI = 0;
  1129. pbResult = LocalAlloc(LPTR, sizeof(BYTE));
  1130. if (NULL == pbResult)
  1131. {
  1132. dwErr = GetLastError();
  1133. goto LDone;
  1134. }
  1135. dwSizeOfResult = sizeof(BYTE);
  1136. pEapTlsValidateServer = (EAPTLS_VALIDATE_SERVER*) pUIContextData;
  1137. nRet = DialogBoxParam(
  1138. GetHInstance(),
  1139. MAKEINTRESOURCE(IDD_VALIDATE_SERVER),
  1140. hWndParent,
  1141. ValidateServerDialogProc,
  1142. (LPARAM)pEapTlsValidateServer);
  1143. if (-1 == nRet)
  1144. {
  1145. dwErr = GetLastError();
  1146. goto LDone;
  1147. }
  1148. else if (IDOK == nRet)
  1149. {
  1150. *pbResult = IDYES;
  1151. }
  1152. else
  1153. {
  1154. *pbResult = IDNO;
  1155. }
  1156. *ppDataFromInteractiveUI = pbResult;
  1157. *pdwSizeOfDataFromInteractiveUI = dwSizeOfResult;
  1158. pbResult = NULL;
  1159. LDone:
  1160. LocalFree(pbResult);
  1161. return(dwErr);
  1162. }
  1163. /*
  1164. Returns:
  1165. Error codes only from winerror.h, raserror.h or mprerror.h
  1166. Notes:
  1167. RasEapInvokeInteractiveUI entry point called by the EAP-PPP engine by name.
  1168. */
  1169. DWORD
  1170. RasEapInvokeInteractiveUI(
  1171. IN DWORD dwEapTypeId,
  1172. IN HWND hWndParent,
  1173. IN BYTE* pUIContextData,
  1174. IN DWORD dwSizeofUIContextData,
  1175. OUT BYTE** ppDataFromInteractiveUI,
  1176. OUT DWORD* pdwSizeOfDataFromInteractiveUI
  1177. )
  1178. {
  1179. DWORD dwRetCode = NO_ERROR;
  1180. PPEAP_EAP_INFO pEapList = NULL;
  1181. PPEAP_EAP_INFO pEapInfo = NULL;
  1182. PPEAP_INTERACTIVE_UI pPeapInteractiveUI = NULL;
  1183. RASEAPINVOKEINTERACTIVEUI pfnInvoke = NULL;
  1184. RASEAPFREE pfnFree = NULL;
  1185. if ( PPP_EAP_TLS == dwEapTypeId )
  1186. {
  1187. dwRetCode = InvokeValidateServerDialog(
  1188. hWndParent,
  1189. pUIContextData,
  1190. dwSizeofUIContextData,
  1191. ppDataFromInteractiveUI,
  1192. pdwSizeOfDataFromInteractiveUI);
  1193. }
  1194. else if ( PPP_EAP_PEAP == dwEapTypeId )
  1195. {
  1196. dwRetCode = PeapEapInfoGetList ( NULL, FALSE, &pEapList );
  1197. if ( NO_ERROR != dwRetCode || NULL == pEapList )
  1198. {
  1199. EapTlsTrace("Unable to load list of EAP Types on this machine.");
  1200. goto LDone;
  1201. }
  1202. pPeapInteractiveUI = (PPEAP_INTERACTIVE_UI)pUIContextData;
  1203. //
  1204. // Load relevant IdentityUI DLL and then invoke
  1205. // the
  1206. dwRetCode = PeapEapInfoFindListNode ( pPeapInteractiveUI->dwEapTypeId,
  1207. pEapList,
  1208. &pEapInfo
  1209. );
  1210. if ( NO_ERROR != dwRetCode || NULL == pEapInfo )
  1211. {
  1212. EapTlsTrace("Cannot find configured PEAP in the list of EAP Types on this machine.");
  1213. goto LDone;
  1214. }
  1215. if ( !((pfnInvoke) = (RASEAPINVOKEINTERACTIVEUI)
  1216. GetProcAddress(
  1217. pEapInfo->hEAPModule,
  1218. "RasEapInvokeInteractiveUI"))
  1219. || !((pfnFree ) = (RASEAPFREE)
  1220. GetProcAddress(
  1221. pEapInfo->hEAPModule,
  1222. "RasEapFreeMemory")))
  1223. {
  1224. dwRetCode = GetLastError();
  1225. EapTlsTrace("failed to get entrypoint. rc=%d", dwRetCode);
  1226. goto LDone;
  1227. }
  1228. //
  1229. // Invoke the entry point here
  1230. //
  1231. dwRetCode = pfnInvoke ( pPeapInteractiveUI->dwEapTypeId,
  1232. hWndParent,
  1233. pPeapInteractiveUI->bUIContextData,
  1234. pPeapInteractiveUI->dwSizeofUIContextData,
  1235. ppDataFromInteractiveUI,
  1236. pdwSizeOfDataFromInteractiveUI
  1237. );
  1238. }
  1239. else
  1240. {
  1241. dwRetCode = ERROR_INVALID_PARAMETER;
  1242. }
  1243. LDone:
  1244. PeapEapInfoFreeList( pEapList );
  1245. return dwRetCode;
  1246. }
  1247. /*
  1248. Returns:
  1249. Error codes only from winerror.h, raserror.h or mprerror.h
  1250. Notes:
  1251. Called to get a context buffer for this EAP session and pass initialization
  1252. information. This will be called before any other call is made.
  1253. */
  1254. DWORD
  1255. EapTlsBegin(
  1256. OUT VOID** ppWorkBuffer,
  1257. IN PPP_EAP_INPUT* pPppEapInput
  1258. )
  1259. {
  1260. DWORD dwErr = NO_ERROR;
  1261. LONG lRet;
  1262. HKEY hKey = NULL;
  1263. DWORD dwType;
  1264. DWORD dwValue;
  1265. DWORD dwSize;
  1266. BOOL fServer = FALSE;
  1267. BOOL fWinLogonData = FALSE;
  1268. EAPTLSCB* pEapTlsCb = NULL;
  1269. EAPTLS_CONN_PROPERTIES * pConnProp = NULL;
  1270. PBYTE pbDecPIN = NULL;
  1271. DWORD cbDecPIN = 0;
  1272. EAPTLS_USER_PROPERTIES * pUserProp = NULL;
  1273. RTASSERT(NULL != ppWorkBuffer);
  1274. RTASSERT(NULL != pPppEapInput);
  1275. EapTlsTrace(""); // Blank line
  1276. EapTlsTrace("EapTlsBegin(%ws)",
  1277. pPppEapInput->pwszIdentity ? pPppEapInput->pwszIdentity : L"");
  1278. #if WINVER > 0x0500
  1279. dwErr = SetupMachineChangeNotification ();
  1280. if ( NO_ERROR != dwErr )
  1281. {
  1282. EapTlsTrace("Error setting up store change notification.");
  1283. goto LDone;
  1284. }
  1285. dwErr = VerifyCallerTrust(_ReturnAddress());
  1286. if ( NO_ERROR != dwErr )
  1287. {
  1288. EapTlsTrace("Unauthorized use of TLS attempted");
  1289. goto LDone;
  1290. }
  1291. #endif
  1292. // Allocate the context buffer
  1293. pEapTlsCb = LocalAlloc(LPTR, sizeof(EAPTLSCB));
  1294. if (NULL == pEapTlsCb)
  1295. {
  1296. dwErr = GetLastError();
  1297. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  1298. goto LDone;
  1299. }
  1300. pEapTlsCb->EapTlsState = EAPTLS_STATE_INITIAL;
  1301. EapTlsTrace("State change to %s", g_szEapTlsState[pEapTlsCb->EapTlsState]);
  1302. pEapTlsCb->fFlags = (pPppEapInput->fAuthenticator) ?
  1303. EAPTLSCB_FLAG_SERVER : 0;
  1304. pEapTlsCb->fFlags |= (pPppEapInput->fFlags & RAS_EAP_FLAG_ROUTER) ?
  1305. EAPTLSCB_FLAG_ROUTER : 0;
  1306. pEapTlsCb->fFlags |= (pPppEapInput->fFlags & RAS_EAP_FLAG_LOGON) ?
  1307. EAPTLSCB_FLAG_LOGON : 0;
  1308. pEapTlsCb->fFlags |= (pPppEapInput->fFlags & RAS_EAP_FLAG_NON_INTERACTIVE) ?
  1309. EAPTLSCB_FLAG_NON_INTERACTIVE : 0;
  1310. pEapTlsCb->fFlags |= (pPppEapInput->fFlags & RAS_EAP_FLAG_FIRST_LINK) ?
  1311. EAPTLSCB_FLAG_FIRST_LINK : 0;
  1312. pEapTlsCb->fFlags |= (pPppEapInput->fFlags & RAS_EAP_FLAG_MACHINE_AUTH) ?
  1313. EAPTLSCB_FLAG_MACHINE_AUTH : 0;
  1314. pEapTlsCb->fFlags |= (pPppEapInput->fFlags & RAS_EAP_FLAG_GUEST_ACCESS) ?
  1315. EAPTLSCB_FLAG_GUEST_ACCESS : 0;
  1316. pEapTlsCb->fFlags |= (pPppEapInput->fFlags & RAS_EAP_FLAG_8021X_AUTH) ?
  1317. EAPTLSCB_FLAG_8021X_AUTH : 0;
  1318. pEapTlsCb->fFlags |= (pPppEapInput->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP )?
  1319. EAPTLSCB_FLAG_EXECUTING_PEAP : 0;
  1320. pEapTlsCb->fFlags |= (pPppEapInput->fFlags & RAS_EAP_FLAG_HOSTED_IN_PEAP )?
  1321. EAPTLSCB_FLAG_HOSTED_INSIDE_PEAP : 0;
  1322. if ( pPppEapInput->fFlags & RAS_EAP_FLAG_RESUME_FROM_HIBERNATE )
  1323. {
  1324. //Clear all cached credentials.
  1325. EnterCriticalSection ( &g_csProtectCachedCredentials );
  1326. ClearCachedCredList ();
  1327. LeaveCriticalSection ( &g_csProtectCachedCredentials );
  1328. }
  1329. if (pPppEapInput->fFlags & RAS_EAP_FLAG_8021X_AUTH)
  1330. {
  1331. EapTlsTrace("EapTlsBegin: Detected 8021X authentication");
  1332. }
  1333. if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP )
  1334. {
  1335. EapTlsTrace("EapTlsBegin: Detected PEAP authentication");
  1336. }
  1337. pEapTlsCb->fFlags |= EAPTLSCB_FLAG_HCRED_INVALID;
  1338. pEapTlsCb->fFlags |= EAPTLSCB_FLAG_HCTXT_INVALID;
  1339. if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER )
  1340. {
  1341. fServer = TRUE;
  1342. pEapTlsCb->hEventLog = pPppEapInput->hReserved;
  1343. pEapTlsCb->fContextReq = ASC_REQ_SEQUENCE_DETECT |
  1344. ASC_REQ_REPLAY_DETECT |
  1345. ASC_REQ_CONFIDENTIALITY |
  1346. ASC_REQ_MUTUAL_AUTH |
  1347. ASC_RET_EXTENDED_ERROR |
  1348. ASC_REQ_ALLOCATE_MEMORY |
  1349. ASC_REQ_STREAM;
  1350. //
  1351. //Server will always allow guest access.
  1352. //
  1353. if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_GUEST_ACCESS ||
  1354. pEapTlsCb->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP
  1355. )
  1356. pEapTlsCb->fContextReq |= ASC_REQ_MUTUAL_AUTH;
  1357. if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP )
  1358. {
  1359. //
  1360. // We are executing PEap. So take the user props from
  1361. // PppEapInput rather than serverconfigdataio.
  1362. //
  1363. dwErr = ReadUserData(pPppEapInput->pUserData,
  1364. pPppEapInput->dwSizeOfUserData, &(pEapTlsCb->pUserProp));
  1365. if (NO_ERROR != dwErr)
  1366. {
  1367. goto LDone;
  1368. }
  1369. }
  1370. else
  1371. {
  1372. #if 0
  1373. dwErr = ServerConfigDataIO(TRUE /* fRead */, NULL /* pwszMachineName */,
  1374. (BYTE**)&(pEapTlsCb->pUserProp), 0);
  1375. if (NO_ERROR != dwErr)
  1376. {
  1377. goto LDone;
  1378. }
  1379. #endif
  1380. if( (NULL != pPppEapInput->pConnectionData)
  1381. && (0 != pPppEapInput->dwSizeOfConnectionData))
  1382. {
  1383. //
  1384. // If Connection data was passed in, make a copy of
  1385. // it.
  1386. //
  1387. pEapTlsCb->pUserProp =
  1388. LocalAlloc(LPTR, pPppEapInput->dwSizeOfConnectionData);
  1389. if(NULL == pEapTlsCb->pUserProp)
  1390. {
  1391. dwErr = E_OUTOFMEMORY;
  1392. goto LDone;
  1393. }
  1394. CopyMemory((PBYTE) pEapTlsCb->pUserProp,
  1395. pPppEapInput->pConnectionData,
  1396. pPppEapInput->dwSizeOfConnectionData);
  1397. }
  1398. else
  1399. {
  1400. //
  1401. // Get the default properties - No point in reading from
  1402. // registry. We won't know which policy that applies to
  1403. // anyway.
  1404. //
  1405. pEapTlsCb->pUserProp = (EAPTLS_USER_PROPERTIES *)
  1406. LocalAlloc(LPTR, sizeof(EAPTLS_USER_PROPERTIES));
  1407. if(NULL == pEapTlsCb->pUserProp)
  1408. {
  1409. dwErr = E_OUTOFMEMORY;
  1410. goto LDone;
  1411. }
  1412. pEapTlsCb->pUserProp->dwVersion = 0;
  1413. pEapTlsCb->pUserProp->dwSize =
  1414. sizeof(EAPTLS_USER_PROPERTIES);
  1415. pEapTlsCb->pUserProp->awszString[0] = 0;
  1416. }
  1417. }
  1418. pEapTlsCb->bId = pPppEapInput->bInitialId;
  1419. }
  1420. else
  1421. {
  1422. //
  1423. // Client side config for TLS
  1424. //
  1425. pEapTlsCb->fContextReq = ISC_REQ_SEQUENCE_DETECT |
  1426. ISC_REQ_REPLAY_DETECT |
  1427. ISC_REQ_CONFIDENTIALITY |
  1428. ISC_RET_EXTENDED_ERROR |
  1429. ISC_REQ_ALLOCATE_MEMORY |
  1430. ISC_REQ_USE_SUPPLIED_CREDS |
  1431. ISC_REQ_STREAM;
  1432. pEapTlsCb->hTokenImpersonateUser = pPppEapInput->hTokenImpersonateUser;
  1433. #if 0
  1434. if (NULL == pPppEapInput->pUserData)
  1435. {
  1436. dwErr = ERROR_INVALID_DATA;
  1437. EapTlsTrace("No user data!");
  1438. goto LDone;
  1439. }
  1440. #endif
  1441. if (pPppEapInput->pUserData != NULL)
  1442. {
  1443. if (0 != *(DWORD*)(pPppEapInput->pUserData))
  1444. {
  1445. fWinLogonData = TRUE;
  1446. }
  1447. }
  1448. if (fWinLogonData)
  1449. {
  1450. // Data from Winlogon
  1451. pEapTlsCb->fFlags |= EAPTLSCB_FLAG_WINLOGON_DATA;
  1452. pEapTlsCb->pUserData = LocalAlloc(LPTR,
  1453. pPppEapInput->dwSizeOfUserData);
  1454. if (NULL == pEapTlsCb->pUserData)
  1455. {
  1456. dwErr = GetLastError();
  1457. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  1458. goto LDone;
  1459. }
  1460. CopyMemory(pEapTlsCb->pUserData, pPppEapInput->pUserData,
  1461. pPppEapInput->dwSizeOfUserData);
  1462. pEapTlsCb->dwSizeOfUserData = pPppEapInput->dwSizeOfUserData;
  1463. }
  1464. else
  1465. {
  1466. dwErr = ReadUserData(pPppEapInput->pUserData,
  1467. pPppEapInput->dwSizeOfUserData, &(pEapTlsCb->pUserProp));
  1468. if (NO_ERROR != dwErr)
  1469. {
  1470. goto LDone;
  1471. }
  1472. }
  1473. }
  1474. dwErr = ReadConnectionData(
  1475. (pPppEapInput->fFlags & RAS_EAP_FLAG_8021X_AUTH),
  1476. (pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER) ?
  1477. NULL : pPppEapInput->pConnectionData,
  1478. (pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER) ?
  1479. 0 : pPppEapInput->dwSizeOfConnectionData,
  1480. &pConnProp);
  1481. if (NO_ERROR != dwErr)
  1482. {
  1483. goto LDone;
  1484. }
  1485. dwErr = ConnPropGetV1Struct ( pConnProp, &(pEapTlsCb->pConnProp) );
  1486. if ( NO_ERROR != dwErr )
  1487. {
  1488. goto LDone;
  1489. }
  1490. //
  1491. // Check to see if it is a 8021x and smart card user.
  1492. // If so, decrypt the pin if one is present
  1493. //
  1494. if ( !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER) &&
  1495. pEapTlsCb->fFlags & EAPTLSCB_FLAG_8021X_AUTH &&
  1496. pEapTlsCb->pConnProp &&
  1497. !(pEapTlsCb->pConnProp->fFlags & EAPTLS_CONN_FLAG_REGISTRY)
  1498. )
  1499. {
  1500. if ( NO_ERROR != DecryptData (
  1501. (PBYTE)pEapTlsCb->pUserProp->pwszPin,
  1502. pEapTlsCb->pUserProp->dwSize - sizeof(EAPTLS_USER_PROPERTIES)
  1503. - ( ( wcslen(pEapTlsCb->pUserProp->pwszDiffUser) + 1 ) * sizeof (WCHAR) ),
  1504. &pbDecPIN,
  1505. &cbDecPIN
  1506. )
  1507. )
  1508. {
  1509. //
  1510. //Dummy pin allocation
  1511. //
  1512. pbDecPIN = LocalAlloc(LPTR, 5);
  1513. cbDecPIN = lstrlen((LPWSTR)pbDecPIN);
  1514. }
  1515. AllocUserDataWithNewPin(pEapTlsCb->pUserProp, pbDecPIN, cbDecPIN, &pUserProp);
  1516. LocalFree(pEapTlsCb->pUserProp);
  1517. pEapTlsCb->pUserProp = pUserProp;
  1518. }
  1519. // Save the identity. On the authenticatee side, this was obtained by
  1520. // calling RasEapGetIdentity; on the authenticator side this was
  1521. // obtained by the Identity request message.
  1522. wcsncpy(pEapTlsCb->awszIdentity,
  1523. pPppEapInput->pwszIdentity ? pPppEapInput->pwszIdentity : L"", UNLEN);
  1524. _wcslwr(pEapTlsCb->awszIdentity);
  1525. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, EAPTLS_KEY_13, 0, KEY_READ,
  1526. &hKey);
  1527. if (ERROR_SUCCESS == lRet)
  1528. {
  1529. dwSize = sizeof(dwValue);
  1530. lRet = RegQueryValueEx(hKey, EAPTLS_VAL_MAX_TLS_MESSAGE_LENGTH,
  1531. NULL, &dwType, (BYTE*)&dwValue, &dwSize);
  1532. if ( (ERROR_SUCCESS == lRet)
  1533. && (REG_DWORD == dwType))
  1534. {
  1535. g_dwMaxBlobSize = dwValue;
  1536. }
  1537. else
  1538. {
  1539. g_dwMaxBlobSize = DEFAULT_MAX_BLOB_SIzE;
  1540. }
  1541. EapTlsTrace("MaxTLSMessageLength is now %d", g_dwMaxBlobSize);
  1542. if (fServer)
  1543. {
  1544. dwSize = sizeof(dwValue);
  1545. lRet = RegQueryValueEx(hKey, EAPTLS_VAL_IGNORE_NO_REVOCATION_CHECK,
  1546. NULL, &dwType, (BYTE*)&dwValue, &dwSize);
  1547. if ( (ERROR_SUCCESS == lRet)
  1548. && (REG_DWORD == dwType))
  1549. {
  1550. g_fIgnoreNoRevocationCheck = dwValue;
  1551. }
  1552. else
  1553. {
  1554. g_fIgnoreNoRevocationCheck = FALSE;
  1555. }
  1556. EapTlsTrace("CRYPT_E_NO_REVOCATION_CHECK will %sbe ignored",
  1557. g_fIgnoreNoRevocationCheck ? "" : "not ");
  1558. dwSize = sizeof(dwValue);
  1559. lRet = RegQueryValueEx(hKey, EAPTLS_VAL_IGNORE_REVOCATION_OFFLINE,
  1560. NULL, &dwType, (BYTE*)&dwValue, &dwSize);
  1561. if ( (ERROR_SUCCESS == lRet)
  1562. && (REG_DWORD == dwType))
  1563. {
  1564. g_fIgnoreRevocationOffline = dwValue;
  1565. }
  1566. else
  1567. {
  1568. g_fIgnoreRevocationOffline = FALSE;
  1569. }
  1570. EapTlsTrace("CRYPT_E_REVOCATION_OFFLINE will %sbe ignored",
  1571. g_fIgnoreRevocationOffline ? "" : "not ");
  1572. dwSize = sizeof(dwValue);
  1573. lRet = RegQueryValueEx(hKey, EAPTLS_VAL_NO_ROOT_REVOCATION_CHECK,
  1574. NULL, &dwType, (BYTE*)&dwValue, &dwSize);
  1575. if ( (ERROR_SUCCESS == lRet)
  1576. && (REG_DWORD == dwType))
  1577. {
  1578. g_fNoRootRevocationCheck = dwValue;
  1579. }
  1580. else
  1581. {
  1582. g_fNoRootRevocationCheck = TRUE;
  1583. }
  1584. EapTlsTrace("The root cert will %sbe checked for revocation",
  1585. g_fNoRootRevocationCheck ? "not " : "");
  1586. dwSize = sizeof(dwValue);
  1587. lRet = RegQueryValueEx(hKey, EAPTLS_VAL_NO_REVOCATION_CHECK,
  1588. NULL, &dwType, (BYTE*)&dwValue, &dwSize);
  1589. if ( (ERROR_SUCCESS == lRet)
  1590. && (REG_DWORD == dwType))
  1591. {
  1592. g_fNoRevocationCheck = dwValue;
  1593. }
  1594. else
  1595. {
  1596. g_fNoRevocationCheck = FALSE;
  1597. }
  1598. EapTlsTrace("The cert will %sbe checked for revocation",
  1599. g_fNoRevocationCheck ? "not " : "");
  1600. }
  1601. RegCloseKey(hKey);
  1602. }
  1603. // pbBlobIn, pbBlobOut, and pAttribues are initially NULL and cbBlobIn,
  1604. // cbBlobInBuffer, cbBlobOut, cbBlobOutBuffer, dwBlobOutOffset,
  1605. // dwBlobOutOffsetNew, and dwBlobInRemining are all 0.
  1606. // bCode, dwErr are also 0.
  1607. LDone:
  1608. LocalFree(pConnProp);
  1609. LocalFree(pbDecPIN);
  1610. if ( (NO_ERROR != dwErr)
  1611. && (NULL != pEapTlsCb))
  1612. {
  1613. LocalFree(pEapTlsCb->pUserProp);
  1614. LocalFree(pEapTlsCb->pConnProp);
  1615. LocalFree(pEapTlsCb->pUserData);
  1616. LocalFree(pEapTlsCb);
  1617. pEapTlsCb = NULL;
  1618. }
  1619. *ppWorkBuffer = pEapTlsCb;
  1620. return(dwErr);
  1621. }
  1622. /*
  1623. Returns:
  1624. Error codes only from winerror.h, raserror.h or mprerror.h
  1625. Notes:
  1626. Called to free the context buffer for this EAP session. Called after this
  1627. session is completed successfully or not.
  1628. */
  1629. DWORD
  1630. EapTlsEnd(
  1631. IN EAPTLSCB* pEapTlsCb
  1632. )
  1633. {
  1634. SECURITY_STATUS Status;
  1635. EapTlsTrace("EapTlsEnd"); // Blank line
  1636. if (NULL != pEapTlsCb)
  1637. {
  1638. EapTlsTrace("EapTlsEnd(%ws)",
  1639. pEapTlsCb->awszIdentity ? pEapTlsCb->awszIdentity : L"");
  1640. if (NULL != pEapTlsCb->pCertContext)
  1641. {
  1642. //
  1643. // Since we are using cached creds dont free the
  1644. // cert context.
  1645. //
  1646. #if 0
  1647. if ( !(EAPTLSCB_FLAG_SERVER & pEapTlsCb->fFlags ) )
  1648. CertFreeCertificateContext(pEapTlsCb->pCertContext);
  1649. #endif
  1650. // Always returns TRUE;
  1651. pEapTlsCb->pCertContext = NULL;
  1652. }
  1653. if (!(EAPTLSCB_FLAG_HCTXT_INVALID & pEapTlsCb->fFlags))
  1654. {
  1655. Status = DeleteSecurityContext(&pEapTlsCb->hContext);
  1656. if (SEC_E_OK != Status)
  1657. {
  1658. EapTlsTrace("DeleteSecurityContext failed and returned 0x%x",
  1659. Status);
  1660. }
  1661. }
  1662. if (!(EAPTLSCB_FLAG_HCRED_INVALID & pEapTlsCb->fFlags))
  1663. {
  1664. //
  1665. // Dont free the credentials handle. We are using
  1666. // cached credentials.
  1667. //
  1668. #if 0
  1669. if ( !(EAPTLSCB_FLAG_SERVER & pEapTlsCb->fFlags ) )
  1670. {
  1671. EapTlsTrace("Freeing Credentials handle: flags are 0x%x",
  1672. pEapTlsCb->fFlags);
  1673. Status = FreeCredentialsHandle(&pEapTlsCb->hCredential);
  1674. if (SEC_E_OK != Status)
  1675. {
  1676. EapTlsTrace("FreeCredentialsHandle failed and returned 0x%x",
  1677. Status);
  1678. }
  1679. }
  1680. #endif
  1681. ZeroMemory( &pEapTlsCb->hCredential, sizeof(CredHandle));
  1682. }
  1683. pEapTlsCb->fFlags |= EAPTLSCB_FLAG_HCRED_INVALID;
  1684. pEapTlsCb->fFlags |= EAPTLSCB_FLAG_HCTXT_INVALID;
  1685. if (NULL != pEapTlsCb->pAttributes)
  1686. {
  1687. RasAuthAttributeDestroy(pEapTlsCb->pAttributes);
  1688. }
  1689. LocalFree(pEapTlsCb->pUserProp);
  1690. LocalFree(pEapTlsCb->pConnProp);
  1691. LocalFree(pEapTlsCb->pNewConnProp);
  1692. LocalFree(pEapTlsCb->pUserData);
  1693. LocalFree(pEapTlsCb->pbBlobIn);
  1694. LocalFree(pEapTlsCb->pbBlobOut);
  1695. LocalFree(pEapTlsCb->pUIContextData);
  1696. if(NULL != pEapTlsCb->pSavedPin)
  1697. {
  1698. if(NULL != pEapTlsCb->pSavedPin->pwszPin)
  1699. {
  1700. ZeroMemory(pEapTlsCb->pSavedPin->pwszPin,
  1701. wcslen(pEapTlsCb->pSavedPin->pwszPin)
  1702. * sizeof(WCHAR));
  1703. LocalFree(pEapTlsCb->pSavedPin->pwszPin);
  1704. }
  1705. LocalFree(pEapTlsCb->pSavedPin);
  1706. }
  1707. //
  1708. // auth result is not good or we are waiting for user ok
  1709. //and we are a client.
  1710. //
  1711. if ( ( NO_ERROR != pEapTlsCb->dwAuthResultCode ||
  1712. EAPTLS_STATE_WAIT_FOR_USER_OK == pEapTlsCb->EapTlsState )&&
  1713. !( pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER )
  1714. )
  1715. {
  1716. EapTlsTrace("Auth failed so freeing cached creds.");
  1717. EnterCriticalSection ( &g_csProtectCachedCredentials );
  1718. FreeCachedCredentials(pEapTlsCb);
  1719. LeaveCriticalSection ( &g_csProtectCachedCredentials );
  1720. }
  1721. ZeroMemory(pEapTlsCb, sizeof(EAPTLSCB));
  1722. LocalFree(pEapTlsCb);
  1723. }
  1724. return(NO_ERROR);
  1725. }
  1726. /*
  1727. Returns:
  1728. Error codes only from winerror.h, raserror.h or mprerror.h
  1729. Notes:
  1730. Called to reset everything in pEapTlsCb (except awszIdentity, the flag
  1731. indicating whether we are the server/router, fContextReq, pConnProp,
  1732. UserProp and hTokenImpersonateUser) to the initial state, for example, when
  1733. a client gets a TLS Start packet.
  1734. */
  1735. DWORD
  1736. EapTlsReset(
  1737. IN EAPTLSCB* pEapTlsCb
  1738. )
  1739. {
  1740. SECURITY_STATUS Status;
  1741. DWORD dwErr = NO_ERROR;
  1742. DWORD fFlags;
  1743. EapTlsTrace("EapTlsReset");
  1744. RTASSERT(NULL != pEapTlsCb);
  1745. pEapTlsCb->EapTlsState = EAPTLS_STATE_INITIAL;
  1746. EapTlsTrace("State change to %s", g_szEapTlsState[pEapTlsCb->EapTlsState]);
  1747. //
  1748. // Forget all the flags, except whether we are a server/client, router
  1749. // I dont get why this is done here. Something to look at. But it is a
  1750. // day 1 thing.
  1751. //
  1752. fFlags = pEapTlsCb->fFlags;
  1753. pEapTlsCb->fFlags = fFlags & EAPTLSCB_FLAG_SERVER;
  1754. pEapTlsCb->fFlags |= fFlags & EAPTLSCB_FLAG_ROUTER;
  1755. pEapTlsCb->fFlags |= fFlags & EAPTLSCB_FLAG_LOGON;
  1756. pEapTlsCb->fFlags |= fFlags & EAPTLSCB_FLAG_WINLOGON_DATA;
  1757. pEapTlsCb->fFlags |= fFlags & EAPTLSCB_FLAG_NON_INTERACTIVE;
  1758. pEapTlsCb->fFlags |= fFlags & EAPTLSCB_FLAG_FIRST_LINK;
  1759. pEapTlsCb->fFlags |= fFlags & EAPTLSCB_FLAG_MACHINE_AUTH;
  1760. pEapTlsCb->fFlags |= fFlags & EAPTLSCB_FLAG_GUEST_ACCESS;
  1761. pEapTlsCb->fFlags |= fFlags & EAPTLSCB_FLAG_8021X_AUTH;
  1762. pEapTlsCb->fFlags |= fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP;
  1763. pEapTlsCb->fFlags |= fFlags & EAPTLSCB_FLAG_HOSTED_INSIDE_PEAP;
  1764. // awszIdentity, hTokenImpersonateUser, pConnProp, UserProp remain the same
  1765. if (NULL != pEapTlsCb->pCertContext)
  1766. {
  1767. //
  1768. // We are using cached creds now. So no need to
  1769. // release the context
  1770. //
  1771. #if 0
  1772. if ( !(EAPTLSCB_FLAG_SERVER & pEapTlsCb->fFlags ) )
  1773. CertFreeCertificateContext(pEapTlsCb->pCertContext);
  1774. #endif
  1775. // Always returns TRUE;
  1776. pEapTlsCb->pCertContext = NULL;
  1777. }
  1778. if (!(EAPTLSCB_FLAG_HCTXT_INVALID & fFlags))
  1779. {
  1780. Status = DeleteSecurityContext(&pEapTlsCb->hContext);
  1781. if (SEC_E_OK != Status)
  1782. {
  1783. EapTlsTrace("DeleteSecurityContext failed and returned 0x%x",
  1784. Status);
  1785. }
  1786. ZeroMemory(&pEapTlsCb->hContext, sizeof(CtxtHandle));
  1787. }
  1788. if (!(EAPTLSCB_FLAG_HCRED_INVALID & fFlags))
  1789. {
  1790. //
  1791. // Since we cache client ans server creds, we dont
  1792. // free the credentials handle anymore.
  1793. //
  1794. #if 0
  1795. if ( !(EAPTLSCB_FLAG_SERVER & pEapTlsCb->fFlags ) )
  1796. {
  1797. EapTlsTrace("Freeing Credentials handle: flags are 0x%x",
  1798. pEapTlsCb->fFlags);
  1799. //if this is a server we are using cached creds
  1800. Status = FreeCredentialsHandle(&pEapTlsCb->hCredential);
  1801. if (SEC_E_OK != Status)
  1802. {
  1803. EapTlsTrace("FreeCredentialsHandle failed and returned 0x%x",
  1804. Status);
  1805. }
  1806. }
  1807. #endif
  1808. ZeroMemory(&pEapTlsCb->hCredential, sizeof(CredHandle));
  1809. }
  1810. pEapTlsCb->fFlags |= EAPTLSCB_FLAG_HCRED_INVALID;
  1811. pEapTlsCb->fFlags |= EAPTLSCB_FLAG_HCTXT_INVALID;
  1812. if (NULL != pEapTlsCb->pAttributes)
  1813. {
  1814. RasAuthAttributeDestroy(pEapTlsCb->pAttributes);
  1815. pEapTlsCb->pAttributes = NULL;
  1816. }
  1817. // fContextReq remains the same
  1818. LocalFree(pEapTlsCb->pbBlobIn);
  1819. pEapTlsCb->pbBlobIn = NULL;
  1820. pEapTlsCb->cbBlobIn = pEapTlsCb->cbBlobInBuffer = 0;
  1821. pEapTlsCb->dwBlobInRemining = 0;
  1822. LocalFree(pEapTlsCb->pbBlobOut);
  1823. pEapTlsCb->pbBlobOut = NULL;
  1824. pEapTlsCb->cbBlobOut = pEapTlsCb->cbBlobOutBuffer = 0;
  1825. pEapTlsCb->dwBlobOutOffset = pEapTlsCb->dwBlobOutOffsetNew = 0;
  1826. LocalFree(pEapTlsCb->pUIContextData);
  1827. pEapTlsCb->pUIContextData = NULL;
  1828. pEapTlsCb->dwAuthResultCode = NO_ERROR;
  1829. dwErr = GetCredentials(pEapTlsCb);
  1830. if (NO_ERROR == dwErr)
  1831. {
  1832. pEapTlsCb->fFlags &= ~EAPTLSCB_FLAG_HCRED_INVALID;
  1833. }
  1834. return(dwErr);
  1835. }
  1836. /*
  1837. Returns:
  1838. Error codes only from winerror.h, raserror.h or mprerror.h.
  1839. Notes:
  1840. Called to process an incoming packet and/or send a packet. cbSendPacket is
  1841. the size in bytes of the buffer pointed to by pSendPacket.
  1842. */
  1843. DWORD
  1844. EapTlsMakeMessage(
  1845. IN EAPTLSCB* pEapTlsCb,
  1846. IN PPP_EAP_PACKET* pInput,
  1847. OUT PPP_EAP_PACKET* pOutput,
  1848. IN DWORD cbSendPacket,
  1849. OUT PPP_EAP_OUTPUT* pEapOutput,
  1850. IN PPP_EAP_INPUT* pEapInput
  1851. )
  1852. {
  1853. EAPTLS_PACKET* pReceivePacket = (EAPTLS_PACKET*) pInput;
  1854. EAPTLS_PACKET* pSendPacket = (EAPTLS_PACKET*) pOutput;
  1855. DWORD dwErr = NO_ERROR;
  1856. BOOL fServer = FALSE;
  1857. BOOL fRouter = FALSE;
  1858. RTASSERT(NULL != pEapTlsCb);
  1859. RTASSERT(NULL != pEapOutput);
  1860. EapTlsTrace(""); // Blank line
  1861. EapTlsTrace("EapTlsMakeMessage(%ws)",
  1862. pEapTlsCb->awszIdentity ? pEapTlsCb->awszIdentity : L"");
  1863. PrintEapTlsPacket(pReceivePacket, TRUE /* fInput */);
  1864. if (!FValidPacket(pReceivePacket))
  1865. {
  1866. pEapOutput->Action = EAPACTION_NoAction;
  1867. return(ERROR_PPP_INVALID_PACKET);
  1868. }
  1869. fServer = pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER;
  1870. fRouter = pEapTlsCb->fFlags & EAPTLSCB_FLAG_ROUTER;
  1871. if ( !fServer
  1872. && !fRouter
  1873. && !(EAPTLSCB_FLAG_LOGON & pEapTlsCb->fFlags)
  1874. && !(EAPTLSCB_FLAG_MACHINE_AUTH & pEapTlsCb->fFlags)
  1875. && !(EAPTLSCB_FLAG_GUEST_ACCESS & pEapTlsCb->fFlags)
  1876. && !(EAPTLSCB_FLAG_EXECUTING_PEAP & pEapTlsCb->fFlags)
  1877. && !ImpersonateLoggedOnUser(pEapTlsCb->hTokenImpersonateUser))
  1878. {
  1879. dwErr = GetLastError();
  1880. EapTlsTrace("ImpersonateLoggedOnUser(%d) failed and returned 0x%x",
  1881. pEapTlsCb->hTokenImpersonateUser, dwErr);
  1882. pEapOutput->Action = EAPACTION_NoAction;
  1883. return(dwErr);
  1884. }
  1885. if (fServer)
  1886. {
  1887. dwErr = EapTlsSMakeMessage(pEapTlsCb, pReceivePacket, pSendPacket,
  1888. cbSendPacket, pEapOutput, pEapInput);
  1889. }
  1890. else
  1891. {
  1892. dwErr = EapTlsCMakeMessage(pEapTlsCb, pReceivePacket, pSendPacket,
  1893. cbSendPacket, pEapOutput, pEapInput);
  1894. if ( pEapOutput->Action == EAPACTION_Done &&
  1895. pEapOutput->dwAuthResultCode == NO_ERROR
  1896. )
  1897. {
  1898. //
  1899. // Auth is done and result is good Cache Credentials here
  1900. // and we are a client
  1901. if ( !( pEapTlsCb->fFlags & EAPTLSCB_FLAG_USING_CACHED_CREDS )
  1902. )
  1903. {
  1904. //
  1905. // If we are not using cached credentials
  1906. //
  1907. SetCachedCredentials (pEapTlsCb);
  1908. }
  1909. }
  1910. }
  1911. if ( !fServer
  1912. && !fRouter
  1913. && !(EAPTLSCB_FLAG_LOGON & pEapTlsCb->fFlags)
  1914. && !RevertToSelf())
  1915. {
  1916. EapTlsTrace("RevertToSelf failed and returned 0x%x", GetLastError());
  1917. }
  1918. return(dwErr);
  1919. }
  1920. /*
  1921. Returns:
  1922. Notes:
  1923. */
  1924. DWORD
  1925. AssociatePinWithCertificate(
  1926. IN PCCERT_CONTEXT pCertContext,
  1927. IN EAPTLS_USER_PROPERTIES* pUserProp,
  1928. IN BOOL fErasePIN,
  1929. IN BOOL fCheckNullPin,
  1930. IN OUT HCRYPTPROV * phProv
  1931. )
  1932. {
  1933. DWORD cbData;
  1934. CRYPT_KEY_PROV_INFO* pCryptKeyProvInfo = NULL;
  1935. #if 0
  1936. HCRYPTPROV hProv = 0;
  1937. #endif
  1938. DWORD count;
  1939. CHAR* pszPin = NULL;
  1940. UNICODE_STRING UnicodeString;
  1941. DWORD dwErr = NO_ERROR;
  1942. EapTlsTrace("AssociatePinWithCertificate");
  1943. cbData = 0;
  1944. if (!CertGetCertificateContextProperty(
  1945. pCertContext,
  1946. CERT_KEY_PROV_INFO_PROP_ID,
  1947. NULL,
  1948. &cbData))
  1949. {
  1950. dwErr = GetLastError();
  1951. EapTlsTrace("CertGetCertificateContextProperty failed: 0x%x", dwErr);
  1952. goto LDone;
  1953. }
  1954. pCryptKeyProvInfo = LocalAlloc(LPTR, cbData);
  1955. if (NULL == pCryptKeyProvInfo)
  1956. {
  1957. dwErr = GetLastError();
  1958. EapTlsTrace("Out of memory");
  1959. goto LDone;
  1960. }
  1961. if (!CertGetCertificateContextProperty(
  1962. pCertContext,
  1963. CERT_KEY_PROV_INFO_PROP_ID,
  1964. pCryptKeyProvInfo,
  1965. &cbData))
  1966. {
  1967. dwErr = GetLastError();
  1968. EapTlsTrace("CertGetCertificateContextProperty failed: 0x%x", dwErr);
  1969. goto LDone;
  1970. }
  1971. if ( !*phProv )
  1972. {
  1973. if (!CryptAcquireContext(
  1974. phProv,
  1975. pCryptKeyProvInfo->pwszContainerName,
  1976. pCryptKeyProvInfo->pwszProvName,
  1977. pCryptKeyProvInfo->dwProvType,
  1978. (pCryptKeyProvInfo->dwFlags &
  1979. ~CERT_SET_KEY_PROV_HANDLE_PROP_ID) |
  1980. CRYPT_SILENT))
  1981. {
  1982. dwErr = GetLastError();
  1983. EapTlsTrace("CryptAcquireContext failed: 0x%x", dwErr);
  1984. goto LDone;
  1985. }
  1986. }
  1987. if (pUserProp->pwszPin[0] != 0)
  1988. {
  1989. if ( fErasePIN )
  1990. DecodePin(pUserProp);
  1991. count = WideCharToMultiByte(
  1992. CP_UTF8,
  1993. 0,
  1994. pUserProp->pwszPin,
  1995. -1,
  1996. NULL,
  1997. 0,
  1998. NULL,
  1999. NULL);
  2000. if (0 == count)
  2001. {
  2002. dwErr = GetLastError();
  2003. EapTlsTrace("WideCharToMultiByte failed: %d", dwErr);
  2004. goto LDone;
  2005. }
  2006. pszPin = LocalAlloc(LPTR, count);
  2007. if (NULL == pszPin)
  2008. {
  2009. dwErr = GetLastError();
  2010. EapTlsTrace("LocalAlloc failed: 0x%x", dwErr);
  2011. goto LDone;
  2012. }
  2013. count = WideCharToMultiByte(
  2014. CP_UTF8,
  2015. 0,
  2016. pUserProp->pwszPin,
  2017. -1,
  2018. pszPin,
  2019. count,
  2020. NULL,
  2021. NULL);
  2022. if (0 == count)
  2023. {
  2024. dwErr = GetLastError();
  2025. EapTlsTrace("WideCharToMultiByte failed: %d", dwErr);
  2026. goto LDone;
  2027. }
  2028. }
  2029. else
  2030. {
  2031. if ( fCheckNullPin )
  2032. {
  2033. //
  2034. //we got an empty pin. So all we do is an alloc
  2035. //and nothing else.
  2036. //
  2037. pszPin = LocalAlloc(LPTR, 5 );
  2038. if (NULL == pszPin)
  2039. {
  2040. dwErr = GetLastError();
  2041. EapTlsTrace("LocalAlloc failed: 0x%x", dwErr);
  2042. goto LDone;
  2043. }
  2044. count = 2;
  2045. }
  2046. }
  2047. if ( pszPin )
  2048. {
  2049. if (!CryptSetProvParam(
  2050. *phProv,
  2051. PP_KEYEXCHANGE_PIN,
  2052. pszPin,
  2053. 0))
  2054. {
  2055. dwErr = GetLastError();
  2056. EapTlsTrace("CryptSetProvParam failed: 0x%x", dwErr);
  2057. ZeroMemory(pszPin, count);
  2058. goto LDone;
  2059. }
  2060. ZeroMemory(pszPin, count);
  2061. }
  2062. if (!CertSetCertificateContextProperty(
  2063. pCertContext,
  2064. CERT_KEY_PROV_HANDLE_PROP_ID,
  2065. CERT_STORE_NO_CRYPT_RELEASE_FLAG,
  2066. (VOID*)(*phProv)))
  2067. {
  2068. dwErr = GetLastError();
  2069. EapTlsTrace("CertSetCertificateContextProperty failed: 0x%x", dwErr);
  2070. goto LDone;
  2071. }
  2072. // Since I didn't set CERT_STORE_NO_CRYPT_RELEASE_FLAG in the above call,
  2073. // the hProv is implicitly released when either the property is set to NULL
  2074. // or on the final free of the CertContext.
  2075. // - Scratch this note. Now the no release flag is set...
  2076. #if 0
  2077. *phProv = 0;
  2078. #endif
  2079. LDone:
  2080. #if 0
  2081. if (0 != hProv)
  2082. {
  2083. CryptReleaseContext(hProv, 0);
  2084. }
  2085. #endif
  2086. LocalFree(pCryptKeyProvInfo);
  2087. LocalFree(pszPin);
  2088. // Nuke the PIN.
  2089. if ( fErasePIN )
  2090. {
  2091. pUserProp->usLength = 0;
  2092. pUserProp->usMaximumLength = 0;
  2093. ZeroMemory(pUserProp->pwszPin, wcslen(pUserProp->pwszPin) * sizeof(WCHAR));
  2094. }
  2095. return(dwErr);
  2096. }
  2097. void FreeCachedCredentials ( EAPTLSCB * pEapTlsCb )
  2098. {
  2099. EAPTLS_CACHED_CREDS * pNode = NULL;
  2100. EapTlsTrace ("FreeCachedCredentials");
  2101. EnterCriticalSection ( &g_csProtectCachedCredentials );
  2102. pNode = FindNodeInCachedCredList ( pEapTlsCb, FALSE, FALSE );
  2103. if ( pNode )
  2104. {
  2105. RemoveNodeFromCachedCredList ( pNode );
  2106. }
  2107. LeaveCriticalSection ( &g_csProtectCachedCredentials );
  2108. }
  2109. DWORD IsTLSSessionReconnect ( EAPTLSCB * pEapTlsCb,
  2110. BOOL * pfIsReconnect
  2111. )
  2112. {
  2113. DWORD dwRetCode = NO_ERROR;
  2114. SecPkgContext_SessionInfo SessionInfo;
  2115. EapTlsTrace("IsTLSSessionReconnect");
  2116. ZeroMemory ( &SessionInfo, sizeof(SessionInfo) );
  2117. dwRetCode = QueryContextAttributes(&(pEapTlsCb->hContext),
  2118. SECPKG_ATTR_SESSION_INFO,
  2119. (PVOID)&SessionInfo
  2120. );
  2121. if(dwRetCode != SEC_E_OK)
  2122. {
  2123. EapTlsTrace ("QueryContextAttributes failed querying session info 0x%x", dwRetCode);
  2124. }
  2125. else
  2126. {
  2127. *pfIsReconnect = ( SessionInfo.dwFlags & SSL_SESSION_RECONNECT );
  2128. }
  2129. return dwRetCode;
  2130. }
  2131. //
  2132. // TLS Fast reconnect and cookie management functions
  2133. //
  2134. DWORD SetTLSFastReconnect ( EAPTLSCB * pEapTlsCb , BOOL fEnable)
  2135. {
  2136. DWORD dwRetCode = NO_ERROR;
  2137. BOOL fReconnect = FALSE;
  2138. SCHANNEL_SESSION_TOKEN SessionToken = {0};
  2139. SecBufferDesc OutBuffer;
  2140. SecBuffer OutBuffers[1];
  2141. EapTlsTrace ("SetTLSFastReconnect");
  2142. dwRetCode = IsTLSSessionReconnect ( pEapTlsCb, &fReconnect );
  2143. if ( SEC_E_OK != dwRetCode )
  2144. {
  2145. return dwRetCode;
  2146. }
  2147. if ( fEnable )
  2148. {
  2149. //
  2150. // We ahve been asked to enable fast reconnects.
  2151. // Check to see if we are already enabled for reconnects
  2152. // If so, we dont have to do this again.
  2153. //
  2154. if ( fReconnect )
  2155. {
  2156. EapTlsTrace ("The session is already setup for reconnects. No need to enable.");
  2157. return NO_ERROR;
  2158. }
  2159. }
  2160. else
  2161. {
  2162. if ( !fReconnect )
  2163. {
  2164. EapTlsTrace("The session is not setup for fast reconnects. No need to disable.");
  2165. return NO_ERROR;
  2166. }
  2167. }
  2168. SessionToken.dwTokenType = SCHANNEL_SESSION;
  2169. SessionToken.dwFlags =
  2170. ( fEnable ? SSL_SESSION_ENABLE_RECONNECTS:
  2171. SSL_SESSION_DISABLE_RECONNECTS
  2172. );
  2173. OutBuffers[0].pvBuffer = &SessionToken;
  2174. OutBuffers[0].BufferType = SECBUFFER_TOKEN;
  2175. OutBuffers[0].cbBuffer = sizeof(SessionToken);
  2176. OutBuffer.cBuffers = 1;
  2177. OutBuffer.pBuffers = OutBuffers;
  2178. OutBuffer.ulVersion = SECBUFFER_VERSION;
  2179. dwRetCode = ApplyControlToken (&(pEapTlsCb->hContext), &OutBuffer);
  2180. if(dwRetCode != SEC_E_OK)
  2181. {
  2182. EapTlsTrace("Error enabling Fast Reconnects : 0x%x", dwRetCode);
  2183. }
  2184. else
  2185. {
  2186. EapTlsTrace ("Fast Reconnects Enabled/Disabled");
  2187. }
  2188. return dwRetCode;
  2189. }
  2190. //
  2191. // Get Session Cookie information
  2192. //
  2193. DWORD GetTLSSessionCookie ( EAPTLSCB * pEapTlsCb,
  2194. PBYTE * ppbCookie,
  2195. DWORD * pdwCookie,
  2196. BOOL * pfIsReconnect
  2197. )
  2198. {
  2199. DWORD dwRetCode = NO_ERROR;
  2200. SecPkgContext_SessionAppData AppData;
  2201. RTASSERT(NULL != pEapTlsCb);
  2202. RTASSERT(NULL != ppbCookie);
  2203. RTASSERT(NULL != pdwCookie);
  2204. EapTlsTrace ("GetTLSSessionCookie");
  2205. *ppbCookie = NULL;
  2206. *pdwCookie = 0;
  2207. *pfIsReconnect = FALSE;
  2208. dwRetCode = IsTLSSessionReconnect ( pEapTlsCb,
  2209. pfIsReconnect
  2210. );
  2211. if(dwRetCode != SEC_E_OK)
  2212. {
  2213. EapTlsTrace ("QueryContextAttributes failed querying session info 0x%x", dwRetCode);
  2214. }
  2215. else
  2216. {
  2217. if ( *pfIsReconnect )
  2218. {
  2219. EapTlsTrace ("Session Reconnected.");
  2220. *pfIsReconnect = TRUE;
  2221. //
  2222. // Get the cookie
  2223. //
  2224. ZeroMemory(&AppData, sizeof(AppData));
  2225. dwRetCode = QueryContextAttributes(&(pEapTlsCb->hContext),
  2226. SECPKG_ATTR_APP_DATA,
  2227. (PVOID)&AppData);
  2228. if(dwRetCode != SEC_E_OK)
  2229. {
  2230. EapTlsTrace("QueryContextAttributes failed querying session cookie. Error 0x%x", dwRetCode);
  2231. }
  2232. else
  2233. {
  2234. *ppbCookie = (PBYTE)LocalAlloc (LPTR, AppData.cbAppData );
  2235. if ( NULL == *ppbCookie )
  2236. {
  2237. EapTlsTrace("Failed allocating memory for session cookie");
  2238. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  2239. }
  2240. else
  2241. {
  2242. CopyMemory( *ppbCookie, AppData.pbAppData, AppData.cbAppData );
  2243. *pdwCookie = AppData.cbAppData;
  2244. }
  2245. // Free returned buffer.
  2246. FreeContextBuffer(AppData.pbAppData);
  2247. }
  2248. }
  2249. }
  2250. return dwRetCode;
  2251. }
  2252. //
  2253. // Setup the session attributes to set the cookie and to enable/disable
  2254. // session reconnects
  2255. //
  2256. DWORD SetTLSSessionCookie ( EAPTLSCB * pEapTlsCb,
  2257. PBYTE pbCookie,
  2258. DWORD cbCookie
  2259. )
  2260. {
  2261. DWORD dwRetCode = NO_ERROR;
  2262. SecPkgContext_SessionAppData AppData;
  2263. EapTlsTrace ("SetTLSSessionCookie");
  2264. ZeroMemory(&AppData, sizeof(AppData));
  2265. AppData.pbAppData = pbCookie;
  2266. AppData.cbAppData = cbCookie;
  2267. dwRetCode = SetContextAttributes(&(pEapTlsCb->hContext),
  2268. SECPKG_ATTR_APP_DATA,
  2269. (PVOID)&AppData,
  2270. sizeof(AppData)
  2271. );
  2272. if(dwRetCode != SEC_E_OK)
  2273. {
  2274. EapTlsTrace ("SetContextAttributes returned error 0x%x setting session cookie\n", dwRetCode);
  2275. }
  2276. else
  2277. {
  2278. EapTlsTrace ("Session cookie set successfully \n");
  2279. }
  2280. return dwRetCode;
  2281. }
  2282. void SetCachedCredentials (EAPTLSCB * pEapTlsCb)
  2283. {
  2284. DWORD dwRetCode = NO_ERROR;
  2285. EapTlsTrace("SetCachedCredentials Flags = 0x%x", pEapTlsCb->fFlags);
  2286. EnterCriticalSection ( &g_csProtectCachedCredentials );
  2287. dwRetCode = AddNodeToCachedCredList ( pEapTlsCb );
  2288. LeaveCriticalSection ( &g_csProtectCachedCredentials );
  2289. return;
  2290. }
  2291. BOOL GetCachedCredentials ( EAPTLSCB * pEapTlsCb, BOOL fDefaultCachedCreds )
  2292. {
  2293. EAPTLS_CACHED_CREDS * pNode = NULL;
  2294. DWORD dwRetCode = NO_ERROR;
  2295. EapTlsTrace("GetCachedCredentials Flags = 0x%x", pEapTlsCb->fFlags);
  2296. EnterCriticalSection ( &g_csProtectCachedCredentials );
  2297. if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_MACHINE_AUTH )
  2298. {
  2299. pNode = FindNodeInCachedCredList ( pEapTlsCb, fDefaultCachedCreds, FALSE );
  2300. }
  2301. else
  2302. {
  2303. pNode = FindNodeInCachedCredList ( pEapTlsCb, fDefaultCachedCreds, TRUE );
  2304. }
  2305. //
  2306. // Check to see if a private key operation can be done successfully
  2307. // using this smart card cached cred.
  2308. // If not, wipe out the cached cred from
  2309. // the list and return FALSE
  2310. //
  2311. if ( pNode
  2312. && !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER)
  2313. && !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_WINLOGON_DATA)
  2314. && !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_GUEST_ACCESS)
  2315. && !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP)
  2316. && !( pEapTlsCb->pConnProp->fFlags & EAPTLS_CONN_FLAG_REGISTRY)
  2317. )
  2318. {
  2319. DecodePin(pEapTlsCb->pUserProp);
  2320. dwRetCode = AssociatePinWithCertificate( pNode->pcCachedCertContext,
  2321. pEapTlsCb->pUserProp,
  2322. FALSE,
  2323. TRUE,
  2324. &(pNode->hCachedProv)
  2325. );
  2326. EncodePin(pEapTlsCb->pUserProp);
  2327. #if 0
  2328. //DecodePin(pEapTlsCb->pUserProp);
  2329. //
  2330. // Force it not to associate the pin to see if
  2331. // we can use the cached pin.
  2332. //
  2333. dwRetCode =
  2334. MatchPublicPrivateKeys ( pNode->pcCachedCertContext,
  2335. FALSE,
  2336. NULL
  2337. );
  2338. //EncodePin(pEapTlsCb->pUserProp);
  2339. if ( NO_ERROR != dwRetCode )
  2340. {
  2341. EapTlsTrace ( "Found cached cred but cannot access private key. Hence removing node");
  2342. RemoveNodeFromCachedCredList ( pNode );
  2343. pNode = NULL;
  2344. }
  2345. #endif
  2346. }
  2347. if ( NULL != pNode )
  2348. {
  2349. //
  2350. // Found the cached cred node. Setup the cred in the control block
  2351. //
  2352. EapTlsTrace("GetCachedCredentials: Using Cached Credentials");
  2353. EapTlsTrace("GetCachedCredentials: Hash of the cert in the cache is");
  2354. TraceDumpEx(g_dwEapTlsTraceId, 1, pEapTlsCb->pUserProp->Hash.pbHash, 20, 1,1,NULL);
  2355. CopyMemory ( &(pEapTlsCb->hCredential),
  2356. &(pNode->hCachedCredential),
  2357. sizeof(CredHandle)
  2358. );
  2359. pEapTlsCb->pCertContext = pNode->pcCachedCertContext;
  2360. }
  2361. LeaveCriticalSection( &g_csProtectCachedCredentials );
  2362. return ( pNode != NULL );
  2363. }
  2364. /*
  2365. Returns:
  2366. Error codes only from winerror.h, raserror.h or mprerror.h
  2367. Notes:
  2368. Get the credentials. fServer is TRUE iff we are the server. Remember to
  2369. call FreeCredentialsHandle(hCredential) at some point.
  2370. */
  2371. DWORD
  2372. GetCredentials(
  2373. IN EAPTLSCB* pEapTlsCb
  2374. )
  2375. {
  2376. SCHANNEL_CRED SchannelCred;
  2377. TimeStamp tsExpiry;
  2378. DWORD dwErr = NO_ERROR;
  2379. SECURITY_STATUS Status;
  2380. HCERTSTORE hCertStore = NULL;
  2381. PCCERT_CONTEXT pCertContext = NULL;
  2382. DWORD dwCertFlags;
  2383. DWORD dwSchCredFlags = 0;
  2384. BOOL fServer = FALSE;
  2385. BOOL fRouter = FALSE;
  2386. WCHAR* pwszName = NULL;
  2387. DWORD cbData = sizeof (DWORD);
  2388. CRYPT_HASH_BLOB HashBlob;
  2389. EapTlsTrace("GetCredentials");
  2390. if (pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER)
  2391. {
  2392. fServer = TRUE;
  2393. dwCertFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
  2394. EapTlsTrace("Flag is Server and Store is local Machine");
  2395. }
  2396. else if (pEapTlsCb->fFlags & EAPTLSCB_FLAG_ROUTER)
  2397. {
  2398. fRouter = TRUE;
  2399. dwCertFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
  2400. EapTlsTrace("Flag is Router and Store is local Machine");
  2401. }
  2402. else if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_MACHINE_AUTH )
  2403. {
  2404. dwCertFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
  2405. EapTlsTrace("Flag is Machine Auth and Store is local Machine");
  2406. }
  2407. else
  2408. {
  2409. dwCertFlags = CERT_SYSTEM_STORE_CURRENT_USER;
  2410. EapTlsTrace("Flag is Client and Store is Current User");
  2411. }
  2412. if ( !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER)
  2413. && !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_WINLOGON_DATA)
  2414. && !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_GUEST_ACCESS)
  2415. && !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP)
  2416. )
  2417. {
  2418. if( !(pEapTlsCb->pConnProp->fFlags & EAPTLS_CONN_FLAG_REGISTRY)
  2419. && (pEapTlsCb->pUserProp->pwszPin[0] != 0))
  2420. {
  2421. //
  2422. // Make a copy of the pin and save it in the control block
  2423. // for saving it in the credmgr. This will be wiped out
  2424. // when ppp engine queries for the creds.
  2425. //
  2426. DecodePin(pEapTlsCb->pUserProp);
  2427. pEapTlsCb->pSavedPin = LocalAlloc(LPTR,
  2428. sizeof(EAPTLS_PIN));
  2429. if(NULL != pEapTlsCb->pSavedPin)
  2430. {
  2431. pEapTlsCb->pSavedPin->pwszPin =
  2432. LocalAlloc(LPTR,
  2433. sizeof(WCHAR) *
  2434. (wcslen(pEapTlsCb->pUserProp->pwszPin) + 1));
  2435. if(NULL != pEapTlsCb->pSavedPin->pwszPin)
  2436. {
  2437. UNICODE_STRING UnicodeStringPin;
  2438. UCHAR ucSeed = 0;
  2439. wcscpy(pEapTlsCb->pSavedPin->pwszPin,
  2440. pEapTlsCb->pUserProp->pwszPin);
  2441. RtlInitUnicodeString(&UnicodeStringPin,
  2442. pEapTlsCb->pSavedPin->pwszPin);
  2443. RtlRunEncodeUnicodeString(&ucSeed, &UnicodeStringPin);
  2444. pEapTlsCb->pSavedPin->usLength = UnicodeStringPin.Length;
  2445. pEapTlsCb->pSavedPin->usMaximumLength =
  2446. UnicodeStringPin.MaximumLength;
  2447. pEapTlsCb->pSavedPin->ucSeed = ucSeed;
  2448. }
  2449. else
  2450. {
  2451. LocalFree(pEapTlsCb->pSavedPin);
  2452. pEapTlsCb->pSavedPin = NULL;
  2453. }
  2454. }
  2455. EncodePin(pEapTlsCb->pUserProp);
  2456. }
  2457. }
  2458. //Check to see if we can get cached credentials
  2459. if ( GetCachedCredentials ( pEapTlsCb, FALSE ) )
  2460. {
  2461. //got cached creds
  2462. pEapTlsCb->fFlags |= EAPTLSCB_FLAG_USING_CACHED_CREDS;
  2463. goto LDone;
  2464. }
  2465. if (EAPTLSCB_FLAG_WINLOGON_DATA & pEapTlsCb->fFlags)
  2466. {
  2467. dwErr = GetCertFromLogonInfo(pEapTlsCb->pUserData,
  2468. pEapTlsCb->dwSizeOfUserData, &pCertContext);
  2469. if (NO_ERROR != dwErr)
  2470. {
  2471. goto LDone;
  2472. }
  2473. }
  2474. else
  2475. {
  2476. if ( ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_GUEST_ACCESS ||
  2477. pEapTlsCb->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP
  2478. )
  2479. && !fServer && !fRouter )
  2480. {
  2481. //if this is guest access and this is a client then
  2482. //no need to get the cert etc.
  2483. EapTlsTrace("No Cert Store. Guest Access requested");
  2484. }
  2485. else
  2486. {
  2487. // Open the "MY" certificate store.
  2488. hCertStore = CertOpenStore(
  2489. CERT_STORE_PROV_SYSTEM_A,
  2490. X509_ASN_ENCODING,
  2491. 0,
  2492. dwCertFlags | CERT_STORE_READONLY_FLAG,
  2493. "MY");
  2494. if (NULL == hCertStore)
  2495. {
  2496. dwErr = GetLastError();
  2497. EapTlsTrace("CertOpenStore failed and returned 0x%x", dwErr);
  2498. goto LDone;
  2499. }
  2500. HashBlob.cbData = pEapTlsCb->pUserProp->Hash.cbHash;
  2501. HashBlob.pbData = pEapTlsCb->pUserProp->Hash.pbHash;
  2502. pCertContext = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING,
  2503. 0, CERT_FIND_HASH, &HashBlob, NULL);
  2504. if ( pCertContext )
  2505. {
  2506. //
  2507. // Check to see if the cert that we're configured for is renewed.
  2508. // If so, throw out the cred. And go for the default cred.
  2509. // Since we cannot save back out config, thanks to ashwinp,
  2510. // and his reluctance to change IAS design to allow IAS to
  2511. // save the eap config per policy,
  2512. // we cannot update the config with renewed cert.
  2513. //
  2514. if(CertGetCertificateContextProperty(pCertContext,
  2515. CERT_ARCHIVED_PROP_ID,
  2516. NULL,
  2517. &cbData))
  2518. {
  2519. CertFreeCertificateContext(pCertContext);
  2520. pCertContext = NULL;
  2521. EapTlsTrace ("Configured Certificate is archived most likely because of autoenrollment. Going after the default cert");
  2522. }
  2523. }
  2524. if (NULL == pCertContext)
  2525. {
  2526. if ( fServer
  2527. || fRouter)
  2528. {
  2529. WCHAR* apwsz[1];
  2530. //
  2531. //Check to see if we can get default cached credentials
  2532. //Rather than creating a new credential.
  2533. //
  2534. if ( GetCachedCredentials ( pEapTlsCb, TRUE ) )
  2535. {
  2536. EapTlsTrace ("Using cached credentials for default machine cert.");
  2537. //got cached creds
  2538. pEapTlsCb->fFlags |= EAPTLSCB_FLAG_USING_CACHED_CREDS;
  2539. goto LDone;
  2540. }
  2541. apwsz[0] = pEapTlsCb->awszIdentity;
  2542. if (0 == HashBlob.cbData)
  2543. {
  2544. RouterLogInformation(pEapTlsCb->hEventLog,
  2545. ROUTERLOG_EAP_TLS_CERT_NOT_CONFIGURED, 1, apwsz, 0);
  2546. }
  2547. else
  2548. {
  2549. RouterLogWarning(pEapTlsCb->hEventLog,
  2550. ROUTERLOG_EAP_TLS_CERT_NOT_FOUND, 1, apwsz, 0);
  2551. }
  2552. dwErr = GetDefaultMachineCert(hCertStore, &pCertContext);
  2553. if (NO_ERROR != dwErr)
  2554. {
  2555. goto LDone;
  2556. }
  2557. pEapTlsCb->fFlags |= EAPTLSCB_FLAG_USING_DEFAULT_CREDS;
  2558. //Now set the user property correctly so that next time we
  2559. //can find the certificate
  2560. pEapTlsCb->pUserProp->Hash.cbHash = MAX_HASH_SIZE;
  2561. if (!CertGetCertificateContextProperty(pCertContext,
  2562. CERT_HASH_PROP_ID, pEapTlsCb->pUserProp->Hash.pbHash,
  2563. &(pEapTlsCb->pUserProp->Hash.cbHash)))
  2564. {
  2565. //not an issue if it fails here.
  2566. //next time on it will get the default machine cert again
  2567. EapTlsTrace("CertGetCertificateContextProperty failed and "
  2568. "returned 0x%x", GetLastError());
  2569. }
  2570. #if 0
  2571. //
  2572. //Should not be an issue if this fails
  2573. //Write the config back to the registry
  2574. //It will always be local registry here
  2575. //
  2576. ServerConfigDataIO( FALSE ,
  2577. NULL ,
  2578. (PBYTE *)&(pEapTlsCb->pUserProp),
  2579. sizeof(EAPTLS_USER_PROPERTIES)
  2580. );
  2581. #endif
  2582. }
  2583. else
  2584. {
  2585. dwErr = GetLastError();
  2586. EapTlsTrace("CertFindCertificateInStore failed and returned "
  2587. "0x%x", dwErr);
  2588. goto LDone;
  2589. }
  2590. }
  2591. }
  2592. }
  2593. if ( !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER)
  2594. && !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_WINLOGON_DATA)
  2595. && !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_GUEST_ACCESS)
  2596. && !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP)
  2597. )
  2598. {
  2599. if( !(pEapTlsCb->pConnProp->fFlags & EAPTLS_CONN_FLAG_REGISTRY)
  2600. && (pEapTlsCb->pUserProp->pwszPin[0] != 0))
  2601. {
  2602. //
  2603. // Make a copy of the pin and save it in the control block
  2604. // for saving it in the credmgr. This will be wiped out
  2605. // when ppp engine queries for the creds.
  2606. //
  2607. DecodePin(pEapTlsCb->pUserProp);
  2608. pEapTlsCb->pSavedPin = LocalAlloc(LPTR,
  2609. sizeof(EAPTLS_PIN));
  2610. if(NULL != pEapTlsCb->pSavedPin)
  2611. {
  2612. pEapTlsCb->pSavedPin->pwszPin =
  2613. LocalAlloc(LPTR,
  2614. sizeof(WCHAR) *
  2615. (wcslen(pEapTlsCb->pUserProp->pwszPin) + 1));
  2616. if(NULL != pEapTlsCb->pSavedPin->pwszPin)
  2617. {
  2618. UNICODE_STRING UnicodeStringPin;
  2619. UCHAR ucSeed = 0;
  2620. wcscpy(pEapTlsCb->pSavedPin->pwszPin,
  2621. pEapTlsCb->pUserProp->pwszPin);
  2622. RtlInitUnicodeString(&UnicodeStringPin,
  2623. pEapTlsCb->pSavedPin->pwszPin);
  2624. RtlRunEncodeUnicodeString(&ucSeed, &UnicodeStringPin);
  2625. pEapTlsCb->pSavedPin->usLength = UnicodeStringPin.Length;
  2626. pEapTlsCb->pSavedPin->usMaximumLength =
  2627. UnicodeStringPin.MaximumLength;
  2628. pEapTlsCb->pSavedPin->ucSeed = ucSeed;
  2629. }
  2630. else
  2631. {
  2632. LocalFree(pEapTlsCb->pSavedPin);
  2633. pEapTlsCb->pSavedPin = NULL;
  2634. }
  2635. }
  2636. EncodePin(pEapTlsCb->pUserProp);
  2637. }
  2638. dwErr = AssociatePinWithCertificate(
  2639. pCertContext,
  2640. pEapTlsCb->pUserProp,
  2641. TRUE,
  2642. !(pEapTlsCb->pConnProp->fFlags & EAPTLS_CONN_FLAG_REGISTRY),
  2643. &(pEapTlsCb->hProv)
  2644. );
  2645. if (NO_ERROR != dwErr)
  2646. {
  2647. goto LDone;
  2648. }
  2649. }
  2650. if ( !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_GUEST_ACCESS ) &&
  2651. !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP )
  2652. )
  2653. {
  2654. if (FCertToStr(pCertContext, 0, fServer || fRouter, &pwszName))
  2655. {
  2656. EapTlsTrace("The name in the certificate is: %ws", pwszName);
  2657. LocalFree(pwszName);
  2658. }
  2659. }
  2660. else
  2661. {
  2662. EapTlsTrace("No Cert Name. Guest access requested");
  2663. }
  2664. // Build Schannel credential structure.
  2665. ZeroMemory(&SchannelCred, sizeof(SchannelCred));
  2666. SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
  2667. if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_GUEST_ACCESS ||
  2668. pEapTlsCb->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP
  2669. )
  2670. {
  2671. //Guest Access and server so set the cert context
  2672. //or elase there is no need.
  2673. if ( fServer )
  2674. {
  2675. SchannelCred.cCreds = 1;
  2676. SchannelCred.paCred = &pCertContext;
  2677. }
  2678. }
  2679. else
  2680. {
  2681. SchannelCred.cCreds = 1;
  2682. SchannelCred.paCred = &pCertContext;
  2683. }
  2684. SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1;
  2685. if (fServer)
  2686. {
  2687. if (!g_fNoRevocationCheck)
  2688. {
  2689. if (g_fNoRootRevocationCheck)
  2690. {
  2691. dwSchCredFlags = SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
  2692. }
  2693. else
  2694. {
  2695. dwSchCredFlags = SCH_CRED_REVOCATION_CHECK_CHAIN;
  2696. }
  2697. if (g_fIgnoreNoRevocationCheck)
  2698. {
  2699. dwSchCredFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK;
  2700. }
  2701. if (g_fIgnoreRevocationOffline)
  2702. {
  2703. dwSchCredFlags |= SCH_CRED_IGNORE_REVOCATION_OFFLINE;
  2704. }
  2705. }
  2706. //
  2707. // Start with disabling fast for PEAP reconnects.
  2708. // Once the full handshake is done,
  2709. // decide if we want to allow reconnects.
  2710. //
  2711. dwSchCredFlags |= SCH_CRED_DISABLE_RECONNECTS;
  2712. }
  2713. else
  2714. {
  2715. dwSchCredFlags = SCH_CRED_NO_SERVERNAME_CHECK |
  2716. SCH_CRED_NO_DEFAULT_CREDS;
  2717. if (EAPTLS_CONN_FLAG_NO_VALIDATE_CERT & pEapTlsCb->pConnProp->fFlags)
  2718. {
  2719. dwSchCredFlags |= SCH_CRED_MANUAL_CRED_VALIDATION;
  2720. EapTlsTrace("Will NOT validate server cert");
  2721. }
  2722. else
  2723. {
  2724. dwSchCredFlags |= SCH_CRED_AUTO_CRED_VALIDATION;
  2725. EapTlsTrace("Will validate server cert");
  2726. }
  2727. }
  2728. SchannelCred.dwFlags = dwSchCredFlags;
  2729. // Create the SSPI credentials.
  2730. Status = AcquireCredentialsHandle(
  2731. NULL, // Name of principal
  2732. UNISP_NAME, // Name of package
  2733. // Flags indicating use
  2734. fServer ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
  2735. NULL, // Pointer to logon ID
  2736. &SchannelCred, // Package specific data
  2737. NULL, // Pointer to GetKey() func
  2738. NULL, // Value to pass to GetKey()
  2739. &(pEapTlsCb->hCredential), // (out) Credential Handle
  2740. &tsExpiry); // (out) Lifetime (optional)
  2741. if (SEC_E_OK != Status)
  2742. {
  2743. dwErr = Status;
  2744. EapTlsTrace("AcquireCredentialsHandle failed and returned 0x%x", dwErr);
  2745. goto LDone;
  2746. }
  2747. // We needn't store the cert context if we get it by calling
  2748. // CertFindCertificateInStore. However, if we get it by calling
  2749. // ScHelperGetCertFromLogonInfo, and we free it, then the hProv will become
  2750. // invalid. In the former case, there is no hProv associated with the cert
  2751. // context and schannel does the CryptAcquireContext itself. In the latter
  2752. // case, there is an hProv associated, and it is invalid after the cert
  2753. // context is freed.
  2754. pEapTlsCb->pCertContext = pCertContext;
  2755. pCertContext = NULL;
  2756. //
  2757. // If we are a server set cached creds here
  2758. //
  2759. if ( fServer )
  2760. {
  2761. SetCachedCredentials ( pEapTlsCb );
  2762. }
  2763. LDone:
  2764. if (NULL != pCertContext)
  2765. {
  2766. CertFreeCertificateContext(pCertContext);
  2767. // Always returns TRUE;
  2768. }
  2769. if (NULL != hCertStore)
  2770. {
  2771. if (!CertCloseStore(hCertStore, 0))
  2772. {
  2773. EapTlsTrace("CertCloseStore failed and returned 0x%x",
  2774. GetLastError());
  2775. }
  2776. }
  2777. if ( (dwErr != NO_ERROR)
  2778. && fServer)
  2779. {
  2780. RouterLogErrorString(pEapTlsCb->hEventLog,
  2781. ROUTERLOG_CANT_GET_SERVER_CRED, 0, NULL, dwErr, 0);
  2782. }
  2783. return(dwErr);
  2784. }
  2785. /*
  2786. Returns:
  2787. Error codes only from winerror.h, raserror.h or mprerror.h.
  2788. Notes:
  2789. Looks at *pEapTlsCb and builds an EAP TLS packet in *pSendPacket.
  2790. cbSendPacket is the number of bytes available in pSendPacket.
  2791. This function looks at the fields bCode, bId, fFlags, cbBlobOut, pbBlobOut,
  2792. and dwBlobOutOffset in pEapTlsCb. It may also set the field
  2793. dwBlobOutOffsetNew.
  2794. */
  2795. DWORD
  2796. BuildPacket(
  2797. OUT EAPTLS_PACKET* pSendPacket,
  2798. IN DWORD cbSendPacket,
  2799. IN EAPTLSCB* pEapTlsCb
  2800. )
  2801. {
  2802. WORD wLength;
  2803. BOOL fLengthIncluded = FALSE;
  2804. DWORD dwBytesRemaining;
  2805. DWORD dwBytesToBeSent;
  2806. DWORD dwErr = NO_ERROR;
  2807. EapTlsTrace("BuildPacket");
  2808. RTASSERT(NULL != pEapTlsCb);
  2809. if (0xFFFF < cbSendPacket)
  2810. {
  2811. // We never send more than 0xFFFF bytes at a time, since the length
  2812. // field in EAPTLS_PACKET has two octets
  2813. cbSendPacket = 0xFFFF;
  2814. }
  2815. if ( (NULL == pSendPacket)
  2816. || (cbSendPacket < PPP_EAP_PACKET_HDR_LEN))
  2817. {
  2818. EapTlsTrace("pSendPacket is NULL or too small (size: %d)",
  2819. cbSendPacket);
  2820. dwErr = TYPE_E_BUFFERTOOSMALL;
  2821. goto LDone;
  2822. }
  2823. pSendPacket->bCode = pEapTlsCb->bCode;
  2824. pSendPacket->bId = pEapTlsCb->bId;
  2825. HostToWireFormat16(PPP_EAP_PACKET_HDR_LEN, pSendPacket->pbLength);
  2826. switch (pEapTlsCb->bCode)
  2827. {
  2828. case EAPCODE_Success:
  2829. case EAPCODE_Failure:
  2830. goto LDone;
  2831. break;
  2832. case EAPCODE_Request:
  2833. case EAPCODE_Response:
  2834. if (cbSendPacket < EAPTLS_PACKET_HDR_LEN_MAX +
  2835. 1 /* Send at least one octet of the TLS blob */)
  2836. {
  2837. // We are being conservative here. It is possible that the buffer
  2838. // is not really too small.
  2839. EapTlsTrace("pSendPacket is too small. Size: %d", cbSendPacket);
  2840. dwErr = TYPE_E_BUFFERTOOSMALL;
  2841. goto LDone;
  2842. }
  2843. // pSendPacket->bCode = pEapTlsCb->bCode;
  2844. // pSendPacket->bId = pEapTlsCb->bId;
  2845. pSendPacket->bType = PPP_EAP_TLS;
  2846. pSendPacket->bFlags = 0;
  2847. break;
  2848. default:
  2849. EapTlsTrace("Unknown EAP code: %d", pEapTlsCb->bCode);
  2850. RTASSERT(FALSE);
  2851. dwErr = E_FAIL;
  2852. goto LDone;
  2853. break;
  2854. }
  2855. // If we reach here, it means that the packet is a request or a response
  2856. if ( (0 == pEapTlsCb->cbBlobOut)
  2857. || (NULL == pEapTlsCb->pbBlobOut))
  2858. {
  2859. // We want to send an empty request or response
  2860. if ( (EAPTLSCB_FLAG_SERVER & pEapTlsCb->fFlags)
  2861. && (EAPTLS_STATE_INITIAL == pEapTlsCb->EapTlsState))
  2862. {
  2863. pSendPacket->bFlags |= EAPTLS_PACKET_FLAG_TLS_START;
  2864. }
  2865. HostToWireFormat16(EAPTLS_PACKET_HDR_LEN, pSendPacket->pbLength);
  2866. goto LDone;
  2867. }
  2868. // If we reach here, it means that the packet is a non empty request or
  2869. // response.
  2870. if (0 == pEapTlsCb->dwBlobOutOffset)
  2871. {
  2872. // We are sending the first bytes of the blob. Let us tell the peer how
  2873. // big the blob is
  2874. fLengthIncluded = TRUE;
  2875. pSendPacket->bFlags |= EAPTLS_PACKET_FLAG_LENGTH_INCL;
  2876. wLength = EAPTLS_PACKET_HDR_LEN_MAX;
  2877. }
  2878. else
  2879. {
  2880. wLength = EAPTLS_PACKET_HDR_LEN;
  2881. }
  2882. dwBytesRemaining = pEapTlsCb->cbBlobOut - pEapTlsCb->dwBlobOutOffset;
  2883. dwBytesToBeSent = cbSendPacket - wLength;
  2884. if (dwBytesRemaining < dwBytesToBeSent)
  2885. {
  2886. dwBytesToBeSent = dwBytesRemaining;
  2887. }
  2888. if (dwBytesRemaining > dwBytesToBeSent)
  2889. {
  2890. // We need to send more fragments
  2891. pSendPacket->bFlags |= EAPTLS_PACKET_FLAG_MORE_FRAGMENTS;
  2892. }
  2893. RTASSERT(dwBytesToBeSent + EAPTLS_PACKET_HDR_LEN_MAX <= 0xFFFF);
  2894. wLength += (WORD) dwBytesToBeSent;
  2895. HostToWireFormat16(wLength, pSendPacket->pbLength);
  2896. if (fLengthIncluded)
  2897. {
  2898. HostToWireFormat32(pEapTlsCb->cbBlobOut, pSendPacket->pbData);
  2899. }
  2900. RTASSERT(NULL != pEapTlsCb->pbBlobOut);
  2901. CopyMemory(pSendPacket->pbData + (fLengthIncluded ? 4 : 0),
  2902. pEapTlsCb->pbBlobOut + pEapTlsCb->dwBlobOutOffset,
  2903. dwBytesToBeSent);
  2904. pEapTlsCb->dwBlobOutOffsetNew = pEapTlsCb->dwBlobOutOffset +
  2905. dwBytesToBeSent;
  2906. LDone:
  2907. if (NO_ERROR == dwErr)
  2908. {
  2909. PrintEapTlsPacket(pSendPacket, FALSE /* fInput */);
  2910. }
  2911. return(dwErr);
  2912. }
  2913. /*
  2914. Returns:
  2915. Error codes only from winerror.h, raserror.h or mprerror.h.
  2916. Notes:
  2917. The pwszIdentity obtained from PPP_EAP_INPUT (on the server side) is of the
  2918. form <DOMAIN>\<user>.
  2919. We ask schannel to map the cert to a user object, get the user name and
  2920. domain name, and make sure that they match pwszIdentity.
  2921. */
  2922. DWORD
  2923. CheckUserName(
  2924. IN CtxtHandle hContext,
  2925. IN WCHAR* pwszIdentity
  2926. )
  2927. {
  2928. DWORD dwErr = NO_ERROR;
  2929. SECURITY_STATUS Status;
  2930. HANDLE Token;
  2931. BOOL fTokenAcquired = FALSE;
  2932. BOOL fImpersonating = FALSE;
  2933. DWORD dwNumChars;
  2934. WCHAR pwszUserName[UNLEN + DNLEN + 2];
  2935. EapTlsTrace("CheckUserName");
  2936. Status = QuerySecurityContextToken(&hContext, &Token);
  2937. if (SEC_E_OK != Status)
  2938. {
  2939. EapTlsTrace("QuerySecurityContextToken failed and returned 0x%x",
  2940. Status);
  2941. dwErr = Status;
  2942. goto LDone;
  2943. }
  2944. fTokenAcquired = TRUE;
  2945. if (!ImpersonateLoggedOnUser(Token))
  2946. {
  2947. dwErr = GetLastError();
  2948. EapTlsTrace("ImpersonateLoggedOnUser failed and returned 0x%x",
  2949. dwErr);
  2950. goto LDone;
  2951. }
  2952. fImpersonating = TRUE;
  2953. dwNumChars = UNLEN + DNLEN + 2;
  2954. if (!GetUserNameEx(NameSamCompatible, pwszUserName, &dwNumChars))
  2955. {
  2956. dwErr = GetLastError();
  2957. EapTlsTrace("GetUserNameExA failed and returned %d", dwErr);
  2958. goto LDone;
  2959. }
  2960. if (_wcsicmp(pwszIdentity, pwszUserName))
  2961. {
  2962. EapTlsTrace("The user claims to be %ws, but is actually %ws",
  2963. pwszIdentity, pwszUserName);
  2964. dwErr = SEC_E_LOGON_DENIED;
  2965. goto LDone;
  2966. }
  2967. LDone:
  2968. if (fImpersonating)
  2969. {
  2970. if (!RevertToSelf())
  2971. {
  2972. EapTlsTrace("RevertToSelf failed and returned 0x%x",
  2973. GetLastError());
  2974. }
  2975. }
  2976. if (fTokenAcquired)
  2977. {
  2978. CloseHandle(Token);
  2979. }
  2980. return(dwErr);
  2981. }
  2982. /*
  2983. Returns:
  2984. Error codes only from winerror.h, raserror.h or mprerror.h.
  2985. Notes:
  2986. Checks to see if the cert sent by the server is of the right type.
  2987. Also checks the name in the cert, the issuer, etc, if necessary.
  2988. */
  2989. DWORD
  2990. AuthenticateServer(
  2991. IN EAPTLSCB* pEapTlsCb,
  2992. OUT BOOL* pfWaitForUserOK
  2993. )
  2994. {
  2995. SECURITY_STATUS Status;
  2996. PCERT_CONTEXT pCertContextServer = NULL;
  2997. EAPTLS_HASH Hash;
  2998. EAPTLS_HASH ServerCertHash;
  2999. BOOL fHashOK = FALSE;
  3000. BOOL fNameOK = FALSE;
  3001. WCHAR* pwszRootCAName = NULL;
  3002. WCHAR* pwszServerName = NULL;
  3003. WCHAR* pwszSavedName = NULL;
  3004. WCHAR awszTitle[NUM_CHARS_TITLE];
  3005. WCHAR* pwszFormat = NULL;
  3006. WCHAR* pwszWarning = NULL;
  3007. DWORD dwSizeOfWszWarning;
  3008. DWORD dwStrLenSaved;
  3009. DWORD dwStrLenServer;
  3010. DWORD dwStrLenRootCA;
  3011. EAPTLS_CONN_PROPERTIES_V1 * pConnProp = NULL;
  3012. EAPTLS_VALIDATE_SERVER* pEapTlsValidateServer;
  3013. DWORD dw = 0;
  3014. DWORD dwErr = NO_ERROR;
  3015. PCERT_ENHKEY_USAGE pUsage = NULL;
  3016. DWORD dwSizeOfGPRootHashBlob = 0;
  3017. BOOL fRootCheckRequired = TRUE; //By default root check is required
  3018. HCERTSTORE hCertStore = NULL;
  3019. PBYTE pbHashTemp = NULL;
  3020. EapTlsTrace("AuthenticateServer");
  3021. RTASSERT(NULL != pEapTlsCb);
  3022. *pfWaitForUserOK = FALSE;
  3023. //
  3024. //if we are doing guest authentication, we always have to authenticate the
  3025. //server.
  3026. //
  3027. if ( ! (pEapTlsCb->fFlags & EAPTLSCB_FLAG_GUEST_ACCESS ) &&
  3028. EAPTLS_CONN_FLAG_NO_VALIDATE_CERT & pEapTlsCb->pConnProp->fFlags)
  3029. {
  3030. // We are done
  3031. goto LDone;
  3032. }
  3033. Status = QueryContextAttributes(&(pEapTlsCb->hContext),
  3034. SECPKG_ATTR_REMOTE_CERT_CONTEXT, &pCertContextServer);
  3035. if (SEC_E_OK != Status)
  3036. {
  3037. RTASSERT(NULL == pCertContextServer);
  3038. EapTlsTrace("QueryContextAttributes failed and returned 0x%x", Status);
  3039. dwErr = Status;
  3040. goto LDone;
  3041. }
  3042. if ( ( dwErr = DwGetEKUUsage ( pCertContextServer, &pUsage )) != ERROR_SUCCESS )
  3043. {
  3044. EapTlsTrace("The server's cert does not have the 'Server "
  3045. "Authentication' usage");
  3046. goto LDone;
  3047. }
  3048. if (!FCheckUsage(pCertContextServer, pUsage, TRUE /* fServer */))
  3049. {
  3050. EapTlsTrace("The server's cert does not have the 'Server "
  3051. "Authentication' usage");
  3052. dwErr = E_FAIL;
  3053. goto LDone;
  3054. }
  3055. dwErr = GetRootCertHashAndNameVerifyChain(pCertContextServer,
  3056. &Hash,
  3057. &pwszRootCAName,
  3058. (pEapTlsCb->fFlags & EAPTLSCB_FLAG_8021X_AUTH ),
  3059. &fRootCheckRequired);
  3060. if (NO_ERROR != dwErr)
  3061. {
  3062. goto LDone;
  3063. }
  3064. EapTlsTrace("Root CA name: %ws", pwszRootCAName);
  3065. dwStrLenRootCA = wcslen(pwszRootCAName);
  3066. //If there is no root check required, the stuff is good to go.
  3067. if ( !fRootCheckRequired )
  3068. fHashOK = TRUE;
  3069. #if 0
  3070. //
  3071. //Check to see if the new flag has been passed in to
  3072. //see if GP needs to be validated.
  3073. //
  3074. if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_8021X_AUTH )
  3075. {
  3076. EapTlsTrace( "8021X Flag Set. Will check for group policy hashes.");
  3077. //
  3078. //Lookup GP and see if we have the hashes to
  3079. //check against.
  3080. //
  3081. dwErr = ReadGPCARootHashes( &dwSizeOfGPRootHashBlob,
  3082. &pbGPRootHashBlob
  3083. );
  3084. if ( ERROR_SUCCESS == dwErr && pbGPRootHashBlob )
  3085. {
  3086. for ( dw = 0; dw < dwSizeOfGPRootHashBlob/MAX_HASH_SIZE; dw++ )
  3087. {
  3088. if ( !memcmp( pbGPRootHashBlob + ( dw * MAX_HASH_SIZE ), Hash.pbHash, MAX_HASH_SIZE ) )
  3089. {
  3090. EapTlsTrace( "8021X Found Hash match in GP");
  3091. fHashOK = TRUE;
  3092. break;
  3093. }
  3094. }
  3095. }
  3096. else
  3097. {
  3098. dwErr = NO_ERROR;
  3099. EapTlsTrace ("Could not get group policy hashes to check cert. Ignoring check.");
  3100. }
  3101. }
  3102. else
  3103. {
  3104. EapTlsTrace( "8021X Flag NOT Set. Will not check for group policy hashes.");
  3105. }
  3106. #endif
  3107. //
  3108. //Check to see if the hash for the root cert is in the list of
  3109. //hashes saved
  3110. //
  3111. if ( !fHashOK )
  3112. {
  3113. for ( dw = 0; dw < pEapTlsCb->pConnProp->dwNumHashes; dw ++ )
  3114. {
  3115. if (!memcmp( ( pEapTlsCb->pConnProp->bData + ( dw * sizeof(EAPTLS_HASH) ) ),
  3116. &Hash,
  3117. sizeof(EAPTLS_HASH)
  3118. )
  3119. )
  3120. {
  3121. EapTlsTrace ("Found Hash");
  3122. fHashOK = TRUE;
  3123. break;
  3124. }
  3125. }
  3126. }
  3127. pwszSavedName = (LPWSTR)(pEapTlsCb->pConnProp->bData + sizeof(EAPTLS_HASH) * pEapTlsCb->pConnProp->dwNumHashes);
  3128. if (!FCertToStr(pCertContextServer, 0, TRUE, &pwszServerName))
  3129. {
  3130. dwErr = E_FAIL;
  3131. goto LDone;
  3132. }
  3133. EapTlsTrace("Server name: %ws", pwszServerName);
  3134. EapTlsTrace("Server name specified: %ws", pwszSavedName);
  3135. dwStrLenServer = wcslen(pwszServerName);
  3136. dwStrLenSaved = wcslen(pwszSavedName);
  3137. if (pEapTlsCb->pConnProp->fFlags & EAPTLS_CONN_FLAG_NO_VALIDATE_NAME)
  3138. {
  3139. fNameOK = TRUE;
  3140. }
  3141. //
  3142. // Check to see if the new server name is in the list that is
  3143. // saved.
  3144. //
  3145. if ( (0 != dwStrLenSaved)
  3146. && StrStrI(pwszSavedName,
  3147. pwszServerName ))
  3148. {
  3149. fNameOK = TRUE;
  3150. dwStrLenServer=0;
  3151. }
  3152. if ( fHashOK
  3153. && fNameOK)
  3154. {
  3155. goto LDone;
  3156. }
  3157. if (pEapTlsCb->fFlags & EAPTLSCB_FLAG_NON_INTERACTIVE)
  3158. {
  3159. EapTlsTrace("No interactive UI's allowed");
  3160. dwErr = E_FAIL;
  3161. goto LDone;
  3162. }
  3163. if (!LoadString(GetHInstance(), IDS_VALIDATE_SERVER_TITLE,
  3164. awszTitle, NUM_CHARS_TITLE))
  3165. {
  3166. awszTitle[0] = 0;
  3167. }
  3168. if (fNameOK && !fHashOK)
  3169. {
  3170. pwszFormat = WszFromId(GetHInstance(), IDS_VALIDATE_SERVER_TEXT);
  3171. if (NULL == pwszFormat)
  3172. {
  3173. dwErr = ERROR_ALLOCATING_MEMORY;
  3174. EapTlsTrace("WszFromId(%d) failed", IDS_VALIDATE_SERVER_TEXT);
  3175. goto LDone;
  3176. }
  3177. dwSizeOfWszWarning =
  3178. (wcslen(pwszFormat) + dwStrLenRootCA) * sizeof(WCHAR);
  3179. pwszWarning = LocalAlloc(LPTR, dwSizeOfWszWarning);
  3180. if (NULL == pwszWarning)
  3181. {
  3182. dwErr = GetLastError();
  3183. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  3184. goto LDone;
  3185. }
  3186. swprintf(pwszWarning, pwszFormat, pwszRootCAName);
  3187. }
  3188. else if (!fNameOK && fHashOK)
  3189. {
  3190. pwszFormat = WszFromId(GetHInstance(), IDS_VALIDATE_NAME_TEXT);
  3191. if (NULL == pwszFormat)
  3192. {
  3193. dwErr = ERROR_ALLOCATING_MEMORY;
  3194. EapTlsTrace("WszFromId(%d) failed", IDS_VALIDATE_NAME_TEXT);
  3195. goto LDone;
  3196. }
  3197. dwSizeOfWszWarning =
  3198. (wcslen(pwszFormat) + dwStrLenServer) * sizeof(WCHAR);
  3199. pwszWarning = LocalAlloc(LPTR, dwSizeOfWszWarning);
  3200. if (NULL == pwszWarning)
  3201. {
  3202. dwErr = GetLastError();
  3203. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  3204. goto LDone;
  3205. }
  3206. swprintf(pwszWarning, pwszFormat, pwszServerName);
  3207. }
  3208. else
  3209. {
  3210. RTASSERT(!fNameOK && !fHashOK);
  3211. pwszFormat = WszFromId(GetHInstance(),
  3212. IDS_VALIDATE_SERVER_WITH_NAME_TEXT);
  3213. if (NULL == pwszFormat)
  3214. {
  3215. dwErr = ERROR_ALLOCATING_MEMORY;
  3216. EapTlsTrace("WszFromId(%d) failed",
  3217. IDS_VALIDATE_SERVER_WITH_NAME_TEXT);
  3218. goto LDone;
  3219. }
  3220. dwSizeOfWszWarning =
  3221. (wcslen(pwszFormat) + dwStrLenRootCA + dwStrLenServer) *
  3222. sizeof(WCHAR);
  3223. pwszWarning = LocalAlloc(LPTR, dwSizeOfWszWarning);
  3224. if (NULL == pwszWarning)
  3225. {
  3226. dwErr = GetLastError();
  3227. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  3228. goto LDone;
  3229. }
  3230. swprintf(pwszWarning, pwszFormat, pwszServerName, pwszRootCAName);
  3231. }
  3232. // If the server name is itg1.msft.com, we want to only store msft.com
  3233. /*
  3234. for (dw = 0; dw < dwStrLenServer; dw++)
  3235. {
  3236. if (L'.' == pwszServerName[dw])
  3237. {
  3238. break;
  3239. }
  3240. }
  3241. */
  3242. //
  3243. //We need to add a new entry to conn prop here
  3244. // Add new hash and append the server name...
  3245. //
  3246. pConnProp = LocalAlloc( LPTR,
  3247. sizeof(EAPTLS_CONN_PROPERTIES_V1) +
  3248. sizeof(EAPTLS_HASH) * ( pEapTlsCb->pConnProp->dwNumHashes + 1 ) +
  3249. dwStrLenServer * sizeof(WCHAR) +
  3250. sizeof(WCHAR) + //This is for the NULL
  3251. sizeof(WCHAR) + //This is for the delimiter
  3252. dwStrLenSaved * sizeof(WCHAR));
  3253. if (NULL == pConnProp)
  3254. {
  3255. dwErr = GetLastError();
  3256. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  3257. goto LDone;
  3258. }
  3259. CopyMemory(pConnProp, pEapTlsCb->pConnProp, sizeof(EAPTLS_CONN_PROPERTIES_V1));
  3260. //One extra char for ;
  3261. pConnProp->dwSize = sizeof(EAPTLS_CONN_PROPERTIES_V1) +
  3262. sizeof(EAPTLS_HASH) * ( pEapTlsCb->pConnProp->dwNumHashes + 1 ) +
  3263. dwStrLenServer * sizeof(WCHAR) + sizeof(WCHAR) + sizeof(WCHAR) +
  3264. dwStrLenSaved * sizeof(WCHAR);
  3265. pConnProp->dwNumHashes ++;
  3266. CopyMemory( pConnProp->bData,
  3267. pEapTlsCb->pConnProp->bData,
  3268. sizeof(EAPTLS_HASH) * pEapTlsCb->pConnProp->dwNumHashes);
  3269. CopyMemory( pConnProp->bData + sizeof(EAPTLS_HASH) * pEapTlsCb->pConnProp->dwNumHashes,
  3270. &Hash,
  3271. sizeof(EAPTLS_HASH)
  3272. );
  3273. if ( dwStrLenSaved )
  3274. {
  3275. wcsncpy ( (LPWSTR)(pConnProp->bData + sizeof(EAPTLS_HASH) * pConnProp->dwNumHashes),
  3276. (LPWSTR)(pEapTlsCb->pConnProp->bData + sizeof(EAPTLS_HASH) * pEapTlsCb->pConnProp->dwNumHashes),
  3277. dwStrLenSaved
  3278. );
  3279. if ( dwStrLenServer )
  3280. {
  3281. wcscat ( (LPWSTR)(pConnProp->bData + sizeof(EAPTLS_HASH) * pConnProp->dwNumHashes + dwStrLenSaved * sizeof(WCHAR)),
  3282. L";"
  3283. );
  3284. wcscat ( (LPWSTR)(pConnProp->bData + sizeof(EAPTLS_HASH) * pConnProp->dwNumHashes + dwStrLenSaved * sizeof(WCHAR) + sizeof(WCHAR)),
  3285. pwszServerName
  3286. );
  3287. }
  3288. }
  3289. else
  3290. {
  3291. if ( !fNameOK )
  3292. {
  3293. wcscpy((LPWSTR)(pConnProp->bData + sizeof(EAPTLS_HASH) * pConnProp->dwNumHashes + dwStrLenSaved * sizeof(WCHAR)),
  3294. pwszServerName
  3295. );
  3296. }
  3297. }
  3298. LocalFree(pEapTlsCb->pUIContextData);
  3299. pEapTlsCb->pUIContextData = LocalAlloc(LPTR,
  3300. sizeof(EAPTLS_VALIDATE_SERVER) + dwSizeOfWszWarning);
  3301. if (NULL == pEapTlsCb->pUIContextData)
  3302. {
  3303. dwErr = GetLastError();
  3304. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  3305. goto LDone;
  3306. }
  3307. //
  3308. // Get the Hash of server certificate
  3309. //
  3310. ZeroMemory( &ServerCertHash, sizeof(ServerCertHash) );
  3311. ServerCertHash.cbHash = MAX_HASH_SIZE;
  3312. if (!CertGetCertificateContextProperty(pCertContextServer, CERT_HASH_PROP_ID,
  3313. ServerCertHash.pbHash, &(ServerCertHash.cbHash)))
  3314. {
  3315. dwErr = GetLastError();
  3316. EapTlsTrace("CertGetCertificateContextProperty failed and "
  3317. "returned 0x%x", dwErr);
  3318. goto LDone;
  3319. }
  3320. //
  3321. // Open my store in local machine and add this certificate in it
  3322. //
  3323. hCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM,
  3324. 0,
  3325. 0,
  3326. CERT_SYSTEM_STORE_CURRENT_USER,
  3327. L"CA"
  3328. );
  3329. if ( NULL == hCertStore )
  3330. {
  3331. dwErr = GetLastError();
  3332. EapTlsTrace("CertOpenStore failed with error 0x%x", dwErr );
  3333. goto LDone;
  3334. }
  3335. //
  3336. // add this context to the store
  3337. //
  3338. if ( !CertAddCertificateContextToStore( hCertStore,
  3339. pCertContextServer,
  3340. CERT_STORE_ADD_ALWAYS,
  3341. NULL
  3342. )
  3343. )
  3344. {
  3345. dwErr = GetLastError();
  3346. EapTlsTrace("CertAddCertCertificateContextToStore failed with error 0x%x", dwErr );
  3347. goto LDone;
  3348. }
  3349. pEapTlsValidateServer =(EAPTLS_VALIDATE_SERVER*)(pEapTlsCb->pUIContextData);
  3350. pEapTlsValidateServer->dwSize =
  3351. sizeof(EAPTLS_VALIDATE_SERVER) + dwSizeOfWszWarning;
  3352. //Show this button iff it is not winlogon scenario.
  3353. pEapTlsValidateServer->fShowCertDetails = !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_LOGON);
  3354. //pEapTlsValidateServer->fShowCertDetails = TRUE;
  3355. CopyMemory( &(pEapTlsValidateServer->Hash),
  3356. &ServerCertHash,
  3357. sizeof(ServerCertHash)
  3358. );
  3359. wcscpy(pEapTlsValidateServer->awszTitle, awszTitle);
  3360. wcscpy(pEapTlsValidateServer->awszWarning, pwszWarning);
  3361. *pfWaitForUserOK = TRUE;
  3362. LDone:
  3363. if (NO_ERROR == dwErr)
  3364. {
  3365. LocalFree(pEapTlsCb->pNewConnProp);
  3366. pEapTlsCb->pNewConnProp = pConnProp;
  3367. pConnProp = NULL;
  3368. }
  3369. if ( pUsage )
  3370. {
  3371. LocalFree(pUsage);
  3372. pUsage = NULL;
  3373. }
  3374. if (NULL != pCertContextServer)
  3375. {
  3376. CertFreeCertificateContext(pCertContextServer);
  3377. // Always returns TRUE;
  3378. }
  3379. if ( hCertStore )
  3380. {
  3381. CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG );
  3382. }
  3383. LocalFree(pwszRootCAName);
  3384. LocalFree(pwszServerName);
  3385. LocalFree(pwszWarning);
  3386. LocalFree(pwszFormat);
  3387. LocalFree(pConnProp);
  3388. #if 0
  3389. if (NULL != pbGPRootHashBlob)
  3390. {
  3391. LocalFree(pbGPRootHashBlob);
  3392. }
  3393. #endif
  3394. if (NO_ERROR != dwErr)
  3395. {
  3396. dwErr = ERROR_UNABLE_TO_AUTHENTICATE_SERVER;
  3397. }
  3398. return(dwErr);
  3399. }
  3400. /*
  3401. Returns:
  3402. Error codes only from winerror.h, raserror.h or mprerror.h.
  3403. Notes:
  3404. */
  3405. DWORD
  3406. AuthenticateUser(
  3407. IN EAPTLSCB* pEapTlsCb
  3408. )
  3409. {
  3410. PCERT_CONTEXT pCertContextUser = NULL;
  3411. SECURITY_STATUS Status;
  3412. DWORD dwErr = NO_ERROR;
  3413. PCERT_ENHKEY_USAGE pUsage = NULL;
  3414. PCCERT_CHAIN_CONTEXT pCCertChainContext = NULL;
  3415. EapTlsTrace("AuthenticateUser");
  3416. RTASSERT(NULL != pEapTlsCb);
  3417. Status = QueryContextAttributes(&(pEapTlsCb->hContext),
  3418. SECPKG_ATTR_REMOTE_CERT_CONTEXT, &pCertContextUser);
  3419. if (SEC_E_OK != Status)
  3420. {
  3421. RTASSERT(NULL == pCertContextUser);
  3422. EapTlsTrace("QueryContextAttributes failed and returned 0x%x", Status);
  3423. //
  3424. //Now that we have default setting of guest access,
  3425. //if there are no credentials it is fine. Just send the error back to IAS
  3426. //and let it decide what has to be done here.
  3427. //
  3428. if ( Status != SEC_E_NO_CREDENTIALS )
  3429. {
  3430. dwErr = SEC_E_LOGON_DENIED;
  3431. }
  3432. else
  3433. {
  3434. if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP )
  3435. {
  3436. EapTlsTrace("Got no credentials from the client and executing PEAP. This is a success for eaptls.");
  3437. dwErr = NO_ERROR;
  3438. goto LDone;
  3439. }
  3440. else
  3441. {
  3442. EapTlsTrace("Got no credentials from the client. Will send success with authresult as SEC_E_NO_CREDENTIALS");
  3443. dwErr = Status;
  3444. }
  3445. }
  3446. goto LDone;
  3447. }
  3448. if ( ( dwErr = DwGetEKUUsage ( pCertContextUser,&pUsage ) ) != ERROR_SUCCESS )
  3449. {
  3450. EapTlsTrace("The user's cert does not have correct usage");
  3451. goto LDone;
  3452. }
  3453. #if WINVER > 0x0500
  3454. //
  3455. // Check to see if the certificate policy is all
  3456. // fine. Now that we allow guest access we definitely need to
  3457. // see manually if the cert chain is valid.
  3458. //
  3459. if ( ( dwErr = DwCheckCertPolicy(pCertContextUser, &pCCertChainContext ) ) != ERROR_SUCCESS)
  3460. {
  3461. EapTlsTrace("The user's cert does not have correct usage.");
  3462. goto LDone;
  3463. }
  3464. if ( NULL == pCCertChainContext )
  3465. {
  3466. EapTlsTrace("No Chain Context for from the certificate.");
  3467. dwErr = SEC_E_CERT_UNKNOWN;
  3468. goto LDone;
  3469. }
  3470. #else
  3471. //
  3472. // We dont have to check Usage separately any more
  3473. // This will be done as a part of policy verification
  3474. // on the chain.
  3475. //
  3476. if (!FCheckUsage(pCertContextUser, pUsage, FALSE))
  3477. {
  3478. EapTlsTrace("The user's cert does not have correct usage");
  3479. dwErr = SEC_E_CERT_UNKNOWN;
  3480. goto LDone;
  3481. }
  3482. #endif
  3483. dwErr = CheckUserName(pEapTlsCb->hContext, pEapTlsCb->awszIdentity);
  3484. if (NO_ERROR != dwErr)
  3485. {
  3486. //Special case handling for bug id:96347
  3487. //if ( dwErr != SEC_E_MULTIPLE_ACCOUNTS )
  3488. //dwErr = SEC_E_LOGON_DENIED;
  3489. goto LDone;
  3490. }
  3491. //Put OIDs in RAS Attributes so that we can send then across to IAS
  3492. dwErr = CreateOIDAttributes ( pEapTlsCb, pUsage, pCCertChainContext );
  3493. if ( NO_ERROR != dwErr )
  3494. {
  3495. dwErr = SEC_E_LOGON_DENIED;
  3496. goto LDone;
  3497. }
  3498. LDone:
  3499. if ( pUsage )
  3500. {
  3501. LocalFree ( pUsage );
  3502. pUsage = NULL;
  3503. }
  3504. if (NULL != pCertContextUser)
  3505. {
  3506. CertFreeCertificateContext(pCertContextUser);
  3507. // Always returns TRUE;
  3508. }
  3509. if ( pCCertChainContext )
  3510. {
  3511. CertFreeCertificateChain ( pCCertChainContext );
  3512. }
  3513. return(dwErr);
  3514. }
  3515. DWORD
  3516. CreateOIDAttributes (
  3517. IN EAPTLSCB * pEapTlsCb,
  3518. PCERT_ENHKEY_USAGE pUsage,
  3519. PCCERT_CHAIN_CONTEXT pCCertChainContext )
  3520. {
  3521. DWORD dwErr = NO_ERROR;
  3522. DWORD dwIndex, dwIndex1;
  3523. DWORD dwNumAttrs = 0;
  3524. PCERT_ENHKEY_USAGE pIssuanceUsage = NULL;
  3525. EapTlsTrace("CreateOIDAttributes");
  3526. #if WINVER > 0x0500
  3527. if ( pCCertChainContext )
  3528. pIssuanceUsage = pCCertChainContext->rgpChain[0]->rgpElement[0]->pIssuanceUsage;
  3529. #endif
  3530. if (NULL != pEapTlsCb->pAttributes)
  3531. {
  3532. RasAuthAttributeDestroy(pEapTlsCb->pAttributes);
  3533. pEapTlsCb->pAttributes = NULL;
  3534. }
  3535. if ( pIssuanceUsage )
  3536. {
  3537. dwNumAttrs = pIssuanceUsage->cUsageIdentifier;
  3538. }
  3539. dwNumAttrs+=pUsage->cUsageIdentifier;
  3540. //Need to allocate one extra for raatMinimum. The function automatically terminates
  3541. // with raat minimum
  3542. pEapTlsCb->pAttributes = RasAuthAttributeCreate(dwNumAttrs);
  3543. if (NULL == pEapTlsCb->pAttributes)
  3544. {
  3545. dwErr = GetLastError();
  3546. EapTlsTrace("RasAuthAttributeCreate failed and returned %d",
  3547. dwErr);
  3548. goto LDone;
  3549. }
  3550. dwIndex = 0;
  3551. while (pUsage->cUsageIdentifier)
  3552. {
  3553. dwErr = RasAuthAttributeInsert(
  3554. dwIndex,
  3555. pEapTlsCb->pAttributes,
  3556. raatCertificateOID,
  3557. FALSE,
  3558. strlen(pUsage->rgpszUsageIdentifier[dwIndex]),
  3559. pUsage->rgpszUsageIdentifier[dwIndex]);
  3560. if (NO_ERROR != dwErr)
  3561. {
  3562. EapTlsTrace("RasAuthAttributeInsert failed for EKU usage and returned %d", dwErr);
  3563. goto LDone;
  3564. }
  3565. dwIndex++;
  3566. pUsage->cUsageIdentifier--;
  3567. }
  3568. dwIndex1 = 0;
  3569. while ( pIssuanceUsage && pIssuanceUsage->cUsageIdentifier )
  3570. {
  3571. dwErr = RasAuthAttributeInsert(
  3572. dwIndex,
  3573. pEapTlsCb->pAttributes,
  3574. raatCertificateOID,
  3575. FALSE,
  3576. strlen(pIssuanceUsage->rgpszUsageIdentifier[dwIndex1]),
  3577. pIssuanceUsage->rgpszUsageIdentifier[dwIndex1]);
  3578. if (NO_ERROR != dwErr)
  3579. {
  3580. EapTlsTrace("RasAuthAttributeInsert failed for Issuance Usage and returned %d", dwErr);
  3581. goto LDone;
  3582. }
  3583. dwIndex++;
  3584. dwIndex1++;
  3585. pIssuanceUsage->cUsageIdentifier--;
  3586. }
  3587. LDone:
  3588. return dwErr;
  3589. }
  3590. /*
  3591. Returns:
  3592. Error codes only from winerror.h, raserror.h or mprerror.h.
  3593. Notes:
  3594. Creates a RAS_AUTH_ATTRIBUTE with the MPPE key in pEapTlsCb->pAttributes.
  3595. */
  3596. DWORD
  3597. CreateMPPEKeyAttributes(
  3598. IN EAPTLSCB* pEapTlsCb
  3599. )
  3600. {
  3601. SECURITY_STATUS Status;
  3602. SecPkgContext_EapKeyBlock EapKeyBlock;
  3603. BYTE MPPEKey[56];
  3604. BYTE* pSendKey;
  3605. BYTE* pRecvKey;
  3606. DWORD dwErr = NO_ERROR;
  3607. RAS_AUTH_ATTRIBUTE * pAttrTemp = NULL;
  3608. EapTlsTrace("CreateMPPEKeyAttributes");
  3609. Status = QueryContextAttributes(&(pEapTlsCb->hContext),
  3610. SECPKG_ATTR_EAP_KEY_BLOCK, &EapKeyBlock);
  3611. if (SEC_E_OK != Status)
  3612. {
  3613. EapTlsTrace("QueryContextAttributes failed and returned 0x%x", Status);
  3614. dwErr = Status;
  3615. goto LDone;
  3616. }
  3617. #if 0
  3618. if (NULL != pEapTlsCb->pAttributes)
  3619. {
  3620. RasAuthAttributeDestroy(pEapTlsCb->pAttributes);
  3621. pEapTlsCb->pAttributes = NULL;
  3622. }
  3623. pEapTlsCb->pAttributes = RasAuthAttributeCreate(2);
  3624. #endif
  3625. pAttrTemp = RasAuthAttributeCopyWithAlloc ( pEapTlsCb->pAttributes, 2 );
  3626. if (NULL == pAttrTemp )
  3627. {
  3628. dwErr = GetLastError();
  3629. EapTlsTrace("RasAuthAttributeCopyWithAlloc failed and returned %d",
  3630. dwErr);
  3631. goto LDone;
  3632. }
  3633. if ( pEapTlsCb->pAttributes )
  3634. {
  3635. RasAuthAttributeDestroy(pEapTlsCb->pAttributes);
  3636. }
  3637. pEapTlsCb->pAttributes = pAttrTemp;
  3638. if (pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER)
  3639. {
  3640. pSendKey = EapKeyBlock.rgbKeys + 32;
  3641. pRecvKey = EapKeyBlock.rgbKeys;
  3642. }
  3643. else
  3644. {
  3645. pSendKey = EapKeyBlock.rgbKeys;
  3646. pRecvKey = EapKeyBlock.rgbKeys + 32;
  3647. }
  3648. #if 0
  3649. EapTlsTrace("Send Key");
  3650. TraceDumpEx(g_dwEapTlsTraceId, 1, pSendKey, 32, 4,1,NULL);
  3651. EapTlsTrace("Receive Key");
  3652. TraceDumpEx(g_dwEapTlsTraceId, 1, pRecvKey, 32, 4,1,NULL);
  3653. #endif
  3654. ZeroMemory(MPPEKey, sizeof(MPPEKey));
  3655. HostToWireFormat32(311, MPPEKey); // Vendor Id
  3656. MPPEKey[4] = 16; // MS-MPPE-Send-Key
  3657. MPPEKey[5] = 1 + 1 + 2 + 1 + 32 + 15; // Vendor Length
  3658. // MPPEKey[6-7] is the zero-filled salt field
  3659. MPPEKey[8] = 32; // Key-Length
  3660. CopyMemory(MPPEKey + 9, pSendKey, 32); // Key
  3661. // MPPEKey[41-55] is the Padding (zero octets)
  3662. dwErr = RasAuthAttributeInsert(
  3663. 0,
  3664. pEapTlsCb->pAttributes,
  3665. raatVendorSpecific,
  3666. FALSE,
  3667. 56,
  3668. MPPEKey);
  3669. if (NO_ERROR != dwErr)
  3670. {
  3671. EapTlsTrace("RasAuthAttributeInsert failed and returned %d", dwErr);
  3672. goto LDone;
  3673. }
  3674. // Change only the fields that are different for MS-MPPE-Recv-Key
  3675. MPPEKey[4] = 17; // MS-MPPE-Recv-Key
  3676. CopyMemory(MPPEKey + 9, pRecvKey, 32); // Key
  3677. dwErr = RasAuthAttributeInsert(
  3678. 1,
  3679. pEapTlsCb->pAttributes,
  3680. raatVendorSpecific,
  3681. FALSE,
  3682. 56,
  3683. MPPEKey);
  3684. if (NO_ERROR != dwErr)
  3685. {
  3686. EapTlsTrace("RasAuthAttributeInsert failed and returned %d", dwErr);
  3687. goto LDone;
  3688. }
  3689. LDone:
  3690. return(dwErr);
  3691. }
  3692. /*
  3693. Returns:
  3694. Notes:
  3695. */
  3696. VOID
  3697. RespondToResult(
  3698. IN EAPTLSCB* pEapTlsCb,
  3699. IN PPP_EAP_OUTPUT* pEapOutput
  3700. )
  3701. {
  3702. EAPTLS_USER_PROPERTIES* pUserProp;
  3703. DWORD dwErr = NO_ERROR;
  3704. PBYTE pbEncPIN = NULL; //Encrypted PIN
  3705. DWORD cbEncPIN = 0;
  3706. RTASSERT( (EAPTLSCB_FLAG_SUCCESS & pEapTlsCb->fFlags)
  3707. || (NO_ERROR != pEapTlsCb->dwAuthResultCode));
  3708. EapTlsTrace("Negotiation %s",
  3709. (EAPTLSCB_FLAG_SUCCESS & pEapTlsCb->fFlags) ?
  3710. "successful" : "unsuccessful");
  3711. pEapOutput->pUserAttributes = pEapTlsCb->pAttributes;
  3712. pEapOutput->dwAuthResultCode = pEapTlsCb->dwAuthResultCode;
  3713. //
  3714. //Duplicate checks all over are bogus. Need to cleanup this
  3715. //part later.
  3716. //
  3717. if (!(pEapTlsCb->fFlags & EAPTLSCB_FLAG_ROUTER) &&
  3718. !(pEapTlsCb->fFlags & EAPTLSCB_FLAG_WINLOGON_DATA)
  3719. )
  3720. {
  3721. //
  3722. // If this is a 802.1x and a smart card based
  3723. // client then dont instruct to save user
  3724. // data.
  3725. if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_8021X_AUTH &&
  3726. !(pEapTlsCb->pConnProp->fFlags & EAPTLS_CONN_FLAG_REGISTRY)
  3727. )
  3728. {
  3729. pEapOutput->fSaveUserData = FALSE;
  3730. }
  3731. else
  3732. {
  3733. pEapOutput->fSaveUserData = TRUE;
  3734. }
  3735. }
  3736. if ( (EAPTLSCB_FLAG_SUCCESS & pEapTlsCb->fFlags)
  3737. && (NULL != pEapTlsCb->pUserProp))
  3738. {
  3739. if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_8021X_AUTH &&
  3740. !(pEapTlsCb->pConnProp->fFlags & EAPTLS_CONN_FLAG_REGISTRY)
  3741. )
  3742. {
  3743. //
  3744. // Encrypt PIN and send it back
  3745. //
  3746. dwErr = EncryptData ( (PBYTE)pEapTlsCb->pUserProp->pwszPin,
  3747. lstrlen(pEapTlsCb->pUserProp->pwszPin) * sizeof(WCHAR),
  3748. &pbEncPIN,
  3749. &cbEncPIN
  3750. );
  3751. if ( NO_ERROR != dwErr )
  3752. {
  3753. //
  3754. //Encryption failed. So wipe Out the PIN
  3755. //Do a dummy allocation
  3756. //
  3757. pbEncPIN = (PBYTE)LocalAlloc(LPTR,5);
  3758. cbEncPIN = lstrlen( (LPWSTR)pbEncPIN );
  3759. }
  3760. }
  3761. else
  3762. {
  3763. pbEncPIN = (PBYTE)LocalAlloc(LPTR, 5);;
  3764. cbEncPIN = lstrlen( (LPWSTR)pbEncPIN );
  3765. }
  3766. dwErr = AllocUserDataWithNewPin(pEapTlsCb->pUserProp, pbEncPIN, cbEncPIN, &pUserProp);
  3767. LocalFree(pEapTlsCb->pUserProp);
  3768. pEapTlsCb->pUserProp = pUserProp;
  3769. pEapOutput->pUserData = (BYTE*)pUserProp;
  3770. if (NULL != pUserProp)
  3771. {
  3772. pEapOutput->dwSizeOfUserData = pUserProp->dwSize;
  3773. }
  3774. else
  3775. {
  3776. pEapOutput->dwSizeOfUserData = 0;
  3777. }
  3778. if (NULL != pEapTlsCb->pNewConnProp)
  3779. {
  3780. pEapOutput->fSaveConnectionData = TRUE;
  3781. //
  3782. //Convert back to the cludgy v0 + v1 extra here
  3783. //
  3784. dwErr = ConnPropGetV0Struct ( pEapTlsCb->pNewConnProp, (EAPTLS_CONN_PROPERTIES ** )&(pEapOutput->pConnectionData) );
  3785. pEapOutput->dwSizeOfConnectionData =
  3786. ((EAPTLS_CONN_PROPERTIES *) (pEapOutput->pConnectionData) )->dwSize;
  3787. }
  3788. }
  3789. else
  3790. {
  3791. pEapOutput->pUserData = NULL;
  3792. pEapOutput->dwSizeOfUserData = 0;
  3793. }
  3794. LocalFree ( pbEncPIN );
  3795. pEapOutput->Action = EAPACTION_Done;
  3796. }
  3797. /*
  3798. Returns:
  3799. Notes:
  3800. */
  3801. VOID
  3802. GetAlert(
  3803. IN EAPTLSCB* pEapTlsCb,
  3804. IN EAPTLS_PACKET* pReceivePacket
  3805. )
  3806. {
  3807. BOOL fLengthIncluded;
  3808. DWORD dwBlobSizeReceived;
  3809. SecBuffer InBuffers[4];
  3810. SecBufferDesc Input;
  3811. DWORD dwAuthResultCode;
  3812. SECURITY_STATUS Status;
  3813. EapTlsTrace("GetAlert");
  3814. if (PPP_EAP_TLS != pReceivePacket->bType)
  3815. {
  3816. dwAuthResultCode = E_FAIL;
  3817. goto LDone;
  3818. }
  3819. if (pEapTlsCb->fFlags & EAPTLSCB_FLAG_HCTXT_INVALID)
  3820. {
  3821. EapTlsTrace("hContext is not valid");
  3822. dwAuthResultCode = ERROR_INVALID_HANDLE;
  3823. goto LDone;
  3824. }
  3825. fLengthIncluded = pReceivePacket->bFlags & EAPTLS_PACKET_FLAG_LENGTH_INCL;
  3826. dwBlobSizeReceived = WireToHostFormat16(pReceivePacket->pbLength) -
  3827. (fLengthIncluded ? EAPTLS_PACKET_HDR_LEN_MAX :
  3828. EAPTLS_PACKET_HDR_LEN);
  3829. if (dwBlobSizeReceived > pEapTlsCb->cbBlobInBuffer)
  3830. {
  3831. EapTlsTrace("Reallocating input TLS blob buffer");
  3832. LocalFree(pEapTlsCb->pbBlobIn);
  3833. pEapTlsCb->pbBlobIn = NULL;
  3834. pEapTlsCb->cbBlobInBuffer = 0;
  3835. pEapTlsCb->pbBlobIn = LocalAlloc(LPTR, dwBlobSizeReceived);
  3836. if (NULL == pEapTlsCb->pbBlobIn)
  3837. {
  3838. dwAuthResultCode = GetLastError();
  3839. EapTlsTrace("LocalAlloc failed and returned %d", dwAuthResultCode);
  3840. goto LDone;
  3841. }
  3842. pEapTlsCb->cbBlobInBuffer = dwBlobSizeReceived;
  3843. }
  3844. CopyMemory(pEapTlsCb->pbBlobIn,
  3845. pReceivePacket->pbData + (fLengthIncluded ? 4 : 0),
  3846. dwBlobSizeReceived);
  3847. pEapTlsCb->cbBlobIn = dwBlobSizeReceived;
  3848. InBuffers[0].pvBuffer = pEapTlsCb->pbBlobIn;
  3849. InBuffers[0].cbBuffer = pEapTlsCb->cbBlobIn;
  3850. InBuffers[0].BufferType = SECBUFFER_DATA;
  3851. InBuffers[1].BufferType = SECBUFFER_EMPTY;
  3852. InBuffers[2].BufferType = SECBUFFER_EMPTY;
  3853. InBuffers[3].BufferType = SECBUFFER_EMPTY;
  3854. Input.cBuffers = 4;
  3855. Input.pBuffers = InBuffers;
  3856. Input.ulVersion = SECBUFFER_VERSION;
  3857. Status = DecryptMessage(&(pEapTlsCb->hContext), &Input, 0, 0);
  3858. dwAuthResultCode = Status;
  3859. LDone:
  3860. if (SEC_E_OK == dwAuthResultCode)
  3861. {
  3862. RTASSERT(FALSE);
  3863. dwAuthResultCode = E_FAIL;
  3864. }
  3865. EapTlsTrace("Error 0x%x", dwAuthResultCode);
  3866. pEapTlsCb->dwAuthResultCode = dwAuthResultCode;
  3867. pEapTlsCb->fFlags &= ~EAPTLSCB_FLAG_SUCCESS;
  3868. }
  3869. /*
  3870. Returns:
  3871. Notes:
  3872. Calls [Initialize|Accept]SecurityContext.
  3873. */
  3874. SECURITY_STATUS
  3875. SecurityContextFunction(
  3876. IN EAPTLSCB* pEapTlsCb
  3877. )
  3878. {
  3879. SecBufferDesc Input;
  3880. SecBuffer InBuffers[2];
  3881. SecBufferDesc Output;
  3882. SecBuffer OutBuffers[1];
  3883. DWORD dwBlobSizeRequired;
  3884. ULONG fContextAttributes;
  3885. ULONG fContextReq;
  3886. TimeStamp tsExpiry;
  3887. BOOL fServer;
  3888. BOOL fTlsStart;
  3889. BOOL fRepeat;
  3890. SECURITY_STATUS Status;
  3891. SECURITY_STATUS StatusTemp;
  3892. EapTlsTrace("SecurityContextFunction");
  3893. RTASSERT(NULL != pEapTlsCb);
  3894. fServer = pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER;
  3895. if (fServer)
  3896. {
  3897. fTlsStart = (EAPTLS_STATE_SENT_START == pEapTlsCb->EapTlsState);
  3898. }
  3899. else
  3900. {
  3901. fTlsStart = (EAPTLS_STATE_INITIAL == pEapTlsCb->EapTlsState);
  3902. }
  3903. fContextReq = pEapTlsCb->fContextReq;
  3904. fRepeat = TRUE;
  3905. while (fRepeat)
  3906. {
  3907. // Set up the input buffers. InBuffers[0] is used to pass in data
  3908. // received from the server. Schannel will consume some or all of this.
  3909. // The amount of the leftover data (if any) will be placed in
  3910. // InBuffers[1].cbBuffer and InBuffers[1].BufferType will be set to
  3911. // SECBUFFER_EXTRA.
  3912. InBuffers[0].pvBuffer = pEapTlsCb->pbBlobIn;
  3913. InBuffers[0].cbBuffer = pEapTlsCb->cbBlobIn;
  3914. InBuffers[0].BufferType = SECBUFFER_TOKEN;
  3915. InBuffers[1].pvBuffer = NULL;
  3916. InBuffers[1].cbBuffer = 0;
  3917. InBuffers[1].BufferType = SECBUFFER_EMPTY;
  3918. Input.cBuffers = 2;
  3919. Input.pBuffers = InBuffers;
  3920. Input.ulVersion = SECBUFFER_VERSION;
  3921. // Set up the output buffers.
  3922. OutBuffers[0].pvBuffer = NULL;
  3923. OutBuffers[0].cbBuffer = 0;
  3924. OutBuffers[0].BufferType= SECBUFFER_TOKEN;
  3925. Output.cBuffers = 1;
  3926. Output.pBuffers = OutBuffers;
  3927. Output.ulVersion = SECBUFFER_VERSION;
  3928. if (fServer)
  3929. {
  3930. // Call AcceptSecurityContext.
  3931. Status = AcceptSecurityContext(
  3932. &(pEapTlsCb->hCredential),
  3933. fTlsStart ? NULL : &(pEapTlsCb->hContext),
  3934. &Input,
  3935. fContextReq,
  3936. SECURITY_NETWORK_DREP,
  3937. &(pEapTlsCb->hContext),
  3938. &Output,
  3939. &fContextAttributes,
  3940. &tsExpiry);
  3941. EapTlsTrace("AcceptSecurityContext returned 0x%x", Status);
  3942. }
  3943. else
  3944. {
  3945. // Call InitializeSecurityContext.
  3946. // The pszTargetName is used for cache indexing, so if you pass in
  3947. // NULL then you will likely take a perf hit, maybe a large one.
  3948. Status = InitializeSecurityContext(
  3949. &(pEapTlsCb->hCredential),
  3950. fTlsStart ? NULL : &(pEapTlsCb->hContext),
  3951. pEapTlsCb->awszIdentity /* pszTargetName */,
  3952. fContextReq,
  3953. 0,
  3954. SECURITY_NETWORK_DREP,
  3955. (fTlsStart) ? NULL : &Input,
  3956. 0,
  3957. &(pEapTlsCb->hContext),
  3958. &Output,
  3959. &fContextAttributes,
  3960. &tsExpiry);
  3961. EapTlsTrace("InitializeSecurityContext returned 0x%x", Status);
  3962. }
  3963. if (!FAILED(Status))
  3964. {
  3965. // If the first call to ASC fails (perhaps because the client sent
  3966. // bad stuff, even though we have nothing wrong on our side), then
  3967. // schannel will not return an hContext to the application. The
  3968. // application should not call DSC in this case, even if it looks
  3969. // like schannel messed up and returned a handle.
  3970. pEapTlsCb->fFlags &= ~EAPTLSCB_FLAG_HCTXT_INVALID;
  3971. }
  3972. // If [Accept|Initialize]SecurityContext was successful (or if the error
  3973. // was one of the special extended ones), send the contents of the
  3974. // output buffer to the peer.
  3975. if (SEC_E_OK == Status ||
  3976. SEC_I_CONTINUE_NEEDED == Status ||
  3977. FAILED(Status) && (fContextAttributes & ISC_RET_EXTENDED_ERROR))
  3978. {
  3979. if (0 != OutBuffers[0].cbBuffer && NULL != OutBuffers[0].pvBuffer)
  3980. {
  3981. dwBlobSizeRequired = OutBuffers[0].cbBuffer;
  3982. if (dwBlobSizeRequired > pEapTlsCb->cbBlobOutBuffer)
  3983. {
  3984. LocalFree(pEapTlsCb->pbBlobOut);
  3985. pEapTlsCb->pbBlobOut = NULL;
  3986. pEapTlsCb->cbBlobOut = 0;
  3987. pEapTlsCb->cbBlobOutBuffer = 0;
  3988. }
  3989. if (NULL == pEapTlsCb->pbBlobOut)
  3990. {
  3991. pEapTlsCb->pbBlobOut = LocalAlloc(LPTR, dwBlobSizeRequired);
  3992. if (NULL == pEapTlsCb->pbBlobOut)
  3993. {
  3994. pEapTlsCb->cbBlobOut = 0;
  3995. pEapTlsCb->cbBlobOutBuffer = 0;
  3996. Status = GetLastError();
  3997. EapTlsTrace("LocalAlloc failed and returned %d",
  3998. Status);
  3999. goto LWhileEnd;
  4000. }
  4001. pEapTlsCb->cbBlobOutBuffer = dwBlobSizeRequired;
  4002. }
  4003. CopyMemory(pEapTlsCb->pbBlobOut, OutBuffers[0].pvBuffer,
  4004. dwBlobSizeRequired);
  4005. pEapTlsCb->cbBlobOut = dwBlobSizeRequired;
  4006. pEapTlsCb->dwBlobOutOffset = pEapTlsCb->dwBlobOutOffsetNew = 0;
  4007. }
  4008. }
  4009. // Copy any leftover data from the "extra" buffer.
  4010. if (InBuffers[1].BufferType == SECBUFFER_EXTRA)
  4011. {
  4012. MoveMemory(pEapTlsCb->pbBlobIn,
  4013. pEapTlsCb->pbBlobIn +
  4014. (pEapTlsCb->cbBlobIn - InBuffers[1].cbBuffer),
  4015. InBuffers[1].cbBuffer);
  4016. pEapTlsCb->cbBlobIn = InBuffers[1].cbBuffer;
  4017. }
  4018. else
  4019. {
  4020. pEapTlsCb->cbBlobIn = 0;
  4021. }
  4022. LWhileEnd:
  4023. if (NULL != OutBuffers[0].pvBuffer)
  4024. {
  4025. StatusTemp = FreeContextBuffer(OutBuffers[0].pvBuffer);
  4026. if (SEC_E_OK != StatusTemp)
  4027. {
  4028. EapTlsTrace("FreeContextBuffer failed and returned 0x%x",
  4029. StatusTemp);
  4030. }
  4031. }
  4032. // ASC (and ISC) will sometimes only consume part of the input buffer,
  4033. // and return a zero length output buffer. In this case, we must just
  4034. // call ASC again (with the input buffer adjusted appropriately).
  4035. if ( (0 == OutBuffers[0].cbBuffer)
  4036. && (SEC_I_CONTINUE_NEEDED == Status))
  4037. {
  4038. EapTlsTrace("Reapeating SecurityContextFunction loop...");
  4039. }
  4040. else
  4041. {
  4042. fRepeat = FALSE;
  4043. }
  4044. }
  4045. return(Status);
  4046. }
  4047. /*
  4048. Returns:
  4049. A TLS alert corresponding to the error.
  4050. Notes:
  4051. */
  4052. DWORD
  4053. AlertFromError(
  4054. IN DWORD * pdwErr,
  4055. IN BOOL fTranslateError
  4056. )
  4057. {
  4058. DWORD dwAlert;
  4059. DWORD dwErr = *pdwErr;
  4060. switch (dwErr)
  4061. {
  4062. case SEC_E_MESSAGE_ALTERED:
  4063. dwAlert = TLS1_ALERT_BAD_RECORD_MAC;
  4064. break;
  4065. case SEC_E_DECRYPT_FAILURE:
  4066. dwAlert = TLS1_ALERT_DECRYPTION_FAILED;
  4067. break;
  4068. case SEC_E_CERT_UNKNOWN:
  4069. dwAlert = TLS1_ALERT_BAD_CERTIFICATE;
  4070. break;
  4071. case CRYPT_E_REVOKED:
  4072. dwAlert = TLS1_ALERT_CERTIFICATE_REVOKED;
  4073. break;
  4074. case SEC_E_CERT_EXPIRED:
  4075. dwAlert = TLS1_ALERT_CERTIFICATE_EXPIRED;
  4076. break;
  4077. case SEC_E_UNTRUSTED_ROOT:
  4078. dwAlert = TLS1_ALERT_UNKNOWN_CA;
  4079. break;
  4080. case SEC_E_LOGON_DENIED:
  4081. case ERROR_UNABLE_TO_AUTHENTICATE_SERVER:
  4082. case SEC_E_NO_IMPERSONATION:
  4083. dwAlert = TLS1_ALERT_ACCESS_DENIED;
  4084. break;
  4085. case SEC_E_ILLEGAL_MESSAGE:
  4086. dwAlert = TLS1_ALERT_DECODE_ERROR;
  4087. break;
  4088. case SEC_E_UNSUPPORTED_FUNCTION:
  4089. dwAlert = TLS1_ALERT_PROTOCOL_VERSION;
  4090. break;
  4091. case SEC_E_ALGORITHM_MISMATCH:
  4092. dwAlert = TLS1_ALERT_INSUFFIENT_SECURITY;
  4093. break;
  4094. #if WINVER > 0x0500
  4095. case SEC_E_MULTIPLE_ACCOUNTS: //Special case handling for : 96347
  4096. dwAlert = TLS1_ALERT_CERTIFICATE_UNKNOWN;
  4097. break;
  4098. #endif
  4099. default:
  4100. dwAlert = TLS1_ALERT_ACCESS_DENIED;
  4101. //We have been instructed to translate the error. So do that.
  4102. if ( fTranslateError )
  4103. *pdwErr = SEC_E_LOGON_DENIED;
  4104. break;
  4105. }
  4106. return(dwAlert);
  4107. }
  4108. /*
  4109. Returns:
  4110. Notes:
  4111. */
  4112. VOID
  4113. MakeAlert(
  4114. IN EAPTLSCB* pEapTlsCb,
  4115. IN DWORD dwAlert,
  4116. IN BOOL fManualAlert
  4117. )
  4118. {
  4119. #define NUM_ALERT_BYTES 7
  4120. static BYTE pbAlert[NUM_ALERT_BYTES - 1]
  4121. = {0x15, 0x03, 0x01, 0x00, 0x02, 0x02};
  4122. SCHANNEL_ALERT_TOKEN Token;
  4123. SecBufferDesc OutBuffer;
  4124. SecBuffer OutBuffers[1];
  4125. BOOL fZeroBlobOut = TRUE;
  4126. DWORD Status;
  4127. DWORD dwErr;
  4128. EapTlsTrace("MakeAlert(%d, %s)",
  4129. dwAlert, fManualAlert ? "Manual" : "Schannel");
  4130. if (fManualAlert)
  4131. {
  4132. if (NUM_ALERT_BYTES > pEapTlsCb->cbBlobOutBuffer)
  4133. {
  4134. LocalFree(pEapTlsCb->pbBlobOut);
  4135. pEapTlsCb->pbBlobOut = NULL;
  4136. pEapTlsCb->cbBlobOut = 0;
  4137. pEapTlsCb->cbBlobOutBuffer = 0;
  4138. }
  4139. if (NULL == pEapTlsCb->pbBlobOut)
  4140. {
  4141. pEapTlsCb->pbBlobOut = LocalAlloc(LPTR, NUM_ALERT_BYTES);
  4142. if (NULL == pEapTlsCb->pbBlobOut)
  4143. {
  4144. pEapTlsCb->cbBlobOut = 0;
  4145. pEapTlsCb->cbBlobOutBuffer = 0;
  4146. dwErr = GetLastError();
  4147. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  4148. goto LDone;
  4149. }
  4150. pEapTlsCb->cbBlobOutBuffer = NUM_ALERT_BYTES;
  4151. }
  4152. CopyMemory(pEapTlsCb->pbBlobOut, pbAlert, NUM_ALERT_BYTES - 1);
  4153. pEapTlsCb->pbBlobOut[NUM_ALERT_BYTES - 1] = (BYTE) dwAlert;
  4154. pEapTlsCb->cbBlobOut = NUM_ALERT_BYTES;
  4155. fZeroBlobOut = FALSE;
  4156. goto LDone;
  4157. }
  4158. if (pEapTlsCb->fFlags & EAPTLSCB_FLAG_HCTXT_INVALID)
  4159. {
  4160. EapTlsTrace("hContext is not valid");
  4161. goto LDone;
  4162. }
  4163. Token.dwTokenType = SCHANNEL_ALERT;
  4164. Token.dwAlertType = TLS1_ALERT_FATAL;
  4165. Token.dwAlertNumber = dwAlert;
  4166. OutBuffers[0].pvBuffer = &Token;
  4167. OutBuffers[0].cbBuffer = sizeof(Token);
  4168. OutBuffers[0].BufferType = SECBUFFER_TOKEN;
  4169. OutBuffer.cBuffers = 1;
  4170. OutBuffer.pBuffers = OutBuffers;
  4171. OutBuffer.ulVersion = SECBUFFER_VERSION;
  4172. Status = ApplyControlToken(&(pEapTlsCb->hContext), &OutBuffer);
  4173. if (FAILED(Status))
  4174. {
  4175. EapTlsTrace("ApplyControlToken failed and returned 0x%x", Status);
  4176. goto LDone;
  4177. }
  4178. Status = SecurityContextFunction(pEapTlsCb);
  4179. fZeroBlobOut = FALSE;
  4180. LDone:
  4181. if (fZeroBlobOut)
  4182. {
  4183. pEapTlsCb->cbBlobOut = pEapTlsCb->dwBlobOutOffset =
  4184. pEapTlsCb->dwBlobOutOffsetNew = 0;
  4185. }
  4186. }
  4187. /*
  4188. Returns:
  4189. Error codes only from winerror.h, raserror.h or mprerror.h.
  4190. Notes:
  4191. Called to process an incoming packet. We collect all the fragments that the
  4192. peer want to send and only then call SecurityContextFunction. There are two
  4193. reasons for this: 1) [Initialize|Accept]SecurityContext sometimes generates
  4194. an output even when the incoming message is incomplete. The RFC requires us
  4195. to send an empty Request/Response. 2) A rogue peer may carefully construct
  4196. a valid 80 MB TLS blob in a denial of service attack. There is no easy way
  4197. to guard against this.
  4198. Errors should be returned from this function for things like LocalAlloc
  4199. failing. Not because we got something bad from the peer. If an error is
  4200. returned from this function, then we should use EAPACTION_NoAction. Perhaps
  4201. we can succeed next time.
  4202. Before calling [Initialize|Accept]SecurityContext, it is OK to return an
  4203. error for things like LocalAlloc failing. After calling the function,
  4204. however, we should always return NO_ERROR, and if something failed, set
  4205. pEapTlsCb->dwAuthResultCode, and go to the state nFinalState. This is
  4206. because we cannot call [Initialize|Accept]SecurityContext again.
  4207. */
  4208. DWORD
  4209. MakeReplyMessage(
  4210. IN EAPTLSCB* pEapTlsCb,
  4211. IN EAPTLS_PACKET* pReceivePacket
  4212. )
  4213. {
  4214. BOOL fLengthIncluded = FALSE;
  4215. BOOL fMoreFragments = FALSE;
  4216. BOOL fManualAlert = FALSE;
  4217. BOOL fWaitForUserOK = FALSE;
  4218. BOOL fServer;
  4219. DWORD dwBlobSizeReceived;
  4220. DWORD dwBlobSizeRequired = 0;
  4221. DWORD dwBlobSizeNew;
  4222. BYTE* pbBlobOld;
  4223. int nFinalState;
  4224. SECURITY_STATUS Status;
  4225. DWORD dwAlert = 0;
  4226. WCHAR* apwszWarning[1];
  4227. DWORD dwAuthResultCode = NO_ERROR;
  4228. DWORD dwErr = NO_ERROR;
  4229. DWORD dwNoCredCode = NO_ERROR;
  4230. BOOL fTranslateError = FALSE;
  4231. EapTlsTrace("MakeReplyMessage");
  4232. RTASSERT(NULL != pEapTlsCb);
  4233. RTASSERT(NULL != pReceivePacket);
  4234. if (PPP_EAP_TLS != pReceivePacket->bType)
  4235. {
  4236. // Don't go to LDone. We don't want to change
  4237. // pEapTlsCb->dwAuthResultCode
  4238. return(ERROR_PPP_INVALID_PACKET);
  4239. }
  4240. fLengthIncluded = pReceivePacket->bFlags & EAPTLS_PACKET_FLAG_LENGTH_INCL;
  4241. if (pEapTlsCb->fFlags & EAPTLSCB_FLAG_SERVER)
  4242. {
  4243. fServer = TRUE;
  4244. nFinalState = EAPTLS_STATE_SENT_FINISHED;
  4245. }
  4246. else
  4247. {
  4248. fServer = FALSE;
  4249. nFinalState = EAPTLS_STATE_RECD_FINISHED;
  4250. }
  4251. fMoreFragments = pReceivePacket->bFlags & EAPTLS_PACKET_FLAG_MORE_FRAGMENTS;
  4252. dwBlobSizeReceived = WireToHostFormat16(pReceivePacket->pbLength) -
  4253. (fLengthIncluded ? EAPTLS_PACKET_HDR_LEN_MAX :
  4254. EAPTLS_PACKET_HDR_LEN);
  4255. if (!(pEapTlsCb->fFlags & EAPTLSCB_FLAG_RECEIVING_FRAGMENTS))
  4256. {
  4257. // We haven't received any fragment yet. Make sure that we have the
  4258. // right amount of memory allocated in pbBlobIn.
  4259. if (!fMoreFragments)
  4260. {
  4261. dwBlobSizeRequired = pEapTlsCb->cbBlobIn + dwBlobSizeReceived;
  4262. }
  4263. else
  4264. {
  4265. // This is the first of many fragments.
  4266. if (!fLengthIncluded)
  4267. {
  4268. EapTlsTrace("TLS Message Length is required");
  4269. dwAuthResultCode = ERROR_INVALID_PARAMETER;
  4270. dwAlert = TLS1_ALERT_ILLEGAL_PARAMETER;
  4271. goto LDone;
  4272. }
  4273. else
  4274. {
  4275. dwBlobSizeNew = WireToHostFormat32(pReceivePacket->pbData);
  4276. if (g_dwMaxBlobSize < dwBlobSizeNew)
  4277. {
  4278. EapTlsTrace("Blob size %d is unacceptable", dwBlobSizeNew);
  4279. dwAuthResultCode = ERROR_INVALID_PARAMETER;
  4280. dwAlert = TLS1_ALERT_ILLEGAL_PARAMETER;
  4281. goto LDone;
  4282. }
  4283. else
  4284. {
  4285. dwBlobSizeRequired = pEapTlsCb->cbBlobIn + dwBlobSizeNew;
  4286. pEapTlsCb->dwBlobInRemining = dwBlobSizeNew;
  4287. pEapTlsCb->fFlags |= EAPTLSCB_FLAG_RECEIVING_FRAGMENTS;
  4288. }
  4289. }
  4290. }
  4291. if (dwBlobSizeRequired > pEapTlsCb->cbBlobInBuffer)
  4292. {
  4293. EapTlsTrace("Reallocating input TLS blob buffer");
  4294. pbBlobOld = pEapTlsCb->pbBlobIn;
  4295. pEapTlsCb->pbBlobIn = LocalAlloc(LPTR, dwBlobSizeRequired);
  4296. if (NULL == pEapTlsCb->pbBlobIn)
  4297. {
  4298. pEapTlsCb->pbBlobIn = pbBlobOld;
  4299. dwErr = GetLastError();
  4300. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  4301. goto LDone;
  4302. }
  4303. pEapTlsCb->cbBlobInBuffer = dwBlobSizeRequired;
  4304. if (0 != pEapTlsCb->cbBlobIn)
  4305. {
  4306. RTASSERT(NULL != pbBlobOld);
  4307. CopyMemory(pEapTlsCb->pbBlobIn, pbBlobOld, pEapTlsCb->cbBlobIn);
  4308. }
  4309. LocalFree(pbBlobOld);
  4310. }
  4311. }
  4312. if (pEapTlsCb->fFlags & EAPTLSCB_FLAG_RECEIVING_FRAGMENTS)
  4313. {
  4314. if (pEapTlsCb->dwBlobInRemining < dwBlobSizeReceived)
  4315. {
  4316. EapTlsTrace("Peer is sending more bytes than promised");
  4317. dwAuthResultCode = ERROR_INVALID_PARAMETER;
  4318. dwAlert = TLS1_ALERT_ILLEGAL_PARAMETER;
  4319. goto LDone;
  4320. }
  4321. else
  4322. {
  4323. pEapTlsCb->dwBlobInRemining -= dwBlobSizeReceived;
  4324. if (0 == pEapTlsCb->dwBlobInRemining)
  4325. {
  4326. pEapTlsCb->fFlags &= ~EAPTLSCB_FLAG_RECEIVING_FRAGMENTS;
  4327. if (fMoreFragments)
  4328. {
  4329. // No need to send an alert here.
  4330. EapTlsTrace("Peer has sent the entire TLS blob, but wants "
  4331. "to send more.");
  4332. }
  4333. }
  4334. }
  4335. }
  4336. // Now we are sure that pEapTlsCb->pbBlobIn is big enough to hold all
  4337. // the information.
  4338. CopyMemory(pEapTlsCb->pbBlobIn + pEapTlsCb->cbBlobIn,
  4339. pReceivePacket->pbData + (fLengthIncluded ? 4 : 0),
  4340. dwBlobSizeReceived);
  4341. pEapTlsCb->cbBlobIn += dwBlobSizeReceived;
  4342. if (!(pEapTlsCb->fFlags & EAPTLSCB_FLAG_RECEIVING_FRAGMENTS))
  4343. {
  4344. Status = SecurityContextFunction(pEapTlsCb);
  4345. //
  4346. // Need to write a function to map the SSPI error
  4347. // to nice and rosy RAS error
  4348. //
  4349. #if WINVER > 0x0500
  4350. if ( Status == SEC_E_UNTRUSTED_ROOT )
  4351. {
  4352. dwAuthResultCode = ERROR_VALIDATING_SERVER_CERT;
  4353. }
  4354. else
  4355. {
  4356. dwAuthResultCode = Status;
  4357. }
  4358. #else
  4359. dwAuthResultCode = Status;
  4360. #endif
  4361. if (SEC_E_OK == Status)
  4362. {
  4363. if (fServer)
  4364. {
  4365. /*
  4366. Normally, the server calls ASC for the last time (from state
  4367. EAPTLS_STATE_SENT_HELLO), gets the blob that contains TLS
  4368. change_cipher_spec, and then checks to see if the user is OK
  4369. (AuthenticateUser, etc). However, if the server then wants to
  4370. send an alert, and wants schannel to create it, it has to undo
  4371. the TLS change_cipher_spec first. Instead, it constructs the
  4372. alert itself.
  4373. */
  4374. fManualAlert = TRUE;
  4375. dwAuthResultCode = AuthenticateUser(pEapTlsCb);
  4376. if ( SEC_E_NO_CREDENTIALS == dwAuthResultCode )
  4377. {
  4378. dwNoCredCode = dwAuthResultCode;
  4379. dwAuthResultCode = NO_ERROR;
  4380. }
  4381. fTranslateError = FALSE;
  4382. }
  4383. else
  4384. {
  4385. dwAuthResultCode = AuthenticateServer(pEapTlsCb,
  4386. &fWaitForUserOK);
  4387. fTranslateError = TRUE;
  4388. }
  4389. if (NO_ERROR != dwAuthResultCode )
  4390. {
  4391. dwAlert = AlertFromError(&dwAuthResultCode, fTranslateError);
  4392. goto LDone;
  4393. }
  4394. //
  4395. // Since we've started with no fast reconnect
  4396. // Session established successfully.
  4397. // Now setup TLS fast reconnect.
  4398. //
  4399. if ( fServer )
  4400. {
  4401. dwAuthResultCode = SetTLSFastReconnect(pEapTlsCb, TRUE);
  4402. if ( NO_ERROR != dwAuthResultCode )
  4403. {
  4404. dwAlert = TLS1_ALERT_INTERNAL_ERROR;
  4405. goto LDone;
  4406. }
  4407. }
  4408. dwAuthResultCode = CreateMPPEKeyAttributes(pEapTlsCb);
  4409. if (NO_ERROR != dwAuthResultCode)
  4410. {
  4411. dwAlert = TLS1_ALERT_INTERNAL_ERROR;
  4412. goto LDone;
  4413. }
  4414. if (fWaitForUserOK)
  4415. {
  4416. pEapTlsCb->EapTlsState = EAPTLS_STATE_WAIT_FOR_USER_OK;
  4417. EapTlsTrace("State change to %s",
  4418. g_szEapTlsState[pEapTlsCb->EapTlsState]);
  4419. goto LDone;
  4420. }
  4421. }
  4422. if (SEC_E_OK == Status)
  4423. {
  4424. pEapTlsCb->fFlags |= EAPTLSCB_FLAG_SUCCESS;
  4425. pEapTlsCb->EapTlsState = nFinalState;
  4426. EapTlsTrace("State change to %s",
  4427. g_szEapTlsState[pEapTlsCb->EapTlsState]);
  4428. }
  4429. if (SEC_I_CONTINUE_NEEDED == dwAuthResultCode)
  4430. {
  4431. dwAuthResultCode = NO_ERROR;
  4432. pEapTlsCb->EapTlsState = fServer ?
  4433. g_nEapTlsServerNextState[pEapTlsCb->EapTlsState]:
  4434. g_nEapTlsClientNextState[pEapTlsCb->EapTlsState];
  4435. EapTlsTrace("State change to %s",
  4436. g_szEapTlsState[pEapTlsCb->EapTlsState]);
  4437. }
  4438. }
  4439. LDone:
  4440. if (0 != dwAlert)
  4441. {
  4442. RTASSERT(NO_ERROR != dwAuthResultCode);
  4443. pEapTlsCb->cbBlobIn = pEapTlsCb->dwBlobInRemining = 0;
  4444. pEapTlsCb->fFlags &= ~EAPTLSCB_FLAG_RECEIVING_FRAGMENTS;
  4445. pEapTlsCb->fFlags &= ~EAPTLSCB_FLAG_SUCCESS;
  4446. MakeAlert(pEapTlsCb, dwAlert, fManualAlert);
  4447. }
  4448. if (NO_ERROR != dwAuthResultCode)
  4449. {
  4450. pEapTlsCb->fFlags &= ~EAPTLSCB_FLAG_SUCCESS;
  4451. if (nFinalState != pEapTlsCb->EapTlsState)
  4452. {
  4453. pEapTlsCb->EapTlsState = nFinalState;
  4454. EapTlsTrace("State change to %s. Error: 0x%x",
  4455. g_szEapTlsState[pEapTlsCb->EapTlsState], dwAuthResultCode);
  4456. }
  4457. //Commented per bug #'s 475244 and 478128
  4458. /*
  4459. if (fServer)
  4460. {
  4461. apwszWarning[0] = pEapTlsCb->awszIdentity ?
  4462. pEapTlsCb->awszIdentity : L"";
  4463. RouterLogErrorString(pEapTlsCb->hEventLog,
  4464. ROUTERLOG_EAP_AUTH_FAILURE, 1, apwszWarning,
  4465. dwAuthResultCode, 1);
  4466. }
  4467. */
  4468. }
  4469. if ( dwNoCredCode == NO_ERROR )
  4470. {
  4471. pEapTlsCb->dwAuthResultCode = dwAuthResultCode;
  4472. }
  4473. else
  4474. {
  4475. EapTlsTrace ( "No Credentials got from the client. Returning 0x%d", dwNoCredCode);
  4476. pEapTlsCb->dwAuthResultCode = dwNoCredCode;
  4477. }
  4478. return(dwErr);
  4479. }
  4480. /*
  4481. Returns:
  4482. Error codes only from winerror.h, raserror.h or mprerror.h.
  4483. Notes:
  4484. Called by the client to process an incoming packet and/or send a packet.
  4485. cbSendPacket is the size in bytes of the buffer pointed to by pSendPacket.
  4486. This function is called only after FValidPacket(pReceivePacket) returns
  4487. TRUE. If pEapOutput->Action is going to be EAPACTION_SendAndDone or
  4488. EAPACTION_Done, make sure that pEapOutput->dwAuthResultCode has been set.
  4489. If dwAuthResultCode is NO_ERROR, make sure that pEapOutput->pUserAttributes
  4490. has been set.
  4491. */
  4492. DWORD
  4493. EapTlsCMakeMessage(
  4494. IN EAPTLSCB* pEapTlsCb,
  4495. IN EAPTLS_PACKET* pReceivePacket,
  4496. OUT EAPTLS_PACKET* pSendPacket,
  4497. IN DWORD cbSendPacket,
  4498. OUT PPP_EAP_OUTPUT* pEapOutput,
  4499. IN PPP_EAP_INPUT* pEapInput
  4500. )
  4501. {
  4502. EAPTLS_USER_PROPERTIES* pUserProp = NULL;
  4503. DWORD dwAuthResultCode;
  4504. DWORD dwErr = NO_ERROR;
  4505. EapTlsTrace("EapTlsCMakeMessage");
  4506. // Response packets should not be sent with any timeout
  4507. if ( (NULL != pReceivePacket)
  4508. && (EAPCODE_Request == pReceivePacket->bCode))
  4509. {
  4510. if ( (pEapTlsCb->bId == pReceivePacket->bId)
  4511. && (EAPTLS_STATE_INITIAL != pEapTlsCb->EapTlsState))
  4512. {
  4513. // The server is repeating its request. Resend our last response.
  4514. pEapTlsCb->bCode = EAPCODE_Response;
  4515. dwErr = BuildPacket(pSendPacket, cbSendPacket, pEapTlsCb);
  4516. if (NO_ERROR != dwErr)
  4517. {
  4518. pEapOutput->Action = EAPACTION_NoAction;
  4519. }
  4520. else
  4521. {
  4522. EapTlsTrace("Resending response for request %d",
  4523. pEapTlsCb->bId);
  4524. pEapOutput->Action = EAPACTION_Send;
  4525. }
  4526. goto LDone;
  4527. }
  4528. else if (pReceivePacket->bFlags & EAPTLS_PACKET_FLAG_TLS_START)
  4529. {
  4530. // The server wants to renogitiate
  4531. dwErr = EapTlsReset(pEapTlsCb);
  4532. if (NO_ERROR != dwErr)
  4533. {
  4534. pEapOutput->Action = EAPACTION_NoAction;
  4535. goto LDone;
  4536. }
  4537. }
  4538. }
  4539. if (NULL != pReceivePacket)
  4540. {
  4541. // We are not getting the same old request. Therefore, whatever we sent
  4542. // last time has reached the server.
  4543. pEapTlsCb->dwBlobOutOffset = pEapTlsCb->dwBlobOutOffsetNew;
  4544. if (pEapTlsCb->dwBlobOutOffset == pEapTlsCb->cbBlobOut)
  4545. {
  4546. // We have sent whatever we wanted to send
  4547. pEapTlsCb->cbBlobOut = 0;
  4548. pEapTlsCb->dwBlobOutOffset = pEapTlsCb->dwBlobOutOffsetNew = 0;
  4549. }
  4550. }
  4551. switch (pEapTlsCb->EapTlsState)
  4552. {
  4553. case EAPTLS_STATE_INITIAL:
  4554. case EAPTLS_STATE_SENT_HELLO:
  4555. case EAPTLS_STATE_SENT_FINISHED:
  4556. if (NULL == pReceivePacket)
  4557. {
  4558. // We are called once in the initial state. Since we are the
  4559. // authenticatee, we do nothing, and wait for a request pakcet
  4560. // from the authenticator.
  4561. pEapOutput->Action = EAPACTION_NoAction;
  4562. goto LDone;
  4563. }
  4564. /*
  4565. else if (EAPCODE_Failure == pReceivePacket->bCode)
  4566. {
  4567. EapTlsTrace("Negotiation result according to peer: failure");
  4568. pEapTlsCb->dwAuthResultCode = E_FAIL;
  4569. pEapTlsCb->fFlags &= ~EAPTLSCB_FLAG_SUCCESS;
  4570. RespondToResult(pEapTlsCb, pEapOutput);
  4571. goto LDone;
  4572. }
  4573. */
  4574. else if (EAPCODE_Request != pReceivePacket->bCode)
  4575. {
  4576. // We shouldn't get any other packet in this state so
  4577. // we simply drop this invalid packet
  4578. EapTlsTrace("Code %d unexpected in state %s",
  4579. pReceivePacket->bCode, g_szEapTlsState[pEapTlsCb->EapTlsState]);
  4580. pEapOutput->Action = EAPACTION_NoAction;
  4581. dwErr = ERROR_PPP_INVALID_PACKET;
  4582. goto LDone;
  4583. }
  4584. else
  4585. {
  4586. if (0 != pEapTlsCb->cbBlobOut)
  4587. {
  4588. // We still have some stuff to send
  4589. if (WireToHostFormat16(pReceivePacket->pbLength) ==
  4590. EAPTLS_PACKET_HDR_LEN)
  4591. {
  4592. // The server is asking for more stuff by sending an empty
  4593. // request.
  4594. pEapTlsCb->bId = pReceivePacket->bId;
  4595. pEapTlsCb->bCode = EAPCODE_Response;
  4596. dwErr = BuildPacket(pSendPacket, cbSendPacket, pEapTlsCb);
  4597. if (NO_ERROR != dwErr)
  4598. {
  4599. pEapOutput->Action = EAPACTION_NoAction;
  4600. }
  4601. else
  4602. {
  4603. pEapOutput->Action = EAPACTION_Send;
  4604. }
  4605. goto LDone;
  4606. }
  4607. else
  4608. {
  4609. // We had more stuff to send, but the peer already wants to
  4610. // say something. Let us forget our stuff.
  4611. pEapTlsCb->cbBlobOut = 0;
  4612. pEapTlsCb->dwBlobOutOffset = 0;
  4613. pEapTlsCb->dwBlobOutOffsetNew = 0;
  4614. }
  4615. }
  4616. // Build the response packet
  4617. dwErr = MakeReplyMessage(pEapTlsCb, pReceivePacket);
  4618. if (NO_ERROR != dwErr)
  4619. {
  4620. pEapOutput->Action = EAPACTION_NoAction;
  4621. goto LDone;
  4622. }
  4623. if (EAPTLS_STATE_WAIT_FOR_USER_OK == pEapTlsCb->EapTlsState)
  4624. {
  4625. EAPTLS_VALIDATE_SERVER* pEapTlsValidateServer;
  4626. pEapOutput->Action = EAPACTION_NoAction;
  4627. pEapOutput->fInvokeInteractiveUI = TRUE;
  4628. pEapTlsValidateServer =
  4629. (EAPTLS_VALIDATE_SERVER*) (pEapTlsCb->pUIContextData);
  4630. pEapOutput->dwSizeOfUIContextData =
  4631. pEapTlsValidateServer->dwSize;
  4632. pEapOutput->pUIContextData = pEapTlsCb->pUIContextData;
  4633. pEapTlsCb->bNextId = pReceivePacket->bId;
  4634. }
  4635. else
  4636. {
  4637. pEapTlsCb->bId = pReceivePacket->bId;
  4638. pEapTlsCb->bCode = EAPCODE_Response;
  4639. dwErr = BuildPacket(pSendPacket, cbSendPacket, pEapTlsCb);
  4640. if (NO_ERROR != dwErr)
  4641. {
  4642. pEapOutput->Action = EAPACTION_NoAction;
  4643. }
  4644. else
  4645. {
  4646. pEapOutput->Action = EAPACTION_Send;
  4647. }
  4648. }
  4649. goto LDone;
  4650. }
  4651. break;
  4652. case EAPTLS_STATE_WAIT_FOR_USER_OK:
  4653. if ( (NULL == pEapInput)
  4654. || (!pEapInput->fDataReceivedFromInteractiveUI))
  4655. {
  4656. pEapOutput->Action = EAPACTION_NoAction;
  4657. break;
  4658. }
  4659. LocalFree(pEapTlsCb->pUIContextData);
  4660. pEapTlsCb->pUIContextData = NULL;
  4661. if ( (pEapInput->dwSizeOfDataFromInteractiveUI != sizeof(BYTE))
  4662. || (IDNO == *(pEapInput->pDataFromInteractiveUI)))
  4663. {
  4664. EapTlsTrace("User chose not to accept the server", dwErr);
  4665. dwAuthResultCode = ERROR_UNABLE_TO_AUTHENTICATE_SERVER;
  4666. pEapTlsCb->cbBlobIn = pEapTlsCb->dwBlobInRemining = 0;
  4667. pEapTlsCb->fFlags &= ~EAPTLSCB_FLAG_RECEIVING_FRAGMENTS;
  4668. pEapTlsCb->fFlags &= ~EAPTLSCB_FLAG_SUCCESS;
  4669. MakeAlert(pEapTlsCb,
  4670. AlertFromError(&dwAuthResultCode, TRUE),
  4671. FALSE);
  4672. }
  4673. else
  4674. {
  4675. EapTlsTrace("User chose to accept the server", dwErr);
  4676. pEapTlsCb->fFlags |= EAPTLSCB_FLAG_SUCCESS;
  4677. dwAuthResultCode = NO_ERROR;
  4678. }
  4679. pEapTlsCb->EapTlsState = EAPTLS_STATE_RECD_FINISHED;
  4680. EapTlsTrace("State change to %s. Error: 0x%x",
  4681. g_szEapTlsState[pEapTlsCb->EapTlsState],
  4682. dwAuthResultCode);
  4683. pEapTlsCb->dwAuthResultCode = dwAuthResultCode;
  4684. pEapTlsCb->bId = pEapTlsCb->bNextId;
  4685. pEapTlsCb->bCode = EAPCODE_Response;
  4686. dwErr = BuildPacket(pSendPacket, cbSendPacket, pEapTlsCb);
  4687. if (NO_ERROR != dwErr)
  4688. {
  4689. pEapOutput->Action = EAPACTION_NoAction;
  4690. }
  4691. else
  4692. {
  4693. pEapOutput->Action = EAPACTION_Send;
  4694. }
  4695. break;
  4696. case EAPTLS_STATE_RECD_FINISHED:
  4697. if (NULL == pReceivePacket)
  4698. {
  4699. // If we did not receive a packet then we check to see if the
  4700. // fSuccessPacketReceived flag is set (we received an NCP packet:
  4701. // an implicit EAP-Success).
  4702. if ( (NULL != pEapInput)
  4703. && (pEapInput->fSuccessPacketReceived))
  4704. {
  4705. // The peer thinks that the negotiation was successful
  4706. EapTlsTrace("Negotiation result according to peer: success");
  4707. RespondToResult(pEapTlsCb, pEapOutput);
  4708. }
  4709. else
  4710. {
  4711. pEapOutput->Action = EAPACTION_NoAction;
  4712. }
  4713. goto LDone;
  4714. }
  4715. else
  4716. {
  4717. switch (pReceivePacket->bCode)
  4718. {
  4719. case EAPCODE_Success:
  4720. case EAPCODE_Failure:
  4721. if (pReceivePacket->bId != pEapTlsCb->bId)
  4722. {
  4723. EapTlsTrace("Success/Failure packet has invalid id: %d. "
  4724. "Expected: %d",
  4725. pReceivePacket->bId, pEapTlsCb->bId);
  4726. }
  4727. EapTlsTrace("Negotiation result according to peer: %s",
  4728. (EAPCODE_Success == pReceivePacket->bCode) ?
  4729. "success" : "failure");
  4730. RespondToResult(pEapTlsCb, pEapOutput);
  4731. goto LDone;
  4732. break;
  4733. case EAPCODE_Request:
  4734. case EAPCODE_Response:
  4735. default:
  4736. if ( pEapTlsCb->fFlags & EAPTLSCB_FLAG_EXECUTING_PEAP )
  4737. {
  4738. //
  4739. // if we are in peap, no success is send back.
  4740. // instead identity request is send across.
  4741. // Complete
  4742. if ( pReceivePacket->bCode == EAPCODE_Request )
  4743. {
  4744. RespondToResult(pEapTlsCb, pEapOutput);
  4745. goto LDone;
  4746. }
  4747. EapTlsTrace("Unexpected code: %d in state %s",
  4748. pReceivePacket->bCode,
  4749. g_szEapTlsState[pEapTlsCb->EapTlsState]);
  4750. pEapOutput->Action = EAPACTION_NoAction;
  4751. }
  4752. else
  4753. {
  4754. EapTlsTrace("Unexpected code: %d in state %s",
  4755. pReceivePacket->bCode,
  4756. g_szEapTlsState[pEapTlsCb->EapTlsState]);
  4757. pEapOutput->Action = EAPACTION_NoAction;
  4758. goto LDone;
  4759. }
  4760. break;
  4761. }
  4762. }
  4763. break;
  4764. default:
  4765. EapTlsTrace("Why is the client in this state: %d?",
  4766. pEapTlsCb->EapTlsState);
  4767. RTASSERT(FALSE);
  4768. pEapOutput->Action = EAPACTION_NoAction;
  4769. dwErr = ERROR_PPP_INVALID_PACKET;
  4770. break;
  4771. }
  4772. LDone:
  4773. return(dwErr);
  4774. }
  4775. /*
  4776. Returns:
  4777. Error codes only from winerror.h, raserror.h or mprerror.h.
  4778. Notes:
  4779. Called by the server to process an incoming packet and/or send a packet.
  4780. cbSendPacket is the size in bytes of the buffer pointed to by pSendPacket.
  4781. This function is called only after FValidPacket(pReceivePacket) returns
  4782. TRUE. If pEapOutput->Action is going to be EAPACTION_SendAndDone or
  4783. EAPACTION_Done, make sure that pEapOutput->dwAuthResultCode has been set.
  4784. If dwAuthResultCode is NO_ERROR, make sure that pEapOutput->pUserAttributes
  4785. has been set.
  4786. */
  4787. DWORD
  4788. EapTlsSMakeMessage(
  4789. IN EAPTLSCB* pEapTlsCb,
  4790. IN EAPTLS_PACKET* pReceivePacket,
  4791. OUT EAPTLS_PACKET* pSendPacket,
  4792. IN DWORD cbSendPacket,
  4793. OUT PPP_EAP_OUTPUT* pEapOutput,
  4794. IN PPP_EAP_INPUT* pEapInput
  4795. )
  4796. {
  4797. DWORD dwErr = NO_ERROR;
  4798. BOOL fSessionResumed = FALSE;
  4799. EapTlsTrace("EapTlsSMakeMessage");
  4800. if ( (NULL != pReceivePacket)
  4801. && (EAPCODE_Response == pReceivePacket->bCode)
  4802. && (pReceivePacket->bId == pEapTlsCb->bId))
  4803. {
  4804. // Whatever we sent last time has reached the client.
  4805. pEapTlsCb->dwBlobOutOffset = pEapTlsCb->dwBlobOutOffsetNew;
  4806. if (pEapTlsCb->dwBlobOutOffset == pEapTlsCb->cbBlobOut)
  4807. {
  4808. // We have sent whatever we wanted to send
  4809. pEapTlsCb->cbBlobOut = 0;
  4810. pEapTlsCb->dwBlobOutOffset = pEapTlsCb->dwBlobOutOffsetNew = 0;
  4811. }
  4812. }
  4813. switch (pEapTlsCb->EapTlsState)
  4814. {
  4815. case EAPTLS_STATE_INITIAL:
  4816. // Create a Request packet
  4817. dwErr = EapTlsReset(pEapTlsCb);
  4818. if (NO_ERROR != dwErr)
  4819. {
  4820. pEapOutput->Action = EAPACTION_NoAction;
  4821. goto LDone;
  4822. }
  4823. // pEapTlsCb->bId already has bInitialId
  4824. pEapTlsCb->bCode = EAPCODE_Request;
  4825. dwErr = BuildPacket(pSendPacket, cbSendPacket, pEapTlsCb);
  4826. if (NO_ERROR != dwErr)
  4827. {
  4828. pEapOutput->Action = EAPACTION_NoAction;
  4829. goto LDone;
  4830. }
  4831. // Request messages must be sent with a timeout
  4832. pEapOutput->Action = EAPACTION_SendWithTimeoutInteractive;
  4833. pEapTlsCb->EapTlsState = EAPTLS_STATE_SENT_START;
  4834. EapTlsTrace("State change to %s",
  4835. g_szEapTlsState[pEapTlsCb->EapTlsState]);
  4836. goto LDone;
  4837. break;
  4838. case EAPTLS_STATE_SENT_START:
  4839. case EAPTLS_STATE_SENT_HELLO:
  4840. case EAPTLS_STATE_SENT_FINISHED:
  4841. if (NULL == pReceivePacket)
  4842. {
  4843. // We timed out waiting for a response from the authenticatee.
  4844. // we need to resend with the same Id.
  4845. pEapTlsCb->bCode = EAPCODE_Request;
  4846. dwErr = BuildPacket(pSendPacket, cbSendPacket, pEapTlsCb);
  4847. if (NO_ERROR != dwErr)
  4848. {
  4849. pEapOutput->Action = EAPACTION_NoAction;
  4850. }
  4851. else
  4852. {
  4853. EapTlsTrace("Resending request %d", pEapTlsCb->bId);
  4854. pEapOutput->Action = EAPACTION_SendWithTimeoutInteractive;
  4855. }
  4856. goto LDone;
  4857. }
  4858. else if (EAPCODE_Response != pReceivePacket->bCode)
  4859. {
  4860. // We should only get responses
  4861. EapTlsTrace("Ignoring non response packet from client");
  4862. pEapOutput->Action = EAPACTION_NoAction;
  4863. dwErr = ERROR_PPP_INVALID_PACKET;
  4864. goto LDone;
  4865. }
  4866. else if (pReceivePacket->bId != pEapTlsCb->bId)
  4867. {
  4868. EapTlsTrace("Ignoring duplicate response packet");
  4869. pEapOutput->Action = EAPACTION_NoAction;
  4870. goto LDone;
  4871. }
  4872. else
  4873. {
  4874. // We have received a response with the right Id.
  4875. if (0 != pEapTlsCb->cbBlobOut)
  4876. {
  4877. // We still have some stuff to send
  4878. if (WireToHostFormat16(pReceivePacket->pbLength) ==
  4879. EAPTLS_PACKET_HDR_LEN)
  4880. {
  4881. // The client is asking for more stuff by sending an empty
  4882. // response.
  4883. pEapTlsCb->bId++;
  4884. pEapTlsCb->bCode = EAPCODE_Request;
  4885. dwErr = BuildPacket(pSendPacket, cbSendPacket, pEapTlsCb);
  4886. if (NO_ERROR != dwErr)
  4887. {
  4888. pEapOutput->Action = EAPACTION_NoAction;
  4889. }
  4890. else
  4891. {
  4892. pEapOutput->Action =
  4893. EAPACTION_SendWithTimeoutInteractive;
  4894. }
  4895. goto LDone;
  4896. }
  4897. else
  4898. {
  4899. // We had more stuff to send, but the peer already wants to
  4900. // say something. Let us forget our stuff.
  4901. pEapTlsCb->cbBlobOut = 0;
  4902. pEapTlsCb->dwBlobOutOffset = 0;
  4903. pEapTlsCb->dwBlobOutOffsetNew = 0;
  4904. }
  4905. }
  4906. if (EAPTLS_STATE_SENT_FINISHED != pEapTlsCb->EapTlsState)
  4907. {
  4908. // We don't have any more stuff to send.
  4909. // Build the response packet
  4910. dwErr = MakeReplyMessage(pEapTlsCb, pReceivePacket);
  4911. if (NO_ERROR != dwErr)
  4912. {
  4913. pEapOutput->Action = EAPACTION_NoAction;
  4914. goto LDone;
  4915. }
  4916. if ( (0 == pEapTlsCb->cbBlobOut)
  4917. && (EAPTLS_STATE_SENT_FINISHED == pEapTlsCb->EapTlsState))
  4918. {
  4919. // If the client sent an alert, send Failure immediately.
  4920. // Do not send one more request.
  4921. pEapTlsCb->bId++;
  4922. if (!(pEapTlsCb->fFlags & EAPTLSCB_FLAG_SUCCESS))
  4923. {
  4924. RTASSERT(NO_ERROR != pEapTlsCb->dwAuthResultCode);
  4925. }
  4926. else
  4927. {
  4928. fSessionResumed = TRUE;
  4929. }
  4930. }
  4931. else
  4932. {
  4933. pEapTlsCb->bId++;
  4934. pEapTlsCb->bCode = EAPCODE_Request;
  4935. dwErr = BuildPacket(pSendPacket, cbSendPacket, pEapTlsCb);
  4936. if (NO_ERROR != dwErr)
  4937. {
  4938. pEapOutput->Action = EAPACTION_NoAction;
  4939. }
  4940. else
  4941. {
  4942. pEapOutput->Action =
  4943. EAPACTION_SendWithTimeoutInteractive;
  4944. }
  4945. goto LDone;
  4946. }
  4947. }
  4948. if (!(pEapTlsCb->fFlags & EAPTLSCB_FLAG_SUCCESS))
  4949. {
  4950. EapTlsTrace("Negotiation unsuccessful");
  4951. pEapTlsCb->bCode = EAPCODE_Failure;
  4952. }
  4953. else
  4954. {
  4955. if ( (WireToHostFormat16(pReceivePacket->pbLength) ==
  4956. EAPTLS_PACKET_HDR_LEN)
  4957. || fSessionResumed)
  4958. {
  4959. EapTlsTrace("Negotiation successful");
  4960. pEapTlsCb->bCode = EAPCODE_Success;
  4961. }
  4962. else
  4963. {
  4964. // We got an alert from the client
  4965. EapTlsTrace("Client sent an alert; "
  4966. "negotiation unsuccessful");
  4967. GetAlert(pEapTlsCb, pReceivePacket);
  4968. pEapTlsCb->bCode = EAPCODE_Failure;
  4969. }
  4970. }
  4971. // pEapTlsCb->bId should be the same as that of the last
  4972. // request.
  4973. dwErr = BuildPacket(pSendPacket, cbSendPacket, pEapTlsCb);
  4974. if (NO_ERROR != dwErr)
  4975. {
  4976. pEapOutput->Action = EAPACTION_NoAction;
  4977. }
  4978. else
  4979. {
  4980. #if 0
  4981. RTASSERT( ( EAPCODE_Failure == pEapTlsCb->bCode
  4982. && NO_ERROR != pEapTlsCb->dwAuthResultCode)
  4983. || ( EAPCODE_Success == pEapTlsCb->bCode
  4984. && NO_ERROR == pEapTlsCb->dwAuthResultCode));
  4985. #endif
  4986. EapTlsTrace ("AuthResultCode = (%ld), bCode = (%ld)",
  4987. pEapTlsCb->dwAuthResultCode,
  4988. pEapTlsCb->bCode);
  4989. pEapOutput->pUserAttributes = pEapTlsCb->pAttributes;
  4990. pEapOutput->dwAuthResultCode = pEapTlsCb->dwAuthResultCode;
  4991. pEapOutput->Action = EAPACTION_SendAndDone;
  4992. }
  4993. goto LDone;
  4994. }
  4995. break;
  4996. default:
  4997. EapTlsTrace("Why is the server in this state: %d?",
  4998. pEapTlsCb->EapTlsState);
  4999. RTASSERT(FALSE);
  5000. pEapOutput->Action = EAPACTION_NoAction;
  5001. dwErr = ERROR_PPP_INVALID_PACKET;
  5002. break;
  5003. }
  5004. LDone:
  5005. return(dwErr);
  5006. }
  5007. DWORD
  5008. RasEapGetCredentials(
  5009. IN DWORD dwTypeId,
  5010. IN VOID * pWorkBuf,
  5011. OUT VOID ** ppCredentials)
  5012. {
  5013. EAPTLSCB *pEapTlsCb = (EAPTLSCB *)pWorkBuf;
  5014. if(PPP_EAP_PEAP == dwTypeId)
  5015. {
  5016. return PeapGetCredentials(
  5017. pWorkBuf,
  5018. ppCredentials);
  5019. }
  5020. else if( (PPP_EAP_TLS != dwTypeId)
  5021. || (NULL == pEapTlsCb))
  5022. {
  5023. return E_INVALIDARG;
  5024. }
  5025. //
  5026. // Get TLS credentials here and return them in the
  5027. // pCredentials blob.
  5028. //
  5029. return GetCredentialsFromUserProperties(pEapTlsCb,
  5030. ppCredentials);
  5031. }
  5032. /////////////////////////////All PEAP related stuff //////////////////////////////////
  5033. DWORD
  5034. EapPeapInitialize(
  5035. IN BOOL fInitialize
  5036. )
  5037. {
  5038. DWORD dwRetCode = NO_ERROR;
  5039. static DWORD dwRefCount = 0;
  5040. EapTlsInitialize(fInitialize);
  5041. //
  5042. // Get a list of all EapTypes that can be Peap enabled
  5043. //
  5044. if ( fInitialize )
  5045. {
  5046. if ( !dwRefCount )
  5047. {
  5048. g_pCachedCreds = NULL;
  5049. dwRetCode = PeapEapInfoGetList ( NULL, FALSE, &g_pEapInfo);
  5050. #ifdef DBG
  5051. //
  5052. // If we are in checked mode, load the test hook if one exists.
  5053. //
  5054. //
  5055. g_hTestHook = LoadLibrary ( L"peaphook.dll");
  5056. if ( NULL == g_hTestHook )
  5057. {
  5058. EapTlsTrace ("peaphook could not be loaded. This is not an error. Return Code 0x%x", GetLastError() );
  5059. }
  5060. else
  5061. {
  5062. //
  5063. // Get Addresses of the functions
  5064. //
  5065. TestHookPacketFromPeer =
  5066. GetProcAddress (g_hTestHook, "TestHookPacketFromPeer");
  5067. TestHookPacketToPeer =
  5068. GetProcAddress (g_hTestHook, "TestHookPacketToPeer");
  5069. TestHookPacketFree =
  5070. GetProcAddress (g_hTestHook, "TestHookPacketFree");
  5071. if ( TestHookPacketFromPeer &&
  5072. TestHookPacketToPeer &&
  5073. TestHookPacketFree
  5074. )
  5075. {
  5076. g_fHookInitialized = TRUE;
  5077. }
  5078. else
  5079. {
  5080. EapTlsTrace ("peaphook does not export all required entry points. Will not use the hook DLL");
  5081. }
  5082. }
  5083. #endif
  5084. }
  5085. dwRefCount++;
  5086. }
  5087. else
  5088. {
  5089. dwRefCount --;
  5090. if ( !dwRefCount )
  5091. {
  5092. PeapEapInfoFreeList( g_pEapInfo );
  5093. g_pEapInfo = NULL;
  5094. #ifdef DBG
  5095. if ( g_hTestHook )
  5096. {
  5097. FreeLibrary ( g_hTestHook );
  5098. g_hTestHook = NULL;
  5099. TestHookPacketFromPeer = NULL;
  5100. TestHookPacketToPeer = NULL;
  5101. TestHookPacketFree = NULL;
  5102. }
  5103. g_fHookInitialized = FALSE;
  5104. #endif
  5105. }
  5106. }
  5107. return dwRetCode;
  5108. }
  5109. DWORD
  5110. EapPeapBegin(
  5111. OUT VOID** ppWorkBuffer,
  5112. IN PPP_EAP_INPUT* pPppEapInput
  5113. )
  5114. {
  5115. DWORD dwRetCode = NO_ERROR;
  5116. PPEAPCB pPeapCB = NULL;
  5117. PPP_EAP_INPUT PppEapInputToTls;
  5118. EAPTLS_USER_PROPERTIES EapTlsUserProp;
  5119. PEAP_ENTRY_USER_PROPERTIES UNALIGNED * pEntryUserProp = NULL;
  5120. PEAP_ENTRY_CONN_PROPERTIES UNALIGNED * pEntryConnProp = NULL;
  5121. PPEAP_USER_PROP pTempUserProp = NULL;
  5122. EapTlsTrace("EapPeapBegin");
  5123. RTASSERT(NULL != ppWorkBuffer);
  5124. RTASSERT(NULL != pPppEapInput);
  5125. RtlSecureZeroMemory ( &PppEapInputToTls, sizeof(PppEapInputToTls));
  5126. dwRetCode = VerifyCallerTrust(_ReturnAddress());
  5127. if ( NO_ERROR != dwRetCode )
  5128. {
  5129. EapTlsTrace("Unauthorized use of PEAP attempted");
  5130. goto LDone;
  5131. }
  5132. pPeapCB = (PPEAPCB)LocalAlloc(LPTR, sizeof(PEAPCB) );
  5133. if ( NULL == pPeapCB )
  5134. {
  5135. EapTlsTrace("Error allocating memory for PEAPCB");
  5136. dwRetCode = ERROR_OUTOFMEMORY;
  5137. goto LDone;
  5138. }
  5139. //
  5140. // Get info for each of the configured eap types and call
  5141. // initialze and then begin
  5142. //
  5143. pPeapCB->PeapState = PEAP_STATE_INITIAL;
  5144. if ( pPppEapInput->fAuthenticator )
  5145. {
  5146. pPeapCB->dwFlags |= PEAPCB_FLAG_SERVER;
  5147. }
  5148. pPppEapInput->fFlags & RAS_EAP_FLAG_ROUTER ?
  5149. pPeapCB->dwFlags |= PEAPCB_FLAG_ROUTER:0;
  5150. pPppEapInput->fFlags & RAS_EAP_FLAG_NON_INTERACTIVE ?
  5151. pPeapCB->dwFlags |= PEAPCB_FLAG_NON_INTERACTIVE:0;
  5152. pPppEapInput->fFlags & RAS_EAP_FLAG_LOGON ?
  5153. pPeapCB->dwFlags |= PEAPCB_FLAG_LOGON:0;
  5154. pPppEapInput->fFlags & RAS_EAP_FLAG_PREVIEW ?
  5155. pPeapCB->dwFlags |= PEAPCB_FLAG_PREVIEW:0;
  5156. pPppEapInput->fFlags & RAS_EAP_FLAG_FIRST_LINK ?
  5157. pPeapCB->dwFlags |= PEAPCB_FLAG_FIRST_LINK:0;
  5158. pPppEapInput->fFlags & RAS_EAP_FLAG_MACHINE_AUTH ?
  5159. pPeapCB->dwFlags |= PEAPCB_FLAG_MACHINE_AUTH:0;
  5160. pPppEapInput->fFlags & RAS_EAP_FLAG_GUEST_ACCESS?
  5161. pPeapCB->dwFlags |= PEAPCB_FLAG_GUEST_ACCESS :0;
  5162. pPppEapInput->fFlags & RAS_EAP_FLAG_8021X_AUTH ?
  5163. pPeapCB->dwFlags |= PEAPCB_FLAG_8021X_AUTH:0;
  5164. pPeapCB->hTokenImpersonateUser = pPppEapInput->hTokenImpersonateUser;
  5165. if ( pPppEapInput->pwszPassword )
  5166. {
  5167. wcsncpy ( pPeapCB->awszPassword, pPppEapInput->pwszPassword, PWLEN );
  5168. }
  5169. if ( pPeapCB->dwFlags & PEAPCB_FLAG_SERVER )
  5170. {
  5171. #if 0
  5172. //
  5173. // Read Server Configuration from the registry
  5174. //
  5175. dwRetCode = PeapServerConfigDataIO(TRUE /* fRead */, NULL /* pwszMachineName */,
  5176. (BYTE**)&(pPeapCB->pUserProp), 0);
  5177. if ( NO_ERROR != dwRetCode )
  5178. {
  5179. EapTlsTrace("Error reading server configuration. 0x%x", dwRetCode );
  5180. goto LDone;
  5181. }
  5182. #endif
  5183. dwRetCode = PeapReadUserData(TRUE,
  5184. pPppEapInput->pConnectionData,
  5185. pPppEapInput->dwSizeOfConnectionData,
  5186. &pPeapCB->pUserProp);
  5187. if(NO_ERROR != dwRetCode)
  5188. {
  5189. goto LDone;
  5190. }
  5191. PeapVerifyUserData(
  5192. g_pEapInfo,
  5193. pPeapCB->pUserProp,
  5194. &pTempUserProp
  5195. );
  5196. if ( pTempUserProp )
  5197. {
  5198. if ( pPeapCB->pUserProp )
  5199. LocalFree (pPeapCB->pUserProp);
  5200. pPeapCB->pUserProp = pTempUserProp;
  5201. }
  5202. //
  5203. // For all configured PEAP types load EAPINFO
  5204. //
  5205. dwRetCode = PeapGetFirstEntryUserProp ( pPeapCB->pUserProp,
  5206. &pEntryUserProp
  5207. );
  5208. if ( NO_ERROR != dwRetCode )
  5209. {
  5210. EapTlsTrace("Error PEAP not configured correctly. 0x%x", dwRetCode );
  5211. goto LDone;
  5212. }
  5213. //
  5214. // Get the selected EAP type
  5215. //
  5216. dwRetCode = PeapEapInfoCopyListNode ( pEntryUserProp->dwEapTypeId,
  5217. g_pEapInfo,
  5218. &pPeapCB->pEapInfo
  5219. );
  5220. if ( NO_ERROR != dwRetCode || NULL == pPeapCB->pEapInfo )
  5221. {
  5222. EapTlsTrace("Cannot find configured PEAP in the list of EAP Types on this machine.");
  5223. goto LDone;
  5224. }
  5225. //
  5226. // Check to see if we are enabled to do fast reconnect
  5227. //
  5228. if ( pPeapCB->pUserProp->dwFlags & PEAP_USER_FLAG_FAST_ROAMING )
  5229. {
  5230. pPeapCB->dwFlags |= PEAPCB_FAST_ROAMING;
  5231. }
  5232. }
  5233. else
  5234. {
  5235. //
  5236. // This is a client. So get PEAP conn prop and
  5237. // user prop
  5238. //
  5239. dwRetCode = PeapReadConnectionData( ( pPppEapInput->fFlags & RAS_EAP_FLAG_8021X_AUTH ),
  5240. pPppEapInput->pConnectionData,
  5241. pPppEapInput->dwSizeOfConnectionData,
  5242. &(pPeapCB->pConnProp)
  5243. );
  5244. if (NO_ERROR != dwRetCode)
  5245. {
  5246. EapTlsTrace("Error Reading Connection Data. 0x%x", dwRetCode);
  5247. goto LDone;
  5248. }
  5249. //
  5250. // Read user data now
  5251. //
  5252. dwRetCode = PeapReadUserData( FALSE,
  5253. pPppEapInput->pUserData,
  5254. pPppEapInput->dwSizeOfUserData,
  5255. &(pPeapCB->pUserProp)
  5256. );
  5257. if ( NO_ERROR != dwRetCode )
  5258. {
  5259. EapTlsTrace("Error Reading User Data. 0x%x", dwRetCode);
  5260. goto LDone;
  5261. }
  5262. dwRetCode = PeapGetFirstEntryConnProp ( pPeapCB->pConnProp,
  5263. &pEntryConnProp
  5264. );
  5265. if ( NO_ERROR != dwRetCode )
  5266. {
  5267. EapTlsTrace("Error PEAP not configured correctly. 0x%x", dwRetCode );
  5268. goto LDone;
  5269. }
  5270. //
  5271. // Get the selected EAP type
  5272. //
  5273. dwRetCode = PeapEapInfoCopyListNode ( pEntryConnProp->dwEapTypeId,
  5274. g_pEapInfo,
  5275. &pPeapCB->pEapInfo
  5276. );
  5277. if ( NO_ERROR != dwRetCode || NULL == pPeapCB->pEapInfo )
  5278. {
  5279. EapTlsTrace("Cannot find configured PEAP in the list of EAP Types on this machine.");
  5280. goto LDone;
  5281. }
  5282. //
  5283. // Check to see if we are enabled to do fast reconnect
  5284. //
  5285. if ( pPeapCB->pConnProp->dwFlags & PEAP_CONN_FLAG_FAST_ROAMING )
  5286. {
  5287. pPeapCB->dwFlags |= PEAPCB_FAST_ROAMING;
  5288. }
  5289. }
  5290. //
  5291. // Call Initialize and Begin for the
  5292. // configured EAP type.
  5293. // Call Begin for EapTls.
  5294. // We need to create PPP_EAP_INFO for this
  5295. //
  5296. //
  5297. // Call Begin for EapTlsBegin first
  5298. //
  5299. ZeroMemory ( &PppEapInputToTls, sizeof(PppEapInputToTls) );
  5300. CopyMemory ( &PppEapInputToTls, pPppEapInput, sizeof(PppEapInputToTls) );
  5301. if ( pPeapCB->dwFlags & PEAPCB_FLAG_SERVER )
  5302. {
  5303. //
  5304. // Zero out the connection data for the server
  5305. //
  5306. PppEapInputToTls.pConnectionData = NULL;
  5307. PppEapInputToTls.dwSizeOfConnectionData = 0;
  5308. }
  5309. PppEapInputToTls.dwSizeInBytes = sizeof(PppEapInputToTls);
  5310. PppEapInputToTls.fFlags = pPppEapInput->fFlags | EAPTLSCB_FLAG_EXECUTING_PEAP;
  5311. if ( pPeapCB->pConnProp )
  5312. {
  5313. //
  5314. // Get the V0 struct required by eaptls
  5315. //
  5316. ConnPropGetV0Struct ( &(pPeapCB->pConnProp->EapTlsConnProp),
  5317. (EAPTLS_CONN_PROPERTIES **) &(PppEapInputToTls.pConnectionData) );
  5318. PppEapInputToTls.dwSizeOfConnectionData =
  5319. ((EAPTLS_CONN_PROPERTIES *) (PppEapInputToTls.pConnectionData) )->dwSize;
  5320. }
  5321. ZeroMemory( &EapTlsUserProp, sizeof(EapTlsUserProp) );
  5322. EapTlsUserProp.dwVersion = 1;
  5323. EapTlsUserProp.dwSize = sizeof(EapTlsUserProp);
  5324. CopyMemory ( &EapTlsUserProp.Hash,
  5325. &(pPeapCB->pUserProp->CertHash),
  5326. sizeof(EapTlsUserProp.Hash)
  5327. );
  5328. PppEapInputToTls.pUserData = (VOID *)&EapTlsUserProp;
  5329. PppEapInputToTls.dwSizeOfUserData = sizeof(EapTlsUserProp);
  5330. dwRetCode = EapTlsBegin ( (VOID **)&(pPeapCB->pEapTlsCB),
  5331. &PppEapInputToTls
  5332. );
  5333. //
  5334. // Save the identity for later use
  5335. //
  5336. wcsncpy(pPeapCB->awszIdentity,
  5337. pPppEapInput->pwszIdentity ? pPppEapInput->pwszIdentity : L"", UNLEN + DNLEN);
  5338. *ppWorkBuffer = (VOID *)pPeapCB;
  5339. LDone:
  5340. if ( PppEapInputToTls.pConnectionData )
  5341. LocalFree ( PppEapInputToTls.pConnectionData );
  5342. EapTlsTrace("EapPeapBegin done");
  5343. return dwRetCode;
  5344. }
  5345. DWORD
  5346. EapPeapEnd(
  5347. IN PPEAPCB pPeapCb
  5348. )
  5349. {
  5350. DWORD dwRetCode = NO_ERROR;
  5351. EapTlsTrace("EapPeapEnd");
  5352. //
  5353. // call end for eaptls and each of the peap types
  5354. // configured first and then execute code for
  5355. // peap end.
  5356. if ( pPeapCb )
  5357. {
  5358. dwRetCode = EapTlsEnd((VOID *)pPeapCb->pEapTlsCB);
  5359. //Call the embedded type's end here
  5360. if ( pPeapCb->pEapInfo )
  5361. {
  5362. dwRetCode = pPeapCb->pEapInfo->PppEapInfo.RasEapEnd
  5363. ( pPeapCb->pEapInfo->pWorkBuf);
  5364. pPeapCb->pEapInfo->pWorkBuf = NULL;
  5365. LocalFree ( pPeapCb->pEapInfo );
  5366. pPeapCb->pEapInfo = NULL;
  5367. }
  5368. LocalFree ( pPeapCb->pConnProp );
  5369. LocalFree ( pPeapCb->pUserProp );
  5370. LocalFree ( pPeapCb->pUIContextData );
  5371. if ( pPeapCb->pPrevReceivePacket )
  5372. {
  5373. LocalFree ( pPeapCb->pPrevReceivePacket );
  5374. }
  5375. if ( pPeapCb->pPrevDecData )
  5376. {
  5377. LocalFree ( pPeapCb->pPrevDecData );
  5378. }
  5379. if ( pPeapCb->pFinalUserAttributes )
  5380. {
  5381. RasAuthAttributeDestroy(pPeapCb->pFinalUserAttributes);
  5382. }
  5383. if ( pPeapCb->pTypeUserAttributes )
  5384. {
  5385. RasAuthAttributeDestroy(pPeapCb->pTypeUserAttributes);
  5386. }
  5387. #ifdef USE_CUSTOM_TUNNEL_KEYS
  5388. if ( pPeapCb->hSendKey )
  5389. {
  5390. CryptDestroyKey ( pPeapCb->hSendKey );
  5391. }
  5392. if ( pPeapCb->hRecvKey )
  5393. {
  5394. CryptDestroyKey ( pPeapCb->hRecvKey );
  5395. }
  5396. #endif
  5397. if ( pPeapCb->hProv )
  5398. {
  5399. CryptReleaseContext(pPeapCb->hProv, 0 );
  5400. }
  5401. if ( pPeapCb->pbIoBuffer )
  5402. {
  5403. LocalFree ( pPeapCb->pbIoBuffer );
  5404. }
  5405. LocalFree ( pPeapCb );
  5406. pPeapCb = NULL;
  5407. }
  5408. EapTlsTrace("EapPeapEnd done");
  5409. return dwRetCode;
  5410. }
  5411. //
  5412. // Check to see if this is a duplicate packet received.
  5413. //
  5414. BOOL
  5415. IsDuplicatePacket
  5416. (
  5417. IN PPEAPCB pPeapCb,
  5418. IN PPP_EAP_PACKET * pNewPacket
  5419. )
  5420. {
  5421. BOOL fRet = FALSE;
  5422. WORD wPacketLen = 0;
  5423. EapTlsTrace("IsDuplicatePacket");
  5424. wPacketLen = WireToHostFormat16 ( pNewPacket->Length );
  5425. if ( wPacketLen == pPeapCb->cbPrevReceivePacket )
  5426. {
  5427. //
  5428. // We have the same packet length
  5429. // Now compare the packet and see
  5430. // if it is the same
  5431. //
  5432. if ( pPeapCb->pPrevReceivePacket )
  5433. {
  5434. if ( !memcmp( pNewPacket, pPeapCb->pPrevReceivePacket, wPacketLen ) )
  5435. {
  5436. //
  5437. // we got a dup packet
  5438. //
  5439. EapTlsTrace("Got Duplicate Packet");
  5440. fRet = TRUE;
  5441. }
  5442. }
  5443. }
  5444. return fRet;
  5445. }
  5446. DWORD
  5447. PeapDecryptTunnelData
  5448. (
  5449. IN PPEAPCB pPeapCb,
  5450. IN OUT PBYTE pbData,
  5451. IN DWORD dwSizeofData
  5452. )
  5453. {
  5454. SecBufferDesc SecBufferDesc;
  5455. SecBuffer SecBuffer[4];
  5456. SECURITY_STATUS status;
  5457. INT i = 0;
  5458. #ifdef DBG
  5459. BOOL fDataReturnedFromHookDLL = FALSE;
  5460. PBYTE pbNewData = NULL;
  5461. DWORD dwSizeOfNewData = 0;
  5462. #endif
  5463. EapTlsTrace("PeapDecryptTunnelData");
  5464. //
  5465. // Use the schannel context to encrypt data
  5466. //
  5467. SecBufferDesc.ulVersion = SECBUFFER_VERSION;
  5468. SecBufferDesc.cBuffers = 4;
  5469. SecBufferDesc.pBuffers = SecBuffer;
  5470. SecBuffer[0].cbBuffer = dwSizeofData;
  5471. SecBuffer[0].BufferType = SECBUFFER_DATA;
  5472. SecBuffer[0].pvBuffer = pbData;
  5473. SecBuffer[1].BufferType = SECBUFFER_EMPTY;
  5474. SecBuffer[2].BufferType = SECBUFFER_EMPTY;
  5475. SecBuffer[3].BufferType = SECBUFFER_EMPTY;
  5476. status = DecryptMessage ( &(pPeapCb->pEapTlsCB->hContext),
  5477. &SecBufferDesc,
  5478. 0,
  5479. 0
  5480. );
  5481. EapTlsTrace("PeapDecryptTunnelData completed with status 0x%x", status);
  5482. if ( SEC_E_OK == status )
  5483. {
  5484. //
  5485. // Copy over the decrypted data to our io buffer
  5486. //
  5487. while ( i < 4 )
  5488. {
  5489. if(SecBuffer[i].BufferType == SECBUFFER_DATA)
  5490. {
  5491. CopyMemory ( pPeapCb->pbIoBuffer,
  5492. SecBuffer[i].pvBuffer,
  5493. SecBuffer[i].cbBuffer
  5494. );
  5495. pPeapCb->dwIoBufferLen = SecBuffer[i].cbBuffer;
  5496. break;
  5497. }
  5498. i++;
  5499. }
  5500. }
  5501. #ifdef DBG
  5502. //
  5503. // Just before encryption if we have a hook call into
  5504. // it to get the new packet
  5505. if ( g_fHookInitialized )
  5506. {
  5507. TestHookPacketFromPeer ( pPeapCb,
  5508. pPeapCb->pbIoBuffer,
  5509. pPeapCb->dwIoBufferLen,
  5510. &pbNewData ,
  5511. &dwSizeOfNewData
  5512. );
  5513. }
  5514. if (pbNewData && dwSizeOfNewData )
  5515. {
  5516. //
  5517. // Copy over the packet send by
  5518. // the hook
  5519. CopyMemory ( pPeapCb->pbIoBuffer,
  5520. pbNewData,
  5521. dwSizeOfNewData
  5522. );
  5523. pPeapCb->dwIoBufferLen = dwSizeOfNewData;
  5524. TestHookPacketFree ( pPeapCb, pbNewData );
  5525. }
  5526. #endif
  5527. return status;
  5528. }
  5529. //
  5530. // Use this function on client side.
  5531. // This will first check to see if this is a duplicate packet
  5532. // If so, it will replace the current packet with duplicate
  5533. // one. Or else it will continue with decryption
  5534. //
  5535. DWORD
  5536. PeapClientDecryptTunnelData
  5537. (
  5538. IN PPEAPCB pPeapCb,
  5539. IN PPP_EAP_PACKET* pReceivePacket,
  5540. IN WORD wOffset
  5541. )
  5542. {
  5543. DWORD dwRetCode = NO_ERROR;
  5544. EapTlsTrace ("PeapClientDecryptTunnelData");
  5545. if ( !pReceivePacket )
  5546. {
  5547. EapTlsTrace ("Got an empty packet");
  5548. goto LDone;
  5549. }
  5550. if ( IsDuplicatePacket ( pPeapCb,
  5551. pReceivePacket
  5552. )
  5553. )
  5554. {
  5555. //
  5556. // Received a duplicate packet
  5557. //
  5558. // So set the data to what was decrypted in the past...
  5559. //
  5560. if ( pPeapCb->pPrevDecData )
  5561. {
  5562. CopyMemory ( &(pReceivePacket->Data[wOffset]),
  5563. pPeapCb->pPrevDecData,
  5564. pPeapCb->cbPrevDecData
  5565. );
  5566. pPeapCb->pbIoBuffer = pPeapCb->pPrevDecData;
  5567. pPeapCb->dwIoBufferLen = pPeapCb->cbPrevDecData;
  5568. HostToWireFormat16 ( (WORD)(sizeof(PPP_EAP_PACKET) + pPeapCb->cbPrevDecData +1),
  5569. pReceivePacket->Length
  5570. );
  5571. }
  5572. else
  5573. {
  5574. EapTlsTrace("Got an unexpected duplicate packet");
  5575. dwRetCode = SEC_E_MESSAGE_ALTERED;
  5576. }
  5577. }
  5578. else
  5579. {
  5580. if ( pPeapCb->pPrevReceivePacket )
  5581. {
  5582. LocalFree(pPeapCb->pPrevReceivePacket);
  5583. pPeapCb->pPrevReceivePacket = NULL;
  5584. pPeapCb->cbPrevReceivePacket = 0;
  5585. }
  5586. if ( pPeapCb->pPrevDecData )
  5587. {
  5588. LocalFree ( pPeapCb->pPrevDecData );
  5589. pPeapCb->pPrevDecData = NULL;
  5590. pPeapCb->cbPrevDecData = 0;
  5591. }
  5592. pPeapCb->pPrevReceivePacket =
  5593. (PPP_EAP_PACKET*)LocalAlloc(LPTR, WireToHostFormat16(pReceivePacket->Length) );
  5594. if ( pPeapCb->pPrevReceivePacket )
  5595. {
  5596. pPeapCb->cbPrevReceivePacket = WireToHostFormat16(pReceivePacket->Length);
  5597. CopyMemory ( pPeapCb->pPrevReceivePacket,
  5598. pReceivePacket,
  5599. pPeapCb->cbPrevReceivePacket
  5600. );
  5601. }
  5602. //
  5603. // Received a new packet. So we need to decrypt it.
  5604. //
  5605. dwRetCode = PeapDecryptTunnelData ( pPeapCb,
  5606. &(pReceivePacket->Data[2]),
  5607. WireToHostFormat16(pReceivePacket->Length)
  5608. - ( sizeof(PPP_EAP_PACKET) + 1 )
  5609. );
  5610. if ( NO_ERROR != dwRetCode )
  5611. {
  5612. // We could not decrypt the tunnel traffic
  5613. // So we silently discard this packet.
  5614. EapTlsTrace ("Failed to decrypt packet.");
  5615. //
  5616. // Wipe out the prev receive packet
  5617. //
  5618. if ( pPeapCb->pPrevReceivePacket )
  5619. {
  5620. LocalFree(pPeapCb->pPrevReceivePacket);
  5621. pPeapCb->pPrevReceivePacket = NULL;
  5622. pPeapCb->cbPrevReceivePacket = 0;
  5623. }
  5624. goto LDone;
  5625. }
  5626. CopyMemory ( &(pReceivePacket->Data[wOffset]),
  5627. pPeapCb->pbIoBuffer,
  5628. pPeapCb->dwIoBufferLen
  5629. );
  5630. pPeapCb->pPrevDecData = (PBYTE)LocalAlloc ( LPTR, pPeapCb->dwIoBufferLen );
  5631. if ( pPeapCb->pPrevDecData )
  5632. {
  5633. CopyMemory ( pPeapCb->pPrevDecData ,
  5634. pPeapCb->pbIoBuffer,
  5635. pPeapCb->dwIoBufferLen
  5636. );
  5637. pPeapCb->cbPrevDecData = (WORD)pPeapCb->dwIoBufferLen;
  5638. }
  5639. HostToWireFormat16 ( (WORD)(sizeof(PPP_EAP_PACKET) + pPeapCb->dwIoBufferLen +1),
  5640. pReceivePacket->Length
  5641. );
  5642. }
  5643. LDone:
  5644. return dwRetCode;
  5645. }
  5646. DWORD
  5647. PeapEncryptTunnelData
  5648. (
  5649. IN PPEAPCB pPeapCb,
  5650. IN OUT PBYTE pbData,
  5651. IN DWORD dwSizeofData
  5652. )
  5653. {
  5654. SecBufferDesc SecBufferDesc;
  5655. SecBuffer SecBuffer[4];
  5656. SECURITY_STATUS status;
  5657. #ifdef DBG
  5658. BOOL fDataReturnedFromHookDLL = FALSE;
  5659. PBYTE pbNewData = NULL;
  5660. DWORD dwSizeOfNewData = 0;
  5661. #endif
  5662. EapTlsTrace("PeapEncryptTunnelData");
  5663. //
  5664. // Use the schannel context to encrypt data
  5665. //
  5666. SecBufferDesc.ulVersion = SECBUFFER_VERSION;
  5667. SecBufferDesc.cBuffers = 4;
  5668. SecBufferDesc.pBuffers = SecBuffer;
  5669. SecBuffer[0].cbBuffer = pPeapCb->PkgStreamSizes.cbHeader;
  5670. SecBuffer[0].BufferType = SECBUFFER_STREAM_HEADER;
  5671. SecBuffer[0].pvBuffer = pPeapCb->pbIoBuffer;
  5672. #ifdef DBG
  5673. //
  5674. // Just before encryption if we have a hook call into
  5675. // it to get the new packet
  5676. if ( g_fHookInitialized )
  5677. {
  5678. TestHookPacketToPeer ( pPeapCb,
  5679. pbData,
  5680. dwSizeofData,
  5681. &pbNewData ,
  5682. &dwSizeOfNewData
  5683. );
  5684. }
  5685. if (pbNewData && dwSizeOfNewData )
  5686. {
  5687. fDataReturnedFromHookDLL = TRUE;
  5688. }
  5689. else
  5690. {
  5691. //Test Hook Did not return either data or size
  5692. //so use our data.
  5693. pbNewData = pbData;
  5694. dwSizeOfNewData = dwSizeofData;
  5695. }
  5696. CopyMemory ( pPeapCb->pbIoBuffer+pPeapCb->PkgStreamSizes.cbHeader,
  5697. pbNewData,
  5698. dwSizeOfNewData
  5699. );
  5700. SecBuffer[1].cbBuffer = dwSizeOfNewData;
  5701. SecBuffer[1].BufferType = SECBUFFER_DATA;
  5702. SecBuffer[1].pvBuffer = pPeapCb->pbIoBuffer+pPeapCb->PkgStreamSizes.cbHeader;
  5703. SecBuffer[2].cbBuffer = pPeapCb->PkgStreamSizes.cbTrailer;
  5704. SecBuffer[2].BufferType = SECBUFFER_STREAM_TRAILER;
  5705. SecBuffer[2].pvBuffer = pPeapCb->pbIoBuffer + pPeapCb->PkgStreamSizes.cbHeader + dwSizeOfNewData;
  5706. #else
  5707. CopyMemory ( pPeapCb->pbIoBuffer+pPeapCb->PkgStreamSizes.cbHeader,
  5708. pbData,
  5709. dwSizeofData
  5710. );
  5711. SecBuffer[1].cbBuffer = dwSizeofData;
  5712. SecBuffer[1].BufferType = SECBUFFER_DATA;
  5713. SecBuffer[1].pvBuffer = pPeapCb->pbIoBuffer+pPeapCb->PkgStreamSizes.cbHeader;
  5714. SecBuffer[2].cbBuffer = pPeapCb->PkgStreamSizes.cbTrailer;
  5715. SecBuffer[2].BufferType = SECBUFFER_STREAM_TRAILER;
  5716. SecBuffer[2].pvBuffer = pPeapCb->pbIoBuffer + pPeapCb->PkgStreamSizes.cbHeader + dwSizeofData;
  5717. #endif
  5718. SecBuffer[3].BufferType = SECBUFFER_EMPTY;
  5719. status = EncryptMessage ( &(pPeapCb->pEapTlsCB->hContext),
  5720. 0,
  5721. &SecBufferDesc,
  5722. 0
  5723. );
  5724. pPeapCb->dwIoBufferLen = SecBuffer[0].cbBuffer +
  5725. SecBuffer[1].cbBuffer +
  5726. SecBuffer[2].cbBuffer;
  5727. #if DBG
  5728. if ( fDataReturnedFromHookDLL )
  5729. {
  5730. TestHookPacketFree ( pPeapCb, pbNewData );
  5731. }
  5732. #endif
  5733. EapTlsTrace("PeapEncryptTunnelData completed with status 0x%x", status);
  5734. return status;
  5735. }
  5736. DWORD
  5737. PeapGetTunnelProperties
  5738. (
  5739. IN PPEAPCB pPeapCb
  5740. )
  5741. {
  5742. SECURITY_STATUS status;
  5743. EapTlsTrace("PeapGetTunnelProperties");
  5744. status = QueryContextAttributes
  5745. ( &(pPeapCb->pEapTlsCB->hContext),
  5746. SECPKG_ATTR_CONNECTION_INFO,
  5747. &(pPeapCb->PkgConnInfo)
  5748. );
  5749. if (SEC_E_OK != status)
  5750. {
  5751. EapTlsTrace ( "QueryContextAttributes for CONN_INFO failed with error 0x%x", status );
  5752. goto LDone;
  5753. }
  5754. status = QueryContextAttributes
  5755. ( &(pPeapCb->pEapTlsCB->hContext),
  5756. SECPKG_ATTR_STREAM_SIZES,
  5757. &(pPeapCb->PkgStreamSizes)
  5758. );
  5759. if (SEC_E_OK != status)
  5760. {
  5761. EapTlsTrace ( "QueryContextAttributes for STREAM_SIZES failed with error 0x%x", status );
  5762. goto LDone;
  5763. }
  5764. EapTlsTrace ( "Successfully negotiated TLS with following parameters"
  5765. "dwProtocol = 0x%x, Cipher= 0x%x, CipherStrength=0x%x, Hash=0x%x",
  5766. pPeapCb->PkgConnInfo.dwProtocol,
  5767. pPeapCb->PkgConnInfo.aiCipher,
  5768. pPeapCb->PkgConnInfo.dwCipherStrength,
  5769. pPeapCb->PkgConnInfo.aiHash
  5770. );
  5771. pPeapCb->pbIoBuffer = (PBYTE)LocalAlloc ( LPTR,
  5772. pPeapCb->PkgStreamSizes.cbHeader +
  5773. pPeapCb->PkgStreamSizes.cbTrailer +
  5774. pPeapCb->PkgStreamSizes.cbMaximumMessage
  5775. );
  5776. if ( NULL == pPeapCb->pbIoBuffer )
  5777. {
  5778. EapTlsTrace ( "Cannot allocate memory for IoBuffer");
  5779. status = ERROR_OUTOFMEMORY;
  5780. }
  5781. LDone:
  5782. EapTlsTrace("PeapGetTunnelProperties done");
  5783. return status;
  5784. }
  5785. DWORD
  5786. EapPeapCMakeMessage(
  5787. IN PPEAPCB pPeapCb,
  5788. IN PPP_EAP_PACKET* pReceivePacket,
  5789. OUT PPP_EAP_PACKET* pSendPacket,
  5790. IN DWORD cbSendPacket,
  5791. OUT PPP_EAP_OUTPUT* pEapOutput,
  5792. IN PPP_EAP_INPUT* pEapInput
  5793. )
  5794. {
  5795. DWORD dwRetCode = NO_ERROR;
  5796. PPP_EAP_INPUT EapTypeInput;
  5797. WORD wPacketLength;
  5798. PEAP_ENTRY_CONN_PROPERTIES UNALIGNED * pEntryConnProp = NULL;
  5799. PEAP_ENTRY_USER_PROPERTIES UNALIGNED * pEntryUserProp = NULL;
  5800. PBYTE pbCookie = NULL;
  5801. DWORD cbCookie = 0;
  5802. BOOL fIsReconnect = FALSE;
  5803. BOOL fReceivedTLV = FALSE;
  5804. DWORD dwVersion = 0;
  5805. WORD wValue = 0;
  5806. BOOL fImpersonating = FALSE;
  5807. EapTlsTrace("EapPeapCMakeMessage");
  5808. if ( !(pPeapCb->dwFlags & PEAPCB_FLAG_SERVER ) &&
  5809. !(pPeapCb->dwFlags & PEAPCB_FLAG_ROUTER) &&
  5810. !(pPeapCb->dwFlags & PEAPCB_FLAG_MACHINE_AUTH ) &&
  5811. !(pPeapCb->dwFlags & PEAPCB_FLAG_LOGON )
  5812. )
  5813. {
  5814. if(!ImpersonateLoggedOnUser(pPeapCb->hTokenImpersonateUser) )
  5815. {
  5816. dwRetCode = GetLastError();
  5817. EapTlsTrace ("PEAP: ImpersonateLoggedonUser failed and returned 0x%x", dwRetCode);
  5818. return dwRetCode;
  5819. }
  5820. fImpersonating = TRUE;
  5821. }
  5822. switch ( pPeapCb->PeapState )
  5823. {
  5824. case PEAP_STATE_INITIAL:
  5825. EapTlsTrace("PEAP:PEAP_STATE_INITIAL");
  5826. //
  5827. // Start the EapTls Conversation here.
  5828. //
  5829. //Receive Packet will be NULL. Call EapTlsSMakeMessage
  5830. //
  5831. if ( pReceivePacket )
  5832. {
  5833. pReceivePacket->Data[0] = PPP_EAP_TLS;
  5834. }
  5835. dwRetCode = EapTlsCMakeMessage( pPeapCb->pEapTlsCB,
  5836. (EAPTLS_PACKET *)pReceivePacket,
  5837. (EAPTLS_PACKET *)pSendPacket,
  5838. cbSendPacket,
  5839. pEapOutput,
  5840. pEapInput
  5841. );
  5842. if ( NO_ERROR == dwRetCode )
  5843. {
  5844. //change the packet to show peap
  5845. pSendPacket->Data[0] = PPP_EAP_PEAP;
  5846. if ( pReceivePacket )
  5847. dwVersion = ((EAPTLS_PACKET *)pReceivePacket)->bFlags & 0x03;
  5848. if ( dwVersion != EAPTLS_PACKET_CURRENT_VERSION )
  5849. {
  5850. ((EAPTLS_PACKET *)pSendPacket)->bFlags |= EAPTLS_PACKET_LOWEST_SUPPORTED_VERSION;
  5851. }
  5852. else
  5853. {
  5854. ((EAPTLS_PACKET *)pSendPacket)->bFlags |= EAPTLS_PACKET_CURRENT_VERSION;
  5855. }
  5856. }
  5857. pPeapCb->PeapState = PEAP_STATE_TLS_INPROGRESS;
  5858. break;
  5859. case PEAP_STATE_TLS_INPROGRESS:
  5860. EapTlsTrace("PEAP:PEAP_STATE_TLS_INPROGRESS");
  5861. if ( pReceivePacket &&
  5862. ( pReceivePacket->Code == EAPCODE_Request ||
  5863. pReceivePacket->Code == EAPCODE_Response
  5864. )
  5865. )
  5866. {
  5867. pReceivePacket->Data[0] = PPP_EAP_TLS;
  5868. }
  5869. //
  5870. // We could either get a TLV_Success Request or
  5871. // and identity request as a termination packet.
  5872. // Both of these are encrypted using the keys.
  5873. // PAss them on to TLS and when it sends a success
  5874. // back, decrypt to see if it was a success or
  5875. // identity.
  5876. //
  5877. dwRetCode = EapTlsCMakeMessage( pPeapCb->pEapTlsCB,
  5878. (EAPTLS_PACKET *)pReceivePacket,
  5879. (EAPTLS_PACKET *)pSendPacket,
  5880. cbSendPacket,
  5881. pEapOutput,
  5882. pEapInput
  5883. );
  5884. if ( NO_ERROR == dwRetCode )
  5885. {
  5886. //
  5887. // if interactive UI was requested, wrap the data in
  5888. // in PEAP interactive UI structure
  5889. //
  5890. if ( pEapOutput->fInvokeInteractiveUI )
  5891. {
  5892. if ( pPeapCb->pUIContextData )
  5893. {
  5894. LocalFree ( pPeapCb->pUIContextData );
  5895. pPeapCb->pUIContextData = NULL;
  5896. }
  5897. pPeapCb->pUIContextData = (PPEAP_INTERACTIVE_UI)
  5898. LocalAlloc(LPTR,
  5899. sizeof(PEAP_INTERACTIVE_UI) + pEapOutput->dwSizeOfUIContextData );
  5900. if ( NULL == pPeapCb->pUIContextData )
  5901. {
  5902. EapTlsTrace("Error allocating memory for PEAP context data");
  5903. dwRetCode = ERROR_OUTOFMEMORY;
  5904. goto LDone;
  5905. }
  5906. pPeapCb->pUIContextData->dwEapTypeId = PPP_EAP_TLS;
  5907. pPeapCb->pUIContextData->dwSizeofUIContextData
  5908. = pEapOutput->dwSizeOfUIContextData;
  5909. CopyMemory( pPeapCb->pUIContextData->bUIContextData,
  5910. pEapOutput->pUIContextData,
  5911. pEapOutput->dwSizeOfUIContextData
  5912. );
  5913. pEapOutput->pUIContextData = (PBYTE)pPeapCb->pUIContextData;
  5914. pEapOutput->dwSizeOfUIContextData =
  5915. sizeof(PEAP_INTERACTIVE_UI) + pEapOutput->dwSizeOfUIContextData;
  5916. }
  5917. else if ( pEapOutput->Action == EAPACTION_Done )
  5918. {
  5919. if ( pEapOutput->dwAuthResultCode == NO_ERROR )
  5920. {
  5921. //
  5922. // PEAP auth was successful. Carefully keep the MPPE
  5923. // session keys returned so that we can encrypt the
  5924. // channel. From now on everything will be encrypted.
  5925. //
  5926. // if we're enabled for fast reconnect check to see if this
  5927. // was a reconnect and see if the cookie is valid.
  5928. //
  5929. //
  5930. // Check to see if we were send back a success or if we were send back an
  5931. // identity request.
  5932. //
  5933. if ( !( pPeapCb->pEapTlsCB->fFlags & EAPTLSCB_FLAG_USING_CACHED_CREDS )
  5934. )
  5935. {
  5936. //
  5937. // If we are not using cached credentials
  5938. //
  5939. SetCachedCredentials (pPeapCb->pEapTlsCB);
  5940. }
  5941. pPeapCb->pTlsUserAttributes = pEapOutput->pUserAttributes;
  5942. dwRetCode = PeapGetTunnelProperties ( pPeapCb );
  5943. if (NO_ERROR != dwRetCode )
  5944. {
  5945. break;
  5946. }
  5947. pEapOutput->pUserAttributes = NULL;
  5948. pEapOutput->Action = EAPACTION_NoAction;
  5949. //
  5950. // Check to see if we need to save connection and user data
  5951. // for TLS
  5952. if ( pEapOutput->fSaveConnectionData )
  5953. {
  5954. //
  5955. // save connection data in PEAP control
  5956. // block and then finally when auth is done
  5957. // We send back a save command.
  5958. //
  5959. if ( ConnPropGetV1Struct ( (EAPTLS_CONN_PROPERTIES *) pEapOutput->pConnectionData,
  5960. &(pPeapCb->pNewTlsConnProp) ) == NO_ERROR )
  5961. {
  5962. pPeapCb->fTlsConnPropDirty = TRUE;
  5963. }
  5964. pEapOutput->fSaveConnectionData = FALSE;
  5965. }
  5966. if ( pEapOutput->fSaveUserData )
  5967. {
  5968. //
  5969. // There is nothing to save in user data for PEAP.
  5970. // But the flag is left here just in case...
  5971. pPeapCb->fTlsUserPropDirty = TRUE;
  5972. pEapOutput->fSaveUserData = FALSE;
  5973. }
  5974. case PEAP_STATE_FAST_ROAMING_IDENTITY_REQUEST:
  5975. //
  5976. // EAPTLS terminated with an identity request
  5977. // so process the received identity request here
  5978. if ( pReceivePacket )
  5979. {
  5980. //
  5981. // This can be either an identity packet or
  5982. // an TLV_Success packet.
  5983. //
  5984. dwRetCode = PeapClientDecryptTunnelData(pPeapCb,pReceivePacket, 2);
  5985. if ( NO_ERROR != dwRetCode )
  5986. {
  5987. EapTlsTrace("PeapDecryptTunnelData failed: silently discarding packet");
  5988. dwRetCode = NO_ERROR;
  5989. pEapOutput->Action = EAPACTION_NoAction;
  5990. break;
  5991. }
  5992. /*
  5993. wPacketLength = WireToHostFormat16(pReceivePacket->Length);
  5994. dwRetCode = PeapDecryptTunnelData ( pPeapCb,
  5995. &(pReceivePacket->Data[2]),
  5996. wPacketLength
  5997. - ( sizeof(PPP_EAP_PACKET) + 1 )
  5998. );
  5999. if ( NO_ERROR != dwRetCode )
  6000. {
  6001. // We could not decrypt the tunnel traffic
  6002. // So we silently discard this packet.
  6003. EapTlsTrace("PeapDecryptTunnelData failed: silently discarding packet");
  6004. dwRetCode = NO_ERROR;
  6005. pEapOutput->Action = EAPACTION_NoAction;
  6006. break;
  6007. }
  6008. CopyMemory ( &(pReceivePacket->Data[2]),
  6009. pPeapCb->pbIoBuffer,
  6010. pPeapCb->dwIoBufferLen
  6011. );
  6012. HostToWireFormat16 ( (WORD)(sizeof(PPP_EAP_PACKET) + pPeapCb->dwIoBufferLen +1),
  6013. pReceivePacket->Length
  6014. );
  6015. */
  6016. pReceivePacket->Data[0] = PPP_EAP_PEAP;
  6017. //This is an AVP message
  6018. if ( pReceivePacket->Data[8] == MS_PEAP_AVP_TYPE_STATUS &&
  6019. pReceivePacket->Data[6] == PEAP_TYPE_AVP
  6020. )
  6021. {
  6022. //This is a TLV message
  6023. dwRetCode = GetPEAPTLVStatusMessageValue ( pPeapCb,
  6024. pReceivePacket,
  6025. &wValue
  6026. );
  6027. if ( NO_ERROR != dwRetCode || wValue != MS_PEAP_AVP_VALUE_SUCCESS )
  6028. {
  6029. EapTlsTrace("Got invalid TLV when expecting TLV_SUCCESS. Silently discarding.");
  6030. dwRetCode = NO_ERROR;
  6031. pEapOutput->Action = EAPACTION_NoAction;
  6032. break;
  6033. }
  6034. //
  6035. // Check to see if this is a success. If this is a success, server wants to
  6036. // do fast roaming. Check to see if this is a fast reconnect and
  6037. // if this is a fast reconnect, get cookie and compare it
  6038. // if all's fine then send a success response or else send a failure
  6039. // response. If none of this works then fail auth with an internal
  6040. // error.
  6041. //
  6042. if ( pPeapCb->dwFlags & PEAPCB_FAST_ROAMING )
  6043. {
  6044. dwRetCode = GetTLSSessionCookie ( pPeapCb->pEapTlsCB,
  6045. &pbCookie,
  6046. &cbCookie,
  6047. &fIsReconnect
  6048. );
  6049. if ( NO_ERROR != dwRetCode)
  6050. {
  6051. //There was an error getting session cookie.
  6052. //Or there is no cookie and this is a reconnet
  6053. // So fail the request.
  6054. EapTlsTrace("Error getting cookie for a reconnected session. Failing auth");
  6055. // We cannot encrypt and send stuff across here.
  6056. // Reconnected Session state is invalid.
  6057. pEapOutput->dwAuthResultCode = dwRetCode;
  6058. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  6059. pEapOutput->Action = EAPACTION_Done;
  6060. break;
  6061. }
  6062. if ( fIsReconnect )
  6063. {
  6064. if ( cbCookie == 0 )
  6065. {
  6066. //There was an error getting session cookie.
  6067. //Or there is no cookie and this is a reconnet
  6068. // So fail the request.
  6069. EapTlsTrace("Error getting cookie for a reconnected session. Failing auth");
  6070. dwRetCode = SetTLSFastReconnect ( pPeapCb->pEapTlsCB , FALSE);
  6071. // We cannot encrypt and send stuff across here.
  6072. // Reconnected Session state is invalid.
  6073. dwRetCode = ERROR_INTERNAL_ERROR;
  6074. pEapOutput->dwAuthResultCode = dwRetCode;
  6075. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  6076. pEapOutput->Action = EAPACTION_Done;
  6077. break;
  6078. }
  6079. //
  6080. // This is a server
  6081. // Check to see if the cookie is fine.
  6082. // If it is fine then there is no need to reauth.
  6083. // So send back a PEAP_SUCCESS response packet
  6084. // and change our state to PEAP_SUCCESS_SEND
  6085. //
  6086. EapTlsTrace ("TLS session fast reconnected");
  6087. dwRetCode = PeapCheckCookie ( pPeapCb, (PPEAP_COOKIE)pbCookie, cbCookie );
  6088. if ( NO_ERROR != dwRetCode )
  6089. {
  6090. //
  6091. // So invalidate the session for fast reconnect
  6092. // and fail auth. Next time a full reconnect will happen
  6093. //
  6094. dwRetCode = SetTLSFastReconnect ( pPeapCb->pEapTlsCB , FALSE);
  6095. if ( NO_ERROR != dwRetCode )
  6096. {
  6097. //
  6098. // This is an internal error
  6099. // So disconnect the session.
  6100. //
  6101. pEapOutput->dwAuthResultCode = dwRetCode;
  6102. pEapOutput->Action = EAPACTION_Done;
  6103. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  6104. break;
  6105. }
  6106. EapTlsTrace ("Error validating the cookie. Failing auth");
  6107. pEapOutput->dwAuthResultCode = dwRetCode;
  6108. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  6109. pEapOutput->Action = EAPACTION_Done;
  6110. break;
  6111. }
  6112. else
  6113. {
  6114. //
  6115. // Cookie is fine.
  6116. //
  6117. //
  6118. // Send a PEAP success TLV response.
  6119. //
  6120. dwRetCode = CreatePEAPTLVStatusMessage ( pPeapCb,
  6121. pSendPacket,
  6122. cbSendPacket,
  6123. FALSE, //Response
  6124. MS_PEAP_AVP_VALUE_SUCCESS
  6125. );
  6126. if ( NO_ERROR != dwRetCode )
  6127. {
  6128. // Internal error
  6129. break;
  6130. }
  6131. pEapOutput->Action = EAPACTION_Send;
  6132. pPeapCb->PeapState = PEAP_STATE_PEAP_SUCCESS_SEND;
  6133. pPeapCb->dwAuthResultCode = NO_ERROR;
  6134. break;
  6135. }
  6136. }
  6137. else
  6138. {
  6139. // server is expecting fast roaming and we are not configured to do it.
  6140. // send a fail tlv here
  6141. EapTlsTrace("Server expects fast roaming and we dont. Sending PEAP_Failure");
  6142. dwRetCode = CreatePEAPTLVStatusMessage ( pPeapCb,
  6143. pSendPacket,
  6144. cbSendPacket,
  6145. FALSE, //Response
  6146. MS_PEAP_AVP_VALUE_FAILURE
  6147. );
  6148. if ( NO_ERROR != dwRetCode )
  6149. {
  6150. // Internal error
  6151. break;
  6152. }
  6153. pEapOutput->Action = EAPACTION_Send;
  6154. pPeapCb->PeapState = PEAP_STATE_FAST_ROAMING_IDENTITY_REQUEST;
  6155. pPeapCb->dwAuthResultCode = NO_ERROR;
  6156. break;
  6157. }
  6158. }
  6159. else
  6160. {
  6161. // Server is requesting fast roaming but we're not setup to do so.
  6162. // So send back a fail request so that the auth fails.
  6163. dwRetCode = CreatePEAPTLVStatusMessage ( pPeapCb,
  6164. pSendPacket,
  6165. cbSendPacket,
  6166. FALSE, //Response
  6167. MS_PEAP_AVP_VALUE_FAILURE
  6168. );
  6169. if ( NO_ERROR != dwRetCode )
  6170. {
  6171. // Internal error
  6172. break;
  6173. }
  6174. //
  6175. // We can expect to get back an encrypted identity request
  6176. // Since the client is not setup to do fast roaming and the
  6177. // server is, we fail the success and expect identity
  6178. // request.
  6179. //
  6180. pEapOutput->Action = EAPACTION_Send;
  6181. pPeapCb->PeapState = PEAP_STATE_FAST_ROAMING_IDENTITY_REQUEST;
  6182. pPeapCb->dwAuthResultCode = NO_ERROR;
  6183. break;
  6184. }
  6185. break;
  6186. }
  6187. else
  6188. {
  6189. if ( pReceivePacket->Data[2] != PEAP_EAPTYPE_IDENTITY )
  6190. {
  6191. EapTlsTrace ("Got unexpected packet when expecting PEAP identity request. Silently discarding packet.");
  6192. dwRetCode = NO_ERROR;
  6193. pEapOutput->Action = EAPACTION_NoAction;
  6194. break;
  6195. }
  6196. }
  6197. //If we've come this far, it must be an identity request.
  6198. pSendPacket->Code = EAPCODE_Response;
  6199. pSendPacket->Id = pReceivePacket->Id;
  6200. CopyMemory ( pPeapCb->awszTypeIdentity,
  6201. pPeapCb->awszIdentity,
  6202. ( DNLEN+ UNLEN) * sizeof(WCHAR)
  6203. );
  6204. //
  6205. //length = sizeof header + 1 byte for code identity + strlen of identity
  6206. //
  6207. pSendPacket->Data[0] = PPP_EAP_PEAP;
  6208. pSendPacket->Data[1] = EAPTLS_PACKET_CURRENT_VERSION;
  6209. pSendPacket->Data[2] = PEAP_EAPTYPE_IDENTITY;
  6210. //copy the identity over
  6211. if ( 0 == WideCharToMultiByte(
  6212. CP_ACP,
  6213. 0,
  6214. pPeapCb->awszIdentity,
  6215. -1,
  6216. (LPSTR)&(pSendPacket->Data[3]),
  6217. UNLEN + DNLEN+ 1,
  6218. NULL,
  6219. NULL )
  6220. )
  6221. {
  6222. //
  6223. // This is an internal error. There is no concept of PEAP_SUCCESS/FAIL TLV here.
  6224. //
  6225. dwRetCode = GetLastError();
  6226. EapTlsTrace("Unable to convert from widechar to multibyte 0x%x", dwRetCode );
  6227. goto LDone;
  6228. }
  6229. dwRetCode = PeapEncryptTunnelData ( pPeapCb,
  6230. &(pSendPacket->Data[2]),
  6231. 1+wcslen(pPeapCb->awszIdentity)
  6232. );
  6233. if ( NO_ERROR != dwRetCode )
  6234. {
  6235. break;
  6236. }
  6237. //Copy over the encrypted data into send buffer
  6238. CopyMemory ( &(pSendPacket->Data[2]),
  6239. pPeapCb->pbIoBuffer,
  6240. pPeapCb->dwIoBufferLen
  6241. );
  6242. HostToWireFormat16
  6243. (
  6244. (WORD)(sizeof(PPP_EAP_PACKET)+ 1 +pPeapCb->dwIoBufferLen),
  6245. pSendPacket->Length
  6246. );
  6247. pEapOutput->Action = EAPACTION_Send;
  6248. pPeapCb->PeapState = PEAP_STATE_IDENTITY_RESPONSE_SENT;
  6249. }
  6250. else
  6251. {
  6252. pEapOutput->Action = EAPACTION_NoAction;
  6253. EapTlsTrace("Got empty packet when expecting identity request. Ignoring.");
  6254. }
  6255. }
  6256. }
  6257. else
  6258. {
  6259. //change the packet to show peap
  6260. pSendPacket->Data[0] = PPP_EAP_PEAP;
  6261. }
  6262. }
  6263. break;
  6264. case PEAP_STATE_IDENTITY_RESPONSE_SENT:
  6265. EapTlsTrace("PEAP:PEAP_STATE_IDENTITY_RESPONSE_SENT");
  6266. //
  6267. // Call begin for eap dll
  6268. //
  6269. // Check to see if we are configured to do this eap type.
  6270. // if not send a NAK back with desired EAP type.
  6271. //
  6272. if ( !pPeapCb->fInvokedInteractiveUI )
  6273. {
  6274. if ( pReceivePacket && pReceivePacket->Code != EAPCODE_Failure )
  6275. {
  6276. dwRetCode = PeapClientDecryptTunnelData ( pPeapCb, pReceivePacket, 0);
  6277. if ( NO_ERROR != dwRetCode )
  6278. {
  6279. EapTlsTrace("PeapDecryptTunnelData failed: silently discarding packet");
  6280. dwRetCode = NO_ERROR;
  6281. pEapOutput->Action = EAPACTION_NoAction;
  6282. break;
  6283. }
  6284. /*
  6285. wPacketLength = WireToHostFormat16( pReceivePacket->Length );
  6286. dwRetCode = PeapDecryptTunnelData ( pPeapCb,
  6287. &(pReceivePacket->Data[2]),
  6288. wPacketLength
  6289. - ( sizeof(PPP_EAP_PACKET) + 1 )
  6290. );
  6291. if ( NO_ERROR != dwRetCode )
  6292. {
  6293. // We could not decrypt the tunnel traffic
  6294. // So we silently discard this packet.
  6295. EapTlsTrace("PeapDecryptTunnelData failed: silently discarding packet");
  6296. dwRetCode = NO_ERROR;
  6297. pEapOutput->Action = EAPACTION_NoAction;
  6298. break;
  6299. }
  6300. CopyMemory ( pReceivePacket->Data,
  6301. pPeapCb->pbIoBuffer,
  6302. pPeapCb->dwIoBufferLen
  6303. );
  6304. HostToWireFormat16 ( (WORD)(sizeof(PPP_EAP_PACKET) + pPeapCb->dwIoBufferLen -1),
  6305. pReceivePacket->Length
  6306. );
  6307. */
  6308. }
  6309. else if ( pReceivePacket && pReceivePacket->Code == EAPCODE_Failure )
  6310. {
  6311. //
  6312. // Fail auth because we have not yet got the Success/Fail TLV
  6313. // The server may not be configured to handle this EAP Type.
  6314. //
  6315. EapTlsTrace ( "Got a failure when negotiating EAP types in PEAP.");
  6316. pEapOutput->Action = EAPACTION_Done;
  6317. pEapOutput->dwAuthResultCode = ERROR_AUTHENTICATION_FAILURE;
  6318. break;
  6319. }
  6320. }
  6321. if ( pReceivePacket &&
  6322. pReceivePacket->Code != EAPCODE_Request
  6323. )
  6324. {
  6325. EapTlsTrace("Invalid packet received. Ignoring");
  6326. pEapOutput->Action = EAPACTION_NoAction;
  6327. }
  6328. else
  6329. {
  6330. //
  6331. // Check to see if this is a TLV packet other than success/fail.
  6332. // If so, send back a NAK.
  6333. //
  6334. if ( pReceivePacket &&
  6335. !pPeapCb->fInvokedInteractiveUI &&
  6336. pPeapCb->pEapInfo->dwTypeId != pReceivePacket->Data[0] )
  6337. {
  6338. //Send a NAK back with the desired typeid
  6339. pSendPacket->Code = EAPCODE_Response;
  6340. pSendPacket->Id = pReceivePacket->Id;
  6341. pSendPacket->Data[0] = PPP_EAP_PEAP;
  6342. pSendPacket->Data[1] = EAPTLS_PACKET_CURRENT_VERSION;
  6343. pSendPacket->Data[2] = PEAP_EAPTYPE_NAK;
  6344. pSendPacket->Data[3] = (BYTE)pPeapCb->pEapInfo->dwTypeId;
  6345. //Encrypt 2 bytes of our NAK
  6346. dwRetCode = PeapEncryptTunnelData ( pPeapCb,
  6347. &(pSendPacket->Data[2]),
  6348. 2
  6349. );
  6350. if ( NO_ERROR != dwRetCode )
  6351. {
  6352. //
  6353. // This is an internal error. Cant do much here but to drop the
  6354. // connection.
  6355. //
  6356. break;
  6357. }
  6358. //
  6359. // Copy over the buffer and readjust the lengths
  6360. //
  6361. CopyMemory ( &(pSendPacket->Data[2]),
  6362. pPeapCb->pbIoBuffer,
  6363. pPeapCb->dwIoBufferLen );
  6364. HostToWireFormat16
  6365. (
  6366. (WORD)(sizeof(PPP_EAP_PACKET) + 1 +pPeapCb->dwIoBufferLen),
  6367. pSendPacket->Length
  6368. );
  6369. pEapOutput->Action = EAPACTION_Send;
  6370. }
  6371. else
  6372. {
  6373. //call begin and then make message
  6374. ZeroMemory ( &EapTypeInput, sizeof(EapTypeInput) );
  6375. CopyMemory( &EapTypeInput, pEapInput, sizeof(EapTypeInput) );
  6376. EapTypeInput.pwszIdentity = pPeapCb->awszTypeIdentity;
  6377. if ( !pPeapCb->fInvokedInteractiveUI )
  6378. {
  6379. //
  6380. // Set the user and connection data from peap cb
  6381. //
  6382. dwRetCode = PeapGetFirstEntryConnProp ( pPeapCb->pConnProp,
  6383. &pEntryConnProp
  6384. );
  6385. if ( NO_ERROR != dwRetCode )
  6386. {
  6387. EapTlsTrace("Error getting entry connection properties. 0x%x", dwRetCode);
  6388. goto LDone;
  6389. }
  6390. dwRetCode = PeapGetFirstEntryUserProp ( pPeapCb->pUserProp,
  6391. &pEntryUserProp
  6392. );
  6393. if ( NO_ERROR != dwRetCode )
  6394. {
  6395. EapTlsTrace("Error getting entry user properties. 0x%x", dwRetCode);
  6396. goto LDone;
  6397. }
  6398. EapTypeInput.pConnectionData = pEntryConnProp->bData;
  6399. EapTypeInput.hTokenImpersonateUser = pPeapCb->hTokenImpersonateUser;
  6400. EapTypeInput.dwSizeOfConnectionData =
  6401. pEntryConnProp->dwSize - sizeof(PEAP_ENTRY_CONN_PROPERTIES) + 1;
  6402. pPeapCb->dwFlags & PEAPCB_FLAG_ROUTER?
  6403. EapTypeInput.fFlags |= RAS_EAP_FLAG_ROUTER :0;
  6404. pPeapCb->dwFlags & PEAPCB_FLAG_NON_INTERACTIVE?
  6405. EapTypeInput.fFlags |= RAS_EAP_FLAG_NON_INTERACTIVE:0;
  6406. pPeapCb->dwFlags & PEAPCB_FLAG_LOGON?
  6407. EapTypeInput.fFlags |= RAS_EAP_FLAG_LOGON :0;
  6408. pPeapCb->dwFlags & PEAPCB_FLAG_PREVIEW ?
  6409. EapTypeInput.fFlags |= RAS_EAP_FLAG_PREVIEW:0;
  6410. pPeapCb->dwFlags & PEAPCB_FLAG_FIRST_LINK?
  6411. EapTypeInput.fFlags |= RAS_EAP_FLAG_FIRST_LINK :0;
  6412. pPeapCb->dwFlags & PEAPCB_FLAG_MACHINE_AUTH ?
  6413. EapTypeInput.fFlags |= RAS_EAP_FLAG_MACHINE_AUTH:0;
  6414. pPeapCb->dwFlags & PEAPCB_FLAG_GUEST_ACCESS?
  6415. EapTypeInput.fFlags |= RAS_EAP_FLAG_GUEST_ACCESS :0;
  6416. pPeapCb->dwFlags & PEAPCB_FLAG_8021X_AUTH ?
  6417. EapTypeInput.fFlags |= RAS_EAP_FLAG_8021X_AUTH:0;
  6418. EapTypeInput.fFlags |= RAS_EAP_FLAG_HOSTED_IN_PEAP;
  6419. if ( pEntryUserProp->fUsingPeapDefault )
  6420. {
  6421. PPEAP_DEFAULT_CREDENTIALS pDefaultCred =
  6422. (PPEAP_DEFAULT_CREDENTIALS)pEntryUserProp->bData;
  6423. //
  6424. // there is no user data to send in this case.
  6425. // just set the identity and password.
  6426. //
  6427. EapTypeInput.pwszPassword = pDefaultCred->wszPassword;
  6428. }
  6429. else
  6430. {
  6431. if ( pEntryUserProp->dwEapTypeId &&
  6432. pEntryUserProp->dwSize
  6433. )
  6434. {
  6435. EapTypeInput.pUserData = pEntryUserProp->bData;
  6436. EapTypeInput.dwSizeOfUserData =
  6437. pEntryUserProp->dwSize - sizeof(PEAP_ENTRY_USER_PROPERTIES) + 1;
  6438. }
  6439. else
  6440. {
  6441. EapTypeInput.pUserData = NULL;
  6442. EapTypeInput.dwSizeOfUserData = 0;
  6443. }
  6444. }
  6445. if ( pPeapCb->awszPassword[0] )
  6446. {
  6447. EapTypeInput.pwszPassword = pPeapCb->awszPassword;
  6448. }
  6449. if ( pReceivePacket )
  6450. EapTypeInput.bInitialId = pReceivePacket->Id;
  6451. else
  6452. EapTypeInput.bInitialId = 0;
  6453. //Call begin function
  6454. dwRetCode = pPeapCb->pEapInfo->PppEapInfo.RasEapBegin( &(pPeapCb->pEapInfo->pWorkBuf ),
  6455. &EapTypeInput
  6456. );
  6457. }
  6458. if ( NO_ERROR == dwRetCode )
  6459. {
  6460. if ( pPeapCb->fInvokedInteractiveUI )
  6461. {
  6462. pPeapCb->fInvokedInteractiveUI = FALSE;
  6463. }
  6464. //Call make message now
  6465. dwRetCode = pPeapCb->pEapInfo->PppEapInfo.RasEapMakeMessage
  6466. ( pPeapCb->pEapInfo->pWorkBuf,
  6467. pReceivePacket,
  6468. pSendPacket,
  6469. cbSendPacket-200,
  6470. pEapOutput,
  6471. &EapTypeInput
  6472. );
  6473. if ( NO_ERROR == dwRetCode )
  6474. {
  6475. if ( pEapOutput->fInvokeInteractiveUI )
  6476. {
  6477. if ( pPeapCb->pUIContextData )
  6478. {
  6479. LocalFree ( pPeapCb->pUIContextData );
  6480. pPeapCb->pUIContextData = NULL;
  6481. }
  6482. pPeapCb->pUIContextData = (PPEAP_INTERACTIVE_UI)
  6483. LocalAlloc(LPTR,
  6484. sizeof(PEAP_INTERACTIVE_UI) + pEapOutput->dwSizeOfUIContextData );
  6485. if ( NULL == pPeapCb->pUIContextData )
  6486. {
  6487. EapTlsTrace("Error allocating memory for PEAP context data");
  6488. dwRetCode = ERROR_OUTOFMEMORY;
  6489. goto LDone;
  6490. }
  6491. pPeapCb->pUIContextData->dwEapTypeId = pPeapCb->pEapInfo->dwTypeId;
  6492. pPeapCb->pUIContextData->dwSizeofUIContextData
  6493. = pEapOutput->dwSizeOfUIContextData;
  6494. CopyMemory( pPeapCb->pUIContextData->bUIContextData,
  6495. pEapOutput->pUIContextData,
  6496. pEapOutput->dwSizeOfUIContextData
  6497. );
  6498. pEapOutput->pUIContextData = (PBYTE)pPeapCb->pUIContextData;
  6499. pEapOutput->dwSizeOfUIContextData =
  6500. sizeof(PEAP_INTERACTIVE_UI) + pEapOutput->dwSizeOfUIContextData;
  6501. pPeapCb->fInvokedInteractiveUI = TRUE;
  6502. }
  6503. else
  6504. {
  6505. wPacketLength = WireToHostFormat16(pSendPacket->Length);
  6506. dwRetCode = PeapEncryptTunnelData ( pPeapCb,
  6507. &(pSendPacket->Data[0]),
  6508. wPacketLength -sizeof(PPP_EAP_PACKET)+1
  6509. );
  6510. if ( NO_ERROR != dwRetCode )
  6511. {
  6512. //
  6513. // This is an internal error.
  6514. // Cant do much here but to terminate connection
  6515. //
  6516. break;
  6517. }
  6518. pSendPacket->Data[0] = PPP_EAP_PEAP;
  6519. pSendPacket->Data[1] = EAPTLS_PACKET_CURRENT_VERSION;
  6520. CopyMemory ( &(pSendPacket->Data[2]),
  6521. pPeapCb->pbIoBuffer,
  6522. pPeapCb->dwIoBufferLen
  6523. );
  6524. HostToWireFormat16
  6525. ( (WORD)(sizeof(PPP_EAP_PACKET)+1+pPeapCb->dwIoBufferLen),
  6526. pSendPacket->Length
  6527. );
  6528. //Set the Id of the packet send. This should have been set
  6529. //by the eap type.
  6530. pPeapCb->bId = pSendPacket->Id;
  6531. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_INPROGRESS;
  6532. }
  6533. }
  6534. else
  6535. {
  6536. EapTlsTrace ( "EapType %d failed in RasEapMakeMEssage and returned 0x%x",
  6537. pPeapCb->pEapInfo->dwTypeId,
  6538. dwRetCode
  6539. );
  6540. }
  6541. }
  6542. else
  6543. {
  6544. EapTlsTrace ( "EapType %d failed in RasEapBegin and returned 0x%x",
  6545. pPeapCb->pEapInfo->dwTypeId,
  6546. dwRetCode
  6547. );
  6548. //
  6549. // Send a PEAP failure here and wait for response from server.
  6550. //
  6551. pEapOutput->dwAuthResultCode = dwRetCode;
  6552. pEapOutput->Action = EAPACTION_Done;
  6553. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  6554. }
  6555. }
  6556. }
  6557. break;
  6558. case PEAP_STATE_EAP_TYPE_INPROGRESS:
  6559. EapTlsTrace("PEAP:PEAP_STATE_EAP_TYPE_INPROGRESS");
  6560. if ( pPeapCb->fInvokedInteractiveUI && !pEapInput->fDataReceivedFromInteractiveUI)
  6561. {
  6562. EapTlsTrace("Waiting on interactive UI. Discarding packets sliently...");
  6563. pEapOutput->Action = EAPACTION_NoAction;
  6564. break;
  6565. }
  6566. ZeroMemory ( &EapTypeInput, sizeof(EapTypeInput) );
  6567. CopyMemory( &EapTypeInput, pEapInput, sizeof(EapTypeInput) );
  6568. EapTypeInput.pwszIdentity = pPeapCb->awszTypeIdentity;
  6569. EapTypeInput.hTokenImpersonateUser = pPeapCb->hTokenImpersonateUser;
  6570. // if we are executing interactive ui ,pReceivePacket will be NULL
  6571. //
  6572. if ( pReceivePacket && !pPeapCb->fInvokedInteractiveUI )
  6573. {
  6574. //Decrypt the packet
  6575. if ( pReceivePacket->Code != EAPCODE_Success &&
  6576. pReceivePacket->Code != EAPCODE_Failure)
  6577. {
  6578. dwRetCode = PeapClientDecryptTunnelData ( pPeapCb, pReceivePacket, 2);
  6579. if ( NO_ERROR != dwRetCode )
  6580. {
  6581. EapTlsTrace("PeapDecryptTunnelData failed: silently discarding packet");
  6582. dwRetCode = NO_ERROR;
  6583. pEapOutput->Action = EAPACTION_NoAction;
  6584. break;
  6585. }
  6586. /*
  6587. wPacketLength = WireToHostFormat16( pReceivePacket->Length );
  6588. dwRetCode = PeapDecryptTunnelData ( pPeapCb,
  6589. &(pReceivePacket->Data[2]),
  6590. wPacketLength - ( sizeof(PPP_EAP_PACKET) + 1 )
  6591. );
  6592. if ( NO_ERROR != dwRetCode )
  6593. {
  6594. // We could not decrypt the tunnel traffic
  6595. // So we silently discard this packet.
  6596. EapTlsTrace("PeapDecryptTunnelData failed: silently discarding packet");
  6597. dwRetCode = NO_ERROR;
  6598. pEapOutput->Action = EAPACTION_NoAction;
  6599. break;
  6600. }
  6601. */
  6602. if ( pPeapCb->pbIoBuffer[6] == MS_PEAP_AVP_TYPE_STATUS &&
  6603. pPeapCb->pbIoBuffer[4] == PEAP_TYPE_AVP
  6604. )
  6605. {
  6606. wValue = 0;
  6607. CopyMemory ( &(pReceivePacket->Data[2]),
  6608. pPeapCb->pbIoBuffer,
  6609. pPeapCb->dwIoBufferLen
  6610. );
  6611. HostToWireFormat16 ( (WORD)( sizeof(PPP_EAP_PACKET) + 1 + pPeapCb->dwIoBufferLen),
  6612. pReceivePacket->Length
  6613. );
  6614. //
  6615. // This is a TLV. So the auth succeeded or failed.
  6616. // Send a manufactured success or fail to the current
  6617. // EAP type and then based on what the EAP type returns
  6618. // send a PEAP success/fail to the server. Change the
  6619. // state then to accept the EAP success or failure.
  6620. //
  6621. dwRetCode = GetPEAPTLVStatusMessageValue ( pPeapCb,
  6622. pReceivePacket,
  6623. &wValue
  6624. );
  6625. if ( NO_ERROR == dwRetCode )
  6626. {
  6627. if ( wValue == MS_PEAP_AVP_VALUE_SUCCESS )
  6628. {
  6629. pReceivePacket->Code = EAPCODE_Success;
  6630. EapTypeInput.fSuccessPacketReceived = TRUE;
  6631. }
  6632. else if ( wValue == MS_PEAP_AVP_VALUE_FAILURE )
  6633. {
  6634. pReceivePacket->Code = EAPCODE_Failure;
  6635. }
  6636. else
  6637. {
  6638. EapTlsTrace("Got an unrecognized TLV Message. Silently discarding the packet");
  6639. dwRetCode = NO_ERROR;
  6640. break;
  6641. }
  6642. pPeapCb->fReceivedTLVSuccessFail = TRUE;
  6643. HostToWireFormat16 ( (WORD)4, pReceivePacket->Length );
  6644. }
  6645. else
  6646. {
  6647. EapTlsTrace("Got an unrecognized TLV Message. Silently discarding the packet");
  6648. dwRetCode = NO_ERROR;
  6649. break;
  6650. }
  6651. }
  6652. else
  6653. {
  6654. //
  6655. // Check to see if it is any type of TLV message
  6656. // We send a NAK back for any TLV message other than status
  6657. //
  6658. //
  6659. if ( fIsPEAPTLVMessage ( pPeapCb, pReceivePacket ) )
  6660. {
  6661. //Send back a NAK
  6662. dwRetCode = CreatePEAPTLVNAKMessage ( pPeapCb,
  6663. pSendPacket,
  6664. cbSendPacket
  6665. );
  6666. if ( NO_ERROR != dwRetCode )
  6667. {
  6668. // this is an internal error. So cannot do much here
  6669. // but to fail auth
  6670. EapTlsTrace ( "Error creating TLV NAK message. Failing auth");
  6671. }
  6672. break;
  6673. }
  6674. else
  6675. {
  6676. CopyMemory ( pReceivePacket->Data,
  6677. pPeapCb->pbIoBuffer,
  6678. pPeapCb->dwIoBufferLen
  6679. );
  6680. HostToWireFormat16 ( (WORD)(sizeof(PPP_EAP_PACKET) + pPeapCb->dwIoBufferLen-1),
  6681. pReceivePacket->Length
  6682. );
  6683. }
  6684. }
  6685. }
  6686. else
  6687. {
  6688. pReceivePacket->Data[0] = (BYTE)pPeapCb->pEapInfo->dwTypeId;
  6689. }
  6690. }
  6691. if ( pEapInput->fDataReceivedFromInteractiveUI )
  6692. {
  6693. //we are done with interactive UI stuff...
  6694. pPeapCb->fInvokedInteractiveUI = FALSE;
  6695. }
  6696. dwRetCode = pPeapCb->pEapInfo->PppEapInfo.RasEapMakeMessage
  6697. ( pPeapCb->pEapInfo->pWorkBuf,
  6698. pReceivePacket,
  6699. pSendPacket,
  6700. cbSendPacket-200,
  6701. pEapOutput,
  6702. &EapTypeInput
  6703. );
  6704. if ( NO_ERROR == dwRetCode )
  6705. {
  6706. //
  6707. // if interactive UI was requested, wrap the data in
  6708. // in PEAP interactive UI structure
  6709. //
  6710. if ( pEapOutput->fInvokeInteractiveUI )
  6711. {
  6712. if ( pPeapCb->pUIContextData )
  6713. {
  6714. LocalFree ( pPeapCb->pUIContextData );
  6715. pPeapCb->pUIContextData = NULL;
  6716. }
  6717. pPeapCb->pUIContextData = (PPEAP_INTERACTIVE_UI)
  6718. LocalAlloc(LPTR,
  6719. sizeof(PEAP_INTERACTIVE_UI) + pEapOutput->dwSizeOfUIContextData );
  6720. if ( NULL == pPeapCb->pUIContextData )
  6721. {
  6722. EapTlsTrace("Error allocating memory for PEAP context data");
  6723. dwRetCode = ERROR_OUTOFMEMORY;
  6724. goto LDone;
  6725. }
  6726. pPeapCb->pUIContextData->dwEapTypeId = pPeapCb->pEapInfo->dwTypeId;
  6727. pPeapCb->pUIContextData->dwSizeofUIContextData
  6728. = pEapOutput->dwSizeOfUIContextData;
  6729. CopyMemory( pPeapCb->pUIContextData->bUIContextData,
  6730. pEapOutput->pUIContextData,
  6731. pEapOutput->dwSizeOfUIContextData
  6732. );
  6733. pEapOutput->pUIContextData = (PBYTE)pPeapCb->pUIContextData;
  6734. pEapOutput->dwSizeOfUIContextData =
  6735. sizeof(PEAP_INTERACTIVE_UI) + pEapOutput->dwSizeOfUIContextData;
  6736. pPeapCb->fInvokedInteractiveUI = TRUE;
  6737. }
  6738. else if ( pEapOutput->Action == EAPACTION_Done || pEapOutput->Action == EAPACTION_Send )
  6739. {
  6740. if ( pEapOutput->Action == EAPACTION_Done )
  6741. {
  6742. // We are done with auth.
  6743. if ( pPeapCb->fReceivedTLVSuccessFail != TRUE )
  6744. {
  6745. //
  6746. // Check to see what is the Auth result.
  6747. // Based on that, we should send back a
  6748. // PEAPSuccess / Fail
  6749. //
  6750. EapTlsTrace ("Failing Auth because we got a success/fail without TLV.");
  6751. dwRetCode = ERROR_INTERNAL_ERROR;
  6752. pPeapCb->fReceivedTLVSuccessFail = FALSE;
  6753. break;
  6754. }
  6755. pPeapCb->dwAuthResultCode = pEapOutput->dwAuthResultCode;
  6756. dwRetCode = CreatePEAPTLVStatusMessage ( pPeapCb,
  6757. pSendPacket,
  6758. cbSendPacket,
  6759. FALSE, //This is a response
  6760. ( pEapOutput->dwAuthResultCode == NO_ERROR ?
  6761. MS_PEAP_AVP_VALUE_SUCCESS:
  6762. MS_PEAP_AVP_VALUE_FAILURE
  6763. )
  6764. );
  6765. if ( pEapOutput->dwAuthResultCode == NO_ERROR )
  6766. {
  6767. pPeapCb->PeapState = PEAP_STATE_PEAP_SUCCESS_SEND;
  6768. }
  6769. else
  6770. {
  6771. pPeapCb->PeapState = PEAP_STATE_PEAP_FAIL_SEND;
  6772. }
  6773. pEapOutput->Action = EAPACTION_Send;
  6774. if ( pEapOutput->dwAuthResultCode == NO_ERROR )
  6775. {
  6776. //Check to see if connectiondata and user data need to be saved
  6777. if ( pEapOutput->fSaveConnectionData )
  6778. {
  6779. //
  6780. // save connection data in PEAP control
  6781. // block and then finally when auth is done
  6782. // We send back a save command.
  6783. //
  6784. pPeapCb->pEapInfo->pbNewClientConfig = pEapOutput->pConnectionData;
  6785. pPeapCb->pEapInfo->dwNewClientConfigSize = pEapOutput->dwSizeOfConnectionData;
  6786. pPeapCb->fEntryConnPropDirty = TRUE;
  6787. }
  6788. if ( pEapOutput->fSaveUserData )
  6789. {
  6790. pPeapCb->pEapInfo->pbUserConfigNew = pEapOutput->pUserData;
  6791. pPeapCb->pEapInfo->dwNewUserConfigSize = pEapOutput->dwSizeOfUserData;
  6792. pPeapCb->fEntryUserPropDirty = TRUE;
  6793. }
  6794. }
  6795. }
  6796. else if ( pEapOutput->Action == EAPACTION_Send )
  6797. {
  6798. //This has to be a request response. So if the length is < sizeof(PPP_EAP_PACKET)
  6799. // We have a problem
  6800. wPacketLength = WireToHostFormat16(pSendPacket->Length);
  6801. if ( wPacketLength >= sizeof(PPP_EAP_PACKET) )
  6802. {
  6803. dwRetCode = PeapEncryptTunnelData ( pPeapCb,
  6804. &(pSendPacket->Data[0]),
  6805. wPacketLength - sizeof(PPP_EAP_PACKET)+1
  6806. );
  6807. if ( NO_ERROR != dwRetCode )
  6808. {
  6809. //
  6810. // This is an internal error. So cannot send TLV's here
  6811. //
  6812. break;
  6813. }
  6814. CopyMemory ( &(pSendPacket->Data[2]),
  6815. pPeapCb->pbIoBuffer,
  6816. pPeapCb->dwIoBufferLen
  6817. );
  6818. wPacketLength = (WORD)(sizeof(PPP_EAP_PACKET)+ 1 + pPeapCb->dwIoBufferLen);
  6819. pSendPacket->Data[0] = PPP_EAP_PEAP;
  6820. pSendPacket->Data[1] = EAPTLS_PACKET_CURRENT_VERSION;
  6821. //Readjust the length
  6822. HostToWireFormat16
  6823. ( wPacketLength,
  6824. pSendPacket->Length
  6825. );
  6826. }
  6827. }
  6828. else
  6829. {
  6830. EapTlsTrace("Invalid length returned by Length");
  6831. dwRetCode = ERROR_INTERNAL_ERROR;
  6832. }
  6833. }
  6834. else
  6835. {
  6836. // we can get send / done / noaction from the client .
  6837. // So this is a no action. pass it on to EAP without
  6838. // any modification
  6839. }
  6840. }
  6841. break;
  6842. case PEAP_STATE_EAP_TYPE_FINISHED:
  6843. EapTlsTrace("PEAP:PEAP_STATE_EAP_TYPE_FINISHED");
  6844. break;
  6845. case PEAP_STATE_PEAP_SUCCESS_SEND:
  6846. EapTlsTrace("PEAP:PEAP_STATE_PEAP_SUCCESS_SEND");
  6847. //
  6848. // We got a PEAP_SUCCESS TLV inside the protected channel and have send
  6849. // a PEAP_SUCCESS response TLV. So we should get an EAP_Success now.
  6850. // Anything else will cause the connection to disconnect.
  6851. //
  6852. if ( pReceivePacket && pReceivePacket->Code == EAPCODE_Success )
  6853. {
  6854. //
  6855. // Check to see if there is a need to create a new conn and/or user blob
  6856. //
  6857. if ( pPeapCb->fEntryConnPropDirty ||
  6858. pPeapCb->fTlsConnPropDirty
  6859. )
  6860. {
  6861. PPEAP_CONN_PROP pNewConnProp = NULL;
  6862. PEAP_ENTRY_CONN_PROPERTIES UNALIGNED * pNewEntryProp = NULL;
  6863. PEAP_ENTRY_CONN_PROPERTIES UNALIGNED * pEntryProp = NULL;
  6864. DWORD dwSize = 0;
  6865. //
  6866. // We need to recreate our PEAP conn prop structure
  6867. //
  6868. dwSize = sizeof(PEAP_CONN_PROP);
  6869. if ( pPeapCb->fTlsConnPropDirty )
  6870. {
  6871. dwSize += pPeapCb->pNewTlsConnProp->dwSize;
  6872. }
  6873. else
  6874. {
  6875. dwSize += pPeapCb->pConnProp->EapTlsConnProp.dwSize;
  6876. }
  6877. if ( pPeapCb->fEntryConnPropDirty )
  6878. {
  6879. dwSize += sizeof(PEAP_ENTRY_CONN_PROPERTIES) +
  6880. pPeapCb->pEapInfo->dwNewClientConfigSize -1;
  6881. }
  6882. else
  6883. {
  6884. PeapGetFirstEntryConnProp ( pPeapCb->pConnProp, &pNewEntryProp );
  6885. dwSize += pNewEntryProp->dwSize;
  6886. }
  6887. pNewConnProp = (PPEAP_CONN_PROP)LocalAlloc (LPTR, dwSize );
  6888. if ( pNewConnProp )
  6889. {
  6890. pNewConnProp->dwVersion = 1;
  6891. pNewConnProp->dwSize = dwSize;
  6892. pNewConnProp->dwNumPeapTypes = 1;
  6893. if ( pPeapCb->fTlsConnPropDirty )
  6894. CopyMemory ( &pNewConnProp->EapTlsConnProp,
  6895. pPeapCb->pNewTlsConnProp,
  6896. pPeapCb->pNewTlsConnProp->dwSize
  6897. );
  6898. else
  6899. CopyMemory ( &pNewConnProp->EapTlsConnProp,
  6900. &pPeapCb->pConnProp->EapTlsConnProp,
  6901. pPeapCb->pConnProp->EapTlsConnProp.dwSize
  6902. );
  6903. PeapGetFirstEntryConnProp ( pNewConnProp, &pNewEntryProp );
  6904. if ( pPeapCb->fEntryConnPropDirty )
  6905. {
  6906. pNewEntryProp->dwVersion = 1;
  6907. pNewEntryProp->dwEapTypeId = pPeapCb->pEapInfo->dwTypeId;
  6908. pNewEntryProp->dwSize = sizeof( PEAP_ENTRY_CONN_PROPERTIES) +
  6909. pPeapCb->pEapInfo->dwNewClientConfigSize -1;
  6910. CopyMemory ( pNewEntryProp->bData,
  6911. pPeapCb->pEapInfo->pbNewClientConfig,
  6912. pPeapCb->pEapInfo->dwNewClientConfigSize
  6913. );
  6914. }
  6915. else
  6916. {
  6917. PeapGetFirstEntryConnProp ( pPeapCb->pConnProp, &pEntryProp );
  6918. CopyMemory ( pNewEntryProp,
  6919. pEntryProp,
  6920. pEntryProp->dwSize
  6921. );
  6922. }
  6923. LocalFree ( pPeapCb->pConnProp );
  6924. pPeapCb->pConnProp = pNewConnProp;
  6925. pEapOutput->fSaveConnectionData = TRUE;
  6926. pEapOutput->pConnectionData = (PBYTE)pNewConnProp;
  6927. pEapOutput->dwSizeOfConnectionData = pNewConnProp->dwSize;
  6928. }
  6929. }
  6930. //
  6931. // check to see if the user props need to be saved
  6932. //
  6933. if ( pPeapCb->fEntryUserPropDirty )
  6934. {
  6935. PPEAP_USER_PROP pNewUserProp = NULL;
  6936. pNewUserProp = (PPEAP_USER_PROP) LocalAlloc( LPTR,
  6937. sizeof( PEAP_USER_PROP ) +
  6938. pPeapCb->pEapInfo->dwNewUserConfigSize -1);
  6939. if ( pNewUserProp )
  6940. {
  6941. pNewUserProp->dwVersion = pPeapCb->pUserProp->dwVersion;
  6942. pNewUserProp->dwSize = sizeof( PEAP_USER_PROP ) +
  6943. pPeapCb->pEapInfo->dwNewUserConfigSize -1;
  6944. pNewUserProp->UserProperties.dwVersion = 1;
  6945. pNewUserProp->UserProperties.dwSize = sizeof(PEAP_ENTRY_USER_PROPERTIES) +
  6946. pPeapCb->pEapInfo->dwNewUserConfigSize -1;
  6947. pNewUserProp->UserProperties.dwEapTypeId =
  6948. pPeapCb->pEapInfo->dwTypeId;
  6949. CopyMemory ( pNewUserProp->UserProperties.bData,
  6950. pPeapCb->pEapInfo->pbUserConfigNew,
  6951. pPeapCb->pEapInfo->dwNewUserConfigSize
  6952. );
  6953. LocalFree ( pPeapCb->pUserProp);
  6954. pPeapCb->pUserProp = pNewUserProp;
  6955. pEapOutput->pUserData = (PBYTE)pNewUserProp;
  6956. pEapOutput->dwSizeOfUserData = pNewUserProp->dwSize;
  6957. pEapOutput->fSaveUserData = TRUE;
  6958. }
  6959. //
  6960. // Set the cookie if we're enabled to do fast reconnect
  6961. //
  6962. if ( pPeapCb->dwFlags & PEAPCB_FAST_ROAMING )
  6963. {
  6964. dwRetCode = PeapCreateCookie ( pPeapCb,
  6965. &pbCookie,
  6966. &cbCookie
  6967. );
  6968. if ( NO_ERROR != dwRetCode )
  6969. {
  6970. EapTlsTrace("Failed to create session cookie. Resetting fast reconnect");
  6971. dwRetCode = SetTLSFastReconnect ( pPeapCb->pEapTlsCB , FALSE);
  6972. if ( NO_ERROR != dwRetCode )
  6973. {
  6974. //
  6975. // This is an internal error
  6976. // So disconnect the session.
  6977. //
  6978. pEapOutput->dwAuthResultCode = dwRetCode;
  6979. pEapOutput->Action = EAPACTION_Done;
  6980. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  6981. break;
  6982. }
  6983. }
  6984. dwRetCode = SetTLSSessionCookie ( pPeapCb->pEapTlsCB ,
  6985. pbCookie,
  6986. cbCookie
  6987. );
  6988. if ( NO_ERROR != dwRetCode )
  6989. {
  6990. EapTlsTrace("Failed to create session cookie. Resetting fast reconnect");
  6991. dwRetCode = SetTLSFastReconnect ( pPeapCb->pEapTlsCB , FALSE);
  6992. if ( NO_ERROR != dwRetCode )
  6993. {
  6994. //
  6995. // This is an internal error
  6996. // So disconnect the session.
  6997. //
  6998. pEapOutput->dwAuthResultCode = dwRetCode;
  6999. pEapOutput->Action = EAPACTION_Done;
  7000. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  7001. break;
  7002. }
  7003. }
  7004. }
  7005. }
  7006. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  7007. pEapOutput->pUserAttributes = pPeapCb->pTlsUserAttributes;
  7008. pEapOutput->dwAuthResultCode = pPeapCb->dwAuthResultCode;
  7009. pEapOutput->Action = EAPACTION_Done;
  7010. }
  7011. else if ( pReceivePacket && pReceivePacket->Code == EAPCODE_Failure )
  7012. {
  7013. //
  7014. // We fail the connection. Even though there is a success from PEAP
  7015. //
  7016. EapTlsTrace("We got a EAP_failure after we got a PEAP_SUCCESS. Failing auth.");
  7017. dwRetCode = ERROR_INTERNAL_ERROR;
  7018. pEapOutput->dwAuthResultCode = ERROR_INTERNAL_ERROR;
  7019. pEapOutput->Action = EAPACTION_Done;
  7020. }
  7021. else
  7022. {
  7023. if ( pReceivePacket )
  7024. EapTlsTrace ("Received Packet with code %x when expecting success", pReceivePacket->Code);
  7025. break;
  7026. }
  7027. break;
  7028. case PEAP_STATE_PEAP_FAIL_SEND:
  7029. EapTlsTrace("PEAP:PEAP_STATE_PEAP_FAIL_SEND");
  7030. //
  7031. // We have send PEAP_FAILURE TLV inside the protected channel
  7032. // So the only thing we should expect is a EAP_Failure from now on
  7033. // Send back a EAP_FAIL with EAP_Done action.
  7034. //
  7035. if ( pReceivePacket && pReceivePacket->Code == EAPCODE_Failure )
  7036. {
  7037. pEapOutput->dwAuthResultCode = pPeapCb->dwAuthResultCode;
  7038. //We have failed auth so uncache the creds
  7039. FreeCachedCredentials (pPeapCb->pEapTlsCB);
  7040. pEapOutput->Action = EAPACTION_Done;
  7041. }
  7042. else if ( pReceivePacket && pReceivePacket->Code == EAPCODE_Success )
  7043. {
  7044. //
  7045. // We fail the connection. Even though there is a success from PEAP
  7046. //
  7047. EapTlsTrace("We got a EAP_Success after we got a PEAP_FAILURE. Failing auth.");
  7048. dwRetCode = ERROR_INTERNAL_ERROR;
  7049. pEapOutput->dwAuthResultCode = ERROR_INTERNAL_ERROR;
  7050. //We have failed auth so uncache the creds
  7051. FreeCachedCredentials (pPeapCb->pEapTlsCB);
  7052. pEapOutput->Action = EAPACTION_Done;
  7053. }
  7054. else
  7055. {
  7056. if ( pReceivePacket )
  7057. EapTlsTrace ("Received Packet with code %x when expecting success", pReceivePacket->Code);
  7058. break;
  7059. }
  7060. default:
  7061. EapTlsTrace("PEAP:Invalid state");
  7062. }
  7063. if ( fImpersonating )
  7064. {
  7065. if (!RevertToSelf() )
  7066. {
  7067. dwRetCode = GetLastError();
  7068. EapTlsTrace("PEAP:RevertToSelf Failed and returned 0x%x", dwRetCode );
  7069. }
  7070. }
  7071. LDone:
  7072. EapTlsTrace("EapPeapCMakeMessage done");
  7073. return dwRetCode;
  7074. }
  7075. DWORD
  7076. EapPeapSMakeMessage(
  7077. IN PPEAPCB pPeapCb,
  7078. IN PPP_EAP_PACKET* pReceivePacket,
  7079. OUT PPP_EAP_PACKET* pSendPacket,
  7080. IN DWORD cbSendPacket,
  7081. OUT PPP_EAP_OUTPUT* pEapOutput,
  7082. IN PPP_EAP_INPUT* pEapInput
  7083. )
  7084. {
  7085. DWORD dwRetCode = NO_ERROR;
  7086. PPP_EAP_INPUT EapTypeInput;
  7087. WORD wPacketLength;
  7088. DWORD dwVersion;
  7089. PBYTE pbCookie = NULL;
  7090. DWORD cbCookie = 0;
  7091. BOOL fIsReconnect = FALSE;
  7092. EapTlsTrace("EapPeapSMakeMessage");
  7093. switch ( pPeapCb->PeapState )
  7094. {
  7095. case PEAP_STATE_INITIAL:
  7096. EapTlsTrace("PEAP:PEAP_STATE_INITIAL");
  7097. //
  7098. // Start the EapTls Conversation here.
  7099. //
  7100. //Receive Packet will be NULL. Call EapTlsSMakeMessage
  7101. //
  7102. //Note: Our version currently is 0. So the packet will
  7103. // be the same as eaptls packet. In future, this needs
  7104. // to change
  7105. dwRetCode = EapTlsSMakeMessage( pPeapCb->pEapTlsCB,
  7106. (EAPTLS_PACKET *)pReceivePacket,
  7107. (EAPTLS_PACKET *)pSendPacket,
  7108. cbSendPacket,
  7109. pEapOutput,
  7110. pEapInput
  7111. );
  7112. if ( NO_ERROR == dwRetCode )
  7113. {
  7114. //change the packet to show peap
  7115. pSendPacket->Data[0] = PPP_EAP_PEAP;
  7116. //Set version
  7117. ((EAPTLS_PACKET *)pSendPacket)->bFlags |=
  7118. EAPTLS_PACKET_HIGHEST_SUPPORTED_VERSION;
  7119. }
  7120. pPeapCb->PeapState = PEAP_STATE_TLS_INPROGRESS;
  7121. break;
  7122. case PEAP_STATE_TLS_INPROGRESS:
  7123. EapTlsTrace("PEAP:PEAP_STATE_TLS_INPROGRESS");
  7124. if ( pReceivePacket )
  7125. {
  7126. if ( !(pPeapCb->dwFlags & PEAPCB_VERSION_OK) )
  7127. {
  7128. //
  7129. // We have not done the version check yet.
  7130. //
  7131. dwVersion = ((EAPTLS_PACKET *)pReceivePacket)->bFlags & 0x03;
  7132. if ( dwVersion > EAPTLS_PACKET_LOWEST_SUPPORTED_VERSION )
  7133. {
  7134. //
  7135. // Send a fail code back and we're done. The versions
  7136. // of PEAP did not match
  7137. EapTlsTrace("Could not negotiate version successfully.");
  7138. EapTlsTrace("Requested version %ld, our lowest version %ld",
  7139. dwVersion, EAPTLS_PACKET_LOWEST_SUPPORTED_VERSION
  7140. );
  7141. pEapOutput->dwAuthResultCode = ERROR_INTERNAL_ERROR;
  7142. pSendPacket->Code = EAPCODE_Failure;
  7143. pSendPacket->Id = pReceivePacket->Id + 1;
  7144. HostToWireFormat16( (WORD)4, pSendPacket->Length );
  7145. pEapOutput->Action = EAPACTION_SendAndDone;
  7146. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  7147. break;
  7148. }
  7149. else
  7150. {
  7151. pPeapCb->dwFlags |= PEAPCB_VERSION_OK;
  7152. }
  7153. }
  7154. pReceivePacket->Data[0] = PPP_EAP_TLS;
  7155. }
  7156. dwRetCode = EapTlsSMakeMessage( pPeapCb->pEapTlsCB,
  7157. (EAPTLS_PACKET *)pReceivePacket,
  7158. (EAPTLS_PACKET *)pSendPacket,
  7159. cbSendPacket,
  7160. pEapOutput,
  7161. pEapInput
  7162. );
  7163. if ( NO_ERROR == dwRetCode )
  7164. {
  7165. //We are done with auth.
  7166. if ( pEapOutput->dwAuthResultCode == NO_ERROR &&
  7167. pSendPacket->Code == EAPCODE_Success
  7168. )
  7169. {
  7170. //Transfer the Id from eaptls control block to peap cb
  7171. pPeapCb->bId = ++pPeapCb->pEapTlsCB->bId;
  7172. //
  7173. // auth was successful. Carefully keep the MPPE
  7174. // session keys returned so that we can encrypt the
  7175. // channel. From now on everything will be encrypted.
  7176. //
  7177. pPeapCb->pTlsUserAttributes = pEapOutput->pUserAttributes;
  7178. dwRetCode = PeapGetTunnelProperties ( pPeapCb );
  7179. if (NO_ERROR != dwRetCode )
  7180. {
  7181. break;
  7182. }
  7183. //
  7184. // Check to see if we get the cookie. If we get the cookie,
  7185. // and it is a fast reconnect, then we compare which auth method
  7186. // was used previously. If it is good, then
  7187. //
  7188. if ( pPeapCb->dwFlags & PEAPCB_FAST_ROAMING )
  7189. {
  7190. dwRetCode = GetTLSSessionCookie ( pPeapCb->pEapTlsCB,
  7191. &pbCookie,
  7192. &cbCookie,
  7193. &fIsReconnect
  7194. );
  7195. if ( NO_ERROR != dwRetCode )
  7196. {
  7197. EapTlsTrace("Error getting cookie for a reconnected session. Failing auth");
  7198. //
  7199. // Set the TLS Fast Reconnect State to FALSE
  7200. //
  7201. dwRetCode = SetTLSFastReconnect ( pPeapCb->pEapTlsCB , FALSE);
  7202. // We cannot encrypt and send stuff across here.
  7203. // Reconnected Session state is invalid.
  7204. pEapOutput->dwAuthResultCode = dwRetCode;
  7205. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  7206. pEapOutput->Action = EAPACTION_SendAndDone;
  7207. break;
  7208. }
  7209. if ( fIsReconnect )
  7210. {
  7211. if ( cbCookie == 0 )
  7212. {
  7213. //There was an error getting session cookie.
  7214. //Or there is no cookie and this is a reconnet
  7215. // So fail the request.
  7216. EapTlsTrace("Error getting cookie for a reconnected session. Failing auth");
  7217. // We cannot encrypt and send stuff across here.
  7218. // Reconnected Session state is invalid.
  7219. dwRetCode = SetTLSFastReconnect ( pPeapCb->pEapTlsCB , FALSE);
  7220. if ( NO_ERROR != dwRetCode )
  7221. {
  7222. //Error setting fast reconnect state
  7223. // cant do much here.
  7224. }
  7225. dwRetCode = ERROR_INTERNAL_ERROR;
  7226. pEapOutput->dwAuthResultCode = dwRetCode;
  7227. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  7228. pEapOutput->Action = EAPACTION_SendAndDone;
  7229. break;
  7230. }
  7231. //
  7232. // This is a server
  7233. // Check to see if the cookie is fine.
  7234. // If it is fine then there is no need to reauth.
  7235. // So send back a PEAP_SUCCESS request packet
  7236. // and change our state to PEAP_SUCCESS_SEND
  7237. // If not, proceed with auth and send identity request
  7238. //
  7239. EapTlsTrace ("TLS session fast reconnected");
  7240. dwRetCode = PeapCheckCookie ( pPeapCb, (PPEAP_COOKIE)pbCookie, cbCookie );
  7241. if ( NO_ERROR != dwRetCode )
  7242. {
  7243. //
  7244. // So invalidate the session for fast reconnect
  7245. // and fail auth. Next time a full reconnect will happen
  7246. //
  7247. dwRetCode = SetTLSFastReconnect ( pPeapCb->pEapTlsCB , FALSE);
  7248. if ( NO_ERROR != dwRetCode )
  7249. {
  7250. //
  7251. // This is an internal error
  7252. // So disconnect the session.
  7253. //
  7254. pEapOutput->dwAuthResultCode = dwRetCode;
  7255. pEapOutput->Action = EAPACTION_Done;
  7256. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  7257. break;
  7258. }
  7259. EapTlsTrace ("Error validating the cookie. Failing auth");
  7260. pEapOutput->dwAuthResultCode = dwRetCode;
  7261. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  7262. pEapOutput->Action = EAPACTION_Done;
  7263. break;
  7264. }
  7265. else
  7266. {
  7267. //
  7268. // Cookie is fine.
  7269. //
  7270. //
  7271. // Send a PEAP success TLV here.
  7272. // We need to do this so that
  7273. // the client does not think he is spoofed.
  7274. //
  7275. dwRetCode = CreatePEAPTLVStatusMessage ( pPeapCb,
  7276. pSendPacket,
  7277. cbSendPacket,
  7278. TRUE,
  7279. MS_PEAP_AVP_VALUE_SUCCESS
  7280. );
  7281. if ( NO_ERROR != dwRetCode )
  7282. {
  7283. break;
  7284. }
  7285. pPeapCb->fSendTLVSuccessforFastRoaming = TRUE;
  7286. pEapOutput->Action = EAPACTION_SendWithTimeoutInteractive;
  7287. pPeapCb->PeapState = PEAP_STATE_PEAP_SUCCESS_SEND;
  7288. pPeapCb->dwAuthResultCode = pEapOutput->dwAuthResultCode;
  7289. pPeapCb->fFastReconnectedSession = TRUE;
  7290. break;
  7291. }
  7292. }
  7293. else
  7294. {
  7295. //
  7296. // Go ahead with the auth and at the end, save the cookie
  7297. // Check to see if fast reconnect has been enabled. If it has been enabled,
  7298. // Set the TLS state to enable fast reconnect. If not do nothing at the
  7299. // end of auth.
  7300. EapTlsTrace ("Full TLS handshake");
  7301. }
  7302. }
  7303. pEapOutput->pUserAttributes = NULL;
  7304. pEapOutput->Action = EAPACTION_SendWithTimeoutInteractive;
  7305. pSendPacket->Code = EAPCODE_Request;
  7306. pSendPacket->Id = pPeapCb->bId;
  7307. //
  7308. // Send encrypted identity request.
  7309. //
  7310. pSendPacket->Data[0] = PPP_EAP_PEAP;
  7311. pSendPacket->Data[1] = EAPTLS_PACKET_CURRENT_VERSION;
  7312. pSendPacket->Data[2] = PEAP_EAPTYPE_IDENTITY;
  7313. //
  7314. // Identity request needs to be encrypted.
  7315. //
  7316. dwRetCode = PeapEncryptTunnelData ( pPeapCb,
  7317. &(pSendPacket->Data[2]),
  7318. 1
  7319. );
  7320. if ( NO_ERROR != dwRetCode )
  7321. {
  7322. break;
  7323. }
  7324. CopyMemory ( &(pSendPacket->Data[2]),
  7325. pPeapCb->pbIoBuffer,
  7326. pPeapCb->dwIoBufferLen
  7327. );
  7328. HostToWireFormat16
  7329. (
  7330. (WORD)(sizeof(PPP_EAP_PACKET)+1 + pPeapCb->dwIoBufferLen),
  7331. pSendPacket->Length
  7332. );
  7333. pPeapCb->PeapState = PEAP_STATE_IDENTITY_REQUEST_SENT;
  7334. }
  7335. else
  7336. {
  7337. //change the packet to show peap
  7338. pSendPacket->Data[0] = PPP_EAP_PEAP;
  7339. }
  7340. }
  7341. break;
  7342. case PEAP_STATE_IDENTITY_REQUEST_SENT:
  7343. EapTlsTrace("PEAP:PEAP_STATE_IDENTITY_REQUEST_SENT");
  7344. //
  7345. // Should get only identity response and nothing else
  7346. // NOTE: in this implementation, this should match
  7347. // the outer identity. But at a later point, we
  7348. // may get many identities and any one of them should
  7349. // match the outer identity.
  7350. //
  7351. // call begin in the eap dll and send back the blob got
  7352. // from begin.
  7353. //decrypt tunnel data here
  7354. if ( pReceivePacket )
  7355. {
  7356. dwRetCode = PeapDecryptTunnelData ( pPeapCb,
  7357. &(pReceivePacket->Data[2]),
  7358. WireToHostFormat16(pReceivePacket->Length)
  7359. - (sizeof(PPP_EAP_PACKET)+1)
  7360. );
  7361. if ( NO_ERROR != dwRetCode )
  7362. {
  7363. // We could not decrypt the tunnel traffic
  7364. // So we silently discard this packet.
  7365. EapTlsTrace("PeapDecryptTunnelData failed: silently discarding packet");
  7366. dwRetCode = NO_ERROR;
  7367. pEapOutput->Action = EAPACTION_NoAction;
  7368. break;
  7369. }
  7370. }
  7371. if ( pReceivePacket &&
  7372. pReceivePacket->Code != EAPCODE_Response &&
  7373. pPeapCb->pbIoBuffer[0] != PEAP_EAPTYPE_IDENTITY )
  7374. {
  7375. EapTlsTrace("Invalid packet received when expecting identity response");
  7376. pEapOutput->Action = EAPACTION_NoAction;
  7377. }
  7378. else
  7379. {
  7380. if ( pReceivePacket && pReceivePacket->Id != pPeapCb->bId )
  7381. {
  7382. EapTlsTrace ("Ignoring packet with mismatched ids");
  7383. pEapOutput->Action = EAPACTION_NoAction;
  7384. break;
  7385. }
  7386. if ( pReceivePacket )
  7387. {
  7388. //
  7389. // get the identity and create a ppp input and pass it on to dll begin
  7390. // of the configured eap type.
  7391. //
  7392. MultiByteToWideChar( CP_ACP,
  7393. 0,
  7394. &pPeapCb->pbIoBuffer[1],
  7395. pPeapCb->dwIoBufferLen - 1,
  7396. pPeapCb->awszTypeIdentity,
  7397. DNLEN+UNLEN );
  7398. ZeroMemory ( &EapTypeInput, sizeof(EapTypeInput) );
  7399. if ( pEapInput )
  7400. {
  7401. CopyMemory( &EapTypeInput, pEapInput, sizeof(EapTypeInput) );
  7402. }
  7403. else
  7404. {
  7405. EapTypeInput.fFlags = RAS_EAP_FLAG_NON_INTERACTIVE;
  7406. EapTypeInput.fAuthenticator = TRUE;
  7407. }
  7408. EapTypeInput.pwszIdentity = pPeapCb->awszIdentity;
  7409. EapTypeInput.bInitialId = ++ pPeapCb->bId;
  7410. //
  7411. // Check to see if config data for this eap was
  7412. // passed in in PeapEapBegin. If so, extract the
  7413. // data and pass it to the eap.
  7414. //
  7415. (VOID)PeapGetEapConfigInfo(
  7416. pPeapCb->pUserProp,
  7417. pPeapCb->pEapInfo->dwTypeId,
  7418. &EapTypeInput.pConnectionData,
  7419. &EapTypeInput.dwSizeOfConnectionData);
  7420. //
  7421. // Call begin function
  7422. //
  7423. dwRetCode = pPeapCb->pEapInfo->PppEapInfo.RasEapBegin(
  7424. &(pPeapCb->pEapInfo->pWorkBuf ),
  7425. &EapTypeInput);
  7426. //
  7427. // Zero out the config information. We are supposed to pass
  7428. // it only to the eap's begin entry point.
  7429. //
  7430. EapTypeInput.pConnectionData = NULL;
  7431. EapTypeInput.dwSizeOfConnectionData = 0;
  7432. }
  7433. if ( NO_ERROR == dwRetCode )
  7434. {
  7435. //
  7436. // Call make message now. This MakeMessage is called in for the first time
  7437. // So send the identity request that came across into this MakeMessage.
  7438. //
  7439. dwRetCode = pPeapCb->pEapInfo->PppEapInfo.RasEapMakeMessage
  7440. ( pPeapCb->pEapInfo->pWorkBuf,
  7441. NULL,
  7442. pSendPacket,
  7443. cbSendPacket-200,
  7444. pEapOutput,
  7445. &EapTypeInput
  7446. );
  7447. if ( NO_ERROR == dwRetCode )
  7448. {
  7449. if ( pEapOutput->Action == EAPACTION_Authenticate )
  7450. {
  7451. //
  7452. // do nothing here. We are passing this on to RADIUS as is
  7453. //
  7454. }
  7455. else
  7456. {
  7457. wPacketLength = WireToHostFormat16(pSendPacket->Length);
  7458. //Encrypt the entire packet that we need to nest
  7459. dwRetCode = PeapEncryptTunnelData ( pPeapCb,
  7460. &(pSendPacket->Data[0]),
  7461. wPacketLength - sizeof(PPP_EAP_PACKET)+1
  7462. );
  7463. if ( NO_ERROR != dwRetCode )
  7464. {
  7465. //
  7466. // This is an internal error. So we cannot send
  7467. // a PEAP_Failure here
  7468. //
  7469. break;
  7470. }
  7471. pSendPacket->Data[0] = PPP_EAP_PEAP;
  7472. pSendPacket->Data[1] =EAPTLS_PACKET_CURRENT_VERSION;
  7473. CopyMemory ( &(pSendPacket->Data[2]),
  7474. pPeapCb->pbIoBuffer,
  7475. pPeapCb->dwIoBufferLen
  7476. );
  7477. //Readjust the length
  7478. wPacketLength = (WORD)(sizeof(PPP_EAP_PACKET) + 1 + pPeapCb->dwIoBufferLen);
  7479. HostToWireFormat16
  7480. ( wPacketLength,
  7481. pSendPacket->Length
  7482. );
  7483. //Set the Id of the packet send. This should have been set
  7484. //by the eap type.
  7485. pPeapCb->bId = pSendPacket->Id;
  7486. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_INPROGRESS;
  7487. }
  7488. }
  7489. else
  7490. {
  7491. EapTlsTrace ( "EapType %d failed in RasEapMakeMEssage and returned 0x%x",
  7492. pPeapCb->pEapInfo->dwTypeId,
  7493. dwRetCode
  7494. );
  7495. }
  7496. }
  7497. else
  7498. {
  7499. EapTlsTrace ( "EapType %d failed in RasEapBegin and returned 0x%x",
  7500. pPeapCb->pEapInfo->dwTypeId,
  7501. dwRetCode
  7502. );
  7503. //
  7504. // Send a PEAP failure TLV here. We need to do this so that
  7505. // the client does not think he is spoofed.
  7506. //
  7507. dwRetCode = CreatePEAPTLVStatusMessage ( pPeapCb,
  7508. pSendPacket,
  7509. cbSendPacket,
  7510. TRUE,
  7511. MS_PEAP_AVP_VALUE_FAILURE
  7512. );
  7513. if ( NO_ERROR != dwRetCode )
  7514. {
  7515. //
  7516. // This is an internal error. So we cannot send
  7517. // a PEAP_Failure here
  7518. //
  7519. break;
  7520. }
  7521. pEapOutput->Action = EAPACTION_SendWithTimeoutInteractive;
  7522. pPeapCb->PeapState = PEAP_STATE_PEAP_FAIL_SEND;
  7523. }
  7524. }
  7525. break;
  7526. case PEAP_STATE_EAP_TYPE_INPROGRESS:
  7527. EapTlsTrace("PEAP:PEAP_STATE_EAP_TYPE_INPROGRESS");
  7528. //
  7529. // Since we are doing only one EAP type now, if we get a NAK here,
  7530. // it means that the client cannot execute the EAP Type that was send
  7531. // so send back a EAP_FAIL with proper error code
  7532. //
  7533. if ( pReceivePacket &&
  7534. pReceivePacket->Code != EAPCODE_Response &&
  7535. pReceivePacket->Id != pPeapCb->bId
  7536. )
  7537. {
  7538. EapTlsTrace("Received packet with some other code than response or the id does not match. Ignoring packet");
  7539. pEapOutput->Action = EAPACTION_NoAction;
  7540. }
  7541. else
  7542. {
  7543. if ( pReceivePacket )
  7544. {
  7545. dwRetCode = PeapDecryptTunnelData ( pPeapCb,
  7546. &(pReceivePacket->Data[2]),
  7547. WireToHostFormat16(pReceivePacket->Length)
  7548. - ( sizeof(PPP_EAP_PACKET) + 1 )
  7549. );
  7550. if ( NO_ERROR != dwRetCode )
  7551. {
  7552. // We could not decrypt the tunnel traffic
  7553. // So we silently discard this packet.
  7554. EapTlsTrace("PeapDecryptTunnelData failed: silently discarding packet");
  7555. dwRetCode = NO_ERROR;
  7556. pEapOutput->Action = EAPACTION_NoAction;
  7557. break;
  7558. }
  7559. }
  7560. if ( pReceivePacket &&
  7561. pPeapCb->pbIoBuffer[0] == PEAP_EAPTYPE_NAK )
  7562. {
  7563. //
  7564. // Check to see if the typeId got back is in our configured list
  7565. // And it is not the same as the first EAP type.
  7566. //
  7567. PEAP_ENTRY_USER_PROPERTIES UNALIGNED * pEntryProp = NULL;
  7568. DWORD dwNewTypeId = pPeapCb->pbIoBuffer[1];
  7569. EapTlsTrace("Got NAK for first configured protocol. Client end back NAK with EAPID: %d",
  7570. dwNewTypeId);
  7571. if ( pPeapCb->pEapInfo->dwTypeId == dwNewTypeId )
  7572. {
  7573. EapTlsTrace("Got NAK for first configured protocol with same typeid. Failing Auth");
  7574. pEapOutput->Action = EAPACTION_Done;
  7575. pEapOutput->dwAuthResultCode = ERROR_PROTOCOL_NOT_CONFIGURED;
  7576. dwRetCode = NO_ERROR;
  7577. break;
  7578. }
  7579. // Check to see if this If is in our configured list
  7580. pEntryProp = PeapFindEntryUserProp ( pPeapCb->pUserProp,
  7581. dwNewTypeId
  7582. );
  7583. if ( NULL == pEntryProp )
  7584. {
  7585. EapTlsTrace("Did not find the NAK'ed Auth type in our list. Failing Auth");
  7586. pEapOutput->Action = EAPACTION_Done;
  7587. pEapOutput->dwAuthResultCode = ERROR_PROTOCOL_NOT_CONFIGURED;
  7588. pSendPacket->Code = EAPCODE_Failure;
  7589. pSendPacket->Id = pReceivePacket->Id;
  7590. HostToWireFormat16
  7591. ( 4,
  7592. pSendPacket->Length
  7593. );
  7594. dwRetCode = NO_ERROR;
  7595. break;
  7596. }
  7597. //
  7598. // The NAK'ed Type is in out list. So redo our data structures and
  7599. // send back a new challenge
  7600. //
  7601. if ( pPeapCb->pEapInfo )
  7602. {
  7603. dwRetCode = pPeapCb->pEapInfo->PppEapInfo.RasEapEnd
  7604. ( pPeapCb->pEapInfo->pWorkBuf);
  7605. pPeapCb->pEapInfo->pWorkBuf = NULL;
  7606. LocalFree ( pPeapCb->pEapInfo );
  7607. pPeapCb->pEapInfo = NULL;
  7608. }
  7609. //
  7610. // Get the selected EAP type
  7611. //
  7612. dwRetCode = PeapEapInfoCopyListNode ( pEntryProp->dwEapTypeId,
  7613. g_pEapInfo,
  7614. &pPeapCb->pEapInfo
  7615. );
  7616. if ( NO_ERROR != dwRetCode || NULL == pPeapCb->pEapInfo )
  7617. {
  7618. EapTlsTrace("Cannot find configured PEAP in the list of EAP Types on this machine. This is an internal error.");
  7619. pEapOutput->Action = EAPACTION_Done;
  7620. pEapOutput->dwAuthResultCode = ERROR_PROTOCOL_NOT_CONFIGURED;
  7621. dwRetCode = NO_ERROR;
  7622. break;
  7623. }
  7624. ZeroMemory ( &EapTypeInput, sizeof(EapTypeInput) );
  7625. if ( pEapInput )
  7626. {
  7627. CopyMemory( &EapTypeInput, pEapInput, sizeof(EapTypeInput) );
  7628. }
  7629. else
  7630. {
  7631. EapTypeInput.fFlags = RAS_EAP_FLAG_NON_INTERACTIVE;
  7632. EapTypeInput.fAuthenticator = TRUE;
  7633. }
  7634. EapTypeInput.pwszIdentity = pPeapCb->awszIdentity;
  7635. EapTypeInput.bInitialId = ++ pPeapCb->bId;
  7636. dwRetCode = pPeapCb->pEapInfo->PppEapInfo.RasEapBegin( &(pPeapCb->pEapInfo->pWorkBuf ),
  7637. &EapTypeInput
  7638. );
  7639. if ( NO_ERROR == dwRetCode )
  7640. {
  7641. //
  7642. // Call make message now. This MakeMessage is called in for the first time
  7643. // So send the identity request that came across into this MakeMessage.
  7644. //
  7645. dwRetCode = pPeapCb->pEapInfo->PppEapInfo.RasEapMakeMessage
  7646. ( pPeapCb->pEapInfo->pWorkBuf,
  7647. NULL,
  7648. pSendPacket,
  7649. cbSendPacket-200,
  7650. pEapOutput,
  7651. &EapTypeInput
  7652. );
  7653. }
  7654. }
  7655. else
  7656. {
  7657. ZeroMemory ( &EapTypeInput, sizeof(EapTypeInput) );
  7658. if ( pEapInput )
  7659. {
  7660. CopyMemory( &EapTypeInput, pEapInput, sizeof(EapTypeInput) );
  7661. }
  7662. else
  7663. {
  7664. EapTypeInput.fFlags = RAS_EAP_FLAG_NON_INTERACTIVE;
  7665. EapTypeInput.fAuthenticator = TRUE;
  7666. }
  7667. FFormatUserIdentity ( pPeapCb->awszTypeIdentity, &EapTypeInput.pwszIdentity );
  7668. if ( pReceivePacket )
  7669. {
  7670. CopyMemory ( pReceivePacket->Data,
  7671. pPeapCb->pbIoBuffer,
  7672. pPeapCb->dwIoBufferLen
  7673. );
  7674. HostToWireFormat16 ( (WORD)(sizeof(PPP_EAP_PACKET) + pPeapCb->dwIoBufferLen -1),
  7675. pReceivePacket->Length
  7676. );
  7677. }
  7678. dwRetCode = pPeapCb->pEapInfo->PppEapInfo.RasEapMakeMessage
  7679. ( pPeapCb->pEapInfo->pWorkBuf,
  7680. pReceivePacket,
  7681. pSendPacket,
  7682. cbSendPacket-200,
  7683. pEapOutput,
  7684. &EapTypeInput
  7685. );
  7686. if ( EapTypeInput.pwszIdentity )
  7687. LocalFree ( EapTypeInput.pwszIdentity );
  7688. }
  7689. if ( NO_ERROR == dwRetCode )
  7690. {
  7691. //
  7692. // Need to translate ActionSendDone to ActionSend and then send peap
  7693. // success.
  7694. //
  7695. if ( pEapOutput->Action == EAPACTION_SendAndDone )
  7696. {
  7697. //
  7698. // If the code is request or response, send the data across
  7699. // and save our state in the context. If it is success or fail
  7700. // there is no data to send back so the following logic will
  7701. // work.
  7702. //
  7703. if ( pSendPacket->Code == EAPCODE_Request )
  7704. {
  7705. EapTlsTrace ("Invalid Code EAPCODE_Request send for Action Send and Done");
  7706. //
  7707. // Auth fails here. We cannot handle EAPCODE_Request yet.
  7708. //
  7709. dwRetCode = ERROR_PPP_INVALID_PACKET;
  7710. break;
  7711. }
  7712. }
  7713. if ( pSendPacket->Code == EAPCODE_Success )
  7714. {
  7715. //
  7716. // Send a PEAP success TLV here.
  7717. // We need to do this so that
  7718. // the client does not think he is spoofed.
  7719. //
  7720. dwRetCode = CreatePEAPTLVStatusMessage ( pPeapCb,
  7721. pSendPacket,
  7722. cbSendPacket,
  7723. TRUE,
  7724. MS_PEAP_AVP_VALUE_SUCCESS
  7725. );
  7726. if ( NO_ERROR != dwRetCode )
  7727. {
  7728. //
  7729. // This is an internal error. So we cannot send
  7730. // a PEAP_Failure here
  7731. //
  7732. break;
  7733. }
  7734. //
  7735. // Append any user attributes returned by embedded
  7736. // EAP method to pPeapCb->pTlsUserAttributes so that
  7737. // they can be send back to IAS once auth is done
  7738. PeapSetTypeUserAttributes ( pPeapCb, pEapOutput->pUserAttributes );
  7739. pEapOutput->pUserAttributes = NULL;
  7740. pEapOutput->Action = EAPACTION_SendWithTimeoutInteractive;
  7741. pPeapCb->PeapState = PEAP_STATE_PEAP_SUCCESS_SEND;
  7742. pPeapCb->dwAuthResultCode = pEapOutput->dwAuthResultCode;
  7743. }
  7744. else if ( pSendPacket->Code == EAPCODE_Failure )
  7745. {
  7746. //
  7747. // Send a PEAP failure TLV here.
  7748. // We need to do this so that
  7749. // the client does not think he is spoofed.
  7750. //
  7751. dwRetCode = CreatePEAPTLVStatusMessage (pPeapCb,
  7752. pSendPacket,
  7753. cbSendPacket,
  7754. TRUE,
  7755. MS_PEAP_AVP_VALUE_FAILURE
  7756. );
  7757. if ( NO_ERROR != dwRetCode )
  7758. {
  7759. //
  7760. // This is an internal error. So we cannot send
  7761. // a PEAP_Failure here
  7762. //
  7763. break;
  7764. }
  7765. pEapOutput->Action = EAPACTION_SendWithTimeoutInteractive;
  7766. pPeapCb->PeapState = PEAP_STATE_PEAP_FAIL_SEND;
  7767. pPeapCb->dwAuthResultCode = pEapOutput->dwAuthResultCode;
  7768. }
  7769. else if ( pEapOutput->Action == EAPACTION_Authenticate )
  7770. {
  7771. //
  7772. // do nothing here. We are passing this on to RADIUS as is
  7773. //
  7774. }
  7775. else
  7776. {
  7777. //This is an action send
  7778. wPacketLength = WireToHostFormat16(pSendPacket->Length);
  7779. dwRetCode = PeapEncryptTunnelData ( pPeapCb,
  7780. &(pSendPacket->Data[0]),
  7781. wPacketLength - sizeof(PPP_EAP_PACKET)+1
  7782. );
  7783. pSendPacket->Data[0] = PPP_EAP_PEAP;
  7784. pSendPacket->Data[1] = EAPTLS_PACKET_CURRENT_VERSION;
  7785. CopyMemory ( &(pSendPacket->Data[2]),
  7786. pPeapCb->pbIoBuffer,
  7787. pPeapCb->dwIoBufferLen
  7788. );
  7789. pPeapCb->bId = pSendPacket->Id;
  7790. wPacketLength = (WORD)(sizeof(PPP_EAP_PACKET) + 1+ pPeapCb->dwIoBufferLen);
  7791. HostToWireFormat16
  7792. ( wPacketLength,
  7793. pSendPacket->Length
  7794. );
  7795. }
  7796. }
  7797. }
  7798. break;
  7799. case PEAP_STATE_EAP_TYPE_FINISHED:
  7800. EapTlsTrace("PEAP:PEAP_STATE_EAP_TYPE_FINISHED");
  7801. break;
  7802. case PEAP_STATE_PEAP_SUCCESS_SEND:
  7803. EapTlsTrace("PEAP:PEAP_STATE_PEAP_SUCCESS_SEND");
  7804. //
  7805. // We have send PEAP_SUCCESS TLV inside the protected channel
  7806. // So the only thing we should expect is a PEAP_SUCCESS TLV response
  7807. // or a PEAP_FAILURE
  7808. // If we get a PEAP_SUCCESS response back, then send back EAP_SUCCESS
  7809. // with EAP_Done action.
  7810. //
  7811. if ( pReceivePacket &&
  7812. pReceivePacket->Code != EAPCODE_Response &&
  7813. pReceivePacket->Id != pPeapCb->bId
  7814. )
  7815. {
  7816. EapTlsTrace("Received packet with some other code than response or the id does not match. Ignoring packet");
  7817. pEapOutput->Action = EAPACTION_NoAction;
  7818. }
  7819. else
  7820. {
  7821. WORD wValue =0;
  7822. if ( pReceivePacket )
  7823. {
  7824. dwRetCode = PeapDecryptTunnelData ( pPeapCb,
  7825. &(pReceivePacket->Data[2]),
  7826. WireToHostFormat16(pReceivePacket->Length)
  7827. - (sizeof(PPP_EAP_PACKET)+1)
  7828. );
  7829. if ( NO_ERROR != dwRetCode )
  7830. {
  7831. // We could not decrypt the tunnel traffic
  7832. // So we silently discard this packet.
  7833. EapTlsTrace("PeapDecryptTunnelData failed: silently discarding packet");
  7834. dwRetCode = NO_ERROR;
  7835. pEapOutput->Action = EAPACTION_NoAction;
  7836. break;
  7837. }
  7838. CopyMemory ( &(pReceivePacket->Data[2]),
  7839. pPeapCb->pbIoBuffer,
  7840. pPeapCb->dwIoBufferLen
  7841. );
  7842. wPacketLength = WireToHostFormat16(pReceivePacket->Length);
  7843. }
  7844. if ( GetPEAPTLVStatusMessageValue ( pPeapCb,
  7845. pReceivePacket,
  7846. &wValue
  7847. ) == ERROR_PPP_INVALID_PACKET
  7848. )
  7849. {
  7850. EapTlsTrace ("Got invalid packet when expecting TLV SUCCESS. Silently discarding packet.");
  7851. dwRetCode = NO_ERROR;
  7852. pEapOutput->Action = EAPACTION_NoAction;
  7853. break;
  7854. }
  7855. if ( wValue == MS_PEAP_AVP_VALUE_SUCCESS )
  7856. {
  7857. //
  7858. // If we're enabled for fast reconnect, setup the cookie in the session
  7859. // so that we can consume it later
  7860. //
  7861. if ( pPeapCb->dwFlags & PEAPCB_FAST_ROAMING )
  7862. {
  7863. dwRetCode = PeapCreateCookie ( pPeapCb,
  7864. &pbCookie,
  7865. &cbCookie
  7866. );
  7867. if ( NO_ERROR != dwRetCode )
  7868. {
  7869. EapTlsTrace("Failed to create session cookie. Resetting fast reconnect");
  7870. dwRetCode = SetTLSFastReconnect ( pPeapCb->pEapTlsCB , FALSE);
  7871. if ( NO_ERROR != dwRetCode )
  7872. {
  7873. //
  7874. // This is an internal error
  7875. // So disconnect the session.
  7876. //
  7877. pEapOutput->dwAuthResultCode = dwRetCode;
  7878. pEapOutput->Action = EAPACTION_Done;
  7879. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  7880. break;
  7881. }
  7882. }
  7883. dwRetCode = SetTLSSessionCookie ( pPeapCb->pEapTlsCB ,
  7884. pbCookie,
  7885. cbCookie
  7886. );
  7887. if ( NO_ERROR != dwRetCode )
  7888. {
  7889. EapTlsTrace("Failed to create session cookie. Resetting fast reconnect");
  7890. dwRetCode = SetTLSFastReconnect ( pPeapCb->pEapTlsCB , FALSE);
  7891. if ( NO_ERROR != dwRetCode )
  7892. {
  7893. //
  7894. // This is an internal error
  7895. // So disconnect the session.
  7896. //
  7897. pEapOutput->dwAuthResultCode = dwRetCode;
  7898. pEapOutput->Action = EAPACTION_Done;
  7899. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  7900. break;
  7901. }
  7902. }
  7903. }
  7904. pSendPacket->Code = EAPCODE_Success;
  7905. }
  7906. else if ( wValue == MS_PEAP_AVP_VALUE_FAILURE )
  7907. {
  7908. pPeapCb->fFastReconnectedSession = FALSE;
  7909. if ( pPeapCb->fSendTLVSuccessforFastRoaming )
  7910. {
  7911. //
  7912. // We got a failure because the client does not support fast roaming.
  7913. //
  7914. // Send encrypted identity request.
  7915. // This is not good. We need to review and cleanup code
  7916. // and make common functions.
  7917. pPeapCb->fSendTLVSuccessforFastRoaming = FALSE;
  7918. pSendPacket->Code = EAPCODE_Request;
  7919. pSendPacket->Id = ++ pPeapCb->bId;
  7920. pSendPacket->Data[0] = PPP_EAP_PEAP;
  7921. pSendPacket->Data[1] = EAPTLS_PACKET_CURRENT_VERSION;
  7922. pSendPacket->Data[2] = PEAP_EAPTYPE_IDENTITY;
  7923. //
  7924. // Identity request needs to be encrypted.
  7925. //
  7926. dwRetCode = PeapEncryptTunnelData ( pPeapCb,
  7927. &(pSendPacket->Data[2]),
  7928. 1
  7929. );
  7930. if ( NO_ERROR != dwRetCode )
  7931. {
  7932. break;
  7933. }
  7934. CopyMemory ( &(pSendPacket->Data[2]),
  7935. pPeapCb->pbIoBuffer,
  7936. pPeapCb->dwIoBufferLen
  7937. );
  7938. HostToWireFormat16
  7939. (
  7940. (WORD)(sizeof(PPP_EAP_PACKET)+1 + pPeapCb->dwIoBufferLen),
  7941. pSendPacket->Length
  7942. );
  7943. pEapOutput->Action = EAPACTION_SendWithTimeoutInteractive;
  7944. pPeapCb->PeapState = PEAP_STATE_IDENTITY_REQUEST_SENT;
  7945. break;
  7946. }
  7947. else
  7948. {
  7949. EapTlsTrace ("Got TLV_Failure when expecting TLV SUCCESS. Failing Auth.");
  7950. pSendPacket->Code = EAPCODE_Failure;
  7951. }
  7952. }
  7953. else
  7954. {
  7955. EapTlsTrace ("Got invalid packet when expecting TLV SUCCESS. Silently discarding packet.");
  7956. dwRetCode = NO_ERROR;
  7957. pEapOutput->Action = EAPACTION_NoAction;
  7958. break;
  7959. }
  7960. pSendPacket->Id = ++ pPeapCb->bId;
  7961. HostToWireFormat16( 4, pSendPacket->Length);
  7962. //
  7963. // Now we're done with Auth. So send back a EAP_Success
  7964. //
  7965. //We are done with auth. No need to encrypt the packet here
  7966. pEapOutput->Action = EAPACTION_SendAndDone;
  7967. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  7968. pEapOutput->dwAuthResultCode = pPeapCb->dwAuthResultCode;
  7969. if ( pEapOutput->dwAuthResultCode == NO_ERROR )
  7970. {
  7971. // Add Peap Specific attributes and
  7972. // return back the MPPE keys
  7973. PeapAddContextAttributes(pPeapCb );
  7974. //
  7975. // Add only non-key attributes to the
  7976. //
  7977. RasAuthAttributeConcat( pPeapCb->pTlsUserAttributes,
  7978. pPeapCb->pTypeUserAttributes,
  7979. &(pPeapCb->pFinalUserAttributes)
  7980. );
  7981. pEapOutput->pUserAttributes = pPeapCb->pFinalUserAttributes;
  7982. }
  7983. }
  7984. break;
  7985. case PEAP_STATE_PEAP_FAIL_SEND:
  7986. EapTlsTrace("PEAP:PEAP_STATE_PEAP_FAIL_SEND");
  7987. //
  7988. // We have send PEAP_FAIL TLV inside the protected channel
  7989. // So the only thing we should expect is a PEAP_FAILURE TLV response
  7990. // Send back a EAP_FAIL with EAP_Done action.
  7991. //
  7992. //
  7993. // We have send PEAP_SUCCESS TLV inside the protected channel
  7994. // So the only thing we should expect is a PEAP_SUCCESS TLV response
  7995. // or a PEAP_FAILURE
  7996. // If we get a PEAP_SUCCESS response back, then send back EAP_SUCCESS
  7997. // with EAP_Done action.
  7998. //
  7999. if ( pReceivePacket &&
  8000. pReceivePacket->Code != EAPCODE_Response &&
  8001. pReceivePacket->Id != pPeapCb->bId
  8002. )
  8003. {
  8004. EapTlsTrace("Received packet with some other code than response or the id does not match. Ignoring packet");
  8005. pEapOutput->Action = EAPACTION_NoAction;
  8006. }
  8007. else
  8008. {
  8009. WORD wValue =0;
  8010. if ( pReceivePacket )
  8011. {
  8012. dwRetCode = PeapDecryptTunnelData ( pPeapCb,
  8013. &(pReceivePacket->Data[2]),
  8014. WireToHostFormat16(pReceivePacket->Length)
  8015. - (sizeof(PPP_EAP_PACKET)+1)
  8016. );
  8017. if ( NO_ERROR != dwRetCode )
  8018. {
  8019. // We could not decrypt the tunnel traffic
  8020. // So we silently discard this packet.
  8021. EapTlsTrace("PeapDecryptTunnelData failed: silently discarding packet");
  8022. dwRetCode = NO_ERROR;
  8023. pEapOutput->Action = EAPACTION_NoAction;
  8024. break;
  8025. }
  8026. CopyMemory ( &(pReceivePacket->Data[2]),
  8027. pPeapCb->pbIoBuffer,
  8028. pPeapCb->dwIoBufferLen
  8029. );
  8030. wPacketLength = WireToHostFormat16(pReceivePacket->Length);
  8031. }
  8032. if ( GetPEAPTLVStatusMessageValue ( pPeapCb,
  8033. pReceivePacket,
  8034. &wValue
  8035. ) == ERROR_PPP_INVALID_PACKET
  8036. )
  8037. {
  8038. EapTlsTrace ("Got invalid packet when expecting TLV FAIL response. Silently discarding packet.");
  8039. dwRetCode = NO_ERROR;
  8040. pEapOutput->Action = EAPACTION_NoAction;
  8041. break;
  8042. }
  8043. if ( wValue != MS_PEAP_AVP_VALUE_FAILURE )
  8044. {
  8045. EapTlsTrace ("Got invalid packet when expecting TLV FAILURE response. Silently discarding packet.");
  8046. dwRetCode = NO_ERROR;
  8047. pEapOutput->Action = EAPACTION_NoAction;
  8048. break;
  8049. }
  8050. //
  8051. // Now we're done with Auth. So send back a EAP_Failure
  8052. //
  8053. pSendPacket->Code = EAPCODE_Failure;
  8054. pSendPacket->Id = ++ pPeapCb->bId;
  8055. HostToWireFormat16( 4, pSendPacket->Length);
  8056. pEapOutput->Action = EAPACTION_SendAndDone;
  8057. pPeapCb->PeapState = PEAP_STATE_EAP_TYPE_FINISHED;
  8058. pEapOutput->dwAuthResultCode = pPeapCb->dwAuthResultCode;
  8059. }
  8060. break;
  8061. #if 0
  8062. /*
  8063. case PEAP_STATE_REQUEST_SENDANDDONE:
  8064. EapTlsTrace("PEAP:PEAP_STATE_REQUEST_SENDANDDONE");
  8065. break;
  8066. */
  8067. #endif
  8068. default:
  8069. EapTlsTrace("PEAP:Invalid state");
  8070. }
  8071. if ( pbCookie )
  8072. LocalFree (pbCookie);
  8073. EapTlsTrace("EapPeapSMakeMessage done");
  8074. return dwRetCode;
  8075. }
  8076. BOOL FValidPeapPacket ( EAPTLS_PACKET * pReceivePacket )
  8077. {
  8078. BOOL fRet = FALSE;
  8079. WORD wLength;
  8080. if ( NULL == pReceivePacket )
  8081. {
  8082. fRet = TRUE;
  8083. goto done;
  8084. }
  8085. wLength = WireToHostFormat16( pReceivePacket->pbLength );
  8086. switch (pReceivePacket->bCode)
  8087. {
  8088. case EAPCODE_Success:
  8089. case EAPCODE_Failure:
  8090. if (PPP_EAP_PACKET_HDR_LEN != wLength)
  8091. {
  8092. EapTlsTrace("PEAP Success/Fail packet has length %d",
  8093. wLength);
  8094. return(FALSE);
  8095. }
  8096. break;
  8097. case EAPCODE_Request:
  8098. case EAPCODE_Response:
  8099. if (PPP_EAP_PEAP != pReceivePacket->bType &&
  8100. pReceivePacket->bType != PEAP_EAPTYPE_IDENTITY &&
  8101. pReceivePacket->bType != PEAP_EAPTYPE_NAK
  8102. )
  8103. {
  8104. // We are not concerned with this packet. It is not TLS.
  8105. EapTlsTrace("Got packet with type id other than PEAP and identity.");
  8106. goto done;
  8107. }
  8108. break;
  8109. }
  8110. fRet = TRUE;
  8111. done:
  8112. return fRet;
  8113. }
  8114. DWORD
  8115. EapPeapMakeMessage(
  8116. IN PPEAPCB pPeapCb,
  8117. IN PPP_EAP_PACKET* pInput,
  8118. OUT PPP_EAP_PACKET* pOutput,
  8119. IN DWORD cbSendPacket,
  8120. OUT PPP_EAP_OUTPUT* pEapOutput,
  8121. IN PPP_EAP_INPUT* pEapInput
  8122. )
  8123. {
  8124. DWORD dwRetCode = NO_ERROR;
  8125. EapTlsTrace("EapPeapMakeMessage");
  8126. //
  8127. // Inititally this will start as eaptls
  8128. // and then will go into each PEAP type configured.
  8129. // For this release we have only eapmschap v2
  8130. //
  8131. if (!FValidPeapPacket((EAPTLS_PACKET *)pInput))
  8132. {
  8133. pEapOutput->Action = EAPACTION_NoAction;
  8134. return(ERROR_PPP_INVALID_PACKET);
  8135. }
  8136. if (pPeapCb->dwFlags & PEAPCB_FLAG_SERVER)
  8137. {
  8138. dwRetCode = EapPeapSMakeMessage( pPeapCb,
  8139. pInput,
  8140. pOutput,
  8141. cbSendPacket,
  8142. pEapOutput,
  8143. pEapInput
  8144. );
  8145. }
  8146. else
  8147. {
  8148. dwRetCode = EapPeapCMakeMessage( pPeapCb,
  8149. pInput,
  8150. pOutput,
  8151. cbSendPacket,
  8152. pEapOutput,
  8153. pEapInput
  8154. );
  8155. }
  8156. EapTlsTrace("EapPeapMakeMessage done");
  8157. return dwRetCode;
  8158. }
  8159. DWORD CreatePEAPTLVNAKMessage ( PPEAPCB pPeapCb,
  8160. PPP_EAP_PACKET * pPacket,
  8161. DWORD cbPacket
  8162. )
  8163. {
  8164. DWORD dwRetCode = NO_ERROR;
  8165. EapTlsTrace("CreatePEAPTLVNAKMessage");
  8166. pPacket->Code = EAPCODE_Response ;
  8167. pPacket->Id = pPeapCb->bId ;
  8168. //
  8169. // The format of this packet is following:
  8170. // Code = Request/Response
  8171. // Id
  8172. // Length
  8173. // Data[0] = Type = PPP_EAP_PEAP
  8174. // Data[1] = Flags + Version
  8175. //
  8176. //Data[2]Code - Request/Response
  8177. //3 Id - Can be same as outer Id
  8178. //4,5 Length - Length this packet
  8179. //6 Type - PEAP_TYPE_AVP
  8180. //7,8 Type - High Bit is set to Mandatory if it is so ( 2 octets )
  8181. //9,10 Length - 2 octets
  8182. //11... Value
  8183. //
  8184. //
  8185. // pPacket->Length is set below.
  8186. //
  8187. pPacket->Data[0] = (BYTE)PPP_EAP_PEAP;
  8188. pPacket->Data[1] = EAPTLS_PACKET_CURRENT_VERSION;
  8189. pPacket->Data[2] = EAPCODE_Response;
  8190. pPacket->Data[3] = pPacket->Id;
  8191. // Data 3 and 4 will have the length of inner packet.
  8192. //
  8193. HostToWireFormat16 ( 7, &(pPacket->Data[4]) );
  8194. pPacket->Data[6] = (BYTE)PEAP_TYPE_AVP;
  8195. pPacket->Data[7] = PEAP_AVP_FLAG_MANDATORY;
  8196. pPacket->Data[8] = PEAP_EAPTYPE_NAK;
  8197. //
  8198. // Encrypt the TLV part of the packet
  8199. //
  8200. dwRetCode = PeapEncryptTunnelData ( pPeapCb,
  8201. &(pPacket->Data[2]),
  8202. 7
  8203. );
  8204. if ( NO_ERROR != dwRetCode )
  8205. {
  8206. return dwRetCode;
  8207. }
  8208. CopyMemory ( &(pPacket->Data[2]),
  8209. pPeapCb->pbIoBuffer,
  8210. pPeapCb->dwIoBufferLen
  8211. );
  8212. HostToWireFormat16
  8213. (
  8214. (WORD)(sizeof(PPP_EAP_PACKET)+ 1 + pPeapCb->dwIoBufferLen),
  8215. pPacket->Length
  8216. );
  8217. return dwRetCode;
  8218. }
  8219. // Format:
  8220. // Code - Request/Resp
  8221. // Id
  8222. // Type - PEAP
  8223. // Method - PEAP_TLV
  8224. // TLV - Type - PEAPSuccess/PEAPFailure
  8225. // Flags -
  8226. // Length -
  8227. // Value -
  8228. //
  8229. DWORD CreatePEAPTLVStatusMessage ( PPEAPCB pPeapCb,
  8230. PPP_EAP_PACKET * pPacket,
  8231. DWORD cbPacket,
  8232. BOOL fRequest,
  8233. WORD wValue //Success or Failure
  8234. )
  8235. {
  8236. DWORD dwRetCode = NO_ERROR;
  8237. EapTlsTrace("CreatePEAPTLVStatusMessage");
  8238. pPacket->Code = ( fRequest ? EAPCODE_Request : EAPCODE_Response );
  8239. pPacket->Id = ( fRequest ? ++ pPeapCb->bId : pPeapCb->bId );
  8240. //
  8241. // The format of this packet is following:
  8242. // Code = Request/Response
  8243. // Id
  8244. // Length
  8245. // Data[0] = Type = PPP_EAP_PEAP
  8246. // Data[1] = Flags + Version
  8247. //
  8248. //Data[2]Code - Request/Response
  8249. //3 Id - Can be same as outer Id
  8250. //4,5 Length - Length this packet
  8251. //6 Type - PEAP_TYPE_AVP
  8252. //7,8 Type - High Bit is set to Mandatory if it is so ( 2 octets )
  8253. //9,10 Length - 2 octets
  8254. //11... Value
  8255. //
  8256. //
  8257. // pPacket->Length is set below.
  8258. //
  8259. pPacket->Data[0] = (BYTE)PPP_EAP_PEAP;
  8260. pPacket->Data[1] = EAPTLS_PACKET_CURRENT_VERSION;
  8261. pPacket->Data[2] = ( fRequest ? EAPCODE_Request : EAPCODE_Response );
  8262. pPacket->Data[3] = pPacket->Id;
  8263. // Data 3 and 4 will have the length of inner packet.
  8264. //
  8265. HostToWireFormat16 ( 11, &(pPacket->Data[4]) );
  8266. pPacket->Data[6] = (BYTE)PEAP_TYPE_AVP;
  8267. pPacket->Data[7] = PEAP_AVP_FLAG_MANDATORY;
  8268. pPacket->Data[8] = MS_PEAP_AVP_TYPE_STATUS;
  8269. //Value Size
  8270. HostToWireFormat16 ( 2, &(pPacket->Data[9]) );
  8271. //Value
  8272. HostToWireFormat16 ( wValue, &(pPacket->Data[11]) );
  8273. //
  8274. // Encrypt the TLV part of the packet
  8275. //
  8276. dwRetCode = PeapEncryptTunnelData ( pPeapCb,
  8277. &(pPacket->Data[2]),
  8278. 11
  8279. );
  8280. if ( NO_ERROR != dwRetCode )
  8281. {
  8282. return dwRetCode;
  8283. }
  8284. CopyMemory ( &(pPacket->Data[2]),
  8285. pPeapCb->pbIoBuffer,
  8286. pPeapCb->dwIoBufferLen
  8287. );
  8288. HostToWireFormat16
  8289. (
  8290. (WORD)(sizeof(PPP_EAP_PACKET)+ 1 + pPeapCb->dwIoBufferLen),
  8291. pPacket->Length
  8292. );
  8293. return dwRetCode;
  8294. }
  8295. //
  8296. // Check to see if this packet is other than success/fail
  8297. // TLV
  8298. //
  8299. BOOL fIsPEAPTLVMessage ( PPEAPCB pPeapCb,
  8300. PPP_EAP_PACKET * pPacket
  8301. )
  8302. {
  8303. WORD wPacketLength = WireToHostFormat16 ( pPacket->Length );
  8304. if ( wPacketLength < 6 )
  8305. return FALSE;
  8306. if ( pPacket->Data[6] != PEAP_TYPE_AVP )
  8307. return FALSE;
  8308. //minimum length required to hold at least one success/fail tlv
  8309. if ( wPacketLength > 17 )
  8310. {
  8311. if ( pPacket->Data[8] != MS_PEAP_AVP_TYPE_STATUS )
  8312. {
  8313. //Save the Id for response
  8314. if ( pPacket->Code == EAPCODE_Request )
  8315. pPeapCb->bId = pPacket->Id;
  8316. return TRUE;
  8317. }
  8318. }
  8319. return ( FALSE);
  8320. }
  8321. DWORD GetPEAPTLVStatusMessageValue ( PPEAPCB pPeapCb,
  8322. PPP_EAP_PACKET * pPacket,
  8323. WORD * pwValue
  8324. )
  8325. {
  8326. DWORD dwRetCode = ERROR_PPP_INVALID_PACKET;
  8327. WORD wLength = 0;
  8328. EapTlsTrace("GetPEAPTLVStatusMessageValue");
  8329. //
  8330. // Check to see if this is a status message
  8331. //
  8332. //
  8333. // The format of this packet is following:
  8334. // Code = Request/Response
  8335. // Id
  8336. // Length
  8337. // Data[0] = Type = PPP_EAP_PEAP
  8338. // Data[1] = Flags + Version
  8339. //
  8340. //Data[2]Code - Request/Response
  8341. //3 Id - Can be same as outer Id
  8342. //4,5 Length - Length this packet
  8343. //6 Type - PEAP_TYPE_AVP
  8344. //7,8 Type - High Bit is set to Mandatory if it is so ( 2 octets )
  8345. //9,10 Length - 2 octets
  8346. //11... Value
  8347. //
  8348. if ( pPacket->Data[0] != (BYTE)PPP_EAP_PEAP )
  8349. {
  8350. goto done;
  8351. }
  8352. if ( pPacket->Data[2] != EAPCODE_Request && pPacket->Data[2] != EAPCODE_Response )
  8353. {
  8354. goto done;
  8355. }
  8356. if ( pPacket->Data[6] != PEAP_TYPE_AVP )
  8357. {
  8358. goto done;
  8359. }
  8360. if ( pPacket->Data[8] != MS_PEAP_AVP_TYPE_STATUS )
  8361. {
  8362. goto done;
  8363. }
  8364. *pwValue = WireToHostFormat16 (&(pPacket->Data[11]));
  8365. //Save the Id for response
  8366. if ( pPacket->Code == EAPCODE_Request )
  8367. pPeapCb->bId = pPacket->Id;
  8368. dwRetCode = NO_ERROR;
  8369. done:
  8370. return dwRetCode;
  8371. }
  8372. //
  8373. // PEAP cookie management functions
  8374. //
  8375. // Create a new cookie to store in cached session
  8376. //
  8377. DWORD PeapCreateCookie ( PPEAPCB pPeapCb,
  8378. PBYTE * ppbCookie,
  8379. DWORD * pcbCookie
  8380. )
  8381. {
  8382. DWORD dwRetCode = NO_ERROR;
  8383. DWORD wCookieSize = 0;
  8384. PPEAP_COOKIE pCookie = NULL;
  8385. RAS_AUTH_ATTRIBUTE * pAttribute = pPeapCb->pTlsUserAttributes;
  8386. EapTlsTrace("PeapCreateCookie");
  8387. wCookieSize = sizeof(PEAP_COOKIE);
  8388. if ( pPeapCb->dwFlags & PEAPCB_FLAG_SERVER )
  8389. {
  8390. wCookieSize += pPeapCb->pUserProp->dwSize;
  8391. }
  8392. else
  8393. {
  8394. wCookieSize += pPeapCb->pConnProp->dwSize;
  8395. }
  8396. pCookie = (PPEAP_COOKIE)LocalAlloc (LPTR, wCookieSize);
  8397. if ( NULL == pCookie )
  8398. {
  8399. EapTlsTrace ("Error allocating cookie");
  8400. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  8401. goto done;
  8402. }
  8403. wcscpy ( pCookie->awszIdentity,
  8404. pPeapCb->awszIdentity
  8405. );
  8406. if ( pPeapCb->dwFlags & PEAPCB_FLAG_SERVER )
  8407. {
  8408. CopyMemory ( pCookie->Data, pPeapCb->pUserProp, pPeapCb->pUserProp->dwSize );
  8409. }
  8410. else
  8411. {
  8412. CopyMemory ( pCookie->Data, pPeapCb->pConnProp, pPeapCb->pConnProp->dwSize );
  8413. }
  8414. *ppbCookie = (PBYTE)pCookie;
  8415. *pcbCookie = wCookieSize;
  8416. done:
  8417. return dwRetCode;
  8418. }
  8419. //
  8420. // Verify current information against the cached
  8421. // cookie
  8422. //
  8423. DWORD PeapCheckCookie ( PPEAPCB pPeapCb,
  8424. PEAP_COOKIE *pCookie,
  8425. DWORD cbCookie
  8426. )
  8427. {
  8428. DWORD dwRetCode = NO_ERROR;
  8429. PEAP_CONN_PROP * pCookieConnProp;
  8430. PEAP_USER_PROP * pCookieUserProp;
  8431. EapTlsTrace ( "PeapCheckCookie");
  8432. //
  8433. // Check to see if the saved and configured PEAP info matches
  8434. //
  8435. if ( pPeapCb->dwFlags & PEAPCB_FLAG_SERVER )
  8436. {
  8437. pCookieUserProp = (PEAP_USER_PROP *)pCookie->Data;
  8438. if ( pCookieUserProp->dwSize != pPeapCb->pUserProp->dwSize )
  8439. {
  8440. EapTlsTrace ("Server config changed since the cookie was cached. Failing auth");
  8441. dwRetCode = ERROR_INVALID_PEAP_COOKIE_CONFIG;
  8442. goto done;
  8443. }
  8444. if ( memcmp ( pCookieUserProp, pPeapCb->pUserProp, pPeapCb->pUserProp->dwSize ) )
  8445. {
  8446. EapTlsTrace ("Server config changed since the cookie was cached. Failing auth");
  8447. dwRetCode = ERROR_INVALID_PEAP_COOKIE_CONFIG;
  8448. goto done;
  8449. }
  8450. }
  8451. else
  8452. {
  8453. pCookieConnProp = (PEAP_CONN_PROP *)pCookie->Data;
  8454. if ( pCookieConnProp->dwSize != pPeapCb->pConnProp->dwSize )
  8455. {
  8456. EapTlsTrace ("Connection Properties changed since the cookie was cached. Failing auth");
  8457. dwRetCode = ERROR_INVALID_PEAP_COOKIE_CONFIG;
  8458. goto done;
  8459. }
  8460. if ( memcmp ( pCookieConnProp, pPeapCb->pConnProp, pPeapCb->pConnProp->dwSize ) )
  8461. {
  8462. EapTlsTrace ("Connection Properties changed since the cookie was cached. Failing auth");
  8463. dwRetCode = ERROR_INVALID_PEAP_COOKIE_CONFIG;
  8464. goto done;
  8465. }
  8466. }
  8467. if ( _wcsicmp ( pCookie->awszIdentity, pPeapCb->awszIdentity ) )
  8468. {
  8469. EapTlsTrace ("Identity in the cookie is %ws and peap got %ws",
  8470. pCookie->awszIdentity,
  8471. pPeapCb->awszIdentity
  8472. );
  8473. dwRetCode = ERROR_INVALID_PEAP_COOKIE_USER;
  8474. goto done;
  8475. }
  8476. //config and Id matches so we are ok.
  8477. done:
  8478. return dwRetCode;
  8479. }
  8480. //phew! This code needs to be revamped very soon.
  8481. DWORD
  8482. PeapGetCredentials(
  8483. IN VOID * pWorkBuf,
  8484. OUT VOID ** ppCredentials)
  8485. {
  8486. PEAPCB *pPeapCb = (PEAPCB *) pWorkBuf;
  8487. DWORD dwRetCode;
  8488. if(NULL == pPeapCb)
  8489. {
  8490. return E_INVALIDARG;
  8491. }
  8492. //
  8493. // Redirect the call to the actual peap module.
  8494. //
  8495. if(pPeapCb->pEapInfo->RasEapGetCredentials != NULL)
  8496. {
  8497. return pPeapCb->pEapInfo->RasEapGetCredentials(
  8498. pPeapCb->pEapInfo->dwTypeId,
  8499. pPeapCb->pEapInfo->pWorkBuf,
  8500. ppCredentials);
  8501. }
  8502. return E_NOTIMPL;
  8503. }