Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F35401188
D265.id1093.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
16 KB
Subscribers
None
D265.id1093.diff
View Options
Index: b/cipher/ecc-curves.c
===================================================================
--- b/cipher/ecc-curves.c
+++ b/cipher/ecc-curves.c
@@ -147,7 +147,7 @@
},
#endif /*0*/
{
- "NIST P-192", 192, 1,
+ "NIST P-192", 192, 0,
MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
"0xfffffffffffffffffffffffffffffffeffffffffffffffff",
"0xfffffffffffffffffffffffffffffffefffffffffffffffc",
Index: b/cipher/ecc.c
===================================================================
--- b/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -73,6 +73,21 @@
};
+/* Sample NIST P-256 key from RFC 6979 A.2.5 */
+static const char sample_public_key_secp256[] =
+"(public-key"
+" (ecc"
+" (curve secp256r1)"
+" (q #0460FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB67903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299#)))";
+
+static const char sample_secret_key_secp256[] =
+"(private-key"
+" (ecc"
+" (curve secp256r1)"
+" (d #C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721#)"
+" (q #0460FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB67903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299#)))";
+
+
/* Registered progress function and its callback value. */
static void (*progress_cb) (void *, const char*, int, int, int);
static void *progress_cb_data;
@@ -1717,23 +1732,161 @@
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 #af2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e9891562113d8a62add1bf#))";
+ static const char sample_data_bad[] =
+ "(data (flags rfc6979)"
+ " (hash sha256 #bf2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e9891562113d8a62add1bf#))";
+ 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;
@@ -1757,7 +1910,7 @@
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",
Index: b/cipher/pubkey-util.c
===================================================================
--- b/cipher/pubkey-util.c
+++ b/cipher/pubkey-util.c
@@ -603,7 +603,11 @@
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;
Index: b/src/fips.c
===================================================================
--- b/src/fips.c
+++ b/src/fips.c
@@ -545,7 +545,7 @@
{
GCRY_PK_RSA,
GCRY_PK_DSA,
- /* GCRY_PK_ECC is not enabled in fips mode. */
+ GCRY_PK_ECC,
0
};
int idx;
Index: b/tests/fipsdrv.c
===================================================================
--- b/tests/fipsdrv.c
+++ b/tests/fipsdrv.c
@@ -1726,6 +1726,33 @@
return key;
}
+/* Generate an ECDSA key on the specified curve and return the complete
+ S-expression. */
+static gcry_sexp_t
+ecdsa_gen_key (const char *curve)
+{
+ gpg_error_t err;
+ gcry_sexp_t keyspec, key;
+
+ err = gcry_sexp_build (&keyspec, NULL,
+ "(genkey"
+ " (ecc"
+ " (use-fips186)"
+ " (curve %s)))",
+ curve);
+ if (err)
+ die ("gcry_sexp_build failed for ECDSA key generation: %s\n",
+ gpg_strerror (err));
+ err = gcry_pk_genkey (&key, keyspec);
+ if (err)
+ die ("gcry_pk_genkey failed for ECDSA: %s\n", gpg_strerror (err));
+
+ gcry_sexp_release (keyspec);
+
+ return key;
+}
+
+
/* Print the domain parameter as well as the derive information. KEY
is the complete key as returned by dsa_gen. We print to stdout
@@ -1998,6 +2025,198 @@
}
+
+static int
+ecdsa_hash_from_string(const char *algo_string)
+{
+ if (strncmp(algo_string, "SHA-", 4))
+ die("algorithms other than the SHA family are unsupported\n");
+
+ switch(atoi(algo_string + 4))
+ {
+ case 1:
+ return GCRY_MD_SHA1;
+ case 224:
+ return GCRY_MD_SHA224;
+ case 256:
+ return GCRY_MD_SHA256;
+ case 384:
+ return GCRY_MD_SHA384;
+ case 512:
+ return GCRY_MD_SHA512;
+ default:
+ die("unsupported SHA function\n");
+ }
+ return GCRY_MD_NONE;
+}
+
+/* Print public key Q (in octet-string format) and private key d.
+ KEY is the complete key as returned by ecdsa_gen_key.
+ with one parameter per line in hex format using this order: d, Q. */
+static void
+print_ecdsa_dq (gcry_sexp_t key)
+{
+ gcry_sexp_t l1, l2;
+ gcry_mpi_t mpi;
+ int idx;
+
+ l1 = gcry_sexp_find_token (key, "private-key", 0);
+ if (!l1)
+ die ("private key not found in genkey result\n");
+
+ l2 = gcry_sexp_find_token (l1, "ecc", 0);
+ if (!l2)
+ die ("returned private key not formed as expected\n");
+ gcry_sexp_release (l1);
+ l1 = l2;
+
+ /* Extract the parameters from the S-expression and print them to stdout. */
+ for (idx=0; "dq"[idx]; idx++)
+ {
+ l2 = gcry_sexp_find_token (l1, "dq"+idx, 1);
+ if (!l2)
+ die ("no %c parameter in returned public key\n", "dq"[idx]);
+ mpi = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+ if (!mpi)
+ die ("no value for %c parameter in returned private key\n","dq"[idx]);
+ gcry_sexp_release (l2);
+ if (standalone_mode)
+ printf ("%c = ", "dQ"[idx]);
+ print_mpi_line (mpi, 1);
+ gcry_mpi_release (mpi);
+ }
+
+ gcry_sexp_release (l1);
+}
+
+
+/* Generate an ECDSA key with specified domain parameters
+ and print the d and Q values, in the standard octet-string format. */
+static void
+run_ecdsa_gen_key (const char *curve)
+{
+ gcry_sexp_t key;
+
+ key = ecdsa_gen_key (curve);
+ print_ecdsa_dq (key);
+
+ gcry_sexp_release (key);
+}
+
+
+
+
+/* Sign DATA of length DATALEN using the key taken from the S-expression
+ encoded KEYFILE. */
+static void
+run_ecdsa_sign (const void *data, size_t datalen, const char *keyfile, const char *algo_string)
+
+{
+ gpg_error_t err;
+ gcry_sexp_t s_data, s_key, s_sig, s_tmp, s_tmp2;
+ char hash[128];
+ gcry_mpi_t tmpmpi;
+ int algo;
+
+ s_key = read_sexp_from_file (keyfile);
+ algo = ecdsa_hash_from_string (algo_string);
+
+ gcry_md_hash_buffer (algo, hash, data, datalen);
+ err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash,
+ gcry_md_get_algo_dlen(algo), NULL);
+ if (!err)
+ {
+ err = gcry_sexp_build (&s_data, NULL,
+ "(data (flags raw)(value %m))", tmpmpi);
+ gcry_mpi_release (tmpmpi);
+ }
+ if (err)
+ die ("gcry_sexp_build failed for ECDSA data input: %s\n",
+ gpg_strerror (err));
+ gcry_sexp_release (s_data);
+ gcry_sexp_release (s_key);
+
+ /* Now return the actual signature. */
+ s_tmp = gcry_sexp_find_token (s_sig, "sig-val", 0);
+ if (!s_tmp)
+ die ("no sig-val element in returned S-expression\n");
+
+ gcry_sexp_release (s_sig);
+ s_sig = s_tmp;
+ s_tmp = gcry_sexp_find_token (s_sig, "ecdsa", 0);
+ if (!s_tmp)
+ die ("no ecdsa element in returned S-expression\n");
+
+ gcry_sexp_release (s_sig);
+ s_sig = s_tmp;
+
+ s_tmp = gcry_sexp_find_token (s_sig, "r", 0);
+ tmpmpi = gcry_sexp_nth_mpi (s_tmp, 1, GCRYMPI_FMT_USG);
+ if (!tmpmpi)
+ die ("no r parameter in returned S-expression\n");
+ print_mpi_line (tmpmpi, 1);
+ gcry_mpi_release (tmpmpi);
+ gcry_sexp_release (s_tmp);
+
+ s_tmp = gcry_sexp_find_token (s_sig, "s", 0);
+ tmpmpi = gcry_sexp_nth_mpi (s_tmp, 1, GCRYMPI_FMT_USG);
+ if (!tmpmpi)
+ die ("no s parameter in returned S-expression\n");
+ print_mpi_line (tmpmpi, 1);
+ gcry_mpi_release (tmpmpi);
+ gcry_sexp_release (s_tmp);
+
+ gcry_sexp_release (s_sig);
+}
+
+
+
+/* Verify DATA of length DATALEN using the public key taken from the
+ S-expression in KEYFILE against the S-expression formatted
+ signature in SIGFILE. */
+static void
+run_ecdsa_verify (const void *data, size_t datalen,
+ const char *keyfile, const char *algo_string, const char *sigfile)
+
+{
+ gpg_error_t err;
+ gcry_sexp_t s_data, s_key, s_sig;
+ char hash[128];
+ gcry_mpi_t tmpmpi;
+ int algo;
+
+ s_key = read_sexp_from_file (keyfile);
+ algo = ecdsa_hash_from_string(algo_string);
+
+ gcry_md_hash_buffer (algo, hash, data, datalen);
+ /* Note that we can't simply use %b with HASH to build the
+ S-expression, because that might yield a negative value. */
+ err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash,
+ gcry_md_get_algo_dlen(algo), NULL);
+ if (!err)
+ {
+ err = gcry_sexp_build (&s_data, NULL,
+ "(data (flags raw)(value %m))", tmpmpi);
+ gcry_mpi_release (tmpmpi);
+ }
+ if (err)
+ die ("gcry_sexp_build failed for DSA data input: %s\n",
+ gpg_strerror (err));
+
+ s_sig = read_sexp_from_file (sigfile);
+
+ err = gcry_pk_verify (s_sig, s_data, s_key);
+ if (!err)
+ puts ("GOOD signature");
+ else if (gpg_err_code (err) == GPG_ERR_BAD_SIGNATURE)
+ puts ("BAD signature");
+ else
+ printf ("ERROR (%s)\n", gpg_strerror (err));
+
+ gcry_sexp_release (s_sig);
+ gcry_sexp_release (s_key);
+ gcry_sexp_release (s_data);
+}
static void
@@ -2014,7 +2233,7 @@
"Run a crypto operation using hex encoded input and output.\n"
"MODE:\n"
" encrypt, decrypt, digest, random, hmac-sha,\n"
- " rsa-{derive,gen,sign,verify}, dsa-{pqg-gen,gen,sign,verify}\n"
+ " rsa-{derive,gen,sign,verify}, dsa-{pqg-gen,gen,sign,verify}, ecdsa-{gen-key,sign,verify}\n"
"OPTIONS:\n"
" --verbose Print additional information\n"
" --binary Input and output is in binary form\n"
@@ -2023,6 +2242,7 @@
" --iv IV Use the hex encoded IV\n"
" --dt DT Use the hex encoded DT for the RNG\n"
" --algo NAME Use algorithm NAME\n"
+ " --curve NAME Select ECC curve spec NAME\n"
" --keysize N Use a keysize of N bits\n"
" --signature NAME Take signature from file NAME\n"
" --chunk N Read in chunks of N bytes (implies --binary)\n"
@@ -2045,6 +2265,7 @@
int progress = 0;
int use_pkcs1 = 0;
const char *mode_string;
+ const char *curve_string = NULL;
const char *key_string = NULL;
const char *iv_string = NULL;
const char *dt_string = NULL;
@@ -2160,6 +2381,14 @@
binary_input = binary_output = 1;
argc--; argv++;
}
+ else if (!strcmp (*argv, "--curve"))
+ {
+ argc--; argv++;
+ if (!argc)
+ usage (0);
+ curve_string = *argv;
+ argc--; argv++;
+ }
else if (!strcmp (*argv, "--pkcs1"))
{
use_pkcs1 = 1;
@@ -2217,7 +2446,8 @@
&& !mct_server
&& strcmp (mode_string, "random")
&& strcmp (mode_string, "rsa-gen")
- && strcmp (mode_string, "dsa-gen") )
+ && strcmp (mode_string, "dsa-gen")
+ && strcmp (mode_string, "ecdsa-gen-key") )
{
data = read_file (input, !binary_input, &datalen);
if (!data)
@@ -2507,6 +2737,43 @@
run_dsa_verify (data, datalen, key_string, signature_string);
}
+ else if (!strcmp (mode_string, "ecdsa-gen-key"))
+ {
+ if (!curve_string)
+ die ("option --curve containing name of the specified curve is required in this mode\n");
+ run_ecdsa_gen_key (curve_string);
+ }
+ else if (!strcmp (mode_string, "ecdsa-sign"))
+ {
+ if (!key_string)
+ die ("option --key is required in this mode\n");
+ if (access (key_string, R_OK))
+ die ("option --key needs to specify an existing keyfile\n");
+ if (!algo_string)
+ die ("use --algo to specify the hash algorithm\n");
+
+ if (!data)
+ die ("no data available (do not use --chunk)\n");
+
+ run_ecdsa_sign (data, datalen, key_string, algo_string);
+ }
+ else if (!strcmp (mode_string, "ecdsa-verify"))
+ {
+ if (!key_string)
+ die ("option --key is required in this mode\n");
+ if (access (key_string, R_OK))
+ die ("option --key needs to specify an existing keyfile\n");
+ if (!algo_string)
+ die ("use --algo to specify the hash algorithm\n");
+ if (!data)
+ die ("no data available (do not use --chunk)\n");
+ if (!signature_string)
+ die ("option --signature is required in this mode\n");
+ if (access (signature_string, R_OK))
+ die ("option --signature needs to specify an existing file\n");
+
+ run_ecdsa_verify (data, datalen, key_string, algo_string, signature_string);
+ }
else
usage (0);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Feb 6, 5:32 PM (16 h, 25 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
14/54/567e269ac84e8ec011fdb51a9861
Attached To
D265: 515_0002-Make-ecdsa-FIPS-186-4-compliant.patch
Event Timeline
Log In to Comment