PKIFCAPI2.cpp

Go to the documentation of this file.
00001 
00009 #include "PKIFCAPI2.h"
00010 #include "ToolkitUtils.h"
00011 #include "CAPIUtils.h" //added here 7/29/2004
00012 #include "PKIFCAPICredential2.h"
00013 #include "PKIFCAPICryptContext2.h"
00014 
00015 #include "PKIFCryptoErrors.h"
00016 #include "PKIFCAPIErrors.h"
00017 #include "PKIFCryptoException.h"
00018 
00019 #include "SubjectPublicKeyInfo.h"
00020 #include "Certificate.h"
00021 #include "KeyUsage.h"
00022 
00023 #include "boost/numeric/conversion/cast.hpp"
00024 
00025 using boost::numeric_cast;
00026 using boost::bad_numeric_cast;
00027 
00028 #include <atlbase.h>
00029 #include <sstream>
00030 using namespace std;
00031 
00032 BYTESREVERSED g_bytesReversed = UNSET;
00033 
00034 //#include "PKIFCAPICredential2.h"
00035 //#include "PKIFCAPICryptContext2.h"
00036 
00038 struct CPKIFCAPI2Impl
00039 {
00040     CPKIFCAPI2* m_parent;
00048     CPKIFCAPI2Impl ()
00049     {
00050         m_parent = NULL;
00051     }
00059     CPKIFCAPI2Impl (CPKIFCAPI2  *p) 
00060     {
00061         m_parent = p;
00062     }
00063     HCRYPTPROV m_hProv;
00064     HCERTSTORE m_hCertStore;
00065     DWORD m_flags;
00066 
00067     char* m_provider;
00068     int m_sysStoRegLoc; 
00069     int m_provType;
00070 
00071     
00072 
00073     void GetContext();
00074     bool CertMatchesCurContext(PCCERT_CONTEXT cert) const;
00075     BYTESREVERSED CheckReversed(HCRYPTKEY * key);
00076     CPKIFCAPICredential2* MakeCAPICredential(PCCERT_CONTEXT cert) const;
00077 };
00079 
00088 CPKIFCAPI2::CPKIFCAPI2(
00090     const char* provider,
00092     int provType,
00094     int sysStoRegLoc)
00095     :m_impl (new CPKIFCAPI2Impl), IPKIFCAPISource(sysStoRegLoc, NULL)
00096 {
00097     LOG_STRING_DEBUG("CPKIFCAPI::CPKIFCAPI(void)", TOOLKIT_CRYPTO_CAPI, 0, this);
00098 
00099     m_impl->m_parent = this;
00100     m_impl->m_provType = provType;
00101     m_impl->m_sysStoRegLoc = sysStoRegLoc;
00102     m_impl->m_provider = NULL;
00103 
00104     size_t len = 0;
00105     if(provider)
00106     {
00107         len = strlen(provider);
00108         m_impl->m_provider = new char[len + 1];
00109 
00110         //reviewed 4/23/2006
00111         strcpy(m_impl->m_provider, provider);
00112     }
00113 
00114     m_impl->m_hProv = NULL;
00115     m_impl->m_hCertStore = NULL;
00116 
00117     //added 9/9/03 to facilitate usage from a service targeting local machine store
00118     m_impl->m_flags = 0;
00119     if(CERT_SYSTEM_STORE_LOCAL_MACHINE == m_impl->m_sysStoRegLoc)
00120         m_impl->m_flags = CRYPT_MACHINE_KEYSET;
00121 }
00129 CPKIFCAPI2::~CPKIFCAPI2(void)
00130 {
00131     LOG_STRING_DEBUG("CPKIFCAPI::~CPKIFCAPI(void)", TOOLKIT_CRYPTO_CAPI, 0, this);
00132 
00133     if(m_impl->m_provider)
00134         delete[] m_impl->m_provider;
00135 
00136     if(NULL != m_impl->m_hProv)
00137     {
00138         CryptReleaseContext(m_impl->m_hProv, 0); m_impl->m_hProv = NULL;
00139     }
00140 
00141     if(NULL != m_impl->m_hCertStore)
00142     {
00143 // this was #ifdef'd _DEBUG prior to moving to trunk
00144         BOOL certSucc = CertCloseStore(m_impl->m_hCertStore,CERT_CLOSE_STORE_CHECK_FLAG); 
00145         int ceerr = GetLastError();
00146         m_impl->m_hCertStore = NULL;
00147 #if 0 // this was the #else
00148         CertCloseStore(m_hCertStore, 0); 
00149         m_hCertStore = NULL;
00150 #endif
00151     }
00152 
00153     delete m_impl;
00154     m_impl = NULL;
00155 }
00163 void CPKIFCAPI2::Initialize()
00164 {
00165     LOG_STRING_DEBUG("CPKIFCAPI2::Initialize()", TOOLKIT_CRYPTO_CAPI, 0, this);
00166 
00167     m_impl->GetContext();
00168 }
00169 
00183 void CPKIFCAPI2Impl::GetContext()
00184 {
00185     LOG_STRING_DEBUG("CPKIFCAPI2::GetContext()", TOOLKIT_CRYPTO_CAPI, 0, this);
00186 
00187     //m_hProv is not NULL then we've been here before and should have a valid context
00188     //if m_provider is NULL then we need not get a context because we will always use the default context
00189     if(NULL == m_hProv && NULL != m_provider)
00190     {
00191         DWORD       cbName;
00192         DWORD       dwType;
00193         DWORD       dwIndex;
00194         CHAR        *pszName = NULL; 
00195 
00196         //---------------------------------------------------------------- 
00197         // Loop through enumerating m_providers.
00198         dwIndex = 0;
00199         while(CryptEnumProviders(dwIndex, NULL, 0, &dwType, NULL, &cbName))
00200         {
00201 
00202             //--------------------------------------------------------------------
00203             //  cbName returns the length of the name of the next m_provider.
00204             //  Allocate memory in a buffer to retrieve that name.
00205 
00206             if (!(pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbName)))
00207             {
00208                 throw CPKIFCryptoException(m_parent->thisComponent, COMMON_MEMORY_ALLOC_FAILURE, "");
00209             }
00210             //--------------------------------------------------------------------
00211             //  Get the m_provider name.
00212             if (CryptEnumProviders(dwIndex++, NULL, 0, &dwType, pszName, &cbName))
00213             {
00214                 //reviewed 4/23/2006 - added strlen
00215                 if(strlen(pszName) == strlen(m_provider) && 0 == stricmp(pszName, m_provider) && dwType == m_provType)
00216                 {
00217                     LocalFree(pszName);
00218                     return;
00219                 }
00220             }
00221             else
00222             {
00223                 LocalFree(pszName);
00224                 std::ostringstream os;
00225                 os << "CryptEnumProviders failed: " << GetLastError();
00226                 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_ACQUIRE_CONTEXT_FAILED, this);
00227             }
00228             LocalFree(pszName);
00229         } // End of while loop
00230 
00231         //modified string 2/23/2005.  it's providers had been turned to m_providers.
00232         RAISE_CRYPTO_EXCEPTION("No provider matching the specified provider name and provider type could be found.", m_parent->thisComponent, PKIFCAPI_ACQUIRE_CONTEXT_FAILED, this);
00233 
00234         //if(!CryptAcquireContext(&m_hProv, NULL, m_provider, m_provType,m_flags))
00235         //{
00236         //  m_hProv = NULL; //just to be sure the state of the object is unchanged upon failure
00237         //  std::string reason;
00238         //  FormatErrorMessage(reason, "CryptAcquireContext failed: ", GetLastError(), __FILE__, __LINE__);
00239         //  throw CPKIFCryptoException(thisComponent, PKIFCAPI_ACQUIRE_CONTEXT_FAILED, reason.c_str());
00240         //}
00241     }
00242 }
00243 
00255 bool CPKIFCAPI2Impl::CertMatchesCurContext(
00257     PCCERT_CONTEXT cert) const
00258 {
00259     LOG_STRING_DEBUG("CPKIFCAPI2::CertMatchesCurContext(PCCERT_CONTEXT cert)", TOOLKIT_CRYPTO_CAPI, 0, this);
00260 
00261     try
00262     {
00263         //create a temp credential and see if we own it using OwnsKey
00264         CPKIFCAPICredential2 tmp(m_provider, m_provType, m_sysStoRegLoc);
00265         tmp.m_certContext = CertDuplicateCertificateContext(cert);
00266         return m_parent->OwnsKey(tmp);
00267     }
00268     catch(CPKIFException& )
00269     {
00270         //delete e;
00271         return false;
00272     }
00273     catch(...)
00274     {
00275         _ASSERT(false);
00276         return false;
00277     }
00278 }
00305 CPKIFCAPICredential2* CPKIFCAPI2Impl::MakeCAPICredential(
00307     PCCERT_CONTEXT cert) const
00308 {
00309     LOG_STRING_DEBUG("CPKIFCAPI2::MakeCAPICredential(PCCERT_CONTEXT cert)", TOOLKIT_CRYPTO_CAPI, 0, this);
00310 
00311     char* name = NULL;
00312     CPKIFCAPICredential2* newKeyID = NULL;
00313 
00314     //The following call to CertGetNameString should behave as follows:
00315     //Checks the certificate for a CERT_FRIENDLY_NAME_PROP_ID property. If the certificate 
00316     //has this property, it is returned. If the certificate does not have the property, 
00317     //the CERT_NAME_SIMPLE_DISPLAY_TYPE is returned.
00318     //
00319     //CERT_NAME_SIMPLE_DISPLAY_TYPE iterates through the following list of name attributes 
00320     //and uses the Subject Name or the Subject Alternative Name extension for the first 
00321     //occurrence of: szOID_COMMON_NAME, szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME, 
00322     //or szOID_RSA_emailAddr. If one of these attributes is not found, uses the Subject 
00323     //Alternative Name extension for a rfc822Name choice. If there is still no match, uses 
00324     //the first attribute.
00325     DWORD dw = CertGetNameString(cert,CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, 0, 0, 0);
00326     if(1 == dw)
00327     {
00328         std::ostringstream os;
00329         os << "CertGetNameString failed: " << GetLastError();
00330         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_GET_NAME_FAILED, this);
00331     }
00332 
00333     name = new char[dw + 1];
00334     dw = CertGetNameString(cert,CERT_NAME_FRIENDLY_DISPLAY_TYPE,0,NULL, name, dw);
00335     if(1 == dw)
00336     {
00337         delete[] name; name = NULL;
00338         std::ostringstream os;
00339         os << "CertGetNameString failed: " << GetLastError();
00340         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_GET_NAME_FAILED, this);
00341     }
00342 
00343     //determine the length of the key info
00344     unsigned char* tmpKeyID = NULL;
00345     DWORD tmpKeyIDLen = 0;
00346 
00347     BOOL succ = CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID ,
00348         NULL, &tmpKeyIDLen);
00349     if(succ)
00350     {
00351         //allocate space for the new 
00352         tmpKeyID = (unsigned char *)malloc(tmpKeyIDLen);
00353         if(NULL == tmpKeyID) 
00354         {
00355             throw CPKIFCryptoException(m_parent->thisComponent, COMMON_MEMORY_ALLOC_FAILURE);
00356         }
00357         
00358         //get the info into the temp object
00359         succ = CertGetCertificateContextProperty(cert,
00360             CERT_KEY_IDENTIFIER_PROP_ID,    (void *)tmpKeyID, &tmpKeyIDLen);
00361         if(!succ)
00362         {
00363             free(tmpKeyID); tmpKeyID = NULL;
00364 
00365             std::ostringstream os;
00366             os << "CertGetCertificateContextProperty failed: " << GetLastError();
00367             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_KEY_PROV_INFO_FAILED, this);
00368         }
00369     }
00370 
00371     char* tmpKeyIDASCII = new char[(tmpKeyIDLen*2) + 1];
00372     btoa((const char*)tmpKeyID, tmpKeyIDASCII, tmpKeyIDLen);
00373 
00374     try
00375     {
00376         newKeyID = new CPKIFCAPICredential2(m_provider, m_provType, m_sysStoRegLoc);
00377         CPKIFStringPtr tmpSP(new std::string(name));
00378         newKeyID->m_name = tmpSP;
00379         CPKIFStringPtr tmpSP2(new std::string(tmpKeyIDASCII));
00380         newKeyID->m_id = tmpSP2;
00381 
00382         delete[] name; name = NULL;
00383         free(tmpKeyID); tmpKeyID = NULL;
00384         delete[] tmpKeyIDASCII; tmpKeyIDASCII = NULL;
00385 
00386         newKeyID->m_certContext = CertDuplicateCertificateContext(cert);
00387         return newKeyID;
00388     }
00389     catch(...)
00390     {
00391         if(NULL != name)
00392         {
00393             delete[] name; name = NULL;
00394         }
00395         if(NULL != newKeyID)
00396         {
00397             delete newKeyID;
00398         }
00399 
00400         std::ostringstream os;
00401         os << "Unknown error creating credential: " << GetLastError();
00402         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, COMMON_UNKNOWN_ERROR, this);
00403     }
00404 }
00405 
00406 //For ownership to be declared, either this instance must not be locked down to a specific m_provider
00407 //or the m_provider and m_provider type from the key itself must match those of this instance.
00417 bool CPKIFCAPI2::OwnsKey(
00419     const CPKIFCredential& keyID) const
00420 {
00421     LOG_STRING_DEBUG("CPKIFCAPI2::OwnsKey(const CPKIFCredential& keyID)", TOOLKIT_CRYPTO_CAPI, 0, this);
00422 
00423     //attempt to cast the keyID param to the type this class would've returned
00424     const CPKIFCAPICredential2* ck2 = dynamic_cast<const CPKIFCAPICredential2*>(&keyID);
00425 
00426     //if the cast fails then we don't "own" this key - we only deal in CPKIFCAPICredential objects
00427     if(NULL == ck2)
00428         return false;
00429 
00430     //if it succeeded and this instance is a general CAPI instance then we do "own" it
00431     if(NULL == m_impl->m_provider && 0 == m_impl->m_provType)
00432         return true;
00433 
00434     //otherwise have the key compare our info with the its info
00435     return ck2->ProviderInfoMatches(m_impl->m_provider, m_impl->m_provType);
00436 }
00437 
00450 void CPKIFCAPI2::GetKeyList(
00452     CPKIFCredentialList& v,
00454     CPKIFKeyUsagePtr& ku)
00455 {
00456     bitset<9> tmp = ku->GetKeyUsage();
00457     GetKeyList(v, &tmp);
00458 }
00459 
00473 void CPKIFCAPI2::GetKeyList(
00475     CPKIFCredentialList& v,
00477     bitset<9>* ku)
00478 {
00479     LOG_STRING_DEBUG("CPKIFCAPI2::GetKeyList(CPKIFCredentialList& v, bitset<9>* ku)", TOOLKIT_CRYPTO_CAPI, 0, this);
00480 
00481     m_impl->GetContext();
00482 
00483     HRESULT hr = S_OK;
00484     DWORD dw = 0;
00485 
00486     const size_t originalCount = v.size();
00487 
00488     USES_CONVERSION;
00489 
00490     //we always look in the MY store of the specified location when listing certs
00491     //we require that the store exist
00492     if(NULL == m_impl->m_hCertStore)
00493     {
00494         m_impl->m_hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, 
00495                                 CERT_STORE_OPEN_EXISTING_FLAG | m_impl->m_sysStoRegLoc, T2OLE("MY"));
00496         if(NULL == m_impl->m_hCertStore)
00497         {
00498             std::ostringstream os;
00499             os << "CertOpenStore failed: " << GetLastError();
00500             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_FAILED_TO_OPEN_CERT_STORE, this);
00501         }
00502     }
00503 
00504     PCCERT_CONTEXT pPrevCertContext = NULL;
00505     BOOL keyUsagePresent = false;
00506     BYTE kuBits[2];
00507     CPKIFCAPICredential2* keyID = NULL;
00508 
00509     try
00510     {
00511         pPrevCertContext = CertEnumCertificatesInStore(m_impl->m_hCertStore, pPrevCertContext);
00512         while(NULL != pPrevCertContext)
00513         {
00514             //get the key usage of the current certificate
00515             keyUsagePresent = CertGetIntendedKeyUsage(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, pPrevCertContext->pCertInfo, (BYTE*)&kuBits, sizeof(kuBits));
00516 
00517             //make sure the context has an associated private key - we are only interested in listing
00518             //certs for which we hold the private keys
00519             if(CertHasKey(pPrevCertContext) && m_impl->CertMatchesCurContext(pPrevCertContext) &&
00520                 (!keyUsagePresent || (keyUsagePresent && keyUsageTest(kuBits, ku))))
00521             {
00522                 //make a credential from the cert context
00523                 keyID = m_impl->MakeCAPICredential(pPrevCertContext);
00524 
00525                 //and push it into the vector
00526                 CPKIFCredentialPtr tmpCred(keyID);
00527                 v.push_back(tmpCred);
00528 
00529                 keyID = NULL;
00530             }
00531 
00532             pPrevCertContext = CertEnumCertificatesInStore(m_impl->m_hCertStore, pPrevCertContext);
00533         }
00534     }
00535     catch(...)
00536     {
00537         if(NULL != keyID)
00538         {
00539             //if we threw before completing the push_back statment, clean up
00540             delete keyID; keyID = NULL;
00541         }
00542 
00543         if(NULL != pPrevCertContext)
00544         {
00545             //if we threw before freeing cert context, clean up
00546             CertFreeCertificateContext(pPrevCertContext); pPrevCertContext = NULL;
00547         }
00548 
00549         std::ostringstream os;
00550         os << "Unknown failure in GetKeyList.  GetLastError returns: " << GetLastError();
00551         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, COMMON_UNKNOWN_ERROR, this);
00552     }
00553 }
00554 
00555 //this function takes a key ID (ascii hex SHA1 hash typically) and creates a CPKIFCAPICredential that may be
00556 //used with the Sign and Decrypt functions.  If a matching key could not be found NULL is returned.
00569 CPKIFCredentialPtr CPKIFCAPI2::MakeKeyID(
00572     const std::string& asciiHexKeyID)
00573 {
00574 #undef CLEANUP
00575 #define CLEANUP \
00576 { \
00577     if (NULL != bin)  \
00578     {   delete[] bin; bin = NULL; }  \
00579     if (NULL != cert)  \
00580     {   CertFreeCertificateContext(cert); cert = NULL; }  \
00581 } 
00582 
00583     LOG_STRING_DEBUG("CPKIFCAPI2::MakeKeyID(const std::string& asciiHexKeyID)", TOOLKIT_CRYPTO_CAPI, 0, this);
00584 
00585     char* bin = NULL;
00586     PCCERT_CONTEXT cert = NULL;
00587 
00588     CPKIFCAPICredential2* newKeyID = NULL; //don't free - this is what gets returned
00589 
00590     //convert the input from ascii hex to binary
00591     const char* hex = asciiHexKeyID.c_str();
00592     unsigned int len = 0;
00593 
00594     try 
00595     {
00596         len = numeric_cast<unsigned int>(asciiHexKeyID.length()/2);
00597     }
00598     catch(bad_numeric_cast &) 
00599     {
00600         throw CPKIFException(TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, "Key identifier is an impossibly long number.");
00601     }
00602     bin = new char[len];
00603     if(0 != atob(bin, const_cast<char*>(hex), &len))
00604     {
00605         CLEANUP;
00606 
00607         std::string reason;
00608         FormatErrorMessage(reason, "Key ID contains non-ASCII hexadecimal characters.", -1, __FILE__, __LINE__);
00609         throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, reason.c_str());
00610     }
00611 
00612     //set up a hash blob containing the binary key ID and length
00613     CRYPT_HASH_BLOB b;
00614     b.cbData = len;
00615     b.pbData = (BYTE*)bin;
00616 
00617     //open the cert store
00618     USES_CONVERSION;
00619     if(NULL == m_impl->m_hCertStore)
00620     {
00621         m_impl->m_hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, CERT_STORE_OPEN_EXISTING_FLAG | m_impl->m_sysStoRegLoc, T2OLE("MY"));
00622         if(NULL == m_impl->m_hCertStore)
00623         {
00624             CLEANUP;
00625 
00626             std::ostringstream os;
00627             os << "CertOpenStore failed: " << GetLastError();
00628             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_FAILED_TO_OPEN_CERT_STORE, this);
00629         }
00630     }
00631 
00632     cert = CertFindCertificateInStore(m_impl->m_hCertStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_KEY_IDENTIFIER, (void*)&b, NULL);
00633 
00634     try
00635     {
00636         if(NULL != cert && true == m_impl->CertMatchesCurContext(cert))
00637         {
00638             //make a credential from the cert context
00639             newKeyID = m_impl->MakeCAPICredential(cert);
00640         }
00641     }
00642     catch(CPKIFException& e)
00643     {
00644         if(NULL != newKeyID)
00645         {
00646             delete newKeyID; newKeyID = NULL;
00647         }
00648 
00649         CLEANUP;
00650         throw e;
00651     }
00652 
00653     CLEANUP;
00654     CPKIFCredentialPtr tmp(newKeyID);
00655     return tmp;
00656 }
00657 
00684 void CPKIFCAPI2::Sign(
00686     const CPKIFCredential& key,
00688     unsigned char* pHashData,
00690     int nHashDataLen,
00692     unsigned char* pSignature,
00695     int* nSignatureLen,
00697     PKIFCRYPTO::HASH_ALG hashAlg
00698     )
00699 {
00700 #undef CLEANUP
00701 #define CLEANUP \
00702 { \
00703     if (NULL != hHash)  \
00704     {   CryptDestroyHash(hHash); hHash = NULL; }  \
00705     if (NULL != tmpHashCtx && true == freeContext)  \
00706     {   CryptReleaseContext(tmpHashCtx, 0); tmpHashCtx = NULL; }  \
00707 } 
00708 
00709     LOG_STRING_DEBUG("CPKIFCAPI2::Sign(const CPKIFCredential& key,...", TOOLKIT_CRYPTO_CAPI, 0, this);
00710 
00711     m_impl->GetContext();
00712 
00713     int err = 0;
00714 
00715     //set up a pointer to a context and an indication of whether or not to free context then get the hash alg
00716     //we use the length of the data to determine the hash alg.  If the hash alg is not known GetHashAlg throws
00717     HCRYPTPROV tmpHashCtx = NULL;
00718     HCRYPTHASH hHash = NULL;
00719     bool freeContext = false;
00720 
00721     ALG_ID HashAlg = GetHashAlg((PKIFCRYPTO::HASH_ALG)nHashDataLen);
00722 
00723     //convert the key to a CAPI key object and see if the key info has been loaded
00724     const CPKIFCAPICredential2* ck2 = dynamic_cast<const CPKIFCAPICredential2*>(&key);
00725     if(NULL == ck2)
00726     {
00727         throw CPKIFCryptoException(thisComponent, CRYPTO_UNRECOGNIZED_CREDENTIAL, "Credential type not recognized.");
00728     }
00729 
00730     if(NULL == ck2->m_keyProviderInfo)
00731     {
00732         //if key info hasn't been loaded - load it - if load fails SetKeyProviderInfo throws
00733         CPKIFCAPICredential2* k2 = const_cast<CPKIFCAPICredential2*>(ck2);
00734         k2->SetKeyProviderInfo();
00735     }
00736 
00737     USES_CONVERSION;
00738 
00739     if(NULL == m_impl->m_hProv)
00740     {
00741         if(!CryptAcquireContext(&tmpHashCtx, OLE2T(ck2->m_keyProviderInfo->pwszContainerName), OLE2T(ck2->m_keyProviderInfo->pwszProvName), ck2->m_keyProviderInfo->dwProvType, m_impl->m_flags))
00742         {
00743             std::ostringstream os;
00744             os << "CryptAcquireContext failed: " << GetLastError();
00745             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_ACQUIRE_CONTEXT_FAILED, this);
00746         }
00747 
00748         freeContext = true;
00749     }
00750     else
00751         tmpHashCtx = m_impl->m_hProv;
00752 
00753     //see if the password has been provided for use in UI-less environment
00754     if(NULL != ck2->m_password)
00755     {
00756         //if one has been provided try to set it - not all CSPs accept this parameter however
00757         HCRYPTKEY userKey = NULL;
00758         if(!CryptGetUserKey(tmpHashCtx, ck2->m_keyProviderInfo->dwKeySpec, &userKey))
00759         {
00760             CLEANUP;
00761 
00762             std::ostringstream os;
00763             os << "CryptGetUserKey failed: " << GetLastError();
00764             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_GET_USER_KEY_FAILED, this);
00765         }
00766 
00767         if(!CryptSetProvParam(tmpHashCtx, PP_SIGNATURE_PIN, ck2->m_password, 0))
00768         {
00769             CLEANUP;
00770 
00771             CryptDestroyKey(userKey);
00772             std::ostringstream os;
00773             os << "CryptSetProvParam failed: " << GetLastError();
00774             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_SET_PASSWORD_FAILED, this);
00775         }
00776 
00777         CryptDestroyKey(userKey);
00778     }
00779 
00780     if(!CryptCreateHash(tmpHashCtx, HashAlg, NULL, 0, &hHash))
00781     {
00782         CLEANUP;
00783 
00784         std::ostringstream os;
00785         os << "CryptCreateHash failed: " << GetLastError();
00786         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_CREATE_HASH_FAILED, this);
00787     }
00788     DWORD hSize = 0;
00789     DWORD hSizeSize = sizeof(hSize);
00790     if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hSize, &hSizeSize, 0))
00791     {
00792         CLEANUP;
00793 
00794         std::ostringstream os;
00795         os << "CryptGetHashParam failed: " << GetLastError();
00796         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_MISC_HASH_CALL_FAILED, this);
00797     }
00798 
00799     if(nHashDataLen != hSize)
00800     {
00801         CLEANUP;
00802 
00803         std::string reason;
00804         FormatErrorMessage(reason, "Hash sizes do not match.  Could not set hash object for signing.", -1, __FILE__, __LINE__);
00805         throw CPKIFCryptoException(thisComponent, PKIFCAPI_MISC_HASH_CALL_FAILED, reason.c_str());
00806     }
00807 
00808     if(!CryptSetHashParam(hHash, HP_HASHVAL, pHashData, 0))
00809     {
00810         CLEANUP;
00811 
00812         std::ostringstream os;
00813         os << "CryptSetHashParam failed: " << GetLastError();
00814         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_MISC_HASH_CALL_FAILED, this);
00815     }
00816 
00817     if(!CryptSignHash(hHash, ck2->m_keyProviderInfo->dwKeySpec, NULL, 0, pSignature, (DWORD*)nSignatureLen))
00818     {
00819         CLEANUP;
00820 
00821         std::ostringstream os;
00822         os << "CryptSignHash failed: " << GetLastError();
00823         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_SIGN_FAILED, this);
00824     }
00825 
00826     if(DSA_CLASS != GetAlgClass(key.GetCertificate()->SubjectPublicKeyInfo()->alg()))
00827         ReverseBytes(pSignature, *nSignatureLen);
00828     else
00829     {
00830         ReverseBytes(pSignature, *nSignatureLen/2);
00831         ReverseBytes(pSignature+(*nSignatureLen/2), *nSignatureLen/2);
00832     }
00833 
00834     CLEANUP;
00835 }
00836 
00854 void CPKIFCAPI2::Decrypt(
00857     const CPKIFCredential& key,
00859     unsigned char* pData,
00861     int nDataLen,
00863     unsigned char* pResult, 
00866     int* pnResultLen)
00867 {
00868 #undef CLEANUP
00869 #define CLEANUP \
00870 { \
00871     if (NULL != userKey)  \
00872     {   CryptDestroyKey(userKey); userKey = NULL; }  \
00873     if (NULL != tmpCtx && TRUE == freeContext)  \
00874     {   CryptReleaseContext(tmpCtx, 0); tmpCtx = NULL; }  \
00875 } 
00876 
00877     LOG_STRING_DEBUG("CPKIFCAPI2::Decrypt(const CPKIFCredential& key,...", TOOLKIT_CRYPTO_CAPI, 0, this);
00878 
00879     m_impl->GetContext();
00880 
00881     USES_CONVERSION;
00882 
00883     HCRYPTPROV tmpCtx = NULL;
00884     BOOL freeContext = false;
00885 
00886     //convert the key to a CAPI key object and see if the key info has been loaded
00887     const CPKIFCAPICredential2* ck2 = dynamic_cast<const CPKIFCAPICredential2*>(&key);
00888     if(NULL == ck2)
00889     {
00890         throw CPKIFCryptoException(thisComponent, CRYPTO_UNRECOGNIZED_CREDENTIAL, "Credential type not recognized.");
00891     }
00892 
00893     if(NULL == ck2->m_keyProviderInfo)
00894     {
00895         //if key info hasn't been loaded - load it - if load fails SetKeyProviderInfo throws
00896         CPKIFCAPICredential2* k2 = const_cast<CPKIFCAPICredential2*>(ck2);
00897         k2->SetKeyProviderInfo();
00898     }
00899 
00900     if(NULL == m_impl->m_hProv)
00901     {
00902         DWORD keySpec = 0;
00903 //      if(!CryptAcquireContext(&tmpCtx, OLE2T(ck2->m_keyProviderInfo->pwszContainerName), OLE2T(ck2->m_keyProviderInfo->pwszProvName), ck2->m_keyProviderInfo->dwm_provType, 0))
00904         if(!CryptAcquireCertificatePrivateKey(ck2->m_certContext, 0, 0, &tmpCtx, &keySpec, &freeContext))
00905         {
00906             std::ostringstream os;
00907             os << "CryptAcquireContext failed: " << GetLastError();
00908             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_ACQUIRE_CONTEXT_FAILED, this);
00909         }
00910     }
00911     else
00912         tmpCtx = m_impl->m_hProv;
00913 
00914     HCRYPTKEY userKey = NULL;
00915     if(!CryptGetUserKey(tmpCtx, ck2->m_keyProviderInfo->dwKeySpec, &userKey))
00916     {
00917         CLEANUP;
00918 
00919         std::ostringstream os;
00920         os << "CryptGetUserKey failed: " << GetLastError();
00921         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_GET_USER_KEY_FAILED, this);
00922     }
00923 
00924     //see if the password has been provided for use in UI-less environment
00925     if(NULL != ck2->m_password)
00926     {
00927         //if one has been provided try to set it - not all CSPs accept this parameter however
00928         if(!CryptSetProvParam(tmpCtx, PP_SIGNATURE_PIN, ck2->m_password, 0))
00929         {
00930             CLEANUP;
00931 
00932             std::ostringstream os;
00933             os << "CryptSetProvParam failed: " << GetLastError();
00934             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_SET_PASSWORD_FAILED, this);
00935         }
00936     }
00937 
00938     memcpy(pResult, pData, nDataLen);
00939     *pnResultLen = nDataLen;
00940 
00941     ReverseBytes(pResult, nDataLen);
00942 
00943     if(!CryptDecrypt(userKey, NULL, true, 0, pResult, (DWORD*)pnResultLen))
00944     {
00945         CLEANUP;
00946 
00947         std::ostringstream os;
00948         os << "CryptDecrypt failed: " << GetLastError();
00949         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_DECRYPT_FAILED, this);
00950     }
00951 
00952     //due to a copy and paste error at some point, the word provider in the following string literal was
00953     //changed to m_provider.  This was changed back on 8/20/2004
00954     //ActiveCard fixed the reversed bytes issue on the new drives a check is added to see if byte reversal is needed. 3/7/2005 Armen
00955 
00956     //reviewed 4/23/2006 - added strlen
00957     const char* pwszProvName = OLE2T(ck2->m_keyProviderInfo->pwszProvName);
00958     if(strlen(pwszProvName) == strlen("ActivCard Gold Cryptographic Service Provider") && 
00959         0 == stricmp("ActivCard Gold Cryptographic Service Provider", pwszProvName))
00960     {
00961         if(UNSET == g_bytesReversed)
00962             g_bytesReversed = m_impl->CheckReversed(&userKey);
00963         
00964         if(REV == g_bytesReversed)
00965             ReverseBytes(pResult, *pnResultLen);
00966     }
00967     CLEANUP;
00968 }
00969 
00981 void CPKIFCAPI2::Encrypt(
00984     const CPKIFCredential& key,
00986     unsigned char* pData,
00988     int nDataLen,
00990     unsigned char* pResult,
00993     int* pnResultLen)
00994 {
00995     LOG_STRING_DEBUG("CPKIFCAPI2::Encrypt(const CPKIFCredential& key, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen)", TOOLKIT_CRYPTO_CAPI, 0, this);
00996 
00997     throw CPKIFCryptoException(thisComponent, COMMON_NOT_IMPLEMENTED, "Encrypt operations are not implemented for stored key material");
00998 }
00999 
01011 bool CPKIFCAPI2::Verify(
01014     const CPKIFCredential& key, 
01017     unsigned char* pHashData,
01019     int nHashDataLen,
01021     unsigned char* pSignature,
01023     int nSignatureLen,
01025     PKIFCRYPTO::HASH_ALG hashAlg
01026     )
01027 {
01028     LOG_STRING_DEBUG("CPKIFCAPI2::Verify(const CPKIFCredential& key, unsigned char* pHashData, int nHashDataLen, unsigned char* pSignature, int nSignatureLen)", TOOLKIT_CRYPTO_CAPI, 0, this);
01029 
01030     throw CPKIFCryptoException(thisComponent, COMMON_NOT_IMPLEMENTED, "Verify operations are not implemented for stored key material");
01031 }
01032 
01051 IPKIFCryptContext* CPKIFCAPI2::CryptInit(
01054     CPKIFCredentialPtr& key,
01056     bool pad)
01057 {
01058     LOG_STRING_DEBUG("CPKIFCAPI2::CryptInit(CPKIFCredentialPtr& key)", TOOLKIT_CRYPTO_CAPI, 0, this);
01059 
01060     //added check for NULL - 8/18/2004
01061     if(key == (CPKIFCredential*)NULL)
01062     {
01063         throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL or invalid key passed to CPKIFCAPI2::CryptInit.");
01064     }
01065 
01066     m_impl->GetContext();
01067 
01068     USES_CONVERSION;
01069 
01070     //convert the key to a CAPI key object and see if the key info has been loaded
01071     const CPKIFCAPICredential2* ck2 = dynamic_cast<const CPKIFCAPICredential2*>(&(*key));
01072     if(NULL == ck2)
01073     {
01074         throw CPKIFCryptoException(thisComponent, CRYPTO_UNRECOGNIZED_CREDENTIAL, "Credential type not recognized.");
01075     }
01076 
01077     if(NULL == ck2->m_keyProviderInfo)
01078     {
01079         //if key info hasn't been loaded - load it - if load fails SetKeyProviderInfo throws
01080         CPKIFCAPICredential2* k2 = const_cast<CPKIFCAPICredential2*>(ck2);
01081         k2->SetKeyProviderInfo();
01082     }
01083 
01084     DWORD keySpec = 0;
01085     BOOL freeContext = false;
01086     CPKIFCAPICryptContext2* cryptContext = new CPKIFCAPICryptContext2();
01087     if(!CryptAcquireCertificatePrivateKey(ck2->m_certContext, 0, 0, &cryptContext->m_cryptContext, &keySpec, &freeContext))
01088     {
01089         delete cryptContext;
01090         std::ostringstream os;
01091         os << "CryptAcquireContext failed: " << GetLastError();
01092         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_ACQUIRE_CONTEXT_FAILED, this);
01093     }
01094 
01095     if(!CryptGetUserKey(cryptContext->m_cryptContext, ck2->m_keyProviderInfo->dwKeySpec, &cryptContext->m_userKey))
01096     {
01097         delete cryptContext;
01098         std::ostringstream os;
01099         os << "CryptGetUserKey failed: " << GetLastError();
01100         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_GET_USER_KEY_FAILED, this);
01101     }
01102 
01103     //see if the password has been provided for use in UI-less environment
01104     if(NULL != ck2->m_password)
01105     {
01106         //if one has been provided try to set it - not all CSPs accept this parameter however
01107         if(!CryptSetProvParam(cryptContext->m_cryptContext, PP_SIGNATURE_PIN, ck2->m_password, 0))
01108         {
01109             std::ostringstream os;
01110             os << "CryptSetProvParam failed: " << GetLastError();
01111             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_SET_PASSWORD_FAILED, this);
01112         }
01113     }
01114 
01115     cryptContext->m_cred = key;
01116     return cryptContext;
01117 }
01118 
01135 void CPKIFCAPI2::Decrypt(
01138     IPKIFCryptContext* cryptContext,
01140     unsigned char* pData,
01142     int nDataLen,
01144     unsigned char* pResult, 
01147     int* pnResultLen,
01150     bool final)
01151 {
01152     LOG_STRING_DEBUG("CPKIFCAPI2::Decrypt(IPKIFCryptContext* cryptContext, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool final)", TOOLKIT_CRYPTO_CAPI, 0, this);
01153 
01154     if(NULL == cryptContext)
01155         throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL or invalid credential passed to CPKIFCAPI2::Decrypt.");
01156 
01157     CPKIFCAPICryptContext2* ccc = dynamic_cast<CPKIFCAPICryptContext2*>(cryptContext);
01158     
01159     //added check for NULL - 8/18/2004
01160     if(NULL == ccc)
01161         throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL or invalid credential passed to CPKIFCAPI2::Decrypt.");
01162 
01163     const CPKIFCAPICredential2* ck2 = dynamic_cast<const CPKIFCAPICredential2*>(&(*cryptContext->GetCredential()));
01164     if(NULL == ck2)
01165     {
01166         throw CPKIFCryptoException(thisComponent, CRYPTO_UNRECOGNIZED_CREDENTIAL, "Credential type not recognized.");
01167     }
01168 
01169     memcpy(pResult, pData, nDataLen);
01170     *pnResultLen = nDataLen;
01171 
01172     ReverseBytes(pResult, nDataLen);
01173 
01174     if(!CryptDecrypt(ccc->m_userKey, NULL, true, 0, pResult, (DWORD*)pnResultLen))
01175     {
01176         std::ostringstream os;
01177         os << "CryptDecrypt failed: " << GetLastError();
01178         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_DECRYPT_FAILED, this);
01179     }
01180 
01181     USES_CONVERSION;
01182     //ActiveCard fixed the reversed bytes issue on the new drives a check is added to see if byte reversal is needed. 3/7/2005 Armen
01183 
01184     //reviewed 4/23/2006 - added strlen
01185     const char* pwszProvName = OLE2T(ck2->m_keyProviderInfo->pwszProvName);
01186     if(strlen(pwszProvName) == strlen("ActivCard Gold Cryptographic Service Provider") && 
01187         0 == stricmp("ActivCard Gold Cryptographic Service Provider", pwszProvName))
01188     {
01189         if(UNSET == g_bytesReversed)
01190             g_bytesReversed = m_impl->CheckReversed(&(ccc->m_userKey));
01191         
01192         if(REV == g_bytesReversed)
01193             ReverseBytes(pResult, *pnResultLen);
01194         
01195     }
01196 }
01197 
01208 void CPKIFCAPI2::Encrypt(
01211     IPKIFCryptContext* cryptContext,
01213     unsigned char* pData,
01215     int nDataLen,
01217     unsigned char* pResult,
01220     int* pnResultLen,
01223     bool final)
01224 {
01225     throw CPKIFCryptoException(thisComponent, COMMON_NOT_IMPLEMENTED, "Encrypt operations are not implemented for stored key material");
01226 }
01227 
01238 BYTESREVERSED CPKIFCAPI2Impl::CheckReversed(
01240     HCRYPTKEY * key)
01241 {
01242     //This function was added 3/7/2005 to check if byte reversal is needed for CAC operations
01243     const unsigned char * testblock = (unsigned char *)"1234";
01244     DWORD datalen = 4;
01245     DWORD blocksizelen = sizeof(DWORD);
01246     DWORD blocksize = 0;
01247     CryptGetKeyParam(*key,KP_BLOCKLEN,(BYTE *)&blocksize,&blocksizelen,0x00);
01248 
01249     unsigned char* pResult = new unsigned char[blocksize];
01250     memset(pResult,0x00,blocksize);
01251     memcpy(pResult,testblock,datalen);
01252 
01253     if(!CryptEncrypt(*key, NULL, true, 0, pResult, &datalen, blocksize))
01254     {
01255         std::ostringstream os;
01256         os << "CryptDecrypt failed: " << GetLastError();
01257         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, CRYPTO_ENCRYPT_FAILED, this);
01258     }
01259 
01260     if(!CryptDecrypt(*key, NULL, true, 0, pResult, &datalen))
01261     {
01262         std::ostringstream os;
01263         os << "CryptDecrypt failed: " << GetLastError();
01264         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_DECRYPT_FAILED, this);
01265     }
01266     
01267     if(memcmp(pResult, "1234", datalen) == 0) 
01268         return NOTREV;
01269 
01270 
01271     return REV;
01272     
01273 }

Generated on Mon Nov 15 11:15:53 2010 for PublicKeyInfrastructureFramework(PKIF) by  doxygen 1.5.6