freebsd-src/crypto/openssl/apps/ec.c
Pierre Pronchery b077aed33b Merge OpenSSL 3.0.9
Migrate to OpenSSL 3.0 in advance of FreeBSD 14.0.  OpenSSL 1.1.1 (the
version we were previously using) will be EOL as of 2023-09-11.

Most of the base system has already been updated for a seamless switch
to OpenSSL 3.0.  For many components we've added
`-DOPENSSL_API_COMPAT=0x10100000L` to CFLAGS to specify the API version,
which avoids deprecation warnings from OpenSSL 3.0.  Changes have also
been made to avoid OpenSSL APIs that were already deprecated in OpenSSL
1.1.1.  The process of updating to contemporary APIs can continue after
this merge.

Additional changes are still required for libarchive and Kerberos-
related libraries or tools; workarounds will immediately follow this
commit.  Fixes are in progress in the upstream projects and will be
incorporated when those are next updated.

There are some performance regressions in benchmarks (certain tests in
`openssl speed`) and in some OpenSSL consumers in ports (e.g.  haproxy).
Investigation will continue for these.

Netflix's testing showed no functional regression and a rather small,
albeit statistically significant, increase in CPU consumption with
OpenSSL 3.0.

Thanks to ngie@ and des@ for updating base system components, to
antoine@ and bofh@ for ports exp-runs and port fixes/workarounds, and to
Netflix and everyone who tested prior to commit or contributed to this
update in other ways.

PR:		271615
PR:		271656 [exp-run]
Relnotes:	Yes
Sponsored by:	The FreeBSD Foundation
2023-06-23 18:53:36 -04:00

295 lines
9.2 KiB
C

