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.

1320 lines
32 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: context.c
  7. //
  8. // Contents: Schannel context management routines.
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 09-23-97 jbanes LSA integration stuff.
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <spbase.h>
  18. #include <certmap.h>
  19. #include <mapper.h>
  20. #include <dsysdbg.h>
  21. DWORD g_cContext = 0;
  22. #if DBG
  23. void DumpContexts(void);
  24. static void AddContextToList(PSPContext pContext);
  25. static void DeleteContextFromList(PSPContext pContext);
  26. #endif
  27. /************************************************************************
  28. * SPContextCreate
  29. *
  30. * Create a new SPContext, and initialize it.
  31. *
  32. * Returns - PSPContext pointer to context object.
  33. *
  34. \***********************************************************************/
  35. PSPContext SPContextCreate(LPWSTR pszTarget)
  36. {
  37. PSPContext pContext;
  38. SP_BEGIN("SPContextCreate");
  39. pContext = (PSPContext)SPExternalAlloc( sizeof(SPContext));
  40. if(!pContext)
  41. {
  42. SP_RETURN(NULL);
  43. }
  44. DebugLog((DEB_TRACE, "Create context:0x%p\n", pContext));
  45. FillMemory(pContext, sizeof(SPContext), 0);
  46. pContext->Magic = SP_CONTEXT_MAGIC;
  47. pContext->Flags = 0;
  48. GenerateRandomThumbprint(&pContext->ContextThumbprint);
  49. if(pszTarget)
  50. {
  51. pContext->pszTarget = SPExternalAlloc((lstrlenW(pszTarget) + 1) * sizeof(WCHAR));
  52. if(pContext->pszTarget == NULL)
  53. {
  54. SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  55. SPExternalFree(pContext);
  56. SP_RETURN(NULL);
  57. }
  58. lstrcpyW(pContext->pszTarget, pszTarget);
  59. }
  60. pContext->dwRequestedCF = CF_EXPORT;
  61. if(SslGlobalStrongEncryptionPermitted)
  62. {
  63. pContext->dwRequestedCF |= CF_DOMESTIC;
  64. }
  65. pContext->fCertChainsAllowed = FALSE;
  66. g_cContext++;
  67. #if DBG
  68. //AddContextToList(pContext);
  69. #endif
  70. SP_RETURN(pContext);
  71. }
  72. /************************************************************************
  73. * VOID SPContextClean(PSPContext pContext)
  74. *
  75. * Clean out everything used by the handshake (in case we want
  76. * to do another).
  77. *
  78. \***********************************************************************/
  79. BOOL
  80. SPContextClean(PSPContext pContext)
  81. {
  82. SP_BEGIN("SPContextClean");
  83. if(pContext == NULL || pContext->Magic != SP_CONTEXT_MAGIC) {
  84. DebugLog((DEB_WARN, "Attempt to delete invalid context\n"));
  85. SP_RETURN(FALSE);
  86. }
  87. if(pContext->pbEncryptedKey)
  88. {
  89. SPExternalFree(pContext->pbEncryptedKey);
  90. pContext->pbEncryptedKey = NULL;
  91. }
  92. if(pContext->pbServerKeyExchange)
  93. {
  94. SPExternalFree(pContext->pbServerKeyExchange);
  95. pContext->pbServerKeyExchange = NULL;
  96. }
  97. if(pContext->pbIssuerList)
  98. {
  99. SPExternalFree(pContext->pbIssuerList);
  100. pContext->pbIssuerList = NULL;
  101. }
  102. if(pContext->pClientHello)
  103. {
  104. SPExternalFree(pContext->pClientHello);
  105. pContext->pClientHello = NULL;
  106. }
  107. if((pContext->Flags & CONTEXT_FLAG_FULL_HANDSHAKE) &&
  108. (pContext->RipeZombie != NULL) &&
  109. (pContext->RipeZombie->pClientCred != NULL))
  110. {
  111. // We've just done a client-side full handshake in which a default
  112. // client certificate was selected. This client credential
  113. // technically belongs to the cache (so that other contexts can
  114. // query the certificate etc) but we want to free up the
  115. // application-process hProv now, while we're in the context
  116. // of the owning process.
  117. PSPCredential pClientCred = pContext->RipeZombie->pClientCred;
  118. if(pClientCred->hRemoteProv)
  119. {
  120. if(!RemoteCryptReleaseContext(
  121. pClientCred->hRemoteProv,
  122. 0,
  123. pClientCred->dwCapiFlags))
  124. {
  125. SP_LOG_RESULT(GetLastError());
  126. }
  127. pClientCred->hRemoteProv = 0;
  128. }
  129. }
  130. pContext->fExchKey = FALSE;
  131. SP_RETURN(TRUE);
  132. }
  133. /************************************************************************
  134. * VOID SPDeleteContext(PSPContext pContext)
  135. *
  136. * Delete an existing context object.
  137. *
  138. \***********************************************************************/
  139. BOOL
  140. SPContextDelete(PSPContext pContext)
  141. {
  142. SP_BEGIN("SPContextDelete");
  143. DebugLog((DEB_TRACE, "Delete context:0x%p\n", pContext));
  144. if(pContext == NULL || pContext->Magic != SP_CONTEXT_MAGIC)
  145. {
  146. DebugLog((DEB_WARN, "Attempt to delete invalid context\n"));
  147. SP_RETURN(FALSE);
  148. }
  149. // DsysAssert((pContext->pCredGroup->dwFlags & CRED_FLAG_DELETED) == 0);
  150. if(pContext->State != SP_STATE_CONNECTED &&
  151. pContext->State != SP_STATE_SHUTDOWN)
  152. {
  153. DebugLog((DEB_WARN, "Attempting to delete an incompleted context\n"));
  154. // The context is being deleted in the middle of a handshake,
  155. // which is curious. This may be caused by the user aborting
  156. // an operation, or it may be caused by a reconfiguration of
  157. // the remote computer that caused the reconnect attempt to
  158. // fail. If it's the latter cause, then the only way to recover
  159. // is to request a full handshake next time. We have no way
  160. // of knowing which it is, so it's probably best that we kill
  161. // the current cache entry.
  162. if(pContext->RipeZombie)
  163. {
  164. pContext->RipeZombie->ZombieJuju = FALSE;
  165. }
  166. }
  167. SPContextClean(pContext);
  168. if(pContext->pszTarget)
  169. {
  170. SPExternalFree(pContext->pszTarget);
  171. pContext->pszTarget = NULL;
  172. }
  173. if(pContext->pszCredentialName)
  174. {
  175. SPExternalFree(pContext->pszCredentialName);
  176. pContext->pszCredentialName = NULL;
  177. }
  178. //
  179. // Delete session keys.
  180. //
  181. if(pContext->hReadKey)
  182. {
  183. if(pContext->pReadCipherInfo->aiCipher != CALG_SKIPJACK)
  184. {
  185. SchCryptDestroyKey(pContext->hReadKey, 0);
  186. pContext->hReadKey = 0;
  187. }
  188. }
  189. if(pContext->hPendingReadKey)
  190. {
  191. if(pContext->pPendingCipherInfo->aiCipher != CALG_SKIPJACK)
  192. {
  193. SchCryptDestroyKey(pContext->hPendingReadKey, 0);
  194. pContext->hPendingReadKey = 0;
  195. }
  196. }
  197. if(pContext->hWriteKey)
  198. {
  199. if(pContext->pWriteCipherInfo->aiCipher != CALG_SKIPJACK)
  200. {
  201. SchCryptDestroyKey(pContext->hWriteKey, 0);
  202. pContext->hWriteKey = 0;
  203. }
  204. }
  205. if(pContext->hPendingWriteKey)
  206. {
  207. if(pContext->pPendingCipherInfo->aiCipher != CALG_SKIPJACK)
  208. {
  209. SchCryptDestroyKey(pContext->hPendingWriteKey, 0);
  210. pContext->hPendingWriteKey = 0;
  211. }
  212. }
  213. if(pContext->hReadMAC)
  214. {
  215. if(pContext->pReadCipherInfo->aiCipher != CALG_SKIPJACK)
  216. {
  217. SchCryptDestroyKey(pContext->hReadMAC, 0);
  218. pContext->hReadMAC = 0;
  219. }
  220. }
  221. if(pContext->hPendingReadMAC)
  222. {
  223. if(pContext->pPendingCipherInfo->aiCipher != CALG_SKIPJACK)
  224. {
  225. SchCryptDestroyKey(pContext->hPendingReadMAC, 0);
  226. pContext->hPendingReadMAC = 0;
  227. }
  228. }
  229. if(pContext->hWriteMAC)
  230. {
  231. if(pContext->pWriteCipherInfo->aiCipher != CALG_SKIPJACK)
  232. {
  233. SchCryptDestroyKey(pContext->hWriteMAC, 0);
  234. pContext->hWriteMAC = 0;
  235. }
  236. }
  237. if(pContext->hPendingWriteMAC)
  238. {
  239. if(pContext->pPendingCipherInfo->aiCipher != CALG_SKIPJACK)
  240. {
  241. SchCryptDestroyKey(pContext->hPendingWriteMAC, 0);
  242. pContext->hPendingWriteMAC = 0;
  243. }
  244. }
  245. //
  246. // Delete the handshake hashes
  247. //
  248. if(pContext->hMd5Handshake)
  249. {
  250. SchCryptDestroyHash(pContext->hMd5Handshake, pContext->RipeZombie->dwCapiFlags);
  251. pContext->hMd5Handshake = 0;
  252. }
  253. if(pContext->hShaHandshake)
  254. {
  255. SchCryptDestroyHash(pContext->hShaHandshake, pContext->RipeZombie->dwCapiFlags);
  256. pContext->hShaHandshake = 0;
  257. }
  258. SPDereferenceCredential(pContext->pCredGroup);
  259. SPCacheDereference(pContext->RipeZombie);
  260. #if DBG
  261. //DeleteContextFromList(pContext);
  262. #endif
  263. FillMemory( pContext, sizeof( SPContext ), 0 );
  264. g_cContext--;
  265. SPExternalFree( pContext );
  266. SP_RETURN(TRUE);
  267. }
  268. /************************************************************************
  269. * SPContext SPContextSetCredentials
  270. *
  271. * Associate a set of credentials with a context.
  272. *
  273. * Returns - PSPContext pointer to context object.
  274. *
  275. \***********************************************************************/
  276. SP_STATUS
  277. SPContextSetCredentials(
  278. PSPContext pContext,
  279. PSPCredentialGroup pCred)
  280. {
  281. DWORD cbThumbprint;
  282. BOOL fNewCredentials = FALSE;
  283. SP_BEGIN("SPContextSetCredentials");
  284. if(pContext->Magic != SP_CONTEXT_MAGIC)
  285. {
  286. SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
  287. }
  288. // DsysAssert((pCred->dwFlags & CRED_FLAG_DELETED) == 0);
  289. //
  290. // Associate the credential group with the context.
  291. //
  292. if(pCred != pContext->pCredGroup)
  293. {
  294. if(pContext->pCredGroup)
  295. {
  296. SPDereferenceCredential(pContext->pCredGroup);
  297. }
  298. SPReferenceCredential(pCred);
  299. pContext->pCredGroup = pCred;
  300. fNewCredentials = TRUE;
  301. }
  302. //
  303. // Set the protocol.
  304. //
  305. if(pContext->State == SP_STATE_NONE)
  306. {
  307. switch(pCred->grbitProtocol)
  308. {
  309. case SP_PROT_UNI_CLIENT:
  310. case SP_PROT_UNI_SERVER:
  311. case SP_PROT_PCT1_CLIENT:
  312. case SP_PROT_PCT1_SERVER:
  313. case SP_PROT_SSL2_CLIENT:
  314. case SP_PROT_SSL2_SERVER:
  315. case SP_PROT_SSL3_CLIENT:
  316. case SP_PROT_SSL3_SERVER:
  317. case SP_PROT_TLS1_CLIENT:
  318. case SP_PROT_TLS1_SERVER:
  319. pContext->ProtocolHandler = ServerProtocolHandler;
  320. pContext->InitiateHello = GenerateHello;
  321. break;
  322. default:
  323. SP_RETURN(SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH));
  324. }
  325. }
  326. //
  327. // If the client application has supplied a new credential, then
  328. // attempt to choose a suitable client certificate to send to
  329. // the server.
  330. //
  331. if(fNewCredentials &&
  332. pContext->State == SSL3_STATE_GEN_SERVER_HELLORESP)
  333. {
  334. Ssl3CheckForExistingCred(pContext);
  335. }
  336. //
  337. // Allow the "manual cred validation" flag to be set from either
  338. // AcquireCredentialsHandle or InitializeSecurityContext.
  339. //
  340. if(pCred->dwFlags & CRED_FLAG_MANUAL_CRED_VALIDATION)
  341. {
  342. if((pContext->Flags & CONTEXT_FLAG_MUTUAL_AUTH) == 0)
  343. {
  344. pContext->Flags |= CONTEXT_FLAG_MANUAL_CRED_VALIDATION;
  345. }
  346. }
  347. SP_RETURN(PCT_ERR_OK);
  348. }
  349. SP_STATUS
  350. ContextInitCiphersFromCache(SPContext *pContext)
  351. {
  352. PSessCacheItem pZombie;
  353. SP_STATUS pctRet;
  354. pZombie = pContext->RipeZombie;
  355. pContext->pPendingCipherInfo = GetCipherInfo(pZombie->aiCipher, pZombie->dwStrength);
  356. pContext->pPendingHashInfo = GetHashInfo(pZombie->aiHash);
  357. pContext->pKeyExchInfo = GetKeyExchangeInfo(pZombie->SessExchSpec);
  358. pContext->dwPendingCipherSuiteIndex = pZombie->dwCipherSuiteIndex;
  359. if(!IsCipherAllowed(pContext,
  360. pContext->pPendingCipherInfo,
  361. pZombie->fProtocol,
  362. pZombie->dwCF))
  363. {
  364. pContext->pPendingCipherInfo = NULL;
  365. return (SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH));
  366. }
  367. // Load the pending hash structure
  368. pContext->pPendingHashInfo = GetHashInfo(pZombie->aiHash);
  369. if(!IsHashAllowed(pContext,
  370. pContext->pPendingHashInfo,
  371. pZombie->fProtocol))
  372. {
  373. pContext->pPendingHashInfo = NULL;
  374. return (SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH));
  375. }
  376. // load the exch info structure
  377. pContext->pKeyExchInfo = GetKeyExchangeInfo(pZombie->SessExchSpec);
  378. if(!IsExchAllowed(pContext,
  379. pContext->pKeyExchInfo,
  380. pZombie->fProtocol))
  381. {
  382. pContext->pKeyExchInfo = NULL;
  383. return (SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH));
  384. }
  385. // Determine the CSP to use, based on the key exchange algorithm.
  386. pctRet = DetermineClientCSP(pContext);
  387. if(pctRet != PCT_ERR_OK)
  388. {
  389. return SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH);
  390. }
  391. #if DBG
  392. switch(pZombie->fProtocol)
  393. {
  394. case SP_PROT_PCT1_CLIENT:
  395. DebugLog((DEB_TRACE, "Protocol:PCT Client\n"));
  396. break;
  397. case SP_PROT_PCT1_SERVER:
  398. DebugLog((DEB_TRACE, "Protocol:PCT Server\n"));
  399. break;
  400. case SP_PROT_SSL2_CLIENT:
  401. DebugLog((DEB_TRACE, "Protocol:SSL2 Client\n"));
  402. break;
  403. case SP_PROT_SSL2_SERVER:
  404. DebugLog((DEB_TRACE, "Protocol:SSL2 Server\n"));
  405. break;
  406. case SP_PROT_SSL3_CLIENT:
  407. DebugLog((DEB_TRACE, "Protocol:SSL3 Client\n"));
  408. break;
  409. case SP_PROT_SSL3_SERVER:
  410. DebugLog((DEB_TRACE, "Protocol:SSL3 Server\n"));
  411. break;
  412. case SP_PROT_TLS1_CLIENT:
  413. DebugLog((DEB_TRACE, "Protocol:TLS Client\n"));
  414. break;
  415. case SP_PROT_TLS1_SERVER:
  416. DebugLog((DEB_TRACE, "Protocol:TLS Server\n"));
  417. break;
  418. default:
  419. DebugLog((DEB_TRACE, "Protocol:0x%x\n", pZombie->fProtocol));
  420. }
  421. DebugLog((DEB_TRACE, "Cipher: %s\n", pContext->pPendingCipherInfo->szName));
  422. DebugLog((DEB_TRACE, "Strength:%d\n", pContext->pPendingCipherInfo->dwStrength));
  423. DebugLog((DEB_TRACE, "Hash: %s\n", pContext->pPendingHashInfo->szName));
  424. DebugLog((DEB_TRACE, "Exchange:%s\n", pContext->pKeyExchInfo->szName));
  425. #endif
  426. return PCT_ERR_OK;
  427. }
  428. SP_STATUS
  429. DetermineClientCSP(PSPContext pContext)
  430. {
  431. PSPCredential pCred = NULL;
  432. if(!(pContext->RipeZombie->fProtocol & SP_PROT_CLIENTS))
  433. {
  434. return PCT_ERR_OK;
  435. }
  436. if(pContext->RipeZombie->hMasterProv != 0)
  437. {
  438. return PCT_ERR_OK;
  439. }
  440. switch(pContext->pKeyExchInfo->Spec)
  441. {
  442. case SP_EXCH_RSA_PKCS1:
  443. pContext->RipeZombie->hMasterProv = g_hRsaSchannel;
  444. break;
  445. case SP_EXCH_DH_PKCS3:
  446. pContext->RipeZombie->hMasterProv = g_hDhSchannelProv;
  447. break;
  448. default:
  449. DebugLog((DEB_ERROR, "Appropriate Schannel CSP not available!\n"));
  450. pContext->RipeZombie->hMasterProv = 0;
  451. return SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH);
  452. }
  453. return PCT_ERR_OK;
  454. }
  455. SP_STATUS
  456. ContextInitCiphers(
  457. SPContext *pContext,
  458. BOOL fRead,
  459. BOOL fWrite)
  460. {
  461. SP_BEGIN("ContextInitCiphers");
  462. if((pContext == NULL) ||
  463. (pContext->RipeZombie == NULL))
  464. {
  465. SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
  466. }
  467. pContext->pCipherInfo = pContext->pPendingCipherInfo;
  468. if ((NULL == pContext->pCipherInfo) || ((pContext->RipeZombie->fProtocol & pContext->pCipherInfo->fProtocol) == 0))
  469. {
  470. SP_RETURN(SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH));
  471. }
  472. pContext->pHashInfo = pContext->pPendingHashInfo;
  473. if ((NULL == pContext->pHashInfo)|| ((pContext->RipeZombie->fProtocol & pContext->pHashInfo->fProtocol) == 0))
  474. {
  475. SP_RETURN(SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH));
  476. }
  477. if (NULL == pContext->pKeyExchInfo)
  478. {
  479. SP_RETURN(SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH));
  480. }
  481. if(fRead)
  482. {
  483. pContext->pReadCipherInfo = pContext->pPendingCipherInfo;
  484. pContext->pReadHashInfo = pContext->pPendingHashInfo;
  485. }
  486. if(fWrite)
  487. {
  488. pContext->pWriteCipherInfo = pContext->pPendingCipherInfo;
  489. pContext->pWriteHashInfo = pContext->pPendingHashInfo;
  490. }
  491. SP_RETURN(PCT_ERR_OK);
  492. }
  493. SP_STATUS
  494. SPContextDoMapping(
  495. PSPContext pContext)
  496. {
  497. PSessCacheItem pZombie;
  498. PSPCredentialGroup pCred;
  499. SP_STATUS pctRet;
  500. LONG iState;
  501. BOOL fSuccess;
  502. LONG iMapper;
  503. const SCH_MAPPER_DEFAULT_STATE = 0;
  504. const SCH_MAPPER_NORMAL_STATE = 1;
  505. SP_BEGIN("SPContextDoMapping");
  506. pZombie = pContext->RipeZombie;
  507. pCred = pContext->RipeZombie->pServerCred;
  508. if(pCred->cMappers)
  509. {
  510. // Clear "called" flags.
  511. for(iMapper = 0; iMapper < pCred->cMappers; iMapper++)
  512. {
  513. pCred->pahMappers[iMapper]->m_dwFlags &= ~SCH_FLAG_MAPPER_CALLED;
  514. }
  515. pZombie->phMapper = NULL;
  516. for(iState = 0; iState < 2; iState++)
  517. {
  518. for(iMapper = 0; iMapper < pCred->cMappers; iMapper++)
  519. {
  520. if(pCred->pahMappers[iMapper]->m_dwFlags & SCH_FLAG_MAPPER_CALLED)
  521. {
  522. // This mapper has already had its chance.
  523. continue;
  524. }
  525. if(iState == SCH_MAPPER_DEFAULT_STATE)
  526. {
  527. if(!(pCred->pahMappers[iMapper]->m_dwFlags & SCH_FLAG_DEFAULT_MAPPER))
  528. {
  529. continue;
  530. }
  531. }
  532. if((pCred->dwFlags & CRED_FLAG_NO_SYSTEM_MAPPER) &&
  533. (pCred->pahMappers[iMapper]->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER))
  534. {
  535. // Skip the system mapper.
  536. DebugLog((DEB_TRACE, "Skip the system mapper\n"));
  537. continue;
  538. }
  539. #if DBG
  540. if(pCred->pahMappers[iMapper]->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER)
  541. {
  542. DebugLog((DEB_TRACE, "Invoke the system mapper\n"));
  543. }
  544. else
  545. {
  546. DebugLog((DEB_TRACE, "Invoke the application mapper\n"));
  547. }
  548. #endif
  549. // Invoke mapper.
  550. pctRet = SslMapCredential(
  551. pCred->pahMappers[iMapper],
  552. X509_ASN_CHAIN,
  553. pZombie->pRemoteCert,
  554. NULL,
  555. &pZombie->hLocator);
  556. pCred->pahMappers[iMapper]->m_dwFlags |= SCH_FLAG_MAPPER_CALLED;
  557. if(NT_SUCCESS(pctRet))
  558. {
  559. // Mapping was successful.
  560. DebugLog((DEB_TRACE, "Mapping was successful (0x%p)\n", pZombie->hLocator));
  561. SslReferenceMapper(pCred->pahMappers[iMapper]);
  562. if(pZombie->phMapper)
  563. {
  564. SslDereferenceMapper(pZombie->phMapper);
  565. }
  566. pZombie->phMapper = pCred->pahMappers[iMapper];
  567. pZombie->LocatorStatus = SEC_E_OK;
  568. break;
  569. }
  570. else
  571. {
  572. // Mapping failed.
  573. DebugLog((DEB_TRACE, "Mapping failed (0x%x)\n", pctRet));
  574. pZombie->LocatorStatus = pctRet;
  575. }
  576. }
  577. if(pZombie->phMapper)
  578. {
  579. break;
  580. }
  581. }
  582. }
  583. SP_RETURN(PCT_ERR_OK);
  584. }
  585. SP_STATUS
  586. RemoveDuplicateIssuers(
  587. PBYTE pbIssuers,
  588. PDWORD pcbIssuers)
  589. {
  590. DWORD cbIssuers = *pcbIssuers;
  591. DWORD cBlob;
  592. PCRYPT_DATA_BLOB rgBlob;
  593. DWORD cbIssuer;
  594. PBYTE pbIssuer;
  595. PBYTE pbSource, pbDest;
  596. DWORD i, j;
  597. if(pbIssuers == NULL || cbIssuers < 2)
  598. {
  599. return PCT_ERR_OK;
  600. }
  601. // Count number of issuers.
  602. cBlob = 0;
  603. pbIssuer = pbIssuers;
  604. while(pbIssuer + 1 < pbIssuers + cbIssuers)
  605. {
  606. cbIssuer = MAKEWORD(pbIssuer[1], pbIssuer[0]);
  607. pbIssuer += 2 + cbIssuer;
  608. cBlob++;
  609. }
  610. // Allocate memory for blob list.
  611. rgBlob = SPExternalAlloc(cBlob * sizeof(CRYPT_DATA_BLOB));
  612. if(rgBlob == NULL)
  613. {
  614. return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  615. }
  616. // Build blob list.
  617. cBlob = 0;
  618. pbIssuer = pbIssuers;
  619. while(pbIssuer + 1 < pbIssuers + cbIssuers)
  620. {
  621. cbIssuer = MAKEWORD(pbIssuer[1], pbIssuer[0]);
  622. rgBlob[cBlob].cbData = 2 + cbIssuer;
  623. rgBlob[cBlob].pbData = pbIssuer;
  624. pbIssuer += 2 + cbIssuer;
  625. cBlob++;
  626. }
  627. // Mark duplicates.
  628. for(i = 0; i < cBlob; i++)
  629. {
  630. if(rgBlob[i].pbData == NULL) continue;
  631. for(j = i + 1; j < cBlob; j++)
  632. {
  633. if(rgBlob[j].pbData == NULL) continue;
  634. if(rgBlob[i].cbData == rgBlob[j].cbData &&
  635. memcmp(rgBlob[i].pbData, rgBlob[j].pbData, rgBlob[j].cbData) == 0)
  636. {
  637. // duplicate found
  638. rgBlob[j].pbData = NULL;
  639. }
  640. }
  641. }
  642. // Compact list.
  643. pbSource = pbIssuers;
  644. pbDest = pbIssuers;
  645. for(i = 0; i < cBlob; i++)
  646. {
  647. if(rgBlob[i].pbData)
  648. {
  649. if(pbDest != pbSource)
  650. {
  651. MoveMemory(pbDest, pbSource, rgBlob[i].cbData);
  652. }
  653. pbDest += rgBlob[i].cbData;
  654. }
  655. pbSource += rgBlob[i].cbData;
  656. }
  657. *pcbIssuers = (DWORD)(pbDest - pbIssuers);
  658. // Free blob list.
  659. SPExternalFree(rgBlob);
  660. return PCT_ERR_OK;
  661. }
  662. SP_STATUS
  663. SPContextGetIssuers(
  664. PSPCredentialGroup pCredGroup)
  665. {
  666. LONG i;
  667. PBYTE pbIssuerList;
  668. DWORD cbIssuerList;
  669. PBYTE pbIssuer;
  670. DWORD cbIssuer;
  671. PBYTE pbNew;
  672. DWORD Status;
  673. LockCredential(pCredGroup);
  674. if((pCredGroup->pbTrustedIssuers != NULL) &&
  675. !(pCredGroup->dwFlags & CRED_FLAG_UPDATE_ISSUER_LIST))
  676. {
  677. // Issuer list has already been built.
  678. Status = PCT_ERR_OK;
  679. goto cleanup;
  680. }
  681. // Free existing issuer list.
  682. if(pCredGroup->pbTrustedIssuers)
  683. {
  684. LocalFree(pCredGroup->pbTrustedIssuers);
  685. pCredGroup->pbTrustedIssuers = NULL;
  686. pCredGroup->cbTrustedIssuers = 0;
  687. }
  688. pCredGroup->dwFlags &= ~CRED_FLAG_UPDATE_ISSUER_LIST;
  689. //
  690. // Get issuers from application-specified ROOT store.
  691. //
  692. pbIssuerList = NULL;
  693. cbIssuerList = 0;
  694. while(pCredGroup->hApplicationRoots)
  695. {
  696. Status = ExtractIssuerNamesFromStore(pCredGroup->hApplicationRoots,
  697. NULL,
  698. &cbIssuerList);
  699. if(Status != PCT_ERR_OK)
  700. {
  701. break;
  702. }
  703. pbIssuerList = LocalAlloc(LPTR, cbIssuerList);
  704. if(pbIssuerList == NULL)
  705. {
  706. break;
  707. }
  708. Status = ExtractIssuerNamesFromStore(pCredGroup->hApplicationRoots,
  709. pbIssuerList,
  710. &cbIssuerList);
  711. if(Status != PCT_ERR_OK)
  712. {
  713. LocalFree(pbIssuerList);
  714. pbIssuerList = NULL;
  715. cbIssuerList = 0;
  716. }
  717. break;
  718. }
  719. //
  720. // Call each of the mappers in turn, building a large
  721. // list of all trusted issuers.
  722. //
  723. for(i = 0; i < pCredGroup->cMappers; i++)
  724. {
  725. #if 0
  726. if((pCredGroup->dwFlags & CRED_FLAG_NO_SYSTEM_MAPPER) &&
  727. (pCredGroup->pahMappers[i]->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER))
  728. {
  729. // Skip the system mapper.
  730. continue;
  731. }
  732. #endif
  733. Status = SslGetMapperIssuerList(pCredGroup->pahMappers[i],
  734. &pbIssuer,
  735. &cbIssuer);
  736. if(!NT_SUCCESS(Status))
  737. {
  738. continue;
  739. }
  740. if(pbIssuerList == NULL)
  741. {
  742. pbIssuerList = LocalAlloc(LPTR, cbIssuer);
  743. if(pbIssuerList == NULL)
  744. {
  745. SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  746. break;
  747. }
  748. }
  749. else
  750. {
  751. pbNew = LocalReAlloc(pbIssuerList,
  752. cbIssuerList + cbIssuer,
  753. LMEM_MOVEABLE);
  754. if(pbNew == NULL)
  755. {
  756. SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  757. break;
  758. }
  759. pbIssuerList = pbNew;
  760. }
  761. CopyMemory(pbIssuerList + cbIssuerList,
  762. pbIssuer,
  763. cbIssuer);
  764. cbIssuerList += cbIssuer;
  765. SPExternalFree(pbIssuer);
  766. }
  767. //
  768. // Remove duplicates from list.
  769. //
  770. if(pbIssuerList)
  771. {
  772. Status = RemoveDuplicateIssuers(pbIssuerList, &cbIssuerList);
  773. if(!NT_SUCCESS(Status))
  774. {
  775. LocalFree(pbIssuerList);
  776. goto cleanup;
  777. }
  778. }
  779. pCredGroup->cbTrustedIssuers = cbIssuerList; // do not reverse these lines
  780. pCredGroup->pbTrustedIssuers = pbIssuerList;
  781. Status = PCT_ERR_OK;
  782. cleanup:
  783. UnlockCredential(pCredGroup);
  784. return Status;
  785. }
  786. SP_STATUS
  787. SPPickClientCertificate(
  788. PSPContext pContext,
  789. DWORD dwExchSpec)
  790. {
  791. PSPCredentialGroup pCred;
  792. PSPCredential pCurrentCred;
  793. SP_STATUS pctRet;
  794. DWORD i;
  795. pCred = pContext->pCredGroup;
  796. if((pCred == NULL) || (pCred->pCredList == NULL))
  797. {
  798. return SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH);
  799. }
  800. pContext->pActiveClientCred = NULL;
  801. pctRet = PCT_ERR_SPECS_MISMATCH;
  802. for(i = 0; i < pCred->cCredList; i++)
  803. {
  804. pCurrentCred = pCred->pCredList + i;
  805. if(pCurrentCred->pCert == NULL)
  806. {
  807. continue;
  808. }
  809. if(pCurrentCred->pPublicKey == NULL)
  810. {
  811. continue;
  812. }
  813. // Does this cert contain the proper key type.
  814. if(dwExchSpec != pCurrentCred->dwExchSpec)
  815. {
  816. continue; // try the next cert.
  817. }
  818. // Does this cert have the proper encoding type?
  819. if(pCurrentCred->pCert->dwCertEncodingType != X509_ASN_ENCODING)
  820. {
  821. continue;
  822. }
  823. // WE FOUND ONE
  824. pContext->pActiveClientCred = pCurrentCred;
  825. pctRet = PCT_ERR_OK;
  826. break;
  827. }
  828. return pctRet;
  829. }
  830. SP_STATUS
  831. SPPickServerCertificate(
  832. PSPContext pContext,
  833. DWORD dwExchSpec)
  834. {
  835. PSPCredentialGroup pCred;
  836. PSPCredential pCurrentCred;
  837. SP_STATUS pctRet;
  838. DWORD i;
  839. pCred = pContext->RipeZombie->pServerCred;
  840. if((pCred == NULL) || (pCred->pCredList == NULL))
  841. {
  842. return SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH);
  843. }
  844. DsysAssert((pContext->RipeZombie->dwFlags & SP_CACHE_FLAG_READONLY) == 0);
  845. #if 0
  846. if(pContext->RipeZombie->dwFlags & SP_CACHE_FLAG_READONLY)
  847. {
  848. // What in the world causes this case to occur? Anything?
  849. // Don't mess with the current credentials.
  850. if(pContext->RipeZombie->pActiveServerCred == NULL)
  851. {
  852. return SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH);
  853. }
  854. else
  855. {
  856. return PCT_ERR_OK;
  857. }
  858. }
  859. #endif
  860. pContext->RipeZombie->pActiveServerCred = NULL;
  861. pctRet = PCT_ERR_SPECS_MISMATCH;
  862. for(i = 0; i < pCred->cCredList; i++)
  863. {
  864. pCurrentCred = pCred->pCredList + i;
  865. if(pCurrentCred->pCert == NULL)
  866. {
  867. continue;
  868. }
  869. if(pCurrentCred->pPublicKey == NULL)
  870. {
  871. continue;
  872. }
  873. // Does this cert contain the proper key type.
  874. if(dwExchSpec != pCurrentCred->dwExchSpec)
  875. {
  876. continue; // try the next cert.
  877. }
  878. // Does this cert have the proper encoding type?
  879. if(pCurrentCred->pCert->dwCertEncodingType != X509_ASN_ENCODING)
  880. {
  881. continue;
  882. }
  883. // WE FOUND ONE
  884. pContext->RipeZombie->pActiveServerCred = pCurrentCred;
  885. pContext->RipeZombie->CredThumbprint = pCred->CredThumbprint;
  886. pContext->RipeZombie->CertThumbprint = pCurrentCred->CertThumbprint;
  887. // Set "master" provider handle to current credential's. Note that
  888. // SSL3 will sometimes overide this selection in favor of its
  889. // ephemeral key pair.
  890. pContext->RipeZombie->hMasterProv = pCurrentCred->hProv;
  891. pctRet = PCT_ERR_OK;
  892. break;
  893. }
  894. return pctRet;
  895. }
  896. // This routine is called by the user process. It frees a context
  897. // structure that was originally allocated by the LSA process,
  898. // and passed over via the SPContextDeserialize routine.
  899. BOOL
  900. LsaContextDelete(PSPContext pContext)
  901. {
  902. if(pContext)
  903. {
  904. if(pContext->hReadKey)
  905. {
  906. SchCryptDestroyKey(pContext->hReadKey, 0);
  907. pContext->hReadKey = 0;
  908. }
  909. if(pContext->hReadMAC)
  910. {
  911. SchCryptDestroyKey(pContext->hReadMAC, 0);
  912. pContext->hReadMAC = 0;
  913. }
  914. if(pContext->hWriteKey)
  915. {
  916. SchCryptDestroyKey(pContext->hWriteKey, 0);
  917. pContext->hWriteKey = 0;
  918. }
  919. if(pContext->hWriteMAC)
  920. {
  921. SchCryptDestroyKey(pContext->hWriteMAC, 0);
  922. pContext->hWriteMAC = 0;
  923. }
  924. // Close locator if this handle belongs to the system
  925. // default certificate mapper.
  926. if(pContext->RipeZombie)
  927. {
  928. if(pContext->RipeZombie->hLocator && pContext->RipeZombie->phMapper)
  929. {
  930. if(pContext->RipeZombie->phMapper->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER)
  931. {
  932. NtClose((HANDLE)pContext->RipeZombie->hLocator);
  933. pContext->RipeZombie->hLocator = 0;
  934. }
  935. }
  936. if(pContext->RipeZombie->pbServerCertificate)
  937. {
  938. SPExternalFree(pContext->RipeZombie->pbServerCertificate);
  939. pContext->RipeZombie->pbServerCertificate = NULL;
  940. }
  941. }
  942. }
  943. return TRUE;
  944. }
  945. /*
  946. *
  947. * Misc Utility functions.
  948. *
  949. */
  950. #if DBG
  951. typedef struct _DbgMapCrypto {
  952. DWORD C;
  953. PSTR psz;
  954. } DbgMapCrypto;
  955. DbgMapCrypto DbgCryptoNames[] = { {CALG_RC4, "RC4 "},
  956. };
  957. CHAR DbgNameSpace[100];
  958. PSTR DbgAlgNames[] = { "Basic RSA", "RSA with MD2", "RSA with MD5", "RC4 stream"};
  959. #define AlgName(x) ((x < sizeof(DbgAlgNames) / sizeof(PSTR)) ? DbgAlgNames[x] : "Unknown")
  960. PSTR
  961. DbgGetNameOfCrypto(DWORD x)
  962. {
  963. int i;
  964. for (i = 0; i < sizeof(DbgCryptoNames) / sizeof(DbgMapCrypto) ; i++ )
  965. {
  966. if (x == DbgCryptoNames[i].C)
  967. {
  968. wsprintf(DbgNameSpace, "%s",
  969. (DbgCryptoNames[i].psz));
  970. return DbgNameSpace;
  971. }
  972. }
  973. return("Unknown");
  974. }
  975. #endif
  976. #if 0
  977. PSTR
  978. CopyString(
  979. PSTR pszString)
  980. {
  981. PSTR pszNewString;
  982. DWORD cchString;
  983. cchString = lstrlen(pszString) + 1;
  984. pszNewString = (PSTR)SPExternalAlloc(cchString);
  985. if (pszNewString)
  986. {
  987. CopyMemory(pszNewString, pszString, cchString);
  988. }
  989. return(pszNewString);
  990. }
  991. #endif
  992. #ifdef LTS
  993. int __cdecl memcmp (
  994. const void * buf1,
  995. const void * buf2,
  996. size_t count
  997. )
  998. {
  999. if (!count)
  1000. return(0);
  1001. while ( --count && *(char *)buf1 == *(char *)buf2 ) {
  1002. buf1 = (char *)buf1 + 1;
  1003. buf2 = (char *)buf2 + 1;
  1004. }
  1005. return( *((unsigned char *)buf1) - *((unsigned char *)buf2) );
  1006. }
  1007. #endif
  1008. #if DBG
  1009. typedef struct _CONTEXTLIST {
  1010. struct _CONTEXTLIST *pNext;
  1011. PSPContext pContext;
  1012. } CONTEXTLIST, *PCONTEXTLIST;
  1013. PCONTEXTLIST g_ContextList = NULL;
  1014. static void AddContextToList(PSPContext pContext)
  1015. {
  1016. PCONTEXTLIST pNew = LocalAlloc(LMEM_FIXED, sizeof(CONTEXTLIST));
  1017. pNew->pNext = g_ContextList;
  1018. pNew->pContext = pContext;
  1019. g_ContextList = pNew;
  1020. }
  1021. static void DeleteContextFromList(PSPContext pContext)
  1022. {
  1023. PCONTEXTLIST pItem, pPrevItem;
  1024. BOOL fFound = FALSE;
  1025. if(g_ContextList == NULL)
  1026. {
  1027. DebugLog((DEB_ERROR, "List is empty!\n"));
  1028. }
  1029. else if(g_ContextList->pContext == pContext)
  1030. {
  1031. // Delete first item in list
  1032. g_ContextList = g_ContextList->pNext;
  1033. fFound = TRUE;
  1034. }
  1035. else
  1036. {
  1037. pPrevItem = g_ContextList;
  1038. for(pItem = g_ContextList->pNext; pItem; pItem = pItem->pNext)
  1039. {
  1040. if(pItem->pContext == pContext)
  1041. {
  1042. pPrevItem->pNext = pItem->pNext;
  1043. LocalFree(pItem);
  1044. fFound = TRUE;
  1045. break;
  1046. }
  1047. pPrevItem = pItem;
  1048. }
  1049. }
  1050. if(!fFound)
  1051. {
  1052. DebugLog((DEB_ERROR, "Unknown context 0x%p\n", pContext));
  1053. }
  1054. }
  1055. void DumpContexts(void)
  1056. {
  1057. PCONTEXTLIST pItem;
  1058. DWORD dwCount = 0;
  1059. SP_BEGIN("DumpContexts");
  1060. for(pItem = g_ContextList; pItem; pItem = pItem->pNext)
  1061. {
  1062. dwCount++;
  1063. DebugLog((DEB_TRACE, "Context:%8x, Cache:%8x\n",
  1064. pItem->pContext,
  1065. pItem->pContext->RipeZombie));
  1066. }
  1067. if(dwCount != g_cContext)
  1068. {
  1069. DebugLog((DEB_ERROR, "Context count discrepancy %d vs. %d\n",
  1070. dwCount,
  1071. g_cContext));
  1072. }
  1073. SP_END();
  1074. }
  1075. #endif