Unix: process protection keyfiles before cached mounts

Apply protection keyfiles once in the application, including cached-password
mounts. This keeps PC/SC out of the core service before FUSE forks.

Preserve protection errors and cache retries, and ignore protection
credentials when protection is disabled.
This commit is contained in:
Mounir IDRASSI committed 2026-09-25 09:36:30 +02:00
1 parent 55920deffb
commit ab9d636e52
1 file changed
+70 -49
+70 -49
View File
@@ -91,65 +91,86 @@ namespace VeraCrypt
virtual shared_ptr <VolumeInfo> MountVolume (MountOptions &options) virtual shared_ptr <VolumeInfo> MountVolume (MountOptions &options)
{ {
shared_ptr <VolumeInfo> mountedVolume; shared_ptr <VolumeInfo> mountedVolume;
const bool useCachedPasswords = !VolumePasswordCache::IsEmpty()
if (!VolumePasswordCache::IsEmpty()
&& (!options.Password || options.Password->IsEmpty()) && (!options.Password || options.Password->IsEmpty())
&& (!options.Keyfiles || options.Keyfiles->empty())) && (!options.Keyfiles || options.Keyfiles->empty());
{ MountOptions newOptions = options;
finally_do_arg (MountOptions*, &options, { if (finally_arg->Password) finally_arg->Password.reset(); });
PasswordIncorrect passwordException;
foreach (shared_ptr <VolumePassword> password, VolumePasswordCache::GetPasswords())
{
try
{
options.Password = password;
mountedVolume = CoreService::RequestMountVolume (options);
break;
}
catch (PasswordIncorrect &e)
{
passwordException = e;
}
}
if (!mountedVolume)
passwordException.Throw();
}
else
{
MountOptions newOptions = options;
// Resolve keyfiles in the application process, also when the outer password
// is cached. Token access must not initialize PC/SC in the core service
// before it forks FUSE.
if (!useCachedPasswords)
newOptions.Password = Keyfile::ApplyListToPassword (options.Keyfiles, options.Password, options.EMVSupportEnabled); newOptions.Password = Keyfile::ApplyListToPassword (options.Keyfiles, options.Password, options.EMVSupportEnabled);
if (newOptions.Keyfiles) if (newOptions.Keyfiles)
newOptions.Keyfiles->clear(); newOptions.Keyfiles->clear();
if (options.Protection == VolumeProtection::HiddenVolumeReadOnly)
newOptions.ProtectionPassword = Keyfile::ApplyListToPassword (options.ProtectionKeyfiles, options.ProtectionPassword, options.EMVSupportEnabled); newOptions.ProtectionPassword = Keyfile::ApplyListToPassword (options.ProtectionKeyfiles, options.ProtectionPassword, options.EMVSupportEnabled);
if (newOptions.ProtectionKeyfiles) else
newOptions.ProtectionKeyfiles->clear(); newOptions.ProtectionPassword.reset();
if (newOptions.ProtectionKeyfiles)
newOptions.ProtectionKeyfiles->clear();
try try
{
if (useCachedPasswords)
{
finally_do_arg (MountOptions*, &options, { if (finally_arg->Password) finally_arg->Password.reset(); });
PasswordIncorrect passwordException;
foreach (shared_ptr <VolumePassword> password, VolumePasswordCache::GetPasswords())
{
try
{
newOptions.Password = password;
mountedVolume = CoreService::RequestMountVolume (newOptions);
break;
}
catch (ProtectionPasswordIncorrect&)
{
// The outer password was accepted; another cached password cannot
// correct the hidden-volume protection credentials.
throw;
}
catch (ProtectionPasswordKeyfilesIncorrect&)
{
throw;
}
catch (PasswordIncorrect &e)
{
passwordException = e;
}
}
if (!mountedVolume)
passwordException.Throw();
}
else
{ {
mountedVolume = CoreService::RequestMountVolume (newOptions); mountedVolume = CoreService::RequestMountVolume (newOptions);
} }
catch (ProtectionPasswordIncorrect &e) }
{ catch (ProtectionPasswordIncorrect &e)
if (options.ProtectionKeyfiles && !options.ProtectionKeyfiles->empty()) {
throw ProtectionPasswordKeyfilesIncorrect (e.what()); if (options.ProtectionKeyfiles && !options.ProtectionKeyfiles->empty())
throw; throw ProtectionPasswordKeyfilesIncorrect (e.what());
} throw;
catch (PasswordIncorrect &e) }
{ catch (ProtectionPasswordKeyfilesIncorrect&)
if (options.Keyfiles && !options.Keyfiles->empty()) {
throw PasswordKeyfilesIncorrect (e.what()); throw;
throw; }
} catch (PasswordIncorrect &e)
{
if (options.Keyfiles && !options.Keyfiles->empty())
throw PasswordKeyfilesIncorrect (e.what());
throw;
}
if (options.CachePassword if (!useCachedPasswords && options.CachePassword
&& ((options.Password && !options.Password->IsEmpty()) || (options.Keyfiles && !options.Keyfiles->empty()))) && ((options.Password && !options.Password->IsEmpty()) || (options.Keyfiles && !options.Keyfiles->empty())))
{ {
VolumePasswordCache::Store (*Keyfile::ApplyListToPassword (options.Keyfiles, options.Password, options.EMVSupportEnabled)); VolumePasswordCache::Store (*Keyfile::ApplyListToPassword (options.Keyfiles, options.Password, options.EMVSupportEnabled));
}
} }
VolumeEventArgs eventArgs (mountedVolume); VolumeEventArgs eventArgs (mountedVolume);