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.

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