opencryptoki / opencryptoki

PKCS#11 library and tools for Linux and AIX. Includes tokens supporting IBM crypto hardware as well as a software token.
Other
137 stars 56 forks source link

Test failures with software TPM #280

Open p-steuer opened 4 years ago

p-steuer commented 4 years ago

Test suite output (z14 TPM token with swtpm https://sourceforge.net/projects/ibmswtpm/files/tpm4769tar.gz/download).

aes_tests.out:Total=187, Ran=60, Passed=60, Failed=0, Skipped=127, Errors=1 (total elapsed time 13s 260045us)
des3_tests.out:Total=224, Ran=89, Passed=89, Failed=0, Skipped=135, Errors=0 (total elapsed time 9s 803141us)
des_tests.out:Total=33, Ran=33, Passed=33, Failed=0, Skipped=0, Errors=0 (total elapsed time 3s 202926us)
dh_tests.out:Total=0, Ran=0, Passed=0, Failed=0, Skipped=0, Errors=0 (total elapsed time 0s 335us)
digest_tests.out:Total=741, Ran=148, Passed=148, Failed=0, Skipped=593, Errors=0 (total elapsed time 9s 176853us)
dilithium_tests.out:Total=1, Ran=0, Passed=0, Failed=0, Skipped=1, Errors=0 (total elapsed time 0s 152862us)
dsa_tests.out:Total=0, Ran=0, Passed=0, Failed=0, Skipped=0, Errors=0 (total elapsed time 0s 207us)
ec_tests.out:Total=5, Ran=0, Passed=0, Failed=0, Skipped=5, Errors=0 (total elapsed time 0s 806285us)
rsa_tests.out:Total=822, Ran=17, Passed=13, Failed=4, Skipped=805, Errors=3 (total elapsed time 13s 465951us)
rsaupdate_tests.out:Total=275, Ran=16, Passed=16, Failed=0, Skipped=259, Errors=0 (total elapsed time 6s 613888us)
ssl3_tests.out:Total=13, Ran=13, Passed=13, Failed=0, Skipped=0, Errors=0 (total elapsed time 0s 171475us)

The aes_tests failure is a RSA Key Wrap/Unwrap Failure:

* TESTCASE do_WrapUnwrapRSA BEGIN AES_CBC_PAD wrap/unwrap of RSA key for key length=16.
* TESTCASE do_WrapUnwrapRSA ERROR (testcases/crypto/aes_func.c:1360)) C_UnWrapKey rc=CKR_FUNCTION_FAILED

The 3 failures on the rsa_tests are:

* TESTCASE do_EncryptDecryptRSA BEGIN RSA PKCS Encrypt and Decrypt with test vector 17.
* TESTCASE do_EncryptDecryptRSA ERROR (testcases/crypto/rsa_func.c:211)) C_Encrypt, rc=CKR_FUNCTION_FAILED

* TESTCASE do_WrapUnwrapRSA BEGIN RSA PKCS Wrap Unwrap with test vector 2,
* TESTCASE do_WrapUnwrapRSA ERROR (testcases/crypto/rsa_func.c:1166)) C_GenerateKeyPair() rc = CKR_TEMPLATE_INCONSISTENT

* TESTCASE do_EncryptDecryptImportRSA BEGIN RSA PKCS Encrypt and Decrypt Import with test vector 0.
* TESTCASE do_EncryptDecryptImportRSA ERROR (testcases/crypto/rsa_func.c:511)) C_Encrypt, rc=CKR_FUNCTION_FAILED
ifranzki commented 4 years ago

I started to debug these failures:

Regarding: aes_tests failure is a RSA Key Wrap/Unwrap Failure:

* TESTCASE do_WrapUnwrapRSA BEGIN AES_CBC_PAD wrap/unwrap of RSA key for key length=16.
* TESTCASE do_WrapUnwrapRSA ERROR (testcases/crypto/aes_func.c:1360)) C_UnWrapKey rc=CKR_FUNCTION_FAILED

This fails because an ber_decode_INTEGER() fails to decode an integer during ber_decode_RSAPrivateKey(). The reason is that the RSA key is assumed to be not-opaque, because the un-wrapping key (an AES key in this case) is not opaque.

A key is opaque if it has the CKA_IBM_OPAQUE attribute.

The common code assumes that when the unwrapping key is not opaque, then also the unwrapped key is not opaque.

For the TPM token, RSA keys are opaque, but AES keys are not.

So during C_WrapKey, the to-be-wrapped key is opaque, and thus, the RSA key is BER-encoded using the opaque key blob as the private key. During C_UnWrapKey, the AES key used to unwrap the key is detected to not being opaque, thus the unwrapped RSA key structure is BER decoded, and it is expected to have the private key components (priv exponent, prime 1 and 2, exponent 1 and 2, coefficient) an INTEGERs. However, since the original RSA key was opaque, it has an OCTET STRING containing the opaque key blob instead of the individual key components.

So the root cause is that for the TPM token, the assumption of the common code, that either all keys are opaque, or all keys are not opaque is not true. Not sure how to fix this....

ifranzki commented 4 years ago

The 2nd RSA failkure is somehow similar:

* TESTCASE do_WrapUnwrapRSA BEGIN RSA PKCS Wrap Unwrap with test vector 2,
* TESTCASE do_WrapUnwrapRSA ERROR (testcases/crypto/rsa_func.c:1166)) C_GenerateKeyPair() rc = CKR_TEMPLATE_INCONSISTENT

First of all, the CKR_TEMPLATE_INCONSISTENT is because the test vector uses an unsupported public exponent. The TPM token only supports a public exponent of 65537. Other tests skip the test if its not that public exponent. The Wrap/Unwrap test dos not skip.

I have added a check for a valid public exponent into the testcase, and then it runs further. However, it then segfaults at test vector 54:

* TESTCASE do_WrapUnwrapRSA BEGIN RSA PKCS Wrap Unwrap with test vector 54,
publ_exp='010001', mod_bits='1024', keylen='8', keytype='CKM_DES_KEY_GEN'
* TESTCASE do_WrapUnwrapRSA PASS (elapsed time 0s 75023us) wrapped and unwrapped key successful.
Segmentation fault (core dumped)

The reason for the segfault is that the unwrapped DES key contains an empty CKA_VALUE attribute, i.e. the attribute length is 0, and the attribute pointer is NULL. The code tries to get the DES key from it and segfaults due to NULL pointer.

The reason for the empty CKA_VALUE attribute of the DES key is similar to above Wrap/Unwrap problem:

The common code checks if the wrapping key is opaque (i.e. if it contains a CKA_IBM_OPAQUE attribute). It then assumes that also the unwrapped key is opaque. Thus, when unwrapping the DES key using RSA, it assumes that because the unwrapping RSA key is opaque, the unwrapped DES key must alos be opaque. Thus, it creates the CKA_IBM_OPAQUE attribute instead of the CKA_VALUE attribute (leaving the CKA_VALUE attribute at its default, i.e. empty).

The code to Encrypt/Decrypt using a DES key wants to get the (non-opaque) DES key from the CKA_VALUE attribute and fails due to the empty attribute.

So the same root cause as above, for the TPM token, the assumption of the common code, that either all keys are opaque, or all keys are not opaque is not true. Again, not sure how to fix this....

ifranzki commented 4 years ago

Patch to skip unsupported public exponents for the TPM token. I would not apply the patch now, since then it segfaults at a later time due to above described error. So its better to live with the CKR_TEMPLATE_INCONSISTENT test failure, than with a segfault.

Subject: [PATCH] TESTCASE: Skip unsupported public exponent tests for TPM token

The TPM token only supports a public exponent of 65537. Check the
public exponent for the Wrap/Unwrap testcases like it does for other
tests.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
---
 testcases/crypto/rsa_func.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/testcases/crypto/rsa_func.c b/testcases/crypto/rsa_func.c
index 774c41f8..0700404f 100644
--- a/testcases/crypto/rsa_func.c
+++ b/testcases/crypto/rsa_func.c
@@ -1129,6 +1129,19 @@ CK_RV do_WrapUnwrapRSA(struct GENERATED_TEST_SUITE_INFO * tsuite)
                 continue;
             }
         }
+        // tpm special cases:
+        // tpm token can only use public exponent 0x010001 (65537)
+        // so skip test if invalid public exponent is used
+        if (is_tpm_token(slot_id)) {
+            if ((!is_valid_tpm_pubexp(tsuite->tv[i].publ_exp,
+                                      tsuite->tv[i].publ_exp_len))
+                || (!is_valid_tpm_modbits(tsuite->tv[i].modbits))) {
+                testcase_skip("TPM Token cannot " "be used with publ_exp.='%s'",
+                              s);
+                continue;
+            }
+        }
+
         // begin test
         testcase_begin("%s Wrap Unwrap with test vector %d, "
                        "\npubl_exp='%s', mod_bits='%lu', keylen='%lu', "
-- 
ifranzki commented 4 years ago

The first RSA failure

* TESTCASE do_EncryptDecryptRSA BEGIN RSA PKCS Encrypt and Decrypt with test vector 17.
* TESTCASE do_EncryptDecryptRSA ERROR (testcases/crypto/rsa_func.c:211)) C_Encrypt, rc=CKR_FUNCTION_FAILED

shows:

[usr/lib/tpm_stdll/tpm_specific.c:2892 tpmtok] ERROR: Tspi_Data_Unbind failed: rc=0x20ca

ox20ca seems to be TCS_E_KM_LOADFAILED:

// Key adressed by Key's UUID cannot be loaded because one of the required
// parent keys needs authorization.
#define TCS_E_KM_LOADFAILED   (UINT32)(TSS_E_BASE + 0x0CAL)

Don't really know what that means. The key was just created before with C_GenerateKeyPair, so I don't know why the parent key is not authorized.... Maybe a setup problem with software TPM ?

ifranzki commented 4 years ago

The 3rd RSA failure

* TESTCASE do_EncryptDecryptImportRSA BEGIN RSA PKCS Encrypt and Decrypt Import with test vector 0.
* TESTCASE do_EncryptDecryptImportRSA ERROR (testcases/crypto/rsa_func.c:511)) C_Encrypt, rc=CKR_FUNCTION_FAILED

is at a C_Encrypt after the key has been imported via C_CreateObject. The TPM token doe snot have a token specific object-add function, so the import is purely common code. Thus it simply creates an object with the clear key attributes.

Normally RSA keys use the CKA_IBM_OPAQUE attribute to store the key blob. For imported keys, this attribute does not exist. So when C_Encrypt checks the key, it finds that there is no CKA_IBM_OPAQUE attribute:

03/17/2020 16:13:41 39169 [usr/lib/common/object.c:472 tpmtok] ERROR: Attribute Type Invalid
03/17/2020 16:13:41 39169 [usr/lib/common/obj_mgr.c:1432 tpmtok] DEVEL: object_get_attribute_values failed.
03/17/2020 16:13:41 39169 [usr/lib/tpm_stdll/tpm_specific.c:312 tpmtok] DEVEL: object_mgr_get_attribute_values failed:rc=0x12
03/17/2020 16:13:41 39169 [usr/lib/tpm_stdll/tpm_specific.c:702 tpmtok] DEVEL: key blob not found, checking for modulus

The code then runs token_wrap_key_object(), which gets the public or private key attributes in clear, and creates a TSS Object from it, gets the key blob, and puts it into the key's CKA_IBM_OPAQUE attribute.

It then does a Tspi_Context_LoadKeyByBlob with the key blob from CKA_IBM_OPAQUE, but this fails:

03/17/2020 16:13:41 39169 [usr/lib/tpm_stdll/tpm_specific.c:3149 tpmtok] ERROR: Tspi_Context_LoadKeyByBlob failed. rc=0x21

0x21 might be TSS_E_PS_KEY_EXISTS: The key already exists in the persistent storage database.

This is quite logical, since token_wrap_key_object() did create the object in the TPM already.

The code for this is as it is for a long time, so I assume that this has not worked for a long time already. I don't know enough about TPM programming to suggest a fix for this.

ifranzki commented 4 years ago

I do see 4 more failures when I run the rsa_tests:

* TESTCASE do_SignVerifyRSA BEGIN RSA PKCS SignRecover and VerifyRecover with test vector 16,
publ_exp='010001', mod_bits='1024', keylen='0'.
* TESTCASE do_SignVerifyRSA FAIL (testcases/crypto/rsa_func.c:809) C_VerifyRecover(), rc=CKR_FUNCTION_FAILED
------
* TESTCASE do_SignVerifyRSA BEGIN RSA PKCS SignRecover and VerifyRecover with test vector 17,
publ_exp='010001', mod_bits='1024', keylen='0'.
* TESTCASE do_SignVerifyRSA FAIL (testcases/crypto/rsa_func.c:809) C_VerifyRecover(), rc=CKR_FUNCTION_FAILED

...

* TESTCASE do_SignVerifyRSA BEGIN RSA PKCS SignRecover and VerifyRecover with test vector 22,
publ_exp='010001', mod_bits='2048', keylen='0'.
* TESTCASE do_SignVerifyRSA FAIL (testcases/crypto/rsa_func.c:809) C_VerifyRecover(), rc=CKR_FUNCTION_FAILED
------
* TESTCASE do_SignVerifyRSA BEGIN RSA PKCS SignRecover and VerifyRecover with test vector 23,
publ_exp='010001', mod_bits='2048', keylen='0'.
* TESTCASE do_SignVerifyRSA FAIL (testcases/crypto/rsa_func.c:809) C_VerifyRecover(), rc=CKR_FUNCTION_FAILED

Those 4 tests are the only 4 test vectors that have a a public exponent of 65537. So basically every SignRecover/VerifyRecover test fails. The same test vectors have been run successfully before without Recover.

They all show:

03/17/2020 16:13:39 39169 [usr/lib/tpm_stdll/tpm_specific.c:3422 tpmtok] ERROR: Tspi_Data_Bind failed. rc=0x3004

This might be: TSS_E_INTERNAL_ERROR: An internal SW error has been detected

The TPM specific token_specific_rsa_verify_recover() just performs a token_specific_rsa_encrypt(), which then performs a Tspi_Data_Bind().

Not sure whats wrong here. I don't know enough about TPM programming to suggest a fix for this.

ifranzki commented 4 years ago

To fix the Wrap/Unwrap issues, I think we need to introduce token specific wrap/unwrap functions, which a token can supply (via struct token_specific_struct) and perform its own wrap/unwrap handling (as it is done for many other functions already).

The Opaque handling in common code's wrap/unwrap handling seems to be broken, and will only work for clear key tokens. Any secure key or opaque key handling should be moved to the token specific implementation. As best, the whole Opaque handling should be removed from common code (if possible).

This will also help to allow the CCA token to fix its broken Wrap/Unwrap handling. Currently the CCA token wraps (encrypts) the secure key blob, but it should rather export/import the secure key under the wrapping key. Not sure if it is that easy, since CCA then needs the wrapping key in EXPORTER/IMPORTER key form.... However, without a token specific wrap/unwrap functions there is no goo way at all to fix this for CCA.