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

CAC regression? #1533

Closed
mouse07410 opened this issue Nov 14, 2018 · 46 comments
Closed

CAC regression? #1533

mouse07410 opened this issue Nov 14, 2018 · 46 comments

Comments

@mouse07410
Copy link
Contributor

Problem Description

When I specify in opensc.conf the driver to use for the CAC as

# DOD CAC
        card_atr 3b:7a:18:00:00:73:66:74:65:20:63:64:31:34:34 {
                driver = "cac";
                name = "DOD CAC";
        }

I am unable to login to remote Web sites via Firefox: it keeps prompting for a PIN forever.

Proposed Resolution

My workaround was to comment out the driver = "cac";, letting the PIV driver to take over. Then I can login fine.

This problem started occuring after CAC1 (the old model) support was re-integrated. Before that CAC driver worked just fine.

Steps to reproduce

  • Build OpenSC.
  • Load Security Device in Firefox, pointing at /Library/OpenSC/lib/opensc-pkcs11.dylib.
  • Insert CAC, go to any DOD web site that wants CAC, e.g., https://owa.us.af.mil and observe the problem.

Logs

Not sure how to capture a log from Firefox.

@dengert
Copy link
Member

dengert commented Nov 14, 2018

/* CAC cards */
    SC_CARD_TYPE_CAC_BASE = 33000,
     SC_CARD_TYPE_CAC_GENERIC,
     SC_CARD_TYPE_CAC_I,
     SC_CARD_TYPE_CAC_II,

Try adding type = 33003; if it is SC_CARD_TYPE_CAC_II

Just a hunch, and is easy to try.

@mouse07410
Copy link
Contributor Author

mouse07410 commented Nov 14, 2018

I have more than one token inserted - a CAC, a Yubikey, a YubiHSM2.

When I added type = 33003; to the appropriate opensc.conf entry, the CAC started working again - but Firefox got into an infinite loop over the other token.

When everything works, it prompts me for a PIN for each token, and then offers a certificate that matches what the server asked for (CAC in this case). So I'd enter a PIN for each token once. Before trying your suggestion, Firefox would enter an infinite loop, asking for the CAC PIN. Now it enters infinite loop asking for the Yubikey PIN - but once I cancel that, it proceeds to the DOD web site correctly.

My conclusion/guess is - something in the CAC detection mechanism of the new driver is screwed up.

Update
My opensc.conf excerpt:

. . . . .
        # Yubikey is known to have the PIV applet and the OpenPGP applet. OpenSC
        # can handle both to access keys and certificates, but only one at a time.
        card_atr 3b:f8:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:34:d4 {
                name = "Yubikey 4";
                # Select the PKI applet to use ("PIV-II" or "openpgp")
                driver = "PIV-II";
                # Recover from other applications accessing a different applet
                flags = "keep_alive";
                pkcs11_enable_InitToken = yes;
        }
        card_atr 3b:fc:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:4e:45:4f:72:33:e1 {
                name = "Yubikey Neo";
                # Select the PKI applet to use ("PIV-II" or "openpgp")
                driver = "PIV-II";
                # Recover from other applications accessing a different applet
                flags = "keep_alive";
                pkcs11_enable_InitToken = yes;
        }
        # DOD CAC
        card_atr 3b:7a:18:00:00:73:66:74:65:20:63:64:31:34:34 {
                driver = "cac";
                type = 33003';
                name = "DOD CAC";
        }
. . . . .

Update 2
When I comment out the driver = "cac"; and type... in the above, it all works fine again. New driver is bad, and it appears to interfere with the PIV driver.

@dengert
Copy link
Member

dengert commented Nov 15, 2018

Problem could be in card.c line 252: if (card->ops->match_card(card) != 1)
Even though the card->ops->match_card(card) failed, it may have modified the card structure and then card->ops->init(card) is called. One of the drivers involved may not handle this correctly.

I don't know if we test forcing a driver very well.

A debug log would help. You can start firefox from a script and have OPENSC_DEBUG=3 and OPENSC_DEBUG_FILE=/tmp/opensc.debug.log set in the script. (Check the env names.)
You could also use the OPENSC_CONF= to point to a modified opensc.conf.

@frankmorgner
Copy link
Member

