From 0fb0bb8d9a960a2473ab70a021d20639a43227e0 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 31 Jan 2011 09:27:06 +0100 Subject: Reworked the ECC changes to better fit into the Libgcrypt API. See ChangeLog for details. Key generation, signing and verification works. Encryption does not yet work. Requires latest Libgcrypt changes. --- g10/keygen.c | 229 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 125 insertions(+), 104 deletions(-) (limited to 'g10/keygen.c') diff --git a/g10/keygen.c b/g10/keygen.c index b42121b28..4d911f0b9 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1081,7 +1081,107 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk, } +static gpg_error_t +ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo) +{ + gpg_error_t err; + gcry_sexp_t list, l2; + char *curve; + int i; + const char *oidstr; + unsigned int nbits; + + array[0] = NULL; + array[1] = NULL; + array[2] = NULL; + + list = gcry_sexp_find_token (sexp, "public-key", 0); + if (!list) + return gpg_error (GPG_ERR_INV_OBJ); + l2 = gcry_sexp_cadr (list); + gcry_sexp_release (list); + list = l2; + if (!list) + return gpg_error (GPG_ERR_NO_OBJ); + + l2 = gcry_sexp_find_token (list, "curve", 0); + if (!l2) + { + err = gpg_error (GPG_ERR_NO_OBJ); + goto leave; + } + curve = gcry_sexp_nth_string (l2, 1); + if (!curve) + { + err = gpg_error (GPG_ERR_NO_OBJ); + goto leave; + } + gcry_sexp_release (l2); + if (!strcmp (curve, "NIST P-256")) + { + oidstr = "1.2.840.10045.3.1.7"; + nbits = 256; + } + else if (!strcmp (curve, "NIST P-384")) + { + oidstr = "1.3.132.0.34"; + nbits = 384; + } + else if (!strcmp (curve, "NIST P-521")) + { + oidstr = "1.3.132.0.35"; + nbits = 521; + } + else + { + err = gpg_error (GPG_ERR_INV_OBJ); + goto leave; + } + err = openpgp_oid_from_str (oidstr, &array[0]); + if (err) + goto leave; + + l2 = gcry_sexp_find_token (list, "q", 0); + if (!l2) + { + err = gpg_error (GPG_ERR_NO_OBJ); + goto leave; + } + array[1] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (l2); + if (!array[1]) + { + err = gpg_error (GPG_ERR_INV_OBJ); + goto leave; + } + gcry_sexp_release (list); + if (algo == PUBKEY_ALGO_ECDH) + { + array[2] = pk_ecdh_default_params (nbits); + if (!array[2]) + { + err = gpg_error_from_syserror (); + goto leave; + } + } + + leave: + if (err) + { + for (i=0; i < 3; i++) + { + gcry_mpi_release (array[i]); + array[i] = NULL; + } + } + return 0; +} + + +/* Extract key parameters from SEXP and store them in ARRAY. ELEMS is + a string where each character denotes a parameter name. TOPNAME is + the name of the top element above the elements. */ static int key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, const char *topname, const char *elems) @@ -1165,7 +1265,10 @@ common_gen (const char *keyparms, int algo, const char *algoelem, pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; - err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem); + if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH) + err = ecckey_from_sexp (pk->pkey, s_key, algo); + else + err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem); if (err) { log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) ); @@ -1173,7 +1276,6 @@ common_gen (const char *keyparms, int algo, const char *algoelem, free_public_key (pk); return err; } - gcry_sexp_release (s_key); pkt = xtrycalloc (1, sizeof *pkt); if (!pkt) @@ -1329,126 +1431,45 @@ gen_dsa (unsigned int nbits, KBNODE pub_root, -/* Create an S-expression string out of QBITS, ALGO and the TRANSIENT - flag. On success a malloced string is returned, on failure NULL - and ERRNO is set. */ -static char * -pk_ecc_build_key_params (int qbits, int algo, int transient) -{ - byte *kek_params = NULL; - size_t kek_params_size; - char qbitsstr[35]; - char *result; - size_t n; - - /* KEK parameters are only needed for long term key generation. */ - if (!transient && algo == PUBKEY_ALGO_ECDH) - { - kek_params = pk_ecdh_default_params (qbits, &kek_params_size); - if (!kek_params) - return NULL; - } - else - kek_params = NULL; - - snprintf (qbitsstr, sizeof qbitsstr, "%u", qbits); - if (algo == PUBKEY_ALGO_ECDSA || !kek_params) - { - result = xtryasprintf ("(genkey(%s(nbits %zu:%s)" - /**/ "(qbits %zu:%s)" - /**/ "(transient-key 1:%d)))", - algo == PUBKEY_ALGO_ECDSA ? "ecdsa" : "ecdh", - strlen (qbitsstr), qbitsstr, - strlen (qbitsstr), qbitsstr, - transient); - } - else - { - char *tmpstr; - - assert (kek_params); - tmpstr = xtryasprintf ("(genkey(ecdh(nbits %zu:%s)" - /**/ "(qbits %zu:%s)" - /**/ "(transient-key 1:%d)" - /**/ "(kek-params %zu:", - strlen (qbitsstr), qbitsstr, - strlen (qbitsstr), qbitsstr, - transient, - kek_params_size); - if (!tmpstr) - { - xfree (kek_params); - return NULL; - } - /* Append the binary KEK parmas. */ - n = strlen (tmpstr); - result = xtryrealloc (tmpstr, n + kek_params_size + 4); - if (!result) - { - xfree (tmpstr); - xfree (kek_params); - return NULL; - } - memcpy (result + n, kek_params, kek_params_size); - strcpy (result + n + kek_params_size, ")))"); - } - xfree (kek_params); - return result; -} - - /* * Generate an ECC key */ static gpg_error_t -gen_ecc (int algo, unsigned int nbits, KBNODE pub_root, +gen_ecc (int algo, unsigned int nbits, kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, char **cache_nonce_addr) { - int err; - unsigned int qbits; + gpg_error_t err; + const char *curve; char *keyparms; assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH); - if (pubkey_get_npkey (PUBKEY_ALGO_ECDSA) != 2 - || pubkey_get_nskey (PUBKEY_ALGO_ECDSA) != 3 - || pubkey_get_npkey (PUBKEY_ALGO_ECDH) != 3 - || pubkey_get_nskey (PUBKEY_ALGO_ECDH) != 4) - { - log_error ("broken version of Libgcrypt\n"); - return gpg_error (GPG_ERR_INTERNAL); /* ABI silently changed. */ - } - - if (nbits != 256 && nbits != 384 && nbits != 521) - { - log_info (_("keysize invalid; using %u bits\n"), 256); - /* FIXME: Where do we set it to 256? */ - } - - /* Figure out a Q size based on the key size. See gen_dsa for more - details. Due to 8-bit rounding we may get 528 here instead of 521. */ - nbits = qbits = (nbits < 521 ? nbits : 521 ); - - keyparms = pk_ecc_build_key_params - (qbits, algo, !!( (keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) - && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION)) ); + /* For now we may only use one of the 3 NISY curves. */ + if (nbits <= 256) + curve = "NIST P-256"; + else if (nbits <= 384) + curve = "NIST P-384"; + else + curve = "NIST P-521"; + + keyparms = xtryasprintf ("(genkey(%s(curve %zu:%s)%s))", + algo == PUBKEY_ALGO_ECDSA ? "ecdsa" : "ecdh", + strlen (curve), curve, + ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) + && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? + "(transient-key)" : "" ); if (!keyparms) - { - err = gpg_error_from_syserror (); - log_error ("ecc pk_ecc_build_key_params failed: %s\n", - gpg_strerror (err)); - } + err = gpg_error_from_syserror (); else { - err = common_gen (keyparms, algo, - algo == PUBKEY_ALGO_ECDSA? "cq" : "cqp", + err = common_gen (keyparms, algo, "", pub_root, timestamp, expireval, is_subkey, keygen_flags, cache_nonce_addr); xfree (keyparms); } - return 0; + return err; } @@ -2428,7 +2449,7 @@ get_parameter_algo( struct para_data_s *para, enum para_name key, || !strcmp (r->u.value, "ELG")) i = GCRY_PK_ELG_E; else - i = gcry_pk_map_name (r->u.value); + i = map_pk_gcry_to_openpgp (gcry_pk_map_name (r->u.value)); if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S) i = 0; /* we don't want to allow generation of these algorithms */ -- cgit v1.2.3