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.

1599 lines
42 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: cred.c
  7. //
  8. // Contents: Schannel credential management routines.
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 09-23-97 jbanes LSA integration stuff.
  15. // 03-15-99 jbanes Remove dead code, fix legacy SGC.
  16. //
  17. //----------------------------------------------------------------------------
  18. #include <spbase.h>
  19. #include <wincrypt.h>
  20. #include <oidenc.h>
  21. #include <mapper.h>
  22. #include <userenv.h>
  23. RTL_CRITICAL_SECTION g_SslCredLock;
  24. LIST_ENTRY g_SslCredList;
  25. HANDLE g_GPEvent;
  26. SP_STATUS
  27. GetPrivateFromCert(
  28. PSPCredential pCred,
  29. DWORD dwProtocol,
  30. PLSA_SCHANNEL_SUB_CRED pSubCred);
  31. BOOL
  32. SslInitCredentialManager(VOID)
  33. {
  34. BOOL fImpersonating = FALSE;
  35. NTSTATUS Status;
  36. Status = RtlInitializeCriticalSection( &g_SslCredLock );
  37. if (!NT_SUCCESS(Status))
  38. {
  39. return FALSE;
  40. }
  41. InitializeListHead( &g_SslCredList );
  42. fImpersonating = SslImpersonateClient();
  43. g_GPEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  44. if(g_GPEvent)
  45. {
  46. if(!RegisterGPNotification(g_GPEvent, FALSE))
  47. {
  48. DebugLog((DEB_ERROR, "Error 0x%x registering for user GP notification\n", GetLastError()));
  49. }
  50. if(!RegisterGPNotification(g_GPEvent, TRUE))
  51. {
  52. DebugLog((DEB_ERROR, "Error 0x%x registering for machine GP notification\n", GetLastError()));
  53. }
  54. }
  55. if(fImpersonating)
  56. {
  57. RevertToSelf();
  58. }
  59. return( TRUE );
  60. }
  61. BOOL
  62. SslFreeCredentialManager(VOID)
  63. {
  64. BOOL fImpersonating = FALSE;
  65. fImpersonating = SslImpersonateClient();
  66. if(g_GPEvent)
  67. {
  68. if(!UnregisterGPNotification(g_GPEvent))
  69. {
  70. DebugLog((DEB_ERROR, "Error 0x%x unregistering for user GP notification\n", GetLastError()));
  71. }
  72. if(!UnregisterGPNotification(g_GPEvent))
  73. {
  74. DebugLog((DEB_ERROR, "Error 0x%x unregistering for machine GP notification\n", GetLastError()));
  75. }
  76. CloseHandle(g_GPEvent);
  77. g_GPEvent = NULL;
  78. }
  79. if(fImpersonating)
  80. {
  81. RevertToSelf();
  82. }
  83. RtlDeleteCriticalSection( &g_SslCredLock );
  84. return TRUE;
  85. }
  86. BOOL
  87. SslCheckForGPEvent(void)
  88. {
  89. PLIST_ENTRY pList;
  90. PSPCredentialGroup pCredGroup;
  91. DWORD Status;
  92. if(g_GPEvent)
  93. {
  94. Status = WaitForSingleObjectEx(g_GPEvent, 0, FALSE);
  95. if(Status == WAIT_OBJECT_0)
  96. {
  97. DebugLog((DEB_WARN, "GP event detected, so download new trusted issuer list\n"));
  98. RtlEnterCriticalSection( &g_SslCredLock );
  99. pList = g_SslCredList.Flink ;
  100. while ( pList != &g_SslCredList )
  101. {
  102. pCredGroup = CONTAINING_RECORD( pList, SPCredentialGroup, ListEntry.Flink );
  103. pCredGroup->dwFlags |= CRED_FLAG_UPDATE_ISSUER_LIST;
  104. pList = pList->Flink ;
  105. }
  106. RtlLeaveCriticalSection( &g_SslCredLock );
  107. return TRUE;
  108. }
  109. }
  110. return FALSE;
  111. }
  112. SP_STATUS
  113. IsCredentialInGroup(
  114. PSPCredentialGroup pCredGroup,
  115. PCCERT_CONTEXT pCertContext,
  116. PBOOL pfInGroup)
  117. {
  118. PSPCredential pCred;
  119. BYTE rgbThumbprint[20];
  120. DWORD cbThumbprint;
  121. BYTE rgbHash[20];
  122. DWORD cbHash;
  123. DWORD i;
  124. *pfInGroup = FALSE;
  125. // Get thumbprint of certificate.
  126. cbThumbprint = sizeof(rgbThumbprint);
  127. if(!CertGetCertificateContextProperty(pCertContext,
  128. CERT_MD5_HASH_PROP_ID,
  129. rgbThumbprint,
  130. &cbThumbprint))
  131. {
  132. SP_LOG_RESULT(GetLastError());
  133. return PCT_INT_UNKNOWN_CREDENTIAL;
  134. }
  135. for(i = 0; i < pCredGroup->cCredList; i++)
  136. {
  137. pCred = pCredGroup->pCredList + i;
  138. // Get thumbprint of certificate.
  139. cbHash = sizeof(rgbHash);
  140. if(!CertGetCertificateContextProperty(pCred->pCert,
  141. CERT_MD5_HASH_PROP_ID,
  142. rgbHash,
  143. &cbHash))
  144. {
  145. SP_LOG_RESULT(GetLastError());
  146. return PCT_INT_UNKNOWN_CREDENTIAL;
  147. }
  148. if(memcmp(rgbThumbprint, rgbHash, cbThumbprint) == 0)
  149. {
  150. *pfInGroup = TRUE;
  151. break;
  152. }
  153. }
  154. return PCT_ERR_OK;
  155. }
  156. BOOL
  157. IsValidThumbprint(
  158. PCRED_THUMBPRINT Thumbprint)
  159. {
  160. if(Thumbprint->LowPart == 0 && Thumbprint->HighPart == 0)
  161. {
  162. return FALSE;
  163. }
  164. return TRUE;
  165. }
  166. BOOL
  167. IsSameThumbprint(
  168. PCRED_THUMBPRINT Thumbprint1,
  169. PCRED_THUMBPRINT Thumbprint2)
  170. {
  171. if(Thumbprint1->LowPart == Thumbprint2->LowPart &&
  172. Thumbprint1->HighPart == Thumbprint2->HighPart)
  173. {
  174. return TRUE;
  175. }
  176. return FALSE;
  177. }
  178. void
  179. GenerateCertThumbprint(
  180. PCCERT_CONTEXT pCertContext,
  181. PCRED_THUMBPRINT Thumbprint)
  182. {
  183. MD5_CTX Md5Hash;
  184. MD5Init(&Md5Hash);
  185. MD5Update(&Md5Hash,
  186. pCertContext->pbCertEncoded,
  187. pCertContext->cbCertEncoded);
  188. MD5Final(&Md5Hash);
  189. CopyMemory((PBYTE)Thumbprint,
  190. Md5Hash.digest,
  191. sizeof(CRED_THUMBPRINT));
  192. }
  193. void
  194. GenerateRandomThumbprint(
  195. PCRED_THUMBPRINT Thumbprint)
  196. {
  197. GenerateRandomBits((PBYTE)Thumbprint, sizeof(CRED_THUMBPRINT));
  198. }
  199. BOOL
  200. DoesCredThumbprintMatch(
  201. PSPCredentialGroup pCredGroup,
  202. PCRED_THUMBPRINT pThumbprint)
  203. {
  204. PSPCredential pCurrentCred;
  205. BOOL fFound = FALSE;
  206. DWORD i;
  207. for(i = 0; i < pCredGroup->cCredList; i++)
  208. {
  209. pCurrentCred = pCredGroup->pCredList + i;
  210. if(IsSameThumbprint(pThumbprint, &pCurrentCred->CertThumbprint))
  211. {
  212. fFound = TRUE;
  213. break;
  214. }
  215. }
  216. return fFound;
  217. }
  218. SP_STATUS
  219. SPCreateCred(
  220. DWORD dwProtocol,
  221. PLSA_SCHANNEL_SUB_CRED pSubCred,
  222. PSPCredential pCurrentCred,
  223. BOOL * pfEventLogged)
  224. {
  225. SP_STATUS pctRet;
  226. pCurrentCred->pCert = CertDuplicateCertificateContext(pSubCred->pCert);
  227. if(pCurrentCred->pCert == NULL)
  228. {
  229. pctRet = SP_LOG_RESULT(SEC_E_CERT_UNKNOWN);
  230. goto error;
  231. }
  232. pctRet = SPPublicKeyFromCert(pCurrentCred->pCert,
  233. &pCurrentCred->pPublicKey,
  234. &pCurrentCred->dwExchSpec);
  235. if(pctRet != PCT_ERR_OK)
  236. {
  237. goto error;
  238. }
  239. pctRet = GetPrivateFromCert(pCurrentCred, dwProtocol, pSubCred);
  240. if(pctRet != PCT_ERR_OK)
  241. {
  242. *pfEventLogged = TRUE;
  243. goto error;
  244. }
  245. pCurrentCred->dwCF = CF_EXPORT;
  246. if(SslGlobalStrongEncryptionPermitted)
  247. {
  248. pCurrentCred->dwCF |= CF_DOMESTIC;
  249. }
  250. // Generate the credential thumbprint. This is computed by
  251. // taking the hash of the certificate.
  252. GenerateCertThumbprint(pCurrentCred->pCert,
  253. &pCurrentCred->CertThumbprint);
  254. DebugLog((DEB_TRACE, "Credential thumbprint: %x %x\n",
  255. pCurrentCred->CertThumbprint.LowPart,
  256. pCurrentCred->CertThumbprint.HighPart));
  257. // Read list of supported algorithms.
  258. if((dwProtocol & SP_PROT_SERVERS) && pCurrentCred->hProv)
  259. {
  260. GetSupportedCapiAlgs(pCurrentCred->hProv,
  261. pCurrentCred->dwCapiFlags,
  262. &pCurrentCred->pCapiAlgs,
  263. &pCurrentCred->cCapiAlgs);
  264. }
  265. // Build SSL3 serialized certificate chain. This is an optimization
  266. // so that we won't have to build it for each connection.
  267. pctRet = SPSerializeCertificate(
  268. SP_PROT_SSL3,
  269. TRUE,
  270. &pCurrentCred->pbSsl3SerializedChain,
  271. &pCurrentCred->cbSsl3SerializedChain,
  272. pCurrentCred->pCert,
  273. CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL);
  274. if(pctRet != PCT_ERR_OK)
  275. {
  276. goto error;
  277. }
  278. error:
  279. return pctRet;
  280. }
  281. SP_STATUS
  282. SPCreateCredential(
  283. PSPCredentialGroup *ppCred,
  284. DWORD grbitProtocol,
  285. PLSA_SCHANNEL_CRED pSchannelCred)
  286. {
  287. PSPCredentialGroup pCred = NULL;
  288. PSPCredential pCurrentCred = NULL;
  289. SECPKG_CALL_INFO CallInfo;
  290. SP_STATUS pctRet = PCT_ERR_OK;
  291. DWORD i;
  292. DWORD dwKeySpec;
  293. HMAPPER * pMapper;
  294. BOOL fSelectiveCrypto;
  295. NTSTATUS Status;
  296. BOOL fImpersonating = FALSE;
  297. BOOL fEventLogged = FALSE;
  298. SP_BEGIN("SPCreateCredential");
  299. DebugLog((DEB_TRACE, " dwVersion: %d\n", pSchannelCred->dwVersion));
  300. DebugLog((DEB_TRACE, " cCreds: %d\n", pSchannelCred->cSubCreds));
  301. DebugLog((DEB_TRACE, " paCred: 0x%p\n", pSchannelCred->paSubCred));
  302. DebugLog((DEB_TRACE, " hRootStore: 0x%p\n", pSchannelCred->hRootStore));
  303. DebugLog((DEB_TRACE, " cMappers: %d\n", pSchannelCred->cMappers));
  304. DebugLog((DEB_TRACE, " aphMappers: 0x%p\n", pSchannelCred->aphMappers));
  305. DebugLog((DEB_TRACE, " cSupportedAlgs: %d\n", pSchannelCred->cSupportedAlgs));
  306. DebugLog((DEB_TRACE, " palgSupportedAlgs: 0x%p\n", pSchannelCred->palgSupportedAlgs));
  307. DebugLog((DEB_TRACE, " grbitEnabledProtocols: 0x%x\n", pSchannelCred->grbitEnabledProtocols));
  308. DebugLog((DEB_TRACE, " dwMinimumCipherStrength:%d\n", pSchannelCred->dwMinimumCipherStrength));
  309. DebugLog((DEB_TRACE, " dwMaximumCipherStrength:%d\n", pSchannelCred->dwMaximumCipherStrength));
  310. DebugLog((DEB_TRACE, " dwSessionLifespan: %d\n", pSchannelCred->dwSessionLifespan));
  311. DebugLog((DEB_TRACE, " dwFlags: 0x%x\n", pSchannelCred->dwFlags));
  312. DebugLog((DEB_TRACE, " reserved: 0x%x\n", pSchannelCred->reserved));
  313. LogCreateCredEvent(grbitProtocol, pSchannelCred);
  314. //
  315. // Allocate the internal credential structure and perform
  316. // basic initialization.
  317. //
  318. pCred = SPExternalAlloc(sizeof(SPCredentialGroup));
  319. if(pCred == NULL)
  320. {
  321. SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
  322. }
  323. DebugLog((DEB_TRACE, "New cred:%p, Protocol:%x\n", pCred, grbitProtocol));
  324. pCred->Magic = PCT_CRED_MAGIC;
  325. pCred->grbitProtocol = grbitProtocol;
  326. Status = RtlInitializeCriticalSection(&pCred->csLock);
  327. if (!NT_SUCCESS(Status))
  328. {
  329. pctRet = SEC_E_NO_CREDENTIALS;
  330. goto error;
  331. }
  332. pCred->RefCount = 0;
  333. pCred->cMappers = 0;
  334. pCred->pahMappers = NULL;
  335. pCred->dwFlags = 0;
  336. pCred->pCredList = NULL;
  337. GenerateRandomThumbprint(&pCred->CredThumbprint);
  338. if((grbitProtocol & SP_PROT_SERVERS) && (pSchannelCred->cSubCreds == 0))
  339. {
  340. pctRet = SP_LOG_RESULT(SEC_E_NO_CREDENTIALS);
  341. goto error;
  342. }
  343. if(LsaTable->GetCallInfo(&CallInfo))
  344. {
  345. pCred->ProcessId = CallInfo.ProcessId;
  346. }
  347. //
  348. // Walk through and initialize all certs and keys.
  349. //
  350. if(pSchannelCred->cSubCreds)
  351. {
  352. pCred->pCredList = SPExternalAlloc(pSchannelCred->cSubCreds * sizeof(SPCredential));
  353. if(pCred->pCredList == NULL)
  354. {
  355. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  356. goto error;
  357. }
  358. pCred->cCredList = pSchannelCred->cSubCreds;
  359. for(i = 0; i < pSchannelCred->cSubCreds; i++)
  360. {
  361. pCurrentCred = pCred->pCredList + i;
  362. pctRet = SPCreateCred(grbitProtocol,
  363. pSchannelCred->paSubCred + i,
  364. pCurrentCred,
  365. &fEventLogged);
  366. if(pctRet != PCT_ERR_OK)
  367. {
  368. goto error;
  369. }
  370. }
  371. }
  372. //
  373. // Determine which protocols are to be supported.
  374. //
  375. if(pSchannelCred->grbitEnabledProtocols == 0)
  376. {
  377. pCred->grbitEnabledProtocols = g_ProtEnabled;
  378. if(g_PctClientDisabledByDefault)
  379. {
  380. pCred->grbitEnabledProtocols &= ~SP_PROT_PCT1_CLIENT;
  381. }
  382. if(g_Ssl2ClientDisabledByDefault)
  383. {
  384. pCred->grbitEnabledProtocols &= ~SP_PROT_SSL2_CLIENT;
  385. }
  386. }
  387. else
  388. {
  389. pCred->grbitEnabledProtocols = pSchannelCred->grbitEnabledProtocols & g_ProtEnabled;
  390. }
  391. // Force credential to client-only or server only.
  392. if(grbitProtocol & SP_PROT_SERVERS)
  393. {
  394. pCred->grbitEnabledProtocols &= SP_PROT_SERVERS;
  395. }
  396. else
  397. {
  398. pCred->grbitEnabledProtocols &= SP_PROT_CLIENTS;
  399. }
  400. //
  401. // Propagate flags from SCHANNEL_CRED structure.
  402. //
  403. if(pSchannelCred->dwFlags & SCH_CRED_NO_SYSTEM_MAPPER)
  404. {
  405. pCred->dwFlags |= CRED_FLAG_NO_SYSTEM_MAPPER;
  406. }
  407. if(pSchannelCred->dwFlags & SCH_CRED_NO_SERVERNAME_CHECK)
  408. {
  409. pCred->dwFlags |= CRED_FLAG_NO_SERVERNAME_CHECK;
  410. }
  411. if(pSchannelCred->dwFlags & SCH_CRED_MANUAL_CRED_VALIDATION)
  412. {
  413. pCred->dwFlags |= CRED_FLAG_MANUAL_CRED_VALIDATION;
  414. }
  415. if(pSchannelCred->dwFlags & SCH_CRED_NO_DEFAULT_CREDS)
  416. {
  417. pCred->dwFlags |= CRED_FLAG_NO_DEFAULT_CREDS;
  418. }
  419. if(pSchannelCred->dwFlags & SCH_CRED_AUTO_CRED_VALIDATION)
  420. {
  421. // Automatically validate server credentials.
  422. pCred->dwFlags &= ~CRED_FLAG_MANUAL_CRED_VALIDATION;
  423. }
  424. if(pSchannelCred->dwFlags & SCH_CRED_USE_DEFAULT_CREDS)
  425. {
  426. // Use default client credentials.
  427. pCred->dwFlags &= ~CRED_FLAG_NO_DEFAULT_CREDS;
  428. }
  429. if(pSchannelCred->dwFlags & SCH_CRED_DISABLE_RECONNECTS)
  430. {
  431. // Disable reconnects.
  432. pCred->dwFlags |= CRED_FLAG_DISABLE_RECONNECTS;
  433. }
  434. // set revocation flags
  435. if(pSchannelCred->dwFlags & SCH_CRED_REVOCATION_CHECK_END_CERT)
  436. pCred->dwFlags |= CRED_FLAG_REVCHECK_END_CERT;
  437. if(pSchannelCred->dwFlags & SCH_CRED_REVOCATION_CHECK_CHAIN)
  438. pCred->dwFlags |= CRED_FLAG_REVCHECK_CHAIN;
  439. if(pSchannelCred->dwFlags & SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
  440. pCred->dwFlags |= CRED_FLAG_REVCHECK_CHAIN_EXCLUDE_ROOT;
  441. if(pSchannelCred->dwFlags & SCH_CRED_IGNORE_NO_REVOCATION_CHECK)
  442. pCred->dwFlags |= CRED_FLAG_IGNORE_NO_REVOCATION_CHECK;
  443. if(pSchannelCred->dwFlags & SCH_CRED_IGNORE_REVOCATION_OFFLINE)
  444. pCred->dwFlags |= CRED_FLAG_IGNORE_REVOCATION_OFFLINE;
  445. // set up the min and max strength
  446. GetBaseCipherSizes(&pCred->dwMinStrength, &pCred->dwMaxStrength);
  447. if(pSchannelCred->dwMinimumCipherStrength == 0)
  448. {
  449. pCred->dwMinStrength = max(40, pCred->dwMinStrength);
  450. }
  451. else if(pSchannelCred->dwMinimumCipherStrength == (DWORD)(-1))
  452. {
  453. // Turn on NULL cipher.
  454. pCred->dwMinStrength = 0;
  455. }
  456. else
  457. {
  458. pCred->dwMinStrength = pSchannelCred->dwMinimumCipherStrength;
  459. }
  460. if(pSchannelCred->dwMaximumCipherStrength == (DWORD)(-1))
  461. {
  462. // NULL cipher only.
  463. pCred->dwMaxStrength = 0;
  464. }
  465. else if(pSchannelCred->dwMaximumCipherStrength != 0)
  466. {
  467. pCred->dwMaxStrength = pSchannelCred->dwMaximumCipherStrength;
  468. }
  469. // set up the allowed ciphers
  470. BuildAlgList(pCred, pSchannelCred->palgSupportedAlgs, pSchannelCred->cSupportedAlgs);
  471. //
  472. // Set up all of the applications mappers and add in the default mapper.
  473. //
  474. pCred->cMappers = pSchannelCred->cMappers + 1;
  475. pCred->pahMappers = SPExternalAlloc(pCred->cMappers * sizeof(HMAPPER *));
  476. if(pCred->pahMappers == NULL)
  477. {
  478. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  479. goto error;
  480. }
  481. // Make system certificate mapper the first mapper in the list.
  482. pCred->pahMappers[0] = SslGetMapper(TRUE);
  483. if(pCred->dwFlags & CRED_FLAG_REVCHECK_END_CERT)
  484. pCred->pahMappers[0]->m_dwFlags |= SCH_FLAG_REVCHECK_END_CERT;
  485. if(pCred->dwFlags & CRED_FLAG_REVCHECK_CHAIN)
  486. pCred->pahMappers[0]->m_dwFlags |= SCH_FLAG_REVCHECK_CHAIN;
  487. if(pCred->dwFlags & CRED_FLAG_REVCHECK_CHAIN_EXCLUDE_ROOT)
  488. pCred->pahMappers[0]->m_dwFlags |= SCH_FLAG_REVCHECK_CHAIN_EXCLUDE_ROOT;
  489. if(pCred->dwFlags & CRED_FLAG_IGNORE_NO_REVOCATION_CHECK)
  490. pCred->pahMappers[0]->m_dwFlags |= SCH_FLAG_IGNORE_NO_REVOCATION_CHECK;
  491. if(pCred->dwFlags & CRED_FLAG_IGNORE_REVOCATION_OFFLINE)
  492. pCred->pahMappers[0]->m_dwFlags |= SCH_FLAG_IGNORE_REVOCATION_OFFLINE;
  493. SslReferenceMapper(pCred->pahMappers[0]);
  494. for(i = 0; i < pSchannelCred->cMappers; i++)
  495. {
  496. pCred->pahMappers[i + 1] = pSchannelCred->aphMappers[i];
  497. pSchannelCred->aphMappers[i] = NULL;
  498. SslReferenceMapper(pCred->pahMappers[i + 1]);
  499. }
  500. // set up timeouts.
  501. if(pSchannelCred->dwSessionLifespan == 0)
  502. {
  503. if(grbitProtocol & SP_PROT_CLIENTS)
  504. {
  505. pCred->dwSessionLifespan = SchannelCache.dwClientLifespan;
  506. }
  507. else
  508. {
  509. pCred->dwSessionLifespan = SchannelCache.dwServerLifespan;
  510. }
  511. }
  512. else if(pSchannelCred->dwSessionLifespan == (DWORD)(-1))
  513. {
  514. pCred->dwSessionLifespan = 0;
  515. }
  516. else
  517. {
  518. pCred->dwSessionLifespan = pSchannelCred->dwSessionLifespan;
  519. }
  520. //
  521. // Add credential to global list of credentials.
  522. //
  523. RtlEnterCriticalSection( &g_SslCredLock );
  524. InsertTailList( &g_SslCredList, &pCred->ListEntry );
  525. RtlLeaveCriticalSection( &g_SslCredLock );
  526. //
  527. // Get list of trusted issuers.
  528. //
  529. if(grbitProtocol & SP_PROT_SERVERS)
  530. {
  531. if(pSchannelCred->hRootStore)
  532. {
  533. pCred->hApplicationRoots = CertDuplicateStore(pSchannelCred->hRootStore);
  534. if(!pCred->hApplicationRoots)
  535. {
  536. DebugLog((DEB_ERROR, "Error 0x%x duplicating app root store\n", GetLastError()));
  537. }
  538. }
  539. fImpersonating = SslImpersonateClient();
  540. pCred->hUserRoots = CertOpenSystemStore(0, "ROOT");
  541. if(!pCred->hUserRoots)
  542. {
  543. DebugLog((DEB_ERROR, "Error 0x%x opening user root store\n", GetLastError()));
  544. }
  545. else
  546. {
  547. if(!CertControlStore(pCred->hUserRoots,
  548. 0,
  549. CERT_STORE_CTRL_NOTIFY_CHANGE,
  550. &g_GPEvent))
  551. {
  552. DebugLog((DEB_ERROR, "Error 0x%x registering user root change notification\n", GetLastError()));
  553. }
  554. }
  555. if(fImpersonating)
  556. {
  557. RevertToSelf();
  558. fImpersonating = FALSE;
  559. }
  560. }
  561. SPReferenceCredential(pCred);
  562. *ppCred = pCred;
  563. SP_RETURN(PCT_ERR_OK);
  564. error:
  565. if(fEventLogged == FALSE)
  566. {
  567. LogCreateCredFailedEvent(grbitProtocol);
  568. }
  569. // Error case, free the credential
  570. if(pCred)
  571. {
  572. SPDeleteCredential(pCred);
  573. }
  574. SP_RETURN(pctRet);
  575. }
  576. BOOL
  577. SPDeleteCredential(
  578. PSPCredentialGroup pCred)
  579. {
  580. DWORD i;
  581. SP_BEGIN("SPDeleteCredential");
  582. if(pCred == NULL)
  583. {
  584. SP_RETURN(TRUE);
  585. }
  586. if(pCred->Magic != PCT_CRED_MAGIC)
  587. {
  588. DebugLog((SP_LOG_ERROR, "Attempting to delete invalid credential!\n"));
  589. SP_RETURN (FALSE);
  590. }
  591. LockCredential(pCred);
  592. if(pCred->pCredList)
  593. {
  594. for(i = 0; i < pCred->cCredList; i++)
  595. {
  596. SPDeleteCred(pCred->pCredList + i);
  597. }
  598. SPExternalFree(pCred->pCredList);
  599. pCred->pCredList = NULL;
  600. pCred->cCredList = 0;
  601. }
  602. if(pCred->cMappers && pCred->pahMappers)
  603. {
  604. for(i=0; i < (DWORD)pCred->cMappers; i++)
  605. {
  606. SslDereferenceMapper(pCred->pahMappers[i]);
  607. }
  608. SPExternalFree(pCred->pahMappers);
  609. }
  610. if(pCred->palgSupportedAlgs)
  611. {
  612. SPExternalFree(pCred->palgSupportedAlgs);
  613. }
  614. pCred->Magic = PCT_INVALID_MAGIC;
  615. if(pCred->ListEntry.Flink)
  616. {
  617. RtlEnterCriticalSection( &g_SslCredLock );
  618. RemoveEntryList( &pCred->ListEntry );
  619. RtlLeaveCriticalSection( &g_SslCredLock );
  620. }
  621. if(pCred->pbTrustedIssuers)
  622. {
  623. // LocalFree is used for the issuer list because realloc
  624. // is used when building the list and the LSA doesn't
  625. // provide a realloc helper function.
  626. LocalFree(pCred->pbTrustedIssuers);
  627. }
  628. if(pCred->hApplicationRoots)
  629. {
  630. CertCloseStore(pCred->hApplicationRoots, 0);
  631. }
  632. if(pCred->hUserRoots)
  633. {
  634. BOOL fImpersonating = SslImpersonateClient();
  635. CertCloseStore(pCred->hUserRoots, 0);
  636. if(fImpersonating) RevertToSelf();
  637. }
  638. UnlockCredential(pCred);
  639. RtlDeleteCriticalSection(&pCred->csLock);
  640. ZeroMemory(pCred, sizeof(SPCredentialGroup));
  641. SPExternalFree(pCred);
  642. SP_RETURN(TRUE);
  643. }
  644. void
  645. SPDeleteCred(PSPCredential pCred)
  646. {
  647. BOOL fImpersonating = FALSE;
  648. if(pCred == NULL)
  649. {
  650. return;
  651. }
  652. if(pCred->pPublicKey)
  653. {
  654. SPExternalFree(pCred->pPublicKey);
  655. pCred->pPublicKey = NULL;
  656. }
  657. if(pCred->pCert)
  658. {
  659. CertFreeCertificateContext(pCred->pCert);
  660. pCred->pCert = NULL;
  661. }
  662. if(pCred->hTek)
  663. {
  664. if(!CryptDestroyKey(pCred->hTek))
  665. {
  666. SP_LOG_RESULT(GetLastError());
  667. }
  668. pCred->hTek = 0;
  669. }
  670. if(pCred->hProv)
  671. {
  672. fImpersonating = SslImpersonateClient();
  673. if(!SchCryptReleaseContext(
  674. pCred->hProv,
  675. 0,
  676. pCred->dwCapiFlags))
  677. {
  678. SP_LOG_RESULT(GetLastError());
  679. }
  680. pCred->hProv = 0;
  681. if(fImpersonating)
  682. {
  683. RevertToSelf();
  684. fImpersonating = FALSE;
  685. }
  686. }
  687. if(pCred->pCapiAlgs)
  688. {
  689. SPExternalFree(pCred->pCapiAlgs);
  690. pCred->pCapiAlgs = NULL;
  691. }
  692. if(pCred->hRemoteProv && !pCred->fAppRemoteProv)
  693. {
  694. if(!RemoteCryptReleaseContext(
  695. pCred->hRemoteProv,
  696. 0,
  697. pCred->dwCapiFlags))
  698. {
  699. SP_LOG_RESULT(GetLastError());
  700. }
  701. pCred->hRemoteProv = 0;
  702. }
  703. if(pCred->hEphem512Prov)
  704. {
  705. if(!SchCryptReleaseContext(pCred->hEphem512Prov,
  706. 0,
  707. pCred->dwCapiFlags))
  708. {
  709. SP_LOG_RESULT(GetLastError());
  710. }
  711. pCred->hEphem512Prov = 0;
  712. }
  713. if(pCred->pbSsl3SerializedChain)
  714. {
  715. SPExternalFree(pCred->pbSsl3SerializedChain);
  716. }
  717. }
  718. // Reference a credential.
  719. // Note: This should only be called by someone who already
  720. // has a reference to the credential, or by the CreateCredential
  721. // call.
  722. BOOL
  723. SPReferenceCredential(
  724. PSPCredentialGroup pCred)
  725. {
  726. BOOL fRet = FALSE;
  727. fRet = (InterlockedIncrement(&pCred->RefCount) > 0);
  728. DebugLog((SP_LOG_TRACE, "Reference Cred %lx: %d\n", pCred, pCred->RefCount));
  729. return fRet;
  730. }
  731. BOOL
  732. SPDereferenceCredential(
  733. PSPCredentialGroup pCred)
  734. {
  735. LONG Ref;
  736. BOOL fRet = FALSE;
  737. if(pCred == NULL)
  738. {
  739. return FALSE;
  740. }
  741. if(pCred->Magic != PCT_CRED_MAGIC)
  742. {
  743. DebugLog((SP_LOG_ERROR, "Attempting to dereference invalid credential!\n"));
  744. return FALSE;
  745. }
  746. fRet = TRUE;
  747. DebugLog((SP_LOG_TRACE, "Dereference Cred %lx: %d\n", pCred, pCred->RefCount-1));
  748. if(0 == InterlockedDecrement(&pCred->RefCount))
  749. {
  750. fRet = SPDeleteCredential(pCred);
  751. }
  752. return fRet;
  753. }
  754. SECURITY_STATUS
  755. UpdateCredentialFormat(
  756. PSCH_CRED pSchCred, // in
  757. PLSA_SCHANNEL_CRED pSchannelCred) // out
  758. {
  759. DWORD dwVersion;
  760. DWORD dwType;
  761. SP_STATUS pctRet;
  762. DWORD i;
  763. PBYTE pbChain;
  764. DWORD cbChain;
  765. PSCH_CRED_PUBLIC_CERTCHAIN pCertChain;
  766. CRYPT_DATA_BLOB DataBlob;
  767. SP_BEGIN("UpdateCredentialFormat");
  768. //
  769. // Initialize the output structure to null credential.
  770. //
  771. if(pSchannelCred == NULL)
  772. {
  773. SP_RETURN(SP_LOG_RESULT(SEC_E_INTERNAL_ERROR));
  774. }
  775. memset(pSchannelCred, 0, sizeof(LSA_SCHANNEL_CRED));
  776. pSchannelCred->dwVersion = SCHANNEL_CRED_VERSION;
  777. //
  778. // If input buffer is empty then we're done.
  779. //
  780. if(pSchCred == NULL)
  781. {
  782. SP_RETURN(SEC_E_OK);
  783. }
  784. //
  785. // Copy over the mapper fields.
  786. //
  787. pSchannelCred->cMappers = pSchCred->cMappers;
  788. pSchannelCred->aphMappers = pSchCred->aphMappers;
  789. //
  790. // Convert the certificates and private keys.
  791. //
  792. if(pSchCred->cCreds == 0)
  793. {
  794. SP_RETURN(SEC_E_OK);
  795. }
  796. pSchannelCred->cSubCreds = pSchCred->cCreds;
  797. pSchannelCred->paSubCred = SPExternalAlloc(sizeof(LSA_SCHANNEL_SUB_CRED) * pSchannelCred->cSubCreds);
  798. if(pSchannelCred->paSubCred == NULL)
  799. {
  800. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  801. goto error;
  802. }
  803. // Loop through each of the creds, and convert them into something we know
  804. for(i = 0; i < pSchannelCred->cSubCreds; i++)
  805. {
  806. PLSA_SCHANNEL_SUB_CRED pSubCred = pSchannelCred->paSubCred + i;
  807. //
  808. // Decode the certificate.
  809. //
  810. dwType = *(PDWORD)pSchCred->paPublic[i];
  811. if(dwType != SCH_CRED_X509_CERTCHAIN)
  812. {
  813. pctRet = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS);
  814. goto error;
  815. }
  816. pCertChain = (PSCH_CRED_PUBLIC_CERTCHAIN)pSchCred->paPublic[i];
  817. pbChain = pCertChain->pCertChain;
  818. cbChain = pCertChain->cbCertChain;
  819. // Decode the credential
  820. pctRet = SPLoadCertificate(0,
  821. X509_ASN_ENCODING,
  822. pbChain,
  823. cbChain,
  824. &pSubCred->pCert);
  825. if(pctRet != PCT_ERR_OK)
  826. {
  827. pctRet = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS);
  828. goto error;
  829. }
  830. //
  831. // Now deal with the private key.
  832. //
  833. dwType = *(DWORD *)pSchCred->paSecret[i];
  834. if(dwType == SCHANNEL_SECRET_PRIVKEY)
  835. {
  836. PUCHAR pPrivateKeySave;
  837. PSCH_CRED_SECRET_PRIVKEY pPrivKey;
  838. DWORD Size;
  839. pPrivKey = (PSCH_CRED_SECRET_PRIVKEY)pSchCred->paSecret[i];
  840. pSubCred->pPrivateKey = SPExternalAlloc(pPrivKey->cbPrivateKey);
  841. if(pSubCred->pPrivateKey == NULL)
  842. {
  843. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  844. goto error;
  845. }
  846. memcpy(pSubCred->pPrivateKey, pPrivKey->pPrivateKey, pPrivKey->cbPrivateKey);
  847. pSubCred->cbPrivateKey = pPrivKey->cbPrivateKey;
  848. Size = strlen(pPrivKey->pszPassword) + sizeof(CHAR);
  849. pSubCred->pszPassword = SPExternalAlloc(Size);
  850. if(pSubCred->pszPassword == NULL)
  851. {
  852. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  853. goto error;
  854. }
  855. memcpy(pSubCred->pszPassword, pPrivKey->pszPassword, Size);
  856. break;
  857. }
  858. else if(dwType == SCHANNEL_SECRET_TYPE_CAPI)
  859. {
  860. PSCH_CRED_SECRET_CAPI pCapiKey;
  861. pCapiKey = (PSCH_CRED_SECRET_CAPI)pSchCred->paSecret[i];
  862. pSubCred->hRemoteProv = pCapiKey->hProv;
  863. break;
  864. }
  865. else
  866. {
  867. pctRet = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS);
  868. goto error;
  869. }
  870. }
  871. SP_RETURN(SEC_E_OK);
  872. error:
  873. if(pSchannelCred->paSubCred)
  874. {
  875. SPExternalFree((PVOID)pSchannelCred->paSubCred);
  876. pSchannelCred->paSubCred = NULL;
  877. }
  878. SP_RETURN(pctRet);
  879. }
  880. SP_STATUS
  881. GetIisPrivateFromCert(
  882. PSPCredential pCred,
  883. PLSA_SCHANNEL_SUB_CRED pSubCred)
  884. {
  885. PBYTE pbPrivate = NULL;
  886. DWORD cbPrivate;
  887. PBYTE pbPassword = NULL;
  888. DWORD cbPassword;
  889. PPRIVATE_KEY_FILE_ENCODE pPrivateFile = NULL;
  890. DWORD cbPrivateFile;
  891. BLOBHEADER *pPrivateBlob = NULL;
  892. DWORD cbPrivateBlob;
  893. HCRYPTKEY hPrivateKey;
  894. PKeyExchangeInfo pExchInfo;
  895. HCRYPTPROV hProv = 0;
  896. SP_STATUS pctRet;
  897. MD5_CTX md5Ctx;
  898. struct RC4_KEYSTRUCT rc4Key;
  899. DWORD i;
  900. if(pSubCred->cbPrivateKey == 0 ||
  901. pSubCred->pPrivateKey == NULL ||
  902. pSubCred->pszPassword == NULL)
  903. {
  904. return SP_LOG_RESULT(SEC_E_NO_CREDENTIALS);
  905. }
  906. pbPrivate = pSubCred->pPrivateKey;
  907. cbPrivate = pSubCred->cbPrivateKey;
  908. pbPassword = pSubCred->pszPassword;
  909. cbPassword = strlen(pbPassword);
  910. // We have to do a little fixup here. Old versions of
  911. // schannel wrote the wrong header data into the ASN
  912. // for private key files, so we must fix the size data.
  913. pbPrivate[2] = MSBOF(cbPrivate - 4);
  914. pbPrivate[3] = LSBOF(cbPrivate - 4);
  915. // ASN.1 decode the private key.
  916. if(!CryptDecodeObject(X509_ASN_ENCODING,
  917. szPrivateKeyFileEncode,
  918. pbPrivate,
  919. cbPrivate,
  920. 0,
  921. NULL,
  922. &cbPrivateFile))
  923. {
  924. DebugLog((SP_LOG_ERROR, "Error 0x%x decoding the private key\n",
  925. GetLastError()));
  926. pctRet = SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  927. goto error;
  928. }
  929. pPrivateFile = SPExternalAlloc(cbPrivateFile);
  930. if(pPrivateFile == NULL)
  931. {
  932. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  933. goto error;
  934. }
  935. if(!CryptDecodeObject(X509_ASN_ENCODING,
  936. szPrivateKeyFileEncode,
  937. pbPrivate,
  938. cbPrivate,
  939. 0,
  940. pPrivateFile,
  941. &cbPrivateFile))
  942. {
  943. DebugLog((SP_LOG_ERROR, "Error 0x%x decoding the private key\n",
  944. GetLastError()));
  945. pctRet = SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  946. goto error;
  947. }
  948. // Decrypt the decoded private key using the password.
  949. MD5Init(&md5Ctx);
  950. MD5Update(&md5Ctx, pbPassword, cbPassword);
  951. MD5Final(&md5Ctx);
  952. rc4_key(&rc4Key, 16, md5Ctx.digest);
  953. rc4(&rc4Key,
  954. pPrivateFile->EncryptedBlob.cbData,
  955. pPrivateFile->EncryptedBlob.pbData);
  956. // Build a PRIVATEKEYBLOB from the decrypted private key.
  957. if(!CryptDecodeObject(X509_ASN_ENCODING,
  958. szPrivateKeyInfoEncode,
  959. pPrivateFile->EncryptedBlob.pbData,
  960. pPrivateFile->EncryptedBlob.cbData,
  961. 0,
  962. NULL,
  963. &cbPrivateBlob))
  964. {
  965. // Maybe this was a SGC style key.
  966. // Re-encrypt it, and build the SGC decrypting
  967. // key, and re-decrypt it.
  968. BYTE md5Digest[MD5DIGESTLEN];
  969. rc4_key(&rc4Key, 16, md5Ctx.digest);
  970. rc4(&rc4Key,
  971. pPrivateFile->EncryptedBlob.cbData,
  972. pPrivateFile->EncryptedBlob.pbData);
  973. CopyMemory(md5Digest, md5Ctx.digest, MD5DIGESTLEN);
  974. MD5Init(&md5Ctx);
  975. MD5Update(&md5Ctx, md5Digest, MD5DIGESTLEN);
  976. MD5Update(&md5Ctx, SGC_KEY_SALT, lstrlen(SGC_KEY_SALT));
  977. MD5Final(&md5Ctx);
  978. rc4_key(&rc4Key, 16, md5Ctx.digest);
  979. rc4(&rc4Key,
  980. pPrivateFile->EncryptedBlob.cbData,
  981. pPrivateFile->EncryptedBlob.pbData);
  982. // Try again...
  983. if(!CryptDecodeObject(X509_ASN_ENCODING,
  984. szPrivateKeyInfoEncode,
  985. pPrivateFile->EncryptedBlob.pbData,
  986. pPrivateFile->EncryptedBlob.cbData,
  987. 0,
  988. NULL,
  989. &cbPrivateBlob))
  990. {
  991. DebugLog((SP_LOG_ERROR, "Error 0x%x building PRIVATEKEYBLOB\n",
  992. GetLastError()));
  993. ZeroMemory(&md5Ctx, sizeof(md5Ctx));
  994. pctRet = SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  995. goto error;
  996. }
  997. }
  998. ZeroMemory(&md5Ctx, sizeof(md5Ctx));
  999. pPrivateBlob = SPExternalAlloc(cbPrivateBlob);
  1000. if(pPrivateBlob == NULL)
  1001. {
  1002. pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  1003. goto error;
  1004. }
  1005. if(!CryptDecodeObject(X509_ASN_ENCODING,
  1006. szPrivateKeyInfoEncode,
  1007. pPrivateFile->EncryptedBlob.pbData,
  1008. pPrivateFile->EncryptedBlob.cbData,
  1009. 0,
  1010. pPrivateBlob,
  1011. &cbPrivateBlob))
  1012. {
  1013. DebugLog((SP_LOG_ERROR, "Error 0x%x building PRIVATEKEYBLOB\n",
  1014. GetLastError()));
  1015. pctRet = SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  1016. goto error;
  1017. }
  1018. // HACKHACK - Make sure that the key contained within the private
  1019. // key blob is marked for "key exchange".
  1020. pPrivateBlob->aiKeyAlg = CALG_RSA_KEYX;
  1021. // Create an in-memory key container.
  1022. if(!CryptAcquireContext(&hProv,
  1023. NULL,
  1024. NULL,
  1025. PROV_RSA_SCHANNEL,
  1026. CRYPT_VERIFYCONTEXT))
  1027. {
  1028. DebugLog((SP_LOG_ERROR, "Couldn't Acquire RSA Provider %lx\n", GetLastError()));
  1029. pctRet = SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  1030. goto error;
  1031. }
  1032. // Import the private key blob into the key container.
  1033. if(!CryptImportKey(hProv,
  1034. (PBYTE)pPrivateBlob,
  1035. cbPrivateBlob,
  1036. 0, 0,
  1037. &hPrivateKey))
  1038. {
  1039. DebugLog((SP_LOG_ERROR, "Error 0x%x importing PRIVATEKEYBLOB\n",
  1040. GetLastError()));
  1041. pctRet = SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  1042. goto error;
  1043. }
  1044. CryptDestroyKey(hPrivateKey);
  1045. // Obtain a matching CSP handle in the application process.
  1046. pctRet = RemoteCryptAcquireContextW(
  1047. &pCred->hRemoteProv,
  1048. NULL,
  1049. NULL,
  1050. PROV_RSA_SCHANNEL,
  1051. CRYPT_VERIFYCONTEXT,
  1052. SCH_CAPI_USE_CSP);
  1053. if(!NT_SUCCESS(pctRet))
  1054. {
  1055. pCred->hRemoteProv = 0;
  1056. SP_LOG_RESULT(pctRet);
  1057. goto error;
  1058. }
  1059. pCred->hProv = hProv;
  1060. pCred->dwKeySpec = AT_KEYEXCHANGE;
  1061. pCred->dwCapiFlags = SCH_CAPI_USE_CSP;
  1062. pctRet = PCT_ERR_OK;
  1063. error:
  1064. if(pPrivateFile) SPExternalFree(pPrivateFile);
  1065. if(pPrivateBlob) SPExternalFree(pPrivateBlob);
  1066. return pctRet;
  1067. }
  1068. SP_STATUS
  1069. LocalCryptAcquireContext(
  1070. HCRYPTPROV * phProv,
  1071. PCRYPT_KEY_PROV_INFO pProvInfo,
  1072. DWORD dwProtocol,
  1073. BOOL * pfEventLogged)
  1074. {
  1075. BOOL fImpersonating = FALSE;
  1076. BOOL fSuccess;
  1077. SP_STATUS Status;
  1078. HCRYPTPROV hProv;
  1079. // If the private key belongs to one of the Microsoft PROV_RSA_FULL
  1080. // CSPs, then manually divert it to the Microsoft PROV_RSA_SCHANNEL
  1081. // CSP. This works because both CSP types use the same private key
  1082. // storage scheme.
  1083. if(pProvInfo->dwProvType == PROV_RSA_FULL)
  1084. {
  1085. if(lstrcmpW(pProvInfo->pwszProvName, MS_DEF_PROV_W) == 0 ||
  1086. lstrcmpW(pProvInfo->pwszProvName, MS_STRONG_PROV_W) == 0 ||
  1087. lstrcmpW(pProvInfo->pwszProvName, MS_ENHANCED_PROV_W) == 0)
  1088. {
  1089. DebugLog((DEB_WARN, "Force CSP type to PROV_RSA_SCHANNEL.\n"));
  1090. pProvInfo->pwszProvName = MS_DEF_RSA_SCHANNEL_PROV_W;
  1091. pProvInfo->dwProvType = PROV_RSA_SCHANNEL;
  1092. }
  1093. }
  1094. if(pProvInfo->dwProvType != PROV_RSA_SCHANNEL &&
  1095. pProvInfo->dwProvType != PROV_DH_SCHANNEL)
  1096. {
  1097. DebugLog((SP_LOG_ERROR, "Bad server CSP type:%d\n", pProvInfo->dwProvType));
  1098. return SP_LOG_RESULT(PCT_ERR_UNKNOWN_CREDENTIAL);
  1099. }
  1100. fImpersonating = SslImpersonateClient();
  1101. fSuccess = CryptAcquireContextW(&hProv,
  1102. pProvInfo->pwszContainerName,
  1103. pProvInfo->pwszProvName,
  1104. pProvInfo->dwProvType,
  1105. pProvInfo->dwFlags | CRYPT_SILENT);
  1106. if(fImpersonating)
  1107. {
  1108. RevertToSelf();
  1109. fImpersonating = FALSE;
  1110. }
  1111. if(!fSuccess)
  1112. {
  1113. Status = GetLastError();
  1114. DebugLog((SP_LOG_ERROR, "Error 0x%x calling CryptAcquireContextW\n", Status));
  1115. LogCredAcquireContextFailedEvent(dwProtocol, Status);
  1116. *pfEventLogged = TRUE;
  1117. return SP_LOG_RESULT(PCT_ERR_UNKNOWN_CREDENTIAL);
  1118. }
  1119. DebugLog((SP_LOG_TRACE, "Local CSP handle acquired (0x%p)\n", hProv));
  1120. *phProv = hProv;
  1121. return PCT_ERR_OK;
  1122. }
  1123. //+---------------------------------------------------------------------------
  1124. //
  1125. // Function: GetPrivateFromCert
  1126. //
  1127. // Synopsis: Given a certificate context, somehow obtain a handle to the
  1128. // corresponding key container. Determine the key spec of the
  1129. // private key.
  1130. //
  1131. // Arguments: [pCred] -- Pointer to the credential.
  1132. //
  1133. // History: 09-24-96 jbanes Hacked for LSA integration.
  1134. //
  1135. // Notes: The private key often lives in a CSP. In this case, a handle
  1136. // to the CSP context is obtained by either reading the
  1137. // CERT_KEY_REMOTE_PROV_HANDLE_PROP_ID property, or by reading
  1138. // the CERT_KEY_PROV_INFO_PROP_ID property and then calling
  1139. // CryptAcquireContext.
  1140. //
  1141. // If this fails, then check and see if the private key is
  1142. // stored by IIS. If this is the case, then the encrypted
  1143. // private key is obtained by reading the
  1144. //
  1145. //----------------------------------------------------------------------------
  1146. SP_STATUS
  1147. GetPrivateFromCert(
  1148. PSPCredential pCred,
  1149. DWORD dwProtocol,
  1150. PLSA_SCHANNEL_SUB_CRED pSubCred)
  1151. {
  1152. PCRYPT_KEY_PROV_INFO pProvInfo = NULL;
  1153. HCRYPTPROV hProv;
  1154. DWORD cbSize;
  1155. BOOL fRemoteProvider = FALSE;
  1156. NTSTATUS Status;
  1157. BOOL fEventLogged = FALSE;
  1158. //
  1159. // Set the output fields to default values.
  1160. //
  1161. pCred->hProv = 0;
  1162. pCred->hRemoteProv = 0;
  1163. pCred->dwCapiFlags = SCH_CAPI_USE_CSP;
  1164. pCred->dwKeySpec = AT_KEYEXCHANGE;
  1165. if(dwProtocol & SP_PROT_CLIENTS)
  1166. {
  1167. // Access the CSP from the application process.
  1168. fRemoteProvider = TRUE;
  1169. }
  1170. //
  1171. // Check to see if the application called CryptAcquireContext. If so then
  1172. // we don't have to. This will typically not be the case.
  1173. //
  1174. if(fRemoteProvider && pSubCred->hRemoteProv)
  1175. {
  1176. DebugLog((SP_LOG_TRACE, "Application provided CSP handle (0x%p)\n", pSubCred->hRemoteProv));
  1177. pCred->hRemoteProv = pSubCred->hRemoteProv;
  1178. pCred->fAppRemoteProv = TRUE;
  1179. }
  1180. //
  1181. // Read the certificate context's "key info" property.
  1182. //
  1183. if(CertGetCertificateContextProperty(pCred->pCert,
  1184. CERT_KEY_PROV_INFO_PROP_ID,
  1185. NULL,
  1186. &cbSize))
  1187. {
  1188. pProvInfo = SPExternalAlloc(cbSize);
  1189. if(pProvInfo == NULL)
  1190. {
  1191. Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
  1192. goto cleanup;
  1193. }
  1194. if(!CertGetCertificateContextProperty(pCred->pCert,
  1195. CERT_KEY_PROV_INFO_PROP_ID,
  1196. pProvInfo,
  1197. &cbSize))
  1198. {
  1199. DebugLog((SP_LOG_ERROR, "Error 0x%x reading CERT_KEY_PROV_INFO_PROP_ID\n",GetLastError()));
  1200. SPExternalFree(pProvInfo);
  1201. pProvInfo = NULL;
  1202. }
  1203. else
  1204. {
  1205. // Success.
  1206. pCred->dwKeySpec = pProvInfo->dwKeySpec;
  1207. DebugLog((SP_LOG_TRACE, "Container:%ls\n", pProvInfo->pwszContainerName));
  1208. DebugLog((SP_LOG_TRACE, "Provider: %ls\n", pProvInfo->pwszProvName));
  1209. DebugLog((SP_LOG_TRACE, "Type: 0x%8.8x\n", pProvInfo->dwProvType));
  1210. DebugLog((SP_LOG_TRACE, "Flags: 0x%8.8x\n", pProvInfo->dwFlags));
  1211. DebugLog((SP_LOG_TRACE, "Key spec: %d\n", pProvInfo->dwKeySpec));
  1212. LogCredPropertiesEvent(dwProtocol, pProvInfo, pCred->pCert);
  1213. }
  1214. }
  1215. if(pCred->hRemoteProv)
  1216. {
  1217. // The application supplied an hProv for us to use.
  1218. Status = PCT_ERR_OK;
  1219. goto cleanup;
  1220. }
  1221. if(pProvInfo)
  1222. {
  1223. //
  1224. // We read the "key info" property successfully, so call
  1225. // CryptAcquireContext in order to get a handle to the appropriate
  1226. // key container.
  1227. //
  1228. if(!fRemoteProvider)
  1229. {
  1230. // Call CryptAcquireContext from the LSA process.
  1231. Status = LocalCryptAcquireContext(&hProv, pProvInfo, dwProtocol, &fEventLogged);
  1232. if(Status != PCT_ERR_OK)
  1233. {
  1234. goto cleanup;
  1235. }
  1236. pCred->hProv = hProv;
  1237. }
  1238. // Obtain a matching CSP handle in the application process.
  1239. Status = RemoteCryptAcquireContextW(
  1240. &pCred->hRemoteProv,
  1241. pProvInfo->pwszContainerName,
  1242. pProvInfo->pwszProvName,
  1243. pProvInfo->dwProvType,
  1244. pProvInfo->dwFlags,
  1245. pCred->dwCapiFlags);
  1246. if(!NT_SUCCESS(Status))
  1247. {
  1248. LogCredAcquireContextFailedEvent(dwProtocol, Status);
  1249. fEventLogged = TRUE;
  1250. Status = SP_LOG_RESULT(PCT_ERR_UNKNOWN_CREDENTIAL);
  1251. goto cleanup;
  1252. }
  1253. }
  1254. else
  1255. {
  1256. //
  1257. // We weren't able to read the "key info" property, so attempt to
  1258. // read the "iis private key" property, and build the private key
  1259. // up from that.
  1260. //
  1261. DebugLog((SP_LOG_TRACE, "Attempt IIS 4.0 compatibility hack.\n"));
  1262. Status = GetIisPrivateFromCert(pCred, pSubCred);
  1263. if(Status != PCT_ERR_OK)
  1264. {
  1265. SP_LOG_RESULT(Status);
  1266. goto cleanup;
  1267. }
  1268. }
  1269. Status = PCT_ERR_OK;
  1270. cleanup:
  1271. if(Status != PCT_ERR_OK && fEventLogged == FALSE)
  1272. {
  1273. if(pProvInfo == NULL)
  1274. {
  1275. LogNoPrivateKeyEvent(dwProtocol);
  1276. }
  1277. else
  1278. {
  1279. LogCreateCredFailedEvent(dwProtocol);
  1280. }
  1281. }
  1282. if(pProvInfo)
  1283. {
  1284. SPExternalFree(pProvInfo);
  1285. }
  1286. return Status;
  1287. }
  1288. DWORD
  1289. GetCredentialKeySize(
  1290. PSPCredential pCred)
  1291. {
  1292. BLOBHEADER *pPublic;
  1293. RSAPUBKEY * pRsaPublic;
  1294. if(pCred->pPublicKey == NULL)
  1295. {
  1296. return 0;
  1297. }
  1298. pPublic = pCred->pPublicKey->pPublic;
  1299. if(pPublic == NULL || pPublic->bType != PUBLICKEYBLOB)
  1300. {
  1301. return 0;
  1302. }
  1303. pRsaPublic = (RSAPUBKEY *)(pPublic + 1);
  1304. return pRsaPublic->bitlen;
  1305. }