[Feature request] Support for Private use DOs #50

Closed
opened 2026-02-17 18:04:04 +08:00 by czietz · 5 comments
czietz commented 2026-02-17 18:04:04 +08:00 (Migrated from github.com)

Currently, private use data objects are not supported:
374cff588c/src/openpgp/files.c (L63)

Particularly Private use (0103) or Private use (0104) (which are PIN-protected) can be used to securely store small amounts of data, such as VeraCrypt key files. While this is of course not the primary purpose of an OpenPGP card, imho it still would provide a nice benefit to users.

Image
Currently, private use data objects are not supported: https://github.com/polhenarejos/pico-openpgp/blob/374cff588c4431ec568027e369b67828162f54d6/src/openpgp/files.c#L63 Particularly _Private use (0103)_ or _Private use (0104)_ (which are PIN-protected) can be used to securely store small amounts of data, such as VeraCrypt key files. While this is of course not the primary purpose of an OpenPGP card, imho it still would provide a nice benefit to users. <img width="586" height="150" alt="Image" src="https://github.com/user-attachments/assets/37178e8c-208a-4d12-a762-9cbfe4c3a071" />
czietz commented 2026-02-18 02:17:53 +08:00 (Migrated from github.com)

Oh wow. Thank you! That was very quick.

However, there is still an issue with deleting the private use DOs again. It might also affect other DOs; I didn't check.

The OpenPGP card spec says:

7.2.8 PUT DATA
With this command DOs can be written to the card. The Tag is given in P1/P2 (e. g. 5F50
for URL or 005B for Name). For simple DOs only the value is in the data field (without
leading Tag/Length). The command can only be used after correct presentation of PW3
(except DO 0101 and DO 0103 after correct verification of PW1 with No. 82).
[...]
An empty data field (Lc absent) deletes the content of a DO with variable length (e. g.
URL), but not the DO itself.

However, sending a PUT DATA command with an empty data field does not delete the DO (here: 0103):

OpenSC Explorer version 0.26.1
Using reader with a card: Pol Henarejos Pico Key CCID OTP FIDO Interfac 0
OpenSC [3F00]> verify chv2
Please enter PIN: Code correct.
OpenSC [3F00]> apdu 00da0103081122334455667788
Sending: 00 DA 01 03 08 11 22 33 44 55 66 77 88
Received (SW1=0x90, SW2=0x00)
Success!
OpenSC [3F00]> apdu 00ca010300
Sending: 00 CA 01 03 00
Received (SW1=0x90, SW2=0x00):
11 22 33 44 55 66 77 88 ."3DUfw.
Success!
OpenSC [3F00]> apdu 00da0103
Sending: 00 DA 01 03
Received (SW1=0x90, SW2=0x00)
Success!
OpenSC [3F00]> apdu 00ca010300
Sending: 00 CA 01 03 00
Received (SW1=0x90, SW2=0x00):
11 22 33 44 55 66 77 88 ."3DUfw.
Success!

Compare this to, e.g., a Nitrokey or YubiKey, where sending 00 DA 01 03 deletes the data again:

opensc-explorer.exe
OpenSC Explorer version 0.26.1
Using reader with a card: Yubico YubiKey OTP+FIDO+CCID 0
OpenSC [3F00]> verify chv2
Please enter PIN: Code correct.
OpenSC [3F00]> apdu 00da0103081122334455667788
Sending: 00 DA 01 03 08 11 22 33 44 55 66 77 88
Received (SW1=0x90, SW2=0x00)
Success!
OpenSC [3F00]> apdu 00ca010300
Sending: 00 CA 01 03 00
Received (SW1=0x90, SW2=0x00):
11 22 33 44 55 66 77 88 ."3DUfw.
Success!
OpenSC [3F00]> apdu 00da0103
Sending: 00 DA 01 03
Received (SW1=0x90, SW2=0x00)
Success!
OpenSC [3F00]> apdu 00ca010300
Sending: 00 CA 01 03 00
Received (SW1=0x90, SW2=0x00)
Success!
Oh wow. Thank you! That was very quick. However, there is still an issue with _deleting_ the private use DOs again. It might also affect other DOs; I didn't check. The OpenPGP card spec says: > 7.2.8 PUT DATA With this command DOs can be written to the card. The Tag is given in P1/P2 (e. g. 5F50 for URL or 005B for Name). For simple DOs only the value is in the data field (without leading Tag/Length). The command can only be used after correct presentation of PW3 (except DO 0101 and DO 0103 after correct verification of PW1 with No. 82). [...] **An empty data field (Lc absent) deletes the content of a DO with variable length (e. g. URL), but not the DO itself.** However, sending a PUT DATA command with an empty data field does not delete the DO (here: 0103): ``` OpenSC Explorer version 0.26.1 Using reader with a card: Pol Henarejos Pico Key CCID OTP FIDO Interfac 0 OpenSC [3F00]> verify chv2 Please enter PIN: Code correct. OpenSC [3F00]> apdu 00da0103081122334455667788 Sending: 00 DA 01 03 08 11 22 33 44 55 66 77 88 Received (SW1=0x90, SW2=0x00) Success! OpenSC [3F00]> apdu 00ca010300 Sending: 00 CA 01 03 00 Received (SW1=0x90, SW2=0x00): 11 22 33 44 55 66 77 88 ."3DUfw. Success! OpenSC [3F00]> apdu 00da0103 Sending: 00 DA 01 03 Received (SW1=0x90, SW2=0x00) Success! OpenSC [3F00]> apdu 00ca010300 Sending: 00 CA 01 03 00 Received (SW1=0x90, SW2=0x00): 11 22 33 44 55 66 77 88 ."3DUfw. Success! ``` Compare this to, e.g., a Nitrokey or YubiKey, where sending `00 DA 01 03` deletes the data again: ``` opensc-explorer.exe OpenSC Explorer version 0.26.1 Using reader with a card: Yubico YubiKey OTP+FIDO+CCID 0 OpenSC [3F00]> verify chv2 Please enter PIN: Code correct. OpenSC [3F00]> apdu 00da0103081122334455667788 Sending: 00 DA 01 03 08 11 22 33 44 55 66 77 88 Received (SW1=0x90, SW2=0x00) Success! OpenSC [3F00]> apdu 00ca010300 Sending: 00 CA 01 03 00 Received (SW1=0x90, SW2=0x00): 11 22 33 44 55 66 77 88 ."3DUfw. Success! OpenSC [3F00]> apdu 00da0103 Sending: 00 DA 01 03 Received (SW1=0x90, SW2=0x00) Success! OpenSC [3F00]> apdu 00ca010300 Sending: 00 CA 01 03 00 Received (SW1=0x90, SW2=0x00) Success! ```
czietz commented 2026-02-18 02:39:52 +08:00 (Migrated from github.com)

