Skip to content
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

Login in one application triggers logout in Firefox, breaks application #2897

Closed
minfrin opened this issue Oct 12, 2023 · 29 comments
Closed

Comments

@minfrin
Copy link

minfrin commented Oct 12, 2023

Problem Description

I have a native messaging web application for Firefox that signs some text using the PKCS11 APIs.

This native messaging web application is a standalone app that is spawned by Firefox and communicates with Firefox via stdin/stdout.

The native messaging web application is successfully able to sign some text, asking for the user's PIN to do so.

When the response is given back to Firefox, the session that Firefox has with the smartcard breaks, and the response cannot be sent back upstream to the server.

It appears that the native messaging web application is doing something to smartcard that breaks Firefox, a totally separate application.

Is the code involved doing something wrong, or is this a bug in opensc?

Code that does the login before the signing:

https://source.redwax.eu/projects/RST/repos/redwax-signtext/browse/src/linux/crypto.c#1082

Code that does the logout after the signing ready to sign the next text:

https://source.redwax.eu/projects/RST/repos/redwax-signtext/browse/src/linux/crypto.c#641

Proposed Resolution

Application A doesn't break application B.

@dengert
Copy link
Member

dengert commented Oct 12, 2023

https://source.redwax.eu/projects/RST/repos/redwax-signtext/browse/src/linux/crypto.c#641 may be the problem, as "logout" may cause the card/token to lose its login state. FireFox may not recognize this.
OpenSC has two ways to do address this: "disconnect=leave" to avoid losing the login state or cache pins so if an operation fails it can internally send pin to card again. A card reset will also lose the login state.

What is version of OpenSC? (0.24.0-rc1 has some logout changes.)
What card or token is used? (specific cards/token may always lose the login state.)
What OS?
What version of FireFox?

When did you see the problem? (Did it ever work, never worked or when did it start failing.)

From the web site, I see it is using p11kit. Firefox uses NSS to call pkcs11 or may use Windows or MacOS services with or without OpenSC.

Can you get an OpenSC debug log for both FireFox and your application. https://github.com/OpenSC/OpenSC/wiki/Using-OpenSC

@minfrin
Copy link
Author

minfrin commented Oct 12, 2023

https://source.redwax.eu/projects/RST/repos/redwax-signtext/browse/src/linux/crypto.c#641 may be the problem, as "logout" may cause the card/token to lose its login state. FireFox may not recognize this. OpenSC has two ways to do address this: "disconnect=leave" to avoid losing the login state or cache pins so if an operation fails it can internally send pin to card again. A card reset will also lose the login state.

Caching PINs won't work for either firefox or the native application, as this needs to work on smartcard readers with a pinpad.

What does "disconnect=leave" do?

What is version of OpenSC? (0.24.0-rc1 has some logout changes.) What card or token is used? (specific cards/token may always lose the login state.) What OS? What version of FireFox?

OpenSC v0.21.0-1 on a raspberry pi. MyEID card. Firefox v102.15.1esr (64 bit).

When did you see the problem? (Did it ever work, never worked or when did it start failing.)

Works fine when firefox does not use a smartcard, and the native application is using the smartcard. Tried using a site that requires a smartcard to log in, and this is where we saw the breakage.

From the web site, I see it is using p11kit. Firefox uses NSS to call pkcs11 or may use Windows or MacOS services with or without OpenSC.

This is Linux - definitely using OpenSC.

Can you get an OpenSC debug log for both FireFox and your application. https://github.com/OpenSC/OpenSC/wiki/Using-OpenSC

This generates 1.6MB of logs, which has low level details of the card in it. Is there a way to get it to you?

@minfrin
Copy link
Author

minfrin commented Oct 12, 2023

Further observation - the moment the native application finishes signing, firefox starts behaving unpredictably.

Sometimes, firefox will stop reading from the native application, which causes the native application to throb indicating it is alive but noone is listening - at the same time the original webpage is still awake and functional and can still access things (possibly with cached connections?). Sometimes firefox will popup a "please enter your PIN" dialog. Sometimes firefox shows a page showing various failures (that I now cannot reproduce).

@dengert
Copy link
Member

dengert commented Oct 12, 2023

@frankmorgner @Jakuje This problem maybe related to #2807

@dengert
Copy link
Member

dengert commented Oct 12, 2023

Using Ubuntu 22.04 with OMNIKEY AG CardMan 3821 00 00 and Myeid card from 2017 (Thanks @hhonkanen) and OpenSC version: 0.24.0-rc1 it worked as expected.

It did not print a prompt on terminal but did on pin-pad reader and created a signature. GDB below shows pkcs11-tool does call myeid_logout.

(gdb) run
Starting program: /opt/ossl-3.1.2/bin/pkcs11-tool --sign --login --id 45 -i /tmp/hello.txt -m SHA256-RSA-PKCS -o /tmp/sig.txt
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Using slot 0 with a present token (0x0)
Using signature algorithm SHA256-RSA-PKCS

Breakpoint 1, myeid_logout (card=0x5555555aac50) at ../../../src/src/libopensc/card-myeid.c:438
438	{
(gdb) where
#0  myeid_logout (card=0x5555555aac50) at ../../../src/src/libopensc/card-myeid.c:438
#1  0x00007ffff76313db in sc_logout (card=0x5555555aac50) at ../../../src/src/libopensc/sec.c:148
#2  0x00007ffff79d5a2c in pkcs15_logout (slot=0x5555555aa040) at ../../../src/src/pkcs11/framework-pkcs15.c:1934
#3  0x00007ffff79bf0a1 in sc_pkcs11_close_session (hSession=93824992742416) at ../../../src/src/pkcs11/pkcs11-session.c:126
#4  0x00007ffff79bf289 in C_CloseSession (hSession=93824992742416) at ../../../src/src/pkcs11/pkcs11-session.c:165
#5  0x0000555555560cc7 in main (argc=11, argv=0x7fffffffde88) at ../../../src/src/tools/pkcs11-tool.c:1503
(gdb) 

444	sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2E, 0x00, 0x00 /*pin ref: 0x01-0x0E, 0=ALL*/);

And it did indeed logout.

./opensc-tool -c default -s "00 20 00 01"
Using reader with a card: OMNIKEY AG CardMan 3821 00 00
Sending: 00 20 00 01 
Received (SW1=0x63, SW2=0xC5)

So problem is not with zero length pin and pin pad reader.

@Jakuje
Copy link
Member

Jakuje commented Oct 12, 2023

Can you try with 0.24.0-rc1 ?

What does "disconnect=leave" do?

this would prevent resetting the smart card when the opensc disconnects from the smart card. Not sure exactly when this happens, if the logout, does it or finalize.

The 0.21.0 defaults is disconnect=reset (unless modified by distribution) so you can try to modify the opensc.conf to use leave. Its easier for handling multiple applcations accessing a single SC, but it can cause different issues if the drivers can not keep the state in sync.

https://github.com/OpenSC/OpenSC/blob/0.21.0/etc/opensc.conf.example.in#L78

I do not see any explicit logout in the myeid driver in the 0.21.0 tag:

https://github.com/OpenSC/OpenSC/blob/0.21.0/src/libopensc/card-myeid.c

@frankmorgner
Copy link
Member

frankmorgner commented Oct 13, 2023

Is the code involved doing something wrong, or is this a bug in opensc?

I suspect this problem is caused by some code not being capable of handling concurrency correctly. PKCS#11 specifically mentions some use cases and I tend to assume that OpenSC's improvements up to the current version support conformance to the standard. However, many applications seem to have problems with some corner cases (NSS/Firefox 👀).

