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.

1129 lines
28 KiB

  1. // PubKeyCtx.cpp -- definition of CPublicKeyContext
  2. // (c) Copyright Schlumberger Technology Corp., unpublished work, created
  3. // 2000. 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" // required by GUI header files
  8. #include <string>
  9. #include <limits>
  10. #include <slbcci.h>
  11. #include <cciPubKey.h>
  12. #include <cciPriKey.h>
  13. #include <cciCert.h>
  14. #include <cciKeyPair.h>
  15. #include "CryptCtx.h"
  16. #include "HashCtx.h"
  17. #include "RsaKey.h"
  18. #include "EncodedMsg.h"
  19. #include "Pkcs11Attr.h"
  20. #include "AuxHash.h"
  21. #include "RsaKPGen.h"
  22. #include "Secured.h"
  23. #include "StResource.h"
  24. #include "PromptUser.h"
  25. #include "PublicKeyHelper.h"
  26. #include "PubKeyCtx.h"
  27. #include "AlignedBlob.h"
  28. #include "CertificateExtensions.h"
  29. using namespace std;
  30. using namespace scu;
  31. using namespace cci;
  32. /////////////////////////// LOCAL/HELPER /////////////////////////////////
  33. namespace
  34. {
  35. DWORD
  36. PkcsToDword(
  37. IN OUT LPBYTE pbPkcs,
  38. IN DWORD lth)
  39. {
  40. LPBYTE pbBegin = pbPkcs;
  41. LPBYTE pbEnd = &pbPkcs[lth - 1];
  42. DWORD length = lth;
  43. while (pbBegin < pbEnd)
  44. {
  45. BYTE tmp = *pbBegin;
  46. *pbBegin++ = *pbEnd;
  47. *pbEnd-- = tmp;
  48. }
  49. for (pbEnd = &pbPkcs[lth - 1]; 0 == *pbEnd; pbEnd -= 1)
  50. length -= 1;
  51. return length;
  52. }
  53. KeySpec
  54. AsKeySpec(ALG_ID algid)
  55. {
  56. KeySpec ks;
  57. switch(algid)
  58. {
  59. case AT_KEYEXCHANGE:
  60. ks = ksExchange;
  61. break;
  62. case AT_SIGNATURE:
  63. ks = ksSignature;
  64. break;
  65. default:
  66. throw scu::OsException(NTE_BAD_KEY);
  67. }
  68. return ks;
  69. }
  70. ALG_ID
  71. AsKeySpec(KeySpec ks)
  72. {
  73. ALG_ID algid;
  74. switch(ks)
  75. {
  76. case ksExchange:
  77. algid = AT_KEYEXCHANGE;
  78. break;
  79. case ksSignature:
  80. algid = AT_SIGNATURE;
  81. break;
  82. default:
  83. throw scu::OsException(NTE_FAIL); // internal error
  84. break;
  85. }
  86. return algid;
  87. }
  88. string
  89. AsString(unsigned char const *p,
  90. size_t cLength)
  91. {
  92. return string(reinterpret_cast<char const *>(p), cLength);
  93. }
  94. // make a "raw modulus" from a modulus by padding with zeroes to meet
  95. // specified strength. The modulus blob is assumed to represent an
  96. // unsigned integer in little endian format whose size less than or
  97. // equal to strength in octets.
  98. Blob
  99. RawModulus(Blob const &rbTrimmedModulus,
  100. RsaKey::StrengthType strength)
  101. {
  102. RsaKey::OctetLengthType const cRawLength =
  103. strength / numeric_limits<Blob::value_type>::digits;
  104. if (cRawLength < rbTrimmedModulus.length())
  105. throw scu::OsException(NTE_BAD_DATA);
  106. Blob bRawModulus(rbTrimmedModulus);
  107. bRawModulus.append(cRawLength - rbTrimmedModulus.length(), 0);
  108. return bRawModulus;
  109. }
  110. /*++
  111. ExtractTag:
  112. This routine extracts a tag from an ASN.1 BER stream.
  113. Arguments:
  114. pbSrc supplies the buffer containing the ASN.1 stream.
  115. pdwTag receives the tag.
  116. Return Value:
  117. The number of bytes extracted from the stream. Errors are thrown
  118. as DWORD status codes.
  119. Author:
  120. Doug Barlow (dbarlow) 10/9/1995
  121. Doug Barlow (dbarlow) 7/31/1997
  122. --*/
  123. DWORD
  124. ExtractTag(BYTE const *pbSrc,
  125. LPDWORD pdwTag,
  126. LPBOOL pfConstr)
  127. {
  128. LONG lth = 0;
  129. DWORD tagw;
  130. BYTE tagc, cls;
  131. tagc = pbSrc[lth++];
  132. cls = tagc & 0xc0; // Top 2 bits.
  133. if (NULL != pfConstr)
  134. *pfConstr = (0 != (tagc & 0x20));
  135. tagc &= 0x1f; // Bottom 5 bits.
  136. if (31 > tagc)
  137. tagw = tagc;
  138. else
  139. {
  140. tagw = 0;
  141. do
  142. {
  143. if (0 != (tagw & 0xfe000000))
  144. throw scu::OsException(ERROR_ARITHMETIC_OVERFLOW);
  145. tagc = pbSrc[lth++];
  146. tagw <<= 7;
  147. tagw |= tagc & 0x7f;
  148. } while (0 != (tagc & 0x80));
  149. }
  150. *pdwTag = tagw | (cls << 24);
  151. return lth;
  152. }
  153. /*++
  154. ExtractLength:
  155. This routine extracts a length from an ASN.1 BER stream. If the
  156. length is indefinite, this routine recurses to figure out the real
  157. length. A flag as to whether or not the encoding was indefinite
  158. is optionally returned.
  159. Arguments:
  160. pbSrc supplies the buffer containing the ASN.1 stream.
  161. pdwLen receives the len.
  162. pfIndefinite, if not NULL, receives a flag indicating whether or not
  163. the
  164. encoding was indefinite.
  165. Return Value:
  166. The number of bytes extracted from the stream. Errors are thrown as
  167. DWORD status codes.
  168. Author:
  169. Doug Barlow (dbarlow) 10/9/1995
  170. Doug Barlow (dbarlow) 7/31/1997
  171. --*/
  172. DWORD
  173. ExtractLength(BYTE const *pbSrc,
  174. LPDWORD pdwLen,
  175. LPBOOL pfIndefinite)
  176. {
  177. DWORD ll, rslt, lth, lTotal = 0;
  178. BOOL fInd = FALSE;
  179. //
  180. // Extract the Length.
  181. //
  182. if (0 == (pbSrc[lTotal] & 0x80))
  183. {
  184. //
  185. // Short form encoding.
  186. //
  187. rslt = pbSrc[lTotal++];
  188. }
  189. else
  190. {
  191. rslt = 0;
  192. ll = pbSrc[lTotal++] & 0x7f;
  193. if (0 != ll)
  194. {
  195. //
  196. // Long form encoding.
  197. //
  198. for (; 0 < ll; ll -= 1)
  199. {
  200. if (0 != (rslt & 0xff000000))
  201. throw scu::OsException(ERROR_ARITHMETIC_OVERFLOW);
  202. rslt = (rslt << 8) | pbSrc[lTotal];
  203. lTotal += 1;
  204. }
  205. }
  206. else
  207. {
  208. DWORD ls = lTotal;
  209. //
  210. // Indefinite encoding.
  211. //
  212. fInd = TRUE;
  213. while ((0 != pbSrc[ls]) || (0 != pbSrc[ls + 1]))
  214. {
  215. // Skip over the Type.
  216. if (31 > (pbSrc[ls] & 0x1f))
  217. ls += 1;
  218. else
  219. while (0 != (pbSrc[++ls] & 0x80)); // Empty loop body.
  220. lth = ExtractLength(&pbSrc[ls], &ll, NULL);
  221. ls += lth + ll;
  222. }
  223. rslt = ls - lTotal;
  224. }
  225. }
  226. //
  227. // Supply the caller with what we've learned.
  228. //
  229. *pdwLen = rslt;
  230. if (NULL != pfIndefinite)
  231. *pfIndefinite = fInd;
  232. return lTotal;
  233. }
  234. /*++
  235. Asn1Length:
  236. This routine parses a given ASN.1 buffer and returns the complete
  237. length of the encoding, including the leading tag and length
  238. bytes.
  239. Arguments:
  240. pbData supplies the buffer to be parsed.
  241. Return Value:
  242. The length of the entire ASN.1 buffer.
  243. Throws:
  244. Overflow errors are thrown as DWORD status codes.
  245. Author:
  246. Doug Barlow (dbarlow) 7/31/1997
  247. --*/
  248. DWORD
  249. Asn1Length(LPCBYTE pbAsn1)
  250. {
  251. DWORD dwTagLen, dwLenLen, dwValLen;
  252. DWORD dwTag;
  253. dwTagLen = ExtractTag(pbAsn1, &dwTag, NULL);
  254. dwLenLen = ExtractLength(&pbAsn1[dwTagLen], &dwValLen, NULL);
  255. return dwTagLen + dwLenLen + dwValLen;
  256. }
  257. } // namespace
  258. /////////////////////////// PUBLIC /////////////////////////////////
  259. // Types
  260. // C'tors/D'tors
  261. CPublicKeyContext::CPublicKeyContext(HCRYPTPROV hProv,
  262. CryptContext &rcryptctx,
  263. ALG_ID algid,
  264. bool fVerifyKeyExists)
  265. : CKeyContext(hProv, KT_PUBLICKEY),
  266. m_rcryptctx(rcryptctx),
  267. m_ks(AsKeySpec(algid))
  268. {
  269. // Make sure the key exists on the card
  270. if (fVerifyKeyExists)
  271. VerifyKeyExists();
  272. }
  273. CPublicKeyContext::~CPublicKeyContext()
  274. {}
  275. // Operators
  276. // Operations
  277. auto_ptr<CKeyContext>
  278. CPublicKeyContext::Clone(DWORD const *pdwReserved,
  279. DWORD dwFlags) const
  280. {
  281. return auto_ptr<CKeyContext>(new CPublicKeyContext(*this,
  282. pdwReserved,
  283. dwFlags));
  284. }
  285. void
  286. CPublicKeyContext::AuxPublicKey(AlignedBlob const &rabMsPublicKey)
  287. {
  288. ClearAuxPublicKey();
  289. m_apabKey = auto_ptr<AlignedBlob>(new AlignedBlob(rabMsPublicKey));
  290. }
  291. void
  292. CPublicKeyContext::ClearAuxPublicKey()
  293. {
  294. m_apabKey = auto_ptr<AlignedBlob>(0);
  295. if (m_hKey)
  296. {
  297. if (!CryptDestroyKey(m_hKey))
  298. throw OsException(GetLastError());
  299. }
  300. }
  301. void
  302. CPublicKeyContext::Certificate(BYTE *pbData)
  303. {
  304. bool fError = false;
  305. DWORD dwErrorCode = NO_ERROR;
  306. if (!pbData)
  307. throw scu::OsException(ERROR_INVALID_PARAMETER);
  308. DWORD dwAsn1Len = Asn1Length(pbData);
  309. if (0 == dwAsn1Len)
  310. throw scu::OsException(ERROR_INVALID_PARAMETER);
  311. Blob blbCert(pbData, dwAsn1Len);
  312. Pkcs11Attributes PkcsAttr(blbCert, AuxProvider());
  313. Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
  314. CKeyPair hkp(KeyPair());
  315. CPublicKey hpubkey(hkp->PublicKey());
  316. // Verify cert's modulus matches the public key's, if it exists
  317. CCard hcard(hsacntr->CardContext()->Card());
  318. bool fLoggedIn = false;
  319. if (hpubkey)
  320. {
  321. if (hcard->IsPKCS11Enabled() && hpubkey->Private())
  322. {
  323. m_rcryptctx.Login(User);
  324. fLoggedIn = true;
  325. }
  326. Blob bKeyModulus(::AsBlob(hpubkey->Modulus()));
  327. Blob bTrimmedModulus(bKeyModulus); // interoperability with V1
  328. TrimExtraZeroes(bTrimmedModulus);
  329. Blob bCertModulus(PkcsAttr.Modulus());
  330. reverse(bCertModulus.begin(), bCertModulus.end()); // little endian
  331. if (0 != bTrimmedModulus.compare(bCertModulus))
  332. throw scu::OsException(NTE_BAD_PUBLIC_KEY);
  333. }
  334. CCertificate hcert(hkp->Certificate());
  335. if (hcert)
  336. OkReplacingCredentials();
  337. if (!fLoggedIn)
  338. {
  339. bool fDoLogin = hcard->IsProtectedMode();
  340. // retrieve the private key handle only if PKCS11 enabled
  341. if (!fDoLogin && hcard->IsPKCS11Enabled())
  342. {
  343. // private key is checked now for login in preparation for
  344. // setting the PKCS11 attributes after the cert is stored
  345. CPrivateKey hprikey(hkp->PrivateKey());
  346. fDoLogin = ((hprikey && hprikey->Private()) || // always private?
  347. (hcert && hcert->Private()));
  348. }
  349. if (fDoLogin)
  350. {
  351. m_rcryptctx.Login(User);
  352. fLoggedIn = true;
  353. }
  354. }
  355. if (hcert)
  356. ClearCertificate(hcert);
  357. hcert = CCertificate(hcard);
  358. hkp->Certificate(hcert);
  359. hcert->Value(AsString(blbCert));
  360. if (hcard->IsPKCS11Enabled())
  361. SetCertDerivedPkcs11Attributes(hkp, PkcsAttr);
  362. CertificateExtensions CertExts(blbCert);
  363. if (CertExts.HasEKU(szOID_KP_SMARTCARD_LOGON) || CertExts.HasEKU(szOID_ENROLLMENT_AGENT))
  364. hcard->DefaultContainer(hsacntr->TheCContainer());
  365. }
  366. Blob
  367. CPublicKeyContext::Decrypt(Blob const &rCipher)
  368. {
  369. Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
  370. // TO DO: Is the explicit check really necessary, or can we catch
  371. // an exception from the CCI/IOP to indicate the key does not exist?
  372. CPrivateKey prikey(KeyPair()->PrivateKey());
  373. if (!prikey)
  374. throw scu::OsException(NTE_NO_KEY);
  375. m_rcryptctx.Login(User);
  376. return ::AsBlob(prikey->InternalAuth(AsString(rCipher)));
  377. }
  378. void
  379. CPublicKeyContext::Decrypt(HCRYPTHASH hAuxHash,
  380. BOOL Final,
  381. DWORD dwFlags,
  382. BYTE *pbData,
  383. DWORD *pdwDataLen)
  384. {
  385. throw scu::OsException(ERROR_NOT_SUPPORTED);
  386. }
  387. void
  388. CPublicKeyContext::Generate(ALG_ID AlgoId,
  389. DWORD dwFlags)
  390. {
  391. RsaKey::StrengthType strength;
  392. strength = HIWORD(dwFlags);
  393. if (0 == strength)
  394. strength = MaxStrength(); // default strength
  395. else
  396. {
  397. if ((MaxStrength() < strength) ||
  398. (MinStrength() > strength))
  399. throw scu::OsException(ERROR_INVALID_PARAMETER);
  400. }
  401. Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
  402. CKeyPair hkp;
  403. PrepToStoreKey(hkp);
  404. RsaKeyPairGenerator GenKey(hkp->Card(), strength);
  405. m_rcryptctx.Login(User); // to create private key
  406. pair<cci::CPrivateKey, cci::CPublicKey> pr(GenKey());
  407. CPrivateKey hprikey(pr.first);
  408. CPublicKey hpubkey(pr.second);
  409. SetAttributes(hpubkey, hprikey, GenKey.OnCard(),
  410. (dwFlags & CRYPT_EXPORTABLE) != 0);
  411. hkp->PrivateKey(hprikey);
  412. hkp->PublicKey(hpubkey);
  413. ClearAuxPublicKey();
  414. }
  415. void
  416. CPublicKeyContext::ImportPrivateKey(MsRsaPrivateKeyBlob const &rmsprikb,
  417. bool fExportable)
  418. {
  419. Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
  420. CKeyPair hkp(hsacntr->TheCContainer()->GetKeyPair(m_ks));
  421. CPrivateKey hprikey(hkp->PrivateKey());
  422. CCard hcard(hkp->Card());
  423. m_rcryptctx.Login(User);
  424. if (!hprikey)
  425. hprikey = CPrivateKey(hkp->Card());
  426. hprikey->Value(*(AsPCciPrivateKeyBlob(rmsprikb).get()));
  427. SetAttributes(CPublicKey(), hprikey, false, fExportable);
  428. hkp->PrivateKey(hprikey);
  429. }
  430. void
  431. CPublicKeyContext::ImportPublicKey(MsRsaPublicKeyBlob const &rmspubkb)
  432. {
  433. Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
  434. CKeyPair hkp(hsacntr->TheCContainer()->GetKeyPair(m_ks));
  435. CPublicKey hpubkey(hkp->PublicKey());
  436. CCard hcard(hkp->Card());
  437. if (hcard->IsProtectedMode() ||
  438. (hcard->IsPKCS11Enabled() &&
  439. (hpubkey && hpubkey->Private())))
  440. m_rcryptctx.Login(User);
  441. if (hpubkey)
  442. {
  443. hpubkey->Delete();
  444. hpubkey = 0;
  445. }
  446. hpubkey = CPublicKey(AsPublicKey(Blob(rmspubkb.Modulus(),
  447. rmspubkb.Length()),
  448. rmspubkb.PublicExponent(),
  449. hcard));
  450. SetAttributes(hpubkey, CPrivateKey(), false, true);
  451. hkp->PublicKey(hpubkey);
  452. AuxPublicKey(rmspubkb.AsAlignedBlob());
  453. }
  454. void
  455. CPublicKeyContext::ImportToAuxCSP()
  456. {
  457. if (!m_hKey)
  458. {
  459. if (!m_apabKey.get())
  460. throw OsException(NTE_NO_KEY);
  461. if (!CryptImportKey(AuxProvider(), m_apabKey->Data(),
  462. m_apabKey->Length(), 0, 0, &m_hKey))
  463. throw scu::OsException(GetLastError());
  464. }
  465. }
  466. void
  467. CPublicKeyContext::Permissions(BYTE bPermissions)
  468. {
  469. if (bPermissions & ~(CRYPT_DECRYPT | CRYPT_ENCRYPT |
  470. CRYPT_EXPORT | CRYPT_READ |
  471. CRYPT_WRITE))
  472. throw scu::OsException(ERROR_INVALID_PARAMETER);
  473. Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
  474. CKeyPair hkp(KeyPair());
  475. CPublicKey hpubkey(hkp->PublicKey());
  476. CPrivateKey hprikey(hkp->PrivateKey());
  477. m_rcryptctx.Login(User);
  478. if (hprikey)
  479. {
  480. hprikey->Decrypt((CRYPT_DECRYPT & bPermissions) != 0);
  481. CCard hcard(hsacntr->CardContext()->Card());
  482. bool PKCS11Enabled = hcard->IsPKCS11Enabled();
  483. bool fExportable = (CRYPT_EXPORT & bPermissions) != 0;
  484. if (PKCS11Enabled)
  485. hprikey->NeverExportable(!fExportable);
  486. hprikey->Exportable(fExportable);
  487. hprikey->Modifiable((CRYPT_WRITE & bPermissions) != 0);
  488. bool fReadable = (CRYPT_READ & bPermissions) != 0;
  489. if (PKCS11Enabled)
  490. hprikey->NeverRead(!fReadable);
  491. hprikey->Read(fReadable);
  492. }
  493. if (hpubkey)
  494. {
  495. hpubkey->Encrypt((CRYPT_ENCRYPT & bPermissions) != 0);
  496. hpubkey->Modifiable((CRYPT_WRITE & bPermissions) != 0);
  497. }
  498. }
  499. // TO DO: Sign is an operation that's performed with the private key,
  500. // not the public key. Make Sign an operation on a PrivateKeyContext.
  501. // string
  502. Blob
  503. CPublicKeyContext::Sign(CHashContext *pHash,
  504. bool fNoHashOid)
  505. {
  506. Blob Message(fNoHashOid
  507. ? pHash->Value()
  508. : pHash->EncodedValue());
  509. // TO DO: When CCI takes object parameters as references,
  510. // em can be const
  511. EncodedMessage em(Message, RsaKey::ktPrivate,
  512. Strength() / numeric_limits<Blob::value_type>::digits);
  513. Blob blob(em.Value());
  514. reverse(blob.begin(), blob.end()); // convert to big endian
  515. Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
  516. // TO DO: Is the explicit check really necessary, or can we catch
  517. // an exception from the CCI/IOP to indicate the key does not exist?
  518. CPrivateKey hprikey(KeyPair()->PrivateKey());
  519. if (!hprikey)
  520. throw scu::OsException(NTE_NO_KEY);
  521. m_rcryptctx.Login(User);
  522. if (!hprikey->Sign())
  523. throw scu::OsException(ERROR_INVALID_PARAMETER);
  524. return ::AsBlob(hprikey->InternalAuth(AsString(blob)));
  525. }
  526. void
  527. CPublicKeyContext::VerifyKeyExists() const
  528. {
  529. Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
  530. CKeyPair hkp(KeyPair());
  531. if (!hkp->PublicKey() && !hkp->PrivateKey())
  532. throw scu::OsException(NTE_NO_KEY);
  533. }
  534. void
  535. CPublicKeyContext::VerifySignature(HCRYPTHASH hHash,
  536. BYTE const *pbSignature,
  537. DWORD dwSigLen,
  538. LPCTSTR sDescription,
  539. DWORD dwFlags)
  540. {
  541. Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
  542. CPublicKey hpubkey(KeyPair()->PublicKey());
  543. if (!hpubkey)
  544. throw scu::OsException(NTE_NO_KEY);
  545. if (!hpubkey->Verify())
  546. throw scu::OsException(ERROR_INVALID_PARAMETER);
  547. //
  548. // Import the Public key to the AUX Provider
  549. //
  550. if (!AuxKeyLoaded())
  551. AuxPublicKey(AsAlignedBlob(0, 0));
  552. ImportToAuxCSP();
  553. //
  554. // Verify the signature in the AUX CSP
  555. //
  556. if (!CryptVerifySignature(hHash, pbSignature, dwSigLen, GetKey(),
  557. sDescription, dwFlags))
  558. throw scu::OsException(GetLastError());
  559. }
  560. // Access
  561. AlignedBlob
  562. CPublicKeyContext::AsAlignedBlob(HCRYPTKEY hDummy,
  563. DWORD dwDummy) const
  564. {
  565. Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
  566. if (hDummy)
  567. throw scu::OsException(ERROR_INVALID_PARAMETER);
  568. CPublicKey hpubkey(KeyPair()->PublicKey());
  569. if (!hpubkey)
  570. throw scu::OsException(NTE_NO_KEY);
  571. ALG_ID ai = (ksSignature == m_ks)
  572. ? CALG_RSA_SIGN
  573. : CALG_RSA_KEYX;
  574. CCard hcard(hsacntr->CardContext()->Card());
  575. if (hcard->IsPKCS11Enabled() && hpubkey->Private())
  576. m_rcryptctx.Login(User);
  577. MsRsaPublicKeyBlob kb(ai,
  578. ::AsBlob(hpubkey->Exponent()),
  579. RawModulus(::AsBlob(hpubkey->Modulus()),
  580. Strength()));
  581. return kb.AsAlignedBlob();
  582. }
  583. Blob
  584. CPublicKeyContext::Certificate()
  585. {
  586. Secured<HAdaptiveContainer> shacntr(m_rcryptctx.AdaptiveContainer());
  587. CKeyPair hkp(KeyPair());
  588. CCertificate hcert(hkp->Certificate());
  589. if (!hcert)
  590. throw scu::OsException(NTE_NOT_FOUND);
  591. if (hcert->Private())
  592. m_rcryptctx.Login(User);
  593. return ::AsBlob(hcert->Value());
  594. }
  595. DWORD
  596. CPublicKeyContext::KeySpec() const
  597. {
  598. return AsKeySpec(m_ks);
  599. }
  600. CPublicKeyContext::StrengthType
  601. CPublicKeyContext::MaxStrength() const
  602. {
  603. return MaxKeyStrength;
  604. }
  605. CPublicKeyContext::StrengthType
  606. CPublicKeyContext::MinStrength() const
  607. {
  608. return MinKeyStrength;
  609. }
  610. BYTE
  611. CPublicKeyContext::Permissions() const
  612. {
  613. Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
  614. VerifyKeyExists();
  615. CKeyPair hkp(KeyPair());
  616. CPublicKey hpubkey(hkp->PublicKey());
  617. CPrivateKey hprikey(hkp->PrivateKey());
  618. BYTE bPermissions = 0;
  619. if (hpubkey)
  620. bPermissions |= hpubkey->Encrypt()
  621. ? CRYPT_ENCRYPT
  622. : 0;
  623. if (hprikey)
  624. {
  625. bPermissions |= hprikey->Decrypt()
  626. ? CRYPT_DECRYPT
  627. : 0;
  628. bPermissions |= hprikey->Exportable()
  629. ? CRYPT_EXPORT
  630. : 0;
  631. bPermissions |= hprikey->Read()
  632. ? CRYPT_READ
  633. : 0;
  634. bPermissions |= hprikey->Modifiable()
  635. ? CRYPT_WRITE
  636. : 0;
  637. }
  638. return bPermissions;
  639. }
  640. CPublicKeyContext::StrengthType
  641. CPublicKeyContext::Strength() const
  642. {
  643. // TO DO: parameterize
  644. return KeyLimits<RsaKey>::cMaxStrength;
  645. }
  646. // Predicates
  647. // Static Variables
  648. /////////////////////////// PROTECTED /////////////////////////////////
  649. // C'tors/D'tors
  650. CPublicKeyContext::CPublicKeyContext(CPublicKeyContext const &rhs,
  651. DWORD const *pdwReserved,
  652. DWORD dwFlags)
  653. : CKeyContext(rhs, pdwReserved, dwFlags),
  654. m_rcryptctx(rhs.m_rcryptctx),
  655. m_ks(rhs.m_ks)
  656. {}
  657. // Operators
  658. // Operations
  659. // Access
  660. // Predicates
  661. bool
  662. CPublicKeyContext::AuxKeyLoaded() const
  663. {
  664. return (0 != m_apabKey.get());
  665. }
  666. // Static Variables
  667. /////////////////////////// PRIVATE /////////////////////////////////
  668. // C'tors/D'tors
  669. // Operators
  670. // Operations
  671. void
  672. CPublicKeyContext::ClearCertificate(CCertificate &rhcert) const
  673. {
  674. rhcert->Delete();
  675. rhcert = 0;
  676. if (AreLogonCredentials())
  677. m_rcryptctx.AdaptiveContainer()->CardContext()->Card()->DefaultContainer(0);
  678. }
  679. void
  680. CPublicKeyContext::OkReplacingCredentials() const
  681. {
  682. UINT uiStyle = MB_OKCANCEL | MB_ICONWARNING;
  683. UINT uiResourceId;
  684. if (AreLogonCredentials())
  685. {
  686. uiResourceId = IDS_REPLACE_LOGON;
  687. uiStyle |= MB_DEFBUTTON2;
  688. }
  689. else
  690. uiResourceId = IDS_REPLACE_CREDENTIALS;
  691. if (m_rcryptctx.GuiEnabled())
  692. {
  693. UINT uiResponse = PromptUser(m_rcryptctx.Window(),
  694. uiResourceId, uiStyle);
  695. switch (uiResponse)
  696. {
  697. case IDCANCEL:
  698. throw scu::OsException(ERROR_CANCELLED);
  699. break;
  700. case IDOK:
  701. break;
  702. default:
  703. throw scu::OsException(ERROR_INTERNAL_ERROR);
  704. break;
  705. };
  706. }
  707. else
  708. throw scu::OsException(NTE_EXISTS);
  709. }
  710. void
  711. CPublicKeyContext::PrepToStoreKey(CKeyPair &rhkp) const
  712. {
  713. CContainer hcntr(m_rcryptctx.AdaptiveContainer()->TheCContainer());
  714. // To the CCI, a key pair always exists, but this call means the
  715. // key pair is not empty.
  716. if (hcntr->KeyPairExists(m_ks))
  717. OkReplacingCredentials();
  718. rhkp = hcntr->GetKeyPair(m_ks);
  719. CPublicKey hpubkey(rhkp->PublicKey());
  720. CPrivateKey hprikey(rhkp->PrivateKey());
  721. CCertificate hcert(rhkp->Certificate());
  722. CCard hcard(hcntr->Card());
  723. if (hcard->IsProtectedMode() ||
  724. (hcard->IsPKCS11Enabled() &&
  725. ((hpubkey && hpubkey->Private()) ||
  726. (hprikey && hprikey->Private()) || // always private?
  727. (hcert && hcert->Private()))))
  728. m_rcryptctx.Login(User);
  729. if (hpubkey)
  730. {
  731. hpubkey->Delete();
  732. hpubkey = 0;
  733. }
  734. if (hprikey)
  735. {
  736. hprikey->Delete();
  737. hprikey = 0;
  738. }
  739. if (hcert)
  740. ClearCertificate(hcert);
  741. }
  742. Blob
  743. CPublicKeyContext::Pkcs11CredentialId(Blob const &rbModulus) const
  744. {
  745. // Hash the modulus
  746. AuxHash ah(AuxContext(AuxProvider()), CALG_MD5);
  747. return ah.Value(rbModulus);
  748. }
  749. Blob
  750. CPublicKeyContext::Pkcs11Id(Blob const &rbRawModulus) const
  751. {
  752. AuxHash ah(AuxContext(AuxProvider()), CALG_SHA1);
  753. return ah.Value(rbRawModulus);
  754. }
  755. // Set PKCS#11 attributes that are derived from the certificate
  756. void
  757. CPublicKeyContext::SetCertDerivedPkcs11Attributes(CKeyPair const &rhkp,
  758. Pkcs11Attributes &rPkcsAttr)
  759. const
  760. {
  761. string sLabel(rPkcsAttr.Label());
  762. string sSubject(rPkcsAttr.Subject());
  763. Blob bRawModulus(rPkcsAttr.RawModulus());
  764. Blob Id(Pkcs11Id(bRawModulus));
  765. CPublicKey hpubkey(rhkp->PublicKey());
  766. if (hpubkey)
  767. {
  768. hpubkey->ID(::AsString(Id));
  769. hpubkey->Label(sLabel);
  770. hpubkey->Subject(sSubject);
  771. }
  772. CPrivateKey hprikey(rhkp->PrivateKey());
  773. if (hprikey)
  774. {
  775. hprikey->ID(::AsString(Id));
  776. hprikey->Label(sLabel);
  777. hprikey->Subject(sSubject);
  778. }
  779. CCertificate hcert(rhkp->Certificate());
  780. hcert->ID(AsString(Id));
  781. hcert->Label(sLabel);
  782. hcert->Subject(sSubject);
  783. hcert->Issuer(::AsString(rPkcsAttr.Issuer()));
  784. hcert->Serial(::AsString(rPkcsAttr.SerialNumber()));
  785. hcert->Modifiable(true);
  786. hcert->CredentialID(::AsString(Pkcs11CredentialId(rPkcsAttr.Modulus())));
  787. Blob ContainerId(rPkcsAttr.ContainerId());
  788. m_rcryptctx.AdaptiveContainer()->TheCContainer()->ID(::AsString(ContainerId));
  789. }
  790. void
  791. CPublicKeyContext::SetAttributes(CPublicKey &rhpubkey,
  792. CPrivateKey &rhprikey,
  793. bool fLocal,
  794. bool fExportable) const
  795. {
  796. // TO DO: A kludge. The old CSP format (V1) doesn't support
  797. // setting key attributes but there isn't an easy way to tell
  798. // which format is being used. (Should have some call to get the
  799. // format characteristics). Since CCI's V1 throws
  800. // ccNotImplemented when calling one of the unsupported routines,
  801. // a try/catch is used to ignore that exception to assume the V1
  802. // format is used.
  803. bool fContinueSettingAttributes = true;
  804. try
  805. {
  806. // The public or the private key could by nil,
  807. // so do both.
  808. if (rhpubkey)
  809. rhpubkey->Encrypt(true);
  810. if (rhprikey)
  811. rhprikey->Decrypt(true);
  812. }
  813. catch (cci::Exception &rExc)
  814. {
  815. if (ccNotImplemented == rExc.Cause())
  816. fContinueSettingAttributes = false;
  817. else
  818. throw;
  819. }
  820. if (fContinueSettingAttributes)
  821. {
  822. if (rhpubkey)
  823. {
  824. rhpubkey->Derive(true);
  825. rhpubkey->Local(fLocal);
  826. rhpubkey->Modifiable(true);
  827. rhpubkey->Verify(true);
  828. }
  829. if (rhprikey)
  830. {
  831. rhprikey->Local(fLocal);
  832. rhprikey->Modifiable(true);
  833. rhprikey->Sign(true);
  834. rhprikey->Exportable(fExportable);
  835. rhprikey->Read(false);
  836. }
  837. if (rhpubkey && rhpubkey->Card()->IsPKCS11Enabled())
  838. SetPkcs11Attributes(rhpubkey, rhprikey);
  839. }
  840. }
  841. void
  842. CPublicKeyContext::SetPkcs11Attributes(CPublicKey &rhpubkey,
  843. CPrivateKey &rhprikey) const
  844. {
  845. Blob bBEModulus(::AsBlob(rhpubkey->Modulus()));
  846. reverse(bBEModulus.begin(), bBEModulus.end()); // make big endian
  847. string sCredentialId(::AsString(Pkcs11CredentialId(bBEModulus)));
  848. rhpubkey->CKInvisible(false);
  849. rhpubkey->CredentialID(sCredentialId);
  850. rhpubkey->VerifyRecover(true);
  851. rhpubkey->Wrap(true);
  852. if (rhprikey)
  853. {
  854. rhprikey->CredentialID(sCredentialId);
  855. rhprikey->Derive(true);
  856. rhprikey->SignRecover(true);
  857. rhprikey->Unwrap(true);
  858. rhprikey->NeverExportable(!rhprikey->Exportable());
  859. rhprikey->NeverRead(!rhprikey->Read());
  860. rhprikey->Modulus(rhpubkey->Modulus());
  861. rhprikey->PublicExponent(rhpubkey->Exponent());
  862. }
  863. }
  864. // Access
  865. CKeyPair
  866. CPublicKeyContext::KeyPair() const
  867. {
  868. return m_rcryptctx.AdaptiveContainer()->TheCContainer()->GetKeyPair(m_ks);
  869. }
  870. // Predicates
  871. bool
  872. CPublicKeyContext::AreLogonCredentials() const
  873. {
  874. HAdaptiveContainer hacntr(m_rcryptctx.AdaptiveContainer());
  875. return (ksExchange == m_ks) &&
  876. (hacntr->TheCContainer() ==
  877. hacntr->CardContext()->Card()->DefaultContainer());
  878. }
  879. // Static Variables