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.

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