disconnect=reset is definitely something, that will break concurrent access and should be changed. Also, you may configure the PKCS#11 module to use atomic=true, which means that a login (logout) will happen before (after) every private key operation when the token is locked by a single applications. The PIN validation status will not be mixed up between two applications. However, in atomic mode a PIN pad reader will force the user to enter the PIN every time when it is used. Note that since 0.24.0-rc1 you can customize opensc.conf for each application, i.e. you can allow use of a PIN pad in your native app while disabling it for authentication in Firefox (enable_pinpad = false), which would allow you to use atomic mode in a reasonable manner.

If you cannot solve your problem, please describe more detailed what you mean by Firefox breaks application. And please try to reproduce this problem without your native app, e.g. by using pkcs11-tool --test --login while you're logged in in Firefox.

@minfrin
Copy link
Author

minfrin commented Oct 13, 2023

Is the code involved doing something wrong, or is this a bug in opensc?

I suspect this problem is caused by some code not being capable of handling concurrency correctly. PKCS#11 specifically mentions some use cases and I tend to assume that OpenSC's improvements up to the current version support conformance to the standard. However, many applications seem to have problems with some corner cases (NSS/Firefox 👀).

disconnect=reset is definitely something, that will break concurrent access and should be changed.

When you say "should be changed", does this refer to the defaults as shipped with opensc, or something more specific?

Also, you may configure the PKCS#11 module to use atomic=true, which means that a login (logout) will happen before (after) every private key operation when the token is locked by a single applications. The PIN validation status will not be mixed up between two applications. However, in atomic mode a PIN pad reader will force the user to enter the PIN every time when it is used.

This is exactly what I want in the application - for the PIN pad reader to force the user to enter the PIN ever time it is used. I definitely don't want this for Firefox, that will drive users mad.

Note that since 0.24.0-rc1 you can customize opensc.conf for each application, i.e. you can allow use of a PIN pad in your native app while disabling it for authentication in Firefox (enable_pinpad = false), which would allow you to use atomic mode in a reasonable manner.

The intention is to package this software and make it available for mere mortals to use, when you say "you can customize opensc.conf for each application", do you mean that it is possible for an OS package to drop a file into a directory like /etc/opensc.d/myapp.conf, or does a human (or some script) have to fiddle with the opensc.conf file on install?

If you cannot solve your problem, please describe more detailed what you mean by Firefox breaks application.

To be more specific, it appears this is "application breaks Firefox".

Most specifically, an application (whose source code for logging into the card and cleaning up is show above) successfully causes Firefox to log out of the smartcard, triggering a new request in Firefox to provide the PIN again, surprising the user and making their life difficult.

@frankmorgner
Copy link
Member

If you plan to package something for real users, you should switch to a version with less vulnerabilities!

Most smart cards don't support concurrent acces (which card do you use?), so every concurrency is implemented in software. This requires trusting the said software. If you do, then you can also trust the software to enforce a PIN verification when you want it to (even if the card is technically unlocked already). So, the simplest solution to your problem would be to track the login state of your token in your app without consulting the card and to not perform a logout (or reset) on cleanup.

@frankmorgner
Copy link
Member

If you plan to package only the native app and not the Firefox, you basically cannot influence Firefox's behavior to benefit from the atomic setting. This then also leaves the absence of a logout as only solution of two apps being logged in simultaniously (Firefox and your native app).

@frankmorgner
Copy link
Member

@dengert to some extent you're right as this is related to #2807. Not in the sense that implementing the logout functionality causes a problem, but in revealing that we are explicitly logging out of a token, when we close a PKCS#11 session. This happens, for example, on C_CloseAllSessions regardless of the disconnect=reset setting, which is only relevant for the PC/SC handle. This design decision was taken two decades ago. PKCS#11 technically dictates that "the login state of the token for the application returns to public sessions" when closing a session. But as said before, since most tokens don't support multiple applications being logged in simultanously, this would technically only be possible to be handled in software rather than relying on the token's capabilities of tracking the login state.

@dengert
Copy link
Member

