Fix -pkeyopt handling in apps/pkeyutl -rawin
authorPetr Gotthard <petr.gotthard@centrum.cz>
Sun, 10 Jan 2021 20:26:32 +0000 (21:26 +0100)
committerTomas Mraz <tomas@openssl.org>
Mon, 22 Feb 2021 11:30:49 +0000 (12:30 +0100)
The EVP_DigestSignInit and EVP_DigestVerifyInit actually have to
be initialized before EVP_PKEY_CTX_ctrl_str is invoked.
Otherwise, when the ctx not initialized, the ctrl command fails.

Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/13828)

apps/pkeyutl.c
test/recipes/20-test_pkeyutl.t

index f1c73b63681c75caa88da486df02e659b52ab609..f2efa1d5b87de6baa5e2970d4286b874ba38dfd4 100644 (file)
@@ -24,7 +24,8 @@ 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,
-                              OSSL_LIB_CTX *libctx);
+                              EVP_MD_CTX *mctx, const char *digestname,
+                              OSSL_LIB_CTX *libctx, const char *propq);
 
 static int setup_peer(EVP_PKEY_CTX *ctx, int peerform, const char *file,
                       ENGINE *e);
@@ -33,8 +34,8 @@ static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op,
                     unsigned char *out, size_t *poutlen,
                     const unsigned char *in, size_t inlen);
 
