]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Implement functionality for direct use of composite signature algorithms
authorRichard Levitte <levitte@openssl.org>
Thu, 18 Jan 2024 14:27:34 +0000 (15:27 +0100)
committerRichard Levitte <levitte@openssl.org>
Wed, 21 Aug 2024 06:21:06 +0000 (08:21 +0200)
The following API groups are extended with a new init function, as well
as an update and final function, to allow the use of explicitly fetched
signature implementations for any composite signature algorithm, like
"sha1WithRSAEncryption":

- EVP_PKEY_sign
- EVP_PKEY_verify
- EVP_PKEY_verify_recover

To support this, providers are required to add a few new functions, not
the least one that declares what key types an signature implementation
supports.

While at this, the validity check in evp_signature_from_algorithm() is
also refactored; the SIGNATURE provider functionality is too complex for
counters.  It's better, or at least more readable, to check function
combinations.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Neil Horman <nhorman@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/23416)

12 files changed:
crypto/err/openssl.txt
crypto/evp/evp_err.c
crypto/evp/evp_local.h
crypto/evp/signature.c
doc/man3/EVP_PKEY_sign.pod
doc/man3/EVP_PKEY_verify.pod
doc/man3/EVP_PKEY_verify_recover.pod
include/openssl/core_dispatch.h
include/openssl/evp.h
include/openssl/evperr.h
util/libcrypto.num
util/perl/OpenSSL/paramnames.pm

index a6f1d9b2e77209c5eb8f25b38dab24acf2e96dca..7cbe4a9b13498c41818b4ac72d9b0f6010772868 100644 (file)
@@ -779,6 +779,8 @@ EVP_R_ONLY_ONESHOT_SUPPORTED:177:only oneshot supported
 EVP_R_OPERATION_NOT_INITIALIZED:151:operation not initialized
 EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE:150:\
        operation not supported for this keytype
+EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_SIGNATURE_TYPE:226:\
+       operation not supported for this signature type
 EVP_R_OUTPUT_WOULD_OVERFLOW:202:output would overflow
 EVP_R_PARAMETER_TOO_LARGE:187:parameter too large
 EVP_R_PARTIALLY_OVERLAPPING:162:partially overlapping buffers
@@ -790,6 +792,8 @@ EVP_R_PRIVATE_KEY_ENCODE_ERROR:146:private key encode error
 EVP_R_PUBLIC_KEY_NOT_RSA:106:public key not rsa
 EVP_R_SETTING_XOF_FAILED:227:setting xof failed
 EVP_R_SET_DEFAULT_PROPERTY_FAILURE:209:set default property failure
+EVP_R_SIGNATURE_TYPE_AND_KEY_TYPE_INCOMPATIBLE:228:\
+       signature type and key type incompatible
 EVP_R_TOO_MANY_RECORDS:183:too many records
 EVP_R_UNABLE_TO_ENABLE_LOCKING:212:unable to enable locking
 EVP_R_UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE:215:unable to get maximum request size
index 42dd7e400972e784df61f00ee5f1457235c7bbcf..ffac813db2525a3c7887f5d0221d92ae4344b827 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2024 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
@@ -132,6 +132,8 @@ static const ERR_STRING_DATA EVP_str_reasons[] = {
     "operation not initialized"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE),
     "operation not supported for this keytype"},
+    {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_SIGNATURE_TYPE),
+    "operation not supported for this signature type"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_OUTPUT_WOULD_OVERFLOW),
     "output would overflow"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PARAMETER_TOO_LARGE),
@@ -149,6 +151,8 @@ static const ERR_STRING_DATA EVP_str_reasons[] = {
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_SETTING_XOF_FAILED), "setting xof failed"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_SET_DEFAULT_PROPERTY_FAILURE),
     "set default property failure"},
+    {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_SIGNATURE_TYPE_AND_KEY_TYPE_INCOMPATIBLE),
+    "signature type and key type incompatible"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_TOO_MANY_RECORDS), "too many records"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNABLE_TO_ENABLE_LOCKING),
     "unable to enable locking"},