Furthermore, sometimes the data is not stored correctly. For example, here I try to store four bytes 01020304 as private use DO 0103, but only the last two bytes can be read back:

OpenSC [3F00]> apdu 00 da 01 03 04 01020304
Sending: 00 DA 01 03 04 01 02 03 04
Received (SW1=0x90, SW2=0x00)
Success!
OpenSC [3F00]> apdu 00ca0103
Sending: 00 CA 01 03
Received (SW1=0x90, SW2=0x00):
03 04 ..
Success!
Furthermore, sometimes the data is not stored correctly. For example, here I try to store four bytes `01020304` as private use DO 0103, but only the last _two_ bytes can be read back: ``` OpenSC [3F00]> apdu 00 da 01 03 04 01020304 Sending: 00 DA 01 03 04 01 02 03 04 Received (SW1=0x90, SW2=0x00) Success! OpenSC [3F00]> apdu 00ca0103 Sending: 00 CA 01 03 Received (SW1=0x90, SW2=0x00): 03 04 .. Success! ```
polhenarejos commented 2026-02-18 07:30:10 +08:00 (Migrated from github.com)

Beautiful coincidence. When you use 01020304 it is interpreted as a TLV DO, with TAG=01, LEN=02, DATA=0304. If you replace 02 by another number not coincident to the length, it will return the entire text (and this is why it passed all tests).

Beautiful coincidence. When you use 01020304 it is interpreted as a TLV DO, with TAG=01, LEN=02, DATA=0304. If you replace 02 by another number not coincident to the length, it will return the entire text (and this is why it passed all tests).
czietz commented 2026-02-18 20:02:46 +08:00 (Migrated from github.com)

Beautiful coincidence. When you use 01020304 it is interpreted as a TLV DO, with TAG=01, LEN=02, DATA=0304. If you replace 02 by another number not coincident to the length, it will return the entire text (and this is why it passed all tests).

Thank you for the quick fix, which I can confirm to be working for the private DOs.

However, other DOs are probably also interpreted as a TLV, even though they shouldn't be. Consider this – arguably slightly contrived – example for the URL (DO 5F50), where the T is probably also interpreted as length, and hence HT is skipped when returning the URL:

gpg/card> url
URL um den öffentlichen Schlüssel zu holen:
HTTP://www.longurl.invalid/veryveryveryveryveryveryveryveryveryveryveryveryvery_long.1
gpg/card> quit


 > gpg-card
Reader ...........: Pol Henarejos Pico Key CCID OTP FIDO Interfac 0
Card type ........: zeitcontrol
Serial number ....: D276000124010304FFFEF11745430000
Application type .: OpenPGP
Version ..........: 3.4
Displayed s/n ....: FFFE F1174543
Manufacturer .....: unmanaged S/N range (fffe)
Name of cardholder: [nicht gesetzt]
Language prefs ...: [nicht gesetzt]
Salutation .......:
URL of public key :
TP://www.longurl.invalid/veryveryveryveryveryveryveryveryveryveryveryveryvery_long.1
> Beautiful coincidence. When you use 01020304 it is interpreted as a TLV DO, with TAG=01, LEN=02, DATA=0304. If you replace 02 by another number not coincident to the length, it will return the entire text (and this is why it passed all tests). Thank you for the quick fix, which I can confirm to be working for the private DOs. However, other DOs are probably also interpreted as a TLV, even though they shouldn't be. Consider this – arguably slightly contrived – example for the URL (DO 5F50), where the `T` is probably also interpreted as length, and hence `HT` is skipped when returning the URL: ``` gpg/card> url URL um den öffentlichen Schlüssel zu holen: HTTP://www.longurl.invalid/veryveryveryveryveryveryveryveryveryveryveryveryvery_long.1 gpg/card> quit > gpg-card Reader ...........: Pol Henarejos Pico Key CCID OTP FIDO Interfac 0 Card type ........: zeitcontrol Serial number ....: D276000124010304FFFEF11745430000 Application type .: OpenPGP Version ..........: 3.4 Displayed s/n ....: FFFE F1174543 Manufacturer .....: unmanaged S/N range (fffe) Name of cardholder: [nicht gesetzt] Language prefs ...: [nicht gesetzt] Salutation .......: URL of public key : TP://www.longurl.invalid/veryveryveryveryveryveryveryveryveryveryveryveryvery_long.1 ```
polhenarejos commented 2026-02-19 22:58:23 +08:00 (Migrated from github.com)

I pushed a fix to do not parse as TLV any flash data. Hope it will work with all DO but not tested with all.

I pushed a fix to do not parse as TLV any flash data. Hope it will work with all DO but not tested with all.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dearsky/pico-openpgp#50