CACCAPIRaw.cpp

Go to the documentation of this file.
00001 
00009 #include "PKIFCAPIRaw.h"
00010 #include "PKIFCAPICryptContext2.h"
00011 #include "PKIFCAPIHashContext.h"
00012 #include "CAPIUtils.h"
00013 
00014 #include "PKIFCryptoException.h"
00015 #include "PKIFKeyMaterial.h"
00016 #include "PKIFCryptoErrors.h"
00017 #include "PKIFCAPIErrors.h"
00018 #include "CAPIRawCryptContext.h"
00019 #include "PKIFAlgorithm.h"
00020 
00021 #include "AlgorithmIdentifier.h"
00022 #include "Buffer.h"
00023 #include "Certificate.h"
00024 #include "ToolkitUtils.h"
00025 #include "components.h"
00026 #include "PKIFException.h"
00027 
00028 #include "SubjectPublicKeyInfo.h"
00029 
00030 #include "ASN1Helper.h"
00031 #include "PKIX1Algorithms88.h"
00032 
00033 #include <iostream>
00034 #include <sstream>
00035 using namespace std;
00036 
00037 #if !defined(ALG_SID_SHA_256)
00038 #define ALG_SID_SHA_256 12 
00039 #define ALG_SID_SHA_384 13 
00040 #define ALG_SID_SHA_512 14 
00041  
00042 #define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) 
00043 #define CALG_SHA_384 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384) 
00044 #define CALG_SHA_512 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512) 
00045 #endif 
00046 
00047 CAC_API char g_defCACCAPITrustStore[] = "Root";
00048 
00050 struct CPKIFCAPIRawImpl
00051 {
00052 
00053     CPKIFCAPIRaw* m_parent;
00054     char * m_provName;
00055     int m_provType;
00063     CPKIFCAPIRawImpl ()
00064     {
00065         m_parent = NULL;
00066     }
00074     CPKIFCAPIRawImpl (CPKIFCAPIRaw  *p) 
00075     {
00076         m_parent = p;
00077     }
00079     HCRYPTPROV m_hProv;
00081     HCRYPTKEY m_hPubPrivKey;
00082 
00083     template<bool _CryptDirection>
00084     void Crypt(const CPKIFKeyMaterial& key, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool pad = true);
00085 
00086     template <bool _CryptDirection>
00087     void CryptFunc(IPKIFRawCryptContext* cryptContext, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool final);
00088 
00089 };
00091 
00100 CPKIFCAPIRaw::CPKIFCAPIRaw(void)
00101     :m_impl (new CPKIFCAPIRawImpl)
00102 {
00103     LOG_STRING_DEBUG("CPKIFCAPIRaw::CPKIFCAPIRaw(void)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00104     InitImpl();
00105 }
00106 
00115 CPKIFCAPIRaw::CPKIFCAPIRaw(
00117              const char* provider,
00119              int provType)
00120      :m_impl (new CPKIFCAPIRawImpl)
00121 {
00122     LOG_STRING_DEBUG("CPKIFCAPIRaw::CPKIFCAPIRaw(provider,provType)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00123     InitImpl(provider,provType);
00124 }
00132 CPKIFCAPIRaw::~CPKIFCAPIRaw(void)
00133 {
00134     LOG_STRING_DEBUG("CPKIFCAPIRaw::~CPKIFCAPIRaw(void)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00135 
00136     if(NULL != m_impl->m_hPubPrivKey)
00137     {
00138         BOOL succ = CryptDestroyKey(m_impl->m_hPubPrivKey);
00139         m_impl->m_hPubPrivKey = NULL;
00140     }
00141     if(NULL != m_impl->m_hProv)
00142     {
00143         BOOL succ = CryptReleaseContext(m_impl->m_hProv, 0);
00144         m_impl->m_hProv = NULL;
00145     }
00146     if(NULL != m_impl->m_provName) {
00147         free(m_impl->m_provName);
00148     }
00149     delete m_impl;
00150     m_impl = NULL;
00151 }
00159 void CPKIFCAPIRaw::Initialize()
00160 {
00161     LOG_STRING_DEBUG("CPKIFCAPIRaw::Initialize()", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00162 }
00163 
00164 
00172 void CPKIFCAPIRaw::InitImpl(const char * provider, int provType)
00173 {
00174     m_impl->m_parent = this;
00175     m_impl->m_hProv = NULL;
00176     m_impl->m_hPubPrivKey = NULL;
00177     if(provider) {
00178         m_impl->m_provName = _strdup(provider);
00179     } else {
00180         m_impl->m_provName = NULL;
00181     }
00182     m_impl->m_provType = provType;
00183 }
00184 
00194 ALG_ID GetSymAlgorithm(
00196     const CPKIFKeyMaterial& key)
00197 {
00198     switch(key.GetSymmetricKeyAlgorithm())
00199     {
00200     case PKIFCRYPTO::DES:
00201         return CALG_DES;
00202     case PKIFCRYPTO::TDES:
00203         return CALG_3DES;
00204     //PKIF Only supports AES through NSS 
00205     //case AES:
00206     //case AES128:
00207     //  return CALG_AES_128;
00208     //case AES192:
00209     //  return CALG_AES_192;
00210     //case AES256:
00211     //  return CALG_AES_256;
00212     default:
00213         RAISE_CRYPTO_EXCEPTION("", TOOLKIT_CRYPTO, CRYPTO_ALG_NOT_SUPPORTED, NULL)
00214     }
00215 }
00225 DWORD GetProvType(
00227     PCCERT_CONTEXT cert)
00228 {
00229     //inspect the subject public key algorithm to determine the type of provider to create
00230     if(0 == strcmp(szOID_X957_DSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId) ||
00231         0 == strcmp(szOID_X957_SHA1DSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId))
00232         return PROV_DSS;
00233     else if(0 == strcmp(szOID_RSA_RSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId) ||
00234         0 == strcmp(szOID_RSA_MD5RSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId) ||
00235         0 == strcmp(szOID_RSA_SHA1RSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId)) 
00236         return PROV_RSA_FULL;
00237     else
00238         RAISE_CRYPTO_EXCEPTION(cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, TOOLKIT_CRYPTO_CAPIRAW, CRYPTO_ALG_NOT_SUPPORTED, NULL)
00239 }
00249 DWORD GetProvType(
00251     const char* oidString)
00252 {
00253     //inspect the subject public key algorithm to determine the type of provider to create
00254     if(0 == strcmp(szOID_X957_DSA, oidString) ||
00255         0 == strcmp(szOID_X957_SHA1DSA, oidString))
00256         return PROV_DSS;
00257     else if(0 == strcmp(szOID_RSA_RSA, oidString) ||
00258         0 == strcmp(szOID_RSA_MD5RSA, oidString) ||
00259         0 == strcmp(szOID_RSA_SHA1RSA, oidString)) 
00260         return PROV_RSA_FULL;
00261     else
00262         RAISE_CRYPTO_EXCEPTION(oidString, TOOLKIT_CRYPTO_CAPIRAW, CRYPTO_ALG_NOT_SUPPORTED, NULL)
00263 }
00279 bool CPKIFCAPIRaw::SupportsAlgorithm(
00281     const CPKIFKeyMaterial& key)
00282 {
00283     LOG_STRING_DEBUG("CPKIFCAPIRaw::SupportsAlgorithm(const CPKIFKeyMaterial& key)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00284 
00285     if(key.ContainsSymmetricKeyMaterial())
00286     {   
00287         try
00288         {
00289             GetSymAlgorithm(key);
00290             return true;
00291         }
00292         catch(CPKIFCryptoException& e)
00293         {
00294             if(CRYPTO_ALG_NOT_SUPPORTED == e.GetErrorCode())
00295             {
00296                 //EXCEPTION DELETION
00297                 //The GetSymAlgorithm function throws upon failure but
00298                 //this function should return false.
00299                 //delete e;
00300                 return false;
00301             }
00302             else
00303                 throw e; //should never happen
00304         }
00305     }
00306     else if(key.ContainsCertificate())
00307     {
00308         PCCERT_CONTEXT cert = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 
00309             key.GetCertificate(), key.GetCertificateLength());
00310         if(NULL == cert)
00311         {
00312             std::ostringstream os;
00313             os << "CertCreateCertificateContext failed: " << GetLastError();
00314             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_CREATE_CERT_FAILED, this)
00315         }
00316 
00317         try
00318         {
00319             GetProvType(cert);
00320             if (NULL != cert)  
00321             {   CertFreeCertificateContext(cert); cert = NULL; }  
00322             return true;
00323         }
00324         catch(CPKIFException& e)
00325         {
00326             if (NULL != cert)  
00327             {   CertFreeCertificateContext(cert); cert = NULL; }  
00328 
00329             if(CRYPTO_ALG_NOT_SUPPORTED == e.GetErrorCode())
00330             {
00331                 //EXCEPTION DELETION
00332                 //The GetSymAlgorithm function throws upon failure but
00333                 //this function should return false.
00334                 //delete e;
00335                 return false;
00336             }
00337             else
00338                 throw e; //should never happen
00339         }
00340     }
00341     else
00342     {
00343         RAISE_CRYPTO_EXCEPTION("key parameter contents not recognized.", thisComponent, COMMON_INVALID_INPUT, this);
00344     }
00345 }
00356 void CPKIFCAPIRaw::Sign(
00358     const CPKIFKeyMaterial& key,
00360     unsigned char* pHashData,
00362     int nHashDataLen,
00364     unsigned char* pSignature,
00366     int* nSignatureLen,
00368     PKIFCRYPTO::HASH_ALG hashAlg
00369     )
00370 {
00371     LOG_STRING_DEBUG("CPKIFCAPIRaw::Sign(const CPKIFKeyMaterial& key,...)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00372 
00373     //skip raw signature generation for now
00374     RAISE_CRYPTO_EXCEPTION("Signing operations are not implemented for raw key material.", thisComponent, COMMON_NOT_IMPLEMENTED, this);
00375 }
00376 
00377 //support RSA and 3DES (DES, AES)
00399 template <bool _CryptDirection>
00400 void CPKIFCAPIRawImpl::Crypt(
00402     const CPKIFKeyMaterial& key,
00404     unsigned char* pData, 
00406     int nDataLen, 
00408     unsigned char* pResult, 
00411     int* pnResultLen, 
00415     bool pad)
00416 {
00417 #undef CLEANUP
00418 #define CLEANUP \
00419 { \
00420     if (NULL != hSessionKey)  \
00421     {   BOOL succ = CryptDestroyKey(hSessionKey); hSessionKey = NULL;}  \
00422     if (NULL != hTmpProv)  \
00423     {   CryptReleaseContext(hTmpProv, 0); hTmpProv = NULL; }  \
00424     if (NULL != cert)  \
00425     {   CertFreeCertificateContext(cert); cert = NULL; }  \
00426 } 
00427 
00428     LOG_STRING_DEBUG("CPKIFCAPIRaw::Crypt(const CPKIFKeyMaterial& key, ...)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00429 
00430     HCRYPTKEY hSessionKey = 0;
00431     BOOL succ = FALSE;
00432     HCRYPTPROV hTmpProv = NULL;
00433     PCCERT_CONTEXT cert = NULL;
00434 
00435     if(key.ContainsSymmetricKeyMaterial())
00436     {
00437         if(NULL == m_hProv)
00438         {
00439             // Create Exponent of One private key
00440             succ = CreatePrivateExponentOneKey(MS_ENHANCED_PROV, PROV_RSA_FULL,
00441                                                 "__PKIFTEMPCONTAINER", AT_KEYEXCHANGE, &m_hProv, &m_hPubPrivKey);
00442             if (!succ)
00443             {
00444                 if(NULL != m_hPubPrivKey)
00445                 {
00446                     CryptDestroyKey(m_hPubPrivKey); m_hPubPrivKey = NULL;
00447                 }
00448                 if(NULL != m_hProv)
00449                 {
00450                     CryptReleaseContext(m_hProv, 0); m_hProv = NULL;
00451                 }
00452                 std::ostringstream os;
00453                 os << "CreatePrivateExponentOneKey failed: " << GetLastError();;
00454                 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_SESSION_KEY_ENCRYPT_FAILED, this);
00455             }
00456         }
00457 
00458         ALG_ID tmpAlgID = GetSymAlgorithm(key);
00459         if (!ImportPlainSessionBlob(m_hProv, m_hPubPrivKey, tmpAlgID, (unsigned char*)key.GetSymmetricKey(), key.GetSymmetricKeyLength(), &hSessionKey))
00460         {
00461             CLEANUP;
00462             std::ostringstream os;
00463             os << "ImportPlainSessionBlob failed: " << GetLastError();;
00464             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_KEY_IMPORT_FAILED, this);
00465         }
00466 
00467         DWORD tmpMode = 0;
00468         switch(key.GetMode())
00469         {
00470         case PKIFCRYPTO::ECB:
00471             tmpMode = CRYPT_MODE_ECB;
00472             break;
00473         case PKIFCRYPTO::CBC:
00474             tmpMode = CRYPT_MODE_CBC;
00475             if(NULL == key.GetIV())
00476                 throw CPKIFCryptoException(m_parent->thisComponent, CRYPTO_MISSING_IV);
00477             break;
00478         default:
00479             throw CPKIFCryptoException(m_parent->thisComponent, CRYPTO_MODE_NOT_SUPPORTED);
00480         }
00481 
00482         DWORD paddingType = PKCS5_PADDING;
00483         if(pad) 
00484         {
00485             if(!CryptSetKeyParam(hSessionKey, KP_PADDING, (BYTE*)&paddingType, 0))
00486             {
00487                 CLEANUP;
00488                 std::ostringstream os;
00489                 os << "CryptSetKeyParam failed: " << GetLastError();;
00490                 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_SET_MODE_FAILED, this);
00491             }
00492         }
00493 
00494         if(!CryptSetKeyParam(hSessionKey, KP_MODE, (BYTE*)&tmpMode, 0))
00495         {
00496             CLEANUP;
00497             std::ostringstream os;
00498             os << "CryptSetKeyParam failed: " << GetLastError();;
00499             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_SET_MODE_FAILED, this);
00500         }
00501 
00502         if(NULL != key.GetIV() && PKIFCRYPTO::CBC == key.GetMode())
00503         {
00504             if(!CryptSetKeyParam(hSessionKey, KP_IV, (BYTE*)key.GetIV(), 0))
00505             {
00506                 CLEANUP;
00507                 std::ostringstream os;
00508                 os << "CryptSetKeyParam failed: " << GetLastError();;
00509                 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_SET_IV_FAILED, this);
00510             }
00511         }
00512     }
00513     else if(key.ContainsCertificate())
00514     {
00515         //create a certificate context from the cert in key
00516         cert = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 
00517             key.GetCertificate(), key.GetCertificateLength());
00518         if(NULL == cert)
00519         {
00520             CLEANUP;
00521             std::ostringstream os;
00522             os << "CertCreateCertificateContext failed: " << GetLastError();;
00523             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_CREATE_CERT_FAILED, this);
00524         }
00525 
00526         DWORD provType = 0;
00527         //inspect the subject public key algorithm to determine the type of provider to create
00528         if(0 == strcmp(szOID_RSA_RSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId) ||
00529             0 == strcmp(szOID_RSA_MD5RSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId) ||
00530             0 == strcmp(szOID_RSA_SHA1RSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId)) 
00531             provType = PROV_RSA_FULL;
00532         else
00533         {
00534             CLEANUP;
00535             throw CPKIFCryptoException(m_parent->thisComponent, CRYPTO_ALG_NOT_SUPPORTED, "Unsupported encryption algorithm identified in certificate.");
00536         }
00537 
00538         //create a temporary verification context into which the key will be imported
00539         succ = CryptAcquireContext(&hTmpProv, NULL, NULL, provType, CRYPT_VERIFYCONTEXT);
00540         if(!succ)
00541         {
00542             CLEANUP;
00543             std::ostringstream os;
00544             os << "CryptAcquireContext failed: " << GetLastError();;
00545             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_ACQUIRE_CONTEXT_FAILED, this);
00546         }
00547 
00548         //import the key
00549         succ = CryptImportPublicKeyInfo(hTmpProv, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &cert->pCertInfo->SubjectPublicKeyInfo, &hSessionKey);
00550         if(!succ)
00551         {
00552             CLEANUP;
00553             std::ostringstream os;
00554             os << "CryptImportPublicKeyInfo failed: " << GetLastError();;
00555             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_KEY_IMPORT_FAILED, this);
00556         }
00557     }
00558     else
00559     {
00560         throw CPKIFCryptoException(m_parent->thisComponent, COMMON_INVALID_INPUT, "Key parameter contents not recognized.");
00561     }
00562 
00563     int maxOut = *pnResultLen;
00564     *pnResultLen = nDataLen;
00565     int err = 0;
00566     memcpy(pResult, pData, nDataLen);
00567     if(_CryptDirection)
00568     {
00569         BOOL last = TRUE;
00570         DWORD resLen = *pnResultLen;
00571         if(!CryptEncrypt(hSessionKey, NULL, last, 0, pResult, &resLen, maxOut))
00572         {
00573             CLEANUP;
00574             std::ostringstream os;
00575             os << "CryptEncrypt failed: " << GetLastError();;
00576             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, CRYPTO_ENCRYPT_FAILED, this);
00577         }
00578 
00579         *pnResultLen = resLen;
00580 
00581         if(key.ContainsCertificate())
00582         {
00583             //when doing public key encryption we need to byte reverse the result for some reason
00584             ReverseBytes(pResult, *pnResultLen);
00585         }
00586     }
00587     else
00588     {
00589         if(!CryptDecrypt(hSessionKey, NULL, TRUE, 0, pResult, (DWORD*)pnResultLen))
00590         {
00591             CLEANUP;
00592             std::ostringstream os;
00593             os << "CryptDecrypt failed: " << GetLastError();;
00594             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, CRYPTO_DECRYPT_FAILED, this);
00595         }
00596     }
00597 
00598     CLEANUP;
00599 }
00607 void CPKIFCAPIRaw::Decrypt(
00609     const CPKIFKeyMaterial& key, 
00611     unsigned char* pData, 
00613     int nDataLen, 
00615     unsigned char* pResult,
00618     int* pnResultLen, 
00621     bool pad)
00622 {
00623     m_impl->Crypt<false>(key, pData, nDataLen, pResult, pnResultLen, pad);
00624 }
00632 void CPKIFCAPIRaw::Encrypt(
00634     const CPKIFKeyMaterial& key,
00636     unsigned char* pData,
00638     int nDataLen,
00640     unsigned char* pResult,
00643     int* pnResultLen,
00646     bool pad)
00647 {
00648     m_impl->Crypt<true>(key, pData, nDataLen, pResult, pnResultLen, pad);
00649 }
00660 HCRYPTHASH CreateHashObjectFromData(
00662     HCRYPTPROV hProv,
00665     unsigned char* pHashData,
00667     int nHashDataLen)
00668 {
00669 #undef CLEANUP
00670 #define CLEANUP \
00671 { \
00672     if (NULL != hHash)  \
00673     {   CryptDestroyHash(hHash); hHash = NULL; }  \
00674 } 
00675 
00676     LOG_STRING_DEBUG("CreateHashObjectFromData(HCRYPTPROV hProv, unsigned char* pHashData, int nHashDataLen)", TOOLKIT_CRYPTO_CAPIRAW, 0, NULL);
00677 
00678     HCRYPTHASH hHash = NULL;
00679 
00680     //determine the hash algorithm from the length of the data (this function can throw)
00681     ALG_ID HashAlg = GetHashAlg((PKIFCRYPTO::HASH_ALG)nHashDataLen);
00682 
00683     //create the hash
00684     if(!CryptCreateHash(hProv, HashAlg, NULL, 0, &hHash))
00685     {
00686         CLEANUP;
00687 
00688         std::ostringstream os;
00689         os << "CryptCreateHash failed: " << GetLastError();;
00690         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
00691     }
00692 
00693     DWORD hSize = 0;
00694     DWORD hSizeSize = sizeof(hSize);
00695 
00696     //do a sanity check on the length expected vs. the length we intend to pass
00697     if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hSize, &hSizeSize, 0))
00698     {
00699         CLEANUP;
00700         std::ostringstream os;
00701         os << "CryptGetHashParam failed: " << GetLastError();;
00702         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_MISC_HASH_CALL_FAILED, NULL);
00703     }
00704     if(nHashDataLen != hSize)
00705     {
00706         CLEANUP;
00707         RAISE_CRYPTO_EXCEPTION("Hash sizes do not match.  Could not set hash object for signing.", TOOLKIT_CRYPTO, PKIFCAPI_MISC_HASH_CALL_FAILED, NULL);
00708     }
00709 
00710     //set the hash value on the hash object
00711     if(!CryptSetHashParam(hHash, HP_HASHVAL, pHashData, 0))
00712     {
00713         CLEANUP;
00714         std::ostringstream os;
00715         os << "CryptSetHashParam failed: " << GetLastError();;
00716         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_MISC_HASH_CALL_FAILED, NULL);
00717     }
00718 
00719     //return the hash
00720     return hHash;
00721 }
00734 bool _Verify(
00736     const CPKIFKeyMaterial& key,
00739     unsigned char* pHashData,
00741     int nHashDataLen,
00743     unsigned char* pSignature,
00745     int nSignatureLen)
00746 {
00747 #undef CLEANUP
00748 #define CLEANUP \
00749 { \
00750     if (capiSpki.Algorithm.Parameters.cbData)  \
00751     {   delete[] capiSpki.Algorithm.Parameters.pbData; capiSpki.Algorithm.Parameters.pbData = NULL; capiSpki.Algorithm.Parameters.cbData = 0;}  \
00752     if (clearParams)  \
00753     {   delete[] cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData; cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData = NULL; cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData = 0;}  \
00754     if (NULL != cert)  \
00755     {   CertFreeCertificateContext(cert); cert = NULL; }  \
00756     if (NULL != hHash)  \
00757     {   CryptDestroyHash(hHash); hHash = NULL; }  \
00758     if (NULL != hKey)  \
00759     {   CryptDestroyKey(hKey); hKey = NULL; }  \
00760     if (NULL != hProv)  \
00761     {   CryptReleaseContext(hProv, 0); hProv = NULL; }  \
00762 } 
00763 
00764     LOG_STRING_DEBUG("_Verify(const CPKIFKeyMaterial& key, unsigned char* pHashData, int nHashDataLen, unsigned char* pSignature, int nSignatureLen)", TOOLKIT_CRYPTO_CAPIRAW, 0, NULL);
00765 
00766     BOOL succ = FALSE;
00767     HCRYPTPROV hProv = NULL;
00768     HCRYPTKEY hKey = NULL;
00769     HCRYPTHASH hHash = NULL;
00770     PCCERT_CONTEXT cert = NULL;
00771     DWORD provType = 0;
00772     bool clearParams = false;
00773 
00774     ALG_ID alg;
00775     CERT_PUBLIC_KEY_INFO capiSpki;
00776     memset(&capiSpki, 0, sizeof(CERT_PUBLIC_KEY_INFO));
00777 
00778     //get the key needed for verification
00779     if(key.ContainsCertificate())
00780     {
00781         //create a certificate context from the cert in key
00782         cert = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 
00783             key.GetCertificate(), key.GetCertificateLength());
00784         if(NULL == cert)
00785         {
00786             CLEANUP;
00787             std::ostringstream os;
00788             os << "CertCreateCertificateContext failed: " << GetLastError();;
00789             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_CERT_FAILED, NULL);
00790         }
00791 
00792 
00793         if(0 == strcmp(szOID_RSA_RSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId) ||
00794             0 == strcmp(szOID_RSA_MD5RSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId) ||
00795             0 == strcmp(szOID_RSA_SHA1RSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId)) 
00796             alg = CALG_RSA_SIGN;
00797         else
00798             alg = CALG_DSS_SIGN;
00799         provType = GetProvType(cert);
00800 
00801         //create a temporary verification context into which the key will be imported
00802         succ = CryptAcquireContext(&hProv, NULL, NULL, provType, CRYPT_VERIFYCONTEXT);
00803         if(!succ)
00804         {
00805             CLEANUP;
00806             std::ostringstream os;
00807             os << "CryptAcquireContext failed: " << GetLastError();;
00808             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_ACQUIRE_CONTEXT_FAILED, NULL);
00809         }
00810 
00811         if(CALG_DSS_SIGN == alg)
00812         {
00813             CPKIFAlgorithmIdentifierPtr workingParams = key.GetWorkingParameters();
00814             if(0 == cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData &&
00815                 workingParams != (CPKIFAlgorithmIdentifier*)NULL)
00816             {
00817                 CPKIFBufferPtr params = workingParams->parameters();
00818                 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData = params->GetLength();
00819                 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData = new unsigned char[params->GetLength()];
00820                 memcpy(cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData, (BYTE*)params->GetBuffer(), params->GetLength());
00821                 //ReverseBytes(cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData);
00822                 clearParams = true;
00823             }
00824         }
00825 
00826         //import the key
00827         succ = CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &cert->pCertInfo->SubjectPublicKeyInfo, &hKey);
00828         if(!succ)
00829         {
00830             CLEANUP;
00831             std::ostringstream os;
00832             os << "CryptImportPublicKeyInfo failed: " << GetLastError();;
00833             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_KEY_IMPORT_FAILED, NULL);
00834         }
00835     }
00836     else if(key.ContainsPublicKeyMaterial())
00837     {
00838         CPKIFSubjectPublicKeyInfoPtr spki = key.GetSubjectPublicKeyInfo();
00839         CPKIFAlgorithmIdentifierPtr spkiAlg = spki->alg();
00840         CPKIFOIDPtr spkiAlgOid = spkiAlg->oid();
00841         const char* spkifAlgOidString = spkiAlgOid->ToString();
00842 
00843         capiSpki.Algorithm.Parameters.cbData = 0;
00844 
00845         if(0 == strcmp(szOID_RSA_RSA, spkifAlgOidString))
00846         {
00847             capiSpki.Algorithm.pszObjId = szOID_RSA_RSA;
00848             alg = CALG_RSA_SIGN;
00849         }
00850         else if(0 == strcmp(szOID_RSA_MD5RSA, spkifAlgOidString))
00851         {
00852             capiSpki.Algorithm.pszObjId = szOID_RSA_MD5RSA;
00853             alg = CALG_RSA_SIGN;
00854         }
00855         else if(0 == strcmp(szOID_RSA_SHA1RSA, spkifAlgOidString)) 
00856         {
00857             capiSpki.Algorithm.pszObjId = szOID_RSA_SHA1RSA;
00858             alg = CALG_RSA_SIGN;
00859         }
00860         else
00861         {
00862             capiSpki.Algorithm.pszObjId = szOID_X957_DSA;
00863             alg = CALG_DSS_SIGN;
00864         }
00865 
00866         provType = GetProvType(spkifAlgOidString);
00867 
00868         CPKIFBufferPtr keyBuf = spki->rawKey();
00869         capiSpki.PublicKey.cbData = keyBuf->GetLength();
00870         capiSpki.PublicKey.pbData = (BYTE*)keyBuf->GetBuffer();
00871 
00872         //create a temporary verification context into which the key will be imported
00873         succ = CryptAcquireContext(&hProv, NULL, NULL, provType, CRYPT_VERIFYCONTEXT);
00874         if(!succ)
00875         {
00876             CLEANUP;
00877             std::ostringstream os;
00878             os << "CryptAcquireContext failed: " << GetLastError();;
00879             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_ACQUIRE_CONTEXT_FAILED, NULL);
00880         }
00881 
00882         if(CALG_DSS_SIGN == alg)
00883         {
00884             CPKIFAlgorithmIdentifierPtr workingParams = key.GetWorkingParameters();
00885             if(0 == capiSpki.Algorithm.Parameters.cbData &&
00886                 workingParams != (CPKIFAlgorithmIdentifier*)NULL)
00887             {
00888                 CPKIFBufferPtr params = workingParams->parameters();
00889                 capiSpki.Algorithm.Parameters.cbData = params->GetLength();
00890                 capiSpki.Algorithm.Parameters.pbData = new unsigned char[params->GetLength()];
00891                 memcpy(capiSpki.Algorithm.Parameters.pbData, (BYTE*)params->GetBuffer(), params->GetLength());
00892                 //ReverseBytes(cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData);
00893                 clearParams = false;
00894             }
00895         }
00896 
00897         //import the key
00898         succ = CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &capiSpki, &hKey);
00899         if(!succ)
00900         {
00901             CLEANUP;
00902             std::ostringstream os;
00903             os << "CryptImportPublicKeyInfo failed: " << GetLastError();;
00904             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_KEY_IMPORT_FAILED, NULL);
00905         }
00906     }
00907     else
00908     {
00909         CLEANUP;
00910         RAISE_CRYPTO_EXCEPTION("CPKIFCAPIRaw::Verify only supports certificate-based key material", TOOLKIT_CRYPTO, PKIFCAPI_KEY_MATERIAL_NOT_SUPPORTED, NULL);
00911     }
00912 
00913     //at this point we must have a valid hProv and hKey - now we need a hash object 
00914     //that contains the hashed data passed in (this function throws upon failure
00915     try
00916     {
00917         hHash = CreateHashObjectFromData(hProv, pHashData, nHashDataLen);
00918     }
00919     catch(CPKIFException& e)
00920     {
00921         CLEANUP;
00922         throw e;
00923     }
00924 
00925     unsigned char revSig[513];
00926     if(CALG_RSA_SIGN == alg)
00927     {
00928         for(int ii = nSignatureLen-1, jj = 0; ii >= 0; --ii, ++jj)
00929             revSig[ii] = pSignature[jj];
00930     }
00931     else
00932     {
00933         unsigned char pRevSig[(MAXHASH*2)+5];
00934         const int maxRorS = nHashDataLen;
00935         bool skipRevStuff = false;
00936         int rlen = maxRorS, slen = maxRorS;
00937         try
00938         {
00939             //try to parse DSS signature
00940             CACASNWRAPPER_CREATE(Dss_Sig_Value, tmpPDU);
00941             ASN1OpenType asnOpenType;
00942             asnOpenType.data = pSignature;
00943             asnOpenType.numocts = nSignatureLen;
00944             Dss_Sig_Value* tmpAttr = tmpPDU.Decode(asnOpenType);
00945     
00946             atob((char*)pRevSig, (char*)tmpAttr->r + 2, (unsigned int*)&rlen);
00947             ReverseBytes(pRevSig, rlen);
00948             unsigned char* p = pRevSig + rlen; //point to end of buf
00949             if(rlen >= nHashDataLen)
00950             {
00951                 int diff = rlen - nHashDataLen;
00952                 while(diff > 0)
00953                 {
00954                     --p; --diff;
00955                 }
00956             }
00957             else
00958             {
00959                 int diff = nHashDataLen - rlen;
00960                 while(diff > 0)
00961                 {
00962                     *p = 0x00; ++p;
00963                     --diff;
00964                 }
00965             }
00966 
00967             //changed from +20 to +rLen
00968             atob((char*)p, (char*)tmpAttr->s + 2, (unsigned int*)&slen);
00969             ReverseBytes(p, slen);
00970             p = p + slen; //point to end of buf
00971             if(slen >= nHashDataLen)
00972             {
00973                 int diff = slen - nHashDataLen;
00974                 while(diff > 0)
00975                 {
00976                     --p; --diff;
00977                 }
00978             }
00979             else
00980             {
00981                 int diff = nHashDataLen - slen;
00982                 while(diff > 0)
00983                 {
00984                     *p = 0x00; ++p;
00985                     --diff;
00986                 }
00987             }
00988             nSignatureLen = nHashDataLen*2;
00989             memcpy(revSig, pRevSig, nSignatureLen);
00990             skipRevStuff = true;
00991         }
00992         catch(CPKIFException& e)
00993         {
00994             //if that fails assume it's  simply r and s concatenated
00995             if(nSignatureLen > MAXHASH)
00996                 throw e;
00997 
00998             //EXCEPTION DELETION
00999             //This is deleted on the chance that the signature is not DER encoded but simply is a concatenated
01000             //r and s - we'll try it that way and fail below if it doesn't work out
01001             //delete e;
01002 
01003             memcpy(revSig, pSignature, nSignatureLen);
01004             ReverseBytes(revSig, nSignatureLen/2);
01005             ReverseBytes(revSig + nSignatureLen/2, nSignatureLen/2);
01006             skipRevStuff = true;
01007         }
01008         /*
01009         if(!skipRevStuff)
01010         {
01011             //at this point either r or s may be in need leading zeroes removed (i.e. those added by DER)
01012             //or may need trailing (because it's byte reversed) zeroes added (i.e. if the actual integer had
01013             //leading zeroes that were removed by DER)
01014             //in boh cases the bytes are being reversed from pRevSig (which despite its name has the bytes 
01015             //in forward order) into revSig
01016 
01017             //added num leading zeroes garbage - 11/6
01018             unsigned int numLeadingZeroes = 0;
01019             for(unsigned int zz = 0; zz < rlen && rlen > maxRorS; ++zz)
01020             {
01021                 if(0 == pRevSig[zz])
01022                     numLeadingZeroes++;
01023                 else
01024                     break;
01025             }
01026 
01027             int padding = rlen < maxRorS ? maxRorS - rlen : 0;
01028 
01029             //set ii to the end of r (rlen - 1 (due to zero based indexing) - number of leading zeroes)
01030             //set jj = to the number of leading zeroes (thus indexing beyond the leading zeroes)
01031             for(int ii = maxRorS-1-numLeadingZeroes-padding, jj = numLeadingZeroes; ii >= 0; --ii, ++jj)
01032                 revSig[ii] = pRevSig[jj]; 
01033 
01034             //set ii = to the number of bytes copied into revSig from pRevSig
01035             for(int ii = rlen-numLeadingZeroes; ii < maxRorS; ++ii)
01036                 revSig[ii] = 0x00;
01037 
01038             //added num leading zeroes garbage - 11/6
01039             unsigned int numLeadingZeroes2 = 0;
01040             for(unsigned int zz = (rlen); zz < (slen+rlen) && slen > maxRorS; ++zz)
01041             {
01042                 if(0 == pRevSig[zz])
01043                     numLeadingZeroes2++;
01044                 else
01045                     break;
01046             }
01047 
01048             nSignatureLen = nHashDataLen*2;
01049 
01050             padding = slen < maxRorS ? maxRorS - slen : 0;
01051             for(int ii = nSignatureLen-1-numLeadingZeroes2-padding, jj = rlen+numLeadingZeroes2; jj < (rlen+slen) && ii >= maxRorS; --ii, ++jj)
01052                 revSig[ii] = pRevSig[jj];
01053 
01054             for(int ii = padding; ii > 0; --ii)
01055                 revSig[nSignatureLen - ii] = 0x00;
01056         }
01057         */
01058     }
01059 
01060     //given hHash and hKey verify the signature
01061     succ = CryptVerifySignature(hHash, revSig, nSignatureLen, hKey, NULL, 0);
01062     if(!succ)
01063     {
01064         CLEANUP;
01065         int errcode = GetLastError();
01066 
01067         return false;
01068     }
01069 
01070     CLEANUP;
01071     return true;
01072 }
01081 bool CPKIFCAPIRaw::VerifyCertificate(
01084     const CPKIFCertificate& issCert,
01087     const CPKIFCertificate& subCert)
01088 {
01089     LOG_STRING_DEBUG("CPKIFCAPIRaw::VerifyCertificate(const CPKIFCertificate& issCert, const CPKIFCertificate& subCert)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
01090 
01091     CPKIFBufferPtr issBuf = issCert.Encoded();
01092     CPKIFBufferPtr subBuf = subCert.Encoded();
01093 
01094     PCCERT_CONTEXT issCtx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
01095         issBuf->GetBuffer(), issBuf->GetLength());
01096 //  PCCERT_CONTEXT subCtx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
01097 //      subBuf->GetBuffer(), subBuf->GetLength());
01098 
01099     if(!issCtx)
01100     {
01101         return false;
01102     }
01103 
01104     int err = 0;
01105     BOOL b = CryptVerifyCertificateSignature(NULL,X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
01106         subBuf->GetBuffer(), subBuf->GetLength(), &issCtx->pCertInfo->SubjectPublicKeyInfo);
01107     if(!b)
01108     {
01109         err = GetLastError();
01110     }
01111 
01112     CertFreeCertificateContext(issCtx);
01113 //  CertFreeCertificateContext(subCtx);
01114 
01115     return TRUE == b;
01116 }
01117 
01118 //support RSA w/ SHA1 (DSS and MD5)
01128 bool CPKIFCAPIRaw::Verify(
01130     const CPKIFKeyMaterial& key,
01132     unsigned char* pHashData, 
01134     int nHashDataLen,
01136     unsigned char* pSignature,
01138     int nSignatureLen,
01140     PKIFCRYPTO::HASH_ALG hashAlg
01141     )
01142 {
01143     //no state 
01144     return _Verify(key, pHashData, nHashDataLen, pSignature, nSignatureLen);
01145 }
01158 void CPKIFCAPIRaw::GenRandom(
01160     unsigned char* buf, 
01162     int len)
01163 {
01164     //This function will use the context in m_hProv if present, otherwise a temp context is created.
01165     //CryptGenRandom is called to retrieve the specified number of bytes.  The buf param is assumed
01166     //to be at least len bytes in size.
01167 
01168     LOG_STRING_DEBUG("CPKIFCAPIRaw::GenRandom(unsigned char* buf, int len)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
01169 
01170     if(NULL == buf || 0 == len)
01171         return; //no need to raise an exception.  the caller asks for nothing and received nothing.
01172 
01173     HCRYPTPROV hProv = NULL;
01174 
01175     //get a pointer to existing context or create a temp
01176     if(NULL != m_impl->m_hProv)
01177         hProv = m_impl->m_hProv;
01178     else
01179     {
01180         if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
01181         {
01182             std::ostringstream os;
01183             os << "CryptAcquireContext failed: " << GetLastError();;
01184             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_ACQUIRE_CONTEXT_FAILED, NULL);
01185         }
01186     }
01187 
01188     //use the context to get requested amount of random data
01189     if(!CryptGenRandom(hProv, len, buf))
01190     {
01191         std::ostringstream os;
01192         os << "CryptGenRandom failed: " << GetLastError();;
01193         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_GEN_RANDOM_FAILED, NULL);
01194     }
01195 
01196     //release the context only if necessary
01197     if(NULL == m_impl->m_hProv)
01198         CryptReleaseContext(hProv, 0);
01199 }
01214 IPKIFHashContext* CPKIFCAPIRaw::HashInit(
01217     PKIFCRYPTO::HASH_ALG alg)
01218 {
01219     LOG_STRING_DEBUG("CPKIFCAPIRaw::HashInit(HASH_ALG alg)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
01220 
01221     //support SHA1 (MD5)
01222     ALG_ID hashAlg;
01223     switch(alg)
01224     {
01225     case PKIFCRYPTO::SHA1:
01226         hashAlg = CALG_SHA1;
01227         break;
01228 #ifndef FIPS_MODE
01229     case PKIFCRYPTO::MD5:
01230         hashAlg = CALG_MD5;
01231         break;
01232 #endif
01233         // XXX *** NO CAPI CONSTANT FOR SHA224
01234     case PKIFCRYPTO::SHA256:
01235         hashAlg = CALG_SHA_256;
01236         break;
01237     case PKIFCRYPTO::SHA384:
01238         hashAlg = CALG_SHA_384;
01239         break;
01240     case PKIFCRYPTO::SHA512:
01241         hashAlg = CALG_SHA_512;
01242         break;
01243     default:
01244         std::ostringstream os;
01245         os << "Unsupported hash algorithm encountered: " << alg;
01246         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, CRYPTO_ALG_NOT_SUPPORTED, NULL);
01247     }
01248 
01249     //create a hash context object and populate it with context and hash objects
01250     //throw bad_alloc; nothing to clean up in this function
01251     CPKIFCAPIHashContext* hashCtx = new CPKIFCAPIHashContext();
01252     if(!CryptAcquireContext(&hashCtx->m_hashContext, NULL, m_impl->m_provName, 
01253         m_impl->m_provType ? m_impl->m_provType : PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
01254     {
01255         delete hashCtx;
01256 
01257         std::ostringstream os;
01258         os << "CryptAcquireContext failed: " << GetLastError();;
01259         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_ACQUIRE_CONTEXT_FAILED, NULL);
01260     }
01261 
01262     if(!CryptCreateHash(hashCtx->m_hashContext, hashAlg, NULL, 0, &hashCtx->m_hash))
01263     {
01264         delete hashCtx;
01265 
01266         std::ostringstream os;
01267         os << "CryptCreateHash failed: " << GetLastError();;
01268         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_CREATE_HASH_FAILED, NULL);
01269     }
01270 
01271     return hashCtx;
01272 }
01287 void CPKIFCAPIRaw::HashUpdate(
01289     IPKIFHashContext* hash, 
01291     unsigned char* pData, 
01293     int nDataLen)
01294 {
01295     LOG_STRING_DEBUG("CPKIFCAPIRaw::HashUpdate(IPKIFHashContext* hash, unsigned char* pData, int nDataLen)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
01296 
01297     //sanity check the inputs: 
01298     //  hash must not be NULL, must be of a type this class supports and must not be empty
01299     //  pData MAY be NULL (if not it is assumed to be at least nDataLen bytes)
01300     //  nDataLen must not be less than zero
01301     if(NULL == hash/* || NULL == pData || 0 >= nDataLen*/ || 0 > nDataLen)
01302         throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HashUpdate.");
01303 
01304     //cast the hash context to the type this class handles.  if the cast fails
01305     //then the context is not the correct type.
01306     CPKIFCAPIHashContext* hashCtx = dynamic_cast<CPKIFCAPIHashContext*>(hash);
01307     if(NULL == hashCtx)
01308         throw CPKIFCryptoException(thisComponent, PKIFCAPI_INCORRECT_HASH_CONTEXT, "Incorrect hash context passed to HashUpdate.");
01309 
01310     if(NULL == hashCtx->m_hashContext || NULL == hashCtx->m_hash)
01311         throw CPKIFCryptoException(thisComponent, PKIFCAPI_EMPTY_HASH_CONTEXT, "Empty hash context passed to HashUpdate.");
01312 
01313     if(!CryptHashData(hashCtx->m_hash, pData, nDataLen, 0))
01314     {
01315         std::ostringstream os;
01316         os << "CryptHashData failed: " << GetLastError();;
01317         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_MISC_HASH_CALL_FAILED, NULL);
01318     }
01319 }
01335 void CPKIFCAPIRaw::HashFinal(
01337     IPKIFHashContext* hash,
01339     unsigned char* pResult, 
01342     int* pnResultLen)
01343 {
01344     LOG_STRING_DEBUG("CPKIFCAPIRaw::HashFinal(IPKIFHashContext* hash, unsigned char* pResult, int* pnResultLen)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
01345 
01346     //sanity check the inputs: 
01347     //  hash must not be NULL, must be of a type this class supports and must not be empty
01348     //  result must not be NULL (it is assumed to be at least *pnResultLen bytes)
01349     //  pnResultLen must not be NULL and *pnResultLen must not be less than or equal to zero
01350     if(NULL == hash || NULL == pResult || NULL == pnResultLen || 0 >= *pnResultLen)
01351         throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HashFinal.");
01352 
01353     CPKIFCAPIHashContext* hashCtx = dynamic_cast<CPKIFCAPIHashContext*>(hash);
01354     if(NULL == hashCtx)
01355         throw CPKIFCryptoException(thisComponent, PKIFCAPI_INCORRECT_HASH_CONTEXT, "Incorrect hash context passed to HashFinal.");
01356 
01357     if(NULL == hashCtx->m_hashContext || NULL == hashCtx->m_hash)
01358         throw CPKIFCryptoException(thisComponent, PKIFCAPI_EMPTY_HASH_CONTEXT, "Empty hash context passed to HashUpdate.");
01359 
01360     //terminate the hash and retrieve the hash value
01361     if(!CryptGetHashParam(hashCtx->m_hash, HP_HASHVAL, pResult, (DWORD*)pnResultLen, 0)) 
01362     {
01363         std::ostringstream os;
01364         os << "CryptGetHashParam failed: " << GetLastError();;
01365         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_MISC_HASH_CALL_FAILED, NULL);
01366     }
01367 }
01390 IPKIFRawCryptContext* CPKIFCAPIRaw::CryptInit(
01393     const CPKIFKeyMaterial& key,
01395     bool pad)
01396 {
01397     LOG_STRING_DEBUG("CPKIFCAPIRaw::CryptInit(const CPKIFKeyMaterial& key)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
01398 
01399     //throw bad_alloc; nothing to clean up in this function
01400     CPKIFCAPIRawCryptContext* cryptContext = new CPKIFCAPIRawCryptContext;
01401 
01402     BOOL succ = FALSE;
01403     PCCERT_CONTEXT cert = NULL;
01404 
01405     if(key.ContainsSymmetricKeyMaterial())
01406     {
01407         if(NULL == m_impl->m_hProv)
01408         {
01409             // Create Exponent of One private key
01410             succ = CreatePrivateExponentOneKey(MS_ENHANCED_PROV, PROV_RSA_FULL,
01411                                                 "__PKIFTEMPCONTAINER", AT_KEYEXCHANGE, &m_impl->m_hProv, &m_impl->m_hPubPrivKey);
01412             if (!succ)
01413             {
01414                 if(NULL != m_impl->m_hPubPrivKey)
01415                 {
01416                     CryptDestroyKey(m_impl->m_hPubPrivKey); m_impl->m_hPubPrivKey = NULL;
01417                 }
01418                 if(NULL != m_impl->m_hProv)
01419                 {
01420                     CryptReleaseContext(m_impl->m_hProv, 0); m_impl->m_hProv = NULL;
01421                 }
01422                 std::ostringstream os;
01423                 os << "CreatePrivateExponentOneKey failed: " << GetLastError();;
01424                 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_SESSION_KEY_ENCRYPT_FAILED, NULL);
01425             }
01426         }
01427 
01428         ALG_ID tmpAlgID = GetSymAlgorithm(key);
01429         if (!ImportPlainSessionBlob(m_impl->m_hProv, m_impl->m_hPubPrivKey, tmpAlgID, (unsigned char*)key.GetSymmetricKey(), key.GetSymmetricKeyLength(), &cryptContext->m_sessionKey))
01430         {
01431             delete cryptContext;
01432             std::ostringstream os;
01433             os << "ImportPlainSessionBlob failed: " << GetLastError();;
01434             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_KEY_IMPORT_FAILED, NULL);
01435         }
01436 
01437         DWORD tmpMode = 0;
01438         switch(key.GetMode())
01439         {
01440         case PKIFCRYPTO::ECB:
01441             tmpMode = CRYPT_MODE_ECB;
01442             break;
01443         case PKIFCRYPTO::CBC:
01444             tmpMode = CRYPT_MODE_CBC;
01445             if(NULL == key.GetIV())
01446                 throw CPKIFCryptoException(thisComponent, CRYPTO_MISSING_IV);
01447             break;
01448         default:
01449             throw CPKIFCryptoException(thisComponent, CRYPTO_MODE_NOT_SUPPORTED);
01450         }
01451 
01452         if(!CryptSetKeyParam(cryptContext->m_sessionKey, KP_MODE, (BYTE*)&tmpMode, 0))
01453         {
01454             delete cryptContext;
01455             std::ostringstream os;
01456             os << "CryptSetKeyParam failed: " << GetLastError();;
01457             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_SET_MODE_FAILED, NULL);
01458         }
01459 
01460         if(NULL != key.GetIV() && PKIFCRYPTO::CBC == key.GetMode())
01461         {
01462             if(!CryptSetKeyParam(cryptContext->m_sessionKey, KP_IV, (BYTE*)key.GetIV(), 0))
01463             {
01464                 delete cryptContext;
01465                 std::ostringstream os;
01466                 os << "CryptSetKeyParam failed: " << GetLastError();;
01467                 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_SET_IV_FAILED, NULL);
01468             }
01469         }
01470 
01471         CPKIFAlgorithm* a = CPKIFAlgorithm::GetAlg(key.GetSymmetricKeyAlgorithm(), key.GetMode());
01472         cryptContext->m_blockLen = a->BlockSize();
01473         cryptContext->m_padbuf = new unsigned char[cryptContext->m_blockLen];
01474         memset(cryptContext->m_padbuf,0x00,cryptContext->m_blockLen);
01475 
01476         cryptContext->m_bNeedsPad = pad;
01477     }
01478     else if(key.ContainsCertificate())
01479     {
01480         //create a certificate context from the cert in key
01481         cert = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 
01482             key.GetCertificate(), key.GetCertificateLength());
01483         if(NULL == cert)
01484         {
01485             delete cryptContext;
01486             std::ostringstream os;
01487             os << "CertCreateCertificateContext failed: " << GetLastError();;
01488             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_CREATE_CERT_FAILED, NULL);
01489         }
01490 
01491         DWORD provType = 0;
01492         //inspect the subject public key algorithm to determine the type of provider to create
01493         if(0 == strcmp(szOID_RSA_RSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId) ||
01494             0 == strcmp(szOID_RSA_MD5RSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId) ||
01495             0 == strcmp(szOID_RSA_SHA1RSA, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId)) 
01496             provType = PROV_RSA_FULL;
01497         else
01498         {
01499             delete cryptContext;
01500             CertFreeCertificateContext(cert);
01501             RAISE_CRYPTO_EXCEPTION("Unsupported encryption algorithm identified in certificate.", thisComponent, CRYPTO_ALG_NOT_SUPPORTED, NULL);
01502         }
01503 
01504         //create a temporary verification context into which the key will be imported
01505         succ = CryptAcquireContext(&cryptContext->m_cryptContext, NULL, NULL, provType, CRYPT_VERIFYCONTEXT);
01506         if(!succ)
01507         {
01508             delete cryptContext;
01509             CertFreeCertificateContext(cert);
01510             std::ostringstream os;
01511             os << "CryptAcquireContext failed: " << GetLastError();;
01512             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_ACQUIRE_CONTEXT_FAILED, NULL);
01513         }
01514 
01515         //import the key
01516         succ = CryptImportPublicKeyInfo(cryptContext->m_cryptContext, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &cert->pCertInfo->SubjectPublicKeyInfo, &cryptContext->m_sessionKey);
01517         if(!succ)
01518         {
01519             delete cryptContext;
01520             CertFreeCertificateContext(cert);
01521             std::ostringstream os;
01522             os << "CryptImportPublicKeyInfo failed: " << GetLastError();;
01523             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_KEY_IMPORT_FAILED, NULL);
01524         }
01525 
01526         cryptContext->m_bFromCert = true;
01527         CertFreeCertificateContext(cert);
01528     }
01529     else
01530     {
01531         delete cryptContext;
01532         throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "Key parameter contents not recognized.");
01533     }
01534 
01535     return cryptContext;
01536 }
01547 void CPKIFCAPIRaw::Decrypt(
01550     IPKIFRawCryptContext* cryptContext, 
01552     unsigned char* pData, 
01554     int nDataLen, 
01556     unsigned char* pResult, 
01559     int* pnResultLen, 
01562     bool final)
01563 {
01564     m_impl->CryptFunc<false>(cryptContext, pData, nDataLen, pResult, pnResultLen, final);
01565 }
01576 void CPKIFCAPIRaw::Encrypt(
01579     IPKIFRawCryptContext* cryptContext, 
01581     unsigned char* pData, 
01583     int nDataLen, 
01585     unsigned char* pResult, 
01588     int* pnResultLen, 
01591     bool final)
01592 {
01593     m_impl->CryptFunc<true>(cryptContext, pData, nDataLen, pResult, pnResultLen, final);
01594 }
01595 
01606 template <bool _CryptDirection>
01607 void CPKIFCAPIRawImpl::CryptFunc(
01610     IPKIFRawCryptContext* cryptContext,
01612     unsigned char* pData,
01614     int nDataLen,
01616     unsigned char* pResult,
01618     int* pnResultLen,
01621     bool final)
01622 {
01623     LOG_STRING_DEBUG("CPKIFCAPIRaw::CryptFunc(IPKIFRawCryptContext* cryptContext, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool final)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
01624 
01625     CPKIFCAPIRawCryptContext* icc = dynamic_cast<CPKIFCAPIRawCryptContext*>(cryptContext);
01626     // If it's an asymmetric operation or the caller is handling the padding on its own, just call through straight
01627     // to the CAPI function
01628     if(icc->m_bFromCert || !icc->m_bNeedsPad)
01629     {
01630         int maxOut = *pnResultLen;
01631         *pnResultLen = nDataLen;
01632         int err = 0;
01633         memcpy(pResult, pData, nDataLen);
01634         if(_CryptDirection)
01635         {
01636             DWORD resLen = *pnResultLen;
01637             if(!CryptEncrypt(icc->m_sessionKey, NULL, final, 0, pResult, &resLen, maxOut))
01638             {
01639                 std::ostringstream os;
01640                 os << "CryptEncrypt failed: " << GetLastError();;
01641                 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, CRYPTO_ENCRYPT_FAILED, NULL);
01642             }
01643 
01644             *pnResultLen = resLen;
01645 
01646             if(icc->m_bFromCert)
01647             {
01648                 //when doing public key encryption we need to byte reverse the result for some reason
01649                 ReverseBytes(pResult, *pnResultLen);
01650             }
01651         }
01652         else
01653         {
01654             if(!CryptDecrypt(icc->m_sessionKey, NULL, final, 0, pResult, (DWORD*)pnResultLen))
01655             {
01656                 std::ostringstream os;
01657                 os << "CryptDecrypt failed: " << GetLastError();;
01658                 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, CRYPTO_DECRYPT_FAILED, NULL);
01659             }
01660         }
01661         return;
01662     }
01663     
01664     
01665     int maxOut = *pnResultLen;
01666     int inLen = nDataLen;
01667     unsigned char * start = pData;
01668     unsigned char * outBuf = pResult;
01669 
01670     DWORD updateLen = 0;
01671     DWORD padUpdateLen = 0;
01672     *pnResultLen = 0;
01673     unsigned int finalLen = 0;
01674 
01675     *pnResultLen = 0;
01676     int err = 0;
01677     if(_CryptDirection)
01678     {
01679         DWORD resLen = *pnResultLen;
01680         if(final)
01681         {
01682             // XXX *** assert maxout >= padlen + inlen + blocksize
01683             if(icc->m_padlen) {
01684                 memcpy(outBuf,icc->m_padbuf,icc->m_padlen);
01685             }
01686             if(start && inLen) memcpy(outBuf + icc->m_padlen,start,inLen);
01687             updateLen = inLen + icc->m_padlen;
01688             icc->m_padlen = 0;
01689             if(!CryptEncrypt(icc->m_sessionKey, NULL, final, 0, outBuf, &updateLen, maxOut))
01690             {
01691                 std::ostringstream os;
01692                 os << "CryptEncrypt failed: " << GetLastError();;
01693                 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, CRYPTO_ENCRYPT_FAILED, NULL);
01694             }
01695             *pnResultLen = updateLen;
01696             return;
01697         }
01698 
01699         // if it's not final, we need to have input
01700         if(!start || !inLen) return;
01701         int leftInBlock = icc->m_blockLen - icc->m_padlen;
01702 
01703 
01704         // if there's not enough to exceed the pad buffer, fill the pad buffer and bail
01705         if(leftInBlock >= inLen) {
01706             memcpy(icc->m_padbuf,start,inLen);
01707             icc->m_padlen += inLen;
01708             *pnResultLen = 0;
01709             return;
01710         }
01711 
01712         // if we're here, we got more than a cipherblock
01713         // 1. Empty the pad buffer
01714         memcpy(outBuf,icc->m_padbuf,icc->m_padlen);
01715         updateLen = icc->m_padlen;
01716         icc->m_padlen = 0;
01717         
01718         // 2. calculate how many bytes go into the pad buffer
01719         int trailing = (inLen + updateLen) % icc->m_blockLen ? 
01720             (inLen + updateLen) % icc->m_blockLen : icc->m_blockLen;
01721 
01722         // 3. empty the input buffer
01723         int copied = inLen - trailing;
01724         memcpy(outBuf+updateLen,start,copied);
01725         start += copied;
01726         updateLen += copied;
01727 
01728         // 4. encrypt
01729         if(!CryptEncrypt(icc->m_sessionKey, NULL, final, 0, outBuf, &updateLen, maxOut))
01730         {
01731             std::ostringstream os;
01732             os << "CryptEncrypt failed: " << GetLastError();;
01733             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, CRYPTO_ENCRYPT_FAILED, NULL);
01734         }
01735 
01736         // 5. copy off the trailing bytes for next time
01737         memcpy(icc->m_padbuf,start,trailing);
01738         icc->m_padlen += trailing;
01739         *pnResultLen = updateLen;
01740     }
01741     else
01742     {
01743         if(final) {
01744             // check this here since CAPI can't
01745             if(maxOut < icc->m_padlen) {
01746                 RAISE_CRYPTO_EXCEPTION("Decrypt() called with insufficient buffer available", m_parent->thisComponent, COMMON_INVALID_INPUT, NULL);
01747             }
01748             if(icc->m_padlen) {
01749                 memcpy(outBuf,icc->m_padbuf,icc->m_padlen);
01750             }
01751             if(start && inLen) memcpy(outBuf + icc->m_padlen,start,inLen);
01752             updateLen = inLen + icc->m_padlen;
01753             icc->m_padlen = 0;
01754             if(!CryptDecrypt(icc->m_sessionKey, NULL, final, 0, outBuf, &updateLen))
01755             {
01756                 std::ostringstream os;
01757                 os << "CryptDecrypt failed: " << GetLastError();;
01758                 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, CRYPTO_DECRYPT_FAILED, NULL);
01759             }
01760             *pnResultLen = updateLen;
01761             return;
01762         }
01763 
01764         // if it's not final, we need to have input
01765         if(!start || !inLen) return;
01766         int leftInBlock = icc->m_blockLen - icc->m_padlen;
01767         // if there's not enough to exceed the pad buffer, fill the pad buffer and bail
01768         if(leftInBlock >= inLen) {
01769             memcpy(icc->m_padbuf,start,inLen);
01770             icc->m_padlen += inLen;
01771             *pnResultLen = 0;
01772             return;
01773         }
01774 
01775         // if we're here, we got more than a cipherblock
01776         // 1. Empty the pad buffer
01777         memcpy(outBuf,icc->m_padbuf,icc->m_padlen);
01778         updateLen = icc->m_padlen;
01779         icc->m_padlen = 0;
01780         
01781         // 2. calculate how many bytes go into the pad buffer
01782         int trailing = (inLen + updateLen) % icc->m_blockLen ? 
01783             (inLen + updateLen) % icc->m_blockLen : icc->m_blockLen;
01784 
01785         // 3. empty the input buffer
01786         int copied = inLen - trailing;
01787         memcpy(outBuf+updateLen,start,copied);
01788         start += copied;
01789         updateLen += copied;
01790 
01791         // 4. decrypt
01792         if(!CryptDecrypt(icc->m_sessionKey, NULL, final, 0, outBuf, &updateLen))
01793         {
01794             std::ostringstream os;
01795             os << "CryptDecrypt failed: " << GetLastError();;
01796             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, CRYPTO_DECRYPT_FAILED, NULL);
01797         }
01798 
01799         // 5. copy off the trailing bytes for next time
01800         memcpy(icc->m_padbuf,start,trailing);
01801         icc->m_padlen += trailing;
01802         *pnResultLen = updateLen;
01803     }
01804 }
01805 
01806 
01819 IPKIFRawCryptContext* CPKIFCAPIRaw::HMACInit(const CPKIFKeyMaterial &key, PKIFCRYPTO::HASH_ALG ha)
01820 {
01821     LOG_STRING_DEBUG("CPKIFCAPIRaw::HMACInit(const CPKIFKeyMaterial& key, HASH_ALG ha)", thisComponent, 0, this);
01822     RAISE_CRYPTO_EXCEPTION("HMAC operations are not implemented for CAPI.", thisComponent, COMMON_NOT_IMPLEMENTED, this);   
01823     return 0;
01824 }
01825 
01837 void CPKIFCAPIRaw::HMACUpdate(IPKIFRawCryptContext* ctx, unsigned char* pData, int nDataLen)
01838 {
01839     LOG_STRING_DEBUG("CPKIFCAPIRaw::HMACUpdate(IPKIFRawCryptContext* ctx, unsigned char* pData, int nDataLen)", thisComponent, 0, this);
01840     RAISE_CRYPTO_EXCEPTION("HMAC operations are not implemented for CAPI.", thisComponent, COMMON_NOT_IMPLEMENTED, this);   
01841 }
01842 
01854 void CPKIFCAPIRaw::HMACFinal(IPKIFRawCryptContext* ctx, unsigned char* pResult, int* pnResultLen)
01855 {
01856     LOG_STRING_DEBUG("CPKIFCAPIRaw::HMACFinal(IPKIFRawCryptContext* ctx, unsigned char* pResult, int* pnResultLen)", thisComponent, 0, this);
01857     RAISE_CRYPTO_EXCEPTION("HMAC operations are not implemented for CAPI.", thisComponent, COMMON_NOT_IMPLEMENTED, this);   
01858 }

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