index 46650f1c59dca47d83b6836577248fa16e29778a..ae8c7bb8a8b28688bdf8d98ae77dfeef5562cd1a 100644 (file)
@@ -167,8 +167,14 @@ struct evp_signature_st {
     OSSL_FUNC_signature_newctx_fn *newctx;
     OSSL_FUNC_signature_sign_init_fn *sign_init;
     OSSL_FUNC_signature_sign_fn *sign;
+    OSSL_FUNC_signature_sign_message_init_fn *sign_message_init;
+    OSSL_FUNC_signature_sign_message_update_fn *sign_message_update;
+    OSSL_FUNC_signature_sign_message_final_fn *sign_message_final;
     OSSL_FUNC_signature_verify_init_fn *verify_init;
     OSSL_FUNC_signature_verify_fn *verify;
+    OSSL_FUNC_signature_verify_message_init_fn *verify_message_init;
+    OSSL_FUNC_signature_verify_message_update_fn *verify_message_update;
+    OSSL_FUNC_signature_verify_message_final_fn *verify_message_final;
     OSSL_FUNC_signature_verify_recover_init_fn *verify_recover_init;
     OSSL_FUNC_signature_verify_recover_fn *verify_recover;
     OSSL_FUNC_signature_digest_sign_init_fn *digest_sign_init;
@@ -189,6 +195,9 @@ struct evp_signature_st {
     OSSL_FUNC_signature_gettable_ctx_md_params_fn *gettable_ctx_md_params;
     OSSL_FUNC_signature_set_ctx_md_params_fn *set_ctx_md_params;
     OSSL_FUNC_signature_settable_ctx_md_params_fn *settable_ctx_md_params;
+
+    /* Signature object checking */
+    OSSL_FUNC_signature_query_key_types_fn *query_key_types;
 } /* EVP_SIGNATURE */;
 
 struct evp_asym_cipher_st {
index c05eb78b51ce255d278b8082f0d933ad4f9e45d0..33910e5bc33528b11794ff4c4582e90bf7657cb4 100644 (file)
@@ -7,8 +7,10 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <openssl/err.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <openssl/core_names.h>
 #include <openssl/objects.h>
 #include <openssl/evp.h>
 #include "internal/numbers.h"   /* includes SIZE_MAX */
@@ -42,9 +44,15 @@ static void *evp_signature_from_algorithm(int name_id,
 {
     const OSSL_DISPATCH *fns = algodef->implementation;
     EVP_SIGNATURE *signature = NULL;
-    int ctxfncnt = 0, signfncnt = 0, verifyfncnt = 0, verifyrecfncnt = 0;
-    int digsignfncnt = 0, digverifyfncnt = 0;
+    /* Counts newctx / freectx */
+    int ctxfncnt = 0;
+    /* Counts all init functions  */
+    int initfncnt = 0;
+    /* Counts all performance functions (oneshot / update / final) */
+    int fncnt = 0;
+    /* Counts all parameter functions */
     int gparamfncnt = 0, sparamfncnt = 0, gmdparamfncnt = 0, smdparamfncnt = 0;
+    int valid = 0;
 
     if ((signature = evp_signature_new(prov)) == NULL) {
         ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
@@ -68,91 +76,137 @@ static void *evp_signature_from_algorithm(int name_id,
             if (signature->sign_init != NULL)
                 break;
             signature->sign_init = OSSL_FUNC_signature_sign_init(fns);
-            signfncnt++;
+            initfncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_SIGN:
             if (signature->sign != NULL)
                 break;
             signature->sign = OSSL_FUNC_signature_sign(fns);
-            signfncnt++;
+            fncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT:
+            if (signature->sign_message_init != NULL)
+                break;
+            signature->sign_message_init
+                = OSSL_FUNC_signature_sign_message_init(fns);
+            initfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_UPDATE:
+            if (signature->sign_message_update != NULL)
+                break;
+            signature->sign_message_update
+                = OSSL_FUNC_signature_sign_message_update(fns);
+            fncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_FINAL:
+            if (signature->sign_message_final != NULL)
+                break;
+            signature->sign_message_final
+                = OSSL_FUNC_signature_sign_message_final(fns);
+            fncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_VERIFY_INIT:
             if (signature->verify_init != NULL)
                 break;
             signature->verify_init = OSSL_FUNC_signature_verify_init(fns);
-            verifyfncnt++;
+            initfncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_VERIFY:
             if (signature->verify != NULL)
                 break;
             signature->verify = OSSL_FUNC_signature_verify(fns);
-            verifyfncnt++;
+            fncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT:
+            if (signature->verify_message_init != NULL)
+                break;
+            signature->verify_message_init
+                = OSSL_FUNC_signature_verify_message_init(fns);
+            initfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_UPDATE:
+            if (signature->verify_message_update != NULL)
+                break;
+            signature->verify_message_update
+                = OSSL_FUNC_signature_verify_message_update(fns);
+            fncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_FINAL:
+            if (signature->verify_message_final != NULL)
+                break;
+            signature->verify_message_final
+                = OSSL_FUNC_signature_verify_message_final(fns);
+            fncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT:
             if (signature->verify_recover_init != NULL)
                 break;
             signature->verify_recover_init
                 = OSSL_FUNC_signature_verify_recover_init(fns);
-            verifyrecfncnt++;
+            initfncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_VERIFY_RECOVER:
             if (signature->verify_recover != NULL)
                 break;
             signature->verify_recover
                 = OSSL_FUNC_signature_verify_recover(fns);
-            verifyrecfncnt++;
+            fncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT:
             if (signature->digest_sign_init != NULL)
                 break;
             signature->digest_sign_init
                 = OSSL_FUNC_signature_digest_sign_init(fns);
+            initfncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE:
             if (signature->digest_sign_update != NULL)
                 break;
             signature->digest_sign_update
                 = OSSL_FUNC_signature_digest_sign_update(fns);
-            digsignfncnt++;
+            fncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL:
             if (signature->digest_sign_final != NULL)
                 break;
             signature->digest_sign_final
                 = OSSL_FUNC_signature_digest_sign_final(fns);
-            digsignfncnt++;
+            fncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_DIGEST_SIGN:
             if (signature->digest_sign != NULL)
                 break;
             signature->digest_sign
                 = OSSL_FUNC_signature_digest_sign(fns);
+            fncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT:
             if (signature->digest_verify_init != NULL)
                 break;
             signature->digest_verify_init
                 = OSSL_FUNC_signature_digest_verify_init(fns);
+            initfncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE:
             if (signature->digest_verify_update != NULL)
                 break;
             signature->digest_verify_update
                 = OSSL_FUNC_signature_digest_verify_update(fns);
-            digverifyfncnt++;
+            fncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL:
             if (signature->digest_verify_final != NULL)
                 break;
             signature->digest_verify_final
                 = OSSL_FUNC_signature_digest_verify_final(fns);
-            digverifyfncnt++;
+            fncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_DIGEST_VERIFY:
             if (signature->digest_verify != NULL)
                 break;
             signature->digest_verify
                 = OSSL_FUNC_signature_digest_verify(fns);
+            fncnt++;
             break;
         case OSSL_FUNC_SIGNATURE_FREECTX:
             if (signature->freectx != NULL)
@@ -221,48 +275,109 @@ static void *evp_signature_from_algorithm(int name_id,
                 = OSSL_FUNC_signature_settable_ctx_md_params(fns);
             smdparamfncnt++;
             break;
+        case OSSL_FUNC_SIGNATURE_QUERY_KEY_TYPES:
+            if (signature->query_key_types != NULL)
+                break;
+            signature->query_key_types
+                = OSSL_FUNC_signature_query_key_types(fns);
+            break;
         }
     }
-    if (ctxfncnt != 2
-        || (signfncnt == 0
-            && verifyfncnt == 0
-            && verifyrecfncnt == 0
-            && digsignfncnt == 0
-            && digverifyfncnt == 0
+    /*
+     * In order to be a consistent set of functions we must have at least
+     * a set of context functions (newctx and freectx) as well as a set of
+     * "signature" functions.  Because there's an overlap between some sets
+     * of functions, counters don't always cut it, we must test known
+     * combinations.
+     * We start by assuming the implementation is valid, and then look for
+     * reasons it's not.
+     */
+    valid = 1;
+    /* Start with the ones where counters say enough */
+    if (ctxfncnt != 2)
+        /* newctx or freectx missing */
+        valid = 0;
+    if (valid
+        && ((gparamfncnt != 0 && gparamfncnt != 2)
+            || (sparamfncnt != 0 && sparamfncnt != 2)
+            || (gmdparamfncnt != 0 && gmdparamfncnt != 2)
+            || (smdparamfncnt != 0 && smdparamfncnt != 2)))
+        /*
+         * Params functions are optional, but if defined, they must
+         * be pairwise complete sets, i.e. a getter must have an
+         * associated gettable, etc
+         */
+        valid = 0;
+    if (valid && (initfncnt == 0 || fncnt < initfncnt))
+        /*
+         * No init functions, or fewer execution functions than init functions
+         */
+        valid = 0;
+
+    /* Now we check for function combinations */
+    if (valid
+        && ((signature->sign_init != NULL
+             && signature->sign == NULL)
+            || (signature->sign_message_init != NULL
+                && signature->sign == NULL
+                && (signature->sign_message_update == NULL
+                    || signature->sign_message_final == NULL))))
+        /* sign_init functions with no signing function?  That's weird */
+        valid = 0;
+    if (valid
+        && (signature->sign != NULL
+            || signature->sign_message_update != NULL
+            || signature->sign_message_final != NULL)
+        && signature->sign_init == NULL
+        && signature->sign_message_init == NULL)
+        /* signing functions with no sign_init? That's odd */
+        valid = 0;
+
+    if (valid
+        && ((signature->verify_init != NULL
+             && signature->verify == NULL)
+            || (signature->verify_message_init != NULL
+                && signature->verify == NULL
+                && (signature->verify_message_update == NULL
+                    || signature->verify_message_final == NULL))))
+        /* verify_init functions with no verification function?  That's weird */
+        valid = 0;
+    if (valid
+        && (signature->verify != NULL
+            || signature->verify_message_update != NULL
+            || signature->verify_message_final != NULL)
+        && signature->verify_init == NULL
+        && signature->verify_message_init == NULL)
+        /* verification functions with no verify_init? That's odd */
+        valid = 0;
+
+    if (valid
+        && (signature->verify_recover_init != NULL)
+            && (signature->verify_recover == NULL))
+        /* verify_recover_init functions with no verify_recover?  How quaint */
+        valid = 0;
+
+    if (valid
+        && (signature->digest_sign_init != NULL
             && signature->digest_sign == NULL
-            && signature->digest_verify == NULL)
-        || (signfncnt != 0 && signfncnt != 2)
-        || (verifyfncnt != 0 && verifyfncnt != 2)
-        || (verifyrecfncnt != 0 && verifyrecfncnt != 2)
-        || (digsignfncnt != 0 && digsignfncnt != 2)
-        || (digsignfncnt == 2 && signature->digest_sign_init == NULL)
-        || (digverifyfncnt != 0 && digverifyfncnt != 2)
-        || (digverifyfncnt == 2 && signature->digest_verify_init == NULL)
-        || (signature->digest_sign != NULL
-            && signature->digest_sign_init == NULL)
-        || (signature->digest_verify != NULL
-            && signature->digest_verify_init == NULL)
-        || (gparamfncnt != 0 && gparamfncnt != 2)
-        || (sparamfncnt != 0 && sparamfncnt != 2)
-        || (gmdparamfncnt != 0 && gmdparamfncnt != 2)
-        || (smdparamfncnt != 0 && smdparamfncnt != 2)) {
+            && (signature->digest_sign_update == NULL
+                || signature->digest_sign_final == NULL)))
         /*
-         * In order to be a consistent set of functions we must have at least
-         * a set of context functions (newctx and freectx) as well as a set of
-         * "signature" functions:
-         *  (sign_init, sign) or
-         *  (verify_init verify) or
-         *  (verify_recover_init, verify_recover) or
-         *  (digest_sign_init, digest_sign_update, digest_sign_final) or
-         *  (digest_verify_init, digest_verify_update, digest_verify_final) or
-         *  (digest_sign_init, digest_sign) or
-         *  (digest_verify_init, digest_verify).
-         *
-         * set_ctx_params and settable_ctx_params are optional, but if one of
-         * them is present then the other one must also be present. The same
-         * applies to get_ctx_params and gettable_ctx_params. The same rules
-         * apply to the "md_params" functions. The dupctx function is optional.
+         * You can't have a digest_sign_init without *some* performing functions
          */
+        valid = 0;
+
+    if (valid
+        && ((signature->digest_verify_init != NULL
+             && signature->digest_verify == NULL
+             && (signature->digest_verify_update == NULL
+                 || signature->digest_verify_final == NULL))))
+        /*
+         * You can't have a digest_verify_init without *some* performing functions
+         */
+        valid = 0;
+
+    if (!valid) {
         ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
         goto err;
     }
@@ -387,12 +502,11 @@ const OSSL_PARAM *EVP_SIGNATURE_settable_ctx_params(const EVP_SIGNATURE *sig)
     return sig->settable_ctx_params(NULL, provctx);
 }
 
-static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation,
-                                   const OSSL_PARAM params[])
+static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature,
+                                   int operation, const OSSL_PARAM params[])
 {
     int ret = 0;
     void *provkey = NULL;
-    EVP_SIGNATURE *signature = NULL;
     EVP_KEYMGMT *tmp_keymgmt = NULL;
     const OSSL_PROVIDER *tmp_prov = NULL;
     const char *supported_sig = NULL;
@@ -406,91 +520,30 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation,
     evp_pkey_ctx_free_old_ops(ctx);
     ctx->operation = operation;
 
-    ERR_set_mark();
-
-    if (evp_pkey_ctx_is_legacy(ctx))
-        goto legacy;
-
-    if (ctx->pkey == NULL) {
-        ERR_clear_last_mark();
-        ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEY_SET);
-        goto err;
-    }
-
-    /*
-     * Try to derive the supported signature from |ctx->keymgmt|.
-     */
-    if (!ossl_assert(ctx->pkey->keymgmt == NULL
-                     || ctx->pkey->keymgmt == ctx->keymgmt)) {
-        ERR_clear_last_mark();
-        ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-    supported_sig = evp_keymgmt_util_query_operation_name(ctx->keymgmt,
-                                                          OSSL_OP_SIGNATURE);
-    if (supported_sig == NULL) {
-        ERR_clear_last_mark();
-        ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
-        goto err;
-    }
+    if (signature != NULL) {
+        /*
+         * It's important to figure out what the key type should be, and if
+         * that is what we have in ctx.
+         */
 
-    /*
-     * We perform two iterations:
-     *
-     * 1.  Do the normal signature fetch, using the fetching data given by
-     *     the EVP_PKEY_CTX.
-     * 2.  Do the provider specific signature fetch, from the same provider
-     *     as |ctx->keymgmt|
-     *
-     * We then try to fetch the keymgmt from the same provider as the
-     * signature, and try to export |ctx->pkey| to that keymgmt (when
-     * this keymgmt happens to be the same as |ctx->keymgmt|, the export
-     * is a no-op, but we call it anyway to not complicate the code even
-     * more).
-     * If the export call succeeds (returns a non-NULL provider key pointer),
-     * we're done and can perform the operation itself.  If not, we perform
-     * the second iteration, or jump to legacy.
-     */
-    for (iter = 1; iter < 3 && provkey == NULL; iter++) {
         EVP_KEYMGMT *tmp_keymgmt_tofree = NULL;
 
-        /*
-         * If we're on the second iteration, free the results from the first.
-         * They are NULL on the first iteration, so no need to check what
-         * iteration we're on.
-         */
-        EVP_SIGNATURE_free(signature);
-        EVP_KEYMGMT_free(tmp_keymgmt);
-
-        switch (iter) {
-        case 1:
-            signature =
-                EVP_SIGNATURE_fetch(ctx->libctx, supported_sig, ctx->propquery);
-            if (signature != NULL)
-                tmp_prov = EVP_SIGNATURE_get0_provider(signature);
-            break;
-        case 2:
-            tmp_prov = EVP_KEYMGMT_get0_provider(ctx->keymgmt);
-            signature =
-                evp_signature_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
-                                              supported_sig, ctx->propquery);
-            if (signature == NULL)
-                goto legacy;
-            break;
+        if (ctx->pkey == NULL) {
+            ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEY_SET);
+            goto err;
         }
-        if (signature == NULL)
-            continue;
 
         /*
-         * Ensure that the key is provided, either natively, or as a cached
-         * export.  We start by fetching the keymgmt with the same name as
-         * |ctx->pkey|, but from the provider of the signature method, using
-         * the same property query as when fetching the signature method.
-         * With the keymgmt we found (if we did), we try to export |ctx->pkey|
-         * to it (evp_pkey_export_to_provider() is smart enough to only actually
-
-         * export it if |tmp_keymgmt| is different from |ctx->pkey|'s keymgmt)
+         * Ensure that the key is provided, either natively, or as a
+         * cached export.  We start by fetching the keymgmt with the same
+         * name as |ctx->pkey|, but from the provider of the signature
+         * method, using the same property query as when fetching the
+         * signature method.  With the keymgmt we found (if we did), we
+         * try to export |ctx->pkey| to it (evp_pkey_export_to_provider()
+         * is smart enough to only actually export it if |tmp_keymgmt|
+         * is different from |ctx->pkey|'s keymgmt)
          */
+        tmp_prov = EVP_SIGNATURE_get0_provider(signature);
         tmp_keymgmt_tofree = tmp_keymgmt =
             evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
                                         EVP_KEYMGMT_get0_name(ctx->keymgmt),
@@ -500,14 +553,163 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation,
                                                   &tmp_keymgmt, ctx->propquery);
         if (tmp_keymgmt == NULL)
             EVP_KEYMGMT_free(tmp_keymgmt_tofree);
-    }
 
-    if (provkey == NULL) {
-        EVP_SIGNATURE_free(signature);
-        goto legacy;
-    }
+        if (provkey == NULL)
+            goto end;
 
-    ERR_pop_to_mark();
+        /*
+         * Check that the signature matches the given key.  This is not
+         * designed to work with legacy keys, so has to be done after we've
+         * ensured that the key is at least exported to a provider (above).
+         */
+        if (signature->query_key_types != NULL) {
+            /* This is expect to be a NULL terminated array */
+            const char **keytypes;
+
+            keytypes = signature->query_key_types();
+            for (; *keytypes != NULL; keytypes++)
+                if (EVP_PKEY_CTX_is_a(ctx, *keytypes))
+                    break;
+            if (*keytypes == NULL) {
+                ERR_raise(ERR_LIB_EVP, EVP_R_SIGNATURE_TYPE_AND_KEY_TYPE_INCOMPATIBLE);
+                return -2;
+            }
+        } else {
+            /*
+             * Fallback 1:
+             * check if the keytype is the same as the signature algorithm name
+             */
+            const char *keytype = EVP_KEYMGMT_get0_name(ctx->keymgmt);
+            int ok = EVP_SIGNATURE_is_a(signature, keytype);
+
+            /*
+             * Fallback 2:
+             * query the pkey for a default signature algorithm name, and check
+             * if it matches the signature implementation
+             */
+            if (!ok) {
+                const char *signame
+                    = evp_keymgmt_util_query_operation_name(ctx->keymgmt,
+                                                            OSSL_OP_SIGNATURE);
+
+                ok = EVP_SIGNATURE_is_a(signature, signame);
+            }
+
+            /* If none of the fallbacks helped, we're lost */
+            if (!ok) {
+                ERR_raise(ERR_LIB_EVP, EVP_R_SIGNATURE_TYPE_AND_KEY_TYPE_INCOMPATIBLE);
+                return -2;
+            }
+        }
+
+        if (!EVP_SIGNATURE_up_ref(signature))
+            return 0;
+    } else {
+        /* Without a pre-fetched signature, it must be figured out somehow */
+        ERR_set_mark();
+
+        if (evp_pkey_ctx_is_legacy(ctx))
+            goto legacy;
+
+        if (ctx->pkey == NULL) {
+            ERR_clear_last_mark();
+            ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEY_SET);
+            goto err;
+        }
+
+        /*
+         * Try to derive the supported signature from |ctx->keymgmt|.
+         */
+        if (!ossl_assert(ctx->pkey->keymgmt == NULL
+                         || ctx->pkey->keymgmt == ctx->keymgmt)) {
+            ERR_clear_last_mark();
+            ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        supported_sig
+            = evp_keymgmt_util_query_operation_name(ctx->keymgmt,
+                                                    OSSL_OP_SIGNATURE);
+        if (supported_sig == NULL) {
+            ERR_clear_last_mark();
+            ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+            goto err;
+        }
+
+        /*
+         * We perform two iterations:
+         *
+         * 1.  Do the normal signature fetch, using the fetching data given by
+         *     the EVP_PKEY_CTX.
+         * 2.  Do the provider specific signature fetch, from the same provider
+         *     as |ctx->keymgmt|
+         *
+         * We then try to fetch the keymgmt from the same provider as the
+         * signature, and try to export |ctx->pkey| to that keymgmt (when
+         * this keymgmt happens to be the same as |ctx->keymgmt|, the export
+         * is a no-op, but we call it anyway to not complicate the code even
+         * more).
+         * If the export call succeeds (returns a non-NULL provider key pointer),
+         * we're done and can perform the operation itself.  If not, we perform
+         * the second iteration, or jump to legacy.
+         */
+        for (iter = 1; iter < 3 && provkey == NULL; iter++) {
+            EVP_KEYMGMT *tmp_keymgmt_tofree = NULL;
+
+            /*
+             * If we're on the second iteration, free the results from the first.
+             * They are NULL on the first iteration, so no need to check what
+             * iteration we're on.
+             */
+            EVP_SIGNATURE_free(signature);
+            EVP_KEYMGMT_free(tmp_keymgmt);
+
+            switch (iter) {
+            case 1:
+                signature =
+                    EVP_SIGNATURE_fetch(ctx->libctx, supported_sig, ctx->propquery);
+                if (signature != NULL)
+                    tmp_prov = EVP_SIGNATURE_get0_provider(signature);
+                break;
+            case 2:
+                tmp_prov = EVP_KEYMGMT_get0_provider(ctx->keymgmt);
+                signature =
+                    evp_signature_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
+                                                  supported_sig, ctx->propquery);
+                if (signature == NULL)
+                    goto legacy;
+                break;
+            }
+            if (signature == NULL)
+                continue;
+
+            /*
+             * Ensure that the key is provided, either natively, or as a
+             * cached export.  We start by fetching the keymgmt with the same
+             * name as |ctx->pkey|, but from the provider of the signature
+             * method, using the same property query as when fetching the
+             * signature method.  With the keymgmt we found (if we did), we
+             * try to export |ctx->pkey| to it (evp_pkey_export_to_provider()
+             * is smart enough to only actually export it if |tmp_keymgmt|
+             * is different from |ctx->pkey|'s keymgmt)
+             */
+            tmp_keymgmt_tofree = tmp_keymgmt =
+                evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
+                                            EVP_KEYMGMT_get0_name(ctx->keymgmt),
+                                            ctx->propquery);
+            if (tmp_keymgmt != NULL)
+                provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
+                                                      &tmp_keymgmt, ctx->propquery);
+            if (tmp_keymgmt == NULL)
+                EVP_KEYMGMT_free(tmp_keymgmt_tofree);
+        }
+
+        if (provkey == NULL) {
+            EVP_SIGNATURE_free(signature);
+            goto legacy;
+        }
+
+        ERR_pop_to_mark();
+    }
 
     /* No more legacy from here down to legacy: */
 
