polhenarejos / pico-openpgp

Converting a Raspberry Pico into an OpenPGP CCID smart card.
GNU General Public License v3.0
43 stars 7 forks source link

Only the first signature action after power-on can be successfully executed #16

Closed imkuang closed 2 days ago

imkuang commented 1 week ago

As the title describes, in my use, I found that if I don't re-plug the USB, only the first signature is successful, and when I perform the signature again, I will encounter the following bad PIN fail (and won't ask me to re-enter the PIN code)

ming@work:~/download$ gpg -s test.txt
File 'test.txt.gpg' exists. Overwrite? (y/N) y
ming@work:~/download$ gpg -s test.txt
File 'test.txt.gpg' exists. Overwrite? (y/N) y
gpg: signing failed: Bad PIN
gpg: signing failed: Bad PIN
ming@work:~/download$ 

After several tests, I found that if the admin password was ever entered (e.g. by executing keytocard cmd or using the admin password to unblock pin), everything works fine, but the problem still occurs after re-plugging the USB (re-powering it up).

I've analyzed and fixed the issue myself, later I'll create a pull request, this issue is created as a reminder and record. PS: I use translation software, forgive my poor English!

imkuang commented 1 week ago

The pull request has been created, it's a non-compliance issue with the protocol specification (probably a typo). The default first byte of the current pw status is 1, it tells gnupg that we will cache the pin code for multiple commands, so gnupg won't ask us for the pin code again afterward. In error logic has_pw1 is reset to false after each signature action execution, but the actions such as signing check the has_pw1 field to make sure the password has been verified, thus causing the issue.

The reason why the admin password makes everything work is probably due to logic similar to the following, where only one of the has_pw3 and has_pw1 fields needs to be true

static int cmd_pso() {
    uint16_t algo_fid = 0x0, pk_fid = 0x0;
    bool is_aes = false;
    if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
        if (!has_pw3 && !has_pw1) {
            return SW_SECURITY_STATUS_NOT_SATISFIED();
        }
        algo_fid = EF_ALGO_PRIV1;
        pk_fid = EF_PK_SIG;
    }

Since I couldn't get the version 2.0 release firmware to be successfully recognized by the system (issue #15), I created my own branch based on the v1.12 tag and simply cherry-picked a few commits that were critical or didn't seem to affect the main functionality to be used to compile my own version of the firmware (e.g., the fix I needed for issue #12). This pull request has been verified on my own branch: https://github.com/imkuang/pico-openpgp/tree/v1.12-patch

Finally, I'm completely new to gpg, and the protocol specification document was only briefly consulted today, so please feel free to point out any problems!

polhenarejos commented 2 days ago

Fixed