Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

598 lines
13 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. certcach.cxx
  5. Abstract:
  6. Contains class implementation for certificate cache object.
  7. This object will hold various Certificate entries.
  8. Contents:
  9. SECURITY_CACHE_LIST_ENTRY::SECURITY_CACHE_LIST_ENTRY
  10. SECURITY_CACHE_LIST_ENTRY::~SECURITY_CACHE_LIST_ENTRY
  11. SECURITY_CACHE_LIST_ENTRY::AddRef
  12. SECURITY_CACHE_LIST_ENTRY::Release
  13. SECURITY_CACHE_LIST_ENTRY::Clear
  14. SECURITY_CACHE_LIST::Find
  15. SECURITY_CACHE_LIST::Add
  16. SECURITY_CACHE_LIST::ClearList
  17. SECURITY_CACHE_LIST::Initialize
  18. SECURITY_CACHE_LIST::Terminate
  19. TODO: Add Cert validation. What if Cert is given but different?
  20. Author:
  21. Arthur L Bierer (arthurbi) 20-Apr-1996
  22. Revision History:
  23. 20-Apr-1996 arthurbi
  24. Created
  25. --*/
  26. #include <wininetp.h>
  27. //
  28. //
  29. // List of encryption packages: PCT, SSL, etc
  30. //
  31. //
  32. // BUGBUG [arthurbi] The SSL and PCT package names
  33. // are hard coded into the stucture below. We need
  34. // to be more flexible in case someone write a FOO security
  35. // package.
  36. //
  37. // BUGBUG: Don't change the order of the packages below. some old SSL2 sites deny the UNISP
  38. // provider, and if we walk down the list to PCT1 or SSL3, things hang.
  39. const SEC_PROVIDER g_cSecProviders[MAX_SEC_PROVIDERS] =
  40. {
  41. UNISP_NAME, INVALID_CRED_VALUE , ENC_CAPS_SSL | ENC_CAPS_SCHANNEL_CREDS, FALSE, SP_PROT_CLIENTS, NULL,
  42. UNISP_NAME, INVALID_CRED_VALUE , ENC_CAPS_SSL | ENC_CAPS_SCHANNEL_CREDS, FALSE, SP_PROT_SSL2_CLIENT, NULL,
  43. // PCT1SP_NAME, INVALID_CRED_VALUE , ENC_CAPS_PCT| ENC_CAPS_SCHANNEL_CREDS, FALSE, SP_PROT_PCT1_CLIENT, NULL,
  44. // SSL3SP_NAME, INVALID_CRED_VALUE , ENC_CAPS_SSL| ENC_CAPS_SCHANNEL_CREDS, FALSE, SP_PROT_SSL3_CLIENT, NULL,
  45. NULL, INVALID_CRED_VALUE , FALSE, FALSE, 0
  46. };
  47. //
  48. // private manifests
  49. //
  50. #define MAX_CERT_CACHE_CERTS 16
  51. //
  52. // private types
  53. //
  54. //
  55. // SECURITY_CACHE_LIST_ENTRY member functions
  56. //
  57. SECURITY_CACHE_LIST_ENTRY::SECURITY_CACHE_LIST_ENTRY(
  58. IN BOOL fNoRevert,
  59. IN LPSTR lpszHostName,
  60. IN INTERNET_PORT ServerPort
  61. )
  62. /*++
  63. Routine Description:
  64. SECURITY_CACHE_LIST_ENTRY constructor. Create object; don't add it to list
  65. Arguments:
  66. fNoRevert - Revert any impersonation on SSL handling?
  67. lpszHostName - name of host for which this cache entry created
  68. Return Value:
  69. None.
  70. --*/
  71. {
  72. DEBUG_ENTER((DBG_OBJECTS,
  73. None,
  74. "SECURITY_CACHE_LIST_ENTRY::SECURITY_CACHE_LIST_ENTRY",
  75. "%q",
  76. lpszHostName
  77. ));
  78. #if INET_DEBUG
  79. _List.Flink = _List.Blink = NULL;
  80. #endif
  81. _cRef = 1;
  82. _fInCache = FALSE;
  83. _ServerName = lpszHostName;
  84. _ServerPort = ServerPort;
  85. ZeroMemory(&_CertInfo, sizeof(_CertInfo));
  86. _dwSecurityFlags = 0;
  87. _dwStatusFlags = 0;
  88. _pCertContextArray = NULL;
  89. _fNoRevert = fNoRevert;
  90. #if INET_DEBUG
  91. m_Signature = 0x454c4353; // 'SCLE'
  92. #endif
  93. DEBUG_LEAVE(0);
  94. }
  95. SECURITY_CACHE_LIST_ENTRY::~SECURITY_CACHE_LIST_ENTRY()
  96. /*++
  97. Routine Description:
  98. SECURITY_CACHE_LIST_ENTRY destructor.
  99. Arguments:
  100. None.
  101. Return Value:
  102. None.
  103. --*/
  104. {
  105. DEBUG_ENTER((DBG_OBJECTS,
  106. None,
  107. "~SECURITY_CACHE_LIST_ENTRY",
  108. "{%#x [%q]}",
  109. this,
  110. _ServerName.StringAddress()
  111. ));
  112. INET_ASSERT((_List.Flink == NULL) && (_List.Blink == NULL));
  113. Clear();
  114. DEBUG_LEAVE(0);
  115. }
  116. LONG
  117. SECURITY_CACHE_LIST_ENTRY::AddRef(
  118. VOID
  119. )
  120. /*++
  121. Routine Description:
  122. Increment reference count of SECURITY_CACHE_LIST_ENTRY
  123. Arguments:
  124. None.
  125. Return Value:
  126. LONG - reference count after increment
  127. --*/
  128. {
  129. DEBUG_ENTER((DBG_OBJECTS,
  130. Int,
  131. "SECURITY_CACHE_LIST_ENTRY::AddRef",
  132. "{%#x [%q, %d]}",
  133. this,
  134. _ServerName.StringAddress(),
  135. _cRef
  136. ));
  137. InterlockedIncrement(&_cRef);
  138. DEBUG_LEAVE(_cRef);
  139. return _cRef;
  140. }
  141. LONG
  142. SECURITY_CACHE_LIST_ENTRY::Release(
  143. VOID
  144. )
  145. /*++
  146. Routine Description:
  147. Decrement reference count and destroy object if (<=) zero
  148. Arguments:
  149. None.
  150. Return Value:
  151. LONG - reference count after decrement
  152. --*/
  153. {
  154. DEBUG_ENTER((DBG_OBJECTS,
  155. Int,
  156. "SECURITY_CACHE_LIST_ENTRY::Release",
  157. "{%q [%d]}",
  158. _ServerName.StringAddress(),
  159. _cRef
  160. ));
  161. LONG cRet;
  162. if (0 >= (cRet = InterlockedDecrement(&_cRef))) {
  163. delete this;
  164. }
  165. DEBUG_LEAVE(cRet);
  166. return cRet;
  167. }
  168. VOID
  169. SECURITY_CACHE_LIST_ENTRY::Clear()
  170. /*++
  171. Routine Description:
  172. Clear out SECURITY_CACHE_LIST_ENTRY
  173. Arguments:
  174. Clear -
  175. Return Value:
  176. None.
  177. --*/
  178. {
  179. if (_CertInfo.pCertificate != NULL)
  180. {
  181. SAFE_WRAP_REVERT_USER_VOID((*g_pfnCertFreeCertificateContext), _fNoRevert, (_CertInfo.pCertificate));
  182. _CertInfo.pCertificate = NULL;
  183. }
  184. ZeroMemory(&_CertInfo, sizeof(_CertInfo));
  185. _CertInfo.dwSize = sizeof(_CertInfo);
  186. _dwSecurityFlags = 0;
  187. _dwStatusFlags = 0;
  188. _ServerName = NULL;
  189. if( _pCertContextArray )
  190. {
  191. delete _pCertContextArray;
  192. _pCertContextArray = NULL;
  193. }
  194. }
  195. //
  196. // SECURITY_CACHE_LIST member functions
  197. //
  198. VOID
  199. SECURITY_CACHE_LIST::ClearList(
  200. VOID
  201. )
  202. /*++
  203. Routine Description:
  204. description-of-function.
  205. Arguments:
  206. None.
  207. Return Value:
  208. None.
  209. --*/
  210. {
  211. DEBUG_ENTER((DBG_OBJECTS,
  212. None,
  213. "SECURITY_CACHE_LIST::ClearList",
  214. NULL
  215. ));
  216. if (!LockSerializedList(&_List))
  217. {
  218. DEBUG_PRINT(OBJECTS,
  219. ERROR,
  220. ("Failed to obtain lock -- SECURITY_CACHE_LIST potentially leaked\n"
  221. ));
  222. goto quit;
  223. }
  224. while (!IsSerializedListEmpty(&_List)) {
  225. SECURITY_CACHE_LIST_ENTRY * CacheEntry;
  226. //
  227. // remove the PROXY_SERVER_LIST_ENTRY at the head of the serialized
  228. // list
  229. //
  230. LPVOID entry = SlDequeueHead(&_List);
  231. //
  232. // entry should not be NULL - IsSerializedListEmpty() told us we
  233. // could expect something
  234. //
  235. INET_ASSERT(entry != NULL);
  236. //
  237. // get the address of the object (should be the same as entry) and
  238. // delete it
  239. //
  240. CacheEntry = CONTAINING_RECORD(entry, SECURITY_CACHE_LIST_ENTRY, _List);
  241. DEBUG_PRINT(OBJECTS,
  242. INFO,
  243. ("releasing %q (%d)\n",
  244. CacheEntry->_ServerName.StringAddress(),
  245. CacheEntry->_cRef
  246. ));
  247. CacheEntry->Release();
  248. }
  249. UnlockSerializedList(&_List);
  250. quit:
  251. DEBUG_LEAVE(0);
  252. }
  253. DWORD
  254. SECURITY_CACHE_LIST::Add(
  255. IN SECURITY_CACHE_LIST_ENTRY * entry
  256. )
  257. /*++
  258. Routine Description:
  259. Adds a CertInfo Structure to the list front of the list.
  260. Arguments:
  261. lpszHost - Hostname to add.
  262. Return Value:
  263. DWORD
  264. Success - ERROR_SUCCESS
  265. Failure - ERROR_NOT_ENOUGH_MEMORY
  266. --*/
  267. {
  268. DEBUG_ENTER((DBG_HTTP,
  269. Dword,
  270. "SECURITY_CACHE_LIST::Add",
  271. "%#x [%q, %d]",
  272. entry,
  273. entry ? entry->_ServerName.StringAddress() : "",
  274. entry ? entry->_cRef : 0
  275. ));
  276. DWORD error = ERROR_SUCCESS;
  277. INET_ASSERT(entry != NULL);
  278. if (entry != NULL) {
  279. if (LockSerializedList(&_List))
  280. {
  281. //
  282. // If we've grown too much, nuke the oldest one.
  283. //
  284. if (ElementsOnSerializedList(&_List) >= MAX_CERT_CACHE_CERTS) {
  285. SECURITY_CACHE_LIST_ENTRY *pOld;
  286. LPVOID old_entry = SlDequeueTail(&_List);
  287. INET_ASSERT(old_entry != NULL);
  288. pOld = CONTAINING_RECORD(old_entry, SECURITY_CACHE_LIST_ENTRY, _List);
  289. //
  290. // entry should not be NULL - IsSerializedListEmpty() told us we
  291. // could expect something
  292. //
  293. pOld->_fInCache = FALSE;
  294. //
  295. // Clean Our old object, and reinstatiate with a new name.
  296. //
  297. pOld->Release();
  298. }
  299. if (InsertAtHeadOfSerializedList(&_List, &entry->_List)) {
  300. entry->AddRef();
  301. entry->_fInCache = TRUE;
  302. }
  303. UnlockSerializedList(&_List);
  304. }
  305. else
  306. error = ERROR_NOT_ENOUGH_MEMORY;
  307. }
  308. DEBUG_LEAVE(error);
  309. return error;
  310. }
  311. SECURITY_CACHE_LIST_ENTRY *
  312. SECURITY_CACHE_LIST::Find(
  313. IN LPSTR lpszHost,
  314. IN INTERNET_PORT HostPort
  315. )
  316. /*++
  317. Routine Description:
  318. Searches the linked list for the Cert, and returns
  319. the found entry, or NULL if not found.
  320. Arguments:
  321. lpszHost - Hostname to search on.
  322. Return Value:
  323. CERT_CACHE_LIST_ENTRY *
  324. Success - Pointer to found entry.
  325. Failure - NULL, not found.
  326. --*/
  327. {
  328. DEBUG_ENTER((DBG_HTTP,
  329. Pointer,
  330. "SECURITY_CACHE_LIST::Find",
  331. "%q",
  332. lpszHost
  333. ));
  334. SECURITY_CACHE_LIST_ENTRY * info = NULL;
  335. //
  336. // BUGBUG need to validate against Server Certifcate on every
  337. // connection, this Find only validates by Hostname.
  338. // What about DNS spoofing? Won't we be hosed?
  339. //
  340. //
  341. // TODO if found, need to push to front of list.
  342. //
  343. if (LockSerializedList(&_List))
  344. {
  345. for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
  346. entry != (PLIST_ENTRY)SlSelf(&_List);
  347. entry = entry->Flink)
  348. {
  349. info = CONTAINING_RECORD(entry, SECURITY_CACHE_LIST_ENTRY, _List);
  350. //
  351. // check to see if they match.
  352. //
  353. if ((info->_ServerName.Stricmp(lpszHost) == 0) && info->_ServerPort == HostPort) {
  354. info->AddRef();
  355. break; // match.
  356. }
  357. info = NULL;
  358. }
  359. UnlockSerializedList(&_List);
  360. }
  361. DEBUG_LEAVE(info);
  362. return info;
  363. }
  364. BOOL SECURITY_CACHE_LIST::Initialize(
  365. VOID
  366. )
  367. {
  368. if (!InitializeSerializedList(&_List))
  369. return FALSE;
  370. #if INET_DEBUG
  371. m_Signature = 0x4c436553; // "SeCL"
  372. #endif
  373. // Fill in default starting values, will enumerate and acquire handles
  374. // during the first SSL handshake for the session.
  375. CopyMemory((LPVOID)_SecProviders,
  376. (CONST VOID *)g_cSecProviders,
  377. sizeof(SEC_PROVIDER) * MAX_SEC_PROVIDERS);
  378. _dwEncFlags = 0;
  379. _dwSecureProtocols = DEFAULT_SECURE_PROTOCOLS;
  380. return TRUE;
  381. }
  382. VOID SECURITY_CACHE_LIST::Terminate(
  383. VOID
  384. )
  385. {
  386. DEBUG_ENTER((DBG_OBJECTS,
  387. None,
  388. "SECURITY_CACHE_LIST::Terminate",
  389. "{%#x}",
  390. this
  391. ));
  392. ClearList();
  393. //
  394. // free all security pkg credential handles
  395. //
  396. for (DWORD i = 0; _SecProviders[i].pszName != NULL ; i++)
  397. {
  398. if (_SecProviders[i].fEnabled)
  399. {
  400. if (_SecProviders[i].pCertCtxt == NULL && !IsCredClear(_SecProviders[i].hCreds))
  401. {
  402. // Beta1 Hack. Because of some circular dependency between dlls
  403. // both crypt32 and schannel's PROCESS_DETACH gets called before wininet.
  404. // This is catastrophic if we have a cert context attached to the credentials
  405. // handle. In this case we will just leak the handle since the process is dying
  406. // anyway. We really need to fix this.
  407. WRAP_REVERT_USER_VOID(g_FreeCredentialsHandle,
  408. IsImpersonationEnabled(),
  409. (&_SecProviders[i].hCreds));
  410. }
  411. }
  412. #if 0 // See comments above.
  413. if (_SecProviders[i].pCertCtxt != NULL)
  414. {
  415. (*g_pfnCertFreeCertificateContext)(_SecProviders[i].pCertCtxt);
  416. _SecProviders[i].pCertCtxt = NULL;
  417. }
  418. #endif
  419. }
  420. TerminateSerializedList(&_List);
  421. DEBUG_LEAVE(0);
  422. }