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.

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