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

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