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

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