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

OpenSC Minidriver with PIVApplet + ECC keys on Win11: error on slot 9c - public key does not match private key #3159

Open
ckahlo opened this issue May 26, 2024 · 28 comments · May be fixed by #3167

Comments

@ckahlo
Copy link

ckahlo commented May 26, 2024

Hi there,

Problem Description

after using @vletoux GIDS applet for quite a while (thanks :)!) I wanted to migrate to ECC and PIV because I need integration with
the OS - such as logon, VPN, TLS, SSH. Unfortunately I could only manage to get a Yubikey running with Active Directory CA
credentials in a manual process with a custom CA template - so I could verify AD and client are prepared to handle at least ECCP256 and do workstation logon. (enrollment for ECC doesn't really seem to work anyway ...?)
I am using the Yubico piv-tool below because I need to generate CSRs and the OpenSC toolchain lacks functionality for that.

So I chose https://github.com/arekinath/PivApplet and compiled it with the settings:

<property name="PIV_SUPPORT_RSA" value="false"/>
<property name="PIV_SUPPORT_EC" value="true"/>
<property name="PIV_SUPPORT_ECCP384" value="false"/>
<property name="PIV_SUPPORT_AES" value="true"/>
<property name="PIV_SUPPORT_3DES" value="false"/>
<property name="PIV_STRICT_CONTACTLESS" value="false"/>
<property name="YKPIV_ATTESTATION" value="true"/>
<property name="APPLET_EXTLEN" value="true"/>
<property name="APPLET_USE_RESET_MEM" value="false"/>
<property name="APPLET_LOW_TRANSIENT" value="false"/>

put it on a NXP P71D321 / J3R180 variant:
...\tools> .\gp.exe -dvil -install C:\Users\ck\git\PivApplet\bin\PivApplet.cap

check the status

...\PIV>piv-init
STATUS:
Version:        5.4.0
Serial Number:  -1654144648
CHUID:  30190000000000000000000000000000000000000000000000000034105db884ca12cbf24fe16120aa25809fa5350832303530303130313e00fe00
CCC:    f015a000000116ff0204345082ddf1aea2203f92e803b8f10121f20121f300f400f50110f600f700fa00fb00fc00fd00fe00
PIN tries left: 5

initialize the attestation, card authentication and key management keys

...\PIV>piv-init initcard
Successfully generated a new private key.
Successfully generated a new private key.
Successfully verified PIN.
Successfully generated a new self signed certificate.
Successfully verified PIN.
Successfully imported a new certificate.
Successfully verified PIN.
Successful ECDSA verification.
Successfully generated a new private key.
Successfully verified PIN.
Successfully generated a new self signed certificate.
Successfully verified PIN.
Successfully imported a new certificate.
Successfully verified PIN.
Successful ECDSA verification.

generate keypairs for PIV authentication and digital signature (testcase here, simulating the exact same problem with real CA)

...\PIV>piv-init selfsign
Successfully generated a new private key.
Successfully verified PIN.
Successfully generated a new self signed certificate.
Successfully verified PIN.
Successfully imported a new certificate.
Successfully verified PIN.
Successful ECDSA verification.
Successfully generated a new private key.
Successfully verified PIN.
Successfully generated a new self signed certificate.
Successfully verified PIN.
Successfully imported a new certificate.
Successfully verified PIN.
Successful ECDSA verification.
Successfully verified PIN.
Successfully set new CCC.
Successfully set new CHUID.

check the results and getting errors, resembling what I observed before:

...\PIV>certutil -scinfo -v -privatekey
Die Microsoft Smartcard-Ressourcenverwaltung wird ausgeführt.
...
=======================================================
Karte im Leser wird analysiert: ACS ACR1255U-J1 PICC Reader 0
Microsoft Base Smart Card Crypto Provider: Gespeicherter Schlüsselsatz fehlt
...
ERROR: Der öffentliche Schlüssel des Zertifikats konnte nicht gegen den privaten Schlüssel überprüft werden.
Microsoft Smart Card Key Storage Provider: KeySpec=0
AES256+RSAES_OAEP(ECC:CNG) Test übersprungen
....
--------------===========================--------------
CertUtil: -SCInfo-Befehl ist fehlgeschlagen: 0x80090016 (-2146893802 NTE_BAD_KEYSET)
CertUtil: Der Schlüsselsatz ist nicht vorhanden.

The certificates show up nicely:

image

I tracked the issue down to the second key slot, being assigned to the 9c ("digital signature") slot in the PIV applet.

I'm attaching all I've got from the logs.

Proposed Resolution

Slot 9c needs to work to do smartcard logon - while TLS client authenticaton may work with slot 9a many other things (VPN, RDP) do not.

Steps to reproduce

For piv-init initcard I do:

:initcard
%PIVTOOL% -r %READER% -agenerate -s f9 -A%ALG% > att-key.pem

REM card authentication key
%PIVTOOL% -r %READER% -agenerate -s 9e -A%ALG% > tmp-key.pem
%PIVTOOL% -r %READER% -P %PIN% -averify -aselfsign-certificate -s 9e -S"/CN=%CN%-CA/" < tmp-key.pem > tmp-cert.pem
%PIVTOOL% -r %READER% -P %PIN% -averify -aimport-certificate -s 9e < tmp-cert.pem
%PIVTOOL% -r %READER% -P %PIN% -averify -atest-signature -s 9e < tmp-cert.pem

REM key management key
%PIVTOOL% -r %READER% -agenerate -s 9d -A%ALG% > tmp-key.pem
%PIVTOOL% -r %READER% -P %PIN% -averify -aselfsign-certificate -s 9d -S"/CN=%CN%-KM/" < tmp-key.pem > tmp-cert.pem
%PIVTOOL% -r %READER% -P %PIN% -averify -aimport-certificate -s 9d < tmp-cert.pem
%PIVTOOL% -r %READER% -P %PIN% -averify -atest-signature -s 9d < tmp-cert.pem
goto status

For piv-init selfsign I do:

:selfsign
REM PIV authentication key
%PIVTOOL% -r %READER% -agenerate -s 9a -A%ALG% > auth-key.pem
%PIVTOOL% -r %READER% -P %PIN% -averify -aselfsign-certificate -s 9a -S"/CN=%CN%-PA/" < auth-key.pem > auth-cert.pem
%PIVTOOL% -r %READER% -P %PIN% -averify -aimport-certificate -s 9a < auth-cert.pem
%PIVTOOL% -r %READER% -P %PIN% -averify -atest-signature -s 9a < auth-cert.pem

REM digital signature key 
%PIVTOOL% -r %READER% -agenerate -s 9c -A%ALG% > sign-key.pem
%PIVTOOL% -r %READER% -P %PIN% -averify -aselfsign-certificate -s 9c -S"/CN=%CN%-DS/" < sign-key.pem > sign-cert.pem
%PIVTOOL% -r %READER% -P %PIN% -averify -aimport-certificate -s 9c < sign-cert.pem
%PIVTOOL% -r %READER% -P %PIN% -averify -atest-signature -s 9c < sign-cert.pem

REM init card capabilities container and UID
%PIVTOOL% -r %READER% -P %PIN% -averify -aset-ccc -aset-chuid
goto status

Logs

see https://gist.github.com/ckahlo/bc00b88d911364a584069dd237601967 for scinfo -v -privatekey

see opensc-debug.txt attached

opensc-debug.txt

Thank you!

@ckahlo
Copy link
Author

ckahlo commented May 26, 2024

PS: I already saw #2592 and found it is probably not related.

PPS: While reviewing the logs again I can also see, that the key management key is verified correctly, but card authentication is not as well.

I added the card to the registry this way, "AllID ..." is just an artificial name starting with "A" - not a real world product. It took me a while until I tracked down everything, so I had to conduct a few experiments.

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\AllID P71 NFC]
"Crypto Provider"="Microsoft Base Smart Card Crypto Provider"
"Smart Card Key Storage Provider"="Microsoft Smart Card Key Storage Provider"
"80000001"="C:\\Program Files\\OpenSC Project\\OpenSC\\minidriver\\opensc-minidriver.dll"
"ATRMask"=hex:ff,ff,ff,ff,ff,ff,ff,ff,ff,ff
"InstalledBy"="OpenSC"
"ATR"=hex:3b,85,80,01,80,73,c8,21,10,0e