@@ -529,6 +731,14 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation,
         }
         ret = signature->sign_init(ctx->op.sig.algctx, provkey, params);
         break;
+    case EVP_PKEY_OP_SIGNMSG:
+        if (signature->sign_message_init == NULL) {
+            ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+            ret = -2;
+            goto err;
+        }
+        ret = signature->sign_message_init(ctx->op.sig.algctx, provkey, params);
+        break;
     case EVP_PKEY_OP_VERIFY:
         if (signature->verify_init == NULL) {
             ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
@@ -537,14 +747,21 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation,
         }
         ret = signature->verify_init(ctx->op.sig.algctx, provkey, params);
         break;
+    case EVP_PKEY_OP_VERIFYMSG:
+        if (signature->verify_message_init == NULL) {
+            ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+            ret = -2;
+            goto err;
+        }
+        ret = signature->verify_message_init(ctx->op.sig.algctx, provkey, params);
+        break;
     case EVP_PKEY_OP_VERIFYRECOVER:
         if (signature->verify_recover_init == NULL) {
             ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
             ret = -2;
             goto err;
         }
-        ret = signature->verify_recover_init(ctx->op.sig.algctx, provkey,
-                                             params);
+        ret = signature->verify_recover_init(ctx->op.sig.algctx, provkey, params);
         break;
     default:
         ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
@@ -615,12 +832,69 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation,
 
 int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx)
 {
-    return evp_pkey_signature_init(ctx, EVP_PKEY_OP_SIGN, NULL);
+    return evp_pkey_signature_init(ctx, NULL, EVP_PKEY_OP_SIGN, NULL);
 }
 
 int EVP_PKEY_sign_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
 {
-    return evp_pkey_signature_init(ctx, EVP_PKEY_OP_SIGN, params);
+    return evp_pkey_signature_init(ctx, NULL, EVP_PKEY_OP_SIGN, params);
+}
+
+int EVP_PKEY_sign_init_ex2(EVP_PKEY_CTX *ctx,
+                           EVP_SIGNATURE *algo, const OSSL_PARAM params[])
+{
+    return evp_pkey_signature_init(ctx, algo, EVP_PKEY_OP_SIGN, params);
+}
+
+int EVP_PKEY_sign_message_init(EVP_PKEY_CTX *ctx,
+                               EVP_SIGNATURE *algo, const OSSL_PARAM params[])
+{
+    return evp_pkey_signature_init(ctx, algo, EVP_PKEY_OP_SIGNMSG, params);
+}
+
+int EVP_PKEY_sign_message_update(EVP_PKEY_CTX *ctx,
+                                 const unsigned char *in, size_t inlen)
+{
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
+        return -1;
+    }
+
+    if (ctx->operation != EVP_PKEY_OP_SIGNMSG) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
+        return -1;
+    }
+
+    if (ctx->op.sig.signature->sign_message_update == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+        return -2;
+    }
+
+    return ctx->op.sig.signature->sign_message_update(ctx->op.sig.algctx,
+                                                      in, inlen);
+}
+
+int EVP_PKEY_sign_message_final(EVP_PKEY_CTX *ctx,
+                                unsigned char *sig, size_t *siglen)
+{
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
+        return -1;
+    }
+
+    if (ctx->operation != EVP_PKEY_OP_SIGNMSG) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
+        return -1;
+    }
+
+    if (ctx->op.sig.signature->sign_message_final == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+        return -2;
+    }
+
+    return ctx->op.sig.signature->sign_message_final(ctx->op.sig.algctx,
+                                                     sig, siglen,
+                                                     (sig == NULL) ? 0 : *siglen);
 }
 
 int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
@@ -634,7 +908,8 @@ int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
         return -1;
     }
 
-    if (ctx->operation != EVP_PKEY_OP_SIGN) {
+    if (ctx->operation != EVP_PKEY_OP_SIGN
+        && ctx->operation != EVP_PKEY_OP_SIGNMSG) {
         ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
         return -1;
     }
@@ -664,12 +939,88 @@ int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
 
 int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx)
 {
-    return evp_pkey_signature_init(ctx, EVP_PKEY_OP_VERIFY, NULL);
+    return evp_pkey_signature_init(ctx, NULL, EVP_PKEY_OP_VERIFY, NULL);
 }
 
 int EVP_PKEY_verify_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
 {
-    return evp_pkey_signature_init(ctx, EVP_PKEY_OP_VERIFY, params);
+    return evp_pkey_signature_init(ctx, NULL, EVP_PKEY_OP_VERIFY, params);
+}
+
+int EVP_PKEY_verify_init_ex2(EVP_PKEY_CTX *ctx,
+                             EVP_SIGNATURE *algo, const OSSL_PARAM params[])
+{
+    return evp_pkey_signature_init(ctx, algo, EVP_PKEY_OP_VERIFY, params);
+}
+
+int EVP_PKEY_verify_message_init(EVP_PKEY_CTX *ctx,
+                                 EVP_SIGNATURE *algo, const OSSL_PARAM params[])
+{
+    return evp_pkey_signature_init(ctx, algo, EVP_PKEY_OP_VERIFYMSG, params);
+}
+
+int EVP_PKEY_CTX_set_signature(EVP_PKEY_CTX *ctx,
+                               const unsigned char *sig, size_t siglen)
+{
+    OSSL_PARAM sig_params[2], *p = sig_params;
+
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    *p++ = OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_SIGNATURE,
+                                             /*
+                                              * Cast away the const. This is
+                                              * read only so should be safe
+                                              */
+                                             (char *)sig, siglen);
+    *p = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, sig_params);
+}
+
+int EVP_PKEY_verify_message_update(EVP_PKEY_CTX *ctx,
+                                   const unsigned char *in, size_t inlen)
+{
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
+        return -1;
+    }
+
+    if (ctx->operation != EVP_PKEY_OP_VERIFYMSG) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
+        return -1;
+    }
+
+    if (ctx->op.sig.signature->verify_message_update == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+        return -2;
+    }
+
+    return ctx->op.sig.signature->verify_message_update(ctx->op.sig.algctx,
+                                                        in, inlen);
+}
+
+int EVP_PKEY_verify_message_final(EVP_PKEY_CTX *ctx)
+{
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
+        return -1;
+    }
+
+    if (ctx->operation != EVP_PKEY_OP_VERIFYMSG) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
+        return -1;
+    }
+
+    if (ctx->op.sig.signature->verify_message_final == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+        return -2;
+    }
+
+    /* The signature must have been set with EVP_PKEY_CTX_set_signature() */
+    return ctx->op.sig.signature->verify_message_final(ctx->op.sig.algctx);
 }
 
 int EVP_PKEY_verify(EVP_PKEY_CTX *ctx,
@@ -683,7 +1034,8 @@ int EVP_PKEY_verify(EVP_PKEY_CTX *ctx,
         return -1;
     }
 
-    if (ctx->operation != EVP_PKEY_OP_VERIFY) {
+    if (ctx->operation != EVP_PKEY_OP_VERIFY
+        && ctx->operation != EVP_PKEY_OP_VERIFYMSG) {
         ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
         return -1;
     }
@@ -711,13 +1063,19 @@ int EVP_PKEY_verify(EVP_PKEY_CTX *ctx,
 
 int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx)
 {
-    return evp_pkey_signature_init(ctx, EVP_PKEY_OP_VERIFYRECOVER, NULL);
+    return evp_pkey_signature_init(ctx, NULL, EVP_PKEY_OP_VERIFYRECOVER, NULL);
 }
 
 int EVP_PKEY_verify_recover_init_ex(EVP_PKEY_CTX *ctx,
                                     const OSSL_PARAM params[])
 {
-    return evp_pkey_signature_init(ctx, EVP_PKEY_OP_VERIFYRECOVER, params);
+    return evp_pkey_signature_init(ctx, NULL, EVP_PKEY_OP_VERIFYRECOVER, params);
+}
+
+int EVP_PKEY_verify_recover_init_ex2(EVP_PKEY_CTX *ctx,
+                                     EVP_SIGNATURE *algo, const OSSL_PARAM params[])
+{
+    return evp_pkey_signature_init(ctx, algo, EVP_PKEY_OP_VERIFYRECOVER, params);
 }
 
 int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx,
index 6752432bd58e36d02e5cdae9e1f13a7edb66cc60..18e09bbdd8332443647ed75367c7f7f15354afcc 100644 (file)
@@ -2,8 +2,9 @@
 
 =head1 NAME
 
-EVP_PKEY_sign_init, EVP_PKEY_sign_init_ex, EVP_PKEY_sign
-- sign using a public key algorithm
+EVP_PKEY_sign_init, EVP_PKEY_sign_init_ex, EVP_PKEY_sign_init_ex2,
+EVP_PKEY_sign, EVP_PKEY_sign_message_init, EVP_PKEY_sign_message_update,
+EVP_PKEY_sign_message_final - sign using a public key algorithm
 
 =head1 SYNOPSIS
 
@@ -11,6 +12,14 @@ EVP_PKEY_sign_init, EVP_PKEY_sign_init_ex, EVP_PKEY_sign
 
  int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx);
  int EVP_PKEY_sign_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]);
+ int EVP_PKEY_sign_init_ex2(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *algo,
+                            const OSSL_PARAM params[]);
+ int EVP_PKEY_sign_message_init(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *algo,
+                                const OSSL_PARAM params[]);
+ int EVP_PKEY_sign_message_update(EVP_PKEY_CTX *ctx,
+                                  unsigned char *in, size_t inlen);
+ int EVP_PKEY_sign_message_final(EVP_PKEY_CTX *ctx, unsigned char *sig,
+                                 size_t *siglen, size_t sigsize);
  int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
                    unsigned char *sig, size_t *siglen,
                    const unsigned char *tbs, size_t tbslen);
@@ -26,37 +35,120 @@ for more information about implicit fetches.
 EVP_PKEY_sign_init_ex() is the same as EVP_PKEY_sign_init() but additionally
 sets the passed parameters I<params> on the context before returning.
 
-The EVP_PKEY_sign() function performs a public key signing operation
-using I<ctx>. The data to be signed is specified using the I<tbs> and
-I<tbslen> parameters. If I<sig> is NULL then the maximum size of the output
-buffer is written to the I<siglen> parameter. If I<sig> is not NULL then
-before the call the I<siglen> parameter should contain the length of the
-I<sig> buffer, if the call is successful the signature is written to
-I<sig> and the amount of data written to I<siglen>.
+EVP_PKEY_sign_init_ex2() initializes a public key algorithm context I<ctx> for
+signing a pre-computed message digest using the algorithm given by I<algo> and
+the key given through L<EVP_PKEY_CTX_new(3)> or L<EVP_PKEY_CTX_new_from_pkey(3)>.
+A context I<ctx> without a pre-loaded key cannot be used with this function.
+This function provides almost the same functionality as EVP_PKEY_sign_init_ex(),
+but is uniquely intended to be used with a pre-computed messsage digest, and
+allows pre-determining the exact conditions for that message digest, if a
+composite signature algorithm (such as RSA-SHA256) was fetched.
+Following a call to this function, setting parameters that modifies the digest
+implementation or padding is not normally supported.
+
+EVP_PKEY_sign_message_init() initializes a public key algorithm context I<ctx>
+for signing an unlimited size message using the algorithm given by I<algo> and
+the key given through L<EVP_PKEY_CTX_new(3)> or L<EVP_PKEY_CTX_new_from_pkey(3)>.
+Passing the message is supported both in a one-shot fashion using
+EVP_PKEY_sign(), and through the combination of EVP_PKEY_sign_message_update()
+and EVP_PKEY_sign_message_final().
+This function enables using algorithms that can process input of arbitrary
+length, such as ED25519, RSA-SHA256 and similar.
+
+EVP_PKEY_sign_message_update() adds I<inlen> bytes from I<in> to the data to be
+processed for signature.  The signature algorithm specification and
+implementation determine how the input bytes are processed and if there's a
+limit on the total size of the input.  See L</NOTES> below for a deeper
+explanation.
+
+EVP_PKEY_sign_message_final() signs the processed data and places the data in
+I<sig>, and the number of signature bytes in I<*siglen>, if the number of
+bytes doesn't surpass the size given by I<sigsize>.
+I<sig> may be NULL, and in that case, only I<*siglen> is updated with the
+number of signature bytes.
+
+EVP_PKEY_sign() is a one-shot function that can be used with all the init
+functions above.
+When initialization was done with EVP_PKEY_sign_init(), EVP_PKEY_sign_init_ex()
+or EVP_PKEY_sign_init_ex2(), the data specified by I<tbs> and I<tbslen> is
+signed after appropriate padding.
+When initialization was done with EVP_PKEY_sign_message_init(), the data
+specified by I<tbs> and I<tbslen> is digested by the implied message digest
+algorithm, and the result is signed after appropriate padding.
+If I<sig> is NULL then the maximum size of the output buffer is written to the
+I<siglen> parameter.
+If I<sig> is not NULL, then before the call the I<siglen> parameter should
+contain the length of the I<sig> buffer, and if the call is successful the
+signature is written to I<sig> and the amount of data written to I<siglen>.
 
 =head1 NOTES
 
-EVP_PKEY_sign() does not hash the data to be signed, and therefore is
-normally used to sign digests. For signing arbitrary messages, see the
-L<EVP_DigestSignInit(3)> and
-L<EVP_SignInit(3)> signing interfaces instead.
+=begin comment
 
-After the call to EVP_PKEY_sign_init() algorithm specific control
-operations can be performed to set any appropriate parameters for the
-operation (see L<EVP_PKEY_CTX_ctrl(3)>).
+These notes are largely replicated in EVP_PKEY_verify.pod, please keep them
+in sync.
 
-The function EVP_PKEY_sign() can be called more than once on the same
-context if several operations are performed using the same parameters.
+=end comment
+
+=head2 General
+
+Some signature implementations only accumulate the input data and do no
+further processing before signing it (they expect the input to be a digest),
+while others compress the data, typically by internally producing a digest,
+and signing the result.
+Some of them support both modes of operation at the same time.
+The caller is expected to know how the chosen algorithm is supposed to behave
+and under what conditions.
+
+For example, an RSA implementation can be expected to only expect a message
+digest as input, while ED25519 can be expected to process the input with a hash,
+i.e. to produce the message digest internally, and while RSA-SHA256 can be
+expected to handle either mode of operation, depending on if the operation was
+initialized with EVP_PKEY_sign_init_ex2() or with EVP_PKEY_sign_message_init(). 
+
+Similarly, an RSA implementation usually expects additional details to be set,
+like the message digest algorithm that the input is supposed to be digested
+with, as well as the padding mode (see L<EVP_PKEY_CTX_set_signature_md(3)> and
+L<EVP_PKEY_CTX_set_rsa_padding(3)> and similar others), while an RSA-SHA256
+implementation usually has these details pre-set and immutable.
+
+The functions described here can't be used to combine separate algorithms.  In
+particular, neither L<EVP_PKEY_CTX_set_signature_md(3)> nor the B<OSSL_PARAM>
+parameter "digest" (B<OSSL_SIGNATURE_PARAM_DIGEST>) can be used to combine a
+signature algorithm with a hash algorithm to process the input.  In other
+words, it's not possible to specify a I<ctx> pre-loaded with an RSA pkey, or
+an I<algo> that fetched C<RSA> and try to specify SHA256 separately to get the
+functionality of RSA-SHA256.  If combining algorithms in that manner is
+desired, please use L<EVP_DigestSignInit(3)> and associated functions.
+
+=head2 Performing multiple signatures
+
+When initialized using EVP_PKEY_sign_init_ex() or  EVP_PKEY_sign_init_ex2(),
+EVP_PKEY_sign() can be called more than once on the same context to have
+several one-shot operations performed using the same parameters.
+
+When initialized using EVP_PKEY_sign_message_init(), it's not possible to
+call EVP_PKEY_sign() multiple times.
 
 =head1 RETURN VALUES
 
-EVP_PKEY_sign_init() and EVP_PKEY_sign() return 1 for success and 0
-or a negative value for failure. In particular a return value of -2
-indicates the operation is not supported by the public key algorithm.
+All functions return 1 for success and 0 or a negative value for failure.
+
+In particular, EVP_PKEY_sign_init() and its other variants may return -2 to
+indicate that the operation is not supported by the public key algorithm.
 
 =head1 EXAMPLES
 
-Sign data using RSA with PKCS#1 padding and SHA256 digest:
+=begin comment
+
+These examples are largely replicated in EVP_PKEY_verify.pod, please keep them
+in sync.
+
+=end comment
+
+=head2 RSA with PKCS#1 padding for SHA256
+
+Sign data using RSA with PKCS#1 padding and a SHA256 digest as input:
 
  #include <openssl/evp.h>
  #include <openssl/rsa.h>
@@ -73,7 +165,7 @@ Sign data using RSA with PKCS#1 padding and SHA256 digest:
   * point to the SHA-256 digest to be signed.
   */
  ctx = EVP_PKEY_CTX_new(signing_key, NULL /* no engine */);
- if (!ctx)
+ if (ctx == NULL)
      /* Error occurred */
  if (EVP_PKEY_sign_init(ctx) <= 0)
      /* Error */
@@ -88,7 +180,50 @@ Sign data using RSA with PKCS#1 padding and SHA256 digest:
 
  sig = OPENSSL_malloc(siglen);
 
- if (!sig)
+ if (sig == NULL)
+     /* malloc failure */
+
+ if (EVP_PKEY_sign(ctx, sig, &siglen, md, mdlen) <= 0)
+     /* Error */
+
+ /* Signature is siglen bytes written to buffer sig */
+
+=head2 RSA-SHA256 with a pre-computed digest
+
+Sign a digest with RSA-SHA256 using one-shot functions.  To be noted is that
+RSA-SHA256 is assumed to be an implementation of C<sha256WithRSAEncryption>,
+for which the padding is pre-determined to be B<RSA_PKCS1_PADDING>, and the
+input digest is assumed to have been computed using SHA256.
+
+ #include <openssl/evp.h>
+ #include <openssl/rsa.h>
+
+ EVP_PKEY_CTX *ctx;
+ /* md is a SHA-256 digest in this example. */
+ unsigned char *md, *sig;
+ size_t mdlen = 32, siglen;
+ EVP_PKEY *signing_key;
+
+ /*
+  * NB: assumes signing_key and md are set up before the next
+  * step. signing_key must be an RSA private key and md must
+  * point to the SHA-256 digest to be signed.
+  */
+ ctx = EVP_PKEY_CTX_new(signing_key, NULL /* no engine */);
+ alg = EVP_SIGNATURE_fetch(NULL, "RSA-SHA256", NULL);
+
+ if (ctx == NULL)
+     /* Error occurred */
+ if (EVP_PKEY_sign_init_ex2(ctx, alg, NULL) <= 0)
+     /* Error */
+
+ /* Determine buffer length */
+ if (EVP_PKEY_sign(ctx, NULL, &siglen, md, mdlen) <= 0)
+     /* Error */
+
+ sig = OPENSSL_malloc(siglen);
+
+ if (sig == NULL)
      /* malloc failure */
 
  if (EVP_PKEY_sign(ctx, sig, &siglen, md, mdlen) <= 0)
@@ -97,6 +232,109 @@ Sign data using RSA with PKCS#1 padding and SHA256 digest:
  /* Signature is siglen bytes written to buffer sig */
 
 
+=head2 RSA-SHA256, one-shot
+
+Sign a document with RSA-SHA256 using one-shot functions.
+To be noted is that RSA-SHA256 is assumed to be an implementation of
+C<sha256WithRSAEncryption>, for which the padding is pre-determined to be
+B<RSA_PKCS1_PADDING>.
+
+ #include <openssl/evp.h>
+ #include <openssl/rsa.h>
+
+ EVP_PKEY_CTX *ctx;
+ /* in is the input in this example. */
+ unsigned char *in, *sig;
+ /* inlen is the length of the input in this example. */
+ size_t inlen, siglen;
+ EVP_PKEY *signing_key;
+ EVP_SIGNATURE *alg;
+
+ /*
+  * NB: assumes signing_key, in and inlen are set up before
+  * the next step. signing_key must be an RSA private key,
+  * in must point to data to be digested and signed, and
+  * inlen must be the size of the data in bytes.
+  */
+ ctx = EVP_PKEY_CTX_new(signing_key, NULL /* no engine */);
+ alg = EVP_SIGNATURE_fetch(NULL, "RSA-SHA256", NULL);
+
+ if (ctx == NULL || alg == NULL)
+     /* Error occurred */
+ if (EVP_PKEY_sign_message_init(ctx, alg, NULL) <= 0)
+     /* Error */
+
+ /* Determine sig buffer length */
+ if (EVP_PKEY_sign(ctx, NULL, &siglen, in, inlen) <= 0)
+     /* Error */
+
+ sig = OPENSSL_malloc(siglen);
+
+ if (sig == NULL)
+     /* malloc failure */
+
+ if (EVP_PKEY_sign(ctx, sig, &siglen, in, inlen) <= 0)
+     /* Error */
+
+ /* Signature is siglen bytes written to buffer sig */
+
+
+=head2 RSA-SHA256, using update and final
+
+This is the same as the previous example, but allowing stream-like
+functionality.
+
+ #include <openssl/evp.h>
+ #include <openssl/rsa.h>
+
+ EVP_PKEY_CTX *ctx;
+ /* in is the input in this example. */
+ unsigned char *in, *sig;
+ /* inlen is the length of the input in this example. */
+ size_t inlen, siglen;
+ EVP_PKEY *signing_key;
+ EVP_SIGNATURE *alg;
+
+ /*
+  * NB: assumes signing_key, in and inlen are set up before
+  * the next step. signing_key must be an RSA private key,
+  * in must point to data to be digested and signed, and
+  * inlen must be the size of the data in bytes.
+  */
+ ctx = EVP_PKEY_CTX_new(signing_key, NULL /* no engine */);
+ alg = EVP_SIGNATURE_fetch(NULL, "RSA-SHA256", NULL);
+
+ if (ctx == NULL || alg == NULL)
+     /* Error occurred */
+ if (EVP_PKEY_sign_message_init(ctx, alg, NULL) <= 0)
+     /* Error */
+
+ while (inlen > 0) {
+     if (EVP_PKEY_sign_message_update(ctx, in, inlen)) <= 0)
+         /* Error */
+     if (inlen > 256) {
+         inlen -= 256;
+         in += 256;
+     } else {
+         inlen = 0;
+     }
+ }
+
+ /* Determine sig buffer length */
+ if (EVP_PKEY_sign_message_final(ctx, NULL, &siglen) <= 0)
+     /* Error */
+
+ sig = OPENSSL_malloc(siglen);
+
+ if (sig == NULL)
+     /* malloc failure */
+
+ if (EVP_PKEY_sign_message_final(ctx, sig, &siglen) <= 0)
+     /* Error */
+
+ /* Signature is siglen bytes written to buffer sig */
+
+
 =head1 SEE ALSO
 
 L<EVP_PKEY_CTX_new(3)>,
@@ -114,6 +352,10 @@ OpenSSL 1.0.0.
 
 The EVP_PKEY_sign_init_ex() function was added in OpenSSL 3.0.
 
+The EVP_PKEY_sign_init_ex2(), EVP_PKEY_sign_message_init(),
+EVP_PKEY_sign_message_update() and EVP_PKEY_sign_message_final() functions
+where added in OpenSSL 3.4.
+
 =head1 COPYRIGHT
 
 Copyright 2006-2021 The OpenSSL Project Authors. All Rights Reserved.
index 77023cab8704f56fce36b347937e3cb8aaa17d96..26b1794f9959cd43dd92629b6614ec2677770376 100644 (file)
@@ -2,8 +2,10 @@
 
 =head1 NAME
 
-EVP_PKEY_verify_init, EVP_PKEY_verify_init_ex, EVP_PKEY_verify
-- signature verification using a public key algorithm
+EVP_PKEY_verify_init, EVP_PKEY_verify_init_ex, EVP_PKEY_verify_init_ex2,
+EVP_PKEY_verify, EVP_PKEY_verify_message_init, EVP_PKEY_verify_message_update,
+EVP_PKEY_verify_message_final, EVP_PKEY_CTX_set_signature - signature
+verification using a public key algorithm
 
 =head1 SYNOPSIS
 
@@ -11,6 +13,15 @@ EVP_PKEY_verify_init, EVP_PKEY_verify_init_ex, EVP_PKEY_verify
 
  int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx);
  int EVP_PKEY_verify_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]);
+ int EVP_PKEY_verify_init_ex2(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *algo,
+                              const OSSL_PARAM params[]);
+ int EVP_PKEY_verify_message_init(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *algo,
+                                  const OSSL_PARAM params[]);
+ int EVP_PKEY_CTX_set_signature(EVP_PKEY_CTX *pctx,
+                                const unsigned char *sig, size_t siglen);
+ int EVP_PKEY_verify_message_update(EVP_PKEY_CTX *ctx,
+                                    unsigned char *in, size_t inlen);
+ int EVP_PKEY_verify_message_final(EVP_PKEY_CTX *ctx);
  int EVP_PKEY_verify(EVP_PKEY_CTX *ctx,
                      const unsigned char *sig, size_t siglen,
                      const unsigned char *tbs, size_t tbslen);
@@ -18,7 +29,7 @@ EVP_PKEY_verify_init, EVP_PKEY_verify_init_ex, EVP_PKEY_verify
 =head1 DESCRIPTION
 
 EVP_PKEY_verify_init() initializes a public key algorithm context I<ctx> for
-signing using the algorithm given when the context was created
+verification using the algorithm given when the context was created
 using L<EVP_PKEY_CTX_new(3)> or variants thereof.  The algorithm is used to
 fetch a B<EVP_SIGNATURE> method implicitly, see L<provider(7)/Implicit fetch>
 for more information about implicit fetches.
@@ -26,27 +37,113 @@ for more information about implicit fetches.
 EVP_PKEY_verify_init_ex() is the same as EVP_PKEY_verify_init() but additionally
 sets the passed parameters I<params> on the context before returning.
 
-The EVP_PKEY_verify() function performs a public key verification operation
-using I<ctx>. The signature is specified using the I<sig> and
-I<siglen> parameters. The verified data (i.e. the data believed originally
-signed) is specified using the I<tbs> and I<tbslen> parameters.
+EVP_PKEY_verify_init_ex2() is the same as EVP_PKEY_verify_init_ex(), but works
+with an explicitly fetched B<EVP_SIGNATURE> I<algo>.
+A context I<ctx> without a pre-loaded key cannot be used with this function.
+Depending on what algorithm was fetched, certain details revolving around the
+treatment of the input to EVP_PKEY_verify() may be pre-determined, and in that
+case, those details may normally not be changed.
+See L</NOTES> below for a deeper explanation.
+
+EVP_PKEY_verify_message_init() initializes a public key algorithm context
+I<ctx> for verifying an unlimited size message using the algorithm given by
+I<algo> and the key given through L<EVP_PKEY_CTX_new(3)> or
+L<EVP_PKEY_CTX_new_from_pkey(3)>.
+Passing the message is supported both in a one-shot fashion using
+EVP_PKEY_verify(), and through the combination of EVP_PKEY_verify_update() and
+EVP_PKEY_verify_final().
+This function enables using algorithms that can process input of arbitrary
+length, such as ED25519, RSA-SHA256 and similar.
+
+EVP_PKEY_CTX_set_signature() specifies the I<siglen> bytes long signature
+I<sig> to be verified against by EVP_PKEY_verify_final().
+It I<must> be used together with EVP_PKEY_verify_update() and
+EVP_PKEY_verify_final().
+See L</NOTES> below for a deeper explanation.
+
+EVP_PKEY_verify_update() adds I<inlen> bytes from I<in> to the data to be
+processed for verification.  The signature algorithm specification and
+implementation determine how the input bytes are processed and if there's a
+limit on the total size of the input.  See L</NOTES> below for a deeper
+explanation.
+
+EVP_PKEY_verify_final() verifies the processed data, given only I<ctx>.
+The signature to verify against must have been given with
+EVP_PKEY_CTX_set_signature().
+
+EVP_PKEY_verify() is a one-shot function that performs the same thing as
+EVP_PKEY_CTX_set_signature() call with I<sig> and I<siglen> as parameters,
+followed by a single EVP_PKEY_verify_update() call with I<tbs> and I<tbslen>,
+followed by EVP_PKEY_verify_final() call.
 
 =head1 NOTES
 
-After the call to EVP_PKEY_verify_init() algorithm specific control
-operations can be performed to set any appropriate parameters for the
-operation.
+=begin comment
+
+These notes are largely replicated in EVP_PKEY_sign.pod, please keep them
+in sync.
+
+=end comment
+
+=head2 General
+
+Some signature implementations only accumulate the input data and do no
+further processing before verifying it (they expect the input to be a digest),
+while others compress the data, typically by internally producing a digest,
+and signing the result, which is then verified against a given signature.
+Some of them support both modes of operation at the same time.
+The caller is expected to know how the chosen algorithm is supposed to behave
+and under what conditions.
+
+For example, an RSA implementation can be expected to only expect a digest as
+input, while ED25519 can be expected to process the input with a hash, i.e.
+to produce the digest internally, and while RSA-SHA256 can be expected to
+handle either mode of operation, depending on if the operation was initialized
+with EVP_PKEY_verify_init_ex2() or with EVP_PKEY_verify_message_init().
+
+Similarly, an RSA implementation usually expects additional details to be set,
+like the message digest algorithm that the input is supposed to be digested
+with, as well as the padding mode (see L<EVP_PKEY_CTX_set_signature_md(3)> and
+L<EVP_PKEY_CTX_set_rsa_padding(3)> and similar others), while an RSA-SHA256
+implementation usually has these details pre-set and immutable.
 
-The function EVP_PKEY_verify() can be called more than once on the same
-context if several operations are performed using the same parameters.
+The functions described here can't be used to combine separate algorithms.  In
+particular, neither L<EVP_PKEY_CTX_set_signature_md(3)> nor the B<OSSL_PARAM>
+parameter "digest" (B<OSSL_SIGNATURE_PARAM_DIGEST>) can be used to combine a
+signature algorithm with a hash algorithm to process the input.  In other
+words, it's not possible to specify a I<ctx> pre-loaded with an RSA pkey, or
+an I<algo> that fetched C<RSA> and try to specify SHA256 separately to get the
+functionality of RSA-SHA256.  If combining algorithms in that manner is
+desired, please use L<EVP_DigestVerifyInit(3)> and associated functions, or
+L<EVP_VerifyInit(3)> and associated functions.
+
+=head2 Performing multiple verifications
+
+When initialized using EVP_PKEY_verify_init_ex() or  EVP_PKEY_verify_init_ex2(),
+EVP_PKEY_verify() can be called more than once on the same context to have
+several one-shot operations performed using the same parameters.
+
+When initialized using EVP_PKEY_verify_message_init(), it's not possible to
+call EVP_PKEY_verify() multiple times.
+
+=head2 On EVP_PKEY_CTX_set_signature()
+
+Some signature algorithms (such as LMS) require the signature verification
+data be specified before verifying the message.
+Other algorithms allow the signature to be specified late.
+To allow either way (which may depend on the application's flow of input), the
+signature to be verified against I<must> be specified using this function when
+using EVP_PKEY_verify_message_update() and EVP_PKEY_verify_message_final() to
+perform the verification.
 
 =head1 RETURN VALUES
 
-EVP_PKEY_verify_init() and EVP_PKEY_verify() return 1 if the verification was
-successful and 0 if it failed. Unlike other functions the return value 0 from
-EVP_PKEY_verify() only indicates that the signature did not verify
-successfully (that is tbs did not match the original data or the signature was
-of invalid form) it is not an indication of a more serious error.
+All functions return 1 for success and 0 or a negative value for failure.
+However, unlike other functions, the return value 0 from EVP_PKEY_verify(),
+EVP_PKEY_verify_recover() and EVP_PKEY_verify_message_final() only indicates
+that the signature did not verify successfully (that is tbs did not match the
+original data or the signature was of invalid form) it is not an indication of
+a more serious error.
 
 A negative value indicates an error other that signature verification failure.
 In particular a return value of -2 indicates the operation is not supported by
@@ -54,7 +151,16 @@ the public key algorithm.
 
 =head1 EXAMPLES
 
-Verify signature using PKCS#1 and SHA256 digest:
+=begin comment
+
+These examples are largely replicated in EVP_PKEY_sign.pod, please keep them
+in sync.
+
+=end comment
+
+=head2 RSA with PKCS#1 padding for SHA256
+
+Verify signature using PKCS#1 padding and a SHA256 digest as input:
 
  #include <openssl/evp.h>
  #include <openssl/rsa.h>
@@ -69,7 +175,7 @@ Verify signature using PKCS#1 and SHA256 digest:
   * and that verify_key is an RSA public key
   */
  ctx = EVP_PKEY_CTX_new(verify_key, NULL /* no engine */);
- if (!ctx)
+ if (ctx == NULL)
      /* Error occurred */
  if (EVP_PKEY_verify_init(ctx) <= 0)
      /* Error */
@@ -86,6 +192,138 @@ Verify signature using PKCS#1 and SHA256 digest:
   * other error.
   */
 
+=head2 RSA-SHA256 with a pre-computed digest
+
+Verify a digest with RSA-SHA256 using one-shot functions.  To be noted is that
+RSA-SHA256 is assumed to be an implementation of C<sha256WithRSAEncryption>,
+for which the padding is pre-determined to be B<RSA_PKCS1_PADDING>, and the
+input digest is assumed to have been computed using SHA256.
+
+ #include <openssl/evp.h>
+ #include <openssl/rsa.h>
+
+ EVP_PKEY_CTX *ctx;
+ /* md is a SHA-256 digest in this example. */
+ unsigned char *md, *sig;
+ size_t mdlen = 32, siglen;
+ EVP_PKEY *signing_key;
+
+ /*
+  * NB: assumes verify_key, sig, siglen, md and mdlen are already set up
+  * and that verify_key is an RSA public key
+  */
+ ctx = EVP_PKEY_CTX_new(signing_key, NULL /* no engine */);
+ alg = EVP_SIGNATURE_fetch(NULL, "RSA-SHA256", NULL);
+
+ if (ctx == NULL)
+     /* Error occurred */
+ if (EVP_PKEY_verify_init_ex2(ctx, alg, NULL) <= 0)
+     /* Error */
+
+ /* Determine buffer length */
+ if (EVP_PKEY_verify(ctx, sig, siglen, md, mdlen) <= 0)
+     /* Error or signature doesn't verify */
+
+ /* Perform operation */
+ ret = EVP_PKEY_verify(ctx, sig, siglen, md, mdlen);
+
+ /*
+  * ret == 1 indicates success, 0 verify failure and < 0 for some
+  * other error.
+  */
+
+=head2 RSA-SHA256, one-shot
+
+Verify a document with RSA-SHA256 using one-shot functions.
+To be noted is that RSA-SHA256 is assumed to be an implementation of
+C<sha256WithRSAEncryption>, for which the padding is pre-determined to be
+B<RSA_PKCS1_PADDING>.
+
+ #include <openssl/evp.h>
+ #include <openssl/rsa.h>
+
+ EVP_PKEY_CTX *ctx;
+ /* in the input in this example. */
+ unsigned char *in, *sig;
+ /* inlen is the length of the input in this example. */
+ size_t inlen, siglen;
+ EVP_PKEY *signing_key;
+ EVP_SIGNATURE *alg;
+
+ /*
+  * NB: assumes signing_key, in and inlen are set up before
+  * the next step. signing_key must be an RSA private key,
+  * in must point to data to be digested and signed, and
+  * inlen must be the size of the data in bytes.
+  */
+ ctx = EVP_PKEY_CTX_new(signing_key, NULL /* no engine */);
+ alg = EVP_SIGNATURE_fetch(NULL, "RSA-SHA256", NULL);
+
+ if (ctx == NULL || alg == NULL)
+     /* Error occurred */
+ if (EVP_PKEY_verify_message_init(ctx, alg, NULL) <= 0)
+     /* Error */
+
+ /* Perform operation */
+ ret = EVP_PKEY_verify(ctx, sig, siglen, in, inlen);
+
+ /*
+  * ret == 1 indicates success, 0 verify failure and < 0 for some
+  * other error.
+  */
+
+=head2 RSA-SHA256, using update and final
+
+This is the same as the previous example, but allowing stream-like
+functionality.
+
+ #include <openssl/evp.h>
+ #include <openssl/rsa.h>
+
+ EVP_PKEY_CTX *ctx;
+ /* in is the input in this example. */
+ unsigned char *in, *sig;
+ /* inlen is the length of the input in this example. */
+ size_t inlen, siglen;
+ EVP_PKEY *signing_key;
+ EVP_SIGNATURE *alg;
+
+ /*
+  * NB: assumes signing_key, in and inlen are set up before
+  * the next step. signing_key must be an RSA private key,
+  * in must point to data to be digested and signed, and
+  * inlen must be the size of the data in bytes.
+  */
+ ctx = EVP_PKEY_CTX_new(signing_key, NULL /* no engine */);
+ alg = EVP_SIGNATURE_fetch(NULL, "RSA-SHA256", NULL);
+
+ if (ctx == NULL || alg == NULL)
+     /* Error occurred */
+ if (EVP_PKEY_verify_message_init(ctx, alg, NULL) <= 0)
+     /* Error */
+
+ /* We have the signature, specify it early */
+ EVP_PKEY_CTX_set_signature(ctx, sig, siglen);
+
+ /* Perform operation */
+ while (inlen > 0) {
+     if (EVP_PKEY_verify_message_update(ctx, in, inlen)) <= 0)
+         /* Error */
+     if (inlen > 256) {
+         inlen -= 256;
+         in += 256;
+     } else {
+         inlen = 0;
+     }
+ }
+ ret = EVP_PKEY_verify_message_final(ctx);
+
+ /*
+  * ret == 1 indicates success, 0 verify failure and < 0 for some
+  * other error.
+  */
+
+
 =head1 SEE ALSO
 
 L<EVP_PKEY_CTX_new(3)>,
@@ -102,6 +340,10 @@ OpenSSL 1.0.0.
 
 The EVP_PKEY_verify_init_ex() function was added in OpenSSL 3.0.
 
+The EVP_PKEY_verify_init_ex2(), EVP_PKEY_verify_message_init(),
+EVP_PKEY_verify_message_update(), EVP_PKEY_verify_message_final() and
+EVP_PKEY_CTX_set_signature() functions where added in OpenSSL 3.4.
+
 =head1 COPYRIGHT
 
 Copyright 2006-2021 The OpenSSL Project Authors. All Rights Reserved.
index 7f0a06c03960c33045571d36bd61301268a43618..fd700313789c87cf62de6f2c3d23a17b8791a8df 100644 (file)
@@ -3,7 +3,7 @@
 =head1 NAME
 
 EVP_PKEY_verify_recover_init, EVP_PKEY_verify_recover_init_ex,
-EVP_PKEY_verify_recover
+EVP_PKEY_verify_recover_init_ex2, EVP_PKEY_verify_recover
 - recover signature using a public key algorithm
 
 =head1 SYNOPSIS
@@ -13,6 +13,8 @@ EVP_PKEY_verify_recover
  int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx);
  int EVP_PKEY_verify_recover_init_ex(EVP_PKEY_CTX *ctx,
                                      const OSSL_PARAM params[]);
+ int EVP_PKEY_verify_recover_init_ex2(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *algo,
+                                      const OSSL_PARAM params[]);
  int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx,
                              unsigned char *rout, size_t *routlen,
                              const unsigned char *sig, size_t siglen);
@@ -29,6 +31,14 @@ EVP_PKEY_verify_recover_init_ex() is the same as
 EVP_PKEY_verify_recover_init() but additionally sets the passed parameters
 I<params> on the context before returning.
 
+EVP_PKEY_verify_recover_init_ex2() is the same as EVP_PKEY_verify_recover_init_ex(),
+but works with an explicitly fetched B<EVP_SIGNATURE> I<algo>.
+A context I<ctx> without a pre-loaded key cannot be used with this function.
+Depending on what algorithm was fetched, certain details revolving around the
+treatment of the input to EVP_PKEY_verify() may be pre-determined, and in that
+case, those details may normally not be changed.
+See L</NOTES> below for a deeper explanation.
+
 The EVP_PKEY_verify_recover() function recovers signed data
 using I<ctx>. The signature is specified using the I<sig> and
 I<siglen> parameters. If I<rout> is NULL then the maximum size of the output
@@ -51,6 +61,10 @@ After the call to EVP_PKEY_verify_recover_init() algorithm specific control
 operations can be performed to set any appropriate parameters for the
 operation.
 
+After the call to EVP_PKEY_verify_recover_init_ex2(), algorithm specific control
+operations may not be needed if the chosen algorithm implies that those controls
+pre-set (and immutable).
+
 The function EVP_PKEY_verify_recover() can be called more than once on the same
 context if several operations are performed using the same parameters.
 
index 2769e753926a17fd7fe93dcdb1c807e15cc1d467..68b3321505ed88313c840056ff87c8ce24f5d092 100644 (file)
@@ -741,22 +741,45 @@ OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, keyexch_gettable_ctx_params,
 # define OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS 23
 # define OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS      24
 # define OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS 25
