Improve performance of the encoder collection
Reviewed-by: Richard Levitte <levitte@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Paul Dale <pauli@openssl.org> Reviewed-by: Hugo Landau <hlandau@openssl.org> (Merged from https://github.com/openssl/openssl/pull/19344)
This commit is contained in:
parent
9eaf07ffe3
commit
c3b4640955
1 changed files with 49 additions and 27 deletions
|
@ -17,6 +17,7 @@
|
|||
#include <openssl/trace.h>
|
||||
#include "internal/provider.h"
|
||||
#include "internal/property.h"
|
||||
#include "internal/namemap.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "encoder_local.h"
|
||||
|
||||
|
@ -72,6 +73,7 @@ int OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX *ctx,
|
|||
|
||||
struct collected_encoder_st {
|
||||
STACK_OF(OPENSSL_CSTRING) *names;
|
||||
int *id_names;
|
||||
const char *output_structure;
|
||||
const char *output_type;
|
||||
|
||||
|
@ -85,41 +87,41 @@ struct collected_encoder_st {
|
|||
static void collect_encoder(OSSL_ENCODER *encoder, void *arg)
|
||||
{
|
||||
struct collected_encoder_st *data = arg;
|
||||
size_t i, end_i;
|
||||
const OSSL_PROVIDER *prov;
|
||||
|
||||
if (data->error_occurred)
|
||||
return;
|
||||
|
||||
data->error_occurred = 1; /* Assume the worst */
|
||||
|
||||
if (data->names == NULL)
|
||||
return;
|
||||
|
||||
end_i = sk_OPENSSL_CSTRING_num(data->names);
|
||||
for (i = 0; i < end_i; i++) {
|
||||
const char *name = sk_OPENSSL_CSTRING_value(data->names, i);
|
||||
const OSSL_PROVIDER *prov = OSSL_ENCODER_get0_provider(encoder);
|
||||
prov = OSSL_ENCODER_get0_provider(encoder);
|
||||
/*
|
||||
* collect_encoder() is called in two passes, one where the encoders
|
||||
* from the same provider as the keymgmt are looked up, and one where
|
||||
* the other encoders are looked up. |data->flag_find_same_provider|
|
||||
* tells us which pass we're in.
|
||||
*/
|
||||
if ((data->keymgmt_prov == prov) == data->flag_find_same_provider) {
|
||||
void *provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
|
||||
size_t i, end_i = sk_OPENSSL_CSTRING_num(data->names);
|
||||
int match;
|
||||
|
||||
/*
|
||||
* collect_encoder() is called in two passes, one where the encoders
|
||||
* from the same provider as the keymgmt are looked up, and one where
|
||||
* the other encoders are looked up. |data->flag_find_same_provider|
|
||||
* tells us which pass we're in.
|
||||
*/
|
||||
if ((data->keymgmt_prov == prov) != data->flag_find_same_provider)
|
||||
continue;
|
||||
for (i = 0; i < end_i; i++) {
|
||||
if (data->flag_find_same_provider)
|
||||
match = (data->id_names[i] == encoder->base.id);
|
||||
else
|
||||
match = OSSL_ENCODER_is_a(encoder, sk_OPENSSL_CSTRING_value(data->names, i));
|
||||
if (!match
|
||||
|| (encoder->does_selection != NULL
|
||||
&& !encoder->does_selection(provctx, data->ctx->selection))
|
||||
|| (data->keymgmt_prov != prov
|
||||
&& encoder->import_object == NULL))
|
||||
continue;
|
||||
|
||||
if (!OSSL_ENCODER_is_a(encoder, name)
|
||||
|| (encoder->does_selection != NULL
|
||||
&& !encoder->does_selection(provctx, data->ctx->selection))
|
||||
|| (data->keymgmt_prov != prov
|
||||
&& encoder->import_object == NULL))
|
||||
continue;
|
||||
|
||||
/* Only add each encoder implementation once */
|
||||
if (OSSL_ENCODER_CTX_add_encoder(data->ctx, encoder))
|
||||
break;
|
||||
/* Only add each encoder implementation once */
|
||||
if (OSSL_ENCODER_CTX_add_encoder(data->ctx, encoder))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
data->error_occurred = 0; /* All is good now */
|
||||
|
@ -227,7 +229,8 @@ static int ossl_encoder_ctx_setup_for_pkey(OSSL_ENCODER_CTX *ctx,
|
|||
struct construct_data_st *data = NULL;
|
||||
const OSSL_PROVIDER *prov = NULL;
|
||||
OSSL_LIB_CTX *libctx = NULL;
|
||||
int ok = 0;
|
||||
int ok = 0, i, end;
|
||||
OSSL_NAMEMAP *namemap;
|
||||
|
||||
if (!ossl_assert(ctx != NULL) || !ossl_assert(pkey != NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
||||
|
@ -269,7 +272,25 @@ static int ossl_encoder_ctx_setup_for_pkey(OSSL_ENCODER_CTX *ctx,
|
|||
encoder_data.error_occurred = 0;
|
||||
encoder_data.keymgmt_prov = prov;
|
||||
encoder_data.ctx = ctx;
|
||||
encoder_data.id_names = NULL;
|
||||
|
||||
/*
|
||||
* collect_encoder() is called many times, and for every call it converts all encoder_data.names
|
||||
* into namemap ids if it calls OSSL_ENCODER_is_a(). We cache the ids here instead,
|
||||
* and can use them for encoders with the same provider as the keymgmt.
|
||||
*/
|
||||
namemap = ossl_namemap_stored(libctx);
|
||||
end = sk_OPENSSL_CSTRING_num(encoder_data.names);
|
||||
if (end > 0) {
|
||||
encoder_data.id_names = OPENSSL_malloc(end * sizeof(int));
|
||||
if (encoder_data.id_names == NULL)
|
||||
goto err;
|
||||
for (i = 0; i < end; ++i) {
|
||||
const char *name = sk_OPENSSL_CSTRING_value(keymgmt_data.names, i);
|
||||
|
||||
encoder_data.id_names[i] = ossl_namemap_name2num(namemap, name);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Place the encoders with the a different provider as the keymgmt
|
||||
* last (the chain is processed in reverse order)
|
||||
|
@ -284,6 +305,7 @@ static int ossl_encoder_ctx_setup_for_pkey(OSSL_ENCODER_CTX *ctx,
|
|||
encoder_data.flag_find_same_provider = 1;
|
||||
OSSL_ENCODER_do_all_provided(libctx, collect_encoder, &encoder_data);
|
||||
|
||||
OPENSSL_free(encoder_data.id_names);
|
||||
sk_OPENSSL_CSTRING_free(keymgmt_data.names);
|
||||
if (encoder_data.error_occurred) {
|
||||
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_CRYPTO_LIB);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue