]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Replace PKCS#1 v1.5 padding in RSA PCT
authorJoachim Vandersmissen <git@jvdsn.com>
Fri, 15 Mar 2024 16:34:12 +0000 (11:34 -0500)
committerPauli <ppzgs1@gmail.com>
Wed, 21 Aug 2024 21:24:29 +0000 (07:24 +1000)
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)

crypto/rsa/rsa_gen.c
doc/man7/OSSL_PROVIDER-FIPS.pod
include/openssl/self_test.h

index bb835cf0fcf1883bbd33dffd596e4e2850509663..c04a4ea3d923dfa79a6811950fad97c48c71aea3 100644 (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;
 
-    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;
 }
index 78b58115bcab3ba858bec237e6d89cff3e9a801d..b9560def0dda291b8499da38fa4d7b651df7d90e 100644 (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>)
index 7a204f5602787d14b5db16e8b67fb6d91ce8b95d..98652f9abdd73e4e8db3b284c16acd56f087609e 100644 (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"