diff options
-rw-r--r-- | cipher/ecc-common.h | 8 | ||||
-rw-r--r-- | cipher/ecc-curves.c | 50 | ||||
-rw-r--r-- | cipher/ecc-eddsa.c | 48 | ||||
-rw-r--r-- | cipher/ecc.c | 159 | ||||
-rw-r--r-- | tests/keygrip.c | 58 |
5 files changed, 269 insertions, 54 deletions
diff --git a/cipher/ecc-common.h b/cipher/ecc-common.h index 93fd449e..0cecdc34 100644 --- a/cipher/ecc-common.h +++ b/cipher/ecc-common.h @@ -70,6 +70,12 @@ gpg_err_code_t _gcry_ecc_fill_in_curve (unsigned int nbits, const char *name, elliptic_curve_t *curve, unsigned int *r_nbits); +gpg_err_code_t _gcry_ecc_update_curve_param (const char *name, + enum gcry_mpi_ec_models *model, + enum ecc_dialects *dialect, + gcry_mpi_t *p, gcry_mpi_t *a, + gcry_mpi_t *b, gcry_mpi_t *g, + gcry_mpi_t *n); const char *_gcry_ecc_get_curve (gcry_sexp_t keyparms, int iterator, @@ -103,6 +109,8 @@ gpg_err_code_t _gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ctx, gcry_mpi_t x, gcry_mpi_t y, unsigned char **r_buffer, unsigned int *r_buflen); +gpg_err_code_t _gcry_ecc_eddsa_ensure_compact (gcry_mpi_t value, + unsigned int nbits); gpg_err_code_t _gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result, unsigned char **r_encpk, diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c index 98fbf0c3..8c63f6c0 100644 --- a/cipher/ecc-curves.c +++ b/cipher/ecc-curves.c @@ -441,6 +441,56 @@ _gcry_ecc_fill_in_curve (unsigned int nbits, const char *name, } +/* Give the name of the curve NAME, store the curve parameters into P, + A, B, G, and N if they pint to NULL value. Note that G is returned + in standard uncompressed format. Also update MODEL and DIALECT if + they are not NULL. */ +gpg_err_code_t +_gcry_ecc_update_curve_param (const char *name, + enum gcry_mpi_ec_models *model, + enum ecc_dialects *dialect, + gcry_mpi_t *p, gcry_mpi_t *a, gcry_mpi_t *b, + gcry_mpi_t *g, gcry_mpi_t *n) +{ + int idx; + + idx = find_domain_parms_idx (name); + if (idx < 0) + return GPG_ERR_UNKNOWN_CURVE; + + if (g) + { + char *buf; + size_t len; + + len = 4; + len += strlen (domain_parms[idx].g_x+2); + len += strlen (domain_parms[idx].g_y+2); + len++; + buf = gcry_malloc (len); + if (!buf) + return gpg_err_code_from_syserror (); + strcpy (stpcpy (stpcpy (buf, "0x04"), domain_parms[idx].g_x+2), + domain_parms[idx].g_y+2); + *g = scanval (buf); + gcry_free (buf); + } + if (model) + *model = domain_parms[idx].model; + if (dialect) + *dialect = domain_parms[idx].dialect; + if (p) + *p = scanval (domain_parms[idx].p); + if (a) + *a = scanval (domain_parms[idx].a); + if (b) + *b = scanval (domain_parms[idx].b); + if (n) + *n = scanval (domain_parms[idx].n); + return 0; +} + + /* Return the name matching the parameters in PKEY. This works only with curves described by the Weierstrass equation. */ const char * diff --git a/cipher/ecc-eddsa.c b/cipher/ecc-eddsa.c index d83b7c69..b9e866d9 100644 --- a/cipher/ecc-eddsa.c +++ b/cipher/ecc-eddsa.c @@ -136,6 +136,54 @@ _gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ec, } +/* Make sure that the opaque MPI VALUE is in compact EdDSA format. + This function updates MPI if needed. */ +gpg_err_code_t +_gcry_ecc_eddsa_ensure_compact (gcry_mpi_t value, unsigned int nbits) +{ + gpg_err_code_t rc; + const unsigned char *buf; + unsigned int rawmpilen; + gcry_mpi_t x, y; + unsigned char *enc; + unsigned int enclen; + + if (!mpi_is_opaque (value)) + return GPG_ERR_INV_OBJ; + buf = gcry_mpi_get_opaque (value, &rawmpilen); + if (!buf) + return GPG_ERR_INV_OBJ; + rawmpilen = (rawmpilen + 7)/8; + + /* Check whether the public key has been given in standard + uncompressed format. In this case extract y and compress. */ + if (rawmpilen > 1 && buf[0] == 0x04 && (rawmpilen%2)) + { + rc = gcry_mpi_scan (&x, GCRYMPI_FMT_STD, + buf+1, (rawmpilen-1)/2, NULL); + if (rc) + return rc; + rc = gcry_mpi_scan (&y, GCRYMPI_FMT_STD, + buf+1+(rawmpilen-1)/2, (rawmpilen-1)/2, NULL); + if (rc) + { + mpi_free (x); + return rc; + } + + rc = eddsa_encode_x_y (x, y, nbits/8, &enc, &enclen); + mpi_free (x); + mpi_free (y); + if (rc) + return rc; + + gcry_mpi_set_opaque (value, enc, 8*enclen); + } + + return 0; +} + + /* Recover X from Y and SIGN (which actually is a parity bit). */ gpg_err_code_t _gcry_ecc_eddsa_recover_x (gcry_mpi_t x, gcry_mpi_t y, int sign, mpi_ec_t ec) diff --git a/cipher/ecc.c b/cipher/ecc.c index d62f5555..b9af1854 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -1428,65 +1428,87 @@ ecc_get_nbits (gcry_sexp_t parms) /* See rsa.c for a description of this function. */ static gpg_err_code_t -compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam) +compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparms) { #define N_COMPONENTS 6 static const char names[N_COMPONENTS+1] = "pabgnq"; - gpg_err_code_t ec = 0; + gpg_err_code_t rc; gcry_sexp_t l1; gcry_mpi_t values[N_COMPONENTS]; int idx; + char *curvename = NULL; + int flags = 0; + enum gcry_mpi_ec_models model = 0; + enum ecc_dialects dialect = 0; - /* Clear the values for easier error cleanup. */ + /* Clear the values first. */ for (idx=0; idx < N_COMPONENTS; idx++) values[idx] = NULL; - /* Fill values with all provided parameters. */ - for (idx=0; idx < N_COMPONENTS; idx++) + + /* Look for flags. */ + l1 = gcry_sexp_find_token (keyparms, "flags", 0); + if (l1) { - l1 = gcry_sexp_find_token (keyparam, names+idx, 1); - if (l1) - { - values[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l1); - if (!values[idx]) - { - ec = GPG_ERR_INV_OBJ; - goto leave; - } - } + rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + if (rc) + goto leave; + } + + /* Extract the parameters. */ + if ((flags & PUBKEY_FLAG_PARAM)) + { + if ((flags & PUBKEY_FLAG_EDDSA)) + rc = _gcry_sexp_extract_param (keyparms, NULL, "p?a?b?g?n?/q", + &values[0], &values[1], &values[2], + &values[3], &values[4], &values[5], + NULL); + else + rc = _gcry_sexp_extract_param (keyparms, NULL, "p?a?b?g?n?q", + &values[0], &values[1], &values[2], + &values[3], &values[4], &values[5], + NULL); + } + else + { + if ((flags & PUBKEY_FLAG_EDDSA)) + rc = _gcry_sexp_extract_param (keyparms, NULL, "/q", + &values[5], NULL); + else + rc = _gcry_sexp_extract_param (keyparms, NULL, "q", + &values[5], NULL); } + if (rc) + goto leave; /* Check whether a curve parameter is available and use that to fill in missing values. */ - l1 = gcry_sexp_find_token (keyparam, "curve", 5); + gcry_sexp_release (l1); + l1 = gcry_sexp_find_token (keyparms, "curve", 5); if (l1) { - char *curve; - gcry_mpi_t tmpvalues[N_COMPONENTS]; - - for (idx = 0; idx < N_COMPONENTS; idx++) - tmpvalues[idx] = NULL; - - curve = _gcry_sexp_nth_string (l1, 1); - gcry_sexp_release (l1); - if (!curve) + curvename = gcry_sexp_nth_string (l1, 1); + if (curvename) { - ec = GPG_ERR_INV_OBJ; /* Name missing or out of core. */ - goto leave; + rc = _gcry_ecc_update_curve_param (curvename, + &model, &dialect, + &values[0], &values[1], &values[2], + &values[3], &values[4]); + if (rc) + return rc; } - ec = _gcry_ecc_get_param (curve, tmpvalues); - gcry_free (curve); - if (ec) - goto leave; + } - for (idx = 0; idx < N_COMPONENTS; idx++) - { - if (!values[idx]) - values[idx] = tmpvalues[idx]; - else - mpi_free (tmpvalues[idx]); - } + /* Guess required fields if a curve parameter has not been given. + FIXME: This is a crude hacks. We need to fix that. */ + if (!curvename) + { + model = ((flags & PUBKEY_FLAG_EDDSA) + ? MPI_EC_TWISTEDEDWARDS + : MPI_EC_WEIERSTRASS); + dialect = ((flags & PUBKEY_FLAG_EDDSA) + ? ECC_DIALECT_ED25519 + : ECC_DIALECT_STANDARD); } /* Check that all parameters are known and normalize all MPIs (that @@ -1495,37 +1517,70 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam) for (idx = 0; idx < N_COMPONENTS; idx++) if (!values[idx]) { - ec = GPG_ERR_NO_OBJ; + rc = GPG_ERR_NO_OBJ; goto leave; } else _gcry_mpi_normalize (values[idx]); + /* Uncompress the public key with the exception of EdDSA where + compression is the default and we thus compute the keygrip using + the compressed version. Because we don't support any non-eddsa + compression, the only thing we need to do is to compress + EdDSA. */ + if ((flags & PUBKEY_FLAG_EDDSA)) + { + if (dialect == ECC_DIALECT_ED25519) + rc = _gcry_ecc_eddsa_ensure_compact (values[5], 256); + else + rc = GPG_ERR_NOT_IMPLEMENTED; + if (rc) + goto leave; + } + /* Hash them all. */ for (idx = 0; idx < N_COMPONENTS; idx++) { char buf[30]; - unsigned char *rawmpi; - unsigned int rawmpilen; - rawmpi = _gcry_mpi_get_buffer (values[idx], 0, &rawmpilen, NULL); - if (!rawmpi) + if (mpi_is_opaque (values[idx])) { - ec = gpg_err_code_from_syserror (); - goto leave; + const unsigned char *raw; + unsigned int n; + + raw = gcry_mpi_get_opaque (values[idx], &n); + n = (n + 7)/8; + snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], n); + gcry_md_write (md, buf, strlen (buf)); + gcry_md_write (md, raw, n); + gcry_md_write (md, ")", 1); + } + else + { + unsigned char *rawmpi; + unsigned int rawmpilen; + + rawmpi = _gcry_mpi_get_buffer (values[idx], 0, &rawmpilen, NULL); + if (!rawmpi) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], rawmpilen); + gcry_md_write (md, buf, strlen (buf)); + gcry_md_write (md, rawmpi, rawmpilen); + gcry_md_write (md, ")", 1); + gcry_free (rawmpi); } - snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], rawmpilen); - gcry_md_write (md, buf, strlen (buf)); - gcry_md_write (md, rawmpi, rawmpilen); - gcry_md_write (md, ")", 1); - gcry_free (rawmpi); } leave: + gcry_free (curvename); + gcry_sexp_release (l1); for (idx = 0; idx < N_COMPONENTS; idx++) _gcry_mpi_release (values[idx]); - return ec; + return rc; #undef N_COMPONENTS } diff --git a/tests/keygrip.c b/tests/keygrip.c index a89bba87..330935db 100644 --- a/tests/keygrip.c +++ b/tests/keygrip.c @@ -104,7 +104,7 @@ static struct { GCRY_PK_ECDSA, "(public-key" - " (ecdsa" + " (ecdsa(flags param)" " (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)" " (a #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC#)" " (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)" @@ -116,6 +116,18 @@ static struct { GCRY_PK_ECDSA, "(public-key" + " (ecdsa(flags param)" + " (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)" + " (curve \"NIST P-256\")" + " (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)" + " (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)" + " (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)" + " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))", + "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6" + }, + { + GCRY_PK_ECDSA, + "(public-key" " (ecdsa" " (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)" " (curve \"NIST P-256\")" @@ -132,10 +144,52 @@ static struct " (curve secp256r1)" " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))", "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6" + }, + { + GCRY_PK_ECC, + "(public-key" + " (ecc" + " (curve secp256r1)" + " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))", + "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6" + }, + { /* Ed25519 standard */ + GCRY_PK_ECC, + "(public-key" + " (ecc" + " (curve Ed25519)" + " (q #04" + " 1CC662926E7EFF4982B7FB8B928E61CD74CCDD85277CC57196C3AD20B611085F" + " 47BD24842905C049257673B3F5249524E0A41FAA17B25B818D0F97E625F1A1D0#)" + " ))", + "\x0C\xCA\xB2\xFD\x48\x9A\x33\x40\x2C\xE8" + "\xE0\x4A\x1F\xB2\x45\xEA\x80\x3D\x0A\xF1" + }, + { /* Ed25519+EdDSA */ + GCRY_PK_ECC, + "(public-key" + " (ecc" + " (curve Ed25519)(flags eddsa)" + " (q #773E72848C1FD5F9652B29E2E7AF79571A04990E96F2016BF4E0EC1890C2B7DB#)" + " ))", + "\x9D\xB6\xC6\x4A\x38\x83\x0F\x49\x60\x70" + "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47" + }, + { /* Ed25519+EdDSA (same but uncompressed)*/ + GCRY_PK_ECC, + "(public-key" + " (ecc" + " (curve Ed25519)(flags eddsa)" + " (q #04" + " 629ad237d1ed04dcd4abe1711dd699a1cf51b1584c4de7a4ef8b8a640180b26f" + " 5bb7c29018ece0f46b01f2960e99041a5779afe7e2292b65f9d51f8c84723e77#)" + " ))", + "\x9D\xB6\xC6\x4A\x38\x83\x0F\x49\x60\x70" + "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47" } - }; + static void check (void) { |