Skip to content

Commit

Permalink
fix multi-threaded operation
Browse files Browse the repository at this point in the history
  • Loading branch information
gotthardp committed Dec 14, 2024
1 parent 9ab3a81 commit 3806857
Show file tree
Hide file tree
Showing 21 changed files with 270 additions and 40 deletions.
2 changes: 1 addition & 1 deletion .cirrus.yml
Original file line number Diff line number Diff line change
@@ -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
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 4 additions & 2 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions src/tpm2-provider-asymcipher-rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
18 changes: 15 additions & 3 deletions src/tpm2-provider-cipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -127,18 +129,24 @@ 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);
CRYPTO_THREAD_unlock(cctx->esys_lock);
TPM2_CHECK_RC(cctx->core, r, TPM2_ERR_CANNOT_CREATE_KEY, return 0);

if (!CRYPTO_THREAD_write_lock(cctx->esys_lock))
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);
CRYPTO_THREAD_unlock(cctx->esys_lock);
TPM2_CHECK_RC(cctx->core, r, TPM2_ERR_CANNOT_CREATE_KEY, return 0);

return 1;
Expand All @@ -158,12 +166,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;
}
Expand Down Expand Up @@ -212,6 +221,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,
Expand All @@ -222,6 +233,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;
}
Expand Down
28 changes: 28 additions & 0 deletions src/tpm2-provider-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
25 changes: 19 additions & 6 deletions src/tpm2-provider-decoder-tss2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
}

Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
26 changes: 23 additions & 3 deletions src/tpm2-provider-digest.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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 {
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}

Expand All @@ -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 */
Expand All @@ -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 */
Expand Down
1 change: 1 addition & 0 deletions src/tpm2-provider-digest.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 3806857

Please sign in to comment.