aboutsummaryrefslogtreecommitdiff
path: root/providers
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2019-12-01 15:01:50 +0100
committerRichard Levitte <levitte@openssl.org>2020-02-22 01:07:15 +0100
commit6f4b7663150e2ee264836dbc5b338bd979828312 (patch)
tree52d0a120512bb8ea123150e2ffccd0841008cbc2 /providers
parente8d0819d52b2741fcb4ddb79ced4d824c3056918 (diff)
downloadopenssl-6f4b7663150e2ee264836dbc5b338bd979828312.zip
openssl-6f4b7663150e2ee264836dbc5b338bd979828312.tar.gz
openssl-6f4b7663150e2ee264836dbc5b338bd979828312.tar.bz2
PROV: add RSA signature implementation
This includes legacy PSS controls to params conversion, and an attempt to generalise the parameter names when they are suitable for more than one operation. Also added crypto/rsa/rsa_aid.c, containing proper AlgorithmIdentifiers for known RSA+hash function combinations. Reviewed-by: Shane Lontis <shane.lontis@oracle.com> Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org> (Merged from https://github.com/openssl/openssl/pull/10557)
Diffstat (limited to 'providers')
-rw-r--r--providers/common/include/prov/providercommonerr.h10
-rw-r--r--providers/common/provider_err.c19
-rw-r--r--providers/defltprov.c1
-rw-r--r--providers/implementations/include/prov/implementations.h1
-rw-r--r--providers/implementations/signature/build.info3
-rw-r--r--providers/implementations/signature/rsa.c1113
6 files changed, 1147 insertions, 0 deletions
diff --git a/providers/common/include/prov/providercommonerr.h b/providers/common/include/prov/providercommonerr.h
index 6586d65..19ecab1 100644
--- a/providers/common/include/prov/providercommonerr.h
+++ b/providers/common/include/prov/providercommonerr.h
@@ -50,6 +50,7 @@ int ERR_load_PROV_strings(void);
* PROV reason codes.
*/
# define PROV_R_AES_KEY_SETUP_FAILED 101
+# define PROV_R_ALGORITHM_MISMATCH 173
# define PROV_R_BAD_DECRYPT 100
# define PROV_R_BAD_ENCODING 141
# define PROV_R_BAD_LENGTH 142
@@ -57,17 +58,20 @@ int ERR_load_PROV_strings(void);
# define PROV_R_BN_ERROR 160
# define PROV_R_BOTH_MODE_AND_MODE_INT 127
# define PROV_R_CIPHER_OPERATION_FAILED 102
+# define PROV_R_DIGEST_NOT_ALLOWED 174
# define PROV_R_FAILED_DURING_DERIVATION 164
# define PROV_R_FAILED_TO_DECRYPT 162
# define PROV_R_FAILED_TO_GENERATE_KEY 121
# define PROV_R_FAILED_TO_GET_PARAMETER 103
# define PROV_R_FAILED_TO_SET_PARAMETER 104
+# define PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 165
# define PROV_R_INAVLID_UKM_LENGTH 146
# define PROV_R_INVALID_AAD 108
# define PROV_R_INVALID_CONSTANT_LENGTH 157
# define PROV_R_INVALID_CUSTOM_LENGTH 111
# define PROV_R_INVALID_DATA 115
# define PROV_R_INVALID_DIGEST 122
+# define PROV_R_INVALID_DIGEST_LENGTH 166
# define PROV_R_INVALID_ITERATION_COUNT 123
# define PROV_R_INVALID_IVLEN 116
# define PROV_R_INVALID_IV_LENGTH 109
@@ -76,12 +80,17 @@ int ERR_load_PROV_strings(void);
# define PROV_R_INVALID_KEY_LEN 124
# define PROV_R_INVALID_KEY_LENGTH 105
# define PROV_R_INVALID_MAC 151
+# define PROV_R_INVALID_MGF1_MD 167
# define PROV_R_INVALID_MODE 125
# define PROV_R_INVALID_MODE_INT 126
+# define PROV_R_INVALID_PADDING_MODE 168
+# define PROV_R_INVALID_PSS_SALTLEN 169
# define PROV_R_INVALID_SALT_LENGTH 112
# define PROV_R_INVALID_SEED_LENGTH 154
# define PROV_R_INVALID_TAG 110
# define PROV_R_INVALID_TAGLEN 118
+# define PROV_R_INVALID_X931_DIGEST 170
+# define PROV_R_KEY_SIZE_TOO_SMALL 171
# define PROV_R_MISSING_CEK_ALG 144
# define PROV_R_MISSING_CIPHER 155
# define PROV_R_MISSING_CONSTANT 156
@@ -99,6 +108,7 @@ int ERR_load_PROV_strings(void);
# define PROV_R_NOT_XOF_OR_INVALID_LENGTH 113
# define PROV_R_NO_KEY_SET 114
# define PROV_R_OUTPUT_BUFFER_TOO_SMALL 106
+# define PROV_R_PSS_SALTLEN_TOO_SMALL 172
# define PROV_R_READ_KEY 159
# define PROV_R_TAG_NOTSET 119
# define PROV_R_TAG_NOT_NEEDED 120
diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c
index 792697c..f73f823 100644
--- a/providers/common/provider_err.c
+++ b/providers/common/provider_err.c
@@ -16,6 +16,8 @@
static const ERR_STRING_DATA PROV_str_reasons[] = {
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_AES_KEY_SETUP_FAILED),
"aes key setup failed"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_ALGORITHM_MISMATCH),
+ "algorithm mismatch"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_BAD_DECRYPT), "bad decrypt"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_BAD_ENCODING), "bad encoding"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_BAD_LENGTH), "bad length"},
@@ -26,6 +28,8 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
"both mode and mode int"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_CIPHER_OPERATION_FAILED),
"cipher operation failed"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_DIGEST_NOT_ALLOWED),
+ "digest not allowed"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_DURING_DERIVATION),
"failed during derivation"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_DECRYPT), "failed to decrypt"},
@@ -35,6 +39,8 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
"failed to get parameter"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_SET_PARAMETER),
"failed to set parameter"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE),
+ "illegal or unsupported padding mode"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INAVLID_UKM_LENGTH),
"inavlid ukm length"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_AAD), "invalid aad"},
@@ -44,6 +50,8 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
"invalid custom length"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_DATA), "invalid data"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_DIGEST), "invalid digest"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_DIGEST_LENGTH),
+ "invalid digest length"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_ITERATION_COUNT),
"invalid iteration count"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_IVLEN), "invalid ivlen"},
@@ -54,14 +62,23 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KEY_LENGTH),
"invalid key length"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_MAC), "invalid mac"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_MGF1_MD), "invalid mgf1 md"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_MODE), "invalid mode"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_MODE_INT), "invalid mode int"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_PADDING_MODE),
+ "invalid padding mode"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_PSS_SALTLEN),
+ "invalid pss saltlen"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_SALT_LENGTH),
"invalid salt length"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_SEED_LENGTH),
"invalid seed length"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_TAG), "invalid tag"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_TAGLEN), "invalid taglen"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_X931_DIGEST),
+ "invalid x931 digest"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_KEY_SIZE_TOO_SMALL),
+ "key size too small"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_MISSING_CEK_ALG), "missing cek alg"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_MISSING_CIPHER), "missing cipher"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_MISSING_CONSTANT), "missing constant"},
@@ -83,6 +100,8 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_NO_KEY_SET), "no key set"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_OUTPUT_BUFFER_TOO_SMALL),
"output buffer too small"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_PSS_SALTLEN_TOO_SMALL),
+ "pss saltlen too small"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_READ_KEY), "read key"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_TAG_NOTSET), "tag notset"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_TAG_NOT_NEEDED), "tag not needed"},
diff --git a/providers/defltprov.c b/providers/defltprov.c
index 0b2390a..5bebf66 100644
--- a/providers/defltprov.c
+++ b/providers/defltprov.c
@@ -384,6 +384,7 @@ static const OSSL_ALGORITHM deflt_signature[] = {
#ifndef OPENSSL_NO_DSA
{ "DSA:dsaEncryption", "provider=default", dsa_signature_functions },
#endif
+ { "RSA:rsaEncryption", "default=yes", rsa_signature_functions },
{ NULL, NULL, NULL }
};
diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h
index ec0507d..6d6a26d 100644
--- a/providers/implementations/include/prov/implementations.h
+++ b/providers/implementations/include/prov/implementations.h
@@ -269,6 +269,7 @@ extern const OSSL_DISPATCH ecdh_keyexch_functions[];
/* Signature */
extern const OSSL_DISPATCH dsa_signature_functions[];
+extern const OSSL_DISPATCH rsa_signature_functions[];
/* Asym Cipher */
extern const OSSL_DISPATCH rsa_asym_cipher_functions[];
diff --git a/providers/implementations/signature/build.info b/providers/implementations/signature/build.info
index a9687fc..22b55dc 100644
--- a/providers/implementations/signature/build.info
+++ b/providers/implementations/signature/build.info
@@ -2,9 +2,12 @@
# switch each to the Legacy provider when needed.
$DSA_GOAL=../../libimplementations.a
+$RSA_GOAL=../../libimplementations.a
IF[{- !$disabled{dsa} -}]
SOURCE[$DSA_GOAL]=dsa.c
ENDIF
+SOURCE[$RSA_GOAL]=rsa.c
+
diff --git a/providers/implementations/signature/rsa.c b/providers/implementations/signature/rsa.c
new file mode 100644
index 0000000..3f941b1
--- /dev/null
+++ b/providers/implementations/signature/rsa.c
@@ -0,0 +1,1113 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * RSA low level APIs are deprecated for public use, but still ok for
+ * internal use.
+ */
+#include "internal/deprecated.h"
+
+#include <string.h>
+#include <openssl/crypto.h>
+#include <openssl/core_numbers.h>
+#include <openssl/core_names.h>
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include <openssl/params.h>
+#include <openssl/evp.h>
+#include "internal/cryptlib.h"
+#include "internal/nelem.h"
+#include "internal/sizes.h"
+#include "crypto/rsa.h"
+#include "prov/providercommonerr.h"
+#include "prov/implementations.h"
+#include "prov/provider_ctx.h"
+
+static OSSL_OP_signature_newctx_fn rsa_newctx;
+static OSSL_OP_signature_sign_init_fn rsa_signature_init;
+static OSSL_OP_signature_verify_init_fn rsa_signature_init;
+static OSSL_OP_signature_verify_recover_init_fn rsa_signature_init;
+static OSSL_OP_signature_sign_fn rsa_sign;
+static OSSL_OP_signature_verify_fn rsa_verify;
+static OSSL_OP_signature_verify_recover_fn rsa_verify_recover;
+static OSSL_OP_signature_digest_sign_init_fn rsa_digest_signverify_init;
+static OSSL_OP_signature_digest_sign_update_fn rsa_digest_signverify_update;
+static OSSL_OP_signature_digest_sign_final_fn rsa_digest_sign_final;
+static OSSL_OP_signature_digest_verify_init_fn rsa_digest_signverify_init;
+static OSSL_OP_signature_digest_verify_update_fn rsa_digest_signverify_update;
+static OSSL_OP_signature_digest_verify_final_fn rsa_digest_verify_final;
+static OSSL_OP_signature_freectx_fn rsa_freectx;
+static OSSL_OP_signature_dupctx_fn rsa_dupctx;
+static OSSL_OP_signature_get_ctx_params_fn rsa_get_ctx_params;
+static OSSL_OP_signature_gettable_ctx_params_fn rsa_gettable_ctx_params;
+static OSSL_OP_signature_set_ctx_params_fn rsa_set_ctx_params;
+static OSSL_OP_signature_settable_ctx_params_fn rsa_settable_ctx_params;
+static OSSL_OP_signature_get_ctx_md_params_fn rsa_get_ctx_md_params;
+static OSSL_OP_signature_gettable_ctx_md_params_fn rsa_gettable_ctx_md_params;
+static OSSL_OP_signature_set_ctx_md_params_fn rsa_set_ctx_md_params;
+static OSSL_OP_signature_settable_ctx_md_params_fn rsa_settable_ctx_md_params;
+
+static OSSL_ITEM padding_item[] = {
+ { RSA_PKCS1_PADDING, "pkcs1" },
+ { RSA_SSLV23_PADDING, "sslv23" },
+ { RSA_NO_PADDING, "none" },
+ { RSA_PKCS1_OAEP_PADDING, "oaep" }, /* Correct spelling first */
+ { RSA_PKCS1_OAEP_PADDING, "oeap" },
+ { RSA_X931_PADDING, "x931" },
+ { RSA_PKCS1_PSS_PADDING, "pss" },
+ { 0, NULL }
+};
+
+/*
+ * What's passed as an actual key is defined by the KEYMGMT interface.
+ * We happen to know that our KEYMGMT simply passes RSA structures, so
+ * we use that here too.
+ */
+
+typedef struct {
+ OPENSSL_CTX *libctx;
+ RSA *rsa;
+
+ /*
+ * Flag to determine if the hash function can be changed (1) or not (0)
+ * Because it's dangerous to change during a DigestSign or DigestVerify
+ * operation, this flag is cleared by their Init function, and set again
+ * by their Final function.
+ */
+ unsigned int flag_allow_md : 1;
+
+ /* The Algorithm Identifier of the combined signature agorithm */
+ unsigned char aid[128];
+ size_t aid_len;
+
+ /* main digest */
+ EVP_MD *md;
+ EVP_MD_CTX *mdctx;
+ int mdnid;
+ char mdname[OSSL_MAX_NAME_SIZE]; /* Purely informational */
+
+ /* RSA padding mode */
+ int pad_mode;
+ /* message digest for MGF1 */
+ EVP_MD *mgf1_md;
+ char mgf1_mdname[OSSL_MAX_NAME_SIZE]; /* Purely informational */
+ /* PSS salt length */
+ int saltlen;
+ /* Minimum salt length or -1 if no PSS parameter restriction */
+ int min_saltlen;
+
+ /* Temp buffer */
+ unsigned char *tbuf;
+
+} PROV_RSA_CTX;
+
+static size_t rsa_get_md_size(const PROV_RSA_CTX *prsactx)
+{
+ if (prsactx->md != NULL)
+ return EVP_MD_size(prsactx->md);
+ return 0;
+}
+
+static int rsa_get_md_nid(const EVP_MD *md)
+{
+ /*
+ * Because the RSA library deals with NIDs, we need to translate.
+ * We do so using EVP_MD_is_a(), and therefore need a name to NID
+ * map.
+ */
+ static const OSSL_ITEM name_to_nid[] = {
+ { NID_sha1, OSSL_DIGEST_NAME_SHA1 },
+ { NID_sha224, OSSL_DIGEST_NAME_SHA2_224 },
+ { NID_sha256, OSSL_DIGEST_NAME_SHA2_256 },
+ { NID_sha384, OSSL_DIGEST_NAME_SHA2_384 },
+ { NID_sha512, OSSL_DIGEST_NAME_SHA2_512 },
+ { NID_md5, OSSL_DIGEST_NAME_MD5 },
+ { NID_md5_sha1, OSSL_DIGEST_NAME_MD5_SHA1 },
+ { NID_md2, OSSL_DIGEST_NAME_MD2 },
+ { NID_md4, OSSL_DIGEST_NAME_MD4 },
+ { NID_mdc2, OSSL_DIGEST_NAME_MDC2 },
+ { NID_ripemd160, OSSL_DIGEST_NAME_RIPEMD160 },
+ { NID_sha3_224, OSSL_DIGEST_NAME_SHA3_224 },
+ { NID_sha3_256, OSSL_DIGEST_NAME_SHA3_256 },
+ { NID_sha3_384, OSSL_DIGEST_NAME_SHA3_384 },
+ { NID_sha3_512, OSSL_DIGEST_NAME_SHA3_512 },
+ };
+ size_t i;
+ int mdnid = NID_undef;
+
+ if (md == NULL)
+ goto end;
+
+ for (i = 0; i < OSSL_NELEM(name_to_nid); i++) {
+ if (EVP_MD_is_a(md, name_to_nid[i].ptr)) {
+ mdnid = (int)name_to_nid[i].id;
+ break;
+ }
+ }
+
+ if (mdnid == NID_undef)
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST);
+
+ end:
+ return mdnid;
+}
+
+static int rsa_check_padding(int mdnid, int padding)
+{
+ if (padding == RSA_NO_PADDING) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE);
+ return 0;
+ }
+
+ if (padding == RSA_X931_PADDING) {
+ if (RSA_X931_hash_id(mdnid) == -1) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_X931_DIGEST);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void *rsa_newctx(void *provctx)
+{
+ PROV_RSA_CTX *prsactx = OPENSSL_zalloc(sizeof(PROV_RSA_CTX));
+
+ if (prsactx == NULL)
+ return NULL;
+
+ prsactx->libctx = PROV_LIBRARY_CONTEXT_OF(provctx);
+ prsactx->flag_allow_md = 1;
+ return prsactx;
+}
+
+/* True if PSS parameters are restricted */
+#define rsa_pss_restricted(prsactx) (prsactx->min_saltlen != -1)
+
+static int rsa_signature_init(void *vprsactx, void *vrsa)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx == NULL || vrsa == NULL || !RSA_up_ref(vrsa))
+ return 0;
+
+ RSA_free(prsactx->rsa);
+ prsactx->rsa = vrsa;
+ if (RSA_get0_pss_params(prsactx->rsa) != NULL)
+ prsactx->pad_mode = RSA_PKCS1_PSS_PADDING;
+ else
+ prsactx->pad_mode = RSA_PKCS1_PADDING;
+ /* Maximum for sign, auto for verify */
+ prsactx->saltlen = RSA_PSS_SALTLEN_AUTO;
+ prsactx->min_saltlen = -1;
+
+ return 1;
+}
+
+static int rsa_setup_md(PROV_RSA_CTX *ctx, const char *mdname,
+ const char *mdprops)
+{
+ if (mdname != NULL) {
+ EVP_MD *md = EVP_MD_fetch(ctx->libctx, mdname, mdprops);
+ int md_nid = rsa_get_md_nid(md);
+ size_t algorithmidentifier_len = 0;
+ const unsigned char *algorithmidentifier = NULL;
+
+ if (md == NULL)
+ return 0;
+
+ if (!rsa_check_padding(md_nid, ctx->pad_mode)) {
+ EVP_MD_free(md);
+ return 0;
+ }
+
+ EVP_MD_CTX_free(ctx->mdctx);
+ EVP_MD_free(ctx->md);
+ ctx->md = NULL;
+ ctx->mdctx = NULL;
+ ctx->mdname[0] = '\0';
+ ctx->aid[0] = '\0';
+ ctx->aid_len = 0;
+
+ algorithmidentifier =
+ rsa_algorithmidentifier_encoding(md_nid, &algorithmidentifier_len);
+
+ ctx->md = md;
+ ctx->mdnid = md_nid;
+ OPENSSL_strlcpy(ctx->mdname, mdname, sizeof(ctx->mdname));
+ if (algorithmidentifier != NULL) {
+ memcpy(ctx->aid, algorithmidentifier, algorithmidentifier_len);
+ ctx->aid_len = algorithmidentifier_len;
+ }
+ }
+
+ return 1;
+}
+
+static int rsa_setup_mgf1_md(PROV_RSA_CTX *ctx, const char *mdname,
+ const char *props)
+{
+ if (ctx->mgf1_mdname[0] != '\0')
+ EVP_MD_free(ctx->mgf1_md);
+
+ if ((ctx->mgf1_md = EVP_MD_fetch(ctx->libctx, mdname, props)) == NULL)
+ return 0;
+ OPENSSL_strlcpy(ctx->mgf1_mdname, mdname, sizeof(ctx->mgf1_mdname));
+
+ return 1;
+}
+
+static int setup_tbuf(PROV_RSA_CTX *ctx)
+{
+ if (ctx->tbuf != NULL)
+ return 1;
+ if ((ctx->tbuf = OPENSSL_malloc(RSA_size(ctx->rsa))) == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ return 1;
+}
+
+static void clean_tbuf(PROV_RSA_CTX *ctx)
+{
+ if (ctx->tbuf != NULL)
+ OPENSSL_cleanse(ctx->tbuf, RSA_size(ctx->rsa));
+}
+
+static void free_tbuf(PROV_RSA_CTX *ctx)
+{
+ OPENSSL_clear_free(ctx->tbuf, RSA_size(ctx->rsa));
+ ctx->tbuf = NULL;
+}
+
+static int rsa_sign(void *vprsactx, unsigned char *sig, size_t *siglen,
+ size_t sigsize, const unsigned char *tbs, size_t tbslen)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ int ret;
+ size_t rsasize = RSA_size(prsactx->rsa);
+ size_t mdsize = rsa_get_md_size(prsactx);
+
+ if (sig == NULL) {
+ *siglen = rsasize;
+ return 1;
+ }
+
+ if (sigsize < (size_t)rsasize)
+ return 0;
+
+ if (mdsize != 0) {
+ if (tbslen != mdsize) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH);
+ return 0;
+ }
+
+ if (EVP_MD_is_a(prsactx->md, OSSL_DIGEST_NAME_MDC2)) {
+ unsigned int sltmp;
+
+ if (prsactx->pad_mode != RSA_PKCS1_PADDING) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE,
+ "only PKCS#1 padding supported with MDC2");
+ return 0;
+ }
+ ret = RSA_sign_ASN1_OCTET_STRING(0, tbs, tbslen, sig, &sltmp,
+ prsactx->rsa);
+
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
+ return 0;
+ }
+ ret = sltmp;
+ goto end;
+ }
+
+ switch (prsactx->pad_mode) {
+ case RSA_X931_PADDING:
+ if ((size_t)RSA_size(prsactx->rsa) < tbslen + 1) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SIZE_TOO_SMALL);
+ return 0;
+ }
+ if (!setup_tbuf(prsactx)) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ memcpy(prsactx->tbuf, tbs, tbslen);
+ prsactx->tbuf[tbslen] = RSA_X931_hash_id(prsactx->mdnid);
+ ret = RSA_private_encrypt(tbslen + 1, prsactx->tbuf,
+ sig, prsactx->rsa, RSA_X931_PADDING);
+ clean_tbuf(prsactx);
+ break;
+
+ case RSA_PKCS1_PADDING:
+ {
+ unsigned int sltmp;
+
+ ret = RSA_sign(prsactx->mdnid, tbs, tbslen, sig, &sltmp,
+ prsactx->rsa);
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
+ return 0;
+ }
+ ret = sltmp;
+ }
+ break;
+
+ case RSA_PKCS1_PSS_PADDING:
+ /* Check PSS restrictions */
+ if (rsa_pss_restricted(prsactx)) {
+ switch (prsactx->saltlen) {
+ case RSA_PSS_SALTLEN_DIGEST:
+ if (prsactx->min_saltlen > EVP_MD_size(prsactx->md)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_PSS_SALTLEN_TOO_SMALL);
+ return 0;
+ }
+ /* FALLTHRU */
+ default:
+ if (prsactx->saltlen >= 0
+ && prsactx->saltlen < prsactx->min_saltlen) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_PSS_SALTLEN_TOO_SMALL);
+ return 0;
+ }
+ break;
+ }
+ }
+ if (!setup_tbuf(prsactx))
+ return 0;
+ if (!RSA_padding_add_PKCS1_PSS_mgf1(prsactx->rsa,
+ prsactx->tbuf, tbs,
+ prsactx->md, prsactx->mgf1_md,
+ prsactx->saltlen)) {
+ ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
+ return 0;
+ }
+ ret = RSA_private_encrypt(RSA_size(prsactx->rsa), prsactx->tbuf,
+ sig, prsactx->rsa, RSA_NO_PADDING);
+ clean_tbuf(prsactx);
+ break;
+
+ default:
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE,
+ "Only X.931, PKCS#1 v1.5 or PSS padding allowed");
+ return 0;
+ }
+ } else {
+ ret = RSA_private_encrypt(tbslen, tbs, sig, prsactx->rsa,
+ prsactx->pad_mode);
+ }
+
+#ifdef LEGACY_MODE
+ end:
+#endif
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
+ return 0;
+ }
+
+ *siglen = ret;
+ return 1;
+}
+
+static int rsa_verify_recover(void *vprsactx,
+ unsigned char *rout,
+ size_t *routlen,
+ size_t routsize,
+ const unsigned char *sig,
+ size_t siglen)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ int ret;
+
+ if (rout == NULL) {
+ *routlen = RSA_size(prsactx->rsa);
+ return 1;
+ }
+
+ if (prsactx->md != NULL) {
+ switch (prsactx->pad_mode) {
+ case RSA_X931_PADDING:
+ if (!setup_tbuf(prsactx))
+ return 0;
+ ret = RSA_public_decrypt(siglen, sig, prsactx->tbuf, prsactx->rsa,
+ RSA_X931_PADDING);
+ if (ret < 1) {
+ ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
+ return 0;
+ }
+ ret--;
+ if (prsactx->tbuf[ret] != RSA_X931_hash_id(prsactx->mdnid)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_ALGORITHM_MISMATCH);
+ return 0;
+ }
+ if (ret != EVP_MD_size(prsactx->md)) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH,
+ "Should be %d, but got %d",
+ EVP_MD_size(prsactx->md), ret);
+ return 0;
+ }
+
+ *routlen = ret;
+ if (routsize < (size_t)ret) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ memcpy(rout, prsactx->tbuf, ret);
+ break;
+
+ case RSA_PKCS1_PADDING:
+ {
+ size_t sltmp;
+
+ ret = int_rsa_verify(prsactx->mdnid, NULL, 0, rout, &sltmp,
+ sig, siglen, prsactx->rsa);
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
+ return 0;
+ }
+ ret = sltmp;
+ }
+ break;
+
+ default:
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE,
+ "Only X.931 or PKCS#1 v1.5 padding allowed");
+ return 0;
+ }
+ } else {
+ ret = RSA_public_decrypt(siglen, sig, rout, prsactx->rsa,
+ prsactx->pad_mode);
+ if (ret < 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
+ return 0;
+ }
+ }
+ *routlen = ret;
+ return 1;
+}
+
+static int rsa_verify(void *vprsactx, const unsigned char *sig, size_t siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ size_t rslen;
+
+ if (prsactx->md != NULL) {
+ switch (prsactx->pad_mode) {
+ case RSA_PKCS1_PADDING:
+ if (!RSA_verify(prsactx->mdnid, tbs, tbslen, sig, siglen,
+ prsactx->rsa)) {
+ ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
+ return 0;
+ }
+ return 1;
+ case RSA_X931_PADDING:
+ if (rsa_verify_recover(prsactx, NULL, &rslen, 0, sig, siglen) <= 0)
+ return 0;
+ break;
+ case RSA_PKCS1_PSS_PADDING:
+ {
+ int ret;
+ size_t mdsize;
+
+ /* Check PSS restrictions */
+ if (rsa_pss_restricted(prsactx)) {
+ switch (prsactx->saltlen) {
+ case RSA_PSS_SALTLEN_AUTO:
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_PSS_SALTLEN);
+ return 0;
+ case RSA_PSS_SALTLEN_DIGEST:
+ if (prsactx->min_saltlen > EVP_MD_size(prsactx->md)) {
+ ERR_raise(ERR_LIB_PROV,
+ PROV_R_PSS_SALTLEN_TOO_SMALL);
+ return 0;
+ }
+ /* FALLTHRU */
+ default:
+ if (prsactx->saltlen >= 0
+ && prsactx->saltlen < prsactx->min_saltlen) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_PSS_SALTLEN_TOO_SMALL);
+ return 0;
+ }
+ break;
+ }
+ }
+
+ /*
+ * We need to check this for the RSA_verify_PKCS1_PSS_mgf1()
+ * call
+ */
+ mdsize = rsa_get_md_size(prsactx);
+ if (tbslen != mdsize) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH,
+ "Should be %d, but got %d",
+ mdsize, tbslen);
+ return 0;
+ }
+
+ if (!setup_tbuf(prsactx))
+ return 0;
+ ret = RSA_public_decrypt(siglen, sig, prsactx->tbuf,
+ prsactx->rsa, RSA_NO_PADDING);
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
+ return 0;
+ }
+ ret = RSA_verify_PKCS1_PSS_mgf1(prsactx->rsa, tbs,
+ prsactx->md, prsactx->mgf1_md,
+ prsactx->tbuf,
+ prsactx->saltlen);
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
+ return 0;
+ }
+ return 1;
+ }
+ default:
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE,
+ "Only X.931, PKCS#1 v1.5 or PSS padding allowed");
+ return 0;
+ }
+ } else {
+ if (!setup_tbuf(prsactx))
+ return 0;
+ rslen = RSA_public_decrypt(siglen, sig, prsactx->tbuf, prsactx->rsa,
+ prsactx->pad_mode);
+ if (rslen == 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
+ return 0;
+ }
+ }
+
+ if ((rslen != tbslen) || memcmp(tbs, prsactx->tbuf, rslen))
+ return 0;
+
+ return 1;
+}
+
+static int rsa_digest_signverify_init(void *vprsactx, const char *mdname,
+ const char *props, void *vrsa)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ prsactx->flag_allow_md = 0;
+ if (!rsa_signature_init(vprsactx, vrsa)
+ || !rsa_setup_md(prsactx, mdname, props))
+ return 0;
+
+ prsactx->mdctx = EVP_MD_CTX_new();
+ if (prsactx->mdctx == NULL)
+ goto error;
+
+ if (!EVP_DigestInit_ex(prsactx->mdctx, prsactx->md, NULL))
+ goto error;
+
+ return 1;
+
+ error:
+ EVP_MD_CTX_free(prsactx->mdctx);
+ EVP_MD_free(prsactx->md);
+ prsactx->mdctx = NULL;
+ prsactx->md = NULL;
+ return 0;
+}
+
+int rsa_digest_signverify_update(void *vprsactx, const unsigned char *data,
+ size_t datalen)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx == NULL || prsactx->mdctx == NULL)
+ return 0;
+
+ return EVP_DigestUpdate(prsactx->mdctx, data, datalen);
+}
+
+int rsa_digest_sign_final(void *vprsactx, unsigned char *sig, size_t *siglen,
+ size_t sigsize)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+
+ prsactx->flag_allow_md = 1;
+ if (prsactx == NULL || prsactx->mdctx == NULL)
+ return 0;
+
+ /*
+ * If sig is NULL then we're just finding out the sig size. Other fields
+ * are ignored. Defer to rsa_sign.
+ */
+ if (sig != NULL) {
+ /*
+ * TODO(3.0): There is the possibility that some externally provided
+ * digests exceed EVP_MAX_MD_SIZE. We should probably handle that somehow -
+ * but that problem is much larger than just in RSA.
+ */
+ if (!EVP_DigestFinal_ex(prsactx->mdctx, digest, &dlen))
+ return 0;
+ }
+
+ return rsa_sign(vprsactx, sig, siglen, sigsize, digest, (size_t)dlen);
+}
+
+
+int rsa_digest_verify_final(void *vprsactx, const unsigned char *sig,
+ size_t siglen)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+
+ prsactx->flag_allow_md = 1;
+ if (prsactx == NULL || prsactx->mdctx == NULL)
+ return 0;
+
+ /*
+ * TODO(3.0): There is the possibility that some externally provided
+ * digests exceed EVP_MAX_MD_SIZE. We should probably handle that somehow -
+ * but that problem is much larger than just in RSA.
+ */
+ if (!EVP_DigestFinal_ex(prsactx->mdctx, digest, &dlen))
+ return 0;
+
+ return rsa_verify(vprsactx, sig, siglen, digest, (size_t)dlen);
+}
+
+static void rsa_freectx(void *vprsactx)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx == NULL)
+ return;
+
+ RSA_free(prsactx->rsa);
+ EVP_MD_CTX_free(prsactx->mdctx);
+ EVP_MD_free(prsactx->md);
+ EVP_MD_free(prsactx->mgf1_md);
+ free_tbuf(prsactx);
+
+ OPENSSL_clear_free(prsactx, sizeof(prsactx));
+}
+
+static void *rsa_dupctx(void *vprsactx)
+{
+ PROV_RSA_CTX *srcctx = (PROV_RSA_CTX *)vprsactx;
+ PROV_RSA_CTX *dstctx;
+
+ dstctx = OPENSSL_zalloc(sizeof(*srcctx));
+ if (dstctx == NULL)
+ return NULL;
+
+ *dstctx = *srcctx;
+ dstctx->rsa = NULL;
+ dstctx->md = NULL;
+ dstctx->mdctx = NULL;
+ dstctx->tbuf = NULL;
+
+ if (srcctx->rsa != NULL && !RSA_up_ref(srcctx->rsa))
+ goto err;
+ dstctx->rsa = srcctx->rsa;
+
+ if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md))
+ goto err;
+ dstctx->md = srcctx->md;
+
+ if (srcctx->mgf1_md != NULL && !EVP_MD_up_ref(srcctx->mgf1_md))
+ goto err;
+ dstctx->mgf1_md = srcctx->mgf1_md;
+
+ if (srcctx->mdctx != NULL) {
+ dstctx->mdctx = EVP_MD_CTX_new();
+ if (dstctx->mdctx == NULL
+ || !EVP_MD_CTX_copy_ex(dstctx->mdctx, srcctx->mdctx))
+ goto err;
+ }
+
+ return dstctx;
+ err:
+ rsa_freectx(dstctx);
+ return NULL;
+}
+
+static int rsa_get_ctx_params(void *vprsactx, OSSL_PARAM *params)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ OSSL_PARAM *p;
+
+ if (prsactx == NULL || params == NULL)
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID);
+ if (p != NULL
+ && !OSSL_PARAM_set_octet_string(p, prsactx->aid, prsactx->aid_len))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_PAD_MODE);
+ if (p != NULL)
+ switch (p->data_type) {
+ case OSSL_PARAM_INTEGER:
+ if (!OSSL_PARAM_set_int(p, prsactx->pad_mode))
+ return 0;
+ break;
+ case OSSL_PARAM_UTF8_STRING:
+ {
+ int i;
+ const char *word = NULL;
+
+ for (i = 0; padding_item[i].id != 0; i++) {
+ if (prsactx->pad_mode == (int)padding_item[i].id) {
+ word = padding_item[i].ptr;
+ break;
+ }
+ }
+
+ if (word != NULL) {
+ if (!OSSL_PARAM_set_utf8_string(p, word))
+ return 0;
+ } else {
+ ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+ }
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST);
+ if (p != NULL && !OSSL_PARAM_set_utf8_string(p, prsactx->mdname))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_MGF1_DIGEST);
+ if (p != NULL && !OSSL_PARAM_set_utf8_string(p, prsactx->mgf1_mdname))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_PSS_SALTLEN);
+ if (p != NULL) {
+ if (p->data_type == OSSL_PARAM_INTEGER) {
+ if (!OSSL_PARAM_set_int(p, prsactx->saltlen))
+ return 0;
+ } else if (p->data_type == OSSL_PARAM_UTF8_STRING) {
+ switch (prsactx->saltlen) {
+ case RSA_PSS_SALTLEN_DIGEST:
+ if (!OSSL_PARAM_set_utf8_string(p, "digest"))
+ return 0;
+ break;
+ case RSA_PSS_SALTLEN_MAX:
+ if (!OSSL_PARAM_set_utf8_string(p, "max"))
+ return 0;
+ break;
+ case RSA_PSS_SALTLEN_AUTO:
+ if (!OSSL_PARAM_set_utf8_string(p, "auto"))
+ return 0;
+ break;
+ default:
+ if (BIO_snprintf(p->data, p->data_size, "%d", prsactx->saltlen)
+ <= 0)
+ return 0;
+ break;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *rsa_gettable_ctx_params(void)
+{
+ return known_gettable_ctx_params;
+}
+
+static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[])
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ const OSSL_PARAM *p;
+
+ if (prsactx == NULL || params == NULL)
+ return 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST);
+ /* Not allowed during certain operations */
+ if (p != NULL && !prsactx->flag_allow_md)
+ return 0;
+ if (p != NULL) {
+ char mdname[OSSL_MAX_NAME_SIZE] = "", *pmdname = mdname;
+ char mdprops[OSSL_MAX_PROPQUERY_SIZE] = "", *pmdprops = mdprops;
+ const OSSL_PARAM *propsp =
+ OSSL_PARAM_locate_const(params,
+ OSSL_SIGNATURE_PARAM_PROPERTIES);
+
+ if (!OSSL_PARAM_get_utf8_string(p, &pmdname, sizeof(mdname)))
+ return 0;
+ if (propsp != NULL
+ && !OSSL_PARAM_get_utf8_string(propsp, &pmdprops, sizeof(mdprops)))
+ return 0;
+
+ /* TODO(3.0) PSS check needs more work */
+ if (rsa_pss_restricted(prsactx)) {
+ /* TODO(3.0) figure out what to do for prsactx->md == NULL */
+ if (prsactx->md == NULL || EVP_MD_is_a(prsactx->md, mdname))
+ return 1;
+ ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED);
+ return 0;
+ }
+
+ /* non-PSS code follows */
+ if (!rsa_setup_md(prsactx, mdname, mdprops))
+ return 0;
+ }
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PAD_MODE);
+ if (p != NULL) {
+ int pad_mode = 0;
+
+ switch (p->data_type) {
+ case OSSL_PARAM_INTEGER: /* Support for legacy pad mode number */
+ if (!OSSL_PARAM_get_int(p, &pad_mode))
+ return 0;
+ break;
+ case OSSL_PARAM_UTF8_STRING:
+ {
+ int i;
+
+ if (p->data == NULL)
+ return 0;
+
+ for (i = 0; padding_item[i].id != 0; i++) {
+ if (strcmp(p->data, padding_item[i].ptr) == 0) {
+ pad_mode = padding_item[i].id;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ switch (pad_mode) {
+ case RSA_PKCS1_OAEP_PADDING:
+ /*
+ * OAEP padding is for asymmetric cipher only so is not compatible
+ * with signature use.
+ */
+ ERR_raise_data(ERR_LIB_PROV,
+ PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE,
+ "OAEP padding not allowed for signing / verifying");
+ return 0;
+ case RSA_PKCS1_PSS_PADDING:
+ if (prsactx->mdname[0] == '\0')
+ rsa_setup_md(prsactx, "SHA1", "");
+ goto cont;
+ case RSA_PKCS1_PADDING:
+ case RSA_SSLV23_PADDING:
+ case RSA_NO_PADDING:
+ case RSA_X931_PADDING:
+ if (RSA_get0_pss_params(prsactx->rsa) != NULL) {
+ ERR_raise_data(ERR_LIB_PROV,
+ PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE,
+ "X.931 padding not allowed with RSA-PSS");
+ return 0;
+ }
+ cont:
+ if (!rsa_check_padding(prsactx->mdnid, pad_mode))
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ prsactx->pad_mode = pad_mode;
+ }
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PSS_SALTLEN);
+ if (p != NULL) {
+ int saltlen;
+
+ if (prsactx->pad_mode != RSA_PKCS1_PSS_PADDING) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED,
+ "PSS saltlen can only be specified if "
+ "PSS padding has been specified first");
+ return 0;
+ }
+
+ switch (p->data_type) {
+ case OSSL_PARAM_INTEGER: /* Support for legacy pad mode number */
+ if (!OSSL_PARAM_get_int(p, &saltlen))
+ return 0;
+ break;
+ case OSSL_PARAM_UTF8_STRING:
+ if (strcmp(p->data, "digest") == 0)
+ saltlen = RSA_PSS_SALTLEN_DIGEST;
+ else if (strcmp(p->data, "max") == 0)
+ saltlen = RSA_PSS_SALTLEN_MAX;
+ else if (strcmp(p->data, "auto") == 0)
+ saltlen = RSA_PSS_SALTLEN_AUTO;
+ else
+ saltlen = atoi(p->data);
+ break;
+ default:
+ return 0;
+ }
+
+ /*
+ * RSA_PSS_SALTLEN_MAX seems curiously named in this check.
+ * Contrary to what it's name suggests, it's the currently
+ * lowest saltlen number possible.
+ */
+ if (saltlen < RSA_PSS_SALTLEN_MAX) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_PSS_SALTLEN);
+ return 0;
+ }
+
+ prsactx->saltlen = saltlen;
+ }
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_MGF1_DIGEST);
+ if (p != NULL) {
+ char mdname[OSSL_MAX_NAME_SIZE] = "", *pmdname = mdname;
+ char mdprops[OSSL_MAX_PROPQUERY_SIZE] = "", *pmdprops = mdprops;
+ const OSSL_PARAM *propsp =
+ OSSL_PARAM_locate_const(params,
+ OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES);
+
+ if (!OSSL_PARAM_get_utf8_string(p, &pmdname, sizeof(mdname)))
+ return 0;
+ if (propsp != NULL
+ && !OSSL_PARAM_get_utf8_string(propsp, &pmdprops, sizeof(mdprops)))
+ return 0;
+
+ if (prsactx->pad_mode != RSA_PKCS1_PSS_PADDING) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MGF1_MD);
+ return 0;
+ }
+
+ /* TODO(3.0) PSS check needs more work */
+ if (rsa_pss_restricted(prsactx)) {
+ /* TODO(3.0) figure out what to do for prsactx->md == NULL */
+ if (prsactx->mgf1_md == NULL
+ || EVP_MD_is_a(prsactx->mgf1_md, mdname))
+ return 1;
+ ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED);
+ return 0;
+ }
+
+ /* non-PSS code follows */
+ if (!rsa_setup_mgf1_md(prsactx, mdname, mdprops))
+ return 0;
+ }
+
+ return 1;
+}
+
+static const OSSL_PARAM known_settable_ctx_params[] = {
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PROPERTIES, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *rsa_settable_ctx_params(void)
+{
+ /*
+ * TODO(3.0): Should this function return a different set of settable ctx
+ * params if the ctx is being used for a DigestSign/DigestVerify? In that
+ * case it is not allowed to set the digest size/digest name because the
+ * digest is explicitly set as part of the init.
+ */
+ return known_settable_ctx_params;
+}
+
+static int rsa_get_ctx_md_params(void *vprsactx, OSSL_PARAM *params)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx->mdctx == NULL)
+ return 0;
+
+ return EVP_MD_CTX_get_params(prsactx->mdctx, params);
+}
+
+static const OSSL_PARAM *rsa_gettable_ctx_md_params(void *vprsactx)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx->md == NULL)
+ return 0;
+
+ return EVP_MD_gettable_ctx_params(prsactx->md);
+}
+
+static int rsa_set_ctx_md_params(void *vprsactx, const OSSL_PARAM params[])
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx->mdctx == NULL)
+ return 0;
+
+ return EVP_MD_CTX_set_params(prsactx->mdctx, params);
+}
+
+static const OSSL_PARAM *rsa_settable_ctx_md_params(void *vprsactx)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx->md == NULL)
+ return 0;
+
+ return EVP_MD_settable_ctx_params(prsactx->md);
+}
+
+const OSSL_DISPATCH rsa_signature_functions[] = {
+ { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))rsa_newctx },
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))rsa_signature_init },
+ { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))rsa_sign },
+ { OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))rsa_signature_init },
+ { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))rsa_verify },
+ { OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT, (void (*)(void))rsa_signature_init },
+ { OSSL_FUNC_SIGNATURE_VERIFY_RECOVER, (void (*)(void))rsa_verify_recover },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT,
+ (void (*)(void))rsa_digest_signverify_init },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE,
+ (void (*)(void))rsa_digest_signverify_update },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL,
+ (void (*)(void))rsa_digest_sign_final },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT,
+ (void (*)(void))rsa_digest_signverify_init },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE,
+ (void (*)(void))rsa_digest_signverify_update },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL,
+ (void (*)(void))rsa_digest_verify_final },
+ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))rsa_freectx },
+ { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))rsa_dupctx },
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))rsa_get_ctx_params },
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS,
+ (void (*)(void))rsa_gettable_ctx_params },
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))rsa_set_ctx_params },
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS,
+ (void (*)(void))rsa_settable_ctx_params },
+ { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS,
+ (void (*)(void))rsa_get_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS,
+ (void (*)(void))rsa_gettable_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS,
+ (void (*)(void))rsa_set_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS,
+ (void (*)(void))rsa_settable_ctx_md_params },
+ { 0, NULL }
+};