@dengert
Copy link
Member

dengert commented May 27, 2024

Looks like it should work. Here are some things to look at:

  • You may need to update HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Cryptography\Calais\SmartCards and install OpenSC 32 bit.
  • Check HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\PIV Device ATR Cache to make sure Windows is not using the Microsoft builtin PIV support is some cases.
  • Are you using multiple tokens or just the same token for the tests?
  • Although you have set <property name="PIV_STRICT_CONTACTLESS" value="false"/> some other software may be looking at the ATR which is saying contacless and not trying the operation.
  • Try running `opensc-tool -a --serial to see the ATR and the serial number that comes is derived from the CHUID, as PIV specs do not say anything about a serial number.

PIV specs call for the 9C key to require a pin verify just before the the signature operation at line 18120 in the debug log:

 Outgoing APDU (44 bytes):
00 87 11 9C 26 7C 24 82 00 81 20 00 01 02 03 04 ....&|$... .....
05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 ................
15 16 17 18 19 1A 1B 1C 1D 1E 1F 00             ............

P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] reader-pcsc.c:244:pcsc_internal_transmit: called
P:3304; T:9592 2024-05-26 21:55:35.950 [cardmod] reader-pcsc.c:334:pcsc_transmit: 
Incoming APDU (2 bytes):
69 82 i.

P:3304; T:9592 2024-05-26 21:55:35.950 [cardmod] apdu.c:382:sc_single_transmit: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.950 [cardmod] apdu.c:539:sc_transmit: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.950 [cardmod] card.c:523:sc_unlock: called
P:3304; T:9592 2024-05-26 21:55:35.950 [cardmod] card-piv.c:5833:piv_check_sw: called
P:3304; T:9592 2024-05-26 21:55:35.950 [cardmod] Security status not satisfied
P:3304; T:9592 2024-05-26 21:55:35.950 [cardmod] Card returned error 

In PKCS11 this is called CKA_ALWAYS_AUTHENTICATE, in PKCS15 it is called user-consent
But it looks like this is not being handle correctly by windows. (You cold try with an RSA key as i think it will work.)

You also also modify opensc.conf it turn on pin caching use_pin_caching and and allow caching PIN for software that does not handle CKA_ALWAYS_AUTHENTICATE/user-consent pin_cache_ignore_user_consent

(You could try with an RSA key for 9C as i think it will work with RSA.)

Also look if there us an option to turn this off for PivApplet.

Also try to sign with pkcs11-tool as a test.

@ckahlo
Copy link
Author

ckahlo commented May 27, 2024

Hi @dengert,

thanks for your reply and suggestions.

  • created additional WOW6432 entries and installed OpenSC 32-Bit
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Cryptography\Calais\SmartCards\AllID P71 NFC]
"Crypto Provider"="Microsoft Base Smart Card Crypto Provider"
"Smart Card Key Storage Provider"="Microsoft Smart Card Key Storage Provider"
"80000001"="C:\\Program Files (x86)\\OpenSC Project\\OpenSC\\minidriver\\opensc-minidriver.dll"
"ATRMask"=hex:ff,ff,ff,ff,ff,ff,ff,ff,ff,ff
"InstalledBy"="OpenSC"
"ATR"=hex:3b,85,80,01,80,73,c8,21,10,0e
  • check PIV-cache does not contain the card
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\PIV Device ATR Cache]
"87689248-fbdf-4138-afb8-c3bd04970337"=hex:3b,87,80,01,55,31,32,33,41,42,43,23
"162d4017-b244-4255-b217-14c17b10f40e"=hex:3b,8a,80,01,80,31,f8,73,f7,41,e0,82,90,00,75
"7c9bbff1-d27d-4431-8739-c95a0358f302"=hex:3b,fc,13,00,00,81,31,fe,15,59,75,62,69,6b,65,79,4e,45,4f,72,33,e1
"69ab85c3-32d2-4f85-8233-da8470b87e6a"=hex:3b,8b,80,01,00,31,c1,64,09,37,72,13,00,90,00,51
"3c0df911-08ce-4bc9-b92b-ec669717bfa0"=hex:3b,dc,18,ff,80,11,c1,80,73,c8,21,13,66,05,03,63,51,00,02,32
  • For the tests I am using the very same chip, for a clean and well defined start I delete and reinstall PIVApplet
  • it's a dual-interface P71 - so I can test contact-based and via NFC, registry entries exist for both ATRs - response of MiniDriver is identical, card is detected correctly "AllID P71 NFC" / "AllID P71 contact"
  • ran opensc-tool against a current test version, serial number might differ because re-initialized applet
C:\Program Files\OpenSC Project\OpenSC\tools>opensc-tool -a --serial -v
Using reader with a card: Alcor Micro USB Smart Card Reader 0
Card ATR:
3B D5 18 FF 81 91 FE 1F C3 80 73 C8 21 10 0A ;.........s.!..
Connecting to card in reader Alcor Micro USB Smart Card Reader 0...
Using card driver Personal Identity Verification Card.
Card serial number:CF 20 D2 3D FE D2 E8 4C 1D 84 F4 36 46 01 FB 0E . .=...L...6F...

  • PIN verification is done by certutil at the beginning
    image
  • changed opensc.conf to
app default {
	debug = 3;
	debug_file = /tmp/opensc-debug.txt;

	use_pin_caching = true;		
	pin_cache_counter = 3;
	pin_cache_ignore_user_consent = true;
}
  • recompiled PIVApplet with <property name="PIV_SUPPORT_RSA" value="true"/>
  • created an "all RSA" card
...\PIV>piv-init.cmd selfsign
Successfully generated a new private key.
Successfully verified PIN.
Successfully generated a new self signed certificate.
Successfully verified PIN.
Successfully imported a new certificate.
Successfully verified PIN.
Successful RSA verification.
Successfully generated a new private key.
Successfully verified PIN.
Successfully generated a new self signed certificate.
Successfully verified PIN.
Successfully imported a new certificate.
Successfully verified PIN.
Successful RSA verification.
Successfully verified PIN.
Successfully set new CCC.
Successfully set new CHUID.
STATUS:
Version:        5.4.0
Serial Number:  -763639613
CHUID:  3019d4e739da739ced39ce739d836858210842108421c84210c3eb3410d2e6e605d88fcde0f0bf7367fc2a4139350832303330303130313e00fe00
CCC:    f015a000000116ff0202a052f2d83f3a3e2fd0d4d85519f10121f20121f300f40100f50110f600f700fa00fb00fc00fd00fe00
Slot 9a:
        Algorithm:      RSA2048
        Subject DN:     CN=test-PA
        Issuer DN:      CN=test-PA
        Fingerprint:    6e016cab513bd28479c5b4eeb18a80629b90ef718ca4a2e4bec9d108dd3759be
        Not Before:     May 27 16:42:01 2024 GMT
        Not After:      May 27 16:42:01 2025 GMT
Slot 9c:
        Algorithm:      RSA2048
        Subject DN:     CN=test-DS
        Issuer DN:      CN=test-DS
        Fingerprint:    e7c733a3cf0f3c60445aaa45d01a504cd4fb2b7f1407b42386b1343a8e14c8a6
        Not Before:     May 27 16:42:15 2024 GMT
        Not After:      May 27 16:42:15 2025 GMT
Slot 9d:
        Algorithm:      RSA2048
        Subject DN:     CN=test-KM
        Issuer DN:      CN=test-KM
        Fingerprint:    89ff65387c312d8e64a7a530f7c6b89ede69425dcaf91e13bc2bf54f726c1cd0
        Not Before:     May 27 16:41:43 2024 GMT
        Not After:      May 25 16:41:43 2034 GMT
Slot 9e:
        Algorithm:      RSA2048
        Subject DN:     CN=test-CA
        Issuer DN:      CN=test-CA
        Fingerprint:    b3474fb84af884113923d3f4980f4cdd7c368bfc8f16588bbbed2576f84f457e
        Not Before:     May 27 16:41:31 2024 GMT
        Not After:      May 25 16:41:31 2034 GMT
PIN tries left: 5

same result at slot 9c:

Signatur stimmt mit dem öffentlichen Schlüssel überein.
Stammzertifikat: Antragsteller stimmt mit Aussteller überein
[...]
Schlüssel-ID-Hash(sha256): 9b8f8fdba90e787a0c33a1627c5fbef4e71cc79f87a1048ef9755710b7f9ad52
[...]
Zertifikathash(sha256): e7c733a3cf0f3c60445aaa45d01a504cd4fb2b7f1407b42386b1343a8e14c8a6
Signaturhash: 913af5492b917a8495ee244cbf279be7b1370d7c8a8d2c1684e4e7d7c8599459

Vergleich  öffentlicher Schlüssel wird durchgeführt...
Vergleich öffentlicher Schlüssel erfolgreich
  Schlüsselcontainer = 02e6e605d88fcde0f0bf7367fc2a4139
  Einfacher Containername: 02e6e605d88fcde0f0bf7367fc2a4139
  Eindeutiger Containername: 02e6e605d88fcde0f0bf7367fc2a4139
  Anbieter = Microsoft Smart Card Key Storage Provider
  Anbietertyp = 0
  Kennzeichen = 1
      (CRYPT_MACHINE_KEYSET -- 20 (32))
      (CRYPT_SILENT -- 40 (64))
    0x1 (1)
  Schlüsselspez. = 0 -- XCN_AT_NONE
ERROR: Der öffentliche Schlüssel des Zertifikats konnte nicht gegen den privaten Schlüssel überprüft werden.
Microsoft Smart Card Key Storage Provider: KeySpec=0
AES256+RSAES_OAEP(RSA:CNG) Test NICHT erfolgreich: Das Zertifikat und der private Schlüssel für die Entschlüsselung wurden nicht gefunden. 0x8009200c (-2146885620 CRYPT_E_NO_DECRYPT_CERT)
[...]
  • using pkcs-tool with all-RSA card for test
C:\Program Files\OpenSC Project\OpenSC\tools>pkcs11-tool -T -M -v
Available slots:
Slot 0 (0x0): ACS ACR1255U-J1 PICC Reader 0
  manufacturer:
  hardware ver:  0.0
  firmware ver:  0.0
  flags:         token present, removable device, hardware slot
  token label        : test-PA
  token manufacturer : piv_II
  token model        : PKCS#15 emulated
  token flags        : login required, token initialized, PIN initialized
  hardware version   : 0.0
  firmware version   : 0.0
  serial num         : f0bf7367fc2a4139
  pin min/max        : 4/8
Using slot 0 with a present token (0x0)
Supported mechanisms:
  SHA-1, digest
  SHA224, digest
  SHA256, digest
  SHA384, digest
  SHA512, digest
  MD5, digest
  RIPEMD160, digest
  GOSTR3411, digest
  RSA-X-509, keySize={1024,3072}, hw, decrypt, sign, verify
  RSA-PKCS, keySize={1024,3072}, hw, decrypt, sign, verify
  SHA1-RSA-PKCS, keySize={1024,3072}, sign, verify
  SHA224-RSA-PKCS, keySize={1024,3072}, sign, verify
  SHA256-RSA-PKCS, keySize={1024,3072}, sign, verify
  SHA384-RSA-PKCS, keySize={1024,3072}, sign, verify
  SHA512-RSA-PKCS, keySize={1024,3072}, sign, verify
  MD5-RSA-PKCS, keySize={1024,3072}, sign, verify
  RIPEMD160-RSA-PKCS, keySize={1024,3072}, sign, verify
  RSA-PKCS-PSS, keySize={1024,3072}, hw, sign, verify
  SHA1-RSA-PKCS-PSS, keySize={1024,3072}, sign, verify
  SHA224-RSA-PKCS-PSS, keySize={1024,3072}, sign, verify
  SHA256-RSA-PKCS-PSS, keySize={1024,3072}, sign, verify
  SHA384-RSA-PKCS-PSS, keySize={1024,3072}, sign, verify
  SHA512-RSA-PKCS-PSS, keySize={1024,3072}, sign, verify
  RSA-PKCS-OAEP, keySize={1024,3072}, hw, decrypt

But it's trying to use "test-PA" - thats PIV Authentication (9A), not digital signature (9C):

C:\Program Files\OpenSC Project\OpenSC\tools>pkcs11-tool -s -v
Using slot 0 with a present token (0x0)
Logging in to "test-PA".
Please enter User PIN: Using signature algorithm RSA-X-509
Test
em║├ÅcðÆ0¦IX┌»Æ...

How do I force PKCS-11 to use test-DS / 9C?

@ckahlo
Copy link
Author

ckahlo commented May 27, 2024

BTW: the "serial number" from the Yubico piv-tool is a Yubikey serial number - out of spec for PIV-II. The PIVApplet just generates one at random during install.
Described at https://github.com/arekinath/PivApplet:

Most YubiKeyPIV-compatible extensions are implemented and working:

PIN policy

Version indicator (we pretend to be a YK5)

Fetch serial number (randomly generated)

Set management key
...

@ckahlo
Copy link
Author

ckahlo commented May 27, 2024

Okay, it is "--id 2" similar to the slot enumeration of the minidriver

C:\Program Files\OpenSC Project\OpenSC\tools>pkcs11-tool -v -s --id 2
Using slot 0 with a present token (0x0)
Logging in to "test-PA".
Please enter User PIN: Using signature algorithm RSA-X-509
Test
Logging in to "test-PA".
Please enter context specific PIN:
D╗·┌2îüGoú@....

Definitely this "context specific PIN" is missing from the mini driver tests.

@ckahlo
Copy link
Author

ckahlo commented May 27, 2024

Thanks for pointing out the 0x6982. I gave it a try and modified PivApplet to use P_DEFAULT (0), which is P_ONCE, instead of P_ALWAYS for slot 0x9C. At least now certutil -scinfo says "private key verified" for slot 0x9C. But PKCS#11 now hangs.
But there are still errors as smartcard logon says "the smartcard cannot be used" and RDP and VPN do not work.

@dengert
Copy link
Member

dengert commented May 27, 2024

Not sure what "modified PivApplet to use P_DEFAULT (0), which is P_ONCE" does.

This Windows policy for ECC keys for login maybe the problem:
https://learn.microsoft.com/en-us/windows/security/identity-protection/smart-cards/smart-card-group-policy-and-registry-settings#allow-ecc-certificates-to-be-used-for-logon-and-authentication

Also says:
"This policy setting only affects a user's ability to sign in to a domain. ECC certificates on a smart card that are used for other applications, such as document signing, aren't affected by this policy setting.
If you use an ECDSA key to sign in, you must also have an associated ECDH key to permit sign in when you're not connected to the network."

Windows also looks at keyUsage bits in certificates, and may also be looking at certificate chains and trusted root CA.

I tried certutil -v -scinfo using a IDEMIA ID-One PIV test card from 2020 using their PIV driver. It prompted for the PIN twice and verified the the certificates "against UNTRUSTED root" These were ECC 256 and 384, yet it produced popup window with "The smart card cannot perform the requested operation or operation requires a different smart card."

@ckahlo
Copy link
Author

ckahlo commented May 27, 2024

I modified https://github.com/arekinath/PivApplet/blob/master/src/net/cooperi/pivapplet/PivApplet.java#L449 to change the PIN-behavior of slot 9C.

The group policy to enable ECC certificates is long in place. The Active Directory CA is of course trusted and >7 years in place, the keyUsage bits are correct. As said in the initial post I was using GIDS for years already and I managed to get it working with a Yubikey and ECC P256.
But Yubikey has a different mini driver - and I can confirm it only works with their mini driver. So my impression is, it is a problem with the OpenSC mini driver.

image

Yes, scinfo should prompt twice if the minidriver forwards the 0x6982 condition to the upper application layer, so it can prompt the user. The OpenSC mini driver is simply not doing this. You proved it yourself with the Idemia Card and Idemias PIV MD.

@dengert
Copy link
Member

dengert commented May 28, 2024

As you already know, the OpenSC PIV for minidriver is not installed by default. This was because Microsoft provides a way to use PIV cards. Have you tried letting Microsoft discover that you have a PIV card? I assume you have, because you are trying to use the OpenSC version.
https://learn.microsoft.com/en-us/windows-hardware/drivers/smartcard/discovery-process#windows-smart-card-class-minidriver-discovery-process.

in your original opensc-debug.log starting at 13273:

P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] MD_Function:CardSignData:4760 called
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] 
P:3304 T:9592 pCardData:0000016D71FF1B40 
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] CardSignData
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] check_reader_status for CardSignData
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] MD_Function:check_card_status:401 called
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] MD_Function:check_card_status:411 returning with: 0x00000000
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] pCardData->hSCardCtx:0xCD00000300000004 hScard:0xEA00000700000000
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] sc.c:340:sc_detect_card_presence: called
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] reader-pcsc.c:471:pcsc_detect_card_presence: called
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] ACS ACR1255U-J1 PICC Reader 0 check
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] reader-pcsc.c:386:refresh_attributes: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] reader-pcsc.c:479:pcsc_detect_card_presence: returning with: 5
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] sc.c:351:sc_detect_card_presence: returning with: 5
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] check_reader_status r=5 flags 0x00000005
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] MD_Function:check_card_reader_status:486 returning with: 0x00000000
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] CardSignData dwVersion=2, bContainerIndex=0, dwKeySpec=3, dwSigningFlags=0x00000000, aiHashAlg=0x00000000
P:3304; T:9592 2024-05-26 21:55:28.140 [cardmod] pInfo->dwVersion = 2
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] CARD_PADDING_INFO_PRESENT not set
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] pInfo->cbSignedData = 64
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] lg = 64
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] pkcs15-sec.c:609:sc_pkcs15_compute_signature: called
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] supported algorithm flags 0x300100, private key usage 0x4
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] ECDSA using SC_ALGORITHM_ECDSA_RAW flags before 0x00000000
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] padding.c:686:sc_get_encoding_flags: called
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] iFlags 0x100000, card capabilities 0x300100
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] pad flags 0x0, secure algorithm flags 0x100000
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] padding.c:752:sc_get_encoding_flags: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] DEE flags:0x00100000 alg_info->flags:0x00300100 pad:0x00000000 sec:0x00100000
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] card.c:471:sc_lock: called
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] card-piv.c:6147:piv_card_reader_lock_obtained: called
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] card-piv.c:4934:piv_find_discovery: called
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] card-piv.c:3005:piv_get_data: called
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] #10, Discovery Object
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] card.c:471:sc_lock: called
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] card.c:513:sc_lock: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] buffer for #10 *buf=0x0000000000000000 len=65279
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] card-piv.c:1745:piv_general_io: called
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] card.c:471:sc_lock: called
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] card.c:513:sc_lock: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] apdu.c:550:sc_transmit_apdu: called
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] card.c:471:sc_lock: called
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] card.c:513:sc_lock: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] apdu.c:515:sc_transmit: called
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] apdu.c:363:sc_single_transmit: called
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] CLA:0, INS:CB, P1:3F, P2:FF, data(3) 000000346DDFD990
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] reader 'ACS ACR1255U-J1 PICC Reader 0'
P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] reader-pcsc.c:325:pcsc_transmit: 
Outgoing APDU (9 bytes):
00 CB 3F FF 03 5C 01 7E 00 ..?..\.~.

P:3304; T:9592 2024-05-26 21:55:28.156 [cardmod] reader-pcsc.c:244:pcsc_internal_transmit: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] reader-pcsc.c:334:pcsc_transmit: 
Incoming APDU (22 bytes):
7E 12 4F 0B A0 00 00 03 08 00 00 10 00 01 00 5F ~.O............_
2F 02 40 00 90 00                               /.@...

P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] apdu.c:382:sc_single_transmit: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] apdu.c:539:sc_transmit: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card.c:523:sc_unlock: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card-piv.c:5833:piv_check_sw: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card.c:523:sc_unlock: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card-piv.c:1797:piv_general_io: returning with: 20
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card.c:523:sc_unlock: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card-piv.c:3104:piv_get_data: returning with: 20
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card-piv.c:4970:piv_find_discovery: returning with: 20
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card-piv.c:6206:piv_card_reader_lock_obtained: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card.c:513:sc_lock: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] sec.c:108:sc_set_security_env: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card-piv.c:4484:piv_set_security_env: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] flags=00000015 op=2 alg=2 algf=00100000 algr=00000100 kr0=9a, krfl=1
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card-piv.c:4516:piv_set_security_env: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] sec.c:112:sc_set_security_env: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] sec.c:62:sc_compute_signature: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card-piv.c:4626:piv_compute_signature: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card-piv.c:4545:piv_validate_general_authentication: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card-piv.c:1745:piv_general_io: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card.c:471:sc_lock: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card.c:513:sc_lock: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] apdu.c:550:sc_transmit_apdu: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card.c:471:sc_lock: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] card.c:513:sc_lock: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] apdu.c:515:sc_transmit: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] apdu.c:363:sc_single_transmit: called
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] CLA:0, INS:87, P1:11, P2:9A, data(38) 000000346DDFBA80
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] reader 'ACS ACR1255U-J1 PICC Reader 0'
P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] reader-pcsc.c:325:pcsc_transmit: 
Outgoing APDU (44 bytes):

This is sign using ECC and 9A key:
00 87 11 9A 26 7C 24 82 00 81 20 00 01 02 03 04 ....&|$... .....
05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 ................
15 16 17 18 19 1A 1B 1C 1D 1E 1F 00             ............

P:3304; T:9592 2024-05-26 21:55:28.204 [cardmod] reader-pcsc.c:244:pcsc_internal_transmit: called
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] reader-pcsc.c:334:pcsc_transmit: 
Incoming APDU (78 bytes):

This is response with signature  length 0x48 30 6 02 ... D7 9F A8 3F as expected

7C 4A 82 48 30 46 02 21 00 CD 84 0C 26 9A FE 0F |J.H0F.!....&...
4D E0 B7 2D 68 F4 05 45 EE D4 EF 40 F4 23 19 1E M..-h..E...@.#..
3C 46 E4 C7 6E 3D C7 61 B7 02 21 00 FE DA A9 8B <F..n=.a..!.....
96 9C E3 49 68 68 DE BD 50 11 C0 2E 0D B2 B7 AD ...Ihh..P.......
A0 3A 73 0E 67 89 72 E5 D7 9F A8 3F 90 00       .:s.g.r....?..

P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] apdu.c:382:sc_single_transmit: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] apdu.c:539:sc_transmit: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] card.c:523:sc_unlock: called
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] card-piv.c:5833:piv_check_sw: called
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] card.c:523:sc_unlock: called
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] card-piv.c:1797:piv_general_io: returning with: 76
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] card-piv.c:4613:piv_validate_general_authentication: returning with: 72
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] asn1.c:2276:sc_asn1_decode_ecdsa_signature: returning with: 64
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] card-piv.c:4654:piv_compute_signature: returning with: 64
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] sec.c:66:sc_compute_signature: returning with: 64
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] card.c:523:sc_unlock: called
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] pkcs15-sec.c:169:use_key: returning with: 64
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] pkcs15-sec.c:786:sc_pkcs15_compute_signature: returning with: 64
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] sc_pkcs15_compute_signature return 64
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] CardSignData, dwVersion=7, name=AllID P71 NFC, hScard=0xEA00000700000000, hSCardCtx=0xCD00000300000004
P:3304; T:9592 2024-05-26 21:55:28.299 [cardmod] MD_Function:CardSignData:5041 returning with: 0x00000000

So it looks like it worked as expected for 9A key.

Since you said it fails for 9C even with RSA, so it looks like it has a problem.

I will look closer tomorrow. Its a holiday in the U.S today.

@ckahlo
Copy link
Author

ckahlo commented May 28, 2024

Have a nice holiday @dengert and thanks for your fast reply. :-)

I did try to let the PIV layer know about the card, it also get's registered in the PIV device ATR cache in this case:
image

As you already imagined it didn't work out, but with the link you provided you're starting to convince me to try
more modifications of the applet. And yes, 9A worked as said. I can use it to login at https://myapps.microsoft.com/
and all the rest of the Azure / Entra cloud via TLS client authentication.

I try to figure out if I can get a debug log from the logon process. I have an almost identical certificate of the Yubikey
on a P71 now - as close as one can get it with a real-world CA.

The Yubikey certutil -scinfo shows it hides away 9C, 9D, 9E and only expose 9A. This sheds a new light on my
assumptions. So with the Yubikey 9C is never seen through the minidriver.

Thanks & best,
Christian

@dengert
Copy link
Member

dengert commented May 28, 2024

@ckahlo can you try setting these in the opensc.conf for the system. The location in registry at HKEY_LOCAL_MACHINE\SOFTWARE\OpenSC Project\OpenSC
And get a debug log with log level at least set at 9.

From
You also also modify opensc.conf it turn on pin caching use_pin_caching and and allow caching PIN for software that does not handle CKA_ALWAYS_AUTHENTICATE/user-consent pin_cache_ignore_user_consent
These should fix problem, at the expense of caching the pin.
Any other fix will take some more effort.

In your original opensc-debug.log The log is all from the same process P:3304 and same thread T:9952 and runs for 49 seconds.

  • 12 times OpenSC was started
  • 4 times piv_logout called
  • 1 signature worked for 9A key
  • 1 signature failed for 9C key

Starting here at line 18021:

P:3304; T:9592 2024-05-26 21:55:35.808 [cardmod] sec.c:203:sc_pin_cmd: called
P:3304; T:9592 2024-05-26 21:55:35.824 [cardmod] sec.c:259:sc_pin_cmd: returning with: 0 (Success)

Pin was entered, but the debug log level needs to be  9 or above to see the pin commands. 

P:3304; T:9592 2024-05-26 21:55:35.824 [cardmod] PIN cmd result 0
P:3304; T:9592 2024-05-26 21:55:35.824 [cardmod] pkcs15-pin.c:749:sc_pkcs15_pincache_add: called

Pin caching is on, but OpenSC knows that the card has at least one key that has CKA_ALWAYS_AUTHENTICATE i.e. user_consent
so refuses to cache the pin. 
 
P:3304; T:9592 2024-05-26 21:55:35.824 [cardmod] caching refused (user consent)
P:3304; T:9592 2024-05-26 21:55:35.840 [cardmod] card.c:523:sc_unlock: called
P:3304; T:9592 2024-05-26 21:55:35.840 [cardmod] pkcs15-pin.c:465:sc_pkcs15_verify_pin_with_session_pin: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.840 [cardmod] pkcs15-pin.c:749:sc_pkcs15_pincache_add: called
P:3304; T:9592 2024-05-26 21:55:35.840 [cardmod] caching refused (user consent)
P:3304; T:9592 2024-05-26 21:55:35.840 [cardmod] pkcs15-pin.c:321:sc_pkcs15_verify_pin: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.840 [cardmod] Pin code correct.
P:3304; T:9592 2024-05-26 21:55:35.840 [cardmod] MD_Function:CardAuthenticateEx:6038 returning with: 0x00000000
P:3304; T:9592 2024-05-26 21:55:35.840 [cardmod] MD_Function:CardSignData:4760 called
P:3304; T:9592 2024-05-26 21:55:35.840 [cardmod] 
P:3304 T:9592 pCardData:0000016D71FD1B20 
P:3304; T:9592 2024-05-26 21:55:35.840 [cardmod] CardSignData
P:3304; T:9592 2024-05-26 21:55:35.840 [cardmod] check_reader_status for CardSignData
P:3304; T:9592 2024-05-26 21:55:35.840 [cardmod] MD_Function:check_card_status:401 called
P:3304; T:9592 2024-05-26 21:55:35.855 [cardmod] MD_Function:check_card_status:411 returning with: 0x00000000
P:3304; T:9592 2024-05-26 21:55:35.855 [cardmod] pCardData->hSCardCtx:0xCD00000400000004 hScard:0xEA00000900000000
P:3304; T:9592 2024-05-26 21:55:35.855 [cardmod] sc.c:340:sc_detect_card_presence: called
P:3304; T:9592 2024-05-26 21:55:35.855 [cardmod] reader-pcsc.c:471:pcsc_detect_card_presence: called
P:3304; T:9592 2024-05-26 21:55:35.855 [cardmod] ACS ACR1255U-J1 PICC Reader 0 check
P:3304; T:9592 2024-05-26 21:55:35.855 [cardmod] reader-pcsc.c:386:refresh_attributes: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.855 [cardmod] reader-pcsc.c:479:pcsc_detect_card_presence: returning with: 5
P:3304; T:9592 2024-05-26 21:55:35.855 [cardmod] sc.c:351:sc_detect_card_presence: returning with: 5
P:3304; T:9592 2024-05-26 21:55:35.855 [cardmod] check_reader_status r=5 flags 0x00000005
P:3304; T:9592 2024-05-26 21:55:35.855 [cardmod] MD_Function:check_card_reader_status:486 returning with: 0x00000000
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] CardSignData dwVersion=2, bContainerIndex=1, dwKeySpec=3, dwSigningFlags=0x00000000, aiHashAlg=0x00000000
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] pInfo->dwVersion = 2
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] CARD_PADDING_INFO_PRESENT not set
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] pInfo->cbSignedData = 64
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] lg = 64
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] pkcs15-sec.c:609:sc_pkcs15_compute_signature: called
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] supported algorithm flags 0x300100, private key usage 0x204
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] ECDSA using SC_ALGORITHM_ECDSA_RAW flags before 0x00000000
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] padding.c:686:sc_get_encoding_flags: called
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] iFlags 0x100000, card capabilities 0x300100
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] pad flags 0x0, secure algorithm flags 0x100000
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] padding.c:752:sc_get_encoding_flags: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] DEE flags:0x00100000 alg_info->flags:0x00300100 pad:0x00000000 sec:0x00100000
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] card.c:471:sc_lock: called
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] card-piv.c:6147:piv_card_reader_lock_obtained: called
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] card-piv.c:4934:piv_find_discovery: called
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] card-piv.c:3005:piv_get_data: called
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] #10, Discovery Object
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] card.c:471:sc_lock: called
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] card.c:513:sc_lock: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.871 [cardmod] buffer for #10 *buf=0x0000000000000000 len=65279
P:3304; T:9592 2024-05-26 21:55:35.884 [cardmod] card-piv.c:1745:piv_general_io: called
P:3304; T:9592 2024-05-26 21:55:35.884 [cardmod] card.c:471:sc_lock: called
P:3304; T:9592 2024-05-26 21:55:35.884 [cardmod] card.c:513:sc_lock: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.884 [cardmod] apdu.c:550:sc_transmit_apdu: called
P:3304; T:9592 2024-05-26 21:55:35.884 [cardmod] card.c:471:sc_lock: called
P:3304; T:9592 2024-05-26 21:55:35.887 [cardmod] card.c:513:sc_lock: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.887 [cardmod] apdu.c:515:sc_transmit: called

The signature is about to be done and PIV card driver makes sure the PIV applet is the active active applet on the card
by using the  PIV Discovery (7E) object  which will return the PIV AID `A0 00 00 03 08 00 00 10 00 01 00` if PIV is active

P:3304; T:9592 2024-05-26 21:55:35.887 [cardmod] apdu.c:363:sc_single_transmit: called
P:3304; T:9592 2024-05-26 21:55:35.887 [cardmod] CLA:0, INS:CB, P1:3F, P2:FF, data(3) 000000346DDFD990
P:3304; T:9592 2024-05-26 21:55:35.887 [cardmod] reader 'ACS ACR1255U-J1 PICC Reader 0'
P:3304; T:9592 2024-05-26 21:55:35.887 [cardmod] reader-pcsc.c:325:pcsc_transmit: 
Outgoing APDU (9 bytes):
00 CB 3F FF 03 5C 01 7E 00 ..?..\.~.

P:3304; T:9592 2024-05-26 21:55:35.887 [cardmod] reader-pcsc.c:244:pcsc_internal_transmit: called
P:3304; T:9592 2024-05-26 21:55:35.919 [cardmod] reader-pcsc.c:334:pcsc_transmit: 
Incoming APDU (22 bytes):
7E 12 4F 0B A0 00 00 03 08 00 00 10 00 01 00 5F ~.O............_
2F 02 40 00 90 00                               /.@...

P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] apdu.c:382:sc_single_transmit: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] apdu.c:539:sc_transmit: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card.c:523:sc_unlock: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card-piv.c:5833:piv_check_sw: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card.c:523:sc_unlock: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card-piv.c:1797:piv_general_io: returning with: 20
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card.c:523:sc_unlock: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card-piv.c:3104:piv_get_data: returning with: 20
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card-piv.c:4970:piv_find_discovery: returning with: 20
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card-piv.c:6206:piv_card_reader_lock_obtained: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card.c:513:sc_lock: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] sec.c:108:sc_set_security_env: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card-piv.c:4484:piv_set_security_env: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] flags=00000015 op=2 alg=2 algf=00100000 algr=00000100 kr0=9c, krfl=1
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card-piv.c:4516:piv_set_security_env: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] sec.c:112:sc_set_security_env: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] sec.c:62:sc_compute_signature: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card-piv.c:4626:piv_compute_signature: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card-piv.c:4545:piv_validate_general_authentication: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card-piv.c:1745:piv_general_io: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card.c:471:sc_lock: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card.c:513:sc_lock: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] apdu.c:550:sc_transmit_apdu: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card.c:471:sc_lock: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] card.c:513:sc_lock: returning with: 0 (Success)
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] apdu.c:515:sc_transmit: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] apdu.c:363:sc_single_transmit: called
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] CLA:0, INS:87, P1:11, P2:9C, data(38) 000000346DDFBA80
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] reader 'ACS ACR1255U-J1 PICC Reader 0'
P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] reader-pcsc.c:325:pcsc_transmit: 

The signature command for key 9C 32 bytes  00 01 02 03 ...: 
Outgoing APDU (44 bytes):
00 87 11 9C 26 7C 24 82 00 81 20 00 01 02 03 04 ....&|$... .....
05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 ................
15 16 17 18 19 1A 1B 1C 1D 1E 1F 00             ............

P:3304; T:9592 2024-05-26 21:55:35.934 [cardmod] reader-pcsc.c:244:pcsc_internal_transmit: called
P:3304; T:9592 2024-05-26 21:55:35.950 [cardmod] reader-pcsc.c:334:pcsc_transmit: 

The command fails because PIV for 9C says in NIST sp800-73-4 (and older versions) :
Incoming APDU (2 bytes):
69 82 i.

in NIST sp800-73-4 (and older versions) :
"The The PKI cryptographic function (see Table 4b) is protected with a “PIN Always” or “OCC Always” access rule. In other words, the PIN or OCC data must be submitted and verified every time immediately before a digital signature key operation. This ensures cardholder participation every time the private key is used for digital signature generation.5"

The use of the '7E" discovery object is inserted between the PIN verify command and the signature key operation. When used with PKCS11, the upper levels tests if a key has the “PIN Always” and asks the user for the PIN and verifies just before the sign command. This may not be happening with minidriver, and/or the lower level code is not notified it is needed to take action like it does with PKCS11.

The use of logout in d7fadae may also complicate this.

@frankmorgner
Copy link
Member

The PKCS#11 workflow often includes PIN verification status requests between the actual verification and creation of the signature. To support the "PIN Always"/"OCC Always" mode, the PIV driver explicitly disabled the status query APDU:

if (priv->logged_in == SC_PIN_STATE_LOGGED_IN) {
/* Avoid status requests when the user is logged in to handle NIST
* 800-73-4 Part 2:
* The PKI cryptographic function (see Table 4b) is protected with
* a “PIN Always” or “OCC Always” access rule. In other words, the
* PIN or OCC data must be submitted and verified every time
* immediately before a digital signature key operation. This
* ensures cardholder participation every time the private key is
* used for digital signature generation */
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}

So similarly, you would need such special treatment when checking whether the applet is selected in piv_card_reader_lock_obtained(). In general, the PIV driver may need to be reviewed to avoid any APDU to be issued that is not strictly necessary in this case.

That being said, the conditions for this special treatment should be refined to something like IF logged in with "PIN Always"/"OCC Always" THEN avoid unnecessary APDUs. Also, the logged-in-state should be reset in this case if some APDU was sent - in best case the signature APDU, in worst case some other APDU that cannot be avoided. This refinement should also applied to the existing code referenced above, I think.

@dengert
Copy link
Member

dengert commented May 29, 2024

Windows appears to have a different way to handle the "PIN Always"/"OCC Always" type of key, by using PIN_CACHE_POLICY_TYPE PinCacheAlwaysPrompt and/or the minidriver.c has a MD_ROLE_USER_SIGN. which need to be investigated.

We do not install the OpenSC PIV entries in the registry, as most vendors provide their own minidriver, or people just use the Microsoft PIV support.

Also note the applet was installed on a "NXP P71D321 / J3R180 variant" device that is not listed on https://github.com/arekinath/PivApplet.

If this device is PIV complaint it should work with the Windows PIV support.

I would still like an opensc debug log using what @ckahlo added:

app default {
	debug = 3;
	debug_file = /tmp/opensc-debug.txt;

	use_pin_caching = true;		
	pin_cache_counter = 3;
	pin_cache_ignore_user_consent = true;
}

I would set debug = 9; to show any pin commands, and set the pin_cache_counter much higher as it applies to all uses.

It would show up in a line like this from the original debug log line15893:

P:3304; T:9592 2024-05-26 21:55:30.956 [cardmod] PKCS#15 options: use_file_cache=0 use_pin_cache=1 pin_cache_counter=10 pin_cache_ignore_user_consent=0 private_certificate=0

@chahlo, Are you doing this for your employer or just for yourself?

@ckahlo
Copy link
Author

ckahlo commented May 29, 2024

Hi @dengert, Hi @frankmorgner,

a couple of very well-known names in here :-)
Doug let me provide the log you wanted as soon as possible. I'm a bit drowning in tasks as well and wanted to let you know about my findings in case it helps to improve the end-user experience.
My employer is adesso SE, a 10k+ employees pan-european IT-company. I'm the Chief Security Architect there. @frankmorgner might remember my name from German eID / BSI TR-03110, 03111, 03112, 03124, 03130, ... At least 15+ years in working groups of our Federal Office for Information Security, etc. pp. That's (eID QES, PACE) implemented in OpenSC as well. :-)
For adesso we're evaluating THALES (SafeNet, Gemalto) products.
I wanted to push open-source products a bit more, but certain things have to work at first. Same situation for @vletoux OpenPGP-CSP.
The Azure Enterprise AD I am testing with is my very own. It's a personal thing to bring OSS into mind. If it works out a funding from @adessoSE can be discussed for sure.
https://www.linkedin.com/in/ckahlo

All the best,
Christian

@ckahlo
Copy link
Author

ckahlo commented May 29, 2024

PS: the J3R180 ist not that far away from J3H145. It's a follow-up, functional superset, much faster.
PPS: If it works out for my private use-case I will be very glad as well. But my funding capabilities may be limited. 🙈

@frankmorgner
Copy link
Member

Sure, I do remember you very well, in particular for the little projects, for example with the BSI, that were very interesting from a technical point of view, even though they may not have had the expected impact. Currently, the biggest problem for OpenSC is the lack support with the heterogenous infrastructure. Apple was constantly changing things in the last couple of years and MS infrastructure didn't get any simpler as well. So your comments and testing are very welcome.

frankmorgner added a commit to frankmorgner/OpenSC that referenced this issue May 30, 2024
TODO
That being said, the conditions for this special treatment should be
refined to something like IF logged in with "PIN Always"/"OCC Always"
THEN avoid unnecessary APDUs. Also, the logged-in-state should be reset
in this case if some APDU was sent - in best case the signature APDU, in
worst case some other APDU that cannot be avoided. This refinement
should also applied to the existing code referenced above, I think.

fixes OpenSC#3159
frankmorgner added a commit to frankmorgner/OpenSC that referenced this issue May 30, 2024
TODO
That being said, the conditions for this special treatment should be
refined to something like IF logged in with "PIN Always"/"OCC Always"
THEN avoid unnecessary APDUs. Also, the logged-in-state should be reset
in this case if some APDU was sent - in best case the signature APDU, in
worst case some other APDU that cannot be avoided. This refinement
should also applied to the existing code referenced above, I think.

fixes OpenSC#3159
@frankmorgner
Copy link
Member

I've pushed #3163 with a quick fix. If everything goes well, you may pull the Windows installer from AppVeyor.

@no-usernames-left
Copy link

So I chose https://github.com/arekinath/PivApplet and compiled it with the settings

Stupid question, but did none of the prebuilt CAPs fit your needs?

@no-usernames-left
Copy link

no-usernames-left commented May 30, 2024

Also note the applet was installed on a "NXP P71D321 / J3R180 variant" device that is not listed on https://github.com/arekinath/PivApplet.

I can send @ckahlo one J2A080 card (JCOP 2.4.1R3, GP 2.2.1, contact-only, OP_READY condition) gratis if this would help for troubleshooting. Let me know if so and I will reach out privately.

@dengert
Copy link
Member

dengert commented May 30, 2024

So similarly, you would need such special treatment when checking whether the applet is selected in piv_card_reader_lock_obtained(). In general, the PIV driver may need to be reviewed to avoid any APDU to be issued that is not strictly necessary in this case.

When a content specific C_Login is done, PIV driver gets an extra lock before doing the verify. This lock is held until the next request by the application to do any operation, which is expected to be a crypto operation. priv->context_specific = 1 is set. See: https://github.com/OpenSC/OpenSC/blob/master/src/libopensc/card-piv.c#L6016-L6031

This avoids this situation: "like IF logged in with "PIN Always"/"OCC Always" THEN avoid unnecessary APDUs" No unnecessary APDUs like checking status or login state are done as the PC/SC lock is being held. When the calling application, which knows it is doing a context specific login and should only do a crypto operation, requests any APDU, that APDU is done, and the lock is released, and priv->context_specific = 0. If an application does not understand a context specific login, the circumvention is to use the ignore-context-specific-login flag and let pin caching retry any failed crypto operation.

That being said, the conditions for this special treatment should be refined to something like IF logged in with "PIN Always"/"OCC Always" THEN avoid unnecessary APDUs. Also, the logged-in-state should be reset in this case if some APDU was sent - in best case the signature APDU, in worst case some other APDU that cannot be avoided. This refinement should also applied to the existing code referenced above, I think.

The use of the extra lock means the reader_lock_obtained code is not called before the next operation, which avoids "unnecessary" operations and also locks out other applications from causing interference between the verify and the crypto operation.

I believe the code current addresses the above, except with minidriver.

With the minidriver, If I am reading the Microsoft docs correctly, the application could be made aware that a verify is needed before the crypto operation, by using the treating the 9C key as requiring PIN_CACHE_POLICY_TYPE PinCacheAlwaysPrompt, which is very similar to the CKA_ALWAYS_AUTHENTICATE. which will cause the CSP to prompt the user of the pin, cause the minidriver to request a verify command be sent. By specifying the PIN as a different pin MD_ROLE_USER_SIGN The PIV really has only one active PIN either a local or global pin, but minidriver could pass verify as special pin, i.e. the same way the content-specific-login is being done. The details need to be worked out how the pkcs15 key and additional pin type are passed between the minidriver and pkcs15 routines.

@frankmorgner
Copy link
Member

Indeed, support for an equivalent of CKA_ALWAYS_AUTHENTICATE is not implemented in minidriver. Since CKA_ALWAYS_AUTHENTICATE is associated with the keys themselves and PinCacheAlwaysPrompt is associated to the PIN that unlocks the key, this cannot done in a straight forward way.

I think the best approach would be to create an additional virtual PIN that differs from the normal PIN only in the PIN_CACHE_POLICY_TYPE. Then all keys with user_consent map to the virtual PIN, keys without map to the normal PIN. The objects and their mapping are initialized in md_set_cmapfile(). For the virtual PIN, SC_AC_CONTEXT_SPECIFIC can then be set before validation. This change, however, needs to be implemented with care, because many places need to be touched that previously looked at the id of the PIN only.

I closed #3163 because it doesn't provide a general solution for keys with user consent, but I still believe it would solve the issue for PIV. So if you're in to quick-and-dirty solutions, you may still want to have a look.

Speaking of quick and dirty solutions, locking the card at the driver level and requiring a subsequent call for unlocking, can break in many ways: If anything goes wrong in between those calls, you will not be able to clean up the lock and the card is unusable within OpenSC and for any other process. It would be better to check the state and avoid commands as described above without locking the card. This discussion, however, should be done elswhere.

@dengert
Copy link
Member

dengert commented May 31, 2024

@maciejsszmigiero as author of the multiple pin support in OpenSC minidriver in bd9cdd2
could you comment on #3159 (comment)) Is PIN_CACHE_POLICY_TYPE PinCacheAlwaysPrompt the way to do this, and could this be added to the MD_ROLE_USER_SIGN or would it be better to a add another role like MD_ROLE_USER_ALWAYS_AUTHENTICATE

It also looks like we would need to flag any keys where the sc-pkcs15_object key object has user_consent > 0 to use MD_ROLE_USER_ALWAYS_AUTHENTICATE.

Then when the CSP requests a PIN verify using the MD_ROLE_USER_ALWAYS_AUTHENTICATE role to pass this to pkcs15 .
It looks like that would happen md_dialog_perform_pin_operation_thread that passes the struct sc_pkcs15_object *pin_obj = (struct sc_pkcs15_object *) parameter[2];

Any advice would be helpful.

@dengert dengert linked a pull request Jun 1, 2024 that will close this issue
5 tasks
@dengert
Copy link
Member

dengert commented Jun 1, 2024

@ckahlo have a look at #3167 which has a potential fix. If you want to use the same MSI files I used which can be found by looking at #3167 in the "Some checks were not successful" box (near the bottom), make sure all all checks are shown, then scroll down to "continuous-integration/appveyor/pr — AppVeyor build succeeded" at the bottom, and click on Details. This will take you to https://ci.appveyor.com/project/frankmorgner/opensc/builds/49934816
Then do this twice:
Click on the first job name with 2017 which should be " Configuration: Release; Platform: x86" then click on artifacts and down load the MSI file.
Click on the second job name with 2017 to get the Configuration: Release; Platform: x64 under artifacts and down load.

@frankmorgner
Copy link
Member

First, I don't think that setting PinCacheAlwaysPrompt for the signature PIN in general is useful for all the card, because if possible PIN caching is a desired feature. But I do agree that creating a "virtual" PIN for keys with required user consent helps in setting the correct PIN caching policy. Second, your approach in #3167 requires modifications of the card driver level of creating the virtual PIN, but that will be hard to do for every existing driver.

My advice would be, to create virtual PINs in the minidriver rather than the card driver based on the existing card profile. I described the approach already above. In md_set_cmapfile() more PINs than the standard roles are already created if the card has more available. Here, you would now add one virtual PIN for every normal PIN that has some key with user consent. Then, associate that key with the new virtual PIN instead of the normal PIN. This potentially doubles the number of pin_objs in VENDOR_SPECIFIC and should allow setting the cache policy for every underlying card driver without modifying anything else than minidriver.c

I will not be able to test this since I don't have any card with that configuration. I can supply some code that might work if someone is interested.

@maciejsszmigiero
Copy link
Contributor

@maciejsszmigiero as author of the multiple pin support in OpenSC minidriver in bd9cdd2
could you comment on #3159 (comment)) Is PIN_CACHE_POLICY_TYPE PinCacheAlwaysPrompt the way to do this, and could this be added to the MD_ROLE_USER_SIGN or would it be better to a add another role like MD_ROLE_USER_ALWAYS_AUTHENTICATE

I think it depends whether there are (or can be) cards where there are multiple sign PINs and only some of these need PIN caching off.

If not, then probably re-using MD_ROLE_USER_SIGN is okay for this.
If, on the other hand, such cards are expected than we need additional PIN role to differentiate between these.

By the way, as I commented here, I don't think we should unconditionally set PinCacheAlwaysPrompt for every MD_ROLE_USER_SIGN PIN.

@dengert
Copy link
Member

dengert commented Jun 2, 2024

@frankmorgner @maciejsszmigiero Thanks for the comments. As noted in comment in the code:
15b00bf#diff-0472a0d91e9f422e4d90a09074f95d9edf67b14a2df432fcb3aacca29b9a3b39R6482 that setting PinCacheAlwaysPrompt for every user_sign pin needs to be checked. I was waiting for @ckahlo to try the current code before fixing this.

Using a MD_ROLE_USER_ALWAYS_AUTHENTICATE could work by using another PKCS15 flag and calling sc_pkcs15_find_pin_by_flags to find if the key needs ALWAYS_AUTHENTICATE.

No other card driver uses SC_AC_CONTEXT_SPECIFIC. It is based on PKCS11 pkcs11-base-v3.0-os says: "The CKA_ALWAYS_AUTHENTICATE attribute can be used to force re-authentication (i.e. force the user to provide a PIN) for each use of a private key." and "Re-authentication occurs by calling C_Login with userType set to CKU_CONTEXT_SPECIFIC immediately after a cryptographic operation using the key has been initiated (e.g. after C_SignInit). In this call, the actual user type is implicitly given by the usage requirements of the active key." So the term SC_AC_CONTEXT_SPECIFIC could be renamed.

PKCS15 has the concept of user_consent which can be an integer of number of times a key can be used before re-verification.
So a user_consent of 1 in effect is the same as PKCS11 ALWAYS_AUTHENTICATE. I believe Windows does not have a number of times a pin can be used, just the PinCacheAlwaysPrompt There a few OpenSC drivers that set user_consent which do need to be reviewed.

The PIV cards have been around since 2004, and the card enforces this policy of no APDUs between verify and crypto operation when using the 9C key. Note that PIV have only one user key which must be re-authenticated. Yubico has this not standard feature to turn this on or off for any key as well a touch policy, So that would require additional changes in the card-piv.c and pkcs15-piv.c.

In regards to pin caching, in my test I turn off the OpenSC caching off, to see what Windows would do. OpenSC pin caching will not work with a pin-pad reader. The simple certutil test I used only prompted once as there was only one crypto operation to be done with the 9C key. I would assume Windows would have prompted more then once to honor the PinCacheAlwaysPrompt

Only the card-piv.c driver test the auth_method for SC_AC_CONTEXT_SPECIFIC. iso7816.c treats it as SC_AC_CHV

Note that PIV is one of the most popular types of cards with multiple card manufacture's providing Windows minidrivers to support vendor specific features, and Windows has its own PIV support. So OpenSC does not install the register profiles for PIV.
It takes someone like @ckahlo to figure it out. I believe I have only heard of 2 other users asking how to do it. So I again say I would like to wait for @ckahlo to test the current code.

In regards to setting an extra lock to force the verify and crypto into the same SCardTransmission, card-piv.c will release it in a number of places. The only real problem would be if the application did a verify and never did any other operation, not a likely situation as the point doing a re-verify is to do a crypt operation immediately after.

@dengert
Copy link
Member

dengert commented Jun 3, 2024

This sounds like #3159 and #3167 because the keys are set at https://github.com/OpenSC/OpenSC/blob/master/src/libopensc/pkcs15-jpki.c#L168

The PKCS15 user_consent = 1 is the equivalent of PKCS11 CKA_ALWAYS_AUTHNETICATE.

What is output of pkcs15-tool --list-pins ?

You could try the MSI files as liksted here: #3159 (comment)

@dengert
Copy link
Member

dengert commented Jun 13, 2024

@ckahlo Please have a look at #3167 Minidriver now works with PIV 9C key. It still need some cleanup.

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