tpm2-software / tpm2-tss

OSS implementation of the TCG TPM2 Software Stack (TSS2)
https://tpm2-software.github.io
BSD 2-Clause "Simplified" License
748 stars 364 forks source link

Error starting session using the openssl engine - ErrorCode (0x00070001) #2581

Closed ldts closed 1 year ago

ldts commented 1 year ago

I added some traces to track the error when starting the auth session: Every trace is tagged as an ERROR so ignore the type of trace (I just wanted to make sure they showed up)

Using OpenSC's pkcs11-tool with libtpm2_pkcs11.so.0.0.0 everything looks sane:

INFO on line: "406" in file: "src/pkcs11.c": enter "C_GetTokenInfo"                                                  
INFO on line: "406" in file: "src/pkcs11.c": return "C_GetTokenInfo" value: 0                                        
INFO on line: "458" in file: "src/pkcs11.c": enter "C_Login"                                                         
INFO on line: "292" in file: "src/lib/backend_esysdb.c": token parent object handle is 0x40418487                                                                                                                                          
ERROR on line: "355" in file: "src/lib/tpm.c": ------------------------------------------------                                                                                                                                            
ERROR on line: "356" in file: "src/lib/tpm.c":  TPM SESSION START                                       
ERROR on line: "357" in file: "src/lib/tpm.c": ------------------------------------------------                                                                                                                                            
ERROR:esys:src/tss2-esys/api/Esys_StartAuthSession.c:110:Esys_StartAuthSession() 
ERROR:esys:src/tss2-esys/api/Esys_StartAuthSession.c:192:Esys_StartAuthSession_Async()                           
trace:esys:src/tss2-esys/api/Esys_StartAuthSession.c:193:Esys_StartAuthSession_Async() context=0x55cf4bfd3570, tpmKey=40418487, bind=40418487,nonceCaller=(nil), sessionType=00, symmetric=0x7ffeda2cb572,authHash=000b 
trace:esys_crypto:src/tss2-esys/esys_crypto.c:34:iesys_crypto_hash_get_digest_size() call: hashAlg=11 size=0x7ffeda2ca7a0                                                                                                                  
trace:esys_crypto:src/tss2-esys/esys_crypto.c:59:iesys_crypto_hash_get_digest_size() return: *size=32                                                                                                                                      
ERROR:esys_crypto:src/tss2-esys/esys_crypto_ossl.c:945:iesys_cryptossl_get_ecdh_point() CURVE 0x19f                                                                                                                                        
ERROR:esys_crypto:src/tss2-esys/esys_crypto_ossl.c:982:iesys_cryptossl_get_ecdh_point() Get priv key [OK]                                                                                                                                  
ERROR:esys_crypto:src/tss2-esys/esys_crypto_ossl.c:987:iesys_cryptossl_get_ecdh_point() Get pubx [OK]                                                                                                                                      
ERROR:esys_crypto:src/tss2-esys/esys_crypto_ossl.c:992:iesys_cryptossl_get_ecdh_point() Get puby [OK]                                                                                                                                      
ERROR:esys_crypto:src/tss2-esys/esys_crypto_ossl.c:999:iesys_cryptossl_get_ecdh_point() Get ephemeral key [OK]                                                                                                                             
debug:esys_crypto:src/tss2-esys/esys_crypto.c:679:iesys_crypto_KDFe() IESYS KDFe hashAlg: 11 label: SECRET bitLength: 256                                                                                                                  
debug:esys_crypto:src/tss2-esys/esys_crypto.c:682:iesys_crypto_KDFe() partyUInfo (size=32):

Using openssl with the pkcs11.so engine and libtpm2_pkcs11.so.0.0.0 the stack fails at getting the ephemeral key

