Blame SOURCES/libgcrypt-1.10.0-fips-selftest.patch

7682e8
From e62829a907a7179ec6b0d9f47258185860f0a6c0 Mon Sep 17 00:00:00 2001
7682e8
From: Jakub Jelen <jjelen@redhat.com>
7682e8
Date: Tue, 2 Aug 2022 20:53:31 +0200
7682e8
Subject: [PATCH 1/6] Run digest&sign self tests for RSA and ECC in FIPS mode
7682e8
7682e8
* cipher/ecc.c (selftest_hash_sign): Implement digest & sign KAT
7682e8
 (selftests_ecdsa): Run the original basic test only with extended tests
7682e8
 (run_selftests): Pass-through the extended argument
7682e8
* cipher/rsa.c (selftest_hash_sign_2048): Implement digest & sign KAT
7682e8
 (selftests_rsa): Run the original basic test only with extended tests
7682e8
 (run_selftests): Pass-through the extended argument
7682e8
---
7682e8
7682e8
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
7682e8
---
7682e8
 cipher/ecc.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++---
7682e8
 cipher/rsa.c | 108 +++++++++++++++++++++++++++++++++++++---
7682e8
 2 files changed, 234 insertions(+), 12 deletions(-)
7682e8
7682e8
diff --git a/cipher/ecc.c b/cipher/ecc.c
7682e8
index 9f0e7b11..63b0d05e 100644
7682e8
--- a/cipher/ecc.c
7682e8
+++ b/cipher/ecc.c
7682e8
@@ -1678,6 +1678,126 @@ _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec)
7682e8
      Self-test section.
7682e8
  */
7682e8
 
7682e8
+static const char *
7682e8
+selftest_hash_sign (gcry_sexp_t pkey, gcry_sexp_t skey)
7682e8
+{
7682e8
+  int md_algo = GCRY_MD_SHA256;
7682e8
+  gcry_md_hd_t hd = NULL;
7682e8
+  const char *data_tmpl = "(data (flags rfc6979) (hash %s %b))";
7682e8
+  /* Sample data from RFC 6979 section A.2.5, hash is of message "sample" */
7682e8
+  static const char sample_data[] = "sample";
7682e8
+  static const char sample_data_bad[] = "sbmple";
7682e8
+  static const char signature_r[] =
7682e8
+    "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716";
7682e8
+  static const char signature_s[] =
7682e8
+    "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8";
7682e8
+
7682e8
+  const char *errtxt = NULL;
7682e8
+  gcry_error_t err;
7682e8
+  gcry_sexp_t sig = NULL;
7682e8
+  gcry_sexp_t l1 = NULL;
7682e8
+  gcry_sexp_t l2 = NULL;
7682e8
+  gcry_mpi_t r = NULL;
7682e8
+  gcry_mpi_t s = NULL;
7682e8
+  gcry_mpi_t calculated_r = NULL;
7682e8
+  gcry_mpi_t calculated_s = NULL;
7682e8
+  int cmp;
7682e8
+
7682e8
+  err = _gcry_md_open (&hd, md_algo, 0);
7682e8
+  if (err)
7682e8
+    {
7682e8
+      errtxt = "gcry_md_open failed";
7682e8
+      goto leave;
7682e8
+    }
7682e8
+
7682e8
+  _gcry_md_write (hd, sample_data, strlen(sample_data));
7682e8
+
7682e8
+  err = _gcry_mpi_scan (&r, GCRYMPI_FMT_HEX, signature_r, 0, NULL);
7682e8
+  if (!err)
7682e8
+    err = _gcry_mpi_scan (&s, GCRYMPI_FMT_HEX, signature_s, 0, NULL);
7682e8
+
7682e8
+  if (err)
7682e8
+    {
7682e8
+      errtxt = "converting data failed";
7682e8
+      goto leave;
7682e8
+    }
7682e8
+
7682e8
+  err = _gcry_pk_sign_md (&sig, data_tmpl, hd, skey, NULL);
7682e8
+  if (err)
7682e8
+    {
7682e8
+      errtxt = "signing failed";
7682e8
+      goto leave;
7682e8
+    }
7682e8
+
7682e8
+  /* check against known signature */
7682e8
+  errtxt = "signature validity failed";
7682e8
+  l1 = _gcry_sexp_find_token (sig, "sig-val", 0);
7682e8
+  if (!l1)
7682e8
+    goto leave;
7682e8
+  l2 = _gcry_sexp_find_token (l1, "ecdsa", 0);
7682e8
+  if (!l2)
7682e8
+    goto leave;
7682e8
+
7682e8
+  sexp_release (l1);
7682e8
+  l1 = l2;
7682e8
+
7682e8
+  l2 = _gcry_sexp_find_token (l1, "r", 0);
7682e8
+  if (!l2)
7682e8
+    goto leave;
7682e8
+  calculated_r = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
7682e8
+  if (!calculated_r)
7682e8
+    goto leave;
7682e8
+
7682e8
+  sexp_release (l2);
7682e8
+  l2 = _gcry_sexp_find_token (l1, "s", 0);
7682e8
+  if (!l2)
7682e8
+    goto leave;
7682e8
+  calculated_s = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
7682e8
+  if (!calculated_s)
7682e8
+    goto leave;
7682e8
+
7682e8
+  errtxt = "known sig check failed";
7682e8
+
7682e8
+  cmp = _gcry_mpi_cmp (r, calculated_r);
7682e8
+  if (cmp)
7682e8
+    goto leave;
7682e8
+  cmp = _gcry_mpi_cmp (s, calculated_s);
7682e8
+  if (cmp)
7682e8
+    goto leave;
7682e8
+
7682e8
+  errtxt = NULL;
7682e8
+
7682e8
+  /* verify generated signature */
7682e8
+  err = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL);
7682e8
+  if (err)
7682e8
+    {
7682e8
+      errtxt = "verify failed";
7682e8
+      goto leave;
7682e8
+    }
7682e8
+
7682e8
+  _gcry_md_reset(hd);
7682e8
+  _gcry_md_write (hd, sample_data_bad, strlen(sample_data_bad));
7682e8
+  err = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL);
7682e8
+  if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE)
7682e8
+    {
7682e8
+      errtxt = "bad signature not detected";
7682e8
+      goto leave;
7682e8
+    }
7682e8
+
7682e8
+
7682e8
+ leave:
7682e8
+  _gcry_md_close (hd);
7682e8
+  sexp_release (sig);
7682e8
+  sexp_release (l1);
7682e8
+  sexp_release (l2);
7682e8
+  mpi_release (r);
7682e8
+  mpi_release (s);
7682e8
+  mpi_release (calculated_r);
7682e8
+  mpi_release (calculated_s);
7682e8
+  return errtxt;
7682e8
+}
7682e8
+
7682e8
+
7682e8
 static const char *
7682e8
 selftest_sign (gcry_sexp_t pkey, gcry_sexp_t skey)
7682e8
 {
7682e8
@@ -1798,7 +1918,7 @@ selftest_sign (gcry_sexp_t pkey, gcry_sexp_t skey)
7682e8
 
7682e8
 
7682e8
 static gpg_err_code_t
7682e8
-selftests_ecdsa (selftest_report_func_t report)
7682e8
+selftests_ecdsa (selftest_report_func_t report, int extended)
7682e8
 {
7682e8
   const char *what;
7682e8
   const char *errtxt;
7682e8
@@ -1826,8 +1946,16 @@ selftests_ecdsa (selftest_report_func_t report)
7682e8
       goto failed;
7682e8
     }
7682e8
 
7682e8
-  what = "sign";
7682e8
-  errtxt = selftest_sign (pkey, skey);
7682e8
+  if (extended)
7682e8
+    {
7682e8
+      what = "sign";
7682e8
+      errtxt = selftest_sign (pkey, skey);
7682e8
+      if (errtxt)
7682e8
+        goto failed;
7682e8
+    }
7682e8
+
7682e8
+  what = "digest sign";
7682e8
+  errtxt = selftest_hash_sign (pkey, skey);
7682e8
   if (errtxt)
7682e8
     goto failed;
7682e8
 
7682e8
@@ -1848,12 +1976,10 @@ selftests_ecdsa (selftest_report_func_t report)
7682e8
 static gpg_err_code_t
7682e8
 run_selftests (int algo, int extended, selftest_report_func_t report)
7682e8
 {
7682e8
-  (void)extended;
7682e8
-
7682e8
   if (algo != GCRY_PK_ECC)
7682e8
     return GPG_ERR_PUBKEY_ALGO;
7682e8
 
7682e8
-  return selftests_ecdsa (report);
7682e8
+  return selftests_ecdsa (report, extended);
7682e8
 }
7682e8
 
7682e8
 
7682e8
diff --git a/cipher/rsa.c b/cipher/rsa.c
7682e8
index 9f2b36e8..34c8e490 100644
7682e8
--- a/cipher/rsa.c
7682e8
+++ b/cipher/rsa.c
7682e8
@@ -1760,6 +1760,96 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam)
7682e8
      Self-test section.
7682e8
  */
7682e8
 
7682e8
+static const char *
7682e8
+selftest_hash_sign_2048 (gcry_sexp_t pkey, gcry_sexp_t skey)
7682e8
+{
7682e8
+  int md_algo = GCRY_MD_SHA256;
7682e8
+  gcry_md_hd_t hd = NULL;
7682e8
+  const char *data_tmpl = "(data (flags pkcs1) (hash %s %b))";
7682e8
+  static const char sample_data[] =
7682e8
+    "11223344556677889900aabbccddeeff"
7682e8
+    "102030405060708090a0b0c0d0f01121";
7682e8
+  static const char sample_data_bad[] =
7682e8
+    "11223344556677889900aabbccddeeff"
7682e8
+    "802030405060708090a0b0c0d0f01121";
7682e8
+
7682e8
+  const char *errtxt = NULL;
7682e8
+  gcry_error_t err;
7682e8
+  gcry_sexp_t sig = NULL;
7682e8
+  /* raw signature data reference */
7682e8
+  const char ref_data[] =
7682e8
+    "518f41dea3ad884e93eefff8d7ca68a6f4c30d923632e35673651d675cebd652"
7682e8
+    "a44ed66f6879b18f3d48b2d235b1dd78f6189be1440352cc94231a55c1f93109"
7682e8
+    "84616b2841c42fe9a6e37be34cd188207209bd028e2fa93e721fbac40c31a068"
7682e8
+    "1253b312d4e07addb9c7f3d508fa89f218ea7c7f7b9f6a9b1e522c19fa1cd839"
7682e8
+    "93f9d4ca2f16c3d0b9abafe5e63e848152afc72ce7ee19ea45353116f85209ea"
7682e8
+    "b9de42129dbccdac8faa461e8e8cc2ae801101cc6add4ba76ccb752030b0e827"
7682e8
+    "7352b11cdecebae9cdc9a626c4701cd9c85cd287618888c5fae8b4d0ba48915d"
7682e8
+    "e5cc64e3aee2ba2862d04348ea71f65454f74f9fd1e3108005cc367ca41585a4";
7682e8
+  gcry_mpi_t ref_mpi = NULL;
7682e8
+  gcry_mpi_t sig_mpi = NULL;
7682e8
+
7682e8
+  err = _gcry_md_open (&hd, md_algo, 0);
7682e8
+  if (err)
7682e8
+    {
7682e8
+      errtxt = "gcry_md_open failed";
7682e8
+      goto leave;
7682e8
+    }
7682e8
+
7682e8
+  _gcry_md_write (hd, sample_data, sizeof(sample_data));
7682e8
+
7682e8
+  err = _gcry_pk_sign_md (&sig, data_tmpl, hd, skey, NULL);
7682e8
+  if (err)
7682e8
+    {
7682e8
+      errtxt = "signing failed";
7682e8
+      goto leave;
7682e8
+    }
7682e8
+
7682e8
+  err = _gcry_mpi_scan(&ref_mpi, GCRYMPI_FMT_HEX, ref_data, 0, NULL);
7682e8
+  if (err)
7682e8
+    {
7682e8
+      errtxt = "converting ref_data to mpi failed";
7682e8
+      goto leave;
7682e8
+    }
7682e8
+
7682e8
+  err = _gcry_sexp_extract_param(sig, "sig-val!rsa", "s", &sig_mpi, NULL);
7682e8
+  if (err)
7682e8
+    {
7682e8
+      errtxt = "extracting signature data failed";
7682e8
+      goto leave;
7682e8
+    }
7682e8
+
7682e8
+  if (mpi_cmp (sig_mpi, ref_mpi))
7682e8
+    {
7682e8
+      errtxt = "signature does not match reference data";
7682e8
+      goto leave;
7682e8
+    }
7682e8
+
7682e8
+  err = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL);
7682e8
+  if (err)
7682e8
+    {
7682e8
+      errtxt = "verify failed";
7682e8
+      goto leave;
7682e8
+    }
7682e8
+
7682e8
+  _gcry_md_reset(hd);
7682e8
+  _gcry_md_write (hd, sample_data_bad, sizeof(sample_data_bad));
7682e8
+  err = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL);
7682e8
+  if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE)
7682e8
+    {
7682e8
+      errtxt = "bad signature not detected";
7682e8
+      goto leave;
7682e8
+    }
7682e8
+
7682e8
+
7682e8
+ leave:
7682e8
+  sexp_release (sig);
7682e8
+  _gcry_md_close (hd);
7682e8
+  _gcry_mpi_release (ref_mpi);
7682e8
+  _gcry_mpi_release (sig_mpi);
7682e8
+  return errtxt;
7682e8
+}
7682e8
+
7682e8
 static const char *
