// PubKeyCtx.cpp -- definition of CPublicKeyContext // (c) Copyright Schlumberger Technology Corp., unpublished work, created // 2000. This computer program includes Confidential, Proprietary // Information and is a Trade Secret of Schlumberger Technology Corp. All // use, disclosure, and/or reproduction is prohibited unless authorized // in writing. All Rights Reserved. #include "stdafx.h" // required by GUI header files #include #include #include #include #include #include #include #include "CryptCtx.h" #include "HashCtx.h" #include "RsaKey.h" #include "EncodedMsg.h" #include "Pkcs11Attr.h" #include "AuxHash.h" #include "RsaKPGen.h" #include "Secured.h" #include "StResource.h" #include "PromptUser.h" #include "PublicKeyHelper.h" #include "PubKeyCtx.h" #include "AlignedBlob.h" #include "CertificateExtensions.h" using namespace std; using namespace scu; using namespace cci; /////////////////////////// LOCAL/HELPER ///////////////////////////////// namespace { DWORD PkcsToDword( IN OUT LPBYTE pbPkcs, IN DWORD lth) { LPBYTE pbBegin = pbPkcs; LPBYTE pbEnd = &pbPkcs[lth - 1]; DWORD length = lth; while (pbBegin < pbEnd) { BYTE tmp = *pbBegin; *pbBegin++ = *pbEnd; *pbEnd-- = tmp; } for (pbEnd = &pbPkcs[lth - 1]; 0 == *pbEnd; pbEnd -= 1) length -= 1; return length; } KeySpec AsKeySpec(ALG_ID algid) { KeySpec ks; switch(algid) { case AT_KEYEXCHANGE: ks = ksExchange; break; case AT_SIGNATURE: ks = ksSignature; break; default: throw scu::OsException(NTE_BAD_KEY); } return ks; } ALG_ID AsKeySpec(KeySpec ks) { ALG_ID algid; switch(ks) { case ksExchange: algid = AT_KEYEXCHANGE; break; case ksSignature: algid = AT_SIGNATURE; break; default: throw scu::OsException(NTE_FAIL); // internal error break; } return algid; } string AsString(unsigned char const *p, size_t cLength) { return string(reinterpret_cast(p), cLength); } // make a "raw modulus" from a modulus by padding with zeroes to meet // specified strength. The modulus blob is assumed to represent an // unsigned integer in little endian format whose size less than or // equal to strength in octets. Blob RawModulus(Blob const &rbTrimmedModulus, RsaKey::StrengthType strength) { RsaKey::OctetLengthType const cRawLength = strength / numeric_limits::digits; if (cRawLength < rbTrimmedModulus.length()) throw scu::OsException(NTE_BAD_DATA); Blob bRawModulus(rbTrimmedModulus); bRawModulus.append(cRawLength - rbTrimmedModulus.length(), 0); return bRawModulus; } /*++ ExtractTag: This routine extracts a tag from an ASN.1 BER stream. Arguments: pbSrc supplies the buffer containing the ASN.1 stream. pdwTag receives the tag. Return Value: The number of bytes extracted from the stream. Errors are thrown as DWORD status codes. Author: Doug Barlow (dbarlow) 10/9/1995 Doug Barlow (dbarlow) 7/31/1997 --*/ DWORD ExtractTag(BYTE const *pbSrc, LPDWORD pdwTag, LPBOOL pfConstr) { LONG lth = 0; DWORD tagw; BYTE tagc, cls; tagc = pbSrc[lth++]; cls = tagc & 0xc0; // Top 2 bits. if (NULL != pfConstr) *pfConstr = (0 != (tagc & 0x20)); tagc &= 0x1f; // Bottom 5 bits. if (31 > tagc) tagw = tagc; else { tagw = 0; do { if (0 != (tagw & 0xfe000000)) throw scu::OsException(ERROR_ARITHMETIC_OVERFLOW); tagc = pbSrc[lth++]; tagw <<= 7; tagw |= tagc & 0x7f; } while (0 != (tagc & 0x80)); } *pdwTag = tagw | (cls << 24); return lth; } /*++ ExtractLength: This routine extracts a length from an ASN.1 BER stream. If the length is indefinite, this routine recurses to figure out the real length. A flag as to whether or not the encoding was indefinite is optionally returned. Arguments: pbSrc supplies the buffer containing the ASN.1 stream. pdwLen receives the len. pfIndefinite, if not NULL, receives a flag indicating whether or not the encoding was indefinite. Return Value: The number of bytes extracted from the stream. Errors are thrown as DWORD status codes. Author: Doug Barlow (dbarlow) 10/9/1995 Doug Barlow (dbarlow) 7/31/1997 --*/ DWORD ExtractLength(BYTE const *pbSrc, LPDWORD pdwLen, LPBOOL pfIndefinite) { DWORD ll, rslt, lth, lTotal = 0; BOOL fInd = FALSE; // // Extract the Length. // if (0 == (pbSrc[lTotal] & 0x80)) { // // Short form encoding. // rslt = pbSrc[lTotal++]; } else { rslt = 0; ll = pbSrc[lTotal++] & 0x7f; if (0 != ll) { // // Long form encoding. // for (; 0 < ll; ll -= 1) { if (0 != (rslt & 0xff000000)) throw scu::OsException(ERROR_ARITHMETIC_OVERFLOW); rslt = (rslt << 8) | pbSrc[lTotal]; lTotal += 1; } } else { DWORD ls = lTotal; // // Indefinite encoding. // fInd = TRUE; while ((0 != pbSrc[ls]) || (0 != pbSrc[ls + 1])) { // Skip over the Type. if (31 > (pbSrc[ls] & 0x1f)) ls += 1; else while (0 != (pbSrc[++ls] & 0x80)); // Empty loop body. lth = ExtractLength(&pbSrc[ls], &ll, NULL); ls += lth + ll; } rslt = ls - lTotal; } } // // Supply the caller with what we've learned. // *pdwLen = rslt; if (NULL != pfIndefinite) *pfIndefinite = fInd; return lTotal; } /*++ Asn1Length: This routine parses a given ASN.1 buffer and returns the complete length of the encoding, including the leading tag and length bytes. Arguments: pbData supplies the buffer to be parsed. Return Value: The length of the entire ASN.1 buffer. Throws: Overflow errors are thrown as DWORD status codes. Author: Doug Barlow (dbarlow) 7/31/1997 --*/ DWORD Asn1Length(LPCBYTE pbAsn1) { DWORD dwTagLen, dwLenLen, dwValLen; DWORD dwTag; dwTagLen = ExtractTag(pbAsn1, &dwTag, NULL); dwLenLen = ExtractLength(&pbAsn1[dwTagLen], &dwValLen, NULL); return dwTagLen + dwLenLen + dwValLen; } } // namespace /////////////////////////// PUBLIC ///////////////////////////////// // Types // C'tors/D'tors CPublicKeyContext::CPublicKeyContext(HCRYPTPROV hProv, CryptContext &rcryptctx, ALG_ID algid, bool fVerifyKeyExists) : CKeyContext(hProv, KT_PUBLICKEY), m_rcryptctx(rcryptctx), m_ks(AsKeySpec(algid)) { // Make sure the key exists on the card if (fVerifyKeyExists) VerifyKeyExists(); } CPublicKeyContext::~CPublicKeyContext() {} // Operators // Operations auto_ptr CPublicKeyContext::Clone(DWORD const *pdwReserved, DWORD dwFlags) const { return auto_ptr(new CPublicKeyContext(*this, pdwReserved, dwFlags)); } void CPublicKeyContext::AuxPublicKey(AlignedBlob const &rabMsPublicKey) { ClearAuxPublicKey(); m_apabKey = auto_ptr(new AlignedBlob(rabMsPublicKey)); } void CPublicKeyContext::ClearAuxPublicKey() { m_apabKey = auto_ptr(0); if (m_hKey) { if (!CryptDestroyKey(m_hKey)) throw OsException(GetLastError()); } } void CPublicKeyContext::Certificate(BYTE *pbData) { bool fError = false; DWORD dwErrorCode = NO_ERROR; if (!pbData) throw scu::OsException(ERROR_INVALID_PARAMETER); DWORD dwAsn1Len = Asn1Length(pbData); if (0 == dwAsn1Len) throw scu::OsException(ERROR_INVALID_PARAMETER); Blob blbCert(pbData, dwAsn1Len); Pkcs11Attributes PkcsAttr(blbCert, AuxProvider()); Secured hsacntr(m_rcryptctx.AdaptiveContainer()); CKeyPair hkp(KeyPair()); CPublicKey hpubkey(hkp->PublicKey()); // Verify cert's modulus matches the public key's, if it exists CCard hcard(hsacntr->CardContext()->Card()); bool fLoggedIn = false; if (hpubkey) { if (hcard->IsPKCS11Enabled() && hpubkey->Private()) { m_rcryptctx.Login(User); fLoggedIn = true; } Blob bKeyModulus(::AsBlob(hpubkey->Modulus())); Blob bTrimmedModulus(bKeyModulus); // interoperability with V1 TrimExtraZeroes(bTrimmedModulus); Blob bCertModulus(PkcsAttr.Modulus()); reverse(bCertModulus.begin(), bCertModulus.end()); // little endian if (0 != bTrimmedModulus.compare(bCertModulus)) throw scu::OsException(NTE_BAD_PUBLIC_KEY); } CCertificate hcert(hkp->Certificate()); if (hcert) OkReplacingCredentials(); if (!fLoggedIn) { bool fDoLogin = hcard->IsProtectedMode(); // retrieve the private key handle only if PKCS11 enabled if (!fDoLogin && hcard->IsPKCS11Enabled()) { // private key is checked now for login in preparation for // setting the PKCS11 attributes after the cert is stored CPrivateKey hprikey(hkp->PrivateKey()); fDoLogin = ((hprikey && hprikey->Private()) || // always private? (hcert && hcert->Private())); } if (fDoLogin) { m_rcryptctx.Login(User); fLoggedIn = true; } } if (hcert) ClearCertificate(hcert); hcert = CCertificate(hcard); hkp->Certificate(hcert); hcert->Value(AsString(blbCert)); if (hcard->IsPKCS11Enabled()) SetCertDerivedPkcs11Attributes(hkp, PkcsAttr); CertificateExtensions CertExts(blbCert); if (CertExts.HasEKU(szOID_KP_SMARTCARD_LOGON) || CertExts.HasEKU(szOID_ENROLLMENT_AGENT)) hcard->DefaultContainer(hsacntr->TheCContainer()); } Blob CPublicKeyContext::Decrypt(Blob const &rCipher) { Secured hsacntr(m_rcryptctx.AdaptiveContainer()); // TO DO: Is the explicit check really necessary, or can we catch // an exception from the CCI/IOP to indicate the key does not exist? CPrivateKey prikey(KeyPair()->PrivateKey()); if (!prikey) throw scu::OsException(NTE_NO_KEY); m_rcryptctx.Login(User); return ::AsBlob(prikey->InternalAuth(AsString(rCipher))); } void CPublicKeyContext::Decrypt(HCRYPTHASH hAuxHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen) { throw scu::OsException(ERROR_NOT_SUPPORTED); } void CPublicKeyContext::Generate(ALG_ID AlgoId, DWORD dwFlags) { RsaKey::StrengthType strength; strength = HIWORD(dwFlags); if (0 == strength) strength = MaxStrength(); // default strength else { if ((MaxStrength() < strength) || (MinStrength() > strength)) throw scu::OsException(ERROR_INVALID_PARAMETER); } Secured hsacntr(m_rcryptctx.AdaptiveContainer()); CKeyPair hkp; PrepToStoreKey(hkp); RsaKeyPairGenerator GenKey(hkp->Card(), strength); m_rcryptctx.Login(User); // to create private key pair pr(GenKey()); CPrivateKey hprikey(pr.first); CPublicKey hpubkey(pr.second); SetAttributes(hpubkey, hprikey, GenKey.OnCard(), (dwFlags & CRYPT_EXPORTABLE) != 0); hkp->PrivateKey(hprikey); hkp->PublicKey(hpubkey); ClearAuxPublicKey(); } void CPublicKeyContext::ImportPrivateKey(MsRsaPrivateKeyBlob const &rmsprikb, bool fExportable) { Secured hsacntr(m_rcryptctx.AdaptiveContainer()); CKeyPair hkp(hsacntr->TheCContainer()->GetKeyPair(m_ks)); CPrivateKey hprikey(hkp->PrivateKey()); CCard hcard(hkp->Card()); m_rcryptctx.Login(User); if (!hprikey) hprikey = CPrivateKey(hkp->Card()); hprikey->Value(*(AsPCciPrivateKeyBlob(rmsprikb).get())); SetAttributes(CPublicKey(), hprikey, false, fExportable); hkp->PrivateKey(hprikey); } void CPublicKeyContext::ImportPublicKey(MsRsaPublicKeyBlob const &rmspubkb) { Secured hsacntr(m_rcryptctx.AdaptiveContainer()); CKeyPair hkp(hsacntr->TheCContainer()->GetKeyPair(m_ks)); CPublicKey hpubkey(hkp->PublicKey()); CCard hcard(hkp->Card()); if (hcard->IsProtectedMode() || (hcard->IsPKCS11Enabled() && (hpubkey && hpubkey->Private()))) m_rcryptctx.Login(User); if (hpubkey) { hpubkey->Delete(); hpubkey = 0; } hpubkey = CPublicKey(AsPublicKey(Blob(rmspubkb.Modulus(), rmspubkb.Length()), rmspubkb.PublicExponent(), hcard)); SetAttributes(hpubkey, CPrivateKey(), false, true); hkp->PublicKey(hpubkey); AuxPublicKey(rmspubkb.AsAlignedBlob()); } void CPublicKeyContext::ImportToAuxCSP() { if (!m_hKey) { if (!m_apabKey.get()) throw OsException(NTE_NO_KEY); if (!CryptImportKey(AuxProvider(), m_apabKey->Data(), m_apabKey->Length(), 0, 0, &m_hKey)) throw scu::OsException(GetLastError()); } } void CPublicKeyContext::Permissions(BYTE bPermissions) { if (bPermissions & ~(CRYPT_DECRYPT | CRYPT_ENCRYPT | CRYPT_EXPORT | CRYPT_READ | CRYPT_WRITE)) throw scu::OsException(ERROR_INVALID_PARAMETER); Secured hsacntr(m_rcryptctx.AdaptiveContainer()); CKeyPair hkp(KeyPair()); CPublicKey hpubkey(hkp->PublicKey()); CPrivateKey hprikey(hkp->PrivateKey()); m_rcryptctx.Login(User); if (hprikey) { hprikey->Decrypt((CRYPT_DECRYPT & bPermissions) != 0); CCard hcard(hsacntr->CardContext()->Card()); bool PKCS11Enabled = hcard->IsPKCS11Enabled(); bool fExportable = (CRYPT_EXPORT & bPermissions) != 0; if (PKCS11Enabled) hprikey->NeverExportable(!fExportable); hprikey->Exportable(fExportable); hprikey->Modifiable((CRYPT_WRITE & bPermissions) != 0); bool fReadable = (CRYPT_READ & bPermissions) != 0; if (PKCS11Enabled) hprikey->NeverRead(!fReadable); hprikey->Read(fReadable); } if (hpubkey) { hpubkey->Encrypt((CRYPT_ENCRYPT & bPermissions) != 0); hpubkey->Modifiable((CRYPT_WRITE & bPermissions) != 0); } } // TO DO: Sign is an operation that's performed with the private key, // not the public key. Make Sign an operation on a PrivateKeyContext. // string Blob CPublicKeyContext::Sign(CHashContext *pHash, bool fNoHashOid) { Blob Message(fNoHashOid ? pHash->Value() : pHash->EncodedValue()); // TO DO: When CCI takes object parameters as references, // em can be const EncodedMessage em(Message, RsaKey::ktPrivate, Strength() / numeric_limits::digits); Blob blob(em.Value()); reverse(blob.begin(), blob.end()); // convert to big endian Secured hsacntr(m_rcryptctx.AdaptiveContainer()); // TO DO: Is the explicit check really necessary, or can we catch // an exception from the CCI/IOP to indicate the key does not exist? CPrivateKey hprikey(KeyPair()->PrivateKey()); if (!hprikey) throw scu::OsException(NTE_NO_KEY); m_rcryptctx.Login(User); if (!hprikey->Sign()) throw scu::OsException(ERROR_INVALID_PARAMETER); return ::AsBlob(hprikey->InternalAuth(AsString(blob))); } void CPublicKeyContext::VerifyKeyExists() const { Secured hsacntr(m_rcryptctx.AdaptiveContainer()); CKeyPair hkp(KeyPair()); if (!hkp->PublicKey() && !hkp->PrivateKey()) throw scu::OsException(NTE_NO_KEY); } void CPublicKeyContext::VerifySignature(HCRYPTHASH hHash, BYTE const *pbSignature, DWORD dwSigLen, LPCTSTR sDescription, DWORD dwFlags) { Secured hsacntr(m_rcryptctx.AdaptiveContainer()); CPublicKey hpubkey(KeyPair()->PublicKey()); if (!hpubkey) throw scu::OsException(NTE_NO_KEY); if (!hpubkey->Verify()) throw scu::OsException(ERROR_INVALID_PARAMETER); // // Import the Public key to the AUX Provider // if (!AuxKeyLoaded()) AuxPublicKey(AsAlignedBlob(0, 0)); ImportToAuxCSP(); // // Verify the signature in the AUX CSP // if (!CryptVerifySignature(hHash, pbSignature, dwSigLen, GetKey(), sDescription, dwFlags)) throw scu::OsException(GetLastError()); } // Access AlignedBlob CPublicKeyContext::AsAlignedBlob(HCRYPTKEY hDummy, DWORD dwDummy) const { Secured hsacntr(m_rcryptctx.AdaptiveContainer()); if (hDummy) throw scu::OsException(ERROR_INVALID_PARAMETER); CPublicKey hpubkey(KeyPair()->PublicKey()); if (!hpubkey) throw scu::OsException(NTE_NO_KEY); ALG_ID ai = (ksSignature == m_ks) ? CALG_RSA_SIGN : CALG_RSA_KEYX; CCard hcard(hsacntr->CardContext()->Card()); if (hcard->IsPKCS11Enabled() && hpubkey->Private()) m_rcryptctx.Login(User); MsRsaPublicKeyBlob kb(ai, ::AsBlob(hpubkey->Exponent()), RawModulus(::AsBlob(hpubkey->Modulus()), Strength())); return kb.AsAlignedBlob(); } Blob CPublicKeyContext::Certificate() { Secured shacntr(m_rcryptctx.AdaptiveContainer()); CKeyPair hkp(KeyPair()); CCertificate hcert(hkp->Certificate()); if (!hcert) throw scu::OsException(NTE_NOT_FOUND); if (hcert->Private()) m_rcryptctx.Login(User); return ::AsBlob(hcert->Value()); } DWORD CPublicKeyContext::KeySpec() const { return AsKeySpec(m_ks); } CPublicKeyContext::StrengthType CPublicKeyContext::MaxStrength() const { return MaxKeyStrength; } CPublicKeyContext::StrengthType CPublicKeyContext::MinStrength() const { return MinKeyStrength; } BYTE CPublicKeyContext::Permissions() const { Secured hsacntr(m_rcryptctx.AdaptiveContainer()); VerifyKeyExists(); CKeyPair hkp(KeyPair()); CPublicKey hpubkey(hkp->PublicKey()); CPrivateKey hprikey(hkp->PrivateKey()); BYTE bPermissions = 0; if (hpubkey) bPermissions |= hpubkey->Encrypt() ? CRYPT_ENCRYPT : 0; if (hprikey) { bPermissions |= hprikey->Decrypt() ? CRYPT_DECRYPT : 0; bPermissions |= hprikey->Exportable() ? CRYPT_EXPORT : 0; bPermissions |= hprikey->Read() ? CRYPT_READ : 0; bPermissions |= hprikey->Modifiable() ? CRYPT_WRITE : 0; } return bPermissions; } CPublicKeyContext::StrengthType CPublicKeyContext::Strength() const { // TO DO: parameterize return KeyLimits::cMaxStrength; } // Predicates // Static Variables /////////////////////////// PROTECTED ///////////////////////////////// // C'tors/D'tors CPublicKeyContext::CPublicKeyContext(CPublicKeyContext const &rhs, DWORD const *pdwReserved, DWORD dwFlags) : CKeyContext(rhs, pdwReserved, dwFlags), m_rcryptctx(rhs.m_rcryptctx), m_ks(rhs.m_ks) {} // Operators // Operations // Access // Predicates bool CPublicKeyContext::AuxKeyLoaded() const { return (0 != m_apabKey.get()); } // Static Variables /////////////////////////// PRIVATE ///////////////////////////////// // C'tors/D'tors // Operators // Operations void CPublicKeyContext::ClearCertificate(CCertificate &rhcert) const { rhcert->Delete(); rhcert = 0; if (AreLogonCredentials()) m_rcryptctx.AdaptiveContainer()->CardContext()->Card()->DefaultContainer(0); } void CPublicKeyContext::OkReplacingCredentials() const { UINT uiStyle = MB_OKCANCEL | MB_ICONWARNING; UINT uiResourceId; if (AreLogonCredentials()) { uiResourceId = IDS_REPLACE_LOGON; uiStyle |= MB_DEFBUTTON2; } else uiResourceId = IDS_REPLACE_CREDENTIALS; if (m_rcryptctx.GuiEnabled()) { UINT uiResponse = PromptUser(m_rcryptctx.Window(), uiResourceId, uiStyle); switch (uiResponse) { case IDCANCEL: throw scu::OsException(ERROR_CANCELLED); break; case IDOK: break; default: throw scu::OsException(ERROR_INTERNAL_ERROR); break; }; } else throw scu::OsException(NTE_EXISTS); } void CPublicKeyContext::PrepToStoreKey(CKeyPair &rhkp) const { CContainer hcntr(m_rcryptctx.AdaptiveContainer()->TheCContainer()); // To the CCI, a key pair always exists, but this call means the // key pair is not empty. if (hcntr->KeyPairExists(m_ks)) OkReplacingCredentials(); rhkp = hcntr->GetKeyPair(m_ks); CPublicKey hpubkey(rhkp->PublicKey()); CPrivateKey hprikey(rhkp->PrivateKey()); CCertificate hcert(rhkp->Certificate()); CCard hcard(hcntr->Card()); if (hcard->IsProtectedMode() || (hcard->IsPKCS11Enabled() && ((hpubkey && hpubkey->Private()) || (hprikey && hprikey->Private()) || // always private? (hcert && hcert->Private())))) m_rcryptctx.Login(User); if (hpubkey) { hpubkey->Delete(); hpubkey = 0; } if (hprikey) { hprikey->Delete(); hprikey = 0; } if (hcert) ClearCertificate(hcert); } Blob CPublicKeyContext::Pkcs11CredentialId(Blob const &rbModulus) const { // Hash the modulus AuxHash ah(AuxContext(AuxProvider()), CALG_MD5); return ah.Value(rbModulus); } Blob CPublicKeyContext::Pkcs11Id(Blob const &rbRawModulus) const { AuxHash ah(AuxContext(AuxProvider()), CALG_SHA1); return ah.Value(rbRawModulus); } // Set PKCS#11 attributes that are derived from the certificate void CPublicKeyContext::SetCertDerivedPkcs11Attributes(CKeyPair const &rhkp, Pkcs11Attributes &rPkcsAttr) const { string sLabel(rPkcsAttr.Label()); string sSubject(rPkcsAttr.Subject()); Blob bRawModulus(rPkcsAttr.RawModulus()); Blob Id(Pkcs11Id(bRawModulus)); CPublicKey hpubkey(rhkp->PublicKey()); if (hpubkey) { hpubkey->ID(::AsString(Id)); hpubkey->Label(sLabel); hpubkey->Subject(sSubject); } CPrivateKey hprikey(rhkp->PrivateKey()); if (hprikey) { hprikey->ID(::AsString(Id)); hprikey->Label(sLabel); hprikey->Subject(sSubject); } CCertificate hcert(rhkp->Certificate()); hcert->ID(AsString(Id)); hcert->Label(sLabel); hcert->Subject(sSubject); hcert->Issuer(::AsString(rPkcsAttr.Issuer())); hcert->Serial(::AsString(rPkcsAttr.SerialNumber())); hcert->Modifiable(true); hcert->CredentialID(::AsString(Pkcs11CredentialId(rPkcsAttr.Modulus()))); Blob ContainerId(rPkcsAttr.ContainerId()); m_rcryptctx.AdaptiveContainer()->TheCContainer()->ID(::AsString(ContainerId)); } void CPublicKeyContext::SetAttributes(CPublicKey &rhpubkey, CPrivateKey &rhprikey, bool fLocal, bool fExportable) const { // TO DO: A kludge. The old CSP format (V1) doesn't support // setting key attributes but there isn't an easy way to tell // which format is being used. (Should have some call to get the // format characteristics). Since CCI's V1 throws // ccNotImplemented when calling one of the unsupported routines, // a try/catch is used to ignore that exception to assume the V1 // format is used. bool fContinueSettingAttributes = true; try { // The public or the private key could by nil, // so do both. if (rhpubkey) rhpubkey->Encrypt(true); if (rhprikey) rhprikey->Decrypt(true); } catch (cci::Exception &rExc) { if (ccNotImplemented == rExc.Cause()) fContinueSettingAttributes = false; else throw; } if (fContinueSettingAttributes) { if (rhpubkey) { rhpubkey->Derive(true); rhpubkey->Local(fLocal); rhpubkey->Modifiable(true); rhpubkey->Verify(true); } if (rhprikey) { rhprikey->Local(fLocal); rhprikey->Modifiable(true); rhprikey->Sign(true); rhprikey->Exportable(fExportable); rhprikey->Read(false); } if (rhpubkey && rhpubkey->Card()->IsPKCS11Enabled()) SetPkcs11Attributes(rhpubkey, rhprikey); } } void CPublicKeyContext::SetPkcs11Attributes(CPublicKey &rhpubkey, CPrivateKey &rhprikey) const { Blob bBEModulus(::AsBlob(rhpubkey->Modulus())); reverse(bBEModulus.begin(), bBEModulus.end()); // make big endian string sCredentialId(::AsString(Pkcs11CredentialId(bBEModulus))); rhpubkey->CKInvisible(false); rhpubkey->CredentialID(sCredentialId); rhpubkey->VerifyRecover(true); rhpubkey->Wrap(true); if (rhprikey) { rhprikey->CredentialID(sCredentialId); rhprikey->Derive(true); rhprikey->SignRecover(true); rhprikey->Unwrap(true); rhprikey->NeverExportable(!rhprikey->Exportable()); rhprikey->NeverRead(!rhprikey->Read()); rhprikey->Modulus(rhpubkey->Modulus()); rhprikey->PublicExponent(rhpubkey->Exponent()); } } // Access CKeyPair CPublicKeyContext::KeyPair() const { return m_rcryptctx.AdaptiveContainer()->TheCContainer()->GetKeyPair(m_ks); } // Predicates bool CPublicKeyContext::AreLogonCredentials() const { HAdaptiveContainer hacntr(m_rcryptctx.AdaptiveContainer()); return (ksExchange == m_ks) && (hacntr->TheCContainer() == hacntr->CardContext()->Card()->DefaultContainer()); } // Static Variables