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.

1332 lines
41 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: pct1cli.c
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 09-23-97 jbanes LSA integration stuff.
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <spbase.h>
  18. #include <pct1msg.h>
  19. #include <pct1prot.h>
  20. VOID
  21. Pct1ActivateSessionKeys(PSPContext pContext)
  22. {
  23. if(pContext->hReadKey)
  24. {
  25. if(!SchCryptDestroyKey(pContext->hReadKey,
  26. pContext->RipeZombie->dwCapiFlags))
  27. {
  28. SP_LOG_RESULT(GetLastError());
  29. }
  30. }
  31. pContext->hReadKey = pContext->hPendingReadKey;
  32. if(pContext->hReadMAC)
  33. {
  34. if(!SchCryptDestroyKey(pContext->hReadMAC,
  35. pContext->RipeZombie->dwCapiFlags))
  36. {
  37. SP_LOG_RESULT(GetLastError());
  38. }
  39. }
  40. pContext->hReadMAC = pContext->hPendingReadMAC;
  41. if(pContext->hWriteKey)
  42. {
  43. if(!SchCryptDestroyKey(pContext->hWriteKey,
  44. pContext->RipeZombie->dwCapiFlags))
  45. {
  46. SP_LOG_RESULT(GetLastError());
  47. }
  48. }
  49. pContext->hWriteKey = pContext->hPendingWriteKey;
  50. if(pContext->hWriteMAC)
  51. {
  52. if(!SchCryptDestroyKey(pContext->hWriteMAC,
  53. pContext->RipeZombie->dwCapiFlags))
  54. {
  55. SP_LOG_RESULT(GetLastError());
  56. }
  57. }
  58. pContext->hWriteMAC = pContext->hPendingWriteMAC;
  59. pContext->hPendingReadKey = 0;
  60. pContext->hPendingReadMAC = 0;
  61. pContext->hPendingWriteKey = 0;
  62. pContext->hPendingWriteMAC = 0;
  63. }
  64. SP_STATUS WINAPI
  65. Pct1ClientProtocolHandler(PSPContext pContext,
  66. PSPBuffer pCommInput,
  67. PSPBuffer pCommOutput)
  68. {
  69. SP_STATUS pctRet= PCT_ERR_OK;
  70. DWORD dwStateTransition;
  71. SP_BEGIN("Pct1ClientProtocolHandler");
  72. if(pCommOutput) pCommOutput->cbData = 0;
  73. /* Protocol handling steps should be listed in most common
  74. * to least common in order to improve performance
  75. */
  76. /* We are not connected, so we're doing
  77. * protocol negotiation of some sort. All protocol
  78. * negotiation messages are sent in the clear */
  79. /* There are no branches in the connecting protocol
  80. * state transition diagram, besides connection and error,
  81. * which means that a simple case statement will do */
  82. /* Do we have enough data to determine what kind of message we have */
  83. /* Do we have enough data to determine what kind of message we have, or how much data we need*/
  84. dwStateTransition = (pContext->State & 0xffff);
  85. if(pCommInput->cbData < 3)
  86. {
  87. if(!(dwStateTransition == PCT1_STATE_RENEGOTIATE ||
  88. dwStateTransition == SP_STATE_SHUTDOWN ||
  89. dwStateTransition == SP_STATE_SHUTDOWN_PENDING))
  90. {
  91. pctRet = PCT_INT_INCOMPLETE_MSG;
  92. }
  93. }
  94. else
  95. {
  96. dwStateTransition = (((PUCHAR)pCommInput->pvBuffer)[2]<<16) |
  97. (pContext->State & 0xffff);
  98. }
  99. if(pctRet == PCT_ERR_OK)
  100. {
  101. switch(dwStateTransition)
  102. {
  103. case SP_STATE_SHUTDOWN_PENDING:
  104. // There's no CloseNotify in PCT, so just transition to
  105. // the shutdown state and leave the output buffer empty.
  106. pContext->State = SP_STATE_SHUTDOWN;
  107. break;
  108. case SP_STATE_SHUTDOWN:
  109. return PCT_INT_EXPIRED;
  110. case PCT1_STATE_RENEGOTIATE:
  111. {
  112. SPBuffer In;
  113. SPBuffer Out;
  114. DWORD cbMessage;
  115. BOOL fAllocated = FALSE;
  116. cbMessage = pContext->pHashInfo->cbCheckSum +
  117. pContext->pCipherInfo->dwBlockSize +
  118. sizeof(PCT1_MESSAGE_HEADER_EX) +
  119. PCT1_MAX_CLIENT_HELLO;
  120. /* are we allocating our own memory? */
  121. if(pCommOutput->pvBuffer == NULL)
  122. {
  123. pCommOutput->pvBuffer = SPExternalAlloc(cbMessage);
  124. if (NULL == pCommOutput->pvBuffer)
  125. {
  126. SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
  127. }
  128. fAllocated = TRUE;
  129. pCommOutput->cbBuffer = cbMessage;
  130. }
  131. if(cbMessage > pCommOutput->cbBuffer)
  132. {
  133. if(fAllocated)
  134. {
  135. SPExternalFree(pCommOutput->pvBuffer);
  136. pCommOutput->pvBuffer = NULL;
  137. SP_RETURN(PCT_INT_INTERNAL_ERROR);
  138. }
  139. pCommOutput->cbData = cbMessage;
  140. SP_RETURN(PCT_INT_BUFF_TOO_SMALL);
  141. }
  142. In.pvBuffer = ((char *)pCommOutput->pvBuffer)+3;
  143. In.cbBuffer = pCommOutput->cbBuffer-3;
  144. In.cbData = 1;
  145. ((char *)In.pvBuffer)[0] = PCT1_ET_REDO_CONN;
  146. // Build a Redo Request
  147. pctRet = Pct1EncryptRaw(pContext, &In, pCommOutput, PCT1_ENCRYPT_ESCAPE);
  148. if(pctRet != PCT_ERR_OK)
  149. {
  150. if(fAllocated)
  151. {
  152. SPExternalFree(pCommOutput->pvBuffer);
  153. pCommOutput->pvBuffer = NULL;
  154. }
  155. break;
  156. }
  157. Out.pvBuffer = (char *)pCommOutput->pvBuffer + pCommOutput->cbData;
  158. Out.cbBuffer = pCommOutput->cbBuffer - pCommOutput->cbData;
  159. // Mark context as "unmapped" so that the new keys will get
  160. // passed to the application process once the handshake is
  161. // completed.
  162. pContext->Flags &= ~CONTEXT_FLAG_MAPPED;
  163. if(!SPCacheClone(&pContext->RipeZombie))
  164. {
  165. if(fAllocated)
  166. {
  167. SPExternalFree(pCommOutput->pvBuffer);
  168. pCommOutput->pvBuffer = NULL;
  169. }
  170. SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
  171. }
  172. pctRet = GeneratePct1StyleHello(pContext, &Out);
  173. pCommOutput->cbData += Out.cbData;
  174. break;
  175. }
  176. /* Client receives Server hello */
  177. case (PCT1_MSG_SERVER_HELLO << 16) | UNI_STATE_CLIENT_HELLO:
  178. case (PCT1_MSG_SERVER_HELLO << 16) | PCT1_STATE_CLIENT_HELLO:
  179. {
  180. PPct1_Server_Hello pHello;
  181. /* Attempt to recognize and handle various versions
  182. * of Server hello, start by trying to unpickle the
  183. * oldest, and the next version, until
  184. * one unpickles. Then run the handle code. We can also put
  185. * unpickling and handling code in here for SSL messages */
  186. if(PCT_ERR_OK == (pctRet = Pct1UnpackServerHello(
  187. pCommInput,
  188. &pHello)))
  189. {
  190. /* let's resurrect the zombie session */
  191. if (pHello->RestartOk)
  192. {
  193. pctRet = Pct1CliRestart(pContext, pHello, pCommOutput);
  194. if(PCT_ERR_OK == pctRet)
  195. {
  196. pContext->State = SP_STATE_CONNECTED;
  197. pContext->DecryptHandler = Pct1DecryptHandler;
  198. pContext->Encrypt = Pct1EncryptMessage;
  199. pContext->Decrypt = Pct1DecryptMessage;
  200. pContext->GetHeaderSize = Pct1GetHeaderSize;
  201. }
  202. }
  203. else
  204. {
  205. pContext->RipeZombie->fProtocol = SP_PROT_PCT1_CLIENT;
  206. if(pContext->RipeZombie->hMasterKey != 0)
  207. {
  208. // We've attempted to do a reconnect and the server has
  209. // blown us off. In this case we must use a new and different
  210. // cache entry.
  211. pContext->RipeZombie->ZombieJuju = FALSE;
  212. if(!SPCacheClone(&pContext->RipeZombie))
  213. {
  214. pctRet = SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  215. }
  216. }
  217. if(pctRet == PCT_ERR_OK)
  218. {
  219. pctRet = Pct1CliHandleServerHello(pContext,
  220. pCommInput,
  221. pHello,
  222. pCommOutput);
  223. }
  224. if(PCT_ERR_OK == pctRet)
  225. {
  226. pContext->State = PCT1_STATE_CLIENT_MASTER_KEY;
  227. pContext->DecryptHandler = Pct1DecryptHandler;
  228. pContext->Encrypt = Pct1EncryptMessage; /* ?DCB? */
  229. pContext->Decrypt = Pct1DecryptMessage; /* ?DCB? */
  230. pContext->GetHeaderSize = Pct1GetHeaderSize;
  231. }
  232. }
  233. SPExternalFree(pHello);
  234. }
  235. else if(pctRet != PCT_INT_INCOMPLETE_MSG)
  236. {
  237. pctRet |= PCT_INT_DROP_CONNECTION;
  238. }
  239. if(SP_FATAL(pctRet))
  240. {
  241. pContext->State = PCT1_STATE_ERROR;
  242. }
  243. break;
  244. }
  245. case (PCT1_MSG_SERVER_VERIFY << 16) | PCT1_STATE_CLIENT_MASTER_KEY:
  246. pctRet = Pct1CliHandleServerVerify(pContext,
  247. pCommInput,
  248. pCommOutput);
  249. if(SP_FATAL(pctRet))
  250. {
  251. pContext->State = PCT1_STATE_ERROR;
  252. }
  253. else
  254. {
  255. if(PCT_ERR_OK == pctRet)
  256. {
  257. pContext->State = SP_STATE_CONNECTED;
  258. pContext->DecryptHandler = Pct1DecryptHandler;
  259. pContext->Encrypt = Pct1EncryptMessage;
  260. pContext->Decrypt = Pct1DecryptMessage;
  261. pContext->GetHeaderSize = Pct1GetHeaderSize;
  262. }
  263. /* We received a non-fatal error, so the state doesn't
  264. * change, giving the app time to deal with this */
  265. }
  266. break;
  267. default:
  268. pContext->State = PCT1_STATE_ERROR;
  269. {
  270. pctRet = PCT_INT_ILLEGAL_MSG;
  271. if(((PUCHAR)pCommInput->pvBuffer)[2] == PCT1_MSG_ERROR)
  272. {
  273. /* we received an error message, process it */
  274. pctRet = Pct1HandleError(pContext,
  275. pCommInput,
  276. pCommOutput);
  277. }
  278. else
  279. {
  280. /* we received an unknown error, generate a
  281. * PCT_ERR_ILLEGAL_MESSAGE */
  282. pctRet = Pct1GenerateError(pContext,
  283. pCommOutput,
  284. PCT_ERR_ILLEGAL_MESSAGE,
  285. NULL);
  286. }
  287. }
  288. }
  289. }
  290. if(pctRet & PCT_INT_DROP_CONNECTION)
  291. {
  292. pContext->State &= ~SP_STATE_CONNECTED;
  293. }
  294. SP_RETURN(pctRet);
  295. }
  296. //+---------------------------------------------------------------------------
  297. //
  298. // Function: Pct1CheckForExistingCred
  299. //
  300. // Synopsis: Choose client certificate. Use one of the certificates
  301. // attached to the credential handle if possible. If the
  302. // credential handle is anonymous, then attempt to create
  303. // a default credential.
  304. //
  305. // Notes: This routine is called by the client-side only.
  306. //
  307. // Returns: PCT_ERR_OK
  308. // The function completed successfully. The
  309. // pContext->pActiveClientCred field has been updated to
  310. // point at a suitable client credential.
  311. //
  312. // SEC_E_INCOMPLETE_CREDENTIALS
  313. // No suitable certificate has been found. Notify the
  314. // application.
  315. //
  316. // SEC_I_INCOMPLETE_CREDENTIALS
  317. // No suitable certificate has been found. Attempt an
  318. // anonymous connection.
  319. //
  320. // <other>
  321. // Fatal error.
  322. //
  323. //----------------------------------------------------------------------------
  324. SP_STATUS
  325. Pct1CheckForExistingCred(
  326. PSPContext pContext)
  327. {
  328. SP_STATUS pctRet;
  329. //
  330. // Examine the certificates attached to the credential group and see
  331. // if any of them are suitable.
  332. //
  333. if(pContext->pCredGroup->pCredList)
  334. {
  335. pctRet = SPPickClientCertificate(pContext, SP_EXCH_RSA_PKCS1);
  336. if(pctRet == PCT_ERR_OK)
  337. {
  338. // We found one.
  339. DebugLog((DEB_TRACE, "Application provided suitable client certificate.\n"));
  340. return PCT_ERR_OK;
  341. }
  342. // The credential group contained one or more certificates,
  343. // but none were suitable. Don't even try to find a default
  344. // certificate in this situation.
  345. goto error;
  346. }
  347. //
  348. // Attempt to acquire a default credential.
  349. //
  350. if(pContext->pCredGroup->dwFlags & CRED_FLAG_NO_DEFAULT_CREDS)
  351. {
  352. // Look in credential manager only.
  353. pctRet = AcquireDefaultClientCredential(pContext, TRUE);
  354. }
  355. else
  356. {
  357. // Look in both credential manager and MY certificate store.
  358. pctRet = AcquireDefaultClientCredential(pContext, FALSE);
  359. }
  360. if(pctRet == PCT_ERR_OK)
  361. {
  362. DebugLog((DEB_TRACE, "Default client certificate acquired.\n"));
  363. return PCT_ERR_OK;
  364. }
  365. error:
  366. if(pContext->Flags & CONTEXT_FLAG_NO_INCOMPLETE_CRED_MSG)
  367. {
  368. return SP_LOG_RESULT(SEC_I_INCOMPLETE_CREDENTIALS);
  369. }
  370. else
  371. {
  372. return SP_LOG_RESULT(SEC_E_INCOMPLETE_CREDENTIALS);
  373. }
  374. }
  375. SP_STATUS Pct1CliHandleServerHello(PSPContext pContext,
  376. PSPBuffer pCommInput,
  377. PPct1_Server_Hello pHello,
  378. PSPBuffer pCommOutput)
  379. {
  380. /* error to return to peer */
  381. SP_STATUS pctRet=PCT_ERR_ILLEGAL_MESSAGE;
  382. PSessCacheItem pZombie;
  383. PPct1_Client_Master_Key pCMKey = NULL;
  384. SPBuffer ErrData;
  385. DWORD i, j;
  386. DWORD fMismatch = 0;
  387. DWORD cbClientCert = 0;
  388. PBYTE pbClientCert = NULL;
  389. BYTE MisData[PCT_NUM_MISMATCHES];
  390. CertTypeMap LocalCertEncodingPref[5] ;
  391. DWORD cLocalCertEncodingPref = 0;
  392. BOOL fClientAuth;
  393. PSigInfo pSigInfo = NULL;
  394. DWORD ClientCertSpec = 0;
  395. SP_BEGIN("Pct1CliHandleServerHello");
  396. pCommOutput->cbData = 0;
  397. /* validate the buffer configuration */
  398. ErrData.cbData = 0;
  399. ErrData.pvBuffer = NULL;
  400. ErrData.cbBuffer = 0;
  401. pZombie = pContext->RipeZombie;
  402. #if DBG
  403. DebugLog((DEB_TRACE, "Hello = %x\n", pHello));
  404. DebugLog((DEB_TRACE, " Restart\t%s\n", pHello->RestartOk ? "Yes":"No"));
  405. DebugLog((DEB_TRACE, " ClientAuth\t%s\n",
  406. pHello->ClientAuthReq ? "Yes":"No"));
  407. DebugLog((DEB_TRACE, " Certificate Type\t%x\n", pHello->SrvCertSpec));
  408. DebugLog((DEB_TRACE, " Hash Type\t%x\n", pHello->SrvHashSpec));
  409. DebugLog((DEB_TRACE, " Cipher Type\t%x (%s)\n", pHello->SrvCipherSpec,
  410. DbgGetNameOfCrypto(pHello->SrvCipherSpec)));
  411. DebugLog((DEB_TRACE, " Certificate Len\t%ld\n", pHello->CertificateLen));
  412. #endif
  413. CopyMemory(pContext->pConnectionID,
  414. pHello->ConnectionID,
  415. pHello->cbConnectionID);
  416. pContext->cbConnectionID = pHello->cbConnectionID;
  417. fClientAuth = pHello->ClientAuthReq;
  418. if(fClientAuth)
  419. {
  420. // If we're doing client auth, check to see if we have
  421. // proper credentials.
  422. /* Build a list of cert specs */
  423. for(i=0; i < cPct1CertEncodingPref; i++)
  424. {
  425. for(j=0; j< pHello->cCertSpecs; j++)
  426. {
  427. // Does the client want this cipher type
  428. if(aPct1CertEncodingPref[i].Spec == pHello->pClientCertSpecs[j])
  429. {
  430. LocalCertEncodingPref[cLocalCertEncodingPref].Spec = aPct1CertEncodingPref[i].Spec;
  431. LocalCertEncodingPref[cLocalCertEncodingPref++].dwCertEncodingType = aPct1CertEncodingPref[i].dwCertEncodingType;
  432. break;
  433. }
  434. }
  435. }
  436. // Decide on a signature algorithm.
  437. for(i = 0; i < cPct1LocalSigKeyPref; i++)
  438. {
  439. for(j = 0; j < pHello->cSigSpecs; j++)
  440. {
  441. if(pHello->pClientSigSpecs[j] != aPct1LocalSigKeyPref[i].Spec)
  442. {
  443. continue;
  444. }
  445. pSigInfo = GetSigInfo(pHello->pClientSigSpecs[j]);
  446. if(pSigInfo == NULL) continue;
  447. if((pSigInfo->fProtocol & SP_PROT_PCT1_CLIENT) == 0)
  448. {
  449. continue;
  450. }
  451. break;
  452. }
  453. if(pSigInfo)
  454. {
  455. break;
  456. }
  457. }
  458. // Our PCT implementation only supports RSA client authentication.
  459. pContext->Ssl3ClientCertTypes[0] = SSL3_CERTTYPE_RSA_SIGN;
  460. pContext->cSsl3ClientCertTypes = 1;
  461. pctRet = Pct1CheckForExistingCred(pContext);
  462. if(pctRet == SEC_E_INCOMPLETE_CREDENTIALS)
  463. {
  464. // It's okay to return here as we haven't done anything
  465. // yet. We just need to return this error as a warning.
  466. SP_RETURN(SEC_I_INCOMPLETE_CREDENTIALS);
  467. }
  468. else if(pctRet != PCT_ERR_OK)
  469. {
  470. // Attempt to carry on without a certificate, and hope
  471. // the server doesn't shut us down.
  472. fClientAuth = FALSE;
  473. pSigInfo = NULL;
  474. LogNoClientCertFoundEvent();
  475. }
  476. else
  477. {
  478. // We are doing client auth with a certificate.
  479. // Check to see if we're doing CHAIN based certificates
  480. // by finding the first shared encoding type that matches
  481. // our certificate type.
  482. for(i=0; i < cLocalCertEncodingPref; i++)
  483. {
  484. if(LocalCertEncodingPref[i].dwCertEncodingType == pContext->pActiveClientCred->pCert->dwCertEncodingType)
  485. {
  486. ClientCertSpec = LocalCertEncodingPref[i].Spec;
  487. if(LocalCertEncodingPref[i].Spec == PCT1_CERT_X509_CHAIN)
  488. {
  489. pContext->fCertChainsAllowed = TRUE;
  490. }
  491. break;
  492. }
  493. }
  494. // Get the client certificate chain.
  495. pctRet = SPSerializeCertificate(SP_PROT_PCT1,
  496. pContext->fCertChainsAllowed,
  497. &pbClientCert,
  498. &cbClientCert,
  499. pContext->pActiveClientCred->pCert,
  500. CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL);
  501. if(pctRet != PCT_ERR_OK)
  502. {
  503. SP_RETURN(pctRet);
  504. }
  505. }
  506. }
  507. for(i=0; i < Pct1NumCipher; i++)
  508. {
  509. if(Pct1CipherRank[i].Spec == pHello->SrvCipherSpec)
  510. {
  511. // Store this cipher identifier in the cache
  512. pZombie->aiCipher = Pct1CipherRank[i].aiCipher;
  513. pZombie->dwStrength = Pct1CipherRank[i].dwStrength;
  514. // Load the pending cipher structure.
  515. pContext->pPendingCipherInfo = GetCipherInfo(pZombie->aiCipher,
  516. pZombie->dwStrength);
  517. if(!IsCipherAllowed(pContext,
  518. pContext->pPendingCipherInfo,
  519. pZombie->fProtocol,
  520. pZombie->dwCF))
  521. {
  522. pContext->pPendingCipherInfo = NULL;
  523. continue;
  524. }
  525. break;
  526. }
  527. }
  528. for(i=0; i < Pct1NumHash; i++)
  529. {
  530. if(Pct1HashRank[i].Spec == pHello->SrvHashSpec)
  531. {
  532. // Store this hash id in the cache
  533. pZombie->aiHash = Pct1HashRank[i].aiHash;
  534. // Load the pending hash sturcture
  535. pContext->pPendingHashInfo = GetHashInfo(pZombie->aiHash);
  536. if(!IsHashAllowed(pContext,
  537. pContext->pPendingHashInfo,
  538. pZombie->fProtocol))
  539. {
  540. pContext->pPendingHashInfo = NULL;
  541. continue;
  542. }
  543. break;
  544. }
  545. }
  546. for(i=0; i < cPct1LocalExchKeyPref; i++)
  547. {
  548. if(aPct1LocalExchKeyPref[i].Spec == pHello->SrvExchSpec)
  549. {
  550. // Store the exch id in the cache.
  551. pZombie->SessExchSpec = aPct1LocalExchKeyPref[i].Spec;
  552. // load the exch info structure
  553. pContext->pKeyExchInfo = GetKeyExchangeInfo(pZombie->SessExchSpec);
  554. if(!IsExchAllowed(pContext,
  555. pContext->pKeyExchInfo,
  556. pZombie->fProtocol))
  557. {
  558. pContext->pKeyExchInfo = NULL;
  559. continue;
  560. }
  561. break;
  562. }
  563. }
  564. if (pContext->pPendingCipherInfo == NULL)
  565. {
  566. fMismatch |= PCT_IMIS_CIPHER;
  567. pctRet = SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH);
  568. goto cleanup;
  569. }
  570. if (pContext->pPendingHashInfo == NULL)
  571. {
  572. fMismatch |= PCT_IMIS_HASH;
  573. pctRet = SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH);
  574. goto cleanup;
  575. }
  576. if (pContext->pKeyExchInfo == NULL)
  577. {
  578. fMismatch |= PCT_IMIS_EXCH;
  579. pctRet = SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH);
  580. goto cleanup;
  581. }
  582. // Determine the CSP to use, based on the key exchange algorithm.
  583. if(pContext->pKeyExchInfo->Spec != SP_EXCH_RSA_PKCS1)
  584. {
  585. pctRet = SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH);
  586. goto cleanup;
  587. }
  588. pContext->RipeZombie->hMasterProv = g_hRsaSchannel;
  589. // Go ahead and move the pending ciphers to active, and init them.
  590. pctRet = ContextInitCiphers(pContext, TRUE, TRUE);
  591. if(PCT_ERR_OK != pctRet)
  592. {
  593. goto cleanup;
  594. }
  595. /* we aren't restarting, so let's continue with the protocol. */
  596. /* Crack the server certificate */
  597. pctRet = SPLoadCertificate(pZombie->fProtocol,
  598. X509_ASN_ENCODING,
  599. pHello->pCertificate,
  600. pHello->CertificateLen,
  601. &pZombie->pRemoteCert);
  602. if(pctRet != PCT_ERR_OK)
  603. {
  604. goto cleanup;
  605. }
  606. if(pContext->RipeZombie->pRemotePublic != NULL)
  607. {
  608. SPExternalFree(pContext->RipeZombie->pRemotePublic);
  609. pContext->RipeZombie->pRemotePublic = NULL;
  610. }
  611. pctRet = SPPublicKeyFromCert(pZombie->pRemoteCert,
  612. &pZombie->pRemotePublic,
  613. NULL);
  614. if(pctRet != PCT_ERR_OK)
  615. {
  616. goto cleanup;
  617. }
  618. // Automatically validate server certificate if appropriate
  619. // context flag is set.
  620. pctRet = AutoVerifyServerCertificate(pContext);
  621. if(pctRet != PCT_ERR_OK)
  622. {
  623. SP_LOG_RESULT(pctRet);
  624. goto cleanup;
  625. }
  626. pZombie->pbServerCertificate = SPExternalAlloc(pHello->CertificateLen);
  627. pZombie->cbServerCertificate = pHello->CertificateLen;
  628. if(pZombie->pbServerCertificate == NULL)
  629. {
  630. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  631. goto cleanup;
  632. }
  633. CopyMemory(pZombie->pbServerCertificate, pHello->pCertificate, pHello->CertificateLen);
  634. /* Create the verify prelude hashes */
  635. /* Which should look like */
  636. /* Hash(CLIENT_MAC_KEY, Hash( "cvp", CLIENT_HELLO, SERVER_HELLO)) */
  637. /* Here we just do the inner hash */
  638. if(pContext->pClientHello == NULL)
  639. {
  640. pctRet = SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  641. goto cleanup;
  642. }
  643. pCMKey = (PPct1_Client_Master_Key)SPExternalAlloc(sizeof(Pct1_Client_Master_Key) + cbClientCert);
  644. if (NULL == pCMKey)
  645. {
  646. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  647. goto cleanup;
  648. }
  649. // Generate Key Args
  650. if(pContext->pCipherInfo->dwBlockSize > 1)
  651. {
  652. GenerateRandomBits(pZombie->pKeyArgs, pContext->pCipherInfo->dwBlockSize);
  653. pZombie->cbKeyArgs = pCMKey->KeyArgLen = pContext->pCipherInfo->dwBlockSize;
  654. /* Copy over the key args */
  655. CopyMemory(pCMKey->KeyArg,
  656. pZombie->pKeyArgs,
  657. pZombie->cbKeyArgs );
  658. }
  659. else
  660. {
  661. pCMKey->KeyArgLen = 0;
  662. }
  663. pctRet = pContext->pKeyExchInfo->System->GenerateClientExchangeValue(
  664. pContext,
  665. pHello->Response,
  666. pHello->ResponseLen,
  667. pCMKey->ClearKey,
  668. &pCMKey->ClearKeyLen,
  669. NULL,
  670. &pCMKey->EncryptedKeyLen);
  671. if(PCT_ERR_OK != pctRet)
  672. {
  673. goto cleanup;
  674. }
  675. pCMKey->pbEncryptedKey = SPExternalAlloc(pCMKey->EncryptedKeyLen);
  676. if(pCMKey->pbEncryptedKey == NULL)
  677. {
  678. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  679. goto cleanup;
  680. }
  681. pctRet = pContext->pKeyExchInfo->System->GenerateClientExchangeValue(
  682. pContext,
  683. pHello->Response,
  684. pHello->ResponseLen,
  685. pCMKey->ClearKey,
  686. &pCMKey->ClearKeyLen,
  687. pCMKey->pbEncryptedKey,
  688. &pCMKey->EncryptedKeyLen);
  689. if(PCT_ERR_OK != pctRet)
  690. {
  691. goto cleanup;
  692. }
  693. pctRet = Pct1BeginVerifyPrelude(pContext,
  694. pContext->pClientHello,
  695. pContext->cbClientHello,
  696. pCommInput->pvBuffer,
  697. pCommInput->cbData);
  698. if(PCT_ERR_OK != pctRet)
  699. {
  700. goto cleanup;
  701. }
  702. // Activate session keys.
  703. Pct1ActivateSessionKeys(pContext);
  704. pCMKey->VerifyPreludeLen = sizeof(pCMKey->VerifyPrelude);
  705. pctRet = Pct1EndVerifyPrelude(pContext,
  706. pCMKey->VerifyPrelude,
  707. &pCMKey->VerifyPreludeLen);
  708. if(PCT_ERR_OK != pctRet)
  709. {
  710. goto cleanup;
  711. }
  712. /* Choose a client cert */
  713. /* For each Cert the server understands, check to see if we */
  714. /* have that type of cert */
  715. pCMKey->ClientCertLen = 0;
  716. pCMKey->ClientCertSpec = 0;
  717. pCMKey->ClientSigSpec = 0;
  718. pCMKey->ResponseLen = 0;
  719. if(fClientAuth && pSigInfo != NULL)
  720. {
  721. // The client cert spec was already chosen
  722. // Also, pContext->fCertChainsAllowed will be
  723. // previously set if we're doing chains.
  724. pCMKey->ClientCertSpec = ClientCertSpec;
  725. pCMKey->ClientSigSpec = pSigInfo->Spec;
  726. pCMKey->pClientCert = (PUCHAR)(pCMKey+1);
  727. pCMKey->ClientCertLen = cbClientCert;
  728. memcpy(pCMKey->pClientCert, pbClientCert, cbClientCert);
  729. // Allocate memory for signature.
  730. pCMKey->ResponseLen = pContext->pActiveClientCred->pPublicKey->cbPublic;
  731. pCMKey->pbResponse = SPExternalAlloc(pCMKey->ResponseLen);
  732. if(pCMKey->pbResponse == NULL)
  733. {
  734. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  735. goto cleanup;
  736. }
  737. DebugLog((DEB_TRACE, "Sign client response.\n"));
  738. // Sign hash via a call to the application process.
  739. pctRet = SignHashUsingCallback(pContext->pActiveClientCred->hRemoteProv,
  740. pContext->pActiveClientCred->dwKeySpec,
  741. pSigInfo->aiHash,
  742. pCMKey->VerifyPrelude,
  743. pCMKey->VerifyPreludeLen,
  744. pCMKey->pbResponse,
  745. &pCMKey->ResponseLen,
  746. TRUE);
  747. if(pctRet != PCT_ERR_OK)
  748. {
  749. goto cleanup;
  750. }
  751. DebugLog((DEB_TRACE, "Client response signed successfully.\n"));
  752. // Convert signature to big endian.
  753. ReverseInPlace(pCMKey->pbResponse, pCMKey->ResponseLen);
  754. }
  755. pctRet = PCT_ERR_ILLEGAL_MESSAGE;
  756. if(PCT_ERR_OK != (pctRet = Pct1PackClientMasterKey(pCMKey,
  757. pCommOutput)))
  758. {
  759. pctRet = SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE);
  760. goto cleanup;
  761. }
  762. pContext->WriteCounter++;
  763. pctRet = PCT_ERR_OK;
  764. cleanup:
  765. if(pCMKey)
  766. {
  767. if(pCMKey->pbEncryptedKey)
  768. {
  769. SPExternalFree(pCMKey->pbEncryptedKey);
  770. }
  771. if(pCMKey->pbResponse)
  772. {
  773. SPExternalFree(pCMKey->pbResponse);
  774. }
  775. SPExternalFree(pCMKey);
  776. }
  777. if(pbClientCert)
  778. {
  779. SPExternalFree(pbClientCert);
  780. }
  781. if(pctRet != PCT_ERR_OK)
  782. {
  783. if(pctRet == PCT_ERR_SPECS_MISMATCH)
  784. {
  785. for(i=0;i<PCT_NUM_MISMATCHES;i++)
  786. {
  787. MisData[i] = (BYTE)(fMismatch & 1);
  788. fMismatch = fMismatch >> 1;
  789. }
  790. ErrData.cbData = ErrData.cbBuffer = PCT_NUM_MISMATCHES;
  791. ErrData.pvBuffer = MisData;
  792. }
  793. pctRet = Pct1GenerateError(pContext,
  794. pCommOutput,
  795. pctRet,
  796. &ErrData);
  797. pctRet |= PCT_INT_DROP_CONNECTION;
  798. }
  799. SP_RETURN(pctRet);
  800. }
  801. SP_STATUS
  802. Pct1CliRestart(PSPContext pContext,
  803. PPct1_Server_Hello pHello,
  804. PSPBuffer pCommOutput)
  805. {
  806. SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE;
  807. UCHAR Response[RESPONSE_SIZE];
  808. DWORD cbResponse;
  809. PPct1_Server_Hello pLocalHello = pHello;
  810. PSessCacheItem pZombie;
  811. SP_BEGIN("Pct1CliRestart");
  812. pZombie = pContext->RipeZombie;
  813. do {
  814. /* if there's no zombie, the message is wrong. We can't restart. */
  815. if(pZombie == NULL)
  816. {
  817. pctRet = SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE);
  818. break;
  819. }
  820. if(!pZombie->hMasterKey)
  821. {
  822. pctRet = SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE);
  823. break;
  824. }
  825. if(!pZombie->ZombieJuju)
  826. {
  827. DebugLog((DEB_WARN, "Session expired on client machine, but not on server.\n"));
  828. }
  829. CopyMemory(pContext->pConnectionID,
  830. pHello->ConnectionID,
  831. pHello->cbConnectionID);
  832. pContext->cbConnectionID = pHello->cbConnectionID;
  833. //Init pending ciphers
  834. pctRet = ContextInitCiphersFromCache(pContext);
  835. if(PCT_ERR_OK != pctRet)
  836. {
  837. break;
  838. }
  839. // We know what our ciphers are, so init the cipher system
  840. pctRet = ContextInitCiphers(pContext, TRUE, TRUE);
  841. if(PCT_ERR_OK != pctRet)
  842. {
  843. break;
  844. }
  845. // Make a new set of session keys.
  846. pctRet = MakeSessionKeys(pContext,
  847. pContext->RipeZombie->hMasterProv,
  848. pContext->RipeZombie->hMasterKey);
  849. if(PCT_ERR_OK != pctRet)
  850. {
  851. break;
  852. }
  853. // Activate session keys.
  854. Pct1ActivateSessionKeys(pContext);
  855. pctRet = PCT_ERR_ILLEGAL_MESSAGE;
  856. DebugLog((DEB_TRACE, "Session Keys Made\n"));
  857. /* let's check the response in the message */
  858. /* check the length */
  859. if (pLocalHello->ResponseLen != pContext->pHashInfo->cbCheckSum)
  860. {
  861. pctRet = SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE);
  862. break;
  863. }
  864. /* calculate the correct response */
  865. cbResponse = sizeof(Response);
  866. pctRet = Pct1ComputeResponse(pContext,
  867. pContext->pChallenge,
  868. pContext->cbChallenge,
  869. pContext->pConnectionID,
  870. pContext->cbConnectionID,
  871. pZombie->SessionID,
  872. pZombie->cbSessionID,
  873. Response,
  874. &cbResponse);
  875. if(pctRet != PCT_ERR_OK)
  876. {
  877. break;
  878. }
  879. /* check it against the response in the message */
  880. if (memcmp(Response, pLocalHello->Response, pLocalHello->ResponseLen))
  881. {
  882. pctRet = SP_LOG_RESULT(PCT_ERR_SERVER_AUTH_FAILED);
  883. break;
  884. }
  885. /* ok, we're done, so let's jettison the auth data */
  886. pContext->ReadCounter = 1;
  887. pContext->WriteCounter = 1;
  888. /* fini. */
  889. SP_RETURN(PCT_ERR_OK);
  890. } while (TRUE);
  891. pctRet = Pct1GenerateError(pContext,
  892. pCommOutput,
  893. pctRet,
  894. NULL);
  895. SP_RETURN(pctRet | PCT_INT_DROP_CONNECTION);
  896. }
  897. SP_STATUS
  898. Pct1CliHandleServerVerify(
  899. PSPContext pContext,
  900. PSPBuffer pCommInput,
  901. PSPBuffer pCommOutput)
  902. {
  903. SP_STATUS pctRet;
  904. PPct1_Server_Verify pVerify = NULL;
  905. SPBuffer ErrData;
  906. PSessCacheItem pZombie;
  907. UCHAR Response[RESPONSE_SIZE];
  908. DWORD cbResponse;
  909. SP_BEGIN("Pct1CliHandleServerVerify");
  910. pZombie = pContext->RipeZombie;
  911. pContext->ReadCounter = 2;
  912. pContext->WriteCounter = 2;
  913. pCommOutput->cbData = 0;
  914. ErrData.cbData = 0;
  915. ErrData.pvBuffer = NULL;
  916. ErrData.cbBuffer = 0;
  917. do
  918. {
  919. /* unpack the message */
  920. pctRet = Pct1UnpackServerVerify(pCommInput, &pVerify);
  921. if (PCT_ERR_OK != pctRet)
  922. {
  923. // If it's an incomplete message or something, just return;
  924. if(!SP_FATAL(pctRet))
  925. {
  926. SP_RETURN(pctRet);
  927. }
  928. break;
  929. }
  930. // compute the correct response
  931. cbResponse = sizeof(Response);
  932. pctRet = Pct1ComputeResponse(pContext,
  933. pContext->pChallenge,
  934. pContext->cbChallenge,
  935. pContext->pConnectionID,
  936. pContext->cbConnectionID,
  937. pVerify->SessionIdData,
  938. PCT_SESSION_ID_SIZE,
  939. Response,
  940. &cbResponse);
  941. if(pctRet != PCT_ERR_OK)
  942. {
  943. SP_LOG_RESULT(pctRet);
  944. break;
  945. }
  946. if(pVerify->ResponseLen != cbResponse ||
  947. memcmp(pVerify->Response, Response, pVerify->ResponseLen))
  948. {
  949. pctRet = SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE);
  950. break;
  951. }
  952. CopyMemory(pZombie->SessionID,
  953. pVerify->SessionIdData,
  954. PCT_SESSION_ID_SIZE);
  955. pZombie->cbSessionID = PCT_SESSION_ID_SIZE;
  956. /* done with the verify data */
  957. SPExternalFree(pVerify);
  958. pVerify = NULL;
  959. /* set up the session in cache */
  960. SPCacheAdd(pContext);
  961. SP_RETURN( PCT_ERR_OK );
  962. } while(TRUE); /* End of polish loop */
  963. if(pVerify) SPExternalFree(pVerify);
  964. pctRet = Pct1GenerateError(pContext,
  965. pCommOutput,
  966. pctRet,
  967. NULL);
  968. SP_RETURN(pctRet | PCT_INT_DROP_CONNECTION);
  969. }
  970. SP_STATUS
  971. WINAPI
  972. GeneratePct1StyleHello(
  973. PSPContext pContext,
  974. PSPBuffer pOutput)
  975. {
  976. Pct1_Client_Hello HelloMessage;
  977. PSessCacheItem pZombie;
  978. CipherSpec aCipherSpecs[10];
  979. HashSpec aHashSpecs[10];
  980. CertSpec aCertSpecs[10];
  981. ExchSpec aExchSpecs[10];
  982. DWORD i;
  983. SP_STATUS pctRet = PCT_INT_INTERNAL_ERROR;
  984. SP_BEGIN("Pct1CliInstigateHello");
  985. HelloMessage.pCipherSpecs = aCipherSpecs;
  986. HelloMessage.pHashSpecs = aHashSpecs;
  987. HelloMessage.pCertSpecs = aCertSpecs;
  988. HelloMessage.pExchSpecs = aExchSpecs;
  989. if(pContext == NULL)
  990. {
  991. SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
  992. }
  993. if (!pOutput)
  994. {
  995. SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
  996. }
  997. pZombie = pContext->RipeZombie;
  998. pContext->Flags |= CONTEXT_FLAG_CLIENT;
  999. GenerateRandomBits( pContext->pChallenge, PCT1_CHALLENGE_SIZE );
  1000. pContext->cbChallenge = PCT1_CHALLENGE_SIZE;
  1001. /* Build the hello message. */
  1002. HelloMessage.cbChallenge = PCT1_CHALLENGE_SIZE;
  1003. HelloMessage.pKeyArg = NULL;
  1004. HelloMessage.cbKeyArgSize = 0;
  1005. HelloMessage.cCipherSpecs = 0;
  1006. for(i=0; i < Pct1NumCipher; i++)
  1007. {
  1008. PCipherInfo pCipherInfo;
  1009. pCipherInfo = GetCipherInfo(Pct1CipherRank[i].aiCipher, Pct1CipherRank[i].dwStrength);
  1010. if(IsCipherAllowed(pContext,
  1011. pCipherInfo,
  1012. pContext->dwProtocol,
  1013. pContext->dwRequestedCF))
  1014. {
  1015. HelloMessage.pCipherSpecs[HelloMessage.cCipherSpecs++] = Pct1CipherRank[i].Spec;
  1016. }
  1017. }
  1018. HelloMessage.cHashSpecs = 0;
  1019. for(i=0; i < Pct1NumHash; i++)
  1020. {
  1021. PHashInfo pHashInfo;
  1022. pHashInfo = GetHashInfo(Pct1HashRank[i].aiHash);
  1023. if(IsHashAllowed(pContext,
  1024. pHashInfo,
  1025. pContext->dwProtocol))
  1026. {
  1027. HelloMessage.pHashSpecs[HelloMessage.cHashSpecs++] = Pct1HashRank[i].Spec;
  1028. }
  1029. }
  1030. HelloMessage.cCertSpecs = 0;
  1031. for(i=0; i < cPct1CertEncodingPref; i++)
  1032. {
  1033. PCertSysInfo pCertInfo = GetCertSysInfo(aPct1CertEncodingPref[i].dwCertEncodingType);
  1034. if(pCertInfo == NULL)
  1035. {
  1036. continue;
  1037. }
  1038. // Is this cert type enabled?
  1039. if(0 == (pCertInfo->fProtocol & SP_PROT_PCT1_CLIENT))
  1040. {
  1041. continue;
  1042. }
  1043. HelloMessage.pCertSpecs[HelloMessage.cCertSpecs++] = aPct1CertEncodingPref[i].Spec;
  1044. }
  1045. HelloMessage.cExchSpecs = 0;
  1046. for(i=0; i < cPct1LocalExchKeyPref; i++)
  1047. {
  1048. PKeyExchangeInfo pExchInfo;
  1049. pExchInfo = GetKeyExchangeInfo(aPct1LocalExchKeyPref[i].Spec);
  1050. if(IsExchAllowed(pContext,
  1051. pExchInfo,
  1052. pContext->dwProtocol))
  1053. {
  1054. HelloMessage.pExchSpecs[HelloMessage.cExchSpecs++] = aPct1LocalExchKeyPref[i].Spec;
  1055. }
  1056. }
  1057. if (pZombie->cbSessionID)
  1058. {
  1059. CopyMemory(HelloMessage.SessionID, pZombie->SessionID, pZombie->cbSessionID);
  1060. HelloMessage.cbSessionID = pZombie->cbSessionID;
  1061. }
  1062. else
  1063. {
  1064. FillMemory(HelloMessage.SessionID, PCT_SESSION_ID_SIZE, 0);
  1065. HelloMessage.cbSessionID = PCT_SESSION_ID_SIZE;
  1066. }
  1067. CopyMemory( HelloMessage.Challenge,
  1068. pContext->pChallenge,
  1069. HelloMessage.cbChallenge );
  1070. HelloMessage.cbChallenge = pContext->cbChallenge;
  1071. pctRet = Pct1PackClientHello(&HelloMessage, pOutput);
  1072. if(PCT_ERR_OK != pctRet)
  1073. {
  1074. SP_RETURN(pctRet);
  1075. }
  1076. // Save the ClientHello message so we can hash it later, once
  1077. // we know what algorithm and CSP we're using.
  1078. if(pContext->pClientHello)
  1079. {
  1080. SPExternalFree(pContext->pClientHello);
  1081. }
  1082. pContext->pClientHello = SPExternalAlloc(pOutput->cbData);
  1083. if(pContext->pClientHello == NULL)
  1084. {
  1085. SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
  1086. }
  1087. CopyMemory(pContext->pClientHello, pOutput->pvBuffer, pOutput->cbData);
  1088. pContext->cbClientHello = pOutput->cbData;
  1089. pContext->dwClientHelloProtocol = SP_PROT_PCT1_CLIENT;
  1090. /* We set this here to tell the protocol engine that we just send a client
  1091. * hello, and we're expecting a pct server hello */
  1092. pContext->State = PCT1_STATE_CLIENT_HELLO;
  1093. SP_RETURN(PCT_ERR_OK);
  1094. }