diff options
-rw-r--r-- | cipher/ecc.c | 48 | ||||
-rw-r--r-- | cipher/pubkey-util.c | 4 | ||||
-rw-r--r-- | src/cipher.h | 17 | ||||
-rw-r--r-- | tests/keygen.c | 17 | ||||
-rw-r--r-- | tests/pubkey.c | 169 |
5 files changed, 229 insertions, 26 deletions
diff --git a/cipher/ecc.c b/cipher/ecc.c index da384e87..3b75feac 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -558,13 +558,10 @@ verify_ecdsa (gcry_mpi_t input, ECC_public_key *pkey, log_mpidump (" x", x); log_mpidump (" r", r); log_mpidump (" s", s); - log_debug ("ecc verify: Not verified\n"); } err = GPG_ERR_BAD_SIGNATURE; goto leave; } - if (DBG_CIPHER) - log_debug ("ecc verify: Accepted\n"); leave: _gcry_mpi_ec_free (ctx); @@ -1208,14 +1205,10 @@ verify_eddsa (gcry_mpi_t input, ECC_public_key *pkey, goto leave; if (tlen != rlen || memcmp (tbuf, rbuf, tlen)) { - if (DBG_CIPHER) - log_debug ("eddsa verify: Not verified\n"); rc = GPG_ERR_BAD_SIGNATURE; goto leave; } - if (DBG_CIPHER) - log_debug ("eddsa verify: Accepted\n"); rc = 0; leave: @@ -1250,10 +1243,12 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) gcry_random_level_t random_level; mpi_ec_t ctx = NULL; gcry_sexp_t curve_info = NULL; + gcry_sexp_t curve_flags = NULL; gcry_mpi_t base = NULL; gcry_mpi_t public = NULL; gcry_mpi_t secret = NULL; int flags = 0; + int ed25519_with_ecdsa = 0; memset (&E, 0, sizeof E); memset (&sk, 0, sizeof sk); @@ -1328,7 +1323,13 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) rc = nist_generate_key (&sk, &E, ctx, random_level, nbits); break; case ECC_DIALECT_ED25519: - rc = eddsa_generate_key (&sk, &E, ctx, random_level); + if ((flags & PUBKEY_FLAG_ECDSA)) + { + ed25519_with_ecdsa = 1; + rc = nist_generate_key (&sk, &E, ctx, random_level, nbits); + } + else + rc = eddsa_generate_key (&sk, &E, ctx, random_level); break; default: rc = GPG_ERR_INTERNAL; @@ -1341,7 +1342,7 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) if (_gcry_mpi_ec_get_affine (x, y, &sk.E.G, ctx)) log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "G"); base = _gcry_ecc_ec2os (x, y, sk.E.p); - if (sk.E.dialect == ECC_DIALECT_ED25519) + if (sk.E.dialect == ECC_DIALECT_ED25519 && !ed25519_with_ecdsa) { unsigned char *encpk; unsigned int encpklen; @@ -1367,16 +1368,23 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) goto leave; } + if (ed25519_with_ecdsa) + { + rc = gcry_sexp_build (&curve_info, NULL, "(flags ecdsa)"); + if (rc) + goto leave; + } + rc = gcry_sexp_build (r_skey, NULL, "(key-data" " (public-key" - " (ecc%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))" + " (ecc%S%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))" " (private-key" - " (ecc%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)(d%m)))" + " (ecc%S%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)(d%m)))" " )", - curve_info, + curve_info, curve_flags, sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, public, - curve_info, + curve_info, curve_flags, sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, public, secret); if (rc) goto leave; @@ -1390,6 +1398,8 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) log_printmpi ("ecgen result n", sk.E.n); log_printmpi ("ecgen result Q", public); log_printmpi ("ecgen result d", secret); + if (ed25519_with_ecdsa) + log_debug ("ecgen result using Ed25519/ECDSA\n"); } leave: @@ -1580,9 +1590,11 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) } if (DBG_CIPHER) { - log_debug ("ecc_sign info: %s/%s\n", + log_debug ("ecc_sign info: %s/%s%s\n", _gcry_ecc_model2str (sk.E.model), - _gcry_ecc_dialect2str (sk.E.dialect)); + _gcry_ecc_dialect2str (sk.E.dialect), + (sk.E.dialect == ECC_DIALECT_ED25519 + && (ctx.flags & PUBKEY_FLAG_ECDSA))? "ECDSA":""); if (sk.E.name) log_debug ("ecc_sign name: %s\n", sk.E.name); log_printmpi ("ecc_sign p", sk.E.p); @@ -1733,9 +1745,11 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) if (DBG_CIPHER) { - log_debug ("ecc_verify info: %s/%s\n", + log_debug ("ecc_verify info: %s/%s%s\n", _gcry_ecc_model2str (pk.E.model), - _gcry_ecc_dialect2str (pk.E.dialect)); + _gcry_ecc_dialect2str (pk.E.dialect), + (pk.E.dialect == ECC_DIALECT_ED25519 + && !(sigflags & PUBKEY_FLAG_EDDSA))? "/ECDSA":""); if (pk.E.name) log_debug ("ecc_verify name: %s\n", pk.E.name); log_printmpi ("ecc_verify p", pk.E.p); diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c index 3dfc0279..caf715eb 100644 --- a/cipher/pubkey-util.c +++ b/cipher/pubkey-util.c @@ -75,6 +75,10 @@ _gcry_pk_util_parse_flaglist (gcry_sexp_t list, encoding = PUBKEY_ENC_RAW; flags |= PUBKEY_FLAG_EDDSA; } + else if (n == 5 && !memcmp (s, "ecdsa", 5)) + { + flags |= PUBKEY_FLAG_ECDSA; + } else if (n == 3 && !memcmp (s, "raw", 3) && encoding == PUBKEY_ENC_UNKNOWN) { diff --git a/src/cipher.h b/src/cipher.h index b3469e57..077af984 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -28,14 +28,15 @@ #define PUBKEY_FLAG_NO_BLINDING (1 << 0) #define PUBKEY_FLAG_RFC6979 (1 << 1) -#define PUBKEY_FLAG_EDDSA (1 << 2) -#define PUBKEY_FLAG_FIXEDLEN (1 << 3) -#define PUBKEY_FLAG_LEGACYRESULT (1 << 4) -#define PUBKEY_FLAG_RAW_FLAG (1 << 5) -#define PUBKEY_FLAG_TRANSIENT_KEY (1 << 6) -#define PUBKEY_FLAG_USE_X931 (1 << 7) -#define PUBKEY_FLAG_USE_FIPS186 (1 << 8) -#define PUBKEY_FLAG_USE_FIPS186_2 (1 << 9) +#define PUBKEY_FLAG_FIXEDLEN (1 << 2) +#define PUBKEY_FLAG_LEGACYRESULT (1 << 3) +#define PUBKEY_FLAG_RAW_FLAG (1 << 4) +#define PUBKEY_FLAG_TRANSIENT_KEY (1 << 5) +#define PUBKEY_FLAG_USE_X931 (1 << 6) +#define PUBKEY_FLAG_USE_FIPS186 (1 << 7) +#define PUBKEY_FLAG_USE_FIPS186_2 (1 << 8) +#define PUBKEY_FLAG_ECDSA (1 << 9) +#define PUBKEY_FLAG_EDDSA (1 << 10) enum pk_operation diff --git a/tests/keygen.c b/tests/keygen.c index b955116c..2b98c42d 100644 --- a/tests/keygen.c +++ b/tests/keygen.c @@ -394,6 +394,23 @@ check_ecc_keys (void) gcry_sexp_release (key); } + + if (verbose) + show ("creating ECC key using curve Ed25519 for ECDSA\n"); + rc = gcry_sexp_build (&keyparm, NULL, + "(genkey(ecc(curve Ed25519)(flags ecdsa)))"); + if (rc) + die ("error creating S-expression: %s\n", gpg_strerror (rc)); + rc = gcry_pk_genkey (&key, keyparm); + gcry_sexp_release (keyparm); + if (rc) + die ("error generating ECC key using curve Ed25519 for ECDSA: %s\n", + gpg_strerror (rc)); + + if (verbose > 1) + show_sexp ("ECC key:\n", key); + + gcry_sexp_release (key); } diff --git a/tests/pubkey.c b/tests/pubkey.c index baf234cc..4dadf882 100644 --- a/tests/pubkey.c +++ b/tests/pubkey.c @@ -28,6 +28,18 @@ #include "../src/gcrypt-int.h" +#define my_isascii(c) (!((c) & 0x80)) +#define digitp(p) (*(p) >= '0' && *(p) <= '9') +#define hexdigitp(a) (digitp (a) \ + || (*(a) >= 'A' && *(a) <= 'F') \ + || (*(a) >= 'a' && *(a) <= 'f')) +#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ + *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) +#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) +#define DIM(v) (sizeof(v)/sizeof((v)[0])) +#define DIMof(type,member) DIM(((type *)0)->member) + + /* Sample RSA keys, taken from basic.c. */ static const char sample_private_key_1[] = @@ -101,6 +113,7 @@ static const char sample_public_key_1[] = static int verbose; +static int error_count; static void die (const char *format, ...) @@ -116,6 +129,27 @@ die (const char *format, ...) } static void +fail (const char *format, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + error_count++; +} + +static void +info (const char *format, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); +} + +static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; @@ -132,6 +166,59 @@ show_sexp (const char *prefix, gcry_sexp_t a) } +/* Convert STRING consisting of hex characters into its binary + representation and return it as an allocated buffer. The valid + length of the buffer is returned at R_LENGTH. The string is + delimited by end of string. The function returns NULL on + error. */ +static void * +data_from_hex (const char *string, size_t *r_length) +{ + const char *s; + unsigned char *buffer; + size_t length; + + buffer = gcry_xmalloc (strlen(string)/2+1); + length = 0; + for (s=string; *s; s +=2 ) + { + if (!hexdigitp (s) || !hexdigitp (s+1)) + die ("error parsing hex string `%s'\n", string); + ((unsigned char*)buffer)[length++] = xtoi_2 (s); + } + *r_length = length; + return buffer; +} + + +static void +extract_cmp_data (gcry_sexp_t sexp, const char *name, const char *expected) +{ + gcry_sexp_t l1; + const void *a; + size_t alen; + void *b; + size_t blen; + + l1 = gcry_sexp_find_token (sexp, name, 0); + a = gcry_sexp_nth_data (l1, 1, &alen); + b = data_from_hex (expected, &blen); + if (!a) + fail ("parameter \"%s\" missing in key\n", name); + else if ( alen != blen || memcmp (a, b, alen) ) + { + fail ("parameter \"%s\" does not match expected value\n", name); + if (verbose) + { + info ("expected: %s\n", expected); + show_sexp ("sexp: ", sexp); + } + } + gcry_free (b); + gcry_sexp_release (l1); +} + + static void check_keys_crypt (gcry_sexp_t pkey, gcry_sexp_t skey, gcry_sexp_t plain0, gpg_err_code_t decrypt_fail_code) @@ -939,6 +1026,85 @@ check_ecc_sample_key (void) } +static void +check_ed25519ecdsa_sample_key (void) +{ + static const char ecc_private_key[] = + "(private-key\n" + " (ecc\n" + " (curve \"Ed25519\")\n" + " (q #044C056555BE4084BB3D8D8895FDF7C2893DFE0256251923053010977D12658321" + " 156D1ADDC07987713A418783658B476358D48D582DB53233D9DED3C1C2577B04#)" + " (d #09A0C38E0F1699073541447C19DA12E3A07A7BFDB0C186E4AC5BCE6F23D55252#)" + "))"; + static const char ecc_private_key_wo_q[] = + "(private-key\n" + " (ecc\n" + " (curve \"Ed25519\")\n" + " (d #09A0C38E0F1699073541447C19DA12E3A07A7BFDB0C186E4AC5BCE6F23D55252#)" + "))"; + static const char ecc_public_key[] = + "(public-key\n" + " (ecc\n" + " (curve \"Ed25519\")\n" + " (q #044C056555BE4084BB3D8D8895FDF7C2893DFE0256251923053010977D12658321" + " 156D1ADDC07987713A418783658B476358D48D582DB53233D9DED3C1C2577B04#)" + "))"; + static const char hash_string[] = + "(data (flags ecdsa rfc6979)\n" + " (hash sha256 #00112233445566778899AABBCCDDEEFF" + /* */ "000102030405060708090A0B0C0D0E0F#))"; + + gpg_error_t err; + gcry_sexp_t key, hash, sig; + + if (verbose) + fprintf (stderr, "Checking sample Ed25519/ECDSA key.\n"); + + if ((err = gcry_sexp_new (&hash, hash_string, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + + if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + + if ((err = gcry_pk_sign (&sig, hash, key))) + die ("gcry_pk_sign failed: %s", gpg_strerror (err)); + + gcry_sexp_release (key); + if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + + if ((err = gcry_pk_verify (sig, hash, key))) + die ("gcry_pk_verify failed: %s", gpg_strerror (err)); + + /* Now try signing without the Q parameter. */ + + gcry_sexp_release (key); + if ((err = gcry_sexp_new (&key, ecc_private_key_wo_q, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + + gcry_sexp_release (sig); + if ((err = gcry_pk_sign (&sig, hash, key))) + die ("gcry_pk_sign without Q failed: %s", gpg_strerror (err)); + + gcry_sexp_release (key); + if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + + if ((err = gcry_pk_verify (sig, hash, key))) + die ("gcry_pk_verify signed without Q failed: %s", gpg_strerror (err)); + + extract_cmp_data (sig, "r", ("a63123a783ef29b8276e08987daca4" + "655d0179e22199bf63691fd88eb64e15")); + extract_cmp_data (sig, "s", ("0d9b45c696ab90b96b08812b485df185" + "623ddaf5d02fa65ca5056cb6bd0f16f1")); + + gcry_sexp_release (sig); + gcry_sexp_release (key); + gcry_sexp_release (hash); +} + + int main (int argc, char **argv) { @@ -969,6 +1135,7 @@ main (int argc, char **argv) check_x931_derived_key (i); check_ecc_sample_key (); + check_ed25519ecdsa_sample_key (); - return 0; + return !!error_count; } |