diff options
Diffstat (limited to 'src/classlibnative/cryptography')
-rw-r--r-- | src/classlibnative/cryptography/.gitmirror | 1 | ||||
-rw-r--r-- | src/classlibnative/cryptography/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/classlibnative/cryptography/cryptography.cpp | 3370 | ||||
-rw-r--r-- | src/classlibnative/cryptography/cryptography.h | 521 | ||||
-rw-r--r-- | src/classlibnative/cryptography/cryptography.nativeproj | 36 | ||||
-rw-r--r-- | src/classlibnative/cryptography/x509certificate.cpp | 1340 | ||||
-rw-r--r-- | src/classlibnative/cryptography/x509certificate.h | 165 |
7 files changed, 0 insertions, 5439 deletions
diff --git a/src/classlibnative/cryptography/.gitmirror b/src/classlibnative/cryptography/.gitmirror deleted file mode 100644 index f507630f94..0000000000 --- a/src/classlibnative/cryptography/.gitmirror +++ /dev/null @@ -1 +0,0 @@ -Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror.
\ No newline at end of file diff --git a/src/classlibnative/cryptography/CMakeLists.txt b/src/classlibnative/cryptography/CMakeLists.txt deleted file mode 100644 index 10c899f7f8..0000000000 --- a/src/classlibnative/cryptography/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -set( COMCRYPT_WKS_SOURCES - Cryptography.cpp - X509Certificate.cpp -) - -add_library_clr( comcrypt_wks ${COMCRYPT_WKS_SOURCES}) diff --git a/src/classlibnative/cryptography/cryptography.cpp b/src/classlibnative/cryptography/cryptography.cpp deleted file mode 100644 index 7851496d52..0000000000 --- a/src/classlibnative/cryptography/cryptography.cpp +++ /dev/null @@ -1,3370 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// -// File: Cryptography.cpp -// - -// -// Native method implementations and helper code for supporting CAPI based operations -//--------------------------------------------------------------------------- - - - -#include "common.h" - -#include "field.h" -#include "cryptography.h" - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) -const BYTE g_rgbPrivKey[] = -{ - 0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, - 0x52, 0x53, 0x41, 0x32, 0x00, 0x02, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0xAB, 0xEF, 0xFA, 0xC6, - 0x7D, 0xE8, 0xDE, 0xFB, 0x68, 0x38, 0x09, 0x92, - 0xD9, 0x42, 0x7E, 0x6B, 0x89, 0x9E, 0x21, 0xD7, - 0x52, 0x1C, 0x99, 0x3C, 0x17, 0x48, 0x4E, 0x3A, - 0x44, 0x02, 0xF2, 0xFA, 0x74, 0x57, 0xDA, 0xE4, - 0xD3, 0xC0, 0x35, 0x67, 0xFA, 0x6E, 0xDF, 0x78, - 0x4C, 0x75, 0x35, 0x1C, 0xA0, 0x74, 0x49, 0xE3, - 0x20, 0x13, 0x71, 0x35, 0x65, 0xDF, 0x12, 0x20, - 0xF5, 0xF5, 0xF5, 0xC1, 0xED, 0x5C, 0x91, 0x36, - 0x75, 0xB0, 0xA9, 0x9C, 0x04, 0xDB, 0x0C, 0x8C, - 0xBF, 0x99, 0x75, 0x13, 0x7E, 0x87, 0x80, 0x4B, - 0x71, 0x94, 0xB8, 0x00, 0xA0, 0x7D, 0xB7, 0x53, - 0xDD, 0x20, 0x63, 0xEE, 0xF7, 0x83, 0x41, 0xFE, - 0x16, 0xA7, 0x6E, 0xDF, 0x21, 0x7D, 0x76, 0xC0, - 0x85, 0xD5, 0x65, 0x7F, 0x00, 0x23, 0x57, 0x45, - 0x52, 0x02, 0x9D, 0xEA, 0x69, 0xAC, 0x1F, 0xFD, - 0x3F, 0x8C, 0x4A, 0xD0, - - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x64, 0xD5, 0xAA, 0xB1, - 0xA6, 0x03, 0x18, 0x92, 0x03, 0xAA, 0x31, 0x2E, - 0x48, 0x4B, 0x65, 0x20, 0x99, 0xCD, 0xC6, 0x0C, - 0x15, 0x0C, 0xBF, 0x3E, 0xFF, 0x78, 0x95, 0x67, - 0xB1, 0x74, 0x5B, 0x60, - - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -const BYTE g_rgbSymKey[] = -{ - 0x01, 0x02, 0x00, 0x00, 0x02, 0x66, 0x00, 0x00, - 0x00, 0xA4, 0x00, 0x00, 0xAD, 0x89, 0x5D, 0xDA, - 0x82, 0x00, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x02, 0x00 -}; - -const BYTE g_rgbPubKey[] = -{ - 0x06, 0x02, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, - 0x52, 0x53, 0x41, 0x31, 0x00, 0x02, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0xab, 0xef, 0xfa, 0xc6, - 0x7d, 0xe8, 0xde, 0xfb, 0x68, 0x38, 0x09, 0x92, - 0xd9, 0x42, 0x7e, 0x6b, 0x89, 0x9e, 0x21, 0xd7, - 0x52, 0x1c, 0x99, 0x3c, 0x17, 0x48, 0x4e, 0x3a, - 0x44, 0x02, 0xf2, 0xfa, 0x74, 0x57, 0xda, 0xe4, - 0xd3, 0xc0, 0x35, 0x67, 0xfa, 0x6e, 0xdf, 0x78, - 0x4c, 0x75, 0x35, 0x1c, 0xa0, 0x74, 0x49, 0xe3, - 0x20, 0x13, 0x71, 0x35, 0x65, 0xdf, 0x12, 0x20, - 0xf5, 0xf5, 0xf5, 0xc1 -}; - - -ProviderCache *ProviderCache::s_pCache = NULL; - -//--------------------------------------------------------------------------------------- -// -// Associate a default CSP name with a CSP type -// -// Arguments: -// dwType - type of CSP to associate the default name with -// pwzProvider - name of the default CSP for dwType -// -// Notes: -// Can throw an OOM if this is the first call into the method and -// the underlying cache has yet to be allocated. See ProviderCache::InternalCacheProvider -// for other details. - -// static -void ProviderCache::CacheProvider(DWORD dwType, __in_z LPWSTR pwzProvider) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(pwzProvider != NULL); - } - CONTRACTL_END; - - if (s_pCache == NULL) - { - NewHolder<ProviderCache> cacheHolder(new ProviderCache()); - LPVOID pvExchange = InterlockedCompareExchangeT(&s_pCache, - cacheHolder.GetValue(), - NULL); - if (pvExchange == NULL) - cacheHolder.SuppressRelease(); - } - - s_pCache->InternalCacheProvider(dwType, pwzProvider); -} - -//--------------------------------------------------------------------------------------- -// -// Get the CSP name associated with the CSP type -// -// Arguments: -// dwType - type of CSP to lookup the name of -// -// Return Value: -// Name of the CSP if it is cached, NULL if there is no association yet - -// static -LPCWSTR ProviderCache::GetProvider(DWORD dwType) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (s_pCache != NULL) - return s_pCache->InternalGetProvider(dwType); - else - return NULL; -} - -//--------------------------------------------------------------------------------------- -// -// Initialize the CSP cache -// -// Notes: -// Can throw an OOM the hashtable could not be setup properly -// - -ProviderCache::ProviderCache() - : m_crstCache(CrstCSPCache) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - LockOwner lockOwner = { &m_crstCache, IsOwnerOfCrst }; - if (!m_htCache.Init(MaxWindowsProviderType, &lockOwner)) - COMPlusThrowOM(); -} - -//--------------------------------------------------------------------------------------- -// -// Associate a default CSP name with a CSP type -// -// Arguments: -// dwType - type of CSP to associate the default name with -// pwzProvider - name of the default CSP for dwType -// - -void ProviderCache::InternalCacheProvider(DWORD dwType, __in_z LPWSTR pwzProvider) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - CAN_TAKE_LOCK; - PRECONDITION(pwzProvider != NULL); - } - CONTRACTL_END; - - CrstHolder lockHolder(&m_crstCache); - if (GetProvider(dwType) == NULL) - m_htCache.InsertValue(dwType, reinterpret_cast<HashDatum>(pwzProvider)); -} - -//--------------------------------------------------------------------------------------- -// -// Get the CSP name associated with the CSP type -// -// Arguments: -// dwType - type of CSP to lookup the name of -// -// Return Value: -// Name of the CSP if it is cached, NULL if there is no association yet - -LPCWSTR ProviderCache::InternalGetProvider(DWORD dwType) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - HashDatum datum; - if (!m_htCache.GetValue(dwType, &datum)) - return NULL; - - _ASSERTE(datum != NULL); - return reinterpret_cast<LPCWSTR>(datum); -} -#endif // FEATURE_CRYPTO - -#if defined(FEATURE_X509) || defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) -// -// Throw a runtime exception based on the HRESULT passed in. -// - -void CryptoHelper::COMPlusThrowCrypto(HRESULT hr) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - GCX_COOP(); - - MethodDescCallSite throwMethod(METHOD__CRYPTO_EXCEPTION__THROW); - - ARG_SLOT args[] = { - (ARG_SLOT) hr - }; - throwMethod.Call(args); -} - -BOOL CryptoHelper::WszCryptAcquireContext_SO_TOLERANT (HCRYPTPROV *phProv, LPCWSTR pwszContainer, LPCWSTR pwszProvider, DWORD dwProvType, DWORD dwFlags) -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_MODE_PREEMPTIVE; - STATIC_CONTRACT_SO_INTOLERANT; - - BOOL fResult = FALSE; - DWORD dwLastError = 0; - -#ifdef FEATURE_CRYPTO - // Specifying both verify context (for an ephemeral key) and machine keyset (for a persisted machine key) - // does not make sense. Additionally, Widows is beginning to lock down against uses of MACHINE_KEYSET - // (for instance in the app container), even if verify context is present. Therefore, if we're using - // an ephemeral key, strip out MACHINE_KEYSET from the flags. - if ((dwFlags & CRYPT_VERIFYCONTEXT) && (dwFlags & CRYPT_MACHINE_KEYSET)) - { - dwFlags &= ~CRYPT_MACHINE_KEYSET; - } -#endif // FEATURE_CRYPTO - - BEGIN_SO_TOLERANT_CODE_CALLING_HOST(GetThread()) - - { - LeaveRuntimeHolder lrh((size_t)::CryptAcquireContextW); - fResult = WszCryptAcquireContext (phProv, pwszContainer, pwszProvider, dwProvType, dwFlags); - if (!fResult) - dwLastError = ::GetLastError(); - } - - END_SO_TOLERANT_CODE_CALLING_HOST; - - // END_SO_TOLERANT_CODE overwrites lasterror. Let's reset it. - ::SetLastError(dwLastError); - return fResult; -} - -// -// Helper method to get a Unicode copy of a managed string object. The Unicode string has to be freed with delete []. -// - -WCHAR* CryptoHelper::STRINGREFToUnicode (STRINGREF s) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(s != NULL); - } CONTRACTL_END; - - int cchUnicodeChar = s->GetStringLength(); - WCHAR* pwszUnicode = new WCHAR[cchUnicodeChar + 1]; - memcpy (pwszUnicode, s->GetBuffer(), cchUnicodeChar * sizeof(WCHAR)); - pwszUnicode[cchUnicodeChar] = W('\0'); - - return pwszUnicode; -} -#endif // FEATURE_X509 || FEATURE_CRYPTO - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) -// -// Helper method to generate a random key container name. -// The caller is responsible for freeing the memory allocated. -// - -WCHAR* CryptoHelper::GetRandomKeyContainer() { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - GUID guid; - HRESULT hr = CoCreateGuid(&guid); - if (hr != S_OK) - COMPlusThrowHR(hr); - - WCHAR* pwszKeyContainerName = new WCHAR[50]; - memcpy(pwszKeyContainerName, W("CLR"), 4 * sizeof(WCHAR)); - - if (GuidToLPWSTR(guid, &pwszKeyContainerName[3], 45) == 0) { - DWORD lastError = GetLastError(); - delete [] pwszKeyContainerName; - COMPlusThrowHR(HRESULT_FROM_WIN32(lastError)); - } - - return pwszKeyContainerName; -} -#endif // FEATURE_CRYPTO - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) || defined(FEATURE_X509) -// -// Helper method to get a Unicode string from an ANSI string. The Unicode string has to be freed with delete []. -// - -WCHAR* CryptoHelper::AnsiToUnicode (__in_z char* pszAnsi) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - int cchUnicodeChar = WszMultiByteToWideChar(CP_ACP, - 0, - pszAnsi, - -1, - NULL, - 0); - if (cchUnicodeChar == 0) - COMPlusThrowWin32(); - - WCHAR* pwszUnicode = new WCHAR[cchUnicodeChar]; - cchUnicodeChar = WszMultiByteToWideChar(CP_ACP, - 0, - pszAnsi, - -1, - pwszUnicode, - cchUnicodeChar); - if (cchUnicodeChar == 0) { - DWORD lastError = GetLastError(); - delete [] pwszUnicode; - COMPlusThrowHR(HRESULT_FROM_WIN32(lastError)); - } - - return pwszUnicode; -} - -// -// Helper method to construct a managed array from an unamanged byte array. The array ref has to be protected. -// - -void CryptoHelper::ByteArrayToU1ARRAYREF (LPBYTE pb, DWORD cb, U1ARRAYREF* u1) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pb)); - } CONTRACTL_END; - - OBJECTREF array = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cb); - SetObjectReference((OBJECTREF*) u1, array, NULL); - memcpyNoGCRefs((*u1)->GetDirectPointerToNonObjectElements(), pb, cb); -} -#endif // FEATURE_CRYPTO || FEATURE_X509 - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) -// -// memrev -// - -inline void CryptoHelper::memrev(LPBYTE pb, DWORD cb) { - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } CONTRACTL_END; - - BYTE b; - LPBYTE pbEnd = pb+cb-1; - LPBYTE pbStart = pb; - - for (DWORD i=0; i<cb/2; i++, pbStart++, pbEnd--) { - b = *pbStart; - *pbStart = *pbEnd; - *pbEnd = b; - } -} -#endif // FEATURE_CRYPTO - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) || defined(FEATURE_X509) -// -// Helper method to construct a byte array from a managed array ref. The unmanaged byte array pointer has to freed with delete []. -// - -BYTE* CryptoHelper::U1ARRAYREFToByteArray (U1ARRAYREF u1) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(u1 != NULL); - } CONTRACTL_END; - - BYTE* pb = new BYTE[u1->GetNumComponents()]; - memcpy(pb, (LPBYTE) u1->GetDirectPointerToNonObjectElements(), u1->GetNumComponents()); - - return pb; -} - -// -// Helper method to get an ANSI string from a Unicode string. The ANSI string has to be freed with delete []. -// - -char* CryptoHelper::UnicodeToAnsi (__in_z WCHAR* pwszUnicode) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - int cchAnsiChar; - cchAnsiChar = WszWideCharToMultiByte(CP_ACP, - 0, - pwszUnicode, - -1, - NULL, - 0, - NULL, - NULL); - if (cchAnsiChar == 0) - COMPlusThrowWin32(); - - char* pszAnsi = new char[cchAnsiChar]; - cchAnsiChar = WszWideCharToMultiByte(CP_ACP, - 0, - pwszUnicode, - -1, - pszAnsi, - cchAnsiChar, - NULL, - NULL); - if (cchAnsiChar == 0) { - DWORD lastError = GetLastError(); - delete [] pszAnsi; - COMPlusThrowHR(HRESULT_FROM_WIN32(lastError)); - } - - return pszAnsi; -} -#endif // FEATURE_CRYPTO || FEATURE_X509 - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) -BOOL CryptoHelper::CryptGenKey_SO_TOLERANT (HCRYPTPROV hProv, ALG_ID Algid, DWORD dwFlags, HCRYPTKEY* phKey) -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_MODE_PREEMPTIVE; - STATIC_CONTRACT_SO_INTOLERANT; - - BOOL fResult = FALSE; - DWORD dwLastError = 0; - - BEGIN_SO_TOLERANT_CODE_CALLING_HOST(GetThread()) - - fResult = CryptGenKey (hProv, Algid, dwFlags, phKey); - if (!fResult) - dwLastError = ::GetLastError(); - - END_SO_TOLERANT_CODE_CALLING_HOST; - - // END_SO_TOLERANT_CODE overwrites lasterror. Let's reset it. - ::SetLastError(dwLastError); - return fResult; -} - -// -// Check to see if a better CSP than the one requested is available -// DSS providers are supersets of each other in the following order: -// 1. MS_ENH_DSS_DH_PROV -// 2. MS_DEF_DSS_DH_PROV -// -// This will return the best provider which is a superset of wszProvider, -// or NULL if there is no upgrade available on the machine. -// -LPCWSTR CryptoHelper::UpgradeDSS(DWORD dwProvType, __in_z LPCWSTR wszProvider) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(dwProvType == PROV_DSS_DH); - PRECONDITION(wszProvider != NULL); - } - CONTRACTL_END; - - LPCWSTR wszUpgrade = NULL; - HandleCSPHolder hProv = NULL; - - if (wcscmp(wszProvider, MS_DEF_DSS_DH_PROV_W) == 0) - { - // If this is the base DSS/DH provider, see if we can use the enhanced provider instead. - if (CryptoHelper::WszCryptAcquireContext_SO_TOLERANT(&hProv, NULL, MS_ENH_DSS_DH_PROV_W, dwProvType, CRYPT_VERIFYCONTEXT)) - wszUpgrade = MS_ENH_DSS_DH_PROV_W; - } - - return wszUpgrade; -} - -// -// Check to see if a better CSP than the one requested is available -// RSA providers are supersets of each other in the following order: -// 1. MS_ENH_RSA_AES_PROV -// 2. MS_ENHANCED_PROV -// 3. MS_DEF_PROV -// -// This will return the best provider which is a superset of wszProvider, -// or NULL if there is no upgrade available on the machine. -// -LPCWSTR CryptoHelper::UpgradeRSA(DWORD dwProvType, __in_z LPCWSTR wszProvider) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(dwProvType == PROV_RSA_FULL); - PRECONDITION(wszProvider != NULL); - } - CONTRACTL_END; - - bool requestedEnhanced = wcscmp(wszProvider, MS_ENHANCED_PROV_W) == 0; - bool requestedBase = wcscmp(wszProvider, MS_DEF_PROV_W) == 0; - - LPCWSTR wszUpgrade = NULL; - HandleCSPHolder hProv = NULL; - - if (requestedBase || requestedEnhanced) - { - // attempt to use the AES provider - if (CryptoHelper::WszCryptAcquireContext_SO_TOLERANT(&hProv, NULL, MS_ENH_RSA_AES_PROV_W, dwProvType, CRYPT_VERIFYCONTEXT)) - wszUpgrade = MS_ENH_RSA_AES_PROV_W; - } - else if (wszUpgrade == NULL && requestedBase) - { - // if AES wasn't available and we requested the base CSP, try the enhanced one - if (CryptoHelper::WszCryptAcquireContext_SO_TOLERANT(&hProv, NULL, MS_ENHANCED_PROV_W, dwProvType, CRYPT_VERIFYCONTEXT)) - wszUpgrade = MS_ENHANCED_PROV_W; - } - - return wszUpgrade; -} - -// -// WARNING: This function side-effects its first argument (hProv) -// MSProviderCryptImportKey does an "exponent-of-one" import of specified -// symmetric key material into a CSP. However, it clobbers any exchange key pair -// already in hProv. -// - -HRESULT COMCryptography::ExponentOfOneImport (HCRYPTPROV hProv, - LPBYTE rgbKeyMaterial, - DWORD cbKeyMaterial, - DWORD dwKeyAlg, - DWORD dwFlags, - HCRYPTKEY* phKey) { - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } CONTRACTL_END; - - HRESULT hr = S_OK; - - LPBYTE pb = NULL; - BLOBHEADER * pbhdr = NULL; - BYTE rgb[sizeof(g_rgbSymKey)]; - - // Do this check here as a sanity check to avoid buffer overruns - // variable bufSize used to allow for overflow. - DWORD bufSize= cbKeyMaterial + sizeof(ALG_ID) + sizeof(BLOBHEADER); - if (bufSize < cbKeyMaterial || bufSize >= sizeof(g_rgbSymKey)) - return E_FAIL; - - memcpy(rgb, g_rgbSymKey, sizeof(g_rgbSymKey)); - - pbhdr = (BLOBHEADER *) rgb; - pbhdr->aiKeyAlg = dwKeyAlg; - pb = &rgb[sizeof(*pbhdr)]; - *((ALG_ID *) pb) = CALG_RSA_KEYX; - - pb += sizeof(ALG_ID); - for (DWORD i=0; i<cbKeyMaterial; i++) - pb[cbKeyMaterial-i-1] = rgbKeyMaterial[i]; - pb[cbKeyMaterial] = 0; - - HandleKeyHolder hPrivKey(NULL); - if (!CryptImportKey(hProv, g_rgbPrivKey, sizeof(g_rgbPrivKey), 0, 0, &hPrivKey)) { - hr = HRESULT_FROM_GetLastError(); - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::ExponentOfOneImport --> CryptImportKey failed.\n", hr)); - } - - if (!CryptImportKey(hProv, rgb, sizeof(rgb), hPrivKey, dwFlags, phKey)) { - hr = HRESULT_FROM_GetLastError(); - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::ExponentOfOneImport --> CryptImportKey failed.\n", hr)); - } - - return hr; -} - -HRESULT COMCryptography::PlainTextKeyBlobImport (HCRYPTPROV hProv, - LPBYTE rgbKeyMaterial, - DWORD cbKeyMaterial, - DWORD dwKeyAlg, - DWORD dwFlags, - HCRYPTKEY* phKey) { - CONTRACTL { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } CONTRACTL_END; - - HRESULT hr = S_OK; - - DWORD cb = cbKeyMaterial + sizeof(DWORD) + sizeof(BLOBHEADER); - NewArrayHolder<BYTE> pbHolder(new BYTE[cb]); - LPBYTE pb = (LPBYTE) pbHolder.GetValue(); - - BLOBHEADER * pbhdr = (BLOBHEADER *) pb; - pbhdr->bType = PLAINTEXTKEYBLOB; - pbhdr->bVersion = CUR_BLOB_VERSION; - pbhdr->reserved = 0x0000; - pbhdr->aiKeyAlg = dwKeyAlg; - - pb += sizeof(*pbhdr); - *((DWORD *) pb) = cbKeyMaterial; - pb += sizeof(DWORD); - memcpy(pb, rgbKeyMaterial, cbKeyMaterial); - - if (!CryptImportKey(hProv, pbHolder, cb, 0, dwFlags, phKey)) { - hr = HRESULT_FROM_GetLastError(); - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::PlainTextKeyBlobImport --> CryptImportKey failed.\n", hr)); - } - - return hr; -} - -HRESULT COMCryptography::LoadKey (LPBYTE rgbKeyMaterial, - DWORD cbKeyMaterial, - HCRYPTPROV hprov, - DWORD dwCalg, - DWORD dwFlags, - HCRYPTKEY* phkey) { - WRAPPER_NO_CONTRACT; - - HRESULT hr = PlainTextKeyBlobImport(hprov, rgbKeyMaterial, cbKeyMaterial, dwCalg, dwFlags, phkey); - if (FAILED(hr)) - hr = ExponentOfOneImport(hprov, rgbKeyMaterial, cbKeyMaterial, dwCalg, dwFlags, phkey); - return hr; -} - -// -// WARNING: This function side-effects its first argument (hProv) -// - -HRESULT COMCryptography::UnloadKey(HCRYPTPROV hprov, - HCRYPTKEY hkey, - LPBYTE* ppb, - DWORD* pcb) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - DWORD cbOut = 0; - HandleKeyHolder hPubKey(NULL); - - HRESULT hr = S_OK; - if (!CryptImportKey(hprov, g_rgbPubKey, sizeof(g_rgbPubKey), 0, 0, &hPubKey)) { - hr = HRESULT_FROM_GetLastError(); - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::UnloadKey --> CryptImportKey failed.\n", hr)); - return hr; - } - - if (!CryptExportKey(hkey, hPubKey, SIMPLEBLOB, 0, NULL, &cbOut)) { - hr = HRESULT_FROM_GetLastError(); - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::UnloadKey --> CryptExportKey failed.\n", hr)); - return hr; - } - - NewArrayHolder<BYTE> pbOut(new BYTE[cbOut]); - if (!CryptExportKey(hkey, hPubKey, SIMPLEBLOB, 0, pbOut, &cbOut)) { - hr = HRESULT_FROM_GetLastError(); - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::UnloadKey --> CryptExportKey failed.\n", hr)); - return hr; - } - - // Get size of the item - LPBYTE pb2 = pbOut + sizeof(BLOBHEADER) + sizeof(DWORD); - DWORD i= cbOut - sizeof(BLOBHEADER) - sizeof(DWORD) - 2; - if (i >= cbOut) { - // integer overflow - return E_FAIL; - } - while (i > 0) { - if (pb2[i] == 0) - break; - i--; - } - - // Now allocate the return buffer - *ppb = new BYTE[i]; - - memcpy(*ppb, pb2, i); - CryptoHelper::memrev(*ppb, i); - *pcb = i; - - return hr; -} - -// -// GetDefaultProvider -// -// Description: -// Find the default provider name to be used in the case that we -// were not actually passed in a provider name. The main purpose -// of this code is really to deal with the enhanched/default provider -// problems given to us by CAPI. -// -// Returns: -// name of the provider to be used. -// - -LPCWSTR COMCryptography::GetDefaultProvider(DWORD dwType) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - // If we have already gotten a name for this provider type, then just return it. - LPCWSTR pwszCached = ProviderCache::GetProvider(dwType); - if (pwszCached != NULL) - return pwszCached; - - // figure out how big the provider name is - DWORD cbProviderName = 0; - if (!WszCryptGetDefaultProvider(dwType, NULL, CRYPT_MACHINE_DEFAULT, NULL, &cbProviderName)) - { - DWORD dwLastError = GetLastError(); - LOG((LF_SECURITY, LL_INFO10, "Error [%#x]: CryptGetDefaultProvider(%d)", dwLastError, dwType)); - return NULL; - } - - // get the CSP name from CAPI - NewArrayHolder<WCHAR> pwszProviderName(new WCHAR[cbProviderName]); - if (!WszCryptGetDefaultProvider(dwType, NULL, CRYPT_MACHINE_DEFAULT, pwszProviderName, &cbProviderName)) - { - DWORD dwLastError = GetLastError(); - LOG((LF_SECURITY, LL_INFO10, "Error [%#x]: CryptGetDefaultProvider(%d)", dwLastError, dwType)); - return NULL; - } - - { - GCX_PREEMP(); - - // check to see if there are upgrades available for the requested CSP - LPCWSTR wszUpgrade = NULL; - if (dwType == PROV_RSA_FULL) - wszUpgrade = CryptoHelper::UpgradeRSA(dwType, pwszProviderName); - else if (dwType == PROV_DSS_DH) - wszUpgrade = CryptoHelper::UpgradeDSS(dwType, pwszProviderName); - - if (wszUpgrade != NULL) - { - LOG((LF_SECURITY, LL_INFO10, "Upgrading from CSP %s to CSP %s", pwszProviderName, wszUpgrade)); - - pwszProviderName.Release(); - const size_t cchProvider = wcslen(wszUpgrade) + 1; - pwszProviderName = new WCHAR[cchProvider]; - wcscpy_s(pwszProviderName, cchProvider, wszUpgrade); - } - } - - ProviderCache::CacheProvider(dwType, pwszProviderName); - pwszProviderName.SuppressRelease(); - - LOG((LF_SECURITY, LL_INFO100, "Using CSP %s as default for CSP type %d", pwszProviderName, dwType)); - return pwszProviderName; -} - -// converts a big-endian byte array to a DWORD value -inline DWORD COMCryptography::ConvertByteArrayToDWORD (LPBYTE pb, DWORD cb) { - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION((cb <= 4 && cb >= 0)); - } CONTRACTL_END; - - DWORD dwOutput = 0; - for (DWORD i = 0; i < cb; i++) { - dwOutput = dwOutput << 8; - dwOutput += pb[i]; - } - return dwOutput; -} - -// output of this routine is always big endian -inline void COMCryptography::ConvertIntToByteArray(DWORD dwInput, LPBYTE * ppb, DWORD * pcb) { - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - SO_INTOLERANT; - } CONTRACTL_END; - - if (dwInput == 0) { - *ppb = new BYTE[1]; - (*ppb)[0] = 0; - return; - } - - *ppb = new BYTE[4]; - - DWORD t1 = dwInput; // t1 is remaining value to account for - DWORD t2; // t2 is (t1 % 256) & 0xFF - DWORD i = 0; - - while (t1 > 0) { - t2 = (t1 % 256) & 0xFF; - (*ppb)[i] = static_cast<BYTE>(t2); - t1 = (t1 - t2) >> 8; - i++; - } - - *pcb = i; - CryptoHelper::memrev(*ppb, i); -} - -// Maps CspProviderFlags enumeration into CAPI flags. -DWORD COMCryptography::MapCspKeyFlags (DWORD dwFlags) { - DWORD dwCapiFlags = 0; - if ((dwFlags & CSP_PROVIDER_FLAGS_USE_NON_EXPORTABLE_KEY) == 0) - dwCapiFlags |= CRYPT_EXPORTABLE; - if (dwFlags & CSP_PROVIDER_FLAGS_USE_ARCHIVABLE_KEY) - dwCapiFlags |= CRYPT_ARCHIVABLE; - if (dwFlags & CSP_PROVIDER_FLAGS_USE_USER_PROTECTED_KEY) - dwCapiFlags |= CRYPT_USER_PROTECTED; - - return dwCapiFlags; -} - -// Maps CspProviderFlags enumeration into CAPI flags. -DWORD COMCryptography::MapCspProviderFlags (DWORD dwFlags) { - DWORD dwCapiFlags = 0; - if (dwFlags & CSP_PROVIDER_FLAGS_USE_MACHINE_KEYSTORE) - dwCapiFlags |= CRYPT_MACHINE_KEYSET; - if (dwFlags & CSP_PROVIDER_FLAGS_USE_CRYPT_SILENT) - dwCapiFlags |= CRYPT_SILENT; - if (dwFlags & CSP_PROVIDER_FLAGS_CREATE_EPHEMERAL_KEY) - dwCapiFlags |= CRYPT_VERIFYCONTEXT; - - return dwCapiFlags; -} - -// -// OpenCSP -// -// Description: -// OpenCSP performs the core work of opening and creating CSPs and -// containers in CSPs. -// - -HRESULT COMCryptography::OpenCSP(OBJECTREF * pSafeThis, DWORD dwFlags, CRYPT_PROV_CTX * pProvCtx) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - NewArrayHolder<WCHAR> pwszProviderHolder = NULL; // if we need to allocate the CSP name ourselves - // store it here so it can be released - LPCWSTR pwszProvider = NULL; // location where the CSP name will be read - // regardless of where we loaded it from - - NewArrayHolder<WCHAR> pwszContainer = NULL; - - // - // Look for the provider type - // - - FieldDesc * pFD = MscorlibBinder::GetField(FIELD__CSP_PARAMETERS__PROVIDER_TYPE); - DWORD dwType = pFD->GetValue32(*pSafeThis); - - // - // Look for the provider name - // - - pFD = MscorlibBinder::GetField(FIELD__CSP_PARAMETERS__PROVIDER_NAME); - - OBJECTREF objref = pFD->GetRefValue(*pSafeThis); - STRINGREF strProvider = ObjectToSTRINGREF(*(StringObject **) &objref); - if (strProvider != NULL) { - LPCWSTR pwsz = strProvider->GetBuffer(); - if ((pwsz != NULL) && (*pwsz != 0)) { - pwszProviderHolder = CryptoHelper::STRINGREFToUnicode(strProvider); - pProvCtx->m_fReleaseProvider = TRUE; - pwszProvider = pwszProviderHolder; - } - else { - pwszProvider = GetDefaultProvider(dwType); - pProvCtx->m_fReleaseProvider = FALSE; - STRINGREF str = StringObject::NewString(pwszProvider); - pFD->SetRefValue(*pSafeThis, (OBJECTREF)str); - } - } else { - pwszProvider = GetDefaultProvider(dwType); - pProvCtx->m_fReleaseProvider = FALSE; - STRINGREF str = StringObject::NewString(pwszProvider); - pFD->SetRefValue(*pSafeThis, (OBJECTREF)str); - } - - // look to see if the user specified that we should pass - // CRYPT_MACHINE_KEYSET to CAPI to use machine key storage instead - // of user key storage - DWORD dwCspProviderFlags = 0; - - objref=NULL; - GCPROTECT_BEGIN (objref); - - pFD = MscorlibBinder::GetField(FIELD__CSP_PARAMETERS__FLAGS); - dwCspProviderFlags = pFD->GetValue32(*pSafeThis); - - // If the user specified CSP_PROVIDER_FLAGS_USE_DEFAULT_KEY_CONTAINER, - // then ignore the container name and hand back the default container - - pFD = MscorlibBinder::GetField(FIELD__CSP_PARAMETERS__KEY_CONTAINER_NAME); - if ((dwCspProviderFlags & CSP_PROVIDER_FLAGS_USE_DEFAULT_KEY_CONTAINER) == 0) { - // Look for the key container name - objref = pFD->GetRefValue(*pSafeThis); - STRINGREF strContainer = ObjectToSTRINGREF(*(StringObject **) &objref); - if (strContainer != NULL) { - LPWSTR pwsz = strContainer->GetBuffer(); - if ((pwsz != NULL) && (*pwsz != 0)) - pwszContainer = CryptoHelper::STRINGREFToUnicode(strContainer); - } - } - - GCPROTECT_END (); - - // Go ahead and try to open the CSP. If we fail, make sure the CSP - // returned is 0 as that is going to be the error check in the caller. - HandleCSPHolder hProv(NULL); - { - GCX_PREEMP(); - dwFlags |= MapCspProviderFlags(dwCspProviderFlags); - - if (!CryptoHelper::WszCryptAcquireContext_SO_TOLERANT(&hProv, pwszContainer, pwszProvider, dwType, dwFlags)) - return HRESULT_FROM_GetLastError(); - } - - // CRYPT_PROV_CTX takes ownership of these resources, and frees them in its Release - hProv.SuppressRelease(); - pwszContainer.SuppressRelease(); - pwszProviderHolder.SuppressRelease(); - - pProvCtx->m_hProv = hProv; - pProvCtx->m_pwszContainer = pwszContainer; - pProvCtx->m_pwszProvider = pwszProvider; - pProvCtx->m_dwType = dwType; - pProvCtx->m_dwFlags = dwFlags; - - // If we are using CRYPT_VERIFYCONTEXT this is an ephemeral key, so clear the persist flag - if (dwFlags & CRYPT_VERIFYCONTEXT) - pProvCtx->m_fPersistKeyInCsp = FALSE; - - return S_OK; -} - -// -// FCALL functions -// - -// -// Native method to open a CSP using CRYPT_VERIFYCONTEXT -// - -FCIMPL2(void, COMCryptography::_AcquireCSP, Object* cspParametersUNSAFE, SafeHandle** hProvUNSAFE) -{ - FCALL_CONTRACT; - - OBJECTREF cspParameters = (OBJECTREF) cspParametersUNSAFE; - SAFEHANDLE hProvSAFE = (SAFEHANDLE) *hProvUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_2(cspParameters, hProvSAFE); - - // - // We want to just open this CSP. Passing in verify context will - // open it and, if a container is given, map to open the container. - // - - NewHolder<CRYPT_PROV_CTX> pProvCtx(new CRYPT_PROV_CTX()); - // protect the allocated structure with a holder - HRESULT hr = OpenCSP(&cspParameters, CRYPT_VERIFYCONTEXT, pProvCtx); - - if (FAILED(hr)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::OpenCSP failed.\n", hr)); - CryptoHelper::COMPlusThrowCrypto(hr); - } - - // we never want to delete a key container when using CRYPT_VERIFYCONTEXT - pProvCtx->m_fPersistKeyInCsp = TRUE; - - // Set the handle field - hProvSAFE->SetHandle((void*) pProvCtx.GetValue()); - pProvCtx.SuppressRelease(); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -// -// This method opens an existing key container. -// It returns FALSE if the container could not be found. -// - -FCIMPL3(HRESULT, COMCryptography::_OpenCSP, Object* cspParametersUNSAFE, DWORD dwFlags, SafeHandle** hProvUNSAFE) -{ - FCALL_CONTRACT; - - HRESULT hr = S_OK; - OBJECTREF cspParameters = (OBJECTREF) cspParametersUNSAFE; - SAFEHANDLE hProvSAFE = (SAFEHANDLE) *hProvUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_2(cspParameters, hProvSAFE); - - NewHolder<CRYPT_PROV_CTX> pProvCtx(new CRYPT_PROV_CTX()); - // We never want to delete a key container if it's already there. - pProvCtx->m_fPersistKeyInCsp = TRUE; - - hr = OpenCSP(&cspParameters, dwFlags, pProvCtx); - if (SUCCEEDED(hr)) { - // Set the handle field - hProvSAFE->SetHandle((void*) pProvCtx.GetValue()); - pProvCtx.SuppressRelease(); - } - - HELPER_METHOD_FRAME_END(); - return hr; -} -FCIMPLEND - -// -// Native method for calling a CSP to get random bytes. -// - -void QCALLTYPE COMCryptography::GetBytes(CRYPT_PROV_CTX * pProvCtx, BYTE * pbOut, INT32 cb) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - NewArrayHolder<BYTE> buffer = new BYTE[cb]; - - if (!CryptGenRandom(pProvCtx->m_hProv, cb, buffer)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - memcpyNoGCRefs(pbOut, buffer, cb); - - END_QCALL; -} - -// -// Native method for calling a CSP to get random bytes. -// - -void QCALLTYPE COMCryptography::GetNonZeroBytes(CRYPT_PROV_CTX * pProvCtx, BYTE * pbOut, INT32 cb) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - NewArrayHolder<BYTE> pb = new BYTE[cb]; - INT32 i = 0; - - while (i < cb) { - if (!CryptGenRandom(pProvCtx->m_hProv, cb, pb)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - for (INT32 j=0; (i<cb) && (j<cb); j++) { - if (pb[j] != 0) pbOut[i++] = pb[j]; - } - } - - END_QCALL; -} - -// -// Release our handle to a CSP, potentially deleting the referenced key -// -// Arguments: -// pProviderContext - CSP context to release -// -// -// Notes: -// This is the target of the System.Security.Cryptography.SafeProvHandle.FreeCsp QCall -// - -// static -void QCALLTYPE COMCryptography::FreeCsp(__in_opt CRYPT_PROV_CTX *pProviderContext) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - if (pProviderContext) - pProviderContext->Release(); - - END_QCALL; -} - -// -// _SearchForAlgorithm -// -// Method for determining whether a CSP supports a particular -// algorithm and (optionally) a key size of that algorithm -// -BOOL QCALLTYPE COMCryptography::SearchForAlgorithm(CRYPT_PROV_CTX * pProvCtx, DWORD dwAlgID, DWORD dwKeyLength) -{ - QCALL_CONTRACT; - - BOOL result = FALSE; - - BEGIN_QCALL; - - DWORD dwFlags = CRYPT_FIRST; - DWORD cbData = 0; - // First, we have to get the max size of the PP - if (CryptGetProvParam(pProvCtx->m_hProv, PP_ENUMALGS_EX, NULL, &cbData, dwFlags)) { - - // Allocate pbData - NewArrayHolder<BYTE> pbData = new BYTE[cbData]; - while (CryptGetProvParam(pProvCtx->m_hProv, PP_ENUMALGS_EX, pbData, &cbData, dwFlags)) { - dwFlags = 0; // so we don't use CRYPT_FIRST more than once - PROV_ENUMALGS_EX *provdata = (PROV_ENUMALGS_EX *) pbData.GetValue(); - ALG_ID provAlgID = provdata->aiAlgid; - DWORD provMinLength = provdata->dwMinLen; - DWORD provMaxLength = provdata->dwMaxLen; - - // OK, now check to see if we have an alg match - if ((ALG_ID) dwAlgID == provAlgID) { - // OK, see if we have a keylength match, or if we don't care - if ((dwKeyLength == 0) || - (dwKeyLength >= provMinLength) && - (dwKeyLength <= provMaxLength)) { - result = TRUE; - break; - } - } // keep looping - } - } - - END_QCALL; - - return result; -} - -// -// This method creates a new key container. -// - -FCIMPL3(void, COMCryptography::_CreateCSP, Object* cspParametersUNSAFE, CLR_BOOL randomKeyContainer, SafeHandle** hProvUNSAFE) -{ - FCALL_CONTRACT; - - OBJECTREF cspParameters = (OBJECTREF) cspParametersUNSAFE; - SAFEHANDLE hProvSAFE = (SAFEHANDLE) *hProvUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_2(cspParameters, hProvSAFE); - - NewHolder<CRYPT_PROV_CTX> pProvCtx(new CRYPT_PROV_CTX()); - - // We always want to delete the random key container we create - pProvCtx->m_fPersistKeyInCsp = (randomKeyContainer ? FALSE : TRUE); - - DWORD dwFlags = CRYPT_NEWKEYSET; - if (randomKeyContainer) { - dwFlags |= CRYPT_VERIFYCONTEXT; - } - - HRESULT hr = OpenCSP(&cspParameters, dwFlags, pProvCtx); - - if (FAILED(hr)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::OpenCSP failed.\n", hr)); - CryptoHelper::COMPlusThrowCrypto(hr); - } - - // Set the handle field - hProvSAFE->SetHandle((void*) pProvCtx.GetValue()); - pProvCtx.SuppressRelease(); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -CRYPT_HASH_CTX * COMCryptography::CreateHash(CRYPT_PROV_CTX * pProvCtx, DWORD dwHashType) -{ - QCALL_CONTRACT; - - CRYPT_HASH_CTX * pHashCtx = NULL; - - BEGIN_QCALL; - - HandleHashHolder hHash = NULL; - HRESULT hr = S_OK; - - if (!CryptCreateHash(pProvCtx->m_hProv, dwHashType, NULL, 0, &hHash)) { - hr = HRESULT_FROM_GetLastError(); - } - - if (FAILED(hr)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::_CreateHash failed.\n", hr)); - CryptoHelper::COMPlusThrowCrypto(hr); - } - - pHashCtx = new CRYPT_HASH_CTX(pProvCtx, hHash); - hHash.SuppressRelease(); - - END_QCALL; - - return pHashCtx; -} - -void QCALLTYPE COMCryptography::DeriveKey(CRYPT_PROV_CTX * pProvCtx, DWORD dwCalgKey, DWORD dwCalgHash, - LPCBYTE pbPwd, DWORD cbPwd, DWORD dwFlags, LPBYTE pbIVIn, DWORD cbIVIn, - QCall::ObjectHandleOnStack retKey) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - HandleHashHolder hHash(NULL); - HandleKeyHolder hKey(NULL); - - NewArrayHolder<BYTE> bufferPwd = new BYTE[cbPwd]; - memcpyNoGCRefs (bufferPwd, pbPwd, cbPwd * sizeof(BYTE)); - - NewArrayHolder<BYTE> rgbKey(NULL); - NewArrayHolder<BYTE> pbIV(NULL); - DWORD cb = 0; - DWORD cbIV = 0; - - if (!CryptCreateHash(pProvCtx->m_hProv, dwCalgHash, NULL, 0, &hHash)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - // Hash the password string - if (!CryptHashData(hHash, pbPwd, cbPwd, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - // Create a block cipher session key based on the hash of the password - if (!CryptDeriveKey(pProvCtx->m_hProv, dwCalgKey, hHash, dwFlags | CRYPT_EXPORTABLE, &hKey)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - HRESULT hr = UnloadKey(pProvCtx->m_hProv, hKey, &rgbKey, &cb); - if (FAILED(hr)) - CryptoHelper::COMPlusThrowCrypto(hr); - - // Get the length of the IV - cbIV = 0; - if (!CryptGetKeyParam(hKey, KP_IV, NULL, &cbIV, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - // Now allocate space for the IV vector - pbIV = new BYTE[cbIV]; - if (!CryptGetKeyParam(hKey, KP_IV, pbIV, &cbIV, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - // Check to avoid writing in the wrong location of the GC heap - if (cbIV != cbIVIn) - COMPlusThrow(kCryptographicException, W("Cryptography_PasswordDerivedBytes_InvalidIV")); - memcpyNoGCRefs (pbIVIn, pbIV, cbIV); - - retKey.SetByteArray(rgbKey, cb); - - END_QCALL; -} - -FCIMPL8(DWORD, COMCryptography::_DecryptData, SafeHandle* hKeyUNSAFE, U1Array* dataUNSAFE, - INT32 dwOffset, INT32 dwCount, U1Array** outputUNSAFE, INT32 dwOutputOffset, DWORD dwPaddingMode, CLR_BOOL fLast) -{ - FCALL_CONTRACT; - - struct _gc - { - U1ARRAYREF data; - U1ARRAYREF output; - SAFEHANDLE hKeySAFE; - } gc; - - gc.data = (U1ARRAYREF) dataUNSAFE; - gc.output = (U1ARRAYREF) *outputUNSAFE; - gc.hKeySAFE = (SAFEHANDLE) hKeyUNSAFE; - - INT32 dwResult = 0; - - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - - DWORD cb2 = dwCount; - // Do this check here as a sanity check. Also, this will catch bugs in CryptoAPITransform - if (dwOffset < 0 || dwCount < 0 || dwCount > (INT32) gc.data->GetNumComponents() || dwOffset > ((INT32) gc.data->GetNumComponents() - dwCount)) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - - NewArrayHolder<BYTE> pb(new BYTE[cb2]); - memcpy(pb, dwOffset + (LPBYTE) gc.data->GetDirectPointerToNonObjectElements(), cb2); - - { - SafeHandleHolder shh(&gc.hKeySAFE); - CRYPT_KEY_CTX * pKeyCtx = CryptoHelper::DereferenceSafeHandle<CRYPT_KEY_CTX>(gc.hKeySAFE); - { - GCX_PREEMP(); - // always call decryption with false, deal with padding manually - if (!CryptDecrypt(pKeyCtx->m_hKey, NULL, FALSE, 0, pb, &cb2)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - } - - DWORD dwPadLen = 0; - if (fLast) { - switch(dwPaddingMode) { - case CRYPTO_PADDING_NONE: - // we don't remove any padding - break; - case CRYPTO_PADDING_Zeros: - // nothing to check for here - break; - case CRYPTO_PADDING_PKCS5: - // PKCS5 padding is as follows: FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07 - dwPadLen = cb2 > 0 ? pb[cb2 - 1] : 0; - - if (cb2 < BLOCK_LEN || dwPadLen <= 0 || dwPadLen > BLOCK_LEN) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - - // Check the padding bytes are all correct - for (DWORD index = cb2 - dwPadLen; index + 1 < cb2; index++) - if (pb[index] != dwPadLen) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - break; - case CRYPTO_PADDING_ISO_10126: - // The padding is as follows: FF FF FF FF FF FF FF FF FF 7D 2A 75 EF F8 EF 07 - dwPadLen = cb2 > 0 ? pb[cb2 - 1] : 0; - if (cb2 < BLOCK_LEN || dwPadLen <= 0 || dwPadLen > BLOCK_LEN) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - - // Just ignore the random bytes - break; - case CRYPTO_PADDING_ANSI_X_923: - // The padding is as follows: FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 07 - dwPadLen = cb2 > 0 ? pb[cb2 - 1] : 0; - if (cb2 < BLOCK_LEN || dwPadLen <= 0 || dwPadLen > BLOCK_LEN) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - - // Check the padding bytes are all zeros - for (DWORD index = cb2 - dwPadLen; index + 1 < cb2; index++) - if (pb[index] != 0) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - break; - } - } - - dwResult = (cb2 - dwPadLen); - if (dwResult < 0) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - - if (gc.output == NULL) { - gc.output = (U1ARRAYREF) AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwResult); - memcpyNoGCRefs(gc.output->GetDirectPointerToNonObjectElements(), pb, dwResult); - SetObjectReference((OBJECTREF*) outputUNSAFE, (OBJECTREF) gc.output, gc.output->GetAppDomain()); - } else { - if (dwOutputOffset < 0 || dwResult < 0 || dwResult > (INT32) gc.output->GetNumComponents() || dwOutputOffset > ((INT32) gc.output->GetNumComponents() - dwResult)) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - memcpyNoGCRefs(dwOutputOffset + (LPBYTE) gc.output->GetDirectPointerToNonObjectElements(), pb, dwResult); - } - - HELPER_METHOD_FRAME_END(); - return dwResult; -} -FCIMPLEND - -//--------------------------------------------------------------------------------------- -// -// Decrypt a symmetric key using the private key in pKeyContext -// -// Arguments: -// pKeyContext - private key used for decrypting pbEncryptedKey -// pbEncryptedKey - [in] encrypted symmetric key -// cbEncryptedKey - size, in bytes, of pbEncryptedKey -// fOAEP - TRUE to use OAEP padding, FALSE to use PKCS #1 type 2 padding -// ohRetDecryptedKey - [out] decrypted key -// -// Notes: -// pbEncryptedKey is byte-reversed from the format that CAPI expects. This is for compatibility with -// previous CLR versions and other RSA implementations. -// -// This method is the target of the System.Security.Cryptography.RSACryptoServiceProvider.DecryptKey QCall -// - -// static -void QCALLTYPE COMCryptography::DecryptKey(__in CRYPT_KEY_CTX *pKeyContext, - __in_bcount(cbEncryptedKey) BYTE *pbEncryptedKey, - DWORD cbEncryptedKey, - BOOL fOAEP, - QCall::ObjectHandleOnStack ohRetDecryptedKey) -{ - CONTRACTL - { - QCALL_CHECK; - PRECONDITION(CheckPointer(pKeyContext)); - PRECONDITION(CheckPointer(pbEncryptedKey)); - PRECONDITION(cbEncryptedKey >= 0); - } - CONTRACTL_END; - - BEGIN_QCALL; - - NewArrayHolder<BYTE> pbKey = new BYTE[cbEncryptedKey]; - memcpy_s(pbKey, cbEncryptedKey, pbEncryptedKey, cbEncryptedKey); - CryptoHelper::memrev(pbKey, cbEncryptedKey); - - DWORD dwDecryptFlags = fOAEP ? CRYPT_OAEP : 0; - DWORD cbDecryptedKey = cbEncryptedKey; - if (!CryptDecrypt(pKeyContext->m_hKey, NULL, TRUE, dwDecryptFlags, pbKey, &cbDecryptedKey)) - { - HRESULT hrDecrypt = HRESULT_FROM_GetLastError(); - - // If we're using OAEP mode and we recieved an NTE_BAD_FLAGS error, then OAEP is not supported on - // this platform (XP+ only). Throw a generic cryptographic exception if we failed to decrypt OAEP - // padded data in order to prevent a chosen ciphertext attack. We will allow NTE_BAD_KEY out, since - // that error does not relate to the padding. Otherwise just throw a cryptographic exception based on - // the error code. - if ((dwDecryptFlags & CRYPT_OAEP) == CRYPT_OAEP && hrDecrypt != NTE_BAD_KEY) - { - if (hrDecrypt == NTE_BAD_FLAGS) - COMPlusThrow(kCryptographicException, W("Cryptography_OAEP_XPOnly")); - else - COMPlusThrow(kCryptographicException, W("Cryptography_OAEPDecoding")); - } - else - { - CryptoHelper::COMPlusThrowCrypto(hrDecrypt); - } - } - - // CryptDecrypt operates in place, so pbKey now has the plaintext version of the key. - // cbDecryptedKey was updated to indicate the number of bytes of plaintext that are in the buffer. - ohRetDecryptedKey.SetByteArray(pbKey, cbDecryptedKey); - END_QCALL; -} - -FCIMPL8(DWORD, COMCryptography::_EncryptData, SafeHandle* hKeyUNSAFE, U1Array* dataUNSAFE, - INT32 dwOffset, INT32 dwCount, U1Array** outputUNSAFE, INT32 dwOutputOffset, DWORD dwPaddingMode, CLR_BOOL fLast) -{ - FCALL_CONTRACT; - - struct _gc - { - U1ARRAYREF data; - U1ARRAYREF output; - SAFEHANDLE hKeySAFE; - } gc; - - gc.data = (U1ARRAYREF) dataUNSAFE; - gc.output = (U1ARRAYREF) *outputUNSAFE; - gc.hKeySAFE = (SAFEHANDLE) hKeyUNSAFE; - - DWORD cb2 = dwCount; - - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - - DWORD cb = dwCount + (fLast ? 16 : 0); // account for an extra padding block that will be added by CAPI - DWORD cbPartial = (dwCount % BLOCK_LEN); - - // Do this check here as a sanity check. Also, this will catch bugs in CryptoAPITransform - if (dwOffset < 0 || dwCount < 0 || dwCount > (INT32) gc.data->GetNumComponents() || dwOffset > ((INT32) gc.data->GetNumComponents() - dwCount)) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - - NewArrayHolder<BYTE> pb(new BYTE[cb]); - - // initialize memory - memset(pb, 0, cb); - memcpy(pb, dwOffset + (LPBYTE) gc.data->GetDirectPointerToNonObjectElements(), dwCount); - - { - SafeHandleHolder shh(&gc.hKeySAFE); - CRYPT_KEY_CTX * pKeyCtx = CryptoHelper::DereferenceSafeHandle<CRYPT_KEY_CTX>(gc.hKeySAFE); - _ASSERTE(pKeyCtx->m_pProvCtx); - CRYPT_PROV_CTX * pProvCtx = pKeyCtx->m_pProvCtx; - - // Deal with padding modes by hand: we need this because Crypto API only supports PKCS#5 padding - if (fLast) { - DWORD dwPadLen = BLOCK_LEN - cbPartial; - switch(dwPaddingMode) { - case CRYPTO_PADDING_NONE: - if (cbPartial > 0) - COMPlusThrow(kCryptographicException, W("Cryptography_SSE_InvalidDataSize")); - break; - case CRYPTO_PADDING_Zeros: - // no further processing required, just adjust the input count - // we don't add zeros if we've got a full number of blocks - if (cbPartial != 0) - cb2 += dwPadLen; - break; - case CRYPTO_PADDING_PKCS5: - // PKCS5 padding is as follows: FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07 - cb2 += dwPadLen; - for (DWORD index = dwCount; index < cb2; index++) - pb[index] = static_cast<BYTE>(dwPadLen); - break; - case CRYPTO_PADDING_ISO_10126: - // The padding is as follows: FF FF FF FF FF FF FF FF FF 7D 2A 75 EF F8 EF 07 - cb2 += dwPadLen; - { - GCX_PREEMP(); - // get some random bytes - if (!CryptGenRandom(pProvCtx->m_hProv, dwPadLen-1, pb+dwCount)) { - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - } - pb[cb2 - 1] = static_cast<BYTE>(dwPadLen); - break; - case CRYPTO_PADDING_ANSI_X_923: - // The padding is as follows: FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 07 - cb2 += dwPadLen; - for (DWORD index = dwCount; index < cb2-1; index++) - pb[index] = 0; - pb[cb2 - 1] = static_cast<BYTE>(dwPadLen); - break; - } - } - - { - GCX_PREEMP(); - // We have done the padding ourselves, so let's just pass the provided fLast flag - // so we ensure the key is initialized for future use - if (!CryptEncrypt(pKeyCtx->m_hKey, NULL, fLast, 0, pb, &cb2, cb)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - } - - // ignore the last padding block added by CAPI - if (fLast) cb2 -= BLOCK_LEN; - - if (gc.output == NULL) { - gc.output = (U1ARRAYREF) AllocatePrimitiveArray(ELEMENT_TYPE_U1, cb2); - memcpyNoGCRefs(gc.output->GetDirectPointerToNonObjectElements(), pb, cb2); - SetObjectReference((OBJECTREF*) outputUNSAFE, (OBJECTREF) gc.output, gc.output->GetAppDomain()); - } else { - if (dwOutputOffset < 0 || (INT32) cb2 < 0 || cb2 > gc.output->GetNumComponents() || dwOutputOffset > ((INT32) gc.output->GetNumComponents() - (INT32) cb2)) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - memcpyNoGCRefs(dwOutputOffset + (LPBYTE) gc.output->GetDirectPointerToNonObjectElements(), pb, cb2); - } - - HELPER_METHOD_FRAME_END(); - return cb2; -} -FCIMPLEND - - -//--------------------------------------------------------------------------------------- -// -// Encrypt a symmetric key using the public key in pKeyContext -// -// Arguments: -// pKeyContext - [in] public to encrypt pbKey with -// pbKey - [in] symmetric key to encrypt -// cbKey - size, in bytes, of pbKey -// fOAEP - TRUE to use OAEP padding, FALSE to use PKCS #1 type 2 padding -// ohRetEncryptedKey - [out] byte array holding the encrypted key -// -// Notes: -// The returned value in ohRetEncryptedKey is byte-reversed from the version CAPI gives us. This is for -// compatibility with previous releases of the CLR and other RSA implementations. -// -// This method is the target of the EncryptKey QCall in System.Security.Cryptography.RSACryptoServiceProvider. -// - -// static -void QCALLTYPE COMCryptography::EncryptKey(__in CRYPT_KEY_CTX *pKeyContext, - __in_bcount(cbKey) BYTE *pbKey, - DWORD cbKey, - BOOL fOAEP, - QCall::ObjectHandleOnStack ohRetEncryptedKey) -{ - CONTRACTL - { - QCALL_CHECK; - PRECONDITION(CheckPointer(pKeyContext)); - PRECONDITION(CheckPointer(pbKey)); - PRECONDITION(cbKey >= 0); - } - CONTRACTL_END; - - BEGIN_QCALL; - - DWORD dwEncryptFlags = fOAEP ? CRYPT_OAEP : 0; - - // Figure out how big the encrypted key will be - DWORD cbEncryptedKey = cbKey; - if (!CryptEncrypt(pKeyContext->m_hKey, NULL, TRUE, dwEncryptFlags, NULL, &cbEncryptedKey, cbEncryptedKey)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - // pbData is an in/out buffer for CryptEncrypt. allocate space for the encrypted key, and copy the - // plaintext key into that space. Since encrypted keys will have padding applied, the size of the encrypted - // key should always be larger than the plaintext key, so use that to determine the buffer size. - _ASSERTE(cbEncryptedKey >= cbKey); - NewArrayHolder<BYTE> pbEncryptedKey = new BYTE[cbEncryptedKey]; - memcpy_s(pbEncryptedKey, cbEncryptedKey, pbKey, cbKey); - - // Encrypt for real - the last parameter is the total size of the in/out buffer, while the second to last - // parameter specifies the size of the plaintext to encrypt. - if (!CryptEncrypt(pKeyContext->m_hKey, NULL, TRUE, dwEncryptFlags, pbEncryptedKey, &cbKey, cbEncryptedKey)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - _ASSERTE(cbKey == cbEncryptedKey); - CryptoHelper::memrev(pbEncryptedKey, cbEncryptedKey); - ohRetEncryptedKey.SetByteArray(pbEncryptedKey, cbEncryptedKey); - END_QCALL; -} - - -void QCALLTYPE COMCryptography::EndHash(CRYPT_HASH_CTX * pHashCtx, QCall::ObjectHandleOnStack retHash) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - DWORD cbHash = 0; - DWORD cbHashCount = sizeof(cbHash); - if (!CryptGetHashParam(pHashCtx->m_hHash, HP_HASHSIZE, reinterpret_cast<BYTE *>(&cbHash), &cbHashCount, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - NewArrayHolder<BYTE> pb = new BYTE[cbHash]; - if (!CryptGetHashParam(pHashCtx->m_hHash, HP_HASHVAL, pb, &cbHash, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - retHash.SetByteArray(pb, cbHash); - - END_QCALL; -} - -// -// Exports key information of an RSACryptoServiceProvider/DSACryptoServiceProvider into a CAPI key blob (PKCS#1 format). -// - -void QCALLTYPE COMCryptography::ExportCspBlob(CRYPT_KEY_CTX * pKeyCtx, DWORD dwBlobType, QCall::ObjectHandleOnStack retBlob) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - HRESULT hr = S_OK; - NewArrayHolder<BYTE> pbRawData(NULL); - DWORD cbRawData = 0; - - if (!CryptExportKey(pKeyCtx->m_hKey, NULL, dwBlobType, 0, NULL, &cbRawData)) - hr = HRESULT_FROM_GetLastError(); - - if (FAILED(hr)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::_ExportCspBlob failed.\n", hr)); - CryptoHelper::COMPlusThrowCrypto(hr); - } - - pbRawData = new BYTE[cbRawData]; - if (!CryptExportKey(pKeyCtx->m_hKey, NULL, dwBlobType, 0, pbRawData, &cbRawData)) - hr = HRESULT_FROM_GetLastError(); - - if (FAILED(hr)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::_ExportCspBlob failed.\n", hr)); - CryptoHelper::COMPlusThrowCrypto(hr); - } - - retBlob.SetByteArray(pbRawData, cbRawData); - - END_QCALL; -} - -// -// _ExportKey -// - -#ifdef _PREFAST_ -#pragma warning(push) -#pragma warning(disable:21000) // Suppress PREFast warning about overly large function -#endif -FCIMPL3(void, COMCryptography::_ExportKey, SafeHandle* hKeyUNSAFE, DWORD dwBlobType, Object* theKeyUNSAFE) -{ - FCALL_CONTRACT; - - HRESULT hr = S_OK; - OBJECTREF theKey = (OBJECTREF) theKeyUNSAFE; - SAFEHANDLE hKeySAFE = (SAFEHANDLE) hKeyUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_2(theKey, hKeySAFE); - - DWORD cb; - BOOL f; - DWORD dwFlags = 0; - NewArrayHolder<BYTE> pb(NULL); - - struct __LocalGCR { - RSA_CSPREF rsaKey; - DSA_CSPREF dsaKey; - } _gcr; - - _gcr.rsaKey = NULL; - _gcr.dsaKey = NULL; - - { - SafeHandleHolder shh(&hKeySAFE); - CRYPT_KEY_CTX * pKeyCtx = CryptoHelper::DereferenceSafeHandle<CRYPT_KEY_CTX>(hKeySAFE); - _ASSERTE(pKeyCtx); - { - GCX_PREEMP(); - // calg - ALG_ID dwCalg; - cb = sizeof(dwCalg); - if (CryptGetKeyParam(pKeyCtx->m_hKey, KP_ALGID, (LPBYTE) &dwCalg, &cb, 0)) { - // We need to add the VER3 handle for DH and DSS keys so that we can - // get the fullest possible amount of information. - if (dwCalg == CALG_DSS_SIGN) - dwFlags |= CRYPT_BLOB_VER3; - } -retry: - f = CryptExportKey(pKeyCtx->m_hKey, NULL, dwBlobType, dwFlags, NULL, &cb); - if (!f) { - if (dwFlags & CRYPT_BLOB_VER3) { - dwFlags &= ~CRYPT_BLOB_VER3; - goto retry; - } - hr = HRESULT_FROM_GetLastError(); - } - - if (FAILED(hr)) { - LOG((LF_SECURITY, LL_INFO100, "Error [%#x]: COMCryptography::_ExportKey failed.\n", hr)); - goto lExit; - } - - pb = new BYTE[cb]; - if (!CryptExportKey(pKeyCtx->m_hKey, NULL, dwBlobType, dwFlags, pb, &cb)) - hr = HRESULT_FROM_GetLastError(); - } - } - - DWORD cbMalloced = cb; - LPBYTE pbX = NULL; - DWORD cbKey = 0; - - GCPROTECT_BEGIN(_gcr); - - if (FAILED(hr)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::_ExportKey failed.\n", hr)); - goto Exit; - } - - BLOBHEADER * pblob = (BLOBHEADER *) pb.GetValue(); - KEY_HEADER * pKeyInfo = NULL; - - switch (pblob->aiKeyAlg) { - case CALG_RSA_KEYX: - case CALG_RSA_SIGN: - VALIDATEOBJECTREF(theKey); - _gcr.rsaKey = (RSA_CSPREF) theKey; - - if (dwBlobType == PUBLICKEYBLOB) { - pKeyInfo = (KEY_HEADER *) pb.GetValue(); - cb = (pKeyInfo->rsa.bitlen/8); - - pbX = pb + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY); - - // Exponent - NewArrayHolder<BYTE> pbExponent(NULL); - DWORD cbExponent = 0; - ConvertIntToByteArray(pKeyInfo->rsa.pubexp, &pbExponent, &cbExponent); - OBJECTREF arrayExponent = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbExponent); - SetObjectReference((OBJECTREF *) &_gcr.rsaKey->m_Exponent, - arrayExponent, - _gcr.rsaKey->GetAppDomain()); - memcpyNoGCRefs(_gcr.rsaKey->m_Exponent->GetDirectPointerToNonObjectElements(), pbExponent, cbExponent); - - // Modulus - OBJECTREF arrayModulus = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cb); - SetObjectReference((OBJECTREF *) &_gcr.rsaKey->m_Modulus, - arrayModulus, - _gcr.rsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cb); - memcpyNoGCRefs(_gcr.rsaKey->m_Modulus->GetDirectPointerToNonObjectElements(), - pbX, cb); - pbX += cb; - } - else if (dwBlobType == PRIVATEKEYBLOB) { - pKeyInfo = (KEY_HEADER *) pb.GetValue(); - cb = (pKeyInfo->rsa.bitlen/8); - DWORD cbHalfModulus = (cb + 1)/2; - - pbX = pb + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY); - - // Exponent - NewArrayHolder<BYTE> pbExponent(NULL); - DWORD cbExponent = 0; - ConvertIntToByteArray(pKeyInfo->rsa.pubexp, &pbExponent, &cbExponent); - OBJECTREF arrayExponent = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbExponent); - SetObjectReference((OBJECTREF *) &_gcr.rsaKey->m_Exponent, - arrayExponent, - _gcr.rsaKey->GetAppDomain()); - memcpyNoGCRefs(_gcr.rsaKey->m_Exponent->GetDirectPointerToNonObjectElements(), pbExponent, cbExponent); - - // Modulus - OBJECTREF arrayModulus = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cb); - SetObjectReference((OBJECTREF *) &_gcr.rsaKey->m_Modulus, - arrayModulus, - _gcr.rsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cb); - memcpyNoGCRefs(_gcr.rsaKey->m_Modulus->GetDirectPointerToNonObjectElements(), - pbX, cb); - pbX += cb; - - // P - OBJECTREF arrayP = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbHalfModulus); - SetObjectReference((OBJECTREF *) &_gcr.rsaKey->m_P, - arrayP, - _gcr.rsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbHalfModulus); - memcpyNoGCRefs(_gcr.rsaKey->m_P->GetDirectPointerToNonObjectElements(), - pbX, cbHalfModulus); - pbX += cbHalfModulus; - - // Q - OBJECTREF arrayQ = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbHalfModulus); - SetObjectReference((OBJECTREF *) &_gcr.rsaKey->m_Q, - arrayQ, - _gcr.rsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbHalfModulus); - memcpyNoGCRefs(_gcr.rsaKey->m_Q->GetDirectPointerToNonObjectElements(), - pbX, cbHalfModulus); - pbX += cbHalfModulus; - - // dp - OBJECTREF arrayDP = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbHalfModulus); - SetObjectReference((OBJECTREF *) &_gcr.rsaKey->m_dp, - arrayDP, - _gcr.rsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbHalfModulus); - memcpyNoGCRefs(_gcr.rsaKey->m_dp->GetDirectPointerToNonObjectElements(), - pbX, cbHalfModulus); - pbX += cbHalfModulus; - - // dq - OBJECTREF arrayDQ = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbHalfModulus); - SetObjectReference((OBJECTREF *) &_gcr.rsaKey->m_dq, - arrayDQ, - _gcr.rsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbHalfModulus); - memcpyNoGCRefs(_gcr.rsaKey->m_dq->GetDirectPointerToNonObjectElements(), - pbX, cbHalfModulus); - pbX += cbHalfModulus; - - // InvQ - OBJECTREF arrayInverseQ = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbHalfModulus); - SetObjectReference((OBJECTREF *) &_gcr.rsaKey->m_InverseQ, - arrayInverseQ, - _gcr.rsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbHalfModulus); - memcpyNoGCRefs(_gcr.rsaKey->m_InverseQ->GetDirectPointerToNonObjectElements(), - pbX, cbHalfModulus); - pbX += cbHalfModulus; - - // d - OBJECTREF arrayD = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cb); - SetObjectReference((OBJECTREF *) &_gcr.rsaKey->m_d, - arrayD, - _gcr.rsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cb); - memcpyNoGCRefs(_gcr.rsaKey->m_d->GetDirectPointerToNonObjectElements(), - pbX, cb); - pbX += cb; - } - else { - hr = E_FAIL; - goto Exit; - } - break; - - case CALG_DSS_SIGN: - _gcr.dsaKey = (DSA_CSPREF) theKey; - // we have to switch on whether the blob is v3 or not, because we have different - // info available if it is... - if (pblob->bVersion > 0x2) { - if (dwBlobType == PUBLICKEYBLOB) { - int cbP, cbQ, cbJ; - DSSPUBKEY_VER3 * pdss; - - pdss = (DSSPUBKEY_VER3 *) (pb + sizeof(BLOBHEADER)); - cbP = (pdss->bitlenP+7)/8; - cbQ = (pdss->bitlenQ+7)/8; - cbJ = (pdss->bitlenJ+7)/8; - pbX = pb + sizeof(BLOBHEADER) + sizeof(DSSPUBKEY_VER3); - - // P - OBJECTREF arrayP = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbP); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_P, arrayP, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbP); - memcpyNoGCRefs(_gcr.dsaKey->m_P->GetDirectPointerToNonObjectElements(), pbX, cbP); - pbX += cbP; - - // Q - OBJECTREF arrayQ = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbQ); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_Q, arrayQ, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbQ); - memcpyNoGCRefs(_gcr.dsaKey->m_Q->GetDirectPointerToNonObjectElements(), pbX, cbQ); - pbX += cbQ; - - // G - OBJECTREF arrayG = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbP); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_G, arrayG, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbP); - memcpyNoGCRefs(_gcr.dsaKey->m_G->GetDirectPointerToNonObjectElements(), pbX, cbP); - pbX += cbP; - - // J - if (cbJ > 0) { - OBJECTREF arrayJ = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbJ); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_J, arrayJ, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbJ); - memcpyNoGCRefs(_gcr.dsaKey->m_J->GetDirectPointerToNonObjectElements(), pbX, cbJ); - pbX += cbJ; - } - - // Y - OBJECTREF arrayY = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbP); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_Y, arrayY, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbP); - memcpyNoGCRefs(_gcr.dsaKey->m_Y->GetDirectPointerToNonObjectElements(), pbX, cbP); - pbX += cbP; - - if (pdss->DSSSeed.counter != 0xFFFFFFFF) { - // seed - OBJECTREF arraySeed = AllocatePrimitiveArray(ELEMENT_TYPE_U1, 20); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_seed, arraySeed, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pdss->DSSSeed.seed, 20); - memcpyNoGCRefs(_gcr.dsaKey->m_seed->GetDirectPointerToNonObjectElements(), pdss->DSSSeed.seed, 20); - // pdss->DSSSeed.c - _gcr.dsaKey->m_counter = pdss->DSSSeed.counter; - } - } - else { - int cbP, cbQ, cbJ, cbX; - DSSPRIVKEY_VER3 * pdss; - - pdss = (DSSPRIVKEY_VER3 *) (pb + sizeof(BLOBHEADER)); - cbP = (pdss->bitlenP+7)/8; - cbQ = (pdss->bitlenQ+7)/8; - cbJ = (pdss->bitlenJ+7)/8; - cbX = (pdss->bitlenX+7)/8; - pbX = pb + sizeof(BLOBHEADER) + sizeof(DSSPRIVKEY_VER3); - - // P - OBJECTREF arrayP = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbP); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_P, arrayP, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbP); - memcpyNoGCRefs(_gcr.dsaKey->m_P->GetDirectPointerToNonObjectElements(), pbX, cbP); - pbX += cbP; - - // Q - OBJECTREF arrayQ = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbQ); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_Q, arrayQ, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbQ); - memcpyNoGCRefs(_gcr.dsaKey->m_Q->GetDirectPointerToNonObjectElements(), pbX, cbQ); - pbX += cbQ; - - // G - OBJECTREF arrayG = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbP); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_G, arrayG, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbP); - memcpyNoGCRefs(_gcr.dsaKey->m_G->GetDirectPointerToNonObjectElements(), pbX, cbP); - pbX += cbP; - - // J - if (pdss->bitlenJ > 0) { - OBJECTREF arrayJ = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbJ); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_J, arrayJ, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbJ); - memcpyNoGCRefs(_gcr.dsaKey->m_J->GetDirectPointerToNonObjectElements(), pbX, cbJ); - pbX += cbJ; - } - - // Y - OBJECTREF arrayY = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbP); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_Y, arrayY, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbP); - memcpyNoGCRefs(_gcr.dsaKey->m_Y->GetDirectPointerToNonObjectElements(), pbX, cbP); - pbX += cbP; - - // X - OBJECTREF arrayX = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbX); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_X, arrayX, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbX); - memcpyNoGCRefs(_gcr.dsaKey->m_X->GetDirectPointerToNonObjectElements(), pbX, cbX); - pbX += cbX; - - if (pdss->DSSSeed.counter != 0xFFFFFFFF) { - // seed - OBJECTREF arraySeed = AllocatePrimitiveArray(ELEMENT_TYPE_U1, 20); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_seed, arraySeed, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pdss->DSSSeed.seed, 20); - memcpyNoGCRefs(_gcr.dsaKey->m_seed->GetDirectPointerToNonObjectElements(), pdss->DSSSeed.seed, 20); - // pdss->DSSSeed.c - _gcr.dsaKey->m_counter = pdss->DSSSeed.counter; - } - } - } else { - // old-style blobs - if (dwBlobType == PUBLICKEYBLOB) { - int cbP, cbQ; - DSSPUBKEY * pdss; - DSSSEED * pseedstruct; - - pdss = (DSSPUBKEY *) (pb + sizeof(BLOBHEADER)); - cbP = (pdss->bitlen+7)/8; // bitlen is size of modulus - cbQ = DSS_Q_LEN; // Q is always 20 bytes in length - pbX = pb + sizeof(BLOBHEADER) + sizeof(DSSPUBKEY); - - // P - OBJECTREF arrayP = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbP); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_P, arrayP, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbP); - memcpyNoGCRefs(_gcr.dsaKey->m_P->GetDirectPointerToNonObjectElements(), pbX, cbP); - pbX += cbP; - - // Q - OBJECTREF arrayQ = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbQ); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_Q, arrayQ, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbQ); - memcpyNoGCRefs(_gcr.dsaKey->m_Q->GetDirectPointerToNonObjectElements(), pbX, cbQ); - pbX += cbQ; - - // G - OBJECTREF arrayG = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbP); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_G, arrayG, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbP); - memcpyNoGCRefs(_gcr.dsaKey->m_G->GetDirectPointerToNonObjectElements(), pbX, cbP); - pbX += cbP; - - // Y - OBJECTREF arrayY = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbP); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_Y, arrayY, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbP); - memcpyNoGCRefs(_gcr.dsaKey->m_Y->GetDirectPointerToNonObjectElements(), pbX, cbP); - pbX += cbP; - - pseedstruct = (DSSSEED *) pbX; - if (pseedstruct->counter > 0) { - // seed & counter - OBJECTREF arraySeed = AllocatePrimitiveArray(ELEMENT_TYPE_U1, 20); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_seed, arraySeed, _gcr.dsaKey->GetAppDomain()); - // seed is always 20 bytes - CryptoHelper::memrev(pseedstruct->seed, 20); - memcpyNoGCRefs(_gcr.dsaKey->m_seed->GetDirectPointerToNonObjectElements(), pseedstruct->seed, 20); - pbX += 20; - - // pdss->DSSSeed.c - _gcr.dsaKey->m_counter = pseedstruct->counter; - pbX += sizeof(DWORD); - } - } - else { - int cbP, cbQ, cbX; - DSSPUBKEY * pdss; - DSSSEED * pseedstruct; - - pdss = (DSSPUBKEY *) (pb + sizeof(BLOBHEADER)); - cbP = (pdss->bitlen+7)/8; //bitlen is size of modulus - cbQ = DSS_Q_LEN; // Q is always 20 bytes in length - pbX = pb + sizeof(BLOBHEADER) + sizeof(DSSPUBKEY); - - // P - OBJECTREF arrayP = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbP); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_P, arrayP, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbP); - memcpyNoGCRefs(_gcr.dsaKey->m_P->GetDirectPointerToNonObjectElements(), pbX, cbP); - pbX += cbP; - - // Q - OBJECTREF arrayQ = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbQ); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_Q, arrayQ, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbQ); - memcpyNoGCRefs(_gcr.dsaKey->m_Q->GetDirectPointerToNonObjectElements(), pbX, cbQ); - pbX += cbQ; - - // G - OBJECTREF arrayG = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbP); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_G, arrayG, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbP); - memcpyNoGCRefs(_gcr.dsaKey->m_G->GetDirectPointerToNonObjectElements(), pbX, cbP); - pbX += cbP; - - // X - cbX = 20; // X must be 20 bytes in length - OBJECTREF arrayX = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbX); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_X, arrayX, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbX); - memcpyNoGCRefs(_gcr.dsaKey->m_X->GetDirectPointerToNonObjectElements(), pbX, cbX); - pbX += cbX; - - pseedstruct = (DSSSEED *) pbX; - if (pseedstruct->counter > 0) { - // seed - OBJECTREF arraySeed = AllocatePrimitiveArray(ELEMENT_TYPE_U1, 20); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_seed, arraySeed, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pseedstruct->seed, 20); - memcpyNoGCRefs(_gcr.dsaKey->m_seed->GetDirectPointerToNonObjectElements(), pseedstruct->seed, 20); - pbX += 20; - // pdss->DSSSeed.c - _gcr.dsaKey->m_counter = pseedstruct->counter; - pbX += sizeof(DWORD); - } - - // Add this sanity check here to avoid reading from the heap - cbKey = (DWORD)(pbX - pb); - if (cbKey > cbMalloced) { - hr = E_FAIL; - goto Exit; - } - - // OK, we have one more thing to do. Because old DSS shared the DSSPUBKEY struct for both public and private keys, - // when we have a private key blob we get X but not Y. TO get Y, we have to do another export asking for a public key blob - - { - SafeHandleHolder shh(&hKeySAFE); - CRYPT_KEY_CTX * pKeyCtx = CryptoHelper::DereferenceSafeHandle<CRYPT_KEY_CTX>(hKeySAFE); - { - GCX_PREEMP(); - f = CryptExportKey(pKeyCtx->m_hKey, NULL, PUBLICKEYBLOB, dwFlags, NULL, &cb); - - if (!f) { - hr = HRESULT_FROM_GetLastError(); - goto Exit; - } - - pb = new BYTE[cb]; - cbMalloced = cb; - - f = CryptExportKey(pKeyCtx->m_hKey, NULL, PUBLICKEYBLOB, dwFlags, pb, &cb); - if (!f) { - hr = HRESULT_FROM_GetLastError(); - goto Exit; - } - } - } - - // skip over header, DSSPUBKEY, P, Q and G. Y is of size cbP - pbX = pb + sizeof(BLOBHEADER) + sizeof(DSSPUBKEY) + cbP + cbQ + cbP; - OBJECTREF arrayY = AllocatePrimitiveArray(ELEMENT_TYPE_U1, cbP); - SetObjectReference((OBJECTREF *) &_gcr.dsaKey->m_Y, arrayY, _gcr.dsaKey->GetAppDomain()); - CryptoHelper::memrev(pbX, cbP); - memcpyNoGCRefs(_gcr.dsaKey->m_Y->GetDirectPointerToNonObjectElements(), pbX, cbP); - pbX += cbP; - } - } - break; - - default: - hr = E_FAIL; - goto Exit; - } - - // Add this sanity check here to avoid reading from the heap - cbKey = (DWORD)(pbX - pb); - if (cbKey > cbMalloced) { - hr = E_FAIL; - goto Exit; - } - - hr = S_OK; - -Exit: ; - GCPROTECT_END(); - -lExit: - - if (FAILED(hr)) - CryptoHelper::COMPlusThrowCrypto(hr); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND -#ifdef _PREFAST_ -#pragma warning(pop) -#endif - -// -// We implicitly assume these methods are not going to do a LoadLibrary -// - - -//--------------------------------------------------------------------------------------- -// -// Release our handle to a hash, potentially also releasing the provider -// -// Arguments: -// pHashContext - Hash context to release -// -// Notes: -// This is the target of the System.Security.Cryptography.SafeHashHandle.FreeHash QCall -// - -// static -void QCALLTYPE COMCryptography::FreeHash(__in_opt CRYPT_HASH_CTX *pHashContext) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - if (pHashContext) - pHashContext->Release(); - - END_QCALL; -} - -//--------------------------------------------------------------------------------------- -// -// Release our handle to a key, potentially also releasing the provider -// -// Arguments: -// pKeyContext - Key context to release -// -// Notes: -// This is the target of the System.Security.Cryptography.SafeKeyHandle.FreeKey QCall -// - -// static -void QCALLTYPE COMCryptography::FreeKey(__in_opt CRYPT_KEY_CTX *pKeyContext) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - if (pKeyContext) - pKeyContext->Release(); - - END_QCALL; -} - -// -// Native method for creation of a key in a CSP -// - -FCIMPL5(void, COMCryptography::_GenerateKey, SafeHandle* hProvUNSAFE, DWORD dwCalg, DWORD dwFlags, DWORD dwKeySize, SafeHandle** hKeyUNSAFE) -{ - FCALL_CONTRACT; - - SAFEHANDLE hProvSAFE = (SAFEHANDLE) hProvUNSAFE; - SAFEHANDLE hKeySAFE = (SAFEHANDLE) *hKeyUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_2(hProvSAFE, hKeySAFE); - - HandleKeyHolder hKey(NULL); - CRYPT_PROV_CTX * pProvCtx = NULL; - HRESULT hr = S_OK; - - { - SafeHandleHolder shh(&hProvSAFE); - pProvCtx = CryptoHelper::DereferenceSafeHandle<CRYPT_PROV_CTX>(hProvSAFE); - { - GCX_PREEMP(); - DWORD dwCapiFlags = MapCspKeyFlags (dwFlags) | (dwKeySize << 16); - if (!CryptoHelper::CryptGenKey_SO_TOLERANT(pProvCtx->m_hProv, dwCalg, dwCapiFlags, &hKey)) - hr = HRESULT_FROM_GetLastError(); - } - } - - if (FAILED(hr)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::_GenerateKey failed.\n", hr)); - CryptoHelper::COMPlusThrowCrypto(hr); - } - - CRYPT_KEY_CTX * pKeyCtx = new CRYPT_KEY_CTX(pProvCtx, hKey); - pKeyCtx->m_dwKeySpec = dwCalg; - hKeySAFE->SetHandle((void*) pKeyCtx); - hKey.SuppressRelease(); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - - -//--------------------------------------------------------------------------------------- -// -// Check to see if the CLR should enforce the machine wide FIPS algorithm policy -// -// Return Value: -// True if the CLR should prevent any non-FIPS certified algorithms from being -// instantiated if the FIPS algorithm policy is set on the machine, false otherwise. -// - -FCIMPL0(FC_BOOL_RET, COMCryptography::_GetEnforceFipsPolicySetting) -{ - FCALL_CONTRACT; - FC_RETURN_BOOL(g_pConfig->EnforceFIPSPolicy()); -} -FCIMPLEND - -// -// This method acquires key specific parameters. -// It will pop up a UI if the key is user protected. -// - -FCIMPL2(U1Array*, COMCryptography::_GetKeyParameter, SafeHandle* hKeyUNSAFE, DWORD dwKeyParam) -{ - FCALL_CONTRACT; - - U1ARRAYREF ret = NULL; - SAFEHANDLE hKeySAFE = (SAFEHANDLE) hKeyUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_2(ret, hKeySAFE); - - DWORD cb = 0; - NewArrayHolder<BYTE> pb(NULL); - NewArrayHolder<WCHAR> pwszUnicode(NULL); - - SafeHandleHolder shh(&hKeySAFE); - CRYPT_KEY_CTX * pKeyCtx = CryptoHelper::DereferenceSafeHandle<CRYPT_KEY_CTX>(hKeySAFE); - switch (dwKeyParam) { - case CLR_KEYLEN: - // Some Csp's may pop up a UI here since we don't use CRYPT_SILENT flag - // which is not supported in downlevel platforms - if (!CryptGetKeyParam(pKeyCtx->m_hKey, KP_KEYLEN, NULL, &cb, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - pb = new BYTE[cb]; - if (!CryptGetKeyParam(pKeyCtx->m_hKey, KP_KEYLEN, pb, &cb, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - CryptoHelper::ByteArrayToU1ARRAYREF(pb, cb, &ret); - break; - - case CLR_PUBLICKEYONLY: - // returns whether the key is a public only key - pb = new BYTE[4]; - *((DWORD*) pb.GetValue()) = pKeyCtx->m_fPublicOnly; - CryptoHelper::ByteArrayToU1ARRAYREF(pb, 4, &ret); - break; - - case CLR_ALGID: - // returns the algorithm ID for the key - if (!CryptGetKeyParam(pKeyCtx->m_hKey, KP_ALGID, NULL, &cb, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - pb = new BYTE[cb]; - if (!CryptGetKeyParam(pKeyCtx->m_hKey, KP_ALGID, pb, &cb, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - CryptoHelper::ByteArrayToU1ARRAYREF(pb, cb, &ret); - break; - - default: - _ASSERTE(FALSE); - } - - HELPER_METHOD_FRAME_END(); - return (U1Array*) OBJECTREFToObject(ret); -} -FCIMPLEND - -// -// _GetKeySetSecurityInfo -// - -FCIMPL3(U1Array*, COMCryptography::_GetKeySetSecurityInfo, SafeHandle* hProvUNSAFE, DWORD dwSecurityInformation, DWORD* pdwErrorCode) -{ - FCALL_CONTRACT; - - U1ARRAYREF ret = NULL; - SAFEHANDLE hProvSAFE = (SAFEHANDLE) hProvUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_1(hProvSAFE); - - SafeHandleHolder shh(&hProvSAFE); - CRYPT_PROV_CTX * pProvCtx = CryptoHelper::DereferenceSafeHandle<CRYPT_PROV_CTX>(hProvSAFE); - - DWORD cb = 0; - NewHolder<BYTE> pSD(NULL); - *pdwErrorCode = 0; - if (!CryptGetProvParam(pProvCtx->m_hProv, PP_KEYSET_SEC_DESCR, NULL, &cb, dwSecurityInformation)) { - *pdwErrorCode = GetLastError(); - goto Error; - } - - pSD = new BYTE[cb]; - if (!CryptGetProvParam(pProvCtx->m_hProv, PP_KEYSET_SEC_DESCR, pSD, &cb, dwSecurityInformation)) { - *pdwErrorCode = GetLastError(); - goto Error; - } - - if (pSD != NULL) - CryptoHelper::ByteArrayToU1ARRAYREF(pSD, cb, &ret); - -Error:; - - HELPER_METHOD_FRAME_END(); - return (U1Array*) OBJECTREFToObject(ret); -} -FCIMPLEND - - -BOOL QCALLTYPE COMCryptography::GetPersistKeyInCsp(CRYPT_PROV_CTX * pProvCtx) -{ - QCALL_CONTRACT; - - BOOL fResult = TRUE; - - BEGIN_QCALL; - - fResult = pProvCtx->m_fPersistKeyInCsp; - - END_QCALL; - - return fResult; -} - -// -// This method queries the key container and gets some of its properties. -// Those properties should never cause a UI to display. -// - -FCIMPL3(Object*, COMCryptography::_GetProviderParameter, SafeHandle* hProvUNSAFE, DWORD dwKeySpec, DWORD dwKeyParam) -{ - FCALL_CONTRACT; - - OBJECTREF ret = NULL; - SAFEHANDLE hProvSAFE = (SAFEHANDLE) hProvUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_2(ret, hProvSAFE); - - DWORD cb = 0; - NewArrayHolder<BYTE> pb(NULL); - NewArrayHolder<WCHAR> pwszUnicode(NULL); - DWORD dwImpType = 0; - HandleKeyHolder hKey(NULL); - - SafeHandleHolder shh(&hProvSAFE); - CRYPT_PROV_CTX * pProvCtx = CryptoHelper::DereferenceSafeHandle<CRYPT_PROV_CTX>(hProvSAFE); - - switch (dwKeyParam) { - case CLR_EXPORTABLE: - cb = sizeof(dwImpType); - if (!CryptGetProvParam(pProvCtx->m_hProv, PP_IMPTYPE, (PBYTE) &dwImpType, &cb, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - if (!(dwImpType & CRYPT_IMPL_HARDWARE)) { - if (!CryptGetUserKey(pProvCtx->m_hProv, dwKeySpec, &hKey)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - DWORD dwPermissions; - dwPermissions = 0; - cb = sizeof(dwPermissions); - if (!CryptGetKeyParam(hKey, KP_PERMISSIONS, (PBYTE) &dwPermissions, &cb, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - pb = new BYTE[4]; - *((DWORD*) pb.GetValue()) = dwPermissions & CRYPT_EXPORT ? 1 : 0; - } else { - // We assume hardware keys are not exportable - pb = new BYTE[4]; - *((DWORD*) pb.GetValue()) = 0; - } - CryptoHelper::ByteArrayToU1ARRAYREF(pb, 4, (U1ARRAYREF*) &ret); - break; - - case CLR_REMOVABLE: - cb = sizeof(dwImpType); - if (!CryptGetProvParam(pProvCtx->m_hProv, PP_IMPTYPE, (PBYTE) &dwImpType, &cb, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - pb = new BYTE[4]; - *((DWORD*) pb.GetValue()) = dwImpType & CRYPT_IMPL_REMOVABLE ? 1 : 0; - CryptoHelper::ByteArrayToU1ARRAYREF(pb, 4, (U1ARRAYREF*) &ret); - break; - - case CLR_HARDWARE: - cb = sizeof(dwImpType); - if (!CryptGetProvParam(pProvCtx->m_hProv, PP_IMPTYPE, (PBYTE) &dwImpType, &cb, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - pb = new BYTE[4]; - *((DWORD*) pb.GetValue()) = dwImpType & CRYPT_IMPL_HARDWARE ? 1 : 0; - CryptoHelper::ByteArrayToU1ARRAYREF(pb, 4, (U1ARRAYREF*) &ret); - break; - - case CLR_ACCESSIBLE: - pb = new BYTE[4]; - *((DWORD*) pb.GetValue()) = CryptGetUserKey(pProvCtx->m_hProv, dwKeySpec, &hKey) ? 1 : 0; - CryptoHelper::ByteArrayToU1ARRAYREF(pb, 4, (U1ARRAYREF*) &ret); - break; - - case CLR_PROTECTED: - cb = sizeof(dwImpType); - if (!CryptGetProvParam(pProvCtx->m_hProv, PP_IMPTYPE, (PBYTE) &dwImpType, &cb, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - BOOL isProtected; - if (dwImpType & CRYPT_IMPL_HARDWARE) { - // Assume hardware keys are protected - isProtected = TRUE; - } else { - isProtected = FALSE; - } - - pb = new BYTE[4]; - *((DWORD*) pb.GetValue()) = isProtected; - CryptoHelper::ByteArrayToU1ARRAYREF(pb, 4, (U1ARRAYREF*) &ret); - break; - - case CLR_UNIQUE_CONTAINER: - if (!CryptGetProvParam(pProvCtx->m_hProv, PP_UNIQUE_CONTAINER, NULL, &cb, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - pb = new BYTE[cb]; - if (!CryptGetProvParam(pProvCtx->m_hProv, PP_UNIQUE_CONTAINER, pb, &cb, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - pwszUnicode = CryptoHelper::AnsiToUnicode((char*) pb.GetValue()); - ret = StringObject::NewString(pwszUnicode); - break; - - default: - _ASSERTE(FALSE); - } - - HELPER_METHOD_FRAME_END(); - return OBJECTREFToObject(ret); -} -FCIMPLEND - -// -// _GetUserKey -// -// Native method to get the user key pair of a key container -// - -FCIMPL3(HRESULT, COMCryptography::_GetUserKey, SafeHandle* hProvUNSAFE, DWORD dwKeySpec, SafeHandle** hKeyUNSAFE) -{ - FCALL_CONTRACT; - - HRESULT hr = S_OK; - - SAFEHANDLE hProvSAFE = (SAFEHANDLE) hProvUNSAFE; - SAFEHANDLE hKeySAFE = (SAFEHANDLE) *hKeyUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_2(hProvSAFE, hKeySAFE); - - HandleKeyHolder hKey(NULL); - CRYPT_PROV_CTX * pProvCtx = NULL; - { - SafeHandleHolder shh(&hProvSAFE); - pProvCtx = CryptoHelper::DereferenceSafeHandle<CRYPT_PROV_CTX>(hProvSAFE); - { - GCX_PREEMP(); - if (!CryptGetUserKey(pProvCtx->m_hProv, dwKeySpec, &hKey)) - hr = HRESULT_FROM_GetLastError(); - } - } - - if (hr == S_OK) { - CRYPT_KEY_CTX * pKeyCtx = new CRYPT_KEY_CTX(pProvCtx, hKey); - pKeyCtx->m_dwKeySpec = dwKeySpec; - hKeySAFE->SetHandle((void*) pKeyCtx); - hKey.SuppressRelease(); - } - - LOG((LF_SECURITY, LL_INFO10000, "COMCryptography::_GetUserKey returned error code [%#x].\n", hr)); - - HELPER_METHOD_FRAME_END(); - return hr; -} -FCIMPLEND - -void QCALLTYPE COMCryptography::HashData(CRYPT_HASH_CTX * pHashCtx, LPCBYTE pData, DWORD cbData, DWORD dwStart, DWORD dwSize) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - // Do this check here as a sanity check. Also, this will catch bugs in CryptoAPITransform - if (dwStart < 0 || dwSize < 0 || dwSize > cbData || dwStart > (cbData - dwSize)) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - - if (!CryptHashData(pHashCtx->m_hHash, pData + dwStart, dwSize, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - END_QCALL; -} - -// -// WARNING: This function side-effects hCSP -// - -FCIMPL5(void, COMCryptography::_ImportBulkKey, SafeHandle* hProvUNSAFE, DWORD dwCalg, CLR_BOOL useSalt, U1Array* rgbKeyUNSAFE, SafeHandle** hKeyUNSAFE) -{ - FCALL_CONTRACT; - - struct _gc - { - U1ARRAYREF rgbKey; - SAFEHANDLE hProvSAFE; - SAFEHANDLE hKeySAFE; - } gc; - - gc.rgbKey = (U1ARRAYREF) rgbKeyUNSAFE; - gc.hProvSAFE = (SAFEHANDLE) hProvUNSAFE; - gc.hKeySAFE = (SAFEHANDLE) *hKeyUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_PROTECT(gc); - - HandleKeyHolder hKey(NULL); - DWORD cbKey = gc.rgbKey->GetNumComponents(); - NewArrayHolder<BYTE> buffer(new BYTE[cbKey]); - memcpyNoGCRefs (buffer, (LPBYTE) gc.rgbKey->GetDirectPointerToNonObjectElements(), cbKey); - CRYPT_PROV_CTX * pProvCtx = NULL; - HRESULT hr = S_OK; - - { - SafeHandleHolder shh(&gc.hProvSAFE); - pProvCtx = CryptoHelper::DereferenceSafeHandle<CRYPT_PROV_CTX>(gc.hProvSAFE); - { - GCX_PREEMP(); - // If we are running in rsabase.dll compatibility mode, make sure 11 bytes of - // zero salt are generated when using a 40 bits RC2 key. - DWORD dwFlags = (dwCalg == CALG_RC2 ? CRYPT_EXPORTABLE | CRYPT_NO_SALT : CRYPT_EXPORTABLE); - if (useSalt && dwCalg == CALG_RC2) - dwFlags &= ~CRYPT_NO_SALT; - hr = LoadKey(buffer, cbKey, pProvCtx->m_hProv, dwCalg, dwFlags, &hKey); - } - } - - if (FAILED(hr)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::_ImportBulkKey failed.\n", hr)); - CryptoHelper::COMPlusThrowCrypto(hr); - } - - CRYPT_KEY_CTX * pKeyCtx = new CRYPT_KEY_CTX(pProvCtx, hKey); - gc.hKeySAFE->SetHandle((void*) pKeyCtx); - hKey.SuppressRelease(); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -// -// Imports a CSP blob into an RSACryptoServiceProvider/DSACryptoServiceProvider managed object. The blob format is CAPI key blob format (PKCS#1) -// - -FCIMPL4(DWORD, COMCryptography::_ImportCspBlob, U1Array* rawDataUNSAFE, SafeHandle* hProvUNSAFE, DWORD dwFlags, SafeHandle** hKeyUNSAFE) -{ - FCALL_CONTRACT; - - DWORD dwKeySpec = 0; - - struct _gc - { - U1ARRAYREF rawDataSAFE; - SAFEHANDLE hProvSAFE; - SAFEHANDLE hKeySAFE; - } gc; - - gc.rawDataSAFE = (U1ARRAYREF) rawDataUNSAFE; - gc.hProvSAFE = (SAFEHANDLE) hProvUNSAFE; - gc.hKeySAFE = (SAFEHANDLE) *hKeyUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - - CRYPT_PROV_CTX * pProvCtx = NULL; - HandleKeyHolder hKey(NULL); - HRESULT hr = S_OK; - - DWORD dwCapiFlags = MapCspKeyFlags (dwFlags); - - if (gc.rawDataSAFE == NULL) - COMPlusThrowArgumentNull(W("rawData")); - - NewArrayHolder<BYTE> pbRawData(CryptoHelper::U1ARRAYREFToByteArray(gc.rawDataSAFE)); - DWORD cbRawData = gc.rawDataSAFE->GetNumComponents(); - - PUBLICKEYSTRUC* pPubKeyStruc = (PUBLICKEYSTRUC*) pbRawData.GetValue(); - // If this is a public key, ignore the CRYPT_EXPORTABLE flag. - if (pPubKeyStruc->bType == PUBLICKEYBLOB) - dwCapiFlags &= ~CRYPT_EXPORTABLE; - - { - SafeHandleHolder shh(&gc.hProvSAFE); - pProvCtx = CryptoHelper::DereferenceSafeHandle<CRYPT_PROV_CTX>(gc.hProvSAFE); - { - GCX_PREEMP(); - if (!CryptImportKey(pProvCtx->m_hProv, pbRawData, cbRawData, NULL, dwCapiFlags, &hKey)) - hr = HRESULT_FROM_GetLastError(); - } - } - - if (FAILED(hr)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::_ImportCspBlob failed.\n", hr)); - CryptoHelper::COMPlusThrowCrypto(hr); - } - - CRYPT_KEY_CTX * pKeyCtx = new CRYPT_KEY_CTX(pProvCtx, hKey); - pKeyCtx->m_dwKeySpec = (pPubKeyStruc->aiKeyAlg == CALG_RSA_KEYX ? AT_KEYEXCHANGE : AT_SIGNATURE); - pKeyCtx->m_fPublicOnly = (pPubKeyStruc->bType == PUBLICKEYBLOB ? TRUE : FALSE); - gc.hKeySAFE->SetHandle((void*) pKeyCtx); - - dwKeySpec = pKeyCtx->m_dwKeySpec; - hKey.SuppressRelease(); - - HELPER_METHOD_FRAME_END(); - return dwKeySpec; -} -FCIMPLEND - -// -// _ImportKey -// - -#ifdef _PREFAST_ -#pragma warning(push) -#pragma warning(disable:21000) // Suppress PREFast warning about overly large function -#endif -FCIMPL5(void, COMCryptography::_ImportKey, SafeHandle* hProvUNSAFE, DWORD dwCalg, DWORD dwFlags, Object* refKeyUNSAFE, SafeHandle** hKeyUNSAFE) -{ - FCALL_CONTRACT; - - struct _gc - { - OBJECTREF refKey; - SAFEHANDLE hProvSAFE; - SAFEHANDLE hKeySAFE; - } gc; - - gc.refKey = (OBJECTREF) refKeyUNSAFE; - gc.hProvSAFE = (SAFEHANDLE) hProvUNSAFE; - gc.hKeySAFE = (SAFEHANDLE) *hKeyUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_PROTECT(gc); - - BOOL fPrivate = FALSE; - HandleKeyHolder hKey(NULL); - NewArrayHolder<BYTE> pbKey(NULL); - DWORD cbKey = 0; - LPBYTE pbX = NULL; - KEY_HEADER* pKeyInfo = NULL; - - switch (dwCalg) { - case CALG_DSS_SIGN: { - DWORD cbP; - DWORD cbQ; - DWORD cbX = 0; - DWORD cbJ = 0; - DSA_CSPREF dssKey; - - VALIDATEOBJECTREF(gc.refKey); - dssKey = (DSA_CSPREF) gc.refKey; - - // Validate the DSA structure first - // P, Q and G are required. Q is a 160 bit divisor of P-1 and G is an element of Z_p - if (dssKey->m_P == NULL || dssKey->m_Q == NULL || dssKey->m_Q->GetNumComponents() != DSS_Q_LEN) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - cbP = dssKey->m_P->GetNumComponents(); - cbQ = dssKey->m_Q->GetNumComponents(); - if (dssKey->m_G == NULL || dssKey->m_G->GetNumComponents() != cbP) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - // If J is present, it should be less than the size of P: J = (P-1) / Q - // This is only a sanity check. Not doing it here is not really an issue as CAPI will fail. - if (dssKey->m_J != NULL && dssKey->m_J->GetNumComponents() >= cbP) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - // Y is present for V3 DSA key blobs, Y = g^j mod P - if (dssKey->m_Y != NULL && dssKey->m_Y->GetNumComponents() != cbP) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - // The seed is allways a 20 byte array - if (dssKey->m_seed != NULL && dssKey->m_seed->GetNumComponents() != 20) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - // The private key is less than q-1 - if (dssKey->m_X != NULL && dssKey->m_X->GetNumComponents() != DSS_Q_LEN) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - - // Compute size of data to include - cbKey = 3*cbP + cbQ + sizeof(KEY_HEADER) + sizeof(DSSSEED); - if (dssKey->m_X != 0) { - cbX = dssKey->m_X->GetNumComponents(); - cbKey += cbX; - } - if (dssKey->m_J != NULL) { - cbJ = dssKey->m_J->GetNumComponents(); - cbKey += cbJ; - } - pbKey = new BYTE[cbKey]; - - // Public or Private import? - - pKeyInfo = (KEY_HEADER *) pbKey.GetValue(); - pKeyInfo->blob.bType = PUBLICKEYBLOB; - pKeyInfo->blob.bVersion = CUR_BLOB_VERSION; - pKeyInfo->blob.reserved = 0; - pKeyInfo->blob.aiKeyAlg = dwCalg; - - if (cbX != 0) { - pKeyInfo->blob.bType = PRIVATEKEYBLOB; - fPrivate = TRUE; - } - - // - // If y is present and this is a private key, or - // If y and J are present and this is a public key, - // this should be a v3 blob - // - // make the assumption that if the item is present, there are bytes - - if (((dssKey->m_Y != NULL) && fPrivate) || - ((dssKey->m_Y != NULL) && (dssKey->m_J != NULL))) { - pKeyInfo->blob.bVersion = 0x3; - } - - pbX = pbKey + sizeof(pKeyInfo->blob); - if (pKeyInfo->blob.bVersion == 0x3) { - if (fPrivate) { - pbX += sizeof(pKeyInfo->dss_priv_v3); - pKeyInfo->dss_priv_v3.bitlenP = cbP*8; - pKeyInfo->dss_priv_v3.bitlenQ = cbQ*8; - pKeyInfo->dss_priv_v3.bitlenJ = cbJ*8; - pKeyInfo->dss_priv_v3.bitlenX = cbX*8; - pKeyInfo->dss_priv_v3.magic = DSS_PRIV_MAGIC_VER3; - } - else { - pbX += sizeof(pKeyInfo->dss_pub_v3); - pKeyInfo->dss_pub_v3.bitlenP = cbP*8; - pKeyInfo->dss_pub_v3.bitlenQ = cbQ*8; - pKeyInfo->dss_pub_v3.bitlenJ = cbJ*8; - pKeyInfo->dss_pub_v3.magic = DSS_PUB_MAGIC_VER3; - } - } - else { - if (fPrivate) { - pKeyInfo->dss_v2.magic = DSS_PRIVATE_MAGIC; - } - else { - pKeyInfo->dss_v2.magic = DSS_MAGIC; - } - pKeyInfo->dss_v2.bitlen = cbP*8; - pbX += sizeof(pKeyInfo->dss_v2); - } - - // P - memcpy(pbX, dssKey->m_P->GetDirectPointerToNonObjectElements(), cbP); - CryptoHelper::memrev(pbX, cbP); - pbX += cbP; - - // Q - memcpy(pbX, dssKey->m_Q->GetDirectPointerToNonObjectElements(), cbQ); - CryptoHelper::memrev(pbX, cbQ); - pbX += cbQ; - - // G - memcpy(pbX, dssKey->m_G->GetDirectPointerToNonObjectElements(), cbP); - CryptoHelper::memrev(pbX, cbP); - pbX += cbP; - - if (pKeyInfo->blob.bVersion == 0x3) { - // J -- if present then bVersion == 3; - if (dssKey->m_J != NULL) { - memcpy(pbX, dssKey->m_J->GetDirectPointerToNonObjectElements(), cbJ); - CryptoHelper::memrev(pbX, cbJ); - pbX += cbJ; - } - } - - if (!fPrivate || (pKeyInfo->blob.bVersion == 0x3)) { - // Y -- if present then bVersion == 3; - if (dssKey->m_Y != NULL) { - memcpy(pbX, dssKey->m_Y->GetDirectPointerToNonObjectElements(), cbP); - CryptoHelper::memrev(pbX, cbP); - pbX += cbP; - } - } - - // X -- if present then private - if (fPrivate) { - memcpy(pbX, dssKey->m_X->GetDirectPointerToNonObjectElements(), cbX); - CryptoHelper::memrev(pbX, cbX); - pbX += cbX; - } - - if ((dssKey->m_seed == NULL) || (dssKey->m_seed->GetNumComponents() == 0)){ - // No seed present, so set them to zero - if (pKeyInfo->blob.bVersion == 0x3) { - if (fPrivate) { - memset(&pKeyInfo->dss_priv_v3.DSSSeed, 0xFFFFFFFF, sizeof(DSSSEED)); - } - else { - memset(&pKeyInfo->dss_pub_v3.DSSSeed, 0xFFFFFFFF, sizeof(DSSSEED)); - } - } - else { - memset(pbX, 0xFFFFFFFF, sizeof(DSSSEED)); - pbX += sizeof(DSSSEED); - } - } else { - if (pKeyInfo->blob.bVersion == 0x3) { - if (fPrivate) { - pKeyInfo->dss_priv_v3.DSSSeed.counter = dssKey->m_counter; - memcpy(pKeyInfo->dss_priv_v3.DSSSeed.seed, dssKey->m_seed->GetDirectPointerToNonObjectElements(), 20); - CryptoHelper::memrev(pKeyInfo->dss_priv_v3.DSSSeed.seed, 20); - } else { - pKeyInfo->dss_pub_v3.DSSSeed.counter = dssKey->m_counter; - memcpy(pKeyInfo->dss_pub_v3.DSSSeed.seed, dssKey->m_seed->GetDirectPointerToNonObjectElements(), 20); - CryptoHelper::memrev(pKeyInfo->dss_pub_v3.DSSSeed.seed, 20); - } - } else { - memcpy(pbX,&dssKey->m_counter, sizeof(DWORD)); - pbX += sizeof(DWORD); - // now the seed - memcpy(pbX, dssKey->m_seed->GetDirectPointerToNonObjectElements(), 20); - CryptoHelper::memrev(pbX, 20); - pbX += 20; - } - } - - cbKey = (DWORD)(pbX - pbKey); - break; - } - - case CALG_RSA_SIGN: - case CALG_RSA_KEYX: { - RSA_CSPREF rsaKey; - - VALIDATEOBJECTREF(gc.refKey); - rsaKey = (RSA_CSPREF) gc.refKey; - - // Validate the RSA structure first - if (rsaKey->m_Modulus == NULL) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - // The exponent is a DWORD, so the byte array must not be longer than 4 bytes - if (rsaKey->m_Exponent == NULL || rsaKey->m_Exponent->GetNumComponents() > 4) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - - DWORD cb = rsaKey->m_Modulus->GetNumComponents(); - DWORD cbHalfModulus = (cb + 1)/2; - // We assume that if P != null, then so are Q, DP, DQ, InverseQ and D - if (rsaKey->m_P != NULL) { - if (rsaKey->m_P->GetNumComponents() != cbHalfModulus) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - if (rsaKey->m_Q == NULL || rsaKey->m_Q->GetNumComponents() != cbHalfModulus) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - if (rsaKey->m_dp == NULL || rsaKey->m_dp->GetNumComponents() != cbHalfModulus) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - if (rsaKey->m_dq == NULL || rsaKey->m_dq->GetNumComponents() != cbHalfModulus) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - if (rsaKey->m_InverseQ == NULL || rsaKey->m_InverseQ->GetNumComponents() != cbHalfModulus) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - if (rsaKey->m_d == NULL || rsaKey->m_d->GetNumComponents() != cb) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_DATA); - } - - // Compute the size of the data to include - pbKey = new BYTE[2*cb + 5*cbHalfModulus + sizeof(KEY_HEADER)]; - - // Public or private import? - - pKeyInfo = (KEY_HEADER *) pbKey.GetValue(); - pKeyInfo->blob.bType = PUBLICKEYBLOB; // will change to PRIVATEKEYBLOB if necessary - pKeyInfo->blob.bVersion = CUR_BLOB_VERSION; - pKeyInfo->blob.reserved = 0; - pKeyInfo->blob.aiKeyAlg = dwCalg; - - pKeyInfo->rsa.magic = RSA_PUB_MAGIC; // will change to RSA_PRIV_MAGIC below if necesary - pKeyInfo->rsa.bitlen = cb*8; - pKeyInfo->rsa.pubexp = ConvertByteArrayToDWORD(rsaKey->m_Exponent->GetDirectPointerToNonObjectElements(), rsaKey->m_Exponent->GetNumComponents()); - pbX = pbKey + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY); - - // Copy over the modulus -- put in for both public & private - - memcpy(pbX, rsaKey->m_Modulus->GetDirectPointerToNonObjectElements(), cb); - CryptoHelper::memrev(pbX, cb); - pbX += cb; - - // - // See if we are doing private keys. - // - - if ((rsaKey->m_P != 0) && (rsaKey->m_P->GetNumComponents() != 0)) { - pKeyInfo->blob.bType = PRIVATEKEYBLOB; - pKeyInfo->rsa.magic = RSA_PRIV_MAGIC; - fPrivate = TRUE; - - // Copy over P - memcpy(pbX, rsaKey->m_P->GetDirectPointerToNonObjectElements(), cbHalfModulus); - CryptoHelper::memrev(pbX, cbHalfModulus); - pbX += cbHalfModulus; - - // Copy over Q - memcpy(pbX, rsaKey->m_Q->GetDirectPointerToNonObjectElements(), cbHalfModulus); - CryptoHelper::memrev(pbX, cbHalfModulus); - pbX += cbHalfModulus; - - // Copy over dp - memcpy(pbX, rsaKey->m_dp->GetDirectPointerToNonObjectElements(), cbHalfModulus); - CryptoHelper::memrev(pbX, cbHalfModulus); - pbX += cbHalfModulus; - - // Copy over dq - memcpy(pbX, rsaKey->m_dq->GetDirectPointerToNonObjectElements(), cbHalfModulus); - CryptoHelper::memrev(pbX, cbHalfModulus); - pbX += cbHalfModulus; - - // Copy over InvQ - memcpy(pbX, rsaKey->m_InverseQ->GetDirectPointerToNonObjectElements(), cbHalfModulus); - CryptoHelper::memrev(pbX, cbHalfModulus); - pbX += cbHalfModulus; - - // Copy over d - memcpy(pbX, rsaKey->m_d->GetDirectPointerToNonObjectElements(), cb); - CryptoHelper::memrev(pbX, cb); - pbX += cb; - } - cbKey = (DWORD)(pbX - pbKey); - break; - } - - default: - COMPlusThrow(kCryptographicException, IDS_EE_CRYPTO_UNKNOWN_OPERATION); - } - - DWORD dwCapiFlags = MapCspKeyFlags(dwFlags); - if (!fPrivate) - dwCapiFlags &= ~CRYPT_EXPORTABLE; - - CRYPT_PROV_CTX * pProvCtx = NULL; - HRESULT hr = S_OK; - - { - SafeHandleHolder shh(&gc.hProvSAFE); - pProvCtx = CryptoHelper::DereferenceSafeHandle<CRYPT_PROV_CTX>(gc.hProvSAFE); - { - GCX_PREEMP(); - if (!CryptImportKey(pProvCtx->m_hProv, pbKey, cbKey, NULL, dwCapiFlags, &hKey)) - hr = HRESULT_FROM_GetLastError(); - } - } - - if (FAILED(hr)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: COMCryptography::_ImportKey failed.\n", hr)); - CryptoHelper::COMPlusThrowCrypto(hr); - } - - CRYPT_KEY_CTX * pKeyCtx = new CRYPT_KEY_CTX(pProvCtx, hKey); - pKeyCtx->m_dwKeySpec = (dwCalg == CALG_RSA_KEYX ? AT_KEYEXCHANGE : AT_SIGNATURE); - pKeyCtx->m_fPublicOnly = (pKeyInfo->blob.bType == PUBLICKEYBLOB ? TRUE : FALSE); - gc.hKeySAFE->SetHandle((void*) pKeyCtx); - hKey.SuppressRelease(); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND -#ifdef _PREFAST_ -#pragma warning(pop) -#endif - -//--------------------------------------------------------------------------------------- -// -// Check to see if we should default to calculating HMAC values correctly or in Whidbey -// compatibility mode. -// -// Return Value: -// Default compatibiltiy mode for HMACSHA384 and HMACSHA512. TRUE indicates that we -// should match Whidbey, false to use the correct calculation. -// - -FCIMPL0(FC_BOOL_RET, COMCryptography::_ProduceLegacyHMACValues) -{ - FCALL_CONTRACT; - - FC_RETURN_BOOL(g_pConfig->LegacyHMACMode()); -} -FCIMPLEND - -// -// SetKeyParamDw -// -// Sets the value of a key parameter -// - -void QCALLTYPE COMCryptography::SetKeyParamDw(CRYPT_KEY_CTX * pKeyCtx, DWORD param, DWORD dwValue) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - if (!CryptSetKeyParam(pKeyCtx->m_hKey, param, (LPBYTE) &dwValue, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - END_QCALL; -} - -// -// SetKeyParamRgb -// - -void QCALLTYPE COMCryptography::SetKeyParamRgb(CRYPT_KEY_CTX * pKeyCtx, DWORD dwParam, LPCBYTE pValue, DWORD cbValue) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - NewArrayHolder<BYTE> buffer = new BYTE[cbValue]; - memcpyNoGCRefs (buffer, pValue, cbValue); - - if (!CryptSetKeyParam(pKeyCtx->m_hKey, dwParam, buffer, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - END_QCALL; -} - -// -// SetKeySetSecurityInfo -// - -DWORD QCALLTYPE COMCryptography::SetKeySetSecurityInfo(CRYPT_PROV_CTX * pProvCtx, DWORD dwSecurityInformation, LPCBYTE pSecurityDescriptor) -{ - QCALL_CONTRACT; - - DWORD dwErrorCode = 0; - - BEGIN_QCALL; - - if (!CryptSetProvParam(pProvCtx->m_hProv, - PP_KEYSET_SEC_DESCR, - pSecurityDescriptor, - dwSecurityInformation)) - dwErrorCode = GetLastError(); - - END_QCALL; - - return dwErrorCode; -} - -// -// SetPersistKeyInCsp -// - -void QCALLTYPE COMCryptography::SetPersistKeyInCsp(CRYPT_PROV_CTX * pProvCtx, BOOL fPersistKeyInCsp) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - pProvCtx->m_fPersistKeyInCsp = fPersistKeyInCsp; - - END_QCALL; -} - -// -// SetProviderParameter -// - -void QCALLTYPE COMCryptography::SetProviderParameter(CRYPT_PROV_CTX * pProvCtx, DWORD dwKeySpec, DWORD dwProvParam, INT_PTR pbData) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - switch (dwProvParam) { - case CLR_PP_CLIENT_HWND: - if (!CryptSetProvParam(pProvCtx->m_hProv, PP_CLIENT_HWND, (LPBYTE) pbData, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - break; - - case CLR_PP_PIN: - if (!CryptSetProvParam(pProvCtx->m_hProv, (dwKeySpec == AT_SIGNATURE ? PP_SIGNATURE_PIN : PP_KEYEXCHANGE_PIN), (LPBYTE) pbData, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - break; - - default: - _ASSERTE(FALSE); - } - - END_QCALL; -} - -// -// SignValue -// - -void QCALLTYPE COMCryptography::SignValue(CRYPT_KEY_CTX * pKeyCtx, DWORD dwKeySpec, DWORD dwCalgKey, DWORD dwCalgHash, - LPCBYTE pbHash, DWORD cbHash, QCall::ObjectHandleOnStack retSignature) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - HandleHashHolder hHash = NULL; - - // Make sure it's either RSA or DSA key - _ASSERTE(dwCalgKey == CALG_DSS_SIGN || dwCalgKey == CALG_RSA_SIGN); - - NewArrayHolder<BYTE> buffer = new BYTE[cbHash]; - memcpyNoGCRefs (buffer, pbHash, cbHash); - - _ASSERTE(pKeyCtx->m_pProvCtx); - CRYPT_PROV_CTX * pProvCtx = pKeyCtx->m_pProvCtx; - - // Take the hash value and create a hash object in the correct CSP. - if (!CryptCreateHash(pProvCtx->m_hProv, dwCalgHash, NULL, 0, &hHash)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - DWORD dwHashSize = 0; - DWORD cbHashSize = sizeof(dwHashSize); - if (!CryptGetHashParam(hHash, HP_HASHSIZE, reinterpret_cast<BYTE *>(&dwHashSize), &cbHashSize, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - if (dwHashSize != cbHash) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_HASH); - - if (!CryptSetHashParam(hHash, HP_HASHVAL, buffer, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - // Find out how long the signature is going to be - DWORD cbSignature = 0; - if (!WszCryptSignHash(hHash, dwKeySpec, NULL, 0, NULL, &cbSignature)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - // Allocate the buffer to hold the signature - NewArrayHolder<BYTE> buffer2 = new BYTE[cbSignature]; - - // Now do the actual signature into the return buffer - if (!WszCryptSignHash(hHash, dwKeySpec, NULL, 0, buffer2, &cbSignature)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - switch(dwCalgKey) { - case CALG_RSA_SIGN: - // the RSA signature needs to be reversed - CryptoHelper::memrev(buffer2, cbSignature); - break; - case CALG_DSS_SIGN: - // A DSA signature consists of two 20-byte components, each of which - // must be reversed in place - if (cbSignature != 40) - COMPlusThrow(kCryptographicException, W("Cryptography_InvalidDSASignatureSize")); - CryptoHelper::memrev(buffer2, 20); - CryptoHelper::memrev(buffer2 + 20, 20); - break; - } - - retSignature.SetByteArray(buffer2, cbSignature); - - END_QCALL; -} - -// -// VerifySign -// - -BOOL QCALLTYPE COMCryptography::VerifySign(CRYPT_KEY_CTX * pKeyCtx, DWORD dwCalgKey, DWORD dwCalgHash, - LPCBYTE pbHash, DWORD cbHash, LPCBYTE pbSignature, DWORD cbSignature) -{ - QCALL_CONTRACT; - - BOOL result = FALSE; - - BEGIN_QCALL; - - // Make sure it's either RSA or DSA key - _ASSERTE(dwCalgKey == CALG_DSS_SIGN || dwCalgKey == CALG_RSA_SIGN); - - HandleHashHolder hHash = NULL; - - // - // Take the hash value and create a hash object in the correct CSP. - // - - NewArrayHolder<BYTE> bufferHash(new BYTE[cbHash]); - memcpyNoGCRefs (bufferHash, pbHash, cbHash * sizeof(BYTE)); - NewArrayHolder<BYTE> bufferSignature(new BYTE[cbSignature]); - memcpyNoGCRefs (bufferSignature, pbSignature, cbSignature * sizeof(BYTE)); - - switch(dwCalgKey) { - case CALG_RSA_SIGN: - // the RSA signature needs to be reversed - CryptoHelper::memrev(bufferSignature, cbSignature); - break; - case CALG_DSS_SIGN: - // A DSA signature consists of two 20-byte components, each of which - // must be reversed in place - if (cbSignature != 40) - COMPlusThrow(kCryptographicException, W("Cryptography_InvalidDSASignatureSize")); - CryptoHelper::memrev(bufferSignature, 20); - CryptoHelper::memrev(bufferSignature + 20, 20); - break; - } - - CRYPT_PROV_CTX * pProvCtx = pKeyCtx->m_pProvCtx; - - if (!CryptCreateHash(pProvCtx->m_hProv, dwCalgHash, NULL, 0, &hHash)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - DWORD dwHashSize = 0; - DWORD cbHashSize = sizeof(dwHashSize); - if (!CryptGetHashParam(hHash, HP_HASHSIZE, reinterpret_cast<BYTE *>(&dwHashSize), &cbHashSize, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - if (dwHashSize != cbHash) - CryptoHelper::COMPlusThrowCrypto(NTE_BAD_HASH); - - if (!CryptSetHashParam(hHash, HP_HASHVAL, bufferHash, 0)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - // Now see if the signature verifies. - result = WszCryptVerifySignature(hHash, bufferSignature, cbSignature, pKeyCtx->m_hKey, NULL, 0); - - END_QCALL; - - return result; -} -#endif // FEATURE_CRYPTO - diff --git a/src/classlibnative/cryptography/cryptography.h b/src/classlibnative/cryptography/cryptography.h deleted file mode 100644 index 70171c7130..0000000000 --- a/src/classlibnative/cryptography/cryptography.h +++ /dev/null @@ -1,521 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -// - - -#ifndef _CRYPTOGRAPHY_H_ -#define _CRYPTOGRAPHY_H_ - -#include <wincrypt.h> - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) -#include "fcall.h" - -class DSA_CSP_Object : public Object { -public: - U1ARRAYREF m_P; // ubyte[] - U1ARRAYREF m_Q; // ubyte[] - U1ARRAYREF m_G; // ubyte[] - U1ARRAYREF m_Y; // ubyte[] - optional - U1ARRAYREF m_J; // ubyte[] - optional - U1ARRAYREF m_X; // ubyte[] - optional - private key - U1ARRAYREF m_seed; // ubyte[] - optional - paired with counter - DWORD m_counter; // DWORD - optional -}; - -class RSA_CSP_Object : public Object { -public: - U1ARRAYREF m_Exponent; // ubyte[] - U1ARRAYREF m_Modulus; // ubyte[] - U1ARRAYREF m_P; // ubyte[] - optional - U1ARRAYREF m_Q; // ubyte[] - optional - U1ARRAYREF m_dp; // ubyte[] - optional - U1ARRAYREF m_dq; // ubyte[] - optional - U1ARRAYREF m_InverseQ; // ubyte[] - optional - U1ARRAYREF m_d; // ubyte[] - optional -}; - -#ifdef USE_CHECKED_OBJECTREFS -typedef REF<DSA_CSP_Object> DSA_CSPREF; -typedef REF<RSA_CSP_Object> RSA_CSPREF; -#else // !_DEBUG -typedef DSA_CSP_Object * DSA_CSPREF; -typedef RSA_CSP_Object * RSA_CSPREF; -#endif // _DEBUG - -#endif // #if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) - -#define DSS_MAGIC 0x31535344 -#define DSS_PRIVATE_MAGIC 0x32535344 -#define DSS_PUB_MAGIC_VER3 0x33535344 -#define DSS_PRIV_MAGIC_VER3 0x34535344 -#define RSA_PUB_MAGIC 0x31415352 -#define RSA_PRIV_MAGIC 0x32415352 - -#define DSS_Q_LEN 20 - -// Keep in sync with managed definition in System.Security.Cryptography.Utils -#define CLR_KEYLEN 1 -#define CLR_PUBLICKEYONLY 2 -#define CLR_EXPORTABLE 3 -#define CLR_REMOVABLE 4 -#define CLR_HARDWARE 5 -#define CLR_ACCESSIBLE 6 -#define CLR_PROTECTED 7 -#define CLR_UNIQUE_CONTAINER 8 -#define CLR_ALGID 9 -#define CLR_PP_CLIENT_HWND 10 -#define CLR_PP_PIN 11 - -#define MAX_CACHE_DEFAULT_PROVIDERS 20 -// size of a symmetric key block size. 8 is the only supported for now -#define BLOCK_LEN 8 - -// Dependency in managed : System/Security/Cryptography/Crypto.cs -#define CRYPTO_PADDING_NONE 1 -#define CRYPTO_PADDING_PKCS5 2 -#define CRYPTO_PADDING_Zeros 3 -#define CRYPTO_PADDING_ANSI_X_923 4 -#define CRYPTO_PADDING_ISO_10126 5 - -// These flags match those defined for the CspProviderFlags enum in -// src/bcl/system/security/cryptography/CryptoAPITransform.cs - -#define CSP_PROVIDER_FLAGS_USE_MACHINE_KEYSTORE 0x0001 -#define CSP_PROVIDER_FLAGS_USE_DEFAULT_KEY_CONTAINER 0x0002 -#define CSP_PROVIDER_FLAGS_USE_NON_EXPORTABLE_KEY 0x0004 -#define CSP_PROVIDER_FLAGS_USE_EXISTING_KEY 0x0008 -#define CSP_PROVIDER_FLAGS_USE_ARCHIVABLE_KEY 0x0010 -#define CSP_PROVIDER_FLAGS_USE_USER_PROTECTED_KEY 0x0020 -#define CSP_PROVIDER_FLAGS_USE_CRYPT_SILENT 0x0040 -#define CSP_PROVIDER_FLAGS_CREATE_EPHEMERAL_KEY 0x0080 - - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) || defined(FEATURE_X509) -class CryptoHelper { -public: - static void COMPlusThrowCrypto (HRESULT hr); - static BOOL WszCryptAcquireContext_SO_TOLERANT (HCRYPTPROV *phProv, LPCWSTR pwszContainer, LPCWSTR pwszProvider, DWORD dwProvType, DWORD dwFlags); - static WCHAR* STRINGREFToUnicode (STRINGREF s); - static WCHAR* AnsiToUnicode (__in_z char* pszAnsi); - static void ByteArrayToU1ARRAYREF (LPBYTE pb, DWORD cb, U1ARRAYREF* u1); - static BYTE* U1ARRAYREFToByteArray (U1ARRAYREF u1); - static char* UnicodeToAnsi (__in_z WCHAR* pwszUnicode); -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) - static WCHAR* GetRandomKeyContainer (); - static inline void memrev (LPBYTE pb, DWORD cb); - static BOOL CryptGenKey_SO_TOLERANT (HCRYPTPROV hProv, ALG_ID Algid, DWORD dwFlags, HCRYPTKEY* phKey); -#endif // FEATURE_CRYPTO - - static LPCWSTR UpgradeDSS(DWORD dwProvType, __in_z LPCWSTR wszProvider); - static LPCWSTR UpgradeRSA(DWORD dwProvType, __in_z LPCWSTR wszProvider); - - // Since crytpo classes use safe handles where the handles are really pointers to structures, we - // need to ensure that they weren't freed and set to NULL if the handle was used in an unsafe - // multithreaded way. This method unpacks the handle, ensuring it doesn't contain a NULL pointer. - template<class T> - static T * DereferenceSafeHandle(const SAFEHANDLE &handle) - { - CONTRACT(T *) - { - POSTCONDITION(RETVAL != NULL); - THROWS; - GC_TRIGGERS; - } - CONTRACT_END; - - T * pValue = static_cast<T *>(handle->GetHandle()); - if (!pValue) - { - LOG((LF_SECURITY, LL_INFO10000, "Attempt to access a NULL crypto handle, possible unsafe use of a crypto function from multiple threads")); - COMPlusThrowCrypto(E_POINTER); - } - - RETURN(pValue); - } -}; -#endif // FEATURE_CRYPTO || FEATURE_X509 - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) -typedef struct { - BLOBHEADER blob; - union { - DSSPRIVKEY_VER3 dss_priv_v3; - DSSPUBKEY_VER3 dss_pub_v3; - DSSPUBKEY dss_v2; - RSAPUBKEY rsa; - }; -} KEY_HEADER; - -// We need to define this unmanaged memory structure to hold -// all the information relevant to the CSP in order to guarantee -// critical finalization of the resources -typedef struct CRYPT_PROV_CTX { -private: - // We implicitely assume this method is not going to do a LoadLibrary - HRESULT DeleteKeyContainer() { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - GCX_PREEMP(); - - HCRYPTPROV hProv = NULL; - if (!CryptoHelper::WszCryptAcquireContext_SO_TOLERANT(&hProv, m_pwszContainer, m_pwszProvider, - m_dwType, (m_dwFlags & CRYPT_MACHINE_KEYSET) | CRYPT_DELETEKEYSET)) - return HRESULT_FROM_GetLastError(); - return S_OK; - } - -public: - HCRYPTPROV m_hProv; - LPCWSTR m_pwszContainer; - LPCWSTR m_pwszProvider; - DWORD m_dwType; - DWORD m_dwFlags; - BOOL m_fPersistKeyInCsp; - BOOL m_fReleaseProvider; - Volatile<ULONG> m_refCount; - - CRYPT_PROV_CTX() : - m_hProv(0), - m_pwszContainer(NULL), - m_pwszProvider(NULL), - m_fReleaseProvider(TRUE), - m_dwType(0), - m_dwFlags(0), - m_fPersistKeyInCsp(TRUE), - m_refCount(1) { - LIMITED_METHOD_CONTRACT; - } - - // This can be called twice. Also it can be called by multiple threads. The only - // invariant that needs to be enforced is that when the refCount reaches 0, the - // object is not going to be referenced anymore by a CRYPT_KEY_CTX or a CRYPT_HASH_CTX. - // But this is true in the way we use this in the managed side. - void Release () { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - ULONG cbRef = InterlockedDecrement((LONG*)&m_refCount); - if (cbRef == 0) { - // Make sure not to delete a key that we want to keep in the key container or an ephemeral key - if (m_fPersistKeyInCsp == FALSE && !(m_dwFlags & CRYPT_VERIFYCONTEXT)) { - // We cannot throw if we fail to delete the key container, since this code runs on the - // finalizer thread and any exception will tear the process - DeleteKeyContainer(); - } - - if (m_pwszContainer) { - delete[] m_pwszContainer; - m_pwszContainer = NULL; - } - - // The provider strings are allocated per process, so - // we should not free m_pwszProvider unless specified otherwise - if (m_fReleaseProvider) { - if (m_pwszProvider) { - delete[] m_pwszProvider; - m_pwszProvider = NULL; - } - } - - // We need to free the CSP handle -- make sure not to throw since this code could be on the - // finalizer thread. - if (m_hProv != 0) - { - CryptReleaseContext(m_hProv, 0); - m_hProv = 0; - } - - delete this; - } - } - -} CRYPT_PROV_CTX; - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) -// A key handle needs to be freed before the provider handle -// it was loaded into is freed; so we need to keep a pointer to -// the CRYPT_PROV_CTX and make the managed SafeKeyHandle contain -// a pointer to the CRYPT_KEY_CTX pointer -typedef struct CRYPT_KEY_CTX { -public: - CRYPT_PROV_CTX *m_pProvCtx; - HCRYPTKEY m_hKey; - DWORD m_dwKeySpec; - BOOL m_fPublicOnly; - - CRYPT_KEY_CTX(CRYPT_PROV_CTX * pProvCtx, HCRYPTKEY hKey) : - m_pProvCtx(pProvCtx), - m_hKey(hKey), - m_dwKeySpec(0), - m_fPublicOnly(FALSE) { - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(hKey != NULL); - PRECONDITION(CheckPointer(m_pProvCtx)); - PRECONDITION((m_pProvCtx->m_refCount >= 1)); // We can't acquire a dead CRYPT_PROV_CTX - } CONTRACTL_END; - - InterlockedIncrement((LONG*)&m_pProvCtx->m_refCount); - } - - void Release () { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - // We cannot throw if CryptDestroyKey fails, since this can be executed on the finalizer thread - if (m_hKey) - CryptDestroyKey(m_hKey); - - // We need to release the reference to the CSP handle - if (m_pProvCtx) - m_pProvCtx->Release(); - - delete this; - } - -} CRYPT_KEY_CTX; - -// A hash handle needs to be freed before the provider handle -// it was loaded into is freed; so we need to keep a pointer to -// the CRYPT_PROV_CTX and make the managed SafeHashHandle contain -// a pointer to the CRYPT_HASH_CTX pointer -typedef struct CRYPT_HASH_CTX { -public: - CRYPT_PROV_CTX *m_pProvCtx; - HCRYPTHASH m_hHash; - - CRYPT_HASH_CTX(CRYPT_PROV_CTX * pProvCtx, HCRYPTHASH hHash) : - m_pProvCtx(pProvCtx), - m_hHash(hHash) { - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(hHash != NULL); - PRECONDITION(CheckPointer(m_pProvCtx)); - PRECONDITION((m_pProvCtx->m_refCount >= 1)); // We can't acquire a dead CRYPT_PROV_CTX - } CONTRACTL_END; - - InterlockedIncrement((LONG*)&m_pProvCtx->m_refCount); - } - - void Release () { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - // We cannot throw if CryptDestroyHash fails since this code could run on the finalizer thread - if (m_hHash) - CryptDestroyHash(m_hHash); - - // We need to release the reference to the CSP handle - if (m_pProvCtx) - m_pProvCtx->Release(); - - delete this; - } - -} CRYPT_HASH_CTX; -#endif // FEATURE_CRYPTO - -class COMCryptography -{ -public: - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) - // - // QCalls from RSACryptoServiceProvider - // - - // Decrypt a symmetric key using the private key in pKeyContext - static - void QCALLTYPE DecryptKey(__in CRYPT_KEY_CTX *pKeyContext, - __in_bcount(cbEncryptedKey) BYTE *pbEncryptedKey, - DWORD cbEncryptedKey, - BOOL fOAEP, - QCall::ObjectHandleOnStack ohRetDecryptedKey); - - // Encrypt a symmetric key using the public key in pKeyContext - static - void QCALLTYPE EncryptKey(__in CRYPT_KEY_CTX *pKeyContext, - __in_bcount(cbKey) BYTE *pbKey, - DWORD cbKey, - BOOL fOAEP, - QCall::ObjectHandleOnStack ohRetEncryptedKey); - - // - // SafeHandle release QCALLS - // -#endif // FEATURE_CRYPTO - // Release our handle to a CSP, potentially deleting the referenced key. - static - void QCALLTYPE FreeCsp(__in_opt CRYPT_PROV_CTX *pProviderContext); - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) - // Release our handle to a hash, potentially also releasing the provider - static - void QCALLTYPE FreeHash(__in_opt CRYPT_HASH_CTX *pHashContext); - - // Release our handle to a key, potentially also releasing the provider - static - void QCALLTYPE FreeKey(__in_opt CRYPT_KEY_CTX *pKeyContext); - - // - // Util QCALLS - // - - static - CRYPT_HASH_CTX * CreateHash(CRYPT_PROV_CTX * pProvCtx, DWORD dwHashType); - - static - void QCALLTYPE DeriveKey(CRYPT_PROV_CTX * pProvCtx, DWORD dwCalgKey, DWORD dwCalgHash, - LPCBYTE pbPwd, DWORD cbPwd, DWORD dwFlags, LPBYTE pbIVIn, DWORD cbIVIn, - QCall::ObjectHandleOnStack retKey); - - static - void QCALLTYPE EndHash(CRYPT_HASH_CTX * pHashCtx, QCall::ObjectHandleOnStack retHash); - - static - void QCALLTYPE ExportCspBlob(CRYPT_KEY_CTX * pKeyCtx, DWORD dwBlobType, QCall::ObjectHandleOnStack retBlob); -#endif // FEATURE_CRYPTO - - static - void QCALLTYPE GetBytes(CRYPT_PROV_CTX * pProvCtx, BYTE * pbOut, INT32 cb); - - static - void QCALLTYPE GetNonZeroBytes(CRYPT_PROV_CTX * pProvCtx, BYTE * pbOut, INT32 cb); - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) - static - BOOL QCALLTYPE GetPersistKeyInCsp(CRYPT_PROV_CTX * pProvCtx); - - static - void QCALLTYPE HashData(CRYPT_HASH_CTX * pHashCtx, LPCBYTE pData, DWORD cbData, DWORD dwStart, DWORD dwSize); - - static - BOOL QCALLTYPE SearchForAlgorithm(CRYPT_PROV_CTX * pProvCtx, DWORD dwAlgID, DWORD dwKeyLength); - - static - void QCALLTYPE SetKeyParamDw(CRYPT_KEY_CTX * pKeyCtx, DWORD dwParam, DWORD dwValue); - - static - void QCALLTYPE SetKeyParamRgb(CRYPT_KEY_CTX * pKeyCtx, DWORD dwParam, LPCBYTE pValue, DWORD cbValue); - - static - DWORD QCALLTYPE SetKeySetSecurityInfo(CRYPT_PROV_CTX * pProvCtx, DWORD dwSecurityInformation, LPCBYTE pSecurityDescriptor); - - static - void QCALLTYPE SetPersistKeyInCsp(CRYPT_PROV_CTX * pProvCtx, BOOL fPersistKeyInCsp); - - static - void QCALLTYPE SetProviderParameter(CRYPT_PROV_CTX * pProvCtx, DWORD dwKeySpec, DWORD dwProvParam, INT_PTR pbData); - - static - void QCALLTYPE SignValue(CRYPT_KEY_CTX * pKeyCtx, DWORD dwKeySpec, DWORD dwCalgKey, DWORD dwCalgHash, - LPCBYTE pbHash, DWORD cbHash, QCall::ObjectHandleOnStack retSignature); - - static - BOOL QCALLTYPE VerifySign(CRYPT_KEY_CTX * pKeyCtx, DWORD dwCalgKey, DWORD dwCalgHash, - LPCBYTE pbHash, DWORD cbHash, LPCBYTE pbSignature, DWORD cbSignature); - -#endif // FEATURE_CRYPTO - -public: - // - // FCalls from System.Security.Cryptography.Utils - // - - static FCDECL2(void, _AcquireCSP, Object* cspParametersUNSAFE, SafeHandle** hProvUNSAFE); - static FCDECL3(HRESULT, _OpenCSP, Object* cspParametersUNSAFE, DWORD dwFlags, SafeHandle** hProvUNSAFE); - static FCDECL0(StringObject*, _GetRandomKeyContainer); - static LPCWSTR GetDefaultProvider(DWORD dwType); - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) - static FCDECL3(void, _CreateCSP, Object* cspParametersUNSAFE, CLR_BOOL randomKeyContainer, SafeHandle** hProvUNSAFE); - static FCDECL8(DWORD, _DecryptData, SafeHandle* hKeyUNSAFE, U1Array* dataUNSAFE, INT32 dwOffset, INT32 dwCount, U1Array** outputUNSAFE, INT32 dwOutputOffset, DWORD dwPaddingMode, CLR_BOOL fLast); - static FCDECL8(DWORD, _EncryptData, SafeHandle* hKeyUNSAFE, U1Array* dataUNSAFE, INT32 dwOffset, INT32 dwCount, U1Array** outputUNSAFE, INT32 dwOutputOffset, DWORD dwPaddingMode, CLR_BOOL fLast); - static FCDECL3(void, _ExportKey, SafeHandle* hKeyUNSAFE, DWORD dwBlobType, Object* theKeyUNSAFE); - static FCDECL5(void, _GenerateKey, SafeHandle* hProvUNSAFE, DWORD dwCalg, DWORD dwFlags, DWORD dwKeySize, SafeHandle** hKeyUNSAFE); - static FCDECL0(FC_BOOL_RET, _GetEnforceFipsPolicySetting); - static FCDECL2(U1Array*, _GetKeyParameter, SafeHandle* hKeyUNSAFE, DWORD dwKeyParam); - static FCDECL3(U1Array*, _GetKeySetSecurityInfo, SafeHandle* hProvUNSAFE, DWORD dwSecurityInformation, DWORD* pdwErrorCode); - static FCDECL3(Object*, _GetProviderParameter, SafeHandle* hKeyUNSAFE, DWORD dwKeySpec, DWORD dwKeyParam); - static FCDECL3(HRESULT, _GetUserKey, SafeHandle* hProvUNSAFE, DWORD dwKeySpec, SafeHandle** hKeyUNSAFE); - static FCDECL5(void, _ImportBulkKey, SafeHandle* hProvUNSAFE, DWORD dwCalg, CLR_BOOL useSalt, U1Array* rgbKeyUNSAFE, SafeHandle** hKeyUNSAFE); - static FCDECL4(DWORD, _ImportCspBlob, U1Array* rawDataUNSAFE, SafeHandle* hProvUNSAFE, DWORD dwFlags, SafeHandle** hKeyUNSAFE); - static FCDECL5(void, _ImportKey, SafeHandle* hProvUNSAFE, DWORD dwCalg, DWORD dwFlags, Object* refKeyUNSAFE, SafeHandle** hKeyUNSAFE); - static FCDECL0(FC_BOOL_RET, _ProduceLegacyHMACValues); -#endif // FEATURE_CRYPTO - -private: - static HRESULT OpenCSP(OBJECTREF * pSafeThis, DWORD dwFlags, CRYPT_PROV_CTX * pProvCtxStruct); - static DWORD MapCspProviderFlags (DWORD dwFlags); - -#if defined(FEATURE_CRYPTO) || defined(FEATURE_LEGACYNETCFCRYPTO) - static HRESULT MSProviderCryptImportKey(HCRYPTPROV hProv, LPBYTE rgbSymKey, DWORD cbSymKey, DWORD dwFlags, HCRYPTKEY * phkey); - static HRESULT ExponentOfOneImport(HCRYPTPROV hProv, LPBYTE rgbKeyMaterial, DWORD cbKeyMaterial, DWORD dwKeyAlg, DWORD dwFlags, HCRYPTKEY * phkey); - static HRESULT PlainTextKeyBlobImport(HCRYPTPROV hProv, LPBYTE rgbKeyMaterial, DWORD cbKeyMaterial, DWORD dwKeyAlg, DWORD dwFlags, HCRYPTKEY * phkey); - static HRESULT LoadKey(LPBYTE rgbKeyMaterial, DWORD cbKeyMaterial, HCRYPTPROV hprov, DWORD dwCalg, DWORD dwFlags, HCRYPTKEY * phkey); - static HRESULT UnloadKey(HCRYPTPROV hprov, HCRYPTKEY hkey, LPBYTE * ppb, DWORD * pcb); - static inline DWORD ConvertByteArrayToDWORD (LPBYTE pb, DWORD cb); - static inline void ConvertIntToByteArray(DWORD dwInput, LPBYTE * ppb, DWORD * pcb); - static DWORD MapCspKeyFlags (DWORD dwFlags); -#endif //FEATURE_CRYPTO - -}; // class COMCryptography - -// @telesto - with talk of registry access, sounds like this should be #ifdef out from Telesto? -//--------------------------------------------------------------------------------------- -// -// Cache of CSP data we've already looked up in the registry -// -// Notes: -// This cache is thread safe. If a CSP is not stored in the cache, it will -// return NULL rather than throwing. Attempting to store multiple CSPs with -// the same type will result in only the first CSP being stored. -// - -class ProviderCache -{ -public: - // Associate a name with a CSP type - static void CacheProvider(DWORD dwType, __in_z LPWSTR pwzProvider); - - // Get the name that's associated with the given type, NULL if there is no association setup - static LPCWSTR GetProvider(DWORD dwType); - -private: - // The largest type of CSP that Windows defines. This should be updated as new CSP types are defined - static const DWORD MaxWindowsProviderType = PROV_RSA_AES; - - static ProviderCache *s_pCache; // singleton cache instance - - EEIntHashTable m_htCache; // Mapping between cached provider types and CSP names - Crst m_crstCache; // Lock guarding access to m_htCache - - ProviderCache(); - - void InternalCacheProvider(DWORD dwType, __in_z LPWSTR pwzProvider); - LPCWSTR InternalGetProvider(DWORD dwType); -}; -#endif // FEATURE_CRYPTO -- review flags - -#endif // !_CRYPTOGRPAPHY_H_ diff --git a/src/classlibnative/cryptography/cryptography.nativeproj b/src/classlibnative/cryptography/cryptography.nativeproj deleted file mode 100644 index 44b8f93aea..0000000000 --- a/src/classlibnative/cryptography/cryptography.nativeproj +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood"> - <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" /> - <Import Project="$(ClrBase)\src\debug\SetDebugTargetLocal.props" /> - <PropertyGroup Label="Globals"> - <SccProjectName>SAK</SccProjectName> - <SccAuxPath>SAK</SccAuxPath> - <SccLocalPath>SAK</SccLocalPath> - <SccProvider>SAK</SccProvider> - </PropertyGroup> - <PropertyGroup> - <BuildCoreBinaries>true</BuildCoreBinaries> - <BuildSysBinaries>true</BuildSysBinaries> - <NoWarningDotH>true</NoWarningDotH> - <ClWarningLevel>4</ClWarningLevel> - <UserIncludes> - $(UserIncludes); - .; - ..\inc; - $(Clrbase)\src\vm; - $(Clrbase)\src\vm\$(TargetCpu); - $(VCToolsIncPath); - $(Clrbase)\src\strongname\inc; - ..\bcltype - </UserIncludes> - <OutputName>comcrypt_wks</OutputName> - <OutputPath>$(ClrLibDest)</OutputPath> - <TargetType>LIBRARY</TargetType> - <CDefines>$(CDefines);UNICODE;_UNICODE</CDefines> - </PropertyGroup> - <ItemGroup> - <CppCompile Include="Cryptography.cpp" /> - <CppCompile Include="X509Certificate.cpp" /> - </ItemGroup> - <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" /> -</Project> diff --git a/src/classlibnative/cryptography/x509certificate.cpp b/src/classlibnative/cryptography/x509certificate.cpp deleted file mode 100644 index 54a45f020a..0000000000 --- a/src/classlibnative/cryptography/x509certificate.cpp +++ /dev/null @@ -1,1340 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// -// File: X509Certificate.cpp -// - -// -// Native method implementations and helper code for supporting CAPI based operations on X509 signatures -// -//--------------------------------------------------------------------------- - - -#include "common.h" - -#ifdef FEATURE_X509 - -#include "x509certificate.h" - -#if !defined(FEATURE_CORECLR) -// -// Builds a certificate chain using the specified policy. -// - -HRESULT X509Helper::BuildChain (PCCERT_CONTEXT pCertContext, - HCERTSTORE hCertStore, - LPCSTR pszPolicy, - PCCERT_CHAIN_CONTEXT * ppChainContext) -{ - CONTRACTL { - THROWS; // THROWS because the delay-loading of crypt32.dll may fail when we call CertGetCertificateChain() - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - GCX_PREEMP(); - - CERT_CHAIN_PARA ChainPara = {0}; - LPSTR rgpszUsageIdentifier[1] = {NULL}; - - // Initialize the structure size. - ChainPara.cbSize = sizeof(ChainPara); - - // Check policy. - if (CERT_CHAIN_POLICY_BASE == pszPolicy) { - // No EKU for base policy. - } - else - return CERT_E_INVALID_POLICY; - - // Build the chain. - if (!CertGetCertificateChain(NULL, - pCertContext, - NULL, - hCertStore, - &ChainPara, - 0, - NULL, - ppChainContext)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertGetCertificateChain failed.\n", HRESULT_FROM_GetLastError())); - return HRESULT_FROM_GetLastError(); - } - - return S_OK; -} - -// -// decodes an ASN encoded data. The caller is responsible for calling delete[] to free the allocated memory. -// - -HRESULT X509Helper::DecodeObject(LPCSTR pszStructType, - LPBYTE pbEncoded, - DWORD cbEncoded, - void** ppvDecoded, - DWORD* pcbDecoded) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - GCX_PREEMP(); - - DWORD cbDecoded = 0; - if (!CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - pszStructType, - pbEncoded, - cbEncoded, - 0, - NULL, - &cbDecoded)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CryptDecodeObject failed.\n", HRESULT_FROM_GetLastError())); - return HRESULT_FROM_GetLastError(); - } - - *ppvDecoded = (void*) new BYTE[cbDecoded]; - if (!CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - pszStructType, - pbEncoded, - cbEncoded, - 0, - *ppvDecoded, - &cbDecoded)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CryptDecodeObject failed.\n", HRESULT_FROM_GetLastError())); - return HRESULT_FROM_GetLastError(); - } - - if (pcbDecoded) - *pcbDecoded = cbDecoded; - - return S_OK; -} - -// -// Deletes a key container given a certificate context. -// - -BOOL X509Helper::DeleteKeyContainer (PCCERT_CONTEXT pCertContext) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - GCX_PREEMP(); - - NewHolder<CRYPT_KEY_PROV_INFO> pProvInfo; - DWORD cbData = 0; - if (!CertGetCertificateContextProperty(pCertContext, - CERT_KEY_PROV_INFO_PROP_ID, - NULL, - &cbData)) - return TRUE; - - pProvInfo = (CRYPT_KEY_PROV_INFO*) new BYTE[cbData]; - if (!CertGetCertificateContextProperty(pCertContext, - CERT_KEY_PROV_INFO_PROP_ID, - (void*) pProvInfo.GetValue(), - &cbData)) - return FALSE; - - // First disassociate the key from the cert. - if (!CertSetCertificateContextProperty(pCertContext, - CERT_KEY_PROV_INFO_PROP_ID, - 0, - NULL)) - return FALSE; - - HCRYPTPROV hProv = NULL; - return CryptoHelper::WszCryptAcquireContext_SO_TOLERANT(&hProv, - pProvInfo->pwszContainerName, - pProvInfo->pwszProvName, - pProvInfo->dwProvType, - (pProvInfo->dwFlags & CRYPT_MACHINE_KEYSET) | CRYPT_DELETEKEYSET); -} -#endif // !FEATURE_CORECLR - -// -// Loads a certificate or store from a blob and returns that content type. -// - -DWORD X509Helper::LoadFromBlob (CERT_BLOB* pCertBlob, - __in_opt WCHAR* pwszPassword, - DWORD dwFlags, - PCCERT_CONTEXT* pCertContext, - HCERTSTORE* phCertStore, - HCRYPTMSG* phCryptMsg) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - DWORD dwContentType = 0; - GCX_PREEMP(); - if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, - pCertBlob, - dwFlags, - X509_CERT_FORMAT_FLAGS, - 0, - NULL, - &dwContentType, - NULL, - phCertStore, - phCryptMsg, - (const void **)pCertContext)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CryptQueryObject failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - return dwContentType; -} - -// -// Loads a certificate or store from a file and returns that content type. -// - -DWORD X509Helper::LoadFromFile (__in_z WCHAR* pwszFileName, - __in_opt WCHAR* pwszPassword, - DWORD dwFlags, - PCCERT_CONTEXT* pCertContext, - HCERTSTORE* phCertStore, - HCRYPTMSG* phCryptMsg) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - DWORD dwContentType = 0; - GCX_PREEMP(); - if (!CryptQueryObject(CERT_QUERY_OBJECT_FILE, - pwszFileName, - dwFlags, - X509_CERT_FORMAT_FLAGS, - 0, - NULL, - &dwContentType, - NULL, - phCertStore, - phCryptMsg, - (const void **)pCertContext)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CryptQueryObject failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - return dwContentType; -} - -// -// Reads a file into memory. The caller is responsible for deleting the allocated memory. -// - -HRESULT X509Helper::ReadFileIntoMemory (LPCWSTR wszFileName, - LPBYTE* ppbBuffer, - DWORD* pdwBufLen) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - GCX_PREEMP(); - - HandleHolder hFile(WszCreateFile (wszFileName, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, - NULL)); - if (hFile == INVALID_HANDLE_VALUE) - return HRESULT_FROM_GetLastError(); - - DWORD dwFileLen = SafeGetFileSize(hFile, 0); - if (dwFileLen == 0xFFFFFFFF) - return HRESULT_FROM_GetLastError(); - - _ASSERTE(ppbBuffer); - *ppbBuffer = new BYTE[dwFileLen]; - - if ((SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == 0xFFFFFFFF) || - (!ReadFile(hFile, *ppbBuffer, dwFileLen, pdwBufLen, NULL))) { - delete[] *ppbBuffer; - *ppbBuffer = 0; - return HRESULT_FROM_GetLastError(); - } - - _ASSERTE(dwFileLen == *pdwBufLen); - return S_OK; -} - -// -// Returns the name for the subject or issuer. -// dwFlags : 0 for subject name or CERT_NAME_ISSUER_FLAG for issuer name. -// dwDisplayType: display type. -// -// It is the caller's responsibility to free the allocated buffer. -// - -WCHAR* COMX509Certificate::GetCertNameInfo(PCCERT_CONTEXT pCertContext, DWORD dwFlags, DWORD dwDisplayType, DWORD dwStrType) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - GCX_PREEMP(); - - DWORD cchCount = 0; - if ((cchCount = CertGetNameString(pCertContext, - dwDisplayType, - dwFlags, - &dwStrType, - NULL, - 0)) == 0) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertGetNameString failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - NewArrayHolder<WCHAR> pwszName(new WCHAR[cchCount]); - if (!CertGetNameString(pCertContext, - dwDisplayType, - dwFlags, - &dwStrType, - pwszName, - cchCount)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertGetNameString failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - pwszName.SuppressRelease(); - return pwszName; -} - -#if !defined(FEATURE_CORECLR) -// -// Finds the first certificate with a private key in a PFX store. -// If none has a private key, we take the first certificatee in the PFX store. -// - -PCCERT_CONTEXT COMX509Certificate::FilterPFXStore (CERT_BLOB* pfxBlob, __in_z WCHAR* pwszPassword, DWORD dwFlags) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - GCX_PREEMP(); - - HandleCertStoreHolder hCertStore = NULL; - hCertStore = PFXImportCertStore(pfxBlob, pwszPassword, dwFlags); - if (hCertStore == NULL) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: PFXImportCertStore failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - // now filter the PFX store - PCCERT_CONTEXT pCertContext = NULL; - PCCERT_CONTEXT pEnumContext = NULL; - DWORD cb = 0; - - // Find the first cert with private key, if none, then simply take the very first cert. - while ((pEnumContext = CertEnumCertificatesInStore(hCertStore, pEnumContext)) != NULL) { - if (CertGetCertificateContextProperty(pEnumContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cb)) { - if (pCertContext != NULL) { - if (CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cb)) { - X509Helper::DeleteKeyContainer(pEnumContext); - } else { - CertFreeCertificateContext(pCertContext); - pCertContext = CertDuplicateCertificateContext(pEnumContext); - } - } else { - pCertContext = CertDuplicateCertificateContext(pEnumContext); - } - } else { - // Keep the first one. - if (pCertContext == NULL) - pCertContext = CertDuplicateCertificateContext(pEnumContext); - } - // Don't free pEnumContext here, as CertEnumCertificatesInStore will do it for us - } - - if (pCertContext == NULL) - CryptoHelper::COMPlusThrowCrypto(ERROR_INVALID_PARAMETER); - - return pCertContext; -} - -// -// Finds the signer certificate in a PKCS7 signed store. -// - -PCCERT_CONTEXT COMX509Certificate::GetSignerInPKCS7Store (HCERTSTORE hCertStore, HCRYPTMSG hCryptMsg) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - GCX_PREEMP(); - - // make sure that there is at least one signer of the certificate store - DWORD dwSigners; - DWORD cbSigners = sizeof(dwSigners); - if (!CryptMsgGetParam(hCryptMsg, - CMSG_SIGNER_COUNT_PARAM, - 0, - &dwSigners, - &cbSigners)) - { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CryptMsgGetParam(CMSG_SIGNER_COUNT_PARAM) failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - if (dwSigners == 0) - CryptoHelper::COMPlusThrowCrypto(CRYPT_E_SIGNER_NOT_FOUND); - - // get the first signer from the store, and use that as the loaded certificate - DWORD cbData = 0; - if (!CryptMsgGetParam(hCryptMsg, - CMSG_SIGNER_INFO_PARAM, - 0, - NULL, - &cbData)) - { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CryptMsgGetParam(CMS_SIGNER_INFO_PARAM) failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - NewArrayHolder<CMSG_SIGNER_INFO> pCmsgSigner = (CMSG_SIGNER_INFO*) new BYTE[cbData]; - if (!CryptMsgGetParam(hCryptMsg, - CMSG_SIGNER_INFO_PARAM, - 0, - pCmsgSigner, - &cbData)) - { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CryptMsgGetParam failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - CERT_INFO CertInfo; - CertInfo.Issuer = pCmsgSigner->Issuer; - CertInfo.SerialNumber = pCmsgSigner->SerialNumber; - PCCERT_CONTEXT pCertContext = CertFindCertificateInStore(hCertStore, - X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - 0, - CERT_FIND_SUBJECT_CERT, - (LPVOID) &CertInfo, - NULL); - - if (pCertContext == NULL) - { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertFindCertificateInStore failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - return pCertContext; -} -#endif // !FEATURE_CORECLR - -// -// FCALL methods -// - -// -// The certificate context ref count is incremented by CertDuplicateCertificateContext, -// so it is the caller's responsibility to free the context. -// - -FCIMPL2(void, COMX509Certificate::DuplicateCertContext, INT_PTR handle, SafeHandle** ppCertUNSAFE) -{ - FCALL_CONTRACT; - - SAFEHANDLE pCertSAFE = (SAFEHANDLE) *ppCertUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_1(pCertSAFE); - - PCCERT_CONTEXT pCertContext = (PCCERT_CONTEXT) handle; - PCCERT_CONTEXT pCertDup = NULL; - BOOL bDelKeyContainer = FALSE; - { - GCX_PREEMP(); - if ((pCertDup = CertDuplicateCertificateContext(pCertContext)) == NULL) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE)); - - DATA_BLOB blob; - DWORD cbData = 0; - if (CertGetCertificateContextProperty(pCertDup, - CERT_DELETE_KEYSET_PROP_ID, // This value should be defined in wincrypt.h - // as well to avoid conflicts. - (void*) &blob, - &cbData)) - bDelKeyContainer = TRUE; - } - - CERT_CTX* pCert = new CERT_CTX(pCertDup); -#if !defined(FEATURE_CORECLR) - pCert->m_fDelKeyContainer = bDelKeyContainer; -#endif // !FEATURE_CORECLR - - pCertSAFE->SetHandle((void*) pCert); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -// -// Free a handle to a CERT_CTX structure. Critical finalizer method for SafeCertContextHandle. -// - -FCIMPL1(void, COMX509Certificate::FreePCertContext, INT_PTR pCertCtx) -{ - FCALL_CONTRACT; - - HELPER_METHOD_FRAME_BEGIN_0(); - - BOOL bRet = TRUE; - CERT_CTX* pCert = (CERT_CTX*) pCertCtx; - - if (pCert) - bRet = pCert->Release(); - - // Add this assert to debug failures to free resources - _ASSERTE(bRet); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -// -// ASN encoded certificate as a byte array. -// - -FCIMPL1(U1Array*, COMX509Certificate::GetCertRawData, SafeHandle* pCertUNSAFE) -{ - FCALL_CONTRACT; - - SAFEHANDLE pCertSAFE = (SAFEHANDLE) pCertUNSAFE; - U1ARRAYREF pbRawData = NULL; - - HELPER_METHOD_FRAME_BEGIN_RET_2(pbRawData, pCertSAFE); - - SafeHandleHolder shh(&pCertSAFE); - CERT_CTX* pCert = CryptoHelper::DereferenceSafeHandle<CERT_CTX>(pCertSAFE); - - CryptoHelper::ByteArrayToU1ARRAYREF(pCert->m_pCtx->pbCertEncoded, - pCert->m_pCtx->cbCertEncoded, - &pbRawData); - - HELPER_METHOD_FRAME_END(); - return (U1Array*) OBJECTREFToObject(pbRawData); -} -FCIMPLEND - -// -// Returns the NotAfter field. -// - -FCIMPL2(void, COMX509Certificate::GetDateNotAfter, SafeHandle* pCertUNSAFE, FILETIME* pFileTime) -{ - FCALL_CONTRACT; - - SAFEHANDLE pCertSAFE = (SAFEHANDLE) pCertUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_1(pCertSAFE); - - SafeHandleHolder shh(&pCertSAFE); - CERT_CTX* pCert = CryptoHelper::DereferenceSafeHandle<CERT_CTX>(pCertSAFE); - - pFileTime->dwLowDateTime = pCert->m_pCtx->pCertInfo->NotAfter.dwLowDateTime; - pFileTime->dwHighDateTime = pCert->m_pCtx->pCertInfo->NotAfter.dwHighDateTime; - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -// -// Returns the NotBefore field. -// - -FCIMPL2(void, COMX509Certificate::GetDateNotBefore, SafeHandle* pCertUNSAFE, FILETIME* pFileTime) -{ - FCALL_CONTRACT; - - SAFEHANDLE pCertSAFE = (SAFEHANDLE) pCertUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_1(pCertSAFE); - - SafeHandleHolder shh(&pCertSAFE); - CERT_CTX* pCert = CryptoHelper::DereferenceSafeHandle<CERT_CTX>(pCertSAFE); - - pFileTime->dwLowDateTime = pCert->m_pCtx->pCertInfo->NotBefore.dwLowDateTime; - pFileTime->dwHighDateTime = pCert->m_pCtx->pCertInfo->NotBefore.dwHighDateTime; - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -// -// Issuer name as a string. -// - -FCIMPL2(StringObject*, COMX509Certificate::GetIssuerName, SafeHandle* pCertUNSAFE, CLR_BOOL fLegacyV1Mode) -{ - FCALL_CONTRACT; - - STRINGREF issuerString = NULL; - SAFEHANDLE pCertSAFE = (SAFEHANDLE) pCertUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_2(issuerString, pCertSAFE); - - DWORD dwStrType = CERT_X500_NAME_STR; - if (!fLegacyV1Mode) - dwStrType |= CERT_NAME_STR_REVERSE_FLAG; - - SafeHandleHolder shh(&pCertSAFE); - CERT_CTX* pCert = CryptoHelper::DereferenceSafeHandle<CERT_CTX>(pCertSAFE); - - DWORD cchCount = 0; - if ((cchCount = CertGetNameString(pCert->m_pCtx, - CERT_NAME_RDN_TYPE, - CERT_NAME_ISSUER_FLAG, - &dwStrType, - NULL, - 0)) == 0) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertGetNameString failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - NewArrayHolder<WCHAR> pwszIssuerName(new WCHAR[cchCount]); - if (!CertGetNameString(pCert->m_pCtx, - CERT_NAME_RDN_TYPE, - CERT_NAME_ISSUER_FLAG, - &dwStrType, - pwszIssuerName, - cchCount)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertGetNameString failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - issuerString = StringObject::NewString(pwszIssuerName); - - HELPER_METHOD_FRAME_END(); - return (StringObject*) OBJECTREFToObject(issuerString); -} -FCIMPLEND - -// -// Returns the public key friendly name. -// - -FCIMPL1(StringObject*, COMX509Certificate::GetPublicKeyOid, SafeHandle* pCertUNSAFE) -{ - FCALL_CONTRACT; - - STRINGREF oidString = NULL; - SAFEHANDLE pCertSAFE = (SAFEHANDLE) pCertUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_2(oidString, pCertSAFE); - - SafeHandleHolder shh(&pCertSAFE); - CERT_CTX* pCert = CryptoHelper::DereferenceSafeHandle<CERT_CTX>(pCertSAFE); - - NewArrayHolder<WCHAR> pwszOid(CryptoHelper::AnsiToUnicode((char*) pCert->m_pCtx->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId)); - oidString = StringObject::NewString(pwszOid); - - HELPER_METHOD_FRAME_END(); - return (StringObject*) OBJECTREFToObject(oidString); -} -FCIMPLEND - -// -// Returns the public key ASN encoded parameters. -// - -FCIMPL1(U1Array*, COMX509Certificate::GetPublicKeyParameters, SafeHandle* pCertUNSAFE) -{ - FCALL_CONTRACT; - - U1ARRAYREF pbParameters = NULL; - SAFEHANDLE pCertSAFE = (SAFEHANDLE) pCertUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_2(pbParameters, pCertSAFE); - - SafeHandleHolder shh(&pCertSAFE); - CERT_CTX* pCert = CryptoHelper::DereferenceSafeHandle<CERT_CTX>(pCertSAFE); - - BOOL bInheritedParams = FALSE; - -#if defined(FEATURE_CORECLR) - // We'll support RSA-based certificates only in Telesto, not DSS. - // This is in lieu of looking up the OID info, as it would require implementing - // CryptFindOIDInfo in the PAL, along with the tables of OID infos relating to - // at least the OIDs whose Algid's are CALG_DSS_SIGN. - _ASSERTE(pCert->m_pCtx->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId != NULL); - if(strncmp(szOID_RSA_RSA, pCert->m_pCtx->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, COUNTOF(szOID_RSA_RSA)) != 0) - CryptoHelper::COMPlusThrowCrypto(COR_E_PLATFORMNOTSUPPORTED); -#else // FEATURE_CORECLR - PCCRYPT_OID_INFO pOidInfo = NULL; - { - GCX_PREEMP(); - - // check to see if this is the most common case -- szOID_RSA_RSA. If so, we know that this is not - // a DSS cert, so we don't need to get extra information about the OID to determine that. If it - // is not, then we can first check in the public key OID group before falling back to check in - // all OID groups. - _ASSERTE(pCert->m_pCtx->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId != NULL); - if(strncmp(szOID_RSA_RSA, pCert->m_pCtx->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, COUNTOF(szOID_RSA_RSA)) != 0) - { - pOidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pCert->m_pCtx->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, CRYPT_PUBKEY_ALG_OID_GROUP_ID); - if(pOidInfo == NULL) - pOidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pCert->m_pCtx->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0); - } - } - - // - // DSS certificates may not have the DSS parameters in the certificate. In this case, we try to build - // the certificate chain and propagate the parameters down from the certificate chain. - // - - if (pOidInfo != NULL && pOidInfo->Algid == CALG_DSS_SIGN) { - if ((pCert->m_pCtx->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData == 0) || - (*pCert->m_pCtx->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData == NULL_ASN_TAG)) { - // Build the chain to inherit parameters in the property, if not already inherited. - DWORD cbData = 0; - HRESULT hr = S_OK; - if (!CertGetCertificateContextProperty(pCert->m_pCtx, - CERT_PUBKEY_ALG_PARA_PROP_ID, - NULL, - &cbData)) { - // build the chain and ignore any errors during the chain building - HandleCertChainHolder pChainContext = NULL; - hr = X509Helper::BuildChain(pCert->m_pCtx, NULL, CERT_CHAIN_POLICY_BASE, &pChainContext); - if (SUCCEEDED(hr)) { - if (!CertGetCertificateContextProperty(pCert->m_pCtx, - CERT_PUBKEY_ALG_PARA_PROP_ID, - NULL, - &cbData)) { - hr = HRESULT_FROM_GetLastError(); - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CERT_PUBKEY_ALG_PARA_PROP_ID property not found.\n", hr)); - } - } - } - if (FAILED(hr)) - CryptoHelper::COMPlusThrowCrypto(hr); - - // The property exists; get it for real. - NewArrayHolder<BYTE> pbData = new BYTE[cbData]; - if (!CertGetCertificateContextProperty(pCert->m_pCtx, - CERT_PUBKEY_ALG_PARA_PROP_ID, - (void*) pbData.GetValue(), - &cbData)) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - CryptoHelper::ByteArrayToU1ARRAYREF(pbData, cbData, &pbParameters); - bInheritedParams = TRUE; - } - } -#endif // (FEATURE_CORECLR) else - - if (!bInheritedParams) { - CryptoHelper::ByteArrayToU1ARRAYREF(pCert->m_pCtx->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData, - pCert->m_pCtx->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData, - &pbParameters); - } - - HELPER_METHOD_FRAME_END(); - return (U1Array*) OBJECTREFToObject(pbParameters); -} -FCIMPLEND - -// -// Returns the public key ASN encoded value. -// - -FCIMPL1(U1Array*, COMX509Certificate::GetPublicKeyValue, SafeHandle* pCertUNSAFE) -{ - FCALL_CONTRACT; - - U1ARRAYREF pbKeyValue = NULL; - SAFEHANDLE pCertSAFE = (SAFEHANDLE) pCertUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_2(pbKeyValue, pCertSAFE); - - SafeHandleHolder shh(&pCertSAFE); - CERT_CTX* pCert = CryptoHelper::DereferenceSafeHandle<CERT_CTX>(pCertSAFE); - - CryptoHelper::ByteArrayToU1ARRAYREF(pCert->m_pCtx->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, - pCert->m_pCtx->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, - &pbKeyValue); - - HELPER_METHOD_FRAME_END(); - return (U1Array*) OBJECTREFToObject(pbKeyValue); -} -FCIMPLEND - -// -// Serial number as a byte array. -// - -FCIMPL1(U1Array*, COMX509Certificate::GetSerialNumber, SafeHandle* pCertUNSAFE) -{ - FCALL_CONTRACT; - - SAFEHANDLE pCertSAFE = (SAFEHANDLE) pCertUNSAFE; - U1ARRAYREF pbSerialNumber = NULL; - HELPER_METHOD_FRAME_BEGIN_RET_2(pbSerialNumber, pCertSAFE); - - SafeHandleHolder shh(&pCertSAFE); - CERT_CTX* pCert = CryptoHelper::DereferenceSafeHandle<CERT_CTX>(pCertSAFE); - - CryptoHelper::ByteArrayToU1ARRAYREF(pCert->m_pCtx->pCertInfo->SerialNumber.pbData, - pCert->m_pCtx->pCertInfo->SerialNumber.cbData, - &pbSerialNumber); - - HELPER_METHOD_FRAME_END(); - return (U1Array*) OBJECTREFToObject(pbSerialNumber); -} -FCIMPLEND - -// -// Subject info as a string. -// - -FCIMPL3(StringObject*, COMX509Certificate::GetSubjectInfo, SafeHandle* pCertUNSAFE, DWORD dwDisplayType, CLR_BOOL fLegacyV1Mode) -{ - FCALL_CONTRACT; - - STRINGREF subjectString = NULL; - SAFEHANDLE pCertSAFE = (SAFEHANDLE) pCertUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_2(subjectString, pCertSAFE); - - SafeHandleHolder shh(&pCertSAFE); - CERT_CTX* pCert = CryptoHelper::DereferenceSafeHandle<CERT_CTX>(pCertSAFE); - - DWORD dwStrType = CERT_X500_NAME_STR; - if (!fLegacyV1Mode) - dwStrType |= CERT_NAME_STR_REVERSE_FLAG; - NewArrayHolder<WCHAR> pwszSubjName(GetCertNameInfo(pCert->m_pCtx, 0, dwDisplayType, dwStrType)); - subjectString = StringObject::NewString(pwszSubjName); - - HELPER_METHOD_FRAME_END(); - return (StringObject*) OBJECTREFToObject(subjectString); -} -FCIMPLEND - -// -// Returns the thumbprint of the certificate. -// - -FCIMPL1(U1Array*, COMX509Certificate::GetThumbprint, SafeHandle* pCertUNSAFE) -{ - FCALL_CONTRACT; - - SAFEHANDLE pCertSAFE = (SAFEHANDLE) pCertUNSAFE; - U1ARRAYREF pbThumbprint = NULL; - - HELPER_METHOD_FRAME_BEGIN_RET_2(pbThumbprint, pCertSAFE); - - SafeHandleHolder shh(&pCertSAFE); - CERT_CTX* pCert = CryptoHelper::DereferenceSafeHandle<CERT_CTX>(pCertSAFE); - - DWORD dwSize = 0; - if(!CertGetCertificateContextProperty(pCert->m_pCtx, - CERT_SHA1_HASH_PROP_ID, - NULL, - &dwSize)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertGetCertificateContextProperty failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - pbThumbprint = (U1ARRAYREF) AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwSize); - if(!CertGetCertificateContextProperty(pCert->m_pCtx, - CERT_SHA1_HASH_PROP_ID, - pbThumbprint->m_Array, - &dwSize)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertGetCertificateContextProperty failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - HELPER_METHOD_FRAME_END(); - return (U1Array*) OBJECTREFToObject(pbThumbprint); -} -FCIMPLEND - -// -// Opens the blob and gets its type, then loads a certificate from it. Depending on the blob type, -// the blob can contain 1 or more certificates. If more than 1, we select the most likely choice. -// - -FCIMPL5(void, COMX509Certificate::LoadCertFromBlob, U1Array* dataUNSAFE, - __in_z WCHAR* pwszPassword, DWORD dwFlags, CLR_BOOL persistKeySet, SafeHandle** ppCertUNSAFE); -{ - FCALL_CONTRACT; - - struct _gc { - U1ARRAYREF dataSAFE; - SAFEHANDLE pCertSAFE; - } gc; - - gc.dataSAFE = (U1ARRAYREF) dataUNSAFE; - gc.pCertSAFE = (SAFEHANDLE) *ppCertUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_PROTECT(gc); - - NewArrayHolder<BYTE> buffer(CryptoHelper::U1ARRAYREFToByteArray(gc.dataSAFE)); - CERT_BLOB certBlob = {gc.dataSAFE->GetNumComponents(), buffer}; - HandleCertContextHolder pCertContext(NULL); - - HandleCertStoreHolder hCertStore(NULL); - HandleCryptMsgHolder hCryptMsg(NULL); - - DWORD dwContentType; dwContentType = X509Helper::LoadFromBlob(&certBlob, - pwszPassword, - X509_CERT_CONTENT_FLAGS, - &pCertContext, - &hCertStore, - &hCryptMsg); - -#if !defined(FEATURE_CORECLR) - if (dwContentType == CERT_QUERY_CONTENT_PKCS7_SIGNED - || dwContentType == CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED) { - pCertContext = GetSignerInPKCS7Store(hCertStore, hCryptMsg); - } else if (dwContentType == CERT_QUERY_CONTENT_PFX) { - pCertContext = FilterPFXStore(&certBlob, pwszPassword, dwFlags); - } -#endif // !FEATURE_CORECLR - - CERT_CTX* pCert = new CERT_CTX(pCertContext); -#if !defined(FEATURE_CORECLR) - if (dwContentType == CERT_QUERY_CONTENT_PFX) - pCert->m_fDelKeyContainer = (persistKeySet == FALSE); -#endif // !FEATURE_CORECLR - - gc.pCertSAFE->SetHandle((void*) pCert); - pCertContext.SuppressRelease(); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -// -// Opens the file and gets its type, then loads a certificate from it. Depending on the blob type, -// the blob can contain 1 or more certificates. If more than 1, we select the most likely choice. -// - -FCIMPL5(void, COMX509Certificate::LoadCertFromFile, StringObject* fileNameUNSAFE, - __in_z WCHAR* pwszPassword, DWORD dwFlags, CLR_BOOL persistKeySet, SafeHandle** ppCertUNSAFE) -{ - FCALL_CONTRACT; - - struct _gc - { - STRINGREF fileNameSAFE; - SAFEHANDLE pCertSAFE; - } gc; - - gc.fileNameSAFE = (STRINGREF) fileNameUNSAFE; - gc.pCertSAFE = (SAFEHANDLE) *ppCertUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_PROTECT(gc); - - NewArrayHolder<WCHAR> pwszFileName(CryptoHelper::STRINGREFToUnicode(gc.fileNameSAFE)); - - HandleCertStoreHolder hCertStore(NULL); - HandleCryptMsgHolder hCryptMsg(NULL); - - HandleCertContextHolder pCertContext(NULL); - DWORD dwContentType; dwContentType = X509Helper::LoadFromFile(pwszFileName, - pwszPassword, - X509_CERT_CONTENT_FLAGS, - &pCertContext, - &hCertStore, - &hCryptMsg); - -#if !defined(FEATURE_CORECLR) - if (dwContentType == CERT_QUERY_CONTENT_PKCS7_SIGNED || dwContentType == CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED) { - pCertContext = GetSignerInPKCS7Store(hCertStore, hCryptMsg); - } else if (dwContentType == CERT_QUERY_CONTENT_PFX) { - NewArrayHolder<BYTE> pb = NULL; - DWORD cb = 0; - // read the file - HRESULT hr = X509Helper::ReadFileIntoMemory(gc.fileNameSAFE->GetBuffer(), &pb, &cb); - if (FAILED(hr)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: ReadFileIntoMemory failed.\n", hr)); - CryptoHelper::COMPlusThrowCrypto(hr); - } - CERT_BLOB certBlob = {cb, pb}; - pCertContext = FilterPFXStore(&certBlob, pwszPassword, dwFlags); - } -#endif // !FEATURE_CORECLR - - CERT_CTX* pCert = new CERT_CTX(pCertContext); -#if !defined(FEATURE_CORECLR) - if (dwContentType == CERT_QUERY_CONTENT_PFX) - pCert->m_fDelKeyContainer = (persistKeySet == FALSE); -#endif // !FEATURE_CORECLR - - gc.pCertSAFE->SetHandle((void*) pCert); - pCertContext.SuppressRelease(); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -// -// This method opens the blob and returns its type. -// - -FCIMPL1(DWORD, COMX509Certificate::QueryCertBlobType, U1Array* dataUNSAFE) -{ - FCALL_CONTRACT; - - DWORD dwContentType = 0; - U1ARRAYREF dataSAFE = (U1ARRAYREF) dataUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_1(dataSAFE); - - NewArrayHolder<BYTE> buffer(CryptoHelper::U1ARRAYREFToByteArray(dataSAFE)); - CERT_BLOB certBlob = {dataSAFE->GetNumComponents(), buffer}; - - { - GCX_PREEMP(); - if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, - &certBlob, - X509_CERT_CONTENT_FLAGS, - X509_CERT_FORMAT_FLAGS, - 0, - NULL, - &dwContentType, - NULL, - NULL, - NULL, - NULL)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CryptQueryObject failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - } - - HELPER_METHOD_FRAME_END(); - return dwContentType; - -} -FCIMPLEND - -// -// This method opens the file and returns its type. -// - -FCIMPL1(DWORD, COMX509Certificate::QueryCertFileType, StringObject* fileNameUNSAFE) -{ - FCALL_CONTRACT; - - DWORD dwContentType = 0; - STRINGREF fileNameSAFE = (STRINGREF) fileNameUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_1(fileNameSAFE); - - NewArrayHolder<WCHAR> buffer(CryptoHelper::STRINGREFToUnicode(fileNameSAFE)); - - { - GCX_PREEMP(); - if (!CryptQueryObject(CERT_QUERY_OBJECT_FILE, - buffer, - X509_CERT_CONTENT_FLAGS, - X509_CERT_FORMAT_FLAGS, - 0, - NULL, - &dwContentType, - NULL, - NULL, - NULL, - NULL)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CryptQueryObject failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - } - - HELPER_METHOD_FRAME_END(); - return dwContentType; - -} -FCIMPLEND - -// -// FCALL methods -// - -#if !defined(FEATURE_CORECLR) -// -// Add a certificate to the store. -// Added certificates are not persisted for non-system stores. -// - -FCIMPL2(void, COMX509Store::AddCertificate, SafeHandle* hStoreUNSAFE, SafeHandle* pCertUNSAFE) -{ - FCALL_CONTRACT; - - SAFEHANDLE hStoreSAFE = (SAFEHANDLE) hStoreUNSAFE; - SAFEHANDLE pCertSAFE = (SAFEHANDLE) pCertUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_2(hStoreSAFE, pCertSAFE); - - SafeHandleHolder shh1(&hStoreSAFE); - SafeHandleHolder shh2(&pCertSAFE); - - HCERTSTORE hCertStore = (HCERTSTORE) hStoreSAFE->GetHandle(); - CERT_CTX* pCert = CryptoHelper::DereferenceSafeHandle<CERT_CTX>(pCertSAFE); - - GCX_PREEMP(); - if (!CertAddCertificateLinkToStore(hCertStore, - pCert->m_pCtx, - CERT_STORE_ADD_ALWAYS, - NULL)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertAddCertificateContextToStore failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -// -// Exports a memory store of certificates into a byte array. -// - -FCIMPL3(U1Array*, COMX509Store::ExportCertificatesToBlob, SafeHandle* hStoreUNSAFE, DWORD dwContentType, __in_z WCHAR* pwszPassword) -{ - FCALL_CONTRACT; - - struct _gc - { - U1ARRAYREF pbBlob; - SAFEHANDLE hStoreSAFE; - } gc; - - gc.pbBlob = NULL; - gc.hStoreSAFE = (SAFEHANDLE) hStoreUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - - SafeHandleHolder shh(&gc.hStoreSAFE); - HCERTSTORE hCertStore = (HCERTSTORE) gc.hStoreSAFE->GetHandle(); - - HandleCertContextHolder pEnumContext(NULL); - NewArrayHolder<BYTE> pbEncoded(NULL); - DWORD dwSaveAs = CERT_STORE_SAVE_AS_PKCS7; - CRYPT_DATA_BLOB DataBlob = {0, NULL}; - - switch(dwContentType) { - case X509_CERT_TYPE: - pEnumContext = CertEnumCertificatesInStore(hCertStore, pEnumContext); - if (pEnumContext.GetValue() != NULL) - CryptoHelper::ByteArrayToU1ARRAYREF(pEnumContext->pbCertEncoded, - pEnumContext->cbCertEncoded, - &gc.pbBlob); - break; - - case X509_SERIALIZED_CERT_TYPE: - pEnumContext = CertEnumCertificatesInStore(hCertStore, pEnumContext); - if (pEnumContext.GetValue() != NULL) { - DWORD cbEncoded = 0; - if (!CertSerializeCertificateStoreElement(pEnumContext, - 0, - NULL, - &cbEncoded)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertSerializeCertificateStoreElement failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - pbEncoded = new BYTE[cbEncoded]; - if (!CertSerializeCertificateStoreElement(pEnumContext, - 0, - pbEncoded, - &cbEncoded)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertSerializeCertificateStoreElement failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - CryptoHelper::ByteArrayToU1ARRAYREF(pbEncoded, cbEncoded, &gc.pbBlob); - } - break; - - case X509_PFX_TYPE: - { - GCX_PREEMP(); - if (!PFXExportCertStore(hCertStore, - &DataBlob, - pwszPassword, - EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: PFXExportCertStorePFXExportCertStore failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - pbEncoded = new BYTE[DataBlob.cbData]; - DataBlob.pbData = pbEncoded; - if (!PFXExportCertStore(hCertStore, - &DataBlob, - pwszPassword, - EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: PFXExportCertStorePFXExportCertStore failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - } - CryptoHelper::ByteArrayToU1ARRAYREF(DataBlob.pbData, DataBlob.cbData, &gc.pbBlob); - break; - - case X509_SERIALIZED_STORE_TYPE: - dwSaveAs = CERT_STORE_SAVE_AS_STORE; - // falling through - case X509_PKCS7_TYPE: - { - GCX_PREEMP(); - // determine the required length - if (!CertSaveStore(hCertStore, - X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - dwSaveAs, - CERT_STORE_SAVE_TO_MEMORY, - (void *) &DataBlob, - 0)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertSaveStore failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - pbEncoded = new BYTE[DataBlob.cbData]; - DataBlob.pbData = pbEncoded; - // now save the store to a memory blob - if (!CertSaveStore(hCertStore, - X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - dwSaveAs, - CERT_STORE_SAVE_TO_MEMORY, - (void *) &DataBlob, - 0)) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertSaveStore failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - } - CryptoHelper::ByteArrayToU1ARRAYREF(DataBlob.pbData, DataBlob.cbData, &gc.pbBlob); - break; - - default: - COMPlusThrow(kCryptographicException, W("Cryptography_X509_InvalidContentType")); - } - - HELPER_METHOD_FRAME_END(); - return (U1Array*) OBJECTREFToObject(gc.pbBlob); -} -FCIMPLEND - -// -// Free an HCERTSTORE handle. Critical finalizer method for SafeCertStoreHandle. -// - -FCIMPL1(void, COMX509Store::FreeCertStoreContext, INT_PTR hCertStore) -{ - FCALL_CONTRACT; - - HELPER_METHOD_FRAME_BEGIN_0(); - - BOOL bRet = TRUE; - HCERTSTORE hStore = (HCERTSTORE) hCertStore; - if (hStore) - bRet = CertCloseStore(hStore, 0); - - // Add this assert to debug failures to free resources - _ASSERTE(bRet); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -// -// Open a certificate store. -// - -FCIMPL4(void, COMX509Store::OpenX509Store, DWORD dwType, DWORD dwFlags, StringObject* storeNameUNSAFE, SafeHandle** phStoreUNSAFE) -{ - FCALL_CONTRACT; - - STRINGREF storeNameSAFE = (STRINGREF) storeNameUNSAFE; - SAFEHANDLE hStoreSAFE = (SAFEHANDLE) *phStoreUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_2(storeNameSAFE, hStoreSAFE); - - NewArrayHolder<WCHAR> pwszStoreName(NULL); - if (storeNameSAFE != NULL) { - DWORD dwSize = storeNameSAFE->GetStringLength(); - if (dwSize > 0) - pwszStoreName = CryptoHelper::STRINGREFToUnicode(storeNameSAFE); - } - - HCERTSTORE hCertStore = NULL; - { - GCX_PREEMP(); - hCertStore = CertOpenStore((LPCSTR)(size_t)dwType, - X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - NULL, - dwFlags | CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, - pwszStoreName); - if (hCertStore == NULL) { - LOG((LF_SECURITY, LL_INFO10000, "Error [%#x]: CertOpenStore failed.\n", HRESULT_FROM_GetLastError())); - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - } - } - - hStoreSAFE->SetHandle(hCertStore); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -// COMX509Store::RemoveCertificate is an FCALL that is not consumed by managed code -// nor is it referred to by native code. This #ifdef makes it be dead code, which it -// would otherwise not be and require CertFindCertificateInStore, which is otherwise -// not required, and thus does not need to get implemented in the PAL. - -// -// Remove a certificate from the store. -// Removed certificates are not persisted for non-system stores. -// - -FCIMPL2(void, COMX509Store::RemoveCertificate, SafeHandle* hStoreUNSAFE, SafeHandle* pCertUNSAFE) -{ - FCALL_CONTRACT; - - SAFEHANDLE hStoreSAFE = (SAFEHANDLE) hStoreUNSAFE; - SAFEHANDLE pCertSAFE = (SAFEHANDLE) pCertUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_2(hStoreSAFE, pCertSAFE); - - SafeHandleHolder shh1(&hStoreSAFE); - SafeHandleHolder shh2(&pCertSAFE); - - HCERTSTORE hCertStore = (HCERTSTORE) hStoreSAFE->GetHandle(); - CERT_CTX* pCert = CryptoHelper::DereferenceSafeHandle<CERT_CTX>(pCertSAFE); - - // Find the certificate in the store. - PCCERT_CONTEXT pCert2 = NULL; - if ((pCert2 = CertFindCertificateInStore(hCertStore, - X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - 0, - CERT_FIND_EXISTING, - (const void *) pCert->m_pCtx, - NULL)) == NULL) - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - // Remove from the store. - if (!CertDeleteCertificateFromStore(pCert2)) - // CertDeleteCertificateFromStore always releases the context regardless of success - // or failure so we don't need to manually release it - CryptoHelper::COMPlusThrowCrypto(HRESULT_FROM_GetLastError()); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND -#endif // !FEATURE_CORECLR - -#endif // FEATURE_X509 diff --git a/src/classlibnative/cryptography/x509certificate.h b/src/classlibnative/cryptography/x509certificate.h deleted file mode 100644 index 3f0dd20b26..0000000000 --- a/src/classlibnative/cryptography/x509certificate.h +++ /dev/null @@ -1,165 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -//+-------------------------------------------------------------------------- -// - -// -//--------------------------------------------------------------------------- -// - -// - - -#ifndef _X509CERTIFICATE_H_ -#define _X509CERTIFICATE_H_ - -#include "cryptography.h" - -#define CERT_DELETE_KEYSET_PROP_ID 101 // This value shall be defined in wincrypt.h later to avoid conflicts. - -#if defined(FEATURE_CORECLR) -#define X509_CERT_CONTENT_FLAGS CERT_QUERY_CONTENT_FLAG_CERT -#define X509_CERT_FORMAT_FLAGS CERT_QUERY_FORMAT_FLAG_BINARY -#else // !FEATURE_CORECLR -#define X509_CERT_CONTENT_FLAGS (\ - CERT_QUERY_CONTENT_FLAG_CERT | CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT | \ - CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED | \ - CERT_QUERY_CONTENT_FLAG_PFX) -#define X509_CERT_FORMAT_FLAGS CERT_QUERY_FORMAT_FLAG_ALL -#endif // (FEATURE_CORECLR) else - -FORCEINLINE void VoidCertFreeCertificateContext(PCCERT_CONTEXT pCert) { LIMITED_METHOD_CONTRACT; CertFreeCertificateContext(pCert); } -FORCEINLINE void VoidCertCloseStore(HCERTSTORE hCertStore) { LIMITED_METHOD_CONTRACT; CertCloseStore(hCertStore, 0); } -FORCEINLINE void VoidCryptMsgClose(HCRYPTMSG hCryptMsg) { LIMITED_METHOD_CONTRACT; CryptMsgClose(hCryptMsg); } -#if !defined(FEATURE_CORECLR) -FORCEINLINE void VoidCertFreeCertificateChain(PCCERT_CHAIN_CONTEXT pChainContext) { LIMITED_METHOD_CONTRACT; CertFreeCertificateChain(pChainContext); } -#endif // !FEATURE_CORECLR - -typedef Wrapper<PCCERT_CONTEXT, DoNothing<PCCERT_CONTEXT>, VoidCertFreeCertificateContext, 0> HandleCertContextHolder; -typedef Wrapper<HCERTSTORE, DoNothing<HCERTSTORE>, VoidCertCloseStore, 0> HandleCertStoreHolder; -typedef Wrapper<HCRYPTMSG, DoNothing<HCRYPTMSG>, VoidCryptMsgClose, 0> HandleCryptMsgHolder; -#if !defined(FEATURE_CORECLR) -typedef Wrapper<PCCERT_CHAIN_CONTEXT, DoNothing<PCCERT_CHAIN_CONTEXT>, VoidCertFreeCertificateChain, 0> HandleCertChainHolder; -#endif // !FEATURE_CORECLR - -class X509Helper { -public: -#if !defined(FEATURE_CORECLR) - static HRESULT BuildChain (PCCERT_CONTEXT pCertContext, HCERTSTORE hCertStore, - LPCSTR pszPolicy, PCCERT_CHAIN_CONTEXT * ppChainContext); - static HRESULT DecodeObject(LPCSTR pszStructType, LPBYTE pbEncoded, - DWORD cbEncoded, void** ppvDecoded, DWORD* pcbDecoded); - static BOOL DeleteKeyContainer (PCCERT_CONTEXT pCertContext); -#endif // !FEATURE_CORECLR - static DWORD LoadFromBlob (CERT_BLOB* pCertBlob, __in_opt WCHAR* pwszPassword, DWORD dwFlags, - PCCERT_CONTEXT* pCertContext, HCERTSTORE* phCertStore, HCRYPTMSG* phCryptMsg); - static DWORD LoadFromFile (__in_z WCHAR* pwszFileName, __in_opt WCHAR* pwszPassword, DWORD dwFlags, - PCCERT_CONTEXT* pCertContext, HCERTSTORE* phCertStore, HCRYPTMSG* phCryptMsg); - static HRESULT ReadFileIntoMemory(LPCWSTR wszFileName, LPBYTE* ppbBuffer, DWORD* pdwBufLen); -}; - -class COMX509Certificate { -private: -#if !defined(FEATURE_CORECLR) - static PCCERT_CONTEXT FilterPFXStore (CERT_BLOB* pfxBlob, __in_z WCHAR* pwszPassword, DWORD dwFlags); -#endif // !FEATURE_CORECLR - static WCHAR* GetCertNameInfo(PCCERT_CONTEXT pCertContext, DWORD dwNameType, DWORD dwDisplayType, DWORD dwStrType); -#if !defined(FEATURE_CORECLR) - static PCCERT_CONTEXT GetSignerInPKCS7Store (HCERTSTORE hCertStore, HCRYPTMSG hCryptMsg); -#endif // !FEATURE_CORECLR - -public: - static FCDECL2(void, DuplicateCertContext, INT_PTR handle, SafeHandle** ppCertUNSAFE); - static FCDECL1(void, FreePCertContext, INT_PTR pCertCtx); - static FCDECL1(U1Array*, GetCertRawData, SafeHandle* pCertUNSAFE); - static FCDECL2(void, GetDateNotAfter, SafeHandle* pCertUNSAFE, FILETIME* pFileTime); - static FCDECL2(void, GetDateNotBefore, SafeHandle* pCertUNSAFE, FILETIME* pFileTime); - static FCDECL2(StringObject*, GetIssuerName, SafeHandle* pCertUNSAFE, CLR_BOOL fLegacyV1Mode); - static FCDECL1(StringObject*, GetPublicKeyOid, SafeHandle* pCertUNSAFE); - static FCDECL1(U1Array*, GetPublicKeyParameters, SafeHandle* pCertUNSAFE); - static FCDECL1(U1Array*, GetPublicKeyValue, SafeHandle* pCertUNSAFE); - static FCDECL1(U1Array*, GetSerialNumber, SafeHandle* pCertUNSAFE); - static FCDECL3(StringObject*, GetSubjectInfo, SafeHandle* pCertUNSAFE, DWORD dwDisplayType, CLR_BOOL fLegacyV1Mode); - static FCDECL1(U1Array*, GetThumbprint, SafeHandle* pCertUNSAFE); - static FCDECL5(void, LoadCertFromBlob, U1Array* dataUNSAFE, __in_z WCHAR* pwszPassword, DWORD dwFlags, CLR_BOOL persistKeySet, SafeHandle** ppCertUNSAFE); - static FCDECL5(void, LoadCertFromFile, StringObject* fileNameUNSAFE, __in_z WCHAR* pwszPassword, DWORD dwFlags, CLR_BOOL persistKeySet, SafeHandle** ppCertUNSAFE); - static FCDECL1(DWORD, QueryCertBlobType, U1Array* dataUNSAFE); - static FCDECL1(DWORD, QueryCertFileType, StringObject* fileNameUNSAFE); -}; - -#define X509_STORE_CONTENT_FLAGS (\ - CERT_QUERY_CONTENT_FLAG_CERT | CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT | \ - CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED | \ - CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED | CERT_QUERY_CONTENT_FLAG_PFX | \ - CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE) - -#define NULL_ASN_TAG 0x05 - -// Keep in sync with System.Security.Cryptography.X509Certificates.X509ContentType -enum X509_ASSERTION_CONTENT_TYPE { - UNKNOWN_TYPE = 0x00, - X509_CERT_TYPE = 0x01, - X509_SERIALIZED_CERT_TYPE = 0x02, - X509_PFX_TYPE = 0x03, - X509_SERIALIZED_STORE_TYPE = 0x04, - X509_PKCS7_TYPE = 0x05, - X509_AUTHENTICODE_TYPE = 0x06 -}; - -// We need to define this unmanaged memory structure to hold -// all the information relevant to the cert context in order to guarantee -// critical finalization of the resources -typedef struct CERT_CTX { -public: - PCCERT_CONTEXT m_pCtx; -#if !defined(FEATURE_CORECLR) - BOOL m_fDelKeyContainer; -#endif // !FEATURE_CORECLR - - CERT_CTX(PCCERT_CONTEXT pCertContext) : - m_pCtx(pCertContext) -#if !defined(FEATURE_CORECLR) - ,m_fDelKeyContainer(FALSE) -#endif // !FEATURE_CORECLR - { - LIMITED_METHOD_CONTRACT; - } - - // This method should not be called twice. - BOOL Release () { - WRAPPER_NO_CONTRACT; -#if !defined(FEATURE_CORECLR) - if (m_fDelKeyContainer) - X509Helper::DeleteKeyContainer(m_pCtx); -#endif // !FEATURE_CORECLR - - // We need to free the cert context. - if (m_pCtx != NULL) - if (!CertFreeCertificateContext(m_pCtx)) - return FALSE; - - m_pCtx = 0; - delete this; - return TRUE; - } - -} CERT_CTX; - -#ifndef FEATURE_CORECLR -class COMX509Store { -public: - static FCDECL2(void, AddCertificate, SafeHandle* hStoreUNSAFE, SafeHandle* pCertUNSAFE); - static FCDECL3(U1Array*, ExportCertificatesToBlob, SafeHandle* hStoreUNSAFE, DWORD dwContentType, __in_z WCHAR* pwszPassword); - static FCDECL1(void, FreeCertStoreContext, INT_PTR hCertStore); - static FCDECL4(void, OpenX509Store, DWORD dwType, DWORD dwFlags, StringObject* storeNameUNSAFE, SafeHandle** phStoreUNSAFE); - // RemoveCertificate is an FCALL that is not consumed by managed code - // nor is it referred to by native code. This #ifdef makes it be dead code, which it - // would otherwise not be and require CertFindCertificateInStore, which is otherwise - // not required, and thus does not need to get implemented in the PAL. - static FCDECL2(void, RemoveCertificate, SafeHandle* hStoreUNSAFE, SafeHandle* pCertUNSAFE); -}; -#endif // !FEATURE_CORECLR - -#endif // !_X509CERTIFICATE_H_ |