{"action":"created","issue":{"url":"https://api.github.com/repos/OpenSC/OpenSC/issues/596","labels_url":"https://api.github.com/repos/OpenSC/OpenSC/issues/596/labels{/name}","comments_url":"https://api.github.com/repos/OpenSC/OpenSC/issues/596/comments","events_url":"https://api.github.com/repos/OpenSC/OpenSC/issues/596/events","html_url":"https://github.com/OpenSC/OpenSC/issues/596","id":114373183,"number":596,"title":"DNIe looses login after the card is used by another program","user":{"login":"rickyepoderi","id":1576140,"avatar_url":"https://avatars.githubusercontent.com/u/1576140?v=3","gravatar_id":"","url":"https://api.github.com/users/rickyepoderi","html_url":"https://github.com/rickyepoderi","followers_url":"https://api.github.com/users/rickyepoderi/followers","following_url":"https://api.github.com/users/rickyepoderi/following{/other_user}","gists_url":"https://api.github.com/users/rickyepoderi/gists{/gist_id}","starred_url":"https://api.github.com/users/rickyepoderi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rickyepoderi/subscriptions","organizations_url":"https://api.github.com/users/rickyepoderi/orgs","repos_url":"https://api.github.com/users/rickyepoderi/repos","events_url":"https://api.github.com/users/rickyepoderi/events{/privacy}","received_events_url":"https://api.github.com/users/rickyepoderi/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":68,"created_at":"2015-10-30T23:36:45Z","updated_at":"2015-12-05T11:07:58Z","closed_at":null,"body":"Hi again,\r\n\r\nOnce the another issue is fixed (issue #480 ) I've been trying to continue testing the DNIe. There is another problem but this time (I think) it is related to the card internals.\r\n\r\nFirst I'm going to describe the problem:\r\n\r\n1.- Go to the DNIe test page:  https://av-dnie.cert.fnmt.es/compruebacert/compruebacert\r\n2.- The browser requests the password and the https process is completed successfully. \r\n3.- Inside the page the information of the certificate is shown. There is a second link that let you test a signature process.\r\n4.- Click the signature link. The new page starts a Java applet (a separate program) that performs a signature sample (it again requests the password and so on).\r\n5.- The signature process also completes successfully.\r\n6.- Reload again the https page. \r\n7.- Here an error is displayed: SC_ERROR_SECURITY_STATUS_NOT_SATISFIED => CKR_USER_NOT_LOGGED_IN. This error continues until you unplug the card from the reader.\r\n\r\nI've been looking the code for a long time, and I think the issue can be described like this:\r\n\r\n1.- It seems that the DNIe can only maintain one secure channel at a time (I don't know if this is a typical behavior or not). The DNIe implementation take this fact into account and the secure channel is re-established if broken, this re-connection is done in the dnie_wrap_apdu function inside cwa-dnie.c:\r\n\r\n                if ( res == SC_ERROR_SM ) {\r\n                        sc_log(ctx,\"Detected SM error/collision. Try %d\",retries);\r\n                        switch(provider->status.session.state) {\r\n                                /* No SM or creating: collision with other process\r\n                                   just retry as SM error reset ICC SM state */\r\n                                case CWA_SM_NONE:\r\n                                case CWA_SM_INPROGRESS:\r\n                                        continue;\r\n                                /* SM was active: force restart SM and retry */\r\n                                case CWA_SM_ACTIVE:\r\n                                        res=cwa_create_secure_channel(card, provider, CWA_SM_COLD);\r\n                                        LOG_TEST_RET(ctx,res,\"Cannot re-enable SM\");\r\n                                        continue;\r\n                        }\r\n                }\r\n\r\n2.- But the current problem is that (although the channel is correctly re-established) the card has also lost the pin (the user is not logged in). Therefore the card return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED. the card also needs to pin_verify again if the secure channel is broken. I think the behavior is intrinsic to DNIe (if you re-create the secure channel, you have to pin_verify also).\r\n3.- Nevertheless inside the pkcs11 layer the slot is still marked as logged in (session->slot->login_user is still set to CKU_USER). So C_GetSessionInfo continues informing the browser that the session is logged in.\r\n\r\nYou can workaround the situation manually logging out or unplugging the card. Firefox logs the user again and everything starts working.\r\n\r\nI've been thinking how to overcome the situation but (I think) it isn't going to be easy. I tried two different approaches. The first one doesn't work and the second solution is very invasive inside opensc code:\r\n\r\n1.- The first solution added a new opensc error that was translated to standard CKR_PIN_EXPIRED pkcs11 error (this error means that the PIN has expired and you need to re-login). But firefox does not act like I wanted and it does not re-login (because C_GetSessionInfo still returns the session is logged, it refuses to re-login although the previous error).\r\n\r\n2.- I added a simple change inside framework-pkcs15.c in order to clean the state (session->slot->login_user = -1) in the pkcs15_prkey_sign function:\r\n\r\n    *** framework-pkcs15.c.ORIG\t2015-10-30 21:40:17.501635616 +0100\r\n    --- framework-pkcs15.c\t2015-10-30 22:11:01.794737610 +0100\r\n    *************** pkcs15_prkey_sign(struct sc_pkcs11_sessi\r\n    *** 3590,3595 ****\r\n    --- 3590,3600 ----\r\n      \t\t\t\t\tpData, ulDataLen, pSignature, *pulDataLen);\r\n      \t}\r\n      \r\n    + \tif (rv == SC_ERROR_PIN_EXPIRED) {\r\n    + \t\tsc_log(context, \"RICKY, setting the slot as not logged in...\");\r\n    + \t\tsession->slot->login_user = -1;\r\n    + \t}\r\n    + \r\n      \tsc_unlock(p11card->card);\r\n      \r\n      \tsc_log(context, \"Sign complete. Result %d.\", rv);\r\n\r\nAs you see, if the new error SC_ERROR_PIN_EXPIRED is returned the session is cleaned. Firefox returns an error the first time but then it realizes that the session is not logged in and requests for the password again. But this change (or a similar one) should be added to a lot of functions in the framework-pkcs15.c file.\r\n\r\nI don't know how to continue. I'm just opening this issue to request an advise from you. Do you know any other card that expires the PIN? How can I inform the pkcs11 layer that the pin is expired and a re-login is necessary?\r\n\r\nSorry for being so stubborn but this DNIe is a pain in the ass.\r\n\r\nThanks!"},"comment":{"url":"https://api.github.com/repos/OpenSC/OpenSC/issues/comments/162172921","html_url":"https://github.com/OpenSC/OpenSC/issues/596#issuecomment-162172921","issue_url":"https://api.github.com/repos/OpenSC/OpenSC/issues/596","id":162172921,"user":{"login":"rickyepoderi","id":1576140,"avatar_url":"https://avatars.githubusercontent.com/u/1576140?v=3","gravatar_id":"","url":"https://api.github.com/users/rickyepoderi","html_url":"https://github.com/rickyepoderi","followers_url":"https://api.github.com/users/rickyepoderi/followers","following_url":"https://api.github.com/users/rickyepoderi/following{/other_user}","gists_url":"https://api.github.com/users/rickyepoderi/gists{/gist_id}","starred_url":"https://api.github.com/users/rickyepoderi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rickyepoderi/subscriptions","organizations_url":"https://api.github.com/users/rickyepoderi/orgs","repos_url":"https://api.github.com/users/rickyepoderi/repos","events_url":"https://api.github.com/users/rickyepoderi/events{/privacy}","received_events_url":"https://api.github.com/users/rickyepoderi/received_events","type":"User","site_admin":false},"created_at":"2015-12-05T11:07:58Z","updated_at":"2015-12-05T11:07:58Z","body":"There is a problem with sc_pkcs15_pincache_revalidate in the last modifications, it seems that the pin is not found, I think the problem is that you're using the wrong object (a sc_pkcs15_prkey_info instead of a sc_pkcs15_object) to call the function. With this change it works again:\r\n```\r\ndiff --git a/src/libopensc/pkcs15-sec.c b/src/libopensc/pkcs15-sec.c\r\nindex 5953fa5..8db083d 100644\r\n--- a/src/libopensc/pkcs15-sec.c\r\n+++ b/src/libopensc/pkcs15-sec.c\r\n@@ -81,7 +81,7 @@ static int select_key_file(struct sc_pkcs15_card *p15card,\r\n }\r\n \r\n static int use_key(struct sc_pkcs15_card *p15card,\r\n-               const struct sc_pkcs15_prkey_info *prkey,\r\n+               const struct sc_pkcs15_object *obj,\r\n                sc_security_env_t *senv,\r\n                int (*card_command)(sc_card_t *card,\r\n                         const u8 * in, size_t inlen,\r\n@@ -90,6 +90,7 @@ static int use_key(struct sc_pkcs15_card *p15card,\r\n {\r\n        int r = SC_SUCCESS;\r\n        int revalidated_cached_pin = 0;\r\n+       const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data;\r\n \r\n        r = sc_lock(p15card->card);\r\n        LOG_TEST_RET(p15card->card->ctx, r, \"sc_lock() failed\");\r\n@@ -112,8 +113,7 @@ static int use_key(struct sc_pkcs15_card *p15card,\r\n                        /* only re-validate once */\r\n                        break;\r\n                if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) {\r\n-                       r = sc_pkcs15_pincache_revalidate(p15card,\r\n-                                       (const struct sc_pkcs15_object *) prkey);\r\n+                       r = sc_pkcs15_pincache_revalidate(p15card, obj);\r\n                        if (r < 0)\r\n                                break;\r\n                        revalidated_cached_pin = 1;\r\n@@ -216,8 +216,7 @@ int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,\r\n        LOG_TEST_RET(ctx, r, \"cannot encode security operation flags\");\r\n        senv.algorithm_flags = sec_flags;\r\n \r\n-       r = use_key(p15card, prkey, &senv, sc_decipher, in, inlen, out,\r\n-                       outlen);\r\n+       r = use_key(p15card, obj, &senv, sc_decipher, in, inlen, out, outlen);\r\n        LOG_TEST_RET(ctx, r, \"use_key() failed\");\r\n \r\n        /* Strip any padding */\r\n@@ -274,8 +273,7 @@ int sc_pkcs15_derive(struct sc_pkcs15_card *p15card,\r\n        LOG_TEST_RET(ctx, r, \"cannot encode security operation flags\");\r\n        senv.algorithm_flags = sec_flags;\r\n \r\n-       r = use_key(p15card, prkey, &senv, sc_decipher, in, inlen, out,\r\n-                       *poutlen);\r\n+       r = use_key(p15card, obj, &senv, sc_decipher, in, inlen, out, *poutlen);\r\n        LOG_TEST_RET(ctx, r, \"use_key() failed\");\r\n \r\n        /* Strip any padding */\r\n@@ -431,8 +429,7 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,\r\n                inlen = modlen;\r\n        }\r\n \r\n-       r = use_key(p15card, prkey, &senv, sc_compute_signature, tmp, inlen,\r\n-                       out, outlen);\r\n+       r = use_key(p15card, obj, &senv, sc_compute_signature, tmp, inlen, out, outlen);\r\n        LOG_TEST_RET(ctx, r, \"use_key() failed\");\r\n        sc_mem_clear(buf, sizeof(buf));\r\n \r\n```"}}