github-af / SmartPGP

SmartPGP is a JavaCard implementation of the OpenPGP card specifications
GNU General Public License v2.0
232 stars 48 forks source link

Factory-resetting a kdf-enabled card cannot restore its PINs to default values on a J3R180 card #47

Open wreps8Owt opened 1 year ago

wreps8Owt commented 1 year ago

Using the factory-reset command of GnuPG on a J3R180 card without kdf enabled does restore its PINs to default values, but factory-resetting a kdf-enabled card cannot. It seems that all parameters return to default, but PINs (especially the admin PIN) does not work. The only way to "restore" it is to reinstall the CAP file.

wreps8Owt commented 1 year ago

Besides, smartpgp-cli seems unable to pass the PIN authentication against a kdf-enabled card.

wreps8Owt commented 1 year ago

This issue is opened when my account remained flagged, so you might not be noticed then.

af-anssi commented 1 year ago

Using the factory-reset command of GnuPG on a card without kdf enabled does restore its PINs to default values, but factory-resetting a kdf-enabled card cannot. It seems that all parameters return to default, but PINs (especially the admin PIN) does not work. The only way to "restore" it is to reinstall the CAP file.

Which version of the applet are you using?

KDF parameters are actually reset within the applet during a factory reset: https://github.com/ANSSI-FR/SmartPGP/blob/master/src/fr/anssi/smartpgp/Persistent.java#L226

After a factory reset did you remove the card from the reader and then reinsert it? I suspect a caching mechanism of GnuPG to not deal correctly with the reset of the KDF parameters.

af-anssi commented 1 year ago

Besides, smartpgp-cli seems unable to pass the PIN authentication against a kdf-enabled card.

Yes KDF-enabled PIN is not supported in smartpgp-cli.

wreps8Owt commented 1 year ago

Using the factory-reset command of GnuPG on a card without kdf enabled does restore its PINs to default values, but factory-resetting a kdf-enabled card cannot. It seems that all parameters return to default, but PINs (especially the admin PIN) does not work. The only way to "restore" it is to reinstall the CAP file. Which version of the applet are you using? The current master, built against jc304.

KDF parameters are actually reset within the applet during a factory reset: https://github.com/ANSSI-FR/SmartPGP/blob/master/src/fr/anssi/smartpgp/Persistent.java#L226

After a factory reset did you remove the card from the reader and then reinsert it? I suspect a caching mechanism of GnuPG to not deal correctly with the reset of the KDF parameters.

Yes. After a factory reset of a card with KDF enabled, reinserting, killing gpg-agent, or even restarting pcscd, cannot make default admin PIN work.

In Persistent() of Persistent.java, key_derivation_function_length is set to 0, and (key_derivation_function_length > 0) is judged in many place , but during reset, it seems to be "reset" to Constants.KEY_DERIVATION_FUNCTION_DEFAULT.length, which may be 3. Is this okay?

af-anssi commented 1 year ago

Yes. After a factory reset of a card with KDF enabled, reinserting, killing gpg-agent, or even restarting pcscd, cannot make default admin PIN work. In Persistent() of Persistent.java, key_derivation_function_length is set to 0, and (key_derivation_function_length > 0) is judged in many place , but during reset, it seems to be "reset" to Constants.KEY_DERIVATION_FUNCTION_DEFAULT.length, which may be 3. Is this okay?

When the Peristent instance is created the key_derivation_function_length is set to 0 https://github.com/ANSSI-FR/SmartPGP/blob/master/src/fr/anssi/smartpgp/Persistent.java#L131, but at the end of the constructor the reset function is called https://github.com/ANSSI-FR/SmartPGP/blob/master/src/fr/anssi/smartpgp/Persistent.java#L137 so the key_derivation_function_length is reset at https://github.com/ANSSI-FR/SmartPGP/blob/master/src/fr/anssi/smartpgp/Persistent.java#L233 to its default value https://github.com/ANSSI-FR/SmartPGP/blob/master/src/fr/anssi/smartpgp/Constants.java#L32.

af-anssi commented 1 year ago

If you agree with my explanations could you close this issue?

wreps8Owt commented 1 year ago

If you agree with my explanations could you close this issue?

Why? The issue remains persist. Your explanations cannot explain the issue.

wreps8Owt commented 1 year ago

It just mean that my guess is not the reason of this issue.

af-anssi commented 1 year ago

SmartPGP is implemented such that its internal status after installation is strictly the same as after a factory reset with only two exceptions: the SM certificate (that you do not use) and the use (or not) of the transaction mechanism (which is not available during first installation). The constructor of the Persistent instance, which holds all data in flash memory (that survives card unplug/power off), ends with a call to its reset function which is also the one called during a factory reset: https://github.com/ANSSI-FR/SmartPGP/blob/master/src/fr/anssi/smartpgp/SmartPGPApplet.java#L1492.

af-anssi commented 1 year ago

After a factory reset could you remove (after a backup if necessary) your .gnupg directory in addition to kill any daemons and finally reinsert your card?

wreps8Owt commented 1 year ago

After a factory reset could you remove (or backup it if necessary) your .gnupg directory in addition to kill any daemons and finally reinsert your card?

Sure, and the issue persists. Even smartpgp-cli cannot pass the authentication with default admin pinl, if only the card had kdf setup, and then factory reset.

af-anssi commented 1 year ago

How did you setup/enable KDF?

wreps8Owt commented 1 year ago

How did you setup/enable KDF?

Use smartpgp-cli .

af-anssi commented 1 year ago

On a blank J3H145 where I install SmartPGP-v1.22.1.

I setup KDF using ./bin/smartpgp-cli -I kdf-setup and define some PIN codes and obtain the following output where we can see everything went well (90 00):

Select OpenPGP Applet
90 00
Get KDF-DO
90 00
Enter User PIN:
Enter PUK PIN:
Enter Admin PIN:
Verify Admin PIN
90 00
Change PW1
90 00
Change PW3
90 00
Put KDF-DO
90 00

With gpg2 --card-status I obtain the following output where we see KDF is on:

Reader ...........: xxxx
Application ID ...: D276000124010304AFAF000000010000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: unknown
Serial number ....: 00000001
Name of cardholder: [not set]
Language prefs ...: en
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 32 32 32
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: on
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

The PIN codes set are correctly verified. Using gpg2 --card-edit I do a factory reset and then verify user PIN (which is back to the default one) and obtain the following output where we can see KDF is correctly set to off and the default user PIN is verified correctly:

gpg/card> admin
Admin commands are allowed

gpg/card> factory-reset
gpg: OpenPGP card no. D276000124010304AFAF000000010000 detected

gpg: Note: This command destroys all keys stored on the card!

Continue? (y/N) y
Really do a factory reset? (enter "yes") yes

gpg/card> list

Reader ...........: xxxx
Application ID ...: D276000124010304AFAF000000010000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: unknown
Serial number ....: 00000001
Name of cardholder: [not set]
Language prefs ...: en
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

gpg/card> verify

Reader ...........: xxxx
Application ID ...: D276000124010304AFAF000000010000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: unknown
Serial number ....: 00000001
Name of cardholder: [not set]
Language prefs ...: en
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

At this point I am not able to reproduce your problem. Could you try the exact same steps and provide the corresponding output?

wreps8Owt commented 1 year ago

On a fresh card J3H145 on which I install SmartPGP-v1.22.1.

I setup kdf using ./bin/smartpgp-cli -I kdf-setup and define some PIN codes and obtain the following output where we can see everything went well (90 00):

Select OpenPGP Applet
90 00
Get KDF-DO
90 00
Enter User PIN:
Enter PUK PIN:
Enter Admin PIN:
Verify Admin PIN
90 00
Change PW1
90 00
Change PW3
90 00
Put KDF-DO
90 00

With gpg2 --card-status I obtain the following output where we see KDF is on:

Reader ...........: xxxx
Application ID ...: D276000124010304AFAF000000010000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: unknown
Serial number ....: 00000014
Name of cardholder: [not set]
Language prefs ...: en
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 32 32 32
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: on
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

The PIN codes set are correctly verified. Using gpg2 --card-edit I do a factory reset and then verify user PIN (which is back to the default one) and obtain the following output where we can see KDF is correctly set to off and the default user PIN is verified correctly:

gpg/card> admin
Admin commands are allowed

gpg/card> factory-reset
gpg: OpenPGP card no. D276000124010304AFAF000000010000 detected

gpg: Note: This command destroys all keys stored on the card!

Continue? (y/N) y
Really do a factory reset? (enter "yes") yes

gpg/card> list

Reader ...........: xxxx
Application ID ...: D276000124010304AFAF000000010000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: unknown
Serial number ....: 00000014
Name of cardholder: [not set]
Language prefs ...: en
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

gpg/card> verify

Reader ...........: xxxx
Application ID ...: D276000124010304AFAF000000010000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: unknown
Serial number ....: 00000014
Name of cardholder: [not set]
Language prefs ...: en
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

At this point I am not able to reproduce your problem. Could you try the exact same steps and provide the corresponding output?

I repeat the same step on an J3R180. When I verify the PIN after factory reset, the following output is generated:

$  gpg --edit-card

Reader ...........: Identive Identive CLOUD 4500 F Dual Interface Reader [uTrust 4700 F Contact Reader] (53201519201674) 00 00 Application ID ...: D276000124010304AFAF000000000000 Application type .: OpenPGP Version ..........: 3.4 Manufacturer .....: unknown Serial number ....: 00000000 Name of cardholder: [not set] Language prefs ...: en Salutation .......: URL of public key : [not set] Login data .......: [not set] Signature PIN ....: forced Key attributes ...: rsa2048 rsa2048 rsa2048 Max. PIN lengths .: 127 127 127 PIN retry counter : 3 0 3 Signature counter : 0 KDF setting ......: off Signature key ....: [none] Encryption key....: [none] Authentication key: [none] General key info..: [none]

gpg/card> verify

