-
Notifications
You must be signed in to change notification settings - Fork 711
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
Major changes for all cards that needs developer review #850
Conversation
2fd7aaf
to
97bddec
Compare
Rebased pull request againt current master and updated it with three more commits:
@mouse07410: While I don't know how Apple software handles C_GetTokenInfo() return values, PS. Looks like commit 6cd28cf broke one of the test builds on AppVeyor. |
Yes I've had this problem. My workaround was not to use Firefox for now. :-( |
97bddec
to
9e7c901
Compare
Rebased pull request against current master and updated with latest commits. Most important of them is adding GCC format checking attributes to log functions and going through Other warnings that were shown when building by GCC on 64-bit Linux, 32-bit and 64-bit mingw builds Also, minidriver is now buildable again on mingw (it looks like it bit rotted a little there). Another important change is provide notification about and handle card resets by other contexts, Now, Windows components seems to deauthenticate card very often, this made at least some cards (for example OpenPGP card and cards having multiple applets) non-working due to lost card state. This all means that we need to catch card resets by other contexts in reader backends and provide higher layers with this information so they can decide what to do when it happens (reinitialize the card More elegant solutions might be possible for particular cards (like I see was done for PIV card Minidriver is a bit special, since transaction begin (where usually the reader backend learns about As usual, please see individual commit messages for details. |
Thanks for the work you put into removing compiler warnings and using additional compiler features! But I think they should go into a separate PR. Also the minidriver changes are interesting, but should be looked at in a separate PR since they concern all cards. I think you should not check for You should not force the developer to put Adding It seems that a7e180d is a hack that will very likely to be used by anyone... I think that e04bf03 can be removed with #842 being accepted. @CardContact could you look at 6cbf2bc? |
Hi Frank, thanks for looking into it (and naturally for all your work with OpenSC!).
The problem was that compiler warning and card reset handling changes are pretty intrusive (and by that I mean they change a lot of places), so they collide with these in minidriver.
This check was added since "cardmod.h" from CNG requires this header, so it won't compile on
Well, it was working some time ago (that's why there still is a "--enable-minidriver" parameter for BTW. The changes are about mingw-w64 targeting both Win32 and Win64 and not mingw32 - sorry
I will remove this check in next patch version.
Are you sure about this that "%zu" is available since Visual Studio 2015? However, on older compiler (or CRT library) releases it is not only about warning, but about correctness: if a we use an unknown (at that version) conversion specifier it is unspecified what will happen - whether the argument is going to be printed as int (which on Win64 has different length) or skipped altogether. I agree this it is ugly but it is better to use an ugly correct solution than nice looking one that is not right. Update:
#842 is only for PIV card and cannot be used with minidriver (which is the main source of card resets), |
#842 was designed to be used with OpenSC calling PCSC. And was designed that other card drivers could write there own routine. The minidriver passes in handles to use. The check_reader_status look to see if the handle changes, Look at sc_ctx_use_reader that passes in the Windows provided handles. to reader-pcsc.c sc_ctx_use_reader. The look at what cardmod_init is doing. Note that |
Handles change when the card is reinserted / replaced.
Normally this happens during transaction begin ("sc_lock()" in OpenSC terminology) and
As I said to Frank:
In other words, "sc_lock" and "sc_unlock" equivalent operations are done by Base CSP.
"holding the card transaction" = sc_lock'ed
We deinit card in CardDeleteContext, this means we have to be careful not to break other contexts |
I should have taken more time to read the thread this morning. As you point out in 7.07: "A card minidriver should assume that transactions are handled by the caller" It also says: "Handling the authentication state of the card is also the responsibility of the caller, not the card minidriver." As you point out card reset is the biggest problem and not having a "logout" function causes The above is a logout APDU command: 00 20 FF XX 00. It is the missing command needed in a multi application environment. I have not found this in any other standards or know if any other cards also support this. I don't believe there are any PIV cards in the field yet that support this either. If the OpenPGP applet or other applet support this it would cut out the need for card_reset. Another problem, which I don't see an obvious solution, are card with multiple applets, where the user may want to use different applets from different applications. PIV and CAC on same card. PIV and OpenPGP on same card, (Yubico supports this.) Selecting the AID of one applet in one processes resets the security status, and also the AID. Another needed APDU command is to query which AID is active, to see if it has changed by some other application. I have not spent much time on the OpenSC PIV driver when used with the OpenSC minidriver because there is not much use for it because Microsoft provides its own PIV minidriver. But a logout to try the 00 20 FF XX 00 command would be easy to add, and if it fails, let the baseCSP do what it does today. Another issue which causes card_reset is the opensc.conf: 77 # What to do when disconnecting from a card (SCardDisconnect ) The default is to always causes a card_reset. You may want to test with: 80 disconnect_action = leave; Another issue is the way OpenSC matches cards. Doing a select AID to see if the applet is on the card may cause the card to reset it state, even if the AID is not on the card. So limiting the card drivers to cards used by the user can cut down on this problem. |
OK, I understand why #842 does not solve the problem in minidriver and why you need a dedicated detection mechanism for resets. But instead of doing a complete |
I suggested to create separate PRs to accelerate adoption of the changes to the OpenPGP driver, which seemed to be your primary target. You may leave this PR as is and wait a little longer for others to do testing and review. |
@dengert the default disconnect/reconnect/transactionend actions for the cardmod driver are left at Update: for reference have a look at |
Yes, I am sure that |
Some more people need to check all the changes that will influence all other cards! |
The card_init may leave the action at SCARD_LEAVE_CARD for the minidriver. I was suggesting that if one also uses FireFox/NSS/PKCS#11/opensc, the action would be reset, that would cause problems with minidriver connections to the card. |
In response to "OK, I understand why #842 does not solve the problem in minidriver and why you need a dedicated detection mechanism for resets." I don't think on Windows you can have a dedicated detection mechanism for resets. This is based on 7.07 saying: "Handling the authentication state of the card is also the responsibility of the caller, not the card minidriver." I read this as Microsoft will not tell the minidriver the card was reset. And reset is not the only interference that other applications can cause. Other vendor's smart card middleware can also cause interference. But if you can avoid other vendor's middleware and use only OpenSC minidriver and OpenSC libs, maybe there is a way on Windows to have the different applications share information about the state of the card. I have not done any windows programming in years, but there should be some way to share and set this information from multiple processes. The state should include what AID is active, what card driver is being used, the login state, and if objects or files have been changed on the card. Things that PCSCD does not keep track of. (Might be able to do this on Linux and MacOS too.) |
Just a side note here: this spec is written with assumption that all smart card accesses are done via I am currently looking if there is a better option overall regarding card reset issue, since what is
I've tried various commands on OpenPGP card but none seemed to work.
Here, problem with knowing currently selected applet looks similar to me as situation with security
Yes, but if an user forces card reset via this setting then he shouldn't be surprised that something
You mean send it blindly to the card with XX replaced with every key reference possible on that card?
Good to know that, that basically means that multiple contexts in this case can break even without
Yes, but then I would need to implement this method for: acos5, asepcos, authentic, belpic, As we need to have reinitialize support in minidriver anyway for "handles changed" situation it was
I will create a separate pull request for these small few-line commits which can be merged separately ( f984c96 cb9d8aa fa4174f 4e5ff7c ).
It would also greatly help if people who maintain or work with cards that do not implement the logout |
https://github.com/maciejsszmigiero, No, XX is key reference the software used in the verify command sent earlier to login to the card. You said: "Do you know any non-PIV card where this could possibly work?" No, i don't. I was asking if anyone else had seen a "logout" command like this in any other card or standard. |
#864 is merged, could you rebase this PR? |
664c394
to
a026628
Compare
Rebased against current master, configure no longer forces developer to put cardmod.h into a specific Also amended log messages format and parameter fixes by minidriver ones which were missing from |
a026628
to
25679f2
Compare
Rebased against current master, added missing "-no-undefined" to src/smm LDFLAGS (this had |
Sorry to say it so late, If it's not too late, |
@viktorTarasov @maciejsszmigiero The reset/logout should be its own PR, so others are aware that their favorite card needs testing, and your PR should point out any issues you see with selected cards, and how they might be addressed. Minidriver only changes should be another PR. Make sure the subject of the PR is not under stated: "A few fixes mostly about OpenPGP card" should have been: "Major changes for all cards that needs developer review and minor changes for OpenPGP." |
That's why this PR is divided into 22 commits.
I will change the PR description.
The old behavior meant that cards than didn't support the logout method (that is, the majority of cards
Do you mean commit 5c82c8f here? If you mean commit 1acde82 then this is an additional
As I said previously the problem is these changes (mostly) depend on each other, for example all significant minidriver changes (that, is excluding minor things like commit b34a34a) depend on each other sequentially and also on card reset handling commit 7eff745. If this process is done sequentially instead (that is, preparing next PR after closing the previous one) then at the current pace (for which I also am to blame since I usually cannot respond / rebase the changes immediately) I am afraid the whole process will take years. Unfortunately, the log arguments fixes are the most intrusive changes (by the number of places changed). There are commits that look like they could be split out relatively easily, though - minidriver build fixes
Will do (without the OpenPGP part as small OpenPGP changes have actually already been merged in |
Minidriver contained a hack since commit 7ef766b in 2010 to print to debug file directly under mingw (instead of using normal OpenSC logging system), as there was problem with "%S" format specifier then. However, on recent mingw versions "%S" format works fine so let's remove this hack. Signed-off-by: Maciej S. Szmigiero <[email protected]>
Minidriver currently has basic support for unblocking card PIN by providing PUK as an administrator password to CardUnblockPin() function. However, this doesn't work for example when trying to unblock PIN via system smartcard PIN unblock screen accessible after pressing Ctrl+Alt+Del as it wants to use challenge / response authentication. MS Smart Card Minidriver specification (version 7.07) explicitly says that challenge / response is the only authentication mode that Windows uses to authenticate an administrator. Unfortunately, this way of unblocking PIN seems to not be widely supported by cards. However, we can simply treat the provided response to challenge as PUK. Because (at least) Ctrl+Alt+Del PIN unblock screen accepts only hex string, every PUK digit X has to be input as '3X' (without quotes) there. Also the response string is not hidden behind asterisks on this screen as it should been. Signed-off-by: Maciej S. Szmigiero <[email protected]>
Most of the cards supported by OpenSC do not support the "logout" method required to deauthenticate a card. This means that the only way to deauthenticate the card without removing it from reader is to reset it. This is done by Base CSP if we return SCARD_E_UNSUPPORTED_FEATURE from CardDeauthenticate() in minidriver, which we do if calling "logout" card method fails. If this happens, all users of this card will lose its state and at least some cards (OpenPGP card and cards having multiple applets) will be non-functional in currently active minidriver contexts as they need some initialization after reset. This makes it really hard to use card from multiple applications as some Windows libraries (like WinHTTP used by IE and WebDAV client) prefer to deauthenticate card after only a few seconds of inactivity (with PIN cached for future operations). Keep a list (critical section protected) of other minidriver contexts which are using this reader (and so this card) to make sure all of them will be reinitialized after the card is reset by Base CSP or some other user. There are other reasons (like card handles changed) where a card needs to be reinitialized, too. This solution isn't most optimal possible, but at least makes these cards work properly - for more detailed discussion about card reset issue please have a look at description of commit "Provide notification about and handle card resets by other contexts". Signed-off-by: Maciej S. Szmigiero <[email protected]>
GCC can check format and parameter correctness in printf()-like functions for us so let's add necessary attributes to our log functions to emit a warning where their way of being called is likely in need to be inspected for correctness. Signed-off-by: Maciej S. Szmigiero <[email protected]>
Since "Add GCC format checking attributes to log functions" commit GCC warns us about problems with format strings and their arguments provided to OpenSC message logging functions. This commit fixes all cases where GCC warned about incorrect format on 64-bit Linux, 32-bit and 64-bit mingw builds (with SM and OpenSSL enabled). Well, almost all since on mingw GCC does not recognize "ll" size specifier (present at least since Visual Studio 2005, also in mingw own CRT) so these (few) warnings about it remain. In most cases format size specifier for size_t type was missing (usually size was left at default int level, with is different on 64-bit x86). Some formats had too few / too many arguments. In some cases pointers were printed as integers. Some long variables were missing "l" prefix (especially with regard to %x format). Signed-off-by: Maciej S. Szmigiero <[email protected]>
Looks like Travis CI build server found a few cases of log function format string not being a string literal (now that log functions have necessary attributes to check for such things). Some instances clearly aren't a real problem, but to be future-proof and to avoid compiler warnings let's fix all of them (that I was able to find in code). Signed-off-by: Maciej S. Szmigiero <[email protected]>
Mingw currently links to msvcrt.dll as C runtime. This library is documented by Microsoft as off-limits to applications and its feature set vary between Windows versions. Due to this, presence of particular printf() format string directives depends on which Windows version the code is run. This is, naturally, bad, so mingw developers introduced ability to replace formatted output functions with built-in equivalents with defined feature set by setting "__USE_MINGW_ANSI_STDIO" macro to 1. There are, however, no built-in equivalents for "_s" suffixed functions. Fortunately, they are used only a few times in minidriver so let's simply replace them with equivalent code using standard functions. This also allows skipping "MINGW_HAS_SECURE_API" macro definition so any future uses will be caught by compiler. Signed-off-by: Maciej S. Szmigiero <[email protected]>
Commit "Add GCC format checking attributes to log functions" added format and parameter checking to OpenSC log functions. Minidriver, however, logs most of its output via a dedicated log function, so this function needs such attributes, too. Signed-off-by: Maciej S. Szmigiero <[email protected]>
Since last commit GCC warns us about problems with format strings and their arguments in minidriver, so let's fix these warnings just as we did in rest of the OpenSC code. Most of these warnings were about DWORDs being printed as ints, there were also some format directives and size_t size specifiers missing and various misc format / parameter disagreements. Attempt was made to keep log strings as-is, only the most obvious typos were fixed. Signed-off-by: Maciej S. Szmigiero <[email protected]>
According to minidriver specs CardGetChallenge() method parameters are purely for output and do not have a meaning of requested challenge length, so remove misleading log line. There is also no need to have a special case for pcbChallengeData being NULL since in this case the function would have exited early anyway with SCARD_E_INVALID_PARAMETER (also, it was just dereferenced in the previous code line). Signed-off-by: Maciej S. Szmigiero <[email protected]>
According to minidriver specs CardReadFile() method output parameters are optional so don't return SCARD_E_INVALID_PARAMETER when they are NULL. Also, use this opportunity to walk through this function helpers to make sure they correctly return error status. Signed-off-by: Maciej S. Szmigiero <[email protected]>
d576573
to
5deedf3
Compare
Rebased against current master, |
If you want to complete a78bc32: sc-hsm's sopin unblocks the user pin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding f2df771, I'm not sure if solving this in the minidriver is the ideal solution. If I'm not mistaken, we have the same problem with resets and with threads also in PKCS#11 or Tokend. @dengert tried to solve this partially by introducing card_reader_lock_obtained
in the lowest possible layer. Isn't this what we should do here, too?
In some commit message you explained why SCardBeginTransmit
(i.e. sc_lock
) is not the right place to check for resets. Instead, you're calling sc_detect_card_presence
and check the result for SC_READER_CARD_RESET
. Isn't this what we should change in the lower layers?
SCF_DEFAULT_SIGN_PIN, | ||
SCF_DEFAULT_OTHER_PIN, | ||
SCF_DEFAULT_USER_PIN | ||
} pin_mode_t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you define this outside of md_set_cmapfile
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do.
@@ -397,41 +397,25 @@ int sc_lock(sc_card_t *card) | |||
return r; | |||
if (card->lock_count == 0) { | |||
if (card->reader->ops->lock != NULL) { | |||
r = card->reader->ops->lock(card->reader); | |||
while (r == SC_ERROR_CARD_RESET || r == SC_ERROR_READER_REATTACHED) { | |||
r = card->reader->ops->lock(card->reader, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still contains the old locking parameter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you change this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still contains the old locking parameter
Here I would prefer to leave this as-is, because this is a very small
change (only 5 changed places, mostly one-liners) and
I am afraid that this functionality (in contrast to a change that added
a new parameter to sc_lock()) might not be easy to add back if the
PC/SC reader driver changes too much.
In fact, I see that a significant rewrite of PC/SC reader driver is waiting to be
merged (issue #892).
Are you planning to merge that change soon?
It looks like this rewrite is going to conflict with changes from this PR so maybe
we can wait until #892 is merged, then I will rebase and we'll see how this
change fits in the rewritten driver?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you change this?
Since the card is going to be reinitialized anyway on reset there is (currently)
no point in calling card_reader_lock_obtained or reopening sm channel.
r2 = sc_mutex_unlock(card->ctx, card->mutex); | ||
if (r2 != SC_SUCCESS) { | ||
sc_log(card->ctx, "unable to release card->mutex lock"); | ||
r = r != SC_SUCCESS ? r : r2; | ||
} | ||
|
||
/* give card driver a chance to do something when reader lock first obtained */ | ||
if (r == 0 && reader_lock_obtained == 1 && card->ops->card_reader_lock_obtained) | ||
r = card->ops->card_reader_lock_obtained(card, was_reset); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You removed the call to card_reader_lock_obtained
. Was this intended?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't remove that the PIV driver, and any other driver that implements card_reader_lock_obtained
depends on it. For any card that does not define its on card_reader_lock_obtained the code is a noop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In previous iteration of this changeset sc_lock() function was always
called with resetok = 0 while card_reader_lock_obtained
method would only get called and sm reopen would only happen
with resetok = 1.
This parameter was removed since Frank said in comment to
line introducing it that we shouldn't add unused code
(OK, this removed code wasn't strictly "added", it was already
there but it would be a dead code after resetok parameter removal).
#ifdef ENABLE_SM | ||
if (card->sm_ctx.ops.open) | ||
card->sm_ctx.ops.open(card); | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sm channel is not reopened on reset anymore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sm channel is not reopened on reset anymore
It is, since a reset triggers card reinitialization and
this results in opening of a sm channel.
BTW. Old code had a difference in behavior there:
in init code the sm channel was opened only in
"Transmit" sm mode, but on reset it was opened
unconditionally.
As I have written previously:
(now this is a commit db5e03c).
As I said in the previous comment, higher layers (like PKCS#11) need to know about |
I STRONGLY object to the removal of the loop. Multiple applications may have been waiting on the
lock, and as each one gets control, they may reset the card again. you really want to leave
the while loop in place.
I disagree with your logic:
"Since the card is going to be reinitialized anyway on reset there is..."
r = card->ops->card_reader_lock_obtained(card, was_reset);
may do something different.
You can change:
r = card->reader->ops->lock(card->reader);
to
r = card->reader->ops->lock(card->reader, 0);
But don't remove the while loop, and don't touch the
…On 2/10/2017 8:52 AM, Maciej S. Szmigiero wrote:
***@***.**** commented on this pull request.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
In src/libopensc/card.c <#850>:
> @@ -397,41 +397,25 @@ int sc_lock(sc_card_t *card)
return r;
if (card->lock_count == 0) {
if (card->reader->ops->lock != NULL) {
- r = card->reader->ops->lock(card->reader);
- while (r == SC_ERROR_CARD_RESET || r == SC_ERROR_READER_REATTACHED) {
+ r = card->reader->ops->lock(card->reader, 0);
@dengert <https://github.com/dengert>:
Why did you change this?
Since the card is going to be reinitialized anyway on reset there is (currently)
no point in calling card_reader_lock_obtained or reopening sm channel.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub <#850>, or mute the thread
<https://github.com/notifications/unsubscribe-auth/AA00MbaojsmEDyjQbSWCrDWkghwF42LUks5rbHm-gaJpZM4JiX_s>.
--
Douglas E. Engert <[email protected]>
|
I can revert this to version before last respin of this changeset where the loop was present. |
Thanks.
…On 2/10/2017 10:08 AM, Maciej S. Szmigiero wrote:
I STRONGLY object to the removal of the loop.
Multiple applications may have been waiting on the lock, and as each one gets control, they may
reset the card again. you really want to leave the while loop in place.
I can revert this to version before last respin of this changeset where the loop was present.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub <#850 (comment)>, or mute the thread
<https://github.com/notifications/unsubscribe-auth/AA00Mf8qNBMNqaofXzMUI9Ga80CeaNKVks5rbItqgaJpZM4JiX_s>.
--
Douglas E. Engert <[email protected]>
|
I created #979 to at least merge the accepted changes from this PR. |
@maciejsszmigiero, the rewrite of the pcsc driver is up for review in #983. I'd like to merge most of your commits. However, I failed to cherry-pick them due to merge conflicts and dependencies to non-picked commits (see #979). If you could make a new PR excluding the following commits, I'll review and merge the others seperately: |
@maciejsszmigiero it's finally done, both PRs are merged. |
All the changes from this pull request are merged now, besides a card reset handling. It is clear, however, that there isn't a consensus yet how exactly to address this issue For users of the majority of cards that do not support the "logout" method there is a simple workaround of disabling card resets completely, at a price of a bit less security. |
This pull request contains a few fixes mostly centered around OpenPGP card:
Remove raw RSA algo flag from OpenPGP card since it doesn't support it.
Initialize PIN logged_in field for OpenPGP card and other cards that do not support PIN info.
This fixes Firefox PIN login problem on these cards introduced by commit 2f10de4 .
Make OpenPGP card user/signature PIN order match expected by _get_auth_object_by_name() function in OpenSC PKCS#11 framework.
Strip execute permission bits from two .c files that have them set.
Please see individual commit messages for details.