From 2784652ab880dcea82aa212096b64d39695012fc Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Sun, 5 Apr 2015 22:21:59 +0200 Subject: Windows vulnerability fix: CryptAcquireContext vulnerability fix. Add checks to random generator to abort in case of error and display a diagnose message to the user. --- src/Common/BootEncryption.cpp | 25 ++++++++++++++++--- src/Common/Dlgcode.c | 36 +++++++++++++++++++++++---- src/Common/Dlgcode.h | 1 + src/Common/Exception.h | 33 ++++++++++++++++++++++++ src/Common/Language.xml | 3 ++- src/Common/Password.c | 6 +++++ src/Common/Random.c | 58 +++++++++++++++++++++++++++++++++++-------- src/Common/Random.h | 1 + src/Common/Tcdefs.h | 4 ++- 9 files changed, 147 insertions(+), 20 deletions(-) (limited to 'src/Common') diff --git a/src/Common/BootEncryption.cpp b/src/Common/BootEncryption.cpp index c01a8b4b..ae57dc37 100644 --- a/src/Common/BootEncryption.cpp +++ b/src/Common/BootEncryption.cpp @@ -1383,7 +1383,12 @@ namespace VeraCrypt request.WipeAlgorithm = wipeAlgorithm; if (Randinit() != ERR_SUCCESS) - throw ParameterIncorrect (SRC_POS); + { + if (CryptoAPILastError == ERROR_SUCCESS) + throw RandInitFailed (SRC_POS, GetLastError ()); + else + throw CryptoApiFailed (SRC_POS, CryptoAPILastError); + } /* force the display of the random enriching dialog */ SetRandomPoolEnrichedByUserStatus (FALSE); @@ -1421,9 +1426,17 @@ namespace VeraCrypt void BootEncryption::WipeHiddenOSCreationConfig () { - if (IsHiddenOSRunning() || Randinit() != ERR_SUCCESS) + if (IsHiddenOSRunning()) throw ParameterIncorrect (SRC_POS); + if (Randinit() != ERR_SUCCESS) + { + if (CryptoAPILastError == ERROR_SUCCESS) + throw RandInitFailed (SRC_POS, GetLastError ()); + else + throw CryptoApiFailed (SRC_POS, CryptoAPILastError); + } + Device device (GetSystemDriveConfiguration().DevicePath); device.CheckOpened(); byte mbr[TC_SECTOR_SIZE_BIOS]; @@ -2280,7 +2293,13 @@ namespace VeraCrypt RandSetHashFunction (pkcs5); } - throw_sys_if (Randinit () != 0); + if (Randinit() != 0) + { + if (CryptoAPILastError == ERROR_SUCCESS) + throw RandInitFailed (SRC_POS, GetLastError ()); + else + throw CryptoApiFailed (SRC_POS, CryptoAPILastError); + } finally_do ({ RandStop (FALSE); }); /* force the display of the random enriching dialog */ diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c index 5f5d2216..94b1fc05 100644 --- a/src/Common/Dlgcode.c +++ b/src/Common/Dlgcode.c @@ -461,11 +461,11 @@ int RemoveFakeDosName (char *lpszDiskFile, char *lpszDosDevice) } -void AbortProcess (char *stringId) +void AbortProcessDirect (wchar_t *abortMsg) { // Note that this function also causes localcleanup() to be called (see atexit()) MessageBeep (MB_ICONEXCLAMATION); - MessageBoxW (NULL, GetString (stringId), lpszTitle, ICON_HAND); + MessageBoxW (NULL, abortMsg, lpszTitle, ICON_HAND); if (hRichEditDll) { FreeLibrary (hRichEditDll); @@ -474,6 +474,12 @@ void AbortProcess (char *stringId) exit (1); } +void AbortProcess (char *stringId) +{ + // Note that this function also causes localcleanup() to be called (see atexit()) + AbortProcessDirect (GetString (stringId)); +} + void AbortProcessSilent (void) { if (hRichEditDll) @@ -4076,6 +4082,18 @@ void handleError (HWND hwndDlg, int code) MessageBoxW (hwndDlg, szTmp, lpszTitle, ICON_HAND); break; +#ifndef SETUP + case ERR_RAND_INIT_FAILED: + StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("INIT_RAND"), SRC_POS, GetLastError ()); + MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_ICONERROR); + break; + + case ERR_CAPI_INIT_FAILED: + StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("CAPI_RAND"), SRC_POS, CryptoAPILastError); + MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_ICONERROR); + break; +#endif + default: StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("ERR_UNKNOWN"), code); MessageBoxW (hwndDlg, szTmp, lpszTitle, ICON_HAND); @@ -5009,7 +5027,10 @@ exit: return 0; } - +/* Randinit is always called before UserEnrichRandomPool, so we don't need + * the extra Randinit call here since it will always succeed but we keep it + * for clarity purposes + */ void UserEnrichRandomPool (HWND hwndDlg) { if ((0 == Randinit()) && !IsRandomPoolEnrichedByUser()) @@ -5060,7 +5081,7 @@ BOOL CALLBACK KeyfileGeneratorDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LP #ifndef VOLFORMAT if (Randinit ()) { - Error ("INIT_RAND", hwndDlg); + handleError (hwndDlg, (CryptoAPILastError == ERROR_SUCCESS)? ERR_RAND_INIT_FAILED : ERR_CAPI_INIT_FAILED); EndDialog (hwndDlg, IDCLOSE); } #endif @@ -9236,7 +9257,12 @@ int ReEncryptVolumeHeader (HWND hwndDlg, char *buffer, BOOL bBoot, CRYPTO_INFO * RandSetHashFunction (cryptoInfo->pkcs5); if (Randinit() != ERR_SUCCESS) - return ERR_PARAMETER_INCORRECT; + { + if (CryptoAPILastError == ERROR_SUCCESS) + return ERR_RAND_INIT_FAILED; + else + return ERR_CAPI_INIT_FAILED; + } UserEnrichRandomPool (NULL); diff --git a/src/Common/Dlgcode.h b/src/Common/Dlgcode.h index 8f6314eb..96d5e865 100644 --- a/src/Common/Dlgcode.h +++ b/src/Common/Dlgcode.h @@ -226,6 +226,7 @@ void UpperCaseCopy ( char *lpszDest , size_t cbDest, const char *lpszSource ); void CreateFullVolumePath ( char *lpszDiskFile , size_t cbDiskFile, const char *lpszFileName , BOOL *bDevice ); int FakeDosNameForDevice ( const char *lpszDiskFile , char *lpszDosDevice , size_t cbDosDevice, char *lpszCFDevice , size_t cbCFDevice, BOOL bNameOnly ); int RemoveFakeDosName ( char *lpszDiskFile , char *lpszDosDevice ); +void AbortProcessDirect ( wchar_t *abortMsg ); void AbortProcess ( char *stringId ); void AbortProcessSilent ( void ); void *err_malloc ( size_t size ); diff --git a/src/Common/Exception.h b/src/Common/Exception.h index e5d4fd4c..0883df14 100644 --- a/src/Common/Exception.h +++ b/src/Common/Exception.h @@ -11,6 +11,7 @@ #include "Platform/PlatformBase.h" #include "Dlgcode.h" +#include namespace VeraCrypt { @@ -62,6 +63,38 @@ namespace VeraCrypt const char *SrcPos; }; + struct RandInitFailed : public Exception + { + RandInitFailed (const char *srcPos, DWORD dwLastError) : SrcPos (srcPos), LastError (dwLastError) { } + + void Show (HWND parent) const + { + char szErrCode[16]; + StringCbPrintf (szErrCode, sizeof(szErrCode), "0x%.8X", LastError); + string msgBody = "The Random Generator initialization failed.\n\n\n(If you report a bug in connection with this, please include the following technical information in the bug report:\n" + string (SrcPos) + "\nLast Error = " + string (szErrCode) + ")"; + MessageBox (parent, msgBody.c_str(), "VeraCrypt", MB_ICONERROR | MB_SETFOREGROUND); + } + + const char *SrcPos; + DWORD LastError; + }; + + struct CryptoApiFailed : public Exception + { + CryptoApiFailed (const char *srcPos, DWORD dwLastError) : SrcPos (srcPos), LastError (dwLastError) { } + + void Show (HWND parent) const + { + char szErrCode[16]; + StringCbPrintf (szErrCode, sizeof(szErrCode), "0x%.8X", LastError); + string msgBody = "Windows Crypto API failed.\n\n\n(If you report a bug in connection with this, please include the following technical information in the bug report:\n" + string (SrcPos) + "\nLast Error = " + string (szErrCode) + ")"; + MessageBox (parent, msgBody.c_str(), "VeraCrypt", MB_ICONERROR | MB_SETFOREGROUND); + } + + const char *SrcPos; + DWORD LastError; + }; + struct TimeOut : public Exception { TimeOut (const char *srcPos) { } diff --git a/src/Common/Language.xml b/src/Common/Language.xml index c149b679..c4d93f22 100644 --- a/src/Common/Language.xml +++ b/src/Common/Language.xml @@ -526,7 +526,8 @@ Your computer must be restarted.\n\nDo you want to restart it now? An error occurred when obtaining the system encryption status. Cannot initialize application components for system encryption. - Failed to initialize the random number generator! + Failed to initialize the random number generator!\n\n\n(If you report a bug in connection with this, please include the following technical information in the bug report:\n%hs, Last Error = 0x%.8X) + Windows Crypto API failed!\n\n\n(If you report a bug in connection with this, please include the following technical information in the bug report:\n%hs, Last Error = 0x%.8X) Unable to initialize the application. Failed to register the Dialog class. Error: Failed to load the Rich Edit system library. VeraCrypt Volume Creation Wizard diff --git a/src/Common/Password.c b/src/Common/Password.c index b1584dbe..8014713c 100644 --- a/src/Common/Password.c +++ b/src/Common/Password.c @@ -230,7 +230,13 @@ int ChangePwd (const char *lpszVolume, Password *oldPassword, int old_pkcs5, BOO } if (Randinit ()) + { + if (CryptoAPILastError == ERROR_SUCCESS) + nStatus = ERR_RAND_INIT_FAILED; + else + nStatus = ERR_CAPI_INIT_FAILED; goto error; + } SetRandomPoolEnrichedByUserStatus (FALSE); /* force the display of the random enriching dialog */ diff --git a/src/Common/Random.c b/src/Common/Random.c index e8433c27..ae91f2da 100644 --- a/src/Common/Random.c +++ b/src/Common/Random.c @@ -60,12 +60,14 @@ HANDLE hNetAPI32 = NULL; // CryptoAPI BOOL CryptoAPIAvailable = FALSE; +DWORD CryptoAPILastError = ERROR_SUCCESS; HCRYPTPROV hCryptProv; /* Init the random number generator, setup the hooks, and start the thread */ int Randinit () { + DWORD dwLastError = ERROR_SUCCESS; if (GetMaxPkcs5OutSize() > RNG_POOL_SIZE) TC_THROW_FATAL_EXCEPTION; @@ -75,6 +77,7 @@ int Randinit () InitializeCriticalSection (&critRandProt); bRandDidInit = TRUE; + CryptoAPILastError = ERROR_SUCCESS; if (pRandPool == NULL) { @@ -98,10 +101,13 @@ int Randinit () handleWin32Error (0); goto error; } - - if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0) - && !CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) + + if (!CryptAcquireContext (&hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + { CryptoAPIAvailable = FALSE; + CryptoAPILastError = GetLastError (); + goto error; + } else CryptoAPIAvailable = TRUE; @@ -111,7 +117,9 @@ int Randinit () return 0; error: + dwLastError = GetLastError(); RandStop (TRUE); + SetLastError (dwLastError); return 1; } @@ -149,6 +157,7 @@ void RandStop (BOOL freePool) { CryptReleaseContext (hCryptProv, 0); CryptoAPIAvailable = FALSE; + CryptoAPILastError = ERROR_SUCCESS; } hMouse = NULL; @@ -359,13 +368,19 @@ BOOL RandgetBytesFull ( void* hwndDlg, unsigned char *buf , int len, BOOL forceS if (bDidSlowPoll == FALSE || forceSlowPoll) { if (!SlowPoll ()) + { + handleError ((HWND) hwndDlg, ERR_CAPI_INIT_FAILED); ret = FALSE; + } else bDidSlowPoll = TRUE; } if (!FastPoll ()) + { + handleError ((HWND) hwndDlg, ERR_CAPI_INIT_FAILED); ret = FALSE; + } /* There's never more than RNG_POOL_SIZE worth of randomess */ if ( (!allowAnyLength) && (len > RNG_POOL_SIZE)) @@ -692,13 +707,24 @@ BOOL SlowPoll (void) CloseHandle (hDevice); } - // CryptoAPI - if (CryptoAPIAvailable && CryptGenRandom (hCryptProv, sizeof (buffer), buffer)) + // CryptoAPI: We always have a valid CryptoAPI context when we arrive here but + // we keep the check for clarity purpose + if ( !CryptoAPIAvailable ) + return FALSE; + if (CryptGenRandom (hCryptProv, sizeof (buffer), buffer)) + { RandaddBuf (buffer, sizeof (buffer)); - burn(buffer, sizeof (buffer)); - Randmix(); - return TRUE; + burn(buffer, sizeof (buffer)); + Randmix(); + return TRUE; + } + else + { + /* return error in case CryptGenRandom fails */ + CryptoAPILastError = GetLastError (); + return FALSE; + } } @@ -803,9 +829,21 @@ BOOL FastPoll (void) RandaddBuf ((unsigned char *) &dwTicks, sizeof (dwTicks)); } - // CryptoAPI - if (CryptoAPIAvailable && CryptGenRandom (hCryptProv, sizeof (buffer), buffer)) + // CryptoAPI: We always have a valid CryptoAPI context when we arrive here but + // we keep the check for clarity purpose + if ( !CryptoAPIAvailable ) + return FALSE; + if (CryptGenRandom (hCryptProv, sizeof (buffer), buffer)) + { RandaddBuf (buffer, sizeof (buffer)); + burn (buffer, sizeof(buffer)); + } + else + { + /* return error in case CryptGenRandom fails */ + CryptoAPILastError = GetLastError (); + return FALSE; + } /* Apply the pool mixing function */ Randmix(); diff --git a/src/Common/Random.h b/src/Common/Random.h index 72427e07..65e793fa 100644 --- a/src/Common/Random.h +++ b/src/Common/Random.h @@ -58,6 +58,7 @@ BOOL RandgetBytesFull ( void* hwndDlg, unsigned char *buf , int len, BOOL forceS extern BOOL volatile bFastPollEnabled; extern BOOL volatile bRandmixEnabled; +extern DWORD CryptoAPILastError; LRESULT CALLBACK MouseProc ( int nCode , WPARAM wParam , LPARAM lParam ); LRESULT CALLBACK KeyboardProc ( int nCode , WPARAM wParam , LPARAM lParam ); diff --git a/src/Common/Tcdefs.h b/src/Common/Tcdefs.h index e177e02c..63dff857 100644 --- a/src/Common/Tcdefs.h +++ b/src/Common/Tcdefs.h @@ -301,7 +301,9 @@ enum ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG = 31, ERR_NONSYS_INPLACE_ENC_INCOMPLETE = 32, ERR_USER_ABORT = 33, - ERR_UNSUPPORTED_TRUECRYPT_FORMAT = 34 + ERR_UNSUPPORTED_TRUECRYPT_FORMAT = 34, + ERR_RAND_INIT_FAILED = 35, + ERR_CAPI_INIT_FAILED = 36 }; #endif // #ifndef TCDEFS_H -- cgit v1.2.3