00001
00010 #include "PKIFBCryptPublicKey.h"
00011
00012 #include <wincrypt.h>
00013 #include <iostream>
00014 #include <sstream>
00015
00016 #include "PKIFKeyMaterial.h"
00017 #include "PKIFCryptoPPKeyMaterial.h"
00018 #include "Buffer.h"
00019
00020 #include "Certificate.h"
00021 #include "AlgorithmIdentifier.h"
00022 #include "SubjectPublicKeyInfo.h"
00023
00024 #include "PKIFException.h"
00025 #include "PKIFCryptoException.h"
00026 #include "ToolkitUtils.h"
00027 #include "components.h"
00028 #include "PKIFCommonErrors.h"
00029 #include "PKIFCNGUtils.h"
00030 #include "PKIFCAPIErrors.h"
00031
00032 #ifndef NT_SUCCESS
00033 #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
00034 #endif
00035
00036 using namespace std;
00037
00045 bool GetCAPI1ProvType(
00047 PCERT_PUBLIC_KEY_INFO spki,
00049 DWORD & prov)
00050 {
00051
00052 if(0 == strcmp(szOID_X957_DSA, spki->Algorithm.pszObjId) ||
00053 0 == strcmp(szOID_X957_SHA1DSA, spki->Algorithm.pszObjId))
00054 prov = PROV_DSS;
00055 else if(0 == strcmp(szOID_RSA_RSA, spki->Algorithm.pszObjId) ||
00056 0 == strcmp(szOID_RSA_MD5RSA, spki->Algorithm.pszObjId) ||
00057 0 == strcmp(szOID_RSA_SHA1RSA, spki->Algorithm.pszObjId))
00058 prov = PROV_RSA_FULL;
00059 else
00060 return false;
00061 return true;
00062 }
00070 CPKIFBCryptPublicKey::CPKIFBCryptPublicKey()
00071 :m_hKey(NULL),m_hAlg(NULL),m_spki((CPKIFSubjectPublicKeyInfo *)0)
00072 {
00073 }
00081 CPKIFBCryptPublicKey::~CPKIFBCryptPublicKey()
00082 {
00083 this->clear();
00084 }
00085
00097 BCRYPT_KEY_HANDLE CPKIFBCryptPublicKey::Initialize(const CPKIFBufferPtr & km)
00098 {
00099 LOG_STRING_DEBUG("CPKIFBCryptPublicKey::Initialize(const CPKIFKeyMaterial& key)", TOOLKIT_CRYPTO_CAPIRAW, 0, NULL);
00100 this->clear();
00101
00102
00103 SECURITY_STATUS cngStatus = ERROR_SUCCESS;
00104 NTSTATUS ntrv = 0L;
00105
00106
00107
00108 PCERT_PUBLIC_KEY_INFO_PKIF capiSpki(0);
00109 DWORD capiSpkiLen = 0;
00110 if(!CryptDecodeObjectEx(X509_ASN_ENCODING,X509_PUBLIC_KEY_INFO,
00111 km->GetBuffer(),(DWORD)km->GetLength(),
00112 CRYPT_DECODE_ALLOC_FLAG,
00113 NULL,
00114 &capiSpki,&capiSpkiLen))
00115 {
00116 std::ostringstream os;
00117 os << "CryptDecodeObjectEx failed to decode subjectPublicKeyInfo structure: " << GetLastError();;
00118 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00119 }
00120 CPKIFOIDPtr spkiOID(new CPKIFOID(CPKIFStringPtr(new string(capiSpki->Algorithm.pszObjId))));
00121 CPKIFBufferPtr spkiParams(new CPKIFBuffer(false,capiSpki->Algorithm.Parameters.pbData,capiSpki->Algorithm.Parameters.cbData));
00122 CPKIFAlgorithmIdentifierPtr algID(new CPKIFAlgorithmIdentifier(spkiOID,spkiParams));
00123 CPKIFBufferPtr keyBuf(new CPKIFBuffer(false,capiSpki->PublicKey.pbData,capiSpki->PublicKey.cbData));
00124 CPKIFSubjectPublicKeyInfoPtr decodedSPKI(new CPKIFSubjectPublicKeyInfo(algID,keyBuf));
00125 CPKIFCryptoPPKeyMaterial cppKM(decodedSPKI);
00126 return Initialize(cppKM);
00127
00128 }
00129
00130
00142 BCRYPT_KEY_HANDLE CPKIFBCryptPublicKey::Initialize(const CPKIFKeyMaterial & km)
00143 {
00144 LOG_STRING_DEBUG("CPKIFBCryptPublicKey::Initialize(const CPKIFKeyMaterial& key)", TOOLKIT_CRYPTO_CAPIRAW, 0, NULL);
00145 this->clear();
00146
00147
00148 SECURITY_STATUS cngStatus = ERROR_SUCCESS;
00149 NTSTATUS ntrv = 0L;
00150
00151
00152 LPCWSTR cngAlg = NULL;
00153
00154
00155 PCERT_PUBLIC_KEY_INFO_PKIF capiSpki(0);
00156
00157 pkif_byte_array paramsGuard(0);
00158
00159
00160
00161
00162 CPKIFSubjectPublicKeyInfoPtr spki = km.GetSubjectPublicKeyInfo();
00163
00164
00165
00166 if(!spki) {
00167 CPKIFCertificatePtr keyCert(new CPKIFCertificate());
00168 keyCert->Decode(km.GetCertificate(),km.GetCertificateLength());
00169 spki = keyCert->GetSubjectPublicKeyInfo();
00170 }
00171
00172
00173
00174 if(!spki)
00175 {
00176 RAISE_CRYPTO_EXCEPTION("A CPKIFKeyMaterial object without a public key was passed to Verify()",
00177 TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, NULL);
00178 }
00179 m_spki = spki;
00180
00181
00182
00183 CPKIFCryptoPPKeyMaterialPtr cppkm(new CPKIFCryptoPPKeyMaterial(spki));
00184 CPKIFBufferPtr rawSPKI = cppkm->GetRawSPKI();
00185 DWORD capiSpkiLen = 0;
00186 if(!CryptDecodeObjectEx(X509_ASN_ENCODING,X509_PUBLIC_KEY_INFO,
00187 rawSPKI->GetBuffer(),(DWORD)rawSPKI->GetLength(),
00188 CRYPT_DECODE_ALLOC_FLAG,
00189 NULL,
00190 &capiSpki,&capiSpkiLen))
00191 {
00192 std::ostringstream os;
00193 os << "CryptDecodeObjectEx failed to decode subjectPublicKeyInfo structure: " << GetLastError();;
00194 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00195 }
00196
00197
00198 CPKIFAlgorithmIdentifierPtr workingParams = km.GetWorkingParameters();
00199 if(0 == capiSpki->Algorithm.Parameters.cbData &&
00200 workingParams != (CPKIFAlgorithmIdentifier*)NULL)
00201 {
00202 CPKIFBufferPtr params = workingParams->parameters();
00203 capiSpki->Algorithm.Parameters.cbData = params->GetLength();
00204 capiSpki->Algorithm.Parameters.pbData = new unsigned char[params->GetLength()];
00205 memcpy(capiSpki->Algorithm.Parameters.pbData, (BYTE*)params->GetBuffer(), params->GetLength());
00206 paramsGuard.reset(capiSpki->Algorithm.Parameters.pbData);
00207 }
00208
00209 if(!CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING,capiSpki,0,0,&m_hKey))
00210 {
00211
00212 DWORD provType;
00213 if(!GetCAPI1ProvType(capiSpki,provType))
00214 {
00215 std::ostringstream os;
00216 os << "CryptImportPublicKeyInfoEx2 failed: " << GetLastError();
00217 os << ", then we were unable to get provider type for " << capiSpki->Algorithm.pszObjId << endl;
00218 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00219 }
00220 LPCWSTR oldBlobType = 0;
00221 LPCWSTR newProvAlgId = 0;
00222 switch(provType)
00223 {
00224 case PROV_DSS:
00225 oldBlobType = LEGACY_DSA_PUBLIC_BLOB;
00226 newProvAlgId = BCRYPT_DSA_ALGORITHM;
00227 break;
00228 case PROV_RSA_FULL:
00229 oldBlobType = LEGACY_RSAPUBLIC_BLOB;
00230 newProvAlgId = BCRYPT_RSA_ALGORITHM;
00231 break;
00232 default:
00233 {
00234 std::ostringstream os;
00235 os << "CryptImportPublicKeyInfoEx2 failed: " << GetLastError();
00236 os << ", then we got an unanticipated provider type for " << capiSpki->Algorithm.pszObjId << endl;
00237 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00238 }
00239 break;
00240 }
00241
00242
00243 HCRYPTPROV_PKIF hProv;
00244 if(!CryptAcquireContext(&hProv,NULL,NULL,provType,CRYPT_VERIFYCONTEXT)) {
00245 std::ostringstream os;
00246 os << "Unable to acquire context for " << capiSpki->Algorithm.pszObjId << " provider: " << GetLastError() << endl;
00247 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00248 }
00249 HCRYPTKEY_PKIF hcapikey;
00250 if(!CryptImportPublicKeyInfo(hProv,X509_ASN_ENCODING,capiSpki,&hcapikey))
00251 {
00252 std::ostringstream os;
00253 os << "CAPI1 was unable to import a key with alg ID " << capiSpki->Algorithm.pszObjId << " after CNG failed: " << GetLastError() << endl;
00254 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00255 }
00256
00257 DWORD cbBlob = 0;
00258
00259 if(!CryptExportKey(hcapikey,0,PUBLICKEYBLOB,CRYPT_BLOB_VER3,NULL,&cbBlob))
00260 {
00261 std::ostringstream os;
00262 os << "CAPI1 was unable to export a key with alg ID " << capiSpki->Algorithm.pszObjId << " for CNG import: " << GetLastError() << endl;
00263 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00264 }
00265 pkif_byte_array pbBlob(new unsigned char[cbBlob]);
00266 if(!CryptExportKey(hcapikey,0,PUBLICKEYBLOB,CRYPT_BLOB_VER3,pbBlob,&cbBlob))
00267 {
00268 std::ostringstream os;
00269 os << "CAPI1 was unable to export a key with alg ID " << capiSpki->Algorithm.pszObjId << " for CNG import: " << GetLastError() << endl;
00270 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00271 }
00272
00273
00274 NCRYPT_PROV_HANDLE_PKIF hNCProv;
00275 if(FAILED(cngStatus = NCryptOpenStorageProvider(&hNCProv, MS_KEY_STORAGE_PROVIDER,0)))
00276 {
00277 std::ostringstream os;
00278 os << "Unable to Open " << MS_KEY_STORAGE_PROVIDER << " for CNG import: ("
00279 << GetLastError() << ")" << "(SECURITY_STATUS code " << cngStatus << ")" << endl;
00280 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00281 }
00282 NCRYPT_KEY_HANDLE_PKIF hTmpKey;
00283 if(FAILED(cngStatus = NCryptImportKey(hNCProv,NULL,oldBlobType,NULL,&hTmpKey,
00284 pbBlob,cbBlob,0)))
00285 {
00286 std::ostringstream os;
00287 os << "Unable to import blob into " << MS_KEY_STORAGE_PROVIDER << ": ("
00288 << GetLastError() << ")" << "(SECURITY_STATUS code " << cngStatus << ")" << endl;
00289 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00290 }
00291
00292
00293 DWORD cbNewBlob = 0;
00294 if(FAILED(cngStatus = NCryptExportKey(hTmpKey,NULL,BCRYPT_PUBLIC_KEY_BLOB,NULL,NULL,0,&cbNewBlob,0)))
00295 {
00296 std::ostringstream os;
00297 os << "Unable to export blob from " << MS_KEY_STORAGE_PROVIDER << " for CNG import: ("
00298 << GetLastError() << ")" << "(SECURITY_STATUS code " << cngStatus << ")" << endl;
00299 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00300 }
00301 pkif_byte_array pbNewBlob(new unsigned char[cbNewBlob]);
00302 if(FAILED(cngStatus = NCryptExportKey(hTmpKey,NULL,BCRYPT_PUBLIC_KEY_BLOB,NULL,pbNewBlob,cbNewBlob,&cbNewBlob,0)))
00303 {
00304 std::ostringstream os;
00305 os << "Unable to export blob from " << MS_KEY_STORAGE_PROVIDER << " for CNG import: ("
00306 << GetLastError() << ")" << "(SECURITY_STATUS code " << cngStatus << ")" << endl;
00307 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00308 }
00309
00310
00311 if(!NT_SUCCESS(ntrv = BCryptOpenAlgorithmProvider(&m_hAlg,newProvAlgId,NULL,0)))
00312 {
00313 std::ostringstream os;
00314 os << "Couldn't open BCrypt algorithm provider for " << capiSpki->Algorithm.pszObjId << " :("
00315 << GetLastError() << ")" << "(NTSTATUS code " << ntrv << ")" << endl;
00316 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00317 }
00318 if(!NT_SUCCESS(ntrv = BCryptImportKeyPair(m_hAlg,NULL,BCRYPT_PUBLIC_KEY_BLOB,&m_hKey,pbNewBlob,cbNewBlob,0))) {
00319 std::ostringstream os;
00320 os << "Couldn't import key for algorithm " << capiSpki->Algorithm.pszObjId << " into CNG:("
00321 << GetLastError() << ")" << "(NTSTATUS code " << cngStatus << ")" << endl;
00322 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_KEY_IMPORT_FAILED, NULL);
00323 }
00324
00325
00326 }
00327 return this->GetCNGHandle();
00328
00329 }
00337 CPKIFAlgorithmIdentifierPtr CPKIFBCryptPublicKey::GetAlgId() const
00338 {
00339 CPKIFAlgorithmIdentifierPtr empty;
00340 if(!m_spki) return empty;
00341 return m_spki->alg();
00342 }
00350 BCRYPT_KEY_HANDLE CPKIFBCryptPublicKey::GetCNGHandle() const
00351 {
00352 return m_hKey;
00353 }
00361 void CPKIFBCryptPublicKey::clear()
00362 {
00363 if(m_hKey) {
00364 BCryptDestroyKey(m_hKey);
00365 m_hKey = NULL;
00366 }
00367 if(m_hAlg) {
00368 BCryptCloseAlgorithmProvider(m_hAlg,0);
00369 m_hAlg = NULL;
00370 }
00371 CPKIFSubjectPublicKeyInfoPtr empty;
00372 m_spki = empty;
00373 }