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.

593 lines
11 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::ClearClientAuthCertChains
  18. TODO: Add Cert validation. What if Cert is given but different?
  19. Author:
  20. Arthur L Bierer (arthurbi) 20-Apr-1996
  21. Revision History:
  22. 20-Apr-1996 arthurbi
  23. Created
  24. --*/
  25. #include <wininetp.h>
  26. //
  27. // private manifests
  28. //
  29. #define MAX_CERT_CACHE_CERTS 16
  30. //
  31. // private types
  32. //
  33. //
  34. // SECURITY_CACHE_LIST_ENTRY member functions
  35. //
  36. SECURITY_CACHE_LIST_ENTRY::SECURITY_CACHE_LIST_ENTRY(
  37. IN LPSTR lpszHostName
  38. )
  39. /*++
  40. Routine Description:
  41. SECURITY_CACHE_LIST_ENTRY constructor. Create object; don't add it to list
  42. Arguments:
  43. lpszHostName - name of host for which this cache entry created
  44. Return Value:
  45. None.
  46. --*/
  47. {
  48. DEBUG_ENTER((DBG_OBJECTS,
  49. None,
  50. "SECURITY_CACHE_LIST_ENTRY::SECURITY_CACHE_LIST_ENTRY",
  51. "%q",
  52. lpszHostName
  53. ));
  54. #if INET_DEBUG
  55. _List.Flink = _List.Blink = NULL;
  56. #endif
  57. _cRef = 1;
  58. _fInCache = FALSE;
  59. _ServerName = lpszHostName;
  60. ZeroMemory(&_CertInfo, sizeof(_CertInfo));
  61. _dwSecurityFlags = 0;
  62. _pCertContextArray = NULL;
  63. _fForceNewSession = FALSE;
  64. _fValidateAll = FALSE;
  65. #if INET_DEBUG
  66. m_Signature = 0x454c4353; // 'SCLE'
  67. #endif
  68. DEBUG_LEAVE(0);
  69. }
  70. SECURITY_CACHE_LIST_ENTRY::~SECURITY_CACHE_LIST_ENTRY()
  71. /*++
  72. Routine Description:
  73. SECURITY_CACHE_LIST_ENTRY destructor.
  74. Arguments:
  75. None.
  76. Return Value:
  77. None.
  78. --*/
  79. {
  80. DEBUG_ENTER((DBG_OBJECTS,
  81. None,
  82. "~SECURITY_CACHE_LIST_ENTRY",
  83. "{%#x [%q]}",
  84. this,
  85. _ServerName.StringAddress()
  86. ));
  87. INET_ASSERT((_List.Flink == NULL) && (_List.Blink == NULL));
  88. Clear();
  89. DEBUG_LEAVE(0);
  90. }
  91. LONG
  92. SECURITY_CACHE_LIST_ENTRY::AddRef(
  93. VOID
  94. )
  95. /*++
  96. Routine Description:
  97. Increment reference count of SECURITY_CACHE_LIST_ENTRY
  98. Arguments:
  99. None.
  100. Return Value:
  101. LONG - reference count after increment
  102. --*/
  103. {
  104. DEBUG_ENTER((DBG_OBJECTS,
  105. Int,
  106. "SECURITY_CACHE_LIST_ENTRY::AddRef",
  107. "{%#x [%q, %d]}",
  108. this,
  109. _ServerName.StringAddress(),
  110. _cRef
  111. ));
  112. InterlockedIncrement(&_cRef);
  113. DEBUG_LEAVE(_cRef);
  114. return _cRef;
  115. }
  116. LONG
  117. SECURITY_CACHE_LIST_ENTRY::Release(
  118. VOID
  119. )
  120. /*++
  121. Routine Description:
  122. Decrement reference count and destroy object if (<=) zero
  123. Arguments:
  124. None.
  125. Return Value:
  126. LONG - reference count after decrement
  127. --*/
  128. {
  129. DEBUG_ENTER((DBG_OBJECTS,
  130. Int,
  131. "SECURITY_CACHE_LIST_ENTRY::Release",
  132. "{%q [%d]}",
  133. _ServerName.StringAddress(),
  134. _cRef
  135. ));
  136. LONG cRet;
  137. if (0 >= (cRet = InterlockedDecrement(&_cRef))) {
  138. delete this;
  139. }
  140. DEBUG_LEAVE(cRet);
  141. return cRet;
  142. }
  143. VOID
  144. SECURITY_CACHE_LIST_ENTRY::Clear()
  145. /*++
  146. Routine Description:
  147. Clear out SECURITY_CACHE_LIST_ENTRY
  148. Arguments:
  149. Clear -
  150. Return Value:
  151. None.
  152. --*/
  153. {
  154. if (_CertInfo.pCertificate != NULL) {
  155. __try {
  156. CertFreeCertificateContext(_CertInfo.pCertificate);
  157. } __except(EXCEPTION_EXECUTE_HANDLER) {
  158. }
  159. ENDEXCEPT
  160. _CertInfo.pCertificate = NULL;
  161. }
  162. ZeroMemory(&_CertInfo, sizeof(_CertInfo));
  163. _CertInfo.dwSize = sizeof(_CertInfo);
  164. _dwSecurityFlags = 0;
  165. _ServerName = NULL;
  166. _pCertContextArray = NULL;
  167. if( _pCertContextArray )
  168. {
  169. delete _pCertContextArray;
  170. _pCertContextArray = NULL;
  171. }
  172. }
  173. //
  174. // SECURITY_CACHE_LIST member functions
  175. //
  176. VOID
  177. SECURITY_CACHE_LIST::ClearList(
  178. VOID
  179. )
  180. /*++
  181. Routine Description:
  182. description-of-function.
  183. Arguments:
  184. None.
  185. Return Value:
  186. None.
  187. --*/
  188. {
  189. DEBUG_ENTER((DBG_OBJECTS,
  190. None,
  191. "SECURITY_CACHE_LIST::ClearList",
  192. NULL
  193. ));
  194. LockSerializedList(&_List);
  195. while (!IsSerializedListEmpty(&_List)) {
  196. SECURITY_CACHE_LIST_ENTRY * CacheEntry;
  197. //
  198. // remove the PROXY_SERVER_LIST_ENTRY at the head of the serialized
  199. // list
  200. //
  201. LPVOID entry = SlDequeueHead(&_List);
  202. //
  203. // entry should not be NULL - IsSerializedListEmpty() told us we
  204. // could expect something
  205. //
  206. INET_ASSERT(entry != NULL);
  207. //
  208. // get the address of the object (should be the same as entry) and
  209. // delete it
  210. //
  211. CacheEntry = CONTAINING_RECORD(entry, SECURITY_CACHE_LIST_ENTRY, _List);
  212. DEBUG_PRINT(OBJECTS,
  213. INFO,
  214. ("releasing %q (%d)\n",
  215. CacheEntry->_ServerName.StringAddress(),
  216. CacheEntry->_cRef
  217. ));
  218. CacheEntry->Release();
  219. }
  220. UnlockSerializedList(&_List);
  221. DEBUG_LEAVE(0);
  222. }
  223. DWORD
  224. SECURITY_CACHE_LIST::Add(
  225. IN SECURITY_CACHE_LIST_ENTRY * entry
  226. )
  227. /*++
  228. Routine Description:
  229. Adds a CertInfo Structure to the list front of the list.
  230. Arguments:
  231. lpszHost - Hostname to add.
  232. Return Value:
  233. DWORD
  234. Success - ERROR_SUCCESS
  235. Failure - ERROR_NOT_ENOUGH_MEMORY
  236. --*/
  237. {
  238. DEBUG_ENTER((DBG_HTTP,
  239. Dword,
  240. "SECURITY_CACHE_LIST::Add",
  241. "%#x [%q, %d]",
  242. entry,
  243. entry ? entry->_ServerName.StringAddress() : "",
  244. entry ? entry->_cRef : 0
  245. ));
  246. DWORD error = ERROR_SUCCESS;
  247. INET_ASSERT(entry != NULL);
  248. if (entry != NULL) {
  249. LockSerializedList(&_List);
  250. //
  251. // If we've grown too much, nuke the oldest one.
  252. //
  253. if (ElementsOnSerializedList(&_List) >= MAX_CERT_CACHE_CERTS) {
  254. SECURITY_CACHE_LIST_ENTRY *pOld;
  255. LPVOID old_entry = SlDequeueTail(&_List);
  256. INET_ASSERT(old_entry != NULL);
  257. pOld = CONTAINING_RECORD(old_entry, SECURITY_CACHE_LIST_ENTRY, _List);
  258. //
  259. // entry should not be NULL - IsSerializedListEmpty() told us we
  260. // could expect something
  261. //
  262. pOld->_fInCache = FALSE;
  263. //
  264. // Clean Our old object, and reinstatiate with a new name.
  265. //
  266. pOld->Release();
  267. }
  268. InsertAtHeadOfSerializedList(&_List, &entry->_List);
  269. entry->AddRef();
  270. entry->_fInCache = TRUE;
  271. UnlockSerializedList(&_List);
  272. }
  273. DEBUG_LEAVE(error);
  274. return error;
  275. }
  276. SECURITY_CACHE_LIST_ENTRY *
  277. SECURITY_CACHE_LIST::Find(
  278. IN LPSTR lpszHost
  279. )
  280. /*++
  281. Routine Description:
  282. Searches the linked list for the Cert, and returns
  283. the found entry, or NULL if not found.
  284. Arguments:
  285. lpszHost - Hostname to search on.
  286. Return Value:
  287. CERT_CACHE_LIST_ENTRY *
  288. Success - Pointer to found entry.
  289. Failure - NULL, not found.
  290. --*/
  291. {
  292. DEBUG_ENTER((DBG_HTTP,
  293. Pointer,
  294. "SECURITY_CACHE_LIST::Find",
  295. "%q",
  296. lpszHost
  297. ));
  298. SECURITY_CACHE_LIST_ENTRY * info = NULL;
  299. //
  300. // BUGBUG need to validate against Server Certifcate on every
  301. // connection, this Find only validates by Hostname.
  302. // What about DNS spoofing? Won't we be hosed?
  303. //
  304. //
  305. // TODO if found, need to push to front of list.
  306. //
  307. LockSerializedList(&_List);
  308. for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
  309. entry != (PLIST_ENTRY)SlSelf(&_List);
  310. entry = entry->Flink)
  311. {
  312. info = CONTAINING_RECORD(entry, SECURITY_CACHE_LIST_ENTRY, _List);
  313. //
  314. // check to see if they match.
  315. //
  316. if (info->_ServerName.Stricmp(lpszHost) == 0) {
  317. info->AddRef();
  318. break; // match.
  319. }
  320. info = NULL;
  321. }
  322. UnlockSerializedList(&_List);
  323. DEBUG_LEAVE(info);
  324. return info;
  325. }
  326. VOID
  327. SECURITY_CACHE_LIST::Remove(
  328. IN LPSTR lpszHost
  329. )
  330. /*++
  331. Routine Description:
  332. Searches the linked list for the Cert, and removes
  333. the entry.
  334. Arguments:
  335. lpszHost - Hostname to search on.
  336. Return Value:
  337. None
  338. --*/
  339. {
  340. DEBUG_ENTER((DBG_HTTP,
  341. Pointer,
  342. "SECURITY_CACHE_LIST::Remove",
  343. "%q",
  344. lpszHost
  345. ));
  346. SECURITY_CACHE_LIST_ENTRY * info = NULL;
  347. LockSerializedList(&_List);
  348. for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
  349. entry != (PLIST_ENTRY)SlSelf(&_List);
  350. entry = entry->Flink)
  351. {
  352. info = CONTAINING_RECORD(entry, SECURITY_CACHE_LIST_ENTRY, _List);
  353. //
  354. // check to see if they match.
  355. //
  356. if (info->_ServerName.Stricmp(lpszHost) == 0) {
  357. RemoveFromSerializedList(&_List, entry);
  358. break; // match.
  359. }
  360. info->_fInCache = FALSE;
  361. info = NULL;
  362. }
  363. UnlockSerializedList(&_List);
  364. DEBUG_LEAVE(0);
  365. }
  366. VOID
  367. SECURITY_CACHE_LIST::ClearClientAuthCertChains(
  368. VOID
  369. )
  370. /*++
  371. Routine Description:
  372. This function walks the cache and releases any client
  373. auth chains associated with each entry. This method
  374. is called in response to the "Clear SSL State" button
  375. being pressed in inetcpl. Starting with Whistler,
  376. client certificates are cached for the logon session,
  377. rather than the process.
  378. Arguments:
  379. None.
  380. Return Value:
  381. None.
  382. --*/
  383. {
  384. DEBUG_ENTER((DBG_HTTP,
  385. None,
  386. "SECURITY_CACHE_LIST::ClearClientAuthCertChains",
  387. NULL
  388. ));
  389. SECURITY_CACHE_LIST_ENTRY * pInfo = NULL;
  390. LockSerializedList(&_List);
  391. for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
  392. entry != (PLIST_ENTRY)SlSelf(&_List);
  393. entry = entry->Flink)
  394. {
  395. pInfo = CONTAINING_RECORD(entry, SECURITY_CACHE_LIST_ENTRY, _List);
  396. // This will delete and NULL the array
  397. pInfo->SetCertContextArray(NULL);
  398. // Ensure new session is negotiated for next SSL connection to server
  399. pInfo->SetForceNewSession(TRUE);
  400. }
  401. UnlockSerializedList(&_List);
  402. DEBUG_LEAVE(0);
  403. }