Skip to content

Commit

Permalink
APPS/pkeyutl: improve -rawin usability (implied by Ed25519 and Ed448)…
Browse files Browse the repository at this point in the history
… and doc
  • Loading branch information
DDvO committed Dec 2, 2023
1 parent dd5fe94 commit 9e1aa2f
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 60 deletions.
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
113 changes: 65 additions & 48 deletions apps/pkeyutl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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,
Expand Down Expand Up @@ -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"},
Expand Down Expand Up @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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:
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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);
Expand Down Expand Up @@ -650,8 +669,6 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize,
ctx = NULL;
}

end:
OPENSSL_free(passin);
return ctx;

}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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");
Expand Down
10 changes: 6 additions & 4 deletions doc/man1/openssl-pkeyutl.pod.in
Original file line number Diff line number Diff line change
Expand Up @@ -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<algorithm>

Expand Down Expand Up @@ -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>

Expand Down
14 changes: 6 additions & 8 deletions test/recipes/20-test_pkeyutl.t
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

Expand Down Expand Up @@ -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"));
};
}

0 comments on commit 9e1aa2f

Please sign in to comment.