OpenSC / libp11

PKCS#11 wrapper library
GNU Lesser General Public License v2.1
310 stars 189 forks source link

RSA-OAEP padding rejected??? #266

Closed mouse07410 closed 5 years ago

mouse07410 commented 5 years ago

I upgraded the YubiHSM2 SDK, and was running an old(er) test-script. To my surprise, it failed on OAEP decryption:

Decrypting the symmetric key on the token...
~/openssl-1.1/bin/openssl rasutl -engine pkcs11 -keyform engine -decrypt -inkey "pkcs11:token=YubiHSM;id=%04%02;type=private" -oaep -in /tmp/derive.1201.key.enc | xxd -p -c 200
engine "pkcs11" set.
Enter PKCS#11 token PIN for YubiHSM:
RSA operation error
140735608378240:error:8106F402:libp11:pkcs11_mechanism:Unsupported padding type:p11_rsa.c:69:

Puzzled, I changed openssl rsautl to openssl pkeyutl, and it worked:

$ yhsm2-rsa-encr-demo2 
Generate a random data file (1000 bytes), Base64-encoded...
openssl rand -base64 -out /tmp/derive.2804.text 1000

Generated
  key: e60b9b067025c9bb597743cd3dda65e634d12336f07ed7ff284268dc70ed1ee8
  iv:  17f8e4e29ea88cec0aadf9823eaec2c7

Encrypt file /tmp/derive.2804.text with this key and IV...
openssl enc -aes-256-cfb -a -e -in /tmp/derive.2804.text -out /tmp/derive.2804.text.enc -K e60b9b067025c9bb597743cd3dda65e634d12336f07ed7ff284268dc70ed1ee8 -iv 17f8e4e29ea88cec0aadf9823eaec2c7

Encrypting this random symmetric key to token RSA KEY MAN key...
echo e60b9b067025c9bb597743cd3dda65e634d12336f07ed7ff284268dc70ed1ee8 | xxd -r -p -c 200 | ~/openssl-1.1/bin/openssl rsautl -engine pkcs11 -keyform engine -encrypt -pubin -inkey "pkcs11:token=YubiHSM;id=%04%02;type=public" -oaep -out /tmp/derive.2804.key.enc
engine "pkcs11" set.
Enter PKCS#11 token PIN for YubiHSM:

Decrypting the symmetric key on the token...
KEY2="~/openssl-1.1/bin/openssl pkeyutl -engine pkcs11 -keyform engine -decrypt -inkey "pkcs11:token=YubiHSM;id=%04%02;type=private" -pkeyopt rsa_padding_mode:oaep -in /tmp/derive.2804.key.enc | xxd -p -c 200"
engine "pkcs11" set.
Enter PKCS#11 token PIN for YubiHSM:

. . . . .

KEY1="e60b9b067025c9bb597743cd3dda65e634d12336f07ed7ff284268dc70ed1ee8"
KEY2="e60b9b067025c9bb597743cd3dda65e634d12336f07ed7ff284268dc70ed1ee8"
Original and decrypted keys  match
Original and decrypted files match

But looking at the code in p11_rsa.c, I noticed that it doesn't seem to accept OAEP paddings (all the support for it is in p11_pkey.c):

static int pkcs11_mechanism(CK_MECHANISM *mechanism, const int padding)
{
    memset(mechanism, 0, sizeof(CK_MECHANISM));
    switch (padding) {
    case RSA_PKCS1_PADDING:
         mechanism->mechanism = CKM_RSA_PKCS;
         break;
    case RSA_NO_PADDING:
        mechanism->mechanism = CKM_RSA_X_509;
        break;
    case RSA_X931_PADDING:
        mechanism->mechanism = CKM_RSA_X9_31;
        break;
    default:
        P11err(P11_F_PKCS11_MECHANISM, P11_R_UNSUPPORTED_PADDING_TYPE);
        return -1;
    }
    return 0;
}

Should anything be done about it? I know that rsautl used to work a few months ago... Since then both libp11 and OpenSC evolved somewhat, and there were some additions for PSS and OAEP support in OpenSC...

mtrojnar commented 5 years ago

Correct. There is no way to implement OAEP on the low-level RSA engine interface of OpenSSL, as the OAEP parameters required to fill the CK_RSA_PKCS_OAEP_PARAMS structure are no longer available at this point.

These OAEP parameters are available in the EVP_PKEY_CTX structure of the PKEY interface. The pkcs11_params_oaep() function may give you some clues if you are interested in the internals of our implementation.

mouse07410 commented 5 years ago

@mtrojnar and @dengert I'm trying to understand why some things work, and some don't.

For example, here's a Yubikey NEO token with two applets (that matter in this context): PIV and OpenPGP. I'm trying to use both with OpenSSL via libp11 and OpenSC opensc-pkcs11.dylib.

With PIV applet, everything works as expected, and OpenSSL "translates" RSA-PSS and RSA-OAEP operations into what the token understands, applying the padding in software:

openssl rand -hex -out /tmp/derive.57559.text 5120

Signing file /tmp/derive.57559.text...
openssl dgst -engine pkcs11 -keyform engine -sign "pkcs11:manufacturer=piv_II;object=SIGN%20key;type=private" -sha384 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -out /tmp/derive.57559.text.sig /tmp/derive.57559.text
engine "pkcs11" set.
Enter PKCS#11 token PIN for Uri the Great:
Signature is stored in /tmp/derive.57559.text.sig

Verifying signature:
openssl dgst -engine pkcs11 -keyform engine -sha384 -verify "pkcs11:manufacturer=piv_II;object=SIGN%20pubkey;type=public" -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -signature /tmp/derive.57559.text.sig  /tmp/derive.57559.text
engine "pkcs11" set.
Verified OK

With OpenPGP applet though, it does fine RSA-PKCS1 signature, but fails with RSA-PSS:

OPENSC_DRIVER=openpgp ~/openssl-1.1/bin/openssl dgst -engine pkcs11 -keyform engine -sign "pkcs11:model=PKCS%2315%20emulated;manufacturer=Yubico;serial=0006038xxxxx;token=User%20PIN%20%28sig%29%20%28OpenPGP%29;id=%01;object=Signature%20key;type=private" -sha384 -sigopt rsa_padding_mode:pss -out t6400.dat.sighsmpss t6400.dat
engine "pkcs11" set.
Enter PKCS#11 token PIN for User PIN (sig) (OpenPGP):
Error Signing Data
4571960768:error:8207A070:PKCS#11 module:pkcs11_private_encrypt:Mechanism invalid:p11_rsa.c:116:

Why is it that in one case the software translation works fine, and in the other one it doesn't happen? And is there a way in libp11 to somehow signal OpenSSL that for the given token it should apply padding in software rather than expect the token to do it?

dengert commented 5 years ago

A PKCS11_SPY trace and an opensc-debug.log would be helpful.

pkcs11_private_encrypt has: / Try signing first, as applications are more likely to use it / / OpenSSL may use it for encryption rather than signing /

PIV only does RAW, so the C_Sign should work.

OpenPGP may place more restrictions on the key, so id C_Sign fails pkcs11_private_encrypt may try C_Encrypt that may fail.

A PKCS11_SPY trace and an opensc-debug.log would be helpful.

mouse07410 commented 5 years ago

@dengert you're certainly right. Here they are:

$ PKCS11SPY_OUTPUT=openpgp-spy.txt OPENSC_DEBUG=9 OPENSC_DRIVER=openpgp openssl dgst -engine pkcs11 -keyform engine -sign "pkcs11:model=PKCS%2315%20emulated;token=User%20PIN%20%28sig%29%20%28OpenPGP%29;id=%01;object=Signature%20key;type=private" -sha384 -sigopt rsa_padding_mode:pss -out t6400.dat.sighsmpkcs t6400.dat
P:83671; T:0x4572628416 08:36:24.882 [opensc-pkcs11] ctx.c:737:process_config_file: Used configuration file '/Library/OpenSC/etc/opensc.conf'
engine "pkcs11" set.
Enter PKCS#11 token PIN for User PIN (sig) (OpenPGP):
Error Signing Data
4572628588:error:8207A070:PKCS#11 module:pkcs11_private_encrypt:Mechanism invalid:p11_rsa.c:116:
$

opensc-debug.log: opensc-log.txt - shows successful signature using PKCS1 padding, and a failed one using PSS. Strange to me that OpenSSL did not apply the padding in software.

PKCS11_SPY log: openpgp-spy.txt - shows that RSA-PSS was requested directly.

So, how does OpenSSL decide whether to apply the padding by itself, or "outsource" it to the engine+token (such as YubiHSM2 that applies PSS by itself)?

mtrojnar commented 5 years ago

So, how does OpenSSL decide whether to apply the padding by itself, or "outsource" it to the engine+token (such as YubiHSM2 that applies PSS by itself)?

OpenSSL doesn't decide what to do. We decide it in libp11. We first try CKM_RSA_PKCS_PSS, and if it fails we let OpenSSL apply the padding and use CKM_RSA_X_509 (raw RSA): https://github.com/OpenSC/libp11/blob/0ac6d4d856885656505b42498f6e72711d2c7810/src/p11_pkey.c#L383-L385

It is obviously possible that the module only supports CKM_RSA_PKCS, so neither CKM_RSA_PKCS_PSS nor CKM_RSA_X_509 can be used.

mouse07410 commented 5 years ago

But I've seen no traces in the SPY log that suggested that anything but PSS was tried. And I'm pretty sure the token does support RSA_X_509.

What's your opinion regarding what's happening with the RSA keys from the OpenPGP applet?

dengert commented 5 years ago

I agree. framework-pkcs11.c has:

5485         /* Check if we support raw RSA */
5486         if (rsa_flags & SC_ALGORITHM_RSA_RAW) {
5487                 mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_X_509, &mech_info, CKK_RSA, NULL, NULL);
5488                 rc = sc_pkcs11_register_mechanism(p11card, mt);
5489                 if (rc != CKR_OK)
5490                         return rc;
5491 
5492                 /* We support PKCS1 padding in software */
5493                 /* either the card supports it or OpenSC does */
5494                 rsa_flags |= SC_ALGORITHM_RSA_PAD_PKCS1;
5495 #ifdef ENABLE_OPENSSL
5496                 rsa_flags |= SC_ALGORITHM_RSA_PAD_PSS;
5497 #endif
5498         }
... then later ...
5576         if (rsa_flags & SC_ALGORITHM_RSA_PAD_PSS) {
5577                 mech_info.flags &= ~(CKF_DECRYPT|CKF_ENCRYPT);
5578                 mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_PSS, &mech_info, CKK_RSA, NULL, NULL);
5579                 rc = sc_pkcs11_register_mechanism(p11card, mt);

Only one card card-sc-hsm.c says it can support both SC_ALGORITHM_RSA_RAW and SC_ALGORITHM_RSA_PAD_PSS on the card:

611         flags = SC_ALGORITHM_RSA_RAW|SC_ALGORITHM_RSA_PAD_PSS|SC_ALGORITHM_ONBOARD_KEY_GEN;

card-sc-hsm.c executes both parts of framework-pkcs11.c above and registers CKM_RSA_PKCS_PSS and the PSS should be done on the card. (A pkcs11-spy and opensc-debug.log) would show which one is actually used.)

card-openpgp.c does not support SC_ALGORITHM_RSA_RAW or SC_ALGORITHM_RSA_PAD_PSS so does not register any PSS mechanisms.

PIV supports SC_ALGORITHM_RSA_RAW so CKA_RSA_X_509 and CKM_RSA_PKCS_PSS get registered. and if CKM_RSA_PKCS_PSS is used, the OpenSC padding will do the padding. (A pkcs11-spy and opensc-debug.log) would show which one is actually used.)

mouse07410 commented 5 years ago

I agree.

@dengert Could you please make it clearer what/who you agree with?

Only one card card-sc-hsm.c says it can support both SC_ALGORITHM_RSA_RAW and SC_ALGORITHM_RSA_PAD_PSS on the card

At least one other card - YubiHSM2 - does support SC_ALGORITHM_RSA_PAD_PSS on the card. At the same time (for security reasons) it does not support SC_ALGORITHM_RSA_RAW. This card does not have a special driver, and works fine with the PIV driver.

Also, this support we're talking about - it's not what the actual card reports, but what the driver thinks the card he's controlling should support, right?

A pkcs11-spy and opensc-debug.log) would show which one is actually used.

Both were attached here. And they seem to indicate that only RSA-PSS was tried (feel free to correct me if I'm wrong here).

Also:

For Yubikey NEO PIV applet (though I'm very sure the token itself does not do RSA-PSS, so it must be the software assist that's handling the PSS padding)

$ pkcs11-tool -M
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
  ECDSA, keySize={256,256}, hw, sign, other flags=0x1800000
  ECDH1-COFACTOR-DERIVE, keySize={256,256}, hw, derive, other flags=0x1800000
  ECDH1-DERIVE, keySize={256,256}, hw, derive, other flags=0x1800000
  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
$ 

For Yubikey NEO OpenPGP applet

$ OPENSC_DRIVER=openpgp pkcs11-tool -L
Available slots:
Slot 0 (0x0): Yubico Yubikey NEO OTP+U2F+CCID
  token label        : User PIN (OpenPGP)
  token manufacturer : Yubico
  token model        : PKCS#15 emulated
  token flags        : login required, rng, token initialized, PIN initialized
  hardware version   : 2.0
  firmware version   : 2.0
  serial num         : 0006038xxxxx
  pin min/max        : 6/127
Slot 1 (0x1): Yubico Yubikey NEO OTP+U2F+CCID
  token label        : User PIN (sig) (OpenPGP)
  token manufacturer : Yubico
  token model        : PKCS#15 emulated
  token flags        : login required, rng, token initialized, PIN initialized
  hardware version   : 2.0
  firmware version   : 2.0
  serial num         : 0006038xxx
  pin min/max        : 6/127
$ OPENSC_DRIVER=openpgp pkcs11-tool -M
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-PKCS, keySize={2048,2048}, hw, decrypt, sign, verify
  SHA1-RSA-PKCS, keySize={2048,2048}, sign, verify
  SHA224-RSA-PKCS, keySize={2048,2048}, sign, verify
  SHA256-RSA-PKCS, keySize={2048,2048}, sign, verify
  SHA384-RSA-PKCS, keySize={2048,2048}, sign, verify
  SHA512-RSA-PKCS, keySize={2048,2048}, sign, verify
  MD5-RSA-PKCS, keySize={2048,2048}, sign, verify
  RIPEMD160-RSA-PKCS, keySize={2048,2048}, sign, verify
  RSA-PKCS-KEY-PAIR-GEN, keySize={2048,2048}, generate_key_pair
$ OPENSC_DRIVER=openpgp pkcs11-tool --slot 0x1 -M
Supported mechanisms:
  SHA-1, digest
  SHA224, digest
  SHA256, digest
  SHA384, digest
  SHA512, digest
  MD5, digest
  RIPEMD160, digest
  GOSTR3411, digest
  RSA-PKCS, keySize={2048,2048}, hw, decrypt, sign, verify
  SHA1-RSA-PKCS, keySize={2048,2048}, sign, verify
  SHA224-RSA-PKCS, keySize={2048,2048}, sign, verify
  SHA256-RSA-PKCS, keySize={2048,2048}, sign, verify
  SHA384-RSA-PKCS, keySize={2048,2048}, sign, verify
  SHA512-RSA-PKCS, keySize={2048,2048}, sign, verify
  MD5-RSA-PKCS, keySize={2048,2048}, sign, verify
  RIPEMD160-RSA-PKCS, keySize={2048,2048}, sign, verify
  RSA-PKCS-KEY-PAIR-GEN, keySize={2048,2048}, generate_key_pair
$ 

It is obviously possible that the module only supports CKM_RSA_PKCS, so neither CKM_RSA_PKCS_PSS nor CKM_RSA_X_509 can be used

@mtrojnar but CKM_RSA_X_509 was not tried, as you can see in the log.

dengert commented 5 years ago

I agreed with @mtrojnar And just to show the sc-hsm mechanisms supported via hardware or software:

./pkcs11-tool -M
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
  ECDSA, keySize={192,521}, hw, sign, other flags=0x1d00000
  ECDSA-SHA1, keySize={192,521}, hw, sign, other flags=0x1d00000
  ECDH1-COFACTOR-DERIVE, keySize={192,521}, hw, derive, other flags=0x1d00000
  ECDH1-DERIVE, keySize={192,521}, hw, derive, other flags=0x1d00000
  ECDSA-KEY-PAIR-GEN, keySize={192,521}, hw, generate_key_pair, other flags=0x1d00000
  RSA-X-509, keySize={1024,4096}, hw, decrypt, sign, verify
  RSA-PKCS, keySize={1024,4096}, hw, decrypt, sign, verify
  SHA1-RSA-PKCS, keySize={1024,4096}, sign, verify
  SHA224-RSA-PKCS, keySize={1024,4096}, sign, verify
  SHA256-RSA-PKCS, keySize={1024,4096}, sign, verify
  SHA384-RSA-PKCS, keySize={1024,4096}, sign, verify
  SHA512-RSA-PKCS, keySize={1024,4096}, sign, verify
  MD5-RSA-PKCS, keySize={1024,4096}, sign, verify
  RIPEMD160-RSA-PKCS, keySize={1024,4096}, sign, verify
  RSA-PKCS-PSS, keySize={1024,4096}, hw, sign, verify
  SHA1-RSA-PKCS-PSS, keySize={1024,4096}, sign, verify
  SHA224-RSA-PKCS-PSS, keySize={1024,4096}, sign, verify
  SHA256-RSA-PKCS-PSS, keySize={1024,4096}, sign, verify
  SHA384-RSA-PKCS-PSS, keySize={1024,4096}, sign, verify
  SHA512-RSA-PKCS-PSS, keySize={1024,4096}, sign, verify
  RSA-PKCS-KEY-PAIR-GEN, keySize={1024,4096}, generate_key_pair

And it looks like OpenSC is setting the "hw" flag correctly on mechanisms that are supported on the card correctly in all 3 cases.

@mouse07410 The limitation of the NEO with OpenPGP is not due to the token, but dueto the OpenPGP applet and the OpenPGP standards.

mouse07410 commented 5 years ago

The limitation of the NEO with OpenPGP is not due to the token, but due to the OpenPGP applet and the OpenPGP standards

So, you think there's nothing reasonable that libp11 (or OpenSSL) could do to make RSA-PSS working with RSA keys from OpenPGP applet... OK. I may not like it, but I'll have to live with it.

mtrojnar commented 5 years ago

Correct. There is no way to implement PSS padding with only PKCS1 padding provided by the module.

mouse07410 commented 5 years ago

There is no way to implement PSS padding with only PKCS1 padding provided by the module.

I guess my confusion stems from the fact that somehow something between OpenSSL and libp11 figures out that Yubikey NEO PIV applet cannot do PSS on the token, and applies PSS padding in software. But it (whatever "it" may be) cannot do the same with the OpenPGP applet on the same token, and requests only straight PSS from the token, which the token is incapable of.

mtrojnar commented 5 years ago

I hoped I explained it quite clearly in https://github.com/OpenSC/libp11/issues/266#issuecomment-449659569...

mouse07410 commented 5 years ago

Well, I must be dense, but I'm afraid I still don't get it. According to your explanation

We decide it in libp11. We first try CKM_RSA_PKCS_PSS, and if it fails we let OpenSSL apply the padding and use CKM_RSA_X_509 (raw RSA)

In case of OpenPGP applet I see the code tried PKCS_PSS, it failed - but the log did not show the subsequent attempt to try X_509. (I guess I will do the SPY over the PIV trial to see how the exchange differs.)

The fact is, both PKCS1 and PSS paddings seem to work ok for PIV keys on both "dumb" tokens (like Yubikey NEO) that only do RSA raw (and maybe PKCS1 but I doubt that), and YubiHSM2 that only does PSS and PKCS1 on the token but no RSA raw.

Somehow, RSA keys in the PIV applet are treated different from those in the OpenPGP applet - and I don't understand why. (Not that I desperately need that capability with OpenPGP keys, but I dislike feeling dumb and puzzled ;)

mtrojnar commented 5 years ago

This is the failed PSS request:

 29: C_SignInit 2018-12-23 08:36:28.533
[in] hsession = 0x7fb932512630
pMechanism->type=CKM_RSA_PKCS_PSS
pMechanism->pParameter->hashAlg=CKM_SHA384
pMechanism->pParameter->mgf=CKG_MGF1_SHA384
pMechanism->pParameter->sLen=206
[in] hKey = 0x7fb932431b80
Returned: 112 CKR_MECHANISM_INVALID

This is the failed raw RSA request:

 30: C_SignInit 2018-12-23 08:36:28.533
[in] hSession = 0x7fb932512630
pMechanism->type=CKM_RSA_X_509
[in] hKey = 0x7fb932431b80
Returned: 112 CKR_MECHANISM_INVALID 

If your question is "Why my module does not support raw RSA?" then I really don't know, and I don't think this is the right forum to ask this questions. The libp11 project doesn't develop PKCS#11 modules.

mouse07410 commented 5 years ago

This is the failed raw RSA request...

Ah, I missed that. Silly me! (And I thought I examined the SPY output carefully... Oh well...)

If your question is "Why my module does not support raw RSA?" then I really don't know...

Oh no, that I didn't want to ask. If the token doesn't support raw RSA (e.g., because OpenPGP applet doesn't), that's a totally different story.

I got my answer - libp11 did try RSA_X_509 after PSS failed, and the token refused. Now it is indeed crystal clear.

Thank you for bearing with me. Happy Holidays!