-static int do_raw_keyop(int pkey_op, EVP_PKEY_CTX *ctx,
-                        const EVP_MD *md, EVP_PKEY *pkey, BIO *in,
+static int do_raw_keyop(int pkey_op, EVP_MD_CTX *mctx,
+                        EVP_PKEY *pkey, BIO *in,
                         int filesize, unsigned char *sig, int siglen,
                         unsigned char **out, size_t *poutlen);
 
@@ -122,7 +123,7 @@ int pkeyutl_main(int argc, char **argv)
     STACK_OF(OPENSSL_STRING) *pkeyopts = NULL;
     STACK_OF(OPENSSL_STRING) *pkeyopts_passin = NULL;
     int rawin = 0;
-    const EVP_MD *md = NULL;
+    EVP_MD_CTX *mctx = NULL;
     int filesize = -1;
     OSSL_LIB_CTX *libctx = app_get0_libctx();
 
@@ -255,10 +256,6 @@ int pkeyutl_main(int argc, char **argv)
         goto opthelp;
 
     app_RAND_load();
-    if (digestname != NULL) {
-        if (!opt_md(digestname, &md))
-            goto end;
-    }
 
     if (rawin && pkey_op != EVP_PKEY_OP_SIGN && pkey_op != EVP_PKEY_OP_VERIFY) {
         BIO_printf(bio_err,
@@ -267,7 +264,7 @@ int pkeyutl_main(int argc, char **argv)
         goto opthelp;
     }
 
-    if (md != NULL && !rawin) {
+    if (digestname != NULL && !rawin) {
         BIO_printf(bio_err,
                    "%s: -digest can only be used with -rawin\n",
                    prog);
@@ -295,9 +292,16 @@ int pkeyutl_main(int argc, char **argv)
                    "%s: no peer key given (-peerkey parameter).\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,
-                   libctx);
+                   mctx, digestname, libctx, app_get0_propq());
     if (ctx == NULL) {
         BIO_printf(bio_err, "%s: Error initializing context\n", prog);
         ERR_print_errors(bio_err);
@@ -446,7 +450,7 @@ int pkeyutl_main(int argc, char **argv)
 
     if (pkey_op == EVP_PKEY_OP_VERIFY) {
         if (rawin) {
-            rv = do_raw_keyop(pkey_op, ctx, md, pkey, in, filesize, sig, siglen,
+            rv = do_raw_keyop(pkey_op, mctx, pkey, in, filesize, sig, siglen,
                               NULL, 0);
         } else {
             rv = EVP_PKEY_verify(ctx, sig, (size_t)siglen,
@@ -466,7 +470,7 @@ int pkeyutl_main(int argc, char **argv)
     } else {
         if (rawin) {
             /* rawin allocates the buffer in do_raw_keyop() */
-            rv = do_raw_keyop(pkey_op, ctx, md, pkey, in, filesize, NULL, 0,
+            rv = do_raw_keyop(pkey_op, mctx, pkey, in, filesize, NULL, 0,
                               &buf_out, (size_t *)&buf_outlen);
         } else {
             rv = do_keyop(ctx, pkey_op, NULL, (size_t *)&buf_outlen,
@@ -500,6 +504,7 @@ int pkeyutl_main(int argc, char **argv)
     }
 
  end:
+    EVP_MD_CTX_free(mctx);
     EVP_PKEY_CTX_free(ctx);
     release_engine(e);
     BIO_free(in);
@@ -517,8 +522,8 @@ 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,
-                              OSSL_LIB_CTX *libctx)
+                              EVP_PKEY **ppkey, EVP_MD_CTX *mctx, const char *digestname,
+                              OSSL_LIB_CTX *libctx, const char *propq)
 {
     EVP_PKEY *pkey = NULL;
     EVP_PKEY_CTX *ctx = NULL;
@@ -578,7 +583,7 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize,
         if (impl != NULL)
             ctx = EVP_PKEY_CTX_new_id(kdfnid, impl);
         else
-            ctx = EVP_PKEY_CTX_new_from_name(libctx, kdfalg, app_get0_propq());
+            ctx = EVP_PKEY_CTX_new_from_name(libctx, kdfalg, propq);
     } else {
         if (pkey == NULL)
             goto end;
@@ -587,7 +592,7 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize,
         if (impl != NULL)
             ctx = EVP_PKEY_CTX_new(pkey, impl);
         else
-            ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, app_get0_propq());
+            ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq);
         if (ppkey != NULL)
             *ppkey = pkey;
         EVP_PKEY_free(pkey);
@@ -596,13 +601,19 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize,
     if (ctx == NULL)
         goto end;
 
-    /*
-     * If rawin then we don't need to actually initialise the EVP_PKEY_CTX
-     * itself. That will get initialised during EVP_DigestSignInit or
-     * EVP_DigestVerifyInit.
-     */
     if (rawin) {
-        rv = 1;
+        EVP_MD_CTX_set_pkey_ctx(mctx, ctx);
+
+        switch (pkey_op) {
+        case EVP_PKEY_OP_SIGN:
+            rv = EVP_DigestSignInit_ex(mctx, NULL, digestname, libctx, propq, pkey);
+            break;
+
+        case EVP_PKEY_OP_VERIFY:
+            rv = EVP_DigestVerifyInit_ex(mctx, NULL, digestname, libctx, propq, pkey);
+            break;
+        }
+
     } else {
         switch (pkey_op) {
         case EVP_PKEY_OP_SIGN:
@@ -698,23 +709,16 @@ static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op,
 
 #define TBUF_MAXSIZE 2048
 
-static int do_raw_keyop(int pkey_op, EVP_PKEY_CTX *ctx,
-                        const EVP_MD *md, EVP_PKEY *pkey, BIO *in,
+static int do_raw_keyop(int pkey_op, EVP_MD_CTX *mctx,
+                        EVP_PKEY *pkey, BIO *in,
                         int filesize, unsigned char *sig, int siglen,
                         unsigned char **out, size_t *poutlen)
 {
     int rv = 0;
-    EVP_MD_CTX *mctx = NULL;
     unsigned char tbuf[TBUF_MAXSIZE];
     unsigned char *mbuf = NULL;
     int buf_len = 0;
 
-    if ((mctx = EVP_MD_CTX_new()) == NULL) {
-        BIO_printf(bio_err, "Error: out of memory\n");
-        return rv;
-    }
-    EVP_MD_CTX_set_pkey_ctx(mctx, ctx);
-
     /* Some algorithms only support oneshot digests */
     if (EVP_PKEY_id(pkey) == EVP_PKEY_ED25519
             || EVP_PKEY_id(pkey) == EVP_PKEY_ED448) {
@@ -726,8 +730,6 @@ static int do_raw_keyop(int pkey_op, EVP_PKEY_CTX *ctx,
         mbuf = app_malloc(filesize, "oneshot sign/verify buffer");
         switch(pkey_op) {
         case EVP_PKEY_OP_VERIFY:
-            if (EVP_DigestVerifyInit(mctx, NULL, md, NULL, pkey) != 1)
-                goto end;
             buf_len = BIO_read(in, mbuf, filesize);
             if (buf_len != filesize) {
                 BIO_printf(bio_err, "Error reading raw input data\n");
@@ -736,8 +738,6 @@ static int do_raw_keyop(int pkey_op, EVP_PKEY_CTX *ctx,
             rv = EVP_DigestVerify(mctx, sig, (size_t)siglen, mbuf, buf_len);
             break;
         case EVP_PKEY_OP_SIGN:
-            if (EVP_DigestSignInit(mctx, NULL, md, NULL, pkey) != 1)
-                goto end;
             buf_len = BIO_read(in, mbuf, filesize);
             if (buf_len != filesize) {
                 BIO_printf(bio_err, "Error reading raw input data\n");
@@ -755,8 +755,6 @@ static int do_raw_keyop(int pkey_op, EVP_PKEY_CTX *ctx,
 
     switch(pkey_op) {
     case EVP_PKEY_OP_VERIFY:
-        if (EVP_DigestVerifyInit(mctx, NULL, md, NULL, pkey) != 1)
-            goto end;
         for (;;) {
             buf_len = BIO_read(in, tbuf, TBUF_MAXSIZE);
             if (buf_len == 0)
@@ -774,8 +772,6 @@ static int do_raw_keyop(int pkey_op, EVP_PKEY_CTX *ctx,
         rv = EVP_DigestVerifyFinal(mctx, sig, (size_t)siglen);
         break;
     case EVP_PKEY_OP_SIGN:
-        if (EVP_DigestSignInit(mctx, NULL, md, NULL, pkey) != 1)
-            goto end;
         for (;;) {
             buf_len = BIO_read(in, tbuf, TBUF_MAXSIZE);
             if (buf_len == 0)
@@ -800,6 +796,5 @@ static int do_raw_keyop(int pkey_op, EVP_PKEY_CTX *ctx,
 
  end:
     OPENSSL_free(mbuf);
-    EVP_MD_CTX_free(mctx);
     return rv;
 }
index 8c0614bc42407f783cab9bf416e0484c12823466..618088a5777e099bab0b7703c0317f86addbe02d 100644 (file)
@@ -16,7 +16,7 @@ use OpenSSL::Test::Utils;
 
 setup("test_pkeyutl");
 
-plan tests => 11;
+plan tests => 12;
 
 # For the tests below we use the cert itself as the TBS file
 
@@ -125,6 +125,14 @@ SKIP: {
                     srctop_file("test","testrsapub.pem"),
                     "-rawin", "-digest", "sha256");
     };
+
+    subtest "RSA CLI signature and verification with pkeyopt" => sub {
+        tsignverify("RSA",
+                    srctop_file("test","testrsa.pem"),
+                    srctop_file("test","testrsapub.pem"),
+                    "-rawin", "-digest", "sha256",
+                    "-pkeyopt", "rsa_padding_mode:pss");
+    };
 }
 
 SKIP: {