Reader ...........: Identive Identive CLOUD 4500 F Dual Interface Reader [uTrust 4700 F Contact Reader] (53201519201674) 00 00 Application ID ...: D276000124010304AFAF000000000000 Application type .: OpenPGP Version ..........: 3.4 Manufacturer .....: unknown Serial number ....: 00000000 Name of cardholder: [not set] Language prefs ...: en Salutation .......: URL of public key : [not set] Login data .......: [not set] Signature PIN ....: forced Key attributes ...: rsa2048 rsa2048 rsa2048 Max. PIN lengths .: 127 127 127 PIN retry counter : 2 0 3 Signature counter : 0 KDF setting ......: off Signature key ....: [none] Encryption key....: [none] Authentication key: [none] General key info..: [none]

gpg/card> Now it seems that factory reset a card with kdf enabled works well on J3H145, but not on J3R180.

wreps8Owt commented 1 year ago

On a fresh card J3H145 on which I install SmartPGP-v1.22.1.

I setup kdf using ./bin/smartpgp-cli -I kdf-setup and define some PIN codes and obtain the following output where we can see everything went well (90 00):

Select OpenPGP Applet
90 00
Get KDF-DO
90 00
Enter User PIN:
Enter PUK PIN:
Enter Admin PIN:
Verify Admin PIN
90 00
Change PW1
90 00
Change PW3
90 00
Put KDF-DO
90 00

With gpg2 --card-status I obtain the following output where we see KDF is on:

Reader ...........: xxxx
Application ID ...: D276000124010304AFAF000000010000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: unknown
Serial number ....: 00000014
Name of cardholder: [not set]
Language prefs ...: en
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 32 32 32
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: on
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

The PIN codes set are correctly verified. Using gpg2 --card-edit I do a factory reset and then verify user PIN (which is back to the default one) and obtain the following output where we can see KDF is correctly set to off and the default user PIN is verified correctly:

gpg/card> admin
Admin commands are allowed

gpg/card> factory-reset
gpg: OpenPGP card no. D276000124010304AFAF000000010000 detected

gpg: Note: This command destroys all keys stored on the card!

Continue? (y/N) y
Really do a factory reset? (enter "yes") yes

gpg/card> list

Reader ...........: xxxx
Application ID ...: D276000124010304AFAF000000010000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: unknown
Serial number ....: 00000014
Name of cardholder: [not set]
Language prefs ...: en
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

gpg/card> verify

Reader ...........: xxxx
Application ID ...: D276000124010304AFAF000000010000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: unknown
Serial number ....: 00000014
Name of cardholder: [not set]
Language prefs ...: en
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

At this point I am not able to reproduce your problem. Could you try the exact same steps and provide the corresponding output?

I repeat the same step on an J3R180. When I verify the PIN after factory reset, the following output is generated:

$  gpg --edit-card

Reader ...........: Identive Identive CLOUD 4500 F Dual Interface Reader [uTrust 4700 F Contact Reader] (53201519201674) 00 00 Application ID ...: D276000124010304AFAF000000000000 Application type .: OpenPGP Version ..........: 3.4 Manufacturer .....: unknown Serial number ....: 00000000 Name of cardholder: [not set] Language prefs ...: en Salutation .......: URL of public key : [not set] Login data .......: [not set] Signature PIN ....: forced Key attributes ...: rsa2048 rsa2048 rsa2048 Max. PIN lengths .: 127 127 127 PIN retry counter : 3 0 3 Signature counter : 0 KDF setting ......: off Signature key ....: [none] Encryption key....: [none] Authentication key: [none] General key info..: [none]

gpg/card> verify

Reader ...........: Identive Identive CLOUD 4500 F Dual Interface Reader [uTrust 4700 F Contact Reader] (53201519201674) 00 00 Application ID ...: D276000124010304AFAF000000000000 Application type .: OpenPGP Version ..........: 3.4 Manufacturer .....: unknown Serial number ....: 00000000 Name of cardholder: [not set] Language prefs ...: en Salutation .......: URL of public key : [not set] Login data .......: [not set] Signature PIN ....: forced Key attributes ...: rsa2048 rsa2048 rsa2048 Max. PIN lengths .: 127 127 127 PIN retry counter : 2 0 3 Signature counter : 0 KDF setting ......: off Signature key ....: [none] Encryption key....: [none] Authentication key: [none] General key info..: [none]

gpg/card> Now it seems that factory reset a card with kdf enabled works well on J3H145, but not on J3R180.

I use https://github.com/ANSSI-FR/SmartPGP/releases/download/v1.22.1-3.0.4-without-secure-messaging/SmartPGP-v1.22.1-jc304-without_sm-rsa_up_to_4096.cap for the above result. Building tag v1.22.1-3.0.4 against jc305u3_kit and upload to my J3R180 gets the same result.

af-anssi commented 1 year ago

I do not have such card to make some tests. Could you checkout branch issue-47, compile, install and test if the patch 4df65b2 solves the problem?

wreps8Owt commented 1 year ago

I do not have such card to make some tests. Could you checkout branch issue-47, compile, install and test the patch 4df65b2 solves the problem?

Sadly this patch does not solve the problem.

wreps8Owt commented 1 year ago

