+ EVP_PKEY_CTX *kctx = NULL;
+ EVP_PKEY_CTX *test_ctx = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *key_A = NULL;
+ EVP_PKEY *key_B = NULL;
+ size_t outlen;
+ size_t test_outlen;
+
+ /* Ensure that the error queue is empty */
+ if (ERR_peek_error()) {
+ BIO_printf(bio_err,
+ "WARNING: the error queue contains previous unhandled errors.\n");
+ ERR_print_errors(bio_err);
+ }
+
+ /* Let's try to create a ctx directly from the NID: this works for
+ * curves like Curve25519 that are not implemented through the low
+ * level EC interface.
+ * If this fails we try creating a EVP_PKEY_EC generic param ctx,
+ * then we set the curve by NID before deriving the actual keygen
+ * ctx for that specific curve. */
+ kctx = EVP_PKEY_CTX_new_id(test_curves[testnum].nid, NULL); /* keygen ctx from NID */
+ if (!kctx) {
+ EVP_PKEY_CTX *pctx = NULL;
+ EVP_PKEY *params = NULL;
+
+ /* If we reach this code EVP_PKEY_CTX_new_id() failed and a
+ * "int_ctx_new:unsupported algorithm" error was added to the
+ * error queue.
+ * We remove it from the error queue as we are handling it. */
+ unsigned long error = ERR_peek_error(); /* peek the latest error in the queue */
+ if (error == ERR_peek_last_error() && /* oldest and latest errors match */
+ /* check that the error origin matches */
+ ERR_GET_LIB(error) == ERR_LIB_EVP &&
+ ERR_GET_FUNC(error) == EVP_F_INT_CTX_NEW &&
+ ERR_GET_REASON(error) == EVP_R_UNSUPPORTED_ALGORITHM)
+ ERR_get_error(); /* pop error from queue */
+ if (ERR_peek_error()) {
+ BIO_printf(bio_err,
+ "Unhandled error in the error queue during ECDH init.\n");
+ ERR_print_errors(bio_err);
+ rsa_count = 1;
+ break;
+ }
+
+ if ( /* Create the context for parameter generation */
+ !(pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) ||
+ /* Initialise the parameter generation */
+ !EVP_PKEY_paramgen_init(pctx) ||
+ /* Set the curve by NID */
+ !EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx,
+ test_curves
+ [testnum].nid) ||
+ /* Create the parameter object params */
+ !EVP_PKEY_paramgen(pctx, ¶ms)) {
+ ecdh_checks = 0;
+ BIO_printf(bio_err, "ECDH EC params init failure.\n");
+ ERR_print_errors(bio_err);
+ rsa_count = 1;
+ break;
+ }
+ /* Create the context for the key generation */
+ kctx = EVP_PKEY_CTX_new(params, NULL);
+
+ EVP_PKEY_free(params);
+ params = NULL;
+ EVP_PKEY_CTX_free(pctx);
+ pctx = NULL;
+ }
+ if (kctx == NULL || /* keygen ctx is not null */
+ !EVP_PKEY_keygen_init(kctx) /* init keygen ctx */ ) {
+ ecdh_checks = 0;
+ BIO_printf(bio_err, "ECDH keygen failure.\n");
+ ERR_print_errors(bio_err);
+ rsa_count = 1;
+ break;
+ }
+
+ if (!EVP_PKEY_keygen(kctx, &key_A) || /* generate secret key A */
+ !EVP_PKEY_keygen(kctx, &key_B) || /* generate secret key B */
+ !(ctx = EVP_PKEY_CTX_new(key_A, NULL)) || /* derivation ctx from skeyA */
+ !EVP_PKEY_derive_init(ctx) || /* init derivation ctx */
+ !EVP_PKEY_derive_set_peer(ctx, key_B) || /* set peer pubkey in ctx */
+ !EVP_PKEY_derive(ctx, NULL, &outlen) || /* determine max length */
+ outlen == 0 || /* ensure outlen is a valid size */
+ outlen > MAX_ECDH_SIZE /* avoid buffer overflow */ ) {
+ ecdh_checks = 0;
+ BIO_printf(bio_err, "ECDH key generation failure.\n");
+ ERR_print_errors(bio_err);
+ rsa_count = 1;
+ break;
+ }
+
+ /* Here we perform a test run, comparing the output of a*B and b*A;
+ * we try this here and assume that further EVP_PKEY_derive calls
+ * never fail, so we can skip checks in the actually benchmarked
+ * code, for maximum performance. */
+ if (!(test_ctx = EVP_PKEY_CTX_new(key_B, NULL)) || /* test ctx from skeyB */
+ !EVP_PKEY_derive_init(test_ctx) || /* init derivation test_ctx */
+ !EVP_PKEY_derive_set_peer(test_ctx, key_A) || /* set peer pubkey in test_ctx */
+ !EVP_PKEY_derive(test_ctx, NULL, &test_outlen) || /* determine max length */
+ !EVP_PKEY_derive(ctx, loopargs[i].secret_a, &outlen) || /* compute a*B */
+ !EVP_PKEY_derive(test_ctx, loopargs[i].secret_b, &test_outlen) || /* compute b*A */
+ test_outlen != outlen /* compare output length */ ) {
+ ecdh_checks = 0;
+ BIO_printf(bio_err, "ECDH computation failure.\n");
+ ERR_print_errors(bio_err);
+ rsa_count = 1;
+ break;
+ }
+
+ /* Compare the computation results: CRYPTO_memcmp() returns 0 if equal */
+ if (CRYPTO_memcmp(loopargs[i].secret_a,
+ loopargs[i].secret_b, outlen)) {