-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG] PivSession.Dispose doesn't close Connection if Yubikey unplugged #104
Comments
I initially thought this was the cause of a SCARD_E_SHARING_VIOLATION when trying to reconnect to a Yubikey which had been unplugged and then plugged in again, but I still got that even after manually disposing the |
Yup. That seems like an issue regardless. Regarding the sharing violation: Typically it's caused by another Windows service racing with your app to make a connection to the YubiKey. I had attempted to "fix" this in 1.9.1 by opening the handle to the smart card exclusively. I did not realize that it would instead cause further issues upstream. This has now been changed back to the previous (1.9.0) behavior and the exclusive locking guarded behind an app compat flag. Hopefully this will be made available in the next release. A more comprehensive fix to the race is still needed, but it'll be more involved too. At least the SDK will be back to behaving how it has been. |
Yep, I gathered that from reading the other issues here, thanks! (Which is why I downgraded, pending a new release with your fix in). |
Hi @canton7 ! Just to gather more info, why do you think that the exception shouldn't be thrown? Thanks, trying to understand. |
Hi @DennisDyallo, thanks for picking this up!
First and foremost, Dispose methods are not expected to throw exceptions in .NET. See for example CA1065. When dealing with a class which implements In addition, I don't think there's a way to check whether a Yubikey is connected? If so, there's no way to write the following code anyway: IYubiKeyDevice yubiKeyToUse = SelectYubiKey();
var piv = new PivSession(yubiKeyToUse)
try
{
/* Perform PIV operations. */
}
finally
{
if (piv.Connection.IsConnected) // I can't find a property such as this? How do you check this?
{
piv.Dispose();
}
}
if (!_disposed)
{
if (disposing)
{
_cardHandle.Dispose();
_context.Dispose();
}
_disposed = true;
}
Thus, if the Yubikey has been disconnected by the user, disposing the .NET best practice is to allow unmanaged resources to be released explicitly by a call to It's worth noting that KeyCollector = null;
ResetAuthenticationStatus();
_disposed = true; None of this happens if the Yubikey has become disconnected.
As discussed this is a very odd decision, which it not documented and goes against the way that the rest of .NET works. Elsewhere, it is always permitted to call It is very much not expected that Yubikey leaks native resources (Finalizer notwithstanding) if the user disconnects a Yubikey!
Sure, but you should at least let the programmer release native resources in the normal way.
Yes, but that's very unusual in .NET (you never see a I also note that your own documentation says:
IYubiKeyDevice yubiKeyToUse = SelectYubiKey();
using (var piv = new PivSession(yubiKeyToUse))
{
/* Perform PIV operations. */
}
According to your comment, this needs to be reworded, and the code sample changed. Although what it should be changed to I'm not sure! I currently have: var piv = new PivSession(yubiKeyToUse);
try
{
/* Perform PIV operations. */
}
finally
{
try
{
piv.Dispose();
}
catch
{
// If the Yubikey is no longer connected, then PivSession.Dispose will throw and won't call Connection.Close, which leaves the underlying Windows connection open.
// This means that subsequent attempts to open a connection to the same device (once reconnected) will fail with SCARD_E_SHARING_VIOLATION.
// See https://github.com/Yubico/Yubico.NET.SDK/issues/104
piv.Connection.Dispose();
}
} In my view, a corrected implementation of public void Dispose()
{
if (!_disposed)
{
// This could fail, e.g. if the Yubikey has been disconnected. Continue freeing resources if so.
try
{
Connection.SendCommand(new SelectApplicationCommand(YubiKeyApplication.Management));
}
catch { }
KeyCollector = null;
ResetAuthenticationStatus();
Connection.Dispose();
_disposed = true;
}
} |
Hi again @canton7 ! |
That's great, thank you! Q4 is fine for me thanks, I have a functional workaround. |
Is there an existing issue for this?
Current Behavior
PivSession.Dispose
attempts to send aSelectApplicationCommand
command, before it does other tidying up.However, if the Yubikey has been disconnected, this
Connection.SendCommand
throws an exception, and the rest of theDispose
method does not run.This means that
Connection.Dispose()
isn't run. This also means that aDispose
method throws an exception, which is not normally expected behaviour.Expected Behavior
PivSession.Dispose
should make a best-effort attempt to clean up all resources, even if the Yubikey has been disconnected.Steps To Reproduce
Version
1.10.0
Version
5.4.3
Anything else?
No response
The text was updated successfully, but these errors were encountered: