diff options
author | Michael Baentsch <57787676+baentsch@users.noreply.github.com> | 2022-12-24 09:20:44 +0100 |
---|---|---|
committer | Todd Short <todd.short@me.com> | 2023-03-31 20:19:18 +0200 |
commit | 4557e280086d9e300c56183b8ad0671857530dc5 (patch) | |
tree | fcc9c4ae73297c0436b82eb2601cd9f78d8932da | |
parent | /dev/crypto: Suppress warning when open /dev/crypto fails with ENXIO. (diff) | |
download | openssl-4557e280086d9e300c56183b8ad0671857530dc5.tar.xz openssl-4557e280086d9e300c56183b8ad0671857530dc5.zip |
Provider-based KEM and SIG alg speed testing added
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Todd Short <todd.short@me.com>
(Merged from https://github.com/openssl/openssl/pull/19968)
-rw-r--r-- | apps/speed.c | 922 | ||||
-rw-r--r-- | doc/man1/openssl-speed.pod.in | 10 |
2 files changed, 905 insertions, 27 deletions
diff --git a/apps/speed.c b/apps/speed.c index 489548f5ca..025c4eedc4 100644 --- a/apps/speed.c +++ b/apps/speed.c @@ -19,6 +19,8 @@ #define EdDSA_SECONDS PKEY_SECONDS #define SM2_SECONDS PKEY_SECONDS #define FFDH_SECONDS PKEY_SECONDS +#define KEM_SECONDS PKEY_SECONDS +#define SIG_SECONDS PKEY_SECONDS /* We need to use some deprecated APIs */ #define OPENSSL_SUPPRESS_DEPRECATED @@ -38,6 +40,7 @@ #include <openssl/objects.h> #include <openssl/core_names.h> #include <openssl/async.h> +#include <openssl/provider.h> #if !defined(OPENSSL_SYS_MSDOS) # include <unistd.h> #endif @@ -111,6 +114,8 @@ typedef struct openssl_speed_sec_st { int eddsa; int sm2; int ffdh; + int kem; + int sig; } openssl_speed_sec_t; static volatile int run = 0; @@ -122,6 +127,8 @@ static double Time_F(int s); static void print_message(const char *s, long num, int length, int tm); static void pkey_print_message(const char *str, const char *str2, long num, unsigned int bits, int sec); +static void kskey_print_message(const char *str, const char *str2, long num, + int tm); static void print_result(int alg, int run_no, int count, double time_used); #ifndef NO_FORK static int do_multi(int multi, int size_num); @@ -230,7 +237,7 @@ typedef enum OPTION_choice { OPT_COMMON, OPT_ELAPSED, OPT_EVP, OPT_HMAC, OPT_DECRYPT, OPT_ENGINE, OPT_MULTI, OPT_MR, OPT_MB, OPT_MISALIGN, OPT_ASYNCJOBS, OPT_R_ENUM, OPT_PROV_ENUM, OPT_CONFIG, - OPT_PRIMES, OPT_SECONDS, OPT_BYTES, OPT_AEAD, OPT_CMAC, OPT_MLOCK + OPT_PRIMES, OPT_SECONDS, OPT_BYTES, OPT_AEAD, OPT_CMAC, OPT_MLOCK, OPT_KEM, OPT_SIG } OPTION_CHOICE; const OPTIONS speed_options[] = { @@ -267,6 +274,10 @@ const OPTIONS speed_options[] = { "Time decryption instead of encryption (only EVP)"}, {"aead", OPT_AEAD, '-', "Benchmark EVP-named AEAD cipher in TLS-like sequence"}, + {"kem-algorithms", OPT_KEM, '-', + "Benchmark KEM algorithms"}, + {"signature-algorithms", OPT_SIG, '-', + "Benchmark signature algorithms"}, OPT_SECTION("Timing"), {"elapsed", OPT_ELAPSED, '-', @@ -476,6 +487,16 @@ static const OPT_PAIR sm2_choices[SM2_NUM] = { static double sm2_results[SM2_NUM][2]; /* 2 ops: sign then verify */ #endif /* OPENSSL_NO_SM2 */ +#define MAX_KEM_NUM 111 +static size_t kems_algs_len = 0; +static char *kems_algname[MAX_KEM_NUM] = { NULL }; +static double kems_results[MAX_KEM_NUM][3]; /* keygen, encaps, decaps */ + +#define MAX_SIG_NUM 111 +static size_t sigs_algs_len = 0; +static char *sigs_algname[MAX_SIG_NUM] = { NULL }; +static double sigs_results[MAX_SIG_NUM][3]; /* keygen, sign, verify */ + #define COND(unused_cond) (run && count < INT_MAX) #define COUNT(d) (count) @@ -513,6 +534,20 @@ typedef struct loopargs_st { #endif EVP_CIPHER_CTX *ctx; EVP_MAC_CTX *mctx; + EVP_PKEY_CTX *kem_gen_ctx[MAX_KEM_NUM]; + EVP_PKEY_CTX *kem_encaps_ctx[MAX_KEM_NUM]; + EVP_PKEY_CTX *kem_decaps_ctx[MAX_KEM_NUM]; + size_t kem_out_len[MAX_KEM_NUM]; + size_t kem_secret_len[MAX_KEM_NUM]; + unsigned char *kem_out[MAX_KEM_NUM]; + unsigned char *kem_send_secret[MAX_KEM_NUM]; + unsigned char *kem_rcv_secret[MAX_KEM_NUM]; + EVP_PKEY_CTX *sig_gen_ctx[MAX_KEM_NUM]; + EVP_PKEY_CTX *sig_sign_ctx[MAX_KEM_NUM]; + EVP_PKEY_CTX *sig_verify_ctx[MAX_KEM_NUM]; + size_t sig_max_sig_len[MAX_KEM_NUM]; + size_t sig_act_sig_len[MAX_KEM_NUM]; + unsigned char *sig_sig[MAX_KEM_NUM]; } loopargs_t; static int run_benchmark(int async_jobs, int (*loop_function) (void *), loopargs_t * loopargs); @@ -1139,6 +1174,131 @@ static int SM2_verify_loop(void *args) } #endif /* OPENSSL_NO_SM2 */ +static long kems_c[MAX_KEM_NUM][3]; /* keygen, encaps, decaps */ +static int KEM_keygen_loop(void *args) +{ + loopargs_t *tempargs = *(loopargs_t **) args; + EVP_PKEY_CTX *ctx = tempargs->kem_gen_ctx[testnum]; + EVP_PKEY *pkey = NULL; + int count; + + for (count = 0; COND(kems_c[testnum][0]); count++) { + if (EVP_PKEY_keygen(ctx, &pkey) <= 0) + return -1; + /* + * runtime defined to quite some degree by randomness, + * so performance overhead of _free doesn't impact + * results significantly. In any case this test is + * meant to permit relative algorithm performance + * comparison. + */ + EVP_PKEY_free(pkey); + pkey = NULL; + } + return count; +} + +static int KEM_encaps_loop(void *args) +{ + loopargs_t *tempargs = *(loopargs_t **) args; + EVP_PKEY_CTX *ctx = tempargs->kem_encaps_ctx[testnum]; + size_t out_len = tempargs->kem_out_len[testnum]; + size_t secret_len = tempargs->kem_secret_len[testnum]; + unsigned char *out = tempargs->kem_out[testnum]; + unsigned char *secret = tempargs->kem_send_secret[testnum]; + int count; + + for (count = 0; COND(kems_c[testnum][1]); count++) { + if (EVP_PKEY_encapsulate(ctx, out, &out_len, secret, &secret_len) <= 0) + return -1; + } + return count; +} + +static int KEM_decaps_loop(void *args) +{ + loopargs_t *tempargs = *(loopargs_t **) args; + EVP_PKEY_CTX *ctx = tempargs->kem_decaps_ctx[testnum]; + size_t out_len = tempargs->kem_out_len[testnum]; + size_t secret_len = tempargs->kem_secret_len[testnum]; + unsigned char *out = tempargs->kem_out[testnum]; + unsigned char *secret = tempargs->kem_send_secret[testnum]; + int count; + + for (count = 0; COND(kems_c[testnum][2]); count++) { + if (EVP_PKEY_decapsulate(ctx, secret, &secret_len, out, out_len) <= 0) + return -1; + } + return count; +} + +static long sigs_c[MAX_SIG_NUM][3]; /* keygen, sign, verify */ +static int SIG_keygen_loop(void *args) +{ + loopargs_t *tempargs = *(loopargs_t **) args; + EVP_PKEY_CTX *ctx = tempargs->sig_gen_ctx[testnum]; + EVP_PKEY *pkey = NULL; + int count; + + for (count = 0; COND(kems_c[testnum][0]); count++) { + EVP_PKEY_keygen(ctx, &pkey); + /* TBD: How much does free influence runtime? */ + EVP_PKEY_free(pkey); + pkey = NULL; + } + return count; +} + +static int SIG_sign_loop(void *args) +{ + loopargs_t *tempargs = *(loopargs_t **) args; + EVP_PKEY_CTX *ctx = tempargs->sig_sign_ctx[testnum]; + /* be sure to not change stored sig: */ + unsigned char *sig = app_malloc(tempargs->sig_max_sig_len[testnum], + "sig sign loop"); + unsigned char md[SHA256_DIGEST_LENGTH] = { 0 }; + size_t md_len = SHA256_DIGEST_LENGTH; + int count; + + for (count = 0; COND(kems_c[testnum][1]); count++) { + size_t sig_len = tempargs->sig_max_sig_len[testnum]; + int ret = EVP_PKEY_sign(ctx, sig, &sig_len, md, md_len); + + if (ret <= 0) { + BIO_printf(bio_err, "SIG sign failure at count %d\n", count); + ERR_print_errors(bio_err); + count = -1; + break; + } + } + OPENSSL_free(sig); + return count; +} + +static int SIG_verify_loop(void *args) +{ + loopargs_t *tempargs = *(loopargs_t **) args; + EVP_PKEY_CTX *ctx = tempargs->sig_verify_ctx[testnum]; + size_t sig_len = tempargs->sig_act_sig_len[testnum]; + unsigned char *sig = tempargs->sig_sig[testnum]; + unsigned char md[SHA256_DIGEST_LENGTH] = { 0 }; + size_t md_len = SHA256_DIGEST_LENGTH; + int count; + + for (count = 0; COND(kems_c[testnum][2]); count++) { + int ret = EVP_PKEY_verify(ctx, sig, sig_len, md, md_len); + + if (ret <= 0) { + BIO_printf(bio_err, "SIG verify failure at count %d\n", count); + ERR_print_errors(bio_err); + count = -1; + break; + } + + } + return count; +} + static int run_benchmark(int async_jobs, int (*loop_function) (void *), loopargs_t * loopargs) { @@ -1373,6 +1533,99 @@ static EVP_PKEY *get_ecdsa(const EC_CURVE *curve) #define stop_it(do_it, test_num)\ memset(do_it + test_num, 0, OSSL_NELEM(do_it) - test_num); +/* Checks to see if algorithms are fetchable */ +#define IS_FETCHABLE(type, TYPE) \ + static int is_ ## type ## _fetchable(const TYPE *alg) \ + { \ + TYPE *impl; \ + const char *propq = app_get0_propq(); \ + OSSL_LIB_CTX *libctx = app_get0_libctx(); \ + const char *name = TYPE ## _get0_name(alg); \ + \ + ERR_set_mark(); \ + impl = TYPE ## _fetch(libctx, name, propq); \ + ERR_pop_to_mark(); \ + if (impl == NULL) \ + return 0; \ + TYPE ## _free(impl); \ + return 1; \ + } + +IS_FETCHABLE(signature, EVP_SIGNATURE) +IS_FETCHABLE(kem, EVP_KEM) + +DEFINE_STACK_OF(EVP_KEM) + +static int kems_cmp(const EVP_KEM * const *a, + const EVP_KEM * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(EVP_KEM_get0_provider(*a)), + OSSL_PROVIDER_get0_name(EVP_KEM_get0_provider(*b))); +} + +static void collect_kem(EVP_KEM *kem, void *stack) +{ + STACK_OF(EVP_KEM) *kem_stack = stack; + + if (is_kem_fetchable(kem) + && sk_EVP_KEM_push(kem_stack, kem) > 0) { + EVP_KEM_up_ref(kem); + } +} + +static int kem_locate(const char *algo, unsigned int *idx) +{ + unsigned int i; + + for (i = 0; i < kems_algs_len; i++) { + if (strcmp(kems_algname[i], algo) == 0) { + *idx = i; + return 1; + } + } + return 0; +} + +DEFINE_STACK_OF(EVP_SIGNATURE) + +static int signatures_cmp(const EVP_SIGNATURE * const *a, + const EVP_SIGNATURE * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(EVP_SIGNATURE_get0_provider(*a)), + OSSL_PROVIDER_get0_name(EVP_SIGNATURE_get0_provider(*b))); +} + +static void collect_signatures(EVP_SIGNATURE *sig, void *stack) +{ + STACK_OF(EVP_SIGNATURE) *sig_stack = stack; + + if (is_signature_fetchable(sig) + && sk_EVP_SIGNATURE_push(sig_stack, sig) > 0) + EVP_SIGNATURE_up_ref(sig); +} + +static int sig_locate(const char *algo, unsigned int *idx) +{ + unsigned int i; + + for (i = 0; i < sigs_algs_len; i++) { + if (strcmp(sigs_algname[i], algo) == 0) { + *idx = i; + return 1; + } + } + return 0; +} + +static int get_max(const uint8_t doit[], size_t algs_len) { + size_t i = 0; + int maxcnt = 0; + + for (i = 0; i < algs_len; i++) + if (maxcnt < doit[i]) maxcnt = doit[i]; + return maxcnt; +} + int speed_main(int argc, char **argv) { CONF *conf = NULL; @@ -1387,9 +1640,12 @@ int speed_main(int argc, char **argv) int async_init = 0, multiblock = 0, pr_header = 0; uint8_t doit[ALGOR_NUM] = { 0 }; int ret = 1, misalign = 0, lengths_single = 0, aead = 0; + STACK_OF(EVP_KEM) *kem_stack = NULL; + STACK_OF(EVP_SIGNATURE) *sig_stack = NULL; long count = 0; unsigned int size_num = SIZE_NUM; unsigned int i, k, loopargs_len = 0, async_jobs = 0; + unsigned int idx; int keylen; int buflen; BIGNUM *bn = NULL; @@ -1401,7 +1657,8 @@ int speed_main(int argc, char **argv) openssl_speed_sec_t seconds = { SECONDS, RSA_SECONDS, DSA_SECONDS, ECDSA_SECONDS, ECDH_SECONDS, EdDSA_SECONDS, SM2_SECONDS, - FFDH_SECONDS }; + FFDH_SECONDS, KEM_SECONDS, + SIG_SECONDS }; static const unsigned char key32[32] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, @@ -1501,6 +1758,12 @@ int speed_main(int argc, char **argv) uint8_t ecdh_doit[EC_NUM] = { 0 }; uint8_t eddsa_doit[EdDSA_NUM] = { 0 }; + uint8_t kems_doit[MAX_KEM_NUM] = { 0 }; + uint8_t sigs_doit[MAX_SIG_NUM] = { 0 }; + + uint8_t do_kems = 0; + uint8_t do_sigs = 0; + /* checks declared curves against choices list. */ OPENSSL_assert(ed_curves[EdDSA_NUM - 1].nid == NID_ED448); OPENSSL_assert(strcmp(eddsa_choices[EdDSA_NUM - 1].name, "ed448") == 0); @@ -1643,7 +1906,8 @@ int speed_main(int argc, char **argv) case OPT_SECONDS: seconds.sym = seconds.rsa = seconds.dsa = seconds.ecdsa = seconds.ecdh = seconds.eddsa - = seconds.sm2 = seconds.ffdh = opt_int_arg(); + = seconds.sm2 = seconds.ffdh + = seconds.kem = seconds.sig = opt_int_arg(); break; case OPT_BYTES: lengths_single = opt_int_arg(); @@ -1653,6 +1917,12 @@ int speed_main(int argc, char **argv) case OPT_AEAD: aead = 1; break; + case OPT_KEM: + do_kems = 1; + break; + case OPT_SIG: + do_sigs = 1; + break; case OPT_MLOCK: domlock = 1; #if !defined(_WIN32) && !defined(OPENSSL_SYS_LINUX) @@ -1665,6 +1935,102 @@ int speed_main(int argc, char **argv) } } + /* find all KEMs currently available */ + kem_stack = sk_EVP_KEM_new(kems_cmp); + EVP_KEM_do_all_provided(app_get0_libctx(), collect_kem, kem_stack); + + kems_algs_len = 0; + + for (idx = 0; idx < (unsigned int)sk_EVP_KEM_num(kem_stack); idx++) { + EVP_KEM *kem = sk_EVP_KEM_value(kem_stack, idx); + + if (strcmp(EVP_KEM_get0_name(kem), "RSA") == 0) { + if (kems_algs_len + OSSL_NELEM(rsa_choices) >= MAX_KEM_NUM) { + BIO_printf(bio_err, + "Too many KEMs registered. Change MAX_KEM_NUM.\n"); + goto end; + } + for (i = 0; i < OSSL_NELEM(rsa_choices); i++) { + kems_doit[kems_algs_len] = 1; + kems_algname[kems_algs_len++] = OPENSSL_strdup(rsa_choices[i].name); + } + } else if (strcmp(EVP_KEM_get0_name(kem), "EC") == 0) { + if (kems_algs_len + 3 >= MAX_KEM_NUM) { + BIO_printf(bio_err, + "Too many KEMs registered. Change MAX_KEM_NUM.\n"); + goto end; + } + kems_doit[kems_algs_len] = 1; + kems_algname[kems_algs_len++] = OPENSSL_strdup("ECP-256"); + kems_doit[kems_algs_len] = 1; + kems_algname[kems_algs_len++] = OPENSSL_strdup("ECP-384"); + kems_doit[kems_algs_len] = 1; + kems_algname[kems_algs_len++] = OPENSSL_strdup("ECP-521"); + } else { + if (kems_algs_len + 1 >= MAX_KEM_NUM) { + BIO_printf(bio_err, + "Too many KEMs registered. Change MAX_KEM_NUM.\n"); + goto end; + } + kems_doit[kems_algs_len] = 1; + kems_algname[kems_algs_len++] = OPENSSL_strdup(EVP_KEM_get0_name(kem)); + } + } + sk_EVP_KEM_pop_free(kem_stack, EVP_KEM_free); + kem_stack = NULL; + + /* find all SIGNATUREs currently available */ + sig_stack = sk_EVP_SIGNATURE_new(signatures_cmp); + EVP_SIGNATURE_do_all_provided(app_get0_libctx(), collect_signatures, sig_stack); + + sigs_algs_len = 0; + + for (idx = 0; idx < (unsigned int)sk_EVP_SIGNATURE_num(sig_stack); idx++) { + EVP_SIGNATURE *s = sk_EVP_SIGNATURE_value(sig_stack, idx); + const char *sig_name = EVP_SIGNATURE_get0_name(s); + + if (strcmp(sig_name, "RSA") == 0) { + if (sigs_algs_len + OSSL_NELEM(rsa_choices) >= MAX_SIG_NUM) { + BIO_printf(bio_err, + "Too many signatures registered. Change MAX_SIG_NUM.\n"); + goto end; + } + for (i = 0; i < OSSL_NELEM(rsa_choices); i++) { + sigs_doit[sigs_algs_len] = 1; + sigs_algname[sigs_algs_len++] = OPENSSL_strdup(rsa_choices[i].name); + } + } + else if (strcmp(sig_name, "DSA") == 0) { + if (sigs_algs_len + DSA_NUM >= MAX_SIG_NUM) { + BIO_printf(bio_err, + "Too many signatures registered. Change MAX_SIG_NUM.\n"); + goto end; + } + for (i = 0; i < DSA_NUM; i++) { + sigs_doit[sigs_algs_len] = 1; + sigs_algname[sigs_algs_len++] = OPENSSL_strdup(dsa_choices[i].name); + } + } + /* skipping these algs as tested elsewhere - and b/o setup is a pain */ + else if (strcmp(sig_name, "ED25519") && + strcmp(sig_name, "ED448") && + strcmp(sig_name, "ECDSA") && + strcmp(sig_name, "HMAC") && + strcmp(sig_name, "SIPHASH") && + strcmp(sig_name, "POLY1305") && + strcmp(sig_name, "CMAC") && + strcmp(sig_name, "SM2")) { /* skip alg */ + if (sigs_algs_len + 1 >= MAX_SIG_NUM) { + BIO_printf(bio_err, + "Too many signatures registered. Change MAX_SIG_NUM.\n"); + goto end; + } + /* activate this provider algorithm */ + sigs_doit[sigs_algs_len] = 1; + sigs_algname[sigs_algs_len++] = OPENSSL_strdup(sig_name); + } + } + /* Remaining arguments are algorithms. */ argc = opt_num_rest(); argv = opt_rest(); @@ -1674,103 +2040,117 @@ int speed_main(int argc, char **argv) for (; *argv; argv++) { const char *algo = *argv; + int algo_found = 0; if (opt_found(algo, doit_choices, &i)) { doit[i] = 1; - continue; + algo_found = 1; } if (strcmp(algo, "des") == 0) { doit[D_CBC_DES] = doit[D_EDE3_DES] = 1; - continue; + algo_found = 1; } if (strcmp(algo, "sha") == 0) { doit[D_SHA1] = doit[D_SHA256] = doit[D_SHA512] = 1; - continue; + algo_found = 1; } #ifndef OPENSSL_NO_DEPRECATED_3_0 if (strcmp(algo, "openssl") == 0) /* just for compatibility */ - continue; + algo_found = 1; #endif if (HAS_PREFIX(algo, "rsa")) { if (algo[sizeof("rsa") - 1] == '\0') { memset(rsa_doit, 1, sizeof(rsa_doit)); - continue; + algo_found = 1; } if (opt_found(algo, rsa_choices, &i)) { rsa_doit[i] = 1; - continue; + algo_found = 1; } } #ifndef OPENSSL_NO_DH if (HAS_PREFIX(algo, "ffdh")) { if (algo[sizeof("ffdh") - 1] == '\0') { memset(ffdh_doit, 1, sizeof(ffdh_doit)); - continue; + algo_found = 1; } if (opt_found(algo, ffdh_choices, &i)) { ffdh_doit[i] = 2; - continue; + algo_found = 1; } } #endif if (HAS_PREFIX(algo, "dsa")) { if (algo[sizeof("dsa") - 1] == '\0') { memset(dsa_doit, 1, sizeof(dsa_doit)); - continue; + algo_found = 1; } if (opt_found(algo, dsa_choices, &i)) { dsa_doit[i] = 2; - continue; + algo_found = 1; } } if (strcmp(algo, "aes") == 0) { doit[D_CBC_128_AES] = doit[D_CBC_192_AES] = doit[D_CBC_256_AES] = 1; - continue; + algo_found = 1; } if (strcmp(algo, "camellia") == 0) { doit[D_CBC_128_CML] = doit[D_CBC_192_CML] = doit[D_CBC_256_CML] = 1; - continue; + algo_found = 1; } if (HAS_PREFIX(algo, "ecdsa")) { if (algo[sizeof("ecdsa") - 1] == '\0') { memset(ecdsa_doit, 1, sizeof(ecdsa_doit)); - continue; + algo_found = 1; } if (opt_found(algo, ecdsa_choices, &i)) { ecdsa_doit[i] = 2; - continue; + algo_found = 1; } } if (HAS_PREFIX(algo, "ecdh")) { if (algo[sizeof("ecdh") - 1] == '\0') { memset(ecdh_doit, 1, sizeof(ecdh_doit)); - continue; + algo_found = 1; } if (opt_found(algo, ecdh_choices, &i)) { ecdh_doit[i] = 2; - continue; + algo_found = 1; } } if (strcmp(algo, "eddsa") == 0) { memset(eddsa_doit, 1, sizeof(eddsa_doit)); - continue; + algo_found = 1; } if (opt_found(algo, eddsa_choices, &i)) { eddsa_doit[i] = 2; - continue; + algo_found = 1; } #ifndef OPENSSL_NO_SM2 if (strcmp(algo, "sm2") == 0) { memset(sm2_doit, 1, sizeof(sm2_doit)); - continue; + algo_found = 1; } if (opt_found(algo, sm2_choices, &i)) { sm2_doit[i] = 2; - continue; + algo_found = 1; } #endif - BIO_printf(bio_err, "%s: Unknown algorithm %s\n", prog, algo); - goto end; + if (kem_locate(algo, &idx)) { + kems_doit[idx]++; + do_kems = 1; + algo_found = 1; + } + if (sig_locate(algo, &idx)) { + sigs_doit[idx]++; + do_sigs = 1; + algo_found = 1; + } + + if (!algo_found) { + BIO_printf(bio_err, "%s: Unknown algorithm %s\n", prog, algo); + goto end; + } } /* Sanity checks */ @@ -1785,6 +2165,28 @@ int speed_main(int argc, char **argv) goto end; } } + if (kems_algs_len > 0) { + int maxcnt = get_max(kems_doit, kems_algs_len); + + if (maxcnt > 1) { + /* some algs explicitly selected */ + for (i = 0; i < kems_algs_len; i++) { + /* disable the rest */ + kems_doit[i]--; + } + } + } + if (sigs_algs_len > 0) { + int maxcnt = get_max(sigs_doit, sigs_algs_len); + + if (maxcnt > 1) { + /* some algs explicitly selected */ + for (i = 0; i < sigs_algs_len; i++) { + /* disable the rest */ + sigs_doit[i]--; + } + } + } if (multiblock) { if (evp_cipher == NULL) { BIO_printf(bio_err, "-mb can be used only with a multi-block" @@ -1871,7 +2273,8 @@ int speed_main(int argc, char **argv) e = setup_engine(engine_id, 0); /* No parameters; turn on everything. */ - if (argc == 0 && !doit[D_EVP] && !doit[D_HMAC] && !doit[D_EVP_CMAC]) { + if (argc == 0 && !doit[D_EVP] && !doit[D_HMAC] + && !doit[D_EVP_CMAC] && !do_kems && !do_sigs) { memset(doit, 1, sizeof(doit)); doit[D_EVP] = doit[D_EVP_CMAC] = 0; ERR_set_mark(); @@ -1909,6 +2312,10 @@ int speed_main(int argc, char **argv) #ifndef OPENSSL_NO_SM2 memset(sm2_doit, 1, sizeof(sm2_doit)); #endif + memset(kems_doit, 1, sizeof(kems_doit)); + do_kems = 1; + memset(sigs_doit, 1, sizeof(sigs_doit)); + do_sigs = 1; } for (i = 0; i < ALGOR_NUM; i++) if (doit[i]) @@ -3170,6 +3577,371 @@ skip_hmac: } } #endif /* OPENSSL_NO_DH */ + + for (testnum = 0; testnum < kems_algs_len; testnum++) { + int kem_checks = 1; + const char *kem_name = kems_algname[testnum]; + + if (!kems_doit[testnum] || !do_kems) + continue; + + for (i = 0; i < loopargs_len; i++) { + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *kem_gen_ctx = NULL; + EVP_PKEY_CTX *kem_encaps_ctx = NULL; + EVP_PKEY_CTX *kem_decaps_ctx = NULL; + size_t send_secret_len, out_len; + size_t rcv_secret_len; + unsigned char *out = NULL, *send_secret = NULL, *rcv_secret; + size_t bits; + char *name; + OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END }; + int use_params = 0; + enum kem_type_t { KEM_RSA = 1, KEM_EC, KEM_X25519, KEM_X448 } kem_type; + + if (strncmp(kem_name, "rsa", 3) == 0) + kem_type = KEM_RSA; + else if (strncmp(kem_name, "EC", 2) == 0) + kem_type = KEM_EC; + else if (strcmp(kem_name, "X25519") == 0) + kem_type = KEM_X25519; + else if (strcmp(kem_name, "X448") == 0) + kem_type = KEM_X448; + else kem_type = 0; + + if (ERR_peek_error()) { + BIO_printf(bio_err, + "WARNING: the error queue contains previous unhandled errors.\n"); + ERR_print_errors(bio_err); + } + + if (kem_type == KEM_RSA) { + bits = atoi(kem_name + 3); + params[0] = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_RSA_BITS, + &bits); + use_params = 1; + } else if (kem_type == KEM_EC) { + name = (char *)(kem_name + 2); + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + name, 0); + use_params = 1; + } + + kem_gen_ctx = EVP_PKEY_CTX_new_from_name(app_get0_libctx(), + (kem_type == KEM_RSA) ? "RSA": + (kem_type == KEM_EC) ? "EC": + kem_name, + app_get0_propq()); + + if ((!kem_gen_ctx || EVP_PKEY_keygen_init(kem_gen_ctx) <= 0) + || (use_params + && EVP_PKEY_CTX_set_params(kem_gen_ctx, params) <= 0)) { + BIO_printf(bio_err, "Error initializing keygen ctx for %s.\n", + kem_name); + goto kem_err_break; + } + if (EVP_PKEY_keygen(kem_gen_ctx, &pkey) <= 0) { + BIO_printf(bio_err, "Error while generating KEM EVP_PKEY.\n"); + goto kem_err_break; + } + /* Now prepare encaps data structs */ + kem_encaps_ctx = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), + pkey, + app_get0_propq()); + if (kem_encaps_ctx == NULL + || EVP_PKEY_encapsulate_init(kem_encaps_ctx, NULL) <= 0 + || (kem_type == KEM_RSA + && EVP_PKEY_CTX_set_kem_op(kem_encaps_ctx, "RSASVE") <= 0) + || ((kem_type == KEM_EC + || kem_type == KEM_X25519 + || kem_type == KEM_X448) + && EVP_PKEY_CTX_set_kem_op(kem_encaps_ctx, "DHKEM") <= 0) + || EVP_PKEY_encapsulate(kem_encaps_ctx, NULL, &out_len, + NULL, &send_secret_len) <= 0) { + BIO_printf(bio_err, + "Error while initializing encaps data structs for %s.\n", + kem_name); + goto kem_err_break; + } + out = app_malloc(out_len, "encaps result"); + send_secret = app_malloc(send_secret_len, "encaps secret"); + if (out == NULL || send_secret == NULL) { + BIO_printf(bio_err, "MemAlloc error in encaps for %s.\n", kem_name); + goto kem_err_break; + } + if (EVP_PKEY_encapsulate(kem_encaps_ctx, out, &out_len, + send_secret, &send_secret_len) <= 0) { + BIO_printf(bio_err, "Encaps error for %s.\n", kem_name); + goto kem_err_break; + } + /* Now prepare decaps data structs */ + kem_decaps_ctx = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), + pkey, + app_get0_propq()); + if (kem_decaps_ctx == NULL + || EVP_PKEY_decapsulate_init(kem_decaps_ctx, NULL) <= 0 + || (kem_type == KEM_RSA + && EVP_PKEY_CTX_set_kem_op(kem_decaps_ctx, "RSASVE") <= 0) + || ((kem_type == KEM_EC + || kem_type == KEM_X25519 + || kem_type == KEM_X448) + && EVP_PKEY_CTX_set_kem_op(kem_decaps_ctx, "DHKEM") <= 0) + || EVP_PKEY_decapsulate(kem_decaps_ctx, NULL, &rcv_secret_len, + out, out_len) <= 0) { + BIO_printf(bio_err, + "Error while initializing decaps data structs for %s.\n", + kem_name); + goto kem_err_break; + } + rcv_secret = app_malloc(rcv_secret_len, "KEM decaps secret"); + if (rcv_secret == NULL) { + BIO_printf(bio_err, "MemAlloc failure in decaps for %s.\n", + kem_name); + goto kem_err_break; + } + if (EVP_PKEY_decapsulate(kem_decaps_ctx, rcv_secret, + &rcv_secret_len, out, out_len) <= 0 + || rcv_secret_len != send_secret_len + || memcmp(send_secret, rcv_secret, send_secret_len)) { + BIO_printf(bio_err, "Decaps error for %s.\n", kem_name); + goto kem_err_break; + } + loopargs[i].kem_gen_ctx[testnum] = kem_gen_ctx; + loopargs[i].kem_encaps_ctx[testnum] = kem_encaps_ctx; + loopargs[i].kem_decaps_ctx[testnum] = kem_decaps_ctx; + loopargs[i].kem_out_len[testnum] = out_len; + loopargs[i].kem_secret_len[testnum] = send_secret_len; + loopargs[i].kem_out[testnum] = out; + loopargs[i].kem_send_secret[testnum] = send_secret; + loopargs[i].kem_rcv_secret[testnum] = rcv_secret; + break; + + kem_err_break: + ERR_print_errors(bio_err); + op_count = 1; + kem_checks = 0; + break; + } + if (kem_checks != 0) { + kskey_print_message(kem_name, "keygen", kems_c[testnum][0], + seconds.kem); + Time_F(START); + count = + run_benchmark(async_jobs, KEM_keygen_loop, loopargs); + d = Time_F(STOP); + BIO_printf(bio_err, + mr ? "+R13:%ld:%s:%.2f\n" : + "%ld %s KEM keygens in %.2fs\n", count, + kem_name, d); + kems_results[testnum][0] = (double)count / d; + op_count = count; + kskey_print_message(kem_name, "encaps", kems_c[testnum][1], + seconds.kem); + Time_F(START); + count = + run_benchmark(async_jobs, KEM_encaps_loop, loopargs); + d = Time_F(STOP); + BIO_printf(bio_err, + mr ? "+R14:%ld:%s:%.2f\n" : + "%ld %s KEM encaps in %.2fs\n", count, + kem_name, d); + kems_results[testnum][1] = (double)count / d; + op_count = count; + kskey_print_message(kem_name, "decaps", kems_c[testnum][2], + seconds.kem); + Time_F(START); + count = + run_benchmark(async_jobs, KEM_decaps_loop, loopargs); + d = Time_F(STOP); + BIO_printf(bio_err, + mr ? "+R15:%ld:%s:%.2f\n" : + "%ld %s KEM decaps in %.2fs\n", count, + kem_name, d); + kems_results[testnum][2] = (double)count / d; + op_count = count; + } + if (op_count <= 1) { + /* if longer than 10s, don't do any more */ + stop_it(kems_doit, testnum); + } + } + + for (testnum = 0; testnum < sigs_algs_len; testnum++) { + int sig_checks = 1; + const char *sig_name = sigs_algname[testnum]; + + if (!sigs_doit[testnum] || !do_sigs) + continue; + + for (i = 0; i < loopargs_len; i++) { + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx_params = NULL; + EVP_PKEY* pkey_params = NULL; + EVP_PKEY_CTX *sig_gen_ctx = NULL; + EVP_PKEY_CTX *sig_sign_ctx = NULL; + EVP_PKEY_CTX *sig_verify_ctx = NULL; + unsigned char md[SHA256_DIGEST_LENGTH]; + unsigned char *sig; + size_t md_len = SHA256_DIGEST_LENGTH; + size_t max_sig_len, sig_len; + size_t bits; + OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END }; + int use_params = 0; + + /* only sign little data to avoid measuring digest performance */ + memset(md, 0, SHA256_DIGEST_LENGTH); + + if (ERR_peek_error()) { + BIO_printf(bio_err, + "WARNING: the error queue contains previous unhandled errors.\n"); + ERR_print_errors(bio_err); + } + + if (strncmp(sig_name, "rsa", 3) == 0) { + bits = atoi(sig_name + 3); + params[0] = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_RSA_BITS, + &bits); + use_params = 1; + } + + if (strncmp(sig_name, "dsa", 3) == 0) { + ctx_params = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL); + if (ctx_params == NULL + || EVP_PKEY_paramgen_init(ctx_params) <= 0 + || EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx_params, + atoi(sig_name + 3)) <= 0 + || EVP_PKEY_paramgen(ctx_params, &pkey_params) <= 0 + || (sig_gen_ctx = EVP_PKEY_CTX_new(pkey_params, NULL)) == NULL + || EVP_PKEY_keygen_init(sig_gen_ctx) <= 0) { + BIO_printf(bio_err, + "Error initializing classic keygen ctx for %s.\n", + sig_name); + goto sig_err_break; + } + } + + if (sig_gen_ctx == NULL) + sig_gen_ctx = EVP_PKEY_CTX_new_from_name(app_get0_libctx(), + (strncmp(sig_name, "rsa", 3) == 0) ? "RSA" : sig_name, + app_get0_propq()); + + if (!sig_gen_ctx || EVP_PKEY_keygen_init(sig_gen_ctx) <= 0 + || (use_params && + EVP_PKEY_CTX_set_params(sig_gen_ctx, params) <= 0)) { + BIO_printf(bio_err, "Error initializing keygen ctx for %s.\n", + sig_name); + goto sig_err_break; + } + if (EVP_PKEY_keygen(sig_gen_ctx, &pkey) <= 0) { + BIO_printf(bio_err, + "Error while generating signature EVP_PKEY for %s.\n", + sig_name); + goto sig_err_break; + } + /* Now prepare signature data structs */ + sig_sign_ctx = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), + pkey, + app_get0_propq()); + if (sig_sign_ctx == NULL + || EVP_PKEY_sign_init(sig_sign_ctx) <= 0 + || (strncmp(sig_name, "rsa", 3) == 0 + && (EVP_PKEY_CTX_set_rsa_padding(sig_sign_ctx, + RSA_PKCS1_PADDING) <= 0)) + || EVP_PKEY_sign(sig_sign_ctx, NULL, &max_sig_len, + md, md_len) <= 0) { + BIO_printf(bio_err, + "Error while initializing signing data structs for %s.\n", + sig_name); + goto sig_err_break; + } + sig = app_malloc(sig_len = max_sig_len, "signature buffer"); + if (sig == NULL) { + BIO_printf(bio_err, "MemAlloc error in sign for %s.\n", sig_name); + goto sig_err_break; + } + if (EVP_PKEY_sign(sig_sign_ctx, sig, &sig_len, md, md_len) <= 0) { + BIO_printf(bio_err, "Signing error for %s.\n", sig_name); + goto sig_err_break; + } + /* Now prepare verify data structs */ + memset(md, 0, SHA256_DIGEST_LENGTH); + sig_verify_ctx = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), + pkey, + app_get0_propq()); + if (sig_verify_ctx == NULL + || EVP_PKEY_verify_init(sig_verify_ctx) <= 0 + || (strncmp(sig_name, "rsa", 3) == 0 + && (EVP_PKEY_CTX_set_rsa_padding(sig_verify_ctx, + RSA_PKCS1_PADDING) <= 0))) { + BIO_printf(bio_err, + "Error while initializing verify data structs for %s.\n", + sig_name); + goto sig_err_break; + } + if (EVP_PKEY_verify(sig_verify_ctx, sig, sig_len, md, md_len) <= 0) { + BIO_printf(bio_err, "Verify error for %s.\n", sig_name); + goto sig_err_break; + } + if (EVP_PKEY_verify(sig_verify_ctx, sig, sig_len, md, md_len) <= 0) { + BIO_printf(bio_err, "Verify 2 error for %s.\n", sig_name); + goto sig_err_break; + } + loopargs[i].sig_gen_ctx[testnum] = sig_gen_ctx; + loopargs[i].sig_sign_ctx[testnum] = sig_sign_ctx; + loopargs[i].sig_verify_ctx[testnum] = sig_verify_ctx; + loopargs[i].sig_max_sig_len[testnum] = max_sig_len; + loopargs[i].sig_act_sig_len[testnum] = sig_len; + loopargs[i].sig_sig[testnum] = sig; + break; + + sig_err_break: + ERR_print_errors(bio_err); + op_count = 1; + sig_checks = 0; + break; + } + + if (sig_checks != 0) { + kskey_print_message(sig_name, "keygen", sigs_c[testnum][0], seconds.sig); + Time_F(START); + count = run_benchmark(async_jobs, SIG_keygen_loop, loopargs); + d = Time_F(STOP); + BIO_printf(bio_err, + mr ? "+R16:%ld:%s:%.2f\n" : + "%ld %s signature keygens in %.2fs\n", count, + sig_name, d); + sigs_results[testnum][0] = (double)count / d; + op_count = count; + kskey_print_message(sig_name, "signs", sigs_c[testnum][1], + seconds.sig); + Time_F(START); + count = + run_benchmark(async_jobs, SIG_sign_loop, loopargs); + d = Time_F(STOP); + BIO_printf(bio_err, + mr ? "+R17:%ld:%s:%.2f\n" : + "%ld %s signature signs in %.2fs\n", count, + sig_name, d); + sigs_results[testnum][1] = (double)count / d; + op_count = count; + + kskey_print_message(sig_name, "verify", sigs_c[testnum][2], + seconds.sig); + Time_F(START); + count = + run_benchmark(async_jobs, SIG_verify_loop, loopargs); + d = Time_F(STOP); + BIO_printf(bio_err, + mr ? "+R18:%ld:%s:%.2f\n" : + "%ld %s signature verifys in %.2fs\n", count, + sig_name, d); + sigs_results[testnum][2] = (double)count / d; + op_count = count; + } + if (op_count <= 1) + stop_it(sigs_doit, testnum); + } + #ifndef NO_FORK show_res: #endif @@ -3221,7 +3993,8 @@ skip_hmac: k, rsa_keys[k].bits, rsa_results[k][0], rsa_results[k][1]); else printf("rsa %4u bits %8.6fs %8.6fs %8.1f %8.1f\n", - rsa_keys[k].bits, 1.0 / rsa_results[k][0], 1.0 / rsa_results[k][1], + rsa_keys[k].bits, 1.0 / rsa_results[k][0], + 1.0 / rsa_results[k][1], rsa_results[k][0], rsa_results[k][1]); } testnum = 1; @@ -3341,6 +4114,48 @@ skip_hmac: } #endif /* OPENSSL_NO_DH */ + testnum = 1; + for (k = 0; k < kems_algs_len; k++) { + const char *kem_name = kems_algname[k]; + + if (!kems_doit[k] || !do_kems) + continue; + if (testnum && !mr) { + printf("%31skeygen encaps decaps keygens/s encaps/s decaps/s\n", " "); + testnum = 0; + } + if (mr) + printf("+F9:%u:%f:%f:%f\n", + k, kems_results[k][0], kems_results[k][1], + kems_results[k][2]); + else + printf("%27s %8.6fs %8.6fs %8.6fs %9.1f %9.1f %9.1f\n", kem_name, + 1.0 / kems_results[k][0], + 1.0 / kems_results[k][1], 1.0 / kems_results[k][2], + kems_results[k][0], kems_results[k][1], kems_results[k][2]); + } + ret = 0; + + testnum = 1; + for (k = 0; k < sigs_algs_len; k++) { + const char *sig_name = sigs_algname[k]; + + if (!sigs_doit[k] || !do_sigs) + continue; + if (testnum && !mr) { + printf("%31skeygen signs verify keygens/s sign/s verify/s\n", " "); + testnum = 0; + } + if (mr) + printf("+F10:%u:%f:%f:%f\n", + k, sigs_results[k][0], sigs_results[k][1], + sigs_results[k][2]); + else + printf("%27s %8.6fs %8.6fs %8.6fs %9.1f %9.1f %9.1f\n", sig_name, + 1.0 / sigs_results[k][0], 1.0 / sigs_results[k][1], + 1.0 / sigs_results[k][2], sigs_results[k][0], + sigs_results[k][1], sigs_results[k][2]); + } ret = 0; end: @@ -3393,11 +4208,29 @@ skip_hmac: EVP_PKEY_free(loopargs[i].sm2_pkey[k]); } #endif + for (k = 0; k < kems_algs_len; k++) { + EVP_PKEY_CTX_free(loopargs[i].kem_gen_ctx[k]); + EVP_PKEY_CTX_free(loopargs[i].kem_encaps_ctx[k]); + EVP_PKEY_CTX_free(loopargs[i].kem_decaps_ctx[k]); + OPENSSL_free(loopargs[i].kem_out[k]); + OPENSSL_free(loopargs[i].kem_send_secret[k]); + OPENSSL_free(loopargs[i].kem_rcv_secret[k]); + } + for (k = 0; k < sigs_algs_len; k++) { + EVP_PKEY_CTX_free(loopargs[i].sig_gen_ctx[k]); + EVP_PKEY_CTX_free(loopargs[i].sig_sign_ctx[k]); + EVP_PKEY_CTX_free(loopargs[i].sig_verify_ctx[k]); + OPENSSL_free(loopargs[i].sig_sig[k]); + } OPENSSL_free(loopargs[i].secret_a); OPENSSL_free(loopargs[i].secret_b); } OPENSSL_free(evp_hmac_name); OPENSSL_free(evp_cmac_name); + for (k = 0; k < kems_algs_len; k++) + OPENSSL_free(kems_algname[k]); + for (k = 0; k < sigs_algs_len; k++) + OPENSSL_free(sigs_algname[k]); if (async_jobs > 0) { for (i = 0; i < loopargs_len; i++) @@ -3436,6 +4269,17 @@ static void pkey_print_message(const char *str, const char *str2, long num, alarm(tm); } +static void kskey_print_message(const char *str, const char *str2, + long num, int tm) +{ + BIO_printf(bio_err, + mr ? "+DTP:%s:%s:%d\n" + : "Doing %s %s's for %ds: ", str, str2, tm); + (void)BIO_flush(bio_err); + run = 1; + alarm(tm); +} + static void print_result(int alg, int run_no, int count, double time_used) { if (count == -1) { @@ -3639,6 +4483,30 @@ static int do_multi(int multi, int size_num) ffdh_results[k][0] += d; } # endif /* OPENSSL_NO_DH */ + } else if (CHECK_AND_SKIP_PREFIX(p, "+F9:")) { + tk = sstrsep(&p, sep); + if (strtoint(tk, 0, OSSL_NELEM(kems_results), &k)) { + d = atof(sstrsep(&p, sep)); + kems_results[k][0] += d; + + d = atof(sstrsep(&p, sep)); + kems_results[k][1] += d; + + d = atof(sstrsep(&p, sep)); + kems_results[k][2] += d; + } + } else if (CHECK_AND_SKIP_PREFIX(p, "+F10:")) { + tk = sstrsep(&p, sep); + if (strtoint(tk, 0, OSSL_NELEM(sigs_results), &k)) { + d = atof(sstrsep(&p, sep)); + sigs_results[k][0] += d; + + d = atof(sstrsep(&p, sep)); + sigs_results[k][1] += d; + + d = atof(sstrsep(&p, sep)); + sigs_results[k][2] += d; + } } else if (!HAS_PREFIX(buf, "+H:")) { BIO_printf(bio_err, "Unknown type '%s' from child %d\n", buf, n); diff --git a/doc/man1/openssl-speed.pod.in b/doc/man1/openssl-speed.pod.in index ab76ca6f13..38e95720a3 100644 --- a/doc/man1/openssl-speed.pod.in +++ b/doc/man1/openssl-speed.pod.in @@ -16,6 +16,8 @@ B<openssl speed> [B<-cmac> I<algo>] [B<-mb>] [B<-aead>] +[B<-kem-algorithms>] +[B<-signature-algorithms>] [B<-multi> I<num>] [B<-async_jobs> I<num>] [B<-misalign> I<num>] @@ -97,6 +99,14 @@ Enable multi-block mode on EVP-named cipher. Benchmark EVP-named AEAD cipher in TLS-like sequence. +=item B<-kem-algorithms> + +Benchmark KEM algorithms: key generation, encapsulation, decapsulation. + +=item B<-signature-algorithms> + +Benchmark signature algorithms: key generation, signature, verification. + =item B<-primes> I<num> Generate a I<num>-prime RSA key and use it to run the benchmarks. This option |