From gniibe at fsij.org Thu Apr 3 10:03:06 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Thu, 03 Apr 2014 17:03:06 +0900 Subject: Smartcard EdDSA Support In-Reply-To: <871txqo24v.fsf@vigenere.g10code.de> References: <1395733394.6984.2.camel@cfw2.gniibe.org> <871txqo24v.fsf@vigenere.g10code.de> Message-ID: <1396512186.15238.3.camel@cfw2.gniibe.org> Hello, Thank you for your comment. I've integrated the EdDSA code into Gnuk. Now, I can login using OpenSSH with Gnuk Token by EdDSA. Here is a patch to master branch of GnuPG, to show it's not that large. I need to clean up this before commit. I know there is still at least a bug for MPI/opaque-bytes. -- diff --git a/agent/pksign.c b/agent/pksign.c index fb593a6..94d1584 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -324,12 +324,18 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, int key_type; int is_RSA = 0; int is_ECDSA = 0; + int is_EdDSA = 0; - key_type = agent_is_dsa_key (s_skey); - if (key_type == 0) - is_RSA = 1; - else if (key_type == GCRY_PK_ECDSA) - is_ECDSA = 1; + if (agent_is_eddsa_key (s_skey)) + is_EdDSA = 1; + else + { + key_type = agent_is_dsa_key (s_skey); + if (key_type == 0) + is_RSA = 1; + else if (key_type == GCRY_PK_ECDSA) + is_ECDSA = 1; + } rc = divert_pksign (ctrl, data, datalen, @@ -356,6 +362,24 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%b)))", len, buf); } + else if (is_EdDSA) + { + unsigned char *r_buf_allocated = NULL; + unsigned char *s_buf_allocated = NULL; + unsigned char *r_buf, *s_buf; + int r_buflen, s_buflen; + + r_buflen = s_buflen = len/2; + + r_buf = buf; + s_buf = buf + len/2; + + rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(eddsa(r%b)(s%b)))", + r_buflen, r_buf, + s_buflen, s_buf); + xfree (r_buf_allocated); + xfree (s_buf_allocated); + } else if (is_ECDSA) { unsigned char *r_buf_allocated = NULL; diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c index a2a3617..94a2296 100644 --- a/common/openpgp-oid.c +++ b/common/openpgp-oid.c @@ -39,7 +39,7 @@ /* The OID for Curve Ed25519 in OpenPGP format. */ static const char oid_ed25519[] = - { 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 }; + { 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 }; /* Helper for openpgp_oid_from_str. */ diff --git a/g10/keygen.c b/g10/keygen.c index 135699d..f3052e4 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -4031,7 +4031,11 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock) else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) - curve = ask_curve (); + { + curve = ask_curve (); + if (curve && !strcmp (curve, "Ed25519")) + algo = PUBKEY_ALGO_EDDSA; + } else nbits = ask_keysize (algo, 0); diff --git a/g10/keyid.c b/g10/keyid.c index 9ed64a4..4ce77aa 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -813,7 +813,9 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array) else { err = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecc(curve%s)(q%m)))", + pk->pubkey_algo == PUBKEY_ALGO_EDDSA ? + "(public-key(ecc(curve%s)(flags eddsa)(q%m)))" + : "(public-key(ecc(curve%s)(q%m)))", curve, pk->pkey[1]); xfree (curve); } diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index da1bec9..4c14e91 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -122,6 +122,7 @@ typedef enum { KEY_TYPE_ECDH, KEY_TYPE_ECDSA, + KEY_TYPE_EDDSA, KEY_TYPE_RSA, } key_type_t; @@ -146,7 +147,8 @@ enum CURVE_NIST_P384, CURVE_NIST_P521, CURVE_SEC_P256K1, - CURVE_UNKOWN, + CURVE_ED25519, + CURVE_UNKNOWN, }; @@ -238,6 +240,10 @@ struct app_local_s { struct { int curve; int hashalgo; + } eddsa; + struct { + int curve; + int hashalgo; int cipheralgo; } ecdh; }; @@ -746,6 +752,8 @@ get_algo_byte (key_type_t key_type) return 19; else if (key_type == KEY_TYPE_ECDH) return 18; + else if (key_type == KEY_TYPE_EDDSA) + return 105; /* (experimental) */ else return 1; /* RSA */ } @@ -770,7 +778,8 @@ store_fpr (app_t app, int keynumber, u32 timestamp, int i; n = 6; /* key packet version, 4-byte timestamps, and algorithm */ - if (key_type == KEY_TYPE_RSA || key_type == KEY_TYPE_ECDSA) + if (key_type == KEY_TYPE_RSA || key_type == KEY_TYPE_ECDSA + || key_type == KEY_TYPE_EDDSA) argc = 2; else if (key_type == KEY_TYPE_ECDH) argc = 3; @@ -935,11 +944,21 @@ get_ecc_key_parameters (int curve, int *r_n_bits, const char **r_curve_oid) *r_n_bits = 521; *r_curve_oid = "1.3.132.0.35"; } - else + else if (curve == CURVE_SEC_P256K1) { *r_n_bits = 256; *r_curve_oid = "1.3.132.0.10"; } + else if (curve == CURVE_ED25519) + { + *r_n_bits = 256; + *r_curve_oid = "1.3.6.1.4.1.11591.15.1"; + } + else + { + *r_n_bits = 0; + *r_curve_oid = "1.3.6.1.4.1.11591.2.12242973"; /* gnu.gnupg.badoid */ + } } static void @@ -973,6 +992,15 @@ send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int number) app->app_local->keyattr[number].ecdh.hashalgo, app->app_local->keyattr[number].ecdh.cipheralgo); } + else if (app->app_local->keyattr[number].key_type == KEY_TYPE_EDDSA) + { + get_ecc_key_parameters (app->app_local->keyattr[number].eddsa.curve, + &n_bits, &curve_oid); + snprintf (buffer, sizeof buffer, "%d 105 %u %d %s", + number+1, n_bits, + app->app_local->keyattr[number].ecdh.hashalgo, + curve_oid); + } else snprintf (buffer, sizeof buffer, "0 0 UNKNOWN"); @@ -1282,8 +1310,12 @@ get_curve_name (int curve) return "NIST P-384"; else if (curve == CURVE_NIST_P521) return "NIST P-521"; - else + else if (curve == CURVE_SEC_P256K1) return "secp256k1"; + else if (curve == CURVE_ED25519) + return "Ed25519"; + else + return "unknown"; } @@ -1455,7 +1487,8 @@ get_public_key (app_t app, int keyno) goto leave; } /* Prepend numbers with a 0 if needed. */ - if (mlen && (*m & 0x80)) + if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_EDDSA + && mlen && (*m & 0x80)) { *mbuf = 0; memcpy (mbuf+1, m, mlen); @@ -1521,6 +1554,29 @@ get_public_key (app_t app, int keyno) gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len); gcry_sexp_release (s_pkey); } + else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_EDDSA) + { + const char *curve_name + = get_curve_name (app->app_local->keyattr[keyno].eddsa.curve); + + err = gcry_sexp_build (&s_pkey, NULL, + "(public-key(ecc(curve%s)(flags eddsa)(q%b)))", + curve_name, mlen, mbuf); + if (err) + goto leave; + + len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0); + + keybuf = xtrymalloc (len); + if (!keybuf) + { + gcry_sexp_release (s_pkey); + err = gpg_error_from_syserror (); + goto leave; + } + gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len); + gcry_sexp_release (s_pkey); + } else { err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); @@ -2695,9 +2751,9 @@ build_privkey_template (app_t app, int keyno, } static gpg_error_t -build_ecdsa_privkey_template (app_t app, int keyno, - const unsigned char *ecc_d, size_t ecc_d_len, - unsigned char **result, size_t *resultlen) +build_ecc_privkey_template (app_t app, int keyno, + const unsigned char *ecc_d, size_t ecc_d_len, + unsigned char **result, size_t *resultlen) { unsigned char privkey[2]; size_t privkey_len; @@ -3179,9 +3235,9 @@ ecdh_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), static gpg_error_t -ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), - void *pincb_arg, int keyno, - const unsigned char *buf, size_t buflen, int depth) +ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, int keyno, + const unsigned char *buf, size_t buflen, int depth) { gpg_error_t err; const unsigned char *tok; @@ -3194,10 +3250,15 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), size_t template_len; unsigned char fprbuf[20]; u32 created_at = 0; - int curve = CURVE_UNKOWN; - - /* (private-key(ecdsa(curve%s)(q%m)(d%m))): curve = "1.2.840.10045.3.1.7" */ - /* (private-key(ecc(curve%s)(q%m)(d%m))): curve = "secp256k1" */ + int curve = CURVE_UNKNOWN; + + /* (private-key(ecdsa(curve%s)(q%m)(d%m))(created-at%d)): + curve = "1.2.840.10045.3.1.7" */ + /* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)): + curve = "secp256k1" */ + /* (private-key(ecc(curve%s)(flags eddsa)(q%b)(d%b))(created-at%d)): + curve = "Ed25519" */ + log_printhex ("q: ", buf, buflen); last_depth1 = depth; while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) && depth && depth >= last_depth1) @@ -3219,33 +3280,34 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), curve = CURVE_NIST_P256; else if (tok && toklen == 9 && !memcmp (tok, "secp256k1", 9)) curve = CURVE_SEC_P256K1; + else if (tok && toklen == 7 && !memcmp (tok, "Ed25519", 7)) + curve = CURVE_ED25519; } else if (tok && toklen == 1) { - const unsigned char **mpi; - size_t *mpi_len; + const unsigned char **buf2; + size_t *buf2len; switch (*tok) { - case 'q': mpi = &ecc_q; mpi_len = &ecc_q_len; break; - case 'd': mpi = &ecc_d; mpi_len = &ecc_d_len; break; - default: mpi = NULL; mpi_len = NULL; break; + case 'q': buf2 = &ecc_q; buf2len = &ecc_q_len; break; + case 'd': buf2 = &ecc_d; buf2len = &ecc_d_len; break; + default: buf2 = NULL; buf2len = NULL; break; } - if (mpi && *mpi) + if (buf2 && *buf2) { err = gpg_error (GPG_ERR_DUP_VALUE); goto leave; } if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) goto leave; - if (tok && mpi) - { - /* Strip off leading zero bytes and save. */ - for (;toklen && !*tok; toklen--, tok++) - ; - *mpi = tok; - *mpi_len = toklen; - } + if (tok && buf2 && curve != CURVE_ED25519) + /* It's MPI. Strip off leading zero bytes and save. */ + for (;toklen && !*tok; toklen--, tok++) + ; + + *buf2 = tok; + *buf2len = toklen; } /* Skip until end of list. */ last_depth2 = depth; @@ -3312,9 +3374,9 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), the OpenPGP card specs version 2.0. */ int exmode; - err = build_ecdsa_privkey_template (app, keyno, - ecc_d, ecc_d_len, - &template, &template_len); + err = build_ecc_privkey_template (app, keyno, + ecc_d, ecc_d_len, + &template, &template_len); if (err) goto leave; @@ -3343,11 +3405,14 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), } err = store_fpr (app, keyno, created_at, fprbuf, app->card_version, - KEY_TYPE_ECDSA, - curve == CURVE_NIST_P256? + curve == CURVE_ED25519 ? KEY_TYPE_EDDSA : KEY_TYPE_ECDSA, + curve == CURVE_ED25519 ? + "\x09\x2b\x06\x01\x04\x01\xda\x47\x0f\x01" + : curve == CURVE_NIST_P256 ? "\x08\x2a\x86\x48\xce\x3d\x03\x01\x07" : "\05\x2b\x81\x04\x00\x0a", - curve == CURVE_NIST_P256? 9 : 6, + curve == CURVE_ED25519 ? 10 + : curve == CURVE_NIST_P256? 9 : 6, ecc_q, ecc_q_len); if (err) goto leave; @@ -3425,7 +3490,7 @@ do_writekey (app_t app, ctrl_t ctrl, else if ((tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0 && (keyno == 0 || keyno == 2)) || (tok && toklen == 5 && memcmp ("ecdsa", tok, toklen) == 0)) - ecdsa_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth); + ecc_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth); else if ((tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0 && keyno == 1) || (tok && toklen == 4 && memcmp ("ecdh", tok, toklen) == 0)) @@ -3912,7 +3977,8 @@ do_auth (app_t app, const char *keyidstr, if (!keyidstr || !*keyidstr) return gpg_error (GPG_ERR_INV_VALUE); - if (indatalen > 101) /* For a 2048 bit key. */ + if (app->app_local->keyattr[2].key_type == KEY_TYPE_RSA + && indatalen > 101) /* For a 2048 bit key. */ return gpg_error (GPG_ERR_INV_VALUE); if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECDSA @@ -3922,6 +3988,12 @@ do_auth (app_t app, const char *keyidstr, indata = p; indatalen -= 19; } + else if (app->app_local->keyattr[2].key_type == KEY_TYPE_EDDSA) + { + const char *p = (const char *)indata + 15; + indata = p; + indatalen -= 15; + } /* Check whether an OpenPGP card of any version has been requested. */ if (!strcmp (keyidstr, "OPENPGP.3")) @@ -4298,14 +4370,18 @@ parse_ecc_curve (const unsigned char *buffer, size_t buflen) { int curve; - if (buflen == 6 && buffer[5] == 0x22) + if (buflen == 5 && buffer[5] == 0x22) curve = CURVE_NIST_P384; - else if (buflen == 6 && buffer[5] == 0x23) + else if (buflen == 5 && buffer[5] == 0x23) curve = CURVE_NIST_P521; - else if (buflen == 9) + else if (buflen == 8) curve = CURVE_NIST_P256; - else + else if (buflen == 5 && buffer[5] == 0x0a) curve = CURVE_SEC_P256K1; + else if (buflen == 9) + curve = CURVE_ED25519; + else + curve = CURVE_UNKNOWN; return curve; } @@ -4374,10 +4450,17 @@ parse_algorithm_attribute (app_t app, int keyno) else if (*buffer == 18 && buflen == 11) /* ECDH */ { app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECDH; - app->app_local->keyattr[keyno].ecdh.curve - = parse_ecc_curve (buffer + 1, buflen - 1); app->app_local->keyattr[keyno].ecdh.hashalgo = buffer[1]; app->app_local->keyattr[keyno].ecdh.cipheralgo = buffer[2]; + app->app_local->keyattr[keyno].ecdh.curve + = parse_ecc_curve (buffer + 3, buflen - 3); + } + else if (*buffer == 105) /* EdDSA (experimental) */ + { + app->app_local->keyattr[keyno].key_type = KEY_TYPE_EDDSA; + app->app_local->keyattr[keyno].eddsa.hashalgo = buffer[1]; + app->app_local->keyattr[keyno].eddsa.curve + = parse_ecc_curve (buffer + 2, buflen - 2); } else if (opt.verbose) log_printhex ("", buffer, buflen); From gniibe at fsij.org Thu Apr 3 10:20:29 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Thu, 03 Apr 2014 17:20:29 +0900 Subject: Smartcard EdDSA Support In-Reply-To: <1396512186.15238.3.camel@cfw2.gniibe.org> References: <1395733394.6984.2.camel@cfw2.gniibe.org> <871txqo24v.fsf@vigenere.g10code.de> <1396512186.15238.3.camel@cfw2.gniibe.org> Message-ID: <1396513229.15238.4.camel@cfw2.gniibe.org> On 2014-04-03 at 17:03 +0900, NIIBE Yutaka wrote: > Now, I can login using OpenSSH with Gnuk Token by EdDSA. Here is timing information. For OpenSSH login to my Sheeva Plug, it takes about 0.4 second. Signing only, looping 1000 times for gpg-connect-agent's "SCD SETDATA XXXX..." and "SCD PKAUTH OPENPGP.3", it takes about 58 seconds. -- From gniibe at fsij.org Fri Apr 4 04:01:53 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Fri, 04 Apr 2014 11:01:53 +0900 Subject: [PATCH] agent: EdDSA support for SSH Message-ID: <1396576913.7580.2.camel@cfw2.gniibe.org> Hello, I encountered login authentication failures of SSH with EdDSA key, and located a bug. When it failed, I found 63-byte signature returned by GPG-Agent, while it should be 64-byte. When the first byte of the value "r" is "00", it was omitted. This was occurred because the value was interpreted as MPI (big endian number). (It was actually little endian number.) Here is a fix. I will update my patch for smartcard support, soon. * agent/command-ssh.c (ssh_signature_encoder_eddsa): Signature is two 32-byte opaque data which should not be interpreted as number. OK to apply? diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 04fe049..4407382 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -1617,15 +1617,13 @@ ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec, gpg_error_t err = 0; gcry_sexp_t valuelist = NULL; gcry_sexp_t sublist = NULL; - gcry_mpi_t sig_value = NULL; - gcry_mpi_t *mpis = NULL; const char *elems; size_t elems_n; int i; unsigned char *data[2] = {NULL, NULL}; size_t data_n[2]; - size_t totallen; + size_t totallen = 0; valuelist = gcry_sexp_nth (s_signature, 1); if (!valuelist) @@ -1637,14 +1635,13 @@ ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec, elems = spec->elems_signature; elems_n = strlen (elems); - mpis = xtrycalloc (elems_n + 1, sizeof *mpis); - if (!mpis) + if (elems_n != DIM(data)) { - err = gpg_error_from_syserror (); + err = gpg_error (GPG_ERR_INV_SEXP); goto out; } - for (i = 0; i < elems_n; i++) + for (i = 0; i < DIM(data); i++) { sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1); if (!sublist) @@ -1653,31 +1650,19 @@ ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec, break; } - sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG); - if (!sig_value) + data[i] = gcry_sexp_nth_buffer (sublist, 1, &data_n[i]); + if (!data[i]) { err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */ break; } + totallen += data_n[i]; gcry_sexp_release (sublist); sublist = NULL; - - mpis[i] = sig_value; } if (err) goto out; - /* EdDSA specific. Actually TOTALLEN will always be 64. */ - - totallen = 0; - for (i = 0; i < DIM(data); i++) - { - err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &data[i], &data_n[i], mpis[i]); - if (err) - goto out; - totallen += data_n[i]; - } - gcry_log_debug (" out: len=%zu\n", totallen); err = stream_write_uint32 (stream, totallen); if (err) @@ -1696,7 +1681,6 @@ ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec, xfree (data[i]); gcry_sexp_release (valuelist); gcry_sexp_release (sublist); - mpint_list_free (mpis); return err; } -- From wk at gnupg.org Fri Apr 4 08:08:47 2014 From: wk at gnupg.org (Werner Koch) Date: Fri, 04 Apr 2014 08:08:47 +0200 Subject: [PATCH] agent: EdDSA support for SSH In-Reply-To: <1396576913.7580.2.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Fri, 04 Apr 2014 11:01:53 +0900") References: <1396576913.7580.2.camel@cfw2.gniibe.org> Message-ID: <87txa9iq34.fsf@vigenere.g10code.de> On Fri, 4 Apr 2014 04:01, gniibe at fsij.org said: > it should be 64-byte. When the first byte of the value "r" is "00", > it was omitted. This was occurred because the value was interpreted It is always the same problem :-(. I should have used opaque MPI (binary buffer stored in an MPI object) here. The EdDSA code in Libgcrypt allows for that. > OK to apply? Sure Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From edfinnerty at gmx.com Fri Apr 4 08:16:11 2014 From: edfinnerty at gmx.com (Ed Finnerty) Date: Fri, 04 Apr 2014 09:16:11 +0300 Subject: NSS 3.16 incompatibility In-Reply-To: <53389593.80602@gmx.com> References: <53389593.80602@gmx.com> Message-ID: <533E4E2B.1040308@gmx.com> > Running this script: > > [...] > > Will eventually produce this output: > > NSS has been initialized. > Got default certdb > cmsutil: failed to decode message. > cmsutil: problem decoding: SEC_ERROR_BAD_DATABASE: security library: bad > database. I've also reported the problem to the NSS team: https://bugzilla.mozilla.org/show_bug.cgi?id=990958 I don't know if this is a problem with NSS not being able to handle a special case of CMS encoding, or if GnuPG's gpgsm produces non-compliant output. From gniibe at fsij.org Fri Apr 4 10:00:03 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Fri, 04 Apr 2014 17:00:03 +0900 Subject: [PATCH] agent: EdDSA support for SSH In-Reply-To: <87txa9iq34.fsf@vigenere.g10code.de> References: <1396576913.7580.2.camel@cfw2.gniibe.org> <87txa9iq34.fsf@vigenere.g10code.de> Message-ID: <1396598403.7834.1.camel@cfw2.gniibe.org> Thank you for your review. The patch was applied, committed, and pushed. On 2014-04-04 at 08:08 +0200, Werner Koch wrote: > I should have used opaque MPI (binary buffer stored in an MPI > object) here. The EdDSA code in Libgcrypt allows for that. I learned the code in Libgcrypt, a bit. IIUC, we can handle opaque binary data by MPI with GCRYMPI_FLAG_OPAQUE. Here, I think that we need to use GCRYMPI_FMT_USG format for gcry_mpi_print, and we need to use "%M" expression for gcry_sexp_build. For the latter, I think that following patch should be applied. I put conditionally adding "(flags eddsa)" for keygrip_from_pk in g10/keyid.c, too. diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 364a8cc..4407382 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -1721,7 +1721,7 @@ sexp_key_construct (gcry_sexp_t *r_sexp, else if (secret) err = gcry_sexp_build (&sexp_new, NULL, "(private-key(ecc(curve %s)" - "(flags eddsa)(q %m)(d %m))" + "(flags eddsa)(q %M)(d %M))" "(comment%s))", curve_name, mpis[0], mpis[1], @@ -1729,7 +1729,7 @@ sexp_key_construct (gcry_sexp_t *r_sexp, else err = gcry_sexp_build (&sexp_new, NULL, "(public-key(ecc(curve %s)" - "(flags eddsa)(q %m))" + "(flags eddsa)(q %M))" "(comment%s))", curve_name, mpis[0], @@ -2257,7 +2257,7 @@ ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret, { err = gcry_sexp_build (&key, NULL, "(private-key(ecc(curve \"Ed25519\")" - "(flags eddsa)(q %m)(d %m))" + "(flags eddsa)(q %M)(d %M))" "(comment%s))", mpi_list[0], mpi_list[1], comment? comment:""); @@ -2266,7 +2266,7 @@ ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret, { err = gcry_sexp_build (&key, NULL, "(public-key(ecc(curve \"Ed25519\")" - "(flags eddsa)(q %m))" + "(flags eddsa)(q %M))" "(comment%s))", mpi_list[0], comment? comment:""); diff --git a/g10/keyid.c b/g10/keyid.c index 9ed64a4..a63ee97 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -813,7 +813,9 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array) else { err = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecc(curve%s)(q%m)))", + pk->pubkey_algo == PUBKEY_ALGO_EDDSA ? + "(public-key(ecc(curve%s)(flags eddsa)(q%M)))" + : "(public-key(ecc(curve%s)(q%m)))", curve, pk->pkey[1]); xfree (curve); } diff --git a/g10/pkglue.c b/g10/pkglue.c index 67d2efd..3dcb8c5 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -100,7 +100,7 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash, { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(ecc(curve %s)" - "(flags eddsa)(q%m)))", + "(flags eddsa)(q%M)))", curve, pkey[1]); xfree (curve); } @@ -115,7 +115,7 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash, if (pkalgo == PUBKEY_ALGO_EDDSA) { if (gcry_sexp_build (&s_hash, NULL, - "(data(flags eddsa)(hash-algo sha512)(value %m))", + "(data(flags eddsa)(hash-algo sha512)(value %M))", hash)) BUG (); /* gcry_sexp_build should never fail. */ } @@ -347,7 +347,7 @@ pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey) { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(ecc(curve %s)" - "(flags eddsa)(q%m)(d%m)))", + "(flags eddsa)(q%M)(d%M)))", curve, skey[1], skey[2]); xfree (curve); } -- From pete at petertodd.org Fri Apr 4 10:46:32 2014 From: pete at petertodd.org (Peter Todd) Date: Fri, 4 Apr 2014 10:46:32 +0200 Subject: Prototyping OpenPGP extensions/signing arbitrary packets Message-ID: <20140404084612.GJ9786@tilt> I'm working on prototyping a new OpenPGP user attribute to allow users to tie Bitcoin addresses to their OpenPGP identities. The goal is to allow the WoT to be used as a means of ensuring that a Bitcoin payment goes to the intended recipient. For instance if I wanted to give funds to Werner Koch my wallet software could extract the address(1) from his OpenPGP, itself verified by the WoT, and pay to that address. Additionally I were using a multifactor/multisig wallet where spending my funds required signing the payment on multiple machines, perhaps my main desktop and a secure air-gapped laptop, the second machine could also verify where the funds were going by the same OpenPGP key/WoT. For my prototype I have a small Python program that generates the user attribute with version of the python-pgpdump library, modified by me to create packets as well as decode them. However to actually sign the packet it seems the only possible way is to import the key with --allow-non-selfsigned-uid option and use the --expert option to override the normal restriction on signing non-selfsigned UIDs. GPGME appears to be the only interface to the GnuPG engine, and it's too high-level to be able to sign arbitrary packets or hashes. Is there another way to do this that I've missed? 1) While standard Bitcoin addresses are not meant to be reused for privacy reasons, I'm also simultaneously working on a new address standard - Stealth Addresses - for which address re-use does not harm privacy. -- 'peter'[:-1]@petertodd.org 0000000000000000f4f5ba334791a4102917e4d3f22f6ad7f2c4f15d97307fe2 -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 665 bytes Desc: Digital signature URL: From wk at gnupg.org Fri Apr 4 22:19:35 2014 From: wk at gnupg.org (Werner Koch) Date: Fri, 04 Apr 2014 22:19:35 +0200 Subject: Prototyping OpenPGP extensions/signing arbitrary packets In-Reply-To: <20140404084612.GJ9786@tilt> (Peter Todd's message of "Fri, 4 Apr 2014 10:46:32 +0200") References: <20140404084612.GJ9786@tilt> Message-ID: <87mwg0hmp4.fsf@vigenere.g10code.de> On Fri, 4 Apr 2014 10:46, pete at petertodd.org said: > For my prototype I have a small Python program that generates the user > attribute with version of the python-pgpdump library, modified by me to I am not sure what you mean by user attribute. I would use a notation to tie something to a user id and let gpg handle the creation (--edit-key , notation). Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From dshaw at jabberwocky.com Sat Apr 5 03:12:00 2014 From: dshaw at jabberwocky.com (David Shaw) Date: Fri, 4 Apr 2014 21:12:00 -0400 Subject: Prototyping OpenPGP extensions/signing arbitrary packets In-Reply-To: <87mwg0hmp4.fsf@vigenere.g10code.de> References: <20140404084612.GJ9786@tilt> <87mwg0hmp4.fsf@vigenere.g10code.de> Message-ID: On Apr 4, 2014, at 4:19 PM, Werner Koch wrote: > On Fri, 4 Apr 2014 10:46, pete at petertodd.org said: >> For my prototype I have a small Python program that generates the user >> attribute with version of the python-pgpdump library, modified by me to > > I am not sure what you mean by user attribute. I would use a notation > to tie something to a user id and let gpg handle the creation > (--edit-key , notation). I think by user attribute he means a UAT (a la photo ID, except not a photo in this case, but rather a Bitcoin address). UAT numbers 100 through 110 are the usual reserved-for-private-use numbers. David From pete at petertodd.org Sat Apr 5 03:33:29 2014 From: pete at petertodd.org (Peter Todd) Date: Sat, 5 Apr 2014 03:33:29 +0200 Subject: Prototyping OpenPGP extensions/signing arbitrary packets In-Reply-To: <87mwg0hmp4.fsf@vigenere.g10code.de> References: <20140404084612.GJ9786@tilt> <87mwg0hmp4.fsf@vigenere.g10code.de> Message-ID: <20140405013329.GB3276@tilt> On Fri, Apr 04, 2014 at 10:19:35PM +0200, Werner Koch wrote: > On Fri, 4 Apr 2014 10:46, pete at petertodd.org said: > > For my prototype I have a small Python program that generates the user > > attribute with version of the python-pgpdump library, modified by me to > > I am not sure what you mean by user attribute. I would use a notation > to tie something to a user id and let gpg handle the creation > (--edit-key , notation). I mean RFC4880 5.12. User Attribute Packet (Tag 17). I don't think signature notations are really the right meaning here. In the case of a Bitcoin address I don't see any reason why the address should be conceptually tied to a specific user-id. Secondly it's perfectly reasonable to want to revoke a specific bitcoin address, perhaps because it's not longer used or compromised, similar to how you might want to revoke a user ID. Notations on signatures conflate a few different meanings there. -- 'peter'[:-1]@petertodd.org 0000000000000000f4f5ba334791a4102917e4d3f22f6ad7f2c4f15d97307fe2 -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 665 bytes Desc: Digital signature URL: From wk at gnupg.org Sat Apr 5 14:42:22 2014 From: wk at gnupg.org (Werner Koch) Date: Sat, 05 Apr 2014 14:42:22 +0200 Subject: Prototyping OpenPGP extensions/signing arbitrary packets In-Reply-To: <20140405013329.GB3276@tilt> (Peter Todd's message of "Sat, 5 Apr 2014 03:33:29 +0200") References: <20140404084612.GJ9786@tilt> <87mwg0hmp4.fsf@vigenere.g10code.de> <20140405013329.GB3276@tilt> Message-ID: <87d2gwgd75.fsf@vigenere.g10code.de> On Sat, 5 Apr 2014 03:33, pete at petertodd.org said: > I mean RFC4880 5.12. User Attribute Packet (Tag 17). Actually they are not really useful in real life. Well, there is the photo id but that's all. No software will be able to handle your new user attribute packet. > I don't think signature notations are really the right meaning here. In > the case of a Bitcoin address I don't see any reason why the address > should be conceptually tied to a specific user-id. Secondly it's Because that make it immediately useful. Put something like "Bitcoin NNNNNNNNNNNNNN" into a user id and flag that user id with a new notation holding the actual Bitcoin key. Or just set a notation referring to subkey usable for Bitcoin. The keyservers will be able to serve that other software won't ignore such a new packet. > perfectly reasonable to want to revoke a specific bitcoin address, > perhaps because it's not longer used or compromised, similar to how you > might want to revoke a user ID. Notations on signatures conflate a few You get that all for free by using a normal user id. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From gniibe at fsij.org Mon Apr 7 04:13:16 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Mon, 07 Apr 2014 11:13:16 +0900 Subject: [PATCH] agent: EdDSA support for SSH In-Reply-To: <1396598403.7834.1.camel@cfw2.gniibe.org> References: <1396576913.7580.2.camel@cfw2.gniibe.org> <87txa9iq34.fsf@vigenere.g10code.de> <1396598403.7834.1.camel@cfw2.gniibe.org> Message-ID: <1396836796.1575.3.camel@cfw2.gniibe.org> On 2014-04-04 at 17:00 +0900, NIIBE Yutaka wrote: > I learned the code in Libgcrypt, a bit. IIUC, we can handle opaque > binary data by MPI with GCRYMPI_FLAG_OPAQUE. Here, I think that we > need to use GCRYMPI_FMT_USG format for gcry_mpi_print, and we need to > use "%M" expression for gcry_sexp_build. This is totally my misunderstanding. With opaque MPI, it is handled correctly with '%m'. No such changes are needed. I'm going to post updated patch. -- From gniibe at fsij.org Mon Apr 7 04:40:40 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Mon, 07 Apr 2014 11:40:40 +0900 Subject: [PATCH] Changes for EdDSA (1/3) Message-ID: <1396838440.1575.5.camel@cfw2.gniibe.org> Here are small changes for EdDSA support. (1) EdDSA a public key shoud have "(flags eddsa)" in the S-expression to compute its keygrip (in g10/keyid.c). (2) When Ed25519 curve is selected, it's a key for EdDSA. I'm not sure if current UI is good or not, but just for now (in g10/keygen.c). (3) Update of OID of Ed25519 to match the ones in the functions openpgp_curve_to_oid and openpgp_oid_to_curve (in common/openpgp-oid.c). It will be updated again soon, but just for now . g10: EdDSA support. * g10/keyid.c (keygrip_from_pk): Compute keygrip of EdDSA key. * g10/keygen.c (generate_subkeypair): Ed25519 is for EdDSA. * common/openpgp-oid.c (oid_ed25519): Update. OK to commit&push? diff --git a/g10/keyid.c b/g10/keyid.c index 9ed64a4..4ce77aa 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -813,7 +813,9 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array) else { err = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecc(curve%s)(q%m)))", + pk->pubkey_algo == PUBKEY_ALGO_EDDSA ? + "(public-key(ecc(curve%s)(flags eddsa)(q%m)))" + : "(public-key(ecc(curve%s)(q%m)))", curve, pk->pkey[1]); xfree (curve); } diff --git a/g10/keygen.c b/g10/keygen.c index 135699d..f3052e4 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -4031,7 +4031,11 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock) else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) - curve = ask_curve (); + { + curve = ask_curve (); + if (curve && !strcmp (curve, "Ed25519")) + algo = PUBKEY_ALGO_EDDSA; + } else nbits = ask_keysize (algo, 0); diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c index a2a3617..94a2296 100644 --- a/common/openpgp-oid.c +++ b/common/openpgp-oid.c @@ -39,7 +39,7 @@ /* The OID for Curve Ed25519 in OpenPGP format. */ static const char oid_ed25519[] = - { 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 }; + { 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 }; /* Helper for openpgp_oid_from_str. */ -- From gniibe at fsij.org Mon Apr 7 06:27:30 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Mon, 07 Apr 2014 13:27:30 +0900 Subject: [PATCH] Changes for EdDSA (2/3) In-Reply-To: <1396838440.1575.5.camel@cfw2.gniibe.org> References: <1396838440.1575.5.camel@cfw2.gniibe.org> Message-ID: <1396844850.1575.10.camel@cfw2.gniibe.org> On 2014-04-07 at 11:40 +0900, NIIBE Yutaka wrote: > Here are small changes for EdDSA support. Second is the change for gpg-agent. agent: Support EdDSA. * agent/pksign.c (agent_pksign_do): Handle EdDSA signature. diff --git a/agent/pksign.c b/agent/pksign.c index fb593a6..713c8ba 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -324,12 +324,18 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, int key_type; int is_RSA = 0; int is_ECDSA = 0; + int is_EdDSA = 0; - key_type = agent_is_dsa_key (s_skey); - if (key_type == 0) - is_RSA = 1; - else if (key_type == GCRY_PK_ECDSA) - is_ECDSA = 1; + if (agent_is_eddsa_key (s_skey)) + is_EdDSA = 1; + else + { + key_type = agent_is_dsa_key (s_skey); + if (key_type == 0) + is_RSA = 1; + else if (key_type == GCRY_PK_ECDSA) + is_ECDSA = 1; + } rc = divert_pksign (ctrl, data, datalen, @@ -356,6 +362,11 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%b)))", len, buf); } + else if (is_EdDSA) + { + rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(eddsa(r%b)(s%b)))", + len/2, buf, len/2, buf + len/2); + } else if (is_ECDSA) { unsigned char *r_buf_allocated = NULL; -- From gniibe at fsij.org Mon Apr 7 06:45:52 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Mon, 07 Apr 2014 13:45:52 +0900 Subject: [PATCH] Changes for EdDSA (3/3) In-Reply-To: <1396844850.1575.10.camel@cfw2.gniibe.org> References: <1396838440.1575.5.camel@cfw2.gniibe.org> <1396844850.1575.10.camel@cfw2.gniibe.org> Message-ID: <1396845952.1575.12.camel@cfw2.gniibe.org> On 2014-04-07 at 13:27 +0900, NIIBE Yutaka wrote: > Second is the change for gpg-agent. Third is the change for scdaemon. scd: EdDSA support. * scd/app-openpgp.c (KEY_TYPE_EDDSA, CURVE_ED25519): New. (struct app_local_s): Add eddsa. (get_algo_byte, store_fpr, send_key_attr, get_public_key): Support KEY_TYPE_EDDSA. (get_ecc_key_parameters, get_curve_name): Support CURVE_ED25519. (ecc_writekey): Rename from ecdsa_writekey. Support CURVE_ED25519. (do_writekey): Follow the change of ecc_writekey. (do_auth): Support KEY_TYPE_EDDSA. (parse_ecc_curve): Support CURVE_ED25519. Bug fix for other curves. (parse_algorithm_attribute): Bug fix for ECDH. Support EdDSA. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index da1bec9..a0fd1c6 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -122,6 +122,7 @@ typedef enum { KEY_TYPE_ECDH, KEY_TYPE_ECDSA, + KEY_TYPE_EDDSA, KEY_TYPE_RSA, } key_type_t; @@ -146,7 +147,8 @@ enum CURVE_NIST_P384, CURVE_NIST_P521, CURVE_SEC_P256K1, - CURVE_UNKOWN, + CURVE_ED25519, + CURVE_UNKNOWN, }; @@ -238,6 +240,10 @@ struct app_local_s { struct { int curve; int hashalgo; + } eddsa; + struct { + int curve; + int hashalgo; int cipheralgo; } ecdh; }; @@ -746,6 +752,8 @@ get_algo_byte (key_type_t key_type) return 19; else if (key_type == KEY_TYPE_ECDH) return 18; + else if (key_type == KEY_TYPE_EDDSA) + return 105; /* (experimental) */ else return 1; /* RSA */ } @@ -770,7 +778,8 @@ store_fpr (app_t app, int keynumber, u32 timestamp, int i; n = 6; /* key packet version, 4-byte timestamps, and algorithm */ - if (key_type == KEY_TYPE_RSA || key_type == KEY_TYPE_ECDSA) + if (key_type == KEY_TYPE_RSA || key_type == KEY_TYPE_ECDSA + || key_type == KEY_TYPE_EDDSA) argc = 2; else if (key_type == KEY_TYPE_ECDH) argc = 3; @@ -935,11 +944,21 @@ get_ecc_key_parameters (int curve, int *r_n_bits, const char **r_curve_oid) *r_n_bits = 521; *r_curve_oid = "1.3.132.0.35"; } - else + else if (curve == CURVE_SEC_P256K1) { *r_n_bits = 256; *r_curve_oid = "1.3.132.0.10"; } + else if (curve == CURVE_ED25519) + { + *r_n_bits = 255; + *r_curve_oid = "1.3.6.1.4.1.11591.15.1"; + } + else + { + *r_n_bits = 0; + *r_curve_oid = "1.3.6.1.4.1.11591.2.12242973"; /* gnu.gnupg.badoid */ + } } static void @@ -973,6 +992,15 @@ send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int number) app->app_local->keyattr[number].ecdh.hashalgo, app->app_local->keyattr[number].ecdh.cipheralgo); } + else if (app->app_local->keyattr[number].key_type == KEY_TYPE_EDDSA) + { + get_ecc_key_parameters (app->app_local->keyattr[number].eddsa.curve, + &n_bits, &curve_oid); + snprintf (buffer, sizeof buffer, "%d 105 %u %d %s", + number+1, n_bits, + app->app_local->keyattr[number].ecdh.hashalgo, + curve_oid); + } else snprintf (buffer, sizeof buffer, "0 0 UNKNOWN"); @@ -1282,8 +1310,12 @@ get_curve_name (int curve) return "NIST P-384"; else if (curve == CURVE_NIST_P521) return "NIST P-521"; - else + else if (curve == CURVE_SEC_P256K1) return "secp256k1"; + else if (curve == CURVE_ED25519) + return "Ed25519"; + else + return "unknown"; } @@ -1455,7 +1487,8 @@ get_public_key (app_t app, int keyno) goto leave; } /* Prepend numbers with a 0 if needed. */ - if (mlen && (*m & 0x80)) + if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_EDDSA + && mlen && (*m & 0x80)) { *mbuf = 0; memcpy (mbuf+1, m, mlen); @@ -1521,6 +1554,29 @@ get_public_key (app_t app, int keyno) gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len); gcry_sexp_release (s_pkey); } + else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_EDDSA) + { + const char *curve_name + = get_curve_name (app->app_local->keyattr[keyno].eddsa.curve); + + err = gcry_sexp_build (&s_pkey, NULL, + "(public-key(ecc(curve%s)(flags eddsa)(q%b)))", + curve_name, mlen, mbuf); + if (err) + goto leave; + + len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0); + + keybuf = xtrymalloc (len); + if (!keybuf) + { + gcry_sexp_release (s_pkey); + err = gpg_error_from_syserror (); + goto leave; + } + gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len); + gcry_sexp_release (s_pkey); + } else { err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); @@ -2695,9 +2751,9 @@ build_privkey_template (app_t app, int keyno, } static gpg_error_t -build_ecdsa_privkey_template (app_t app, int keyno, - const unsigned char *ecc_d, size_t ecc_d_len, - unsigned char **result, size_t *resultlen) +build_ecc_privkey_template (app_t app, int keyno, + const unsigned char *ecc_d, size_t ecc_d_len, + unsigned char **result, size_t *resultlen) { unsigned char privkey[2]; size_t privkey_len; @@ -3179,9 +3235,9 @@ ecdh_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), static gpg_error_t -ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), - void *pincb_arg, int keyno, - const unsigned char *buf, size_t buflen, int depth) +ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, int keyno, + const unsigned char *buf, size_t buflen, int depth) { gpg_error_t err; const unsigned char *tok; @@ -3194,10 +3250,14 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), size_t template_len; unsigned char fprbuf[20]; u32 created_at = 0; - int curve = CURVE_UNKOWN; - - /* (private-key(ecdsa(curve%s)(q%m)(d%m))): curve = "1.2.840.10045.3.1.7" */ - /* (private-key(ecc(curve%s)(q%m)(d%m))): curve = "secp256k1" */ + int curve = CURVE_UNKNOWN; + + /* (private-key(ecdsa(curve%s)(q%m)(d%m))(created-at%d)): + curve = "1.2.840.10045.3.1.7" */ + /* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)): + curve = "secp256k1" */ + /* (private-key(ecc(curve%s)(flags eddsa)(q%m)(d%m))(created-at%d)): + curve = "Ed25519" */ last_depth1 = depth; while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) && depth && depth >= last_depth1) @@ -3219,33 +3279,34 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), curve = CURVE_NIST_P256; else if (tok && toklen == 9 && !memcmp (tok, "secp256k1", 9)) curve = CURVE_SEC_P256K1; + else if (tok && toklen == 7 && !memcmp (tok, "Ed25519", 7)) + curve = CURVE_ED25519; } else if (tok && toklen == 1) { - const unsigned char **mpi; - size_t *mpi_len; + const unsigned char **buf2; + size_t *buf2len; switch (*tok) { - case 'q': mpi = &ecc_q; mpi_len = &ecc_q_len; break; - case 'd': mpi = &ecc_d; mpi_len = &ecc_d_len; break; - default: mpi = NULL; mpi_len = NULL; break; + case 'q': buf2 = &ecc_q; buf2len = &ecc_q_len; break; + case 'd': buf2 = &ecc_d; buf2len = &ecc_d_len; break; + default: buf2 = NULL; buf2len = NULL; break; } - if (mpi && *mpi) + if (buf2 && *buf2) { err = gpg_error (GPG_ERR_DUP_VALUE); goto leave; } if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) goto leave; - if (tok && mpi) - { - /* Strip off leading zero bytes and save. */ - for (;toklen && !*tok; toklen--, tok++) - ; - *mpi = tok; - *mpi_len = toklen; - } + if (tok && buf2 && curve != CURVE_ED25519) + /* It's MPI. Strip off leading zero bytes and save. */ + for (;toklen && !*tok; toklen--, tok++) + ; + + *buf2 = tok; + *buf2len = toklen; } /* Skip until end of list. */ last_depth2 = depth; @@ -3312,9 +3373,9 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), the OpenPGP card specs version 2.0. */ int exmode; - err = build_ecdsa_privkey_template (app, keyno, - ecc_d, ecc_d_len, - &template, &template_len); + err = build_ecc_privkey_template (app, keyno, + ecc_d, ecc_d_len, + &template, &template_len); if (err) goto leave; @@ -3343,11 +3404,14 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), } err = store_fpr (app, keyno, created_at, fprbuf, app->card_version, - KEY_TYPE_ECDSA, - curve == CURVE_NIST_P256? + curve == CURVE_ED25519 ? KEY_TYPE_EDDSA : KEY_TYPE_ECDSA, + curve == CURVE_ED25519 ? + "\x09\x2b\x06\x01\x04\x01\xda\x47\x0f\x01" + : curve == CURVE_NIST_P256 ? "\x08\x2a\x86\x48\xce\x3d\x03\x01\x07" : "\05\x2b\x81\x04\x00\x0a", - curve == CURVE_NIST_P256? 9 : 6, + curve == CURVE_ED25519 ? 10 + : curve == CURVE_NIST_P256? 9 : 6, ecc_q, ecc_q_len); if (err) goto leave; @@ -3425,7 +3489,7 @@ do_writekey (app_t app, ctrl_t ctrl, else if ((tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0 && (keyno == 0 || keyno == 2)) || (tok && toklen == 5 && memcmp ("ecdsa", tok, toklen) == 0)) - ecdsa_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth); + ecc_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth); else if ((tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0 && keyno == 1) || (tok && toklen == 4 && memcmp ("ecdh", tok, toklen) == 0)) @@ -3912,7 +3976,8 @@ do_auth (app_t app, const char *keyidstr, if (!keyidstr || !*keyidstr) return gpg_error (GPG_ERR_INV_VALUE); - if (indatalen > 101) /* For a 2048 bit key. */ + if (app->app_local->keyattr[2].key_type == KEY_TYPE_RSA + && indatalen > 101) /* For a 2048 bit key. */ return gpg_error (GPG_ERR_INV_VALUE); if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECDSA @@ -3922,6 +3987,12 @@ do_auth (app_t app, const char *keyidstr, indata = p; indatalen -= 19; } + else if (app->app_local->keyattr[2].key_type == KEY_TYPE_EDDSA) + { + const char *p = (const char *)indata + 15; + indata = p; + indatalen -= 15; + } /* Check whether an OpenPGP card of any version has been requested. */ if (!strcmp (keyidstr, "OPENPGP.3")) @@ -4298,14 +4369,18 @@ parse_ecc_curve (const unsigned char *buffer, size_t buflen) { int curve; - if (buflen == 6 && buffer[5] == 0x22) + if (buflen == 5 && buffer[5] == 0x22) curve = CURVE_NIST_P384; - else if (buflen == 6 && buffer[5] == 0x23) + else if (buflen == 5 && buffer[5] == 0x23) curve = CURVE_NIST_P521; - else if (buflen == 9) + else if (buflen == 8) curve = CURVE_NIST_P256; - else + else if (buflen == 5 && buffer[5] == 0x0a) curve = CURVE_SEC_P256K1; + else if (buflen == 9) + curve = CURVE_ED25519; + else + curve = CURVE_UNKNOWN; return curve; } @@ -4374,10 +4449,17 @@ parse_algorithm_attribute (app_t app, int keyno) else if (*buffer == 18 && buflen == 11) /* ECDH */ { app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECDH; - app->app_local->keyattr[keyno].ecdh.curve - = parse_ecc_curve (buffer + 1, buflen - 1); app->app_local->keyattr[keyno].ecdh.hashalgo = buffer[1]; app->app_local->keyattr[keyno].ecdh.cipheralgo = buffer[2]; + app->app_local->keyattr[keyno].ecdh.curve + = parse_ecc_curve (buffer + 3, buflen - 3); + } + else if (*buffer == 105) /* EdDSA (experimental) */ + { + app->app_local->keyattr[keyno].key_type = KEY_TYPE_EDDSA; + app->app_local->keyattr[keyno].eddsa.hashalgo = buffer[1]; + app->app_local->keyattr[keyno].eddsa.curve + = parse_ecc_curve (buffer + 2, buflen - 2); } else if (opt.verbose) log_printhex ("", buffer, buflen); -- From gniibe at fsij.org Mon Apr 7 07:35:18 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Mon, 07 Apr 2014 14:35:18 +0900 Subject: [PATCH] Changes for EdDSA (3/3) In-Reply-To: <1396845952.1575.12.camel@cfw2.gniibe.org> References: <1396838440.1575.5.camel@cfw2.gniibe.org> <1396844850.1575.10.camel@cfw2.gniibe.org> <1396845952.1575.12.camel@cfw2.gniibe.org> Message-ID: <1396848918.1575.14.camel@cfw2.gniibe.org> On 2014-04-07 at 13:45 +0900, NIIBE Yutaka wrote: > diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c > index da1bec9..a0fd1c6 100644 > @@ -238,6 +240,10 @@ struct app_local_s { > struct { > int curve; > int hashalgo; > + } eddsa; > + struct { > + int curve; > + int hashalgo; > int cipheralgo; > } ecdh; > }; Here needs additional explanation. Since the paper of EdDSA [ed25519] suggests other hash functions, I reserved a field of hash algorithm for EdDSA algorithm attribute of OpenPGP card. But, it seems that it's not good idea. Reading RFC4880 again, I think that it would be better to allocate another public-key algorithm ID for (say) EdDSA-SHA3, perhaps. [ed25519] 23pp. (PDF) Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, Bo-Yin Yang. High-speed high-security signatures. Journal of Cryptographic Engineering 2 (2012), 77-89. Document ID: a1a62a2f76d23f65d622484ddd09caf8. URL: http://cr.yp.to/papers.html#ed25519. Date: 2011.09.26. -- From wk at gnupg.org Mon Apr 7 17:27:29 2014 From: wk at gnupg.org (Werner Koch) Date: Mon, 07 Apr 2014 17:27:29 +0200 Subject: [PATCH] Changes for EdDSA (1/3) In-Reply-To: <1396838440.1575.5.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Mon, 07 Apr 2014 11:40:40 +0900") References: <1396838440.1575.5.camel@cfw2.gniibe.org> Message-ID: <87wqf1duse.fsf@vigenere.g10code.de> On Mon, 7 Apr 2014 04:40, gniibe at fsij.org said: > (1) EdDSA a public key shoud have "(flags eddsa)" in the S-expression > to compute its keygrip (in g10/keyid.c). Right. > (2) When Ed25519 curve is selected, it's a key for EdDSA. > I'm not sure if current UI is good or not, but just for now > (in g10/keygen.c). For now it is okay. We may later need change that depending on whether an encrypt or a sign key is to be created. > (3) Update of OID of Ed25519 to match the ones in the > functions openpgp_curve_to_oid and openpgp_oid_to_curve > (in common/openpgp-oid.c). > It will be updated again soon, but just for now . ok. > OK to commit&push? ok. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Mon Apr 7 17:29:46 2014 From: wk at gnupg.org (Werner Koch) Date: Mon, 07 Apr 2014 17:29:46 +0200 Subject: [PATCH] Changes for EdDSA (2/3) In-Reply-To: <1396844850.1575.10.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Mon, 07 Apr 2014 13:27:30 +0900") References: <1396838440.1575.5.camel@cfw2.gniibe.org> <1396844850.1575.10.camel@cfw2.gniibe.org> Message-ID: <87sippduol.fsf@vigenere.g10code.de> On Mon, 7 Apr 2014 06:27, gniibe at fsij.org said: > agent: Support EdDSA. > > * agent/pksign.c (agent_pksign_do): Handle EdDSA signature. Right, that was missing. I did not looked the smartcard code path. -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Mon Apr 7 17:35:52 2014 From: wk at gnupg.org (Werner Koch) Date: Mon, 07 Apr 2014 17:35:52 +0200 Subject: [PATCH] Changes for EdDSA (3/3) In-Reply-To: <1396848918.1575.14.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Mon, 07 Apr 2014 14:35:18 +0900") References: <1396838440.1575.5.camel@cfw2.gniibe.org> <1396844850.1575.10.camel@cfw2.gniibe.org> <1396845952.1575.12.camel@cfw2.gniibe.org> <1396848918.1575.14.camel@cfw2.gniibe.org> Message-ID: <87ob0dduef.fsf@vigenere.g10code.de> On Mon, 7 Apr 2014 07:35, gniibe at fsij.org said: > Reading RFC4880 again, I think that it would be better to allocate > another public-key algorithm ID for (say) EdDSA-SHA3, perhaps. If that will ever be the case, this could be done. I current id4a on how to handle EdDSA in OpenPGP is to specify an EdDSA algorithm and tie the curve to the size of the key. That is for a keysize < 256 Ed25519 is used, for other keysizes other curves. Thus there will be only one fixed list of curves and not a myriad of variants. In case an algorithm needs to be replaced, we need to change the code anyway and thus a flexible specification does not gain much. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From gniibe at fsij.org Tue Apr 8 05:22:26 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Tue, 08 Apr 2014 12:22:26 +0900 Subject: [PATCH] Changes for EdDSA (3/3) In-Reply-To: <87ob0dduef.fsf@vigenere.g10code.de> References: <1396838440.1575.5.camel@cfw2.gniibe.org> <1396844850.1575.10.camel@cfw2.gniibe.org> <1396845952.1575.12.camel@cfw2.gniibe.org> <1396848918.1575.14.camel@cfw2.gniibe.org> <87ob0dduef.fsf@vigenere.g10code.de> Message-ID: <1396927346.3196.4.camel@cfw2.gniibe.org> 1/3 (change for g10) and 2/3 (change for agent) are committed and pushed. On 2014-04-07 at 17:35 +0200, Werner Koch wrote: > On Mon, 7 Apr 2014 07:35, gniibe at fsij.org said: > > > Reading RFC4880 again, I think that it would be better to allocate > > another public-key algorithm ID for (say) EdDSA-SHA3, perhaps. > > If that will ever be the case, this could be done. I current id4a on > how to handle EdDSA in OpenPGP is to specify an EdDSA algorithm and tie > the curve to the size of the key. That is for a keysize < 256 Ed25519 > is used, for other keysizes other curves. Thus there will be only one > fixed list of curves and not a myriad of variants. > > In case an algorithm needs to be replaced, we need to change the code > anyway and thus a flexible specification does not gain much. Thank you for your comment. In that case, we need size of key (instead of OID) for key attribute of smartcard. Let me think again about scdaemon change. -- From gniibe at fsij.org Tue Apr 8 10:09:16 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Tue, 08 Apr 2014 17:09:16 +0900 Subject: [PATCH] Revised: Changes for EdDSA (3/3) In-Reply-To: <1396927346.3196.4.camel@cfw2.gniibe.org> References: <1396838440.1575.5.camel@cfw2.gniibe.org> <1396844850.1575.10.camel@cfw2.gniibe.org> <1396845952.1575.12.camel@cfw2.gniibe.org> <1396848918.1575.14.camel@cfw2.gniibe.org> <87ob0dduef.fsf@vigenere.g10code.de> <1396927346.3196.4.camel@cfw2.gniibe.org> Message-ID: <1396944556.17577.1.camel@cfw2.gniibe.org> On 2014-04-08 at 12:22 +0900, NIIBE Yutaka wrote: > Let me think again about scdaemon change. Here is a revised patch for scdaemon to support EdDSA. I removed hash algorithm ID from key attribute of smartcard. I considered not including OID thing too, but it's already included for the computation of fingerprint (currently) like ECDSA key, so, I leave it. We will need to update the code anyway, when we will decide public key algorithm ID (and OID). I tested with current development version of Gnuk. OK to push? scd: EdDSA support. * scd/app-openpgp.c (KEY_TYPE_EDDSA, CURVE_ED25519): New. (struct app_local_s): Add eddsa. (get_algo_byte, store_fpr, send_key_attr, get_public_key): Support KEY_TYPE_EDDSA. (get_ecc_key_parameters, get_curve_name): Support CURVE_ED25519. (ecc_writekey): Rename from ecdsa_writekey. Support CURVE_ED25519. (do_writekey): Follow the change of ecc_writekey. (do_auth): Support KEY_TYPE_EDDSA. (parse_ecc_curve): Support CURVE_ED25519. Bug fix for other curves. (parse_algorithm_attribute): Bug fix for ECDH. Support EdDSA. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index da1bec9..8978a7d 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -122,6 +122,7 @@ typedef enum { KEY_TYPE_ECDH, KEY_TYPE_ECDSA, + KEY_TYPE_EDDSA, KEY_TYPE_RSA, } key_type_t; @@ -146,7 +147,8 @@ enum CURVE_NIST_P384, CURVE_NIST_P521, CURVE_SEC_P256K1, - CURVE_UNKOWN, + CURVE_ED25519, + CURVE_UNKNOWN, }; @@ -237,6 +239,9 @@ struct app_local_s { } ecdsa; struct { int curve; + } eddsa; + struct { + int curve; int hashalgo; int cipheralgo; } ecdh; @@ -746,6 +751,8 @@ get_algo_byte (key_type_t key_type) return 19; else if (key_type == KEY_TYPE_ECDH) return 18; + else if (key_type == KEY_TYPE_EDDSA) + return 105; /* (experimental) */ else return 1; /* RSA */ } @@ -770,7 +777,8 @@ store_fpr (app_t app, int keynumber, u32 timestamp, int i; n = 6; /* key packet version, 4-byte timestamps, and algorithm */ - if (key_type == KEY_TYPE_RSA || key_type == KEY_TYPE_ECDSA) + if (key_type == KEY_TYPE_RSA || key_type == KEY_TYPE_ECDSA + || key_type == KEY_TYPE_EDDSA) argc = 2; else if (key_type == KEY_TYPE_ECDH) argc = 3; @@ -935,11 +943,21 @@ get_ecc_key_parameters (int curve, int *r_n_bits, const char **r_curve_oid) *r_n_bits = 521; *r_curve_oid = "1.3.132.0.35"; } - else + else if (curve == CURVE_SEC_P256K1) { *r_n_bits = 256; *r_curve_oid = "1.3.132.0.10"; } + else if (curve == CURVE_ED25519) + { + *r_n_bits = 255; + *r_curve_oid = "1.3.6.1.4.1.11591.15.1"; + } + else + { + *r_n_bits = 0; + *r_curve_oid = "1.3.6.1.4.1.11591.2.12242973"; /* gnu.gnupg.badoid */ + } } static void @@ -973,6 +991,13 @@ send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int number) app->app_local->keyattr[number].ecdh.hashalgo, app->app_local->keyattr[number].ecdh.cipheralgo); } + else if (app->app_local->keyattr[number].key_type == KEY_TYPE_EDDSA) + { + get_ecc_key_parameters (app->app_local->keyattr[number].eddsa.curve, + &n_bits, &curve_oid); + snprintf (buffer, sizeof buffer, "%d 105 %u %s", + number+1, n_bits, curve_oid); + } else snprintf (buffer, sizeof buffer, "0 0 UNKNOWN"); @@ -1282,8 +1307,12 @@ get_curve_name (int curve) return "NIST P-384"; else if (curve == CURVE_NIST_P521) return "NIST P-521"; - else + else if (curve == CURVE_SEC_P256K1) return "secp256k1"; + else if (curve == CURVE_ED25519) + return "Ed25519"; + else + return "unknown"; } @@ -1455,7 +1484,8 @@ get_public_key (app_t app, int keyno) goto leave; } /* Prepend numbers with a 0 if needed. */ - if (mlen && (*m & 0x80)) + if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_EDDSA + && mlen && (*m & 0x80)) { *mbuf = 0; memcpy (mbuf+1, m, mlen); @@ -1521,6 +1551,29 @@ get_public_key (app_t app, int keyno) gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len); gcry_sexp_release (s_pkey); } + else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_EDDSA) + { + const char *curve_name + = get_curve_name (app->app_local->keyattr[keyno].eddsa.curve); + + err = gcry_sexp_build (&s_pkey, NULL, + "(public-key(ecc(curve%s)(flags eddsa)(q%b)))", + curve_name, mlen, mbuf); + if (err) + goto leave; + + len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0); + + keybuf = xtrymalloc (len); + if (!keybuf) + { + gcry_sexp_release (s_pkey); + err = gpg_error_from_syserror (); + goto leave; + } + gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len); + gcry_sexp_release (s_pkey); + } else { err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); @@ -2695,9 +2748,9 @@ build_privkey_template (app_t app, int keyno, } static gpg_error_t -build_ecdsa_privkey_template (app_t app, int keyno, - const unsigned char *ecc_d, size_t ecc_d_len, - unsigned char **result, size_t *resultlen) +build_ecc_privkey_template (app_t app, int keyno, + const unsigned char *ecc_d, size_t ecc_d_len, + unsigned char **result, size_t *resultlen) { unsigned char privkey[2]; size_t privkey_len; @@ -3179,9 +3232,9 @@ ecdh_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), static gpg_error_t -ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), - void *pincb_arg, int keyno, - const unsigned char *buf, size_t buflen, int depth) +ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, int keyno, + const unsigned char *buf, size_t buflen, int depth) { gpg_error_t err; const unsigned char *tok; @@ -3194,10 +3247,14 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), size_t template_len; unsigned char fprbuf[20]; u32 created_at = 0; - int curve = CURVE_UNKOWN; - - /* (private-key(ecdsa(curve%s)(q%m)(d%m))): curve = "1.2.840.10045.3.1.7" */ - /* (private-key(ecc(curve%s)(q%m)(d%m))): curve = "secp256k1" */ + int curve = CURVE_UNKNOWN; + + /* (private-key(ecdsa(curve%s)(q%m)(d%m))(created-at%d)): + curve = "1.2.840.10045.3.1.7" */ + /* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)): + curve = "secp256k1" */ + /* (private-key(ecc(curve%s)(flags eddsa)(q%m)(d%m))(created-at%d)): + curve = "Ed25519" */ last_depth1 = depth; while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) && depth && depth >= last_depth1) @@ -3219,33 +3276,34 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), curve = CURVE_NIST_P256; else if (tok && toklen == 9 && !memcmp (tok, "secp256k1", 9)) curve = CURVE_SEC_P256K1; + else if (tok && toklen == 7 && !memcmp (tok, "Ed25519", 7)) + curve = CURVE_ED25519; } else if (tok && toklen == 1) { - const unsigned char **mpi; - size_t *mpi_len; + const unsigned char **buf2; + size_t *buf2len; switch (*tok) { - case 'q': mpi = &ecc_q; mpi_len = &ecc_q_len; break; - case 'd': mpi = &ecc_d; mpi_len = &ecc_d_len; break; - default: mpi = NULL; mpi_len = NULL; break; + case 'q': buf2 = &ecc_q; buf2len = &ecc_q_len; break; + case 'd': buf2 = &ecc_d; buf2len = &ecc_d_len; break; + default: buf2 = NULL; buf2len = NULL; break; } - if (mpi && *mpi) + if (buf2 && *buf2) { err = gpg_error (GPG_ERR_DUP_VALUE); goto leave; } if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) goto leave; - if (tok && mpi) - { - /* Strip off leading zero bytes and save. */ - for (;toklen && !*tok; toklen--, tok++) - ; - *mpi = tok; - *mpi_len = toklen; - } + if (tok && buf2 && curve != CURVE_ED25519) + /* It's MPI. Strip off leading zero bytes and save. */ + for (;toklen && !*tok; toklen--, tok++) + ; + + *buf2 = tok; + *buf2len = toklen; } /* Skip until end of list. */ last_depth2 = depth; @@ -3312,9 +3370,9 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), the OpenPGP card specs version 2.0. */ int exmode; - err = build_ecdsa_privkey_template (app, keyno, - ecc_d, ecc_d_len, - &template, &template_len); + err = build_ecc_privkey_template (app, keyno, + ecc_d, ecc_d_len, + &template, &template_len); if (err) goto leave; @@ -3343,11 +3401,14 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), } err = store_fpr (app, keyno, created_at, fprbuf, app->card_version, - KEY_TYPE_ECDSA, - curve == CURVE_NIST_P256? + curve == CURVE_ED25519 ? KEY_TYPE_EDDSA : KEY_TYPE_ECDSA, + curve == CURVE_ED25519 ? + "\x09\x2b\x06\x01\x04\x01\xda\x47\x0f\x01" + : curve == CURVE_NIST_P256 ? "\x08\x2a\x86\x48\xce\x3d\x03\x01\x07" : "\05\x2b\x81\x04\x00\x0a", - curve == CURVE_NIST_P256? 9 : 6, + curve == CURVE_ED25519 ? 10 + : curve == CURVE_NIST_P256? 9 : 6, ecc_q, ecc_q_len); if (err) goto leave; @@ -3425,7 +3486,7 @@ do_writekey (app_t app, ctrl_t ctrl, else if ((tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0 && (keyno == 0 || keyno == 2)) || (tok && toklen == 5 && memcmp ("ecdsa", tok, toklen) == 0)) - ecdsa_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth); + ecc_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth); else if ((tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0 && keyno == 1) || (tok && toklen == 4 && memcmp ("ecdh", tok, toklen) == 0)) @@ -3912,7 +3973,8 @@ do_auth (app_t app, const char *keyidstr, if (!keyidstr || !*keyidstr) return gpg_error (GPG_ERR_INV_VALUE); - if (indatalen > 101) /* For a 2048 bit key. */ + if (app->app_local->keyattr[2].key_type == KEY_TYPE_RSA + && indatalen > 101) /* For a 2048 bit key. */ return gpg_error (GPG_ERR_INV_VALUE); if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECDSA @@ -3922,6 +3984,12 @@ do_auth (app_t app, const char *keyidstr, indata = p; indatalen -= 19; } + else if (app->app_local->keyattr[2].key_type == KEY_TYPE_EDDSA) + { + const char *p = (const char *)indata + 15; + indata = p; + indatalen -= 15; + } /* Check whether an OpenPGP card of any version has been requested. */ if (!strcmp (keyidstr, "OPENPGP.3")) @@ -4298,14 +4366,18 @@ parse_ecc_curve (const unsigned char *buffer, size_t buflen) { int curve; - if (buflen == 6 && buffer[5] == 0x22) + if (buflen == 5 && buffer[5] == 0x22) curve = CURVE_NIST_P384; - else if (buflen == 6 && buffer[5] == 0x23) + else if (buflen == 5 && buffer[5] == 0x23) curve = CURVE_NIST_P521; - else if (buflen == 9) + else if (buflen == 8) curve = CURVE_NIST_P256; - else + else if (buflen == 5 && buffer[5] == 0x0a) curve = CURVE_SEC_P256K1; + else if (buflen == 9) + curve = CURVE_ED25519; + else + curve = CURVE_UNKNOWN; return curve; } @@ -4374,10 +4446,16 @@ parse_algorithm_attribute (app_t app, int keyno) else if (*buffer == 18 && buflen == 11) /* ECDH */ { app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECDH; - app->app_local->keyattr[keyno].ecdh.curve - = parse_ecc_curve (buffer + 1, buflen - 1); app->app_local->keyattr[keyno].ecdh.hashalgo = buffer[1]; app->app_local->keyattr[keyno].ecdh.cipheralgo = buffer[2]; + app->app_local->keyattr[keyno].ecdh.curve + = parse_ecc_curve (buffer + 3, buflen - 3); + } + else if (*buffer == 105) /* EdDSA (experimental) */ + { + app->app_local->keyattr[keyno].key_type = KEY_TYPE_EDDSA; + app->app_local->keyattr[keyno].eddsa.curve + = parse_ecc_curve (buffer + 1, buflen - 1); } else if (opt.verbose) log_printhex ("", buffer, buflen); -- From wk at gnupg.org Tue Apr 8 11:34:02 2014 From: wk at gnupg.org (Werner Koch) Date: Tue, 08 Apr 2014 11:34:02 +0200 Subject: [PATCH] Revised: Changes for EdDSA (3/3) In-Reply-To: <1396944556.17577.1.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Tue, 08 Apr 2014 17:09:16 +0900") References: <1396838440.1575.5.camel@cfw2.gniibe.org> <1396844850.1575.10.camel@cfw2.gniibe.org> <1396845952.1575.12.camel@cfw2.gniibe.org> <1396848918.1575.14.camel@cfw2.gniibe.org> <87ob0dduef.fsf@vigenere.g10code.de> <1396927346.3196.4.camel@cfw2.gniibe.org> <1396944556.17577.1.camel@cfw2.gniibe.org> Message-ID: <87lhvgcghh.fsf@vigenere.g10code.de> On Tue, 8 Apr 2014 10:09, gniibe at fsij.org said: > OK to push? Sure, it is experimental anyway so it should not harm. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From gniibe at fsij.org Wed Apr 9 04:45:21 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Wed, 09 Apr 2014 11:45:21 +0900 Subject: [PATCH] Revised: Changes for EdDSA (3/3) In-Reply-To: <87lhvgcghh.fsf@vigenere.g10code.de> References: <1396838440.1575.5.camel@cfw2.gniibe.org> <1396844850.1575.10.camel@cfw2.gniibe.org> <1396845952.1575.12.camel@cfw2.gniibe.org> <1396848918.1575.14.camel@cfw2.gniibe.org> <87ob0dduef.fsf@vigenere.g10code.de> <1396927346.3196.4.camel@cfw2.gniibe.org> <1396944556.17577.1.camel@cfw2.gniibe.org> <87lhvgcghh.fsf@vigenere.g10code.de> Message-ID: <1397011521.1551.3.camel@cfw2.gniibe.org> On 2014-04-08 at 11:34 +0200, Werner Koch wrote: > Sure, it is experimental anyway so it should not harm. Committed and pushed. I'll consider about ECDH things. For those who have interest: With development version of GnuPG, you can test SSH authentication by EdDSA. OpenPGP signing doesn't work yet, encryption/decryption, either. So, you can't create Ed25519 primary key, yet. Only you can create Ed25519 subkey for authentication for your experiment. The format (specifically, public key algorithm ID and OID) is subject to change soon. Please understand this is experimental and you won't be able to keep using the subkey created by development version of GnuPG. -- From gniibe at fsij.org Tue Apr 15 14:46:43 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Tue, 15 Apr 2014 21:46:43 +0900 Subject: ECDH using Curve25519 Message-ID: <1397566003.4793.1.camel@latx1.gniibe.org> Hello, I'm considering another experiment, that is, ECDH using Curve25519. This week, I wrote Curve25519 routines for Gnuk: Gnuk: Add Curve25519 computation: https://gitorious.org/gnuk/gnuk/commit/85b2698bb3d741dd32517533ec9086343d1df1bb I had thought that its were the name of the curve, but it's actually the name of ECDH function. I read two papers ([curve25519], [curvezero]) at: http://cr.yp.to/ecdh.html Curve25519 uses x-coordinate only representation for its public key. If we apply Andrey Jivsov's draft-jivsov-ecc-compact-05 to RFC 6637 (Elliptic Curve Cryptography (ECC) in OpenPGP, also written by him) for public key representation, I think that we can naturally extend RFC 6637 for Curve25519. The differences are that (1) it's defined on Montgomery curve, and (2) its cofactor is 8. (1) is no problem for ECDH, and (2) is no problem (against the small-subgroup attack) as Curve25519's private key is multiple of 8. >From the viewpoint of Curve25519, MPI representation is a bit different culture, though. In this case (extending RFC 6637 with Curve25519), all we need is the OID of the Montgomery curve. Werner once suggested that using Ed25519 curve (as we already have it's routine in libgcrypt). However, with the experience of writing an implementation (for Gnuk), I think that implementing Montgomery curve in libgcrypt would be straight-forward and better in long term. We need two things: (a) implement Montgomery's double-and-add function and (b) extend the gcry_mpi_ec_mul_point function for Montgomery curve. Then, we can implement Curve25519 function by a specific Montgomery curve over prime field 2^255-19 calling the gcry_mpi_ec_mul_point function. (Note that we will not implement gcry_mpi_ec_add_points for Montgomery curve, as it's not used for ECDH, and Montgomery curve is only for ECDH.) I think that (a) is not that hard and (b) will become naturally constant-time implementation. Shall I go ahead to experiment with libgcrypt (and then, GnuPG, hopefully) for Curve25519 function? Any comments are appreciated. -- From wk at gnupg.org Tue Apr 15 16:14:54 2014 From: wk at gnupg.org (Werner Koch) Date: Tue, 15 Apr 2014 16:14:54 +0200 Subject: ECDH using Curve25519 In-Reply-To: <1397566003.4793.1.camel@latx1.gniibe.org> (NIIBE Yutaka's message of "Tue, 15 Apr 2014 21:46:43 +0900") References: <1397566003.4793.1.camel@latx1.gniibe.org> Message-ID: <87r44y4r35.fsf@vigenere.g10code.de> On Tue, 15 Apr 2014 14:46, gniibe at fsij.org said: > In this case (extending RFC 6637 with Curve25519), all we need is the > OID of the Montgomery curve. 1.3.6.1.4.1.3029.1.5.1 from Peter Gutmann's arc as posted to cryptography last year. > Werner once suggested that using Ed25519 curve (as we already have > it's routine in libgcrypt). However, with the experience of writing The reason is that we already have this implementation, only one implementation would be needed, and it is not much slower than the Montgomery form. Thus for GNUnet we decided on using Ed25519 also for ECDH. However, there we don't need to comply with any existing standards. > an implementation (for Gnuk), I think that implementing Montgomery > curve in libgcrypt would be straight-forward and better in long term. Given that Libgcrypt is a collection of many algorithms we should have Montgomery arithmetic for EC as well. What new curves will eventually be a SHOULD or MUST in OpenPGP is a different issue. Given that you can easily use RFC-6637, it makes sense to experiment with it. > Shall I go ahead to experiment with libgcrypt (and then, GnuPG, > hopefully) for Curve25519 function? Please do that; at least it will be a good occassion to start a new discussion on the OpenPGP WG. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From hans at guardianproject.info Tue Apr 15 21:05:55 2014 From: hans at guardianproject.info (Hans-Christoph Steiner) Date: Tue, 15 Apr 2014 15:05:55 -0400 Subject: automated cppcheck for gnupg Message-ID: <534D8313.9040901@guardianproject.info> As part of all the C/C++ jobs that we run on our jenkins build server, I set up cppcheck on them. It is a static code analyzer that has caught some of our mistakes (a kin to heartbleed, they are easy to make in C). I have cppcheck running on the gnupg jobs that are already running there. It does not seem to be pointing to anything too alarming, but it does claim a number of memory leaks: libgcrypt/tests/rsacvt.c:426 resourceLeak Resource leak: input libgcrypt/src/hmac256.c:510 deallocDealloc Deallocating a deallocated pointer: hd libksba/src/cert.c:447 nullPointer Possible null pointer dereference: cert - otherwise it is redundant to check if cert is null at line 445 libgcrypt/cipher/test-getrusage.c:49 wrongPrintfScanfArgNum fprintf format string has 7 parameters but only 0 are given libgcrypt/cipher/md.c:1251 nullPointer Possible null pointer dereference: spec - otherwise it is redundant to check if spec is null at line 1247 libgcrypt/cipher/md.c:976 nullPointer Possible null pointer dereference: r - otherwise it is redundant to check if r is null at line 971 libassuan/src/assuan.c:136 nullPointer Possible null pointer dereference: ctx - otherwise it is redundant to check if ctx is null at line 135 gpgme/tests/gpg/t-eventloop.c:82 autoVariables Assigning address of local auto-variable to a function parameter. gpgme/src/w32-io.c:797 memleak Memory leak: ctx gpgme/src/w32-util.c:713 memleak Memory leak: tmpname Also, in my experience, cppcheck does a better job when there are fewer little hacks like: pinentry/gtk+-2/gtksecentry.h:188 syntaxError Invalid number of character ({) when these macros are defined: 'MAKE_EMACS_HAPPY;__cplusplus' So the question is whether these should be automatically reported to committers, like build errors and test errors? Are there any other static code analyzers that we can run there? .hc -- PGP fingerprint: 5E61 C878 0F86 295C E17D 8677 9F0F E587 374B BE81 From ekleog at gmail.com Tue Apr 15 21:22:30 2014 From: ekleog at gmail.com (Leo Gaspard) Date: Tue, 15 Apr 2014 21:22:30 +0200 Subject: automated cppcheck for gnupg In-Reply-To: <534D8313.9040901@guardianproject.info> References: <534D8313.9040901@guardianproject.info> Message-ID: <20140415192230.GB24527@leortable> On Tue, Apr 15, 2014 at 03:05:55PM -0400, Hans-Christoph Steiner wrote: > As part of all the C/C++ jobs that we run on our jenkins build server, I set > up cppcheck on them. It is a static code analyzer that has caught some of our > mistakes (a kin to heartbleed, they are easy to make in C). > > I have cppcheck running on the gnupg jobs that are already running there. It > does not seem to be pointing to anything too alarming, but it does claim a > number of memory leaks: Given that you report errors such as > deallocDealloc Deallocating a deallocated pointer: hd (and others, including null dereferences), that could possibly be security flaws (don't know, didn't look at the code), I suggest that, next time, you report it to Werner by private email instead of using a public mailing list. Just my two cents ! Leo From wk at gnupg.org Tue Apr 15 22:06:15 2014 From: wk at gnupg.org (Werner Koch) Date: Tue, 15 Apr 2014 22:06:15 +0200 Subject: automated cppcheck for gnupg In-Reply-To: <534D8313.9040901@guardianproject.info> (Hans-Christoph Steiner's message of "Tue, 15 Apr 2014 15:05:55 -0400") References: <534D8313.9040901@guardianproject.info> Message-ID: <87ioqa4atk.fsf@vigenere.g10code.de> On Tue, 15 Apr 2014 21:05, hans at guardianproject.info said: > libgcrypt/tests/rsacvt.c:426 > resourceLeak Resource leak: input Who cares, it is short running test program. > libgcrypt/src/hmac256.c:510 > deallocDealloc Deallocating a deallocated pointer: hd Just checked it. It is pretty clear the HD is initialzied and has not been deinitialized. But please prove me wrong. > libksba/src/cert.c:447 > nullPointer Possible null pointer dereference: cert - otherwise it is > redundant to check if cert is null at line 445 Good catch. However, it is questionanble whether the extra check is usefull at all. The fucntion is only specified if a cert object is passed. I'll fix it anyway. > libgcrypt/cipher/test-getrusage.c:49 > wrongPrintfScanfArgNum fprintf format string has 7 parameters but only 0 are Unfinished code from 2007 - the file is not even used. I'll fix it, though. > libgcrypt/cipher/md.c:1251 > nullPointer Possible null pointer dereference: spec - > otherwise it is redundant to check if spec is null at line 1247 Actually this is a failsafe check, but right, it should be correct. > libgcrypt/cipher/md.c:976 > nullPointer Possible null pointer dereference: r - otherwise it > is redundant to check if r is null at line 971 Code not found. > libassuan/src/assuan.c:136 > nullPointer Possible null pointer dereference: ctx - otherwise it is > redundant to check if ctx is null at line 135 A bit hairy to fix. I'll postpone it to tomorrow. > gpgme/tests/gpg/t-eventloop.c:82 > autoVariables Assigning address of local auto-variable to a function parameter. That looks okay. The variable aliases a function parameter. > gpgme/src/w32-io.c:797 > memleak Memory leak: ctx Leaking in a out of resource case. Fixed. > gpgme/src/w32-util.c:713 > memleak Memory leak: tmpname Fixed. > Also, in my experience, cppcheck does a better job when there are fewer little > hacks like: > > pinentry/gtk+-2/gtksecentry.h:188 syntaxError > Invalid number of character ({) when these macros are defined: > 'MAKE_EMACS_HAPPY;__cplusplus' Replaced by #ifdef __cplusplus extern "C" { #if 0 } /* Make Emacs happy. */ #endif #endif /* __cplusplus */ which is what is used everywhere else. > So the question is whether these should be automatically reported to > committers, like build errors and test errors? Are there any other static That are the only errors, or did you filter them? Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From hans at guardianproject.info Tue Apr 15 23:23:16 2014 From: hans at guardianproject.info (Hans-Christoph Steiner) Date: Tue, 15 Apr 2014 17:23:16 -0400 Subject: automated cppcheck for gnupg In-Reply-To: <20140415192230.GB24527@leortable> References: <534D8313.9040901@guardianproject.info> <20140415192230.GB24527@leortable> Message-ID: <534DA344.3010004@guardianproject.info> On 04/15/2014 03:22 PM, Leo Gaspard wrote: > On Tue, Apr 15, 2014 at 03:05:55PM -0400, Hans-Christoph Steiner wrote: >> As part of all the C/C++ jobs that we run on our jenkins build server, I set >> up cppcheck on them. It is a static code analyzer that has caught some of our >> mistakes (a kin to heartbleed, they are easy to make in C). >> >> I have cppcheck running on the gnupg jobs that are already running there. It >> does not seem to be pointing to anything too alarming, but it does claim a >> number of memory leaks: > > Given that you report errors such as >> deallocDealloc Deallocating a deallocated pointer: hd > (and others, including null dereferences), that could possibly be security flaws > (don't know, didn't look at the code), I suggest that, next time, you report it > to Werner by private email instead of using a public mailing list. > > Just my two cents ! > > Leo If I had discovered flaws on my own accord that cppcheck had missed, then I agree it would make sense to keep it private. Since its really not hard to run cppcheck, I think it doesn't need to be kept private since anyone looking for exploits would start with automatic tools like cppcheck. .hc -- PGP fingerprint: 5E61 C878 0F86 295C E17D 8677 9F0F E587 374B BE81 From ekleog at gmail.com Tue Apr 15 23:35:09 2014 From: ekleog at gmail.com (Leo Gaspard) Date: Tue, 15 Apr 2014 23:35:09 +0200 Subject: automated cppcheck for gnupg In-Reply-To: <534DA344.3010004@guardianproject.info> References: <534D8313.9040901@guardianproject.info> <20140415192230.GB24527@leortable> <534DA344.3010004@guardianproject.info> Message-ID: <20140415213509.GC24527@leortable> On Tue, Apr 15, 2014 at 05:23:16PM -0400, Hans-Christoph Steiner wrote: > > > On 04/15/2014 03:22 PM, Leo Gaspard wrote: > > On Tue, Apr 15, 2014 at 03:05:55PM -0400, Hans-Christoph Steiner wrote: > >> As part of all the C/C++ jobs that we run on our jenkins build server, I set > >> up cppcheck on them. It is a static code analyzer that has caught some of our > >> mistakes (a kin to heartbleed, they are easy to make in C). > >> > >> I have cppcheck running on the gnupg jobs that are already running there. It > >> does not seem to be pointing to anything too alarming, but it does claim a > >> number of memory leaks: > > > > Given that you report errors such as > >> deallocDealloc Deallocating a deallocated pointer: hd > > (and others, including null dereferences), that could possibly be security flaws > > (don't know, didn't look at the code), I suggest that, next time, you report it > > to Werner by private email instead of using a public mailing list. > > > > Just my two cents ! > > > > Leo > > If I had discovered flaws on my own accord that cppcheck had missed, then I > agree it would make sense to keep it private. Since its really not hard to > run cppcheck, I think it doesn't need to be kept private since anyone looking > for exploits would start with automatic tools like cppcheck. Well, it might be that noone ever tried ccpcheck, and other tools do not report the same mistakes. There are a number of static analysis tools available, and keeping it private costs virtually nothing. (The null dereference in libassuan that Werner said he would fix tomorrow might be specially important, given it's in actively used code -- or did I misunderstand Werner's message?). Proof anyone looking for exploits do not use cppcheck: you are the first to report these. Anyway, that's off-topic and I'm most likely wrong, given there seems to be nothing serious enough to damage gnupg's security. Cheers, Leo From gniibe at fsij.org Wed Apr 16 02:50:39 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Wed, 16 Apr 2014 09:50:39 +0900 Subject: ECDH using Curve25519 In-Reply-To: <87r44y4r35.fsf@vigenere.g10code.de> References: <1397566003.4793.1.camel@latx1.gniibe.org> <87r44y4r35.fsf@vigenere.g10code.de> Message-ID: <1397609439.1537.1.camel@cfw2.gniibe.org> On 2014-04-15 at 16:14 +0200, Werner Koch wrote: > 1.3.6.1.4.1.3029.1.5.1 > > from Peter Gutmann's arc as posted to cryptography last year. Thanks, I'll use this. > > Werner once suggested that using Ed25519 curve (as we already have > > it's routine in libgcrypt). However, with the experience of writing > > The reason is that we already have this implementation, only one > implementation would be needed, and it is not much slower than the > Montgomery form. Thus for GNUnet we decided on using Ed25519 also for > ECDH. However, there we don't need to comply with any existing > standards. I see that reusing code of Ed25519 would be the shortest path. Even, we could emulate Curve25519 computation by computing [n]Q with Ed25519 (converting its coordinate from/to Montgomery curve). My concern is the ways towards different optimizations (in future) and libgcrypt's API. For both of EdDSA and ECDH, it calls the general function gcry_mpi_ec_mul_point now. But it could be optimized, in different ways, since it's fixed point for EdDSA, and it's not fixed point for ECDH but ECDH only requires x-coordinate. Speaking about API, the design intention and common practice around Curve25519/Ed25519 are that Montgomery curve for ECDH and Edwards curve for EdDSA. In this situation, it seems for me that it's reasonable to imply ECDH-only when specifying Montgomery curve and EdDSA-only when specifying Edwards curve. Well, I'm going to play with libgcrypt. I'll back after I will finish libgcrypt experiment. -- From gniibe at fsij.org Wed Apr 16 06:38:24 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Wed, 16 Apr 2014 13:38:24 +0900 Subject: Gnuk 1.1.3 Message-ID: <1397623104.29070.1.camel@cfw2.gniibe.org> Hello, Development version of Gnuk 1.1.3 was released. Gnuk is an implementation of Cryptographic Token for GnuPG, and it runs on STM32F103. This is an experimental version. While it's daily use for me, this version is for developers, basically. In this version, I added the support of Ed25519 curve for EdDSA signature. When enabled (manual editing is required to remove -DRSA_AUTH and add -DEDDSA_AUTH), you can use the EdDSA key with development version of GnuPG 2.1.x for OpenSSH (as authentication subkey). Here is the list of noteworthy change (in 1.1.3): * Experimental EdDSA support. After configure, you can edit the DEFS variable in src/Makefile, so that Gnuk can support EdDSA with Ed25519 (for authentication). Note that this is pretty much experimental, and subjects to change. Note that this is highly experimental and the key format is subject to change soon, you will not be able to keep using your authentication subkey. Links: Gnuk Documentation: http://www.fsij.org/doc-gnuk/ Gnuk Repository: http://gitorious.org/gnuk/ While Gnuk is software, we have a reference hardware. It's named FST-01 (Flying Stone Technology ZERO ONE). It's PCB design is available as free hardware design. FST-01 introduction: http://www.seeedstudio.com/wiki/index.php?title=FST-01 FST-01 Gnuk Handbook (in Japanese); http://no-passwd.net/fst-01-gnuk-handbook/ Enjoy, -- From wk at gnupg.org Wed Apr 16 09:21:20 2014 From: wk at gnupg.org (Werner Koch) Date: Wed, 16 Apr 2014 09:21:20 +0200 Subject: automated cppcheck for gnupg In-Reply-To: <20140415213509.GC24527@leortable> (Leo Gaspard's message of "Tue, 15 Apr 2014 23:35:09 +0200") References: <534D8313.9040901@guardianproject.info> <20140415192230.GB24527@leortable> <534DA344.3010004@guardianproject.info> <20140415213509.GC24527@leortable> Message-ID: <8738hd4u4v.fsf@vigenere.g10code.de> On Tue, 15 Apr 2014 23:35, ekleog at gmail.com said: > keeping it private costs virtually nothing. (The null dereference in libassuan > that Werner said he would fix tomorrow might be specially important, No it isn't: The code is similar to this ctx = malloc (sizeof *ctx); if (!ctx) { trace_error (ctx->err_source) return NULL; } but uses a macro for the tracing. This is a simple NULL deref which raises a segv (because for ages OSes do not map the first memory page). I had to replace a macro with a inline function to avoid double evaluation of a macro parameter. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From ekleog at gmail.com Wed Apr 16 12:41:07 2014 From: ekleog at gmail.com (Leo Gaspard) Date: Wed, 16 Apr 2014 12:41:07 +0200 Subject: automated cppcheck for gnupg In-Reply-To: <8738hd4u4v.fsf@vigenere.g10code.de> References: <534D8313.9040901@guardianproject.info> <20140415192230.GB24527@leortable> <534DA344.3010004@guardianproject.info> <20140415213509.GC24527@leortable> <8738hd4u4v.fsf@vigenere.g10code.de> Message-ID: <20140416104107.GD24527@leortable> On Wed, Apr 16, 2014 at 09:21:20AM +0200, Werner Koch wrote: > On Tue, 15 Apr 2014 23:35, ekleog at gmail.com said: > > keeping it private costs virtually nothing. (The null dereference in libassuan > > that Werner said he would fix tomorrow might be specially important, > > No it isn't: The code is similar to this > > ctx = malloc (sizeof *ctx); > if (!ctx) > { > trace_error (ctx->err_source) > return NULL; > } > > but uses a macro for the tracing. This is a simple NULL deref which > raises a segv (because for ages OSes do not map the first memory page). > I had to replace a macro with a inline function to avoid double > evaluation of a macro parameter. [I'm assuming I'm not that off-topic, since you answered.] Well... Actually, not long ago, I read about a null pointer dereference leading to complete system compromise (it was used on a root-run program). Sure, it was used in conjunction with a mac os x flaw (which forced the first page to be mapped read-only to some kernel-space memory, but did not give any kernel-level access); yet unfortunately I can't remember where I found it, nor the exact details... (Only that it was something that tried to explain almost any kind of bug can be turned into a "remote" code injection... perhaps a book, now that I think about it..) It thus requires local access to the system (anyway, to trigger a malloc failure...), yet would (IIRC) allow some other user (or daemon) to peep into your running gpg-agent (as, AFAIK, gpg-agent uses libassuan), and so uncovering your secret key. Here, the argument to gpg_strsource (assuming the point of the mistake is the one of the latest git commit on libassuan) would be attacker-controlled, as a consequence the one to gpg_err_source. Doing no check, it means the argument to msgidxof would be attacker-controlled. I unfortunately do not know enough about gettext to know whether dgettext and/or msgidxof are secure enough to (i) not overflow the msgidx buffer, and (ii) not trigger a vulnerability in dgettext and/or msgidxof. Anyway, that's fixed now! Cheers, Leo From hans at guardianproject.info Wed Apr 16 12:50:53 2014 From: hans at guardianproject.info (Hans-Christoph Steiner) Date: Wed, 16 Apr 2014 06:50:53 -0400 Subject: automated cppcheck for gnupg In-Reply-To: <87y4z53d1t.fsf@vigenere.g10code.de> References: <534D8313.9040901@guardianproject.info> <87ioqa4atk.fsf@vigenere.g10code.de> <534DA83C.9080803@guardianproject.info> <87y4z53d1t.fsf@vigenere.g10code.de> Message-ID: <534E608D.7080204@guardianproject.info> On 04/16/2014 04:15 AM, Werner Koch wrote: > On Tue, 15 Apr 2014 23:44, hans at guardianproject.info said: > >> I have seen cppcheck find new issues when fixing seemingly trivial ones like >> this. Plus it makes automated reporting a lot easier if the trivial errors >> are fixed. > > By definition of C stdio streams are closed at process end (or well > after returning from main). > >>> Just checked it. It is pretty clear the HD is initialzied and has not >>> been deinitialized. But please prove me wrong. >> >> Same as above, making cppcheck happy on things like this helps it find other >> errors. (That's my experience, I don't have any other specific knowledge). > > Sorry, I have no idea on how to do that. This is prety sstandard code > and I actually fail to see why cppcheck complains about it. > >>>> libgcrypt/cipher/md.c:976 >>> >>>> nullPointer Possible null pointer dereference: r - otherwise it >>>> is redundant to check if r is null at line 971 >>> >>> Code not found. >> >> This is from LIBGCRYPT-1-6-BRANCH since its the GPG-Android build. > > Okay, I was on master but the code is identuical. Let's see > > 969: GcryDigestEntry *r = a->ctx->list; > 970: > 971: if (r && r->next) > 972: { > 973: fips_signal_error ("possible usage error"); > 974: log_error ("WARNING: more than one algorithm in md_get_algo()\n"); > 975: } > 976: return r ? r->spec->algo : 0; > > On 971 I check a condition whether to print a warning. > On 971 I return the algo or 0. > > All fine. > >> It was a quick sample, here is the whole list from master on all projects but >> libgcrypt, where it is on LIBGCRYPT-1-6-BRANCH: > > Let's see > >> resourceLeak >> ------------ >> gnupg/tools/symcryptrun.c:380 Resource leak: in >> gnupg/kbx/keybox-dump.c:679 Resource leak: fp >> gnupg/tools/symcryptrun.c:420 Resource leak: out >> libassuan/src/mkheader.c:251 Resource leak: fp >> libgcrypt/tests/fipsdrv.c:2525 Resource leak: input >> libgcrypt/tests/rsacvt.c:426 Resource leak: input >> libgpg-error/src/mkheader.c:426 Resource leak: fp > > These are all helper programs and they do not leak anything. > >> memleak >> ------- >> gpgme/src/w32-io.c:797 Memory leak: ctx >> gpgme/src/w32-io.c:428 Memory leak: ctx >> gpgme/src/w32-util.c:713 Memory leak: tmpname > > I fixed the one at 428. > >> gpgme/src/engine-gpg.c:904 Memory leak: fd_data_map > > Hard to fix. I added this comment: > > /* We leak fd_data_map and the fds. This is not easy > to avoid and given that we reach this here only > after a malloc failure for a small object, it is > probably better not to do anything. */ > >> gpgme/src/gpgme-tool.c:2621 Memory leak: filename >> gpgme/src/gpgme-tool.c:2644 Memory leak: filename >> gpgme/src/gpgme-tool.c:2668 Memory leak: filename > > No leaks there. server_parse_fd (ctx, line, &sysfd, &filename) > guarantees that NULL is stored at FILENAME on error. > >> uninitvar >> --------- >> gnupg/keyserver/gpgkeys_ldap.c:897 >> Uninitialized variable: keyid >> gnupg/keyserver/gpgkeys_hkp.c:235 >> Uninitialized variable: keyid > > Not sure which version of GnuPG. 2.1 does not use code in keyserver, > anyway. > >> gpgme/src/data.c:255 >> Uninitialized variable: buffer > > Sure, BUFFER is initialzied: > > char buffer[BUFFER_SIZE]; > char *bufp = buffer; > > >> nullPointer >> ----------- >> gnupg/tools/sockprox.c:446 >> Possible null pointer dereference: protocol_file > > Fixed. > >> gnupg/tests/asschk.c:1088 >> Possible null pointer dereference: p - otherwise it is redundant to check if >> p is null at line 1086 > > Nope, that is correct: > > if (!p) > die_0 ("incomplete script line"); > *p = 0; > > cppcheck needs to know more about the semantics of functions. > >> gnupg/sm/server.c:126 >> Possible null pointer dereference: s - otherwise it is redundant to check if >> s is null at line 124 > > 124: if (s && s >= skip_options (line)) > 125: return 0; > 126: return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n))); > > Sorry, I can't see a problem. > >> gnupg/kbx/keybox-blob.c:950 >> Possible null pointer dereference: blob - otherwise it is redundant to check >> if blob is null at line 951 > > Right, the check is redunant. No NULL deref, though. > > >> gnupg/scd/apdu.c:4200 >> Possible null pointer dereference: p > > Nope: > > *retbuf = p = xtrymalloc (bufsize + 2); > if (!*retbuf) > { > unlock_slot (slot); > xfree (result_ ); > return SW_HOST_OUT_OF_CORE; > } > assert (resultlen < bufsize); > 4200: memcpy (p, result, resultlen); > > P has already been checked above. > >> gnupg/g10/server.c:99 >> Possible null pointer dereference: s - otherwise it is redundant to check if >> s is null at line 97 > > Nope, same as above in sm.server.c > >> gnupg/g10/keylist.c:825 >> Possible null pointer dereference: pk - otherwise it is redundant to check if >> pk is null at line 886 >> gnupg/g10/keylist.c:837 >> Possible null pointer dereference: pk - otherwise it is redundant to check if >> pk is null at line 886 >> gnupg/g10/keylist.c:843 >> Possible null pointer dereference: pk - otherwise it is redundant to check if >> pk is null at line 886 >> gnupg/g10/keylist.c:849 >> Possible null pointer dereference: pk - otherwise it is redundant to check if >> pk is null at line 886 > > > Consider them an assert (pk); > >> gnupg/g10/keyid.c:369 >> Possible null pointer dereference: sub_pk - otherwise it is redundant to >> check if sub_pk is null at line 366 > > Huh? > > keyid_from_pk (main_pk, NULL); > if (sub_pk) > keyid_from_pk (sub_pk, NULL); > > return keystr_with_sub (main_pk->keyid, sub_pk? sub_pk->keyid:NULL); > > That looks pretty right. > > >> gnupg/common/estream.c:3106 >> Possible null pointer dereference: stream - otherwise it is redundant to >> check if stream is null at line 3104 > > Okay. I removed the redunant check. > > >> gnupg/agent/command.c:285 >> Possible null pointer dereference: s - otherwise it is redundant to check if >> s is null at line 282 > > Nope. Similars in sm/server.c and g10/server.c. > >> gnupg/agent/command.c:268 >> Possible null pointer dereference: s - otherwise it is redundant to check if >> s is null at line 266 > > Ditto. > > >> libassuan/src/assuan.c:136 >> Possible null pointer dereference: ctx - otherwise it is redundant to check >> if ctx is null at line 135 > > Mean while fixed. > >> libgcrypt/cipher/md.c:976 >> Possible null pointer dereference: r - otherwise it is redundant to check if >> r is null at line 971 > > See above. > >> libgcrypt/cipher/md.c:1251 >> Possible null pointer dereference: spec - otherwise it is redundant to check >> if spec is null at line 1247 > > Already fixed. > > >> libksba/src/cert.c:447 >> Possible null pointer dereference: cert - otherwise it is redundant to check >> if cert is null at line 445 > > Ditto. > > >> libgcrypt/src/hmac256.c:510 >> Deallocating a deallocated pointer: hd > > I still can't see the problem. > >> gpgme/tests/gpg/t-eventloop.c:82 >> Assigning address of local auto-variable to a function parameter. > > See yesterdays comment. > >> >> pinentry/gtk+-2/gtksecentry.h:188 >> number of character ({) when these macros are defined: >> 'MAKE_EMACS_HAPPY;__cplusplus'. > > See yesterdays comment. > > >> The bad news is that cppcheck did not check a lot of files because there were >> more combinations of #ifdefs than its limit. I'll try upping the limit and >> running it again. These are the files that were not checked because of >> "Interrupted checking because of too many #ifdef configurations." > > Somehow I doubt that it makes sense to go through a list of so many > false positives. At least I can't do that in the next days. > > Anyway, we found a couple of things and that was worth it. > > > Feel free to forward to gnupg-devel. The question now is whether you want cppcheck errors to automatically trigger an email to the committers. That will be a lot easier if cppcheck does not find things its thinks are errors. That means doing things like: - char buffer[BUFFER_SIZE]; + char buffer[BUFFER_SIZE] = ""; // make cppcheck happy I'm happy to submit these kinds of fixes if you are willing to accept them. .hc -- PGP fingerprint: 5E61 C878 0F86 295C E17D 8677 9F0F E587 374B BE81 From hanno at hboeck.de Wed Apr 16 12:53:54 2014 From: hanno at hboeck.de (Hanno =?UTF-8?B?QsO2Y2s=?=) Date: Wed, 16 Apr 2014 12:53:54 +0200 Subject: gpg --import segfaults on a specific key Message-ID: <20140416125354.13461606@hboeck.de> Hi, I already posted this to the gcrypt-devel list, but seems there isn't much activity and I don't know if this is a bug in libgcrypt or gnupg, so I repost it here: ------------------------------- On my system if I try to import this key http://pgp.mit.edu/pks/lookup?op=get&search=0x98EEB6F7D87171CF with gnupg it segfaults. Backtrace (see below) indicates that the crash happens somewhere in libgcrypt, so I'm posting it here. My libgcrypt version is 1.6.1, gnupg is 2.0.22. I can reproduce it on another system with libgcrypt 1.5.3. Both are Gentoo. ---------------------- Others were able to reproduce on Debian: http://marc.info/?l=gcrypt-devel&m=139684958006467&w=2 and already proposed patches: http://marc.info/?l=gcrypt-devel&m=139702920722553&w=2 cu, -- Hanno B?ck http://hboeck.de/ mail/jabber: hanno at hboeck.de GPG: BBB51E42 -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: not available URL: From wk at gnupg.org Wed Apr 16 14:04:30 2014 From: wk at gnupg.org (Werner Koch) Date: Wed, 16 Apr 2014 14:04:30 +0200 Subject: automated cppcheck for gnupg In-Reply-To: <20140416104107.GD24527@leortable> (Leo Gaspard's message of "Wed, 16 Apr 2014 12:41:07 +0200") References: <534D8313.9040901@guardianproject.info> <20140415192230.GB24527@leortable> <534DA344.3010004@guardianproject.info> <20140415213509.GC24527@leortable> <8738hd4u4v.fsf@vigenere.g10code.de> <20140416104107.GD24527@leortable> Message-ID: <87ob011nw1.fsf@vigenere.g10code.de> On Wed, 16 Apr 2014 12:41, ekleog at gmail.com said: >> ctx = malloc (sizeof *ctx); >> if (!ctx) >> { >> trace_error (ctx->err_source) >> return NULL; >> } > Here, the argument to gpg_strsource (assuming the point of the mistake is the > one of the latest git commit on libassuan) would be attacker-controlled, as a > consequence the one to gpg_err_source. Doing no check, it means the No, the argument is not attacker controlled. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Wed Apr 16 14:14:11 2014 From: wk at gnupg.org (Werner Koch) Date: Wed, 16 Apr 2014 14:14:11 +0200 Subject: automated cppcheck for gnupg In-Reply-To: <534E608D.7080204@guardianproject.info> (Hans-Christoph Steiner's message of "Wed, 16 Apr 2014 06:50:53 -0400") References: <534D8313.9040901@guardianproject.info> <87ioqa4atk.fsf@vigenere.g10code.de> <534DA83C.9080803@guardianproject.info> <87y4z53d1t.fsf@vigenere.g10code.de> <534E608D.7080204@guardianproject.info> Message-ID: <87k3ap1nfw.fsf@vigenere.g10code.de> On Wed, 16 Apr 2014 12:50, hans at guardianproject.info said: > The question now is whether you want cppcheck errors to automatically trigger > an email to the committers. That will be a lot easier if cppcheck does not > find things its thinks are errors. That means doing things like: One mail more does not harm. However, given the long list of false positives I doubt that it makes sense to look at the identified problems regularly. > > - char buffer[BUFFER_SIZE]; > + char buffer[BUFFER_SIZE] = ""; // make cppcheck happy No, that is plainly wrong. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From ekleog at gmail.com Wed Apr 16 14:14:16 2014 From: ekleog at gmail.com (Leo Gaspard) Date: Wed, 16 Apr 2014 14:14:16 +0200 Subject: automated cppcheck for gnupg In-Reply-To: <87ob011nw1.fsf@vigenere.g10code.de> References: <534D8313.9040901@guardianproject.info> <20140415192230.GB24527@leortable> <534DA344.3010004@guardianproject.info> <20140415213509.GC24527@leortable> <8738hd4u4v.fsf@vigenere.g10code.de> <20140416104107.GD24527@leortable> <87ob011nw1.fsf@vigenere.g10code.de> Message-ID: <20140416121416.GE24527@leortable> On Wed, Apr 16, 2014 at 02:04:30PM +0200, Werner Koch wrote: > On Wed, 16 Apr 2014 12:41, ekleog at gmail.com said: > > >> ctx = malloc (sizeof *ctx); > >> if (!ctx) > >> { > >> trace_error (ctx->err_source) > >> return NULL; > >> } > > > Here, the argument to gpg_strsource (assuming the point of the mistake is the > > one of the latest git commit on libassuan) would be attacker-controlled, as a > > consequence the one to gpg_err_source. Doing no check, it means the > > No, the argument is not attacker controlled. Well... Assuming the OS flaw from the first paragraph of my former answer, it would be, as it is a NULL deref that is mapped to a page chosen by the attacker (so long as the needed page can be found in the kernel pages, but there are a lot of kernel pages) From wk at gnupg.org Wed Apr 16 14:57:35 2014 From: wk at gnupg.org (Werner Koch) Date: Wed, 16 Apr 2014 14:57:35 +0200 Subject: gpg --import segfaults on a specific key In-Reply-To: <20140416125354.13461606@hboeck.de> ("Hanno =?utf-8?Q?B=C3=B6?= =?utf-8?Q?ck=22's?= message of "Wed, 16 Apr 2014 12:53:54 +0200") References: <20140416125354.13461606@hboeck.de> Message-ID: <87bnw11lfk.fsf@vigenere.g10code.de> On Wed, 16 Apr 2014 12:53, hanno at hboeck.de said: > I already posted this to the gcrypt-devel list, but seems there isn't > much activity and I don't know if this is a bug in libgcrypt or gnupg, Sorry for delaying this. I just looked at it and found a fix. See below. > I can reproduce it on another system with libgcrypt 1.5.3. Both are I have not yet analyzed why it also crashes with libgcrypt 1.5.3. 1.5.3 still knows about RSA_S (3). Anyway the patch to GnupG 2.0 fixes it. GnuPG master is not affected due to an explict OpenPGP/Libgcrypt algorithm mapping table. Salam-Shalom, Werner ==== >From efecbb7a3f0c32ea40db3a050c89f288550b05c2 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 15 Apr 2014 16:40:48 +0200 Subject: [PATCH] gpg: Fix use of deprecated RSA_E and RSA_E with newer libgcrypts. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * g10/misc.c (pubkey_get_npkey): Map RSA_E and RSA_S to RSA. (pubkey_get_nskey): Ditto. (pubkey_get_nsig): Ditto. (pubkey_get_nenc): Ditto. (pubkey_nbits): Take care of RSA_E and RSA_S. -- The problem was that parse_key did not know about RSA_S and thus used an opaque MPI which later crashed Libgcrypt. It is possible to fix that also in Libgcrypt but we better do it here as well. A test key using RSA_S is 0x98EEB6F7D87171CF. Reported-by: Hanno B?ck --- g10/misc.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/g10/misc.c b/g10/misc.c index 9b7c8ab..82a13aa 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -1359,6 +1359,9 @@ pubkey_get_npkey( int algo ) if (algo == GCRY_PK_ELG_E) algo = GCRY_PK_ELG; + else if (algo == GCRY_PK_RSA_E || algo == GCRY_PK_RSA_S) + algo = GCRY_PK_RSA; + if (gcry_pk_algo_info (map_pk_openpgp_to_gcry (algo), GCRYCTL_GET_ALGO_NPKEY, NULL, &n)) n = 0; @@ -1379,6 +1382,9 @@ pubkey_get_nskey( int algo ) if (algo == GCRY_PK_ELG_E) algo = GCRY_PK_ELG; + else if (algo == GCRY_PK_RSA_E || algo == GCRY_PK_RSA_S) + algo = GCRY_PK_RSA; + if (gcry_pk_algo_info (map_pk_openpgp_to_gcry (algo), GCRYCTL_GET_ALGO_NSKEY, NULL, &n )) n = 0; @@ -1399,6 +1405,9 @@ pubkey_get_nsig( int algo ) if (algo == GCRY_PK_ELG_E) algo = GCRY_PK_ELG; + else if (algo == GCRY_PK_RSA_E || algo == GCRY_PK_RSA_S) + algo = GCRY_PK_RSA; + if (gcry_pk_algo_info (map_pk_openpgp_to_gcry (algo), GCRYCTL_GET_ALGO_NSIGN, NULL, &n)) n = 0; @@ -1419,6 +1428,9 @@ pubkey_get_nenc( int algo ) if (algo == GCRY_PK_ELG_E) algo = GCRY_PK_ELG; + else if (algo == GCRY_PK_RSA_E || algo == GCRY_PK_RSA_S) + algo = GCRY_PK_RSA; + if (gcry_pk_algo_info (map_pk_openpgp_to_gcry (algo), GCRYCTL_GET_ALGO_NENCR, NULL, &n )) n = 0; @@ -1443,7 +1455,9 @@ pubkey_nbits( int algo, gcry_mpi_t *key ) "(public-key(elg(p%m)(g%m)(y%m)))", key[0], key[1], key[2] ); } - else if( algo == GCRY_PK_RSA ) { + else if (algo == GCRY_PK_RSA + || algo == GCRY_PK_RSA_S + || algo == GCRY_PK_RSA_E ) { rc = gcry_sexp_build ( &sexp, NULL, "(public-key(rsa(n%m)(e%m)))", key[0], key[1] ); -- 1.8.4.3 -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Wed Apr 16 15:25:35 2014 From: wk at gnupg.org (Werner Koch) Date: Wed, 16 Apr 2014 15:25:35 +0200 Subject: automated cppcheck for gnupg In-Reply-To: <20140416121416.GE24527@leortable> (Leo Gaspard's message of "Wed, 16 Apr 2014 14:14:16 +0200") References: <534D8313.9040901@guardianproject.info> <20140415192230.GB24527@leortable> <534DA344.3010004@guardianproject.info> <20140415213509.GC24527@leortable> <8738hd4u4v.fsf@vigenere.g10code.de> <20140416104107.GD24527@leortable> <87ob011nw1.fsf@vigenere.g10code.de> <20140416121416.GE24527@leortable> Message-ID: <8738hd1k4w.fsf@vigenere.g10code.de> On Wed, 16 Apr 2014 14:14, ekleog at gmail.com said: > Well... Assuming the OS flaw from the first paragraph of my former answer, it Well, okay. But that is a clear OS bug given the >30 year tradition of not mapping respective clearing the first page. [ In that case the attacker would only be able to return an arbitrary integer which is the used to index (with bounds check) a table of strings shown in a trace output. ] Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From ekleog at gmail.com Wed Apr 16 16:17:37 2014 From: ekleog at gmail.com (Leo Gaspard) Date: Wed, 16 Apr 2014 16:17:37 +0200 Subject: automated cppcheck for gnupg In-Reply-To: <8738hd1k4w.fsf@vigenere.g10code.de> References: <534D8313.9040901@guardianproject.info> <20140415192230.GB24527@leortable> <534DA344.3010004@guardianproject.info> <20140415213509.GC24527@leortable> <8738hd4u4v.fsf@vigenere.g10code.de> <20140416104107.GD24527@leortable> <87ob011nw1.fsf@vigenere.g10code.de> <20140416121416.GE24527@leortable> <8738hd1k4w.fsf@vigenere.g10code.de> Message-ID: <20140416141737.GF24527@leortable> On Wed, Apr 16, 2014 at 03:25:35PM +0200, Werner Koch wrote: > [...] > > [ In that case the attacker would only be able to return an arbitrary > integer which is the used to index (with bounds check) a table of > strings shown in a trace output. ] So there are bound checks. I had nothing to worry about. Thanks! Leo From hans at guardianproject.info Wed Apr 16 21:22:10 2014 From: hans at guardianproject.info (Hans-Christoph Steiner) Date: Wed, 16 Apr 2014 15:22:10 -0400 Subject: automated cppcheck for gnupg In-Reply-To: <87k3ap1nfw.fsf@vigenere.g10code.de> References: <534D8313.9040901@guardianproject.info> <87ioqa4atk.fsf@vigenere.g10code.de> <534DA83C.9080803@guardianproject.info> <87y4z53d1t.fsf@vigenere.g10code.de> <534E608D.7080204@guardianproject.info> <87k3ap1nfw.fsf@vigenere.g10code.de> Message-ID: <534ED862.8080606@guardianproject.info> On 04/16/2014 08:14 AM, Werner Koch wrote: > On Wed, 16 Apr 2014 12:50, hans at guardianproject.info said: > >> The question now is whether you want cppcheck errors to automatically trigger >> an email to the committers. That will be a lot easier if cppcheck does not >> find things its thinks are errors. That means doing things like: > > One mail more does not harm. However, given the long list of false > positives I doubt that it makes sense to look at the identified problems > regularly. > >> >> - char buffer[BUFFER_SIZE]; >> + char buffer[BUFFER_SIZE] = ""; // make cppcheck happy > > No, that is plainly wrong. The point is to initialize it with something that does no harm, whatever that might be (memcpy(0)?). It may seem pointless to placate the automaton (cppcheck), but while it is not as good as a human at catching and understanding errors, it does so tirelessly and basically for free. The kind of setup that works best with jenkins automation is when the pointless errors are fixed so that Jenkins can easily notify the committer when new errors arise. It seems this quick and dirty scan caught a bunch of issues, so it is worthwhile. Another option is adding this comment on the line before to disable the error: // cppcheck-suppress memleak where 'memleak' is the error type. .hc -- PGP fingerprint: 5E61 C878 0F86 295C E17D 8677 9F0F E587 374B BE81 From nicholas.cole at gmail.com Mon Apr 21 18:13:39 2014 From: nicholas.cole at gmail.com (Nicholas Cole) Date: Mon, 21 Apr 2014 17:13:39 +0100 Subject: --homedir in gnupg 2.1 Message-ID: When management of the secret keys is moved to gpg-agent, will it still be possible to mimic the effect of --homedir in previous versions? Currently, for a lot of testing I want a completely blank setup. I simply set --homedir to a temporary directory, and avoid affecting any existing public or private keyrings. In the same way, one might manage different identities (eg. home and work) by doing this kind of thing. How will this kind of thing work in gnupg 2.1? Best wishes, Nicholas From wk at gnupg.org Tue Apr 22 14:10:39 2014 From: wk at gnupg.org (Werner Koch) Date: Tue, 22 Apr 2014 14:10:39 +0200 Subject: --homedir in gnupg 2.1 In-Reply-To: (Nicholas Cole's message of "Mon, 21 Apr 2014 17:13:39 +0100") References: Message-ID: <87y4yxva2o.fsf@vigenere.g10code.de> On Mon, 21 Apr 2014 18:13, nicholas.cole at gmail.com said: > Currently, for a lot of testing I want a completely blank setup. I > simply set --homedir to a temporary directory, and avoid affecting any > existing public or private keyrings. I do it this way: $ cd foo $ GNUPGHOME="$pwd" gpg-agent --daemon bash and use that new shell for testing. If you are done with it an exit shuts down the agent after some seconds. As usual watchgnupg in another xterm is quite helpful. > How will this kind of thing work in gnupg 2.1? Actually 2.0 behaves just the same for gpgsm because gpgsm has always stored the keys under control of the gpg-agent. Any modern version of gpg2 should connect to a running agent using the socket "S.gpg-agent" in the home directory if the envvar GPG_AGENT_INFO is not set (which is the default for 2.1). The problem is that if there is no running agent, a new agent is started but --homedir is not passed to that agent. This is clearly surprising and should be fixed. Dirmngr in 2.1 is already started on the fly with --homedir passed. Stay tuned for the next commit. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From dkg at fifthhorseman.net Wed Apr 23 00:46:15 2014 From: dkg at fifthhorseman.net (Daniel Kahn Gillmor) Date: Tue, 22 Apr 2014 18:46:15 -0400 Subject: [PATCH] correct "trusted" to "valid" for trust-model always Message-ID: <1398206775-23106-1-git-send-email-dkg@fifthhorseman.net> With --trust-model=always, all keys and user IDs are considered automatically valid; they are not automatically trusted (setting universal ownertrust to anything other than "ultimate" would be insufficient to acheive the effect of --trust-model=always, due to --max-cert-depth and certificate path reachability). Thanks to Nicolai Josuttis for pointing out this documentation error. --- doc/gpg.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 26179bd..8274da5 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1428,7 +1428,7 @@ Set what trust model GnuPG should follow. The models are: @item always @opindex trust-mode:always Skip key validation and assume that used keys are always fully - trusted. You generally won't use this unless you are using some + valid. You generally won't use this unless you are using some external validation scheme. This option also suppresses the "[uncertain]" tag printed with signature checks when there is no evidence that the user ID is bound to the key. -- 1.9.2 From nicholas.cole at gmail.com Wed Apr 23 10:12:39 2014 From: nicholas.cole at gmail.com (Nicholas Cole) Date: Wed, 23 Apr 2014 09:12:39 +0100 Subject: --homedir in gnupg 2.1 In-Reply-To: <87y4yxva2o.fsf@vigenere.g10code.de> References: <87y4yxva2o.fsf@vigenere.g10code.de> Message-ID: On Tue, Apr 22, 2014 at 1:10 PM, Werner Koch wrote: > On Mon, 21 Apr 2014 18:13, nicholas.cole at gmail.com said: > >> Currently, for a lot of testing I want a completely blank setup. I >> simply set --homedir to a temporary directory, and avoid affecting any >> existing public or private keyrings. > > I do it this way: > > $ cd foo > $ GNUPGHOME="$pwd" gpg-agent --daemon bash > > and use that new shell for testing. If you are done with it an exit > shuts down the agent after some seconds. As usual watchgnupg in another > xterm is quite helpful. > >> How will this kind of thing work in gnupg 2.1? > > Actually 2.0 behaves just the same for gpgsm because gpgsm has always > stored the keys under control of the gpg-agent. > > Any modern version of gpg2 should connect to a running agent using the > socket "S.gpg-agent" in the home directory if the envvar GPG_AGENT_INFO > is not set (which is the default for 2.1). > > The problem is that if there is no running agent, a new agent is started > but --homedir is not passed to that agent. This is clearly surprising > and should be fixed. Dirmngr in 2.1 is already started on the fly with > --homedir passed. Stay tuned for the next commit. Thanks Werner. I assume that works because gpg-agent sets appropriate environment variables, and that I could set it up so that it doesn't interfere with any other gpg-agent processes that might be running. So just to be clear, I would need to: start a new agent with a non-standard --homedir make sure that GPG_AGENT_INFO is set start gpg with the non-standard --homedir Best wishes, N. From gniibe at fsij.org Wed Apr 23 12:33:12 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Wed, 23 Apr 2014 19:33:12 +0900 Subject: [PATCH] Small bug fixes for ECDH Message-ID: <1398249192.2448.1.camel@cfw2.gniibe.org> While working for Curve25519, I found two bugs for ECDH. (1) SEXP length calculation is wrong. It's something like: (5:value65:...)\0 ^ ^ ^ | | | p new p endp after ++ (len - 10) is length of the header and content. So, it's not 11 but 10 which should be subtracted. (2) According to RFC 6637, "Algorithm-Specific Fields for ECDH" are: * an ephemeral public key then, * symmetric key info (size, key) OK to apply? diff --git a/g10/call-agent.c b/g10/call-agent.c index 5ad0983..dc52139 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -1928,7 +1928,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, xfree (buf); return gpg_error (GPG_ERR_INV_SEXP); } - len -= 11; /* Count only the data of the second part. */ + len -= 10; /* Count only the data of the second part. */ p = buf + 8; /* Skip leading parenthesis and the value tag. */ n = strtoul (p, &endp, 10); diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index a563ec0..60f7611 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -185,7 +185,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) err = gpg_error (GPG_ERR_BAD_MPI); else err = gcry_sexp_build (&s_data, NULL, "(enc-val(ecdh(s%m)(e%m)))", - enc->data[0], enc->data[1]); + enc->data[1], enc->data[0]); } else err = gpg_error (GPG_ERR_BUG); -- From gniibe at fsij.org Wed Apr 23 12:45:26 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Wed, 23 Apr 2014 19:45:26 +0900 Subject: [PATCH] Curve25519 for ECDH Message-ID: <1398249926.2587.1.camel@cfw2.gniibe.org> Hello, Here is a patch to support Curve25519 for ECDH. It requires changes of libgcrypt which will be soon posted to gcrypt-devel. This is not mature and it will be revised soon. The change g10/ecdh.c is just for Curve25519. I think that we should change the code to call key the generation routine in libgcrypt. Curve25519 has cofactor 8, and in its design, private key should be multiple of 8. We could consider ECDH with cofactor where we multiply cofactor, but this private key handling (of multiple of cofactor) looks better for me. diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c index 94a2296..73407cd 100644 --- a/common/openpgp-oid.c +++ b/common/openpgp-oid.c @@ -280,6 +280,11 @@ openpgp_curve_to_oid (const char *name, unsigned int *r_nbits) oidstr = "1.3.6.1.4.1.11591.15.1"; nbits = 255; } + else if (!strcmp (name, "Curve25519") || !strcmp (name, "curve25519")) + { + oidstr = "1.3.6.1.4.1.3029.1.5.1"; + nbits = 255; + } else if (!strcmp (name, "nistp256")) { oidstr = "1.2.840.10045.3.1.7"; @@ -335,6 +340,8 @@ openpgp_oid_to_curve (const char *oid) name = ""; else if (!strcmp (oid, "1.3.6.1.4.1.11591.15.1")) name = "ed25519"; + else if (!strcmp (oid, "1.3.6.1.4.1.3029.1.5.1")) + name = "curve25519"; else if (!strcmp (oid, "1.2.840.10045.3.1.7")) name = "nistp256"; else if (!strcmp (oid, "1.3.132.0.10")) diff --git a/g10/ecdh.c b/g10/ecdh.c index 0b06239..cd18e55 100644 --- a/g10/ecdh.c +++ b/g10/ecdh.c @@ -434,6 +434,11 @@ gen_k (unsigned nbits) gcry_free (buffer); } + gcry_mpi_clear_bit (k, 255); + gcry_mpi_set_bit (k, 254); + gcry_mpi_clear_bit (k, 2); + gcry_mpi_clear_bit (k, 1); + gcry_mpi_clear_bit (k, 0); return k; } diff --git a/g10/keygen.c b/g10/keygen.c index f3052e4..942078a 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -2099,7 +2099,10 @@ ask_curve (void) const char *pretty_name; } curves[] = { #if GPG_USE_EDDSA - { "Ed25519", 0, 0, "Curve 25519" }, + { "Ed25519", 0, 0, "Curve 25519 in Edwards form (for signature)" }, +#endif +#if GPG_USE_ECDH + { "Curve25519", 0, 0, "Curve 25519 for Encryption" }, #endif #if GPG_USE_ECDSA || GPG_USE_ECDH { "NIST P-256", 0, 1, }, -- From wk at gnupg.org Wed Apr 23 14:12:06 2014 From: wk at gnupg.org (Werner Koch) Date: Wed, 23 Apr 2014 14:12:06 +0200 Subject: --homedir in gnupg 2.1 In-Reply-To: (Nicholas Cole's message of "Wed, 23 Apr 2014 09:12:39 +0100") References: <87y4yxva2o.fsf@vigenere.g10code.de> Message-ID: <87sip4s0rt.fsf@vigenere.g10code.de> On Wed, 23 Apr 2014 10:12, nicholas.cole at gmail.com said: > I assume that works because gpg-agent sets appropriate environment > variables, and that I could set it up so that it doesn't interfere No, gpg since 2.1 (i.e. git master) uses the socket S.gpg-agent in the GNUPGHOME directory by default. Older versions used a random socket and conveyed it via an envvar. The new system is much easier and on Windows on use for many years. The only drawback is that it won't work on certain remote file systems - if that ever turns out to be a problem we will find a solution. With 2.0 you may also use the fixed socket name approach by putting "use-standard-socket" into gpg-agent.conf or a similar configure option. My latest fix to start it correctly is not in 2.0; could be backported, though > So just to be clear, I would need to: > > start a new agent with a non-standard --homedir > make sure that GPG_AGENT_INFO is set With the latest change you better make sure that GPG_AGENT_INFO is not set. > start gpg with the non-standard --homedir My tests showed that it worked really nice. It will also help to make the tests suite more robust. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Wed Apr 23 14:19:40 2014 From: wk at gnupg.org (Werner Koch) Date: Wed, 23 Apr 2014 14:19:40 +0200 Subject: [PATCH] Curve25519 for ECDH In-Reply-To: <1398249926.2587.1.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Wed, 23 Apr 2014 19:45:26 +0900") References: <1398249926.2587.1.camel@cfw2.gniibe.org> Message-ID: <87oazss0f7.fsf@vigenere.g10code.de> On Wed, 23 Apr 2014 12:45, gniibe at fsij.org said: > #if GPG_USE_EDDSA > - { "Ed25519", 0, 0, "Curve 25519" }, > + { "Ed25519", 0, 0, "Curve 25519 in Edwards form (for signature)" }, > +#endif > +#if GPG_USE_ECDH > + { "Curve25519", 0, 0, "Curve 25519 for Encryption" }, > #endif My idea with the description was to only show Curve25519 because that is the name most people know about. With the addition of ECDH we will use the appropriate appropriate curve depending on the use (Ed25519 for a signing key and Curve25519 for an encryption key) Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Wed Apr 23 14:21:10 2014 From: wk at gnupg.org (Werner Koch) Date: Wed, 23 Apr 2014 14:21:10 +0200 Subject: [PATCH] Curve25519 for ECDH In-Reply-To: <1398249926.2587.1.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Wed, 23 Apr 2014 19:45:26 +0900") References: <1398249926.2587.1.camel@cfw2.gniibe.org> Message-ID: <87k3ags0cp.fsf@vigenere.g10code.de> On Wed, 23 Apr 2014 12:45, gniibe at fsij.org said: > The change g10/ecdh.c is just for Curve25519. I think that we should > change the code to call key the generation routine in libgcrypt. What about moving the entire OpenPGP specific code int Libgcrypt and to keep gpg clear of ECC specific things. Similar to the various padding modes for RSA. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Wed Apr 23 14:22:53 2014 From: wk at gnupg.org (Werner Koch) Date: Wed, 23 Apr 2014 14:22:53 +0200 Subject: [PATCH] Small bug fixes for ECDH In-Reply-To: <1398249192.2448.1.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Wed, 23 Apr 2014 19:33:12 +0900") References: <1398249192.2448.1.camel@cfw2.gniibe.org> Message-ID: <87fvl4s09u.fsf@vigenere.g10code.de> On Wed, 23 Apr 2014 12:33, gniibe at fsij.org said: > (len - 10) is length of the header and content. > So, it's not 11 but 10 which should be subtracted. Ohhh. My fault I guess. > (2) According to RFC 6637, "Algorithm-Specific Fields for ECDH" are: > > * an ephemeral public key > > then, > > * symmetric key info (size, key) I don't understand that. Why do we need to swap the parameters. was there a regression? -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From gniibe at fsij.org Thu Apr 24 06:54:53 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Thu, 24 Apr 2014 13:54:53 +0900 Subject: [PATCH] Small bug fixes for ECDH In-Reply-To: <87fvl4s09u.fsf@vigenere.g10code.de> References: <1398249192.2448.1.camel@cfw2.gniibe.org> <87fvl4s09u.fsf@vigenere.g10code.de> Message-ID: <1398315293.760.1.camel@cfw2.gniibe.org> On 2014-04-23 at 14:22 +0200, Werner Koch wrote: > > (2) According to RFC 6637, "Algorithm-Specific Fields for ECDH" are: > > > > * an ephemeral public key > > > > then, > > > > * symmetric key info (size, key) > > I don't understand that. Why do we need to swap the parameters. was > there a regression? I didn't understand well, either. I debugged and found it's swapped. It seems for me that... it was not working well long time. I don't know how the code around ECDH has been tested. I just found that tests/openpgp/ecc.test has been skipped for a while. At least, something like following is needed. Before Curve25519, I'm going to fix the code around ECDH. diff --git a/tests/openpgp/ecc.test b/tests/openpgp/ecc.test index 062a1ae..6f07f74 100755 --- a/tests/openpgp/ecc.test +++ b/tests/openpgp/ecc.test @@ -20,7 +20,7 @@ mainkeyids='BAA59D9C 45AF2FFE' -if have_pubkey_algo "ECC"; then +if have_pubkey_algo "ECDSA"; then : else info "No ECC support due to an old Libgcrypt" -- From gniibe at fsij.org Fri Apr 25 03:41:52 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Fri, 25 Apr 2014 10:41:52 +0900 Subject: [PATCH] ECC working again with new libgcrypt Message-ID: <1398390112.1511.5.camel@cfw2.gniibe.org> Here is a patch to fix ECC issues. With this patch, it now gets success on "make check" (specifically, ecc.test). There are confusions about PUBKEY_ALGO, if it's (1) the value defined by OpenPGP specification or (2) it's the value defined by libgcrypt API. Because it gets the value by the gcry_pk_map_name function (in convert_from_openpgp_main), it's (2). So, it is wrong to call map_pk_openpgp_to_gcry in do_unprotect and convert_from_openpgp_main. (This causes mysterious result of all keys will be handled as ECDH, as the value of PUBKEY_ALGO_ECDH equals to GCRY_PK_ECC.) Besides, the gcry_pk_map_name function in newer libgcrypt (1.6 and later), returns generic value, and doesn't distinguish detail. For example, "ECDSA" -> GCRY_PK_ECC "ECDH" -> GCRY_PK_ECC Because of this, we can't keep distinguishing "ECDSA" and "ECDH", although client sends specific information to agent. And, I confirmed that the change in g10/pubkey-enc.c (swapping data[0] and data[1]) is correct. OK to apply? diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 4c34130..ef34463 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -68,21 +68,17 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip) break; case GCRY_PK_ELG: - case GCRY_PK_ELG_E: err = gcry_sexp_build (&s_pkey, NULL, "(public-key(elg(p%m)(g%m)(y%m)))", pkey[0], pkey[1], pkey[2]); break; case GCRY_PK_RSA: - case GCRY_PK_RSA_E: - case GCRY_PK_RSA_S: err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]); break; - case GCRY_PK_ECDSA: - case GCRY_PK_ECDH: + case GCRY_PK_ECC: err = gcry_sexp_build (&s_pkey, NULL, "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))", pkey[0], pkey[1], pkey[2], pkey[3], pkey[4], @@ -138,14 +134,10 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey) skey[5]); break; - case GCRY_PK_ECDSA: - case GCRY_PK_ECDH: - /* Although our code would work with "ecc" we explicitly use - "ecdh" or "ecdsa" to implicitly set the key capabilities. */ + case GCRY_PK_ECC: err = gcry_sexp_build (&s_skey, NULL, - "(private-key(%s(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)" + "(private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)" "(d%m)))", - pubkey_algo == GCRY_PK_ECDSA?"ecdsa":"ecdh", skey[0], skey[1], skey[2], skey[3], skey[4], skey[5], skey[6]); break; @@ -186,7 +178,6 @@ convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, break; case GCRY_PK_ELG: - case GCRY_PK_ELG_E: err = gcry_sexp_build (&s_skey, NULL, "(protected-private-key(elg(p%m)(g%m)(y%m)" @@ -196,8 +187,6 @@ convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, case GCRY_PK_RSA: - case GCRY_PK_RSA_E: - case GCRY_PK_RSA_S: err = gcry_sexp_build (&s_skey, NULL, "(protected-private-key(rsa(n%m)(e%m)", @@ -205,15 +194,11 @@ convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, skey[0], skey[1], transfer_key ); break; - case GCRY_PK_ECDSA: - case GCRY_PK_ECDH: - /* Although our code would work with "ecc" we explicitly use - "ecdh" or "ecdsa" to implicitly set the key capabilities. */ + case GCRY_PK_ECC: err = gcry_sexp_build (&s_skey, NULL, - "(protected-private-key(%s(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)" + "(protected-private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)" "(protected openpgp-native%S)))", - pubkey_algo == GCRY_PK_ECDSA?"ecdsa":"ecdh", skey[0], skey[1], skey[2], skey[3], skey[4], skey[5], transfer_key); break; @@ -359,10 +344,6 @@ do_unprotect (const char *passphrase, *r_key = NULL; - /* Unfortunately, the OpenPGP PK algorithm numbers need to be - re-mapped for Libgcrypt. */ - pubkey_algo = map_pk_openpgp_to_gcry (pubkey_algo); - err = prepare_unprotect (pubkey_algo, skey, skeysize, s2k_mode, &npkey, &nskey, &skeylen); if (err) @@ -864,14 +845,12 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, if (unattended && !from_native) { - int pubkey_g_algo = map_pk_openpgp_to_gcry (pubkey_algo); - - err = prepare_unprotect (pubkey_g_algo, skey, DIM(skey), s2k_mode, + err = prepare_unprotect (pubkey_algo, skey, DIM(skey), s2k_mode, NULL, NULL, NULL); if (err) goto leave; - err = convert_transfer_key (&s_skey, pubkey_g_algo, skey, s_pgp); + err = convert_transfer_key (&s_skey, pubkey_algo, skey, s_pgp); if (err) goto leave; } @@ -1195,7 +1174,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase, else if (!strcmp (name, "ecc")) { /* FIXME: We need to use the curve parameter. */ - algoname = "?"; /* Decide later by checking the usage. */ + algoname = "ecc"; /* Decide later by checking the usage. */ npkey = 6; nskey = 7; err = gcry_sexp_extract_param (list, NULL, "pabgnqd", diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 8078cba..5319e49 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -2546,12 +2546,3 @@ check_for_running_agent (int silent, int mode) assuan_release (ctx); return 0; } - -/* TODO: it is also in misc, which is not linked with the agent */ -/* FIXME: The agent should not know about openpgp internals - weel - except for some stuff in cvt-openpgp. */ -int -map_pk_openpgp_to_gcry (int algo) -{ - return (algo==PUBKEY_ALGO_ECDSA ? GCRY_PK_ECDSA : (algo==PUBKEY_ALGO_ECDH ? GCRY_PK_ECDH : algo)); -} diff --git a/g10/call-agent.c b/g10/call-agent.c index ad578db..42cc9ea 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -1991,7 +1991,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, xfree (buf); return gpg_error (GPG_ERR_INV_SEXP); } - len -= 11; /* Count only the data of the second part. */ + len -= 10; /* Count only the data of the second part. */ p = buf + 8; /* Skip leading parenthesis and the value tag. */ n = strtoul (p, &endp, 10); diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index a563ec0..60f7611 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -185,7 +185,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) err = gpg_error (GPG_ERR_BAD_MPI); else err = gcry_sexp_build (&s_data, NULL, "(enc-val(ecdh(s%m)(e%m)))", - enc->data[0], enc->data[1]); + enc->data[1], enc->data[0]); } else err = gpg_error (GPG_ERR_BUG); diff --git a/tests/openpgp/ecc.test b/tests/openpgp/ecc.test index 062a1ae..d609549 100755 --- a/tests/openpgp/ecc.test +++ b/tests/openpgp/ecc.test @@ -20,7 +20,7 @@ mainkeyids='BAA59D9C 45AF2FFE' -if have_pubkey_algo "ECC"; then +if have_pubkey_algo "ECDSA"; then : else info "No ECC support due to an old Libgcrypt" -- From wk at gnupg.org Fri Apr 25 12:38:13 2014 From: wk at gnupg.org (Werner Koch) Date: Fri, 25 Apr 2014 12:38:13 +0200 Subject: [PATCH] ECC working again with new libgcrypt In-Reply-To: <1398390112.1511.5.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Fri, 25 Apr 2014 10:41:52 +0900") References: <1398390112.1511.5.camel@cfw2.gniibe.org> Message-ID: <871twlofsa.fsf@vigenere.g10code.de> On Fri, 25 Apr 2014 03:41, gniibe at fsij.org said: > OK to apply? Sure. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From gniibe at fsij.org Mon Apr 28 03:56:38 2014 From: gniibe at fsij.org (NIIBE Yutaka) Date: Mon, 28 Apr 2014 10:56:38 +0900 Subject: [PATCH] ECC working again with new libgcrypt In-Reply-To: <871twlofsa.fsf@vigenere.g10code.de> References: <1398390112.1511.5.camel@cfw2.gniibe.org> <871twlofsa.fsf@vigenere.g10code.de> Message-ID: <1398650198.1534.2.camel@cfw2.gniibe.org> On 2014-04-25 at 12:38 +0200, Werner Koch wrote: > On Fri, 25 Apr 2014 03:41, gniibe at fsij.org said: > > > OK to apply? > > Sure. I applied and pushed it to the master branch. It now works with newer libgcrypt (>= 1.6) (but not with newest development version). I don't apply the change of tests/openpgp/ecc.test which enables the ECC tests again, because ECC tests fails with newest version of libgcrypt. I think that it is a problem of libgcrypt, and I have posted a patch with subject: [PATCH] ECC: (flags param) is only for key generation After this fix of libgcrypt, I'll apply the change to tests/openpgp/ecc.test. --