I do not have such card to make some tests. Could you checkout branch issue-47, compile, install and test the patch 4df65b2 solves the problem?

Sadly this patch does not solve the problem.

Besides, Using bin/smartpgp-cli get-kdf -o kdf to read the default kdf gets

00000000  c2 81 01 00                                       |....| 00000004

af-anssi commented 1 year ago

在 2023/4/12 09:28, Driner 写道:

I do not have such card to make some tests. Could you checkout branch issue-47, compile, install and test the patch [4df65b2](https://github.com/ANSSI-FR/SmartPGP/commit/4df65b23e6afaa730280be4704f06a2a65f59869) solves the problem? > Sadly this patch does not solve the problem. Besides, Using bin/smartpgp-cli get-kdf -o kdf to read the default kdf gets 00000000 c2 81 01 00 |....| 00000004

The problem does not come from the KDF DO but from the PIN objects.

af-anssi commented 1 year ago

I do not have such card to make some tests. Could you checkout branch issue-47, compile, install and test the patch [4df65b2](https://github.com/ANSSI-FR/SmartPGP/commit/4df65b23e6afaa730280be4704f06a2a65f59869) solves the problem? Sadly this patch does not solve the problem.

Could you confirm you properly uninstalled the applet AND the package from the card before testing the one built from branch issue-47?

wreps8Owt commented 1 year ago

I do not have such card to make some tests. Could you checkout branch issue-47, compile, install and test the patch [4df65b2](https://github.com/ANSSI-FR/SmartPGP/commit/4df65b23e6afaa730280be4704f06a2a65f59869) solves the problem? Sadly this patch does not solve the problem. Could you confirm you properly uninstalled the applet AND the package from the card before testing the one built from branch issue-47?

Yes. Properly uninstalling the applet AND the package from the card before testing the one built from branch issue-47 changes nothing. The issue persists.

af-anssi commented 1 year ago

The KDF DO is correctly reset. It seems like the call to *_pin.update in the reset function of the Persistent object has no effect. I suspect the transaction mechanism.

Could try with last revision of branch issue-47 where I just committed a change to deactivate any transaction around the user and admin PIN changes (https://github.com/ANSSI-FR/SmartPGP/commit/46da4109d835314a8dddb81414adf8d2a872c23a) to:

Could you please provide all outputs of the above operations? Sorry for the nconvenience of making you make a lot of tests.

wreps8Owt commented 1 year ago

The KDF DO is correctly reset. It seems like the call to *_pin.update in the reset function of the Persistent object has no effect I suspect the transaction mechanism.

Could try with last revision of branch issue-47 where I just committed a change to deactivate any transaction around the user and admin PIN changes (https://github.com/ANSSI-FR/SmartPGP/commit/46da4109d835314a8dddb81414adf8d2a872c23a), compile and install it and then:

  • setup-kdf with smartpgp-cli
  • use gpg2 --card-edit to change the user PIN to a non-default value
  • factory reset the card
  • verify the user PIN to check it is back ti its default value (123456)

Could you please provide all outputs of the above operations? Sorry for inconvenience of making you make a lot of tests.

$ JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 JC_HOME=../oracle_javacard_sdks/jc304_kit/ ant Buildfile: /home/user/git/SmartPGP/build.xml       [get] Destination already exists (skipping): /home/user/git/SmartPGP/ant-javacard.jar

convert:       [cap] INFO: using JavaCard 3.0.4 SDK in /home/user/git/oracle_javacard_sdks/jc304_kit       [cap] INFO: Setting package name to fr.anssi.smartpgp       [cap] Building CAP with 1 applet from package fr.anssi.smartpgp (AID: D27600012401)       [cap] fr.anssi.smartpgp.SmartPGPApplet D276000124010304AFAF000000000000   [compile] Compiling files from /home/user/git/SmartPGP/src   [compile] Compiling 10 source files to /tmp/jccpro12635575473400202718   [convert] [ INFO: ] Converter [v3.0.4]   [convert] [ INFO: ]     Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.   [convert]        [convert]        [convert] [ INFO: ] conversion completed with 0 errors and 0 warnings.  [javacard] NB! Please use JavaCard SDK 3.0.5u3 or later for verifying!    [verify] Verification passed       [cap] CAP saved to /home/user/git/SmartPGP/SmartPGPApplet.cap

BUILD SUCCESSFUL Total time: 3 seconds $ java -jar ../GlobalPlatformPro/gp.jar --install SmartPGPApplet.cap

Warning: no keys given, defaulting to 404142434445464748494A4B4C4D4E4F

CAP loaded $ bin/smartpgp-cli setup-kdf Select OpenPGP Applet 90 00 Get KDF-DO 90 00 Verify Admin PIN 90 00 Change PW1 90 00 Change PW3 90 00 Put KDF-DO 90 00 $ gpg --edit-card

Reader ...........: Identive Identive CLOUD 4500 F Dual Interface Reader [uTrust 4700 F Contact Reader] (53201519201674) 00 00 Application ID ...: D276000124010304AFAF000000000000 Application type .: OpenPGP Version ..........: 3.4 Manufacturer .....: unknown Serial number ....: 00000000 Name of cardholder: [not set] Language prefs ...: en Salutation .......: URL of public key : [not set] Login data .......: [not set] Signature PIN ....: forced Key attributes ...: rsa2048 rsa2048 rsa2048 Max. PIN lengths .: 32 32 32 PIN retry counter : 3 0 3 Signature counter : 0 KDF setting ......: on Signature key ....: [none] Encryption key....: [none] Authentication key: [none] General key info..: [none]

gpg/card> passwd gpg: OpenPGP card no. D276000124010304AFAF000000000000 detected PIN changed.

gpg/card>

Reader ...........: Identive Identive CLOUD 4500 F Dual Interface Reader [uTrust 4700 F Contact Reader] (53201519201674) 00 00 Application ID ...: D276000124010304AFAF000000000000 Application type .: OpenPGP Version ..........: 3.4 Manufacturer .....: unknown Serial number ....: 00000000 Name of cardholder: [not set] Language prefs ...: en Salutation .......: URL of public key : [not set] Login data .......: [not set] Signature PIN ....: forced Key attributes ...: rsa2048 rsa2048 rsa2048 Max. PIN lengths .: 32 32 32 PIN retry counter : 3 0 3 Signature counter : 0 KDF setting ......: on Signature key ....: [none] Encryption key....: [none] Authentication key: [none] General key info..: [none]

gpg/card> admin Admin commands are allowed

gpg/card> factory-reset gpg: OpenPGP card no. D276000124010304AFAF000000000000 detected

gpg: Note: This command destroys all keys stored on the card!

Continue? (y/N) y Really do a factory reset? (enter "yes") yes

gpg/card>

Reader ...........: Identive Identive CLOUD 4500 F Dual Interface Reader [uTrust 4700 F Contact Reader] (53201519201674) 00 00 Application ID ...: D276000124010304AFAF000000000000 Application type .: OpenPGP Version ..........: 3.4 Manufacturer .....: unknown Serial number ....: 00000000 Name of cardholder: [not set] Language prefs ...: en Salutation .......: URL of public key : [not set] Login data .......: [not set] Signature PIN ....: forced Key attributes ...: rsa2048 rsa2048 rsa2048 Max. PIN lengths .: 127 127 127 PIN retry counter : 3 0 3 Signature counter : 0 KDF setting ......: off Signature key ....: [none] Encryption key....: [none] Authentication key: [none] General key info..: [none]

gpg/card> q $ killall gpg-agent

(card reinserted)

$ gpg --edit-card

Reader ...........: Identive Identive CLOUD 4500 F Dual Interface Reader [uTrust 4700 F Contact Reader] (53201519201674) 00 00 Application ID ...: D276000124010304AFAF000000000000 Application type .: OpenPGP Version ..........: 3.4 Manufacturer .....: unknown Serial number ....: 00000000 Name of cardholder: [not set] Language prefs ...: en Salutation .......: URL of public key : [not set] Login data .......: [not set] Signature PIN ....: forced Key attributes ...: rsa2048 rsa2048 rsa2048 Max. PIN lengths .: 127 127 127 PIN retry counter : 3 0 3 Signature counter : 0 KDF setting ......: off Signature key ....: [none] Encryption key....: [none] Authentication key: [none] General key info..: [none]

gpg/card> verify

Reader ...........: Identive Identive CLOUD 4500 F Dual Interface Reader [uTrust 4700 F Contact Reader] (53201519201674) 00 00 Application ID ...: D276000124010304AFAF000000000000 Application type .: OpenPGP Version ..........: 3.4 Manufacturer .....: unknown Serial number ....: 00000000 Name of cardholder: [not set] Language prefs ...: en Salutation .......: URL of public key : [not set] Login data .......: [not set] Signature PIN ....: forced Key attributes ...: rsa2048 rsa2048 rsa2048 Max. PIN lengths .: 127 127 127 PIN retry counter : 2 0 3 Signature counter : 0 KDF setting ......: off Signature key ....: [none] Encryption key....: [none] Authentication key: [none] General key info..: [none]

gpg/card>

af-anssi commented 1 year ago

:( I pushed another commit which replaces any existing PIN objects at reset. This is really not a good idea in general but I would like to confirm it just works. Could you please try it?

wreps8Owt commented 1 year ago

The KDF DO is correctly reset. It seems like the call to *_pin.update in the reset function of the Persistent object has no effect I suspect the transaction mechanism.

Really? Why do *_pin.update() work without KDF set, but do not work with KDF set?

af-anssi commented 1 year ago

From the applet point of view KDF is just a bunch of bytes that can be set and retrieved by client applications to know how to derive the PIN code before it is sent to the applet for verification. The applet does not care at all about the PIN is a raw user PIN or a KDF derived one.

I suspect you have exactly the same problem without KDF activated. On a released version of SmartPGP (NOT from issue-47), without KDF enabled, you can try to change the PIN to a large value such as 32 digits, verify it is working, then factory reset. If the default PIN (123456) is restored and verifies correctly then I have no clue what's going one...

wreps8Owt commented 1 year ago

:( I pushed another commit which replaces any existing PIN objects at reset. This is really not a good idea in general but I would like to confirm it just works. Could you please try it?

$ LANG=en_US.UTF-8 JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 JC_HOME=../oracle_javacard_sdks/jc304_kit/ ant Buildfile: /home/user/git/SmartPGP/build.xml       [get] Destination already exists (skipping): /home/user/git/SmartPGP/ant-javacard.jar

convert:       [cap] INFO: using JavaCard 3.0.4 SDK in /home/user/git/oracle_javacard_sdks/jc304_kit       [cap] INFO: Setting package name to fr.anssi.smartpgp       [cap] Building CAP with 1 applet from package fr.anssi.smartpgp (AID: D27600012401)       [cap] fr.anssi.smartpgp.SmartPGPApplet D276000124010304AFAF000000000000   [compile] Compiling files from /home/user/git/SmartPGP/src   [compile] Compiling 10 source files to /tmp/jccpro10811319647470149789   [compile] /home/user/git/SmartPGP/src/fr/anssi/smartpgp/Persistent.java:237: error: cannot assign a value to final variable user_pin   [compile]         user_pin = new OwnerPIN(Constants.USER_PIN_RETRY_COUNT, Constants.USER_PIN_MAX_SIZE);   [compile]         ^   [compile] /home/user/git/SmartPGP/src/fr/anssi/smartpgp/Persistent.java:252: error: cannot assign a value to final variable admin_pin   [compile]         admin_pin = new OwnerPIN(Constants.ADMIN_PIN_RETRY_COUNT, Constants.ADMIN_PIN_MAX_SIZE);   [compile]         ^   [compile] 2 errors

BUILD FAILED /home/user/git/SmartPGP/build.xml:7: Compile failed; see the compiler error output for details.

Total time: 2 seconds

af-anssi commented 1 year ago

Sorry for the inconvenience, I have just fixed this.

wreps8Owt commented 1 year ago

Sorry for the inconvenience, I have just fixed this.

$ bin/smartpgp-cli setup-kdf Select OpenPGP Applet 90 00 Get KDF-DO 90 00 Verify Admin PIN 69 82 Traceback (most recent call last):   File "/home/user/git/SmartPGP/bin/smartpgp-cli", line 111, in     main()   File "/home/user/git/SmartPGP/bin/smartpgp-cli", line 104, in main     VALID_COMMANDSargs.command   File "/home/user/git/SmartPGP/bin/smartpgp/highlevel.py", line 462, in cmd_setup_kdf     raise AdminPINFailed smartpgp.highlevel.AdminPINFailed

af-anssi commented 1 year ago

It just means you entered the incorrect current admin PIN...

wreps8Owt commented 1 year ago

It just means you entered the incorrect current admin PIN...

No. It is the first command after installing the applet, which means the default admin PIN cannot pass.

af-anssi commented 1 year ago

Mea culpa I forgot to set the initial/default value. It should be OK now.

wreps8Owt commented 1 year ago

Mea culpa I forward to set the initial/default value. It should be OK now.

Yes, it is okay now.

Besides, is it possible to commitTransaction() only once during Persistent.reset()?

af-anssi commented 1 year ago

Yes, it is okay now.

This is really odd/strange to have to create a new OwnPIN object. This is clearly not the philosophy of JavaCard.

Besides, is it possible to commitTransaction() only once during Persistent.reset()?

No, the context would be too huge for the card, and there is no chance it accepts such a large transaction at once.

As already mentioned previously: I suspect you have exactly the same problem without KDF activated. On a released version of SmartPGP (NOT a compiled version from issue-47), without KDF enabled, can you try to change the PIN to a large value such as 32 digits, verify it is working, then factory reset. If the default PIN (123456) is restored and verifies correctly then I have no clue what's going one. Otherwise there is a strong problem in the implementation of the OwnerPIN class in this platform.

wreps8Owt commented 1 year ago

As already mentioned previously: I suspect you have exactly the same problem without KDF activated. On a released version of SmartPGP (NOT a compiled version from issue-47), without KDF enabled, can you try to change the PIN to a large value such as 32 digits, verify it is working, then factory reset. If the default PIN (123456) is restored and verifies correctly then there is a strong problem in the implementation of the OwnerPIN class in this platform.

Setting a 28-byte PIN on my J3R180 running a released version of SmartPGP without KDF enabled can make the default PIN (123456) not restored nor verified after a factory reset, but it is possible to unblock it and set it to a new value via the default admin PIN.

af-anssi commented 1 year ago

Ok, so there is definitely a strong bug in the implementation of the update procedure of the OwnerPIN on the J3R180.

To confirm it, could you try, without KDF enabled and without doing a factory reset, to simply change the user PIN twice:

wreps8Owt commented 1 year ago

As already mentioned previously: I suspect you have exactly the same problem without KDF activated. On a released version of SmartPGP (NOT a compiled version from issue-47), without KDF enabled, can you try to change the PIN to a large value such as 32 digits, verify it is working, then factory reset. If the default PIN (123456) is restored and verifies correctly then there is a strong problem in the implementation of the OwnerPIN class in this platform. Setting a 28-byte PIN on my J3R180 running a released version of SmartPGP without KDF enabled can make the default PIN (123456) not restored nor verified after a factory reset, but it is possible to unblock it and set it to a new value via the default admin PIN.

However, the new value cannot be verifies correctly.

af-anssi commented 1 year ago

Ok, so there is definitely a strong bug in the implementation of the update procedure of the OwnerPIN on the J3R180.

To confirm it, could you try, without KDF enabled and without doing a factory reset, to simply change the user PIN twice:

* from the default (123456) to a large one (123456789012345678901234567890)

* verify the PIN has really been changed

* from the large one to a smaller one (12345678)

* verify the PIN has really been changed

Could you try the test mentioned above?

wreps8Owt commented 1 year ago

Ok, so there is definitely a strong bug in the implementation of the update procedure of the OwnerPIN on the J3R180.

To confirm it, could you try, without KDF enabled and without doing a factory reset, to simply change the user PIN twice:

  • from the default (123456) to a large one (123456789012345678901234567890)
  • verify the PIN has really been changed
  • from the large one to a smaller one (12345678)
  • verify the PIN has really been changed

As you expect, at last the short new pin can neither be verified nor keep the last (long) value.

af-anssi commented 1 year ago

So it confirms the (strong) bug in the OwnerPIN.update method on this platform.

I have updated the branch issue-47 to provide a single patch to you to have a working version: a new OwnerPIN instance is created before each call to udpate so everything should just work for your card. I cannot integrate such patch in the official releases of SmartPGP.

FYI @martinpaljak

wreps8Owt commented 1 year ago

So it confirms the (strong) bug in the OwnerPIN.update method on this platform.

I have updated the branch issue-47 to provide a single patch to you to have a working version: a new OwnerPIN instance is created before each call to udpate so everything should just work for your card. I cannot integrate such patch in the official releases of SmartPGP.

FYI @martinpaljak

Thanks. This is okay for a patch of walk-around.

To confirm it, could you try, without KDF enabled and without doing a factory reset, to simply change the user PIN twice:

  • from the default (123456) to a large one (123456789012345678901234567890)
  • verify the PIN has really been changed
  • from the large one to a smaller one (12345678)
  • verify the PIN has really been changed

Besides, is it better to mention such test and the patch in the document? It may ease the owner of cards with a buggy OwnerPIN implementation to find the patch.

For example:

Installing the CAP file

...

For cards with a buggy OwnerPIN implementation

If you find that you cannot verify PIN right after a seemingly successful change or factory reset, your card may have a buggy OwnerPIN implementation, like the one mentioned in https://github.com/ANSSI-FR/SmartPGP/issues/47 .

In such case, recreating rather than updating the OwnerPIN objects may help. You can try to apply this patch for a walk-around.

wreps8Owt commented 1 year ago

So it confirms the (strong) bug in the OwnerPIN.update method on this platform.

This may even be another aspect related to https://github.com/ANSSI-FR/SmartPGP/issues/29#issuecomment-993684939 , as my card also belongs to the J3R series.

@bitlogik Can you test whether this issue exists in your J3R110?

wreps8Owt commented 1 year ago

Ok, so there is definitely a strong bug in the implementation of the update procedure of the OwnerPIN on the J3R180.

To confirm it, could you try, without KDF enabled and without doing a factory reset, to simply change the user PIN twice:

* from the default (123456) to a large one (123456789012345678901234567890)

* verify the PIN has really been changed

* from the large one to a smaller one (12345678)

* verify the PIN has really been changed

Could you try the test mentioned above?

Further test against the new release on my J3R180 shows that a 16-byte PIN will not trigger the bug inside itsOwnerPIN implementation, but a 17-byte PIN will, which means that 16 is the max-pin-length of my J3R180 in practice.

Is it possible to set the three *_PIN_MAX_SIZE to 16 as a walk-around?

af-anssi commented 1 year ago

Unfortunately if you set the PIN_MAX_SIZE to 16 you will not be able to use KDF. KDF in OpenPGP relies on SHA256 (respectively SH512) (https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf, page 19) which makes the real PIN to be stored 32 bytes (resp. 64 bytes) long :/

wreps8Owt commented 1 year ago

After I set the PIN_MAX_SIZE to 16, set a PIN longer than 16 in gpg will fail with "Error changing the PIN: Invalid value" as expected, but running bin/smartpgp-cli setup-kdf will still seemingly succeed:

$ bin/smartpgp-cli setup-kdf Select OpenPGP Applet 90 00 Get KDF-DO 90 00 Verify Admin PIN 90 00 Change PW1 67 00 Change PW3 67 00 Put KDF-DO 90 00

However, "Change PW1" and "Change PW3" are actually failed, but in highlevel.py the return value of change_reference_data_pw1() and change_reference_data_pw3() are not checked, so the smartpgp-cli does not stop, and the overall effect is only changing the kdf-do.

All possible error during setup-kdf had better be collected, like the patch below:

diff --git a/bin/smartpgp/highlevel.py b/bin/smartpgp/highlevel.py
--- a/bin/smartpgp/highlevel.py
+++ b/bin/smartpgp/highlevel.py
@@ -462,17 +462,17 @@ class CardConnectionContext:
             raise AdminPINFailed
         ####### step 3bis
         if nresetting_code != None:
-            set_resetting_code(self.connection, nresetting_code)
+            (_,sw1,sw2) = set_resetting_code(self.connection, nresetting_code)
             if sw1!=0x90 or sw2!=0x00:
                 print("set_resetting_code failed")
                 return
         ####### step 4
-        change_reference_data_pw1(self.connection, ascii_encode_pin(pw1), list(npw1))
+        (sw1,sw2) = change_reference_data_pw1(self.connection, ascii_encode_pin(pw1), list(npw1))
         if sw1!=0x90 or sw2!=0x00:
             print("change_reference_data_pw1 failed")
             return
         ####### step 4bis
-        change_reference_data_pw3(self.connection, ascii_encode_pin(pw3), list(npw3))
+        (sw1,sw2) = change_reference_data_pw3(self.connection, ascii_encode_pin(pw3), list(npw3))
         if sw1!=0x90 or sw2!=0x00:
             print("change_reference_data_pw3 failed")
             return
af-anssi commented 1 year ago

Could you submit a pull request on branch javacard-3.0.1 with this patch? So that your contribution will be tracked in the repository :)

wreps8Owt commented 1 year ago

No, thanks. I know (and hate) the game rule of github very well, but I do not want to be conspicuous, for example, to be "tracked" in the commit log of a project. That is why I posted this patch in the issue in the first place, rather than forking the whole project to submit a mere "pull request".

You are totally free to take this patch as your own contribution.

wreps8Owt commented 1 year ago

Unfortunately if you set the PIN_MAX_SIZE to 16 you will not be able to use KDF. KDF in OpenPGP relies on SHA256 (respectively SH512) (https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf, page 19) which make the real PIN to be stored is 32 bytes (resp. 64 bytes) long :/

Further tests show that after setting the PIN_MAX_SIZE to 16, if kdf-do is not set,factory-reset of gpg will fail with error card command TERMINATE DF failed: Bad PIN (0x6982), but fortunately, bin/smartpgp-cli reset works well:

$ gpg --edit-card

Reader ...........: Identive Identive CLOUD 4500 F Dual Interface Reader [uTrust 4700 F Contact Reader] (53201519201674) 00 00 Application ID ...: D276000124010304FFAF000000020000 Application type .: OpenPGP Version ..........: 3.4 Manufacturer .....: unmanaged S/N range Serial number ....: 00000002 Name of cardholder: [not set] Language prefs ...: en Salutation .......: URL of public key : [not set] Login data .......: [not set] Signature PIN ....: forced Key attributes ...: rsa2048 rsa2048 rsa2048 Max. PIN lengths .: 16 16 16 PIN retry counter : 3 0 3 Signature counter : 0 KDF setting ......: off Signature key ....: [none] Encryption key....: [none] Authentication key: [none] General key info..: [none]

gpg/card> admin Admin commands are allowed

gpg/card> factory-reset gpg: OpenPGP card no. D276000124010304FFAF000000020000 detected

gpg: Note: This command destroys all keys stored on the card!

Continue? (y/N) y Really do a factory reset? (enter "yes") yes card command TERMINATE DF failed: Bad PIN (0x6982)

gpg/card> q $ killall gpg-agent $ bin/smartpgp-cli reset Select OpenPGP Applet 90 00 Verify Admin PIN 69 82 Verify Admin PIN 69 82 Verify Admin PIN 69 82 Terminate 90 00 Activate 90 00 but if kdf-do is set, factory-reset of gpg will work:

$ bin/smartpgp-cli set-kdf -i kdf Select OpenPGP Applet 90 00 Verify Admin PIN 90 00 Put KDF-DO 90 00 $ gpg --edit-card

Reader ...........: Identive Identive CLOUD 4500 F Dual Interface Reader [uTrust 4700 F Contact Reader] (53201519201674) 00 00 Application ID ...: D276000124010304FFAF000000020000 Application type .: OpenPGP Version ..........: 3.4 Manufacturer .....: unmanaged S/N range Serial number ....: 00000002 Name of cardholder: [not set] Language prefs ...: en Salutation .......: URL of public key : [not set] Login data .......: [not set] Signature PIN ....: forced Key attributes ...: rsa2048 rsa2048 rsa2048 Max. PIN lengths .: 32 32 32 PIN retry counter : 3 0 3 Signature counter : 0 KDF setting ......: on Signature key ....: [none] Encryption key....: [none] Authentication key: [none] General key info..: [none]

gpg/card> admin Admin commands are allowed

gpg/card> factory-reset gpg: OpenPGP card no. D276000124010304FFAF000000020000 detected

gpg: Note: This command destroys all keys stored on the card!

Continue? (y/N) y Really do a factory reset? (enter "yes") yes

gpg/card>