+# define OSSL_FUNC_SIGNATURE_QUERY_KEY_TYPES        26
+# define OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT      27
+# define OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_UPDATE    28
+# define OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_FINAL     29
+# define OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT    30
+# define OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_UPDATE  31
+# define OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_FINAL   32
 
 OSSL_CORE_MAKE_FUNC(void *, signature_newctx, (void *provctx,
-                                                  const char *propq))
+                                               const char *propq))
 OSSL_CORE_MAKE_FUNC(int, signature_sign_init, (void *ctx, void *provkey,
                                                const OSSL_PARAM params[]))
 OSSL_CORE_MAKE_FUNC(int, signature_sign, (void *ctx,  unsigned char *sig,
-                                             size_t *siglen, size_t sigsize,
-                                             const unsigned char *tbs,
-                                             size_t tbslen))
+                                          size_t *siglen, size_t sigsize,
+                                          const unsigned char *tbs,
+                                          size_t tbslen))
+OSSL_CORE_MAKE_FUNC(int, signature_sign_message_init,
+                    (void *ctx, void *provkey, const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(int, signature_sign_message_update,
+                    (void *ctx, const unsigned char *in, size_t inlen))
+OSSL_CORE_MAKE_FUNC(int, signature_sign_message_final,
+                    (void *ctx, unsigned char *sig,
+                     size_t *siglen, size_t sigsize))
 OSSL_CORE_MAKE_FUNC(int, signature_verify_init, (void *ctx, void *provkey,
                                                  const OSSL_PARAM params[]))
 OSSL_CORE_MAKE_FUNC(int, signature_verify, (void *ctx,
-                                               const unsigned char *sig,
-                                               size_t siglen,
-                                               const unsigned char *tbs,
-                                               size_t tbslen))
+                                            const unsigned char *sig,
+                                            size_t siglen,
+                                            const unsigned char *tbs,
+                                            size_t tbslen))
+OSSL_CORE_MAKE_FUNC(int, signature_verify_message_init,
+                    (void *ctx, void *provkey, const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(int, signature_verify_message_update,
+                    (void *ctx, const unsigned char *in, size_t inlen))
+/*
+ * signature_verify_final requires that the signature to be verified against
+ * is specified via an OSSL_PARAM.
+ */
+OSSL_CORE_MAKE_FUNC(int, signature_verify_message_final, (void *ctx))
 OSSL_CORE_MAKE_FUNC(int, signature_verify_recover_init,
                     (void *ctx, void *provkey, const OSSL_PARAM params[]))
 OSSL_CORE_MAKE_FUNC(int, signature_verify_recover,
@@ -801,7 +824,7 @@ OSSL_CORE_MAKE_FUNC(int, signature_set_ctx_md_params,
                     (void *ctx, const OSSL_PARAM params[]))
 OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, signature_settable_ctx_md_params,
                     (void *ctx))
-
+OSSL_CORE_MAKE_FUNC(const char **, signature_query_key_types, (void))
 
 /* Asymmetric Ciphers */
 
index 5ce5dbb234350334822a9b55f0b5ade8eb57070a..97ca2a08319750bfaeaaf0a4148b0bf2d6a6389e 100644 (file)
@@ -1703,11 +1703,15 @@ const char *EVP_PKEY_get0_type_name(const EVP_PKEY *key);
 # define EVP_PKEY_OP_DERIVE              (1 << 11)
 # define EVP_PKEY_OP_ENCAPSULATE         (1 << 12)
 # define EVP_PKEY_OP_DECAPSULATE         (1 << 13)
+# define EVP_PKEY_OP_SIGNMSG             (1 << 14)
+# define EVP_PKEY_OP_VERIFYMSG           (1 << 15)
 /* Update the following when adding new EVP_PKEY_OPs */
-# define EVP_PKEY_OP_ALL                ((1 << 14) - 1)
+# define EVP_PKEY_OP_ALL                ((1 << 16) - 1)
 
 # define EVP_PKEY_OP_TYPE_SIG                                           \
-    (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYRECOVER  \
+    (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_SIGNMSG                             \
+     | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYMSG                       \
+     | EVP_PKEY_OP_VERIFYRECOVER                                        \
      | EVP_PKEY_OP_SIGNCTX | EVP_PKEY_OP_VERIFYCTX)
 
 # define EVP_PKEY_OP_TYPE_CRYPT                                         \
@@ -1857,6 +1861,9 @@ EVP_PKEY *EVP_PKEY_CTX_get0_peerkey(EVP_PKEY_CTX *ctx);
 void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data);
 void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx);
 
+int EVP_PKEY_CTX_set_signature(EVP_PKEY_CTX *pctx,
+                               const unsigned char *sig, size_t siglen);
+
 void EVP_SIGNATURE_free(EVP_SIGNATURE *signature);
 int EVP_SIGNATURE_up_ref(EVP_SIGNATURE *signature);
 OSSL_PROVIDER *EVP_SIGNATURE_get0_provider(const EVP_SIGNATURE *signature);
@@ -1910,17 +1917,35 @@ const OSSL_PARAM *EVP_KEM_settable_ctx_params(const EVP_KEM *kem);
 
 int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_sign_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]);
+int EVP_PKEY_sign_init_ex2(EVP_PKEY_CTX *ctx,
+                           EVP_SIGNATURE *algo, const OSSL_PARAM params[]);
 int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
                   unsigned char *sig, size_t *siglen,
                   const unsigned char *tbs, size_t tbslen);
+int EVP_PKEY_sign_message_init(EVP_PKEY_CTX *ctx,
+                               EVP_SIGNATURE *algo, const OSSL_PARAM params[]);
+int EVP_PKEY_sign_message_update(EVP_PKEY_CTX *ctx,
+                                 const unsigned char *in, size_t inlen);
+int EVP_PKEY_sign_message_final(EVP_PKEY_CTX *ctx,
+                                unsigned char *sig, size_t *siglen);
 int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_verify_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]);
+int EVP_PKEY_verify_init_ex2(EVP_PKEY_CTX *ctx,
+                             EVP_SIGNATURE *algo, const OSSL_PARAM params[]);
 int EVP_PKEY_verify(EVP_PKEY_CTX *ctx,
                     const unsigned char *sig, size_t siglen,
                     const unsigned char *tbs, size_t tbslen);
+int EVP_PKEY_verify_message_init(EVP_PKEY_CTX *ctx,
+                                 EVP_SIGNATURE *algo, const OSSL_PARAM params[]);
+int EVP_PKEY_verify_message_update(EVP_PKEY_CTX *ctx,
+                                   const unsigned char *in, size_t inlen);
+int EVP_PKEY_verify_message_final(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_verify_recover_init_ex(EVP_PKEY_CTX *ctx,
                                     const OSSL_PARAM params[]);
+int EVP_PKEY_verify_recover_init_ex2(EVP_PKEY_CTX *ctx,
+                                     EVP_SIGNATURE *algo,
+                                     const OSSL_PARAM params[]);
 int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx,
                             unsigned char *rout, size_t *routlen,
                             const unsigned char *sig, size_t siglen);
index 11f3faa459ed0c841021e977640e01ebdeae149d..2d879342242e50f6570d5fddfe55ed91506c97ef 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2024 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
@@ -94,6 +94,7 @@
 # define EVP_R_ONLY_ONESHOT_SUPPORTED                     177
 # define EVP_R_OPERATION_NOT_INITIALIZED                  151
 # define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE   150
+# define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_SIGNATURE_TYPE 226
 # define EVP_R_OUTPUT_WOULD_OVERFLOW                      202
 # define EVP_R_PARAMETER_TOO_LARGE                        187
 # define EVP_R_PARTIALLY_OVERLAPPING                      162
 # define EVP_R_PUBLIC_KEY_NOT_RSA                         106
 # define EVP_R_SETTING_XOF_FAILED                         227
 # define EVP_R_SET_DEFAULT_PROPERTY_FAILURE               209
+# define EVP_R_SIGNATURE_TYPE_AND_KEY_TYPE_INCOMPATIBLE   228
 # define EVP_R_TOO_MANY_RECORDS                           183
 # define EVP_R_UNABLE_TO_ENABLE_LOCKING                   212
 # define EVP_R_UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE         215
index ef11c0302e396872ec05b8a1facb9b224cc1d068..57c1e4686cd29049ca6f2b357d7b897415e65044 100644 (file)
@@ -5716,3 +5716,13 @@ OSSL_BASIC_ATTR_CONSTRAINTS_free        ?        3_4_0   EXIST::FUNCTION:
 OSSL_BASIC_ATTR_CONSTRAINTS_new         ?      3_4_0   EXIST::FUNCTION:
 OSSL_BASIC_ATTR_CONSTRAINTS_it          ?      3_4_0   EXIST::FUNCTION:
 EVP_KEYMGMT_gen_gettable_params         ?      3_4_0   EXIST::FUNCTION:
+EVP_PKEY_CTX_set_signature              ?      3_4_0   EXIST::FUNCTION:
+EVP_PKEY_sign_init_ex2                  ?      3_4_0   EXIST::FUNCTION:
+EVP_PKEY_sign_message_init              ?      3_4_0   EXIST::FUNCTION:
+EVP_PKEY_sign_message_update            ?      3_4_0   EXIST::FUNCTION:
+EVP_PKEY_sign_message_final             ?      3_4_0   EXIST::FUNCTION:
+EVP_PKEY_verify_init_ex2                ?      3_4_0   EXIST::FUNCTION:
+EVP_PKEY_verify_message_init            ?      3_4_0   EXIST::FUNCTION:
+EVP_PKEY_verify_message_update          ?      3_4_0   EXIST::FUNCTION:
+EVP_PKEY_verify_message_final           ?      3_4_0   EXIST::FUNCTION:
+EVP_PKEY_verify_recover_init_ex2        ?      3_4_0   EXIST::FUNCTION:
index e4edb550be03dae3d7243c951ddd6ffab6bc358d..9117b621523fe6cbe24ccc2b4c04c908e9014bcf 100644 (file)
@@ -434,6 +434,7 @@ my %params = (
     'SIGNATURE_PARAM_FIPS_RSA_PSS_SALTLEN_CHECK' => "rsa-pss-saltlen-check",
     'SIGNATURE_PARAM_FIPS_SIGN_X931_PAD_CHECK' => "sign-x931-pad-check",
     'SIGNATURE_PARAM_FIPS_APPROVED_INDICATOR' => '*ALG_PARAM_FIPS_APPROVED_INDICATOR',
+    'SIGNATURE_PARAM_SIGNATURE' =>          "signature",
 
 # Asym cipher parameters
     'ASYM_CIPHER_PARAM_DIGEST' =>                   '*PKEY_PARAM_DIGEST',