From e0972d3d962548972872d889b362560e499340d1 Mon Sep 17 00:00:00 2001 From: Andrey Jivsov Date: Wed, 5 Jan 2011 17:33:17 -0800 Subject: Integrating http://code.google.com/p/gnupg-ecc/source/detail?r=15 . The following works: gpg2 --gen-key (ECC) gpg2 --list-keys gpg2 --list-packets ~/.gnupg/pubring.gpg gpg2 --list-packets ECDH doesn't work yet as the code must be re-written to adjust for gpg-agent refactoring. --- g10/export.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'g10/export.c') diff --git a/g10/export.c b/g10/export.c index 91c6a73d7..82d97511f 100644 --- a/g10/export.c +++ b/g10/export.c @@ -1161,6 +1161,18 @@ build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent) /* iobuf_put (out,')'); iobuf_put (out,'\n'); */ /* (*indent)--; */ /* } */ +/* + else if (sk->pubkey_algo == PUBKEY_ALGO_ECDSA && !sk->is_protected) + { + write_sexp_line (out, indent, "(ecdsa\n"); + (*indent)++; + write_sexp_keyparm (out, indent, "c", sk->skey[0]); iobuf_put (out,'\n'); + write_sexp_keyparm (out, indent, "q", sk->skey[6]); iobuf_put (out,'\n'); + write_sexp_keyparm (out, indent, "d", sk->skey[7]); + iobuf_put (out,')'); iobuf_put (out,'\n'); + (*indent)--; + } +*/ /* else if (is_ELGAMAL (sk->pubkey_algo) && !sk->is_protected) */ /* { */ /* write_sexp_line (out, indent, "(elg\n"); */ -- cgit v1.2.3 From 90b0ff23b7e51332592668e4034967c1aac1c593 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 21 Jan 2011 12:00:57 +0100 Subject: Editorial changes and allow building with old libgcrypts. Changed order of some conditional to make to put the special case into the true branch. Indentation changes. Minor other changes to make the ECC code more similar to the rest of our code. It builds but many sefltests still fail. Need to fix that before using it with an ECDH enabled libgcrypt. [/] 2011-01-21 Werner Koch * configure.ac: Need Libgcrypt 1.4.6 due to AESWRAP. (HAVE_GCRY_PK_ECDH): Add new test. [agent/] 2011-01-21 Werner Koch * cvt-openpgp.c (GCRY_PK_ECDH) [!HAVE_GCRY_PK_ECDH]: New. [include/] 2011-01-21 Werner Koch * cipher.h (GCRY_PK_USAGE_CERT): Remove compatibility macros because we now require libgcrypt 1.4.6. (GCRY_PK_ECDH): Add replacement. --- g10/export.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'g10/export.c') diff --git a/g10/export.c b/g10/export.c index 82d97511f..74a7b0c51 100644 --- a/g10/export.c +++ b/g10/export.c @@ -1161,18 +1161,16 @@ build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent) /* iobuf_put (out,')'); iobuf_put (out,'\n'); */ /* (*indent)--; */ /* } */ -/* - else if (sk->pubkey_algo == PUBKEY_ALGO_ECDSA && !sk->is_protected) - { - write_sexp_line (out, indent, "(ecdsa\n"); - (*indent)++; - write_sexp_keyparm (out, indent, "c", sk->skey[0]); iobuf_put (out,'\n'); - write_sexp_keyparm (out, indent, "q", sk->skey[6]); iobuf_put (out,'\n'); - write_sexp_keyparm (out, indent, "d", sk->skey[7]); - iobuf_put (out,')'); iobuf_put (out,'\n'); - (*indent)--; - } -*/ + /* else if (sk->pubkey_algo == PUBKEY_ALGO_ECDSA && !sk->is_protected) */ + /* { */ + /* write_sexp_line (out, indent, "(ecdsa\n"); */ + /* (*indent)++; */ + /* write_sexp_keyparm (out, indent, "c", sk->skey[0]); iobuf_put (out,'\n'); */ + /* write_sexp_keyparm (out, indent, "q", sk->skey[6]); iobuf_put (out,'\n'); */ + /* write_sexp_keyparm (out, indent, "d", sk->skey[7]); */ + /* iobuf_put (out,')'); iobuf_put (out,'\n'); */ + /* (*indent)--; */ + /* } */ /* else if (is_ELGAMAL (sk->pubkey_algo) && !sk->is_protected) */ /* { */ /* write_sexp_line (out, indent, "(elg\n"); */ -- cgit v1.2.3 From 4659c923a08002a72cb4bb5b3c4e6a02d7484767 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 2 Feb 2011 15:48:54 +0100 Subject: Sample ECC keys and message do now work. Import and export of secret keys does now work. Encryption has been fixed to be compatible with the sample messages. This version tests for new Libgcrypt function and thus needs to be build with a new Libgcrypt installed. --- g10/export.c | 148 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 113 insertions(+), 35 deletions(-) (limited to 'g10/export.c') diff --git a/g10/export.c b/g10/export.c index 1eb0baa8b..91a6c87f1 100644 --- a/g10/export.c +++ b/g10/export.c @@ -107,7 +107,7 @@ export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, kbnode_t *keyblock_out, unsigned int options ) { int any, rc; - + rc = do_export_stream (ctrl, out, users, 0, keyblock_out, options, &any); if (!rc && !any) rc = -1; @@ -197,9 +197,9 @@ do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options ) int any, rc; armor_filter_context_t *afx = NULL; compress_filter_context_t zfx; - + memset( &zfx, 0, sizeof zfx); - + rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, &out ); if (rc) return rc; @@ -251,7 +251,7 @@ subkey_in_list_p (subkey_list_t list, KBNODE node) u32 kid[2]; keyid_from_pk (node->pkt->pkt.public_key, kid); - + for (; list; list = list->next) if (list->kid[0] == kid[0] && list->kid[1] == kid[1]) return 1; @@ -293,17 +293,17 @@ exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node) case KEYDB_SEARCH_MODE_LONG_KID: keyid_from_pk (node->pkt->pkt.public_key, kid); break; - + case KEYDB_SEARCH_MODE_FPR16: case KEYDB_SEARCH_MODE_FPR20: case KEYDB_SEARCH_MODE_FPR: fingerprint_from_pk (node->pkt->pkt.public_key, fpr,&fprlen); break; - + default: break; } - + switch(desc->mode) { case KEYDB_SEARCH_MODE_SHORT_KID: @@ -346,7 +346,7 @@ canon_pubkey_algo (int algo) case GCRY_PK_RSA: case GCRY_PK_RSA_E: case GCRY_PK_RSA_S: return GCRY_PK_RSA; - case GCRY_PK_ELG: + case GCRY_PK_ELG: case GCRY_PK_ELG_E: return GCRY_PK_ELG; default: return algo; } @@ -354,7 +354,7 @@ canon_pubkey_algo (int algo) /* Use the key transfer format given in S_PGP to create the secinfo - structure in PK and chnage the parameter array in PK to include the + structure in PK and change the parameter array in PK to include the secret parameters. */ static gpg_error_t transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) @@ -415,7 +415,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) goto bad_seckey; protect_algo = gcry_cipher_map_name (string); xfree (string); - + value = gcry_sexp_nth_data (list, 3, &valuelen); if (!value || !valuelen || valuelen > sizeof iv) goto bad_seckey; @@ -460,6 +460,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) || gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey) || !npkey || npkey >= nskey || nskey > PUBKEY_MAX_NSKEY) goto bad_seckey; + pubkey_algo = map_pk_gcry_to_openpgp (pubkey_algo); gcry_sexp_release (list); list = gcry_sexp_find_token (top_list, "skey", 0); @@ -557,6 +558,77 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) goto leave; } + /* We need to change the received parameters for ECC algorithms. + The transfer format has all parameters but OpenPGP defines that + only the OID of the curve is to be used. */ + if (pubkey_algo == PUBKEY_ALGO_ECDSA || pubkey_algo == PUBKEY_ALGO_ECDH) + { + gcry_sexp_t s_pubkey; + const char *curvename, *curveoidstr; + gcry_mpi_t mpi; + + /* We build an S-expression with the public key parameters and + ask Libgcrypt to return the matching curve name. */ + if (npkey != 6 || !skey[0] || !skey[1] || !skey[2] + || !skey[3] || !skey[4] || !skey[5] + || !skey[6] || skey[7]) + { + err = gpg_error (GPG_ERR_INTERNAL); + goto leave; + } + err = gcry_sexp_build (&s_pubkey, NULL, + "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)))", + skey[0], skey[1], skey[2], skey[3], skey[4]); + if (err) + goto leave; +#ifdef HAVE_GCRY_PK_GET_CURVE + curvename = gcry_pk_get_curve (s_pubkey, 0, NULL); +#else + curvename = "?"; +#endif + gcry_sexp_release (s_pubkey); + curveoidstr = gpg_curve_to_oid (curvename, NULL); + if (!curveoidstr) + { + log_error ("no OID known for curve `%s'\n", curvename); + err = gpg_error (GPG_ERR_UNKNOWN_NAME); + goto leave; + } + err = openpgp_oid_from_str (curveoidstr, &mpi); + if (err) + goto leave; + + /* Now replace the curve parameters by the OID and shift the + rest of the parameters. */ + gcry_mpi_release (skey[0]); + skey[0] = mpi; + for (idx=1; idx <= 4; idx++) + gcry_mpi_release (skey[idx]); + skey[1] = skey[5]; + skey[2] = skey[6]; + for (idx=3; idx <= 6; idx++) + skey[idx] = NULL; + + /* Fixup the NPKEY and NSKEY to match OpenPGP reality. */ + npkey = 2; + nskey = 3; + + /* for (idx=0; skey[idx]; idx++) */ + /* { */ + /* log_info ("YYY skey[%d]:", idx); */ + /* if (gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE)) */ + /* { */ + /* void *p; */ + /* unsigned int nbits; */ + /* p = gcry_mpi_get_opaque (skey[idx], &nbits); */ + /* log_printhex (NULL, p, (nbits+7)/8); */ + /* } */ + /* else */ + /* gcry_mpi_dump (skey[idx]); */ + /* log_printf ("\n"); */ + /* } */ + } + /* Do some sanity checks. */ if (s2k_count <= 1024) { @@ -576,11 +648,17 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) err = openpgp_md_test_algo (s2k_algo); if (err) goto leave; - - /* Check that the public key parameters match. */ + + /* Check that the public key parameters match. Since Libgcrypt 1.5 + and the gcry_pk_get_curve function, gcry_mpi_cmp handles opaque + MPI correctly and thus we don't need to to do the extra + opaqueness checks. */ for (idx=0; idx < npkey; idx++) - if (gcry_mpi_get_flag (pk->pkey[idx], GCRYMPI_FLAG_OPAQUE) + if (0 +#ifndef HAVE_GCRY_PK_GET_CURVE + gcry_mpi_get_flag (pk->pkey[idx], GCRYMPI_FLAG_OPAQUE) || gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE) +#endif || gcry_mpi_cmp (pk->pkey[idx], skey[idx])) { err = gpg_error (GPG_ERR_BAD_PUBKEY); @@ -607,7 +685,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) err = gpg_error_from_syserror (); goto leave; } - + ski->is_protected = 1; ski->sha1chk = 1; ski->algo = protect_algo; @@ -636,7 +714,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) bad_seckey: err = gpg_error (GPG_ERR_BAD_SECKEY); goto leave; - + outofmem: err = gpg_error (GPG_ERR_ENOMEM); goto leave; @@ -671,7 +749,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, init_packet (&pkt); kdbhd = keydb_new (); - if (!users) + if (!users) { ndesc = 1; desc = xcalloc (ndesc, sizeof *desc); @@ -679,10 +757,10 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, } else { - for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++) + for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++) ; desc = xmalloc ( ndesc * sizeof *desc); - + for (ndesc=0, sl=users; sl; sl = sl->next) { if (!(err=classify_user_id (sl->d, desc+ndesc))) @@ -708,7 +786,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, goto leave; } #endif - + /* For secret key export we need to setup a decryption context. */ if (secret) { @@ -721,7 +799,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, log_error ("error getting the KEK: %s\n", gpg_strerror (err)); goto leave; } - + /* Prepare a cipher context. */ err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_AESWRAP, 0); @@ -737,20 +815,20 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, kek = NULL; } - while (!(err = keydb_search2 (kdbhd, desc, ndesc, &descindex))) + while (!(err = keydb_search2 (kdbhd, desc, ndesc, &descindex))) { int skip_until_subkey = 0; u32 keyid[2]; PKT_public_key *pk; - if (!users) + if (!users) desc[0].mode = KEYDB_SEARCH_MODE_NEXT; /* Read the keyblock. */ release_kbnode (keyblock); keyblock = NULL; err = keydb_get_keyblock (kdbhd, &keyblock); - if (err) + if (err) { log_error (_("error reading keyblock: %s\n"), gpg_strerror (err)); goto leave; @@ -802,7 +880,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, clean_key (keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL); /* And write it. */ - for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); ) + for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); ) { if (skip_until_subkey) { @@ -835,7 +913,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, subkey and include that subkey into the output too. Need to add this subkey to a list so that it won't get processed a second time. - + So the first step here is to check that list and skip in any case if the key is in that list. @@ -843,7 +921,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, function of GnuPG < 2.1 is not able to merge secret keys and thus it is useless to output them as two separate keys and have import merge them. */ - if (subkey_in_list_p (subkey_list, node)) + if (subkey_in_list_p (subkey_list, node)) skip_until_subkey = 1; /* Already processed this one. */ else { @@ -854,7 +932,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, && exact_subkey_match_p (desc+j, node)) break; if (!(j < ndesc)) - skip_until_subkey = 1; /* No other one matching. */ + skip_until_subkey = 1; /* No other one matching. */ } } @@ -885,7 +963,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, && node->pkt->pkt.signature->revkey) { int i; - + for (i=0;ipkt->pkt.signature->numrevkeys;i++) if ( (node->pkt->pkt.signature->revkey[i]->class & 0x40)) break; @@ -904,7 +982,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, or a signature on an attrib */ while (kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE) kbctx = kbctx->next; - + continue; } @@ -913,7 +991,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, { u32 subkidbuf[2], *subkid; char *hexgrip, *serialno; - + pk = node->pkt->pkt.public_key; if (node->pkt->pkttype == PKT_PUBLIC_KEY) subkid = NULL; @@ -930,7 +1008,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, skip_until_subkey = 1; continue; } - + err = hexkeygrip_from_pk (pk, &hexgrip); if (err) { @@ -970,7 +1048,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, /* Create a key stub. */ struct seckey_info *ski; const char *s; - + pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); if (!ski) { @@ -989,7 +1067,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, ski->ivlen++, s += 2) ski->iv[ski->ivlen] = xtoi_2 (s); } - + if ((options&EXPORT_SEXP_FORMAT)) err = build_sexp (out, node->pkt, &indent); else @@ -1032,7 +1110,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err); if (!realkeylen) goto unwraperror; /* Invalid csexp. */ - + err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen); xfree (key); key = NULL; @@ -1252,7 +1330,7 @@ build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent) /* For some packet types we write them in a S-expression format. This is still EXPERIMENTAL and subject to change. */ -static int +static int build_sexp (iobuf_t out, PACKET *pkt, int *indent) { int rc; -- cgit v1.2.3