summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cipher/ecc.c48
-rw-r--r--cipher/pubkey-util.c4
-rw-r--r--src/cipher.h17
-rw-r--r--tests/keygen.c17
-rw-r--r--tests/pubkey.c169
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;
}