diff --git a/CHANGES.md b/CHANGES.md index 93365619fa8f8f..6109befe0ac348 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -33,6 +33,11 @@ OpenSSL 3.3 *James Muir* + * The `-rawin` option of the `pkeyutl` apps is now implied (and thus no more + required) when signing or verifying with an Ed25519 or Ed448 key. + + *David von Oheimb* + * The build of exporters (such as `.pc` files for pkg-config) cleaned up to be less hard coded in the build file templates, and to allow easier addition of more exporters. With that, an exporter for CMake is also diff --git a/apps/pkeyutl.c b/apps/pkeyutl.c index b5390c64c2a81f..13c8150db49486 100644 --- a/apps/pkeyutl.c +++ b/apps/pkeyutl.c @@ -20,10 +20,13 @@ #define KEY_PUBKEY 2 #define KEY_CERT 3 +static EVP_PKEY *get_pkey(const char *kdfalg, + const char *keyfile, int keyform, int key_type, + char *passinarg, int pkey_op, ENGINE *e); static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, - const char *keyfile, int keyform, int key_type, - char *passinarg, int pkey_op, ENGINE *e, - const int impl, int rawin, EVP_PKEY **ppkey, + int pkey_op, ENGINE *e, + const int impl, int rawin, + EVP_PKEY *pkey /* may get deallocated */, EVP_MD_CTX *mctx, const char *digestname, OSSL_LIB_CTX *libctx, const char *propq); @@ -39,6 +42,14 @@ static int do_raw_keyop(int pkey_op, EVP_MD_CTX *mctx, int filesize, unsigned char *sig, int siglen, unsigned char **out, size_t *poutlen); +static int only_rawin(const EVP_PKEY *pkey) +{ + if (pkey == NULL) + return 0; + return EVP_PKEY_get_id(pkey) == EVP_PKEY_ED25519 + || EVP_PKEY_get_id(pkey) == EVP_PKEY_ED448; +} + typedef enum OPTION_choice { OPT_COMMON, OPT_ENGINE, OPT_ENGINE_IMPL, OPT_IN, OPT_OUT, @@ -68,7 +79,7 @@ const OPTIONS pkeyutl_options[] = { OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input file - default stdin"}, - {"rawin", OPT_RAWIN, '-', "Indicate the input data is in raw form"}, + {"rawin", OPT_RAWIN, '-', "Indicate that signature input data is not hashed"}, {"inkey", OPT_INKEY, 's', "Input key, by default private key"}, {"pubin", OPT_PUBIN, '-', "Input key is a public key"}, {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, @@ -259,26 +270,6 @@ int pkeyutl_main(int argc, char **argv) if (!app_RAND_load()) goto end; - if (rawin && pkey_op != EVP_PKEY_OP_SIGN && pkey_op != EVP_PKEY_OP_VERIFY) { - BIO_printf(bio_err, - "%s: -rawin can only be used with -sign or -verify\n", - prog); - goto opthelp; - } - - if (digestname != NULL && !rawin) { - BIO_printf(bio_err, - "%s: -digest can only be used with -rawin\n", - prog); - goto opthelp; - } - - if (rawin && rev) { - BIO_printf(bio_err, "%s: -rev cannot be used with raw input\n", - prog); - goto opthelp; - } - if (kdfalg != NULL) { if (kdflen == 0) { BIO_printf(bio_err, @@ -295,14 +286,33 @@ int pkeyutl_main(int argc, char **argv) goto opthelp; } + pkey = get_pkey(kdfalg, inkey, keyform, key_type, passinarg, pkey_op, e); + if (pkey_op == EVP_PKEY_OP_SIGN || pkey_op == EVP_PKEY_OP_VERIFY) { + if (only_rawin(pkey)) + rawin = 1; /* implied for Ed25519 and Ed448 */ + } else if (rawin) { + BIO_printf(bio_err, + "%s: -rawin can only be used with -sign or -verify\n", prog); + goto opthelp; + } + if (digestname != NULL && !rawin) { + BIO_printf(bio_err, + "%s: -digest can only be used with -rawin\n", prog); + goto opthelp; + } + + if (rawin && rev) { + BIO_printf(bio_err, "%s: -rev cannot be used with raw input\n", prog); + goto opthelp; + } + if (rawin) { if ((mctx = EVP_MD_CTX_new()) == NULL) { BIO_printf(bio_err, "Error: out of memory\n"); goto end; } } - ctx = init_ctx(kdfalg, &keysize, inkey, keyform, key_type, - passinarg, pkey_op, e, engine_impl, rawin, &pkey, + ctx = init_ctx(kdfalg, &keysize, pkey_op, e, engine_impl, rawin, pkey, mctx, digestname, libctx, app_get0_propq()); if (ctx == NULL) { BIO_printf(bio_err, "%s: Error initializing context\n", prog); @@ -356,8 +366,10 @@ int pkeyutl_main(int argc, char **argv) goto end; } } else { - /* Get password as a passin argument: First split option name - * and passphrase argument into two strings */ + /* + * Get password as a passin argument: First split option name + * and passphrase argument into two strings + */ *passin = 0; passin++; if (app_passwd(passin, NULL, &passwd, NULL) == 0) { @@ -429,6 +441,7 @@ int pkeyutl_main(int argc, char **argv) size_t i; unsigned char ctmp; size_t l = (size_t)buf_inlen; + for (i = 0; i < l / 2; i++) { ctmp = buf_in[i]; buf_in[i] = buf_in[l - 1 - i]; @@ -519,29 +532,23 @@ int pkeyutl_main(int argc, char **argv) return ret; } -static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, - const char *keyfile, int keyform, int key_type, - char *passinarg, int pkey_op, ENGINE *e, - const int engine_impl, int rawin, - EVP_PKEY **ppkey, EVP_MD_CTX *mctx, const char *digestname, - OSSL_LIB_CTX *libctx, const char *propq) +static EVP_PKEY *get_pkey(const char *kdfalg, + const char *keyfile, int keyform, int key_type, + char *passinarg, int pkey_op, ENGINE *e) { EVP_PKEY *pkey = NULL; - EVP_PKEY_CTX *ctx = NULL; - ENGINE *impl = NULL; char *passin = NULL; - int rv = -1; X509 *x; if (((pkey_op == EVP_PKEY_OP_SIGN) || (pkey_op == EVP_PKEY_OP_DECRYPT) || (pkey_op == EVP_PKEY_OP_DERIVE)) && (key_type != KEY_PRIVKEY && kdfalg == NULL)) { BIO_printf(bio_err, "A private key is needed for this operation\n"); - goto end; + return NULL; } if (!app_passwd(passinarg, NULL, &passin, NULL)) { BIO_printf(bio_err, "Error getting password\n"); - goto end; + return NULL; } switch (key_type) { case KEY_PRIVKEY: @@ -564,6 +571,20 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, break; } + OPENSSL_free(passin); + return pkey; +} + +static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, + int pkey_op, ENGINE *e, + const int engine_impl, int rawin, + EVP_PKEY *pkey /* may get deallocated */, + EVP_MD_CTX *mctx, const char *digestname, + OSSL_LIB_CTX *libctx, const char *propq) +{ + EVP_PKEY_CTX *ctx = NULL; + ENGINE *impl = NULL; + int rv = -1; #ifndef OPENSSL_NO_ENGINE if (engine_impl) @@ -578,7 +599,7 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, if (kdfnid == NID_undef) { BIO_printf(bio_err, "The given KDF \"%s\" is unknown.\n", kdfalg); - goto end; + return NULL; } } if (impl != NULL) @@ -587,20 +608,18 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, ctx = EVP_PKEY_CTX_new_from_name(libctx, kdfalg, propq); } else { if (pkey == NULL) - goto end; + return NULL; *pkeysize = EVP_PKEY_get_size(pkey); if (impl != NULL) ctx = EVP_PKEY_CTX_new(pkey, impl); else ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq); - if (ppkey != NULL) - *ppkey = pkey; EVP_PKEY_free(pkey); } if (ctx == NULL) - goto end; + return NULL; if (rawin) { EVP_MD_CTX_set_pkey_ctx(mctx, ctx); @@ -650,8 +669,6 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, ctx = NULL; } - end: - OPENSSL_free(passin); return ctx; } @@ -682,6 +699,7 @@ static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op, const unsigned char *in, size_t inlen) { int rv = 0; + switch (pkey_op) { case EVP_PKEY_OP_VERIFYRECOVER: rv = EVP_PKEY_verify_recover(ctx, out, poutlen, in, inlen); @@ -720,8 +738,7 @@ static int do_raw_keyop(int pkey_op, EVP_MD_CTX *mctx, int buf_len = 0; /* Some algorithms only support oneshot digests */ - if (EVP_PKEY_get_id(pkey) == EVP_PKEY_ED25519 - || EVP_PKEY_get_id(pkey) == EVP_PKEY_ED448) { + if (only_rawin(pkey)) { if (filesize < 0) { BIO_printf(bio_err, "Error: unable to determine file size for oneshot operation\n"); diff --git a/doc/man1/openssl-pkeyutl.pod.in b/doc/man1/openssl-pkeyutl.pod.in index 1dae76cc1288b9..b8504ccdc5a5a9 100644 --- a/doc/man1/openssl-pkeyutl.pod.in +++ b/doc/man1/openssl-pkeyutl.pod.in @@ -59,10 +59,11 @@ if this option is not specified. =item B<-rawin> -This indicates that the input data is raw data, which is not hashed by any -message digest algorithm. The user can specify a digest algorithm by using -the B<-digest> option. This option can only be used with B<-sign> and -B<-verify> and must be used with the Ed25519 and Ed448 algorithms. +This indicates that signature input data is raw data, which for most signature +algorithms (but not EdDSA) needs to be hashed by some message digest algorithm. +The user can specify a digest algorithm by using the B<-digest> option. +This option can only be used with B<-sign> and B<-verify> +and is implied by the Ed25519 and Ed448 algorithms. =item B<-digest> I @@ -120,6 +121,7 @@ The input is a certificate containing a public key. Reverse the order of the input buffer. This is useful for some libraries (such as CryptoAPI) which represent the buffer in little endian format. +This cannot be used in conjunction with B<-rawin>. =item B<-sign> diff --git a/test/recipes/20-test_pkeyutl.t b/test/recipes/20-test_pkeyutl.t index 76e4f0a869459d..f7cf1a9f9c5bee 100644 --- a/test/recipes/20-test_pkeyutl.t +++ b/test/recipes/20-test_pkeyutl.t @@ -61,24 +61,24 @@ SKIP: { ok(run(app(([ 'openssl', 'pkeyutl', '-sign', '-in', srctop_file('test', 'certs', 'server-ed25519-cert.pem'), '-inkey', srctop_file('test', 'certs', 'server-ed25519-key.pem'), - '-out', 'Ed25519.sig', '-rawin']))), + '-out', 'Ed25519.sig']))), "Sign a piece of data using Ed25519"); ok(run(app(([ 'openssl', 'pkeyutl', '-verify', '-certin', '-in', srctop_file('test', 'certs', 'server-ed25519-cert.pem'), '-inkey', srctop_file('test', 'certs', 'server-ed25519-cert.pem'), - '-sigfile', 'Ed25519.sig', '-rawin']))), + '-sigfile', 'Ed25519.sig']))), "Verify an Ed25519 signature against a piece of data"); # Ed448 ok(run(app(([ 'openssl', 'pkeyutl', '-sign', '-in', srctop_file('test', 'certs', 'server-ed448-cert.pem'), '-inkey', srctop_file('test', 'certs', 'server-ed448-key.pem'), - '-out', 'Ed448.sig', '-rawin']))), + '-out', 'Ed448.sig']))), "Sign a piece of data using Ed448"); ok(run(app(([ 'openssl', 'pkeyutl', '-verify', '-certin', '-in', srctop_file('test', 'certs', 'server-ed448-cert.pem'), '-inkey', srctop_file('test', 'certs', 'server-ed448-cert.pem'), - '-sigfile', 'Ed448.sig', '-rawin']))), + '-sigfile', 'Ed448.sig']))), "Verify an Ed448 signature against a piece of data"); } @@ -189,14 +189,12 @@ SKIP: { subtest "Ed2559 CLI signature generation and verification" => sub { tsignverify("Ed25519", srctop_file("test","tested25519.pem"), - srctop_file("test","tested25519pub.pem"), - "-rawin"); + srctop_file("test","tested25519pub.pem")); }; subtest "Ed448 CLI signature generation and verification" => sub { tsignverify("Ed448", srctop_file("test","tested448.pem"), - srctop_file("test","tested448pub.pem"), - "-rawin"); + srctop_file("test","tested448pub.pem")); }; }