diff --git a/.cirrus.yml b/.cirrus.yml index 613a9a9..197a379 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,6 +1,6 @@ task: freebsd_instance: - image_family: freebsd-14-0 + image_family: freebsd-14-1 env: PKG_CONFIG_PATH: /usr/local/lib/pkgconfig LD_LIBRARY_PATH: /usr/local/lib diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 232dde9..b692115 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -29,15 +29,15 @@ jobs: sudo apt-get install --yes autoconf-archive libtss2-dev - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/gcc-distcheck.yml b/.github/workflows/gcc-distcheck.yml index 04ffdf9..b870b3e 100644 --- a/.github/workflows/gcc-distcheck.yml +++ b/.github/workflows/gcc-distcheck.yml @@ -51,7 +51,7 @@ jobs: TPM2OPENSSL_TCTI: ${{ env.TCTI_ADDRESS }} - name: Submit code coverage - uses: codecov/codecov-action@v1.2.1 + uses: codecov/codecov-action@v5 - name: Check the distribution # AM_DISTCHECK_CONFIGURE_FLAGS are not ready for clang and asan diff --git a/.gitignore b/.gitignore index a6560a8..8280538 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ test/.dirstamp test/*.o test/*.trs test/selftest +test/rand_threads test/ec_genpkey_store_load test/ec_genpkey_x509_csr test/rsa_genpkey_decrypt diff --git a/Makefile.am b/Makefile.am index 994a8e3..099dd1e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -58,6 +58,12 @@ test_selftest_CFLAGS = $(COMMON_CFLAGS) test_selftest_LDADD = $(CRYPTO_LIBS) test_selftest_LDFLAGS = $(COMMON_LDFLAGS) +check_PROGRAMS += test/rand_threads +test_rand_threads_SOURCES = test/rand_threads.c +test_rand_threads_CFLAGS = $(COMMON_CFLAGS) +test_rand_threads_LDADD = $(CRYPTO_LIBS) +test_rand_threads_LDFLAGS = $(COMMON_LDFLAGS) + check_PROGRAMS += test/ec_genpkey_store_load test_ec_genpkey_store_load_SOURCES = test/ec_genpkey_store_load.c test_ec_genpkey_store_load_CFLAGS = $(COMMON_CFLAGS) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index fb3a3bb..98f3e88 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -5,9 +5,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) ## [1.3.0] - 2024-xx-yy ### Added -- Added support for RSA-OAEP decryption -- Added Parent to textual information printed by 'openssl pkey -text' +- Added support for RSA-OAEP decryption. +- Added Parent to textual information printed by 'openssl pkey -text'. ### Fixed +- Fixed multi-threaded operation, preventing the 'Esys called in bad sequence' + errors (thanks to @Danigaralfo, @famez, and @AndreasFuchsTPM). - Fixed handling of absent emptyAuth value in the TSS2 PRIVATE KEY file. - Set authorization value of newly generated keys. This allows users of the C API to direcly use just generated EVP_PKEY. diff --git a/src/tpm2-provider-asymcipher-rsa.c b/src/tpm2-provider-asymcipher-rsa.c index d0433bb..9047194 100644 --- a/src/tpm2-provider-asymcipher-rsa.c +++ b/src/tpm2-provider-asymcipher-rsa.c @@ -20,6 +20,7 @@ typedef struct tpm2_rsa_asymcipher_ctx_st TPM2_RSA_ASYMCIPHER_CTX; struct tpm2_rsa_asymcipher_ctx_st { const OSSL_CORE_HANDLE *core; + CRYPTO_RWLOCK *esys_lock; ESYS_CONTEXT *esys_ctx; TPM2_CAPABILITY capability; TPMT_RSA_DECRYPT decrypt; @@ -47,6 +48,7 @@ static void return NULL; actx->core = cprov->core; + actx->esys_lock = cprov->esys_lock; actx->esys_ctx = cprov->esys_ctx; actx->capability = cprov->capability; actx->decrypt.scheme = TPM2_ALG_RSAES; @@ -78,9 +80,12 @@ decrypt_message(TPM2_RSA_ASYMCIPHER_CTX *actx, cipher.size = inlen; memcpy(cipher.buffer, in, inlen); + if (!CRYPTO_THREAD_write_lock(actx->esys_lock)) + return 0; r = Esys_RSA_Decrypt(actx->esys_ctx, actx->pkey->object, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &cipher, &actx->decrypt, &label, &actx->message); + CRYPTO_THREAD_unlock(actx->esys_lock); TPM2_CHECK_RC(actx->core, r, TPM2_ERR_CANNOT_DECRYPT, return 0); return 1; @@ -114,9 +119,7 @@ rsa_asymcipher_freectx(void *ctx) if (actx == NULL) return; - if (actx->message != NULL) - free(actx->message); - + free(actx->message); OPENSSL_clear_free(actx, sizeof(TPM2_RSA_ASYMCIPHER_CTX)); } diff --git a/src/tpm2-provider-cipher.c b/src/tpm2-provider-cipher.c index efd5929..84db9bf 100644 --- a/src/tpm2-provider-cipher.c +++ b/src/tpm2-provider-cipher.c @@ -14,6 +14,7 @@ typedef struct tpm2_cipher_ctx_st TPM2_CIPHER_CTX; struct tpm2_cipher_ctx_st { const OSSL_CORE_HANDLE *core; + CRYPTO_RWLOCK *esys_lock; ESYS_CONTEXT *esys_ctx; TPM2_CAPABILITY capability; ESYS_TR object; @@ -46,6 +47,7 @@ tpm2_cipher_all_newctx(void *provctx, return NULL; cctx->core = cprov->core; + cctx->esys_lock = cprov->esys_lock; cctx->esys_ctx = cprov->esys_ctx; cctx->capability = cprov->capability; cctx->algorithm = algdef; @@ -82,7 +84,7 @@ tpm2_cipher_freectx(void *ctx) if (cctx == NULL) return; - Esys_FlushContext(cctx->esys_ctx, cctx->object); + tpm2_esys_flush_context(cctx->esys_lock, cctx->esys_ctx, cctx->object); OPENSSL_clear_free(cctx->ivector, sizeof(TPM2B_IV)); OPENSSL_clear_free(cctx, sizeof(TPM2_CIPHER_CTX)); @@ -127,18 +129,21 @@ tpm2_load_external_key(TPM2_CIPHER_CTX *cctx, ESYS_TR parent, TPM2B_PUBLIC *keyPublic = NULL; TPM2B_PRIVATE *keyPrivate = NULL; + if (!CRYPTO_THREAD_write_lock(cctx->esys_lock)) + return 0; /* older TPM2 chips do not support Esys_CreateLoaded */ r = Esys_Create(cctx->esys_ctx, parent, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &inSensitive, &inPublic, &outside_info, &creation_pcr, &keyPrivate, &keyPublic, NULL, NULL, NULL); - TPM2_CHECK_RC(cctx->core, r, TPM2_ERR_CANNOT_CREATE_KEY, return 0); - - r = Esys_Load(cctx->esys_ctx, parent, - ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, - keyPrivate, keyPublic, &cctx->object); - free(keyPublic); - free(keyPrivate); + if (!r) { + r = Esys_Load(cctx->esys_ctx, parent, + ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, + keyPrivate, keyPublic, &cctx->object); + free(keyPublic); + free(keyPrivate); + } + CRYPTO_THREAD_unlock(cctx->esys_lock); TPM2_CHECK_RC(cctx->core, r, TPM2_ERR_CANNOT_CREATE_KEY, return 0); return 1; @@ -158,12 +163,13 @@ tpm2_cipher_init(TPM2_CIPHER_CTX *cctx, DBG("CIPHER %sCRYPT_INIT load key %zu bytes\n", cctx->decrypt ? "DE" : "EN", keylen); - if (!tpm2_build_primary(cctx->core, cctx->esys_ctx, cctx->capability.algorithms, + if (!tpm2_build_primary(cctx->core, cctx->esys_lock, cctx->esys_ctx, + cctx->capability.algorithms, ESYS_TR_RH_NULL, NULL, &parent)) return 0; res = tpm2_load_external_key(cctx, parent, key, keylen); - Esys_FlushContext(cctx->esys_ctx, parent); + tpm2_esys_flush_context(cctx->esys_lock, cctx->esys_ctx, parent); if (!res) return 0; } @@ -212,6 +218,8 @@ encrypt_decrypt(TPM2_CIPHER_CTX *cctx, { TSS2_RC r; + if (!CRYPTO_THREAD_write_lock(cctx->esys_lock)) + return 0; r = Esys_EncryptDecrypt2(cctx->esys_ctx, cctx->object, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &cctx->buffer, cctx->decrypt, TPM2_ALG_NULL, @@ -222,6 +230,7 @@ encrypt_decrypt(TPM2_CIPHER_CTX *cctx, cctx->decrypt, TPM2_ALG_NULL, cctx->ivector, &cctx->buffer, outbuff, ivector); } + CRYPTO_THREAD_unlock(cctx->esys_lock); return r; } diff --git a/src/tpm2-provider-core.c b/src/tpm2-provider-core.c index 41305ce..c662222 100644 --- a/src/tpm2-provider-core.c +++ b/src/tpm2-provider-core.c @@ -100,6 +100,34 @@ tpm2_list_params(const char *text, const OSSL_PARAM params[]) fprintf(stderr, " ]\n"); } +TSS2_RC +tpm2_esys_tr_close(CRYPTO_RWLOCK *esys_lock, ESYS_CONTEXT *esys_ctx, ESYS_TR *object) +{ + TSS2_RC r; + + if (!CRYPTO_THREAD_write_lock(esys_lock)) + return TSS2_ESYS_RC_GENERAL_FAILURE; + + r = Esys_TR_Close(esys_ctx, object); + + CRYPTO_THREAD_unlock(esys_lock); + return r; +} + +TSS2_RC +tpm2_esys_flush_context(CRYPTO_RWLOCK *esys_lock, ESYS_CONTEXT *esys_ctx, ESYS_TR flush_handle) +{ + TSS2_RC r; + + if (!CRYPTO_THREAD_write_lock(esys_lock)) + return TSS2_ESYS_RC_GENERAL_FAILURE; + + r = Esys_FlushContext(esys_ctx, flush_handle); + + CRYPTO_THREAD_unlock(esys_lock); + return r; +} + int tpm2_supports_algorithm(const TPMS_CAPABILITY_DATA *caps, TPM2_ALG_ID algorithm) { diff --git a/src/tpm2-provider-decoder-tss2.c b/src/tpm2-provider-decoder-tss2.c index c50e950..63d6d48 100644 --- a/src/tpm2-provider-decoder-tss2.c +++ b/src/tpm2-provider-decoder-tss2.c @@ -20,6 +20,7 @@ typedef struct tpm2_tss2_decoder_ctx_st TPM2_TSS2_DECODER_CTX; struct tpm2_tss2_decoder_ctx_st { const OSSL_CORE_HANDLE *core; OSSL_LIB_CTX *libctx; + CRYPTO_RWLOCK *esys_lock; ESYS_CONTEXT *esys_ctx; TPM2_CAPABILITY capability; TPM2B_DIGEST parentAuth; @@ -42,6 +43,7 @@ tpm2_tss2_decoder_newctx(void *provctx) dctx->core = cprov->core; dctx->libctx = cprov->libctx; + dctx->esys_lock = cprov->esys_lock; dctx->esys_ctx = cprov->esys_ctx; dctx->capability = cprov->capability; return dctx; @@ -70,16 +72,19 @@ decode_privkey(TPM2_TSS2_DECODER_CTX *dctx, TPM2_PKEY *pkey, if (pkey->data.parent && pkey->data.parent != TPM2_RH_OWNER) { DBG("TSS2 DECODER LOAD parent: persistent 0x%x\n", pkey->data.parent); - if (!tpm2_load_parent(pkey->core, pkey->esys_ctx, + if (!tpm2_load_parent(pkey->core, pkey->esys_lock, pkey->esys_ctx, pkey->data.parent, &dctx->parentAuth, &parent)) goto error1; } else { DBG("TSS2 DECODER LOAD parent: primary 0x%x\n", TPM2_RH_OWNER); - if (!tpm2_build_primary(pkey->core, pkey->esys_ctx, pkey->capability.algorithms, + if (!tpm2_build_primary(pkey->core, pkey->esys_lock, pkey->esys_ctx, + pkey->capability.algorithms, ESYS_TR_RH_OWNER, &dctx->parentAuth, &parent)) goto error1; } + if (!CRYPTO_THREAD_write_lock(pkey->esys_lock)) + goto error1; r = Esys_Load(pkey->esys_ctx, parent, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &pkey->data.priv, &pkey->data.pub, &pkey->object); @@ -89,11 +94,15 @@ decode_privkey(TPM2_TSS2_DECODER_CTX *dctx, TPM2_PKEY *pkey, else Esys_FlushContext(pkey->esys_ctx, parent); + CRYPTO_THREAD_unlock(pkey->esys_lock); TPM2_CHECK_RC(pkey->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto error1); } else if (pkey->data.privatetype == KEY_TYPE_HANDLE) { + if (!CRYPTO_THREAD_write_lock(pkey->esys_lock)) + goto error1; r = Esys_TR_FromTPMPublic(pkey->esys_ctx, pkey->data.handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &pkey->object); + CRYPTO_THREAD_unlock(pkey->esys_lock); TPM2_CHECK_RC(pkey->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto error1); } else { TPM2_ERROR_raise(pkey->core, TPM2_ERR_INPUT_CORRUPTED); @@ -111,7 +120,10 @@ decode_privkey(TPM2_TSS2_DECODER_CTX *dctx, TPM2_PKEY *pkey, } userauth.size = plen; + if (!CRYPTO_THREAD_write_lock(pkey->esys_lock)) + goto error2; r = Esys_TR_SetAuth(dctx->esys_ctx, pkey->object, &userauth); + CRYPTO_THREAD_unlock(pkey->esys_lock); TPM2_CHECK_RC(dctx->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto error2); } @@ -123,9 +135,9 @@ decode_privkey(TPM2_TSS2_DECODER_CTX *dctx, TPM2_PKEY *pkey, return keytype; error2: if (pkey->data.privatetype == KEY_TYPE_HANDLE) - Esys_TR_Close(pkey->esys_ctx, &pkey->object); + tpm2_esys_tr_close(pkey->esys_lock, pkey->esys_ctx, &pkey->object); else - Esys_FlushContext(pkey->esys_ctx, pkey->object); + tpm2_esys_flush_context(pkey->esys_lock, pkey->esys_ctx, pkey->object); error1: pkey->object = ESYS_TR_NONE; return NULL; @@ -156,6 +168,7 @@ tpm2_tss2_decoder_decode(void *ctx, OSSL_CORE_BIO *cin, int selection, goto error2; pkey->core = dctx->core; + pkey->esys_lock = dctx->esys_lock; pkey->esys_ctx = dctx->esys_ctx; pkey->capability = dctx->capability; pkey->object = ESYS_TR_NONE; @@ -188,9 +201,9 @@ tpm2_tss2_decoder_decode(void *ctx, OSSL_CORE_BIO *cin, int selection, error1: if (pkey->object != ESYS_TR_NONE) { if (pkey->data.privatetype == KEY_TYPE_HANDLE) - Esys_TR_Close(pkey->esys_ctx, &pkey->object); + tpm2_esys_tr_close(pkey->esys_lock, pkey->esys_ctx, &pkey->object); else - Esys_FlushContext(pkey->esys_ctx, pkey->object); + tpm2_esys_flush_context(pkey->esys_lock, pkey->esys_ctx, pkey->object); } OPENSSL_clear_free(pkey, sizeof(TPM2_PKEY)); return res; diff --git a/src/tpm2-provider-digest.c b/src/tpm2-provider-digest.c index 5d83cf6..d99f972 100644 --- a/src/tpm2-provider-digest.c +++ b/src/tpm2-provider-digest.c @@ -14,6 +14,7 @@ tpm2_hash_sequence_init(TPM2_HASH_SEQUENCE *seq, TPM2_PROVIDER_CTX *cprov, TPM2_ALG_ID algin) { seq->core = cprov->core; + seq->esys_lock = cprov->esys_lock; seq->esys_ctx = cprov->esys_ctx; seq->algorithm = algin; seq->handle = ESYS_TR_NONE; @@ -23,7 +24,7 @@ void tpm2_hash_sequence_flush(TPM2_HASH_SEQUENCE *seq) { if (seq->handle != ESYS_TR_NONE) - Esys_FlushContext(seq->esys_ctx, seq->handle); + tpm2_esys_flush_context(seq->esys_lock, seq->esys_ctx, seq->handle); } int @@ -33,14 +34,18 @@ tpm2_hash_sequence_dup(TPM2_HASH_SEQUENCE *seq, const TPM2_HASH_SEQUENCE *src) TSS2_RC r; seq->core = src->core; + seq->esys_lock = src->esys_lock; seq->esys_ctx = src->esys_ctx; seq->algorithm = src->algorithm; if (src->handle != ESYS_TR_NONE) { + if (!CRYPTO_THREAD_write_lock(seq->esys_lock)) + return 0; /* duplicate the sequence */ r = Esys_ContextSave(src->esys_ctx, src->handle, &context); - TPM2_CHECK_RC(src->core, r, TPM2_ERR_CANNOT_DUPLICATE, goto error); - r = Esys_ContextLoad(seq->esys_ctx, context, &seq->handle); + if (!r) + r = Esys_ContextLoad(seq->esys_ctx, context, &seq->handle); + CRYPTO_THREAD_unlock(seq->esys_lock); TPM2_CHECK_RC(seq->core, r, TPM2_ERR_CANNOT_DUPLICATE, goto error); free(context); } else { @@ -64,8 +69,11 @@ tpm2_hash_sequence_start(TPM2_HASH_SEQUENCE *seq) seq->buffer.size = 0; + if (!CRYPTO_THREAD_write_lock(seq->esys_lock)) + return 0; r = Esys_HashSequenceStart(seq->esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &null_auth, seq->algorithm, &seq->handle); + CRYPTO_THREAD_unlock(seq->esys_lock); TPM2_CHECK_RC(seq->core, r, TPM2_ERR_CANNOT_HASH, return 0); return 1; @@ -94,9 +102,12 @@ tpm2_hash_sequence_update(TPM2_HASH_SEQUENCE *seq, if (seq->buffer.size < TPM2_MAX_DIGEST_BUFFER) return 1; /* wait for more data */ + if (!CRYPTO_THREAD_write_lock(seq->esys_lock)) + return 0; r = Esys_SequenceUpdate(seq->esys_ctx, seq->handle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &seq->buffer); seq->buffer.size = 0; + CRYPTO_THREAD_unlock(seq->esys_lock); TPM2_CHECK_RC(seq->core, r, TPM2_ERR_CANNOT_HASH, return 0); } @@ -110,15 +121,21 @@ tpm2_hash_sequence_complete(TPM2_HASH_SEQUENCE *seq, TSS2_RC r; if (seq->buffer.size > 0) { + if (!CRYPTO_THREAD_write_lock(seq->esys_lock)) + return 0; r = Esys_SequenceUpdate(seq->esys_ctx, seq->handle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &seq->buffer); seq->buffer.size = 0; + CRYPTO_THREAD_unlock(seq->esys_lock); TPM2_CHECK_RC(seq->core, r, TPM2_ERR_CANNOT_HASH, return 0); } + if (!CRYPTO_THREAD_write_lock(seq->esys_lock)) + return 0; r = Esys_SequenceComplete(seq->esys_ctx, seq->handle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, NULL, ESYS_TR_RH_OWNER, digest, validation); + CRYPTO_THREAD_unlock(seq->esys_lock); TPM2_CHECK_RC(seq->core, r, TPM2_ERR_CANNOT_HASH, return 0); /* the update may be called again to sign another data block */ @@ -138,9 +155,12 @@ tpm2_hash_sequence_hash(TPM2_HASH_SEQUENCE *seq, if (data != NULL) memcpy(seq->buffer.buffer, data, datalen); + if (!CRYPTO_THREAD_write_lock(seq->esys_lock)) + return 0; r = Esys_Hash(seq->esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &seq->buffer, seq->algorithm, ESYS_TR_RH_OWNER, digest, validation); + CRYPTO_THREAD_unlock(seq->esys_lock); TPM2_CHECK_RC(seq->core, r, TPM2_ERR_CANNOT_HASH, return 0); } else { /* too much data, we need a full sequence hashing */ diff --git a/src/tpm2-provider-digest.h b/src/tpm2-provider-digest.h index b115522..f46f1f1 100644 --- a/src/tpm2-provider-digest.h +++ b/src/tpm2-provider-digest.h @@ -10,6 +10,7 @@ typedef struct tpm2_hash_sequence_st TPM2_HASH_SEQUENCE; struct tpm2_hash_sequence_st { const OSSL_CORE_HANDLE *core; + CRYPTO_RWLOCK *esys_lock; ESYS_CONTEXT *esys_ctx; TPM2_ALG_ID algorithm; ESYS_TR handle; diff --git a/src/tpm2-provider-keyexch.c b/src/tpm2-provider-keyexch.c index 4ee0cfe..e749c90 100644 --- a/src/tpm2-provider-keyexch.c +++ b/src/tpm2-provider-keyexch.c @@ -16,6 +16,7 @@ typedef struct tpm2_keyexch_ctx_st TPM2_KEYEXCH_CTX; struct tpm2_keyexch_ctx_st { const OSSL_CORE_HANDLE *core; OSSL_LIB_CTX *libctx; + CRYPTO_RWLOCK *esys_lock; ESYS_CONTEXT *esys_ctx; TPM2_PKEY *pkey; TPM2B_ECC_POINT peer; @@ -48,6 +49,7 @@ tpm2_keyexch_newctx(void *provctx) kexc->core = cprov->core; kexc->libctx = cprov->libctx; + kexc->esys_lock = cprov->esys_lock; kexc->esys_ctx = cprov->esys_ctx; return kexc; } @@ -110,9 +112,12 @@ tpm2_keyexch_derive_kdf(TPM2_KEYEXCH_CTX *kexc, unsigned char *secret, return 0; } + if (!CRYPTO_THREAD_write_lock(kexc->esys_lock)) + return 0; r = Esys_ECDH_ZGen(kexc->esys_ctx, kexc->pkey->object, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &kexc->peer, &outPoint); + CRYPTO_THREAD_unlock(kexc->esys_lock); TPM2_CHECK_RC(kexc->core, r, TPM2_ERR_CANNOT_GENERATE, return 0); if ((kdf = EVP_KDF_fetch(kexc->libctx, kexc->kdf_name, kexc->kdf_propq)) == NULL @@ -146,9 +151,12 @@ tpm2_keyexch_derive_plain(TPM2_KEYEXCH_CTX *kexc, unsigned char *secret, DBG("KEYEXCH DERIVE plain\n"); + if (!CRYPTO_THREAD_write_lock(kexc->esys_lock)) + return 0; r = Esys_ECDH_ZGen(kexc->esys_ctx, kexc->pkey->object, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &kexc->peer, &outPoint); + CRYPTO_THREAD_unlock(kexc->esys_lock); TPM2_CHECK_RC(kexc->core, r, TPM2_ERR_CANNOT_GENERATE, return 0); /* shared value is the x-coordinate */ diff --git a/src/tpm2-provider-keymgmt-ec.c b/src/tpm2-provider-keymgmt-ec.c index 15609f9..e207ec6 100644 --- a/src/tpm2-provider-keymgmt-ec.c +++ b/src/tpm2-provider-keymgmt-ec.c @@ -42,6 +42,7 @@ typedef struct tpm2_ecgen_ctx_st TPM2_ECGEN_CTX; struct tpm2_ecgen_ctx_st { const OSSL_CORE_HANDLE *core; + CRYPTO_RWLOCK *esys_lock; ESYS_CONTEXT *esys_ctx; TPM2_CAPABILITY capability; TPM2_HANDLE parentHandle; @@ -82,6 +83,7 @@ tpm2_ec_keymgmt_new(void *provctx) } pkey->core = cprov->core; + pkey->esys_lock = cprov->esys_lock; pkey->esys_ctx = cprov->esys_ctx; pkey->capability = cprov->capability; pkey->object = ESYS_TR_NONE; @@ -105,6 +107,7 @@ tpm2_ec_keymgmt_gen_init(void *provctx, int selection, const OSSL_PARAM params[] return NULL; gen->core = cprov->core; + gen->esys_lock = cprov->esys_lock; gen->esys_ctx = cprov->esys_ctx; gen->capability = cprov->capability; @@ -216,6 +219,7 @@ tpm2_ec_keymgmt_gen(void *ctx, OSSL_CALLBACK *cb, void *cbarg) } pkey->core = gen->core; + pkey->esys_lock = gen->esys_lock; pkey->esys_ctx = gen->esys_ctx; pkey->capability = gen->capability; @@ -226,12 +230,13 @@ tpm2_ec_keymgmt_gen(void *ctx, OSSL_CALLBACK *cb, void *cbarg) /* load parent */ if (gen->parentHandle && gen->parentHandle != TPM2_RH_OWNER) { DBG("EC GEN parent: persistent 0x%x\n", gen->parentHandle); - if (!tpm2_load_parent(pkey->core, pkey->esys_ctx, + if (!tpm2_load_parent(pkey->core, pkey->esys_lock, pkey->esys_ctx, gen->parentHandle, &gen->parentAuth, &parent)) goto error1; } else { DBG("EC GEN parent: primary 0x%x\n", TPM2_RH_OWNER); - if (!tpm2_build_primary(pkey->core, pkey->esys_ctx, pkey->capability.algorithms, + if (!tpm2_build_primary(pkey->core, pkey->esys_lock, pkey->esys_ctx, + pkey->capability.algorithms, ESYS_TR_RH_OWNER, &gen->parentAuth, &parent)) goto error1; } @@ -239,6 +244,8 @@ tpm2_ec_keymgmt_gen(void *ctx, OSSL_CALLBACK *cb, void *cbarg) TPM2B_DATA outside_info = { .size = 0 }; TPML_PCR_SELECTION creation_pcr = { .count = 0 }; + if (!CRYPTO_THREAD_write_lock(gen->esys_lock)) + return 0; /* older TPM2 chips do not support Esys_CreateLoaded */ r = Esys_Create(gen->esys_ctx, parent, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, @@ -266,10 +273,12 @@ tpm2_ec_keymgmt_gen(void *ctx, OSSL_CALLBACK *cb, void *cbarg) r = Esys_TR_SetAuth(gen->esys_ctx, pkey->object, &gen->inSensitive.sensitive.userAuth); TPM2_CHECK_RC(gen->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto error2); } + CRYPTO_THREAD_unlock(gen->esys_lock); return pkey; error2: Esys_FlushContext(gen->esys_ctx, pkey->object); error1: + CRYPTO_THREAD_unlock(gen->esys_lock); OPENSSL_clear_free(pkey, sizeof(TPM2_PKEY)); return NULL; } @@ -314,9 +323,9 @@ tpm2_ec_keymgmt_free(void *keydata) if (pkey->object != ESYS_TR_NONE) { if (pkey->data.privatetype == KEY_TYPE_HANDLE) - Esys_TR_Close(pkey->esys_ctx, &pkey->object); + tpm2_esys_tr_close(pkey->esys_lock, pkey->esys_ctx, &pkey->object); else - Esys_FlushContext(pkey->esys_ctx, pkey->object); + tpm2_esys_flush_context(pkey->esys_lock, pkey->esys_ctx, pkey->object); } OPENSSL_clear_free(pkey, sizeof(TPM2_PKEY)); @@ -349,8 +358,11 @@ tpm2_ec_keymgmt_get_params(void *keydata, OSSL_PARAM params[]) return 1; TRACE_PARAMS("EC GET_PARAMS", params); + if (!CRYPTO_THREAD_write_lock(pkey->esys_lock)) + return 0; r = Esys_ECC_Parameters(pkey->esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_PKEY_EC_CURVE(pkey), &details); + CRYPTO_THREAD_unlock(pkey->esys_lock); TPM2_CHECK_RC(pkey->core, r, TPM2_ERR_UNKNOWN_ALGORITHM, return 0); p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_GROUP_NAME); diff --git a/src/tpm2-provider-keymgmt-rsa.c b/src/tpm2-provider-keymgmt-rsa.c index bb0554d..afd27cf 100644 --- a/src/tpm2-provider-keymgmt-rsa.c +++ b/src/tpm2-provider-keymgmt-rsa.c @@ -42,6 +42,7 @@ typedef struct tpm2_rsagen_ctx_st TPM2_RSAGEN_CTX; struct tpm2_rsagen_ctx_st { const OSSL_CORE_HANDLE *core; + CRYPTO_RWLOCK *esys_lock; ESYS_CONTEXT *esys_ctx; TPM2_CAPABILITY capability; TPM2_HANDLE parentHandle; @@ -82,6 +83,7 @@ tpm2_rsa_keymgmt_new(void *provctx) } pkey->core = cprov->core; + pkey->esys_lock = cprov->esys_lock; pkey->esys_ctx = cprov->esys_ctx; pkey->capability = cprov->capability; pkey->object = ESYS_TR_NONE; @@ -103,6 +105,7 @@ tpm2_create_rsagen_ctx(void *provctx) return NULL; gen->core = cprov->core; + gen->esys_lock = cprov->esys_lock; gen->esys_ctx = cprov->esys_ctx; gen->capability = cprov->capability; return gen; @@ -258,6 +261,7 @@ tpm2_rsa_keymgmt_gen(void *ctx, OSSL_CALLBACK *cb, void *cbarg) } pkey->core = gen->core; + pkey->esys_lock = gen->esys_lock; pkey->esys_ctx = gen->esys_ctx; pkey->capability = gen->capability; @@ -268,12 +272,13 @@ tpm2_rsa_keymgmt_gen(void *ctx, OSSL_CALLBACK *cb, void *cbarg) /* load parent */ if (gen->parentHandle && gen->parentHandle != TPM2_RH_OWNER) { DBG("RSA GEN parent: persistent 0x%x\n", gen->parentHandle); - if (!tpm2_load_parent(pkey->core, pkey->esys_ctx, + if (!tpm2_load_parent(pkey->core, pkey->esys_lock, pkey->esys_ctx, gen->parentHandle, &gen->parentAuth, &parent)) goto error1; } else { DBG("RSA GEN parent: primary 0x%x\n", TPM2_RH_OWNER); - if (!tpm2_build_primary(pkey->core, pkey->esys_ctx, pkey->capability.algorithms, + if (!tpm2_build_primary(pkey->core, pkey->esys_lock, pkey->esys_ctx, + pkey->capability.algorithms, ESYS_TR_RH_OWNER, &gen->parentAuth, &parent)) goto error1; } @@ -281,12 +286,14 @@ tpm2_rsa_keymgmt_gen(void *ctx, OSSL_CALLBACK *cb, void *cbarg) TPM2B_DATA outside_info = { .size = 0 }; TPML_PCR_SELECTION creation_pcr = { .count = 0 }; + if (!CRYPTO_THREAD_write_lock(gen->esys_lock)) + goto error1; /* older TPM2 chips do not support Esys_CreateLoaded */ r = Esys_Create(gen->esys_ctx, parent, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &gen->inSensitive, &gen->inPublic, &outside_info, &creation_pcr, &keyPrivate, &keyPublic, NULL, NULL, NULL); - TPM2_CHECK_RC(gen->core, r, TPM2_ERR_CANNOT_CREATE_KEY, goto error1); + TPM2_CHECK_RC(gen->core, r, TPM2_ERR_CANNOT_CREATE_KEY, goto error2); pkey->data.pub = *keyPublic; pkey->data.privatetype = KEY_TYPE_BLOB; @@ -297,7 +304,7 @@ tpm2_rsa_keymgmt_gen(void *ctx, OSSL_CALLBACK *cb, void *cbarg) keyPrivate, keyPublic, &pkey->object); free(keyPublic); free(keyPrivate); - TPM2_CHECK_RC(gen->core, r, TPM2_ERR_CANNOT_CREATE_KEY, goto error1); + TPM2_CHECK_RC(gen->core, r, TPM2_ERR_CANNOT_CREATE_KEY, goto error2); if (gen->parentHandle && gen->parentHandle != TPM2_RH_OWNER) Esys_TR_Close(gen->esys_ctx, &parent); @@ -306,11 +313,14 @@ tpm2_rsa_keymgmt_gen(void *ctx, OSSL_CALLBACK *cb, void *cbarg) if (gen->inSensitive.sensitive.userAuth.size > 0) { r = Esys_TR_SetAuth(gen->esys_ctx, pkey->object, &gen->inSensitive.sensitive.userAuth); - TPM2_CHECK_RC(gen->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto error2); + TPM2_CHECK_RC(gen->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto error3); } + CRYPTO_THREAD_unlock(gen->esys_lock); return pkey; -error2: +error3: Esys_FlushContext(gen->esys_ctx, pkey->object); +error2: + CRYPTO_THREAD_unlock(gen->esys_lock); error1: OPENSSL_clear_free(pkey, sizeof(TPM2_PKEY)); return NULL; @@ -356,9 +366,9 @@ tpm2_rsa_keymgmt_free(void *keydata) if (pkey->object != ESYS_TR_NONE) { if (pkey->data.privatetype == KEY_TYPE_HANDLE) - Esys_TR_Close(pkey->esys_ctx, &pkey->object); + tpm2_esys_tr_close(pkey->esys_lock, pkey->esys_ctx, &pkey->object); else - Esys_FlushContext(pkey->esys_ctx, pkey->object); + tpm2_esys_flush_context(pkey->esys_lock, pkey->esys_ctx, pkey->object); } OPENSSL_clear_free(pkey, sizeof(TPM2_PKEY)); diff --git a/src/tpm2-provider-pkey.c b/src/tpm2-provider-pkey.c index b5a1fc7..b0dd686 100644 --- a/src/tpm2-provider-pkey.c +++ b/src/tpm2-provider-pkey.c @@ -256,7 +256,7 @@ static const TPML_PCR_SELECTION allCreationPCR = { }; int -tpm2_load_parent(const OSSL_CORE_HANDLE *core, ESYS_CONTEXT *esys_ctx, +tpm2_load_parent(const OSSL_CORE_HANDLE *core, CRYPTO_RWLOCK *esys_lock, ESYS_CONTEXT *esys_ctx, TPM2_HANDLE handle, TPM2B_DIGEST *auth, ESYS_TR *object) { TSS2_RC r; @@ -277,6 +277,8 @@ tpm2_load_parent(const OSSL_CORE_HANDLE *core, ESYS_CONTEXT *esys_ctx, } } + if (!CRYPTO_THREAD_write_lock(esys_lock)) + return 0; r = Esys_TR_FromTPMPublic(esys_ctx, handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, object); @@ -287,21 +289,26 @@ tpm2_load_parent(const OSSL_CORE_HANDLE *core, ESYS_CONTEXT *esys_ctx, TPM2_CHECK_RC(core, r, TPM2_ERR_CANNOT_LOAD_PARENT, goto error2); } + CRYPTO_THREAD_unlock(esys_lock); return 1; -error2: +error3: Esys_FlushContext(esys_ctx, *object); +error2: + CRYPTO_THREAD_unlock(esys_lock); error1: return 0; } int -tpm2_build_primary(const OSSL_CORE_HANDLE *core, ESYS_CONTEXT *esys_ctx, +tpm2_build_primary(const OSSL_CORE_HANDLE *core, CRYPTO_RWLOCK *esys_lock, ESYS_CONTEXT *esys_ctx, const TPMS_CAPABILITY_DATA *algorithms, ESYS_TR hierarchy, const TPM2B_DIGEST *auth, ESYS_TR *object) { const TPM2B_PUBLIC *primaryTemplate = NULL; TSS2_RC r; + if (!CRYPTO_THREAD_write_lock(esys_lock)) + return 0; r = Esys_TR_SetAuth(esys_ctx, hierarchy, auth); TPM2_CHECK_RC(core, r, TPM2_ERR_CANNOT_CREATE_PRIMARY, goto error); @@ -326,8 +333,10 @@ tpm2_build_primary(const OSSL_CORE_HANDLE *core, ESYS_CONTEXT *esys_ctx, } TPM2_CHECK_RC(core, r, TPM2_ERR_CANNOT_CREATE_PRIMARY, goto error); + CRYPTO_THREAD_unlock(esys_lock); return 1; error: + CRYPTO_THREAD_unlock(esys_lock); return 0; } diff --git a/src/tpm2-provider-pkey.h b/src/tpm2-provider-pkey.h index 0a3fc23..e54d9af 100644 --- a/src/tpm2-provider-pkey.h +++ b/src/tpm2-provider-pkey.h @@ -28,11 +28,11 @@ int tpm2_keydata_read(BIO *bin, TPM2_KEYDATA *keydata, TPM2_PKEY_FORMAT format); int -tpm2_load_parent(const OSSL_CORE_HANDLE *core, ESYS_CONTEXT *esys_ctx, +tpm2_load_parent(const OSSL_CORE_HANDLE *core, CRYPTO_RWLOCK *esys_lock, ESYS_CONTEXT *esys_ctx, TPM2_HANDLE handle, TPM2B_DIGEST *auth, ESYS_TR *object); int -tpm2_build_primary(const OSSL_CORE_HANDLE *core, ESYS_CONTEXT *esys_ctx, +tpm2_build_primary(const OSSL_CORE_HANDLE *core, CRYPTO_RWLOCK *esys_lock, ESYS_CONTEXT *esys_ctx, const TPMS_CAPABILITY_DATA *capability, ESYS_TR hierarchy, const TPM2B_DIGEST *auth, ESYS_TR *object); diff --git a/src/tpm2-provider-rand.c b/src/tpm2-provider-rand.c index 5990a46..64532d8 100644 --- a/src/tpm2-provider-rand.c +++ b/src/tpm2-provider-rand.c @@ -14,6 +14,7 @@ typedef struct tpm2_rand_ctx_st TPM2_RAND_CTX; struct tpm2_rand_ctx_st { const OSSL_CORE_HANDLE *core; + CRYPTO_RWLOCK *esys_lock; ESYS_CONTEXT *esys_ctx; CRYPTO_RWLOCK *lock; }; @@ -41,6 +42,7 @@ tpm2_rand_newctx(void *provctx, void *parent, return NULL; rand->core = cprov->core; + rand->esys_lock = cprov->esys_lock; rand->esys_ctx = cprov->esys_ctx; return rand; } @@ -85,9 +87,12 @@ tpm2_rand_generate(void *ctx, unsigned char *out, size_t outlen, TSS2_RC r; TPM2B_DIGEST *b; + if (!CRYPTO_THREAD_write_lock(rand->esys_lock)) + return 0; r = Esys_GetRandom(rand->esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, outlen, &b); + CRYPTO_THREAD_unlock(rand->esys_lock); TPM2_CHECK_RC(rand->core, r, TPM2_ERR_CANNOT_GET_RANDOM, return 0); memcpy(out, &b->buffer, b->size); diff --git a/src/tpm2-provider-signature.c b/src/tpm2-provider-signature.c index 2b83e88..9e44154 100644 --- a/src/tpm2-provider-signature.c +++ b/src/tpm2-provider-signature.c @@ -18,6 +18,7 @@ struct tpm2_signature_ctx_st { TPM2_HASH_SEQUENCE hashSequence; struct { const OSSL_CORE_HANDLE *core; + CRYPTO_RWLOCK *esys_lock; ESYS_CONTEXT *esys_ctx; }; }; @@ -113,10 +114,13 @@ ensure_key_loaded(TPM2_PKEY *pkey) /* imported public keys are not auto-loaded by keymgmt */ if (pkey->object == ESYS_TR_NONE) { + if (!CRYPTO_THREAD_write_lock(pkey->esys_lock)) + return 0; r = Esys_LoadExternal(pkey->esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, NULL, &pkey->data.pub, ESYS_TR_RH_NULL, &pkey->object); + CRYPTO_THREAD_unlock(pkey->esys_lock); TPM2_CHECK_RC(pkey->core, r, TPM2_ERR_CANNOT_LOAD_KEY, return 0); } @@ -351,9 +355,12 @@ tpm2_signature_sign(void *ctx, unsigned char *sig, size_t *siglen, size_t sigsiz digest.size = tbslen; memcpy(digest.buffer, tbs, tbslen); + if (!CRYPTO_THREAD_write_lock(sctx->esys_lock)) + return 0; r = Esys_Sign(sctx->esys_ctx, sctx->pkey->object, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &digest, &sctx->signScheme, &empty_validation, &sctx->signature); + CRYPTO_THREAD_unlock(sctx->esys_lock); TPM2_CHECK_RC(sctx->core, r, TPM2_ERR_CANNOT_SIGN, return 0); if (!get_signature_buffer(sctx->signature, sig, siglen, sigsize)) @@ -428,11 +435,14 @@ digest_sign_calculate(TPM2_SIGNATURE_CTX *sctx) if (validation->digest.size == 0) DBG("SIGN DIGEST_SIGN_CALCULATE zero size ticket\n"); + if (!CRYPTO_THREAD_write_lock(sctx->esys_lock)) + return 0; r = Esys_Sign(sctx->esys_ctx, sctx->pkey->object, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, digest, &sctx->signScheme, validation, &sctx->signature); free(digest); free(validation); + CRYPTO_THREAD_unlock(sctx->esys_lock); TPM2_CHECK_RC(sctx->core, r, TPM2_ERR_CANNOT_SIGN, return 0); return 1; @@ -490,11 +500,14 @@ tpm2_signature_digest_sign(void *ctx, unsigned char *sig, size_t *siglen, if (validation->digest.size == 0) DBG("SIGN DIGEST_SIGN zero size ticket\n"); + if (!CRYPTO_THREAD_write_lock(sctx->esys_lock)) + return 0; r = Esys_Sign(sctx->esys_ctx, sctx->pkey->object, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, digest, &sctx->signScheme, validation, &sctx->signature); free(digest); free(validation); + CRYPTO_THREAD_unlock(sctx->esys_lock); TPM2_CHECK_RC(sctx->core, r, TPM2_ERR_CANNOT_SIGN, return 0); if (!get_signature_buffer(sctx->signature, sig, siglen, sigsize)) @@ -521,11 +534,14 @@ tpm2_signature_digest_verify_final(void *ctx, const unsigned char *sig, size_t s &digest, NULL)) return 0; + if (!CRYPTO_THREAD_write_lock(sctx->esys_lock)) + return 0; r = Esys_VerifySignature(sctx->esys_ctx, sctx->pkey->object, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, digest, &signature, &validation); free(digest); free(validation); + CRYPTO_THREAD_unlock(sctx->esys_lock); TPM2_CHECK_RC(sctx->core, r, TPM2_ERR_VERIFICATION_FAILED, return 0); return 1; diff --git a/src/tpm2-provider-store-handle.c b/src/tpm2-provider-store-handle.c index 5cb3ddc..e5239ec 100644 --- a/src/tpm2-provider-store-handle.c +++ b/src/tpm2-provider-store-handle.c @@ -13,6 +13,7 @@ typedef struct tpm2_handle_ctx_st TPM2_HANDLE_CTX; struct tpm2_handle_ctx_st { const OSSL_CORE_HANDLE *core; + CRYPTO_RWLOCK *esys_lock; ESYS_CONTEXT *esys_ctx; TPM2_CAPABILITY capability; int has_pass; @@ -41,6 +42,7 @@ tpm2_handle_open(void *provctx, const char *uri) return NULL; ctx->core = cprov->core; + ctx->esys_lock = cprov->esys_lock; ctx->esys_ctx = cprov->esys_ctx; ctx->capability = cprov->capability; @@ -92,6 +94,7 @@ tpm2_handle_attach(void *provctx, OSSL_CORE_BIO *cin) return NULL; ctx->core = cprov->core; + ctx->esys_lock = cprov->esys_lock; ctx->esys_ctx = cprov->esys_ctx; ctx->capability = cprov->capability; @@ -169,13 +172,17 @@ tpm2_handle_load_pkey(TPM2_HANDLE_CTX *sctx, ESYS_TR object, return 0; pkey->core = sctx->core; + pkey->esys_lock = sctx->esys_lock; pkey->esys_ctx = sctx->esys_ctx; pkey->capability = sctx->capability; pkey->object = object; + if (!CRYPTO_THREAD_write_lock(sctx->esys_lock)) + goto final; r = Esys_ReadPublic(sctx->esys_ctx, object, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &out_public, NULL, NULL); + CRYPTO_THREAD_unlock(sctx->esys_lock); TPM2_CHECK_RC(sctx->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto final); pkey->data.pub = *out_public; @@ -221,9 +228,12 @@ tpm2_handle_load_index(TPM2_HANDLE_CTX *sctx, ESYS_TR object, TSS2_RC r; int ret = 0; + if (!CRYPTO_THREAD_write_lock(sctx->esys_lock)) + goto final; r = Esys_NV_ReadPublic(sctx->esys_ctx, object, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &metadata, NULL); + CRYPTO_THREAD_unlock(sctx->esys_lock); TPM2_CHECK_RC(sctx->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto final); read_len = metadata->nvPublic.dataSize; @@ -237,9 +247,12 @@ tpm2_handle_load_index(TPM2_HANDLE_CTX *sctx, ESYS_TR object, uint16_t bytes_to_read = read_len < read_max ? read_len : read_max; TPM2B_MAX_NV_BUFFER *buff = NULL; + if (!CRYPTO_THREAD_write_lock(sctx->esys_lock)) + goto final; r = Esys_NV_Read(sctx->esys_ctx, object, object, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, bytes_to_read, data_len, &buff); + CRYPTO_THREAD_unlock(sctx->esys_lock); TPM2_CHECK_RC(sctx->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto final); memcpy(data + data_len, buff->buffer, buff->size); @@ -315,18 +328,26 @@ tpm2_handle_load(void *ctx, if ((buffer_size = read_until_eof(sctx->bio, &buffer)) < 0) return 0; + if (!CRYPTO_THREAD_write_lock(sctx->esys_lock)) { + OPENSSL_free(buffer); + return 0; + } /* read object metadata */ r = Esys_TR_Deserialize(sctx->esys_ctx, buffer, buffer_size, &object); - OPENSSL_free(buffer); - /* TODO: should use Esys_TR_GetTpmHandle */ - sctx->handle = TPM2_HR_PERSISTENT; + if (!r) { + OPENSSL_free(buffer); + r = Esys_TR_GetTpmHandle(sctx->esys_ctx, object, &sctx->handle); + } } else { + if (!CRYPTO_THREAD_write_lock(sctx->esys_lock)) + return 0; /* create reference to a pre-existing TPM object */ r = Esys_TR_FromTPMPublic(sctx->esys_ctx, sctx->handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &object); sctx->load_done = 1; } + CRYPTO_THREAD_unlock(sctx->esys_lock); TPM2_CHECK_RC(sctx->core, r, TPM2_ERR_CANNOT_LOAD_KEY, return 0); if (sctx->has_pass) { @@ -340,7 +361,10 @@ tpm2_handle_load(void *ctx, } userauth.size = plen; + if (!CRYPTO_THREAD_write_lock(sctx->esys_lock)) + goto error; r = Esys_TR_SetAuth(sctx->esys_ctx, object, &userauth); + CRYPTO_THREAD_unlock(sctx->esys_lock); TPM2_CHECK_RC(sctx->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto error); } @@ -350,17 +374,17 @@ tpm2_handle_load(void *ctx, case TPM2_HT_PERSISTENT: ret = tpm2_handle_load_pkey(sctx, object, object_cb, object_cbarg); if (!ret) - Esys_TR_Close(sctx->esys_ctx, &object); + tpm2_esys_tr_close(sctx->esys_lock, sctx->esys_ctx, &object); break; case TPM2_HT_NV_INDEX: ret = tpm2_handle_load_index(sctx, object, object_cb, object_cbarg); - Esys_TR_Close(sctx->esys_ctx, &object); + tpm2_esys_tr_close(sctx->esys_lock, sctx->esys_ctx, &object); break; } return ret; error: - Esys_TR_Close(sctx->esys_ctx, &object); + tpm2_esys_tr_close(sctx->esys_lock, sctx->esys_ctx, &object); return 0; } diff --git a/src/tpm2-provider.c b/src/tpm2-provider.c index 29679b2..045168f 100644 --- a/src/tpm2-provider.c +++ b/src/tpm2-provider.c @@ -340,9 +340,13 @@ tpm2_self_test(void *provctx) TSS2_RC r; DBG("PROVIDER SELFTEST\n"); + + if (!CRYPTO_THREAD_write_lock(cprov->esys_lock)) + return 0; r = Esys_SelfTest(cprov->esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_YES); + CRYPTO_THREAD_unlock(cprov->esys_lock); return r == TPM2_RC_SUCCESS; } @@ -358,6 +362,7 @@ tpm2_teardown(void *provctx) free(cprov->capability.properties); free(cprov->capability.algorithms); free(cprov->capability.commands); + CRYPTO_THREAD_lock_free(cprov->esys_lock); OSSL_LIB_CTX_free(cprov->libctx); r = Esys_GetTcti(cprov->esys_ctx, &tcti_ctx); @@ -500,28 +505,33 @@ OSSL_provider_init(const OSSL_CORE_HANDLE *handle, r = Esys_Initialize(&cprov->esys_ctx, tcti_ctx, NULL); TPM2_CHECK_RC(cprov->core, r, TPM2_ERR_CANNOT_CONNECT, goto err2); + if ((cprov->esys_lock = CRYPTO_THREAD_lock_new()) == NULL) + goto err3; + r = Esys_GetCapability(cprov->esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_CAP_TPM_PROPERTIES, 0, TPM2_MAX_TPM_PROPERTIES, NULL, &cprov->capability.properties); - TPM2_CHECK_RC(cprov->core, r, TPM2_ERR_CANNOT_GET_CAPABILITY, goto err3); + TPM2_CHECK_RC(cprov->core, r, TPM2_ERR_CANNOT_GET_CAPABILITY, goto err4); r = Esys_GetCapability(cprov->esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_CAP_ALGS, 0, TPM2_MAX_CAP_ALGS, NULL, &cprov->capability.algorithms); - TPM2_CHECK_RC(cprov->core, r, TPM2_ERR_CANNOT_GET_CAPABILITY, goto err3); + TPM2_CHECK_RC(cprov->core, r, TPM2_ERR_CANNOT_GET_CAPABILITY, goto err4); r = Esys_GetCapability(cprov->esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_CAP_COMMANDS, 0, TPM2_MAX_CAP_CC, NULL, &cprov->capability.commands); - TPM2_CHECK_RC(cprov->core, r, TPM2_ERR_CANNOT_GET_CAPABILITY, goto err3); + TPM2_CHECK_RC(cprov->core, r, TPM2_ERR_CANNOT_GET_CAPABILITY, goto err4); *out = tpm2_dispatch_table; *provctx = cprov; return 1; +err4: + CRYPTO_THREAD_lock_free(cprov->esys_lock); err3: Esys_Finalize(&cprov->esys_ctx); err2: diff --git a/src/tpm2-provider.h b/src/tpm2-provider.h index 513f9ad..d764815 100644 --- a/src/tpm2-provider.h +++ b/src/tpm2-provider.h @@ -25,6 +25,7 @@ typedef struct { struct tpm2_provider_ctx_st { const OSSL_CORE_HANDLE *core; OSSL_LIB_CTX *libctx; + CRYPTO_RWLOCK *esys_lock; ESYS_CONTEXT *esys_ctx; TPM2_CAPABILITY capability; }; @@ -52,6 +53,7 @@ typedef struct { TPM2_KEYDATA data; TPM2B_DIGEST userauth; const OSSL_CORE_HANDLE *core; + CRYPTO_RWLOCK *esys_lock; ESYS_CONTEXT *esys_ctx; TPM2_CAPABILITY capability; ESYS_TR object; @@ -131,6 +133,12 @@ tpm2_list_params(const char *text, const OSSL_PARAM params[]); #define TPM2_ERROR_set_debug(core) tpm2_set_error_debug((core), OPENSSL_FILE, OPENSSL_LINE, OPENSSL_FUNC) #endif +TSS2_RC +tpm2_esys_tr_close(CRYPTO_RWLOCK *esys_lock, ESYS_CONTEXT *esys_ctx, ESYS_TR *object); + +TSS2_RC +tpm2_esys_flush_context(CRYPTO_RWLOCK *esys_lock, ESYS_CONTEXT *esys_ctx, ESYS_TR flush_handle); + int tpm2_supports_algorithm(const TPMS_CAPABILITY_DATA *caps, TPM2_ALG_ID algorithm); diff --git a/test/rand_threads.c b/test/rand_threads.c new file mode 100644 index 0000000..81b45fb --- /dev/null +++ b/test/rand_threads.c @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include +#include + +#define THREAD_COUNT 10 + +void *generate_random(void *arg) { + unsigned char buffer[1024]; + + /* 1 on success */ + return (void *)(size_t)(RAND_bytes(buffer, sizeof(buffer)) == 1); +} + +int main() { + OSSL_PROVIDER *prov; + pthread_t thread[THREAD_COUNT]; + int i, failed = 0; + size_t res; + + if ((prov = OSSL_PROVIDER_load(NULL, "tpm2")) == NULL) + return THREAD_COUNT+1; + + /* start multiple parallel operations */ + for (i = 0; i < THREAD_COUNT; i++) { + if (pthread_create(thread+i, NULL, generate_random, NULL)) + return THREAD_COUNT+2; + } + + /* count failures */ + for (i = 0; i < THREAD_COUNT; i++) { + if (pthread_join(thread[i], (void **)&res) || !res) + failed++; + } + + if (!OSSL_PROVIDER_unload(prov)) + return THREAD_COUNT+3; + + return failed; +} +