Replace PKCS#1 v1.5 padding in RSA PCT

After December 31, 2023, SP 800-131Ar2 [0] no longer allows PKCS#1 v1.5
padding for RSA "key-transport" (aka encryption and decryption).
There's a few good options to replace this usage in the RSA PCT, but
the simplest is verifying m = (m^e)^d mod n, (where 1 < m < (n − 1)).
This is specified in SP 800-56Br2 (Section 6.4.1.1) [1] and allowed by
FIPS 140-3 IG 10.3.A. In OpenSSL, this corresponds to RSA_NO_PADDING.

[0]: https://doi.org/10.6028/NIST.SP.800-131Ar2
[1]: https://doi.org/10.6028/NIST.SP.800-56Br2

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/23832)
This commit is contained in:
Joachim Vandersmissen 2024-03-15 11:34:12 -05:00 committed by Pauli
parent 9341e6683c
commit 6c39d21a48
3 changed files with 60 additions and 21 deletions

View File

@ -23,9 +23,7 @@
#include <time.h>
#include "internal/cryptlib.h"
#include <openssl/bn.h>
#include <openssl/obj_mac.h>
#include <openssl/self_test.h>
#include "crypto/sha.h"
#include "prov/providercommon.h"
#include "rsa_local.h"
@ -651,45 +649,83 @@ static int rsa_keygen(OSSL_LIB_CTX *libctx, RSA *rsa, int bits, int primes,
}
/*
* For RSA key generation it is not known whether the key pair will be used
* for key transport or signatures. FIPS 140-2 IG 9.9 states that in this case
* either a signature verification OR an encryption operation may be used to
* perform the pairwise consistency check. The simpler encrypt/decrypt operation
* has been chosen for this case.
* AS10.35 (and its VEs/TEs) of the FIPS 140-3 standard requires a PCT for every
* generated key pair. There are 3 options:
* 1) If the key pair is to be used for key transport (asymmetric cipher), the
* PCT consists of encrypting a plaintext, verifying that the result
* (ciphertext) is not equal to the plaintext, decrypting the ciphertext, and
* verifying that the result is equal to the plaintext.
* 2) If the key pair is to be used for digital signatures, the PCT consists of
* computing and verifying a signature.
* 3) If the key pair is to be used for key agreement, the exact PCT is defined
* in the applicable standards. For RSA-based schemes, this is defined in
* SP 800-56Br2 (Section 6.4.1.1) as:
* "The owner shall perform a pair-wise consistency test by verifying that m
* = (m^e)^d mod n for some integer m satisfying 1 < m < (n - 1)."
*
* OpenSSL implements all three use cases: RSA-OAEP for key transport,
* RSA signatures with PKCS#1 v1.5 or PSS padding, and KAS-IFC-SSC (KAS1/KAS2)
* using RSASVE.
*
* According to FIPS 140-3 IG 10.3.A, if at the time when the PCT is performed
* the keys' intended usage is not known, then any of the three PCTs described
* in AS10.35 shall be performed on this key pair.
*
* Because of this allowance from the IG, the simplest option is 3, i.e.
* RSA_public_encrypt() and RSA_private_decrypt() with RSA_NO_PADDING.
*/
static int rsa_keygen_pairwise_test(RSA *rsa, OSSL_CALLBACK *cb, void *cbarg)
{
int ret = 0;
unsigned int sig_len;
unsigned char *sig = NULL;
const unsigned char md[SHA256_DIGEST_LENGTH] = {0};
unsigned int plaintxt_len;
unsigned char *plaintxt = NULL;
unsigned int ciphertxt_len;
unsigned char *ciphertxt = NULL;
unsigned char *decoded = NULL;
unsigned int decoded_len;
int padding = RSA_NO_PADDING;
OSSL_SELF_TEST *st = NULL;
st = OSSL_SELF_TEST_new(cb, cbarg);
if (st == NULL)
goto err;
OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_PCT,
OSSL_SELF_TEST_DESC_PCT_RSA_PKCS1);
OSSL_SELF_TEST_DESC_PCT_RSA);
sig_len = RSA_size(rsa);
sig = OPENSSL_zalloc(sig_len);
if (sig == NULL)
/*
* For RSA_NO_PADDING, RSA_public_encrypt() and RSA_private_decrypt()
* require the 'to' and 'from' parameters to have equal length and a
* maximum of RSA_size() - allocate space for plaintxt, ciphertxt, and
* decoded.
*/
plaintxt_len = RSA_size(rsa);
plaintxt = OPENSSL_zalloc(plaintxt_len * 3);
if (plaintxt == NULL)
goto err;
ciphertxt = plaintxt + plaintxt_len;
decoded = ciphertxt + plaintxt_len;
/* SP 800-56Br2 Section 6.4.1.1 requires that plaintext is greater than 1 */
plaintxt[plaintxt_len - 1] = 2;
ciphertxt_len = RSA_public_encrypt(plaintxt_len, plaintxt, ciphertxt, rsa,
padding);
if (ciphertxt_len <= 0)
goto err;
if (RSA_sign(NID_sha256, md, SHA256_DIGEST_LENGTH, sig, &sig_len, rsa) == 0)
goto err;
OSSL_SELF_TEST_oncorrupt_byte(st, ciphertxt);
OSSL_SELF_TEST_oncorrupt_byte(st, sig);
if (RSA_verify(NID_sha256, md, SHA256_DIGEST_LENGTH, sig, sig_len,
rsa) == 0)
decoded_len = RSA_private_decrypt(ciphertxt_len, ciphertxt, decoded, rsa,
padding);
if (decoded_len != plaintxt_len
|| memcmp(decoded, plaintxt, decoded_len) != 0)
goto err;
ret = 1;
err:
OSSL_SELF_TEST_onend(st, ret);
OSSL_SELF_TEST_free(st);
OPENSSL_free(sig);
OPENSSL_free(plaintxt);
return ret;
}

View File

@ -339,6 +339,8 @@ The FIPS module passes the following descriptions(s) to OSSL_SELF_TEST_onbegin()
=item "RSA" (B<OSSL_SELF_TEST_DESC_PCT_RSA_PKCS1>)
=item "RSA" (B<OSSL_SELF_TEST_DESC_PCT_RSA>)
=item "ECDSA" (B<OSSL_SELF_TEST_DESC_PCT_ECDSA>)
=item "EDDSA" (B<OSSL_SELF_TEST_DESC_PCT_EDDSA>)

View File

@ -44,6 +44,7 @@ extern "C" {
/* Test event sub categories */
# define OSSL_SELF_TEST_DESC_NONE "None"
# define OSSL_SELF_TEST_DESC_INTEGRITY_HMAC "HMAC"
# define OSSL_SELF_TEST_DESC_PCT_RSA "RSA"
# define OSSL_SELF_TEST_DESC_PCT_RSA_PKCS1 "RSA"
# define OSSL_SELF_TEST_DESC_PCT_ECDSA "ECDSA"
# define OSSL_SELF_TEST_DESC_PCT_EDDSA "EDDSA"