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

YubiKey PIN policy is not supported #1769

Open
ghost opened this issue Aug 20, 2019 · 26 comments
Open

YubiKey PIN policy is not supported #1769

ghost opened this issue Aug 20, 2019 · 26 comments

Comments

@ghost
Copy link

ghost commented Aug 20, 2019

Problem Description

I have a YubiKey 5 which supports PIN policies per slot [1] [2]. There are three different PIN policies: never required, required once and always required. However, it seems the first two are unsupported, as applications always ask for PIN regardless of the policy. This does not allow to authenticate the card only. An example of the desired behavior is when in pkcs11-tool the code responsible for logging in is disabled (opt_login forced to false).

Proposed Resolution

Maybe CKF_LOGIN_REQUIRED should be ignored and login should be deferred until actually required (CKR_USER_NOT_LOGGED_IN). I don't really know, tell me the proper way this should be handled and I can try to implement it.

Steps to reproduce

ykman piv import-key 9e key.key --pin-policy never
# requires PIN
pkcs11-tool --sign
# works as desired
patched/pkcs11-tool --sign

Logs

OPENSC_DEBUG=9 patched/pkcs11-tool --sign
pkcs11-tool -L
pkcs11-tool -O

@dengert
Copy link
Member

dengert commented Aug 21, 2019

This sounds like some new Yubico extension. The PIV specifications from NIST NIST.SP.800-73-4 defines fixed pin policies.

A quick look at 1 and 2 does not show how to read the policy for a specific key.

@dengert
Copy link
Member

dengert commented Aug 21, 2019

By default key 9E should not require a PIN. You said you have a "patched/pkcs11-tool" What is the patch?

@ghost
Copy link
Author

ghost commented Aug 21, 2019

9E should not require PIN, but it still asks somehow to login into the card. The patch (for 0.19.0) is:

--- opensc/src/tools/pkcs11-tool.c	2018-09-13 13:52:42.000000000 +0200
+++ opensc-patched/src/tools/pkcs11-tool.c	2019-08-21 10:08:15.588537191 +0200
@@ -981,8 +981,6 @@
 		get_token_info(opt_slot, &info);
 		if (!(info.flags & CKF_TOKEN_INITIALIZED))
 			util_fatal("Token not initialized");
-		if (info.flags & CKF_LOGIN_REQUIRED)
-			opt_login++;
 	}
 
 	if (do_init_token)

As for pkcs11-tool -O, the output looks same regardless of the policy.

@dengert
Copy link
Member

dengert commented Aug 21, 2019

The info.flags are for the token. The PIV specs (sp800-74-4 Part1 Table 3) also say the 9A and 9E and their certificates "X.509 Certificate for PIV Authentication" and "X.509 Certificate for Card Authentication" are mandatory. So there is a conflict as to how the info.flags in PKCS#11 should be set when the card has more then the 9E key or some Yubico specific pin policy is set for other keys.

The PIV card is the only card I know of that has a key that does not require a login. I would be reluctant to make any changes for this special situation.

How do you plan on using pkcs11-tool with the 9E key?
Will the card have other keys?
You could consider using pkcs15-crypt or write (or add) pkcs11 calls to your own program.

A simple change to pkcs11-tool would be to change your modified patch by adding a parameter that does not execute the two lines you wanted to delete. Something like --nologin. You might also need to add need_session_session = NEED_SESSION_RO;

Or add another value to opt_login_type to say "don't need login" to skip the call to login().

pkcs11-tool has a lot of functionality. Keep any modification as simple as possible.

@ghost
Copy link
Author

ghost commented Aug 21, 2019

Actually the pkcs11-tool is not my focus, I would like the existing applications to support the token without requiring the PIN. If setting of the CKF_LOGIN_REQUIRED flag is suppressed with the following patch, applications works correctly with slots using the "no PIN required" policy.

--- opensc/src/pkcs11/framework-pkcs15.c	2018-09-13 13:52:42.000000000 +0200
+++ opensc-patched/src/pkcs11/framework-pkcs15.c	2019-08-21 18:02:50.739628908 +0200
@@ -1078,7 +1078,6 @@
 			else
 				/* The PIN label is empty or says just non-useful "PIN" */
 				snprintf(label, sizeof(label), "%s", p15card->tokeninfo->label);
