From: Matt Caswell Date: Mon, 28 Oct 2019 13:40:39 +0000 (+0000) Subject: Move RSA Asym cipher code to the default provider X-Git-Tag: openssl-3.0.0-alpha1~957 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=89abd1b6f42ab93402a36db0f16f12dc7a392354;p=oweals%2Fopenssl.git Move RSA Asym cipher code to the default provider Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/10152) --- diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 6bbe025bfc..ce1b051b74 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "internal/cryptlib.h" #include "crypto/asn1.h" #include "crypto/evp.h" @@ -701,6 +702,33 @@ static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype, return EVP_PKEY_CTX_set_signature_md(ctx, p2); case EVP_PKEY_CTRL_GET_MD: return EVP_PKEY_CTX_get_signature_md(ctx, p2); + case EVP_PKEY_CTRL_RSA_PADDING: + return EVP_PKEY_CTX_set_rsa_padding(ctx, p1); + case EVP_PKEY_CTRL_GET_RSA_PADDING: + return EVP_PKEY_CTX_get_rsa_padding(ctx, p2); + case EVP_PKEY_CTRL_RSA_OAEP_MD: + return EVP_PKEY_CTX_set_rsa_oaep_md(ctx, p2); + case EVP_PKEY_CTRL_GET_RSA_OAEP_MD: + return EVP_PKEY_CTX_get_rsa_oaep_md(ctx, p2); + case EVP_PKEY_CTRL_RSA_MGF1_MD: + return EVP_PKEY_CTX_set_rsa_oaep_md(ctx, p2); + case EVP_PKEY_CTRL_GET_RSA_MGF1_MD: + return EVP_PKEY_CTX_get_rsa_oaep_md(ctx, p2); + case EVP_PKEY_CTRL_RSA_OAEP_LABEL: + return EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, p2, p1); + case EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL: + return EVP_PKEY_CTX_get0_rsa_oaep_label(ctx, (unsigned char **)p2); + case EVP_PKEY_CTRL_PKCS7_ENCRYPT: + case EVP_PKEY_CTRL_PKCS7_DECRYPT: +#ifndef OPENSSL_NO_CMS + case EVP_PKEY_CTRL_CMS_DECRYPT: + case EVP_PKEY_CTRL_CMS_ENCRYPT: +#endif + if (ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS) + return 1; + ERR_raise(ERR_LIB_EVP, + EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return -2; } return 0; } @@ -784,6 +812,52 @@ static int legacy_ctrl_str_to_param(EVP_PKEY_CTX *ctx, const char *name, return ret; } + if (strcmp(name, "rsa_padding_mode") == 0) { + int pm; + + if (strcmp(value, "pkcs1") == 0) { + pm = RSA_PKCS1_PADDING; + } else if (strcmp(value, "sslv23") == 0) { + pm = RSA_SSLV23_PADDING; + } else if (strcmp(value, "none") == 0) { + pm = RSA_NO_PADDING; + } else if (strcmp(value, "oeap") == 0) { + pm = RSA_PKCS1_OAEP_PADDING; + } else if (strcmp(value, "oaep") == 0) { + pm = RSA_PKCS1_OAEP_PADDING; + } else if (strcmp(value, "x931") == 0) { + pm = RSA_X931_PADDING; + } else if (strcmp(value, "pss") == 0) { + pm = RSA_PKCS1_PSS_PADDING; + } else { + ERR_raise(ERR_LIB_RSA, RSA_R_UNKNOWN_PADDING_TYPE); + return -2; + } + return EVP_PKEY_CTX_set_rsa_padding(ctx, pm); + } + + if (strcmp(name, "rsa_mgf1_md") == 0) + return EVP_PKEY_CTX_set_rsa_mgf1_md_name(ctx, value, NULL); + + if (strcmp(name, "rsa_oaep_md") == 0) + return EVP_PKEY_CTX_set_rsa_oaep_md_name(ctx, value, NULL); + + if (strcmp(name, "rsa_oaep_label") == 0) { + unsigned char *lab; + long lablen; + int ret; + + lab = OPENSSL_hexstr2buf(value, &lablen); + if (lab == NULL) + return 0; + ret = EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, lab, lablen); + if (ret <= 0) + OPENSSL_free(lab); + return ret; + } + + + return 0; } diff --git a/crypto/rsa/rsa_lib.c b/crypto/rsa/rsa_lib.c index 353b9d8725..71e4b78306 100644 --- a/crypto/rsa/rsa_lib.c +++ b/crypto/rsa/rsa_lib.c @@ -9,11 +9,12 @@ #include #include +#include +#include +#include #include "internal/cryptlib.h" #include "internal/refcount.h" #include "crypto/bn.h" -#include -#include #include "crypto/evp.h" #include "crypto/rsa.h" #include "rsa_local.h" @@ -733,3 +734,391 @@ int rsa_get0_all_params(RSA *r, STACK_OF(BIGNUM_const) *primes, return 1; } + +int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int pad_mode) +{ + OSSL_PARAM pad_params[2], *p = pad_params; + + if (ctx == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA or RSA-PSS return error */ + if (ctx->pmeth != NULL + && ctx->pmeth->pkey_id != EVP_PKEY_RSA + && ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS) + return -1; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (!EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + || ctx->op.ciph.ciphprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, -1, -1, EVP_PKEY_CTRL_RSA_PADDING, + pad_mode, NULL); + + *p++ = OSSL_PARAM_construct_int(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, &pad_mode); + *p++ = OSSL_PARAM_construct_end(); + + return EVP_PKEY_CTX_set_params(ctx, pad_params); +} + +int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, int *pad_mode) +{ + OSSL_PARAM pad_params[2], *p = pad_params; + + if (ctx == NULL || pad_mode == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA or RSA-PSS return error */ + if (ctx->pmeth != NULL + && ctx->pmeth->pkey_id != EVP_PKEY_RSA + && ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS) + return -1; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (!EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + || ctx->op.ciph.ciphprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, -1, -1, EVP_PKEY_CTRL_GET_RSA_PADDING, 0, + pad_mode); + + *p++ = OSSL_PARAM_construct_int(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, pad_mode); + *p++ = OSSL_PARAM_construct_end(); + + if (!EVP_PKEY_CTX_get_params(ctx, pad_params)) + return 0; + + return 1; + +} + +int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) +{ + const char *name; + + if (ctx == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA return error */ + if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA) + return -1; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.ciph.ciphprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)md); + + name = (md == NULL) ? "" : EVP_MD_name(md); + + return EVP_PKEY_CTX_set_rsa_oaep_md_name(ctx, name, NULL); +} + +int EVP_PKEY_CTX_set_rsa_oaep_md_name(EVP_PKEY_CTX *ctx, const char *mdname, + const char *mdprops) +{ + OSSL_PARAM rsa_params[3], *p = rsa_params; + + if (ctx == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA return error */ + if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA) + return -1; + + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, + /* + * Cast away the const. This is read + * only so should be safe + */ + (char *)mdname, + strlen(mdname) + 1); + if (mdprops != NULL) { + *p++ = OSSL_PARAM_construct_utf8_string( + OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS, + /* + * Cast away the const. This is read + * only so should be safe + */ + (char *)mdprops, + strlen(mdprops) + 1); + } + *p++ = OSSL_PARAM_construct_end(); + + return EVP_PKEY_CTX_set_params(ctx, rsa_params); +} + +int EVP_PKEY_CTX_get_rsa_oaep_md_name(EVP_PKEY_CTX *ctx, char *name, + size_t namelen) +{ + OSSL_PARAM rsa_params[2], *p = rsa_params; + + if (ctx == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA return error */ + if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA) + return -1; + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, + name, namelen); + *p++ = OSSL_PARAM_construct_end(); + + if (!EVP_PKEY_CTX_get_params(ctx, rsa_params)) + return -1; + + return 1; +} + +int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **md) +{ + /* 80 should be big enough */ + char name[80] = ""; + + if (ctx == NULL || md == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA return error */ + if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA) + return -1; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.ciph.ciphprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_GET_RSA_OAEP_MD, 0, (void *)md); + + if (EVP_PKEY_CTX_get_rsa_oaep_md_name(ctx, name, sizeof(name)) <= 0) + return -1; + + /* May be NULL meaning "unknown" */ + *md = EVP_get_digestbyname(name); + + return 1; +} + +int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) +{ + const char *name; + + if (ctx == NULL + || (!EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + && !EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx))) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA return error */ + if (ctx->pmeth != NULL + && ctx->pmeth->pkey_id != EVP_PKEY_RSA + && ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS) + return -1; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if ((EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + && ctx->op.ciph.ciphprovctx == NULL) + || (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) + && ctx->op.sig.sigprovctx == NULL)) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, + EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)md); + + name = (md == NULL) ? "" : EVP_MD_name(md); + + return EVP_PKEY_CTX_set_rsa_mgf1_md_name(ctx, name, NULL); +} + +int EVP_PKEY_CTX_set_rsa_mgf1_md_name(EVP_PKEY_CTX *ctx, const char *mdname, + const char *mdprops) +{ + OSSL_PARAM rsa_params[3], *p = rsa_params; + + if (ctx == NULL + || mdname == NULL + || (!EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + && !EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx))) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA return error */ + if (ctx->pmeth != NULL + && ctx->pmeth->pkey_id != EVP_PKEY_RSA + && ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS) + return -1; + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, + /* + * Cast away the const. This is read + * only so should be safe + */ + (char *)mdname, + strlen(mdname) + 1); + if (mdprops != NULL) { + *p++ = OSSL_PARAM_construct_utf8_string( + OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS, + /* + * Cast away the const. This is read + * only so should be safe + */ + (char *)mdprops, + strlen(mdprops) + 1); + } + *p++ = OSSL_PARAM_construct_end(); + + return EVP_PKEY_CTX_set_params(ctx, rsa_params); +} + +int EVP_PKEY_CTX_get_rsa_mgf1_md_name(EVP_PKEY_CTX *ctx, char *name, + size_t namelen) +{ + OSSL_PARAM rsa_params[2], *p = rsa_params; + + if (ctx == NULL + || (!EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + && !EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx))) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA or RSA-PSS return error */ + if (ctx->pmeth != NULL + && ctx->pmeth->pkey_id != EVP_PKEY_RSA + && ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS) + return -1; + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, + name, namelen); + *p++ = OSSL_PARAM_construct_end(); + + if (!EVP_PKEY_CTX_get_params(ctx, rsa_params)) + return -1; + + return 1; +} + +int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **md) +{ + /* 80 should be big enough */ + char name[80] = ""; + + if (ctx == NULL + || (!EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + && !EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx))) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA or RSA-PSS return error */ + if (ctx->pmeth != NULL + && ctx->pmeth->pkey_id != EVP_PKEY_RSA + && ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS) + return -1; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if ((EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + && ctx->op.ciph.ciphprovctx == NULL) + || (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) + && ctx->op.sig.sigprovctx == NULL)) + return EVP_PKEY_CTX_ctrl(ctx, -1, + EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void *)md); + + if (EVP_PKEY_CTX_get_rsa_mgf1_md_name(ctx, name, sizeof(name)) <= 0) + return -1; + + /* May be NULL meaning "unknown" */ + *md = EVP_get_digestbyname(name); + + return 1; +} + +int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, void *label, int llen) +{ + OSSL_PARAM rsa_params[2], *p = rsa_params; + + if (ctx == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA return error */ + if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA) + return -1; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.ciph.ciphprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_OAEP_LABEL, llen, + (void *)label); + + *p++ = OSSL_PARAM_construct_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, + /* + * Cast away the const. This is read + * only so should be safe + */ + (void *)label, + (size_t)llen); + *p++ = OSSL_PARAM_construct_end(); + + if (!EVP_PKEY_CTX_set_params(ctx, rsa_params)) + return 0; + + OPENSSL_free(label); + return 1; +} + +int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx, unsigned char **label) +{ + OSSL_PARAM rsa_params[3], *p = rsa_params; + size_t labellen; + + if (ctx == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + /* If key type not RSA return error */ + if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA) + return -1; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.ciph.ciphprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL, 0, + (void *)label); + + *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, + (void **)label, 0); + *p++ = OSSL_PARAM_construct_size_t(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN, + &labellen); + *p++ = OSSL_PARAM_construct_end(); + + if (!EVP_PKEY_CTX_get_params(ctx, rsa_params)) + return -1; + + if (labellen > INT_MAX) + return -1; + + return (int)labellen; +} diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index 42350e80d1..cdc493bae1 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -190,9 +190,18 @@ extern "C" { #define OSSL_EXCHANGE_PARAM_PAD "pad" /* uint */ /* Signature parameters */ -#define OSSL_SIGNATURE_PARAM_DIGEST "digest" +#define OSSL_SIGNATURE_PARAM_DIGEST OSSL_ALG_PARAM_DIGEST #define OSSL_SIGNATURE_PARAM_DIGEST_SIZE "digest-size" +/* Asym cipher parameters */ +#define OSSL_ASYM_CIPHER_PARAM_PAD_MODE "pad-mode" +#define OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST OSSL_ALG_PARAM_DIGEST +#define OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS "digest-props" +#define OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST "mgf1-digest" +#define OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS "mgf1-digest-props" +#define OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL "oaep-label" +#define OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN "oaep-label-len" + # ifdef __cplusplus } # endif diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h index eba0604455..852981dfcf 100644 --- a/include/openssl/rsa.h +++ b/include/openssl/rsa.h @@ -100,11 +100,8 @@ extern "C" { # define RSA_FLAG_NO_EXP_CONSTTIME RSA_FLAG_NO_CONSTTIME # endif -# define EVP_PKEY_CTX_set_rsa_padding(ctx, pad) \ - RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, NULL) - -# define EVP_PKEY_CTX_get_rsa_padding(ctx, ppad) \ - RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_GET_RSA_PADDING, 0, ppad) +int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int pad_mode); +int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, int *pad_mode); # define EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, len) \ RSA_pkey_ctx_ctrl(ctx, (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), \ @@ -138,39 +135,34 @@ extern "C" { RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, \ EVP_PKEY_CTRL_RSA_KEYGEN_PRIMES, primes, NULL) -# define EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) \ - RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, \ - EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)(md)) +int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md); +int EVP_PKEY_CTX_set_rsa_mgf1_md_name(EVP_PKEY_CTX *ctx, const char *mdname, + const char *mdprops); +int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **md); +int EVP_PKEY_CTX_get_rsa_mgf1_md_name(EVP_PKEY_CTX *ctx, char *name, + size_t namelen); + # define EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md(ctx, md) \ EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA_PSS, EVP_PKEY_OP_KEYGEN, \ EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)(md)) -# define EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) \ - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, \ - EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)(md)) - -# define EVP_PKEY_CTX_get_rsa_mgf1_md(ctx, pmd) \ - RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, \ - EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void *)(pmd)) - -# define EVP_PKEY_CTX_get_rsa_oaep_md(ctx, pmd) \ - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, \ - EVP_PKEY_CTRL_GET_RSA_OAEP_MD, 0, (void *)(pmd)) - -# define EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, l, llen) \ - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, \ - EVP_PKEY_CTRL_RSA_OAEP_LABEL, llen, (void *)(l)) - -# define EVP_PKEY_CTX_get0_rsa_oaep_label(ctx, l) \ - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, \ - EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL, 0, (void *)(l)) +int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md); +int EVP_PKEY_CTX_set_rsa_oaep_md_name(EVP_PKEY_CTX *ctx, const char *mdname, + const char *mdprops); +int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **md); +int EVP_PKEY_CTX_get_rsa_oaep_md_name(EVP_PKEY_CTX *ctx, char *name, + size_t namelen); +int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, void *label, + int llen); +int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx, unsigned char **label); # define EVP_PKEY_CTX_set_rsa_pss_keygen_md(ctx, md) \ EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA_PSS, \ EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_MD, \ 0, (void *)(md)) + # define EVP_PKEY_CTRL_RSA_PADDING (EVP_PKEY_ALG_CTRL + 1) # define EVP_PKEY_CTRL_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 2) diff --git a/providers/defltprov.c b/providers/defltprov.c index 5384028a8d..ceb3fd0896 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -365,6 +365,10 @@ static const OSSL_ALGORITHM deflt_signature[] = { { NULL, NULL, NULL } }; +static const OSSL_ALGORITHM deflt_asym_cipher[] = { + { "RSA:rsaEncryption", "default=yes", rsa_asym_cipher_functions }, + { NULL, NULL, NULL } +}; static const OSSL_ALGORITHM deflt_keymgmt[] = { #ifndef OPENSSL_NO_DH @@ -397,6 +401,8 @@ static const OSSL_ALGORITHM *deflt_query(OSSL_PROVIDER *prov, return deflt_keyexch; case OSSL_OP_SIGNATURE: return deflt_signature; + case OSSL_OP_ASYM_CIPHER: + return deflt_asym_cipher; } return NULL; } diff --git a/providers/implementations/asymciphers/build.info b/providers/implementations/asymciphers/build.info new file mode 100644 index 0000000000..aa050803d4 --- /dev/null +++ b/providers/implementations/asymciphers/build.info @@ -0,0 +1,4 @@ +LIBS=../../../libcrypto +SOURCE[../../../libcrypto]=rsa_enc.c + + diff --git a/providers/implementations/asymciphers/rsa_enc.c b/providers/implementations/asymciphers/rsa_enc.c new file mode 100644 index 0000000000..9b17377783 --- /dev/null +++ b/providers/implementations/asymciphers/rsa_enc.c @@ -0,0 +1,391 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "internal/constant_time.h" +#include "prov/providercommonerr.h" +#include "prov/provider_ctx.h" +#include "prov/implementations.h" + +#include + +static OSSL_OP_asym_cipher_newctx_fn rsa_newctx; +static OSSL_OP_asym_cipher_encrypt_init_fn rsa_init; +static OSSL_OP_asym_cipher_encrypt_fn rsa_encrypt; +static OSSL_OP_asym_cipher_decrypt_init_fn rsa_init; +static OSSL_OP_asym_cipher_decrypt_fn rsa_decrypt; +static OSSL_OP_asym_cipher_freectx_fn rsa_freectx; +static OSSL_OP_asym_cipher_dupctx_fn rsa_dupctx; +static OSSL_OP_asym_cipher_get_ctx_params_fn rsa_get_ctx_params; +static OSSL_OP_asym_cipher_gettable_ctx_params_fn rsa_gettable_ctx_params; +static OSSL_OP_asym_cipher_set_ctx_params_fn rsa_set_ctx_params; +static OSSL_OP_asym_cipher_settable_ctx_params_fn rsa_settable_ctx_params; + + +/* + * 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; + int pad_mode; + /* OAEP message digest */ + EVP_MD *oaep_md; + /* message digest for MGF1 */ + EVP_MD *mgf1_md; + /* OAEP label */ + unsigned char *oaep_label; + size_t oaep_labellen; +} PROV_RSA_CTX; + +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); + + return prsactx; +} + +static int rsa_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; + prsactx->pad_mode = RSA_PKCS1_PADDING; + return 1; +} + +static int rsa_encrypt(void *vprsactx, unsigned char *out, size_t *outlen, + size_t outsize, const unsigned char *in, size_t inlen) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + int ret; + + if (out == NULL) { + size_t len = RSA_size(prsactx->rsa); + + if (len == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + *outlen = len; + return 1; + } + + if (prsactx->pad_mode == RSA_PKCS1_OAEP_PADDING) { + int rsasize = RSA_size(prsactx->rsa); + unsigned char *tbuf; + + if ((tbuf = OPENSSL_malloc(rsasize)) == NULL) { + PROVerr(0, ERR_R_MALLOC_FAILURE); + return 0; + } + ret = RSA_padding_add_PKCS1_OAEP_mgf1(tbuf, rsasize, in, inlen, + prsactx->oaep_label, + prsactx->oaep_labellen, + prsactx->oaep_md, + prsactx->mgf1_md); + + if (!ret) { + OPENSSL_free(tbuf); + return 0; + } + ret = RSA_public_encrypt(rsasize, tbuf, out, prsactx->rsa, + RSA_NO_PADDING); + OPENSSL_free(tbuf); + } else { + ret = RSA_public_encrypt(inlen, in, out, prsactx->rsa, + prsactx->pad_mode); + } + /* A ret value of 0 is not an error */ + if (ret < 0) + return ret; + *outlen = ret; + return 1; +} + +static int rsa_decrypt(void *vprsactx, unsigned char *out, size_t *outlen, + size_t outsize, const unsigned char *in, size_t inlen) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + int ret; + + if (out == NULL) { + size_t len = RSA_size(prsactx->rsa); + + if (len == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + *outlen = len; + return 1; + } + + if (prsactx->pad_mode == RSA_PKCS1_OAEP_PADDING) { + int rsasize = RSA_size(prsactx->rsa); + unsigned char *tbuf; + + if ((tbuf = OPENSSL_malloc(rsasize)) == NULL) { + PROVerr(0, ERR_R_MALLOC_FAILURE); + return 0; + } + ret = RSA_private_decrypt(inlen, in, tbuf, prsactx->rsa, + RSA_NO_PADDING); + if (ret <= 0) { + OPENSSL_free(tbuf); + return 0; + } + ret = RSA_padding_check_PKCS1_OAEP_mgf1(out, ret, tbuf, + ret, ret, + prsactx->oaep_label, + prsactx->oaep_labellen, + prsactx->oaep_md, + prsactx->mgf1_md); + OPENSSL_free(tbuf); + } else { + ret = RSA_private_decrypt(inlen, in, out, prsactx->rsa, + prsactx->pad_mode); + } + *outlen = constant_time_select_s(constant_time_msb_s(ret), *outlen, ret); + ret = constant_time_select_int(constant_time_msb(ret), 0, 1); + return ret; +} + +static void rsa_freectx(void *vprsactx) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + RSA_free(prsactx->rsa); + + EVP_MD_free(prsactx->oaep_md); + EVP_MD_free(prsactx->mgf1_md); + + OPENSSL_free(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; + if (dstctx->rsa != NULL && !RSA_up_ref(dstctx->rsa)) { + OPENSSL_free(dstctx); + return NULL; + } + + if (dstctx->oaep_md != NULL && !EVP_MD_up_ref(dstctx->oaep_md)) { + RSA_free(dstctx->rsa); + OPENSSL_free(dstctx); + return NULL; + } + + if (dstctx->mgf1_md != NULL && !EVP_MD_up_ref(dstctx->mgf1_md)) { + RSA_free(dstctx->rsa); + EVP_MD_free(dstctx->oaep_md); + OPENSSL_free(dstctx); + return NULL; + } + + return dstctx; +} + +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_ASYM_CIPHER_PARAM_PAD_MODE); + if (p != NULL && !OSSL_PARAM_set_int(p, prsactx->pad_mode)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, prsactx->oaep_md == NULL + ? "" + : EVP_MD_name(prsactx->oaep_md))) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST); + if (p != NULL) { + EVP_MD *mgf1_md = prsactx->mgf1_md == NULL ? prsactx->oaep_md + : prsactx->mgf1_md; + + if (!OSSL_PARAM_set_utf8_string(p, mgf1_md == NULL + ? "" + : EVP_MD_name(mgf1_md))) + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL); + if (p != NULL && !OSSL_PARAM_set_octet_ptr(p, prsactx->oaep_label, 0)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, prsactx->oaep_labellen)) + return 0; + + return 1; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, NULL, 0), + OSSL_PARAM_int(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, NULL, 0), + OSSL_PARAM_DEFN(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, OSSL_PARAM_OCTET_PTR, + NULL, 0), + OSSL_PARAM_size_t(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN, NULL), + 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; + /* Should be big enough */ + char mdname[80], mdprops[80] = { '\0' }; + char *str = mdname; + int pad_mode; + + if (prsactx == NULL || params == NULL) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST); + if (p != NULL) { + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdname))) + return 0; + + str = mdprops; + p = OSSL_PARAM_locate_const(params, + OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS); + if (p != NULL) { + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops))) + return 0; + } + + EVP_MD_free(prsactx->oaep_md); + prsactx->oaep_md = EVP_MD_fetch(prsactx->libctx, mdname, mdprops); + + if (prsactx->oaep_md == NULL) + return 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE); + if (p != NULL) { + if (!OSSL_PARAM_get_int(p, &pad_mode)) + return 0; + /* + * PSS padding is for signatures only so is not compatible with + * asymmetric cipher use. + */ + if (pad_mode == RSA_PKCS1_PSS_PADDING) + return 0; + if (pad_mode == RSA_PKCS1_OAEP_PADDING && prsactx->oaep_md == NULL) { + prsactx->oaep_md = EVP_MD_fetch(prsactx->libctx, "SHA1", mdprops); + if (prsactx->oaep_md == NULL) + return 0; + } + prsactx->pad_mode = pad_mode; + } + + p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST); + if (p != NULL) { + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdname))) + return 0; + + str = mdprops; + p = OSSL_PARAM_locate_const(params, + OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS); + if (p != NULL) { + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops))) + return 0; + } else { + str = NULL; + } + + EVP_MD_free(prsactx->mgf1_md); + prsactx->mgf1_md = EVP_MD_fetch(prsactx->libctx, mdname, str); + + if (prsactx->mgf1_md == NULL) + return 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL); + if (p != NULL) { + void *tmp_label = NULL; + size_t tmp_labellen; + + if (!OSSL_PARAM_get_octet_string(p, &tmp_label, 0, &tmp_labellen)) + return 0; + OPENSSL_free(prsactx->oaep_label); + prsactx->oaep_label = (unsigned char *)tmp_label; + prsactx->oaep_labellen = tmp_labellen; + } + + return 1; +} + +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, NULL, 0), + OSSL_PARAM_int(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS, NULL, 0), + OSSL_PARAM_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *rsa_settable_ctx_params(void) +{ + return known_settable_ctx_params; +} + +const OSSL_DISPATCH rsa_asym_cipher_functions[] = { + { OSSL_FUNC_ASYM_CIPHER_NEWCTX, (void (*)(void))rsa_newctx }, + { OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT, (void (*)(void))rsa_init }, + { OSSL_FUNC_ASYM_CIPHER_ENCRYPT, (void (*)(void))rsa_encrypt }, + { OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT, (void (*)(void))rsa_init }, + { OSSL_FUNC_ASYM_CIPHER_DECRYPT, (void (*)(void))rsa_decrypt }, + { OSSL_FUNC_ASYM_CIPHER_FREECTX, (void (*)(void))rsa_freectx }, + { OSSL_FUNC_ASYM_CIPHER_DUPCTX, (void (*)(void))rsa_dupctx }, + { OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS, + (void (*)(void))rsa_get_ctx_params }, + { OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS, + (void (*)(void))rsa_gettable_ctx_params }, + { OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS, + (void (*)(void))rsa_set_ctx_params }, + { OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS, + (void (*)(void))rsa_settable_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/build.info b/providers/implementations/build.info index 0fc0822074..a2fbf45a22 100644 --- a/providers/implementations/build.info +++ b/providers/implementations/build.info @@ -1 +1 @@ -SUBDIRS=digests ciphers macs kdfs exchange keymgmt signature +SUBDIRS=digests ciphers macs kdfs exchange keymgmt signature asymciphers diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index e241e6b49a..490843c544 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -258,3 +258,6 @@ extern const OSSL_DISPATCH dh_keyexch_functions[]; /* Signature */ extern const OSSL_DISPATCH dsa_signature_functions[]; + +/* Asym Cipher */ +extern const OSSL_DISPATCH rsa_asym_cipher_functions[]; diff --git a/util/libcrypto.num b/util/libcrypto.num index 58bf343e0b..6bdfcb328c 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4862,3 +4862,15 @@ EVP_ASYM_CIPHER_is_a ? 3_0_0 EXIST::FUNCTION: EVP_ASYM_CIPHER_number ? 3_0_0 EXIST::FUNCTION: EVP_ASYM_CIPHER_do_all_provided ? 3_0_0 EXIST::FUNCTION: EVP_ASYM_CIPHER_names_do_all ? 3_0_0 EXIST::FUNCTION: +EVP_PKEY_CTX_set_rsa_padding ? 3_0_0 EXIST::FUNCTION:RSA +EVP_PKEY_CTX_get_rsa_padding ? 3_0_0 EXIST::FUNCTION:RSA +EVP_PKEY_CTX_set_rsa_mgf1_md ? 3_0_0 EXIST::FUNCTION:RSA +EVP_PKEY_CTX_set_rsa_mgf1_md_name ? 3_0_0 EXIST::FUNCTION:RSA +EVP_PKEY_CTX_get_rsa_mgf1_md ? 3_0_0 EXIST::FUNCTION:RSA +EVP_PKEY_CTX_set_rsa_oaep_md ? 3_0_0 EXIST::FUNCTION:RSA +EVP_PKEY_CTX_set_rsa_oaep_md_name ? 3_0_0 EXIST::FUNCTION:RSA +EVP_PKEY_CTX_get_rsa_oaep_md ? 3_0_0 EXIST::FUNCTION:RSA +EVP_PKEY_CTX_set0_rsa_oaep_label ? 3_0_0 EXIST::FUNCTION:RSA +EVP_PKEY_CTX_get0_rsa_oaep_label ? 3_0_0 EXIST::FUNCTION:RSA +EVP_PKEY_CTX_get_rsa_mgf1_md_name ? 3_0_0 EXIST::FUNCTION:RSA +EVP_PKEY_CTX_get_rsa_oaep_md_name ? 3_0_0 EXIST::FUNCTION:RSA