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.

1838 lines
53 KiB

  1. // Cspi.cpp -- Schlumberger Cryptographic Service Provider Interface definition
  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. // Don't allow the min & max macros in WINDEF.H to be defined so the
  8. // min/max methods declared in limits are accessible.
  9. #define NOMINMAX
  10. #if defined(_UNICODE)
  11. #if !defined(UNICODE)
  12. #define UNICODE
  13. #endif //!UNICODE
  14. #endif //_UNICODE
  15. #if defined(UNICODE)
  16. #if !defined(_UNICODE)
  17. #define _UNICODE
  18. #endif //!_UNICODE
  19. #endif //UNICODE
  20. #include "stdafx.h"
  21. #include <memory> // for auto_ptr
  22. #include <limits>
  23. #include <string>
  24. #include <vector>
  25. #include <functional>
  26. #include <algorithm>
  27. #include <numeric>
  28. #include <stddef.h>
  29. #include <rpc.h>
  30. #include <SCardLib.h>
  31. #include <scuOsExc.h>
  32. #include <pkiExc.h>
  33. #include "Guard.h"
  34. #include "slbCsp.h"
  35. #include "CspProfile.h"
  36. #include "CryptCtx.h"
  37. #include "SesKeyCtx.h"
  38. #include "PubKeyCtx.h"
  39. #include "HashCtx.h"
  40. #include "CSpec.h"
  41. #include "Blob.h"
  42. #include "Cspi.h"
  43. #include "StResource.h"
  44. #include "scarderr.h" // must be last for now
  45. using namespace std;
  46. using namespace scu;
  47. #define HANDLEID_CRYPT_CONTEXT 17
  48. static CHandleList hlCryptContexts(HANDLEID_CRYPT_CONTEXT);
  49. #if defined(_DEBUG)
  50. #define CSPI_DEFINE_ROUTINE_NAME(sRoutine) \
  51. LPCTSTR cspi_sRoutine = sRoutine
  52. #define CSPI_TRACE_ROUTINE(sFlag) \
  53. TRACE(TEXT("%s %s, Thread Id %08X\n"), cspi_sRoutine, \
  54. sFlag, GetCurrentThreadId());
  55. #else
  56. #define CSPI_DEFINE_ROUTINE_NAME(sRoutine)
  57. #define CSPI_TRACE_ROUTINE(sFlag)
  58. #endif // defined(_DEBUG)
  59. typedef DWORD CapiError;
  60. #define CSPI_TRY(Routine) \
  61. { \
  62. bool cspi_fExceptionCaught = false; \
  63. CapiError cspi_ce = AsCapiError(ERROR_SUCCESS); \
  64. \
  65. { \
  66. AFX_MANAGE_STATE(AfxGetStaticModuleState()); \
  67. \
  68. CSPI_DEFINE_ROUTINE_NAME(TEXT(#Routine)); \
  69. CSPI_TRACE_ROUTINE(TEXT("Begin")); \
  70. \
  71. CWaitCursor cspi_wc; \
  72. \
  73. try
  74. #define CSPI_CATCH(fStatus) \
  75. catch (scu::Exception const &rExc) \
  76. { \
  77. cspi_fExceptionCaught = true; \
  78. cspi_ce = AsCapiError(rExc); \
  79. } \
  80. \
  81. catch (std::bad_alloc const &rExc) \
  82. { \
  83. cspi_fExceptionCaught = true; \
  84. cspi_ce = AsCapiError(rExc); \
  85. } \
  86. \
  87. catch (DWORD dwError) \
  88. { \
  89. cspi_fExceptionCaught = true; \
  90. cspi_ce = AsCapiError(dwError); \
  91. } \
  92. \
  93. catch (...) \
  94. { \
  95. cspi_fExceptionCaught = true; \
  96. cspi_ce = AsCapiError(NTE_FAIL); \
  97. } \
  98. \
  99. CSPI_TRACE_ROUTINE(TEXT("End")); \
  100. \
  101. (fStatus) = cspi_fExceptionCaught \
  102. ? CRYPT_FAILED \
  103. : CRYPT_SUCCEED; \
  104. } \
  105. \
  106. SetLastError(cspi_ce); \
  107. \
  108. }
  109. namespace
  110. { // Helper routines
  111. template<class CauseCode>
  112. struct ErrorCodeMap
  113. {
  114. typename CauseCode m_cc;
  115. DWORD m_dwErrorCode;
  116. };
  117. template<class CauseCode>
  118. DWORD
  119. FindErrorCode(ErrorCodeMap<typename CauseCode> const *pFirst,
  120. ErrorCodeMap<typename CauseCode> const *pLast,
  121. typename CauseCode cc)
  122. {
  123. bool fFound = false;
  124. DWORD dwErrorCode = NTE_FAIL;
  125. for (ErrorCodeMap<CauseCode> const *p = pFirst;
  126. !fFound && (p < pLast); p++)
  127. {
  128. if (p->m_cc == cc)
  129. {
  130. dwErrorCode = p->m_dwErrorCode;
  131. fFound = true;
  132. }
  133. }
  134. return dwErrorCode;
  135. }
  136. ErrorCodeMap<cci::CauseCode> CciErrorMap[] =
  137. {
  138. { cci::ccBadKeySpec, SCARD_E_INVALID_VALUE },
  139. { cci::ccBadPinLength, SCARD_E_INVALID_VALUE },
  140. { cci::ccNoCertificate, SCARD_E_NO_SUCH_CERTIFICATE },
  141. { cci::ccNotPersonalized, SCARD_E_UNSUPPORTED_FEATURE },
  142. { cci::ccOutOfPrivateKeySlots, NTE_TOKEN_KEYSET_STORAGE_FULL },
  143. { cci::ccOutOfSymbolTableSpace, NTE_TOKEN_KEYSET_STORAGE_FULL },
  144. { cci::ccOutOfSymbolTableEntries, NTE_TOKEN_KEYSET_STORAGE_FULL },
  145. };
  146. ErrorCodeMap<iop::CSmartCard::CauseCode> SmartCardErrorMap[] =
  147. {
  148. { iop::CSmartCard::ccAccessConditionsNotMet, SCARD_W_SECURITY_VIOLATION },
  149. { iop::CSmartCard::ccAlgorithmIdNotSupported, CRYPT_E_UNKNOWN_ALGO },
  150. { iop::CSmartCard::ccAuthenticationFailed, SCARD_W_WRONG_CHV },
  151. { iop::CSmartCard::ccChvVerificationFailedMoreAttempts,
  152. SCARD_W_WRONG_CHV },
  153. { iop::CSmartCard::ccDataPossiblyCorrupted, ERROR_FILE_CORRUPT },
  154. { iop::CSmartCard::ccFileExists, ERROR_FILE_EXISTS },
  155. { iop::CSmartCard::ccInsufficientSpace, NTE_TOKEN_KEYSET_STORAGE_FULL },
  156. { iop::CSmartCard::ccOutOfSpaceToCreateFile, NTE_TOKEN_KEYSET_STORAGE_FULL },
  157. { iop::CSmartCard::ccKeyBlocked, SCARD_W_CHV_BLOCKED },
  158. { iop::CSmartCard::ccNoAccess, SCARD_W_SECURITY_VIOLATION },
  159. { iop::CSmartCard::ccReturnedDataCorrupted, ERROR_FILE_CORRUPT },
  160. { iop::CSmartCard::ccTimeOut, E_UNEXPECTED },
  161. { iop::CSmartCard::ccUnidentifiedTechnicalProblem, E_UNEXPECTED },
  162. { iop::CSmartCard::ccVerificationFailed, SCARD_W_WRONG_CHV },
  163. };
  164. ErrorCodeMap<iop::CauseCode> IopErrorMap[] =
  165. {
  166. { iop::ccAlgorithmIdNotSupported, CRYPT_E_UNKNOWN_ALGO },
  167. { iop::ccInvalidParameter, E_INVALIDARG },
  168. { iop::ccNoResponseAvailable, E_UNEXPECTED },
  169. { iop::ccResourceManagerDisabled, SCARD_E_NO_SERVICE },
  170. { iop::ccUnknownCard, SCARD_E_UNKNOWN_CARD },
  171. { iop::ccUnsupportedCommand, SCARD_E_UNSUPPORTED_FEATURE },
  172. };
  173. bool
  174. IsHResult(DWORD dwError)
  175. {
  176. return HRESULT_SEVERITY(static_cast<HRESULT>(dwError))
  177. ? true
  178. : false;
  179. }
  180. CapiError
  181. AsCapiError(HRESULT hr)
  182. {
  183. // If the HRESULT has been converted from a Win32 error code
  184. // (WIN32 facility), then convert it back to a Win32 error
  185. // code. These types of HRESULTs confuse WinLogon, according
  186. // to Doug Barlow (Microsoft)
  187. return (FACILITY_WIN32 == HRESULT_FACILITY(hr))
  188. ? HRESULT_CODE(hr)
  189. : static_cast<DWORD>(hr);
  190. }
  191. CapiError
  192. AsCapiError(DWORD dwError)
  193. {
  194. if (IsHResult(dwError))
  195. dwError = AsCapiError(static_cast<HRESULT>(dwError));
  196. return dwError;
  197. }
  198. CapiError
  199. AsCapiError(cci::Exception const &rExc)
  200. {
  201. return AsCapiError(FindErrorCode(CciErrorMap,
  202. (CciErrorMap +
  203. (sizeof CciErrorMap /
  204. sizeof *CciErrorMap)),
  205. rExc.Cause()));
  206. }
  207. CapiError
  208. AsCapiError(iop::Exception const &rExc)
  209. {
  210. return AsCapiError(FindErrorCode(IopErrorMap,
  211. (IopErrorMap +
  212. (sizeof IopErrorMap /
  213. sizeof *IopErrorMap)),
  214. rExc.Cause()));
  215. }
  216. CapiError
  217. AsCapiError(scu::OsException const &rExc)
  218. {
  219. return AsCapiError(rExc.Cause());
  220. }
  221. CapiError
  222. AsCapiError(iop::CSmartCard::Exception const &rExc)
  223. {
  224. return AsCapiError(FindErrorCode(SmartCardErrorMap,
  225. (SmartCardErrorMap +
  226. (sizeof SmartCardErrorMap /
  227. sizeof *SmartCardErrorMap)),
  228. rExc.Cause()));
  229. }
  230. CapiError
  231. AsCapiError(pki::Exception const &rExc)
  232. {
  233. return AsCapiError(ERROR_INVALID_PARAMETER);
  234. }
  235. CapiError
  236. AsCapiError(scu::Exception const &rExc)
  237. {
  238. using namespace scu;
  239. CapiError ce;
  240. switch (rExc.Facility())
  241. {
  242. case Exception::fcCCI:
  243. ce = AsCapiError(static_cast<cci::Exception const &>(rExc));
  244. break;
  245. case Exception::fcIOP:
  246. ce = AsCapiError(static_cast<iop::Exception const &>(rExc));
  247. break;
  248. case Exception::fcOS:
  249. ce = AsCapiError(static_cast<scu::OsException const &>(rExc));
  250. break;
  251. case Exception::fcPKI:
  252. ce = AsCapiError(static_cast<pki::Exception const &>(rExc));
  253. break;
  254. case Exception::fcSmartCard:
  255. ce = AsCapiError(static_cast<iop::CSmartCard::Exception const &>(rExc));
  256. break;
  257. default:
  258. ce = AsCapiError(E_UNEXPECTED);
  259. break;
  260. }
  261. return ce;
  262. }
  263. CapiError
  264. AsCapiError(std::bad_alloc const &rExc)
  265. {
  266. return AsCapiError(NTE_NO_MEMORY);
  267. }
  268. void
  269. Assign(void *pvDestination,
  270. DWORD *pcbDestinationLength,
  271. void const *pvSource,
  272. size_t cSourceLength)
  273. {
  274. DWORD dwError = ERROR_SUCCESS;
  275. if (pcbDestinationLength)
  276. {
  277. if (numeric_limits<DWORD>::max() >= cSourceLength)
  278. {
  279. if (pvSource)
  280. {
  281. if (pvDestination)
  282. {
  283. if (*pcbDestinationLength >= cSourceLength)
  284. CopyMemory(pvDestination, pvSource, cSourceLength);
  285. else
  286. dwError = ERROR_MORE_DATA;
  287. }
  288. }
  289. *pcbDestinationLength = cSourceLength;
  290. }
  291. else
  292. dwError = ERROR_INVALID_PARAMETER;
  293. }
  294. else
  295. dwError = ERROR_INVALID_PARAMETER;
  296. if (ERROR_SUCCESS != dwError)
  297. throw scu::OsException(dwError);
  298. }
  299. void
  300. Assign(void *pvDestination,
  301. DWORD *pcbDestinationLength,
  302. LPCTSTR pvSource
  303. )
  304. {
  305. DWORD dwError = ERROR_SUCCESS;
  306. if (pcbDestinationLength)
  307. {
  308. // We want the number of characters including NULL
  309. DWORD cSourceLength = _tcslen(pvSource) + 1;
  310. if (numeric_limits<DWORD>::max() >= cSourceLength)
  311. {
  312. if (pvSource)
  313. {
  314. if (pvDestination)
  315. {
  316. if (*pcbDestinationLength >= cSourceLength)
  317. {
  318. char *sTarget = (char *)pvDestination;
  319. for(int i =0; i<cSourceLength; i++)
  320. sTarget[i] = static_cast<char>(*(pvSource+i));
  321. }
  322. else
  323. dwError = ERROR_MORE_DATA;
  324. }
  325. }
  326. *pcbDestinationLength = cSourceLength;
  327. }
  328. else
  329. dwError = ERROR_INVALID_PARAMETER;
  330. }
  331. else
  332. dwError = ERROR_INVALID_PARAMETER;
  333. if (ERROR_SUCCESS != dwError)
  334. throw scu::OsException(dwError);
  335. }
  336. void
  337. Assign(void *pvDestination,
  338. DWORD *pcbDestinationLength,
  339. Blob const &rblob)
  340. {
  341. Assign(pvDestination, pcbDestinationLength,
  342. rblob.data(), rblob.length());
  343. }
  344. void
  345. Assign(void *pvDestination,
  346. DWORD cbDestinationLength,
  347. Blob const &rblob)
  348. {
  349. if (cbDestinationLength < rblob.length())
  350. throw scu::OsException(ERROR_INTERNAL_ERROR);
  351. Assign(pvDestination, &cbDestinationLength,
  352. rblob.data(), rblob.length());
  353. }
  354. // Helper to BufferLengthRequired to compare length of strings.
  355. struct LengthIsLess
  356. : public binary_function<string const &, string const &, bool>
  357. {
  358. public:
  359. explicit
  360. LengthIsLess()
  361. {};
  362. result_type
  363. operator()(first_argument_type lhs,
  364. second_argument_type rhs) const
  365. {
  366. return lhs.length() < rhs.length();
  367. }
  368. };
  369. // Return the data buffer length required to hold the largest
  370. // string in the vector.
  371. DWORD
  372. BufferLengthRequired(vector<string> const &rvs)
  373. {
  374. DWORD dwRequiredLength = 0;
  375. vector<string>::const_iterator
  376. itLongestString(max_element(rvs.begin(), rvs.end(),
  377. LengthIsLess()));
  378. if (rvs.end() != itLongestString)
  379. dwRequiredLength = itLongestString->length() + 1;
  380. return dwRequiredLength;
  381. }
  382. // Helper to enumerate the container names for the given context,
  383. // returning the result in user parameters pbData and pdwDataLen.
  384. void
  385. EnumContainers(Guarded<CryptContext *> &rgpCtx,
  386. BYTE *pbData,
  387. DWORD *pdwDataLen,
  388. bool fFirst)
  389. {
  390. DWORD dwError = ERROR_SUCCESS;
  391. string sName;
  392. DWORD dwReturnLength = 0;
  393. void const *pvReturnData = 0;
  394. if (!pbData)
  395. {
  396. // can't specify 0 for pbData without CRYPT_FIRST
  397. if (!fFirst)
  398. dwError = ERROR_INVALID_PARAMETER;
  399. else
  400. {
  401. // Return the buffer size required for the longest string
  402. ContainerEnumerator const ce(rgpCtx->CntrEnumerator(true));
  403. dwReturnLength = BufferLengthRequired(ce.Names());
  404. if (0 == dwReturnLength)
  405. dwError = ERROR_NO_MORE_ITEMS;
  406. }
  407. }
  408. else
  409. {
  410. ContainerEnumerator ce(rgpCtx->CntrEnumerator(fFirst));
  411. vector<string>::const_iterator &rit = ce.Iterator();
  412. if (ce.Names().end() != rit)
  413. {
  414. sName = *rit++;
  415. dwReturnLength = sName.length() + 1;
  416. pvReturnData = sName.c_str();
  417. if (dwReturnLength > *pdwDataLen)
  418. {
  419. // tell'em the size required for the longest name
  420. pbData = 0;
  421. dwReturnLength =
  422. BufferLengthRequired(ce.Names());
  423. dwError = ERROR_MORE_DATA;
  424. }
  425. else
  426. rgpCtx->CntrEnumerator(ce);
  427. }
  428. else
  429. dwError = ERROR_NO_MORE_ITEMS;
  430. }
  431. if ((ERROR_SUCCESS != dwError) &&
  432. (ERROR_MORE_DATA != dwError))
  433. throw scu::OsException(dwError);
  434. Assign(pbData, pdwDataLen, pvReturnData, dwReturnLength);
  435. }
  436. bool
  437. FlagsAreSet(DWORD dwFlags,
  438. DWORD dwFlagsToTestFor)
  439. {
  440. return (dwFlags & dwFlagsToTestFor)
  441. ? true
  442. : false;
  443. }
  444. void
  445. Pin(Guarded<CryptContext *> const &rgpCtx,
  446. char const *pszPin)
  447. {
  448. // TO DO: Should forward PIN setting to aux context
  449. // when this context is ephemeral.
  450. if (rgpCtx->IsEphemeral())
  451. throw scu::OsException(ERROR_INVALID_PARAMETER);
  452. // TO DO: UNICODE ?
  453. rgpCtx->Pin(User, pszPin);
  454. }
  455. // Throw if more than dwValidFlags are set in dwFlags
  456. void
  457. ValidateFlags(DWORD dwFlags,
  458. DWORD dwValidFlags)
  459. {
  460. if (dwFlags & ~dwValidFlags)
  461. throw scu::OsException(NTE_BAD_FLAGS);
  462. }
  463. class StaleContainerKeyAccumulator
  464. : public binary_function<vector<AdaptiveContainerRegistrar::EnrolleeType>,
  465. AdaptiveContainerRegistrar::RegistryType::CollectionType::value_type,
  466. vector<AdaptiveContainerRegistrar::EnrolleeType> >
  467. {
  468. public:
  469. explicit
  470. StaleContainerKeyAccumulator()
  471. {}
  472. result_type
  473. operator()(first_argument_type &rvStaleCntrs,
  474. second_argument_type const &rvt) const
  475. {
  476. if (!rvt.second->CardContext(false))
  477. rvStaleCntrs.push_back(rvt.second);
  478. return rvStaleCntrs;
  479. }
  480. private:
  481. };
  482. bool FindCryptCtxForACntr(HAdaptiveContainer &rhAdptCntr)
  483. {
  484. bool fRetValue = false;
  485. for(int i = 0; i< hlCryptContexts.Count();i++)
  486. {
  487. CryptContext *pCryptCtx = static_cast<CryptContext *>
  488. (hlCryptContexts.GetQuietly(hlCryptContexts.IndexHandle(i)));
  489. if( pCryptCtx && pCryptCtx->AdaptiveContainer() == rhAdptCntr)
  490. {
  491. fRetValue = true;
  492. }
  493. }
  494. return fRetValue;
  495. }
  496. void CollectRegistryGarbage()
  497. {
  498. Guarded<Lockable *> guard(&AdaptiveContainerRegistrar::Registry()); // serialize registry access
  499. AdaptiveContainerRegistrar::ConstRegistryType &rRegistry =
  500. AdaptiveContainerRegistrar::Registry();
  501. AdaptiveContainerRegistrar::ConstRegistryType::CollectionType
  502. &rcollection = rRegistry();
  503. vector<AdaptiveContainerRegistrar::EnrolleeType>
  504. vStaleCntrs(accumulate(rcollection.begin(), rcollection.end(),
  505. vector<AdaptiveContainerRegistrar::EnrolleeType>(),
  506. StaleContainerKeyAccumulator()));
  507. for (vector<AdaptiveContainerRegistrar::EnrolleeType>::iterator iCurrent(vStaleCntrs.begin());
  508. iCurrent != vStaleCntrs.end(); ++iCurrent)
  509. {
  510. //Lookup the CryptContext list to see if any of these
  511. //stale container are referenced. If not, remove them
  512. //to avoid memory leaks.
  513. if(!FindCryptCtxForACntr(HAdaptiveContainer(*iCurrent)))
  514. {
  515. //Remove the adaptive container from the registry
  516. AdaptiveContainerKey aKey(HCardContext(0),
  517. (*iCurrent)->Name());
  518. AdaptiveContainerRegistrar::Discard(aKey);
  519. }
  520. }
  521. }
  522. } // namespace
  523. ////////////////////////// BEGIN CSP INTERFACE /////////////////////////////
  524. //
  525. // See MSDN for documentation on these interfaces.
  526. //
  527. SLBCSPAPI
  528. CPAcquireContext(OUT HCRYPTPROV *phProv,
  529. IN LPCTSTR pszContainer,
  530. IN DWORD dwFlags,
  531. IN PVTableProvStruc pVTable)
  532. {
  533. BOOL fSts = CRYPT_FAILED;
  534. CSPI_TRY(CPAcquireContext)
  535. {
  536. Guard<Lockable> grdMaster(TheMasterLock());
  537. CSpec cspec(pszContainer
  538. ? AsCCharP(pszContainer)
  539. : "");
  540. ValidateFlags(dwFlags, (CRYPT_VERIFYCONTEXT |
  541. CRYPT_NEWKEYSET |
  542. CRYPT_MACHINE_KEYSET |
  543. CRYPT_DELETEKEYSET |
  544. CRYPT_SILENT));
  545. if (!phProv)
  546. throw scu::OsException(ERROR_INVALID_PARAMETER);
  547. bool const fMakeEphemeral = FlagsAreSet(dwFlags,
  548. CRYPT_VERIFYCONTEXT);
  549. bool const fGuiEnabled = !(FlagsAreSet(dwFlags, CRYPT_SILENT) ||
  550. (cspec.CardId().empty() &&
  551. fMakeEphemeral));
  552. bool const fCreateContainer = FlagsAreSet(dwFlags, CRYPT_NEWKEYSET);
  553. auto_ptr<CryptContext> apCtx(new CryptContext(cspec, pVTable,
  554. fGuiEnabled,
  555. fCreateContainer,
  556. fMakeEphemeral));
  557. if (FlagsAreSet(dwFlags, CRYPT_DELETEKEYSET))
  558. apCtx->RemoveContainer();
  559. else
  560. {
  561. *phProv =
  562. static_cast<HCRYPTPROV>(hlCryptContexts.Add(apCtx.get()));
  563. apCtx.release();
  564. }
  565. }
  566. CSPI_CATCH(fSts);
  567. return fSts;
  568. }
  569. SLBCSPAPI
  570. CPGetProvParam(IN HCRYPTPROV hProv,
  571. IN DWORD dwParam,
  572. IN BYTE *pbData,
  573. IN OUT DWORD *pdwDataLen,
  574. IN DWORD dwFlags)
  575. {
  576. using namespace ProviderProfile;
  577. BOOL fSts = CRYPT_FAILED;
  578. CSPI_TRY(CPGetProvParam)
  579. {
  580. Guard<Lockable> grdMaster(TheMasterLock());
  581. Guarded<CryptContext *>
  582. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  583. switch (dwParam)
  584. {
  585. case PP_CONTAINER:
  586. case PP_UNIQUE_CONTAINER:
  587. {
  588. ValidateFlags(dwFlags, 0);
  589. HAdaptiveContainer hacntr = gpCtx->AdaptiveContainer();
  590. if (!hacntr)
  591. throw scu::OsException(ERROR_INVALID_PARAMETER);
  592. string sName(hacntr->TheCContainer()->Name());
  593. Assign(pbData, pdwDataLen, sName.c_str(),
  594. sName.length() + 1);
  595. }
  596. break;
  597. case PP_ENUMALGS:
  598. case PP_ENUMALGS_EX:
  599. {
  600. ValidateFlags(dwFlags, CRYPT_FIRST);
  601. AlignedBlob abAlgInfo;
  602. gpCtx->EnumAlgorithms(dwParam, dwFlags, (0 != pbData),
  603. abAlgInfo);
  604. Assign(pbData, pdwDataLen, abAlgInfo.Data(),
  605. abAlgInfo.Length());
  606. }
  607. break;
  608. case PP_ENUMCONTAINERS:
  609. ValidateFlags(dwFlags, CRYPT_FIRST | CRYPT_MACHINE_KEYSET);
  610. EnumContainers(gpCtx, pbData, pdwDataLen,
  611. (CRYPT_FIRST & dwFlags));
  612. break;
  613. case PP_IMPTYPE:
  614. {
  615. ValidateFlags(dwFlags, 0);
  616. DWORD const dwImplType = CRYPT_IMPL_MIXED | CRYPT_IMPL_REMOVABLE;
  617. Assign(pbData, pdwDataLen, &dwImplType,
  618. sizeof dwImplType);
  619. }
  620. break;
  621. case PP_NAME:
  622. {
  623. ValidateFlags(dwFlags, 0);
  624. CString sName(CspProfile::Instance().Name());
  625. Assign(pbData, pdwDataLen, (LPCTSTR)sName);
  626. }
  627. break;
  628. case PP_VERSION:
  629. {
  630. ValidateFlags(dwFlags, 0);
  631. VersionInfo const &ver = CspProfile::Instance().Version();
  632. DWORD dwVersion = (ver.m_dwMajor << 8) | ver.m_dwMinor;
  633. Assign(pbData, pdwDataLen, &dwVersion, sizeof dwVersion);
  634. }
  635. break;
  636. case PP_PROVTYPE:
  637. {
  638. ValidateFlags(dwFlags, 0);
  639. DWORD const dwType = CspProfile::Instance().Type();
  640. Assign(pbData, pdwDataLen, &dwType, sizeof dwType);
  641. }
  642. break;
  643. case PP_KEYX_KEYSIZE_INC: // fall-through
  644. case PP_SIG_KEYSIZE_INC:
  645. {
  646. ValidateFlags(dwFlags, 0);
  647. DWORD const dwIncrement = 0;
  648. Assign(pbData, pdwDataLen, &dwIncrement, sizeof dwIncrement);
  649. }
  650. break;
  651. case PP_ENUMEX_SIGNING_PROT:
  652. ValidateFlags(dwFlags, 0);
  653. if (CryptGetProvParam(gpCtx->AuxContext(), dwParam,
  654. pbData, pdwDataLen, dwFlags))
  655. throw scu::OsException(GetLastError());
  656. break;
  657. case PP_KEYSPEC:
  658. {
  659. ValidateFlags(dwFlags, 0);
  660. DWORD const dwKeySpec = AT_SIGNATURE | AT_KEYEXCHANGE;
  661. Assign(pbData, pdwDataLen, &dwKeySpec, sizeof
  662. dwKeySpec);
  663. }
  664. break;
  665. default:
  666. throw scu::OsException(NTE_BAD_TYPE);
  667. break;
  668. }
  669. }
  670. CSPI_CATCH(fSts);
  671. return fSts;
  672. }
  673. SLBCSPAPI
  674. CPReleaseContext(IN HCRYPTPROV hProv,
  675. IN DWORD dwFlags)
  676. {
  677. BOOL fSts = CRYPT_FAILED;
  678. CSPI_TRY(CPReleaseContext)
  679. {
  680. ValidateFlags(dwFlags, 0);
  681. Guard<Lockable> grdMaster(TheMasterLock());
  682. auto_ptr<CryptContext> apCtx(static_cast<CryptContext *>(hlCryptContexts.Close(hProv)));
  683. // TO DO: Verify current thread is this context's owning
  684. // thread *and* not currently in use; if not, return
  685. // ERROR_BUSY.
  686. //Garbage collection of unusable adaptive containers
  687. //that this or other threads may have left behind. An unusable
  688. //container is one which is not referenced by any of the
  689. //existing active crypt contexts.
  690. try
  691. {
  692. CollectRegistryGarbage();
  693. }
  694. catch(...)
  695. {
  696. //Don't let exceptions during garbage collection
  697. //propagate outside. These are likely due to other
  698. //problems which are better exposed with proper error
  699. //codes from other parts of the CSP.
  700. }
  701. }
  702. CSPI_CATCH(fSts);
  703. if ((CRYPT_SUCCEED == fSts) && (0 != dwFlags))
  704. fSts = false;
  705. return fSts;
  706. }
  707. SLBCSPAPI
  708. CPSetProvParam(IN HCRYPTPROV hProv,
  709. IN DWORD dwParam,
  710. IN BYTE *pbData,
  711. IN DWORD dwFlags)
  712. {
  713. BOOL fSts = CRYPT_FAILED;
  714. CSPI_TRY(CPSetProvParam)
  715. {
  716. Guard<Lockable> grdMaster(TheMasterLock());
  717. Guarded<CryptContext *>
  718. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  719. switch (dwParam)
  720. {
  721. case PP_KEYEXCHANGE_PIN: // fall-through
  722. case PP_SIGNATURE_PIN:
  723. Pin(gpCtx, reinterpret_cast<char *>(pbData));
  724. break;
  725. case PP_KEYSET_SEC_DESCR:
  726. // Ignore this option and return success.
  727. break;
  728. case PP_USE_HARDWARE_RNG:
  729. if (!CryptSetProvParam(gpCtx->AuxContext(), dwParam,
  730. pbData, dwFlags))
  731. throw scu::OsException(GetLastError());
  732. break;
  733. default:
  734. throw scu::OsException(ERROR_NOT_SUPPORTED);
  735. break;
  736. }
  737. }
  738. CSPI_CATCH(fSts);
  739. return fSts;
  740. }
  741. SLBCSPAPI
  742. CPDeriveKey(IN HCRYPTPROV hProv,
  743. IN ALG_ID Algid,
  744. IN HCRYPTHASH hHash,
  745. IN DWORD dwFlags,
  746. OUT HCRYPTKEY *phKey)
  747. {
  748. BOOL fSts = CRYPT_FAILED;
  749. CSPI_TRY(CPDeriveKey)
  750. {
  751. Guarded<CryptContext *>
  752. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  753. CHashContext *pHash = gpCtx->LookupHash(hHash);
  754. auto_ptr<CSessionKeyContext>
  755. apSessionKey(new CSessionKeyContext(gpCtx->AuxContext()));
  756. apSessionKey->Derive(Algid, pHash->HashHandleInAuxCSP(),
  757. dwFlags);
  758. *phKey = gpCtx->Add(apSessionKey);
  759. }
  760. CSPI_CATCH(fSts);
  761. return fSts;
  762. }
  763. SLBCSPAPI
  764. CPDestroyKey(IN HCRYPTPROV hProv,
  765. IN HCRYPTKEY hKey)
  766. {
  767. BOOL fSts = CRYPT_FAILED;
  768. // TO DO: Throw ERROR_BUSY if destroying thread is not the owning
  769. // thread OR some other thread has a handle to this key.
  770. CSPI_TRY(CPDestroyKey)
  771. {
  772. Guard<Lockable> grdMaster(TheMasterLock());
  773. Guarded<CryptContext *>
  774. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  775. // TO DO: Deleting the first handle usually fails for some reason.
  776. // For now, protect against the exception and carry on.
  777. try
  778. {
  779. auto_ptr<CKeyContext> apKey(gpCtx->CloseKey(hKey));
  780. }
  781. catch (...)
  782. {}
  783. }
  784. CSPI_CATCH(fSts);
  785. return fSts;
  786. }
  787. SLBCSPAPI
  788. CPDuplicateHash(IN HCRYPTPROV hProv,
  789. IN HCRYPTHASH hHash,
  790. IN DWORD *pdwReserved,
  791. IN DWORD dwFlags,
  792. OUT HCRYPTHASH *phDupHash)
  793. {
  794. BOOL fSts = CRYPT_FAILED;
  795. CSPI_TRY(CPDuplicateHash)
  796. {
  797. ValidateFlags(dwFlags, 0);
  798. Guard<Lockable> grdMaster(TheMasterLock());
  799. Guarded<CryptContext *>
  800. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  801. CHashContext *pHash = gpCtx->LookupHash(hHash);
  802. auto_ptr<CHashContext> apDupHash(pHash->Clone(pdwReserved, dwFlags));
  803. *phDupHash = gpCtx->Add(apDupHash);
  804. }
  805. CSPI_CATCH(fSts);
  806. return fSts;
  807. }
  808. SLBCSPAPI
  809. CPDuplicateKey(IN HCRYPTPROV hProv,
  810. IN HCRYPTKEY hKey,
  811. IN DWORD *pdwReserved,
  812. IN DWORD dwFlags,
  813. OUT HCRYPTKEY *phDupKey)
  814. {
  815. BOOL fSts = CRYPT_FAILED;
  816. CSPI_TRY(CPDuplicateKey)
  817. {
  818. ValidateFlags(dwFlags, 0);
  819. Guard<Lockable> grdMaster(TheMasterLock());
  820. Guarded<CryptContext *>
  821. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  822. CKeyContext *pKey = gpCtx->LookupKey(hKey);
  823. auto_ptr<CKeyContext> apDupKey(pKey->Clone(pdwReserved, dwFlags));
  824. *phDupKey = gpCtx->Add(apDupKey);
  825. }
  826. CSPI_CATCH(fSts);
  827. return fSts;
  828. }
  829. SLBCSPAPI
  830. CPExportKey(IN HCRYPTPROV hProv,
  831. IN HCRYPTKEY hKey,
  832. IN HCRYPTKEY hExpKey,
  833. IN DWORD dwBlobType,
  834. IN DWORD dwFlags,
  835. OUT BYTE *pbData,
  836. IN OUT DWORD *pdwDataLen)
  837. {
  838. BOOL fSts = CRYPT_FAILED;
  839. CSPI_TRY(CPExportKey)
  840. {
  841. ValidateFlags(dwFlags, 0);
  842. if (PRIVATEKEYBLOB == dwBlobType)
  843. throw scu::OsException(ERROR_INVALID_PARAMETER);
  844. Guard<Lockable> grdMaster(TheMasterLock());
  845. Guarded<CryptContext *>
  846. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  847. CKeyContext *pKey = gpCtx->LookupKey(hKey);
  848. if (KT_SESSIONKEY == pKey->TypeOfKey())
  849. {
  850. if ((SIMPLEBLOB != dwBlobType) &&
  851. (SYMMETRICWRAPKEYBLOB != dwBlobType))
  852. throw scu::OsException(NTE_BAD_TYPE);
  853. }
  854. else
  855. if (PUBLICKEYBLOB != dwBlobType)
  856. throw scu::OsException(NTE_BAD_TYPE);
  857. if (hExpKey && (PUBLICKEYBLOB == dwBlobType))
  858. throw scu::OsException(ERROR_INVALID_PARAMETER);
  859. CKeyContext *pExpKey = 0;
  860. if (SIMPLEBLOB != dwBlobType)
  861. {
  862. pExpKey = hExpKey
  863. ? gpCtx->LookupKey(hExpKey)
  864. : 0;
  865. }
  866. else
  867. {
  868. CPublicKeyContext *pPubExpKey = hExpKey
  869. ? gpCtx->LookupPublicKey(hExpKey)
  870. : 0;
  871. if (pPubExpKey)
  872. {
  873. if (!pPubExpKey->AuxKeyLoaded())
  874. pPubExpKey->AuxPublicKey(pPubExpKey->AsAlignedBlob(0, dwBlobType));
  875. }
  876. pExpKey = pPubExpKey;
  877. }
  878. HCRYPTKEY hAuxExpKey = pExpKey
  879. ? pExpKey->KeyHandleInAuxCSP()
  880. : 0;
  881. AlignedBlob abKey(pKey->AsAlignedBlob(hAuxExpKey, dwBlobType));
  882. Assign(pbData, pdwDataLen, Blob(abKey.Data(), abKey.Length()));
  883. }
  884. CSPI_CATCH(fSts);
  885. return fSts;
  886. }
  887. SLBCSPAPI
  888. CPGenKey(IN HCRYPTPROV hProv,
  889. IN ALG_ID Algid,
  890. IN DWORD dwFlags,
  891. OUT HCRYPTKEY *phKey)
  892. {
  893. BOOL fSts = CRYPT_FAILED;
  894. CSPI_TRY(CPGenKey)
  895. {
  896. Guard<Lockable> grdMaster(TheMasterLock());
  897. Guarded<CryptContext *>
  898. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  899. if (FlagsAreSet(dwFlags, CRYPT_USER_PROTECTED) &&
  900. !gpCtx->GuiEnabled())
  901. throw scu::OsException(NTE_SILENT_CONTEXT);
  902. *phKey = gpCtx->GenerateKey(Algid, dwFlags);
  903. fSts = CRYPT_SUCCEED;
  904. }
  905. CSPI_CATCH(fSts);
  906. return fSts;
  907. }
  908. SLBCSPAPI
  909. CPGetKeyParam(IN HCRYPTPROV hProv,
  910. IN HCRYPTKEY hKey,
  911. IN DWORD dwParam,
  912. OUT BYTE *pbData,
  913. IN DWORD *pdwDataLen,
  914. IN DWORD dwFlags)
  915. {
  916. BOOL fSts = CRYPT_FAILED;
  917. CSPI_TRY(CPGetKeyParam)
  918. {
  919. Guard<Lockable> grdMaster(TheMasterLock());
  920. Guarded<CryptContext *>
  921. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  922. CKeyContext *pKey = gpCtx->LookupKey(hKey);
  923. ValidateFlags(dwFlags, 0);
  924. if (KT_PUBLICKEY == pKey->TypeOfKey())
  925. {
  926. // Public key
  927. CPublicKeyContext *pPubKey =
  928. static_cast<CPublicKeyContext *>(pKey);
  929. switch (dwParam)
  930. {
  931. case KP_ALGID:
  932. {
  933. pPubKey->VerifyKeyExists();
  934. ALG_ID algid;
  935. if (pPubKey->KeySpec() == AT_KEYEXCHANGE)
  936. algid = CALG_RSA_KEYX;
  937. else
  938. algid = CALG_RSA_SIGN;
  939. Assign(pbData, pdwDataLen, &algid, sizeof algid);
  940. }
  941. break;
  942. case KP_BLOCKLEN:
  943. {
  944. pPubKey->VerifyKeyExists();
  945. CPublicKeyContext::StrengthType stBlockLen =
  946. pPubKey->MaxStrength();
  947. Assign(pbData, pdwDataLen, &stBlockLen, sizeof stBlockLen);
  948. }
  949. break;
  950. case KP_KEYLEN:
  951. {
  952. pPubKey->VerifyKeyExists();
  953. DWORD dwKeyLen = pPubKey->MaxStrength(); // must be DWORD
  954. Assign(pbData, pdwDataLen, &dwKeyLen, sizeof dwKeyLen);
  955. }
  956. break;
  957. case KP_PERMISSIONS:
  958. {
  959. pPubKey->VerifyKeyExists();
  960. BYTE bPermissions = pPubKey->Permissions();
  961. Assign(pbData, pdwDataLen,
  962. &bPermissions, sizeof bPermissions);
  963. }
  964. break;
  965. case KP_CERTIFICATE:
  966. {
  967. CWaitCursor waitCursor;
  968. Blob const blob(pPubKey->Certificate());
  969. Assign(pbData, pdwDataLen, blob);
  970. }
  971. break;
  972. default:
  973. throw scu::OsException(NTE_BAD_TYPE);
  974. }
  975. }
  976. else
  977. {
  978. // session key
  979. CSessionKeyContext *pSessionKey =
  980. static_cast<CSessionKeyContext *>(pKey);
  981. if (!CryptGetKeyParam(pSessionKey->KeyHandleInAuxCSP(),
  982. dwParam, pbData, pdwDataLen, dwFlags))
  983. throw scu::OsException(GetLastError());
  984. }
  985. }
  986. CSPI_CATCH(fSts);
  987. return fSts;
  988. }
  989. SLBCSPAPI
  990. CPGenRandom(IN HCRYPTPROV hProv,
  991. IN DWORD dwLen,
  992. IN OUT BYTE *pbBuffer)
  993. {
  994. BOOL fSts = CRYPT_FAILED;
  995. CSPI_TRY(CPGenRandom)
  996. {
  997. Guard<Lockable> grdMaster(TheMasterLock());
  998. Guarded<CryptContext *>
  999. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1000. if (!pbBuffer || (0 == dwLen))
  1001. throw scu::OsException(ERROR_INVALID_PARAMETER);
  1002. HAdaptiveContainer hacntr = gpCtx->AdaptiveContainer();
  1003. if (!hacntr)
  1004. {
  1005. if (!CryptGenRandom(gpCtx->AuxContext(), dwLen, pbBuffer))
  1006. throw scu::OsException(GetLastError());
  1007. }
  1008. else
  1009. {
  1010. Secured<HAdaptiveContainer> hsacntr(hacntr);
  1011. hsacntr->TheCContainer()->Card()->GenRandom(dwLen, pbBuffer);
  1012. }
  1013. fSts = CRYPT_SUCCEED;
  1014. }
  1015. CSPI_CATCH(fSts);
  1016. return fSts;
  1017. }
  1018. SLBCSPAPI
  1019. CPGetUserKey(IN HCRYPTPROV hProv,
  1020. IN DWORD dwKeySpec,
  1021. OUT HCRYPTKEY *phUserKey)
  1022. {
  1023. BOOL fSts = CRYPT_FAILED;
  1024. CSPI_TRY(CPGetUserKey)
  1025. {
  1026. Guard<Lockable> grdMaster(TheMasterLock());
  1027. Guarded<CryptContext *>
  1028. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1029. // TO DO: This should really be a key pair, not public key.
  1030. CKeyContext *pKey = 0;
  1031. auto_ptr<CKeyContext>
  1032. apKey(new CPublicKeyContext(gpCtx->AuxContext(), **gpCtx,
  1033. dwKeySpec));
  1034. *phUserKey = gpCtx->Add(apKey);
  1035. fSts = CRYPT_SUCCEED;
  1036. }
  1037. CSPI_CATCH(fSts);
  1038. return fSts;
  1039. }
  1040. SLBCSPAPI
  1041. CPImportKey(IN HCRYPTPROV hProv,
  1042. IN CONST BYTE *pbData,
  1043. IN DWORD dwDataLen,
  1044. IN HCRYPTKEY hImpKey,
  1045. IN DWORD dwFlags,
  1046. OUT HCRYPTKEY *phKey)
  1047. {
  1048. BOOL fSts = CRYPT_FAILED;
  1049. CSPI_TRY(CPImportKey)
  1050. {
  1051. Guard<Lockable> grdMaster(TheMasterLock());
  1052. Guarded<CryptContext *>
  1053. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1054. if (!phKey)
  1055. throw scu::OsException(ERROR_INVALID_PARAMETER);
  1056. // Conversion to do here
  1057. PUBLICKEYSTRUC const *pPubKey =
  1058. reinterpret_cast<PUBLICKEYSTRUC const *>(pbData);
  1059. if (CUR_BLOB_VERSION != pPubKey->bVersion) // 2
  1060. throw scu::OsException(NTE_BAD_VER);
  1061. switch(pPubKey->bType)
  1062. {
  1063. case PRIVATEKEYBLOB: // fall-through intentional
  1064. case PUBLICKEYBLOB:
  1065. {
  1066. DWORD dwKeySpec;
  1067. switch (pPubKey->aiKeyAlg)
  1068. {
  1069. case CALG_RSA_SIGN:
  1070. dwKeySpec = AT_SIGNATURE;
  1071. break;
  1072. case CALG_RSA_KEYX:
  1073. dwKeySpec = AT_KEYEXCHANGE;
  1074. break;
  1075. default:
  1076. throw scu::OsException(NTE_BAD_ALGID);
  1077. }
  1078. Blob const blbMsKey(pbData, dwDataLen);
  1079. auto_ptr<CPublicKeyContext> apKey;
  1080. if (PRIVATEKEYBLOB == pPubKey->bType)
  1081. {
  1082. HCRYPTKEY hEncKey = hImpKey
  1083. ? gpCtx->LookupSessionKey(hImpKey)->KeyHandleInAuxCSP()
  1084. : 0;
  1085. ValidateFlags(dwFlags, CRYPT_EXPORTABLE);
  1086. apKey = gpCtx->ImportPrivateKey(blbMsKey,
  1087. dwKeySpec,
  1088. (dwFlags &
  1089. CRYPT_EXPORTABLE) != 0,
  1090. hEncKey);
  1091. }
  1092. else
  1093. {
  1094. if (0 != hImpKey)
  1095. throw scu::OsException(ERROR_INVALID_PARAMETER);
  1096. ValidateFlags(dwFlags, 0);
  1097. apKey = gpCtx->ImportPublicKey(blbMsKey,
  1098. dwKeySpec);
  1099. }
  1100. *phKey = gpCtx->Add(apKey);
  1101. }
  1102. break;
  1103. case SIMPLEBLOB:
  1104. {
  1105. auto_ptr<CSessionKeyContext> apKey;
  1106. ALG_ID const *pAlgId =
  1107. reinterpret_cast<ALG_ID const *>(&pbData[sizeof BLOBHEADER]);
  1108. if (CALG_RSA_KEYX == *pAlgId)
  1109. {
  1110. // ignore hImp
  1111. apKey = gpCtx->UseSessionKey(pbData, dwDataLen, 0, dwFlags);
  1112. }
  1113. else
  1114. {
  1115. // if other algo then hImp shall specify a session key
  1116. if (!hImpKey)
  1117. throw scu::OsException(ERROR_INVALID_PARAMETER);
  1118. // Find the handle in the Aux CSP corresponding
  1119. // to hImpKey which should have been previously
  1120. // imported in the CSP
  1121. CSessionKeyContext *pSessionKey =
  1122. gpCtx->LookupSessionKey(hImpKey);
  1123. apKey = gpCtx->UseSessionKey(pbData, dwDataLen,
  1124. pSessionKey->KeyHandleInAuxCSP(),
  1125. dwFlags);
  1126. }
  1127. *phKey = gpCtx->Add(apKey);
  1128. }
  1129. }
  1130. }
  1131. CSPI_CATCH(fSts);
  1132. return fSts;
  1133. }
  1134. SLBCSPAPI
  1135. CPSetKeyParam(IN HCRYPTPROV hProv,
  1136. IN HCRYPTKEY hKey,
  1137. IN DWORD dwParam,
  1138. IN BYTE *pbData,
  1139. IN DWORD dwFlags)
  1140. {
  1141. BOOL fSts = CRYPT_FAILED;
  1142. CSPI_TRY(CPSetKeyParam)
  1143. {
  1144. Guard<Lockable> grdMaster(TheMasterLock());
  1145. Guarded<CryptContext *>
  1146. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1147. CKeyContext *pKey = gpCtx->LookupKey(hKey);
  1148. switch (pKey->TypeOfKey())
  1149. {
  1150. case KT_PUBLICKEY:
  1151. {
  1152. CPublicKeyContext *pPubKey =
  1153. static_cast<CPublicKeyContext *>(pKey);
  1154. // Error return is a special case for KP_CERTIFICATE,
  1155. // see below.
  1156. if (KP_CERTIFICATE != dwParam)
  1157. ValidateFlags(dwFlags, 0);
  1158. switch(dwParam)
  1159. {
  1160. case KP_CERTIFICATE:
  1161. try
  1162. {
  1163. ValidateFlags(dwFlags, 0);
  1164. pPubKey->Certificate(pbData);
  1165. }
  1166. // Xenroll provided by Microsoft only recognizes
  1167. // SCARD_ errors when writing a certificate. It
  1168. // does, however, recognize all other errors when
  1169. // *not* writing a certificate. The MS
  1170. // OS/Security group recognizes Xenroll is in
  1171. // error but it will be some time, if ever, before
  1172. // it will be fixed. So, all errors are
  1173. // translated into SCARD_ errors at this point.
  1174. catch (scu::Exception const &rExc)
  1175. {
  1176. CapiError ce(AsCapiError(rExc));
  1177. if (NTE_TOKEN_KEYSET_STORAGE_FULL == ce)
  1178. ce = SCARD_E_WRITE_TOO_MANY;
  1179. else
  1180. if (FACILITY_SCARD != HRESULT_FACILITY(ce))
  1181. ce = SCARD_E_UNEXPECTED;
  1182. throw scu::OsException(ce);
  1183. }
  1184. catch (...)
  1185. {
  1186. throw scu::OsException(SCARD_E_UNEXPECTED);
  1187. }
  1188. break;
  1189. case KP_PERMISSIONS:
  1190. pPubKey->Permissions(*pbData);
  1191. break;
  1192. case PP_KEYEXCHANGE_PIN: // fall-through
  1193. case PP_SIGNATURE_PIN:
  1194. Pin(gpCtx, reinterpret_cast<char *>(pbData));
  1195. break;
  1196. default:
  1197. throw scu::OsException(ERROR_NOT_SUPPORTED);
  1198. break;
  1199. }
  1200. break;
  1201. }
  1202. case KT_SESSIONKEY:
  1203. {
  1204. CSessionKeyContext *pSessionKey =
  1205. static_cast<CSessionKeyContext*>(pKey);
  1206. if (!CryptSetKeyParam(pSessionKey->KeyHandleInAuxCSP(),
  1207. dwParam, pbData, dwFlags))
  1208. throw scu::OsException(GetLastError());
  1209. break;
  1210. }
  1211. default:
  1212. throw scu::OsException(ERROR_NOT_SUPPORTED);
  1213. break;
  1214. }
  1215. }
  1216. CSPI_CATCH(fSts);
  1217. return fSts;
  1218. }
  1219. SLBCSPAPI
  1220. CPEncrypt(IN HCRYPTPROV hProv,
  1221. IN HCRYPTKEY hKey,
  1222. IN HCRYPTHASH hHash,
  1223. IN BOOL Final,
  1224. IN DWORD dwFlags,
  1225. IN OUT BYTE *pbData,
  1226. IN OUT DWORD *pdwDataLen,
  1227. IN DWORD dwBufLen)
  1228. {
  1229. BOOL fSts = CRYPT_FAILED;
  1230. CSPI_TRY(CPEncrypt)
  1231. {
  1232. Guard<Lockable> grdMaster(TheMasterLock());
  1233. Guarded<CryptContext *>
  1234. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1235. CKeyContext *pKeyCtx = gpCtx->LookupKey(hKey);
  1236. ValidateFlags(dwFlags, CRYPT_OAEP);
  1237. HCRYPTHASH hAuxHash = hHash
  1238. ? gpCtx->LookupHash(hHash)->HashHandleInAuxCSP()
  1239. : NULL;
  1240. pKeyCtx->Encrypt(hAuxHash, Final, dwFlags, pbData, pdwDataLen,
  1241. dwBufLen);
  1242. }
  1243. CSPI_CATCH(fSts);
  1244. return fSts;
  1245. }
  1246. SLBCSPAPI
  1247. CPDecrypt(IN HCRYPTPROV hProv,
  1248. IN HCRYPTKEY hKey,
  1249. IN HCRYPTHASH hHash,
  1250. IN BOOL Final,
  1251. IN DWORD dwFlags,
  1252. IN OUT BYTE *pbData,
  1253. IN OUT DWORD *pdwDataLen)
  1254. {
  1255. BOOL fSts = CRYPT_FAILED;
  1256. CSPI_TRY(CPDecrypt)
  1257. {
  1258. Guard<Lockable> grdMaster(TheMasterLock());
  1259. Guarded<CryptContext *>
  1260. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1261. CSessionKeyContext *pSessionKey = gpCtx->LookupSessionKey(hKey);
  1262. ValidateFlags(dwFlags, CRYPT_OAEP);
  1263. if (hHash)
  1264. {
  1265. CHashContext *pHash = gpCtx->LookupHash(hHash);
  1266. pSessionKey->Decrypt(pHash->HashHandleInAuxCSP(), Final,
  1267. dwFlags, pbData, pdwDataLen);
  1268. pHash->ExportFromAuxCSP();
  1269. }
  1270. else
  1271. pSessionKey->Decrypt(0, Final, dwFlags, pbData, pdwDataLen);
  1272. }
  1273. CSPI_CATCH(fSts);
  1274. return fSts;
  1275. }
  1276. SLBCSPAPI
  1277. CPCreateHash(
  1278. IN HCRYPTPROV hProv,
  1279. IN ALG_ID Algid,
  1280. IN HCRYPTKEY hKey,
  1281. IN DWORD dwFlags,
  1282. OUT HCRYPTHASH *phHash)
  1283. {
  1284. BOOL fSts = CRYPT_FAILED;
  1285. CSPI_TRY(CPCreateHash)
  1286. {
  1287. Guard<Lockable> grdMaster(TheMasterLock());
  1288. Guarded<CryptContext *>
  1289. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1290. ValidateFlags(dwFlags, 0);
  1291. auto_ptr<CHashContext> apHash(CHashContext::Make(Algid, **gpCtx));
  1292. apHash->ImportToAuxCSP();
  1293. *phHash = gpCtx->Add(apHash);
  1294. }
  1295. CSPI_CATCH(fSts);
  1296. return fSts;
  1297. }
  1298. SLBCSPAPI
  1299. CPDestroyHash(IN HCRYPTPROV hProv,
  1300. IN HCRYPTHASH hHash)
  1301. {
  1302. BOOL fSts = CRYPT_FAILED;
  1303. CSPI_TRY(CPDestroyHash)
  1304. {
  1305. Guard<Lockable> grdMaster(TheMasterLock());
  1306. Guarded<CryptContext *>
  1307. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1308. auto_ptr<CHashContext> apHash(gpCtx->CloseHash(hHash));
  1309. apHash->Close();
  1310. }
  1311. CSPI_CATCH(fSts);
  1312. return fSts;
  1313. }
  1314. SLBCSPAPI
  1315. CPGetHashParam(IN HCRYPTPROV hProv,
  1316. IN HCRYPTHASH hHash,
  1317. IN DWORD dwParam,
  1318. OUT BYTE *pbData,
  1319. IN DWORD *pdwDataLen,
  1320. IN DWORD dwFlags)
  1321. {
  1322. BOOL fSts = CRYPT_FAILED;
  1323. CSPI_TRY(CPGetHashParam)
  1324. {
  1325. Guard<Lockable> grdMaster(TheMasterLock());
  1326. Guarded<CryptContext *>
  1327. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1328. CHashContext *pHash = gpCtx->LookupHash(hHash);
  1329. ValidateFlags(dwFlags, 0);
  1330. switch (dwParam)
  1331. {
  1332. case HP_ALGID:
  1333. {
  1334. ALG_ID const algid = pHash->AlgId();
  1335. Assign(pbData, pdwDataLen, &algid, sizeof algid);
  1336. }
  1337. break;
  1338. case HP_HASHSIZE:
  1339. {
  1340. CHashContext::SizeType const cLength = pHash->Length();
  1341. Assign(pbData, pdwDataLen, &cLength, sizeof cLength);
  1342. }
  1343. break;
  1344. case HP_HASHVAL:
  1345. {
  1346. Blob const blob(pHash->Value());
  1347. Assign(pbData, pdwDataLen, blob);
  1348. }
  1349. break;
  1350. default:
  1351. throw scu::OsException(ERROR_INVALID_PARAMETER);
  1352. break;
  1353. }
  1354. }
  1355. CSPI_CATCH(fSts);
  1356. return fSts;
  1357. }
  1358. SLBCSPAPI
  1359. CPHashData(IN HCRYPTPROV hProv,
  1360. IN HCRYPTHASH hHash,
  1361. IN CONST BYTE *pbData,
  1362. IN DWORD dwDataLen,
  1363. IN DWORD dwFlags)
  1364. {
  1365. BOOL fSts = CRYPT_FAILED;
  1366. CSPI_TRY(CPHashData)
  1367. {
  1368. Guard<Lockable> grdMaster(TheMasterLock());
  1369. Guarded<CryptContext *>
  1370. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1371. CHashContext *pHash = gpCtx->LookupHash(hHash);
  1372. if (!CryptHashData(pHash->HashHandleInAuxCSP(), pbData, dwDataLen,
  1373. dwFlags))
  1374. throw scu::OsException(GetLastError());
  1375. }
  1376. CSPI_CATCH(fSts);
  1377. return fSts;
  1378. }
  1379. SLBCSPAPI
  1380. CPHashSessionKey(IN HCRYPTPROV hProv,
  1381. IN HCRYPTHASH hHash,
  1382. IN HCRYPTKEY hKey,
  1383. IN DWORD dwFlags)
  1384. {
  1385. BOOL fSts = CRYPT_FAILED;
  1386. CSPI_TRY(CPHashSessionKey)
  1387. {
  1388. Guard<Lockable> grdMaster(TheMasterLock());
  1389. Guarded<CryptContext *>
  1390. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1391. CSessionKeyContext *pSessionKey = gpCtx->LookupSessionKey(hKey);
  1392. CHashContext *pHash = gpCtx->LookupHash(hHash);
  1393. if (!CryptHashSessionKey(pHash->HashHandleInAuxCSP(),
  1394. pSessionKey->KeyHandleInAuxCSP(),
  1395. dwFlags))
  1396. throw scu::OsException(GetLastError());
  1397. pHash->ExportFromAuxCSP();
  1398. }
  1399. CSPI_CATCH(fSts);
  1400. return fSts;
  1401. }
  1402. SLBCSPAPI
  1403. CPSetHashParam(IN HCRYPTPROV hProv,
  1404. IN HCRYPTHASH hHash,
  1405. IN DWORD dwParam,
  1406. IN BYTE *pbData,
  1407. IN DWORD dwFlags)
  1408. {
  1409. BOOL fSts = CRYPT_FAILED;
  1410. CSPI_TRY(CPSetHashParam)
  1411. {
  1412. Guard<Lockable> grdMaster(TheMasterLock());
  1413. Guarded<CryptContext *>
  1414. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1415. CHashContext *pHash = gpCtx->LookupHash(hHash);
  1416. if (!CryptSetHashParam(pHash->HashHandleInAuxCSP(), dwParam,
  1417. pbData, dwFlags))
  1418. throw scu::OsException(GetLastError());
  1419. }
  1420. CSPI_CATCH(fSts);
  1421. return fSts;
  1422. }
  1423. SLBCSPAPI
  1424. CPSignHash(IN HCRYPTPROV hProv,
  1425. IN HCRYPTHASH hHash,
  1426. IN DWORD dwKeySpec,
  1427. IN LPCTSTR szDescription,
  1428. IN DWORD dwFlags,
  1429. OUT BYTE *pbSignature,
  1430. IN OUT DWORD *pdwSigLen)
  1431. {
  1432. BOOL fSts = CRYPT_FAILED;
  1433. CSPI_TRY(CPSignHash)
  1434. {
  1435. Guard<Lockable> grdMaster(TheMasterLock());
  1436. Guarded<CryptContext *>
  1437. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1438. CHashContext *pHash = gpCtx->LookupHash(hHash);
  1439. if (!pdwSigLen)
  1440. throw scu::OsException(ERROR_INVALID_PARAMETER);
  1441. ValidateFlags(dwFlags, CRYPT_NOHASHOID);
  1442. // TO DO: This should really be a private key and
  1443. // avoid having to fetch the public key to get the modulus
  1444. CPublicKeyContext Key(gpCtx->AuxContext(), **gpCtx, dwKeySpec);
  1445. DWORD cSignatureLength =
  1446. Key.Strength() / numeric_limits<BYTE>::digits;
  1447. if (!pbSignature)
  1448. {
  1449. *pdwSigLen = cSignatureLength;
  1450. }
  1451. else if (*pdwSigLen < cSignatureLength)
  1452. {
  1453. *pdwSigLen = cSignatureLength;
  1454. throw scu::OsException(ERROR_MORE_DATA);
  1455. }
  1456. else
  1457. {
  1458. // TO DO: Continue support to add a description?
  1459. if (szDescription && (0 < lstrlen(szDescription)))
  1460. pHash->Hash(reinterpret_cast<BYTE const *>(szDescription),
  1461. lstrlen(szDescription) * sizeof TCHAR);
  1462. Blob SignedHash(Key.Sign(pHash, dwFlags & CRYPT_NOHASHOID));
  1463. memcpy(pbSignature, SignedHash.data(), SignedHash.length());
  1464. *pdwSigLen = SignedHash.length();
  1465. }
  1466. }
  1467. CSPI_CATCH(fSts);
  1468. return fSts;
  1469. }
  1470. SLBCSPAPI
  1471. CPVerifySignature(IN HCRYPTPROV hProv,
  1472. IN HCRYPTHASH hHash,
  1473. IN CONST BYTE *pbSignature,
  1474. IN DWORD dwSigLen,
  1475. IN HCRYPTKEY hPubKey,
  1476. IN LPCTSTR szDescription,
  1477. IN DWORD dwFlags)
  1478. {
  1479. BOOL fSts = CRYPT_FAILED;
  1480. CSPI_TRY(CPVerifySignature)
  1481. {
  1482. Guard<Lockable> grdMaster(TheMasterLock());
  1483. Guarded<CryptContext *>
  1484. gpCtx(static_cast<CryptContext *>(hlCryptContexts[hProv]));
  1485. CHashContext *pHash = gpCtx->LookupHash(hHash);
  1486. CPublicKeyContext *pKey = gpCtx->LookupPublicKey(hPubKey);
  1487. ValidateFlags(dwFlags, CRYPT_NOHASHOID);
  1488. pKey->VerifySignature(pHash->HashHandleInAuxCSP(),
  1489. pbSignature, dwSigLen,
  1490. szDescription, dwFlags);
  1491. }
  1492. CSPI_CATCH(fSts);
  1493. return fSts;
  1494. }