diff options
author | Vitezslav Cizek <vcizek@suse.com> | 2015-10-27 14:29:11 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2016-03-18 15:26:28 +0100 |
commit | a242e3d9185e6e2dc13902ea9331131755bbba01 (patch) | |
tree | 11679a351ba6f54edf67fc395bf1d3d5ff80f7c5 /cipher | |
parent | e40939b2141306238cc30a340b867b60fa4dc2a3 (diff) | |
download | libgcrypt-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.c | 2 | ||||
-rw-r--r-- | cipher/ecc.c | 171 | ||||
-rw-r--r-- | cipher/pubkey-util.c | 9 |
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; |