Closed ldts closed 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"?
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]");
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.
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)
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?
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.
@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
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.
@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.
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,
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-----
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
This is an architecture view of what we have implemented and the reason why we have been pushing for these changes.
Will leave the issue open until the PR is merged. thx.
@ldts thanks for the additional information, and the tedious debugging with this good result
code has been merged upstream . will close this now
Thank you, @ldts!
@ldts also from me many thanks!
vow, thanks! you are a very welcoming team, not used to this kind of treatment, feels great :)
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:
Using openssl with the pkcs11.so engine and libtpm2_pkcs11.so.0.0.0 the stack fails at getting the ephemeral key
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.