Try to isolate the problem:

  • use a single card
  • use `pkcs11-tool --test

Generate logs with debug = 3 in opensc.conf, this even works in Firefox (whoa!). I think you're working long enough with OpenSC to know that we can't do the debugging for you, so please try to get to the ground yourself as good as possible.

@dengert
Copy link
Member

dengert commented Nov 15, 2018

Are you using p11-kit? Or just opensc-pkcs11.so.

Prior to the regression Firefox would preset a list of certificates to use. Do there certificates have the same subjectName? Are they signed by the same CA? Firefox might get mixed up if same subjectName.

Prior to the regression it all worked, and your card was recognized as a CAC card. Do you have a log of that to compare to current logs.

As Frank said, can you get pkcs11-tool to fail to select the CAC card without the card_atr ? before and after regression.

@mouse07410
Copy link
Contributor Author

Are you using p11-kit? Or just opensc-pkcs11.so.

AFAIK, only opensc-pkcs11.so, because it's how Firefox works.

Prior to the regression Firefox would preset a list of certificates to use. Do there certificates have the same subjectName? Are they signed by the same CA?

No to both. Different DN's with different chain of trust and different CAs.

Prior to the regression it all worked, and your card was recognized as a CAC card.

I think the card is still recognized as a CAC card (and the "cac" driver was forced in opensc.conf) - the problem is it stopped behaving correctly.

Do you have a log of that to compare to current logs.

Alas, I don't.

As Frank said, can you get pkcs11-tool to fail to select the CAC card without the card_atr ? before and after regression.

I'll try - but I don't think it's the problem of selecting the card - every time I enter the PIN, the appropriate card reader blinks, so apparently they are in communication (i.e., the card is selected and being talked to).

@mouse07410
Copy link
Contributor Author

First, I rebuilt OpenSC with the current (as of last night) master.

I started with OPENSC_CONF=${HOME}/opensc-cac.conf pkcs11-tool ......, and everything appeared to work. Then I re-inserted Yubikey 4 (HSM2 stayed in all the time, as it isn't on the PKCS#11 slot list), and it still worked:

$ OPENSC_CONF=/Users/ur20980/opensc-cac.conf pkcs11-tool -L
Available slots:
Slot 0 (0x0): Yubico Yubikey 4 OTP+U2F+CCID
  token label        : Bxxxxxxxx, Uri (UR20980)
  token manufacturer : piv_II
  token model        : PKCS#15 emulated
  token flags        : login required, rng, token initialized, PIN initialized
  hardware version   : 0.0
  firmware version   : 0.0
  serial num         : bbbbbbbbbbbbbbbbb
  pin min/max        : 4/8
Slot 1 (0x4): SCR3310 Smart Card Reader
  token label        : Bxxxxxxxxx.URI.1xxxxxxxx
  token manufacturer : Common Access Card
  token model        : PKCS#15 emulated
  token flags        : login required, rng, token initialized, PIN initialized
  hardware version   : 0.0
  firmware version   : 0.0
  serial num         : 999999999999999
  pin min/max        : 4/8
$ OPENSC_CONF=/Users/ur20980/opensc-cac.conf pkcs11-tool --slot 0x4 --test --login
Logging in to "Bxxxxx.URI.1xxxxxxx".
Please enter User PIN: 
C_SeedRandom() and C_GenerateRandom():
  seeding (C_SeedRandom) not supported
  seems to be OK
Digests:
  all 4 digest functions seem to work
  MD5: OK
  SHA-1: OK
  RIPEMD160: OK
Signatures (currently only for RSA)
  testing key 0 (CAC ID Certificate) 
  all 4 signature functions seem to work
  testing signature mechanisms:
    RSA-X-509: OK
    RSA-PKCS: OK
    SHA1-RSA-PKCS: OK
    MD5-RSA-PKCS: OK
    RIPEMD160-RSA-PKCS: OK
    SHA256-RSA-PKCS: OK
  testing key 1 (2048 bits, label=CAC Email Signature Certificate) with 1 signature mechanism
    RSA-X-509: OK
  testing key 2 (2048 bits, label=CAC Email Encryption Certificate) with 1 signature mechanism -- can't be used to sign/verify, skipping
  testing key 3 (2048 bits, label=CAC Cert 4) with 1 signature mechanism
    RSA-X-509: OK
Verify (currently only for RSA)
  testing key 0 (CAC ID Certificate)
    RSA-X-509: OK
    RSA-PKCS: OK
    SHA1-RSA-PKCS: OK
    MD5-RSA-PKCS: OK
    RIPEMD160-RSA-PKCS: OK
  testing key 1 (CAC Email Signature Certificate) with 1 mechanism
    RSA-X-509: OK
  testing key 2 (CAC Email Encryption Certificate) with 1 mechanism -- can't be used to sign/verify, skipping
  testing key 3 (CAC Cert 4) with 1 mechanism
    RSA-X-509: OK
Unwrap: not implemented
Decryption (currently only for RSA)
  testing key 0 (CAC ID Certificate)  -- can't be used to decrypt, skipping
  testing key 1 (CAC Email Signature Certificate)  -- can't be used to decrypt, skipping
  testing key 2 (CAC Email Encryption Certificate) 
    RSA-X-509: OK
    RSA-PKCS: OK
  testing key 3 (CAC Cert 4)  -- can't be used to decrypt, skipping
No errors
$ 

This is what happens when the driver is not selected by ATR:

$ pkcs11-tool -L
Available slots:
Slot 0 (0x0): Yubico Yubikey 4 OTP+U2F+CCID
  token label        : Bxxxxxxxxx, Uri (UR20980)
  token manufacturer : piv_II
  token model        : PKCS#15 emulated
  token flags        : login required, rng, token initialized, PIN initialized
  hardware version   : 0.0
  firmware version   : 0.0
  serial num         : bbbbbbbbbbbbbbbbbbbbb
  pin min/max        : 4/8
Slot 1 (0x4): SCR3310 Smart Card Reader
  token label        : BxxxxxxxxxxL.URI.1xxxxxxxxxx
  token manufacturer : piv_II
  token model        : PKCS#15 emulated
  token flags        : login required, rng, token initialized, PIN initialized
  hardware version   : 0.0
  firmware version   : 0.0
  serial num         : d1dddddddddddddddddd
  pin min/max        : 4/8
$ pkcs11-tool --slot 0x4 --test --login
Logging in to "Bxxxxxxxx.URI.1xxxxxxxxxxxx".
Please enter User PIN: 
C_SeedRandom() and C_GenerateRandom():
  seeding (C_SeedRandom) not supported
  ERR: C_GenerateRandom failed: CKR_DATA_INVALID (0x20)
Digests:
  all 4 digest functions seem to work
  MD5: OK
  SHA-1: OK
  RIPEMD160: OK
Signatures (currently only for RSA)
  testing key 0 (PIV AUTH key) 
  all 4 signature functions seem to work
  testing signature mechanisms:
    RSA-X-509: OK
    RSA-PKCS: OK
    SHA1-RSA-PKCS: OK
    MD5-RSA-PKCS: OK
    RIPEMD160-RSA-PKCS: OK
    SHA256-RSA-PKCS: OK
  testing key 1 (2048 bits, label=SIGN key) with 1 signature mechanism
Logging in to "Bxxxxxxxxxxx.URI.1xxxxxxxxxxxxxxx".
Please enter context specific PIN: 
    RSA-X-509: OK
  testing key 2 (2048 bits, label=KEY MAN key) with 1 signature mechanism -- can't be used to sign/verify, skipping
Verify (currently only for RSA)
  testing key 0 (PIV AUTH key)
    RSA-X-509: OK
    RSA-PKCS: OK
    SHA1-RSA-PKCS: OK
    MD5-RSA-PKCS: OK
    RIPEMD160-RSA-PKCS: OK
  testing key 1 (SIGN key) with 1 mechanism
Logging in to "Bxxxxxxxxxxx.URI.1xxxxxxxxxx".
Please enter context specific PIN: 
    RSA-X-509: OK
  testing key 2 (KEY MAN key) with 1 mechanism -- can't be used to sign/verify, skipping
Unwrap: not implemented
Decryption (currently only for RSA)
  testing key 0 (PIV AUTH key) 
    RSA-X-509: OK
    RSA-PKCS: OK
  testing key 1 (SIGN key) 
    RSA-X-509: Logging in to "Bxxxxxxxxxxx.URI.1xxxxxxxxxxx".
Please enter context specific PIN: 
OK
    RSA-PKCS: Logging in to "Bxxxxxxxxxxxxxx.URI.1xxxxxxxxx".
Please enter context specific PIN: 
OK
  testing key 2 (KEY MAN key) 
    RSA-X-509: OK
    RSA-PKCS: OK
1 errors
$ 

BTW, note how crazy it got regarding "context-specific PIN", asking for it every time even when it's clearly unnecessary (e.g., for KEY MAN key).

Then I tried

$ OPENSC_CONF=${HOME}/opensc-cac.conf /Applications/FirefoxDeveloperEdition.app/Contents/MacOS/firefox

To my surprise, it worked as expected:
opensc-cac-debug3.log.txt
So, not sure if it would be of any use. But I'm happy that it seems to work now.

I guess I could/should close this issue...

@dengert
Copy link
Member

dengert commented Nov 15, 2018

As for the "crazy" part:

There was a mod added on behalf of Yubico users who wanted to use different key attributes then defined in NIST 800-73. It only allied to a non government cards, (FASC-N in CHUID not present or starts with 9999) For a non government card pkcs15-piv.c to use the certificates keyUsage attribute to map to the SC_PKCS15_PRKEY_USAGE_* bits. For the retired keys pkcs15-piv.c would set user_consent, not the first 4 keys.

if (i >= 4 && (ckis[i].priv_usage & SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)) {
                                                 prkey_obj.user_consent = 1;

These lines all show the 4 keys have the 0x02 SC_X509_NON_REPUDIATION bit set.
Have a look at the certificates and see if nonRepudition is set.

But this should not be a problem with the 4 main certificates, as

If these are signed by your CA you may want to reevaluate what keyUsage bits you are setting.

0x7fff8ff1d380 14:39:36.353 [opensc-pkcs11] pkcs15-piv.c:1197:sc_pkcs15emu_piv_init: USAGE: cert_keyUsage_present:1 usage:0x0000002e
0x7fff8ff1d380 14:39:36.353 [opensc-pkcs11] pkcs15-piv.c:1197:sc_pkcs15emu_piv_init: USAGE: cert_keyUsage_present:1 usage:0x0000022e
0x7fff8ff1d380 14:39:36.353 [opensc-pkcs11] pkcs15-piv.c:1197:sc_pkcs15emu_piv_init: USAGE: cert_keyUsage_present:1 usage:0x00000022
0x7fff8ff1d380 14:39:36.353 [opensc-pkcs11] pkcs15-piv.c:1197:sc_pkcs15emu_piv_init: USAGE: cert_keyUsage_present:1 usage:0x0000002e

@dengert
Copy link
Member

dengert commented Nov 16, 2018

Disregard the above. looking closer at your:

  testing key 0 (PIV AUTH key) 
    RSA-X-509: OK
    RSA-PKCS: OK
  testing key 1 (SIGN key) 
    RSA-X-509: Logging in to "Bxxxxxxxxxxx.URI.1xxxxxxxxxxx".
Please enter context specific PIN: 
OK
    RSA-PKCS: Logging in to "Bxxxxxxxxxxxxxx.URI.1xxxxxxxxx".
Please enter context specific PIN: 
OK
  testing key 2 (KEY MAN key) 
    RSA-X-509: OK
    RSA-PKCS: OK
1 errors

Looks correct. pkcs11-tool tests the "key 1 (SIGN key)" with RSA-X-509 and RSA-PKCS. So two sign operations are done, each prompts for the context specific pin, does the crypto and write "OK"

pkcs11-test then goes on to test "key 2 (KEY MAN key)" with RSA-X-509 and RSA-PKCS but does not prompt because user is still logged into card.

@mouse07410
Copy link
Contributor Author

Looks correct. pkcs11-tool tests the "key 1 (SIGN key)" with RSA-X-509 and RSA-PKCS. So two sign operations are done, each prompts for the context specific pin, does the crypto and write "OK"

I still want to revert this to being prompted as needed instead of when the OpenSC software thinks the card may want to re-authenticate (and being wrong most of the time, at least for single-run invocations).

@dengert
Copy link
Member

dengert commented Nov 16, 2018

Live with it. We have had these discussions before.

You can always go with the `ignore_user_consent" and "use_pin_caching".

@mouse07410
Copy link
Contributor Author

You can always go with the `ignore_user_consent" and "use_pin_caching".

Alas, that setting appears to be ignored, as you could observe in the above screen log.

@dengert
Copy link
Member

dengert commented Nov 16, 2018

What is missing is ignore_user_consent and use_pin_caching are used for applications that
don't query for CKA_ALWAYS_AUTHENTICATE. But if an applications does query for CKA_ALWAYS_AUTHENTICATE it is returned and the application will then do a context specific login etc.

What is missing is an override_user_consent which would never return CKA_ALWAYS_AUTHENTICATE=TRUE, and would fall back to use_pin_caching which should/must be set.

This could be implemented in framework-pkcs15.c for all cards, or after pkcs15-piv.c line 1196 as the last operation in the loop to test if override_user_consent is set, and do prkey_obj.user_consent = 0;

You could test this by adding the one line (and make sure use_pin_caching is set):

--- a/src/libopensc/pkcs15-piv.c
+++ b/src/libopensc/pkcs15-piv.c
@@ -1194,6 +1194,7 @@ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DEE Adding pin %d label=%s",i, label);
                                sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsupported key_alg %d", ckis[i].key_alg);
                                r = 0; /* we just skip this one */
                }
+               prkey_obj.user_consent = 0; /****** TEST ******/
                sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"USAGE: cert_keyUsage_present:%d usage:0x%8.8x", ckis[i].cert_keyUsage_present ,prkey_info.usage);
                if (r < 0)
                        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);

@dengert
Copy link
Member

dengert commented Nov 16, 2018

The patch should have been: prkey_obj.user_consent = 0; /****** TEST ******/

@mouse07410
Copy link
Contributor Author

   prkey_obj.user_consent = 0; /****** TEST ******/

Should the above force override_user_consent?

P.S. I have both pin_caching and override_user_consent set appropriately (it was also needed to sign Java JARs with a key on the token).

@mouse07410
Copy link
Contributor Author

Tested. It became worse:

$ pkcs11-tool --test --login
Using slot 0 with a present token (0x0)
Logging in to "Bxxxx, Uri (UR20980)".
Please enter User PIN: 
C_SeedRandom() and C_GenerateRandom():
  seeding (C_SeedRandom) not supported
  seems to be OK
Digests:
  all 4 digest functions seem to work
  MD5: OK
  SHA-1: OK
  RIPEMD160: OK
Signatures (currently only for RSA)
  testing key 0 (PIV AUTH key) 
  all 4 signature functions seem to work
  testing signature mechanisms:
    RSA-X-509: OK
    RSA-PKCS: OK
    SHA1-RSA-PKCS: OK
    MD5-RSA-PKCS: OK
    RIPEMD160-RSA-PKCS: OK
    SHA256-RSA-PKCS: OK
  testing key 1 (2048 bits, label=SIGN key) with 1 signature mechanism
Logging in to "Bxxxxxx, Uri (UR20980)".
Please enter context specific PIN: 
    RSA-X-509: OK
  testing key 2 (2048 bits, label=KEY MAN key) with 1 signature mechanism -- can't be used to sign/verify, skipping
  testing key 3 (2048 bits, label=CARD AUTH key) with 1 signature mechanism
    RSA-X-509: OK
Verify (currently only for RSA)
  testing key 0 (PIV AUTH key)
    RSA-X-509: OK
    RSA-PKCS: OK
    SHA1-RSA-PKCS: OK
    MD5-RSA-PKCS: OK
    RIPEMD160-RSA-PKCS: OK
  testing key 1 (SIGN key) with 1 mechanism
Logging in to "Bxxxxxxxx, Uri (UR20980)".
Please enter context specific PIN: 
    RSA-X-509: OK
  testing key 2 (KEY MAN key) with 1 mechanism -- can't be used to sign/verify, skipping
  testing key 3 (CARD AUTH key) with 1 mechanism
    RSA-X-509: OK
Unwrap: not implemented
Decryption (currently only for RSA)
  testing key 0 (PIV AUTH key) 
    RSA-X-509: OK
    RSA-PKCS: OK
  testing key 1 (SIGN key) 
    RSA-X-509: Logging in to "Bxxxxxxxx, Uri (UR20980)".
Please enter context specific PIN: 
OK
    RSA-PKCS: Logging in to "Bxxxxxxx, Uri (UR20980)".
Please enter context specific PIN: 
OK
  testing key 2 (KEY MAN key) 
    RSA-X-509: OK
    RSA-PKCS: OK
  testing key 3 (CARD AUTH key) 
    RSA-X-509: OK
    RSA-PKCS: OK
No errors
$ 

@dengert
Copy link
Member

dengert commented Nov 16, 2018

The above patch is just to test if this would do what you want. i.e. does the pin caching then take effect if the sign operation fails and reissue the command, and it it fails a second time, return to the user as not logged in.

In the offline discussion you said: "The driver has the control over what to report to the app, upon which the app decides whether to prompt the user or not."

This is not always true. With PKCS#11 the application may query for the CKA_ALWAYS_AUTHENTICATE once and assume the value does not change. This is not a dynamic request of the attribute. It is a statement of a policy that the card and/or issuer wants the user to follow, i.e. the user will provide the PIN each time. There is no restriction placed on when the application can ask for the attribute, or what the application can do between the query for CKA_ALWAYS_AUTHENTICATE and a C_Sign operation.
The application can even cache the PIN. But applications that support CKA_ALWAYS_AUTHENTICATE are trying to follow the policy be not caching the pin.

With PKCS#15 user_consent is the number of times the PIN can be used before the user has to login again. PKCS#11 does not have this concept, just the CKA_ALWAYS_AUTHENTICATE.

In you statement, for the app to decide whether to prompt the user or not could involve commands to the card which could then change the state of the card.

Just returning USER_NOT_LOGGED_IN may not cause the application to do another login. Some applications use C_GetTokenInfo (or some such call) to test if the user is logged it. They do this expecting the state will not change while doing a Sign operation, and there are really 2 states, the login state and the CKA_ALWAYS_AUTHENTICATE state. This may differ for different cards.

The PIV driver goes to great lengths to avoid any interference to the card between a CKU_CONEXT_SPECIFIC login and a crypto operation. so as to satisfy the card's PIN_Always requirements. It does not do that for a normal login.

We do not have much control over the applications and much of what you want to do requires the applications to do things they do not do today.

So my approach to this is to let users set options in opensc.conf to not only ignore_user_consent,
but to allow them to override the policies of the card and/or the card issuers by caching the pin in the driver.

(And don't forget about the PIN PAD readers which are designed to enforce policy. )

@dengert
Copy link
Member

dengert commented Nov 16, 2018

Do you have an opensc.debug.log to show why it did not work? It may need some additional locking.

@dengert
Copy link
Member

dengert commented Nov 16, 2018

Sorry, the patch is in the wrong spot. Needs to be in 2 spots. RSA and ECC.

pkcs15-piv.c.test.txt

I get usng NIST demo card 1:

/opt/ossl-1.1/bin/pkcs11-tool' has changed; re-reading symbols.
Starting program: /opt/ossl-1.1/bin/pkcs11-tool --test --login
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff543d700 (LWP 16789)]
[New Thread 0x7ffff4c3c700 (LWP 16790)]
Using slot 0 with a present token (0x0)
Logging in to "Test Cardholder".
Please enter User PIN: 
C_SeedRandom() and C_GenerateRandom():
  seeding (C_SeedRandom) not supported
  ERR: C_GenerateRandom failed: CKR_DATA_INVALID (0x20)
Digests:
  all 4 digest functions seem to work
  MD5: OK
  SHA-1: OK
  RIPEMD160: OK
Signatures (currently only for RSA)
  testing key 0 (PIV AUTH key) 
  all 4 signature functions seem to work
  testing signature mechanisms:
    RSA-X-509: OK
    RSA-PKCS: OK
    SHA1-RSA-PKCS: OK
    MD5-RSA-PKCS: OK
    RIPEMD160-RSA-PKCS: OK
    SHA256-RSA-PKCS: OK
  testing key 1 (2048 bits, label=SIGN key) with 1 signature mechanism
    RSA-X-509: OK
  testing key 2 (2048 bits, label=KEY MAN key) with 1 signature mechanism -- can't be used to sign/verify, skipping
  testing key 3 (2048 bits, label=CARD AUTH key) with 1 signature mechanism
    RSA-X-509: OK
Verify (currently only for RSA)
  testing key 0 (PIV AUTH key)
    RSA-X-509: OK
    RSA-PKCS: OK
    SHA1-RSA-PKCS: OK
    MD5-RSA-PKCS: OK
    RIPEMD160-RSA-PKCS: OK
  testing key 1 (SIGN key) with 1 mechanism
    RSA-X-509: OK
  testing key 2 (KEY MAN key) with 1 mechanism -- can't be used to sign/verify, skipping
  testing key 3 (CARD AUTH key) with 1 mechanism
    RSA-X-509: OK
Unwrap: not implemented
Decryption (currently only for RSA)
  testing key 0 (PIV AUTH key) 
    RSA-X-509: OK
    RSA-PKCS: OK
  testing key 1 (SIGN key) 
    RSA-X-509: OK
    RSA-PKCS: OK
  testing key 2 (KEY MAN key) 
    RSA-X-509: OK
    RSA-PKCS: OK
  testing key 3 (CARD AUTH key)  -- can't be used to decrypt, skipping
1 errors

@mouse07410
Copy link
Contributor Author

The above patch is just to test if this would do what you want. i.e. does the pin caching then take effect if the sign operation fails and reissue the command, and it it fails a second time, return to the user as not logged in.

I see, thanks.

Just returning USER_NOT_LOGGED_IN may not cause the application to do another login

The sane thing for an app to do upon such a return code would be to either attempt another login, or abort.

...and there are really 2 states, the login state and the CKA_ALWAYS_AUTHENTICATE state. This may differ for different cards

I'm not sure I understand the above - but if I do, I disagree. There is no "ALWAYS_AUTHENTICATE state". The card will tell you if it needs another login, when it needs another login.

The potential problem is somebody else interfering between C_SignInit() and C_Sign(). But I don't see that as a reason to force a re-login, even if you label it "context specific".

So my approach to this is to let users set options in opensc.conf to not only ignore_user_consent,
but to allow them to override the policies of the card and/or the card issuers by caching the pin in the driver

Which IMHO is the consequence of the (IMHO unfortunate) decision to always re-authenticate by software whim, instead of relying on the card itself to tell you whether it needs a re-auth or not.

(Assuming that by "override the policies" you mean "the user has a choice between suffering the software prompting for the PIN always regardless of whether it's needed or not - and 'overriding' when it won't prompt at all, except for the first time".)

We do not have much control over the applications and much of what you want to do requires the applications to do things they do not do today.

I don't know enough to agree or disagree with the above. I don't think I've observed apps conforming to what you described, but I may be missing something.

(And don't forget about the PIN PAD readers which are designed to enforce policy. )

The policy IMHO is adequately enforced by the card hardware/firmware itself. It doesn't need an OpenSC software cop to ride shotgun over it. IMHO, PIN PAD readers' main purpose is to avoid exposing the PIN to the computer at all, thus eliminating the potential for malware to steal it like it steals passwords.

Do you have an opensc.debug.log to show why it did not work? It may need some additional locking.

Sure:
opensc-test.log.txt

@mouse07410
Copy link
Contributor Author

mouse07410 commented Nov 16, 2018

Sorry, the patch is in the wrong spot. Needs to be in 2 spots. RSA and ECC.

I should've spotted that. No worries.

I've applied the patch in the RSA place, and it worked excellent, exhibiting the behavior I like and can accept.

Although I'd prefer to use the "override" as the last resort (like, for Java that cannot deal with tokens correctly without it), and in "normal" cases rely on the card: if for whatever reasons the login state was lost and re-login is needed - ask for it, otherwise proceed without bothering the user. That doesn't incur the risk of caching the PIN, and doesn't inconvenience the user needlessly.

@dengert
Copy link
Member

dengert commented Nov 17, 2018

You said: "There is no "ALWAYS_AUTHENTICATE state". I would disagree. For the PIV, the state exists after a verify until the next APDU. This is the only time a key with the "PIN Always" can do a crypto operation General Authenticate with INS=87

Have a look at #1529. It causes pkcs15-crypt to do only one verify and signals the PIV driver to do an extra PCSC lock which start a PCSC transaction. The transaction will not end until the piv driver finishes the next APDU what ever it is. In the case of pkcs15-crypt this is the crypto operation.

Putting both the verify and crypto commands in the same transaction then locks out other applications from sending any APDUs to the card for the PIV applet, other applet like OpenPGP or testing APDU like those use to match a driver to a card.

Because of all the problems with the multiple applets on a card, and other applications looking at cards between transactions, the PIV driver at the start of every transaction, checks for the active AID and the
login state if possible. This checking of the state uses APDUs the causes the "PIN Always" state to be lost.

So it might be possible to treat the verify from the original C_Login such that it does the extra PCSC lock,
to keep the transaction from ending. But how long to hold the lock? What if the next command is not the crypto command. What is the response to a query for CKA_ALWAYS_AUTHENTICATE after the verify?

Or for the first C_Login at least tell the PIV driver to not check the state of the card until after the next command is sent. But this allows interference from other applications.

@mouse07410
Copy link
Contributor Author

mouse07410 commented Nov 18, 2018

You said: "There is no ALWAYS_AUTHENTICATE state". I would disagree. For the PIV, the state exists after a verify until the next APDU. This is the only time a key with the "PIN Always" can do a crypto operation General Authenticate with INS=87...
Because of all the problems with the multiple applets on a card, and other applications looking at cards between transactions, the PIV driver at the start of every transaction, checks for the active AID and the login state if possible. This checking of the state uses APDUs the causes the "PIN Always" state to be lost...
So it might be possible to treat the verify from the original C_Login such that it does the extra PCSC lock, to keep the transaction from ending. But how long to hold the lock? What if the next command is not the crypto command.

If I understand you correctly, you are saying that enforcing "VERIFY" by the software/middleware for a key marked "ALWAYS_AUTHENTICATE" is necessary to accommodate the possibility that multiple apps are accessing the token (this applet, or other/multiple applets)?

What is the response to a query for CKA_ALWAYS_AUTHENTICATE after the verify?

It seemed to me that the software doesn't even need to know whether the key has the ALWAYS_AUTHENTICATE attribute or not, let alone query for it. If C_Sign() (or C_Decrypt()) returns "NOT_LOGGED_IN", run VERIFY, otherwise proceed. What's the probability of it failing for unrelated reasons (such as another app disturbed the state)? And in such a case - wouldn't it be simpler to just fail and let the user repeat the whole operation (because that's what the user would probably have to do anyway)?

@dengert
Copy link
Member

dengert commented Nov 18, 2018

"Enforcing "VERIFY" by the software/middleware for a key marked "ALWAYS_AUTHENTICATE" does 3 things.

  1. It holds a PCSC lock (does not end the PCSC transaction after the verify) to stop interference from other applications or threads of the current application.

  2. It uses the PKCS#11 defined way to handle such keys. The context specific login will be be immediately followed by the crypto operation.

  3. Because the PCSC lock is held, the driver does need to make sure the the correct AID is selected because there is not interference thus no beginning of transactions need to be done.

Unfortunately just returning "NOT_LOGGED_IN" to an application is not good enough. We have seen applications that may do more then just redoo the verify. They may backup further and do other commands between the VERIFY and the crypto operation again. We have also seen applications do a C_GetSessionInfo to test the login state just before the crypto operation and don't expect the crypto to return NOT_LOGGED_IN.

We do not have control over these applications.

There are some trade offs being made between avoiding any interference, using two applets at the same time, not caching the pin, and trying to use use the initial verify of a PIN to satisfy the "PIN Always".

Right now the circumvention is to use pin caching.

Will continue discussion of Dual CAC/PIV with next comment...

@dengert
Copy link
Member

dengert commented Nov 18, 2018

The PIV driver has to deal with Dual CAC/PIV cards and PIV/OpenPGP cards. And it has to deal with PIV applets which do not follow NIST specifications especially dealing the login state. I would like to add better detection of Dual PIV/CAC cards to the PIV driver.

My problem is I don't have and CAC or Dual CAC/PIV cards. There have been a number of recent issues dealing with what look like Dual CAC/PIV cards. On way to solve some of these was in: #1460 (comment)

I would like the assistance of: @mouse07410, @Jakuje or anyone else who has a CAC or Dual CAC/PIV card to sent the ATR and the output of the CCC. (See below.)

Both PIV and CAC define a CCC. NIST 800-73-4 says: "The Card Capability Container (CCC) is a mandatory data object whose purpose is to facilitate compatibility of Government Smart Card Interoperability Specification (GSC-IS) applications with PIV Cards."

ref1.c.i-CAC_End-Point_Implementation_Guide_v1-22.pdf
contains "Data Model Discovery" to determine if the card is a CACv1, CACv2,
CAC Transitional or PIV end-point card as well as what is in the CCC.

The PIV driver can return the CCC to the application, (but has not needed to use it internally.) For example reading the CCC of the NIST Demo card 1:

$ pkcs11-tool -r -y data --application-id 2.16.840.1.101.3.7.1.219.0 | xxd -p 
Using slot 1 with a present token (0x1)
531bf000f100f200f300f400f50110f600f700fa00fb00fc00fd00fe00

or

pkcs11-tool -r -y data --application-id 2.16.840.1.101.3.7.1.219.0 | od -t x1 
Using slot 1 with a present token (0x1)
0000000 53 1b f0 00 f1 00 f2 00 f3 00 f4 00 f5 01 10 f6
0000020 00 f7 00 fa 00 fb 00 fc 00 fd 00 fe 00
0000035

I am especially interested in the F3 and F5 tags.

Thanks.

@Jakuje
Copy link
Member

Jakuje commented Nov 19, 2018

It looks like we diverged a bit from the original subject that the issue started with. Can we start a new clean issue with just discusison about the CAC/PIV detection?

I would be happy to help. I have two CAC cards (from 2012 or so) at hand, from which one of them should be dual, but it is not detected by the PIV driver and the other should be plain CAC.

The CCC in the CAC driver is not exposed as an object in PKCS#11 interface, but used internally to detect the objects on the card. If I see right what you ask for, it is F3 tag (ApplicationsCardURL) and F5 (Registered Data Model).

For the cards I have, I get the following cardURLs:

0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 0 79 2 fb  len=7, path->value = 2 fb len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 0 79  len=5 appid= 2 fb len=2 objid= 2 fb len=2
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 0 79 2 fe  len=7, path->value = 2 fe len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 0 79  len=5 appid= 2 fe len=2 objid= 2 fe len=2
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1504:cac_parse_cardurl: CARDURL: gen_object found, objectID=2fe (PKI Certificate),
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 0 79 2 fd  len=7, path->value = 2 fd len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 0 79  len=5 appid= 2 fd len=2 objid= 2 fd len=2
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1504:cac_parse_cardurl: CARDURL: gen_object found, objectID=2fd (PKI Credential),
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 0 79 2 0  len=7, path->value = 2 0 len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 0 79  len=5 appid= 2 0 len=2 objid= 2 0 len=2
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1504:cac_parse_cardurl: CARDURL: gen_object found, objectID=200 (Person Instance),
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 0 79 2 1  len=7, path->value = 2 1 len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 0 79  len=5 appid= 2 1 len=2 objid= 2 1 len=2
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1504:cac_parse_cardurl: CARDURL: gen_object found, objectID=201 (Personnel),
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 0 79 1 0  len=7, path->value = 1 0 len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 0 79  len=5 appid= 1 0 len=2 objid= 1 0 len=2
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1493:cac_parse_cardurl: CARDURL: pki_object found, cert_next=0 (CAC ID Certificate),
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.207 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 0 79 1 1  len=7, path->value = 1 1 len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 0 79  len=5 appid= 1 1 len=2 objid= 1 1 len=2
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1493:cac_parse_cardurl: CARDURL: pki_object found, cert_next=1 (CAC Email Signature Certificate),
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 0 79 1 2  len=7, path->value = 1 2 len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 0 79  len=5 appid= 1 2 len=2 objid= 1 2 len=2
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1493:cac_parse_cardurl: CARDURL: pki_object found, cert_next=2 (CAC Email Encryption Certificate),
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 1 16 30 0  len=7, path->value = 30 0 len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 1 16  len=5 appid= 30 0 len=2 objid= 30 0 len=2
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 1 16 30 0  len=7, path->value = 60 10 len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 1 16  len=5 appid= 30 0 len=2 objid= 60 10 len=2
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 1 16 30 0  len=7, path->value = 60 30 len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 1 16  len=5 appid= 30 0 len=2 objid= 60 30 len=2
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 1 16 30 0  len=7, path->value = 90 0 len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 1 16  len=5 appid= 30 0 len=2 objid= 90 0 len=2
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 0 79 12 1  len=7, path->value = 12 1 len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 0 79  len=5 appid= 12 1 len=2 objid= 12 1 len=2
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1595:cac_parse_CCC: TAG:CARDURL
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1403:cac_path_from_cardurl: path->aid=a0 0 0 0 79 12 2  len=7, path->value = 12 2 len=2 path->type=0 (0)
0x7fc331c42740 09:16:55.208 [opensc-pkcs11] card-cac.c:1409:cac_path_from_cardurl: rid=a0 0 0 0 79  len=5 appid= 12 2 len=2 objid= 12 2 len=2

The second card (non-PIV compliant) I have is missing the AID a0 0 0 1 16 30 0 (with all associated OIDs) -- these actually provide many security objects ensuring the integrity of the card (not sure in which document it is described, but I think it was one of the PIV transitional on the PIV documentation website).

The data mode number for the dual card is 0x10:

0x7f5773251880 09:32:51.371 [opensc-pkcs11] card-cac.c:1495:cac_parse_CCC: TAG: Registered Data Model Number (0x10)

And 0x02 for the CAC only:

0x7fbbf83e8880 09:32:00.855 [opensc-pkcs11] card-cac.c:1495:cac_parse_CCC: TAG: Registered Data Model Number (0x02)

Collected using master + #1535

@dengert
Copy link
Member

dengert commented Nov 19, 2018

The reason for the divergence is I expect to find that Dual CAC/PIV cards have a problem with one or more of the PIV card_issues. It might be possible to back off on commands used at the start of every PIV transaction for Dual CAC/PIV, as these commands were added mostly for the Dual PIV and OpenPGP applets on the same card. I don't think there would ever be CAC, PIV and OpenPGP applets on the same card.

The PIV CCC is mandatory for a true PIV card, (But not needed by OpenSC PIV driver). So if present it can be used to see if any of the F3 or F5 indicate it is also CAC. So would expect it to be there for any Dual CAC/PIV as (I believe) these are all government issued cards,

And it is not clear if on a Dual mode card, that the "PIN Always" in enforced on the PIV SIGN key. Or if the PIV driver could use the CAC commands to use the CAC "CAC Email Signature" key, that appears to be the same certificate and key and I believe that the CAC applet does not enforce "PIN Always" on the card.

If any of above are true, it might avoid the "CKA_ALWAYS_AUTHENTICATE" for the PIV SIGN Key on these Dual CAC/PIV cards.

A lot of testing would be needed.

@dengert
Copy link
Member

dengert commented Nov 19, 2018

@mouse07410
Can you run the command on the card you are having problems with:
pkcs11-tool -r -y data --application-id 2.16.840.1.101.3.7.1.219.0 | od -t x1

and send results.

Can you try adding to opensc.conf with your ATR:

  card_atr 3b:7d:96:00:00:80:31:80:65:b0:83:11:17:d6:83:00:90:00 {
                driver = "PIV-II";
                type = 14005;
       }
and see what it does. 

@mouse07410
Copy link
Contributor Author

But the ATR you provided above is not for CAC:

$ opensc-tool -lian
. . . . .
Nr.  Card  Features  Name
0    Yes             SCR3310 Smart Card Reader
Using reader with a card: SCR3310 Smart Card Reader
3b:7a:18:00:00:73:66:74:65:20:63:64:31:34:34
DOD CAC
$ 

For Yubikey 4 the ATR is 3b:f8:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:34:d4.

As far as I can tell, the ATR you gave does nothing (observable).

For the CAC (new issue):

$ pkcs11-tool -r -y data --application-id 2.16.840.1.101.3.7.1.219.0 | xxd -p
Using slot 0 with a present token (0x0)
error: object not found
Aborting.
$

Having both tokens inserted:

$ opensc-tool -lian
OpenSC 0.19.00 [gcc  4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.11.45.5)]
Enabled features: locking zlib readline openssl pcsc(/System/Library/Frameworks/PCSC.framework/PCSC)
# Detected readers (pcsc)
Nr.  Card  Features  Name
0    Yes             Yubico Yubikey 4 OTP+U2F+CCID
1    Yes             SCR3310 Smart Card Reader
Using reader with a card: Yubico Yubikey 4 OTP+U2F+CCID
3b:f8:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:34:d4
Yubikey 4
$ pkcs11-tool -L
Available slots:
Slot 0 (0x0): Yubico Yubikey 4 OTP+U2F+CCID
  token label        : Bxxxxxxxxxx, Uri (UR20980)
  token manufacturer : piv_II
  token model        : PKCS#15 emulated
  token flags        : login required, rng, token initialized, PIN initialized
  hardware version   : 0.0
  firmware version   : 0.0
  serial num         : bbbbbbbbbbbbbbbbb
  pin min/max        : 4/8
Slot 1 (0x4): SCR3310 Smart Card Reader
  token label        : Bxxxxxxxx.URI.1xxxxxxxxx
  token manufacturer : Common Access Card
  token model        : PKCS#15 emulated
  token flags        : login required, rng, token initialized, PIN initialized
  hardware version   : 0.0
  firmware version   : 0.0
  serial num         : 999999999999999
  pin min/max        : 4/8
$ pkcs11-tool -r -y data --application-id 2.16.840.1.101.3.7.1.219.0 | od -t x1
Using slot 0 with a present token (0x0)
error: get CKA_VALUE failed
Aborting.
$ pkcs11-tool --slot 0x4 -r -y data --application-id 2.16.840.1.101.3.7.1.219.0 | od -t x1
error: object not found
Aborting.
$ pkcs11-tool --login --slot 0x4 -r -y data --application-id 2.16.840.1.101.3.7.1.219.0 | od -t x1
error: util_getpass error
Aborting.
0000000    4c  6f  67  67  69  6e  67  20  69  6e  20  74  6f  20  22  42
0000020    4c  55  4d  45  4e  54  48  41  4c  2e  55  52  49  2e  31  33
0000040    39  36  33  36  38  30  34  34  22  2e  0a  50  6c  65  61  73
0000060    65  20  65  6e  74  65  72  20  55  73  65  72  20  50  49  4e
0000100    3a  20                                                        
0000102
$ 

Replacing the ATR you gave with the proper one for my CAC (i.e., forcing it to be a PIV):

$ pkcs11-tool --slot 0x4 -r -y data --application-id 2.16.840.1.101.3.7.1.219.0 | od -t x1
error: get CKA_VALUE failed
Aborting.
$

So, the object doesn't appear to be there.

@dengert
Copy link
Member

dengert commented Nov 19, 2018

Well Thanks for trying to see if the PIV applet has a CCC. The hex output above is a prompt to login that was sent to stdout, and the util_getpass had an error, Most likely because no pssword was entered.

Since the driver being used was the CAC driver, --application-id 2.16.840.1.101.3.7.1.219.0
was not understood by the cac driver. "2.16.840.1.101.3.7.1.219.0" specs so only the PIV driver would understand it. .

Based on the #1533 (comment) it sounded like this was a request to look at some of the CKA_ALWAYS_AUTHENTICATE issues. Bu I think I may have lead you and Jakub down the wrong path as the original problem sounds like some driver cross talk, when more then one card is inserted.

I guess I should have stopped when you said in: #1533 (comment)
"So, not sure if it would be of any use. But I'm happy that it seems to work now.
I guess I could/should close this issue..."

@mouse07410
Copy link
Contributor Author

mouse07410 commented Nov 19, 2018

The hex output above is a prompt to login that was sent to stdout, and the util_getpass had an error, Most likely because no password was entered

The password certainly was not entered, because there was no prompt for it. Some stdin/stdout redirection screw-up, I think.

...trying to see if the PIV applet has a CCC

As you saw above, the PIV applet response with error: get CKA_VALUE failed. The CAC applet merely does not find the object.

it sounded like this was a request to look at some of the CKA_ALWAYS_AUTHENTICATE issues

It certainly was on my side. And your test-patch addressed it. What's missing is extending that patch into checking for whether pin_cache_ignore_user_consent option is set, and only then forcing the desired behavior. Though if that turns out too hard, I can live with the way it is now (with your test-patch applied).

I don't think there would ever be CAC, PIV and OpenPGP applets on the same card.

I concur: either CAC+PIV, or PIV+OpenPGP.

@dengert
Copy link
Member

dengert commented Nov 19, 2018

Sounds like the regression and crazy behavior was solved by building from master.

The issue of pin_cache_ignore_user_consent was there for applications that did yet support the concept of CKA_ALWAYS_AUTHENTICATE or user_consent. (The PIV card enforces the PIN Always' policy on the card, so to ignore it also requires user_pin_caching = true; Other cards may not enforce it on the card.) But for applications that do ask for it and can do the C_Login(CKU_CONTEXT_SPECIFIC) will still prompt for the PIN.

The test patch was in the PIV driver to not set user_consent = 1; thus turning off the setting of CKA_ALWAYS_AUTHENTICATE and user_consent for selected keys for PIV cards only.

I would like to ask @frankmorgner and others to comment on how should the user express their desire to override this possible policy of the card issuer:

  • Should we support allowing the user to override user_consent in all cases?

  • Should a different parameter be used like override_user_consent_policy?

  • Should it apply to all cards?

  • Should it be at the card_atr level?

  • Are there PKCS#15 cards or other cards that do set user_consent?

  • Should this new parameter also set use_pin_caching?

  • Should pin_cache_ignore_user_consent be extended to cover this scenario?

I for one, consider this an overriding of a policy of the card issuer and the user or site should understand that they are overriding a policy and the override should not be the default.

@mouse07410
Copy link
Contributor Author

mouse07410 commented Nov 20, 2018

There is no card that I know of, that would set ALWAYS_AUTHENTICATE but not enforce it in hardware. In fact, I claim that such a card is not compliant.

Therefore I re-state my opinion that OpenSC shouldn't play a cop for such cards (whose existence, BTW, is unclear).

Yes, if this "enforcement" is going to continue - of course user's desire to override must be respected for all the cases.

No, there's no need for a different parameter.

Yes it should apply to all cards, but in addition to that the ability of the user to constrain it to some cards only, via, e.g., ATR, would be great.

I agree that if the decision is to keep the enforcement in place, override should not be the default setting.

@frankmorgner
Copy link
Member

  • Should a different parameter be used like override_user_consent_policy?

If it can be avoided, we should try not to add more options. Keep in mind, that it's the vendor's intended behavior and there's no need to make it comfortable to avoid.

  • Should it apply to all cards?
  • Should it be at the card_atr level?

A per-card-configuration would be useful, yes. But since it won't be used very often, I personally will not put too much effort into this.

  • Are there PKCS#15 cards or other cards that do set user_consent?

Yes. It should reflect a behavior that's enforced in hardware (I agree with @mouse07410 ). We should, however, treat it correctly by default at the PKCS#15 level to avoid unexpected failures at the lower level.

  • Should this new parameter also set use_pin_caching?
  • Should pin_cache_ignore_user_consent be extended to cover this scenario?
  • Should we support allowing the user to override user_consent in all cases?

To answer these, we need to look at the original intention of this setting given in ISO7816-15 (previously PKCS#15):

The userConsent component gives, in the case of a private object (or an object for which access conditions has been specified), the number of times an application may access the object without explicit consent from the user (e.g. a value of 3 indicates that a new authentication will be required before the first, the 4 , the 7 , etc. access). The card may enforce this value, e.g. through the use of “counter objects” (see ISO/IEC 7816-8). A value of 1 means that a new authentication is required before each access.

So actually it tells us how many times we can use the private key before we need to ask the PIN again. However, in OpenSC we only use this flag to check whether we are allowed to cache the PIN or not. So before adding new options here and there, we need to question whether we have a good understanding of this setting.

@frankmorgner
Copy link
Member

... and back to the original question. Am I getting this right that there isn't any problem with CAC/PIV/OpenPGP left? Identification and functionality of the cards are as expected (i.e. OK)?

@mouse07410
Copy link
Contributor Author

Give me a day to confirm. It's been somewhat unstable, and I couldn't determine the cause yet.

@dengert
Copy link
Member

dengert commented Nov 20, 2018

I agree that we don't have a good understanding of the PKCS#15 user_consent. Keep in mind that in PKCS#11 the CKA_ALWAYS_AUTHENTICATE is TRUE or FALSE, and is being set if user_consent != 0.
and PKCS#11 uses the CKU_CONTEXT_SPECIFIC login that does not require the same key. So the two standards have some overlap. How a card may enforce either of these is also questionable.

Note PKCS$15 says about user_consent: "the card may enforce this value". I read this as saying the card issuer by setting user_consent expects the middleware to enforce this even if the card does not. That is why I am in favor of "override" and "policy" in option name. (I disagree with Mouse's comment: "It doesn't need an OpenSC software cop to ride shotgun over it.")

Here is some sample code that can implement a pin_cache_override_user_consent_policy.diff.txt

The override is actually implemented in 2 places as examples of what we could do:

  1. framework-pkcs15.c will not set CKA_ALWAYS_AUTHENTICATE if pin_cache_override_user_consent_policy !=0 This would thus apply to all cards at the PKCS#11 level.
  2. pkcs15-piv.c will not set user_consent for a private key if pin_cache_override_user_consent_policy !=0 So this is at a card level.

PKCS#15 cards set user_consent in asn1.c This would be another place to implement it.

For emulated cards, the code in pkcs15-piv.c could be moved to sc_pkcs15emu_add_rsa_prkey and
sc_pkcs15emu_add_ec_prkey. pkcs15-jpki.c, card-dnie.c and pkcs15-piv.c set user_consent. I don't know how many PKCS#15 cards do.

So the sample patch still needs work to add or remove some code.

I tested patch using pkcs11-tool --test --login with NIST demo card with and without setting the option.

@mouse07410
Copy link
Contributor Author

Note PKCS#15 says about user_consent: "the card may enforce this value". I read this as saying the card issuer by setting user_consent expects the middleware to enforce this even if the card does not. That is why I am in favor of "override" and "policy" in option name. (I disagree with Mouse's comment: "It doesn't need an OpenSC software cop to ride shotgun over it.")

Since you've been in the field longer than I have - could you name one card you know of that "expects the middleware to enforce..."? Not to mention that from security point of view "delegating" the responsibilities (that I might point out are the primary reason to use hardware tokens!) to software that may or may not care, would not be a good policy for a card manufacturer that wishes to stay in business. And probably not many of commercial (or government) purchasers would be eager to buy such a card.

So, I think the "may enforce" piece is technically valid, but 100% impractical and unreasonable.

@dengert
Copy link
Member

dengert commented Nov 20, 2018

No I can not name one. I got into Kerberos in the late 80's so passwords would not be sent over the internet, then in the late 90's got in to smartcards so one would not need a password but instead use a smartcard with Microsoft AD (as the Kerberos KDC) and even pushed for pin pad readers so even the PIN was not exposed. I have concentrated on the PIV since HSPD-12 was released in 2004. It was obvious that the DOE Lab where I retired from would eventually be using PIV cards.

OpenSC was originally designed to support PKCS#15 cards and there may be cards where keys have user_consent set, but I don't have much interest in PKCS#15 cards and don't have any.

I leave it up to the PKCS#15 developers to answer your question.

@mouse07410
Copy link
Contributor Author

I got into Kerberos in the late 80's so passwords would not be sent over the internet, then in the late 90's got in to smartcards so one would not need a password but instead use a smartcard

Back then I added SecureNetKey hardware token support to Kerberos-IV, and then ported it to -V. ;-)

...there may be cards where keys have user_consent set

No argument here - but my point is: if a card supports that kind of a flag, it invariably enforces it in hardware by itself. It would not rely on software to do it.

@mouse07410
Copy link
Contributor Author

OK. It looks like we diverged a little from the main line of this issue.

I confirm that the current master worked OK with the current Firefox (Dev Edition) and the current (reasonably "fresh") CAC.

Thank you for your help!

@Jakuje
Copy link
Member

Jakuje commented Nov 21, 2018

So the original issue is resolved. We started discussion about ignoring the always authenticate few comments back with a new option (sigh ...) and with some working patch from @dengert. Should we follow up on this with new issue or PR?

Anyway, from what I remember, neither of the NIST PIV Test cards enforces the always authenticate policy (the coolkey driver ignored this and worked as a charm). But that is not an excuse and I think OpenSC does the right thing enforcing this policy, while we should indeed provide a working solution to overwrite it if needed.

@mouse07410
Copy link
Contributor Author

mouse07410 commented Nov 21, 2018

@Jakuje are you saying that your test NIST PIV cards allow other operations between login and, e.g., signing with an ALWAYS_AUTHENTICATE key? Please forgive me if I don't believe it.

Or do you mean that when you perform signatures with those cards/keys, since there's no "flow interruption" between token login and requested crypto - it knows it doesn't need to bug you with an extra PIN request, so it doesn't?

Also, does your test setup user PIN caching? (which would silently feed the PIN to the card without asking you)?

@hhonkanen
Copy link
Contributor

This goes a bit off topic, but as you are talking about userConsent... I've noticed that OpenSC maps PKCS#15 userConsent to CKA_ALWAYS_AUTHENTICATE when reading cards and parsing PKCS#15, but seems to ignore this attribute when creating keys via PKCS#11.

I would like to add handling of CKA_ALWAYS_AUTHENTICATE to functions pkcs15_create_private_key() and pkcs15_create_secret_key() and map it to userConsent=1. Card drivers could then set their own card specific flags when creating keys, to enforce re-authentication for each use of a specific key. At least in MyEID it can be set separately for each key object. Authentication state of a selected PIN is reset after using the key, if set.

@mouse07410
Copy link
Contributor Author

As I understand, OpenSC usually prefers that vendor-provided tools are used to generate keys.

@mouse07410
Copy link
Contributor Author

CAC driver keeps giving me trouble once in a while (on access to DOD sites that want SIGN cert), starting to prompt incessantly for a PIN. When I change opensc.conf relevant lines to this:

        # DOD CAC
        card_atr 3b:7a:18:00:00:73:66:74:65:20:63:64:31:34:34 {
                #driver = "cac";
                #type = 33003;
                name = "DOD CAC";
        }

everything becomes normal. I have user_consent configured properly, especially since it is required for Java jarsigner to work with hardware tokens.

I guess I shouldn't waste mine and everybody else's time trying to get CAC driver to work, when PIV does the job fine enough.

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

No branches or pull requests

5 participants