From: Joachim Vandersmissen Date: Fri, 15 Mar 2024 16:34:12 +0000 (-0500) Subject: Replace PKCS#1 v1.5 padding in RSA PCT X-Git-Tag: openssl-3.4.0-alpha1~69 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6c39d21a4844cab997164454ece9b21186881f2a;p=thirdparty%2Fopenssl.git 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 Reviewed-by: Shane Lontis Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/23832) --- diff --git a/crypto/rsa/rsa_gen.c b/crypto/rsa/rsa_gen.c index bb835cf0fcf..c04a4ea3d92 100644 --- a/crypto/rsa/rsa_gen.c +++ b/crypto/rsa/rsa_gen.c @@ -23,9 +23,7 @@ #include #include "internal/cryptlib.h" #include -#include #include -#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; - if (RSA_sign(NID_sha256, md, SHA256_DIGEST_LENGTH, sig, &sig_len, rsa) == 0) + ciphertxt_len = RSA_public_encrypt(plaintxt_len, plaintxt, ciphertxt, rsa, + padding); + if (ciphertxt_len <= 0) goto err; - OSSL_SELF_TEST_oncorrupt_byte(st, sig); + OSSL_SELF_TEST_oncorrupt_byte(st, ciphertxt); - 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; } diff --git a/doc/man7/OSSL_PROVIDER-FIPS.pod b/doc/man7/OSSL_PROVIDER-FIPS.pod index 78b58115bca..b9560def0dd 100644 --- a/doc/man7/OSSL_PROVIDER-FIPS.pod +++ b/doc/man7/OSSL_PROVIDER-FIPS.pod @@ -339,6 +339,8 @@ The FIPS module passes the following descriptions(s) to OSSL_SELF_TEST_onbegin() =item "RSA" (B) +=item "RSA" (B) + =item "ECDSA" (B) =item "EDDSA" (B) diff --git a/include/openssl/self_test.h b/include/openssl/self_test.h index 7a204f56027..98652f9abdd 100644 --- a/include/openssl/self_test.h +++ b/include/openssl/self_test.h @@ -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"