7682e8
 selftest_sign_2048 (gcry_sexp_t pkey, gcry_sexp_t skey)
7682e8
 {
7682e8
@@ -1996,7 +2086,7 @@ selftest_encr_2048 (gcry_sexp_t pkey, gcry_sexp_t skey)
7682e8
 
7682e8
 
7682e8
 static gpg_err_code_t
7682e8
-selftests_rsa (selftest_report_func_t report)
7682e8
+selftests_rsa (selftest_report_func_t report, int extended)
7682e8
 {
7682e8
   const char *what;
7682e8
   const char *errtxt;
7682e8
@@ -2024,8 +2114,16 @@ selftests_rsa (selftest_report_func_t report)
7682e8
       goto failed;
7682e8
     }
7682e8
 
7682e8
-  what = "sign";
7682e8
-  errtxt = selftest_sign_2048 (pkey, skey);
7682e8
+  if (extended)
7682e8
+    {
7682e8
+      what = "sign";
7682e8
+      errtxt = selftest_sign_2048 (pkey, skey);
7682e8
+      if (errtxt)
7682e8
+        goto failed;
7682e8
+    }
7682e8
+
7682e8
+  what = "digest sign";
7682e8
+  errtxt = selftest_hash_sign_2048 (pkey, skey);
7682e8
   if (errtxt)
7682e8
     goto failed;
7682e8
 
7682e8
@@ -2053,12 +2151,10 @@ run_selftests (int algo, int extended, selftest_report_func_t report)
7682e8
 {
7682e8
   gpg_err_code_t ec;
7682e8
 
7682e8
-  (void)extended;
7682e8
-
7682e8
   switch (algo)
7682e8
     {
7682e8
     case GCRY_PK_RSA:
7682e8
-      ec = selftests_rsa (report);
7682e8
+      ec = selftests_rsa (report, extended);
7682e8
       break;
7682e8
     default:
7682e8
       ec = GPG_ERR_PUBKEY_ALGO;
7682e8
-- 
7682e8
2.37.1
7682e8
7682e8
7682e8
From b386e9862e7c3c0f6623fb1c43b0cf0481bbebc7 Mon Sep 17 00:00:00 2001
7682e8
From: Jakub Jelen <jjelen@redhat.com>
7682e8
Date: Mon, 8 Aug 2022 13:50:15 +0200
7682e8
Subject: [PATCH 2/6] fips: Add function-name based FIPS indicator
7682e8
7682e8
* doc/gcrypt.texi: Document the new function-based fips indicator
7682e8
  GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION
7682e8
* src/fips.c (_gcry_fips_indicator_function): New function indicating
7682e8
  non-approved functions.
7682e8
* src/gcrypt.h.in (enum gcry_ctl_cmds): New symbol
7682e8
  GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION
7682e8
* src/global.c (_gcry_vcontrol): Handle new FIPS indicator.
7682e8
---
7682e8
7682e8
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
7682e8
---
7682e8
 doc/gcrypt.texi |  7 +++++++
7682e8
 src/fips.c      | 12 ++++++++++++
7682e8
 src/g10lib.h    |  1 +
7682e8
 src/gcrypt.h.in |  3 ++-
7682e8
 src/global.c    |  7 +++++++
7682e8
 5 files changed, 29 insertions(+), 1 deletion(-)
7682e8
7682e8
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
7682e8
index f2c1cc94..b608dba2 100644
7682e8
--- a/doc/gcrypt.texi
7682e8
+++ b/doc/gcrypt.texi
7682e8
@@ -995,6 +995,13 @@ certification. If the KDF is approved, this function returns
7682e8
 @code{GPG_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED}
7682e8
 is returned.
7682e8
 
7682e8
+@item GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION; Arguments: const char *
7682e8
+
7682e8
+Check if the given function is approved under the current FIPS 140-3
7682e8
+certification. If the function is approved, this function returns
7682e8
+@code{GPG_ERR_NO_ERROR} (other restrictions might still apply).
7682e8
+Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned.
7682e8
+
7682e8
 @end table
7682e8
 
7682e8
 @end deftypefun
7682e8
diff --git a/src/fips.c b/src/fips.c
7682e8
index a1958b14..9a524ea4 100644
7682e8
--- a/src/fips.c
7682e8
+++ b/src/fips.c
7682e8
@@ -390,6 +390,18 @@ _gcry_fips_indicator_kdf (va_list arg_ptr)
7682e8
     }
7682e8
 }
7682e8
 
7682e8
+int
7682e8
+_gcry_fips_indicator_function (va_list arg_ptr)
7682e8
+{
7682e8
+  const char *function = va_arg (arg_ptr, const char *);
7682e8
+
7682e8
+  if (strcmp (function, "gcry_sign") == 0 ||
7682e8
+      strcmp (function, "gcry_verify") == 0)
7682e8
+    return GPG_ERR_NOT_SUPPORTED;
7682e8
+
7682e8
+  return GPG_ERR_NO_ERROR;
7682e8
+}
7682e8
+
7682e8
 
7682e8
 /* This is a test on whether the library is in the error or
7682e8
    operational state. */
7682e8
diff --git a/src/g10lib.h b/src/g10lib.h
7682e8
index 8ba0a5c2..eff6295f 100644
7682e8
--- a/src/g10lib.h
7682e8
+++ b/src/g10lib.h
7682e8
@@ -468,6 +468,7 @@ void _gcry_fips_signal_error (const char *srcfile,
7682e8
 
7682e8
 int _gcry_fips_indicator_cipher (va_list arg_ptr);
7682e8
 int _gcry_fips_indicator_kdf (va_list arg_ptr);
7682e8
+int _gcry_fips_indicator_function (va_list arg_ptr);
7682e8
 
7682e8
 int _gcry_fips_is_operational (void);
7682e8
 
7682e8
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
7682e8
index 299261db..d6a1d516 100644
7682e8
--- a/src/gcrypt.h.in
7682e8
+++ b/src/gcrypt.h.in
7682e8
@@ -329,7 +329,8 @@ enum gcry_ctl_cmds
7682e8
     GCRYCTL_SET_DECRYPTION_TAG = 80,
7682e8
     GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER = 81,
7682e8
     GCRYCTL_FIPS_SERVICE_INDICATOR_KDF = 82,
7682e8
-    GCRYCTL_NO_FIPS_MODE = 83
7682e8
+    GCRYCTL_NO_FIPS_MODE = 83,
7682e8
+    GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION = 84
7682e8
   };
7682e8
 
7682e8
 /* Perform various operations defined by CMD. */
7682e8
diff --git a/src/global.c b/src/global.c
7682e8
index 258ea4d1..debf6194 100644
7682e8
--- a/src/global.c
7682e8
+++ b/src/global.c
7682e8
@@ -797,6 +797,13 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
7682e8
       rc = _gcry_fips_indicator_kdf (arg_ptr);
7682e8
       break;
7682e8
 
7682e8
+    case GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION:
7682e8
+      /* Get FIPS Service Indicator for a given function from the API.
7682e8
+       * Returns GPG_ERR_NO_ERROR if the function is allowed or
7682e8
+       * GPG_ERR_NOT_SUPPORTED otherwise */
7682e8
+      rc = _gcry_fips_indicator_function (arg_ptr);
7682e8
+      break;
7682e8
+
7682e8
     case PRIV_CTL_INIT_EXTRNG_TEST:  /* Init external random test.  */
7682e8
       rc = GPG_ERR_NOT_SUPPORTED;
7682e8
       break;
7682e8
-- 
7682e8
2.37.1
7682e8
7682e8
7682e8
From 756cdfaf30c2b12d2b2a931591089b1de22444f4 Mon Sep 17 00:00:00 2001
7682e8
From: Jakub Jelen <jjelen@redhat.com>
7682e8
Date: Mon, 8 Aug 2022 15:58:16 +0200
7682e8
Subject: [PATCH 4/6] rsa: Run PCT in FIPS mode also with digest step
7682e8
7682e8
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
7682e8
---
7682e8
 cipher/rsa.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++-
7682e8
 1 file changed, 68 insertions(+), 1 deletion(-)
7682e8
7682e8
diff --git a/cipher/rsa.c b/cipher/rsa.c
7682e8
index 6e7be8e8..78c26f2f 100644
7682e8
--- a/cipher/rsa.c
7682e8
+++ b/cipher/rsa.c
7682e8
@@ -177,6 +177,73 @@ test_keys (RSA_secret_key *sk, unsigned int nbits)
7682e8
   return result;
7682e8
 }
7682e8
 
7682e8
+static int
7682e8
+test_keys_fips (RSA_secret_key *sk)
7682e8
+{
7682e8
+  int result = -1; /* Default to failure.  */
7682e8
+  char plaintext[128];
7682e8
+  gcry_sexp_t sig = NULL;
7682e8
+  gcry_sexp_t skey = NULL, pkey = NULL;
7682e8
+  const char *data_tmpl = "(data (flags pkcs1) (hash %s %b))";
7682e8
+  gcry_md_hd_t hd = NULL;
7682e8
+  int ec;
7682e8
+
7682e8
+  /* Put the relevant parameters into a public key structure.  */
7682e8
+  ec = sexp_build (&pkey, NULL,
7682e8
+                   "(key-data"
7682e8
+                   " (public-key"
7682e8
+                   "  (rsa(n%m)(e%m))))",
7682e8
+                   sk->n, sk->e);
7682e8
+  if (ec)
7682e8
+    goto leave;
7682e8
+
7682e8
+  /* Put the relevant parameters into a secret key structure.  */
7682e8
+  ec = sexp_build (&skey, NULL,
7682e8
+                   "(key-data"
7682e8
+                   " (public-key"
7682e8
+                   "  (rsa(n%m)(e%m)))"
7682e8
+                   " (private-key"
7682e8
+                   "  (rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))",
7682e8
+                   sk->n, sk->e,
7682e8
+                   sk->n, sk->e, sk->d, sk->p, sk->q, sk->u);
7682e8
+  if (ec)
7682e8
+    goto leave;
7682e8
+
7682e8
+  /* Create a random plaintext.  */
7682e8
+  _gcry_randomize (plaintext, sizeof plaintext, GCRY_WEAK_RANDOM);
7682e8
+
7682e8
+  /* Open MD context and feed the random data in */
7682e8
+  ec = _gcry_md_open (&hd, GCRY_MD_SHA256, 0);
7682e8
+  if (ec)
7682e8
+    goto leave;
7682e8
+  _gcry_md_write (hd, plaintext, sizeof(plaintext));
7682e8
+
7682e8
+  /* Use the RSA secret function to create a signature of the plaintext.  */
7682e8
+  ec = _gcry_pk_sign_md (&sig, data_tmpl, hd, skey, NULL);
7682e8
+  if (ec)
7682e8
+    goto leave;
7682e8
+
7682e8
+  /* Use the RSA public function to verify this signature.  */
7682e8
+  ec = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL);
7682e8
+  if (ec)
7682e8
+    goto leave;
7682e8
+
7682e8
+  /* Modify the data and check that the signing fails.  */
7682e8
+  _gcry_md_reset(hd);
7682e8
+  plaintext[sizeof plaintext / 2] ^= 1;
7682e8
+  _gcry_md_write (hd, plaintext, sizeof(plaintext));
7682e8
+  ec = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL);
7682e8
+  if (ec != GPG_ERR_BAD_SIGNATURE)
7682e8
+    goto leave; /* Signature verification worked on modified data  */
7682e8
+
7682e8
+  result = 0; /* All tests succeeded.  */
7682e8
+ leave:
7682e8
+  sexp_release (sig);
7682e8
+  _gcry_md_close (hd);
7682e8
+  sexp_release (pkey);
7682e8
+  sexp_release (skey);
7682e8
+  return result;
7682e8
+}
7682e8
 
7682e8
 /* Callback used by the prime generation to test whether the exponent
7682e8
    is suitable. Returns 0 if the test has been passed. */
7682e8
@@ -648,7 +715,7 @@ generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e,
7682e8
   sk->u = u;
7682e8
 
7682e8
   /* Now we can test our keys. */
7682e8
-  if (ec || (!testparms && test_keys (sk, nbits - 64)))
7682e8
+  if (ec || (!testparms && test_keys_fips (sk)))
7682e8
     {
7682e8
       _gcry_mpi_release (sk->n); sk->n = NULL;
7682e8
       _gcry_mpi_release (sk->e); sk->e = NULL;
7682e8
-- 
7682e8
2.37.1
7682e8
7682e8
7682e8
From de7ad6375be11a0cef45c6e9aa8119c4ce7a3258 Mon Sep 17 00:00:00 2001
7682e8
From: Jakub Jelen <jjelen@redhat.com>
7682e8
Date: Mon, 15 Aug 2022 19:55:33 +0200
7682e8
Subject: [PATCH 5/6] ecc: Run PCT also with the digest step
7682e8
7682e8
* cipher/ecc.c (test_keys_fips): New function
7682e8
  (nist_generate_key): In FIPS mode, execute new PCT test
7682e8
---
7682e8
7682e8
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
7682e8
---
7682e8
 cipher/ecc.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++
7682e8
 1 file changed, 81 insertions(+)
7682e8
7682e8
diff --git a/cipher/ecc.c b/cipher/ecc.c
7682e8
index 63b0d05e..783e249d 100644
7682e8
--- a/cipher/ecc.c
7682e8
+++ b/cipher/ecc.c
7682e8
@@ -101,6 +101,7 @@ static void *progress_cb_data;
7682e8
 
7682e8
 /* Local prototypes. */
7682e8
 static void test_keys (mpi_ec_t ec, unsigned int nbits);
7682e8
+static void test_keys_fips (mpi_ec_t ec, gcry_mpi_t x, gcry_mpi_t y);
7682e8
 static void test_ecdh_only_keys (mpi_ec_t ec, unsigned int nbits, int flags);
7682e8
 static unsigned int ecc_get_nbits (gcry_sexp_t parms);
7682e8
 
7682e8
@@ -255,6 +256,8 @@ nist_generate_key (mpi_ec_t ec, int flags,
7682e8
     ; /* User requested to skip the test.  */
7682e8
   else if (ec->model == MPI_EC_MONTGOMERY)
7682e8
     test_ecdh_only_keys (ec, ec->nbits - 63, flags);
7682e8
+  else if (fips_mode ())
7682e8
+    test_keys_fips (ec, x, y);
7682e8
   else
7682e8
     test_keys (ec, ec->nbits - 64);
7682e8
 
7682e8
@@ -304,6 +307,84 @@ test_keys (mpi_ec_t ec, unsigned int nbits)
7682e8
   mpi_free (test);
7682e8
 }
7682e8
 
7682e8
+/* We should get here only with the NIST curves as they are the only ones
7682e8
+ * having the fips bit set in ecc_domain_parms_t struct so this is slightly
7682e8
+ * simpler than the whole ecc_generate function */
7682e8
+static void
7682e8
+test_keys_fips (mpi_ec_t ec, gcry_mpi_t Qx, gcry_mpi_t Qy)
7682e8
+{
7682e8
+  gcry_md_hd_t hd = NULL;
7682e8
+  const char *data_tmpl = "(data (flags rfc6979) (hash %s %b))";
7682e8
+  gcry_sexp_t skey = NULL, pkey = NULL;
7682e8
+  gcry_sexp_t curve_info = NULL;
7682e8
+  gcry_sexp_t sig = NULL;
7682e8
+  gcry_mpi_t public = NULL;
7682e8
+  char plaintext[128];
7682e8
+  int rc;
7682e8
+
7682e8
+  /* Build keys structures */
7682e8
+  if (ec->name)
7682e8
+    {
7682e8
+      rc = sexp_build (&curve_info, NULL, "(curve %s)", ec->name);
7682e8
+      if (rc)
7682e8
+        log_fatal ("ECDSA operation: failed to build curve_info\n");
7682e8
+    }
7682e8
+
7682e8
+  public = _gcry_ecc_ec2os (Qx, Qy, ec->p);
7682e8
+  rc = sexp_build (&pkey, NULL,
7682e8
+                   "(key-data"
7682e8
+                   " (public-key"
7682e8
+                   "  (ecc%S(q%m)))"
7682e8
+                   " )",
7682e8
+                   curve_info,
7682e8
+                   public);
7682e8
+  if (rc)
7682e8
+    log_fatal ("ECDSA operation: failed to build public key: %s\n", gpg_strerror (rc));
7682e8
+  rc = sexp_build (&skey, NULL,
7682e8
+                   "(key-data"
7682e8
+                   " (private-key"
7682e8
+                   "  (ecc%S(q%m)(d%m)))"
7682e8
+                   " )",
7682e8
+                   curve_info,
7682e8
+                   public, ec->d);
7682e8
+  if (rc)
7682e8
+    log_fatal ("ECDSA operation: failed to build private key: %s\n", gpg_strerror (rc));
7682e8
+
7682e8
+  /* Create a random plaintext.  */
7682e8
+  _gcry_randomize (plaintext, sizeof plaintext, GCRY_WEAK_RANDOM);
7682e8
+
7682e8
+  /* Open MD context and feed the random data in */
7682e8
+  rc = _gcry_md_open (&hd, GCRY_MD_SHA256, 0);
7682e8
+  if (rc)
7682e8
+    log_fatal ("ECDSA operation: failed to initialize MD context: %s\n", gpg_strerror (rc));
7682e8
+  _gcry_md_write (hd, plaintext, sizeof(plaintext));
7682e8
+
7682e8
+  /* Sign the data */
7682e8
+  rc = _gcry_pk_sign_md (&sig, data_tmpl, hd, skey, NULL);
7682e8
+  if (rc)
7682e8
+    log_fatal ("ECDSA operation: signing failed: %s\n", gpg_strerror (rc));
7682e8
+
7682e8
+  /* Verify this signature.  */
7682e8
+  rc = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL);
7682e8
+  if (rc)
7682e8
+    log_fatal ("ECDSA operation: verification failed: %s\n", gpg_strerror (rc));
7682e8
+
7682e8
+  /* Modify the data and check that the signing fails.  */
7682e8
+  _gcry_md_reset(hd);
7682e8
+  plaintext[sizeof plaintext / 2] ^= 1;
7682e8
+  _gcry_md_write (hd, plaintext, sizeof(plaintext));
7682e8
+  rc = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL);
7682e8
+  if (rc != GPG_ERR_BAD_SIGNATURE)
7682e8
+    log_fatal ("ECDSA operation: signature verification worked on modified data\n");
7682e8
+
7682e8
+  mpi_free (public);
7682e8
+  sexp_release (curve_info);
7682e8
+  _gcry_md_close (hd);
7682e8
+  sexp_release (pkey);
7682e8
+  sexp_release (skey);
7682e8
+  sexp_release (sig);
7682e8
+}
7682e8
+
7682e8
 
7682e8
 static void
7682e8
 test_ecdh_only_keys (mpi_ec_t ec, unsigned int nbits, int flags)
7682e8
-- 
7682e8
2.37.1
7682e8
7682e8
7682e8
From 2cca95e488d58ae79975dd867e7782504b155212 Mon Sep 17 00:00:00 2001
7682e8
From: Jakub Jelen <jjelen@redhat.com>
7682e8
Date: Tue, 16 Aug 2022 10:27:46 +0200
7682e8
Subject: [PATCH 6/6] Simplify the PCT for RSA and ECDSA
7682e8
7682e8
Could be squashed.
7682e8
7682e8
* cipher/ecc.c (test_keys_fips): Simplify to accept key in SEXP format
7682e8
  (nist_generate_key): Skip call to test keys
7682e8
  (ecc_generate): Call test keys in FIPS mode later, when we have
7682e8
  complete SEXP key structure.
7682e8
* cipher/rsa.c (test_keys_fips): Simplify to accept key in SEXP format
7682e8
  (generate_fips): Skip selftest at this stage
7682e8
  (rsa_generate): Test the keys later when we already have key in SEXP
7682e8
  format
7682e8
---
7682e8
7682e8
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
7682e8
---
7682e8
 cipher/ecc.c | 50 ++++++++------------------------------------------
7682e8
 cipher/rsa.c | 47 ++++++++++++-----------------------------------
7682e8
 2 files changed, 20 insertions(+), 77 deletions(-)
7682e8
7682e8
diff --git a/cipher/ecc.c b/cipher/ecc.c
7682e8
index 783e249d..1e80200e 100644
7682e8
--- a/cipher/ecc.c
7682e8
+++ b/cipher/ecc.c
7682e8
@@ -101,7 +101,7 @@ static void *progress_cb_data;
7682e8
 
7682e8
 /* Local prototypes. */
7682e8
 static void test_keys (mpi_ec_t ec, unsigned int nbits);
7682e8
-static void test_keys_fips (mpi_ec_t ec, gcry_mpi_t x, gcry_mpi_t y);
7682e8
+static void test_keys_fips (gcry_sexp_t skey);
7682e8
 static void test_ecdh_only_keys (mpi_ec_t ec, unsigned int nbits, int flags);
7682e8
 static unsigned int ecc_get_nbits (gcry_sexp_t parms);
7682e8
 
7682e8
@@ -256,9 +256,7 @@ nist_generate_key (mpi_ec_t ec, int flags,
7682e8
     ; /* User requested to skip the test.  */
7682e8
   else if (ec->model == MPI_EC_MONTGOMERY)
7682e8
     test_ecdh_only_keys (ec, ec->nbits - 63, flags);
7682e8
-  else if (fips_mode ())
7682e8
-    test_keys_fips (ec, x, y);
7682e8
-  else
7682e8
+  else if (!fips_mode ())
7682e8
     test_keys (ec, ec->nbits - 64);
7682e8
 
7682e8
   return 0;
7682e8
@@ -311,45 +309,14 @@ test_keys (mpi_ec_t ec, unsigned int nbits)
7682e8
  * having the fips bit set in ecc_domain_parms_t struct so this is slightly
7682e8
  * simpler than the whole ecc_generate function */
7682e8
 static void
7682e8
-test_keys_fips (mpi_ec_t ec, gcry_mpi_t Qx, gcry_mpi_t Qy)
7682e8
+test_keys_fips (gcry_sexp_t skey)
7682e8
 {
7682e8
   gcry_md_hd_t hd = NULL;
7682e8
   const char *data_tmpl = "(data (flags rfc6979) (hash %s %b))";
7682e8
-  gcry_sexp_t skey = NULL, pkey = NULL;
7682e8
-  gcry_sexp_t curve_info = NULL;
7682e8
   gcry_sexp_t sig = NULL;
7682e8
-  gcry_mpi_t public = NULL;
7682e8
   char plaintext[128];
7682e8
   int rc;
7682e8
 
7682e8
-  /* Build keys structures */
7682e8
-  if (ec->name)
7682e8
-    {
7682e8
-      rc = sexp_build (&curve_info, NULL, "(curve %s)", ec->name);
7682e8
-      if (rc)
7682e8
-        log_fatal ("ECDSA operation: failed to build curve_info\n");
7682e8
-    }
7682e8
-
7682e8
-  public = _gcry_ecc_ec2os (Qx, Qy, ec->p);
7682e8
-  rc = sexp_build (&pkey, NULL,
7682e8
-                   "(key-data"
7682e8
-                   " (public-key"
7682e8
-                   "  (ecc%S(q%m)))"
7682e8
-                   " )",
7682e8
-                   curve_info,
7682e8
-                   public);
7682e8
-  if (rc)
7682e8
-    log_fatal ("ECDSA operation: failed to build public key: %s\n", gpg_strerror (rc));
7682e8
-  rc = sexp_build (&skey, NULL,
7682e8
-                   "(key-data"
7682e8
-                   " (private-key"
7682e8
-                   "  (ecc%S(q%m)(d%m)))"
7682e8
-                   " )",
7682e8
-                   curve_info,
7682e8
-                   public, ec->d);
7682e8
-  if (rc)
7682e8
-    log_fatal ("ECDSA operation: failed to build private key: %s\n", gpg_strerror (rc));
7682e8
-
7682e8
   /* Create a random plaintext.  */
7682e8
   _gcry_randomize (plaintext, sizeof plaintext, GCRY_WEAK_RANDOM);
7682e8
 
7682e8
@@ -365,7 +332,7 @@ test_keys_fips (mpi_ec_t ec, gcry_mpi_t Qx, gcry_mpi_t Qy)
7682e8
     log_fatal ("ECDSA operation: signing failed: %s\n", gpg_strerror (rc));
7682e8
 
7682e8
   /* Verify this signature.  */
7682e8
-  rc = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL);
7682e8
+  rc = _gcry_pk_verify_md (sig, data_tmpl, hd, skey, NULL);
7682e8
   if (rc)
7682e8
     log_fatal ("ECDSA operation: verification failed: %s\n", gpg_strerror (rc));
7682e8
 
7682e8
@@ -373,15 +340,11 @@ test_keys_fips (mpi_ec_t ec, gcry_mpi_t Qx, gcry_mpi_t Qy)
7682e8
   _gcry_md_reset(hd);
7682e8
   plaintext[sizeof plaintext / 2] ^= 1;
7682e8
   _gcry_md_write (hd, plaintext, sizeof(plaintext));
7682e8
-  rc = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL);
7682e8
+  rc = _gcry_pk_verify_md (sig, data_tmpl, hd, skey, NULL);
7682e8
   if (rc != GPG_ERR_BAD_SIGNATURE)
7682e8
     log_fatal ("ECDSA operation: signature verification worked on modified data\n");
7682e8
 
7682e8
-  mpi_free (public);
7682e8
-  sexp_release (curve_info);
7682e8
   _gcry_md_close (hd);
7682e8
-  sexp_release (pkey);
7682e8
-  sexp_release (skey);
7682e8
   sexp_release (sig);
7682e8
 }
7682e8
 
7682e8
@@ -714,6 +677,9 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
7682e8
         log_debug ("ecgen result  using Ed25519+EdDSA\n");
7682e8
     }
7682e8
 
7682e8
+  if (!(flags & PUBKEY_FLAG_NO_KEYTEST) && fips_mode ())
7682e8
+    test_keys_fips (*r_skey);
7682e8
+
7682e8
  leave:
7682e8
   mpi_free (public);
7682e8
   mpi_free (base);
7682e8
diff --git a/cipher/rsa.c b/cipher/rsa.c
7682e8
index 78c26f2f..9d14a474 100644
7682e8
--- a/cipher/rsa.c
7682e8
+++ b/cipher/rsa.c
7682e8
@@ -178,37 +178,15 @@ test_keys (RSA_secret_key *sk, unsigned int nbits)
7682e8
 }
7682e8
 
7682e8
 static int
7682e8
-test_keys_fips (RSA_secret_key *sk)
7682e8
+test_keys_fips (gcry_sexp_t skey)
7682e8
 {
7682e8
   int result = -1; /* Default to failure.  */
7682e8
   char plaintext[128];
7682e8
   gcry_sexp_t sig = NULL;
7682e8
-  gcry_sexp_t skey = NULL, pkey = NULL;
7682e8
   const char *data_tmpl = "(data (flags pkcs1) (hash %s %b))";
7682e8
   gcry_md_hd_t hd = NULL;
7682e8
   int ec;
7682e8
 
7682e8
-  /* Put the relevant parameters into a public key structure.  */
7682e8
-  ec = sexp_build (&pkey, NULL,
7682e8
-                   "(key-data"
7682e8
-                   " (public-key"
7682e8
-                   "  (rsa(n%m)(e%m))))",
7682e8
-                   sk->n, sk->e);
7682e8
-  if (ec)
7682e8
-    goto leave;
7682e8
-
7682e8
-  /* Put the relevant parameters into a secret key structure.  */
7682e8
-  ec = sexp_build (&skey, NULL,
7682e8
-                   "(key-data"
7682e8
-                   " (public-key"
7682e8
-                   "  (rsa(n%m)(e%m)))"
7682e8
-                   " (private-key"
7682e8
-                   "  (rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))",
7682e8
-                   sk->n, sk->e,
7682e8
-                   sk->n, sk->e, sk->d, sk->p, sk->q, sk->u);
7682e8
-  if (ec)
7682e8
-    goto leave;
7682e8
-
7682e8
   /* Create a random plaintext.  */
7682e8
   _gcry_randomize (plaintext, sizeof plaintext, GCRY_WEAK_RANDOM);
7682e8
 
7682e8
@@ -224,7 +202,7 @@ test_keys_fips (RSA_secret_key *sk)
7682e8
     goto leave;
7682e8
 
7682e8
   /* Use the RSA public function to verify this signature.  */
7682e8
-  ec = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL);
7682e8
+  ec = _gcry_pk_verify_md (sig, data_tmpl, hd, skey, NULL);
7682e8
   if (ec)
7682e8
     goto leave;
7682e8
 
7682e8
@@ -232,7 +210,7 @@ test_keys_fips (RSA_secret_key *sk)
7682e8
   _gcry_md_reset(hd);
7682e8
   plaintext[sizeof plaintext / 2] ^= 1;
7682e8
   _gcry_md_write (hd, plaintext, sizeof(plaintext));
7682e8
-  ec = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL);
7682e8
+  ec = _gcry_pk_verify_md (sig, data_tmpl, hd, skey, NULL);
7682e8
   if (ec != GPG_ERR_BAD_SIGNATURE)
7682e8
     goto leave; /* Signature verification worked on modified data  */
7682e8
 
7682e8
@@ -240,8 +218,6 @@ test_keys_fips (RSA_secret_key *sk)
7682e8
  leave:
7682e8
   sexp_release (sig);
7682e8
   _gcry_md_close (hd);
7682e8
-  sexp_release (pkey);
7682e8
-  sexp_release (skey);
7682e8
   return result;
7682e8
 }
7682e8
 
7682e8
@@ -714,8 +690,7 @@ generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e,
7682e8
   sk->d = d;
7682e8
   sk->u = u;
7682e8
 
7682e8
-  /* Now we can test our keys. */
7682e8
-  if (ec || (!testparms && test_keys_fips (sk)))
7682e8
+  if (ec)
7682e8
     {
7682e8
       _gcry_mpi_release (sk->n); sk->n = NULL;
7682e8
       _gcry_mpi_release (sk->e); sk->e = NULL;
7682e8
@@ -723,11 +698,6 @@ generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e,
7682e8
       _gcry_mpi_release (sk->q); sk->q = NULL;
7682e8
       _gcry_mpi_release (sk->d); sk->d = NULL;
7682e8
       _gcry_mpi_release (sk->u); sk->u = NULL;
7682e8
-      if (!ec)
7682e8
-        {
7682e8
-          fips_signal_error ("self-test after key generation failed");
7682e8
-          return GPG_ERR_SELFTEST_FAILED;
7682e8
-        }
7682e8
     }
7682e8
 
7682e8
   return ec;
7682e8
@@ -1306,7 +1276,7 @@ rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
7682e8
                      /**/    : NULL);
7682e8
 
7682e8
       /* Generate.  */
7682e8
-      if (deriveparms || fips_mode())
7682e8
+      if (deriveparms || fips_mode ())
7682e8
         {
7682e8
           ec = generate_fips (&sk, nbits, evalue, deriveparms,
7682e8
                               !!(flags & PUBKEY_FLAG_TRANSIENT_KEY));
7682e8
@@ -1341,6 +1311,13 @@ rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
7682e8
   mpi_free (sk.u);
7682e8
   sexp_release (swap_info);
7682e8
 
7682e8
+  if (!ec && fips_mode () && test_keys_fips (*r_skey))
7682e8
+    {
7682e8
+      sexp_release (*r_skey); *r_skey = NULL;
7682e8
+      fips_signal_error ("self-test after key generation failed");
7682e8
+      return GPG_ERR_SELFTEST_FAILED;
7682e8
+    }
7682e8
+
7682e8
   return ec;
7682e8
 }
7682e8
 
7682e8
-- 
7682e8
2.37.1