Support D-Trust Card 5.1 (Std. RSA CardOS6.0) with CAN
Problem Description
The D-Trust Signature Card 5.1 Std. (EIDAS QES signature certificate for signing and encryption certificate on card) with CardOS6.0 is currently not supported by OpenSC. To connect to the card/use the card a CAN number is needed (the CAN is printed on the card). It seems that OpenSC hasn't the possibility to provide/submit a CAN.
Proposed Resolution
It would be great if this card type is supported by OpenSC. This is merely a feature request than a bug report.
Steps to reproduce
$ echo "Sign me" | pkcs11-tool --slot 1 -a Signaturzertifikat -s -m RSA-PKCS -p XXXXXXXX
error: PKCS11 function C_GetTokenInfo failed: rv = CKR_TOKEN_NOT_RECOGNIZED (0xe1)
Aborting.
Debug log: log.txt
Logs
➜ ~ opensc-tool --version
OpenSC-<version not available>, rev: 0a4b772, commit-time: 2024-04-04 16:21:38 +0200
P:94404; T:0x140704682469312 22:40:04.528 [opensc-tool] ctx.c:747:process_config_file: scconf_parse failed: Line 2: not expecting 'default'
P:94404; T:0x140704682469312 22:40:04.529 [opensc-tool] ctx.c:981:sc_context_create: ===================================
P:94404; T:0x140704682469312 22:40:04.529 [opensc-tool] ctx.c:982:sc_context_create: OpenSC version: 0.25.1
P:94404; T:0x140704682469312 22:40:04.529 [opensc-tool] ctx.c:983:sc_context_create: Configured for opensc-tool (/Library/OpenSC/bin/opensc-tool)
P:94404; T:0x140704682469312 22:40:04.530 [opensc-tool] ctx.c:858:sc_openssl3_init: Failed to load OpenSSL Legacy provider
P:94404; T:0x140704682469312 22:40:04.530 [opensc-tool] reader-pcsc.c:897:pcsc_init: PC/SC options: connect_exclusive=0 disconnect_action=0 transaction_end_action=0 reconnect_action=0 enable_pinpad=1 enable_pace=1
P:94404; T:0x140704682469312 22:40:04.546 [opensc-tool] reader-pcsc.c:1397:pcsc_detect_readers: called
P:94404; T:0x140704682469312 22:40:04.546 [opensc-tool] reader-pcsc.c:1410:pcsc_detect_readers: Probing PC/SC readers
P:94404; T:0x140704682469312 22:40:04.546 [opensc-tool] reader-pcsc.c:1463:pcsc_detect_readers: Establish PC/SC context
P:94404; T:0x140704682469312 22:40:04.594 [opensc-tool] reader-pcsc.c:1346:pcsc_add_reader: Adding new PC/SC reader 'REINER SCT cyberJack one'
P:94404; T:0x140704682469312 22:40:04.594 [opensc-tool] reader-pcsc.c:361:refresh_attributes: REINER SCT cyberJack one check
P:94404; T:0x140704682469312 22:40:04.596 [opensc-tool] reader-pcsc.c:407:refresh_attributes: current state: 0x00000022
P:94404; T:0x140704682469312 22:40:04.596 [opensc-tool] reader-pcsc.c:408:refresh_attributes: previous state: 0x00000000
P:94404; T:0x140704682469312 22:40:04.596 [opensc-tool] reader-pcsc.c:463:refresh_attributes: card present, changed
P:94404; T:0x140704682469312 22:40:04.804 [opensc-tool] reader-pcsc.c:1564:pcsc_detect_readers: REINER SCT cyberJack one:SCardConnect(SHARED): 0x00000000
P:94404; T:0x140704682469312 22:40:04.804 [opensc-tool] reader-pcsc.c:1145:detect_reader_features: called
P:94404; T:0x140704682469312 22:40:04.805 [opensc-tool] reader-pcsc.c:1147:detect_reader_features: Requesting reader features ...
P:94404; T:0x140704682469312 22:40:04.806 [opensc-tool] reader-pcsc.c:1165:detect_reader_features: Reader feature 06 found
P:94404; T:0x140704682469312 22:40:04.806 [opensc-tool] reader-pcsc.c:1165:detect_reader_features: Reader feature 07 found
P:94404; T:0x140704682469312 22:40:04.806 [opensc-tool] reader-pcsc.c:1165:detect_reader_features: Reader feature 08 found
P:94404; T:0x140704682469312 22:40:04.806 [opensc-tool] reader-pcsc.c:1185:detect_reader_features: Reader feature 08 is not supported
P:94404; T:0x140704682469312 22:40:04.806 [opensc-tool] reader-pcsc.c:1165:detect_reader_features: Reader feature 09 found
P:94404; T:0x140704682469312 22:40:04.806 [opensc-tool] reader-pcsc.c:1185:detect_reader_features: Reader feature 09 is not supported
P:94404; T:0x140704682469312 22:40:04.806 [opensc-tool] reader-pcsc.c:1193:detect_reader_features: Reader supports pinpad PIN verification
P:94404; T:0x140704682469312 22:40:04.806 [opensc-tool] reader-pcsc.c:1203:detect_reader_features: Reader supports pinpad PIN modification
P:94404; T:0x140704682469312 22:40:04.806 [opensc-tool] reader-pcsc.c:1125:part10_get_vendor_product: id_vendor=ffffffff id_product=ffffffff
P:94404; T:0x140704682469312 22:40:04.807 [opensc-tool] reader-pcsc.c:1293:detect_reader_features: Reader supports sending 1014 bytes of data
P:94404; T:0x140704682469312 22:40:04.807 [opensc-tool] reader-pcsc.c:1306:detect_reader_features: Reader supports receiving 1014 bytes of data
P:94404; T:0x140704682469312 22:40:04.809 [opensc-tool] reader-pcsc.c:1579:pcsc_detect_readers: returning with: 0 (Success)
P:94404; T:0x140704682469312 22:40:04.809 [opensc-tool] ctx.c:1066:sc_release_context: called
P:94404; T:0x140704682469312 22:40:04.809 [opensc-tool] reader-pcsc.c:978:pcsc_finish: called
$ cardos-tool -i
Using reader with a card: REINER SCT cyberJack one
Card type FFFFFFFF: not a CardOS card
Debug log: cardostool.txt
$ opensc-tool --name
Using reader with a card: REINER SCT cyberJack one
Unsupported card
Debug log: opensctool--name.txt
$ pkcs11-tool -T
Available slots:
No slots.
Debug log: pkcs11-tool.txt
$ pkcs15-tool -D
Using reader with a card: REINER SCT cyberJack one
Failed to connect to card: Card is invalid or cannot be handled
Debug log: pkcs15-tool.txt
$ dtrust-tool
Using reader with a card: REINER SCT cyberJack one
Failed to connect to card: Security status not satisfied
Debug log: dtrust-tool.txt
$ opensc-tool -a
Using reader with a card: REINER SCT cyberJack one
3b:d2:18:00:81:31:fe:58:cb:01:16
Just to check whether PACE of the card is compatible with OpenSC's implementation, could you please try npa-tool --can=123456?
➜ ~ npa-tool --can=XXXXXX -v
Using reader with a card: REINER SCT cyberJack one
Connecting to card in reader REINER SCT cyberJack one...
Using card driver Default driver for unknown cards.
Established PACE channel with CAN.
Thanks, so mechanisms are in place, but we need to correctly look at the metadata. I'll try to get some developer information from D-Trust.
Maybe this is also interesting for @hamarituc
Thanks, so mechanisms are in place, but we need to correctly look at the metadata. I'll try to get some developer information from D-Trust.
Maybe this is also interesting for @hamarituc
Today in the morning I received my account to access the developer docs. I will check it tomorrow and contact you if there are any questions, so you don't need to waste time.
Thanks, so mechanisms are in place, but we need to correctly look at the metadata. I'll try to get some developer information from D-Trust.
Maybe this is also interesting for @hamarituc
According to the developer docs a PACE channel is necessary for:
- PIN operations
- private key operations
- even for querying the vendor and product information of the card
Whilst it is evident to protect the communication via PACE for contactless usage, it is even required when using the contact based interface. This makes the driver implementation a bit complicated, because up to two separate PINs have to be queried: the CAN at least for the first time and then signature PIN every time in case of a standard card.
@frankmorgner: You developed the PACE implementation and the ePA-driver. Is this behavior implementable in the PKCS#11 workflow at all? If I understand the ePA driver correctly, the CAN is statically configured in the configuration file. This would not be an option in my use case so it needs a way to query the CAN through regular usage from the end user. Is the ePA driver a good candidate to build upon or do we need a different approach?
even for querying the vendor and product information of the card
That's not exactly true. DF.Certs, which holds all certificates is ALWAYS readable as well as, for example, EF.GDO with the serial number. So there should be enough meta data available to identify the card.
Is this behavior implementable in the PKCS#11 workflow at all?
Not exactly, no.
If I understand the ePA driver correctly, the CAN is statically configured in the configuration file.
Correct.
This would not be an option in my use case so it needs a way to query the CAN through regular usage from the end user. Is the ePA driver a good candidate to build upon or do we need a different approach?
First, you will always need to request the CAN via a propriatery PIN dialog, because of the PKCS#11 limitations. Read src/libopensc/card-dnie.c and search for ENABLE_DNIE_UI - there you will find PIN dialogs for Windows, macOS and Linux. By default, this code is not enabled so please use with care. If you have a reader capable of doing PACE when inputting the CAN on the pin pad, then you may even do so without spawning a dedicated window and just use sc_notify().
Second, once you collected the CAN, you may want to cache this on disk to avoid prompting the user too often (remember that the user always needs to enter PIN.AUT or PIN.QES as well!). (Only) On Windows, you could use RegSetValueEx() in the user context (see src/minidriver/minidriver.c for example). The other option which works on any OS, is to use sc_pkcs15_cache_file() to cache the CAN on disk using a virtual file path. This virtual file will be associated with the serial number of your card and should work even with using multiple cards (with different CANs) for a single user.
@frankmorgner @hamarituc if you need some help with debugging/testing I am happy to assist you with my signature card
@frankmorgner @hamarituc if you need some help with debugging/testing I am happy to assist you with my signature card
Which operating system do you use? I can only test Linux and Windows. Finding a Mac user would be helpful.
But to be honest, it seems to be a lot work to be done because of the PACE encryption required by these cards. I cannot make an estimate when I am able to deliver a first test candidate.
My primary operating system is macOS (x86 and Apple Silicon/ARM architecture). But I have windows and linux machines too
Establishing PACE channels for a hard coded CAN is implemented here (according to the specification) if you want to try: https://github.com/frankmorgner/OpenSC/commit/80349e2c8aa8ac4d2379c1ea0f473a985f721a43
Establishing PACE channels for a hard coded CAN is implemented here (according to the specification) if you want to try: frankmorgner@80349e2
@frankmorgner Thank for the sample code. I was able to get PACE authentication working in dtrust-tool. Currently it shows the status of the transport protection and the PIN status. Next step will be implementing the card initialization procedure.
@janknieling If you already initialized your card with the D-Trust provided Card Assistant I would be happy if you could provide me the output of dtrust-tool -s -c. This can confirm my patches are working as they should.
@hamarituc yes my card is already initialized. I have tried to build OpenSC on my mac but it seems that there is something wrong.
../../src/sm/sm-eac.h:37:10: fatal error: 'eac/cv_cert.h' file not found
#include <eac/cv_cert.h>
^~~~~~~~~~~~~~~
1 error generated.
make[3]: *** [dtrust-tool.o] Error 1
make[3]: *** Waiting for unfinished jobs....
make[2]: *** [all-recursive] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2
The CI/CD pipeline has the same problem (https://github.com/OpenSC/OpenSC/actions/runs/9227516607/job/25389623718#step:4:12322)
dtrust-tool needs to be compiled with OpenPACE...
Implementing the sample, I also noticed some other problems:
-
I suggested to use a virtual smart card file in order to store the cached CAN, i.e. by using
sc_pkcs15_cache_file()). Since you're currently using the synthetic PKCS#15 layer, you cannot customize this behavior at the moment. So for caching the CAN, I see two options: 1.1 use dtrust-tool to store a CAN in the local file system, then read this local file in card-dtrust.c (CAN is queried via CLI in dtrust-tool) 1.2 implement a PKCS#15 layer (i.e. pkcs15-dtrust.c) based on the synthetic behavior and add a virtual file for CAN. (CAN is queried via deditacted window in card-dtrust.c) -
You will likely run into problems with PIN pad readers, because
sc_pin_cmd()orSC_READER_CAP_PIN_PADcurrently only knowsFEATURE_VERIFY_PIN_DIRECT, but notSC_READER_CAP_PACE_EID. However, ifperform_pace()is executed with an empty PIN and the reader has a PIN pad with PACE capabilities, then the PACE PIN is requested on the PIN pad. To work around this, I suggest that you setSC_CARD_CAP_PROTECTED_AUTHENTICATION_PATHif the reader supports PACE via PIN pad. This notifies the upper layers that the PIN doesn't need to be prompted by the application, instead you are handling this in card-dtrust.c by executingperform_pace()with an empty PIN. Unfortunately, this also means that you will have to manually deal withFEATURE_MODIFY_PIN_DIRECT, e.g for PIN modification...
@frankmorgner is there a documentation for compiling with openpace on macOS available? Seems that the CI/CD pipeline isn't compiling with openpace too because there is the same error that openpace is missing
./MacOSX/build will do all the work for you. This is also what we successfully use in our pipeline https://github.com/OpenSC/OpenSC/actions/workflows/macos.yml
Unfortunately ./MacOSX/build drops the same error. Regarding the pipeline: If you'll take a look at the pipeline execution from the pull request (#3137) for this issue you will see the same error that eac/cv_cert.h is missing/was not found (https://github.com/OpenSC/OpenSC/actions/runs/9227516607/job/25389623718?pr=3137).
src/tools/Makefile.am needs to add $(OPENPACE_LIBS) and $(OPENPACE_CFLAGS) for dtrust-tool. But that is a problem of the OpenSC build system - OpenPACE is built in CI and works as expected.
dtrust-tool needs to be compiled with OpenPACE...
...
src/tools/Makefile.am needs to add (OPENPACELIBS)and(OPENPACE_CFLAGS) for dtrust-tool. But that is a problem of the OpenSC build system - OpenPACE is built in CI and works as expected.
I will add it. Strictly speaking OpenPACE is only necessary for D-Trust Card 5, but not for version 4. So at least the D-Trust Card 4 should should still be supported without enabling OpenPACE. Is adding
dtrust_tool_LDADD = $(OPENPACE_LIBS)
dtrust_tool_CFLAGS = $(OPENPACE_CFLAGS)
unconditionally OK? The variables should be empty i think, when OpenPACE is disabled, weren't they?
In the D-Trust driver the parts which are specific to OpenPACE should not be compiled when OpenPACE support is disabled. Is
#ifdef ENABLE_OPENPACE
#endif
sufficient or does it need to be?
#if defined(ENABLE_SM) && defined(ENABLE_OPENPACE)
#endif
just add cflags and libs. as long as you don't use any openpace specific header files or function calls, sm/eac.h will handle non-availability of openpace.
@hamarituc here is the output of dtrust-tool -s -c
➜ OpenSC git:(dtrust-5) ✗ dtrust-tool -s -c
Using reader with a card: REINER SCT cyberJack one
Enter CAN:
Authentication PIN: usable (3 tries left)
Transport PIN (Authentication): not usable (transport protection still in force)
Card Holder PUK: not usable (transport protection still in force)
Signature PIN: usable (3 tries left)
Transport PIN (Signature): not usable (transport protection still in force)
Transport protection of Authentication PIN is broken.
Transport protection of Signature PIN is broken.
pkcs11-tool -T
➜ OpenSC git:(dtrust-5) ✗ pkcs11-tool -T
Available slots:
Slot 0 (0x0): REINER SCT cyberJack one
token label : D-TRUST Card 5.1 Std. R... (CAN)
token manufacturer : D-TRUST GmbH (C)
token model : PKCS#15
token flags : login required, PIN pad present, token initialized, PIN initialized
hardware version : 0.0
firmware version : 0.0
serial num : 003212310002329f
pin min/max : 6/6
uri : pkcs11:model=PKCS%2315;manufacturer=D-TRUST%20GmbH%20%28C%29;serial=003212310002329f;token=D-TRUST%20Card%205.1%20Std.%20R...%20%28CAN%29
Slot 1 (0x1): REINER SCT cyberJack one
token label : D-TRUST Card ... (Signature-PIN)
token manufacturer : D-TRUST GmbH (C)
token model : PKCS#15
token flags : login required, PIN pad present, token initialized, PIN initialized
hardware version : 0.0
firmware version : 0.0
serial num : 003212310002329f
pin min/max : 8/8
uri : pkcs11:model=PKCS%2315;manufacturer=D-TRUST%20GmbH%20%28C%29;serial=003212310002329f;token=D-TRUST%20Card%20...%20%28Signature-PIN%29
Slot 2 (0x2): REINER SCT cyberJack one
token label : D-TRUST ... (Authentication-PIN)
token manufacturer : D-TRUST GmbH (C)
token model : PKCS#15
token flags : login required, PIN pad present, token initialized, PIN initialized
hardware version : 0.0
firmware version : 0.0
serial num : 003212310002329f
pin min/max : 8/8
uri : pkcs11:model=PKCS%2315;manufacturer=D-TRUST%20GmbH%20%28C%29;serial=003212310002329f;token=D-TRUST%20...%20%28Authentication-PIN%29
pkcs15-tool -D
➜ OpenSC git:(dtrust-5) ✗ pkcs15-tool -D
Using reader with a card: REINER SCT cyberJack one
PKCS#15 Card [D-TRUST Card 5.1 Std. RSA 2ca]:
Version : 1
Serial number : 9276003212310002329f
Manufacturer ID: D-TRUST GmbH (C)
Flags : Login required, PRN generation
PIN [CAN]
Object Flags : [0x01], private
ID : 03
Flags : [0x11], case-sensitive, initialized
Length : min_len:6, max_len:6, stored_len:6
Pad char : 0x00
Reference : 3 (0x03)
Type : UTF-8
PIN [Card-PUK]
Object Flags : [0x03], private, modifiable
ID : 04
Flags : [0x859], case-sensitive, unblock-disabled, initialized, unblockingPin, exchangeRefData
Length : min_len:8, max_len:8, stored_len:8
Pad char : 0x00
Reference : 4 (0x04)
Type : UTF-8
PIN [Signature-PIN]
Object Flags : [0x03], private, modifiable
Auth ID : 04
ID : 07
Flags : [0x2813], case-sensitive, local, initialized, exchangeRefData
Length : min_len:8, max_len:8, stored_len:8
Pad char : 0x00
Reference : 135 (0x87)
Type : UTF-8
Path : 3f000101
PIN [Authentication-PIN]
Object Flags : [0x03], private, modifiable
Auth ID : 04
ID : 11
Flags : [0x2813], case-sensitive, local, initialized, exchangeRefData
Length : min_len:8, max_len:8, stored_len:8
Pad char : 0x00
Reference : 145 (0x91)
Type : UTF-8
Path : 3f000102
Tries left : 3
Private RSA Key [Authentisierungsschluessel]
Object Flags : [0x01], private
Usage : [0x2E], decrypt, sign, signRecover, unwrap
Access Flags : [0x00]
Algo_refs : 0
ModLength : 3072
Key ref : 3 (0x03)
Native : yes
Path : 3f000102
Auth ID : 11
ID : 03
MD:guid : f8d9b5ed-1251-c905-70c6-3bd8613a840c
Private RSA Key [Signaturschluessel]
Object Flags : [0x01], private
Usage : [0x200], nonRepudiation
Access Flags : [0x00]
Algo_refs : 0
ModLength : 3072
Key ref : 2 (0x02)
Native : yes
Path : 3f000101
Auth ID : 07
ID : 02
MD:guid : fbaa8582-260d-f5c4-f830-1e3962a0a1ef
X.509 Certificate [Authentisierungszertifikat]
Object Flags : [0x02], modifiable
Authority : no
Path : 3f0001030204
ID : 03
Encoded serial : 02 03 68D858
X.509 Certificate [Signaturzertifikat]
Object Flags : [0x02], modifiable
Authority : no
Path : 3f0001030201
ID : 02
Encoded serial : 02 10 71B5D5B5F85868B8763E8B300B6ECC4A
X.509 Certificate [CA-Zertifikat fuer Authentisierung]
Object Flags : [0x02], modifiable
Authority : yes
Path : 3f0001030205
ID : 03
Encoded serial : 02 03 0FE54B
X.509 Certificate [Root-CA-Zertifikat fuer Authentisierung]
Object Flags : [0x02], modifiable
Authority : yes
Path : 3f0001030206
ID : 03
Encoded serial : 02 03 0FE529
X.509 Certificate [CA-Zertifikat fuer Signatur]
Object Flags : [0x02], modifiable
Authority : yes
Path : 3f0001030202
ID : 02
Encoded serial : 02 10 69F4C9580F580F631488B9632371E72E
X.509 Certificate [Root-CA-Zertifikat fuer Signatur]
Object Flags : [0x02], modifiable
Authority : yes
Path : 3f0001030203
ID : 02
Encoded serial : 02 10 6BC22A5479D8EA68A9C5A27A909BA938
@hamarituc just write me if you need further debugging assistance