INFO on line: "434" in file: "src/pkcs11.c": enter "C_OpenSession"
ERROR on line: "98" in file: "src/lib/session.c": Open session with flags 0x4
INFO on line: "434" in file: "src/pkcs11.c": return "C_OpenSession" value: 0
INFO on line: "446" in file: "src/pkcs11.c": enter "C_GetSessionInfo"
INFO on line: "446" in file: "src/pkcs11.c": return "C_GetSessionInfo" value: 0
INFO on line: "458" in file: "src/pkcs11.c": enter "C_Login"
INFO on line: "292" in file: "src/lib/backend_esysdb.c": token parent object handle is 0x40418487
ERROR on line: "355" in file: "src/lib/tpm.c": ------------------------------------------------
ERROR on line: "356" in file: "src/lib/tpm.c":  TPM SESSION START 
ERROR on line: "357" in file: "src/lib/tpm.c": ------------------------------------------------
ERROR:esys:src/tss2-esys/api/Esys_StartAuthSession.c:110:Esys_StartAuthSession() 
ERROR:esys:src/tss2-esys/api/Esys_StartAuthSession.c:192:Esys_StartAuthSession_Async() 
trace:esys:src/tss2-esys/api/Esys_StartAuthSession.c:193:Esys_StartAuthSession_Async() context=0x55931a07f400, tpmKey=40418487, bind=40418487,nonceCaller=(nil), sessionType=00, symmetric=0x7ffc79190ce2,authHash=000b 
trace:esys_crypto:src/tss2-esys/esys_crypto.c:34:iesys_crypto_hash_get_digest_size() call: hashAlg=11 size=0x7ffc7918ff10 
trace:esys_crypto:src/tss2-esys/esys_crypto.c:59:iesys_crypto_hash_get_digest_size() return: *size=32 
ERROR:esys_crypto:src/tss2-esys/esys_crypto_ossl.c:945:iesys_cryptossl_get_ecdh_point() CURVE 0x19f 
ERROR:esys_crypto:src/tss2-esys/esys_crypto_ossl.c:982:iesys_cryptossl_get_ecdh_point() Get priv key [OK] 
ERROR:esys_crypto:src/tss2-esys/esys_crypto_ossl.c:985:iesys_cryptossl_get_ecdh_point() Get pubx error 
ERROR:esys_crypto:src/tss2-esys/esys_crypto_ossl.c:990:iesys_cryptossl_get_ecdh_point() Get puby error 
ERROR:esys_crypto:src/tss2-esys/esys_crypto_ossl.c:997:iesys_cryptossl_get_ecdh_point() ErrorCode (0x00070001) Get ephemeral key 
ERROR:esys:src/tss2-esys/esys_iutil.c:534:iesys_compute_encrypted_salt() During computation of ECC public key. ErrorCode (0x00070001) 
ERROR:esys:src/tss2-esys/api/Esys_StartAuthSession.c:229:Esys_StartAuthSession_Async() Error in parameter encryption. ErrorCode (0x00070001) 
ERROR:esys:src/tss2-esys/api/Esys_StartAuthSession.c:115:Esys_StartAuthSession() Error in async function ErrorCode (0x00070001) 
ERROR on line: "388" in file: "src/lib/tpm.c": Esys_StartAuthSession: esapi:Catch all for all errors not otherwise specified
ERROR on line: "295" in file: "src/lib/backend_esysdb.c": Could not start Auth Session with the TPM.
ERROR on line: "249" in file: "src/lib/session_ctx.c": Error unsealing wrapping key
INFO on line: "458" in file: "src/pkcs11.c": return "C_Login" value: 5

I reported this issue a few weeks back but since the issue was not reproduceable using an openssl provider instead of the engine I moved to using the provider. However curl does not support the provider so I am back to fixing this....karmic justice.

Any help/suggestions debugging this will be much appreciated.

JuergenReppSIT commented 1 year ago

pubx and puby are computed directly after the creation of the ephemeral key. But I could not see the error messages from the current esys source of this function? What function call did produce the error message "Get pubx error"?

ldts commented 1 year ago

sorry, I added those traces manually in my work area....it is redundant but I wanted to know where we were failing

    if (!EVP_PKEY_get_bn_param(eph_pkey, OSSL_PKEY_PARAM_PRIV_KEY, &eph_priv_key))
        LOG_ERROR("Get priv key error");
    else
        LOG_ERROR("Get priv key [OK]");

    if (!EVP_PKEY_get_bn_param(eph_pkey, OSSL_PKEY_PARAM_EC_PUB_X, &bn_x))
        LOG_ERROR("Get pubx error");
    else
        LOG_ERROR("Get pubx [OK]");

    if (!EVP_PKEY_get_bn_param(eph_pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &bn_y))
        LOG_ERROR("Get puby error");
    else
        LOG_ERROR("Get puby [OK]");

    if (!EVP_PKEY_get_bn_param(eph_pkey, OSSL_PKEY_PARAM_PRIV_KEY, &eph_priv_key)
            || !EVP_PKEY_get_bn_param(eph_pkey, OSSL_PKEY_PARAM_EC_PUB_X, &bn_x)
            || !EVP_PKEY_get_bn_param(eph_pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &bn_y)) {
        goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Get ephemeral key", cleanup);
    } else
        LOG_ERROR("Get ephemeral key [OK]");
