Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP2:GA
libgcrypt.20076
libgcrypt-fips_ecdsa.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File libgcrypt-fips_ecdsa.patch of Package libgcrypt.20076
Index: libgcrypt-1.6.1/cipher/ecc-curves.c =================================================================== --- libgcrypt-1.6.1.orig/cipher/ecc-curves.c 2014-01-29 10:48:38.000000000 +0100 +++ libgcrypt-1.6.1/cipher/ecc-curves.c 2015-03-16 15:32:31.284501952 +0100 @@ -114,7 +114,7 @@ "0x6666666666666666666666666666666666666666666666666666666666666658" }, { - "NIST P-192", 192, 1, + "NIST P-192", 192, 0, MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, "0xfffffffffffffffffffffffffffffffeffffffffffffffff", "0xfffffffffffffffffffffffffffffffefffffffffffffffc", Index: libgcrypt-1.6.1/cipher/pubkey-util.c =================================================================== --- libgcrypt-1.6.1.orig/cipher/pubkey-util.c 2013-12-16 18:44:32.000000000 +0100 +++ libgcrypt-1.6.1/cipher/pubkey-util.c 2015-03-16 15:32:31.285501958 +0100 @@ -593,7 +593,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: libgcrypt-1.6.1/tests/fipsdrv.c =================================================================== --- libgcrypt-1.6.1.orig/tests/fipsdrv.c 2015-03-16 15:32:31.238501672 +0100 +++ libgcrypt-1.6.1/tests/fipsdrv.c 2015-03-16 16:47:43.169441673 +0100 @@ -1764,6 +1764,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 @@ -1900,6 +1927,46 @@ } +/* 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 DSA pq domain parameters for a modulus size of KEYSIZE. The result is printed to stdout with one parameter per line in hex format and in this order: p, q, seed, counter. If SEED is @@ -1972,6 +2039,20 @@ } +/* 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); +} + + static int dsa_hash_from_key(gcry_sexp_t s_key) { @@ -2161,6 +2242,120 @@ } + +/* 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 int algo) + +{ + gpg_error_t err; + gcry_sexp_t s_data, s_key, s_sig, s_tmp, s_tmp2; + char hash[128]; + gcry_mpi_t tmpmpi; + + s_key = read_sexp_from_file (keyfile); + + 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)(hash %s %M))", gcry_md_algo_name(algo), tmpmpi); + gcry_mpi_release (tmpmpi); + } + if (err) + die ("gcry_sexp_build failed for ECDSA data input: %s\n", + gpg_strerror (err)); + + err = gcry_pk_sign (&s_sig, s_data, s_key); + if (err) + { + die ("gcry_pk_signed failed: %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 int algo, const char *sigfile) + +{ + gpg_error_t err; + gcry_sexp_t s_data, s_key, s_sig; + char hash[128]; + gcry_mpi_t tmpmpi; + + s_key = read_sexp_from_file (keyfile); + + 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)(hash %s %M))", gcry_md_algo_name(algo), 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 @@ -2177,7 +2372,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-{pq-gen,g-gen,gen,sign,verify}\n" + " rsa-{derive,gen,sign,verify}, dsa-{pq-gen,g-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" @@ -2186,6 +2381,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" " --qize N Use a DSA q parameter size of N bits\n" " --signature NAME Take signature from file NAME\n" @@ -2209,6 +2405,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; @@ -2333,6 +2530,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; @@ -2390,7 +2595,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) @@ -2706,6 +2912,53 @@ 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")) + { + int algo; + + 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 digest algorithm\n"); + algo = gcry_md_map_name (algo_string); + if (!algo) + die ("digest algorithm `%s' is not supported\n", algo_string); + + if (!data) + die ("no data available (do not use --chunk)\n"); + + run_ecdsa_sign (data, datalen, key_string, algo); + } + else if (!strcmp (mode_string, "ecdsa-verify")) + { + int algo; + + 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 digest algorithm\n"); + algo = gcry_md_map_name (algo_string); + if (!algo) + die ("digest algorithm `%s' is not supported\n", algo_string); + 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, signature_string); + } else usage (0); Index: libgcrypt-1.6.1/src/fips.c =================================================================== --- libgcrypt-1.6.1.orig/src/fips.c 2015-03-16 15:32:31.231501629 +0100 +++ libgcrypt-1.6.1/src/fips.c 2015-03-16 15:32:31.285501958 +0100 @@ -557,7 +557,7 @@ { GCRY_PK_RSA, GCRY_PK_DSA, - /* GCRY_PK_ECC is not enabled in fips mode. */ + GCRY_PK_ECC, 0 }; int idx; Index: libgcrypt-1.6.1/cipher/ecc.c =================================================================== --- libgcrypt-1.6.1.orig/cipher/ecc.c 2014-01-29 10:48:38.000000000 +0100 +++ libgcrypt-1.6.1/cipher/ecc.c 2015-03-16 15:32:31.286501964 +0100 @@ -76,6 +76,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; @@ -1702,23 +1717,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; @@ -1742,7 +1895,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, "pabgnq", "pabgnqd", "sw", "rs", "pabgnq",
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor