if (!ossl_cms_env_asn1_ctrl(ri, 1))
goto err;
+ if (EVP_PKEY_is_a(pkey, "RSA"))
+ /* upper layer CMS code incorrectly assumes that a successful RSA
+ * decryption means that the key matches ciphertext (which never
+ * was the case, implicit rejection or not), so to make it work
+ * disable implicit rejection for RSA keys */
+ EVP_PKEY_CTX_ctrl_str(ktri->pctx, "rsa_pkcs1_implicit_rejection", "0");
+
if (EVP_PKEY_decrypt(ktri->pctx, NULL, &eklen,
ktri->encryptedKey->data,
ktri->encryptedKey->length) <= 0)
EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL, NULL, NULL,
OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, OSSL_PARAM_OCTET_STRING, NULL },
+ { SET, EVP_PKEY_RSA, 0, EVP_PKEY_OP_TYPE_CRYPT,
+ EVP_PKEY_CTRL_RSA_IMPLICIT_REJECTION, NULL,
+ "rsa_pkcs1_implicit_rejection",
+ OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION, OSSL_PARAM_UNSIGNED_INTEGER,
+ NULL },
+
{ SET, EVP_PKEY_RSA_PSS, 0, EVP_PKEY_OP_TYPE_GEN,
EVP_PKEY_CTRL_MD, "rsa_pss_keygen_md", NULL,
OSSL_ALG_PARAM_DIGEST, OSSL_PARAM_UTF8_STRING, fix_md },
BIGNUM *unblind = NULL;
BN_BLINDING *blinding = NULL;
+ /*
+ * we need the value of the private exponent to perform implicit rejection
+ */
+ if ((rsa->flags & RSA_FLAG_EXT_PKEY) && (padding == RSA_PKCS1_PADDING))
+ padding = RSA_PKCS1_NO_IMPLICIT_REJECT_PADDING;
+
if ((ctx = BN_CTX_new_ex(rsa->libctx)) == NULL)
goto err;
BN_CTX_start(ctx);
* derive the Key Derivation Key from private exponent and public
* ciphertext
*/
- if (!(rsa->flags & RSA_FLAG_EXT_PKEY)) {
+ if (padding == RSA_PKCS1_PADDING) {
/*
* because we use d as a handle to rsa->d we need to keep it local and
* free before any further use of rsa->d
goto err;
switch (padding) {
+ case RSA_PKCS1_NO_IMPLICIT_REJECT_PADDING:
+ r = RSA_padding_check_PKCS1_type_2(to, num, buf, j, num);
+ break;
case RSA_PKCS1_PADDING:
- if (rsa->flags & RSA_FLAG_EXT_PKEY)
- r = RSA_padding_check_PKCS1_type_2(to, num, buf, j, num);
- else
- r = ossl_rsa_padding_check_PKCS1_type_2(rsa->libctx, to, num, buf, j, num, kdk);
+ r = ossl_rsa_padding_check_PKCS1_type_2(rsa->libctx, to, num, buf, j, num, kdk);
break;
case RSA_PKCS1_OAEP_PADDING:
r = RSA_padding_check_PKCS1_OAEP(to, num, buf, j, num, NULL, 0);
/* OAEP label */
unsigned char *oaep_label;
size_t oaep_labellen;
+ /* if to use implicit rejection in PKCS#1 v1.5 decryption */
+ int implicit_rejection;
} RSA_PKEY_CTX;
/* True if PSS parameters are restricted */
/* Maximum for sign, auto for verify */
rctx->saltlen = RSA_PSS_SALTLEN_AUTO;
rctx->min_saltlen = -1;
+ rctx->implicit_rejection = 1;
ctx->data = rctx;
ctx->keygen_info = rctx->gentmp;
ctx->keygen_info_count = 2;
dctx->md = sctx->md;
dctx->mgf1md = sctx->mgf1md;
dctx->saltlen = sctx->saltlen;
+ dctx->implicit_rejection = sctx->implicit_rejection;
if (sctx->oaep_label) {
OPENSSL_free(dctx->oaep_label);
dctx->oaep_label = OPENSSL_memdup(sctx->oaep_label, sctx->oaep_labellen);
const unsigned char *in, size_t inlen)
{
int ret;
+ int pad_mode;
RSA_PKEY_CTX *rctx = ctx->data;
/*
* Discard const. Its marked as const because this may be a cached copy of
rctx->oaep_labellen,
rctx->md, rctx->mgf1md);
} else {
- ret = RSA_private_decrypt(inlen, in, out, rsa, rctx->pad_mode);
+ if (rctx->pad_mode == RSA_PKCS1_PADDING &&
+ rctx->implicit_rejection == 0)
+ pad_mode = RSA_PKCS1_NO_IMPLICIT_REJECT_PADDING;
+ else
+ pad_mode = rctx->pad_mode;
+ ret = RSA_private_decrypt(inlen, in, out, rsa, pad_mode);
}
*outlen = constant_time_select_s(constant_time_msb_s(ret), *outlen, ret);
ret = constant_time_select_int(constant_time_msb(ret), ret, 1);
*(unsigned char **)p2 = rctx->oaep_label;
return rctx->oaep_labellen;
+ case EVP_PKEY_CTRL_RSA_IMPLICIT_REJECTION:
+ if (rctx->pad_mode != RSA_PKCS1_PADDING) {
+ ERR_raise(ERR_LIB_RSA, RSA_R_INVALID_PADDING_MODE);
+ return -2;
+ }
+ rctx->implicit_rejection = p1;
+ return 1;
+
case EVP_PKEY_CTRL_DIGESTINIT:
case EVP_PKEY_CTRL_PKCS7_SIGN:
#ifndef OPENSSL_NO_CMS
Sets the digest used for the OAEP hash function. If not explicitly set then
SHA1 is used.
+=item B<rsa_pkcs1_implicit_rejection:>I<flag>
+
+Disables (when set to 0) or enables (when set to 1) the use of implicit
+rejection with PKCS#1 v1.5 decryption. When enabled (the default), as a
+protection against Bleichenbacher attack, the library will generate a
+deterministic random plaintext that it will return to the caller in case
+of padding check failure.
+When disabled, it's the callers' responsibility to handle the returned
+errors in a side-channel free manner.
+
=back
=head1 RSA-PSS ALGORITHM
want to remain secure while using earlier versions of OpenSSL, still need to
handle both the error code from the RSA decryption operation and the
returned message in a side channel secure manner.
+This protection against Bleichenbacher attacks can be disabled by setting
+the OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION (an unsigned integer) to 0.
=head2 DSA parameters
The negotiated TLS protocol version.
+=item "implicit-rejection" (B<OSSL_PKEY_PARAM_IMPLICIT_REJECTION>) <unsigned integer>
+
+Gets of sets the use of the implicit rejection mechanism for RSA PKCS#1 v1.5
+decryption. When set (non zero value), the decryption API will return
+a deterministically random value if the PKCS#1 v1.5 padding check fails.
+This makes explotation of the Bleichenbacher significantly harder, even
+if the code using the RSA decryption API is not implemented in side-channel
+free manner. Set by default.
+
=back
OSSL_FUNC_asym_cipher_gettable_ctx_params() and OSSL_FUNC_asym_cipher_settable_ctx_params()
#define OSSL_PKEY_PARAM_DIST_ID "distid"
#define OSSL_PKEY_PARAM_PUB_KEY "pub"
#define OSSL_PKEY_PARAM_PRIV_KEY "priv"
+#define OSSL_PKEY_PARAM_IMPLICIT_REJECTION "implicit-rejection"
/* Diffie-Hellman/DSA Parameters */
#define OSSL_PKEY_PARAM_FFC_P "p"
#define OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL "oaep-label"
#define OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION "tls-client-version"
#define OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION "tls-negotiated-version"
+#define OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION "implicit-rejection"
/*
* Encoder / decoder parameters
# define EVP_PKEY_CTRL_RSA_KEYGEN_PRIMES (EVP_PKEY_ALG_CTRL + 13)
+# define EVP_PKEY_CTRL_RSA_IMPLICIT_REJECTION (EVP_PKEY_ALG_CTRL + 14)
+
# define RSA_PKCS1_PADDING 1
# define RSA_NO_PADDING 3
# define RSA_PKCS1_OAEP_PADDING 4
# define RSA_PKCS1_PSS_PADDING 6
# define RSA_PKCS1_WITH_TLS_PADDING 7
+/* internal RSA_ only */
+# define RSA_PKCS1_NO_IMPLICIT_REJECT_PADDING 8
+
# define RSA_PKCS1_PADDING_SIZE 11
# define RSA_set_app_data(s,arg) RSA_set_ex_data(s,0,arg)
/* TLS padding */
unsigned int client_version;
unsigned int alt_version;
+ /* PKCS#1 v1.5 decryption mode */
+ unsigned int implicit_rejection;
} PROV_RSA_CTX;
static void *rsa_newctx(void *provctx)
RSA_free(prsactx->rsa);
prsactx->rsa = vrsa;
prsactx->operation = operation;
+ prsactx->implicit_rejection = 1;
switch (RSA_test_flags(prsactx->rsa, RSA_FLAG_TYPE_MASK)) {
case RSA_FLAG_TYPE_RSA:
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
int ret;
+ int pad_mode;
size_t len = RSA_size(prsactx->rsa);
if (!ossl_prov_is_running())
}
OPENSSL_free(tbuf);
} else {
- ret = RSA_private_decrypt(inlen, in, out, prsactx->rsa,
- prsactx->pad_mode);
+ if ((prsactx->implicit_rejection == 0) &&
+ (prsactx->pad_mode == RSA_PKCS1_PADDING))
+ pad_mode = RSA_PKCS1_NO_IMPLICIT_REJECT_PADDING;
+ else
+ pad_mode = prsactx->pad_mode;
+ ret = RSA_private_decrypt(inlen, in, out, prsactx->rsa, 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);
if (p != NULL && !OSSL_PARAM_set_uint(p, prsactx->alt_version))
return 0;
+ p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION);
+ if (p != NULL && !OSSL_PARAM_set_uint(p, prsactx->implicit_rejection))
+ return 0;
+
return 1;
}
NULL, 0),
OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL),
OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL),
+ OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION, NULL),
OSSL_PARAM_END
};
return 0;
prsactx->alt_version = alt_version;
}
+ p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION);
+ if (p != NULL) {
+ unsigned int implicit_rejection;
+
+ if (!OSSL_PARAM_get_uint(p, &implicit_rejection))
+ return 0;
+ prsactx->implicit_rejection = implicit_rejection;
+ }
return 1;
}
OSSL_PARAM_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, NULL, 0),
OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL),
OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL),
+ OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION, NULL),
OSSL_PARAM_END
};