JuergenReppSIT commented 1 year ago

The function EVP_PKEY_get_bn_param was called in the OpenSSL 3 part of the function but the tss engine was not ported to OpenSSL 3.

ldts commented 1 year ago

ah, um I wonder why it seems to work for the private key which adds to the confusion.... would you know? also I forgot to add, I am using the pkcs11.so engine (not the tss one)

JuergenReppSIT commented 1 year ago

So the sequence of the function calls with the same curve in both cases is: EVP_PKEY_CTX_new_id, EVP_PKEY_CTX_set_ec_paramgen_curve_nid, EVP_PKEY_get_bn_param(eph_pkey, OSSL_PKEY_PARAM_EC_PUB_X, &bn_x) with one ok and one fail. It looks like the internal state of openssl is corrupted. Would it be possible to test your application with valgrind?

ldts commented 1 year ago

um, I believe the issue is in openssl/crypto/evn/ctrl_params_translate.c

There is no translation for legacy OSSL_PKEY_PARAM_EC_PUB_X or OSSL_PKEY_PARAM_EC_PUB_Y

static const struct translation_st evp_pkey_translations[] = {
    /*
     * The following contain no ctrls, they are exclusively here to extract
     * key payloads from legacy keys, using OSSL_PARAMs, and rely entirely
     * on |fixup_args| to pass the actual data.  The |fixup_args| should
     * expect to get the EVP_PKEY pointer through |ctx->p2|.
     */

    /* DH, DSA & EC */
    { GET, -1, -1, -1, 0, NULL, NULL,
      OSSL_PKEY_PARAM_GROUP_NAME, OSSL_PARAM_UTF8_STRING,
      get_payload_group_name },
    { GET, -1, -1, -1, 0, NULL, NULL,
      OSSL_PKEY_PARAM_PRIV_KEY, OSSL_PARAM_UNSIGNED_INTEGER,
      get_payload_private_key },
    { GET, -1, -1, -1, 0, NULL, NULL,
      OSSL_PKEY_PARAM_PUB_KEY,
      0/* no data type, let get_payload_public_key() handle that */,
      get_payload_public_key }

For reference my test code is just this script (thanks for asking @JuergenReppSIT )

#!/bin/bash

shopt -s expand_aliases

export LD_LIBRARY_PATH=/home/jramirez/Src/install/usr/local/lib:/home/jramirez/Src/install/usr/local/lib64

alias tpm2pkcs11='LD_LIBRARY_PATH=/home/jramirez/Src/install/usr/local/lib TPM2_PKCS11_STORE=/tmp/db/ TSS2_LOG=fapi+NONE OPENSSL_CONF=/home/jramirez/Src/import/scripts/certificate/engine.cnf pkcs11-tool --module /home/jramirez/Src/import/tpm2-pkcs11/src/.libs/libtpm2_pkcs11.so.0.0.0'

read -p "Delete SQLLite database" foo
rm /tmp/db//tpm2_pkcs11.sqlite3
sync

read -p "Init token "
tpm2pkcs11  --init-token --label aktualizr --so-pin 1111

read -p "Init pin "
tpm2pkcs11 --init-pin --token-label aktualizr --so-pin 1111 --pin 1111

read -p "Keypair 01 "
tpm2pkcs11 --keypairgen --key-type EC:prime256v1 --token-label aktualizr --id 01 --label tls  --pin 1111

read -p "Create certificate"
TPM2_PKCS11_STORE=/tmp/db/  TSS2_LOG=fapi+NONE OPENSSL_CONF=/home/jramirez/Src/import/scripts/certificate/engine.cnf openssl req -new -engine pkcs11 -keyform engine -key "pkcs11:token=aktualizr;object=tls;type=private;pin-value=1111"

with the config

openssl_conf = oc

[oc]
engines = eng

[eng]
pkcs11 = p11

[p11]
engine_id = pkcs11
dynamic_path = /usr/lib/x86_64-linux-gnu/engines-3/pkcs11.so
MODULE_PATH = /home/jramirez/Src/import/tpm2-pkcs11/src/.libs/libtpm2_pkcs11.so.0.0.0
PIN = 1111

[req]
distinguished_name = dn
req_extensions = ext
default_md = sha256
prompt = no

[dn]
CN=5312a33e-5c6c-460b-aae9-5d1bb59d5011
OU=foo

[ext]
extendedKeyUsage=critical, clientAuth
keyUsage=critical, digitalSignature

The conversion for the private key is pretty simple (just a bignum) hence why it works....but this needs more work for the EC_POINT x and y components. I'll try to have a look.

ldts commented 1 year ago

@gotthardp was this PR tested with OpenSSL 3.0 and EC keys? or was it more some kind of preparation work? It would help me understand where we are at.

https://github.com/tpm2-software/tpm2-tss/commit/362fda1daa398da2944e76013c215500761d46a5

ldts commented 1 year ago

ok I have a fix. will post it to openssl and share it here after I tidy it up a bit.

would have been nice to have a comment indicating that this code was broken.

gotthardp commented 1 year ago

@ldts thanks for the fix. We didn't know the code was broken. We always welcome users to test the release candidates in their environment and report problems.

ldts commented 1 year ago

This has not been fully tested (there will be issues with keys with padding) but we can now generate valid certificates using EC keys:

i,e this is now supported witm tpm2_pkcs11:

openssl req -new -engine pkcs11 -keyform engine -key "pkcs11:token=aktualizr;object=tls;type=private;pin-value=1111"

The OpenSSL missing bits below:

From: Jorge Ramirez-Ortiz <jorge@foundries.io>
Date: Wed, 8 Mar 2023 12:50:25 +0100
Subject: [PATCH] translation: EC legacy keys, handle OSSL_PKEY_PARAM_EC_PUB_*

---
 crypto/evp/ctrl_params_translate.c | 72 ++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/crypto/evp/ctrl_params_translate.c b/crypto/evp/ctrl_params_translate.c
index 7d2f501dfb..d223efea95 100644
--- a/crypto/evp/ctrl_params_translate.c
+++ b/crypto/evp/ctrl_params_translate.c
@@ -1644,6 +1644,72 @@ static int get_payload_public_key(enum state state,
     return ret;
 }

+static int get_payload_public_key_ec(enum state state,
+                                     const struct translation_st* translation,
+                                     struct translation_ctx_st* ctx)
+{
+    EVP_PKEY* pkey = ctx->p2;
+    unsigned char* buf = NULL;
+    BIGNUM* bn = NULL;
+    int ret = 0;
+
+    ctx->p2 = NULL;
+    switch (EVP_PKEY_get_base_id(pkey)) {
+#ifndef OPENSSL_NO_EC
+        case EVP_PKEY_EC:
+            if (ctx->params->data_type != OSSL_PARAM_UNSIGNED_INTEGER)
+                return 0;
+
+            const EC_KEY* eckey = EVP_PKEY_get0_EC_KEY(pkey);
+            BN_CTX* bnctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(eckey));
+            const EC_GROUP* ecg = EC_KEY_get0_group(eckey);
+            const EC_POINT* point = EC_KEY_get0_public_key(eckey);
+            if (bnctx == NULL)
+                return 0;
+            size_t len = EC_POINT_point2buf(ecg, point,
+                                            POINT_CONVERSION_UNCOMPRESSED,
+                                            &buf, bnctx);
+            if (!len) {
+                ret = 0;
+                goto out;
+            }
+
+            /* skip tag */
+            len = len - 1;
+
+            if (!memcmp(ctx->params->key, OSSL_PKEY_PARAM_EC_PUB_X,
+                        strnlen(OSSL_PKEY_PARAM_EC_PUB_X, 2))) {
+                bn = BN_new();
+                BN_bin2bn(buf + 1, len / 2, bn);
+            }
+
+            if (!memcmp(ctx->params->key, OSSL_PKEY_PARAM_EC_PUB_Y,
+                             strnlen(OSSL_PKEY_PARAM_EC_PUB_Y, 2))) {
+                bn = BN_new();
+                BN_bin2bn(buf + 1 + len / 2, len / 2, bn);
+            }
+
+            if (bn)
+                ctx->p2 = bn;
+
+            BN_CTX_free(bnctx);
+            break;
+#endif
+        default:
+            ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEY_TYPE);
+            return 0;
+    }
+
+    if (ctx->p2)
+        ret = default_fixup_args(state, translation, ctx);
+out:
+    OPENSSL_free(buf);
+    if (bn)
+        BN_free(bn);
+
+    return ret;
+}
+
 static int get_payload_bn(enum state state,
                           const struct translation_st *translation,
                           struct translation_ctx_st *ctx, const BIGNUM *bn)
