+ const char *type, const char *value)
+{
+ if (value == NULL) {
+ RSAerr(RSA_F_PKEY_RSA_CTRL_STR, RSA_R_VALUE_MISSING);
+ return 0;
+ }
+ if (strcmp(type, "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 {
+ RSAerr(RSA_F_PKEY_RSA_CTRL_STR, RSA_R_UNKNOWN_PADDING_TYPE);
+ return -2;
+ }
+ return EVP_PKEY_CTX_set_rsa_padding(ctx, pm);
+ }
+
+ if (strcmp(type, "rsa_pss_saltlen") == 0) {
+ int saltlen;
+
+ if (!strcmp(value, "digest"))
+ saltlen = RSA_PSS_SALTLEN_DIGEST;
+ else if (!strcmp(value, "max"))
+ saltlen = RSA_PSS_SALTLEN_MAX;
+ else if (!strcmp(value, "auto"))
+ saltlen = RSA_PSS_SALTLEN_AUTO;
+ else
+ saltlen = atoi(value);
+ return EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, saltlen);
+ }
+
+ if (strcmp(type, "rsa_keygen_bits") == 0) {
+ int nbits = atoi(value);
+
+ return EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, nbits);
+ }
+
+ if (strcmp(type, "rsa_keygen_pubexp") == 0) {
+ int ret;
+
+ BIGNUM *pubexp = NULL;
+ if (!BN_asc2bn(&pubexp, value))
+ return 0;
+ ret = EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, pubexp);
+ if (ret <= 0)
+ BN_free(pubexp);
+ return ret;
+ }
+
+ if (strcmp(type, "rsa_keygen_primes") == 0) {
+ int nprimes = atoi(value);
+
+ return EVP_PKEY_CTX_set_rsa_keygen_primes(ctx, nprimes);
+ }
+
+ if (strcmp(type, "rsa_mgf1_md") == 0)
+ return EVP_PKEY_CTX_md(ctx,
+ EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
+ EVP_PKEY_CTRL_RSA_MGF1_MD, value);
+
+ if (pkey_ctx_is_pss(ctx)) {
+
+ if (strcmp(type, "rsa_pss_keygen_mgf1_md") == 0)
+ return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_KEYGEN,
+ EVP_PKEY_CTRL_RSA_MGF1_MD, value);
+
+ if (strcmp(type, "rsa_pss_keygen_md") == 0)
+ return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_KEYGEN,
+ EVP_PKEY_CTRL_MD, value);
+
+ if (strcmp(type, "rsa_pss_keygen_saltlen") == 0) {
+ int saltlen = atoi(value);
+
+ return EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen(ctx, saltlen);
+ }
+ }
+
+ if (strcmp(type, "rsa_oaep_md") == 0)
+ return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_TYPE_CRYPT,
+ EVP_PKEY_CTRL_RSA_OAEP_MD, value);
+
+ if (strcmp(type, "rsa_oaep_label") == 0) {
+ unsigned char *lab;
+ long lablen;
+ int ret;
+
+ lab = OPENSSL_hexstr2buf(value, &lablen);
+ if (!lab)
+ return 0;
+ ret = EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, lab, lablen);
+ if (ret <= 0)
+ OPENSSL_free(lab);
+ return ret;
+ }
+
+ return -2;
+}
+
+/* Set PSS parameters when generating a key, if necessary */
+static int rsa_set_pss_param(RSA *rsa, EVP_PKEY_CTX *ctx)
+{
+ RSA_PKEY_CTX *rctx = ctx->data;
+
+ if (!pkey_ctx_is_pss(ctx))
+ return 1;
+ /* If all parameters are default values don't set pss */
+ if (rctx->md == NULL && rctx->mgf1md == NULL && rctx->saltlen == -2)
+ return 1;
+ rsa->pss = rsa_pss_params_create(rctx->md, rctx->mgf1md,
+ rctx->saltlen == -2 ? 0 : rctx->saltlen);
+ if (rsa->pss == NULL)
+ return 0;
+ return 1;
+}
+
+static int pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
+{
+ RSA *rsa = NULL;
+ RSA_PKEY_CTX *rctx = ctx->data;
+ BN_GENCB *pcb;
+ int ret;
+
+ if (rctx->pub_exp == NULL) {
+ rctx->pub_exp = BN_new();
+ if (rctx->pub_exp == NULL || !BN_set_word(rctx->pub_exp, RSA_F4))
+ return 0;
+ }
+ rsa = RSA_new();
+ if (rsa == NULL)
+ return 0;
+ if (ctx->pkey_gencb) {
+ pcb = BN_GENCB_new();
+ if (pcb == NULL) {
+ RSA_free(rsa);
+ return 0;
+ }
+ evp_pkey_set_cb_translate(pcb, ctx);
+ } else {
+ pcb = NULL;
+ }
+ ret = RSA_generate_multi_prime_key(rsa, rctx->nbits, rctx->primes,
+ rctx->pub_exp, pcb);
+ BN_GENCB_free(pcb);
+ if (ret > 0 && !rsa_set_pss_param(rsa, ctx)) {
+ RSA_free(rsa);
+ return 0;
+ }
+ if (ret > 0)
+ EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, rsa);
+ else
+ RSA_free(rsa);
+ return ret;
+}
+
+const EVP_PKEY_METHOD rsa_pkey_meth = {
+ EVP_PKEY_RSA,
+ EVP_PKEY_FLAG_AUTOARGLEN,
+ pkey_rsa_init,
+ pkey_rsa_copy,
+ pkey_rsa_cleanup,
+
+ 0, 0,
+
+ 0,
+ pkey_rsa_keygen,
+
+ 0,
+ pkey_rsa_sign,
+
+ 0,
+ pkey_rsa_verify,
+
+ 0,
+ pkey_rsa_verifyrecover,
+
+ 0, 0, 0, 0,
+
+ 0,
+ pkey_rsa_encrypt,
+
+ 0,
+ pkey_rsa_decrypt,
+
+ 0, 0,
+
+ pkey_rsa_ctrl,
+ pkey_rsa_ctrl_str
+};
+
+/*
+ * Called for PSS sign or verify initialisation: checks PSS parameter
+ * sanity and sets any restrictions on key usage.
+ */
+
+static int pkey_pss_init(EVP_PKEY_CTX *ctx)
+{
+ RSA *rsa;
+ RSA_PKEY_CTX *rctx = ctx->data;
+ const EVP_MD *md;
+ const EVP_MD *mgf1md;
+ int min_saltlen, max_saltlen;
+
+ /* Should never happen */
+ if (!pkey_ctx_is_pss(ctx))
+ return 0;
+ rsa = ctx->pkey->pkey.rsa;
+ /* If no restrictions just return */
+ if (rsa->pss == NULL)
+ return 1;
+ /* Get and check parameters */
+ if (!rsa_pss_get_param(rsa->pss, &md, &mgf1md, &min_saltlen))
+ return 0;
+
+ /* See if minimum salt length exceeds maximum possible */
+ max_saltlen = RSA_size(rsa) - EVP_MD_size(md);
+ if ((RSA_bits(rsa) & 0x7) == 1)
+ max_saltlen--;
+ if (min_saltlen > max_saltlen) {
+ RSAerr(RSA_F_PKEY_PSS_INIT, RSA_R_INVALID_SALT_LENGTH);
+ return 0;
+ }
+
+ rctx->min_saltlen = min_saltlen;
+
+ /*
+ * Set PSS restrictions as defaults: we can then block any attempt to
+ * use invalid values in pkey_rsa_ctrl
+ */
+
+ rctx->md = md;
+ rctx->mgf1md = mgf1md;
+ rctx->saltlen = min_saltlen;
+
+ return 1;
+}
+
+const EVP_PKEY_METHOD rsa_pss_pkey_meth = {
+ EVP_PKEY_RSA_PSS,
+ EVP_PKEY_FLAG_AUTOARGLEN,
+ pkey_rsa_init,
+ pkey_rsa_copy,
+ pkey_rsa_cleanup,
+
+ 0, 0,
+
+ 0,
+ pkey_rsa_keygen,
+
+ pkey_pss_init,
+ pkey_rsa_sign,
+
+ pkey_pss_init,
+ pkey_rsa_verify,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ pkey_rsa_ctrl,
+ pkey_rsa_ctrl_str
+};