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.

473 lines
14 KiB

  1. // AdptvCntr.cpp -- ADaPTiVe CoNTaineR class implementation
  2. // (c) Copyright Schlumberger Technology Corp., unpublished work, created
  3. // 1999. This computer program includes Confidential, Proprietary
  4. // Information and is a Trade Secret of Schlumberger Technology Corp. All
  5. // use, disclosure, and/or reproduction is prohibited unless authorized
  6. // in writing. All Rights Reserved.
  7. #include "stdafx.h"
  8. #include "NoWarning.h"
  9. #include "ForceLib.h"
  10. #include <vector>
  11. #include <algorithm>
  12. #include <functional>
  13. #include <scuOsExc.h>
  14. #include <cciPriKey.h>
  15. #include "RsaKey.h"
  16. #include "CSpec.h"
  17. #include "HAdptvCntr.h"
  18. #include "Secured.h"
  19. #include "ACntrFinder.h"
  20. #include <scarderr.h>
  21. #include <assert.h>
  22. using namespace std;
  23. using namespace cci;
  24. /////////////////////////// LOCAL/HELPER /////////////////////////////////
  25. namespace
  26. {
  27. // Predicate helper functor (function object) returning true iff
  28. // the container object's name matches the pattern.
  29. class ContainerMatcher
  30. : public unary_function<string, bool>
  31. {
  32. public:
  33. explicit
  34. ContainerMatcher(string const &rsPattern)
  35. : m_sPattern(rsPattern)
  36. {}
  37. bool
  38. operator()(CContainer &rcntr) const
  39. {
  40. return CSpec::Equiv(m_sPattern, rcntr->Name());
  41. }
  42. private:
  43. string const m_sPattern;
  44. };
  45. CContainer
  46. FindOnCard(HCardContext &rhcardctx,
  47. string const &rsContainer)
  48. {
  49. Secured<HCardContext> shcardctx(rhcardctx);
  50. vector<CContainer> vcContainers(shcardctx->Card()->EnumContainers());
  51. vector<CContainer>::const_iterator
  52. ci(find_if(vcContainers.begin(),
  53. vcContainers.end(),
  54. ContainerMatcher(rsContainer)));
  55. CContainer hcntr;
  56. if (vcContainers.end() != ci)
  57. hcntr = *ci;
  58. return hcntr;
  59. }
  60. } // namespace
  61. /////////////////////////// PUBLIC /////////////////////////////////
  62. // Types
  63. // C'tors/D'tors
  64. // Operators
  65. // Operations
  66. void
  67. AdaptiveContainer::ClearCache()
  68. {
  69. m_hcntr = 0;
  70. }
  71. // Access
  72. CContainer
  73. AdaptiveContainer::TheCContainer()
  74. {
  75. if (!m_hcntr)
  76. {
  77. RefreshContainer();
  78. if (!m_hcntr)
  79. {
  80. Discard(*m_hacKey);
  81. throw scu::OsException(NTE_BAD_KEYSET);
  82. }
  83. }
  84. return m_hcntr;
  85. }
  86. HCardContext
  87. AdaptiveContainer::CardContext(bool bReconnect)
  88. {
  89. if(bReconnect)
  90. {
  91. if(m_fValidContext)
  92. {
  93. try
  94. {
  95. //Verify that the card context is good
  96. Retained<HCardContext>(m_hacKey->CardContext());
  97. }
  98. catch(scu::OsException const &rExc)
  99. {
  100. ReconnectOnError(rExc, Retained<HCardContext>(0));
  101. }
  102. }
  103. else
  104. {
  105. scu::OsException Exc(SCARD_W_REMOVED_CARD);
  106. ReconnectOnError(Exc, Retained<HCardContext>(0));
  107. }
  108. }
  109. return m_hacKey->CardContext();
  110. }
  111. AdaptiveContainer::EnrolleeType
  112. AdaptiveContainer::Find(AdaptiveContainerKey const &rKey)
  113. {
  114. // Take a lazy approach to finding the container. If it wasn't
  115. // first found in the registry but exists on the card, then make
  116. // an instance.
  117. EnrolleeType enrollee = AdaptiveContainerRegistrar::Find(rKey);
  118. if (!enrollee)
  119. {
  120. // See if it exists on the card
  121. CContainer hcntr(FindOnCard(rKey.CardContext(),
  122. rKey.ContainerName()));
  123. if (hcntr)
  124. enrollee = Instance(rKey);
  125. }
  126. return enrollee;
  127. }
  128. string
  129. AdaptiveContainer::Name() const
  130. {
  131. return m_hacKey->ContainerName();
  132. }
  133. void
  134. AdaptiveContainer::NullifyCard()
  135. {
  136. Guarded<Lockable *> guard(&AdaptiveContainerRegistrar::Registry()); // serialize registry access
  137. AdaptiveContainerKey aKey(*m_hacKey);
  138. m_hacKey->ClearCardContext();
  139. Enroll(*m_hacKey, this);
  140. Discard(aKey);
  141. Expire();
  142. }
  143. // Predicates
  144. // Static Variables
  145. /////////////////////////// PROTECTED /////////////////////////////////
  146. // C'tors/D'tors
  147. AdaptiveContainer::AdaptiveContainer(AdaptiveContainerKey const &rKey)
  148. : Lockable(),
  149. Securable(),
  150. AdaptiveContainerRegistrar(rKey),
  151. m_hacKey(HAdaptiveContainerKey(new AdaptiveContainerKey(rKey))),
  152. m_stkRetainedCardContexts(),
  153. m_stkSecuredCardContexts(),
  154. m_fValidContext(false)
  155. {
  156. Secured<HCardContext> shcardctx(m_hacKey->CardContext());
  157. RefreshContainer();
  158. // Create the container if it doesn't exist on the card.
  159. if (!m_hcntr)
  160. {
  161. // To make native Windows (pure CAPI) environment more robust,
  162. // test that there is enough room for a private key before
  163. // creating the container.
  164. CCard hcard(shcardctx->Card());
  165. if (!hcard->IsPKCS11Enabled())
  166. {
  167. CPrivateKey hprikey(hcard);
  168. CPrivateKeyBlob prikb;
  169. // Divide by 2 since the key info is divided in the structures.
  170. prikb.bPLen = prikb.bQLen = prikb.bInvQLen =
  171. prikb.bKsecModQLen = prikb.bKsecModPLen =
  172. InOctets(KeyLimits<RsaKey>::cMaxStrength) / 2;
  173. // Now test there is a key slot available by trying to
  174. // allocate a key slot on the card. If there isn't enough
  175. // space or some other failure occurs, then try to delete
  176. // the new key (ignoring any exception that occurs during
  177. // the delete), then throw the original exception.
  178. try
  179. {
  180. hprikey->Value(prikb); // actually alloc's
  181. // key slot
  182. }
  183. catch (...)
  184. {
  185. try
  186. {
  187. hprikey->Delete(); // cleanup after
  188. // test
  189. }
  190. catch (...)
  191. {
  192. }
  193. throw; // throw original error
  194. }
  195. // There's key space available, so delete the test key.
  196. hprikey->Delete();
  197. hprikey = 0;
  198. }
  199. m_hcntr = CContainer(hcard);
  200. m_hcntr->Name(rKey.ContainerName());
  201. }
  202. }
  203. AdaptiveContainer::~AdaptiveContainer()
  204. {}
  205. // Operators
  206. // Operations
  207. void
  208. AdaptiveContainer::ClearCardContext()
  209. {
  210. m_hacKey->ClearCardContext();
  211. }
  212. void
  213. AdaptiveContainer::DiscardHook()
  214. {
  215. Expire();
  216. RemoveReference();
  217. }
  218. AdaptiveContainer::EnrolleeType
  219. AdaptiveContainer::DoInstantiation(AdaptiveContainerKey const &rKey)
  220. {
  221. return new AdaptiveContainer(rKey);
  222. }
  223. void
  224. AdaptiveContainer::EnrollHook()
  225. {
  226. AddReference();
  227. m_fValidContext = true;
  228. }
  229. // Access
  230. // Predicates
  231. bool
  232. AdaptiveContainer::KeepEnrolled()
  233. {
  234. bool fKeep = true;
  235. try
  236. {
  237. RefreshContainer();
  238. }
  239. catch (...)
  240. {
  241. fKeep = false;
  242. }
  243. return fKeep;
  244. }
  245. void
  246. AdaptiveContainer::ReconnectOnError(scu::OsException const &rExc,
  247. Retained<HCardContext> &rhcardctx)
  248. {
  249. rhcardctx = Retained<HCardContext>(0);
  250. if ((rExc.Cause() == SCARD_W_REMOVED_CARD
  251. || rExc.Cause() == ERROR_BROKEN_PIPE
  252. || rExc.Cause() == SCARD_E_SERVICE_STOPPED
  253. || rExc.Cause() == SCARD_E_NO_SERVICE
  254. || rExc.Cause() == SCARD_E_READER_UNAVAILABLE) && m_hacKey)
  255. {
  256. //Handle the case of card removed by trying to
  257. //determine if the card has been re-inserted in
  258. //any of the available readers. If so, reconnect
  259. //silently
  260. // Declared here to remain in scope for CntrFinder
  261. // destructor in case of an exception...some anomaly that's as
  262. // yet unexplained.
  263. CString sEmptyWinTitle;
  264. try
  265. {
  266. //Find, adapt, and enroll it properly
  267. //First, discard the old card context before acquiring
  268. //a new one. This is essential in order to avoid
  269. //resource mgr hangup.
  270. Guarded<Lockable *> guard(&AdaptiveContainerRegistrar::Registry()); // serialize registry access
  271. std::string sContainerName(m_hacKey->ContainerName());
  272. RemoveEnrollee(*m_hacKey);
  273. Expire();
  274. ContainerFinder CntrFinder(CardFinder::DialogDisplayMode::ddmNever,
  275. 0,//window handle
  276. sEmptyWinTitle);
  277. //Don't know the reader where the card may be in.
  278. //Use a non fully qualified name to look for the card.
  279. CSpec cspec(string(), sContainerName);
  280. HContainer hcntr = CntrFinder.Find(cspec);
  281. m_hcntr = hcntr->TheCContainer();
  282. m_hacKey = CntrFinder.MakeAdaptiveContainerKey();
  283. m_fValidContext = true;
  284. InsertEnrollee(*m_hacKey, this);
  285. rhcardctx =
  286. Retained<HCardContext>(m_hacKey->CardContext());
  287. }
  288. catch(...)
  289. {
  290. //Didn't work. Apparently the card is gone
  291. //permanently for the duration of this session.
  292. //Cleanup and raise the original exception...
  293. Expire();
  294. rExc.Raise();
  295. }
  296. }
  297. else
  298. {
  299. //Cannot handle this exception. Let the system handle it
  300. rExc.Raise();
  301. }
  302. }
  303. // Static Variables
  304. /////////////////////////// PRIVATE /////////////////////////////////
  305. // C'tors/D'tors
  306. // Operators
  307. // Operations
  308. void
  309. AdaptiveContainer::Abandon()
  310. {
  311. // Simplifying assumptions: (1) Abandon is only called by the
  312. // Secured destructor, (2) once the object is constructed, Secure
  313. // and Abandon are the only routines that access
  314. // m_stkSecuredCardContexts, and (3) Abandon is called by a thread
  315. // within the scope of a Retain (e.g. using Retained) which the
  316. // Secured class enforces. Because of (1) and (2), an underflow
  317. // check on m_stkSecuredCardContexts is not necessary since Secure
  318. // will have already been called. Because of (3), protection
  319. // against race conditions accessing m_stkSecuredCardContexts
  320. // isn't necessary since Retain acts as a lock.
  321. m_stkSecuredCardContexts.pop_front();
  322. }
  323. void
  324. AdaptiveContainer::Expire()
  325. {
  326. // allow the resources to be released so that other resources can
  327. // be acquired that may have a dependency (e.g. releasing the
  328. // container's card context so that another card context can be
  329. // acquired later on the same reader without the RM blocking).
  330. m_fValidContext = false;
  331. m_hacKey->ClearCardContext();
  332. ClearCache();
  333. }
  334. void
  335. AdaptiveContainer::RefreshContainer()
  336. {
  337. if(m_hacKey->CardContext())
  338. {
  339. try
  340. {
  341. m_hcntr = FindOnCard(m_hacKey->CardContext(),
  342. m_hacKey->ContainerName());
  343. }
  344. catch(scu::OsException const &rExc)
  345. {
  346. ReconnectOnError(rExc, Retained<HCardContext>(0));
  347. }
  348. }
  349. else
  350. {
  351. scu::OsException Exc(SCARD_W_REMOVED_CARD);
  352. ReconnectOnError(Exc, Retained<HCardContext>(0));
  353. }
  354. }
  355. void
  356. AdaptiveContainer::Relinquish()
  357. {
  358. // Simplifying assumptions: (1) Relinquish is only called by the
  359. // Retained destructor and (2) once the object is constructed,
  360. // Retain and Relinquish are the only routines that access the
  361. // m_stkRetainedCardContexts. Because of (1) and (2), an
  362. // underflow check on m_stkRetainedCardContexts is not necessary
  363. // since Retain will have already been called.
  364. // Note: Retained<HCardContext> acts as a lock protecting against
  365. // race conditions updating m_stkRetainedCardContexts.
  366. Retained<HCardContext> hrcc(m_stkRetainedCardContexts.front());
  367. m_stkRetainedCardContexts.pop_front();
  368. }
  369. void
  370. AdaptiveContainer::Retain()
  371. {
  372. // Simplifying assumptions: (1) Retain is only called by the
  373. // Retained constructor and (2) once the object is constructed,
  374. // Retain and Relinquish are the only routines that access the
  375. // m_stkRetainedCardContexts. Because of (1) and (2), an
  376. // underflow check on m_stkRetainedCardContexts is not necessary
  377. // since Retain will have already been called.
  378. Retained<HCardContext> rhcardctx;
  379. try
  380. {
  381. rhcardctx = Retained<HCardContext>(m_hacKey->CardContext());
  382. }
  383. catch(scu::OsException const &rExc)
  384. {
  385. ReconnectOnError(rExc, rhcardctx);
  386. }
  387. m_stkRetainedCardContexts.push_front(rhcardctx);
  388. }
  389. void
  390. AdaptiveContainer::Secure()
  391. {
  392. // Simplifying assumptions: (1) Secure is always called by a
  393. // thread within the scope of a Retain (e.g. using Retained). The
  394. // Secured template enforces this allowing Retain to act as a lock
  395. // to prevent race conditions updating
  396. // m_stkSecuredCardContexts. (2) Once the object is constructed,
  397. // Secure and Abandon are the only routines that access
  398. // m_stkSecuredCardContexts.
  399. m_stkSecuredCardContexts.push_front(Secured<HCardContext>(m_hacKey->CardContext()));
  400. }
  401. // Access
  402. // Predicates
  403. // Static Variables