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.

1043 lines
30 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: ssl2srv.c
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 8-08-95 RichardW Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <spbase.h>
  18. #include <ssl2msg.h>
  19. #include <ssl2prot.h>
  20. SP_STATUS Ssl2SrvGenerateServerFinish(PSPContext pContext,
  21. PSPBuffer pCommOutput);
  22. SP_STATUS Ssl2SrvGenerateServerVerify(PSPContext pContext,
  23. PSPBuffer pCommOutput);
  24. SP_STATUS Ssl2SrvVerifyClientFinishMsg(PSPContext pContext,
  25. PSPBuffer pCommInput);
  26. #define SSL_OFFSET_OF(t, v) ((DWORD)(ULONG_PTR)&(((t)NULL)->v))
  27. #define SSL2_CERT_TYPE_FROM_CAPI(s) X509_ASN_ENCODING
  28. SP_STATUS WINAPI
  29. Ssl2ServerProtocolHandler(
  30. PSPContext pContext,
  31. PSPBuffer pCommInput,
  32. PSPBuffer pCommOutput)
  33. {
  34. SP_STATUS pctRet = 0;
  35. DWORD cMessageType;
  36. DWORD dwStateTransition;
  37. BOOL fRaw = TRUE;
  38. SPBuffer MsgInput;
  39. DWORD cbMsg;
  40. PUCHAR pb;
  41. UCHAR bCT;
  42. if (NULL != pCommOutput)
  43. {
  44. pCommOutput->cbData = 0;
  45. }
  46. MsgInput.pvBuffer = pCommInput->pvBuffer;
  47. MsgInput.cbBuffer = pCommInput->cbBuffer;
  48. MsgInput.cbData = pCommInput->cbData;
  49. // In the following states, we should decrypt the message:
  50. switch(pContext->State)
  51. {
  52. case SSL2_STATE_SERVER_VERIFY:
  53. case SSL2_STATE_SERVER_RESTART:
  54. pctRet = Ssl2DecryptMessage(pContext, pCommInput, &MsgInput);
  55. cMessageType = ((PUCHAR) MsgInput.pvBuffer)[0];
  56. fRaw = FALSE;
  57. break;
  58. case SP_STATE_SHUTDOWN:
  59. case SP_STATE_SHUTDOWN_PENDING:
  60. cMessageType = 0;
  61. break;
  62. case SP_STATE_CONNECTED:
  63. // The server has attempted to initiate a reconnect.
  64. return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
  65. default:
  66. if(pCommInput->cbData < 3)
  67. {
  68. return SP_LOG_RESULT(PCT_INT_INCOMPLETE_MSG);
  69. }
  70. cMessageType = ((PUCHAR) MsgInput.pvBuffer)[2];
  71. break;
  72. }
  73. if (pctRet != PCT_ERR_OK)
  74. {
  75. // to handle incomplete message errors
  76. return(pctRet);
  77. }
  78. dwStateTransition = pContext->State | (cMessageType<<16);
  79. switch(dwStateTransition)
  80. {
  81. case SP_STATE_SHUTDOWN_PENDING:
  82. // There's no CloseNotify in SSL2, so just transition to
  83. // the shutdown state and leave the output buffer empty.
  84. pContext->State = SP_STATE_SHUTDOWN;
  85. break;
  86. case SP_STATE_SHUTDOWN:
  87. return PCT_INT_EXPIRED;
  88. /* Server receives client hello */
  89. case (SSL2_MT_CLIENT_HELLO << 16) | SP_STATE_NONE:
  90. {
  91. PSsl2_Client_Hello pSsl2Hello;
  92. // Attempt to recognize and handle various versions of client
  93. // hello, start by trying to unpickle the most recent version, and
  94. // then next most recent, until one unpickles. Then run the handle
  95. // code. We can also put unpickling and handling code in here for
  96. // SSL messages.
  97. pctRet = Ssl2UnpackClientHello(pCommInput, &pSsl2Hello);
  98. if (PCT_ERR_OK == pctRet)
  99. {
  100. if (((pContext->Flags & CONTEXT_FLAG_NOCACHE) == 0) &&
  101. (pSsl2Hello->cbSessionID) &&
  102. (SPCacheRetrieveBySession(pContext,
  103. pSsl2Hello->SessionID,
  104. pSsl2Hello->cbSessionID,
  105. &pContext->RipeZombie)))
  106. {
  107. DebugLog((DEB_TRACE, "Accept client's reconnect request.\n"));
  108. pctRet = Ssl2SrvGenRestart(pContext,
  109. pSsl2Hello,
  110. pCommOutput);
  111. if (PCT_ERR_OK == pctRet)
  112. {
  113. pContext->State = SSL2_STATE_SERVER_VERIFY;
  114. }
  115. }
  116. else
  117. {
  118. // We're doing a full handshake, so allocate a cache entry.
  119. if(!SPCacheRetrieveNew(TRUE,
  120. pContext->pszTarget,
  121. &pContext->RipeZombie))
  122. {
  123. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  124. }
  125. else
  126. {
  127. pContext->RipeZombie->fProtocol = pContext->dwProtocol;
  128. pContext->RipeZombie->dwCF = pContext->dwRequestedCF;
  129. pContext->RipeZombie->pServerCred = pContext->pCredGroup;
  130. pctRet = Ssl2SrvHandleClientHello(pContext,
  131. pCommInput,
  132. pSsl2Hello,
  133. pCommOutput);
  134. if (PCT_ERR_OK == pctRet)
  135. {
  136. pContext->State = SSL2_STATE_SERVER_HELLO;
  137. }
  138. }
  139. }
  140. SPExternalFree(pSsl2Hello);
  141. }
  142. else if(pctRet != PCT_INT_INCOMPLETE_MSG)
  143. {
  144. pctRet |= PCT_INT_DROP_CONNECTION;
  145. }
  146. if (SP_FATAL(pctRet))
  147. {
  148. pContext->State = PCT1_STATE_ERROR;
  149. }
  150. break;
  151. }
  152. case (SSL2_MT_CLIENT_MASTER_KEY << 16) | SSL2_STATE_SERVER_HELLO:
  153. pctRet = Ssl2SrvHandleCMKey(pContext, pCommInput, pCommOutput);
  154. if (SP_FATAL(pctRet))
  155. {
  156. pContext->State = PCT1_STATE_ERROR;
  157. }
  158. else
  159. {
  160. if (PCT_ERR_OK == pctRet)
  161. {
  162. pContext->State = SSL2_STATE_SERVER_VERIFY;
  163. }
  164. // We received a non-fatal error, so the state doesn't change,
  165. // giving the app time to deal with this.
  166. }
  167. break;
  168. case (SSL2_MT_CLIENT_FINISHED_V2 << 16) | SSL2_STATE_SERVER_VERIFY:
  169. pctRet = Ssl2SrvHandleClientFinish(
  170. pContext,
  171. &MsgInput,
  172. pCommOutput);
  173. if (SP_FATAL(pctRet))
  174. {
  175. pContext->State = PCT1_STATE_ERROR;
  176. }
  177. else
  178. {
  179. if (PCT_ERR_OK == pctRet)
  180. {
  181. pContext->State = SP_STATE_CONNECTED;
  182. pContext->DecryptHandler = Ssl2DecryptHandler;
  183. pContext->Encrypt = Ssl2EncryptMessage;
  184. pContext->Decrypt = Ssl2DecryptMessage;
  185. pContext->GetHeaderSize = Ssl2GetHeaderSize;
  186. }
  187. // We received a non-fatal error, so the state doesn't change,
  188. // giving the app time to deal with this.
  189. }
  190. break;
  191. default:
  192. DebugLog((DEB_WARN, "Error in protocol, dwStateTransition is %lx\n", dwStateTransition));
  193. pContext->State = PCT1_STATE_ERROR;
  194. pctRet = SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
  195. break;
  196. }
  197. if (pctRet & PCT_INT_DROP_CONNECTION)
  198. {
  199. pContext->State &= ~SP_STATE_CONNECTED;
  200. }
  201. return(pctRet);
  202. }
  203. SP_STATUS
  204. Ssl2SrvHandleClientHello(
  205. PSPContext pContext,
  206. PSPBuffer pCommInput,
  207. PSsl2_Client_Hello pHello,
  208. PSPBuffer pCommOutput)
  209. {
  210. SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE;
  211. PSPCredential pCred;
  212. Ssl2_Server_Hello Reply;
  213. DWORD cCommonCiphers;
  214. DWORD CommonCiphers[MAX_UNI_CIPHERS];
  215. PSessCacheItem pZombie;
  216. BOOL fFound;
  217. DWORD i,j;
  218. SP_BEGIN("Ssl2SrvHandleClientHello");
  219. pCommOutput->cbData = 0;
  220. /* validate the buffer configuration */
  221. if(NULL == pContext)
  222. {
  223. SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
  224. }
  225. pZombie = pContext->RipeZombie;
  226. // See if we have a cert that supports ssl2
  227. pctRet = SPPickServerCertificate(pContext, SP_EXCH_RSA_PKCS1);
  228. if(PCT_ERR_OK != pctRet)
  229. {
  230. SP_RETURN(pctRet | PCT_INT_DROP_CONNECTION);
  231. }
  232. pCred = pZombie->pActiveServerCred;
  233. if (!pCred)
  234. {
  235. SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
  236. }
  237. do {
  238. ZeroMemory(&Reply, sizeof(Reply));
  239. //
  240. // Calculate common ciphers:
  241. //
  242. cCommonCiphers = 0;
  243. for(i = 0; i < UniNumCiphers; i++)
  244. {
  245. PCipherInfo pCipherInfo;
  246. PHashInfo pHashInfo;
  247. PKeyExchangeInfo pExchInfo;
  248. // Is this an SSL2 cipher suite?
  249. if(!(UniAvailableCiphers[i].fProt & pContext->RipeZombie->fProtocol))
  250. {
  251. continue;
  252. }
  253. pCipherInfo = GetCipherInfo(UniAvailableCiphers[i].aiCipher,
  254. UniAvailableCiphers[i].dwStrength);
  255. if(NULL == pCipherInfo)
  256. {
  257. continue;
  258. }
  259. if(!IsCipherSuiteAllowed(pContext,
  260. pCipherInfo,
  261. pZombie->fProtocol,
  262. pZombie->dwCF,
  263. UniAvailableCiphers[i].dwFlags))
  264. {
  265. continue;
  266. }
  267. pHashInfo = GetHashInfo(UniAvailableCiphers[i].aiHash);
  268. if(NULL == pHashInfo)
  269. {
  270. continue;
  271. }
  272. if(!IsHashAllowed(pContext, pHashInfo, pZombie->fProtocol))
  273. {
  274. continue;
  275. }
  276. pExchInfo = GetKeyExchangeInfo(UniAvailableCiphers[i].KeyExch);
  277. if(NULL == pExchInfo)
  278. {
  279. continue;
  280. }
  281. if(!IsExchAllowed(pContext, pExchInfo, pZombie->fProtocol))
  282. {
  283. continue;
  284. }
  285. // Is this cipher suite supported by the client?
  286. for(fFound = FALSE, j = 0; j < pHello->cCipherSpecs; j++)
  287. {
  288. if(UniAvailableCiphers[i].CipherKind == pHello->CipherSpecs[j])
  289. {
  290. fFound = TRUE;
  291. break;
  292. }
  293. }
  294. if(!fFound)
  295. {
  296. continue;
  297. }
  298. // Does the CSP support this cipher suite?
  299. if(!IsAlgSupportedCapi(pContext->RipeZombie->fProtocol,
  300. UniAvailableCiphers + i,
  301. pCred->pCapiAlgs,
  302. pCred->cCapiAlgs))
  303. {
  304. continue;
  305. }
  306. // Add this cipher to list.
  307. CommonCiphers[cCommonCiphers++] = UniAvailableCiphers[i].CipherKind;
  308. }
  309. //
  310. // if cCommonCipers == 0, then we have none in common. At this point, we
  311. // should generate an error response, but that is for later. For now,
  312. // we will generate an invalid_token return, and bail out.
  313. //
  314. if (cCommonCiphers == 0)
  315. {
  316. pctRet = SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH);
  317. LogCipherMismatchEvent();
  318. break;
  319. }
  320. Reply.cCipherSpecs = cCommonCiphers;
  321. Reply.pCipherSpecs = CommonCiphers;
  322. Reply.SessionIdHit = 0;
  323. Reply.CertificateType = SSL2_CERT_TYPE_FROM_CAPI(pCred->pCert->dwCertEncodingType);
  324. // Auto allocate the certificate. !We must free them when we're done....
  325. Reply.pCertificate = NULL;
  326. Reply.cbCertificate = 0;
  327. pctRet = SPSerializeCertificate(SP_PROT_SSL2,
  328. FALSE,
  329. &Reply.pCertificate,
  330. &Reply.cbCertificate,
  331. pCred->pCert,
  332. 0);
  333. if (PCT_ERR_OK != pctRet)
  334. {
  335. break;
  336. }
  337. /* Generate a conneciton id to use while establishing connection */
  338. Reply.cbConnectionID = SSL2_GEN_CONNECTION_ID_LEN;
  339. GenerateRandomBits( Reply.ConnectionID,
  340. Reply.cbConnectionID );
  341. CopyMemory(pContext->pConnectionID,
  342. Reply.ConnectionID,
  343. Reply.cbConnectionID);
  344. pContext->cbConnectionID = Reply.cbConnectionID;
  345. /* keep challenge around for later */
  346. CopyMemory( pContext->pChallenge,
  347. pHello->Challenge,
  348. pHello->cbChallenge);
  349. pContext->cbChallenge = pHello->cbChallenge;
  350. pctRet = Ssl2PackServerHello(&Reply, pCommOutput);
  351. if(Reply.pCertificate)
  352. {
  353. SPExternalFree(Reply.pCertificate);
  354. }
  355. if (PCT_ERR_OK != pctRet)
  356. {
  357. break;
  358. }
  359. pContext->WriteCounter = 1; /* received client hello */
  360. pContext->ReadCounter = 1; /* Sending server hello */
  361. SP_RETURN(PCT_ERR_OK);
  362. } while (TRUE); /* end Polish Loop */
  363. if((pContext->Flags & CONTEXT_FLAG_EXT_ERR) &&
  364. (pctRet == PCT_ERR_SPECS_MISMATCH))
  365. {
  366. // Our SSL2 implementation does not do client auth,
  367. // so there is only one error message, cipher error.
  368. pCommOutput->cbData = 3; // MSG-ERROR + ERROR-CODE-MSB + ERROR-CODE-LSB
  369. if(pCommOutput->pvBuffer == NULL)
  370. {
  371. pCommOutput->pvBuffer = SPExternalAlloc(pCommOutput->cbData);
  372. if (NULL == pCommOutput->pvBuffer)
  373. {
  374. SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
  375. }
  376. pCommOutput->cbBuffer = pCommOutput->cbData;
  377. }
  378. if(pCommOutput->cbData > pCommOutput->cbBuffer)
  379. {
  380. // Required buffer size returned in pCommOutput->cbData.
  381. SP_RETURN(SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL));
  382. }
  383. ((PUCHAR)pCommOutput->pvBuffer)[0] = SSL2_MT_ERROR;
  384. ((PUCHAR)pCommOutput->pvBuffer)[1] = MSBOF(SSL_PE_NO_CIPHER);
  385. ((PUCHAR)pCommOutput->pvBuffer)[2] = LSBOF(SSL_PE_NO_CIPHER);
  386. }
  387. SP_RETURN(pctRet | PCT_INT_DROP_CONNECTION);
  388. }
  389. SP_STATUS
  390. Ssl2SrvGenRestart(
  391. PSPContext pContext,
  392. PSsl2_Client_Hello pHello,
  393. PSPBuffer pCommOutput)
  394. {
  395. SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE;
  396. SPBuffer SecondOutput;
  397. Ssl2_Server_Hello Reply;
  398. DWORD cbMessage, cbMsg, cPadding;
  399. PSessCacheItem pZombie;
  400. SP_BEGIN("Ssl2SrvGenRestart");
  401. pCommOutput->cbData = 0;
  402. /* validate the buffer configuration */
  403. /* make sure we have the needed authentication data area */
  404. if (NULL == pContext)
  405. {
  406. SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
  407. }
  408. pZombie = pContext->RipeZombie;
  409. do {
  410. FillMemory( &Reply, sizeof( Reply ), 0 );
  411. Reply.SessionIdHit = (DWORD)1;
  412. Reply.cCipherSpecs = 0;
  413. Reply.pCipherSpecs = NULL;
  414. Reply.pCertificate = NULL;
  415. Reply.cbCertificate = 0;
  416. Reply.CertificateType = 0;
  417. /* Note, we generate both a server hello, and a server verify in
  418. * this handling routing. This is because netscape will not send
  419. * us a client finish until the server verify is received
  420. */
  421. // Load pending ciphers from cache
  422. pctRet = ContextInitCiphersFromCache(pContext);
  423. if(PCT_ERR_OK != pctRet)
  424. {
  425. break;
  426. }
  427. pctRet = ContextInitCiphers(pContext, TRUE, TRUE);
  428. if(PCT_ERR_OK != pctRet)
  429. {
  430. break;
  431. }
  432. Reply.cbConnectionID = SSL2_GEN_CONNECTION_ID_LEN;
  433. GenerateRandomBits( Reply.ConnectionID,
  434. Reply.cbConnectionID );
  435. CopyMemory(pContext->pConnectionID,
  436. Reply.ConnectionID,
  437. Reply.cbConnectionID);
  438. pContext->cbConnectionID = Reply.cbConnectionID;
  439. /* keep challenge around for later */
  440. CopyMemory( pContext->pChallenge,
  441. pHello->Challenge,
  442. pHello->cbChallenge);
  443. pContext->cbChallenge = pHello->cbChallenge;
  444. // Make a new set of session keys.
  445. pctRet = MakeSessionKeys(pContext,
  446. pContext->RipeZombie->hMasterProv,
  447. pContext->RipeZombie->hMasterKey);
  448. if(pctRet != PCT_ERR_OK)
  449. {
  450. break;
  451. }
  452. // Activate session keys.
  453. pContext->hReadKey = pContext->hPendingReadKey;
  454. pContext->hWriteKey = pContext->hPendingWriteKey;
  455. pContext->hPendingReadKey = 0;
  456. pContext->hPendingWriteKey = 0;
  457. /* calc size of the server hello (restart only) */
  458. cbMessage = Reply.cbConnectionID +
  459. Reply.cbCertificate +
  460. Reply.cCipherSpecs * sizeof(Ssl2_Cipher_Tuple) +
  461. SSL_OFFSET_OF(PSSL2_SERVER_HELLO, VariantData) -
  462. sizeof(SSL2_MESSAGE_HEADER);
  463. pCommOutput->cbData = cbMessage + 2;
  464. /* calc size of server verify */
  465. cbMsg = sizeof(UCHAR) + pContext->cbChallenge;
  466. cPadding = ((cbMsg+pContext->pHashInfo->cbCheckSum) % pContext->pCipherInfo->dwBlockSize);
  467. if(cPadding)
  468. {
  469. cPadding = pContext->pCipherInfo->dwBlockSize - cPadding;
  470. }
  471. pCommOutput->cbData += cbMsg +
  472. pContext->pHashInfo->cbCheckSum +
  473. cPadding +
  474. (cPadding?3:2);
  475. /* are we allocating our own memory? */
  476. if(pCommOutput->pvBuffer == NULL) {
  477. pCommOutput->pvBuffer = SPExternalAlloc(pCommOutput->cbData);
  478. if (NULL == pCommOutput->pvBuffer)
  479. SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
  480. pCommOutput->cbBuffer = pCommOutput->cbData;
  481. }
  482. if(pCommOutput->cbData > pCommOutput->cbBuffer)
  483. {
  484. // Required buffer size returned in pCommOutput->cbData.
  485. SP_RETURN(PCT_INT_BUFF_TOO_SMALL);
  486. }
  487. pctRet = Ssl2PackServerHello(&Reply, pCommOutput);
  488. if (PCT_ERR_OK != pctRet)
  489. {
  490. break;
  491. }
  492. pContext->WriteCounter = 1; /* received client hello */
  493. pContext->ReadCounter = 1; /* Sending server hello */
  494. /* Now pack the server verify message and encrypt it */
  495. SecondOutput.pvBuffer = (PUCHAR)pCommOutput->pvBuffer+pCommOutput->cbData;
  496. SecondOutput.cbBuffer = pCommOutput->cbBuffer-pCommOutput->cbData;
  497. pctRet = Ssl2SrvGenerateServerVerify(pContext, &SecondOutput);
  498. if (PCT_ERR_OK != pctRet)
  499. {
  500. break;
  501. }
  502. pCommOutput->cbData += SecondOutput.cbData;
  503. SP_RETURN(PCT_ERR_OK);
  504. } while (TRUE); /* end Polish Loop */
  505. SP_RETURN(pctRet | PCT_INT_DROP_CONNECTION);
  506. }
  507. SP_STATUS
  508. Ssl2SrvHandleCMKey(
  509. PSPContext pContext,
  510. PSPBuffer pCommInput,
  511. PSPBuffer pCommOutput)
  512. {
  513. SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE;
  514. PSsl2_Client_Master_Key pMasterKey = NULL;
  515. DWORD dwKeyLen;
  516. DWORD EncryptedLen;
  517. DWORD i;
  518. DWORD cbData;
  519. PSessCacheItem pZombie;
  520. SP_BEGIN("Ssl2SrvHandleCMKey");
  521. pCommOutput->cbData = 0;
  522. pZombie = pContext->RipeZombie;
  523. do {
  524. /* make sure we have the needed authentication data area */
  525. cbData = pCommInput->cbData;
  526. pctRet = Ssl2UnpackClientMasterKey(pCommInput, &pMasterKey);
  527. if (PCT_ERR_OK != pctRet)
  528. {
  529. // If it's an incomplete message or something, just return;
  530. if(!SP_FATAL(pctRet))
  531. {
  532. SP_RETURN(pctRet);
  533. }
  534. break;
  535. }
  536. pctRet = PCT_ERR_ILLEGAL_MESSAGE;
  537. /* CMK sent cleartext, so we must auto-inc the read counter */
  538. pContext->ReadCounter++;
  539. pContext->pCipherInfo = NULL;
  540. pContext->pHashInfo = NULL;
  541. pContext->pKeyExchInfo = NULL;
  542. // Pick a cipher suite
  543. pctRet = PCT_ERR_SPECS_MISMATCH;
  544. for(i = 0; i < UniNumCiphers; i++)
  545. {
  546. // Is this an SSL2 cipher suite?
  547. if(!(UniAvailableCiphers[i].fProt & pContext->RipeZombie->fProtocol))
  548. {
  549. continue;
  550. }
  551. if(UniAvailableCiphers[i].CipherKind != pMasterKey->CipherKind)
  552. {
  553. continue;
  554. }
  555. pZombie->aiCipher = UniAvailableCiphers[i].aiCipher;
  556. pZombie->dwStrength = UniAvailableCiphers[i].dwStrength;
  557. pZombie->aiHash = UniAvailableCiphers[i].aiHash;
  558. pZombie->SessExchSpec = UniAvailableCiphers[i].KeyExch;
  559. pctRet = ContextInitCiphersFromCache(pContext);
  560. if(pctRet != PCT_ERR_OK)
  561. {
  562. continue;
  563. }
  564. break;
  565. }
  566. pctRet = ContextInitCiphers(pContext, TRUE, TRUE);
  567. if(pctRet != PCT_ERR_OK)
  568. {
  569. SP_LOG_RESULT(pctRet);
  570. break;
  571. }
  572. /* Copy over the key args */
  573. CopyMemory( pZombie->pKeyArgs,
  574. pMasterKey->KeyArg,
  575. pMasterKey->KeyArgLen );
  576. pZombie->cbKeyArgs = pMasterKey->KeyArgLen;
  577. // Store the clear key in the context structure.
  578. CopyMemory( pZombie->pClearKey,
  579. pMasterKey->ClearKey,
  580. pMasterKey->ClearKeyLen);
  581. pZombie->cbClearKey = pMasterKey->ClearKeyLen;
  582. /* Decrypt the encrypted portion of the master key */
  583. pctRet = pContext->pKeyExchInfo->System->GenerateServerMasterKey(
  584. pContext,
  585. pMasterKey->ClearKey,
  586. pMasterKey->ClearKeyLen,
  587. pMasterKey->pbEncryptedKey,
  588. pMasterKey->EncryptedKeyLen);
  589. if(PCT_ERR_OK != pctRet)
  590. {
  591. break;
  592. }
  593. SPExternalFree( pMasterKey );
  594. pMasterKey = NULL;
  595. // Update keys.
  596. pContext->hReadKey = pContext->hPendingReadKey;
  597. pContext->hWriteKey = pContext->hPendingWriteKey;
  598. pContext->hPendingReadKey = 0;
  599. pContext->hPendingWriteKey = 0;
  600. pctRet = Ssl2SrvGenerateServerVerify(pContext, pCommOutput);
  601. SP_RETURN(pctRet);
  602. } while(TRUE);
  603. if (pMasterKey)
  604. {
  605. SPExternalFree( pMasterKey );
  606. }
  607. if((pContext->Flags & CONTEXT_FLAG_EXT_ERR) &&
  608. (pctRet == PCT_ERR_SPECS_MISMATCH))
  609. {
  610. // Our SSL2 implementation does not do client auth,
  611. // so there is only one error message, cipher error.
  612. pCommOutput->cbData = 3; // MSG-ERROR + ERROR-CODE-MSB + ERROR-CODE-LSB
  613. /* are we allocating our own memory? */
  614. if(pCommOutput->pvBuffer == NULL)
  615. {
  616. pCommOutput->pvBuffer = SPExternalAlloc(pCommOutput->cbData);
  617. if (NULL == pCommOutput->pvBuffer)
  618. {
  619. SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
  620. }
  621. pCommOutput->cbBuffer = pCommOutput->cbData;
  622. }
  623. if(pCommOutput->cbData <= pCommOutput->cbBuffer)
  624. {
  625. ((PUCHAR)pCommOutput->pvBuffer)[0] = SSL2_MT_ERROR;
  626. ((PUCHAR)pCommOutput->pvBuffer)[1] = MSBOF(SSL_PE_NO_CIPHER);
  627. ((PUCHAR)pCommOutput->pvBuffer)[2] = LSBOF(SSL_PE_NO_CIPHER);
  628. }
  629. else
  630. {
  631. pCommOutput->cbData = 0;
  632. }
  633. }
  634. SP_RETURN((PCT_INT_DROP_CONNECTION | pctRet));
  635. }
  636. SP_STATUS
  637. Ssl2SrvVerifyClientFinishMsg(
  638. PSPContext pContext,
  639. PSPBuffer pCommInput)
  640. {
  641. SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE;
  642. PSSL2_CLIENT_FINISHED pFinished;
  643. SP_BEGIN("Ssl2SrvVerifyClientFinishMsg");
  644. /* Note, there is no header in this message, as it has been pre-decrypted */
  645. if (pCommInput->cbData != sizeof(UCHAR) + pContext->cbConnectionID)
  646. {
  647. SP_RETURN(SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG));
  648. }
  649. pFinished = pCommInput->pvBuffer;
  650. if (pFinished->MessageId != SSL2_MT_CLIENT_FINISHED_V2)
  651. {
  652. SP_RETURN(SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG));
  653. }
  654. if ( memcmp(pFinished->ConnectionID,
  655. pContext->pConnectionID,
  656. pContext->cbConnectionID))
  657. {
  658. SP_RETURN(SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG));
  659. }
  660. SP_RETURN(PCT_ERR_OK);
  661. }
  662. SP_STATUS
  663. Ssl2SrvGenerateServerVerify(
  664. PSPContext pContext,
  665. PSPBuffer pCommOutput)
  666. {
  667. SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE;
  668. PSSL2_SERVER_VERIFY pVerify;
  669. DWORD HeaderSize;
  670. SPBuffer MsgOutput;
  671. DWORD cPadding;
  672. BOOL fAlloced = FALSE;
  673. pCommOutput->cbData = 0;
  674. SP_BEGIN("Ssl2SrvGenerateServerVerify");
  675. do {
  676. MsgOutput.cbData = sizeof(UCHAR) + pContext->cbChallenge;
  677. cPadding = ((MsgOutput.cbData+pContext->pHashInfo->cbCheckSum) % pContext->pCipherInfo->dwBlockSize);
  678. if(cPadding)
  679. {
  680. cPadding = pContext->pCipherInfo->dwBlockSize - cPadding;
  681. }
  682. HeaderSize = (cPadding?3:2);
  683. pCommOutput->cbData = MsgOutput.cbData +
  684. pContext->pHashInfo->cbCheckSum +
  685. cPadding + HeaderSize;
  686. /* are we allocating our own memory? */
  687. if (pCommOutput->pvBuffer == NULL) {
  688. pCommOutput->pvBuffer = SPExternalAlloc(pCommOutput->cbData);
  689. if (NULL == pCommOutput->pvBuffer)
  690. {
  691. SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
  692. }
  693. fAlloced = TRUE;
  694. pCommOutput->cbBuffer = pCommOutput->cbData;
  695. }
  696. MsgOutput.pvBuffer= (PUCHAR)pCommOutput->pvBuffer +
  697. HeaderSize+pContext->pHashInfo->cbCheckSum;
  698. MsgOutput.cbBuffer= pCommOutput->cbBuffer -
  699. HeaderSize-pContext->pHashInfo->cbCheckSum;
  700. pVerify = (PSSL2_SERVER_VERIFY) MsgOutput.pvBuffer;
  701. pVerify->MessageId = SSL2_MT_SERVER_VERIFY;
  702. CopyMemory( pVerify->ChallengeData,
  703. pContext->pChallenge,
  704. pContext->cbChallenge );
  705. pctRet = Ssl2EncryptMessage( pContext, &MsgOutput, pCommOutput);
  706. if(PCT_ERR_OK != pctRet)
  707. {
  708. break;
  709. }
  710. SP_RETURN(PCT_ERR_OK);
  711. } while(TRUE);
  712. if(fAlloced && (NULL != pCommOutput->pvBuffer))
  713. {
  714. SPExternalFree(pCommOutput->pvBuffer);
  715. pCommOutput->cbBuffer = 0;
  716. pCommOutput->cbData = 0;
  717. pCommOutput->pvBuffer = NULL;
  718. }
  719. SP_RETURN(PCT_INT_DROP_CONNECTION | pctRet);
  720. }
  721. SP_STATUS
  722. Ssl2SrvGenerateServerFinish(
  723. PSPContext pContext,
  724. PSPBuffer pCommOutput)
  725. {
  726. SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE;
  727. PSSL2_SERVER_FINISHED pFinish;
  728. DWORD HeaderSize;
  729. SPBuffer MsgOutput;
  730. DWORD cPadding;
  731. BOOL fAlloced = FALSE;
  732. pCommOutput->cbData = 0;
  733. SP_BEGIN("Ssl2SrvGenerateServerFinish");
  734. do {
  735. /* Generate a session id to use during the session */
  736. pContext->RipeZombie->cbSessionID = SSL2_SESSION_ID_LEN;
  737. /* store this context in the cache */
  738. /* note - we don't check error 'cause it's recoverable
  739. * if we don't cache */
  740. SPCacheAdd(pContext);
  741. MsgOutput.cbData = sizeof(UCHAR) + pContext->RipeZombie->cbSessionID;
  742. cPadding = ((MsgOutput.cbData+pContext->pHashInfo->cbCheckSum) % pContext->pCipherInfo->dwBlockSize);
  743. if(cPadding)
  744. {
  745. cPadding = pContext->pCipherInfo->dwBlockSize - cPadding;
  746. }
  747. HeaderSize = (cPadding?3:2);
  748. pCommOutput->cbData = MsgOutput.cbData +
  749. pContext->pHashInfo->cbCheckSum +
  750. cPadding +
  751. HeaderSize;
  752. /* are we allocating our own memory? */
  753. if(pCommOutput->pvBuffer == NULL)
  754. {
  755. pCommOutput->pvBuffer = SPExternalAlloc(pCommOutput->cbData);
  756. if (NULL == pCommOutput->pvBuffer)
  757. {
  758. SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
  759. }
  760. fAlloced = TRUE;
  761. pCommOutput->cbBuffer = pCommOutput->cbData;
  762. }
  763. if(pCommOutput->cbData > pCommOutput->cbBuffer)
  764. {
  765. // Required buffer size returned in pCommOutput->cbData.
  766. SP_RETURN(SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL));
  767. }
  768. MsgOutput.pvBuffer= (PUCHAR)pCommOutput->pvBuffer + HeaderSize+pContext->pHashInfo->cbCheckSum;
  769. MsgOutput.cbBuffer= pCommOutput->cbBuffer-HeaderSize-pContext->pHashInfo->cbCheckSum;
  770. pFinish = (PSSL2_SERVER_FINISHED) MsgOutput.pvBuffer;
  771. pFinish->MessageId = SSL2_MT_SERVER_FINISHED_V2;
  772. CopyMemory( pFinish->SessionID,
  773. pContext->RipeZombie->SessionID,
  774. pContext->RipeZombie->cbSessionID );
  775. /* Cache Context Here */
  776. pctRet = Ssl2EncryptMessage( pContext, &MsgOutput, pCommOutput);
  777. if(PCT_ERR_OK != pctRet)
  778. {
  779. break;
  780. }
  781. SP_RETURN(PCT_ERR_OK);
  782. } while(TRUE);
  783. if(fAlloced && (NULL != pCommOutput->pvBuffer))
  784. {
  785. SPExternalFree(pCommOutput->pvBuffer);
  786. pCommOutput->cbBuffer = 0;
  787. pCommOutput->cbData = 0;
  788. pCommOutput->pvBuffer = NULL;
  789. }
  790. SP_RETURN(PCT_INT_DROP_CONNECTION | pctRet);
  791. }
  792. SP_STATUS
  793. Ssl2SrvHandleClientFinish(
  794. PSPContext pContext,
  795. PSPBuffer pCommInput,
  796. PSPBuffer pCommOutput)
  797. {
  798. SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE;
  799. SP_BEGIN("Ssl2SrvHandleClientFinish");
  800. pCommOutput->cbData = 0;
  801. pctRet = Ssl2SrvVerifyClientFinishMsg(pContext, pCommInput);
  802. if (PCT_ERR_OK != pctRet)
  803. {
  804. SP_RETURN(pctRet);
  805. }
  806. pctRet = Ssl2SrvGenerateServerFinish(pContext, pCommOutput);
  807. SP_RETURN(pctRet);
  808. }