CAPIUtils.cpp

Go to the documentation of this file.
00001 
00009 #include "CAPIUtils.h"
00010 #include "ToolkitUtils.h"
00011 #include "PKIFException.h"
00012 #include "PKIFCryptoErrors.h"
00013 #include "components.h"
00021 void CAC_API ReverseBytes(
00023     unsigned char* buf,
00025     int bufLen)
00026 {
00027     unsigned char tmp;
00028     int top = bufLen - 1;
00029     for(int bottom = 0; bottom < top; ++bottom, --top)
00030     {
00031         tmp = buf[top];
00032         buf[top] = buf[bottom];
00033         buf[bottom] = tmp;
00034     }
00035 }
00036 
00037 //The next two functions (CreatePrivateExponentOneKey and ImportPlainSessionBlob)
00038 //were taken directly from the Microsoft Knowledge Base.  There's a Q article
00039 //there describing that the Microsoft CSPs do not allow import of plaintext
00040 //symmetric keys.  Thus we have to do the dance of these functions to achieve
00041 //that functionality.
00053 BOOL CreatePrivateExponentOneKey(
00055     LPTSTR szProvider, 
00057     DWORD dwProvType,
00059     LPTSTR szContainer,
00061     DWORD dwKeySpec,
00063     HCRYPTPROV *hProv, 
00065     HCRYPTKEY *hPrivateKey)
00066 {
00067    BOOL succ = FALSE;
00068    BOOL fReturn = FALSE;
00069    BOOL fResult;
00070    unsigned int n;
00071    LPBYTE keyblob = NULL;
00072    DWORD dwkeyblob;
00073    DWORD dwBitLen;
00074    BYTE *ptr;
00075 
00076    __try
00077    {
00078       *hProv = 0;
00079       *hPrivateKey = 0;
00080 
00081       if ((dwKeySpec != AT_KEYEXCHANGE) && (dwKeySpec != AT_SIGNATURE))  __leave;
00082 
00083       // Try to create new container
00084       fResult = CryptAcquireContext(hProv, szContainer, szProvider, 
00085                                     dwProvType, CRYPT_NEWKEYSET);
00086       if (!fResult)
00087       {
00088          // If the container exists, open it
00089          if (GetLastError() == NTE_EXISTS)
00090          {
00091             // delete the keyset, then try again
00092             fResult = CryptAcquireContext(hProv, szContainer, szProvider, dwProvType, CRYPT_DELETEKEYSET);
00093             if (!fResult)
00094             {
00095                // No good, leave
00096                __leave;
00097             }
00098             fResult = CryptAcquireContext(hProv, szContainer, szProvider, 
00099                                     dwProvType, CRYPT_NEWKEYSET);
00100             if (!fResult)
00101             {
00102                // No good, leave
00103                __leave;
00104             }
00105          }
00106          else
00107          {
00108             // No good, leave
00109             __leave;
00110          }
00111       }
00112 
00113       // Generate the private key
00114       fResult = CryptGenKey(*hProv, dwKeySpec, CRYPT_EXPORTABLE, hPrivateKey);
00115       if (!fResult) __leave;
00116 
00117       // Export the private key, we'll convert it to a private
00118       // exponent of one key
00119       fResult = CryptExportKey(*hPrivateKey, 0, PRIVATEKEYBLOB, 0, NULL, &dwkeyblob);
00120       if (!fResult) __leave;      
00121 
00122       //keyblob = (LPBYTE)LocalAlloc(LPTR, dwkeyblob);
00123       keyblob = new unsigned char[dwkeyblob];
00124       if (!keyblob) __leave;
00125 
00126       fResult = CryptExportKey(*hPrivateKey, 0, PRIVATEKEYBLOB, 0, keyblob, &dwkeyblob);
00127       if (!fResult) __leave;
00128 
00129 
00130       succ = CryptDestroyKey(*hPrivateKey);
00131       *hPrivateKey = 0;
00132 
00133       // Get the bit length of the key
00134       memcpy(&dwBitLen, &keyblob[12], 4);      
00135 
00136       // Modify the Exponent in Key BLOB format
00137       // Key BLOB format is documented in SDK
00138 
00139       // Convert pubexp in rsapubkey to 1
00140       ptr = &keyblob[16];
00141       for (n = 0; n < 4; n++)
00142       {
00143          if (n == 0) ptr[n] = 1;
00144          else ptr[n] = 0;
00145       }
00146 
00147       // Skip pubexp
00148       ptr += 4;
00149       // Skip modulus, prime1, prime2
00150       ptr += (dwBitLen/8);
00151       ptr += (dwBitLen/16);
00152       ptr += (dwBitLen/16);
00153 
00154       // Convert exponent1 to 1
00155       for (n = 0; n < (dwBitLen/16); n++)
00156       {
00157          if (n == 0) ptr[n] = 1;
00158          else ptr[n] = 0;
00159       }
00160 
00161       // Skip exponent1
00162       ptr += (dwBitLen/16);
00163 
00164       // Convert exponent2 to 1
00165       for (n = 0; n < (dwBitLen/16); n++)
00166       {
00167          if (n == 0) ptr[n] = 1;
00168          else ptr[n] = 0;
00169       }
00170 
00171       // Skip exponent2, coefficient
00172       ptr += (dwBitLen/16);
00173       ptr += (dwBitLen/16);
00174 
00175       // Convert privateExponent to 1
00176       for (n = 0; n < (dwBitLen/8); n++)
00177       {
00178          if (n == 0) ptr[n] = 1;
00179          else ptr[n] = 0;
00180       }
00181       
00182       // Import the exponent-of-one private key.      
00183       if (!CryptImportKey(*hProv, keyblob, dwkeyblob, 0, 0, hPrivateKey))
00184       {                 
00185          __leave;
00186       }
00187 
00188       fReturn = TRUE;
00189    }
00190    __finally
00191    {
00192       //if (keyblob) LocalFree(keyblob);
00193       if (keyblob)
00194       {
00195           delete[] keyblob; 
00196           keyblob = NULL;
00197       }
00198 
00199       if (!fReturn)
00200       {
00201          if (*hPrivateKey) CryptDestroyKey(*hPrivateKey);
00202          if (*hProv) CryptReleaseContext(*hProv, 0);
00203       }
00204    }
00205 
00206    return fReturn;
00207 }
00219 BOOL ImportPlainSessionBlob(
00221     HCRYPTPROV hProv,
00223     HCRYPTKEY hPrivateKey,
00225     ALG_ID dwAlgId,
00227     LPBYTE pbKeyMaterial ,
00229     DWORD dwKeyMaterial ,
00231     HCRYPTKEY *hSessionKey)
00232 {
00233    BOOL succ = FALSE;
00234    BOOL fResult;   
00235    BOOL fReturn = FALSE;
00236    BOOL fFound = FALSE;
00237    LPBYTE pbSessionBlob = NULL;
00238    DWORD dwSessionBlob, dwSize, n;
00239    DWORD dwPublicKeySize;
00240    DWORD dwProvSessionKeySize;
00241    ALG_ID dwPrivKeyAlg;
00242    LPBYTE pbPtr; 
00243    DWORD dwFlags = CRYPT_FIRST;
00244    PROV_ENUMALGS_EX ProvEnum;
00245    HCRYPTKEY hTempKey = 0;
00246 
00247    __try
00248    {
00249       // Double check to see if this provider supports this algorithm
00250       // and key size
00251       do
00252       {        
00253          dwSize = sizeof(ProvEnum);
00254          fResult = CryptGetProvParam(hProv, PP_ENUMALGS_EX, (LPBYTE)&ProvEnum,
00255                                      &dwSize, dwFlags);
00256          if (!fResult) break;
00257 
00258          dwFlags = 0;
00259 
00260          if (ProvEnum.aiAlgid == dwAlgId) fFound = TRUE;
00261                                      
00262       } while (!fFound);
00263 
00264       if (!fFound) __leave;
00265 
00266       // We have to get the key size(including padding)
00267       // from an HCRYPTKEY handle.  PP_ENUMALGS_EX contains
00268       // the key size without the padding so we can't use it.
00269       fResult = CryptGenKey(hProv, dwAlgId, 0, &hTempKey);
00270       if (!fResult) __leave;
00271       
00272       dwSize = sizeof(DWORD);
00273       fResult = CryptGetKeyParam(hTempKey, KP_KEYLEN, (LPBYTE)&dwProvSessionKeySize,
00274                                  &dwSize, 0);
00275       if (!fResult) __leave;      
00276       succ = CryptDestroyKey(hTempKey);
00277       hTempKey = 0;
00278 
00279       // Our key is too big, leave
00280       if ((dwKeyMaterial * 8) > dwProvSessionKeySize) __leave;
00281 
00282       // Get private key's algorithm
00283       dwSize = sizeof(ALG_ID);
00284       fResult = CryptGetKeyParam(hPrivateKey, KP_ALGID, (LPBYTE)&dwPrivKeyAlg, &dwSize, 0);
00285       if (!fResult) __leave;
00286 
00287       // Get private key's length in bits
00288       dwSize = sizeof(DWORD);
00289       fResult = CryptGetKeyParam(hPrivateKey, KP_KEYLEN, (LPBYTE)&dwPublicKeySize, &dwSize, 0);
00290       if (!fResult) __leave;
00291 
00292       // calculate Simple blob's length
00293       dwSessionBlob = (dwPublicKeySize/8) + sizeof(ALG_ID) + sizeof(BLOBHEADER);
00294 
00295       // allocate simple blob buffer
00296       //pbSessionBlob = (LPBYTE)LocalAlloc(LPTR, dwSessionBlob);
00297       pbSessionBlob = new unsigned char[dwSessionBlob];
00298       if (!pbSessionBlob) __leave;
00299 
00300       memset(pbSessionBlob, 0, dwSessionBlob);
00301 
00302       pbPtr = pbSessionBlob;
00303 
00304       // SIMPLEBLOB Format is documented in SDK
00305       // Copy header to buffer
00306       ((BLOBHEADER *)pbPtr)->bType = SIMPLEBLOB;
00307       ((BLOBHEADER *)pbPtr)->bVersion = 2;
00308       ((BLOBHEADER *)pbPtr)->reserved = 0;
00309       ((BLOBHEADER *)pbPtr)->aiKeyAlg = dwAlgId;
00310       pbPtr += sizeof(BLOBHEADER);
00311 
00312       // Copy private key algorithm to buffer
00313       *((DWORD *)pbPtr) = dwPrivKeyAlg;
00314       pbPtr += sizeof(ALG_ID);
00315 
00316       // Place the key material in reverse order
00317       for (n = 0; n < dwKeyMaterial; n++)
00318       {
00319          pbPtr[n] = pbKeyMaterial[dwKeyMaterial-n-1];
00320       }
00321      
00322       // 3 is for the first reserved byte after the key material + the 2 reserved bytes at the end.
00323       dwSize = dwSessionBlob - (sizeof(ALG_ID) + sizeof(BLOBHEADER) + dwKeyMaterial + 3);
00324       pbPtr += (dwKeyMaterial+1);
00325 
00326       // Generate random data for the rest of the buffer
00327       // (except that last two bytes)
00328       fResult = CryptGenRandom(hProv, dwSize, pbPtr);
00329       if (!fResult) __leave;
00330 
00331       for (n = 0; n < dwSize; n++)
00332       {
00333          if (pbPtr[n] == 0) pbPtr[n] = 1;
00334       }
00335 
00336       pbSessionBlob[dwSessionBlob - 2] = 2;
00337 
00338       fResult = CryptImportKey(hProv, pbSessionBlob , dwSessionBlob, 
00339                                hPrivateKey, CRYPT_EXPORTABLE, hSessionKey);
00340       if (!fResult) __leave;
00341 
00342       fReturn = TRUE;           
00343    }
00344    __finally
00345    {
00346       if (hTempKey) CryptDestroyKey(hTempKey);
00347       //if (pbSessionBlob) LocalFree(pbSessionBlob);
00348       if (pbSessionBlob) delete[] pbSessionBlob;
00349    }
00350    
00351    return fReturn;
00352 }
00353 
00354 //This function simply determines if there is a private key associated with 
00355 //a given cert.
00363 bool CertHasKey(
00365     PCCERT_CONTEXT pPrevCertContent)
00366 {
00367     if(NULL == pPrevCertContent)
00368         return false;
00369 
00370     DWORD            dwPropId = 0; 
00371     while(dwPropId = CertEnumCertificateContextProperties(
00372        pPrevCertContent, // The context whose properties are to be listed.
00373        dwPropId))    // Number of the last property found. This must 
00374                      // be zero to find the first property identifier.
00375     {
00376         if(CERT_KEY_PROV_INFO_PROP_ID == dwPropId)
00377             return true;
00378     }
00379 
00380     return false;
00381 }
00395 ALG_ID GetHashAlg(
00397     PKIFCRYPTO::HASH_ALG alg)
00398 {
00399     switch(alg)
00400     {
00401     case PKIFCRYPTO::SHA1:
00402         return CALG_SHA1;
00403     case PKIFCRYPTO::MD5:
00404         return CALG_MD5;
00405     default:
00406         throw CPKIFException(TOOLKIT_CRYPTO, CRYPTO_ALG_NOT_SUPPORTED, "Hashing algorithm not supported");
00407     }
00408 }
00409 
00423 wchar_t* GetCNGHashAlg(
00425     PKIFCRYPTO::HASH_ALG alg)
00426 {
00427     switch(alg)
00428     {
00429     case PKIFCRYPTO::SHA1:
00430         return BCRYPT_SHA1_ALGORITHM;
00431     case PKIFCRYPTO::SHA256:
00432         return BCRYPT_SHA256_ALGORITHM;
00433     case PKIFCRYPTO::SHA384:
00434         return BCRYPT_SHA384_ALGORITHM;
00435     case PKIFCRYPTO::SHA512:
00436         return BCRYPT_SHA512_ALGORITHM;
00437     case PKIFCRYPTO::MD5:
00438         return BCRYPT_MD5_ALGORITHM;
00439     default:
00440         throw CPKIFException(TOOLKIT_CRYPTO, CRYPTO_ALG_NOT_SUPPORTED, "Hashing algorithm not supported");
00441     }
00442 }
00450 void StrToName(
00452     const char* dn,
00454     unsigned char** enc, 
00456     DWORD* len)
00457 {
00458     int err = 0;
00459     const char* errstr = NULL;
00460 
00461     //expects the DN in LDAP order (i.e. most to least specific)
00462     BOOL succ = CertStrToName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, dn, 
00463         CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, NULL, NULL, len, &errstr);
00464     if(!succ)
00465     {
00466         err = GetLastError();
00467         *len = 0;
00468         *enc = NULL;
00469         return;
00470     }
00471     *enc = new unsigned char[(*len) + 1];
00472     succ = CertStrToName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, dn, 
00473         CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, NULL, *enc, len, &errstr);
00474     if(!succ)
00475     {
00476         err = GetLastError();
00477     }
00478 }

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