/*
* Copyright 2002-2022 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <string.h>
#include <openssl/opensslconf.h>
#include <openssl/evp.h>
#include <openssl/encoder.h>
#include <openssl/decoder.h>
#include <openssl/core_names.h>
#include <openssl/core_dispatch.h>
#include <openssl/params.h>
#include <openssl/err.h>
#include "apps.h"
#include "progs.h"
#include "ec_common.h"
typedef enum OPTION_choice {
OPT_COMMON,
OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_IN, OPT_OUT,
OPT_NOOUT, OPT_TEXT, OPT_PARAM_OUT, OPT_PUBIN, OPT_PUBOUT,
OPT_PASSIN, OPT_PASSOUT, OPT_PARAM_ENC, OPT_CONV_FORM, OPT_CIPHER,
OPT_NO_PUBLIC, OPT_CHECK, OPT_PROV_ENUM
} OPTION_CHOICE;
const OPTIONS ec_options[] = {
OPT_SECTION("General"),
{"help", OPT_HELP, '-', "Display this summary"},
#ifndef OPENSSL_NO_ENGINE
{"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
#endif
OPT_SECTION("Input"),
{"in", OPT_IN, 's', "Input file"},
{"inform", OPT_INFORM, 'f', "Input format (DER/PEM/P12/ENGINE)"},
{"pubin", OPT_PUBIN, '-', "Expect a public key in input file"},
{"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
{"check", OPT_CHECK, '-', "check key consistency"},
{"", OPT_CIPHER, '-', "Any supported cipher"},
{"param_enc", OPT_PARAM_ENC, 's',
"Specifies the way the ec parameters are encoded"},
{"conv_form", OPT_CONV_FORM, 's', "Specifies the point conversion form "},
OPT_SECTION("Output"),
{"out", OPT_OUT, '>', "Output file"},
{"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"},
{"noout", OPT_NOOUT, '-', "Don't print key out"},
{"text", OPT_TEXT, '-', "Print the key"},
{"param_out", OPT_PARAM_OUT, '-', "Print the elliptic curve parameters"},
{"pubout", OPT_PUBOUT, '-', "Output public key, not private"},
{"no_public", OPT_NO_PUBLIC, '-', "exclude public key from private key"},
{"passout", OPT_PASSOUT, 's', "Output file pass phrase source"},
OPT_PROV_OPTIONS,
{NULL}
};
int ec_main(int argc, char **argv)
{
OSSL_ENCODER_CTX *ectx = NULL;
OSSL_DECODER_CTX *dctx = NULL;
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *eckey = NULL;
BIO *out = NULL;
ENGINE *e = NULL;
EVP_CIPHER *enc = NULL;
char *infile = NULL, *outfile = NULL, *ciphername = NULL, *prog;
char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL;
OPTION_CHOICE o;
int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, text = 0, noout = 0;
int pubin = 0, pubout = 0, param_out = 0, ret = 1, private = 0;
int check = 0;
char *asn1_encoding = NULL;
char *point_format = NULL;
int no_public = 0;
prog = opt_init(argc, argv, ec_options);
while ((o = opt_next()) != OPT_EOF) {
switch (o) {
case OPT_EOF:
case OPT_ERR:
opthelp:
BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
goto end;
case OPT_HELP:
opt_help(ec_options);
ret = 0;
goto end;
case OPT_INFORM:
if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat))
goto opthelp;
break;
case OPT_IN:
infile = opt_arg();
break;
case OPT_OUTFORM:
if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
goto opthelp;
break;
case OPT_OUT:
outfile = opt_arg();
break;
case OPT_NOOUT:
noout = 1;
break;
case OPT_TEXT:
text = 1;
break;
case OPT_PARAM_OUT:
param_out = 1;
break;
case OPT_PUBIN:
pubin = 1;
break;
case OPT_PUBOUT:
pubout = 1;
break;
case OPT_PASSIN:
passinarg = opt_arg();
break;
case OPT_PASSOUT:
passoutarg = opt_arg();
break;
case OPT_ENGINE:
e = setup_engine(opt_arg(), 0);
break;
case OPT_CIPHER:
ciphername = opt_unknown();
break;
case OPT_CONV_FORM:
point_format = opt_arg();
if (!opt_string(point_format, point_format_options))
goto opthelp;
break;
case OPT_PARAM_ENC:
asn1_encoding = opt_arg();
if (!opt_string(asn1_encoding, asn1_encoding_options))
goto opthelp;
break;
case OPT_NO_PUBLIC:
no_public = 1;
break;
case OPT_CHECK:
check = 1;
break;
case OPT_PROV_CASES:
if (!opt_provider(o))
goto end;
break;
}
}
/* No extra arguments. */
argc = opt_num_rest();
if (argc != 0)
goto opthelp;
if (ciphername != NULL) {
if (!opt_cipher(ciphername, &enc))
goto opthelp;
}
private = param_out || pubin || pubout ? 0 : 1;
if (text && !pubin)
private = 1;
if (!app_passwd(passinarg, passoutarg, &passin, &passout)) {
BIO_printf(bio_err, "Error getting passwords\n");
goto end;
}
BIO_printf(bio_err, "read EC key\n");
if (pubin)
eckey = load_pubkey(infile, informat, 1, passin, e, "public key");
else
eckey = load_key(infile, informat, 1, passin, e, "private key");
if (eckey == NULL) {
BIO_printf(bio_err, "unable to load Key\n");
goto end;
}
out = bio_open_owner(outfile, outformat, private);
if (out == NULL)
goto end;
if (point_format
&& !EVP_PKEY_set_utf8_string_param(
eckey, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
point_format)) {
BIO_printf(bio_err, "unable to set point conversion format\n");
goto end;
}
if (asn1_encoding != NULL
&& !EVP_PKEY_set_utf8_string_param(
eckey, OSSL_PKEY_PARAM_EC_ENCODING, asn1_encoding)) {
BIO_printf(bio_err, "unable to set asn1 encoding format\n");
goto end;
}
if (no_public) {
if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 0)) {
BIO_printf(bio_err, "unable to disable public key encoding\n");
goto end;
}
} else {
if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 1)) {
BIO_printf(bio_err, "unable to enable public key encoding\n");
goto end;
}
}
if (text) {
assert(pubin || private);
if ((pubin && EVP_PKEY_print_public(out, eckey, 0, NULL) <= 0)
|| (!pubin && EVP_PKEY_print_private(out, eckey, 0, NULL) <= 0)) {
BIO_printf(bio_err, "unable to print EC key\n");
goto end;
}
}
if (check) {
pctx = EVP_PKEY_CTX_new_from_pkey(NULL, eckey, NULL);
if (pctx == NULL) {
BIO_printf(bio_err, "unable to check EC key\n");
goto end;
}
if (EVP_PKEY_check(pctx) <= 0)
BIO_printf(bio_err, "EC Key Invalid!\n");
else
BIO_printf(bio_err, "EC Key valid.\n");
ERR_print_errors(bio_err);
}
if (!noout) {
int selection;
const char *output_type = outformat == FORMAT_ASN1 ? "DER" : "PEM";
const char *output_structure = "type-specific";
BIO_printf(bio_err, "writing EC key\n");
if (param_out) {
selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS;
} else if (pubin || pubout) {
selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS
| OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
output_structure = "SubjectPublicKeyInfo";
} else {
selection = OSSL_KEYMGMT_SELECT_ALL;
assert(private);
}
ectx = OSSL_ENCODER_CTX_new_for_pkey(eckey, selection,
output_type, output_structure,
NULL);
if (enc != NULL) {
OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL);
/* Default passphrase prompter */
OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL);
if (passout != NULL)
/* When passout given, override the passphrase prompter */
OSSL_ENCODER_CTX_set_passphrase(ectx,
(const unsigned char *)passout,
strlen(passout));
}
if (!OSSL_ENCODER_to_bio(ectx, out)) {
BIO_printf(bio_err, "unable to write EC key\n");
goto end;
}
}
ret = 0;
end:
if (ret != 0)
ERR_print_errors(bio_err);
BIO_free_all(out);
EVP_PKEY_free(eckey);
EVP_CIPHER_free(enc);
OSSL_ENCODER_CTX_free(ectx);
OSSL_DECODER_CTX_free(dctx);
EVP_PKEY_CTX_free(pctx);
release_engine(e);
if (passin != NULL)
OPENSSL_clear_free(passin, strlen(passin));
if (passout != NULL)
OPENSSL_clear_free(passout, strlen(passout));
return ret;
}