-			slot->token_info.flags |= CKF_LOGIN_REQUIRED;
 		}
 	}
 	else   {

I see the Yubico policies are in conflict with the per-token flag. Stripping the flag when only slots having the "no PIN required" policy are in use would make this work automatically at least in some simple scenarios. Sadly, I don't see a way to obtain the PIN policy, not even using Yubico's provisioning tools. Would it be instead possible to introduce either an opensc.conf option or maybe nopin-opensc-pkcs11.so to strip the CKF_LOGIN_REQUIRED flag?

@dengert
Copy link
Member

dengert commented Aug 21, 2019

Try this patch that needs a lot of testing.
proposed-fix-1769.diff.txt
You can use it as a starting point and submit a PR if you want.

It moves the test for CKF_LOGIN_REQUIRED till after the CKS_RW_PUBLIC_SESSION session is obtained. If the key can be found then object is set and opt_login++ is not done.
If not found object is still CK_INVALID_HANDLE and opt_login++ is set to cause a login.

Login changes the session from CKS_RW_PUBLIC_SESSION to CKS_RW_USER_FUNCTIONS

if object == CK_INVALID_HANDLE the find_object is done again and will find other keys.

This worked on a PIV demo card using:

pkcs11-tool --sign --id 04 -m SHA256-RSA-PKCS --input-file /tmp/data
and did not prompt for password when using the --id 04 i.e. the 9E key.

@ghost
Copy link
Author

ghost commented Aug 21, 2019

Thank you for the patch. However, looks like it inhibited login completely regardless of the policy. find_object always returns 1, so this approach sadly would not work with Yubikey.
The complete log is here.

@dengert
Copy link
Member

dengert commented Aug 22, 2019

It should work the same.

The default the PIV and Yubico 9E key does not require a login. If the Yubico can not tell you what is the policy then report problem to Yubico. They must have a way, but may not have documented it. If they do have a way that could be added to the card-piv.c.

I think the find_object returns the number of objects it has found. It should be either 1 or 0 as you need to specify the -id. The test may be wrong. A pkcs11spy would be very helpful.

Did the pkcs11-tool --sign example include any other parameters? You need a "-m" and "-id".

Your card only has one certificate and one key. I did not look at the find_key closely. It might default to returning that one key. If you also added a 9A auth key and '9Csign key and their certificates and use the -id 01 for9A and -id 02 for '9C it would be a better test.

@ghost
Copy link
Author

ghost commented Aug 22, 2019

I meant find_object always returned 1 in case of the slot 9E, even if the policy was set to require PIN always or once. Similarly, it returns 0 for 9A and 9C. Below are the debug logs for pkcs11-tool --sign -m ECDSA --id ID.

Default PIN policies

(9A once, 9C always and 9E never)

01: log spy
02: log spy
04: log spy

Reversed PIN policies

(9A never, 9C never and 9E always)

01: log spy
02: log spy
04: log spy

@dengert
Copy link
Member

dengert commented Aug 22, 2019

The patch is working for the default pin policies. (See exception below)

The Revised PIN policies will not work unless Yubico documents how to test for policy of a key on a Yubico device. It looks like they almost do: yubikey-5-series-technical-manual and PIV_attestation
(I have sent an e-mail to Yubico on this.)

This sould then need to added to card-piv.c and /or pkcs15-piv.c PIV specs define the policies as (9A once, 9C always, 9D once and 9E never) and this is hard coded in card-piv.c and /or pkcs15-piv.c.

The exception with the pkcs11-tool.c is when run without -id and the 9E key and its certificate are present. Without the -id find_object will find any key and will always find the 9E key in the first call to find_object. Thus opt_login++; is never set. I would say it could be fixed by not doing the first find_object if the -id is not set. i.e. do what the current pkcs11-tool code does.

@dengert
Copy link
Member

dengert commented Aug 22, 2019

New version of the patch:
fix-1747.diff-v2.diff.txt

Unmodified pkcs11-tool.c would have done a login first so session was CKS_RW_USER_FUNCTIONS then find_object would see all the keys and select the key with --id or the first key found if no --id.

To keep the same functionality, The new patch will only look for a key as seen by CKS_RW_PUBLIC_SESSION if --id is provided.

This still does not "fix" the general issue of "YubiKey PIN policy is not supported" but does if you stick to using the Default PIN policies.

@mouse07410
Copy link
Contributor

I thought that Yubikey policies affect the token itself. Which means - the software need not bother trying to learn what they are. Just attempt the operation - and if the response is NOT LOGGED IN, prompt for a PIN and do the login before retrying the operation. Why not?

@dengert
Copy link
Member

dengert commented Aug 23, 2019

PKCS#11 imposes some other restrictions. You must first call C_OpenSession, which gets a CKS_RW_PUBLIC_SESSION session. At this point you can call C_FindObjects* to search for objects not protected by a PIN. Then if you call C_Login the session becomes CKS_RW_USER_FUNCTIONS and then call C_FindObjects* to search for all objects. So you must provide a PIN to search for PIN protected objects.

In this case we are call C_FindObjects to search for CKO_PRIVATE_KEY. A handle to the key object is returned then passed to C_SignInit.

Also complicating the process is the C_GetTokenInfo and flags CKF_LOGIN_REQUIRED that applies to the whole token.

The patch to pkcs11-tool.c takes the above approach to first search for the requested key using CKS_RW_PUBLIC_SESSION Then if not found do the login and search for the key using the CKS_RW_USER_FUNCTIONS session.

pkcs11-tool -O and pkcs11-tool -O --login can show the difference. On a PIV card you will see private key "04" a.k.a '9E' in both. All the other keys are only visible after a login.
The 3 spy trace above under "Default PIN policies" also show this.

There are really 2 problems here.

  • pkcs11-tool would always require the login before searching.
  • Yubico utilities can set the PIN policy but it is not clear if there is a simple APDU to query what it is.

@mouse07410
Copy link
Contributor

Yubico utilities can set the PIN policy but it is not clear if there is a simple APDU to query what it is.

My point is that it's unnecessary to query it in software. Just issue a command. If it fails with CKR_USER_NOT_LOGGED_IN, you'll know to login and retry.

So, again - why not? The simplest way to figure out if an operation requires login or not is to try it and observe the return code.

And if you can't even find an object (private key) for a given slot - do you need to query some fancy policy to figure that you need a login?

@dengert
Copy link
Member

dengert commented Aug 23, 2019

If you think there is a simple command to find the private key without first doing a C_Login, show how to defer the login in pkcs11-tool.c. I don't think it can be done that way based on the PKCS#11 restrictions to find pin protected objects. Its a "Catch-22"

The "fancy policy query" (if Yubico has one), would be used in card-piv.c from pkcs15-piv.c to set SC_PKCS15_CO_FLAG_PRIVATE on keys requiring a login and not set it on keys not requiring a login.

grep -r SC_PKCS15_CO_FLAG_PRIVATE OpenSC/src/* to see how it is used. Note the 9E key does not show up in pkcs15-piv.c because PIV specs say which objects require a login, SC_PKCS15_CO_FLAG_PRIVATE is hard coded in pkcs15-piv.c.

pkcs11/framework-pkcs15.c _add_public_objects and _add_pin_related_objects is where these are added to the slot based on SC_PKCS15_CO_FLAG_PRIVATE.

@mouse07410
Copy link
Contributor

If you think there is a simple command to find the private key without first doing a C_Login

I think you showed that you can find an unprotected private key. We all agree that you must login to the token in order to find PIN-protected keys (regardless of whether they're PIN_ALWAYS or not).

My point was that once you do have a key object (either the unprotected only without prior login, or all the keys after you logged in once), you do not need to login (again?) unless the token forces you to by returning CKR_USER_NOR_LOGGED_IN.

@Jakuje
Copy link
Member

Jakuje commented Sep 12, 2019

As I already wrote in the #1784, I think the PIN policy of the key should be available in the certificate extension and PIV driver should be able to read it. See the section Attestation in the Yubikey technical manual:

https://support.yubico.com/support/solutions/articles/15000014219-yubikey-5-series-technical-manual#Attestation41qc5un

@dengert
Copy link
Member

dengert commented Sep 12, 2019

In a separate e-mail to Yubico 8/22/2019 I asked:
"As an OpenSC developer I am trying to address: "YubiKey PIN policy is not supported #1769"

#1769

The OpenSC PIV driver only supports the standard PIN policies for a key. Where is the ADPU
to determine the PIN policy of a private key? I see "Attestation" has the PIN Policy but
Attestation says: "This certificate should only be used for the purpose of verifying that
the key was generated in device, not for any other purposes." The user is interested in
importing the key, so Attestation does not apply.

Thanks."

The response was:
"Currently we don't have that capability, I can definately see the use case. Essentially this would be some form of get metadata that would return pin and touch policies and maybe public key as well? I'll carry this forward internally."

The way I read the response the "Attestation" can not return the pin policy for individual keys.

@ghost
Copy link
Author

ghost commented Sep 13, 2019

You can of course read the policy from the attestation certificate. However, the attestation feature is not the way to go. It overwrites whatever certificate was stored in the attestation slot and is unusable when the associated key was imported to the device.

@ghost
Copy link
Author

ghost commented Sep 13, 2019

Apparently, I have confused the purpose of the attestation slot, which is to supply a key used to sign the attestation. But the second point still stands.

@dengert
Copy link
Member

dengert commented Sep 13, 2019

Just to clarify the situation, Yubico has implemented their own PIN policy extensions to the NIST PIV standards, but provide no way to actually test use them except a trial and error method which is all but impossibly to implement within the PKCS#11 and PKCS#15 standards.

NIST sp800-73-3 PIV specs define 4 basic key/certificate pairs and up to 20 others in the History object. sp800-73-4 defines one more. The pin policy for these are fixed and enforced on the card. Yubico has defined a way to set these when the key is imported/generated. But there appears to be is no way to read the policy for each key. Thus I said: "The way I read the response the "Attestation" can not return the pin policy for individual keys." and why the note to Yubico.

NIST also defines some objects as pin protected. Most objects are not accessible over the contactless (NFC) interface. Yubico violated these access restrictions too. But these restrictions are minor and a NIST approved PIV card will enforce these.

Additionally NIST sp800-73-4 also defines optional Secure Messaging for use over NFC but no one appears to be interested in this feature and Yubico does not support it either so I have not done much to implement it. (I do have a NIST approved card that does support it. )

I will look at #1769 (comment) about in a certificate extension That could work, but the CA needs to add the extension to a certificate.

(When I am back from vacation.)

@arekinath
Copy link

It looks like in firmware ver 5.3 Yubico added a new "get metadata" instruction (0xF7) which returns metadata about a particular key slot, including the PIN/touch policy being applied to the key.

https://developers.yubico.com/PIV/Introduction/Yubico_extensions.html#_get_metadata

Seems that the "policy" tag (0x02) is expected to contain two bytes, with values given the same way as when you're instructing it to apply the policy to a slot, so e.g. 0x02 0x03 means "PIN required once per session, touch required and cached for 15sec".

They implement it in the code for libykcs11 now:

https://github.com/Yubico/yubico-piv-tool/blob/master/lib/ykpiv.c#L1961
https://github.com/Yubico/yubico-piv-tool/blob/master/lib/util.c#L1513

@dengert
Copy link
Member

dengert commented Apr 29, 2020

You are welcome to submit a PR, if you think that address all the concerns above, about violating the NIST standards.

@dengert
Copy link
Member

dengert commented Apr 29, 2020

One thing you can try to see what happens:

piv-tool -s"00:f7:00:9A:00"
Then repeat using for 9B, 9C, 9D, 9E, 80, 81 for all the keys.

I do not have a Yubico 5, so can not try this.

@frankmorgner
Copy link
Member

Closing this issue due to inactivity. Please re-open the ticket if more input is available.

@frankmorgner frankmorgner closed this as not planned Won't fix, can't repro, duplicate, stale Mar 14, 2024
frankmorgner added a commit to frankmorgner/OpenSC that referenced this issue Mar 14, 2024
@frankmorgner frankmorgner reopened this Mar 14, 2024
@frankmorgner
Copy link
Member

I did a bit of procastination and implemented this in #3071 . This implementation is purely based on the specification, so I'd appreciate someone actually testing the pull request.

frankmorgner added a commit to frankmorgner/OpenSC that referenced this issue Mar 14, 2024
frankmorgner added a commit to frankmorgner/OpenSC that referenced this issue Apr 1, 2024
frankmorgner added a commit to frankmorgner/OpenSC that referenced this issue Apr 12, 2024
fixes detection of Yubikey version, which was broken since f6b4a2e, see
OpenSC#3071 (comment)

fixes OpenSC#1769
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