diff --git a/src/Main/Forms/MountOptionsDialog.cpp b/src/Main/Forms/MountOptionsDialog.cpp index 23911c9c..17bd7a1b 100644 --- a/src/Main/Forms/MountOptionsDialog.cpp +++ b/src/Main/Forms/MountOptionsDialog.cpp @@ -33,7 +33,7 @@ namespace VeraCrypt #ifdef __WXGTK__ // GTK apparently needs wxRESIZE_BORDER to support dynamic resizing , wxDefaultPosition, wxSize (-1,-1), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER #endif - ), Options (options) + ), Options (options), ProtectionRecovery (false) #ifdef TC_UNIX , m_showRedBorder(false) #endif @@ -79,6 +79,7 @@ namespace VeraCrypt NoFilesystemCheckBox->SetValidator (wxGenericValidator (&Options.NoFilesystem)); RemovableCheckBox->SetValidator (wxGenericValidator (&Options.Removable)); PartitionInSystemEncryptionScopeCheckBox->SetValidator (wxGenericValidator (&Options.PartitionInSystemEncryptionScope)); + BackupHeaderCheckBox->SetValidator (wxGenericValidator (&Options.UseBackupHeaders)); TransferDataToWindow(); @@ -88,14 +89,16 @@ namespace VeraCrypt FilesystemOptionsTextCtrl->SetValue (Options.FilesystemOptions); ReadOnlyCheckBox->SetValue (Options.Protection == VolumeProtection::ReadOnly); - BackupHeaderCheckBox->SetValidator (wxGenericValidator (&Options.UseBackupHeaders)); ProtectionCheckBox->SetValue (Options.Protection == VolumeProtection::HiddenVolumeReadOnly); OptionsButtonLabel = OptionsButton->GetLabel(); OptionsButton->SetLabel (OptionsButtonLabel + L" >"); OptionsPanel->Show (false); - ProtectionPasswordPanel = new VolumePasswordPanel (ProtectionSizer->GetStaticBox(), &options, options.ProtectionPassword, options.ProtectionKeyfiles, false, true, true, false, true, true, LangString["IDT_HIDDEN_PROT_PASSWD"]); + MountOptions protectionOptions; + protectionOptions.Pim = options.ProtectionPim; + protectionOptions.Kdf = options.ProtectionKdf; + ProtectionPasswordPanel = new VolumePasswordPanel (ProtectionSizer->GetStaticBox(), &protectionOptions, options.ProtectionPassword, options.ProtectionKeyfiles, false, true, true, false, true, true, LangString["IDT_HIDDEN_PROT_PASSWD"]); ProtectionPasswordPanel->TopOwnerParent = this; ProtectionPasswordSizer->Add (ProtectionPasswordPanel, 1, wxALL | wxEXPAND); @@ -105,7 +108,25 @@ namespace VeraCrypt void MountOptionsDialog::OnInitDialog (wxInitDialogEvent& event) { - PasswordPanel->SetFocusToPasswordTextCtrl(); + if (ProtectionRecovery) + ProtectionPasswordPanel->SetFocusToPasswordTextCtrl(); + else + PasswordPanel->SetFocusToPasswordTextCtrl(); + } + + void MountOptionsDialog::SetProtectionRecovery (bool recovery) + { + if (recovery && !ProtectionRecovery) + PasswordPanel->SetPasswordVisible (false); + ProtectionRecovery = recovery; + PasswordPanel->Enable (!recovery); + if (recovery) + { + BackupHeaderCheckBox->SetValue (Options.UseBackupHeaders); + OptionsPanel->Show (true); + OptionsButton->SetLabel (OptionsButtonLabel + L" <"); + UpdateDialog(); + } } void MountOptionsDialog::OnMountPointButtonClick (wxCommandEvent& event) @@ -118,12 +139,12 @@ namespace VeraCrypt void MountOptionsDialog::OnOKButtonClick (wxCommandEvent& event) { /* verify that PIM values are valid before continuing*/ - int Pim = PasswordPanel->GetVolumePim(); + int Pim = ProtectionRecovery ? Options.Pim : PasswordPanel->GetVolumePim(); int ProtectionPim = (!ReadOnlyCheckBox->IsChecked() && ProtectionCheckBox->IsChecked())? ProtectionPasswordPanel->GetVolumePim() : 0; /* invalid PIM: set focus to PIM field and stop processing */ - if (-1 == Pim || (PartitionInSystemEncryptionScopeCheckBox->IsChecked() && Pim > MAX_BOOT_PIM_VALUE)) + if (!ProtectionRecovery && (-1 == Pim || (PartitionInSystemEncryptionScopeCheckBox->IsChecked() && Pim > MAX_BOOT_PIM_VALUE))) { PasswordPanel->SetFocusToPimTextCtrl(); return; @@ -137,25 +158,28 @@ namespace VeraCrypt TransferDataFromWindow(); - try + if (!ProtectionRecovery) { - Options.Password = PasswordPanel->GetPassword(Options.PartitionInSystemEncryptionScope); + try + { + Options.Password = PasswordPanel->GetPassword(Options.PartitionInSystemEncryptionScope); + } + catch (PasswordException& e) + { + Gui->ShowWarning (e); + return; + } + + if (Options.PartitionInSystemEncryptionScope && Options.Password->Size() > VolumePassword::MaxLegacySize) + { + Gui->ShowWarning (StringFormatter (LangString["LINUX_SYSTEM_ENC_PW_LENGTH_NOTE"], (int) VolumePassword::MaxLegacySize)); + return; + } + + Options.Pim = Pim; + Options.Kdf = PasswordPanel->GetPkcs5Kdf(); + Options.Keyfiles = PasswordPanel->GetKeyfiles(); } - catch (PasswordException& e) - { - Gui->ShowWarning (e); - return; - } - - if (Options.PartitionInSystemEncryptionScope && Options.Password->Size() > VolumePassword::MaxLegacySize) - { - Gui->ShowWarning (StringFormatter (LangString["LINUX_SYSTEM_ENC_PW_LENGTH_NOTE"], (int) VolumePassword::MaxLegacySize)); - return; - } - - Options.Pim = Pim; - Options.Kdf = PasswordPanel->GetPkcs5Kdf(); - Options.Keyfiles = PasswordPanel->GetKeyfiles(); if (ReadOnlyCheckBox->IsChecked()) { diff --git a/src/Main/Forms/MountOptionsDialog.h b/src/Main/Forms/MountOptionsDialog.h index c4814b2f..375d9fe4 100644 --- a/src/Main/Forms/MountOptionsDialog.h +++ b/src/Main/Forms/MountOptionsDialog.h @@ -24,6 +24,7 @@ namespace VeraCrypt public: MountOptionsDialog (wxWindow* parent, MountOptions &options, const wxString &title = wxEmptyString, bool disableMountOptions = false); void OnShow (); + void SetProtectionRecovery (bool recovery); #ifdef TC_MACOSX virtual bool ProcessEvent(wxEvent& event); @@ -47,6 +48,7 @@ namespace VeraCrypt #endif MountOptions &Options; + bool ProtectionRecovery; #ifdef TC_UNIX bool m_showRedBorder; #endif diff --git a/src/Main/Forms/VolumePasswordPanel.cpp b/src/Main/Forms/VolumePasswordPanel.cpp index 2659de7a..6b9ccc13 100644 --- a/src/Main/Forms/VolumePasswordPanel.cpp +++ b/src/Main/Forms/VolumePasswordPanel.cpp @@ -401,16 +401,18 @@ namespace VeraCrypt } } - void VolumePasswordPanel::OnDisplayPasswordCheckBoxClick (wxCommandEvent& event) + void VolumePasswordPanel::SetPasswordVisible (bool visible) { + DisplayPasswordCheckBox->SetValue (visible); + if (PasswordTextCtrl->IsShown()) - DisplayPassword (event.IsChecked(), &PasswordTextCtrl, 1); + DisplayPassword (visible, &PasswordTextCtrl, 1); if (ConfirmPasswordTextCtrl->IsShown()) - DisplayPassword (event.IsChecked(), &ConfirmPasswordTextCtrl, 2); + DisplayPassword (visible, &ConfirmPasswordTextCtrl, 2); if (VolumePimTextCtrl->IsShown()) - DisplayPassword (event.IsChecked(), &VolumePimTextCtrl, 3); + DisplayPassword (visible, &VolumePimTextCtrl, 3); OnUpdate(); } diff --git a/src/Main/Forms/VolumePasswordPanel.h b/src/Main/Forms/VolumePasswordPanel.h index 48de7df9..00701976 100644 --- a/src/Main/Forms/VolumePasswordPanel.h +++ b/src/Main/Forms/VolumePasswordPanel.h @@ -37,6 +37,7 @@ namespace VeraCrypt void SetFocusToPimCheckBox () { PimCheckBox->SetFocus(); } void SetFocusToPimTextCtrl () { VolumePimTextCtrl->SetSelection (-1, -1); VolumePimTextCtrl->SetFocus(); } void ResetVolumePimToDefault (); + void SetPasswordVisible (bool visible); void SetVolumePim (int pim); bool PasswordsMatch () const; void EnableUsePim (bool pimOnlyDisplay = false); @@ -54,7 +55,7 @@ namespace VeraCrypt void OnAddKeyfileDirMenuItemSelected (wxCommandEvent& event); void OnAddKeyfilesMenuItemSelected (wxCommandEvent& event); void OnAddSecurityTokenSignatureMenuItemSelected (wxCommandEvent& event); - void OnDisplayPasswordCheckBoxClick (wxCommandEvent& event); + void OnDisplayPasswordCheckBoxClick (wxCommandEvent& event) { SetPasswordVisible (event.IsChecked()); } void OnKeyfilesButtonClick (wxCommandEvent& event); void OnKeyfilesButtonRightClick (wxMouseEvent& event); void OnKeyfilesButtonRightDown (wxMouseEvent& event); diff --git a/src/Main/GraphicUserInterface.cpp b/src/Main/GraphicUserInterface.cpp index 321a9396..053f215b 100644 --- a/src/Main/GraphicUserInterface.cpp +++ b/src/Main/GraphicUserInterface.cpp @@ -15,6 +15,7 @@ #ifdef TC_UNIX #include #include +#include #include #include #include @@ -905,6 +906,17 @@ namespace VeraCrypt } shared_ptr GraphicUserInterface::MountVolume (MountOptions &options, bool tryCachedPasswords) const + { + return MountVolumeInternal (options, tryCachedPasswords, false); + } + + shared_ptr GraphicUserInterface::MountVolumeWithProtectionRecovery (MountOptions &options, const PasswordException &protectionError) const + { + ShowWarning (protectionError); + return MountVolumeInternal (options, false, true); + } + + shared_ptr GraphicUserInterface::MountVolumeInternal (MountOptions &options, bool tryCachedPasswords, bool protectionRecovery) const { CheckRequirementsForMountingVolume(); @@ -937,7 +949,32 @@ namespace VeraCrypt try { - if (tryCachedPasswords + bool protectionError = protectionRecovery; + auto mountWithProtectionRecovery = [&] () -> shared_ptr + { + protectionError = false; + try + { + return UserInterface::MountVolume (options); + } + catch (ProtectionPasswordIncorrect &e) + { + ShowWarning (e); + } + catch (ProtectionPasswordKeyfilesIncorrect &e) + { + ShowWarning (e); + } + + protectionError = true; + // Keep the accepted outer credential source, including the password + // cache. An explicit empty list prevents default keyfiles being added. + if (!options.Keyfiles) + options.Keyfiles = make_shared (); + return shared_ptr (); + }; + + if (!protectionError && tryCachedPasswords && (!options.Password || options.Password->IsEmpty()) && (!options.Keyfiles || options.Keyfiles->empty()) && !Core->IsPasswordCacheEmpty()) @@ -946,21 +983,25 @@ namespace VeraCrypt try { wxBusyCursor busy; - return UserInterface::MountVolume (options); + volume = mountWithProtectionRecovery(); + if (volume) + return volume; } catch (PasswordException&) { } } - if (!options.Keyfiles && GetPreferences().UseKeyfiles && !GetPreferences().DefaultKeyfiles.empty()) + if (!protectionError && !options.Keyfiles && GetPreferences().UseKeyfiles && !GetPreferences().DefaultKeyfiles.empty()) options.Keyfiles = make_shared (GetPreferences().DefaultKeyfiles); - if ((options.Password && !options.Password->IsEmpty()) - || (options.Keyfiles && !options.Keyfiles->empty() && options.Password)) + if (!protectionError && ((options.Password && !options.Password->IsEmpty()) + || (options.Keyfiles && !options.Keyfiles->empty() && options.Password))) { try { wxBusyCursor busy; - return UserInterface::MountVolume (options); + volume = mountWithProtectionRecovery(); + if (volume) + return volume; } catch (PasswordException&) { } } @@ -970,17 +1011,54 @@ namespace VeraCrypt MountOptionsDialog dialog (GetTopWindow(), options); int incorrectPasswordCount = 0; + int incorrectProtectionPasswordCount = 0; + bool autoBackupHeaderUsed = false; while (!volume) { dialog.Hide(); + dialog.SetProtectionRecovery (protectionError); if (dialog.ShowModal() != wxID_OK) return volume; try { wxBusyCursor busy; - volume = UserInterface::MountVolume (options); + volume = mountWithProtectionRecovery(); + + if (!volume && protectionError && !options.UseBackupHeaders + && ++incorrectProtectionPasswordCount > 2) + { + // The outer primary header was accepted, but the hidden primary + // header may be damaged. Try the backups once for this attempt. + options.UseBackupHeaders = true; + try + { + volume = UserInterface::MountVolume (options); + autoBackupHeaderUsed = true; + } + catch (PasswordException&) + { + // Keep recovering against the accepted primary outer header. + options.UseBackupHeaders = false; + } +#ifdef TC_UNIX + catch (SystemException &e) + { + options.UseBackupHeaders = false; + if (e.GetErrorCode() != EIO) + throw; + + // An unreadable backup must not prevent another primary-header attempt. + ShowWarning (e); + } +#endif + catch (...) + { + options.UseBackupHeaders = false; + throw; + } + } } catch (PasswordIncorrect &e) { @@ -988,15 +1066,16 @@ namespace VeraCrypt { // Try to mount the volume using the backup header options.UseBackupHeaders = true; + autoBackupHeaderUsed = true; try { - volume = UserInterface::MountVolume (options); - ShowWarning ("HEADER_DAMAGED_AUTO_USED_HEADER_BAK"); + volume = mountWithProtectionRecovery(); } catch (...) { options.UseBackupHeaders = false; + autoBackupHeaderUsed = false; ShowWarning (e); } } @@ -1008,6 +1087,9 @@ namespace VeraCrypt ShowWarning (e); } } + + if (autoBackupHeaderUsed && options.UseBackupHeaders) + ShowWarning ("HEADER_DAMAGED_AUTO_USED_HEADER_BAK"); } catch (exception &e) { diff --git a/src/Main/GraphicUserInterface.h b/src/Main/GraphicUserInterface.h index fba52b19..fede9a1a 100644 --- a/src/Main/GraphicUserInterface.h +++ b/src/Main/GraphicUserInterface.h @@ -120,6 +120,7 @@ namespace VeraCrypt Event OpenVolumeSystemRequestEvent; protected: + virtual shared_ptr MountVolumeWithProtectionRecovery (MountOptions &options, const PasswordException &protectionError) const; virtual void OnEndSession (wxCloseEvent& event) { OnLogOff(); } #ifdef wxHAS_POWER_EVENTS virtual void OnPowerSuspending (wxPowerEvent& event); @@ -145,6 +146,7 @@ public: #endif private: + shared_ptr MountVolumeInternal (MountOptions &options, bool tryCachedPasswords, bool protectionRecovery) const; GraphicUserInterface (const GraphicUserInterface &); GraphicUserInterface &operator= (const GraphicUserInterface &); }; diff --git a/src/Main/UserInterface.cpp b/src/Main/UserInterface.cpp index b88d5286..7b7c82fb 100644 --- a/src/Main/UserInterface.cpp +++ b/src/Main/UserInterface.cpp @@ -851,11 +851,16 @@ namespace VeraCrypt { CloseSecurityTokenSessionsAfterMountScope closeTokenSessionsScope (Preferences.CloseSecurityTokenSessionsAfterMount); - // A protection failure accepted the outer password. Let the UI recover - // using that cache; only skip a cache sweep that failed outer authentication. + // A protection failure accepted the outer credentials. Preserve that + // state for UI recovery; otherwise skip the failed cache sweep. bool protectionError = dynamic_cast (&e) || dynamic_cast (&e); - shared_ptr volume = MountVolume (favoriteOptions, protectionError); + // Do not add default outer keyfiles to credentials already accepted. + if (protectionError && !favoriteOptions.Keyfiles) + favoriteOptions.Keyfiles = make_shared (); + shared_ptr volume = protectionError + ? MountVolumeWithProtectionRecovery (favoriteOptions, e) + : MountVolume (favoriteOptions, false); if (!volume) break; diff --git a/src/Main/UserInterface.h b/src/Main/UserInterface.h index 6f6792bb..538ae6f9 100644 --- a/src/Main/UserInterface.h +++ b/src/Main/UserInterface.h @@ -102,6 +102,7 @@ namespace VeraCrypt protected: UserInterface (); + virtual shared_ptr MountVolumeWithProtectionRecovery (MountOptions &options, const PasswordException &protectionError) const { return MountVolume (options); } virtual bool OnExceptionInMainLoop () { throw; } virtual void OnUnhandledException (); virtual void OnVolumeMounted (EventArgs &args);