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.

1223 lines
31 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: keyxmsdh.c
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 10-21-97 jbanes CAPI integration stuff.
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <spbase.h>
  18. #include <align.h>
  19. // PROV_DH_SCHANNEL handle used for client and server operations. This is
  20. // where the schannel ephemeral DH key lives.
  21. HCRYPTPROV g_hDhSchannelProv = 0;
  22. PROV_ENUMALGS_EX * g_pDhSchannelAlgs = NULL;
  23. DWORD g_cDhSchannelAlgs = 0;
  24. SP_STATUS
  25. WINAPI
  26. DHGenerateServerExchangeValue(
  27. SPContext * pContext, // in
  28. PUCHAR pServerExchangeValue, // out
  29. DWORD * pcbServerExchangeValue // in/out
  30. );
  31. SP_STATUS
  32. WINAPI
  33. DHGenerateClientExchangeValue(
  34. SPContext * pContext, // in
  35. PUCHAR pServerExchangeValue, // in
  36. DWORD cbServerExchangeValue, // in
  37. PUCHAR pClientClearValue, // out
  38. DWORD * pcbClientClearValue, // in/out
  39. PUCHAR pClientExchangeValue, // out
  40. DWORD * pcbClientExchangeValue // in/out
  41. );
  42. SP_STATUS
  43. WINAPI
  44. DHGenerateServerMasterKey(
  45. SPContext * pContext, // in
  46. PUCHAR pClientClearValue, // in
  47. DWORD cbClientClearValue, // in
  48. PUCHAR pClientExchangeValue, // in
  49. DWORD cbClientExchangeValue // in
  50. );
  51. KeyExchangeSystem keyexchDH = {
  52. SP_EXCH_DH_PKCS3,
  53. "Diffie Hellman",
  54. DHGenerateServerExchangeValue,
  55. DHGenerateClientExchangeValue,
  56. DHGenerateServerMasterKey,
  57. };
  58. SP_STATUS
  59. SPSignDssParams(
  60. PSPContext pContext,
  61. PSPCredential pCred,
  62. PBYTE pbParams,
  63. DWORD cbParams,
  64. PBYTE pbEncodedSignature,
  65. PDWORD pcbEncodedSignature)
  66. {
  67. HCRYPTHASH hHash;
  68. BYTE rgbSignature[DSA_SIGNATURE_SIZE];
  69. DWORD cbSignature;
  70. if(pCred == NULL)
  71. {
  72. return SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE);
  73. }
  74. if(!CryptCreateHash(pCred->hProv,
  75. CALG_SHA,
  76. 0,
  77. 0,
  78. &hHash))
  79. {
  80. SP_LOG_RESULT(GetLastError());
  81. return PCT_ERR_ILLEGAL_MESSAGE;
  82. }
  83. if(!CryptHashData(hHash, pContext->rgbS3CRandom, 32, 0))
  84. {
  85. SP_LOG_RESULT(GetLastError());
  86. CryptDestroyHash(hHash);
  87. return PCT_ERR_ILLEGAL_MESSAGE;
  88. }
  89. if(!CryptHashData(hHash, pContext->rgbS3SRandom, 32, 0))
  90. {
  91. SP_LOG_RESULT(GetLastError());
  92. CryptDestroyHash(hHash);
  93. return PCT_ERR_ILLEGAL_MESSAGE;
  94. }
  95. if(!CryptHashData(hHash, pbParams, cbParams, 0))
  96. {
  97. SP_LOG_RESULT(GetLastError());
  98. CryptDestroyHash(hHash);
  99. return PCT_ERR_ILLEGAL_MESSAGE;
  100. }
  101. cbSignature = sizeof(rgbSignature);
  102. if(!CryptSignHash(hHash,
  103. pCred->dwKeySpec,
  104. NULL,
  105. 0,
  106. rgbSignature,
  107. &cbSignature))
  108. {
  109. SP_LOG_RESULT(GetLastError());
  110. CryptDestroyHash(hHash);
  111. return PCT_ERR_ILLEGAL_MESSAGE;
  112. }
  113. CryptDestroyHash(hHash);
  114. if(!CryptEncodeObject(X509_ASN_ENCODING,
  115. X509_DSS_SIGNATURE,
  116. rgbSignature,
  117. pbEncodedSignature,
  118. pcbEncodedSignature))
  119. {
  120. SP_LOG_RESULT(GetLastError());
  121. return PCT_ERR_ILLEGAL_MESSAGE;
  122. }
  123. // Return success.
  124. return PCT_ERR_OK;
  125. }
  126. SP_STATUS
  127. SPVerifyDssParams(
  128. PSPContext pContext,
  129. HCRYPTPROV hProv,
  130. HCRYPTKEY hPublicKey,
  131. PBYTE pbParams,
  132. DWORD cbParams,
  133. PBYTE pbEncodedSignature,
  134. DWORD cbEncodedSignature)
  135. {
  136. HCRYPTHASH hHash;
  137. BYTE rgbSignature[DSA_SIGNATURE_SIZE];
  138. DWORD cbSignature;
  139. // Decode the signature.
  140. cbSignature = sizeof(rgbSignature);
  141. if(!CryptDecodeObject(X509_ASN_ENCODING,
  142. X509_DSS_SIGNATURE,
  143. pbEncodedSignature,
  144. cbEncodedSignature,
  145. 0,
  146. rgbSignature,
  147. &cbSignature))
  148. {
  149. SP_LOG_RESULT(GetLastError());
  150. return PCT_ERR_ILLEGAL_MESSAGE;
  151. }
  152. if(!CryptCreateHash(hProv,
  153. CALG_SHA,
  154. 0,
  155. 0,
  156. &hHash))
  157. {
  158. SP_LOG_RESULT(GetLastError());
  159. return PCT_ERR_ILLEGAL_MESSAGE;
  160. }
  161. if(!CryptHashData(hHash, pContext->rgbS3CRandom, 32, 0))
  162. {
  163. SP_LOG_RESULT(GetLastError());
  164. CryptDestroyHash(hHash);
  165. return PCT_ERR_ILLEGAL_MESSAGE;
  166. }
  167. if(!CryptHashData(hHash, pContext->rgbS3SRandom, 32, 0))
  168. {
  169. SP_LOG_RESULT(GetLastError());
  170. CryptDestroyHash(hHash);
  171. return PCT_ERR_ILLEGAL_MESSAGE;
  172. }
  173. if(!CryptHashData(hHash, pbParams, cbParams, 0))
  174. {
  175. SP_LOG_RESULT(GetLastError());
  176. CryptDestroyHash(hHash);
  177. return PCT_ERR_ILLEGAL_MESSAGE;
  178. }
  179. if(!CryptVerifySignature(hHash,
  180. rgbSignature,
  181. cbSignature,
  182. hPublicKey,
  183. NULL,
  184. 0))
  185. {
  186. SP_LOG_RESULT(GetLastError());
  187. CryptDestroyHash(hHash);
  188. return PCT_INT_MSG_ALTERED;
  189. }
  190. CryptDestroyHash(hHash);
  191. return PCT_ERR_OK;
  192. }
  193. SP_STATUS
  194. GetDHEphemKey(
  195. PSPContext pContext,
  196. HCRYPTPROV * phProv,
  197. HCRYPTKEY * phTek)
  198. {
  199. PSPCredentialGroup pCredGroup;
  200. PSPCredential pCred;
  201. DWORD dwKeySize;
  202. DWORD cbData;
  203. DWORD Status;
  204. pCredGroup = pContext->RipeZombie->pServerCred;
  205. if(pCredGroup == NULL)
  206. {
  207. return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  208. }
  209. pCred = pContext->RipeZombie->pActiveServerCred;
  210. if(pCredGroup == NULL)
  211. {
  212. return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  213. }
  214. LockCredentialExclusive(pCredGroup);
  215. if(phProv)
  216. {
  217. *phProv = pCred->hProv;
  218. }
  219. dwKeySize = 1024;
  220. // Determine if we've already created an ephemeral key.
  221. if(pCred->hTek)
  222. {
  223. *phTek = pCred->hTek;
  224. Status = PCT_ERR_OK;
  225. goto cleanup;
  226. }
  227. // Generate the ephemeral key.
  228. if(!CryptGenKey(pCred->hProv,
  229. CALG_DH_EPHEM,
  230. dwKeySize << 16,
  231. phTek))
  232. {
  233. SP_LOG_RESULT(GetLastError());
  234. Status = PCT_INT_INTERNAL_ERROR;
  235. goto cleanup;
  236. }
  237. pCred->hTek = *phTek;
  238. Status = PCT_ERR_OK;
  239. cleanup:
  240. if(Status == PCT_ERR_OK)
  241. {
  242. // Determine size of key exchange key.
  243. cbData = sizeof(DWORD);
  244. if(!CryptGetKeyParam(*phTek,
  245. KP_BLOCKLEN,
  246. (PBYTE)&pContext->RipeZombie->dwExchStrength,
  247. &cbData,
  248. 0))
  249. {
  250. SP_LOG_RESULT(GetLastError());
  251. pContext->RipeZombie->dwExchStrength = 0;
  252. }
  253. }
  254. UnlockCredential(pCredGroup);
  255. return Status;
  256. }
  257. //+---------------------------------------------------------------------------
  258. //
  259. // Function: DHGenerateServerExchangeValue
  260. //
  261. // Synopsis: Create a ServerKeyExchange message, containing an ephemeral
  262. // DH key.
  263. //
  264. // Arguments: [pContext] -- Schannel context.
  265. // [pServerExchangeValue] --
  266. // [pcbServerExchangeValue] --
  267. //
  268. // History: 03-24-98 jbanes Added CAPI integration.
  269. //
  270. // Notes: The following data is placed in the output buffer by
  271. // this routine:
  272. //
  273. // struct {
  274. // opaque dh_p<1..2^16-1>;
  275. // opaque dh_g<1..2^16-1>;
  276. // opaque dh_Ys<1..2^16-1>;
  277. // } ServerDHParams;
  278. //
  279. // struct {
  280. // ServerDHParams params;
  281. // Signature signed_params;
  282. // } ServerKeyExchange;
  283. //
  284. //----------------------------------------------------------------------------
  285. SP_STATUS
  286. WINAPI
  287. DHGenerateServerExchangeValue(
  288. PSPContext pContext, // in
  289. PBYTE pServerExchangeValue, // out
  290. DWORD * pcbServerExchangeValue) // in/out
  291. {
  292. PSPCredential pCred;
  293. HCRYPTPROV hProv = 0;
  294. HCRYPTKEY hServerDhKey = 0;
  295. PBYTE pbMessage;
  296. DWORD cbMessage;
  297. DWORD cbBytesLeft;
  298. DWORD cbData;
  299. DWORD cbP;
  300. DWORD cbG;
  301. DWORD cbY;
  302. DWORD cbSignature;
  303. SP_STATUS pctRet;
  304. BOOL fImpersonating = FALSE;
  305. pCred = pContext->RipeZombie->pActiveServerCred;
  306. if(pCred == NULL)
  307. {
  308. return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  309. }
  310. if(pContext->RipeZombie->fProtocol != SP_PROT_SSL3_SERVER &&
  311. pContext->RipeZombie->fProtocol != SP_PROT_TLS1_SERVER)
  312. {
  313. // SSL2 and PCT do not support DH.
  314. return SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH);
  315. }
  316. // Always send a ServerKeyExchange message.
  317. pContext->fExchKey = TRUE;
  318. fImpersonating = SslImpersonateClient();
  319. //
  320. // Generate ephemeral DH key.
  321. //
  322. pctRet = GetDHEphemKey(pContext,
  323. &hProv,
  324. &hServerDhKey);
  325. if(pctRet != PCT_ERR_OK)
  326. {
  327. SP_LOG_RESULT(pctRet);
  328. goto cleanup;
  329. }
  330. //
  331. // Estimate sizes of P, G, and Y.
  332. //
  333. if(!CryptGetKeyParam(hServerDhKey, KP_P, NULL, &cbP, 0))
  334. {
  335. SP_LOG_RESULT(GetLastError());
  336. pctRet = PCT_INT_INTERNAL_ERROR;
  337. goto cleanup;
  338. }
  339. if(!CryptGetKeyParam(hServerDhKey, KP_G, NULL, &cbG, 0))
  340. {
  341. SP_LOG_RESULT(GetLastError());
  342. pctRet = PCT_INT_INTERNAL_ERROR;
  343. goto cleanup;
  344. }
  345. if(!CryptExportKey(hServerDhKey,
  346. 0,
  347. PUBLICKEYBLOB,
  348. 0,
  349. NULL,
  350. &cbY))
  351. {
  352. SP_LOG_RESULT(GetLastError());
  353. pctRet = PCT_INT_INTERNAL_ERROR;
  354. goto cleanup;
  355. }
  356. //
  357. // Compute approximate size of ServerKeyExchange message.
  358. //
  359. cbMessage = 2 + cbP +
  360. 2 + cbG +
  361. 2 + cbY + sizeof(DWORD) +
  362. 2 + MAX_DSA_ENCODED_SIGNATURE_SIZE;
  363. if(pServerExchangeValue == NULL)
  364. {
  365. *pcbServerExchangeValue = cbMessage;
  366. pctRet = PCT_ERR_OK;
  367. goto cleanup;
  368. }
  369. if(*pcbServerExchangeValue < cbMessage)
  370. {
  371. *pcbServerExchangeValue = cbMessage;
  372. pctRet = SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL);
  373. goto cleanup;
  374. }
  375. //
  376. // Build the ServerDHParams structure.
  377. //
  378. pbMessage = pServerExchangeValue;
  379. cbBytesLeft = cbMessage;
  380. // Get P.
  381. if(!CryptGetKeyParam(hServerDhKey, KP_P, pbMessage + 2, &cbP, 0))
  382. {
  383. SP_LOG_RESULT(GetLastError());
  384. pctRet = PCT_INT_INTERNAL_ERROR;
  385. goto cleanup;
  386. }
  387. ReverseInPlace(pbMessage + 2, cbP);
  388. pbMessage[0] = MSBOF(cbP);
  389. pbMessage[1] = LSBOF(cbP);
  390. pbMessage += 2 + cbP;
  391. cbBytesLeft -= 2 + cbP;
  392. // Get G.
  393. if(!CryptGetKeyParam(hServerDhKey, KP_G, pbMessage + 2, &cbG, 0))
  394. {
  395. SP_LOG_RESULT(GetLastError());
  396. pctRet = PCT_INT_INTERNAL_ERROR;
  397. goto cleanup;
  398. }
  399. ReverseInPlace(pbMessage + 2, cbG);
  400. pbMessage[0] = MSBOF(cbG);
  401. pbMessage[1] = LSBOF(cbG);
  402. pbMessage += 2 + cbG;
  403. cbBytesLeft -= 2 + cbG;
  404. // Get Ys.
  405. {
  406. BLOBHEADER *pBlobHeader;
  407. DHPUBKEY * pDHPubKey;
  408. PBYTE pbKey;
  409. DWORD cbKey;
  410. pBlobHeader = (BLOBHEADER *)ROUND_UP_POINTER(pbMessage, ALIGN_DWORD);
  411. cbData = cbBytesLeft - sizeof(DWORD);
  412. if(!CryptExportKey(hServerDhKey,
  413. 0,
  414. PUBLICKEYBLOB,
  415. 0,
  416. (PBYTE)pBlobHeader,
  417. &cbData))
  418. {
  419. SP_LOG_RESULT(GetLastError());
  420. pctRet = PCT_INT_INTERNAL_ERROR;
  421. goto cleanup;
  422. }
  423. pDHPubKey = (DHPUBKEY *)(pBlobHeader + 1);
  424. pbKey = (BYTE *)(pDHPubKey + 1);
  425. cbKey = pDHPubKey->bitlen / 8;
  426. if(pDHPubKey->bitlen % 8) cbKey++;
  427. MoveMemory(pbMessage + 2, pbKey, cbKey);
  428. ReverseInPlace(pbMessage + 2, cbKey);
  429. pbMessage[0] = MSBOF(cbKey);
  430. pbMessage[1] = LSBOF(cbKey);
  431. pbMessage += 2 + cbKey;
  432. cbBytesLeft -= 2 + cbKey;
  433. }
  434. //
  435. // Sign the ServerDHParams structure.
  436. //
  437. cbSignature = cbBytesLeft - 2;
  438. pctRet = SPSignDssParams(pContext,
  439. pCred,
  440. pServerExchangeValue,
  441. (DWORD)(pbMessage - pServerExchangeValue),
  442. pbMessage + 2,
  443. &cbSignature);
  444. if(pctRet != PCT_ERR_OK)
  445. {
  446. SP_LOG_RESULT(pctRet);
  447. goto cleanup;
  448. }
  449. pbMessage[0] = MSBOF(cbSignature);
  450. pbMessage[1] = LSBOF(cbSignature);
  451. pbMessage += 2 + cbSignature;
  452. cbBytesLeft -= 2 + cbSignature;
  453. //
  454. // Update function outputs.
  455. //
  456. SP_ASSERT(cbBytesLeft < cbMessage);
  457. *pcbServerExchangeValue = (DWORD)(pbMessage - pServerExchangeValue);
  458. // Use ephemeral key for the new connection.
  459. pContext->RipeZombie->hMasterProv = hProv;
  460. pctRet = PCT_ERR_OK;
  461. cleanup:
  462. if(fImpersonating)
  463. {
  464. RevertToSelf();
  465. }
  466. return pctRet;
  467. }
  468. SP_STATUS
  469. ParseServerKeyExchange(
  470. PSPContext pContext, // in
  471. PBYTE pbMessage, // in
  472. DWORD cbMessage, // in
  473. PBYTE * ppbServerP, // out
  474. PDWORD pcbServerP, // out
  475. PBYTE * ppbServerG, // out
  476. PDWORD pcbServerG, // out
  477. PBYTE * ppbServerY, // out
  478. PDWORD pcbServerY, // out
  479. BOOL fValidateSig) // in
  480. {
  481. PBYTE pbData;
  482. BLOBHEADER *pPublicBlob;
  483. DWORD cbPublicBlob;
  484. HCRYPTKEY hServerPublic = 0;
  485. PBYTE pbSignature;
  486. DWORD cbSignature;
  487. DWORD cbSignedData;
  488. SP_STATUS pctRet;
  489. //
  490. // Parse out ServerKeyExchange message fields
  491. //
  492. pbData = pbMessage;
  493. if(pbData + 2 > pbMessage + cbMessage)
  494. {
  495. return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
  496. }
  497. *pcbServerP = MAKEWORD(pbData[1], pbData[0]);
  498. *ppbServerP = pbData + 2;
  499. pbData += 2 + *pcbServerP;
  500. if(pbData + 2 > pbMessage + cbMessage)
  501. {
  502. return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
  503. }
  504. *pcbServerG = MAKEWORD(pbData[1], pbData[0]);
  505. *ppbServerG = pbData + 2;
  506. pbData += 2 + *pcbServerG;
  507. if(pbData + 2 > pbMessage + cbMessage)
  508. {
  509. return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
  510. }
  511. *pcbServerY = MAKEWORD(pbData[1], pbData[0]);
  512. *ppbServerY = pbData + 2;
  513. pbData += 2 + *pcbServerY;
  514. if(pbData + 2 > pbMessage + cbMessage)
  515. {
  516. return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
  517. }
  518. cbSignedData = (DWORD)(pbData - pbMessage);
  519. cbSignature = MAKEWORD(pbData[1], pbData[0]);
  520. pbSignature = pbData + 2;
  521. pbData += 2 + cbSignature;
  522. if(pbData != pbMessage + cbMessage)
  523. {
  524. return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
  525. }
  526. if(fValidateSig == FALSE)
  527. {
  528. return PCT_ERR_OK;
  529. }
  530. //
  531. // Validate signature.
  532. //
  533. pPublicBlob = pContext->RipeZombie->pRemotePublic->pPublic;
  534. cbPublicBlob = pContext->RipeZombie->pRemotePublic->cbPublic;
  535. if(!CryptImportKey(pContext->RipeZombie->hMasterProv,
  536. (PBYTE)pPublicBlob,
  537. cbPublicBlob,
  538. 0,
  539. 0,
  540. &hServerPublic))
  541. {
  542. return SP_LOG_RESULT(GetLastError());
  543. }
  544. pctRet = SPVerifyDssParams(
  545. pContext,
  546. pContext->RipeZombie->hMasterProv,
  547. hServerPublic,
  548. pbMessage,
  549. cbSignedData,
  550. pbSignature,
  551. cbSignature);
  552. if(pctRet != PCT_ERR_OK)
  553. {
  554. CryptDestroyKey(hServerPublic);
  555. return SP_LOG_RESULT(pctRet);
  556. }
  557. CryptDestroyKey(hServerPublic);
  558. return PCT_ERR_OK;
  559. }
  560. //+---------------------------------------------------------------------------
  561. //
  562. // Function: DHGenerateClientExchangeValue
  563. //
  564. // Synopsis: Create a ClientKeyExchange message, containing an ephemeral
  565. // DH key.
  566. //
  567. // Arguments:
  568. //
  569. // History: 03-24-98 jbanes Added CAPI integration.
  570. //
  571. // Notes: The following data is placed in the output buffer by
  572. // this routine:
  573. //
  574. // struct {
  575. // opaque dh_Yc<1..2^16-1>;
  576. // } ClientDiffieHellmanPublic;
  577. //
  578. //----------------------------------------------------------------------------
  579. SP_STATUS
  580. WINAPI
  581. DHGenerateClientExchangeValue(
  582. SPContext * pContext, // in
  583. PUCHAR pServerExchangeValue, // in
  584. DWORD cbServerExchangeValue, // in
  585. PUCHAR pClientClearValue, // out
  586. DWORD * pcbClientClearValue, // in/out
  587. PUCHAR pClientExchangeValue, // out
  588. DWORD * pcbClientExchangeValue) // in/out
  589. {
  590. HCRYPTKEY hClientDHKey = 0;
  591. PSessCacheItem pZombie;
  592. CRYPT_DATA_BLOB Data;
  593. ALG_ID Algid;
  594. DWORD cbHeader;
  595. SP_STATUS pctRet;
  596. PBYTE pbServerP = NULL;
  597. DWORD cbServerP;
  598. PBYTE pbServerG = NULL;
  599. DWORD cbServerG;
  600. PBYTE pbServerY = NULL;
  601. DWORD cbServerY;
  602. PBYTE pbClientY = NULL;
  603. DWORD cbClientY;
  604. PBYTE pbBlob = NULL;
  605. DWORD cbBlob;
  606. DWORD cbData;
  607. DWORD dwKeySize;
  608. UNREFERENCED_PARAMETER(pClientClearValue);
  609. UNREFERENCED_PARAMETER(pcbClientClearValue);
  610. pZombie = pContext->RipeZombie;
  611. if(pZombie == NULL)
  612. {
  613. return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  614. }
  615. if(pZombie->hMasterProv == 0)
  616. {
  617. return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  618. }
  619. // We're doing a full handshake.
  620. pContext->Flags |= CONTEXT_FLAG_FULL_HANDSHAKE;
  621. if(pZombie->fProtocol == SP_PROT_SSL3_CLIENT)
  622. {
  623. Algid = CALG_SSL3_MASTER;
  624. }
  625. else if(pZombie->fProtocol == SP_PROT_TLS1_CLIENT)
  626. {
  627. Algid = CALG_TLS1_MASTER;
  628. }
  629. else
  630. {
  631. return SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH);
  632. }
  633. if(pServerExchangeValue == NULL)
  634. {
  635. return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
  636. }
  637. //
  638. // Is the output buffer large enough?
  639. //
  640. pctRet = ParseServerKeyExchange(pContext,
  641. pServerExchangeValue,
  642. cbServerExchangeValue,
  643. &pbServerP,
  644. &cbServerP,
  645. &pbServerG,
  646. &cbServerG,
  647. &pbServerY,
  648. &cbServerY,
  649. FALSE);
  650. if(pctRet != PCT_ERR_OK)
  651. {
  652. return pctRet;
  653. }
  654. cbBlob = sizeof(BLOBHEADER) + sizeof(DHPUBKEY) + cbServerY + 20;
  655. if(pClientExchangeValue == NULL)
  656. {
  657. *pcbClientExchangeValue = cbBlob;
  658. return PCT_ERR_OK;
  659. }
  660. if(*pcbClientExchangeValue < cbBlob)
  661. {
  662. *pcbClientExchangeValue = cbBlob;
  663. return SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL);
  664. }
  665. //
  666. // Parse the ServerKeyExchange message.
  667. //
  668. pctRet = ParseServerKeyExchange(pContext,
  669. pServerExchangeValue,
  670. cbServerExchangeValue,
  671. &pbServerP,
  672. &cbServerP,
  673. &pbServerG,
  674. &cbServerG,
  675. &pbServerY,
  676. &cbServerY,
  677. TRUE);
  678. if(pctRet != PCT_ERR_OK)
  679. {
  680. return pctRet;
  681. }
  682. //
  683. // Create buffer to use for endian-izing data.
  684. //
  685. cbBlob = sizeof(BLOBHEADER) + sizeof(DHPUBKEY) + cbServerY;
  686. cbBlob = max(cbBlob, cbServerP);
  687. cbBlob = max(cbBlob, cbServerG);
  688. SafeAllocaAllocate(pbBlob, cbBlob);
  689. if(pbBlob == NULL)
  690. {
  691. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  692. goto cleanup;
  693. }
  694. //
  695. // Generate and set the parameters on the client DH key.
  696. //
  697. dwKeySize = cbServerP * 8;
  698. if(!CryptGenKey(pZombie->hMasterProv,
  699. CALG_DH_EPHEM,
  700. (dwKeySize << 16) | CRYPT_PREGEN,
  701. &hClientDHKey))
  702. {
  703. pctRet = SP_LOG_RESULT(GetLastError());
  704. goto cleanup;
  705. }
  706. ReverseMemCopy(pbBlob, pbServerP, cbServerP);
  707. Data.pbData = pbBlob;
  708. Data.cbData = cbServerP;
  709. if(!CryptSetKeyParam(hClientDHKey,
  710. KP_P,
  711. (PBYTE)&Data,
  712. 0))
  713. {
  714. pctRet = SP_LOG_RESULT(GetLastError());
  715. goto cleanup;
  716. }
  717. ReverseMemCopy(pbBlob, pbServerG, cbServerG);
  718. Data.pbData = pbBlob;
  719. Data.cbData = cbServerG;
  720. if(cbServerG < cbServerP)
  721. {
  722. // Expand G so that it's the same size as P.
  723. ZeroMemory(pbBlob + cbServerG, cbServerP - cbServerG);
  724. Data.cbData = cbServerP;
  725. }
  726. if(!CryptSetKeyParam(hClientDHKey,
  727. KP_G,
  728. (PBYTE)&Data,
  729. 0))
  730. {
  731. pctRet = SP_LOG_RESULT(GetLastError());
  732. goto cleanup;
  733. }
  734. // actually create the client private DH key
  735. if(!CryptSetKeyParam(hClientDHKey,
  736. KP_X,
  737. NULL,
  738. 0))
  739. {
  740. pctRet = SP_LOG_RESULT(GetLastError());
  741. goto cleanup;
  742. }
  743. //
  744. // Import the server's public key and generate the master secret.
  745. //
  746. {
  747. BLOBHEADER * pBlobHeader;
  748. DHPUBKEY * pDHPubKey;
  749. PBYTE pbKey;
  750. // Build PUBLICKEYBLOB around the server's public key.
  751. pBlobHeader = (BLOBHEADER *)pbBlob;
  752. pDHPubKey = (DHPUBKEY *)(pBlobHeader + 1);
  753. pbKey = (PBYTE)(pDHPubKey + 1);
  754. pBlobHeader->bType = PUBLICKEYBLOB;
  755. pBlobHeader->bVersion = CUR_BLOB_VERSION;
  756. pBlobHeader->reserved = 0;
  757. pBlobHeader->aiKeyAlg = CALG_DH_EPHEM;
  758. pDHPubKey->magic = MAGIC_DH1;
  759. pDHPubKey->bitlen = cbServerY * 8;
  760. ReverseMemCopy(pbKey, pbServerY, cbServerY);
  761. if(!CryptImportKey(pZombie->hMasterProv,
  762. pbBlob,
  763. cbBlob,
  764. hClientDHKey,
  765. 0,
  766. &pZombie->hMasterKey))
  767. {
  768. pctRet = GetLastError();
  769. goto cleanup;
  770. }
  771. }
  772. // Determine size of key exchange key.
  773. cbData = sizeof(DWORD);
  774. if(!CryptGetKeyParam(hClientDHKey,
  775. KP_BLOCKLEN,
  776. (PBYTE)&pZombie->dwExchStrength,
  777. &cbData,
  778. 0))
  779. {
  780. SP_LOG_RESULT(GetLastError());
  781. pContext->RipeZombie->dwExchStrength = 0;
  782. }
  783. //
  784. // Convert the agreed key to the appropriate master key type.
  785. //
  786. if(!CryptSetKeyParam(pZombie->hMasterKey,
  787. KP_ALGID,
  788. (PBYTE)&Algid,
  789. 0))
  790. {
  791. pctRet = SP_LOG_RESULT(GetLastError());
  792. goto cleanup;
  793. }
  794. //
  795. // Export the client public key, strip off the blob header
  796. // goo and attach a two byte length field. This will make up our
  797. // ClientKeyExchange message.
  798. //
  799. if(!CryptExportKey(hClientDHKey,
  800. 0,
  801. PUBLICKEYBLOB,
  802. 0,
  803. pClientExchangeValue,
  804. pcbClientExchangeValue))
  805. {
  806. pctRet = SP_LOG_RESULT(GetLastError());
  807. goto cleanup;
  808. }
  809. cbHeader = sizeof(BLOBHEADER) + sizeof(DHPUBKEY);
  810. cbClientY = *pcbClientExchangeValue - cbHeader;
  811. pbClientY = pClientExchangeValue + cbHeader;
  812. pClientExchangeValue[0] = MSBOF(cbClientY);
  813. pClientExchangeValue[1] = LSBOF(cbClientY);
  814. ReverseInPlace(pbClientY, cbClientY);
  815. MoveMemory(pClientExchangeValue + 2, pbClientY, cbClientY);
  816. *pcbClientExchangeValue = 2 + cbClientY;
  817. //
  818. // Build the session keys.
  819. //
  820. pctRet = MakeSessionKeys(pContext,
  821. pZombie->hMasterProv,
  822. pZombie->hMasterKey);
  823. if(pctRet != PCT_ERR_OK)
  824. {
  825. goto cleanup;
  826. }
  827. // Update perf counter.
  828. InterlockedIncrement(&g_cClientHandshakes);
  829. pctRet = PCT_ERR_OK;
  830. cleanup:
  831. if(pbBlob)
  832. {
  833. SafeAllocaFree(pbBlob);
  834. }
  835. if(hClientDHKey)
  836. {
  837. CryptDestroyKey(hClientDHKey);
  838. }
  839. return pctRet;
  840. }
  841. //+---------------------------------------------------------------------------
  842. //
  843. // Function: PkcsGenerateServerMasterKey
  844. //
  845. // Synopsis: Decrypt the master secret (from the ClientKeyExchange message)
  846. // and derive the session keys from it.
  847. //
  848. // Arguments: [pContext] -- Schannel context.
  849. // [pClientClearValue] -- Not used.
  850. // [cbClientClearValue] -- Not used.
  851. // [pClientExchangeValue] --
  852. // [cbClientExchangeValue] --
  853. //
  854. // History: 03-25-98 jbanes Created.
  855. //
  856. // Notes: The following data is supposed to be in the input buffer:
  857. //
  858. // struct {
  859. // opaque dh_Yc<1..2^16-1>;
  860. // } ClientDiffieHellmanPublic;
  861. //
  862. //----------------------------------------------------------------------------
  863. SP_STATUS
  864. WINAPI
  865. DHGenerateServerMasterKey(
  866. SPContext * pContext, // in
  867. PUCHAR pClientClearValue, // in
  868. DWORD cbClientClearValue, // in
  869. PUCHAR pClientExchangeValue, // in
  870. DWORD cbClientExchangeValue) // in
  871. {
  872. PSessCacheItem pZombie;
  873. ALG_ID Algid;
  874. SP_STATUS pctRet;
  875. PBYTE pbClientY;
  876. DWORD cbClientY;
  877. HCRYPTKEY hTek;
  878. BOOL fImpersonating = FALSE;
  879. UNREFERENCED_PARAMETER(pClientClearValue);
  880. UNREFERENCED_PARAMETER(cbClientClearValue);
  881. pZombie = pContext->RipeZombie;
  882. if(pZombie == NULL)
  883. {
  884. return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  885. }
  886. if(pZombie->hMasterProv == 0)
  887. {
  888. return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  889. }
  890. // We're doing a full handshake.
  891. pContext->Flags |= CONTEXT_FLAG_FULL_HANDSHAKE;
  892. fImpersonating = SslImpersonateClient();
  893. pctRet = GetDHEphemKey(pContext,
  894. NULL,
  895. &hTek);
  896. if(pctRet != PCT_ERR_OK)
  897. {
  898. SP_LOG_RESULT(pctRet);
  899. goto cleanup;
  900. }
  901. if(pZombie->fProtocol == SP_PROT_SSL3_SERVER)
  902. {
  903. Algid = CALG_SSL3_MASTER;
  904. }
  905. else if(pZombie->fProtocol == SP_PROT_TLS1_SERVER)
  906. {
  907. Algid = CALG_TLS1_MASTER;
  908. }
  909. else
  910. {
  911. pctRet = SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH);
  912. goto cleanup;
  913. }
  914. //
  915. // Parse ClientKeyExchange message.
  916. //
  917. if(pClientExchangeValue == NULL || cbClientExchangeValue <= 2)
  918. {
  919. pctRet = SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
  920. goto cleanup;
  921. }
  922. cbClientY = MAKEWORD(pClientExchangeValue[1], pClientExchangeValue[0]);
  923. pbClientY = pClientExchangeValue + 2;
  924. if(2 + cbClientY != cbClientExchangeValue)
  925. {
  926. pctRet = SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
  927. goto cleanup;
  928. }
  929. if(cbClientY == 0)
  930. {
  931. pctRet = SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
  932. goto cleanup;
  933. }
  934. //
  935. // Import the client's public key and generate the master secret.
  936. //
  937. {
  938. BLOBHEADER * pBlobHeader;
  939. DHPUBKEY * pDHPubKey;
  940. PBYTE pbKey;
  941. PBYTE pbBlob;
  942. DWORD cbBlob;
  943. // Build PUBLICKEYBLOB around the server's public key.
  944. cbBlob = sizeof(BLOBHEADER) + sizeof(DHPUBKEY) + cbClientY;
  945. SafeAllocaAllocate(pbBlob, cbBlob);
  946. if(pbBlob == NULL)
  947. {
  948. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  949. goto cleanup;
  950. }
  951. pBlobHeader = (BLOBHEADER *)pbBlob;
  952. pDHPubKey = (DHPUBKEY *)(pBlobHeader + 1);
  953. pbKey = (PBYTE)(pDHPubKey + 1);
  954. pBlobHeader->bType = PUBLICKEYBLOB;
  955. pBlobHeader->bVersion = CUR_BLOB_VERSION;
  956. pBlobHeader->reserved = 0;
  957. pBlobHeader->aiKeyAlg = CALG_DH_EPHEM;
  958. pDHPubKey->magic = MAGIC_DH1;
  959. pDHPubKey->bitlen = cbClientY * 8;
  960. ReverseMemCopy(pbKey, pbClientY, cbClientY);
  961. if(!CryptImportKey(pZombie->hMasterProv,
  962. pbBlob,
  963. cbBlob,
  964. hTek,
  965. 0,
  966. &pZombie->hMasterKey))
  967. {
  968. pctRet = GetLastError();
  969. SafeAllocaFree(pbBlob);
  970. goto cleanup;
  971. }
  972. SafeAllocaFree(pbBlob);
  973. }
  974. //
  975. // Convert the agreed key to the appropriate master key type.
  976. //
  977. if(!CryptSetKeyParam(pZombie->hMasterKey,
  978. KP_ALGID, (PBYTE)&Algid,
  979. 0))
  980. {
  981. pctRet = SP_LOG_RESULT(GetLastError());
  982. goto cleanup;
  983. }
  984. //
  985. // Build the session keys.
  986. //
  987. pctRet = MakeSessionKeys(pContext,
  988. pZombie->hMasterProv,
  989. pZombie->hMasterKey);
  990. if(pctRet != PCT_ERR_OK)
  991. {
  992. goto cleanup;
  993. }
  994. // Update perf counter.
  995. InterlockedIncrement(&g_cServerHandshakes);
  996. pctRet = PCT_ERR_OK;
  997. cleanup:
  998. if(fImpersonating)
  999. {
  1000. RevertToSelf();
  1001. }
  1002. return pctRet;
  1003. }
  1004. void
  1005. ReverseInPlace(PUCHAR pByte, DWORD cbByte)
  1006. {
  1007. DWORD i;
  1008. BYTE bSave;
  1009. for(i=0; i< cbByte/2; i++)
  1010. {
  1011. bSave = pByte[i];
  1012. pByte[i] = pByte[cbByte-i-1];
  1013. pByte[cbByte-i-1] = bSave;
  1014. }
  1015. }