From b300beb172d5813b01b93bfd62fe191f8187fe1e Mon Sep 17 00:00:00 2001
From: Dmitry Belyavskiy <dbelyavs@redhat.com>
Date: Mon, 21 Aug 2023 12:05:23 +0200
Subject: [PATCH 20/48] 0044-FIPS-140-3-keychecks.patch

Patch-name: 0044-FIPS-140-3-keychecks.patch
Patch-id: 44
Patch-status: |
    # Extra public/private key checks required by FIPS-140-3
---
 crypto/dh/dh_key.c                            | 26 ++++++++++
 .../implementations/exchange/ecdh_exch.c      | 19 ++++++++
 providers/implementations/keymgmt/ec_kmgmt.c  | 24 +++++++++-
 providers/implementations/keymgmt/rsa_kmgmt.c | 18 +++++++
 .../implementations/signature/ecdsa_sig.c     | 37 +++++++++++++--
 providers/implementations/signature/rsa_sig.c | 47 +++++++++++++++++--
 6 files changed, 162 insertions(+), 9 deletions(-)

diff --git a/crypto/dh/dh_key.c b/crypto/dh/dh_key.c
index 4e9705beef..83773cceea 100644
--- a/crypto/dh/dh_key.c
+++ b/crypto/dh/dh_key.c
@@ -43,6 +43,9 @@ int ossl_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
     BN_MONT_CTX *mont = NULL;
     BIGNUM *z = NULL, *pminus1;
     int ret = -1;
+#ifdef FIPS_MODULE
+    int validate = 0;
+#endif
 
     if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) {
         ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
@@ -54,6 +57,13 @@ int ossl_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
         return 0;
     }
 
+#ifdef FIPS_MODULE
+    if (DH_check_pub_key(dh, pub_key, &validate) <= 0) {
+        ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_INVALID);
+        return 0;
+    }
+#endif
+
     ctx = BN_CTX_new_ex(dh->libctx);
     if (ctx == NULL)
         goto err;
@@ -262,6 +272,9 @@ static int generate_key(DH *dh)
 #endif
     BN_CTX *ctx = NULL;
     BIGNUM *pub_key = NULL, *priv_key = NULL;
+#ifdef FIPS_MODULE
+    int validate = 0;
+#endif
 
     if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) {
         ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
@@ -354,8 +367,21 @@ static int generate_key(DH *dh)
     if (!ossl_dh_generate_public_key(ctx, dh, priv_key, pub_key))
         goto err;
 
+#ifdef FIPS_MODULE
+    if (DH_check_pub_key(dh, pub_key, &validate) <= 0) {
+        ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_INVALID);
+        goto err;
+    }
+#endif
+
     dh->pub_key = pub_key;
     dh->priv_key = priv_key;
+#ifdef FIPS_MODULE
+    if (ossl_dh_check_pairwise(dh) <= 0) {
+        abort();
+    }
+#endif
+
     dh->dirty_cnt++;
     ok = 1;
  err:
diff --git a/providers/implementations/exchange/ecdh_exch.c b/providers/implementations/exchange/ecdh_exch.c
index 43caedb6df..73873f9758 100644
--- a/providers/implementations/exchange/ecdh_exch.c
+++ b/providers/implementations/exchange/ecdh_exch.c
@@ -489,6 +489,25 @@ int ecdh_plain_derive(void *vpecdhctx, unsigned char *secret,
     }
 
     ppubkey = EC_KEY_get0_public_key(pecdhctx->peerk);
+#ifdef FIPS_MODULE
+    {
+        BN_CTX *bn_ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(privk));
+        int check = 0;
+
+        if (bn_ctx == NULL) {
+            ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+            goto end;
+        }
+
+        check = ossl_ec_key_public_check(pecdhctx->peerk, bn_ctx);
+        BN_CTX_free(bn_ctx);
+
+        if (check <= 0) {
+            ERR_raise(ERR_LIB_PROV, EC_R_INVALID_PEER_KEY);
+            goto end;
+        }
+    }
+#endif
 
     retlen = ECDH_compute_key(secret, size, ppubkey, privk, NULL);
 
diff --git a/providers/implementations/keymgmt/ec_kmgmt.c b/providers/implementations/keymgmt/ec_kmgmt.c
index a37cbbdba8..bca3f3c674 100644
--- a/providers/implementations/keymgmt/ec_kmgmt.c
+++ b/providers/implementations/keymgmt/ec_kmgmt.c
@@ -989,8 +989,17 @@ struct ec_gen_ctx {
     EC_GROUP *gen_group;
     unsigned char *dhkem_ikm;
     size_t dhkem_ikmlen;
+#ifdef FIPS_MODULE
+    void *ecdsa_sig_ctx;
+#endif
 };
 
+#ifdef FIPS_MODULE
+void *ecdsa_newctx(void *provctx, const char *propq);
+void ecdsa_freectx(void *vctx);
+int do_ec_pct(void *, const char *, void *);
+#endif
+
 static void *ec_gen_init(void *provctx, int selection,
                          const OSSL_PARAM params[])
 {
@@ -1009,6 +1018,10 @@ static void *ec_gen_init(void *provctx, int selection,
             gctx = NULL;
         }
     }
+#ifdef FIPS_MODULE
+    if (gctx != NULL)
+        gctx->ecdsa_sig_ctx = ecdsa_newctx(provctx, NULL);
+#endif
     return gctx;
 }
 
@@ -1279,6 +1292,12 @@ static void *ec_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
 
     if (gctx->ecdh_mode != -1)
         ret = ret && ossl_ec_set_ecdh_cofactor_mode(ec, gctx->ecdh_mode);
+#ifdef FIPS_MODULE
+    /* Pairwise consistency test */
+    if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0
+        && do_ec_pct(gctx->ecdsa_sig_ctx, "sha256", ec) != 1)
+        abort();
+#endif
 
     if (gctx->group_check != NULL)
         ret = ret && ossl_ec_set_check_group_type_from_name(ec,
@@ -1348,7 +1367,10 @@ static void ec_gen_cleanup(void *genctx)
 
     if (gctx == NULL)
         return;
-
+#ifdef FIPS_MODULE
+    ecdsa_freectx(gctx->ecdsa_sig_ctx);
+    gctx->ecdsa_sig_ctx = NULL;
+#endif
     OPENSSL_clear_free(gctx->dhkem_ikm, gctx->dhkem_ikmlen);
     EC_GROUP_free(gctx->gen_group);
     BN_free(gctx->p);
diff --git a/providers/implementations/keymgmt/rsa_kmgmt.c b/providers/implementations/keymgmt/rsa_kmgmt.c
index 3ba12c4889..ff49f8fcd8 100644
--- a/providers/implementations/keymgmt/rsa_kmgmt.c
+++ b/providers/implementations/keymgmt/rsa_kmgmt.c
@@ -434,6 +434,7 @@ struct rsa_gen_ctx {
 #if defined(FIPS_MODULE) && !defined(OPENSSL_NO_ACVP_TESTS)
     /* ACVP test parameters */
     OSSL_PARAM *acvp_test_params;
+    void *prov_rsa_ctx;
 #endif
 };
 
@@ -447,6 +448,12 @@ static int rsa_gencb(int p, int n, BN_GENCB *cb)
     return gctx->cb(params, gctx->cbarg);
 }
 
+#ifdef FIPS_MODULE
+void *rsa_newctx(void *provctx, const char *propq);
+void rsa_freectx(void *vctx);
+int do_rsa_pct(void *, const char *, void *);
+#endif
+
 static void *gen_init(void *provctx, int selection, int rsa_type,
                       const OSSL_PARAM params[])
 {
@@ -474,6 +481,10 @@ static void *gen_init(void *provctx, int selection, int rsa_type,
 
     if (!rsa_gen_set_params(gctx, params))
         goto err;
+#ifdef FIPS_MODULE
+    if (gctx != NULL)
+        gctx->prov_rsa_ctx = rsa_newctx(provctx, NULL);
+#endif
     return gctx;
 
 err:
@@ -630,6 +641,11 @@ static void *rsa_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
 
     rsa = rsa_tmp;
     rsa_tmp = NULL;
+#ifdef FIPS_MODULE
+    /* Pairwise consistency test */
+    if (do_rsa_pct(gctx->prov_rsa_ctx, "sha256", rsa) != 1)
+        abort();
+#endif
  err:
     BN_GENCB_free(gencb);
     RSA_free(rsa_tmp);
@@ -645,6 +661,8 @@ static void rsa_gen_cleanup(void *genctx)
 #if defined(FIPS_MODULE) && !defined(OPENSSL_NO_ACVP_TESTS)
     ossl_rsa_acvp_test_gen_params_free(gctx->acvp_test_params);
     gctx->acvp_test_params = NULL;
+    rsa_freectx(gctx->prov_rsa_ctx);
+    gctx->prov_rsa_ctx = NULL;
 #endif
     BN_clear_free(gctx->pub_exp);
     OPENSSL_free(gctx);
diff --git a/providers/implementations/signature/ecdsa_sig.c b/providers/implementations/signature/ecdsa_sig.c
index 865d49d100..ebeb30e002 100644
--- a/providers/implementations/signature/ecdsa_sig.c
+++ b/providers/implementations/signature/ecdsa_sig.c
@@ -32,7 +32,7 @@
 #include "crypto/ec.h"
 #include "prov/der_ec.h"
 
-static OSSL_FUNC_signature_newctx_fn ecdsa_newctx;
+OSSL_FUNC_signature_newctx_fn ecdsa_newctx;
 static OSSL_FUNC_signature_sign_init_fn ecdsa_sign_init;
 static OSSL_FUNC_signature_verify_init_fn ecdsa_verify_init;
 static OSSL_FUNC_signature_sign_fn ecdsa_sign;
@@ -43,7 +43,7 @@ static OSSL_FUNC_signature_digest_sign_final_fn ecdsa_digest_sign_final;
 static OSSL_FUNC_signature_digest_verify_init_fn ecdsa_digest_verify_init;
 static OSSL_FUNC_signature_digest_verify_update_fn ecdsa_digest_signverify_update;
 static OSSL_FUNC_signature_digest_verify_final_fn ecdsa_digest_verify_final;
-static OSSL_FUNC_signature_freectx_fn ecdsa_freectx;
+OSSL_FUNC_signature_freectx_fn ecdsa_freectx;
 static OSSL_FUNC_signature_dupctx_fn ecdsa_dupctx;
 static OSSL_FUNC_signature_get_ctx_params_fn ecdsa_get_ctx_params;
 static OSSL_FUNC_signature_gettable_ctx_params_fn ecdsa_gettable_ctx_params;
@@ -104,7 +104,7 @@ typedef struct {
     unsigned int nonce_type;
 } PROV_ECDSA_CTX;
 
-static void *ecdsa_newctx(void *provctx, const char *propq)
+void *ecdsa_newctx(void *provctx, const char *propq)
 {
     PROV_ECDSA_CTX *ctx;
 
@@ -370,7 +370,7 @@ int ecdsa_digest_verify_final(void *vctx, const unsigned char *sig,
     return ecdsa_verify(ctx, sig, siglen, digest, (size_t)dlen);
 }
 
-static void ecdsa_freectx(void *vctx)
+void ecdsa_freectx(void *vctx)
 {
     PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
 
@@ -581,6 +581,35 @@ static const OSSL_PARAM *ecdsa_settable_ctx_md_params(void *vctx)
     return EVP_MD_settable_ctx_params(ctx->md);
 }
 
+#ifdef FIPS_MODULE
+int do_ec_pct(void *vctx, const char *mdname, void *ec)
+{
+    static const unsigned char data[32];
+    unsigned char sigbuf[256];
+    size_t siglen = sizeof(sigbuf);
+
+    if (ecdsa_digest_sign_init(vctx, mdname, ec, NULL) <= 0)
+        return 0;
+
+    if (ecdsa_digest_signverify_update(vctx, data, sizeof(data)) <= 0)
+        return 0;
+
+    if (ecdsa_digest_sign_final(vctx, sigbuf, &siglen, sizeof(sigbuf)) <= 0)
+        return 0;
+
+    if (ecdsa_digest_verify_init(vctx, mdname, ec, NULL) <= 0)
+        return 0;
+
+    if (ecdsa_digest_signverify_update(vctx, data, sizeof(data)) <= 0)
+        return 0;
+
+    if (ecdsa_digest_verify_final(vctx, sigbuf, siglen) <= 0)
+        return 0;
+
+    return 1;
+}
+#endif
+
 const OSSL_DISPATCH ossl_ecdsa_signature_functions[] = {
     { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))ecdsa_newctx },
     { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))ecdsa_sign_init },
diff --git a/providers/implementations/signature/rsa_sig.c b/providers/implementations/signature/rsa_sig.c
index cd5de6bd51..d4261e8f7d 100644
--- a/providers/implementations/signature/rsa_sig.c
+++ b/providers/implementations/signature/rsa_sig.c
@@ -34,7 +34,7 @@
 
 #define RSA_DEFAULT_DIGEST_NAME OSSL_DIGEST_NAME_SHA1
 
-static OSSL_FUNC_signature_newctx_fn rsa_newctx;
+OSSL_FUNC_signature_newctx_fn rsa_newctx;
 static OSSL_FUNC_signature_sign_init_fn rsa_sign_init;
 static OSSL_FUNC_signature_verify_init_fn rsa_verify_init;
 static OSSL_FUNC_signature_verify_recover_init_fn rsa_verify_recover_init;
@@ -47,7 +47,7 @@ static OSSL_FUNC_signature_digest_sign_final_fn rsa_digest_sign_final;
 static OSSL_FUNC_signature_digest_verify_init_fn rsa_digest_verify_init;
 static OSSL_FUNC_signature_digest_verify_update_fn rsa_digest_signverify_update;
 static OSSL_FUNC_signature_digest_verify_final_fn rsa_digest_verify_final;
-static OSSL_FUNC_signature_freectx_fn rsa_freectx;
+OSSL_FUNC_signature_freectx_fn rsa_freectx;
 static OSSL_FUNC_signature_dupctx_fn rsa_dupctx;
 static OSSL_FUNC_signature_get_ctx_params_fn rsa_get_ctx_params;
 static OSSL_FUNC_signature_gettable_ctx_params_fn rsa_gettable_ctx_params;
@@ -170,7 +170,7 @@ static int rsa_check_parameters(PROV_RSA_CTX *prsactx, int min_saltlen)
     return 1;
 }
 
-static void *rsa_newctx(void *provctx, const char *propq)
+void *rsa_newctx(void *provctx, const char *propq)
 {
     PROV_RSA_CTX *prsactx = NULL;
     char *propq_copy = NULL;
@@ -977,7 +977,7 @@ int rsa_digest_verify_final(void *vprsactx, const unsigned char *sig,
     return rsa_verify(vprsactx, sig, siglen, digest, (size_t)dlen);
 }
 
-static void rsa_freectx(void *vprsactx)
+void rsa_freectx(void *vprsactx)
 {
     PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
 
@@ -1455,6 +1455,45 @@ static const OSSL_PARAM *rsa_settable_ctx_md_params(void *vprsactx)
     return EVP_MD_settable_ctx_params(prsactx->md);
 }
 
+#ifdef FIPS_MODULE
+int do_rsa_pct(void *vctx, const char *mdname, void *rsa)
+{
+    static const unsigned char data[32];
+    unsigned char *sigbuf = NULL;
+    size_t siglen = 0;
+    int ret = 0;
+
+    if (rsa_digest_sign_init(vctx, mdname, rsa, NULL) <= 0)
+        return 0;
+
+    if (rsa_digest_signverify_update(vctx, data, sizeof(data)) <= 0)
+        return 0;
+
+    if (rsa_digest_sign_final(vctx, NULL, &siglen, 0) <= 0)
+        return 0;
+
+    if ((sigbuf = OPENSSL_malloc(siglen)) == NULL)
+        return 0;
+
+    if (rsa_digest_sign_final(vctx, sigbuf, &siglen, siglen) <= 0)
+        goto err;
+
+    if (rsa_digest_verify_init(vctx, mdname, rsa, NULL) <= 0)
+        goto err;
+
+    if (rsa_digest_signverify_update(vctx, data, sizeof(data)) <= 0)
+        goto err;
+
+    if (rsa_digest_verify_final(vctx, sigbuf, siglen) <= 0)
+        goto err;
+    ret = 1;
+
+ err:
+    OPENSSL_free(sigbuf);
+    return ret;
+}
+#endif
+
 const OSSL_DISPATCH ossl_rsa_signature_functions[] = {
     { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))rsa_newctx },
     { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))rsa_sign_init },
diff --git a/crypto/rsa/rsa_gen.c b/crypto/rsa/rsa_gen.c
index e0d139d..35f23b2 100644
--- a/crypto/rsa/rsa_gen.c
+++ b/crypto/rsa/rsa_gen.c
@@ -463,6 +463,9 @@ static int rsa_keygen(OSSL_LIB_CTX *libctx, RSA *rsa, int bits, int primes,
             rsa->dmp1 = NULL;
             rsa->dmq1 = NULL;
             rsa->iqmp = NULL;
+#ifdef FIPS_MODULE
+            abort();
+#endif /* defined(FIPS_MODULE) */
         }
     }
     return ok;
-- 
2.41.0

