summaryrefslogtreecommitdiff
path: root/cipher
diff options
context:
space:
mode:
authorVitezslav Cizek <vcizek@suse.com>2015-10-27 14:29:11 +0100
committerWerner Koch <wk@gnupg.org>2016-03-18 15:26:28 +0100
commita242e3d9185e6e2dc13902ea9331131755bbba01 (patch)
tree11679a351ba6f54edf67fc395bf1d3d5ff80f7c5 /cipher
parente40939b2141306238cc30a340b867b60fa4dc2a3 (diff)
downloadlibgcrypt-a242e3d9185e6e2dc13902ea9331131755bbba01.tar.gz
ecc: ECDSA adjustments for FIPS 186-4
* cipher/ecc-curves.c: Unmark curve P-192 for FIPS. * cipher/ecc.c: Add ECDSA self test. * cipher/pubkey-util.c (_gcry_pk_util_init_encoding_ctx): Use SHA-2 in FIPS mode. * tests/fipsdrv.c: Add support for ECDSA signatures. -- Enable ECC in FIPS mode. According to NIST SP 800-131A, curve P-192 and SHA-1 are disallowed for key pair generation and signature generation after 2013. Thanks to Jan Matejek for the patch. Signed-off-by: Vitezslav Cizek <vcizek@suse.com> Minor source code re-formatting by -wk.
Diffstat (limited to 'cipher')
-rw-r--r--cipher/ecc-curves.c2
-rw-r--r--cipher/ecc.c171
-rw-r--r--cipher/pubkey-util.c9
3 files changed, 175 insertions, 7 deletions
diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c
index a74501db..91f29cc7 100644
--- a/cipher/ecc-curves.c
+++ b/cipher/ecc-curves.c
@@ -160,7 +160,7 @@ static const ecc_domain_parms_t domain_parms[] =
},
#endif /*0*/
{
- "NIST P-192", 192, 1,
+ "NIST P-192", 192, 0,
MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
"0xfffffffffffffffffffffffffffffffeffffffffffffffff",
"0xfffffffffffffffffffffffffffffffefffffffffffffffc",
diff --git a/cipher/ecc.c b/cipher/ecc.c
index f65203f5..5b035306 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -73,6 +73,25 @@ static const char *ecc_names[] =
};
+/* Sample NIST P-256 key from RFC 6979 A.2.5 */
+static const char sample_public_key_secp256[] =
+ "(public-key"
+ " (ecc"
+ " (curve secp256r1)"
+ " (q #04"
+ /**/ "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6"
+ /**/ "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299#)))";
+
+static const char sample_secret_key_secp256[] =
+ "(private-key"
+ " (ecc"
+ " (curve secp256r1)"
+ " (d #C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721#)"
+ " (q #04"
+ /**/ "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6"
+ /**/ "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299#)))";
+
+
/* Registered progress function and its callback value. */
static void (*progress_cb) (void *, const char*, int, int, int);
static void *progress_cb_data;
@@ -1956,23 +1975,165 @@ _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec)
Self-test section.
*/
+static const char *
+selftest_sign (gcry_sexp_t pkey, gcry_sexp_t skey)
+{
+ /* Sample data from RFC 6979 section A.2.5, hash is of message "sample" */
+ static const char sample_data[] =
+ "(data (flags rfc6979)"
+ " (hash sha256 #af2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e98915"
+ /**/ "62113d8a62add1bf#))";
+ static const char sample_data_bad[] =
+ "(data (flags rfc6979)"
+ " (hash sha256 #bf2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e98915"
+ /**/ "62113d8a62add1bf#))";
+ static const char signature_r[] =
+ "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716";
+ static const char signature_s[] =
+ "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8";
+
+ const char *errtxt = NULL;
+ gcry_error_t err;
+ gcry_sexp_t data = NULL;
+ gcry_sexp_t data_bad = NULL;
+ gcry_sexp_t sig = NULL;
+ gcry_sexp_t l1 = NULL;
+ gcry_sexp_t l2 = NULL;
+ gcry_mpi_t r = NULL;
+ gcry_mpi_t s = NULL;
+ gcry_mpi_t calculated_r = NULL;
+ gcry_mpi_t calculated_s = NULL;
+ int cmp;
+
+ err = sexp_sscan (&data, NULL, sample_data, strlen (sample_data));
+ if (!err)
+ err = sexp_sscan (&data_bad, NULL,
+ sample_data_bad, strlen (sample_data_bad));
+ if (!err)
+ err = _gcry_mpi_scan (&r, GCRYMPI_FMT_HEX, signature_r, 0, NULL);
+ if (!err)
+ err = _gcry_mpi_scan (&s, GCRYMPI_FMT_HEX, signature_s, 0, NULL);
+
+ if (err)
+ {
+ errtxt = "converting data failed";
+ goto leave;
+ }
+
+ err = _gcry_pk_sign (&sig, data, skey);
+ if (err)
+ {
+ errtxt = "signing failed";
+ goto leave;
+ }
+
+ /* check against known signature */
+ errtxt = "signature validity failed";
+ l1 = _gcry_sexp_find_token (sig, "sig-val", 0);
+ if (!l1)
+ goto leave;
+ l2 = _gcry_sexp_find_token (l1, "ecdsa", 0);
+ if (!l2)
+ goto leave;
+
+ sexp_release (l1);
+ l1 = l2;
+
+ l2 = _gcry_sexp_find_token (l1, "r", 0);
+ if (!l2)
+ goto leave;
+ calculated_r = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+ if (!calculated_r)
+ goto leave;
+
+ l2 = _gcry_sexp_find_token (l1, "s", 0);
+ if (!l2)
+ goto leave;
+ calculated_s = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+ if (!calculated_s)
+ goto leave;
+
+ errtxt = "known sig check failed";
+
+ cmp = _gcry_mpi_cmp (r, calculated_r);
+ if (cmp)
+ goto leave;
+ cmp = _gcry_mpi_cmp (s, calculated_s);
+ if (cmp)
+ goto leave;
+
+ errtxt = NULL;
+
+ /* verify generated signature */
+ err = _gcry_pk_verify (sig, data, pkey);
+ if (err)
+ {
+ errtxt = "verify failed";
+ goto leave;
+ }
+ err = _gcry_pk_verify (sig, data_bad, pkey);
+ if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE)
+ {
+ errtxt = "bad signature not detected";
+ goto leave;
+ }
+
+
+ leave:
+ sexp_release (sig);
+ sexp_release (data_bad);
+ sexp_release (data);
+ sexp_release (l1);
+ sexp_release (l2);
+ mpi_release (r);
+ mpi_release (s);
+ mpi_release (calculated_r);
+ mpi_release (calculated_s);
+ return errtxt;
+}
+
static gpg_err_code_t
selftests_ecdsa (selftest_report_func_t report)
{
const char *what;
const char *errtxt;
+ gcry_error_t err;
+ gcry_sexp_t skey = NULL;
+ gcry_sexp_t pkey = NULL;
+
+ what = "convert";
+ err = sexp_sscan (&skey, NULL, sample_secret_key_secp256,
+ strlen (sample_secret_key_secp256));
+ if (!err)
+ err = sexp_sscan (&pkey, NULL, sample_public_key_secp256,
+ strlen (sample_public_key_secp256));
+ if (err)
+ {
+ errtxt = _gcry_strerror (err);
+ goto failed;
+ }
+
+ what = "key consistency";
+ err = ecc_check_secret_key(skey);
+ if (err)
+ {
+ errtxt = _gcry_strerror (err);
+ goto failed;
+ }
- what = "low-level";
- errtxt = NULL; /*selftest ();*/
+ what = "sign";
+ errtxt = selftest_sign (pkey, skey);
if (errtxt)
goto failed;
- /* FIXME: need more tests. */
-
+ sexp_release(pkey);
+ sexp_release(skey);
return 0; /* Succeeded. */
failed:
+ sexp_release(pkey);
+ sexp_release(skey);
if (report)
report ("pubkey", GCRY_PK_ECC, what, errtxt);
return GPG_ERR_SELFTEST_FAILED;
@@ -1996,7 +2157,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report)
gcry_pk_spec_t _gcry_pubkey_spec_ecc =
{
- GCRY_PK_ECC, { 0, 0 },
+ GCRY_PK_ECC, { 0, 1 },
(GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR),
"ECC", ecc_names,
"pabgnhq", "pabgnhqd", "sw", "rs", "pabgnhq",
diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c
index d0d6003a..76d39232 100644
--- a/cipher/pubkey-util.c
+++ b/cipher/pubkey-util.c
@@ -617,7 +617,14 @@ _gcry_pk_util_init_encoding_ctx (struct pk_encoding_ctx *ctx,
ctx->nbits = nbits;
ctx->encoding = PUBKEY_ENC_UNKNOWN;
ctx->flags = 0;
- ctx->hash_algo = GCRY_MD_SHA1;
+ if (fips_mode ())
+ {
+ ctx->hash_algo = GCRY_MD_SHA256;
+ }
+ else
+ {
+ ctx->hash_algo = GCRY_MD_SHA1;
+ }
ctx->label = NULL;
ctx->labellen = 0;
ctx->saltlen = 20;