@@ -2295,6 +2361,12 @@ static const struct translation_st evp_pkey_translations[] = {
       OSSL_PKEY_PARAM_PUB_KEY,
       0 /* no data type, let get_payload_public_key() handle that */,
       get_payload_public_key },
+    { GET, -1, -1, -1, 0, NULL, NULL,
+        OSSL_PKEY_PARAM_EC_PUB_X, OSSL_PARAM_UNSIGNED_INTEGER,
+        get_payload_public_key_ec },
+    { GET, -1, -1, -1, 0, NULL, NULL,
+        OSSL_PKEY_PARAM_EC_PUB_Y, OSSL_PARAM_UNSIGNED_INTEGER,
+        get_payload_public_key_ec },

     /* DH and DSA */
     { GET, -1, -1, -1, 0, NULL, NULL,
ldts commented 1 year ago

Another thing I am noticing after the certificate is generated is the error line in the trace below (the test is the bash script I posted yesterday in this thread)

I have checked the certificate and the public key corresponds with the public key in the pkcs11 DB so I believe the certificate to be correct. I still need to check the reason for that error message...maybe it is just a warning, not sure.

WARNING: Getting tokens from fapi backend failed.
Key pair generated:
Private Key Object; EC
  label:      tls
  ID:         01
  Usage:      decrypt, sign, derive
  Access:     sensitive, always sensitive, never extractable, local
  Allowed mechanisms: ECDSA,ECDSA-SHA1,ECDSA-SHA256,ECDSA-SHA384,ECDSA-SHA512,ECDH1-DERIVE
Public Key Object; EC  EC_POINT 256 bits
  EC_POINT:   044104df5b4d955c3b22b282bf487fa2e3ce4ea3b474e7fe5866ce95b3271974ab98e7bdd3b61415d0259056137c9b8c154f7302d7e815ab4b0be26a019cf2e25d62d1
  EC_PARAMS:  06082a8648ce3d030107
  label:      tls
  ID:         01
  Usage:      encrypt, verify, derive
  Access:     local

Create certificateEngine "pkcs11" set.
WARNING: Getting tokens from fapi backend failed.
ERROR: EVP_PKEY_fromdata_init: %s: error:03000096:digital envelope routines::operation not supported for this keytype
-----BEGIN CERTIFICATE REQUEST-----
MIIBMjCB2AIBADA9MS0wKwYDVQQDDCQ1MzEyYTMzZS01YzZjLTQ2MGItYWFlOS01
ZDFiYjU5ZDUwMTExDDAKBgNVBAsMA2ZvbzBZMBMGByqGSM49AgEGCCqGSM49AwEH
A0IABN9bTZVcOyKygr9If6Ljzk6jtHTn/lhmzpWzJxl0q5jnvdO2FBXQJZBWE3yb
jBVPcwLX6BWrSwviagGc8uJdYtGgOTA3BgkqhkiG9w0BCQ4xKjAoMBYGA1UdJQEB
/wQMMAoGCCsGAQUFBwMCMA4GA1UdDwEB/wQEAwIHgDAKBggqhkjOPQQDAgNJADBG
AiEA08kUjM8kQnlg+5xA79EiG1lmEEcBBrWAraAg3evmQVcCIQDbidYJSToyc3fX
/xs2bhgJKQa667/HBLZTj+9SVItV8A==
-----END CERTIFICATE REQUEST-----
ldts commented 1 year ago

Just for completeness, these are the configurations I have tested to generate a CSR, a million mile view diagram - this PR fixing the issue when using the pkcs11 engine instead of the provider which works unchanged

configurations-tested

ldts commented 1 year ago

This is an architecture view of what we have implemented and the reason why we have been pushing for these changes.

lmp-device-arch

Will leave the issue open until the PR is merged. thx.

JuergenReppSIT commented 1 year ago

@ldts thanks for the additional information, and the tedious debugging with this good result

ldts commented 1 year ago

code has been merged upstream . will close this now

gotthardp commented 1 year ago

Thank you, @ldts!

JuergenReppSIT commented 1 year ago

@ldts also from me many thanks!

ldts commented 1 year ago

vow, thanks! you are a very welcoming team, not used to this kind of treatment, feels great :)