PKIFCNGCAPI.cpp

Go to the documentation of this file.
00001 
00009 #include "PKIFCNGCAPI.h"
00010 #include "ToolkitUtils.h"
00011 #include "CAPIUtils.h"
00012 #include "PKIFCAPICredential2.h"
00013 #include "PKIFCAPICryptContext2.h"
00014 #include "PKIFCNGKeyAgreeContext.h"
00015 #include "PKIFBCryptPublicKey.h"
00016 #include "PKIFCryptoPPKeyMaterial.h"
00017 #include "PKIFAlgorithm.h"
00018 
00019 #include "PKIFCryptoErrors.h"
00020 #include "PKIFCAPIErrors.h"
00021 #include "PKIFCryptoException.h"
00022 
00023 #include "SubjectPublicKeyInfo.h"
00024 #include "Certificate.h"
00025 #include "KeyUsage.h"
00026 
00027 
00028 #include "boost/numeric/conversion/cast.hpp"
00029 
00030 using boost::numeric_cast;
00031 using boost::bad_numeric_cast;
00032 
00033 #include <atlbase.h>
00034 #include <sstream>
00035 using namespace std;
00036 
00037 #include "PKIFCNGUtils.h"
00038 
00039 #define NT_SUCCESS(Status)          (((NTSTATUS)(Status)) >= 0)
00040 #define STATUS_UNSUCCESSFUL         ((NTSTATUS)0xC0000001L)
00041 
00042 
00044 struct CPKIFCNGCAPIImpl
00045 {
00046     CPKIFCNGCAPI* m_parent;
00054     CPKIFCNGCAPIImpl ()
00055     {
00056         m_parent = NULL;
00057     }
00065     CPKIFCNGCAPIImpl (CPKIFCNGCAPI  *p) 
00066     {
00067         m_parent = p;
00068     }
00069     HCRYPTPROV m_hProv;
00070     HCERTSTORE m_hCertStore;
00071     DWORD m_flags;
00072 
00073     char* m_provider;
00074     int m_sysStoRegLoc; 
00075     int m_provType;
00076 
00077     bool CertCanBeUsedByCurrentColleague(PCCERT_CONTEXT cert) const;
00078     
00079     CPKIFCAPICredential2* MakeCAPICredential(PCCERT_CONTEXT cert) const;
00080 };
00082 
00091 CPKIFCNGCAPI::CPKIFCNGCAPI(
00093     const char* provider,
00095     int provType,
00097     int sysStoRegLoc)
00098     :m_impl (new CPKIFCNGCAPIImpl), IPKIFCAPISource(sysStoRegLoc, NULL)
00099 {
00100     LOG_STRING_DEBUG("CPKIFCAPI::CPKIFCAPI(void)", TOOLKIT_CRYPTO_CAPI, 0, this);
00101 
00102     m_impl->m_parent = this;
00103     m_impl->m_provType = provType;
00104     m_impl->m_sysStoRegLoc = sysStoRegLoc;
00105     m_impl->m_provider = NULL;
00106 
00107     size_t len = 0;
00108     if(provider)
00109     {
00110         len = strlen(provider);
00111         m_impl->m_provider = new char[len + 1];
00112 
00113         //reviewed 4/23/2006
00114         strcpy(m_impl->m_provider, provider);
00115     }
00116 
00117     m_impl->m_hProv = NULL;
00118     m_impl->m_hCertStore = NULL;
00119 
00120     //added 9/9/03 to facilitate usage from a service targeting local machine store
00121     m_impl->m_flags = 0;
00122     if(CERT_SYSTEM_STORE_LOCAL_MACHINE == m_impl->m_sysStoRegLoc)
00123         m_impl->m_flags = CRYPT_MACHINE_KEYSET;
00124 }
00132 CPKIFCNGCAPI::~CPKIFCNGCAPI(void)
00133 {
00134     LOG_STRING_DEBUG("CPKIFCAPI::~CPKIFCAPI(void)", TOOLKIT_CRYPTO_CAPI, 0, this);
00135 
00136     if(m_impl->m_provider)
00137         delete[] m_impl->m_provider;
00138 
00139     if(NULL != m_impl->m_hProv)
00140     {
00141         CryptReleaseContext(m_impl->m_hProv, 0); m_impl->m_hProv = NULL;
00142     }
00143 
00144     if(NULL != m_impl->m_hCertStore)
00145     {
00146         BOOL certSucc = CertCloseStore(m_impl->m_hCertStore,CERT_CLOSE_STORE_CHECK_FLAG);
00147 #ifdef _DEBUG
00148         int ceerr = GetLastError();
00149 #endif
00150         m_impl->m_hCertStore = NULL;
00151     }
00152 
00153     delete m_impl;
00154     m_impl = NULL;
00155 }
00163 void CPKIFCNGCAPI::Initialize()
00164 {
00165     LOG_STRING_DEBUG("CPKIFCNGCAPI::Initialize()", TOOLKIT_CRYPTO_CAPI, 0, this);
00166     // no longer critical to initialize before there's a particular key
00167     // to be used. Do we want a flag so we can throw to enforce the documented
00168     // pattern?
00169 }
00170 
00171 
00183 bool CPKIFCNGCAPIImpl::CertCanBeUsedByCurrentColleague(
00185     PCCERT_CONTEXT cert) const
00186 {
00187     LOG_STRING_DEBUG("CPKIFCNGCAPI::CertCanBeUsedByCurrentColleague(PCCERT_CONTEXT cert)", TOOLKIT_CRYPTO_CAPI, 0, this);
00188 
00189     try
00190     {
00191         //create a temp credential and see if we own it using OwnsKey
00192         CPKIFCAPICredential2 tmp(m_provider, m_provType, m_sysStoRegLoc);
00193         tmp.m_certContext = CertDuplicateCertificateContext(cert);
00194         return m_parent->OwnsKey(tmp);
00195     }
00196     catch(CPKIFException& )
00197     {
00198         //delete e;
00199         return false;
00200     }
00201     catch(...)
00202     {
00203         _ASSERT(false);
00204         return false;
00205     }
00206 }
00233 CPKIFCAPICredential2* CPKIFCNGCAPIImpl::MakeCAPICredential(
00235     PCCERT_CONTEXT cert) const
00236 {
00237     LOG_STRING_DEBUG("CPKIFCNGCAPI::MakeCAPICredential(PCCERT_CONTEXT cert)", TOOLKIT_CRYPTO_CAPI, 0, this);
00238 
00239     pkif_char_array name(0);
00240     std::auto_ptr<CPKIFCAPICredential2> newKeyID((CPKIFCAPICredential2*) 0);
00241 
00242 
00243     //The following call to CertGetNameString should behave as follows:
00244     //Checks the certificate for a CERT_FRIENDLY_NAME_PROP_ID property. If the certificate 
00245     //has this property, it is returned. If the certificate does not have the property, 
00246     //the CERT_NAME_SIMPLE_DISPLAY_TYPE is returned.
00247     //
00248     //CERT_NAME_SIMPLE_DISPLAY_TYPE iterates through the following list of name attributes 
00249     //and uses the Subject Name or the Subject Alternative Name extension for the first 
00250     //occurrence of: szOID_COMMON_NAME, szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME, 
00251     //or szOID_RSA_emailAddr. If one of these attributes is not found, uses the Subject 
00252     //Alternative Name extension for a rfc822Name choice. If there is still no match, uses 
00253     //the first attribute.
00254     DWORD ccount = CertGetNameString(cert,CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, 0, 0, 0);
00255     if(1 == ccount)
00256     {
00257         std::ostringstream os;
00258         os << "CertGetNameString failed: " << GetLastError();
00259         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_GET_NAME_FAILED, this);
00260     }
00261 
00262     // character count includes the terminating 0 character
00263     name.reset(new char[ccount]);
00264     ccount = CertGetNameString(cert,CERT_NAME_FRIENDLY_DISPLAY_TYPE,0,NULL, name, ccount);
00265     if(1 == ccount)
00266     {
00267         std::ostringstream os;
00268         os << "CertGetNameString failed: " << GetLastError();
00269         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_GET_NAME_FAILED, this);
00270     }
00271 
00272     //determine the length of the key info
00273     DWORD tmpKeyIDLen = 0;
00274 
00275     BOOL succ = CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID ,
00276         NULL, &tmpKeyIDLen);
00277     if(!succ)
00278     {
00279         std::ostringstream os;
00280         os << "CertGetCertificateContextProperty failed: " << GetLastError();
00281         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_KEY_PROV_INFO_FAILED, this);
00282     }
00283     pkif_byte_array tmpKeyID(new unsigned char[tmpKeyIDLen]);
00284     //get the info into the temp object
00285     succ = CertGetCertificateContextProperty(cert,
00286                 CERT_KEY_IDENTIFIER_PROP_ID, (void *)tmpKeyID.get(), &tmpKeyIDLen);
00287     if(!succ)
00288     {
00289         std::ostringstream os;
00290         os << "CertGetCertificateContextProperty failed: " << GetLastError();
00291         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, PKIFCAPI_KEY_PROV_INFO_FAILED, this);
00292     }
00293 
00294     pkif_char_array tmpKeyIDASCII(new char[(tmpKeyIDLen*2) + 1]);
00295     btoa((const char*)tmpKeyID.get(), tmpKeyIDASCII.get(), tmpKeyIDLen);
00296 
00297     try
00298     {
00299         newKeyID.reset(new CPKIFCAPICredential2(m_provider, m_provType, m_sysStoRegLoc));
00300         CPKIFStringPtr tmpSP(new std::string(name));
00301         newKeyID->m_name = tmpSP;
00302         CPKIFStringPtr tmpSP2(new std::string(tmpKeyIDASCII));
00303         newKeyID->m_id = tmpSP2;
00304         newKeyID->m_certContext = CertDuplicateCertificateContext(cert);
00305         return newKeyID.release();
00306     }
00307     catch(...)
00308     {
00309         std::ostringstream os;
00310         os << "Unknown error creating credential: " << GetLastError();
00311         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), m_parent->thisComponent, COMMON_UNKNOWN_ERROR, this);
00312     }
00313 }
00314 
00315 //For ownership to be declared, either this instance must not be locked down to a specific m_provider
00316 //or the m_provider and m_provider type from the key itself must match those of this instance.
00326 bool CPKIFCNGCAPI::OwnsKey(
00328     const CPKIFCredential& keyID) const
00329 {
00330     LOG_STRING_DEBUG("CPKIFCNGCAPI::OwnsKey(const CPKIFCredential& keyID)", TOOLKIT_CRYPTO_CAPI, 0, this);
00331 
00332     //attempt to cast the keyID param to the type this class would've returned
00333     const CPKIFCAPICredential2* ck2 = dynamic_cast<const CPKIFCAPICredential2*>(&keyID);
00334 
00335     //if the cast fails then we don't "own" this key - we only deal in CPKIFCAPICredential objects
00336     if(NULL == ck2)
00337         return false;
00338 
00339     //if it succeeded and this instance is a general CAPI instance then we do "own" it
00340     if(NULL == m_impl->m_provider && 0 == m_impl->m_provType)
00341         return true;
00342 
00343     //otherwise have the key compare our info with the its info
00344     return ck2->ProviderInfoMatches(m_impl->m_provider, m_impl->m_provType);
00345 }
00346 
00359 void CPKIFCNGCAPI::GetKeyList(
00361     CPKIFCredentialList& v,
00363     CPKIFKeyUsagePtr& ku)
00364 {
00365     bitset<9> tmp = ku->GetKeyUsage();
00366     GetKeyList(v, &tmp);
00367 }
00368 
00382 void CPKIFCNGCAPI::GetKeyList(
00384     CPKIFCredentialList& v,
00386     bitset<9>* ku)
00387 {
00388     LOG_STRING_DEBUG("CPKIFCNGCAPI::GetKeyList(CPKIFCredentialList& v, bitset<9>* ku)", TOOLKIT_CRYPTO_CAPI, 0, this);
00389 
00390     HRESULT hr = S_OK;
00391     DWORD dw = 0;
00392 
00393     const size_t originalCount = v.size();
00394 
00395     USES_CONVERSION;
00396 
00397     //we always look in the MY store of the specified location when listing certs
00398     //we require that the store exist
00399     if(NULL == m_impl->m_hCertStore)
00400     {
00401         m_impl->m_hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, 
00402                                 CERT_STORE_OPEN_EXISTING_FLAG | m_impl->m_sysStoRegLoc, T2OLE("MY"));
00403         if(NULL == m_impl->m_hCertStore)
00404         {
00405             std::ostringstream os;
00406             os << "CertOpenStore failed: " << GetLastError();
00407             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_FAILED_TO_OPEN_CERT_STORE, this);
00408         }
00409     }
00410 
00411     PCCERT_CONTEXT pPrevCertContext = NULL;
00412     BOOL keyUsagePresent = false;
00413     BYTE kuBits[2];
00414     CPKIFCAPICredential2* keyID = NULL;
00415 
00416     try
00417     {
00418         // continue using this instead of an equivalent NCrypt function because I couldn't
00419         // find one that was as easily constrainted to keys with certs, and PKIF can't really
00420         // use a key without a cert. This appears to work with CNG keys as well as with CAPI ones.
00421         pPrevCertContext = CertEnumCertificatesInStore(m_impl->m_hCertStore, pPrevCertContext);
00422         while(NULL != pPrevCertContext)
00423         {
00424             //get the key usage of the current certificate
00425             keyUsagePresent = CertGetIntendedKeyUsage(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, pPrevCertContext->pCertInfo, (BYTE*)&kuBits, sizeof(kuBits));
00426 
00427             //make sure the context has an associated private key - we are only interested in listing
00428             //certs for which we hold the private keys
00429             if(CertHasKey(pPrevCertContext) && m_impl->CertCanBeUsedByCurrentColleague(pPrevCertContext) &&
00430                 (!keyUsagePresent || (keyUsagePresent && keyUsageTest(kuBits, ku))))
00431             {
00432                 //make a credential from the cert context
00433                 keyID = m_impl->MakeCAPICredential(pPrevCertContext);
00434 
00435                 //and push it into the vector
00436                 CPKIFCredentialPtr tmpCred(keyID);
00437                 v.push_back(tmpCred);
00438 
00439                 keyID = NULL;
00440             }
00441 
00442             pPrevCertContext = CertEnumCertificatesInStore(m_impl->m_hCertStore, pPrevCertContext);
00443         }
00444     }
00445     catch(...)
00446     {
00447         if(NULL != keyID)
00448         {
00449             //if we threw before completing the push_back statment, clean up
00450             delete keyID; keyID = NULL;
00451         }
00452 
00453         if(NULL != pPrevCertContext)
00454         {
00455             //if we threw before freeing cert context, clean up
00456             CertFreeCertificateContext(pPrevCertContext); pPrevCertContext = NULL;
00457         }
00458 
00459         std::ostringstream os;
00460         os << "Unknown failure in GetKeyList.  GetLastError returns: " << GetLastError();
00461         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, COMMON_UNKNOWN_ERROR, this);
00462     }
00463 }
00464 
00465 //this function takes a key ID (ascii hex SHA1 hash typically) and creates a CPKIFCAPICredential that may be
00466 //used with the Sign and Decrypt functions.  If a matching key could not be found NULL is returned.
00479 CPKIFCredentialPtr CPKIFCNGCAPI::MakeKeyID(
00482     const std::string& asciiHexKeyID)
00483 {
00484     LOG_STRING_DEBUG("CPKIFCNGCAPI::MakeKeyID(const std::string& asciiHexKeyID)", TOOLKIT_CRYPTO_CAPI, 0, this);
00485 
00486     pkif_char_array bin(NULL);
00487     PCCERT_CONTEXT_PKIF cert(0);
00488 
00489     std::auto_ptr<CPKIFCAPICredential2> newKeyID; //don't free - this is what gets returned
00490 
00491     //convert the input from ascii hex to binary
00492     const char* hex = asciiHexKeyID.c_str();
00493     unsigned int len = 0;
00494 
00495     try 
00496     {
00497         len = numeric_cast<unsigned int>(asciiHexKeyID.length()/2);
00498     }
00499     catch(bad_numeric_cast &) 
00500     {
00501         throw CPKIFException(TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, "Key identifier is an impossibly long number.");
00502     }
00503     bin.reset(new char[len]);
00504     if(0 != atob(bin, const_cast<char*>(hex), &len))
00505     {
00506         std::string reason;
00507         FormatErrorMessage(reason, "Key ID contains non-ASCII hexadecimal characters.", -1, __FILE__, __LINE__);
00508         throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, reason.c_str());
00509     }
00510 
00511     //set up a hash blob containing the binary key ID and length
00512     CRYPT_HASH_BLOB b;
00513     b.cbData = len;
00514     b.pbData = (BYTE*)bin.get();
00515 
00516     //open the cert store
00517     USES_CONVERSION;
00518     if(NULL == m_impl->m_hCertStore)
00519     {
00520         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"));
00521         if(NULL == m_impl->m_hCertStore)
00522         {
00523             std::ostringstream os;
00524             os << "CertOpenStore failed: " << GetLastError();
00525             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_FAILED_TO_OPEN_CERT_STORE, this);
00526         }
00527     }
00528 
00529     cert.reset(CertFindCertificateInStore(m_impl->m_hCertStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_KEY_IDENTIFIER, (void*)&b, NULL));
00530 
00531     if(NULL != cert.get() && true == m_impl->CertCanBeUsedByCurrentColleague(cert))
00532     {
00533         //make a credential from the cert context
00534         newKeyID.reset(m_impl->MakeCAPICredential(cert));
00535     }
00536 
00537     CPKIFCredentialPtr rv(newKeyID.release());
00538     return rv;
00539 }
00540 
00567 void CPKIFCNGCAPI::Sign(
00569     const CPKIFCredential& key,
00571     unsigned char* pHashData,
00573     int nHashDataLen,
00575     unsigned char* pSignature,
00578     int* nSignatureLen,
00580     PKIFCRYPTO::HASH_ALG hashAlg
00581     )
00582 {
00583     LOG_STRING_DEBUG("CPKIFCNGCAPI::Sign(const CPKIFCredential& key,...", TOOLKIT_CRYPTO_CAPI, 0, this);
00584 
00585     NCRYPT_PROV_HANDLE_PKIF     hProvider(0);
00586     NCRYPT_KEY_HANDLE_PKIF      hKey(0);
00587     SECURITY_STATUS             cngStatus       = ERROR_SUCCESS;
00588     DWORD                       cbSignature     = 0;
00589     BCRYPT_PKCS1_PADDING_INFO   PKCS1PaddingInfo= {0};
00590 
00591     NCRYPT_KEY_HANDLE hKeyPtr = 0;
00592 
00593     //m_impl->GetContext();
00594 
00595     int err = 0;
00596 
00597     //set up a pointer to a context and an indication of whether or not to free context then get the hash alg
00598     //we use the length of the data to determine the hash alg.  If the hash alg is not known GetHashAlg throws
00599     HCRYPTPROV tmpHashCtx = NULL;
00600     bool freeContext = false;
00601 
00602     //convert the key to a CAPI key object and see if the key info has been loaded
00603     const CPKIFCAPICredential2* ck2 = dynamic_cast<const CPKIFCAPICredential2*>(&key);
00604     if(NULL == ck2)
00605     {
00606         throw CPKIFCryptoException(thisComponent, CRYPTO_UNRECOGNIZED_CREDENTIAL, "Credential type not recognized.");
00607     }
00608 
00609     if(NULL == ck2->m_keyProviderInfo)
00610     {
00611         //if key info hasn't been loaded - load it - if load fails SetKeyProviderInfo throws
00612         CPKIFCAPICredential2* k2 = const_cast<CPKIFCAPICredential2*>(ck2);
00613         k2->SetKeyProviderInfo();
00614     }
00615 
00616 
00617 
00618     if(FAILED(cngStatus = NCryptOpenStorageProvider(
00619                                             &hProvider, 
00620                                             MS_KEY_STORAGE_PROVIDER, 
00621                                             0)))
00622     {
00623         std::ostringstream os;
00624         os << "NCryptOpenStorageProvider failed: " << cngStatus;
00625         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_OPEN_STORAGE_PROVIDER_FAILED, NULL);
00626     }
00627 
00628     if(FAILED(cngStatus = NCryptOpenKey(
00629                                         hProvider, 
00630                                         &hKey, 
00631                                         ck2->m_keyProviderInfo->pwszContainerName,
00632                                         0,
00633                                         0)))
00634     {
00635         DWORD ks = 0;
00636         BOOL gottaFree = FALSE;
00637         HCRYPTPROV_OR_NCRYPT_KEY_HANDLE tmpKey;
00638         if(!CryptAcquireCertificatePrivateKey(ck2->m_certContext,
00639             CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG,NULL,&tmpKey,&ks,&gottaFree))
00640         {
00641             std::ostringstream os;
00642             os << "Unable to access key material: " << cngStatus;
00643             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_OPEN_KEY_FAILED, NULL);
00644         }
00645         if(ks == CERT_NCRYPT_KEY_SPEC) {
00646             hKey.reset(tmpKey);
00647         } else {
00648             if(FAILED(cngStatus = NCryptTranslateHandle(
00649                 NULL,&hKey,tmpKey,NULL,ks,0)))
00650             {
00651                 // if this didn't work, the CNG colleague just can't work with the key
00652                 // free it and move on.
00653                 if(gottaFree) {
00654                     CryptReleaseContext(tmpKey,0);
00655                 }
00656                 std::ostringstream os;
00657                 os << "Unable to access legacy key material from CAPING: " << cngStatus;
00658                 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_OPEN_KEY_FAILED, NULL);
00659             }
00660         }
00661         // CNG may or may not need us to free this key. If it doesn't, our
00662         // scope guard object needs to let go.
00663         if(!gottaFree)
00664         {
00665             hKeyPtr = hKey.release();
00666         } else {
00667             hKeyPtr = hKey.get();
00668         }
00669 
00670 
00671     }
00672     else
00673     {
00674         hKeyPtr = hKey.get();
00675     }
00676 
00677     //see if the password has been provided for use in UI-less environment
00678     if(NULL != ck2->m_password)
00679     {
00680         USES_CONVERSION;
00681         if( FAILED(cngStatus = NCryptSetProperty(
00682             hKeyPtr,
00683             NCRYPT_PIN_PROPERTY,
00684             ck2->m_password, // XXX *** I don't have a way to test this right now.
00685                              // There may be some need to convert the password, though this
00686                              // responsibility is best placed on the Setter, I think.
00687             ck2->m_nPasswordLen,
00688             0)))
00689         {
00690             std::ostringstream os;
00691             os << "CryptSetProvParam failed: " << GetLastError();
00692             RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_SET_PASSWORD_FAILED, this);
00693         }
00694 
00695     }
00696     
00697     LPCWSTR sHashAlg = NULL;
00698     switch(hashAlg)
00699     {
00700     case PKIFCRYPTO::SHA1:
00701         PKCS1PaddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
00702         sHashAlg = NCRYPT_SHA1_ALGORITHM;
00703         break;
00704     case PKIFCRYPTO::SHA256:
00705         PKCS1PaddingInfo.pszAlgId = BCRYPT_SHA256_ALGORITHM;
00706         sHashAlg = NCRYPT_SHA256_ALGORITHM;
00707         break;
00708     case PKIFCRYPTO::SHA384:
00709         PKCS1PaddingInfo.pszAlgId = BCRYPT_SHA384_ALGORITHM;
00710         sHashAlg = NCRYPT_SHA384_ALGORITHM;
00711         break;
00712     case PKIFCRYPTO::SHA512:
00713         PKCS1PaddingInfo.pszAlgId = BCRYPT_SHA512_ALGORITHM;
00714         sHashAlg = NCRYPT_SHA512_ALGORITHM;
00715         break;
00716     default:
00717         std::ostringstream os;
00718         os << "Unsupported hash algorithm encountered: " << hashAlg;
00719         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, CRYPTO_ALG_NOT_SUPPORTED, NULL);
00720     }
00721 
00722     BCRYPT_PKCS1_PADDING_INFO * pi = 0;
00723     DWORD pflags = 0;
00724     // if this is an RSA signature, need to set those properly.
00725     // if it's not an RSA signature, CNG gets angry if you do :-/
00726     DWORD algPropSize = 0;
00727     if(FAILED(cngStatus = NCryptGetProperty(hKeyPtr,NCRYPT_ALGORITHM_GROUP_PROPERTY,
00728                                             NULL,0,&algPropSize,0)))
00729     {
00730         RAISE_CRYPTO_EXCEPTION("Unable to obtain signature algorithm group for key", TOOLKIT_CRYPTO, CRYPTO_ALG_NOT_SUPPORTED, NULL);
00731     }
00732     pkif_byte_array algName(new unsigned char[algPropSize]);
00733     memset(algName,0x00,algPropSize);
00734     if(FAILED(cngStatus = NCryptGetProperty(hKeyPtr,NCRYPT_ALGORITHM_GROUP_PROPERTY,
00735                                             algName,algPropSize,&algPropSize,0)))
00736     {
00737         RAISE_CRYPTO_EXCEPTION("Unable to obtain signature algorithm group for key", TOOLKIT_CRYPTO, CRYPTO_ALG_NOT_SUPPORTED, NULL);
00738     }
00739     if(0 == wcscmp(NCRYPT_RSA_ALGORITHM_GROUP,(wchar_t *)algName.get()))
00740     {
00741         pi = &PKCS1PaddingInfo;
00742         pflags = BCRYPT_PAD_PKCS1;
00743     }
00744 
00745     if(FAILED(cngStatus = NCryptSignHash(hKeyPtr,pi,(PBYTE)pHashData,nHashDataLen,pSignature,
00746                                     *nSignatureLen,&cbSignature,pflags)))
00747     {
00748         std::ostringstream os;
00749         os << "NCryptSignHash failed to sign hash: " << cngStatus;
00750         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_SIGN_HASH_FAILED, NULL);
00751     }
00752 
00753     *nSignatureLen = cbSignature;
00754 
00755 }
00756 
00774 void CPKIFCNGCAPI::Decrypt(
00777     const CPKIFCredential& key,
00779     unsigned char* pData,
00781     int nDataLen,
00783     unsigned char* pResult, 
00786     int* pnResultLen)
00787 {
00788     LOG_STRING_DEBUG("CPKIFCNGCAPI::Decrypt(const CPKIFCredential& key,...", TOOLKIT_CRYPTO_CAPI, 0, this);
00789 
00790     NCRYPT_PROV_HANDLE_PKIF hProvider(0);
00791     NCRYPT_KEY_HANDLE_PKIF  hKey(0);
00792     SECURITY_STATUS         secStatus = ERROR_SUCCESS;
00793     DWORD                   cbCipherText                = 0; 
00794 
00795     USES_CONVERSION;
00796 
00797     HCRYPTPROV tmpCtx = NULL;
00798     BOOL freeContext = false;
00799 
00800     //convert the key to a CAPI key object and see if the key info has been loaded
00801     const CPKIFCAPICredential2* ck2 = dynamic_cast<const CPKIFCAPICredential2*>(&key);
00802     if(NULL == ck2)
00803     {
00804         throw CPKIFCryptoException(thisComponent, CRYPTO_UNRECOGNIZED_CREDENTIAL, "Credential type not recognized.");
00805     }
00806 
00807     if(NULL == ck2->m_keyProviderInfo)
00808     {
00809         //if key info hasn't been loaded - load it - if load fails SetKeyProviderInfo throws
00810         CPKIFCAPICredential2* k2 = const_cast<CPKIFCAPICredential2*>(ck2);
00811         k2->SetKeyProviderInfo();
00812     }
00813 
00814     // Open Microsoft KSP
00815     if(FAILED(secStatus = NCryptOpenStorageProvider(
00816                                             &hProvider, 
00817                                             MS_KEY_STORAGE_PROVIDER, 
00818                                             0)))
00819     {
00820         std::ostringstream os;
00821         os << "NCryptOpenStorageProvider failed: " << GetLastError();;
00822         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_OPEN_STORAGE_PROVIDER_FAILED, NULL);
00823     }
00824 
00825     if(FAILED(secStatus = NCryptOpenKey(
00826                                         hProvider, 
00827                                         &hKey, 
00828                                         ck2->m_keyProviderInfo->pwszContainerName,
00829                                         0,
00830                                         0)))
00831     {
00832         std::ostringstream os;
00833         os << "NCryptOpenKey failed: " << GetLastError();;
00834         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_OPEN_KEY_FAILED, NULL);
00835     }
00836 
00837     int paddingFlag = NCRYPT_PAD_PKCS1_FLAG;
00838 
00839     if(FAILED(secStatus = NCryptDecrypt(
00840                                     hKey,
00841                                     (PBYTE)pData,
00842                                     nDataLen,
00843                                     NULL,
00844                                     NULL,
00845                                     0,
00846                                     &cbCipherText,
00847                                     paddingFlag)))    
00848     {
00849         std::ostringstream os;
00850         os << "NCryptDecrypt failed: " << GetLastError();;
00851         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_DECRYPT_FAILED, NULL);
00852 
00853     }
00854     if(FAILED(secStatus = NCryptDecrypt(
00855                                     hKey,
00856                                     (PBYTE)pData,
00857                                     nDataLen,
00858                                     NULL,
00859                                     pResult,
00860                                     *pnResultLen,
00861                                     &cbCipherText,
00862                                     paddingFlag)))
00863     {
00864         std::ostringstream os;
00865         os << "NCryptDecrypt failed: " << GetLastError();;
00866         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_DECRYPT_FAILED, NULL);
00867     }
00868     *pnResultLen = cbCipherText;
00869 }
00870 
00882 void CPKIFCNGCAPI::Encrypt(
00885     const CPKIFCredential& key,
00887     unsigned char* pData,
00889     int nDataLen,
00891     unsigned char* pResult,
00894     int* pnResultLen)
00895 {
00896     LOG_STRING_DEBUG("CPKIFCNGCAPI::Encrypt(const CPKIFCredential& key, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen)", TOOLKIT_CRYPTO_CAPI, 0, this);
00897 
00898     throw CPKIFCryptoException(thisComponent, COMMON_NOT_IMPLEMENTED, "Encrypt operations are not implemented for stored key material");
00899 }
00900 
00912 bool CPKIFCNGCAPI::Verify(
00915     const CPKIFCredential& key, 
00918     unsigned char* pHashData,
00920     int nHashDataLen,
00922     unsigned char* pSignature,
00924     int nSignatureLen,
00926     PKIFCRYPTO::HASH_ALG hashAlg
00927     )
00928 {
00929     LOG_STRING_DEBUG("CPKIFCNGCAPI::Verify(const CPKIFCredential& key, unsigned char* pHashData, int nHashDataLen, unsigned char* pSignature, int nSignatureLen)", TOOLKIT_CRYPTO_CAPI, 0, this);
00930 
00931     throw CPKIFCryptoException(thisComponent, COMMON_NOT_IMPLEMENTED, "Verify operations are not implemented for stored key material");
00932 }
00933 
00952 IPKIFCryptContext* CPKIFCNGCAPI::CryptInit(
00955     CPKIFCredentialPtr& key,
00957     bool pad)
00958 {
00959     LOG_STRING_DEBUG("CPKIFCNGCAPI::CryptInit(CPKIFCredentialPtr& key)", TOOLKIT_CRYPTO_CAPI, 0, this);
00960 
00961     RAISE_CRYPTO_EXCEPTION("Context-based operations are unimplemented for CNG stored key material.",thisComponent,COMMON_NOT_IMPLEMENTED,this);
00962     return 0;
00963     
00964 }
00965 
00982 void CPKIFCNGCAPI::Decrypt(
00985     IPKIFCryptContext* cryptContext,
00987     unsigned char* pData,
00989     int nDataLen,
00991     unsigned char* pResult, 
00994     int* pnResultLen,
00997     bool final)
00998 {
00999     LOG_STRING_DEBUG("CPKIFCNGCAPI::Decrypt(IPKIFCryptContext* cryptContext, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool final)", TOOLKIT_CRYPTO_CAPI, 0, this);
01000     RAISE_CRYPTO_EXCEPTION("Context-based operations are unimplemented for CNG stored key material.",thisComponent,COMMON_NOT_IMPLEMENTED,this);
01001 }
01002 
01013 void CPKIFCNGCAPI::Encrypt(
01016     IPKIFCryptContext* cryptContext,
01018     unsigned char* pData,
01020     int nDataLen,
01022     unsigned char* pResult,
01025     int* pnResultLen,
01028     bool final)
01029 {
01030     LOG_STRING_DEBUG("CPKIFCNGCAPI::Encrypt(IPKIFCryptContext* cryptContext, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool final)", TOOLKIT_CRYPTO_CAPI, 0, this);
01031     RAISE_CRYPTO_EXCEPTION("Context-based operations are unimplemented for CNG stored key material.",thisComponent,COMMON_NOT_IMPLEMENTED,this);
01032 }
01033 
01034 // Key Agreement stuff
01035 
01049 IPKIFKeyAgreeContextPtr CPKIFCNGCAPI::SecretAgree(
01052                                         CPKIFCredentialPtr& myPrivateKey,
01054                                         const CPKIFCertificatePtr& theirCert,
01056                                         const CPKIFAlgorithm * alg)
01057 {
01058     LOG_STRING_DEBUG("SecretAgree(CPKIFCredentialPtr& myPrivateKey, const CPKIFCertificatePtr& theirCert,const CPKIFAlgorithm * alg)", TOOLKIT_CRYPTO_CAPI, 0, this);
01059     // use a CPKIFCryptoPPKeyMaterial object for ease of subjectPublicKeyInfo access
01060     CPKIFCryptoPPKeyMaterialPtr km(new CPKIFCryptoPPKeyMaterial(*theirCert));
01061     CPKIFBufferPtr rawKey = km->GetRawSPKI();
01062     return SecretAgree(myPrivateKey, rawKey, alg);
01063 }
01064 
01082 IPKIFKeyAgreeContextPtr CPKIFCNGCAPI::SecretAgree(
01085                                         CPKIFCredentialPtr& myPrivateKey,
01089                                         const CPKIFBufferPtr& theirPublicKey,
01091                                         const CPKIFAlgorithm * alg)
01092 {
01093     IPKIFKeyAgreeContextPtr rv;
01094     throw CPKIFCryptoException(thisComponent, COMMON_NOT_IMPLEMENTED, "Not yet implemented.");
01095     return rv;
01096 }
01097 
01098 // originator interfaces for authenticated key agreement
01113 IPKIFKeyAgreeContextPtr CPKIFCNGCAPI::SecretAgree(
01115                                         const CPKIFCredentialPtr& myPrivateKey,
01117                                         CPKIFCredentialPtr & ephemeralKeyPair,
01119                                         const CPKIFCertificatePtr& theirCert,
01121                                         const CPKIFAlgorithm * alg)
01122 {
01123     IPKIFKeyAgreeContextPtr rv;
01124     throw CPKIFCryptoException(thisComponent, COMMON_NOT_IMPLEMENTED, "CNG does not provide authenticated key agreement.");
01125     return rv;
01126 }
01127 
01145 IPKIFKeyAgreeContextPtr CPKIFCNGCAPI::SecretAgree(
01147                                         const CPKIFCredentialPtr& myPrivateKey,
01149                                         CPKIFCredentialPtr & ephemeralKeyPair,
01151                                         const CPKIFBufferPtr& theirPublicKey,
01153                                         const CPKIFAlgorithm * alg)
01154 {
01155     IPKIFKeyAgreeContextPtr rv;
01156     throw CPKIFCryptoException(thisComponent, COMMON_NOT_IMPLEMENTED, "CNG does not provide authenticated key agreement.");
01157     return rv;
01158 }
01159 
01160 // recipient interfaces for authenticated key agreement
01161 
01177 IPKIFKeyAgreeContextPtr CPKIFCNGCAPI::SecretAgree(
01179                                         const CPKIFCredentialPtr& myPrivateKey,
01182                                         const CPKIFBufferPtr& ephemeralPublicKey,
01184                                         const CPKIFCertificatePtr& theirCert,
01186                                         const CPKIFAlgorithm * alg)
01187 {
01188     IPKIFKeyAgreeContextPtr rv;
01189     throw CPKIFCryptoException(thisComponent, COMMON_NOT_IMPLEMENTED, "CNG does not provide authenticated key agreement.");
01190     return rv;
01191 }
01192 
01211 IPKIFKeyAgreeContextPtr CPKIFCNGCAPI::SecretAgree(
01213                                         const CPKIFCredentialPtr& myPrivateKey,
01216                                         const CPKIFBufferPtr& ephemeralPublicKey,
01218                                         const CPKIFBufferPtr& theirPublicKey,
01220                                         const CPKIFAlgorithm * alg)
01221 {
01222     IPKIFKeyAgreeContextPtr rv;
01223     throw CPKIFCryptoException(thisComponent, COMMON_NOT_IMPLEMENTED, "CNG does not provide authenticated key agreement.");
01224     return rv;
01225 }
01226 
01235 CPKIFKeyMaterialPtr CPKIFCNGCAPI::DeriveKey(
01237                                                     const IPKIFKeyAgreeContextPtr & context,
01239                                                     unsigned long keyLen
01240                                                     )
01241 {
01242     CPKIFKeyMaterialPtr key;
01243     return key;
01244 }

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