dengert commented Oct 13, 2023

@minfrin can you build either the version of OpenSC you have or OpenSC 0.24.0-rc1 and try this patch:

diff --git a/src/libopensc/sec.c b/src/libopensc/sec.c
index c4b980127..a1eba9cc5 100644
--- a/src/libopensc/sec.c
+++ b/src/libopensc/sec.c
@@ -143,6 +143,16 @@ int sc_verify(sc_card_t *card, unsigned int type, int ref,
 
 int sc_logout(sc_card_t *card)
 {
+	scconf_block *conf_block = NULL;
+	conf_block = sc_get_conf_block(card->ctx, "framework", "pkcs15", 1);
+
+	if (conf_block) {
+		if (scconf_get_int(conf_block, "logout", 1) == 0) {
+			sc_log(card->ctx, "warning: sc_logout skipping logout");
+			return SC_ERROR_NOT_SUPPORTED;
+		}
+	}
+
 	if (card->ops->logout == NULL)
 		return SC_ERROR_NOT_SUPPORTED;
 	return card->ops->logout(card);

and add "logout = 0;" to your opensc.conf so it looks something like this:

app default {
         debug = 20; 
         debug_file = /tmp/opensc-debug.txt;
        framework pkcs15 {
                # use_file_caching = no; 
                # use_pin_cache = false;
                # use_file_caching = public;
                logout = 0;  
        }

@dengert
Copy link
Member

dengert commented Oct 14, 2023

@frankmorgner two decades ago is a step in the right direction. But OpenSC is run by each application in its own process. There is not system wide tracking of sessions and login state. And possibly by different users.

The only OS that I know of that provided a system wide PKCS11 was Sun's Solaris. It used it for all crypto operations. (I had a Sun workstation many years ago.)

PC/SC is usually only run by the OS. But it does not keep track of login state. The PC/SC docs say it could keep track of users but AFAIK PCSClite does not. @LudovicRousseau ?

The patch I suggested to @minfrin is simple way around the logout problem. It (or some similar patch) could be added to 0.24.0 incase other users run into the same problem.

In the @minfrin case, p11kit is also being used which may complicate the situation.

@LudovicRousseau
Copy link
Member

@dengert "The PC/SC docs say it could keep track of users but AFAIK PCSClite does not." Do you have a pointer to this PC/SC documentation?

@dengert
Copy link
Member

dengert commented Oct 14, 2023

"The PC/SC docs say it could keep track of users but AFAIK PCSClite does not." Do you have a pointer to this PC/SC documentation?

http:https://pcscworkgroup.com/Download/Specifications/pcsc1_v2.01.01.pdf Talks about:

2.4.1 System
The “system” is the computer and connected peripheral devices. These specifications
focus on personal computers with a single user; however, they can be extended to multiuser,
multiple terminal computers.

2.4.2 User
The “user” is the end user of the PC system. In general, a user is identified and
authenticated based on an Operating System–defined mechanism. Processes started on
behalf of the user are generally deemed to be running on the user’s behalf and have the
access rights and/or security attributes associated with the user. In terms of this
specification, the user is also the ICC cardholder."

This might require the OS to limit access to the reader at the device level to a specific user, much like limiting access to the keyboard and mouse to the terminal user. And this maybe sufficient. But if PC/SC is running as root accessing the device on behalf or a different user, this could lead to bypassing the OS access restrictions. I am not sure if this a problem or not or what it would take to fix it.

Although smart cards are normally used on single user workstations, these workstations may allow network access to other users( for example SSH) thus making these workstations: "multiuser, multiple terminal computers." So depending on what the OS can do, PC/SC may need to enforce: "the user is also the ICC cardholder." We also have HSM devices that may allow multiple users to access them. I believe SoftHSM controls access because user data is stored in files only accessible by the user.

@LudovicRousseau
Copy link
Member

I see. This is not the same as the dwScope parameter for SCardEstablishContext() https://learn.microsoft.com/fr-fr/windows/win32/api/winscard/nf-winscard-scardestablishcontext
And pcsc-lite does not use this value.

pcsc-lite supports polkit (https://github.com/LudovicRousseau/PCSC/blob/master/doc/README.polkit). Some GNU/Linux distribution (RedHat & Fedora, maybe others) only allow the use the PC/SC interface for the locally connected user. Maybe that can help.

@frankmorgner
Copy link
Member

@frankmorgner two decades ago is a step in the right direction. But OpenSC is run by each application in its own process. There is not system wide tracking of sessions and login state. And possibly by different users.

The only OS that I know of that provided a system wide PKCS11 was Sun's Solaris. It used it for all crypto operations. (I had a Sun workstation many years ago.)

Windows and Apple are tracking login states across process boundaries (via Minidriver and CTK). And this would also be possible to do via PKCS#11: Run a daemon in background that is the single process which accesses a token; then create a PKCS#11 library to connect to this daemon and forwarding every request including information about the requesting process/user. https://github.com/p11-glue/p11-kit could be the right place to implement such an access control, but as far as I know, this currently out of scope.

@dengert
Copy link
Member

dengert commented Oct 15, 2023

@LudovicRousseau polkit appears to address my concern.
On Ubuntu-22.04 polkit is installed and /usr/share/polkit-1/actions has 42 policy files but none with org.debian.pcsc-lite.policy

pcscd installs /usr/share/doc/pcscd/README.polkit but appear it was not built with --enable-polkit and does not install ./doc/org.debian.pcsc-lite.policy.

This is very helpful: https://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html

Thanks.

@dengert
Copy link
Member

dengert commented Oct 15, 2023

@frankmorgner good to hear: "Windows and Apple are tracking login states across process boundaries (via Minidriver and CTK)." and pcsc-lite can restrict access to readers if configured with --enable-polkit and polkit is also installed.

But I am afraid 0.24.0 with always logout from PKCS11 is going to introduce problems for many users.
As a precaution I would suggest we add some code like in: #2897 (comment) so users have an option.

We should still wait for @minfrin to try the patch.

@frankmorgner
Copy link
Member

Just one more clearification: We were talking about explicit logout of the token if a session is closed. However, when calling C_Logout explicitly, the login state of the token will be reset as well. Since according to PKCS#11, C_Logout is also limited to the calling application only, we may want to not logout explicitly here as well as this may impact other applications running in parallel.

Your patch Doug, does the job, so it is good for testing purposes. However, I think there are some problems with it.

  1. It should be possible to limit this configuration setting to PKCS#11, because CTK and MD have a global view
  2. The current configuration switch is located in the PKCS15 framework, which does not have an abstraction for logging out. We have an abstraction for validation/unblocking/changing, but not for logout. This could be an opportunity to strengthen the module separation within OpenSC.

My preference would be to make this option part of the PKCS#11 configuration, which would respect 1. and avoid big refactoring (2.).

@dengert
Copy link
Member

dengert commented Oct 18, 2023

@frankmorgner A parameter to pkcs11/misc.c and opensc.conf something like this:

app opensc-pkcs11 {
        pkcs11 {
                 logout = 0    
...

PKCS11 calls sc_logout is called from pkcs15_logout here:
https://github.com/OpenSC/OpenSC/blob/master/src/pkcs11/framework-pkcs15.c#L1934

and pkcs15_logout is called indirectly from:
https://github.com/OpenSC/OpenSC/blob/master/src/pkcs11/pkcs11-session.c#L126

https://github.com/OpenSC/OpenSC/blob/master/src/pkcs11/pkcs11-session.c#L442

C_logout is used to cleanup memory but does not need to call sc_logout.

@Jakuje
Copy link
Member

Jakuje commented Oct 18, 2023

I am not happy with introducing yet another configuration option that would be up to user/system administrator/packager to tune, modify and make sure it is set up correctly for given deployment/use-case. In any case, I think we should have some sane default that should work. And in linux, multiple applications using the same pkcs11 module is still unsolved issue.

  • If we force logout we break concurrent applications
  • If we don't we are opening to PIN bypass

I think if we want to address both of the issues, the card logout should not be called from C_Logout() or C_CloseSession() by default (when it should be called then?) and we can not rely on the card login state inside OpenSC, at least not for the first switch of the session from the not-logged in state to logged in state (with zero-length pin, without pinpad reader -- this would be the alternative to the system-wide context you have in Windows/Mac).

I think developing and deploying system-wide pkcs11 module in linux would be a long shot (I think opencryptoki has something like that, pkcslotd daemon, but it requires complete rethink of the access to the tokens). Something like that could be already put together using p11-kit remoting but users are used to access pkcs11 modules directly over the last decades so the change wont be fast. We might want to have a look into this more later, but we will need some short-term solution earlier for 0.24.0 release as this seems to be quite pain with rc1.

@frankmorgner
Copy link
Member

@Jakuje I agree, although I find it sad to re-implement the PIN status tracking in software even though the card is doing the same. I also like the idea of a background service (have seen this in proprietary PKCS#11 modules as well), which may also give us the opportunity to throw away some of todays complexity of opensc-pkcs11.so. We could also think about implementing this e.g. in rust...

As a side note, if we rely on the PKCS#11 module's pin status tracking as intermediate solution, we also need to restrict the use of sc_pkcs15_get_pin_info()...

@dengert
Copy link
Member

dengert commented Oct 19, 2023

I find it sad to re-implement the PIN status tracking in software even though the card is doing the same.

Most cards can respond to VERIFY with Lc=0 to query number of retries SW=(63 CX) or login state is logged_in SW=(90 00)

Form a PIV perspective, NIST did not define a logout command until 800-73-4:
"If P1='FF', and Lc and the command data field are absent, the command shall reset the security status of the key reference in P2. The security status of the key reference specified in P2 shall be set to FALSE and the retry counter associated with the key reference shall remain unchanged."

d7fadae was added by @frankmorgner post 0.23.0 which will try logout any every PIV type card in 0.24.0-rc1.

@frankmorgner
Copy link
Member

You can find my proposal here: #2907

That being said, I'm not quite sure if it fixes the OP's issue, because above it was stated that login in process A triggers logout in process B and I cannot quite see how this can happen at all...

@dengert
Copy link
Member

dengert commented Oct 20, 2023

You can find my proposal here: #2907

needs #if defined(SW_PIN_LOGOUT_ONLY) && SW_PIN_LOGOUT_ONLY == 1 for int rc; at: https://github.com/OpenSC/OpenSC/pull/2907/files#diff-a456d510424af4a38a7f5993e94ae1bf7932e6524792cb87f6f77872b9fd6a7cR1930

That being said, I'm not quite sure if it fixes the OP's issue, because above it was stated that login in process A triggers logout in process B and I cannot quite see how this can happen at all...

Where does "it" say that? Only if a different PIN pin is used?

Or the error handling in Process B can not handle card/token returning 69 82 which should return to to calling application CKR_USER_NOT_LOGGED_IN.

@frankmorgner
Copy link
Member

The combination of login/logout is stated in the OP's title.

Could you elaborate on the issue regarding SW 69 82?

@frankmorgner
Copy link
Member

If the merge #2907 didn't solve the problem, please elaborate.

@minfrin
Copy link
Author

minfrin commented Mar 14, 2024

Finally got a chance to properly test this, I needed to rebuild a system from scratch to do it - TL;DR it works great.

Firefox+OpenSC v0.25 on a Mac, along with VMWare Fusion containing Fedora Rawhide+OpenSC v0.25 and Windows 11 + Aventra drivers, all sharing the same smartcard at the same time, and no more login popups (caused by apps logging other apps out).

Thank you for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants