From malte at wk3.org Tue Aug 4 01:36:16 2015 From: malte at wk3.org (malte at wk3.org) Date: Tue, 4 Aug 2015 01:36:16 +0200 Subject: [Sks-devel] Analyzing key server data In-Reply-To: <1435915384.20594.8.camel@cryptobitch.de> References: <20150322125848.218ee839@pc1> <1435915384.20594.8.camel@cryptobitch.de> Message-ID: <20150804013616.72eeaccf7de17a8c72c7ccd1@wk3.org> Hi, Hockeypuck uses MongoDB or PostgreSQL as key storage backends. I don't know about MongoDB, but I know that while the tables are kept quite minimal in PostgreSQL, you could easily create a new table which inherits from the original one, adding more columns you can filter for. The size of the whole database in PostgreSQL is 21 GB. It's quite fast. Sincerely, Malte From ueno at gnu.org Tue Aug 4 09:57:14 2015 From: ueno at gnu.org (Daiki Ueno) Date: Tue, 04 Aug 2015 16:57:14 +0900 Subject: Memory Hole protected e-mail headers In-Reply-To: <87egjo86ox.fsf@alice.fifthhorseman.net> (Daniel Kahn Gillmor's message of "Fri, 31 Jul 2015 15:31:42 -0400") References: <87egjo86ox.fsf@alice.fifthhorseman.net> Message-ID: Daniel Kahn Gillmor writes: > https://modernpgp.org/memoryhole/ > https://github.com/ModernPGP/memoryhole/ > > If you're an implementor of a Mail User Agent (MUA) that handles or > generates OpenPGP-signed or -encrypted messages, we want to make sure > this makes sense to you. As I will eventually implement it in Emacs (Gnus), I would like to clarify a point: is it just meant to be a guideline, or aiming at an amendment to RFC 3156? If it is the former, it makes sense to reuse the valid MIME structure. However, the implementation could be complicated, as it basically means to add an exception based on the message structure. On the other hand, if it is possible to revise RFC 3156, perhaps we could have a simpler message structure, something like: |--- multipart/signed |--- text/plain |--- application/pgp-signature |--- application/octet-stream (signed rfc822-headers) or: |--- multipart/encrypted |--- application/pgp-encrypted |--- application/octet-stream |--- application/octet-stream (encrypted rfc822-headers) where the rfc822-headers part is appended to the message as an optional 3rd part. This is an incompatible change, but I suppose this doesn't break most of existing MUAs, as long as they only look at the first two parts. Also, like Werner's idea[1], it allows IMAP MUAs to retrieve the metadata part (the 3rd part) independently of the main part. That would be useful for generating a summary. There are, of course, some drawbacks: - the 3rd part cannot be verified/decrypted with existing MUAs - the 3rd part must be securely associated with the 2nd part, to prevent the entire message structure from being crafted by attackers Regards, Footnotes: [1] https://lists.gnupg.org/pipermail/gnupg-devel/2015-June/030078.html -- Daiki Ueno From wk at gnupg.org Tue Aug 4 13:04:00 2015 From: wk at gnupg.org (Werner Koch) Date: Tue, 04 Aug 2015 13:04:00 +0200 Subject: Memory Hole protected e-mail headers In-Reply-To: <87egjo86ox.fsf@alice.fifthhorseman.net> (Daniel Kahn Gillmor's message of "Fri, 31 Jul 2015 15:31:42 -0400") References: <87egjo86ox.fsf@alice.fifthhorseman.net> Message-ID: <87d1z3tivz.fsf@vigenere.g10code.de> On Fri, 31 Jul 2015 21:31, dkg at fifthhorseman.net said: > * a description of how protected headers are structured, and how to > interpret them Is there a discussion on the pros and cons of rfc822-headers vs. TOP level MIME object headers? > * rough guidance on how to generate different forms of these messages. Sorry, I only see an outline of that guidance. > * a corpus of e-mails that conform or don't conform to the standard. > we want people to try these (both in memoryhole-aware and > non-memoryhole-aware MUAs) and make sure they look/behave as > expected. Yep. > patches, you can send them here, send them to me privately, or prepare > them as pull requests on github. If you have screenshots, i think [Why the hell a proprietary service like Github?] Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From dkg at fifthhorseman.net Tue Aug 4 19:09:05 2015 From: dkg at fifthhorseman.net (Daniel Kahn Gillmor) Date: Tue, 04 Aug 2015 13:09:05 -0400 Subject: Memory Hole protected e-mail headers In-Reply-To: References: <87egjo86ox.fsf@alice.fifthhorseman.net> Message-ID: <871tfj56by.fsf@alice.fifthhorseman.net> On Tue 2015-08-04 03:57:14 -0400, Daiki Ueno wrote: > As I will eventually implement it in Emacs (Gnus), yay! glad to hear this. > I would like to clarify a point: is it just meant to be a guideline, > or aiming at an amendment to RFC 3156? in the long term, we hope to make a formal specification. there was enough interest among a group of developers to experiment with different mechanisms first, though. We are hoping to gather development experience and a rough consensus about how this works for existing MUAs before submitting a formal RFC. > If it is the former, it makes sense to reuse the valid MIME structure. > However, the implementation could be complicated, as it basically > means to add an exception based on the message structure. It's not an exception based on message structure -- it's that the header information is bound to the message body. > On the other hand, if it is possible to revise RFC 3156, perhaps we > could have a simpler message structure, something like: > > |--- multipart/signed > |--- text/plain > |--- application/pgp-signature > |--- application/octet-stream (signed rfc822-headers) > > or: > > |--- multipart/encrypted > |--- application/pgp-encrypted > |--- application/octet-stream > |--- application/octet-stream (encrypted rfc822-headers) We've had similar proposals (see the "alternatives considered" section at https://github.com/ModernPGP/memoryhole/blob/master/README.md). > where the rfc822-headers part is appended to the message as an optional > 3rd part. This is an incompatible change, but I suppose this doesn't > break most of existing MUAs, as long as they only look at the first two > parts. The particular structure you propose would be a violation of RFC 3156. (https://tools.ietf.org/html/rfc3156#section-4 "The multipart/encrypted MIME body MUST consist of exactly two body parts," and https://tools.ietf.org/html/rfc3156#section-5 "The multipart/signed body MUST consist of exactly two parts."). We don't want to break existing clients that read these rules strictly. But other structures are possible, including this kind of approach: ???multipart/signed 1706 bytes ???multipart/mixed 850 bytes ????text/rfc822-headers 228 bytes ????multipart/alternative 450 bytes ? ???text/plain 86 bytes ? ???text/html 202 bytes ???application/pgp-signature 455 bytes Because we want some (but not all) protected headers to be visible for users of legacy (non-memoryhole-aware) MUAs, we might then need multiple text/rfc822-headers parts (one part for visible headers inside an encrypted message, the other for invisible). In discussion last week, several of us came to agreement that using the embedded MIME headers seemed the cleanest for invisible headers, and that we'd reserve a text/rfc822-header for explicitly visible ("force-display") headers. > Also, like Werner's idea[1], it allows IMAP MUAs to retrieve the > metadata part (the 3rd part) independently of the main part. That > would be useful for generating a summary. Sure, but such a summary would necessarily be independent of the message as a whole, right? because the MUA couldn't fetch the whole message to verify it. So you'd get a verifiable and/or encrypted summary that might or might not be legitimately bound to the message itself. This seems like a different goal than the goal of protecting e-mail headers. If folks want to talk separately about a separately-fetchable e-mail manifest, i think that would be a distinct conversation. > There are, of course, some drawbacks: > > - the 3rd part cannot be verified/decrypted with existing MUAs in the scheme we're looking at, we don't expect the embedded headers (the pieces in the MIME header blocks themselves) to be visible to existing MUAs. But we do expect the "force-display" part to be visible to any MUA that can decrypt and can render DSNs, so we are aiming for some level of backward compatibility here. > - the 3rd part must be securely associated with the 2nd part, to prevent > the entire message structure from being crafted by attackers This strikes me as a very tricky risk and a source of serious confusion and UI/UX trouble. I'd really rather not get into those particular problems with this proposal unless we have a well-understood and simple way out of them. Do you see a way to resolve it cleanly? --dkg From dkg at fifthhorseman.net Tue Aug 4 19:15:47 2015 From: dkg at fifthhorseman.net (Daniel Kahn Gillmor) Date: Tue, 04 Aug 2015 13:15:47 -0400 Subject: Memory Hole protected e-mail headers In-Reply-To: <87d1z3tivz.fsf@vigenere.g10code.de> References: <87egjo86ox.fsf@alice.fifthhorseman.net> <87d1z3tivz.fsf@vigenere.g10code.de> Message-ID: <87y4hr3rgc.fsf@alice.fifthhorseman.net> On Tue 2015-08-04 07:04:00 -0400, Werner Koch wrote: > On Fri, 31 Jul 2015 21:31, dkg at fifthhorseman.net said: > >> * a description of how protected headers are structured, and how to >> interpret them > > Is there a discussion on the pros and cons of rfc822-headers vs. TOP > level MIME object headers? I just sent some discussion about that in response to Daiki Ueno's post. Happy to discuss it more if there are more questions. >> * rough guidance on how to generate different forms of these messages. > > Sorry, I only see an outline of that guidance. yes, it's *very* rough. I'd welcome any patches that flesh out the guidance more fully. > [Why the hell a proprietary service like Github?] I share your dislike of github and other proprietary centralizers in general. For memoryhole, i see Github as merely a place to post the repository and make it easy for people to get to it and to look at parts of it without having to clone it. Thanks to the underlying decentralization of git itself, we'll be able to move the corpus elsewhere easily should github misbehave and someone else volunteer to perform the administrative duties of hosting public web presence. The repository is also available here for people who don't want to clone from github: git://lair.fifthhorseman.net/~dkg/memoryhole and as i said in the initial announcement, e-mailed patches are quite welcome. Regards, --dkg From gniibe at fsij.org Wed Aug 5 01:29:22 2015 From: gniibe at fsij.org (NIIBE Yutaka) Date: Wed, 05 Aug 2015 08:29:22 +0900 Subject: Scdaemon fixes Message-ID: <55C14AD2.5010903@fsij.org> Hello, I pushed fixes for scdaemon for ECC keys. I'm going to post the Curve25519 support patch. -- From gniibe at fsij.org Wed Aug 5 02:13:32 2015 From: gniibe at fsij.org (NIIBE Yutaka) Date: Wed, 05 Aug 2015 09:13:32 +0900 Subject: [TESTING] Curve25519 encryption support (update-2) In-Reply-To: <559C71F6.1070607@fsij.org> References: <559657AE.2050900@fsij.org> <559C71F6.1070607@fsij.org> Message-ID: <55C1552C.60906@fsij.org> On 07/08/2015 09:42 AM, NIIBE Yutaka wrote: > Here is a patch I am testing for Curve25519 encryption support (which > requires libgcrypt change for Curve25519, and Gnuk master branch). [...] > There are things we need to decide: OID, algo ID, and format. > Currently, I use: > > OID: 1.3.6.1.4.1.3029.1.5.1 > algo ID: ECC = 18 (not 22 nor 23) I think those two are stable. > Public key OpenPGP format: prefix 0x40 and native little endian I follow EdDSA for the prefix. With the prefix, it's always 33-byte. Even if it would misunderstood as MPI, it goes well. > Libgcrypt SEXP format: Use (flags eddsa) to specify DJB format/processing > (flags comp) for prefix 0x40 This is implementation detail and interaction between libgcrypt. Now, we use "(flags djb-tweak)" for preprocessed key (msb and cofactor), and "(flags comp)" for prefix 0x40. "(flags comp)" sounds a bit odd because it has no way to have full (x,y) for Montgomery curve and it results longer key data (+1 byte), but it matches EdDSA. It's more like "native little endian (possibly compressed)" now. Note that I need to remove an alias of "Ed25519" in common/openpgp-oid.c, since it's not compatible to libgcrypt. diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 562179b..39ccba2 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -83,14 +83,25 @@ get_keygrip (int pubkey_algo, const char *curve, gcry_mpi_t *pkey, case GCRY_PK_ECC: if (!curve) err = gpg_error (GPG_ERR_BAD_SECKEY); - else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) - err = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecc(curve %s)(flags eddsa)(q%m)))", - "Ed25519", pkey[0]); else - err = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecc(curve %s)(q%m)))", - curve, pkey[0]); + { + const char *format; + + if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + { + format = "(public-key(ecc(curve %s)(flags eddsa)(q%m)))"; + curve = "Ed25519"; + } + else if (!strcmp (curve, openpgp_curve_to_oid ("Curve25519", NULL))) + { + format = "(public-key(ecc(curve %s)(flags djb-tweak)(q%m)))"; + curve = "Curve25519"; + } + else + format = "(public-key(ecc(curve %s)(q%m)))"; + + err = gcry_sexp_build (&s_pkey, NULL, format, curve, pkey[0]); + } break; default: @@ -146,19 +157,27 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, case GCRY_PK_ECC: if (!curve) err = gpg_error (GPG_ERR_BAD_SECKEY); - else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + else { - /* Do not store the OID as name but the real name and the - EdDSA flag. */ - err = gcry_sexp_build (&s_skey, NULL, - "(private-key(ecc(curve%s)(flags eddsa)" - "(q%m)(d%m)))", - "Ed25519", skey[0], skey[1]); + const char *format; + + if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + { + /* Do not store the OID as name but the real name and the + EdDSA flag. */ + format = "(private-key(ecc(curve %s)(flags eddsa)(q%m)(d%m)))"; + curve = "Ed25519"; + } + else if (!strcmp (curve, openpgp_curve_to_oid ("Curve25519", NULL))) + { + format = "(private-key(ecc(curve %s)(flags djb-tweak)(q%m)(d%m)))"; + curve = "Curve25519"; + } + else + format = "(private-key(ecc(curve %s)(q%m)(d%m)))"; + + err = gcry_sexp_build (&s_skey, NULL, format, curve, skey[0], skey[1]); } - else - err = gcry_sexp_build (&s_skey, NULL, - "(private-key(ecc(curve%s)(q%m)(d%m)))", - curve, skey[0], skey[1]); break; default: @@ -216,22 +235,30 @@ convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, case GCRY_PK_ECC: if (!curve) err = gpg_error (GPG_ERR_BAD_SECKEY); - else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + else { - /* Do not store the OID as name but the real name and the - EdDSA flag. */ - err = gcry_sexp_build - (&s_skey, NULL, - "(protected-private-key(ecc(curve%s)(flags eddsa)(q%m)" - "(protected openpgp-native%S)))", - "Ed25519", skey[0], transfer_key); + const char *format; + + if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + { + /* Do not store the OID as name but the real name and the + EdDSA flag. */ + format = "(protected-private-key(ecc(curve %s)(flags eddsa)(q%m)" + "(protected openpgp-native%S)))"; + curve = "Ed25519"; + } + else if (!strcmp (curve, openpgp_curve_to_oid ("Curve25519", NULL))) + { + format = "(protected-private-key(ecc(curve %s)(flags djb-tweak)(q%m)" + "(protected openpgp-native%S)))"; + curve = "Curve25519"; + } + else + format = "(protected-private-key(ecc(curve %s)(q%m)" + "(protected openpgp-native%S)))"; + + err = gcry_sexp_build (&s_skey, NULL, format, curve, skey[0], transfer_key); } - else - err = gcry_sexp_build - (&s_skey, NULL, - "(protected-private-key(ecc(curve%s)(q%m)" - "(protected openpgp-native%S)))", - curve, skey[0], transfer_key); break; default: diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c index 676079c..3c7fd1a 100644 --- a/common/openpgp-oid.c +++ b/common/openpgp-oid.c @@ -45,7 +45,8 @@ static struct { const char *alias; /* NULL or alternative name of the curve. */ } oidtable[] = { - { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519" }, + { "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255 }, + { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255 }, { "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" }, { "NIST P-384", "1.3.132.0.34", 384, "nistp384" }, @@ -65,6 +66,10 @@ static struct { static const char oid_ed25519[] = { 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 }; +/* The OID for Curve25519 in OpenPGP format. */ +static const char oid_curve25519[] = + { 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 }; + /* Helper for openpgp_oid_from_str. */ static size_t @@ -291,6 +296,22 @@ openpgp_oid_is_ed25519 (gcry_mpi_t a) } +int +openpgp_oid_is_curve25519 (gcry_mpi_t a) +{ + const unsigned char *buf; + unsigned int nbits; + size_t n; + + if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) + return 0; + + buf = gcry_mpi_get_opaque (a, &nbits); + n = (nbits+7)/8; + return (n == DIM (oid_curve25519) + && !memcmp (buf, oid_curve25519, DIM (oid_curve25519))); +} + /* Map the Libgcrypt ECC curve NAME to an OID. If R_NBITS is not NULL store the bit size of the curve there. Returns NULL for unknown diff --git a/common/util.h b/common/util.h index 90acefa..23a9342 100644 --- a/common/util.h +++ b/common/util.h @@ -322,6 +322,7 @@ size_t percent_unescape_inplace (char *string, int nulrepl); gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi); char *openpgp_oid_to_str (gcry_mpi_t a); int openpgp_oid_is_ed25519 (gcry_mpi_t a); +int openpgp_oid_is_curve25519 (gcry_mpi_t a); const char *openpgp_curve_to_oid (const char *name, unsigned int *r_nbits); const char *openpgp_oid_to_curve (const char *oid); const char *openpgp_enum_curves (int *idxp); diff --git a/g10/ecdh.c b/g10/ecdh.c index 9576a1c..a1b7ecf 100644 --- a/g10/ecdh.c +++ b/g10/ecdh.c @@ -134,9 +134,12 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, } secret_x_size = (nbits+7)/8; - assert (nbytes > secret_x_size); - memmove (secret_x, secret_x+1, secret_x_size); - memset (secret_x+secret_x_size, 0, nbytes-secret_x_size); + assert (nbytes >= secret_x_size); + if ((nbytes & 1)) + /* Remove the "04" prefix of non-compressed format. */ + memmove (secret_x, secret_x+1, secret_x_size); + if (nbytes - secret_x_size) + memset (secret_x+secret_x_size, 0, nbytes-secret_x_size); if (DBG_CRYPTO) log_printhex ("ECDH shared secret X is:", secret_x, secret_x_size ); diff --git a/g10/keygen.c b/g10/keygen.c index 796d18f..f03c148 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1520,6 +1520,13 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root, (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? " transient-key" : "")); + else if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "Curve25519")) + keyparms = xtryasprintf + ("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))", + strlen (curve), curve, + (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) + && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? + " transient-key" : "")); else keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))", @@ -2125,7 +2132,7 @@ ask_keysize (int algo, unsigned int primary_keysize) function may adjust. Returns a malloced string with the name of the curve. BOTH tells that gpg creates a primary and subkey. */ static char * -ask_curve (int *algo, int both) +ask_curve (int *algo, int *subkey_algo) { struct { const char *name; @@ -2176,7 +2183,7 @@ ask_curve (int *algo, int both) continue; if (!gcry_pk_get_curve (keyparms, 0, NULL)) continue; - if (both && curves[idx].fix_curve) + if (subkey_algo && curves[idx].fix_curve) { /* Both Curve 25519 keys are to be created. Check that Libgcrypt also supports the real Curve25519. */ @@ -2241,6 +2248,11 @@ ask_curve (int *algo, int both) if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA) && curves[idx].fix_curve) { + if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA) + { + *subkey_algo = PUBKEY_ALGO_EDDSA; + result = xstrdup ("Ed25519"); + } *algo = PUBKEY_ALGO_EDDSA; result = xstrdup ("Ed25519"); } @@ -3672,7 +3684,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname, || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { - curve = ask_curve (&algo, both); + curve = ask_curve (&algo, &subkey_algo); r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo); @@ -3743,7 +3755,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname, || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { - curve = ask_curve (&algo, 0); + curve = ask_curve (&algo, NULL); nbits = 0; r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = pKEYCURVE; @@ -4292,7 +4304,7 @@ 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 (&algo, 0); + curve = ask_curve (&algo, NULL); else nbits = ask_keysize (algo, 0); diff --git a/g10/keyid.c b/g10/keyid.c index 6b6f670..9513c3f 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -761,14 +761,18 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array) case PUBKEY_ALGO_ECDH: { char *curve = openpgp_oid_to_str (pk->pkey[0]); + if (!curve) err = gpg_error_from_syserror (); else { err = gcry_sexp_build (&s_pkey, NULL, - pk->pubkey_algo == PUBKEY_ALGO_EDDSA ? - "(public-key(ecc(curve%s)(flags eddsa)(q%m)))" - : "(public-key(ecc(curve%s)(q%m)))", + pk->pubkey_algo == PUBKEY_ALGO_EDDSA? + "(public-key(ecc(curve%s)(flags eddsa)(q%m)))": + (pk->pubkey_algo == PUBKEY_ALGO_ECDH + && openpgp_oid_is_curve25519 (pk->pkey[0]))? + "(public-key(ecc(curve%s)(flags djb-tweak)(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 d72275b..a8b92f6 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -228,9 +228,13 @@ pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data, rc = gpg_error_from_syserror (); else { + int with_djb_tweak_flag = openpgp_oid_is_curve25519 (pkey[0]); + /* Now use the ephemeral secret to compute the shared point. */ rc = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecdh(curve%s)(q%m)))", + with_djb_tweak_flag ? + "(public-key(ecdh(curve%s)(flags djb-tweak)(q%m)))" + : "(public-key(ecdh(curve%s)(q%m)))", curve, pkey[1]); xfree (curve); /* Put K into a simplified S-expression. */ diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index cb834af..fd7f812 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -250,8 +250,8 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) if(err) goto leave; - /* Reuse NFRAME, which size is sufficient to include the session key. */ - err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &nframe, decoded); + xfree (frame); + err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &frame, &nframe, decoded); mpi_release (decoded); if (err) goto leave; diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 83465f4..35f6190 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -235,7 +235,7 @@ struct app_local_s { } keyattr[3]; }; -#define ECC_FLAG_EDDSA (1 << 0) +#define ECC_FLAG_DJB_TWEAK (1 << 0) /***** Local prototypes *****/ @@ -909,8 +909,9 @@ send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int keyno) { snprintf (buffer, sizeof buffer, "%d %d %s", keyno+1, - app->app_local->keyattr[keyno].ecc.flags? PUBKEY_ALGO_EDDSA: - (keyno==1? PUBKEY_ALGO_ECDH: PUBKEY_ALGO_ECDSA), + keyno==1? PUBKEY_ALGO_ECDH : + app->app_local->keyattr[keyno].ecc.flags? + PUBKEY_ALGO_EDDSA : PUBKEY_ALGO_ECDSA, openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid)); } else @@ -1378,59 +1379,52 @@ get_public_key (app_t app, int keyno) } } - - mbuf = xtrymalloc ( mlen + 1); + mbuf = xtrymalloc (mlen + 1); if (!mbuf) { err = gpg_error_from_syserror (); goto leave; } - /* Prepend numbers with a 0 if needed. */ + if ((app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA || (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC && !app->app_local->keyattr[keyno].ecc.flags)) && mlen && (*m & 0x80)) - { + { /* Prepend numbers with a 0 if needed for MPI. */ *mbuf = 0; memcpy (mbuf+1, m, mlen); mlen++; } - else - memcpy (mbuf, m, mlen); - - ebuf = xtrymalloc ( elen + 1); - if (!ebuf) - { - err = gpg_error_from_syserror (); - goto leave; - } - /* Prepend numbers with a 0 if needed. */ - if (elen && (*e & 0x80)) - { - *ebuf = 0; - memcpy (ebuf+1, e, elen); - elen++; + else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC + && app->app_local->keyattr[keyno].ecc.flags) + { /* Prepend 0x40 prefix. */ + *mbuf = 0x40; + memcpy (mbuf+1, m, mlen); + mlen++; } else - memcpy (ebuf, e, elen); + memcpy (mbuf, m, mlen); if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA) { - err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%b)(e%b)))", - (int)mlen, mbuf, (int)elen, ebuf); - if (err) - goto leave; - - len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0); - keybuf = xtrymalloc (len); - if (!keybuf) + ebuf = xtrymalloc (elen + 1); + if (!ebuf) { - 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); + /* Prepend numbers with a 0 if needed. */ + if (elen && (*e & 0x80)) + { + *ebuf = 0; + memcpy (ebuf+1, e, elen); + elen++; + } + else + memcpy (ebuf, e, elen); + + err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%b)(e%b)))", + (int)mlen, mbuf, (int)elen, ebuf); } else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC) { @@ -1438,32 +1432,32 @@ get_public_key (app_t app, int keyno) if (!app->app_local->keyattr[keyno].ecc.flags) format = "(public-key(ecc(curve%s)(q%b)))"; + else if (keyno == 1) + format = "(public-key(ecc(curve%s)(flags djb-tweak)(q%b)))"; else format = "(public-key(ecc(curve%s)(flags eddsa)(q%b)))"; err = gcry_sexp_build (&s_pkey, NULL, format, openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid), (int)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); + + if (err) + goto leave; + + len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0); + + keybuf = xtrymalloc (len); + if (!keybuf) { - err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + 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); app->app_local->pk[keyno].key = (unsigned char*)keybuf; app->app_local->pk[keyno].keylen = len - 1; /* Decrement for trailing '\0' */ @@ -3171,7 +3165,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), size_t ecc_q_len, ecc_d_len; u32 created_at = 0; const char *oidstr = NULL; - int flag_eddsa = 0; + int flag_djb_tweak = 0; int algo; /* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)): @@ -3216,8 +3210,12 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) goto leave; - if (tok && toklen == 5 && !memcmp (tok, "eddsa", 5)) - flag_eddsa = 1; + if (tok) + { + if ((toklen == 5 && !memcmp (tok, "eddsa", 5)) + || (toklen == 9 && !memcmp (tok, "djb-tweak", 9))) + flag_djb_tweak = 1; + } } else if (tok && toklen == 1) { @@ -3237,7 +3235,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), } if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) goto leave; - if (tok && buf2 && !flag_eddsa) + if (tok && buf2 && !flag_djb_tweak) /* It's MPI. Strip off leading zero bytes and save. */ for (;toklen && !*tok; toklen--, tok++) ; @@ -3300,7 +3298,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), err = gpg_error (GPG_ERR_INV_VALUE); goto leave; } - if (flag_eddsa && keyno != 1) + if (flag_djb_tweak && keyno != 1) algo = PUBKEY_ALGO_EDDSA; else if (keyno == 1) algo = PUBKEY_ALGO_ECDH; @@ -3309,7 +3307,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC || app->app_local->keyattr[keyno].ecc.oid != oidstr - || app->app_local->keyattr[keyno].ecc.flags != flag_eddsa) + || app->app_local->keyattr[keyno].ecc.flags != flag_djb_tweak) { log_error ("key attribute on card doesn't match\n"); err = gpg_error (GPG_ERR_INV_VALUE); @@ -4469,11 +4467,18 @@ parse_algorithm_attribute (app_t app, int keyno) { app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECC; app->app_local->keyattr[keyno].ecc.oid = oid; - app->app_local->keyattr[keyno].ecc.flags = (*buffer == PUBKEY_ALGO_EDDSA); + if (*buffer == PUBKEY_ALGO_EDDSA + || (*buffer == PUBKEY_ALGO_ECDH + && !strcmp (app->app_local->keyattr[keyno].ecc.oid, + "1.3.6.1.4.1.3029.1.5.1"))) + app->app_local->keyattr[keyno].ecc.flags = ECC_FLAG_DJB_TWEAK; + else + app->app_local->keyattr[keyno].ecc.flags = 0; if (opt.verbose) log_printf ("ECC, curve=%s%s\n", app->app_local->keyattr[keyno].ecc.oid, - app->app_local->keyattr[keyno].ecc.flags ? " (eddsa)": ""); + !app->app_local->keyattr[keyno].ecc.flags ? "": + keyno==1? " (djb-tweak)": " (eddsa)"); } } else if (opt.verbose) -- From dkg at fifthhorseman.net Wed Aug 5 04:15:08 2015 From: dkg at fifthhorseman.net (Daniel Kahn Gillmor) Date: Tue, 04 Aug 2015 22:15:08 -0400 Subject: TOFU Design In-Reply-To: <87mvyofr3u.fsf@vigenere.g10code.de> References: <87615jkm4z.wl-neal@walfield.org> <87mvyofr3u.fsf@vigenere.g10code.de> Message-ID: <87h9oe32hf.fsf@alice.fifthhorseman.net> Hi Neal-- thanks for working on a TOFU mechanism for GnuPG, i think it's a great plan! On Wed 2015-07-22 06:01:41 -0400, Werner Koch wrote: > On Fri, 17 Jul 2015 14:24, neal at walfield.org said: > >> Finally, we'd have to regularize names. At least for latin and >> germanic languages, UTF-8 canonicalization, space compression and down >> casing should be enough. But, I'm not sure about other languages >> where letters are combined. > > Just to clarify: GnuPG only knows about UTF-8 (as per OpenPGP) and it > does not handle IDNA etc. Any mapping to the encoding required for > example by rfc822 has to be done outside of GnuPG. > >> Note: it is unclear what to do when the OpenPGP User ID is not in RFC >> 2822 form or there is no email address. > > I suggest to ignore such a user id. > See gnupg/common/mbox-util.c:mailbox_from_userid on GnuPG parses userids. I agree with Werner here. If we're doing TOFU, there are potentially many contexts in which to do TOFU. By default, gnupg could implement TOFU only in an "e-mail address" context. the other obvious context to implement would be an "exact User ID" context. Applications using this mechanism would know by default which context they're in, and the databases could be distinct. I'd start with the "e-mail address" context, and i think your general outline loks like the right one to me. fwiw, i also think that we should match e-mail addresses after downcasing both the local part and the domain part of the e-mail address. I've been bit by this too many times! It's conceivable that for well-known domains that offer particular rules (e.g. gmail's dot-injection mappings that treat foo.bar at gmail.com and foobar at gmail.com the same, or common +suffix mechanisms mapping foo+anything at example.com to foo at example.com), a pragmatic TOFU "e-mail address" context could retain a set of domain-specific normalizations that it's willing to apply before doing its search. > For TOFU alone this would be okay but TOFU is only one part of the > story. We need to limit user interaction to the bare minimum. Thus in > this case we need to lookup the key using DNS (PKA style CERT records) > by th mail address. The binding should have a "Initial-Source" field to > record that the binding has been created from > > a) PKA > b) keyserver lookup by fingerprint > c) a key send with a message > d) the verification of a signed message > e) a manually imported key with verified fingerprint (keysigning). > > This information can be useful in cae of a conflict. For example a > manually imported key should be more trustworthy than one take from a > keyserver. The exact rules need to be worked out but tracking the > source needs to be there right from the beginning. i agree that if the TOFU db is going to have relatively flexible data storage (and if the db isn't exported publicly), keeping this info around doesn't hurt much. otoh, i'm not convinced that there's a set of logical rules/policy that make sense for how to use it for most people. But having it makes it possible to experiment with possible rules. >> course, for new bindings, the key is probably not yet available and if >> the user hasn't enabled auto-key-locate (which is disabled by >> default), then we can't do the verification nor can we update the > > We need to change some of the defaults - at least for email use. > Traffic patterns are anyway not protected and thus it does not sense to > avoid network access by default. For those who need it they can use > --disable-dirmngr to avoid all kind of network access or use the > proposed --enable-tor option. The goal is to increase the use of > encrypted mail and not to be safe against targeted attacks by default. I disagree here. Users who want automated key discovery could have lots of ways that they want to do it, and not all of those ways are as privacy-preserving as they could be on the network. I wouldn't want to see these defaults changed automatically. Maybe they'd be changed explicitly as part of the user opting into a TOFU scheme (i.e., when you opt into TOFU, you have to also choose what sort of network-discovery profile(s) you want to enable)? For example, when Alice send e-mail to bob at example.com, and Bob doesn't have an OpenPGP key at all, automated network checks imply that Alice's MUA would leak her interaction with Bob to the network *every single time* she sends him an e-mail. Unless her key lookup queries are done via the same exact channel that her e-mails are sent (e.g. see draft-moore-smtp-addrquery), this is a significant additional negative privacy impact. I do want increased use of encrypted e-mail, but i don't want users of encrypted mail to be subject to *worse* privacy situations than people who don't use encrypted mail. >> Export >> ====== >> >> Should TOFU bindings be exportable? TOFU reveals the user's social > > No. That should be kept local like the trustdb. I agree with Werner and Robert that TOFU bindings should be kept local to the user. We can talk more later about whether there might be scenarios where one might want to publish such a binding, but the default should certainly be "no". There's enough good stuff to work on here without trying to wade through the tradeoffs and implementation details around publication. --dkg -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 948 bytes Desc: not available URL: From dkg at fifthhorseman.net Wed Aug 5 08:17:43 2015 From: dkg at fifthhorseman.net (Daniel Kahn Gillmor) Date: Wed, 05 Aug 2015 02:17:43 -0400 Subject: pinentry 0.9.5 fails with g++ 5 : unrestricted unions only available with -std=++11 or -std=gnu++11 Message-ID: <87d1z21coo.fsf@alice.fifthhorseman.net> hi folks-- debian unstable is switching to gcc 5 as the default compiler. Trying to build pinentry 0.9.5 with gcc 5.2.1, i see this error: g++ -DHAVE_CONFIG_H -I. -I.. -pthread -I/usr/include/libsecret-1 -I/usr/include/glib-2.0 -I/usr/lib/aarch64-linux-gnu/glib-2.0/include -I.. -I../secmem -I/usr/include/ncursesw -I../pinentry -D_FORTIFY_SOURCE=2 -Wall -DQT_SHARED -I/usr/include/qt4 -I/usr/include/qt4/QtCore -DQT_SHARED -I/usr/include/qt4 -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I/usr/include/qt4/QtCore -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -c -o pinentrydialog.o pinentrydialog.cpp In file included from /usr/include/c++/5/string:52:0, from /usr/include/qt4/QtCore/qstring.h:54, from /usr/include/qt4/QtCore/qobject.h:48, from /usr/include/qt4/QtGui/qwidget.h:47, from /usr/include/qt4/QtGui/qdialog.h:45, from /usr/include/qt4/QtGui/QDialog:1, from pinentrydialog.h:27, from pinentrydialog.cpp:24: /usr/include/c++/5/bits/basic_string.h: In instantiation of 'union std::__cxx11::basic_string, secmem::alloc >::': /usr/include/c++/5/bits/basic_string.h:119:7: required from 'class std::__cxx11::basic_string, secmem::alloc >' secstring.h:37:1: required from here /usr/include/c++/5/bits/basic_string.h:121:53: error: member 'QChar std::__cxx11::basic_string, secmem::alloc >::::_M_local_buf [8]' with constructor not allowed in union _CharT _M_local_buf[_S_local_capacity + 1]; ^ /usr/include/c++/5/bits/basic_string.h:121:53: note: unrestricted unions only available with -std=c++11 or -std=gnu++11 make[4]: *** [pinentrydialog.o] Error 1 Makefile:475: recipe for target 'pinentrydialog.o' failed You can see more of these logs here: https://buildd.debian.org/status/logs.php?pkg=pinentry&ver=0.9.5-3 I haven't tried to build from git master yet. maybe the removal of the custom textentry field will remove this concern? or should i be adding -std=c++11 to the CFLAGS? Someone posted a brief explanation of the error message on stackoverflow: https://stackoverflow.com/questions/5548636/what-are-unrestricted-unions-proposed-in-c11 --dkg From wk at gnupg.org Wed Aug 5 08:40:41 2015 From: wk at gnupg.org (Werner Koch) Date: Wed, 05 Aug 2015 08:40:41 +0200 Subject: [TESTING] Curve25519 encryption support (update-2) In-Reply-To: <55C1552C.60906@fsij.org> (NIIBE Yutaka's message of "Wed, 05 Aug 2015 09:13:32 +0900") References: <559657AE.2050900@fsij.org> <559C71F6.1070607@fsij.org> <55C1552C.60906@fsij.org> Message-ID: <87twses0eu.fsf@vigenere.g10code.de> On Wed, 5 Aug 2015 02:13, gniibe at fsij.org said: > Note that I need to remove an alias of "Ed25519" in > common/openpgp-oid.c, since it's not compatible to libgcrypt. [...] > --- a/common/openpgp-oid.c > +++ b/common/openpgp-oid.c > @@ -45,7 +45,8 @@ static struct { > const char *alias; /* NULL or alternative name of the curve. */ > } oidtable[] = { > > - { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519" }, > + { "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255 }, > + { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255 }, Without the alias we change how we print such a key: Now it is sec ed25519/E3FDFF218E45B72B 2015-02-18 [expires: 2025-02-15] but with the change this will be sec Ed25519/E3FDFF218E45B72B 2015-02-18 [expires: 2025-02-15] (see g10/keyid.c:pubkey_string) I'd very much like to have the algo/curve in lowercase. And while we are at it sec Curve25519/... is quite long. What about having an alias sec crv25519/... to shorten this. I expect that this will eventully be the standard key and thus a shorter description for the common case would be nicer. What about /* Map an OpenPGP OID to the Libgcrypt curve NAME. Returns NULL for - unknown curve names. We prefer an alias name here which is more - suitable for printing. */ + unknown curve names. Unless CANON is set we prefer an alias name + here which is more suitable for printing. */ const char * -openpgp_oid_to_curve (const char *oidstr) +openpgp_oid_to_curve (const char *oidstr, int canon) { int i; @@ -345,7 +345,7 @@ openpgp_oid_to_curve (const char *oidstr) for (i=0; oidtable[i].name; i++) if (!strcmp (oidtable[i].oidstr, oidstr)) - return oidtable[i].alias? oidtable[i].alias : oidtable[i].name; + return !canon && oidtable[i].alias? oidtable[i].alias : oidtable[i].name; return NULL; } and changing all callers which pass the name to Libgcrypt to set CANON? (Or maybe FOR_PRINT instead of CANON and revert the logic) Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From aheinecke at intevation.de Wed Aug 5 11:20:13 2015 From: aheinecke at intevation.de (Andre Heinecke) Date: Wed, 05 Aug 2015 11:20:13 +0200 Subject: pinentry 0.9.5 fails with g++ 5 : unrestricted unions only available with -std=++11 or -std=gnu++11 In-Reply-To: <87d1z21coo.fsf@alice.fifthhorseman.net> References: <87d1z21coo.fsf@alice.fifthhorseman.net> Message-ID: <5033662.H9vDaKFis2@esus> Hi, On Wednesday, August 05, 2015 02:17:43 AM Daniel Kahn Gillmor wrote: > I haven't tried to build from git master yet. maybe the removal of the > custom textentry field will remove this concern? or should i be adding > -std=c++11 to the CFLAGS? > > Someone posted a brief explanation of the error message on stackoverflow: > > https://stackoverflow.com/questions/5548636/what-are-unrestricted-unions-pr > oposed-in-c11 As the whole secstring / std::string handling is now removed I can compile current master with gcc-5.2.0 (I've only tested windows target with qt5 but it should not make a difference). As a workaround for 0.9.5 adding -std=c++11 should be ok for versions < 0.9.6 Regards, Andre -- Andre Heinecke | ++49-541-335083-262 | http://www.intevation.de/ Intevation GmbH, Neuer Graben 17, 49074 Osnabr?ck | AG Osnabr?ck, HR B 18998 Gesch?ftsf?hrer: Frank Koormann, Bernhard Reiter, Dr. Jan-Oliver Wagner From gniibe at fsij.org Wed Aug 5 13:34:30 2015 From: gniibe at fsij.org (NIIBE Yutaka) Date: Wed, 05 Aug 2015 20:34:30 +0900 Subject: [TESTING] Curve25519 encryption support (update-2) In-Reply-To: <87twses0eu.fsf@vigenere.g10code.de> References: <559657AE.2050900@fsij.org> <559C71F6.1070607@fsij.org> <55C1552C.60906@fsij.org> <87twses0eu.fsf@vigenere.g10code.de> Message-ID: <55C1F4C6.9000607@fsij.org> On 08/05/2015 03:40 PM, Werner Koch wrote: > Without the alias we change how we print such a key: Now it is > > sec ed25519/E3FDFF218E45B72B 2015-02-18 [expires: 2025-02-15] > > but with the change this will be > > sec Ed25519/E3FDFF218E45B72B 2015-02-18 [expires: 2025-02-15] > > (see g10/keyid.c:pubkey_string) I'd very much like to have the > algo/curve in lowercase. Sorry. My badness. I was not careful enough for printing. > What about > > /* Map an OpenPGP OID to the Libgcrypt curve NAME. Returns NULL for > - unknown curve names. We prefer an alias name here which is more > - suitable for printing. */ > + unknown curve names. Unless CANON is set we prefer an alias name > + here which is more suitable for printing. */ > const char * > -openpgp_oid_to_curve (const char *oidstr) > +openpgp_oid_to_curve (const char *oidstr, int canon) > { > int i; > OK. I prefer CANON. With a bit different spelling, we have a statue (of Buddhism) in our prefecture: http://takasakikannon.or.jp/images/about/kannon.jpg Here is the revised version, including your suggestion. diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 562179b..39ccba2 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -83,14 +83,25 @@ get_keygrip (int pubkey_algo, const char *curve, gcry_mpi_t *pkey, case GCRY_PK_ECC: if (!curve) err = gpg_error (GPG_ERR_BAD_SECKEY); - else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) - err = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecc(curve %s)(flags eddsa)(q%m)))", - "Ed25519", pkey[0]); else - err = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecc(curve %s)(q%m)))", - curve, pkey[0]); + { + const char *format; + + if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + { + format = "(public-key(ecc(curve %s)(flags eddsa)(q%m)))"; + curve = "Ed25519"; + } + else if (!strcmp (curve, openpgp_curve_to_oid ("Curve25519", NULL))) + { + format = "(public-key(ecc(curve %s)(flags djb-tweak)(q%m)))"; + curve = "Curve25519"; + } + else + format = "(public-key(ecc(curve %s)(q%m)))"; + + err = gcry_sexp_build (&s_pkey, NULL, format, curve, pkey[0]); + } break; default: @@ -146,19 +157,27 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, case GCRY_PK_ECC: if (!curve) err = gpg_error (GPG_ERR_BAD_SECKEY); - else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + else { - /* Do not store the OID as name but the real name and the - EdDSA flag. */ - err = gcry_sexp_build (&s_skey, NULL, - "(private-key(ecc(curve%s)(flags eddsa)" - "(q%m)(d%m)))", - "Ed25519", skey[0], skey[1]); + const char *format; + + if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + { + /* Do not store the OID as name but the real name and the + EdDSA flag. */ + format = "(private-key(ecc(curve %s)(flags eddsa)(q%m)(d%m)))"; + curve = "Ed25519"; + } + else if (!strcmp (curve, openpgp_curve_to_oid ("Curve25519", NULL))) + { + format = "(private-key(ecc(curve %s)(flags djb-tweak)(q%m)(d%m)))"; + curve = "Curve25519"; + } + else + format = "(private-key(ecc(curve %s)(q%m)(d%m)))"; + + err = gcry_sexp_build (&s_skey, NULL, format, curve, skey[0], skey[1]); } - else - err = gcry_sexp_build (&s_skey, NULL, - "(private-key(ecc(curve%s)(q%m)(d%m)))", - curve, skey[0], skey[1]); break; default: @@ -216,22 +235,30 @@ convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, case GCRY_PK_ECC: if (!curve) err = gpg_error (GPG_ERR_BAD_SECKEY); - else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + else { - /* Do not store the OID as name but the real name and the - EdDSA flag. */ - err = gcry_sexp_build - (&s_skey, NULL, - "(protected-private-key(ecc(curve%s)(flags eddsa)(q%m)" - "(protected openpgp-native%S)))", - "Ed25519", skey[0], transfer_key); + const char *format; + + if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + { + /* Do not store the OID as name but the real name and the + EdDSA flag. */ + format = "(protected-private-key(ecc(curve %s)(flags eddsa)(q%m)" + "(protected openpgp-native%S)))"; + curve = "Ed25519"; + } + else if (!strcmp (curve, openpgp_curve_to_oid ("Curve25519", NULL))) + { + format = "(protected-private-key(ecc(curve %s)(flags djb-tweak)(q%m)" + "(protected openpgp-native%S)))"; + curve = "Curve25519"; + } + else + format = "(protected-private-key(ecc(curve %s)(q%m)" + "(protected openpgp-native%S)))"; + + err = gcry_sexp_build (&s_skey, NULL, format, curve, skey[0], transfer_key); } - else - err = gcry_sexp_build - (&s_skey, NULL, - "(protected-private-key(ecc(curve%s)(q%m)" - "(protected openpgp-native%S)))", - curve, skey[0], transfer_key); break; default: diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c index 676079c..580084d 100644 --- a/common/openpgp-oid.c +++ b/common/openpgp-oid.c @@ -45,6 +45,7 @@ static struct { const char *alias; /* NULL or alternative name of the curve. */ } oidtable[] = { + { "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "crv25519" }, { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519" }, { "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" }, @@ -65,6 +66,10 @@ static struct { static const char oid_ed25519[] = { 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 }; +/* The OID for Curve25519 in OpenPGP format. */ +static const char oid_curve25519[] = + { 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 }; + /* Helper for openpgp_oid_from_str. */ static size_t @@ -291,6 +296,22 @@ openpgp_oid_is_ed25519 (gcry_mpi_t a) } +int +openpgp_oid_is_curve25519 (gcry_mpi_t a) +{ + const unsigned char *buf; + unsigned int nbits; + size_t n; + + if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) + return 0; + + buf = gcry_mpi_get_opaque (a, &nbits); + n = (nbits+7)/8; + return (n == DIM (oid_curve25519) + && !memcmp (buf, oid_curve25519, DIM (oid_curve25519))); +} + /* Map the Libgcrypt ECC curve NAME to an OID. If R_NBITS is not NULL store the bit size of the curve there. Returns NULL for unknown @@ -333,10 +354,10 @@ openpgp_curve_to_oid (const char *name, unsigned int *r_nbits) /* Map an OpenPGP OID to the Libgcrypt curve NAME. Returns NULL for - unknown curve names. We prefer an alias name here which is more - suitable for printing. */ + unknown curve names. Unless CANON is set we prefer an alias name + here which is more suitable for printing. */ const char * -openpgp_oid_to_curve (const char *oidstr) +openpgp_oid_to_curve (const char *oidstr, int canon) { int i; @@ -345,7 +366,7 @@ openpgp_oid_to_curve (const char *oidstr) for (i=0; oidtable[i].name; i++) if (!strcmp (oidtable[i].oidstr, oidstr)) - return oidtable[i].alias? oidtable[i].alias : oidtable[i].name; + return !canon && oidtable[i].alias? oidtable[i].alias : oidtable[i].name; return NULL; } diff --git a/common/util.h b/common/util.h index 90acefa..113ed8a 100644 --- a/common/util.h +++ b/common/util.h @@ -322,8 +322,9 @@ size_t percent_unescape_inplace (char *string, int nulrepl); gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi); char *openpgp_oid_to_str (gcry_mpi_t a); int openpgp_oid_is_ed25519 (gcry_mpi_t a); +int openpgp_oid_is_curve25519 (gcry_mpi_t a); const char *openpgp_curve_to_oid (const char *name, unsigned int *r_nbits); -const char *openpgp_oid_to_curve (const char *oid); +const char *openpgp_oid_to_curve (const char *oid, int canon); const char *openpgp_enum_curves (int *idxp); diff --git a/g10/ecdh.c b/g10/ecdh.c index 9576a1c..a1b7ecf 100644 --- a/g10/ecdh.c +++ b/g10/ecdh.c @@ -134,9 +134,12 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, } secret_x_size = (nbits+7)/8; - assert (nbytes > secret_x_size); - memmove (secret_x, secret_x+1, secret_x_size); - memset (secret_x+secret_x_size, 0, nbytes-secret_x_size); + assert (nbytes >= secret_x_size); + if ((nbytes & 1)) + /* Remove the "04" prefix of non-compressed format. */ + memmove (secret_x, secret_x+1, secret_x_size); + if (nbytes - secret_x_size) + memset (secret_x+secret_x_size, 0, nbytes-secret_x_size); if (DBG_CRYPTO) log_printhex ("ECDH shared secret X is:", secret_x, secret_x_size ); diff --git a/g10/import.c b/g10/import.c index 0a2ebcd..e92769d 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1414,7 +1414,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock, err = gpg_error_from_syserror (); else { - const char *curvename = openpgp_oid_to_curve (curvestr); + const char *curvename = openpgp_oid_to_curve (curvestr, 1); err = gcry_sexp_build (&curve, NULL, "(curve %s)", curvename?curvename:curvestr); xfree (curvestr); diff --git a/g10/keygen.c b/g10/keygen.c index 796d18f..f03c148 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1520,6 +1520,13 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root, (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? " transient-key" : "")); + else if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "Curve25519")) + keyparms = xtryasprintf + ("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))", + strlen (curve), curve, + (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) + && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? + " transient-key" : "")); else keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))", @@ -2125,7 +2132,7 @@ ask_keysize (int algo, unsigned int primary_keysize) function may adjust. Returns a malloced string with the name of the curve. BOTH tells that gpg creates a primary and subkey. */ static char * -ask_curve (int *algo, int both) +ask_curve (int *algo, int *subkey_algo) { struct { const char *name; @@ -2176,7 +2183,7 @@ ask_curve (int *algo, int both) continue; if (!gcry_pk_get_curve (keyparms, 0, NULL)) continue; - if (both && curves[idx].fix_curve) + if (subkey_algo && curves[idx].fix_curve) { /* Both Curve 25519 keys are to be created. Check that Libgcrypt also supports the real Curve25519. */ @@ -2241,6 +2248,11 @@ ask_curve (int *algo, int both) if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA) && curves[idx].fix_curve) { + if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA) + { + *subkey_algo = PUBKEY_ALGO_EDDSA; + result = xstrdup ("Ed25519"); + } *algo = PUBKEY_ALGO_EDDSA; result = xstrdup ("Ed25519"); } @@ -3672,7 +3684,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname, || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { - curve = ask_curve (&algo, both); + curve = ask_curve (&algo, &subkey_algo); r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo); @@ -3743,7 +3755,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname, || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { - curve = ask_curve (&algo, 0); + curve = ask_curve (&algo, NULL); nbits = 0; r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = pKEYCURVE; @@ -4292,7 +4304,7 @@ 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 (&algo, 0); + curve = ask_curve (&algo, NULL); else nbits = ask_keysize (algo, 0); diff --git a/g10/keyid.c b/g10/keyid.c index 6b6f670..9ccee6e 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -119,7 +119,7 @@ pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize) else if (prefix) { char *curve = openpgp_oid_to_str (pk->pkey[0]); - const char *name = openpgp_oid_to_curve (curve); + const char *name = openpgp_oid_to_curve (curve, 0); if (name) snprintf (buffer, bufsize, "%s", name); @@ -766,9 +766,12 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array) else { err = gcry_sexp_build (&s_pkey, NULL, - pk->pubkey_algo == PUBKEY_ALGO_EDDSA ? - "(public-key(ecc(curve%s)(flags eddsa)(q%m)))" - : "(public-key(ecc(curve%s)(q%m)))", + pk->pubkey_algo == PUBKEY_ALGO_EDDSA? + "(public-key(ecc(curve%s)(flags eddsa)(q%m)))": + (pk->pubkey_algo == PUBKEY_ALGO_ECDH + && openpgp_oid_is_curve25519 (pk->pkey[0]))? + "(public-key(ecc(curve%s)(flags djb-tweak)(q%m)))": + "(public-key(ecc(curve%s)(q%m)))", curve, pk->pkey[1]); xfree (curve); } diff --git a/g10/keylist.c b/g10/keylist.c index d81e7dd..b43165f 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -1091,7 +1091,7 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, || pk2->pubkey_algo == PUBKEY_ALGO_ECDH) { char *curve = openpgp_oid_to_str (pk2->pkey[0]); - const char *name = openpgp_oid_to_curve (curve); + const char *name = openpgp_oid_to_curve (curve, 0); if (!name) name = curve; es_fprintf (es_stdout, " %s", name); @@ -1358,7 +1358,7 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr) || pk->pubkey_algo == PUBKEY_ALGO_ECDH) { char *curve = openpgp_oid_to_str (pk->pkey[0]); - const char *name = openpgp_oid_to_curve (curve); + const char *name = openpgp_oid_to_curve (curve, 0); if (!name) name = curve; es_fputs (name, es_stdout); @@ -1487,7 +1487,7 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr) || pk->pubkey_algo == PUBKEY_ALGO_ECDH) { char *curve = openpgp_oid_to_str (pk->pkey[0]); - const char *name = openpgp_oid_to_curve (curve); + const char *name = openpgp_oid_to_curve (curve, 0); if (!name) name = curve; es_fputs (name, es_stdout); diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 6131d32..478612a 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -2086,7 +2086,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, || algorithm == PUBKEY_ALGO_ECDH) && i==0) { char *curve = openpgp_oid_to_str (pk->pkey[0]); - const char *name = openpgp_oid_to_curve (curve); + const char *name = openpgp_oid_to_curve (curve, 0); es_fprintf (listfp, " %s (%s)", name?name:"", curve); xfree (curve); } diff --git a/g10/pkglue.c b/g10/pkglue.c index d72275b..a8b92f6 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -228,9 +228,13 @@ pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data, rc = gpg_error_from_syserror (); else { + int with_djb_tweak_flag = openpgp_oid_is_curve25519 (pkey[0]); + /* Now use the ephemeral secret to compute the shared point. */ rc = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecdh(curve%s)(q%m)))", + with_djb_tweak_flag ? + "(public-key(ecdh(curve%s)(flags djb-tweak)(q%m)))" + : "(public-key(ecdh(curve%s)(q%m)))", curve, pkey[1]); xfree (curve); /* Put K into a simplified S-expression. */ diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index cb834af..fd7f812 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -250,8 +250,8 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) if(err) goto leave; - /* Reuse NFRAME, which size is sufficient to include the session key. */ - err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &nframe, decoded); + xfree (frame); + err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &frame, &nframe, decoded); mpi_release (decoded); if (err) goto leave; diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 83465f4..dd9e3c8 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -235,7 +235,7 @@ struct app_local_s { } keyattr[3]; }; -#define ECC_FLAG_EDDSA (1 << 0) +#define ECC_FLAG_DJB_TWEAK (1 << 0) /***** Local prototypes *****/ @@ -909,9 +909,10 @@ send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int keyno) { snprintf (buffer, sizeof buffer, "%d %d %s", keyno+1, - app->app_local->keyattr[keyno].ecc.flags? PUBKEY_ALGO_EDDSA: - (keyno==1? PUBKEY_ALGO_ECDH: PUBKEY_ALGO_ECDSA), - openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid)); + keyno==1? PUBKEY_ALGO_ECDH : + app->app_local->keyattr[keyno].ecc.flags? + PUBKEY_ALGO_EDDSA : PUBKEY_ALGO_ECDSA, + openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid, 0)); } else snprintf (buffer, sizeof buffer, "%d 0 0 UNKNOWN", keyno+1); @@ -1378,59 +1379,52 @@ get_public_key (app_t app, int keyno) } } - - mbuf = xtrymalloc ( mlen + 1); + mbuf = xtrymalloc (mlen + 1); if (!mbuf) { err = gpg_error_from_syserror (); goto leave; } - /* Prepend numbers with a 0 if needed. */ + if ((app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA || (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC && !app->app_local->keyattr[keyno].ecc.flags)) && mlen && (*m & 0x80)) - { + { /* Prepend numbers with a 0 if needed for MPI. */ *mbuf = 0; memcpy (mbuf+1, m, mlen); mlen++; } - else - memcpy (mbuf, m, mlen); - - ebuf = xtrymalloc ( elen + 1); - if (!ebuf) - { - err = gpg_error_from_syserror (); - goto leave; - } - /* Prepend numbers with a 0 if needed. */ - if (elen && (*e & 0x80)) - { - *ebuf = 0; - memcpy (ebuf+1, e, elen); - elen++; + else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC + && app->app_local->keyattr[keyno].ecc.flags) + { /* Prepend 0x40 prefix. */ + *mbuf = 0x40; + memcpy (mbuf+1, m, mlen); + mlen++; } else - memcpy (ebuf, e, elen); + memcpy (mbuf, m, mlen); if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA) { - err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%b)(e%b)))", - (int)mlen, mbuf, (int)elen, ebuf); - if (err) - goto leave; - - len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0); - keybuf = xtrymalloc (len); - if (!keybuf) + ebuf = xtrymalloc (elen + 1); + if (!ebuf) { - 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); + /* Prepend numbers with a 0 if needed. */ + if (elen && (*e & 0x80)) + { + *ebuf = 0; + memcpy (ebuf+1, e, elen); + elen++; + } + else + memcpy (ebuf, e, elen); + + err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%b)(e%b)))", + (int)mlen, mbuf, (int)elen, ebuf); } else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC) { @@ -1438,32 +1432,32 @@ get_public_key (app_t app, int keyno) if (!app->app_local->keyattr[keyno].ecc.flags) format = "(public-key(ecc(curve%s)(q%b)))"; + else if (keyno == 1) + format = "(public-key(ecc(curve%s)(flags djb-tweak)(q%b)))"; else format = "(public-key(ecc(curve%s)(flags eddsa)(q%b)))"; err = gcry_sexp_build (&s_pkey, NULL, format, - openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid), + openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid, 1), (int)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); + + if (err) + goto leave; + + len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0); + + keybuf = xtrymalloc (len); + if (!keybuf) { - err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + 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); app->app_local->pk[keyno].key = (unsigned char*)keybuf; app->app_local->pk[keyno].keylen = len - 1; /* Decrement for trailing '\0' */ @@ -3171,7 +3165,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), size_t ecc_q_len, ecc_d_len; u32 created_at = 0; const char *oidstr = NULL; - int flag_eddsa = 0; + int flag_djb_tweak = 0; int algo; /* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)): @@ -3216,8 +3210,12 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) goto leave; - if (tok && toklen == 5 && !memcmp (tok, "eddsa", 5)) - flag_eddsa = 1; + if (tok) + { + if ((toklen == 5 && !memcmp (tok, "eddsa", 5)) + || (toklen == 9 && !memcmp (tok, "djb-tweak", 9))) + flag_djb_tweak = 1; + } } else if (tok && toklen == 1) { @@ -3237,7 +3235,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), } if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) goto leave; - if (tok && buf2 && !flag_eddsa) + if (tok && buf2 && !flag_djb_tweak) /* It's MPI. Strip off leading zero bytes and save. */ for (;toklen && !*tok; toklen--, tok++) ; @@ -3300,7 +3298,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), err = gpg_error (GPG_ERR_INV_VALUE); goto leave; } - if (flag_eddsa && keyno != 1) + if (flag_djb_tweak && keyno != 1) algo = PUBKEY_ALGO_EDDSA; else if (keyno == 1) algo = PUBKEY_ALGO_ECDH; @@ -3309,7 +3307,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC || app->app_local->keyattr[keyno].ecc.oid != oidstr - || app->app_local->keyattr[keyno].ecc.flags != flag_eddsa) + || app->app_local->keyattr[keyno].ecc.flags != flag_djb_tweak) { log_error ("key attribute on card doesn't match\n"); err = gpg_error (GPG_ERR_INV_VALUE); @@ -4469,11 +4467,18 @@ parse_algorithm_attribute (app_t app, int keyno) { app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECC; app->app_local->keyattr[keyno].ecc.oid = oid; - app->app_local->keyattr[keyno].ecc.flags = (*buffer == PUBKEY_ALGO_EDDSA); + if (*buffer == PUBKEY_ALGO_EDDSA + || (*buffer == PUBKEY_ALGO_ECDH + && !strcmp (app->app_local->keyattr[keyno].ecc.oid, + "1.3.6.1.4.1.3029.1.5.1"))) + app->app_local->keyattr[keyno].ecc.flags = ECC_FLAG_DJB_TWEAK; + else + app->app_local->keyattr[keyno].ecc.flags = 0; if (opt.verbose) log_printf ("ECC, curve=%s%s\n", app->app_local->keyattr[keyno].ecc.oid, - app->app_local->keyattr[keyno].ecc.flags ? " (eddsa)": ""); + !app->app_local->keyattr[keyno].ecc.flags ? "": + keyno==1? " (djb-tweak)": " (eddsa)"); } } else if (opt.verbose) -- From wk at gnupg.org Wed Aug 5 20:20:00 2015 From: wk at gnupg.org (Werner Koch) Date: Wed, 05 Aug 2015 20:20:00 +0200 Subject: [TESTING] Curve25519 encryption support (update-2) In-Reply-To: <55C1F4C6.9000607@fsij.org> (NIIBE Yutaka's message of "Wed, 05 Aug 2015 20:34:30 +0900") References: <559657AE.2050900@fsij.org> <559C71F6.1070607@fsij.org> <55C1552C.60906@fsij.org> <87twses0eu.fsf@vigenere.g10code.de> <55C1F4C6.9000607@fsij.org> Message-ID: <87bnelsilr.fsf@vigenere.g10code.de> On Wed, 5 Aug 2015 13:34, gniibe at fsij.org said: > Here is the revised version, including your suggestion. Great. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From gniibe at fsij.org Thu Aug 6 10:29:58 2015 From: gniibe at fsij.org (NIIBE Yutaka) Date: Thu, 06 Aug 2015 17:29:58 +0900 Subject: [TESTING] Curve25519 encryption support (update-2) In-Reply-To: <87bnelsilr.fsf@vigenere.g10code.de> References: <559657AE.2050900@fsij.org> <559C71F6.1070607@fsij.org> <55C1552C.60906@fsij.org> <87twses0eu.fsf@vigenere.g10code.de> <55C1F4C6.9000607@fsij.org> <87bnelsilr.fsf@vigenere.g10code.de> Message-ID: <55C31B06.2070506@fsij.org> Hello, I pushed the patches by two commits. "make check" works fine with libgcrypt 1.6.3 and patched libgcrypt. -- From wk at gnupg.org Thu Aug 6 16:07:33 2015 From: wk at gnupg.org (Werner Koch) Date: Thu, 06 Aug 2015 16:07:33 +0200 Subject: [TESTING] Curve25519 encryption support (update-2) In-Reply-To: <55C31B06.2070506@fsij.org> (NIIBE Yutaka's message of "Thu, 06 Aug 2015 17:29:58 +0900") References: <559657AE.2050900@fsij.org> <559C71F6.1070607@fsij.org> <55C1552C.60906@fsij.org> <87twses0eu.fsf@vigenere.g10code.de> <55C1F4C6.9000607@fsij.org> <87bnelsilr.fsf@vigenere.g10code.de> <55C31B06.2070506@fsij.org> Message-ID: <87mvy4o6hm.fsf@vigenere.g10code.de> On Thu, 6 Aug 2015 10:29, gniibe at fsij.org said: > I pushed the patches by two commits. "make check" works fine > with libgcrypt 1.6.3 and patched libgcrypt. Works well, thanks. There is one aesthetic thing I would like to change: sec ed25519/C68CE6D1ED0319C8 2015-08-06 uid [ultimate] Curve25519 Test 150806.1 ssb crv25519/49238B9F0712C9BF 2015-08-06 crv25519 ssb rsa2048/8AEAF74014699D2C 2015-08-06 ssb crv25519/8EC3776830B08736 2015-08-06 crv25519 the columns are still not aligned nicely. Given that the most common keys are RSA and DSA keys we would be abale to get a prettier output if we change the alias for Curve25519 to just "cv25519": sec ed25519/C68CE6D1ED0319C8 2015-08-06 uid [ultimate] Curve25519 Test 150806.1 ssb cv25519/49238B9F0712C9BF 2015-08-06 crv25519 ssb rsa2048/8AEAF74014699D2C 2015-08-06 ssb cv25519/8EC3776830B08736 2015-08-06 crv25519 What do you think? Shall I change it? Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From dkg at fifthhorseman.net Thu Aug 6 17:00:10 2015 From: dkg at fifthhorseman.net (Daniel Kahn Gillmor) Date: Thu, 06 Aug 2015 11:00:10 -0400 Subject: [TESTING] Curve25519 encryption support (update-2) In-Reply-To: <87mvy4o6hm.fsf@vigenere.g10code.de> References: <559657AE.2050900@fsij.org> <559C71F6.1070607@fsij.org> <55C1552C.60906@fsij.org> <87twses0eu.fsf@vigenere.g10code.de> <55C1F4C6.9000607@fsij.org> <87bnelsilr.fsf@vigenere.g10code.de> <55C31B06.2070506@fsij.org> <87mvy4o6hm.fsf@vigenere.g10code.de> Message-ID: <87bnekxy11.fsf@alice.fifthhorseman.net> On Thu 2015-08-06 10:07:33 -0400, Werner Koch wrote: > On Thu, 6 Aug 2015 10:29, gniibe at fsij.org said: > >> I pushed the patches by two commits. "make check" works fine >> with libgcrypt 1.6.3 and patched libgcrypt. > > Works well, thanks. There is one aesthetic thing I would like to > change: > > sec ed25519/C68CE6D1ED0319C8 2015-08-06 > uid [ultimate] Curve25519 Test 150806.1 > ssb crv25519/49238B9F0712C9BF 2015-08-06 crv25519 > ssb rsa2048/8AEAF74014699D2C 2015-08-06 > ssb crv25519/8EC3776830B08736 2015-08-06 crv25519 > > the columns are still not aligned nicely. Given that the most common > keys are RSA and DSA keys we would be abale to get a prettier output if > we change the alias for Curve25519 to just "cv25519": > > sec ed25519/C68CE6D1ED0319C8 2015-08-06 > uid [ultimate] Curve25519 Test 150806.1 > ssb cv25519/49238B9F0712C9BF 2015-08-06 crv25519 > ssb rsa2048/8AEAF74014699D2C 2015-08-06 > ssb cv25519/8EC3776830B08736 2015-08-06 crv25519 > > > What do you think? Shall I change it? I like the alignment, but now i would wonder about why cv25519 shows up before the / and crv25519 shows up at the tail end of the line, and yet neither of them are the official "Curve25519" name. Remind me why we need both, and both need to be shortened (differently from one another)? --dkg From wk at gnupg.org Thu Aug 6 18:15:45 2015 From: wk at gnupg.org (Werner Koch) Date: Thu, 06 Aug 2015 18:15:45 +0200 Subject: [TESTING] Curve25519 encryption support (update-2) In-Reply-To: <87bnekxy11.fsf@alice.fifthhorseman.net> (Daniel Kahn Gillmor's message of "Thu, 06 Aug 2015 11:00:10 -0400") References: <559657AE.2050900@fsij.org> <559C71F6.1070607@fsij.org> <55C1552C.60906@fsij.org> <87twses0eu.fsf@vigenere.g10code.de> <55C1F4C6.9000607@fsij.org> <87bnelsilr.fsf@vigenere.g10code.de> <55C31B06.2070506@fsij.org> <87mvy4o6hm.fsf@vigenere.g10code.de> <87bnekxy11.fsf@alice.fifthhorseman.net> Message-ID: <87h9oco0jy.fsf@vigenere.g10code.de> On Thu, 6 Aug 2015 17:00, dkg at fifthhorseman.net said: > I like the alignment, but now i would wonder about why cv25519 shows up > before the / and crv25519 shows up at the tail end of the line, and yet Weel spotted. That is cruft from the early ECC days. I just removed it. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From gniibe at fsij.org Fri Aug 7 09:17:47 2015 From: gniibe at fsij.org (NIIBE Yutaka) Date: Fri, 07 Aug 2015 16:17:47 +0900 Subject: [TESTING] Curve25519 encryption support (update-2) In-Reply-To: <87mvy4o6hm.fsf@vigenere.g10code.de> References: <559657AE.2050900@fsij.org> <559C71F6.1070607@fsij.org> <55C1552C.60906@fsij.org> <87twses0eu.fsf@vigenere.g10code.de> <55C1F4C6.9000607@fsij.org> <87bnelsilr.fsf@vigenere.g10code.de> <55C31B06.2070506@fsij.org> <87mvy4o6hm.fsf@vigenere.g10code.de> Message-ID: <55C45B9B.1050302@fsij.org> On 08/06/2015 11:07 PM, Werner Koch wrote: > the columns are still not aligned nicely. Given that the most common > keys are RSA and DSA keys we would be abale to get a prettier output if > we change the alias for Curve25519 to just "cv25519": > > sec ed25519/C68CE6D1ED0319C8 2015-08-06 > uid [ultimate] Curve25519 Test 150806.1 > ssb cv25519/49238B9F0712C9BF 2015-08-06 crv25519 > ssb rsa2048/8AEAF74014699D2C 2015-08-06 > ssb cv25519/8EC3776830B08736 2015-08-06 crv25519 > > > What do you think? Shall I change it? Please change it. Since I am not a native English speaker, I don't have an idea about abbreviation. -- From wk at gnupg.org Fri Aug 7 09:43:28 2015 From: wk at gnupg.org (Werner Koch) Date: Fri, 07 Aug 2015 09:43:28 +0200 Subject: [TESTING] Curve25519 encryption support (update-2) In-Reply-To: <55C45B9B.1050302@fsij.org> (NIIBE Yutaka's message of "Fri, 07 Aug 2015 16:17:47 +0900") References: <559657AE.2050900@fsij.org> <559C71F6.1070607@fsij.org> <55C1552C.60906@fsij.org> <87twses0eu.fsf@vigenere.g10code.de> <55C1F4C6.9000607@fsij.org> <87bnelsilr.fsf@vigenere.g10code.de> <55C31B06.2070506@fsij.org> <87mvy4o6hm.fsf@vigenere.g10code.de> <55C45B9B.1050302@fsij.org> Message-ID: <87fv3vlf1b.fsf@vigenere.g10code.de> On Fri, 7 Aug 2015 09:17, gniibe at fsij.org said: > Please change it. Done. > Since I am not a native English speaker, I don't have an idea about > abbreviation. Neither me. But it looks better. It also make it easy to spot the NIST curve names which a byte longer ;-) Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From gniibe at fsij.org Mon Aug 10 12:19:42 2015 From: gniibe at fsij.org (NIIBE Yutaka) Date: Mon, 10 Aug 2015 19:19:42 +0900 Subject: [TESTING] Curve25519 encryption support (update-2) In-Reply-To: <55C31B06.2070506@fsij.org> References: <559657AE.2050900@fsij.org> <559C71F6.1070607@fsij.org> <55C1552C.60906@fsij.org> <87twses0eu.fsf@vigenere.g10code.de> <55C1F4C6.9000607@fsij.org> <87bnelsilr.fsf@vigenere.g10code.de> <55C31B06.2070506@fsij.org> Message-ID: <55C87ABE.3020603@fsij.org> On 08/06/2015 05:29 PM, NIIBE Yutaka wrote: > I pushed the patches by two commits. "make check" works fine > with libgcrypt 1.6.3 and patched libgcrypt. I committed following fix. I was confused that GnuPG frontend use curve OID when sending to gpg-agent, but it is curve name. agent: fix ECC key handling. * agent/cvt-openpgp.c (get_keygrip, convert_secret_key) (convert_transfer_key): CURVE is the name of curve. diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 39ccba2..8bf5873 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -87,16 +87,10 @@ get_keygrip (int pubkey_algo, const char *curve, gcry_mpi_t *pkey, { const char *format; - if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) - { - format = "(public-key(ecc(curve %s)(flags eddsa)(q%m)))"; - curve = "Ed25519"; - } - else if (!strcmp (curve, openpgp_curve_to_oid ("Curve25519", NULL))) - { - format = "(public-key(ecc(curve %s)(flags djb-tweak)(q%m)))"; - curve = "Curve25519"; - } + if (!strcmp (curve, "Ed25519")) + format = "(public-key(ecc(curve %s)(flags eddsa)(q%m)))"; + else if (!strcmp (curve, "Curve25519")) + format = "(public-key(ecc(curve %s)(flags djb-tweak)(q%m)))"; else format = "(public-key(ecc(curve %s)(q%m)))"; @@ -161,18 +155,12 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, { const char *format; - if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) - { - /* Do not store the OID as name but the real name and the - EdDSA flag. */ - format = "(private-key(ecc(curve %s)(flags eddsa)(q%m)(d%m)))"; - curve = "Ed25519"; - } - else if (!strcmp (curve, openpgp_curve_to_oid ("Curve25519", NULL))) - { - format = "(private-key(ecc(curve %s)(flags djb-tweak)(q%m)(d%m)))"; - curve = "Curve25519"; - } + if (!strcmp (curve, "Ed25519")) + /* Do not store the OID as name but the real name and the + EdDSA flag. */ + format = "(private-key(ecc(curve %s)(flags eddsa)(q%m)(d%m)))"; + else if (!strcmp (curve, "Curve25519")) + format = "(private-key(ecc(curve %s)(flags djb-tweak)(q%m)(d%m)))"; else format = "(private-key(ecc(curve %s)(q%m)(d%m)))"; @@ -239,23 +227,17 @@ convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, { const char *format; - if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) - { - /* Do not store the OID as name but the real name and the - EdDSA flag. */ - format = "(protected-private-key(ecc(curve %s)(flags eddsa)(q%m)" - "(protected openpgp-native%S)))"; - curve = "Ed25519"; - } - else if (!strcmp (curve, openpgp_curve_to_oid ("Curve25519", NULL))) - { - format = "(protected-private-key(ecc(curve %s)(flags djb-tweak)(q%m)" - "(protected openpgp-native%S)))"; - curve = "Curve25519"; - } + if (!strcmp (curve, "Ed25519")) + /* Do not store the OID as name but the real name and the + EdDSA flag. */ + format = "(protected-private-key(ecc(curve %s)(flags eddsa)(q%m)" + "(protected openpgp-native%S)))"; + else if (!strcmp (curve, "Curve25519")) + format = "(protected-private-key(ecc(curve %s)(flags djb-tweak)(q%m)" + "(protected openpgp-native%S)))"; else - format = "(protected-private-key(ecc(curve %s)(q%m)" - "(protected openpgp-native%S)))"; + format = "(protected-private-key(ecc(curve %s)(q%m)" + "(protected openpgp-native%S)))"; err = gcry_sexp_build (&s_skey, NULL, format, curve, skey[0], transfer_key); } -- From wk at gnupg.org Mon Aug 10 19:06:32 2015 From: wk at gnupg.org (Werner Koch) Date: Mon, 10 Aug 2015 19:06:32 +0200 Subject: [TESTING] Curve25519 encryption support (update-2) In-Reply-To: <55C87ABE.3020603@fsij.org> (NIIBE Yutaka's message of "Mon, 10 Aug 2015 19:19:42 +0900") References: <559657AE.2050900@fsij.org> <559C71F6.1070607@fsij.org> <55C1552C.60906@fsij.org> <87twses0eu.fsf@vigenere.g10code.de> <55C1F4C6.9000607@fsij.org> <87bnelsilr.fsf@vigenere.g10code.de> <55C31B06.2070506@fsij.org> <55C87ABE.3020603@fsij.org> Message-ID: <87egjbgjjb.fsf@vigenere.g10code.de> On Mon, 10 Aug 2015 12:19, gniibe at fsij.org said: > I committed following fix. I was confused that GnuPG frontend > use curve OID when sending to gpg-agent, but it is curve name. Thanks. Having finished the monthly bookkeeping and tax stuff right now, I will see whether I can get out a new release by tomorrow. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From gniibe at fsij.org Tue Aug 11 03:39:37 2015 From: gniibe at fsij.org (NIIBE Yutaka) Date: Tue, 11 Aug 2015 10:39:37 +0900 Subject: Checksum error importing (unencrypted) ecdsa private key In-Reply-To: <1422491615.27984.YahooMailBasic@web125805.mail.ne1.yahoo.com> References: <1422491615.27984.YahooMailBasic@web125805.mail.ne1.yahoo.com> Message-ID: <55C95259.9000006@fsij.org> Hello, Sorry for late response. Thanks a lot for your bug report with reproducible case. It helps us to debug. On 01/29/2015 09:33 AM, KB Sriram wrote: > command 'IMPORT_KEY' failed: Checksum error > etc. > > I may be wrong, but it seems like the issue is triggered around here: > > http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=agent/cvt-openpgp.c;h=8cf00233e4178ee34592273c167875d083406a17;hb=0c2bfd9d5a49a6134188f8f7820f6ccdebd9f181#l831 > > The line > if (is_enc || curve) > { > > and subsequent comment assumes that encrypted parameters or ecc > parameters should be stored as opaque gcry_mpi_t numbers; but seems > to me that unencrypted ecc values should not enter this clause? You are right. I confirmed that the code is wrong and your proposed fix is right. I think that agent/cvt-openpgp.c needs some more clean up, because we have some experimental code remained (for ECC), and there are some confusions about handling of opaque buffer. I'll do that after 2.1.7 release, possibly this week. In the libgcrypt computation of ECC, it uses opaque buffer for public key of modern curves (Ed25519 and Curve25519), instead of (big endian) MPI, as those keys are defined in little endian. In GnuPG, the code under g10/ (gpg frontend) just treats it as if it were MPI, and it works well because of the prefix 0x40 for keys of modern curves. It should be also no problem for the code under agent/ (gpg-agent) to treat it as if it were MPI, and it does so successfully at most parts. Currentlyu, we have some code in agent/cvt-openpgp.c, trying differently somehow, and it is not correct for both of modern curves and traditional curves (NIST, Brainpool, etc.), unfortunately. If we would do that faithfully, we need to distinguish the curve if its key is opaque in libgcrypt or not. But for conversion from/to openpgp to libgcrypt format, and for handling public key, I think that we can treat it as if it were MPI. Because GnuPG 2.1 doesn't allow exporting private key with no protection, this bug can be only encountered with external keys. -- From bjk at luxsci.net Tue Aug 11 03:26:57 2015 From: bjk at luxsci.net (Ben Kibbey) Date: Mon, 10 Aug 2015 21:26:57 -0400 Subject: [PATCH] Check the return value when starting gpg. Message-ID: <1439256422-6806642.03140296.ft7B1QwiS001775@rs146.luxsci.com> * src/engine-gpg.c (gpg_decrypt, gpg_delete, gpg_passwd): Check return value of start(). --- src/engine-gpg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 510dfd9..c3e36ae 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -1456,7 +1456,7 @@ gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain) err = add_data (gpg, ciph, -1, 0); if (!err) - start (gpg); + err = start (gpg); return err; } @@ -1479,7 +1479,7 @@ gpg_delete (void *engine, gpgme_key_t key, int allow_secret) } if (!err) - start (gpg); + err = start (gpg); return err; } @@ -1497,7 +1497,7 @@ gpg_passwd (void *engine, gpgme_key_t key, unsigned int flags) if (!err) err = add_arg (gpg, key->subkeys->fpr); if (!err) - start (gpg); + err = start (gpg); return err; } -- 2.5.0 From dkg at fifthhorseman.net Tue Aug 11 06:01:26 2015 From: dkg at fifthhorseman.net (Daniel Kahn Gillmor) Date: Tue, 11 Aug 2015 00:01:26 -0400 Subject: [PATCH] improve documentation of VALIDSIG Message-ID: <1439265686-6217-1-git-send-email-dkg@fifthhorseman.net> * doc/DETAILS (VALIDSIG): clean up description. --- doc/DETAILS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/DETAILS b/doc/DETAILS index 23a5420..eb889c9 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -409,7 +409,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB: - [ ] This status indicates that the signature is cryptographically - valid. This similar to GOODSIG or EXPSIG or EXPKEYSIG or REVSIG + valid. This is similar to GOODSIG, EXPSIG, EXPKEYSIG, or REVKEYSIG (depending on the date and the state of the signature and signing key) but has the fingerprint as the argument. Multiple status lines (VALIDSIG and the other appropriate *SIG status) are emitted -- 2.4.6 From gniibe at fsij.org Tue Aug 11 06:01:43 2015 From: gniibe at fsij.org (NIIBE Yutaka) Date: Tue, 11 Aug 2015 13:01:43 +0900 Subject: [PATCH] (GnupG 2.0) g10: fix --card-status creating stub. Message-ID: <55C973A7.2050603@fsij.org> Hello, This is a simple fix against the issue reported to gnupg-users: https://lists.gnupg.org/pipermail/gnupg-users/2015-July/053993.html The fix is that it should search exact match of secret key. The specific function get_seckeyblock_byfprint is only used by the particular calls in the card_status function in g10/card-util.c. So, I think that there will be no impact other than --card-status itself. I'll push this. diff --git a/g10/getkey.c b/g10/getkey.c index 6c14683..476445f 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1414,6 +1414,7 @@ get_seckeyblock_byfprint (KBNODE *ret_keyblock, const byte *fprint, return G10ERR_GENERAL; /* Oops */ memset (&ctx, 0, sizeof ctx); + ctx.exact = 1 ; ctx.not_allocated = 1; ctx.kr_handle = keydb_new (1); ctx.nitems = 1; -- From dkg at fifthhorseman.net Tue Aug 11 06:07:49 2015 From: dkg at fifthhorseman.net (Daniel Kahn Gillmor) Date: Tue, 11 Aug 2015 00:07:49 -0400 Subject: misconfigured redirections on https://lists.gnupg.org Message-ID: <874mk6qxgq.fsf@alice.fifthhorseman.net> Most web servers will redirect by adding a trailing slash if one was missing from the URL. https://lists.gnupg.org/ does a peculiar broken redirection when looking at the pipermail archives. Consider the difference between the two URLs: X https://lists.gnupg.org/pipermail/gnupg-devel/2015-August Y https://lists.gnupg.org/pipermail/gnupg-devel/2015-August/ X should get redirected to Y, but instead it gets redirected to a service on a non-active port entirely: http://lists.gnupg.org:8002/pipermail/gnupg-devel/2015-August/ (see wget log below) This transitions from https to http, even, which means that the response could be forged by a network attacker, which would be strange (and in contradiction to the HSTS header provided). please let me know if there's a better place to report this than gnupg-devel. Regards, --dkg 0 dkg at alice:/tmp/cdtemp.3U28xU$ wget -O/dev/null -S --progress=dot https://lists.gnupg.org/pipermail/gnupg-devel/2015-August --2015-08-11 00:03:11-- https://lists.gnupg.org/pipermail/gnupg-devel/2015-August Resolving lists.gnupg.org (lists.gnupg.org)... 217.69.76.57, 2001:aa8:fff1:2100::57 Connecting to lists.gnupg.org (lists.gnupg.org)|217.69.76.57|:443... connected. HTTP request sent, awaiting response... HTTP/1.1 301 Moved Permanently Date: Tue, 11 Aug 2015 03:55:41 GMT Strict-Transport-Security: max-age=31536000 Accept-Ranges: bytes Connection: close Content-Type: text/html; charset=ISO-8859-1 Location: http://lists.gnupg.org:8002/pipermail/gnupg-devel/2015-August/ Location: http://lists.gnupg.org:8002/pipermail/gnupg-devel/2015-August/ [following] --2015-08-11 00:03:11-- http://lists.gnupg.org:8002/pipermail/gnupg-devel/2015-August/ Connecting to lists.gnupg.org (lists.gnupg.org)|217.69.76.57|:8002... failed: Connection refused. Connecting to lists.gnupg.org (lists.gnupg.org)|2001:aa8:fff1:2100::57|:8002... failed: Network is unreachable. Resolving lists.gnupg.org (lists.gnupg.org)... 217.69.76.57, 2001:aa8:fff1:2100::57 Connecting to lists.gnupg.org (lists.gnupg.org)|217.69.76.57|:8002... failed: Connection refused. Connecting to lists.gnupg.org (lists.gnupg.org)|2001:aa8:fff1:2100::57|:8002... failed: Network is unreachable. 4 dkg at alice:/tmp/cdtemp.3U28xU$ -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 948 bytes Desc: not available URL: From wk at gnupg.org Tue Aug 11 10:22:34 2015 From: wk at gnupg.org (Werner Koch) Date: Tue, 11 Aug 2015 10:22:34 +0200 Subject: misconfigured redirections on https://lists.gnupg.org In-Reply-To: <874mk6qxgq.fsf@alice.fifthhorseman.net> (Daniel Kahn Gillmor's message of "Tue, 11 Aug 2015 00:07:49 -0400") References: <874mk6qxgq.fsf@alice.fifthhorseman.net> Message-ID: <874mk6grp1.fsf@vigenere.g10code.de> On Tue, 11 Aug 2015 06:07, dkg at fifthhorseman.net said: > X should get redirected to Y, but instead it gets redirected to a > service on a non-active port entirely: > > http://lists.gnupg.org:8002/pipermail/gnupg-devel/2015-August/ I know that is an annoying bug. > This transitions from https to http, even, which means that the response > could be forged by a network attacker, which would be strange (and in > contradiction to the HSTS header provided). Nope, port 8002 is only listening on localhost. We round pound as frontend with two instaces of boa as backend (listening at localhost:800n) Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Tue Aug 11 11:52:34 2015 From: wk at gnupg.org (Werner Koch) Date: Tue, 11 Aug 2015 11:52:34 +0200 Subject: misconfigured redirections on https://lists.gnupg.org In-Reply-To: <874mk6grp1.fsf@vigenere.g10code.de> (Werner Koch's message of "Tue, 11 Aug 2015 10:22:34 +0200") References: <874mk6qxgq.fsf@alice.fifthhorseman.net> <874mk6grp1.fsf@vigenere.g10code.de> Message-ID: <87wpx2f8yl.fsf@vigenere.g10code.de> On Tue, 11 Aug 2015 10:22, wk at gnupg.org said: > I know that is an annoying bug. Please check again it should be fixed now. If Boa is configured for STS it will now use https: in the Location header for the redirect. The new configure option NoRedirectPort now strips the port number in a redirect. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Tue Aug 11 17:32:42 2015 From: wk at gnupg.org (Werner Koch) Date: Tue, 11 Aug 2015 17:32:42 +0200 Subject: [Announce] GnuPG 2.1.7 released Message-ID: <87egj9g7s5.fsf@vigenere.g10code.de> Hello! The GnuPG Project is pleased to announce the availability of a new release of GnuPG modern: Version 2.1.7. The GNU Privacy Guard (GnuPG) is a complete and free implementation of the OpenPGP standard which is commonly abbreviated as PGP. GnuPG allows to encrypt and sign data and communication, features a versatile key management system as well as access modules for public key directories. GnuPG itself is a command line tool with features for easy integration with other applications. A wealth of frontend applications and libraries making use of GnuPG are available. Since version 2 GnuPG provides support for S/MIME and Secure Shell in addition to OpenPGP. GnuPG is Free Software (meaning that it respects your freedom). It can be freely used, modified and distributed under the terms of the GNU General Public License. Three different branches of GnuPG are actively maintained: - GnuPG "modern" (2.1) is the latest development with a lot of new features. This announcement is about this branch. - GnuPG "stable" (2.0) is the current stable version for general use. This is what most users are currently using. - GnuPG "classic" (1.4) is the old standalone version which is most suitable for older or embedded platforms. You may not install "modern" (2.1) and "stable" (2.0) at the same time. However, it is possible to install "classic" (1.4) along with any of the other versions. Noteworthy changes in version 2.1.7 =================================== * gpg: Support encryption with Curve25519 if Libgcrypt 1.7 is used. * gpg: In the --edit-key menu: Removed the need for "toggle", changed how secret keys are indicated, new commands "fpr *" and "grip". * gpg: More fixes related to legacy keys in a keyring. * gpgv: Does now also work with a "trustedkeys.kbx" file. * scd: Support some feature from the OpenPGP card 3.0 specs. * scd: Improved ECC support * agent: New option --force for the DELETE_KEY command. * w32: Look for the Pinentry at more places. * Dropped deprecated gpgsm-gencert.sh * Various other bug fixes. A detailed description of the changes found in the 2.1 branch can be found at . Please be aware that there are still known bugs which we are working on. Check https://bugs.gnupg.org, https://wiki.gnupg.org, and the mailing list archives for known problems and workarounds. Getting the Software ==================== Please follow the instructions found at https://gnupg.org/download/ or read on: GnuPG 2.1.7 may be downloaded from one of the GnuPG mirror sites or direct from its primary FTP server. The list of mirrors can be found at . Note that GnuPG is not available at ftp.gnu.org. On ftp.gnupg.org you find these files: ftp://ftp.gnupg.org/gcrypt/gnupg/gnupg-2.1.7.tar.bz2 (4803k) ftp://ftp.gnupg.org/gcrypt/gnupg/gnupg-2.1.7.tar.bz2.sig This is the GnuPG source code compressed using BZIP2 and its OpenPGP signature. ftp://ftp.gnupg.org/gcrypt/binary/gnupg-w32-2.1.7_20150811.exe (2578k) ftp://ftp.gnupg.org/gcrypt/binary/gnupg-w32-2.1.7_20150811.exe.sig This is an installer for Windows without graphical frontends except for a basic Pinentry tool. Note that on Windows TLS access to keyservers is not yet available. The sources used to build the installer can be found in the same directory with an ".tar.xz" suffix. Checking the Integrity ====================== In order to check that the version of GnuPG which you are going to install is an original and unmodified one, you can do it in one of the following ways: * If you already have a version of GnuPG installed, you can simply verify the supplied signature. For example to verify the signature of the file gnupg-2.1.7.tar.bz2 you would use this command: gpg --verify gnupg-2.1.7.tar.bz2.sig gnupg-2.1.7.tar.bz2 This checks whether the signature file matches the source file. You should see a message indicating that the signature is good and made by one or more of the release signing keys. Make sure that this is a valid key, either by matching the shown fingerprint against a trustworthy list of valid release signing keys or by checking that the key has been signed by trustworthy other keys. See below for information on the signing keys. * If you are not able to use an existing version of GnuPG, you have to verify the SHA-1 checksum. On Unix systems the command to do this is either "sha1sum" or "shasum". Assuming you downloaded the file gnupg-2.1.7.tar.bz2, you run the command like this: sha1sum gnupg-2.1.7.tar.bz2 and check that the output matches the next line: 1a345804f34a2acd05c1555e40ddfa297f38438b gnupg-2.1.7.tar.bz2 dfea3fa2499f64cac223c9329c9f017bc3da11a5 gnupg-w32-2.1.7_20150811.exe 20439f65b8d94ec79523c45ad72418670ca9d5eb gnupg-w32-2.1.7_20150811.tar.xz Release Signing Keys ==================== To guarantee that a downloaded GnuPG version has not been tampered by malicious entities we provide signature files for all tarballs and binary versions. The keys are also signed by the long term keys of their respective owners. Current releases are signed by one or more of these four keys: 2048R/4F25E3B6 2011-01-12 [expires: 2019-12-31] Key fingerprint = D869 2123 C406 5DEA 5E0F 3AB5 249B 39D2 4F25 E3B6 Werner Koch (dist sig) rsa2048/E0856959 2014-10-29 [expires: 2019-12-31] Key fingerprint = 46CC 7308 65BB 5C78 EBAB ADCF 0437 6F3E E085 6959 David Shaw (GnuPG Release Signing Key) rsa2048/33BD3F06 2014-10-29 [expires: 2016-10-28] Key fingerprint = 031E C253 6E58 0D8E A286 A9F2 2071 B08A 33BD 3F06 NIIBE Yutaka (GnuPG Release Key) rsa2048/7EFD60D9 2014-10-19 [expires: 2020-12-31] Key fingerprint = D238 EA65 D64C 67ED 4C30 73F2 8A86 1B1C 7EFD 60D9 Werner Koch (Release Signing Key) You may retrieve these keys from a keyserver using this command gpg --keyserver hkp://keys.gnupg.net --recv-keys \ 249B39D24F25E3B6 04376F3EE0856959 \ 2071B08A33BD3F06 8A861B1C7EFD60D9 The keys are also available at https://gnupg.org/signature_key.html and in any recently released GnuPG tarball in the file g10/distsigkey.gpg . Note that this mail has been signed using by a different key. Internationalization ==================== This version of GnuPG has support for 26 languages with Chinese, Czech, French, German, Japanese, Russian, and Ukrainian being almost completely translated (2074 different strings). Documentation ============= If you used GnuPG in the past you should read the description of changes and new features at doc/whats-new-in-2.1.txt or online at https://gnupg.org/faq/whats-new-in-2.1.html The file gnupg.info has the complete user manual of the system. Separate man pages are included as well but they have not all the details available as are the manual. It is also possible to read the complete manual online in HTML format at https://gnupg.org/documentation/manuals/gnupg/ or in Portable Document Format at https://gnupg.org/documentation/manuals/gnupg.pdf . The chapters on gpg-agent, gpg and gpgsm include information on how to set up the whole thing. You may also want search the GnuPG mailing list archives or ask on the gnupg-users mailing lists for advise on how to solve problems. Many of the new features are around for several years and thus enough public knowledge is already available. You may also want to follow postings at https://gnupg.org/blob/. Support ======== Please consult the archive of the gnupg-users mailing list before reporting a bug . We suggest to send bug reports for a new release to this list in favor of filing a bug at . For commercial support requests we keep a list of known service companies at: https://gnupg.org/service.html If you are a developer and you may need a certain feature for your project, please do not hesitate to bring it to the gnupg-devel mailing list for discussion. Thanks ====== We have to thank all the people who helped with this release, be it testing, coding, translating, suggesting, auditing, administering the servers, spreading the word, and answering questions on the mailing lists. Maintenance and development of GnuPG is possible due to many individual and corporate donations; for a list of non-anonymous donors see . For the GnuPG hackers, Werner p.s. This is a announcement only mailing list. Please send replies only to the gnupg-users at gnupg.org mailing list. -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 180 bytes Desc: not available URL: -------------- next part -------------- _______________________________________________ Gnupg-announce mailing list Gnupg-announce at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-announce From dkg at fifthhorseman.net Tue Aug 11 23:33:04 2015 From: dkg at fifthhorseman.net (Daniel Kahn Gillmor) Date: Tue, 11 Aug 2015 17:33:04 -0400 Subject: misconfigured redirections on https://lists.gnupg.org In-Reply-To: <87wpx2f8yl.fsf@vigenere.g10code.de> References: <874mk6qxgq.fsf@alice.fifthhorseman.net> <874mk6grp1.fsf@vigenere.g10code.de> <87wpx2f8yl.fsf@vigenere.g10code.de> Message-ID: <87io8lo6i7.fsf@alice.fifthhorseman.net> On Tue 2015-08-11 05:52:34 -0400, Werner Koch wrote: > On Tue, 11 Aug 2015 10:22, wk at gnupg.org said: > >> I know that is an annoying bug. > > Please check again it should be fixed now. yep, i think it's fixed now. My persistent browser is still remembering the 301, but maybe eventually it will stop doing that :P thanks for the fix, --dkg From wk at gnupg.org Wed Aug 12 08:14:00 2015 From: wk at gnupg.org (Werner Koch) Date: Wed, 12 Aug 2015 08:14:00 +0200 Subject: [PATCH] Check the return value when starting gpg. In-Reply-To: <1439256422-6806642.03140296.ft7B1QwiS001775@rs146.luxsci.com> (Ben Kibbey's message of "Mon, 10 Aug 2015 21:26:57 -0400") References: <1439256422-6806642.03140296.ft7B1QwiS001775@rs146.luxsci.com> Message-ID: <87zj1xc9uf.fsf@vigenere.g10code.de> On Tue, 11 Aug 2015 03:26, bjk at luxsci.net said: > * src/engine-gpg.c (gpg_decrypt, gpg_delete, gpg_passwd): Check return > value of start(). Thanks. Any special reason why you did not changed this for gpg_sign() too? I wonder why Marcus checked the return value only on some invocations when he chnaged the code in 2003. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From bjk at luxsci.net Wed Aug 12 12:45:18 2015 From: bjk at luxsci.net (Ben Kibbey) Date: Wed, 12 Aug 2015 06:45:18 -0400 Subject: [PATCH] Check the return value when starting gpg. In-Reply-To: <87zj1xc9uf.fsf@vigenere.g10code.de> References: <1439256422-6806642.03140296.ft7B1QwiS001775@rs146.luxsci.com> <87zj1xc9uf.fsf@vigenere.g10code.de> Message-ID: <1439376362-8185788.3064346.ft7CAjJpU003212@rs146.luxsci.com> On Wed, Aug 12, 2015 at 08:14:00AM +0200, Werner Koch wrote: > On Tue, 11 Aug 2015 03:26, bjk at luxsci.net said: > > * src/engine-gpg.c (gpg_decrypt, gpg_delete, gpg_passwd): Check return > > value of start(). > > Thanks. Any special reason why you did not changed this for gpg_sign() > too? None other than I overlooked it. :) > I wonder why Marcus checked the return value only on some invocations > when he chnaged the code in 2003. Not sure. But when stress testing I'm getting crashes in _gpgme_io_select() so there may be a race condition which may be related to the FIXME's in start(). Without returning an error from start() it gets stuck in a _gpgme_io_select() loop. -- Ben Kibbey From gniibe at fsij.org Wed Aug 12 15:46:27 2015 From: gniibe at fsij.org (NIIBE Yutaka) Date: Wed, 12 Aug 2015 22:46:27 +0900 Subject: SSH with ed25519 Message-ID: <55CB4E33.9090900@fsij.org> Hello, I forgot when I tested OpenSSH with Ed25519, it worked at that time. Today, I needed a patch like this: diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 2a3037c..7526634 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -1964,6 +1964,11 @@ ssh_key_to_blob (gcry_sexp_t sexp, int with_secret, err = gpg_error (GPG_ERR_INV_SEXP); goto out; } + if (data[0] == 0x40) + { + data++; + datalen--; + } err = stream_write_string (stream, data, datalen); if (err) goto out; The above fix is not quite right (I think that always removing the prefix is right), but I'm not sure if there's existing old keys. In the git commit log, I found following change. I think that after this change, we need to remove prefix when sending to SSH. commit 557cc11a605dd280d03c52d8b546deed8c4c714d Author: Werner Koch Date: Thu Jul 24 16:16:53 2014 +0200 gpg: Switch to an EdDSA format with prefix byte. * g10/keygen.c (gen_ecc): USe "comp" for EdDSA. -- From wk at gnupg.org Wed Aug 12 15:45:24 2015 From: wk at gnupg.org (Werner Koch) Date: Wed, 12 Aug 2015 15:45:24 +0200 Subject: [PATCH] Check the return value when starting gpg. In-Reply-To: <1439376362-8185788.3064346.ft7CAjJpU003212@rs146.luxsci.com> (Ben Kibbey's message of "Wed, 12 Aug 2015 06:45:18 -0400") References: <1439256422-6806642.03140296.ft7B1QwiS001775@rs146.luxsci.com> <87zj1xc9uf.fsf@vigenere.g10code.de> <1439376362-8185788.3064346.ft7CAjJpU003212@rs146.luxsci.com> Message-ID: <878u9gd3ij.fsf@vigenere.g10code.de> On Wed, 12 Aug 2015 12:45, bjk at luxsci.net said: > Not sure. But when stress testing I'm getting crashes in > _gpgme_io_select() so there may be a race condition which may be related > to the FIXME's in start(). Without returning an error from start() it > gets stuck in a _gpgme_io_select() loop. Good to know. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From zzhang at securityinnovation.com Thu Aug 13 17:28:39 2015 From: zzhang at securityinnovation.com (Zhenfei Zhang) Date: Thu, 13 Aug 2015 11:28:39 -0400 Subject: Issues with enabling new crypto (NTRU) for GnuPG Message-ID: Hi all, I am on a task of enabling NTRU for GnuPG. The idea is to use NTRU as the public key encryption algorithm, while still using DSA or ECC for signatures. I was able to integrate NTRU to libgcrypt. Please see the linked email for the commit. http://gnupg.10057.n7.nabble.com/PATCH-Add-NTRUEncrypt-public-key-encryption-algorithm-td43855.html In my libgcrypt modification, I was able to use NTRU functions by setting an s-expression parameter such as (genkey(ntru(n439))) My next task is to get GnuPG working with NTRU, and this is where I am having trouble with. I modified the key generation function in g10/keygen.c I creates a gen_ntru() function which is an analogy to gen_rsa(), except it allows me to pass "(genkey(ntru(n439)))" to the common_gen(). And I was expecting that libgcrypt will receive it. However, I get "general errors" from gpg-agent. Here is the debug information: ======================================================== gpg: DBG: chan_4 -> RESET gpg: DBG: chan_4 <- OK gpg: DBG: chan_4 -> GENKEY 7C798651354C5E8DD8DE0874 gpg: DBG: chan_4 <- S INQUIRE_MAXLEN 1024 gpg: DBG: chan_4 <- INQUIRE KEYPARAM gpg: DBG: chan_4 -> D (genkey(ntru(n439))) gpg: DBG: chan_4 -> END gpg: DBG: chan_4 <- INQUIRE PINENTRY_LAUNCHED 2170 gpg: DBG: chan_4 -> END gpg: DBG: chan_4 <- INQUIRE PINENTRY_LAUNCHED 2176 gpg: DBG: chan_4 -> END gpg: DBG: chan_4 <- ERR 67108865 General error ======================================================== >From what I understand, GnuPG calls the gpg-agent, who passes the param to libassuan and then libassuan to libgcrypt. But it appears that gpg-agent was never able to talk to libgcrypt. I have done the following debugging: *I checked that libassuan does receive the param. The error seems to occur within a _assuan_read_from_server call in assaun_transact() *I tested that gpg-agent works fine with DSA/ECC/RSA key generation. *I also tried to call gcry_pk_genkey(&ntru_keypair, ntru_parms) of libgcrypt directly from my gen_ntru() function and it works fine. So I would like to ask for your help. Sorry that my presentation of the problem may not be clear. I wish to put more info here, but I am not sure which are relevant. Thanks in advance. Cheers, Zhenfei -------------- next part -------------- An HTML attachment was scrubbed... URL: From bertrand at jacquin.bzh Mon Aug 17 02:10:45 2015 From: bertrand at jacquin.bzh (Bertrand Jacquin) Date: Mon, 17 Aug 2015 01:10:45 +0100 Subject: [PATCH] scd: support any curves defined by libgcrypt. In-Reply-To: mid:6111 References: mid:6111 Message-ID: <1fddfe3daeaaecb1060409738c070115@mail.meleeweb.net> Hi, This patch introduce as issue with OpenGPG Card FTS-01. I've run a git bisect to be able to point that particular commit. I have a FTS-01 OpenGPG card with a EdDSA sign key and a EdDSA auth key and using gpg-agent as a ssh agent. Since that particular commit, info given by gpg-agent to ssh-add are not conform for ssh: $ ssh-add -l error fetching identities for protocol 2: invalid format The agent has no identities. scdaemon is returning the following to gpg-agent: [pid 14395] read(4, "GETATTR SERIALNO\n", 1002) = 17 [pid 14395] write(5, "S SERIALNO D276000124010200FFFE50FF6A060000", 43) = 43 [pid 14395] write(5, "\n", 1) = 1 [pid 14395] write(5, "OK", 2) = 2 [pid 14395] write(5, "\n", 1) = 1 [pid 14395] read(4, "READKEY OPENPGP.3\n", 1002) = 18 [pid 14395] write(5, "D (10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q33:@\7\323|\256d\353Mo\16^Onu\212\330\333\256Z8Uo\366x\33\337}\333s\220\310\241N)))\n", 100) = 100 [pid 14395] write(5, "OK", 2) = 2 [pid 14395] write(5, "\n", 1) = 1 [pid 14395] read(4, "GETATTR $DISPSERIALNO\n", 1002) = 22 [pid 14395] write(5, "S $DISPSERIALNO FFFE50FF6A06", 28) = 28 gpg-agent is returning the following to ssh-add: [pid 14471] write(5, "\0\0\0T", 4) = 4 [pid 14471] write(5, "\f\0\0\0\1\0\0\0004\0\0\0\vssh-ed25519\0\0\0!@\7\323|\256d\353Mo\16^Onu\212\330\333\256Z8Uo\366x\33\337}\333s\220\310\241N\0\0\0\23cardno:FFFE50FF6A06", 84) = 84 [pid 14471] read(5, "", 1) = 0 [pid 14471] write(9, "RESTART", 7) = 7 Here is the details about my setup: $ /usr/bin/usb_strings.py Device: Vendor: Free Software Initiative of Japan Product: Gnuk Token Serial: FSIJ-1.1.7-87062311 Revision: release/1.1.7 Config: FST_01:dfu=no:debug=no:pinpad=no:certdo=yes Sys: 2.1 Board: FST-01 $ gpg --version gpg (GnuPG) 2.1.7 libgcrypt 1.6.3 $ gpg --card-status | grep -E 'Version|Key\ attributes|key' Version ..........: 2.0 Key attributes ...: ed25519 rsa2048 ed25519 Signature key ....: DB2A 5D8D 1506 34ED 349C 32E4 71D8 37C4 7EA9 B667 Encryption key....: 1FBC 26CC 2BAB CE26 A3F8 8D4F C356 C8D7 FF60 3A1A Authentication key: 3266 F1CD 03C5 46F6 22A1 3EBE E710 BC72 3D40 CCE8 General key info..: sub ed25519/0x71D837C47EA9B667 2014-11-10 Bertrand Jacquin Is there a need to use a particular libgcrypt version ? Cheers, Bertrand On 25/07/2015 04:09, NIIBE Yutaka wrote: > * g10/call-agent.h (struct agent_card_info_s): Add curve field. > * g10/call-agent.c (learn_status_cb): Use curve name. > * g10/card-util.c (card_status): Show pubkey name. > * scd/app-openpgp.c (struct app_local_s): Record OID and flags. > (store_fpr): Use ALGO instead of key type. > (send_key_attr): Use curve name instead of OID. > (get_public_key): Clean up by OID to curve name. > (ecc_writekey): Support any curves in libgcrypt. > (do_genkey, do_auth, ): Follow the change. > (ecc_oid): New. > (parse_algorithm_attribute): Show OID here. > --- > g10/call-agent.c | 28 ++++- > g10/call-agent.h | 5 +- > g10/card-util.c | 19 +-- > scd/app-openpgp.c | 360 > +++++++++++++++++++++--------------------------------- > 4 files changed, 180 insertions(+), 232 deletions(-) > > diff --git a/g10/call-agent.c b/g10/call-agent.c > index edee66e..0df572a 100644 > --- a/g10/call-agent.c > +++ b/g10/call-agent.c > @@ -645,14 +645,32 @@ learn_status_cb (void *opaque, const char *line) > } > else if (keywordlen == 8 && !memcmp (keyword, "KEY-ATTR", > keywordlen)) > { > - int keyno, algo, nbits; > + int keyno = 0; > + int algo = PUBKEY_ALGO_RSA; > + int n = 0; > > - sscanf (line, "%d %d %d", &keyno, &algo, &nbits); > + sscanf (line, "%d %d %n", &keyno, &algo, &n); > keyno--; > - if (keyno >= 0 && keyno < DIM (parm->key_attr)) > + if (keyno < 0 || keyno >= DIM (parm->key_attr)) > + return 0; > + > + parm->key_attr[keyno].algo = algo; > + if (algo == PUBKEY_ALGO_RSA) > + parm->key_attr[keyno].nbits = strtoul (line+n+3, NULL, 10); > + else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA > + || algo == PUBKEY_ALGO_EDDSA) > { > - parm->key_attr[keyno].algo = algo; > - parm->key_attr[keyno].nbits = nbits; > + const char *curve; > + > + i = 0; > + do > + { > + curve = openpgp_enum_curves (&i); > + if (!strcmp (curve, line+n)) > + break; > + } > + while (curve != NULL); > + parm->key_attr[keyno].curve = curve; > } > } > else if (keywordlen == 12 && !memcmp (keyword, "PRIVATE-DO-", 11) > diff --git a/g10/call-agent.h b/g10/call-agent.h > index df570a4..70421db 100644 > --- a/g10/call-agent.h > +++ b/g10/call-agent.h > @@ -55,7 +55,10 @@ struct agent_card_info_s > int chvretry[3]; /* Allowed retries for the CHV; 0 = blocked. */ > struct { /* Array with key attributes. */ > int algo; /* Algorithm identifier. */ > - unsigned int nbits; /* Supported keysize. */ > + union { > + unsigned int nbits; /* Supported keysize. */ > + const char *curve; /* Name of curve. */ > + }; > } key_attr[3]; > struct { > unsigned int ki:1; /* Key import available. */ > diff --git a/g10/card-util.c b/g10/card-util.c > index 890bf2d..ed69058 100644 > --- a/g10/card-util.c > +++ b/g10/card-util.c > @@ -471,9 +471,14 @@ card_status (estream_t fp, char *serialno, size_t > serialnobuflen) > > es_fprintf (fp, "forcepin:%d:::\n", !info.chv1_cached); > for (i=0; i < DIM (info.key_attr); i++) > - if (info.key_attr[0].algo) > + if (info.key_attr[0].algo == PUBKEY_ALGO_RSA) > es_fprintf (fp, "keyattr:%d:%d:%u:\n", i+1, > info.key_attr[i].algo, info.key_attr[i].nbits); > + else if (info.key_attr[i].algo == PUBKEY_ALGO_ECDH > + || info.key_attr[i].algo == PUBKEY_ALGO_ECDSA > + || info.key_attr[i].algo == PUBKEY_ALGO_EDDSA) > + es_fprintf (fp, "keyattr:%d:%d:%s:\n", i+1, > + info.key_attr[i].algo, info.key_attr[i].curve); > es_fprintf (fp, "maxpinlen:%d:%d:%d:\n", > info.chvmaxlen[0], info.chvmaxlen[1], > info.chvmaxlen[2]); > es_fprintf (fp, "pinretry:%d:%d:%d:\n", > @@ -553,12 +558,12 @@ card_status (estream_t fp, char *serialno, > size_t serialnobuflen) > { > tty_fprintf (fp, "Key attributes ...:"); > for (i=0; i < DIM (info.key_attr); i++) > - tty_fprintf (fp, " %u%c", > - info.key_attr[i].nbits, > - info.key_attr[i].algo == 1? 'R': > - info.key_attr[i].algo == 17? 'D': > - info.key_attr[i].algo == 18? 'e': > - info.key_attr[i].algo == 19? 'E': '?'); > + if (info.key_attr[i].algo == PUBKEY_ALGO_RSA) > + tty_fprintf (fp, " rsa%u", info.key_attr[i].nbits); > + else if (info.key_attr[i].algo == PUBKEY_ALGO_ECDH > + || info.key_attr[i].algo == PUBKEY_ALGO_ECDSA > + || info.key_attr[i].algo == PUBKEY_ALGO_EDDSA) > + tty_fprintf (fp, " %s", info.key_attr[i].curve); > tty_fprintf (fp, "\n"); > } > tty_fprintf (fp, "Max. PIN lengths .: %d %d %d\n", > diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c > index 81b4923..72f7640 100644 > --- a/scd/app-openpgp.c > +++ b/scd/app-openpgp.c > @@ -126,7 +126,6 @@ static struct { > typedef enum > { > KEY_TYPE_ECC, > - KEY_TYPE_EDDSA, > KEY_TYPE_RSA, > } > key_type_t; > @@ -144,18 +143,6 @@ typedef enum > rsa_key_format_t; > > > -/* Elliptic Curves. */ > -enum > - { > - CURVE_NIST_P256, > - CURVE_NIST_P384, > - CURVE_NIST_P521, > - CURVE_SEC_P256K1, > - CURVE_ED25519, > - CURVE_UNKNOWN, > - }; > - > - > /* One cache item for DOs. */ > struct cache_s { > struct cache_s *next; > @@ -241,15 +228,14 @@ struct app_local_s { > rsa_key_format_t format; > } rsa; > struct { > - int curve; > + const char *oid; > + int flags; > } ecc; > - struct { > - int curve; > - } eddsa; > }; > } keyattr[3]; > }; > > +#define ECC_FLAG_EDDSA (1 << 0) > > > /***** Local prototypes *****/ > @@ -745,25 +731,12 @@ parse_login_data (app_t app) > } > > > -static unsigned char > -get_algo_byte (int keynumber, key_type_t key_type) > -{ > - if (key_type == KEY_TYPE_ECC && keynumber != 1) > - return PUBKEY_ALGO_ECDSA; > - else if (key_type == KEY_TYPE_ECC && keynumber == 1) > - return PUBKEY_ALGO_ECDH; > - else if (key_type == KEY_TYPE_EDDSA) > - return PUBKEY_ALGO_EDDSA; > - else > - return PUBKEY_ALGO_RSA; > -} > - > #define MAX_ARGS_STORE_FPR 3 > > /* Note, that FPR must be at least 20 bytes. */ > static gpg_error_t > store_fpr (app_t app, int keynumber, u32 timestamp, unsigned char > *fpr, > - key_type_t key_type, ...) > + int algo, ...) > { > unsigned int n, nbits; > unsigned char *buffer, *p; > @@ -776,21 +749,17 @@ store_fpr (app_t app, int keynumber, u32 > timestamp, unsigned char *fpr, > int i; > > n = 6; /* key packet version, 4-byte timestamps, and algorithm */ > - if (keynumber == 1 && key_type == KEY_TYPE_ECC) > + if (algo == PUBKEY_ALGO_ECDH) > argc = 3; > else > argc = 2; > > - va_start (ap, key_type); > + va_start (ap, algo); > for (i = 0; i < argc; i++) > { > m[i] = va_arg (ap, const unsigned char *); > mlen[i] = va_arg (ap, size_t); > - if (key_type != KEY_TYPE_EDDSA) > - /* strip off leading zeroes */ > - for (; mlen[i] && !*m[i]; mlen[i]--, m[i]++) > - ; > - if (key_type == KEY_TYPE_RSA || i == 1) > + if (algo == PUBKEY_ALGO_RSA || i == 1) > n += 2; > n += mlen[i]; > } > @@ -808,11 +777,11 @@ store_fpr (app_t app, int keynumber, u32 > timestamp, unsigned char *fpr, > *p++ = timestamp >> 16; > *p++ = timestamp >> 8; > *p++ = timestamp; > - *p++ = get_algo_byte (keynumber, key_type); > + *p++ = algo; > > for (i = 0; i < argc; i++) > { > - if (key_type == KEY_TYPE_RSA || i == 1) > + if (algo == PUBKEY_ALGO_RSA || i == 1) > { > nbits = count_bits (m[i], mlen[i]); > *p++ = nbits >> 8; > @@ -924,70 +893,25 @@ send_key_data (ctrl_t ctrl, const char *name, > > > static void > -get_ecc_key_parameters (int curve, int *r_n_bits, const char > **r_curve_oid) > -{ > - if (curve == CURVE_NIST_P256) > - { > - *r_n_bits = 256; > - *r_curve_oid = "1.2.840.10045.3.1.7"; > - } > - else if (curve == CURVE_NIST_P384) > - { > - *r_n_bits = 384; > - *r_curve_oid = "1.3.132.0.34"; > - } > - else if (curve == CURVE_NIST_P521) > - { > - *r_n_bits = 521; > - *r_curve_oid = "1.3.132.0.35"; > - } > - 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 > -send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int > number) > +send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int keyno) > { > char buffer[200]; > - int n_bits; > - const char *curve_oid; > > - assert (number >=0 && number < DIM(app->app_local->keyattr)); > + assert (keyno >=0 && keyno < DIM(app->app_local->keyattr)); > > - if (app->app_local->keyattr[number].key_type == KEY_TYPE_RSA) > - snprintf (buffer, sizeof buffer, "%d 1 %u %u %d", > - number+1, > - app->app_local->keyattr[number].rsa.n_bits, > - app->app_local->keyattr[number].rsa.e_bits, > - app->app_local->keyattr[number].rsa.format); > - else if (app->app_local->keyattr[number].key_type == KEY_TYPE_ECC) > + if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA) > + snprintf (buffer, sizeof buffer, "%d 1 rsa%u %u %d", > + keyno+1, > + app->app_local->keyattr[keyno].rsa.n_bits, > + app->app_local->keyattr[keyno].rsa.e_bits, > + app->app_local->keyattr[keyno].rsa.format); > + else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC) > { > - get_ecc_key_parameters > (app->app_local->keyattr[number].ecc.curve, > - &n_bits, &curve_oid); > - snprintf (buffer, sizeof buffer, "%d %d %u %s", > - number+1, > - number==1? PUBKEY_ALGO_ECDH: PUBKEY_ALGO_ECDSA, > - n_bits, curve_oid); > - } > - 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 22 %u %s", > - number+1, n_bits, curve_oid); > + snprintf (buffer, sizeof buffer, "%d %d %s", > + keyno+1, > + app->app_local->keyattr[keyno].ecc.flags? > PUBKEY_ALGO_EDDSA: > + (keyno==1? PUBKEY_ALGO_ECDH: PUBKEY_ALGO_ECDSA), > + openpgp_oid_to_curve > (app->app_local->keyattr[keyno].ecc.oid)); > } > else > snprintf (buffer, sizeof buffer, "0 0 UNKNOWN"); > @@ -1295,24 +1219,6 @@ retrieve_key_material (FILE *fp, const char > *hexkeyid, > #endif /*GNUPG_MAJOR_VERSION > 1*/ > > > -static const char * > -get_curve_name (int curve) > -{ > - if (curve == CURVE_NIST_P256) > - return "NIST P-256"; > - else if (curve == CURVE_NIST_P384) > - return "NIST P-384"; > - else if (curve == CURVE_NIST_P521) > - return "NIST P-521"; > - else if (curve == CURVE_SEC_P256K1) > - return "secp256k1"; > - else if (curve == CURVE_ED25519) > - return "Ed25519"; > - else > - return "unknown"; > -} > - > - > /* Get the public key for KEYNO and store it as an S-expresion with > the APP handle. On error that field gets cleared. If we already > know about the public key we will just return. Note that this does > @@ -1480,7 +1386,9 @@ get_public_key (app_t app, int keyno) > goto leave; > } > /* Prepend numbers with a 0 if needed. */ > - if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_EDDSA > + if ((app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA > + || (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC > + && !app->app_local->keyattr[keyno].ecc.flags)) > && mlen && (*m & 0x80)) > { > *mbuf = 0; > @@ -1526,35 +1434,12 @@ get_public_key (app_t app, int keyno) > } > else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC) > { > - const char *curve_name > - = get_curve_name (app->app_local->keyattr[keyno].ecc.curve); > - > err = gcry_sexp_build (&s_pkey, NULL, > - "(public-key(ecc(curve%s)(q%b)))", > - curve_name, (int)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 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, (int)mlen, mbuf); > + "(public-key(ecc(curve%s)%s(q%b)))", > + openpgp_oid_to_curve > (app->app_local->keyattr[keyno].ecc.oid), > + app->app_local->keyattr[keyno].ecc.flags? > + "(flags eddsa)" : "", > + (int)mlen, mbuf); > if (err) > goto leave; > > @@ -3256,7 +3141,7 @@ rsa_writekey (app_t app, gpg_error_t > (*pincb)(void*, const char *, char **), > goto leave; > } > > - err = store_fpr (app, keyno, created_at, fprbuf, KEY_TYPE_RSA, > + err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA, > rsa_n, rsa_n_len, rsa_e, rsa_e_len); > if (err) > goto leave; > @@ -3280,11 +3165,10 @@ ecc_writekey (app_t app, gpg_error_t > (*pincb)(void*, const char *, char **), > const unsigned char *ecc_q = NULL; > const unsigned char *ecc_d = NULL; > size_t ecc_q_len, ecc_d_len; > - unsigned char *template = NULL; > - size_t template_len; > - unsigned char fprbuf[20]; > u32 created_at = 0; > - int curve = CURVE_UNKNOWN; > + const char *oidstr = NULL; > + int flag_eddsa = 0; > + int algo; > > /* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)): > curve = "NIST P-256" */ > @@ -3306,21 +3190,30 @@ ecc_writekey (app_t app, gpg_error_t > (*pincb)(void*, const char *, char **), > > if (tok && toklen == 5 && !memcmp (tok, "curve", 5)) > { > + unsigned char *curve; > + > if ((err = parse_sexp (&buf, &buflen, &depth, &tok, > &toklen))) > goto leave; > > - if (tok && toklen == 10 && !memcmp (tok, "NIST P-256", 10)) > - 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 > + curve = xtrymalloc (toklen+1); > + if (!curve) > { > - log_error (_("unsupported curve\n")); > - err = gpg_error (GPG_ERR_INV_VALUE); > + err = gpg_error_from_syserror (); > goto leave; > } > + > + memcpy (curve, tok, toklen); > + curve[toklen] = 0; > + oidstr = openpgp_curve_to_oid (curve, NULL); > + xfree (curve); > + } > + else if (tok && toklen == 5 && !memcmp (tok, "flags", 5)) > + { > + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, > &toklen))) > + goto leave; > + > + if (tok && toklen == 5 && !memcmp (tok, "eddsa", 5)) > + flag_eddsa = 1; > } > else if (tok && toklen == 1) > { > @@ -3340,7 +3233,7 @@ ecc_writekey (app_t app, gpg_error_t > (*pincb)(void*, const char *, char **), > } > if ((err = parse_sexp (&buf, &buflen, &depth, &tok, > &toklen))) > goto leave; > - if (tok && buf2 && curve != CURVE_ED25519) > + if (tok && buf2 && !flag_eddsa) > /* It's MPI. Strip off leading zero bytes and save. */ > for (;toklen && !*tok; toklen--, tok++) > ; > @@ -3391,12 +3284,33 @@ ecc_writekey (app_t app, gpg_error_t > (*pincb)(void*, const char *, char **), > > /* Check that we have all parameters and that they match the card > description. */ > + if (!oidstr) > + { > + log_error (_("unsupported curve\n")); > + err = gpg_error (GPG_ERR_INV_VALUE); > + goto leave; > + } > if (!created_at) > { > log_error (_("creation timestamp missing\n")); > err = gpg_error (GPG_ERR_INV_VALUE); > goto leave; > } > + if (flag_eddsa && keyno != 1) > + algo = PUBKEY_ALGO_EDDSA; > + else if (keyno == 1) > + algo = PUBKEY_ALGO_ECDH; > + else > + algo = PUBKEY_ALGO_ECDSA; > + > + if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC > + || app->app_local->keyattr[keyno].ecc.oid != oidstr > + || app->app_local->keyattr[keyno].ecc.flags != flag_eddsa) > + { > + log_error ("key attribute on card doesn't match\n"); > + err = gpg_error (GPG_ERR_INV_VALUE); > + goto leave; > + } > > if (opt.verbose) > log_info ("ECC private key size is %u bytes\n", (unsigned > int)ecc_d_len); > @@ -3411,6 +3325,8 @@ ecc_writekey (app_t app, gpg_error_t > (*pincb)(void*, const char *, char **), > { > /* Build the private key template as described in section > 4.3.3.7 of > the OpenPGP card specs version 2.0. */ > + unsigned char *template; > + size_t template_len; > int exmode; > > err = build_ecc_privkey_template (app, keyno, > @@ -3422,7 +3338,10 @@ ecc_writekey (app_t app, gpg_error_t > (*pincb)(void*, const char *, char **), > /* Prepare for storing the key. */ > err = verify_chv3 (app, pincb, pincb_arg); > if (err) > - goto leave; > + { > + xfree (template); > + goto leave; > + } > > /* Store the key. */ > if (app->app_local->cardcap.ext_lc_le && template_len > 254) > @@ -3433,32 +3352,41 @@ ecc_writekey (app_t app, gpg_error_t > (*pincb)(void*, const char *, char **), > exmode = 0; > err = iso7816_put_data_odd (app->slot, exmode, 0x3fff, > template, template_len); > + xfree (template); > } > else > - return gpg_error (GPG_ERR_NOT_SUPPORTED); > + err = gpg_error (GPG_ERR_NOT_SUPPORTED); > > if (err) > { > log_error (_("failed to store the key: %s\n"), gpg_strerror > (err)); > goto leave; > } > + else > + { > + gcry_mpi_t oid; > + const unsigned char *oidbuf; > + size_t oid_len; > + unsigned char fprbuf[20]; > > - err = store_fpr (app, keyno, created_at, fprbuf, > - curve == CURVE_ED25519 ? KEY_TYPE_EDDSA : > KEY_TYPE_ECC, > - 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" > - : "\x05\x2b\x81\x04\x00\x0a", > - (size_t)(curve == CURVE_ED25519 ? 10 > - : curve == CURVE_NIST_P256? 9 : 6), > - ecc_q, ecc_q_len, "\x03\x01\x08\x07", (size_t)4); > - if (err) > - goto leave; > + err = openpgp_oid_from_str (oidstr, &oid); > + if (err) > + goto leave; > > + oidbuf = gcry_mpi_get_opaque (oid, &oid_len); > + if (!oidbuf) > + { > + err = gpg_error_from_syserror (); > + gcry_mpi_release (oid); > + goto leave; > + } > + err = store_fpr (app, keyno, created_at, fprbuf, algo, > + oidbuf, oid_len, ecc_q, ecc_q_len, > + "\x03\x01\x08\x07", (size_t)4); > + gcry_mpi_release (oid); > + } > > leave: > - xfree (template); > return err; > } > > @@ -3661,7 +3589,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char > *keynostr, unsigned int flags, > send_status_info (ctrl, "KEY-CREATED-AT", > numbuf, (size_t)strlen(numbuf), NULL, 0); > > - rc = store_fpr (app, keyno, (u32)created_at, fprbuf, KEY_TYPE_RSA, > + rc = store_fpr (app, keyno, (u32)created_at, fprbuf, > PUBKEY_ALGO_RSA, > m, mlen, e, elen); > if (rc) > goto leave; > @@ -4014,18 +3942,21 @@ do_auth (app_t app, const char *keyidstr, > && indatalen > 101) /* For a 2048 bit key. */ > return gpg_error (GPG_ERR_INV_VALUE); > > - if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECC > - && (indatalen == 51 || indatalen == 67 || indatalen == 83)) > + if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECC) > { > - const char *p = (const char *)indata + 19; > - 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; > + if (!app->app_local->keyattr[2].ecc.flags > + && (indatalen == 51 || indatalen == 67 || indatalen == 83)) > + { > + const char *p = (const char *)indata + 19; > + indata = p; > + indatalen -= 19; > + } > + else > + { > + const char *p = (const char *)indata + 15; > + indata = p; > + indatalen -= 15; > + } > } > > /* Check whether an OpenPGP card of any version has been requested. > */ > @@ -4429,25 +4360,25 @@ parse_historical (struct app_local_s *apploc, > } > > > -static int > -parse_ecc_curve (const unsigned char *buffer, size_t buflen) > +static const char * > +ecc_oid (unsigned char *buf, size_t buflen) > { > - int curve; > + gcry_mpi_t oid; > + char *oidstr; > + const char *result; > > - if (buflen == 5 && buffer[5] == 0x22) > - curve = CURVE_NIST_P384; > - else if (buflen == 5 && buffer[5] == 0x23) > - curve = CURVE_NIST_P521; > - else if (buflen == 8) > - curve = CURVE_NIST_P256; > - else if (buflen == 5 && buffer[5] == 0x0a) > - curve = CURVE_SEC_P256K1; > - else if (buflen == 9) > - curve = CURVE_ED25519; > - else > - curve = CURVE_UNKNOWN; > + oid = gcry_mpi_set_opaque (NULL, buf, buflen * 8); > + if (!oid) > + return NULL; > > - return curve; > + oidstr = openpgp_oid_to_str (oid); > + gcry_mpi_release (oid); > + if (!oidstr) > + return NULL; > + > + result = openpgp_curve_to_oid (oidstr, NULL); > + xfree (oidstr); > + return result; > } > > > @@ -4505,25 +4436,16 @@ parse_algorithm_attribute (app_t app, int > keyno) > app->app_local->keyattr[keyno].rsa.format == RSA_CRT? > "crt" : > app->app_local->keyattr[keyno].rsa.format == > RSA_CRT_N?"crt+n":"?"); > } > - else if (*buffer == PUBKEY_ALGO_ECDH || *buffer == > PUBKEY_ALGO_ECDSA) > + else if (*buffer == PUBKEY_ALGO_ECDH || *buffer == PUBKEY_ALGO_ECDSA > + || *buffer == PUBKEY_ALGO_EDDSA) > { > app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECC; > - app->app_local->keyattr[keyno].ecc.curve > - = parse_ecc_curve (buffer + 1, buflen - 1); > + app->app_local->keyattr[keyno].ecc.oid = ecc_oid (buffer + 1, > buflen - 1); > + app->app_local->keyattr[keyno].ecc.flags = (*buffer == > PUBKEY_ALGO_EDDSA); > if (opt.verbose) > log_printf > - ("ECC, curve=%s\n", > - get_curve_name (app->app_local->keyattr[keyno].ecc.curve)); > - } > - else if (*buffer == PUBKEY_ALGO_EDDSA) > - { > - app->app_local->keyattr[keyno].key_type = KEY_TYPE_EDDSA; > - app->app_local->keyattr[keyno].eddsa.curve > - = parse_ecc_curve (buffer + 1, buflen - 1); > - if (opt.verbose) > - log_printf > - ("EdDSA, curve=%s\n", > - get_curve_name > (app->app_local->keyattr[keyno].eddsa.curve)); > + ("ECC, curve=%s%s\n", > app->app_local->keyattr[keyno].ecc.oid, > + app->app_local->keyattr[keyno].ecc.flags ? " (eddsa)": ""); > } > else if (opt.verbose) > log_printhex ("", buffer, buflen); -- Bertrand From gniibe at fsij.org Mon Aug 17 06:47:03 2015 From: gniibe at fsij.org (NIIBE Yutaka) Date: Mon, 17 Aug 2015 13:47:03 +0900 Subject: [PATCH] scd: support any curves defined by libgcrypt. In-Reply-To: <1fddfe3daeaaecb1060409738c070115@mail.meleeweb.net> References: mid:6111 <1fddfe3daeaaecb1060409738c070115@mail.meleeweb.net> Message-ID: <55D16747.8020004@fsij.org> Hello, Thank you for the detailed report. On 08/17/2015 09:10 AM, Bertrand Jacquin wrote: > This patch introduce as issue with OpenGPG Card FTS-01. I've run a > git bisect to be able to point that particular commit. > > I have a FTS-01 OpenGPG card with a EdDSA sign key and a EdDSA auth > key and using gpg-agent as a ssh agent. Since that particular > commit, info given by gpg-agent to ssh-add are not conform for ssh: > > Is there a need to use a particular libgcrypt version ? No, it's not required for EdDSA. If you use encryption (ECDH with Curve25519), you need to use the development version of libgcrypt, though. I also noticed the failure on my side, and I posted: SSH with ed25519: https://lists.gnupg.org/pipermail/gnupg-devel/2015-August/030224.html If I understand correctly, the problem is in the code of general EdDSA with SSH (I mean, including the private key in a host, as well as the one in smartcard). My change for scdaemon unveiled this issue. EdDSA with FST-01 just worked before, because of the public key representation from scdaemon didn't include the prefix of 0x40. My change of scdaemon for the support of more curves "fix"-ed to be proper representation between scdaemon<->gpg-agent and it now include the prefix of 0x40. I think that correct fix should be to the code in general EdDSA with SSH (not reverting a part of my change of scdaemon). The change in the post of mine works, but it's not good fix. This is basically to point out the issue. We need to confirm that gpg-agent handles EdDSA key with the representation of the prefix 0x40, and it is correct for its SSH handling to remove the prefix. Sorry, for your inconvenience. -- From andrei.macavei89 at gmail.com Mon Aug 17 15:06:44 2015 From: andrei.macavei89 at gmail.com (Andrei Macavei) Date: Mon, 17 Aug 2015 16:06:44 +0300 Subject: GPGME export secret key In-Reply-To: <55D1B02A.7050601@gmail.com> References: <55D1B02A.7050601@gmail.com> Message-ID: <55D1DC64.30701@gmail.com> Hello, Following this old topic (http://marc.info/?l=gnupg-devel&m=122054361932189&w=2) , about making an option to export private key in GPGME. Has this been fixed since then or is there any plan for adding this in the near future? Thank you, Andrei Macavei From bertrand at jacquin.bzh Wed Aug 19 00:15:45 2015 From: bertrand at jacquin.bzh (Bertrand Jacquin) Date: Tue, 18 Aug 2015 23:15:45 +0100 Subject: [PATCH] scd: support any curves defined by libgcrypt. In-Reply-To: <55D16747.8020004@fsij.org> References: mid:6111 <1fddfe3daeaaecb1060409738c070115@mail.meleeweb.net> <55D16747.8020004@fsij.org> Message-ID: <60aa0a6abc4d221f06a05df65b3a39b4@mail.meleeweb.net> HI, On 17/08/2015 05:47, NIIBE Yutaka wrote: > Hello, > > Thank you for the detailed report. > > On 08/17/2015 09:10 AM, Bertrand Jacquin wrote: >> This patch introduce as issue with OpenGPG Card FTS-01. I've run a >> git bisect to be able to point that particular commit. >> >> I have a FTS-01 OpenGPG card with a EdDSA sign key and a EdDSA auth >> key and using gpg-agent as a ssh agent. Since that particular >> commit, info given by gpg-agent to ssh-add are not conform for ssh: >> >> Is there a need to use a particular libgcrypt version ? > > No, it's not required for EdDSA. If you use encryption (ECDH with > Curve25519), you need to use the development version of libgcrypt, > though. > > I also noticed the failure on my side, and I posted: > > SSH with ed25519: > > https://lists.gnupg.org/pipermail/gnupg-devel/2015-August/030224.html Thanks for having taking care of this. I can easily wait for that to be properly fixed. Thanks ! > If I understand correctly, the problem is in the code of general EdDSA > with SSH (I mean, including the private key in a host, as well as the > one in smartcard). My change for scdaemon unveiled this issue. > > EdDSA with FST-01 just worked before, because of the public key > representation from scdaemon didn't include the prefix of 0x40. > > My change of scdaemon for the support of more curves "fix"-ed to be > proper representation between scdaemon<->gpg-agent and it now include > the prefix of 0x40. > > I think that correct fix should be to the code in general EdDSA with > SSH (not reverting a part of my change of scdaemon). > > The change in the post of mine works, but it's not good fix. This is > basically to point out the issue. We need to confirm that gpg-agent > handles EdDSA key with the representation of the prefix 0x40, and > it is correct for its SSH handling to remove the prefix. > > Sorry, for your inconvenience. -- Bertrand From bertrand at jacquin.bzh Wed Aug 19 23:27:50 2015 From: bertrand at jacquin.bzh (Bertrand Jacquin) Date: Wed, 19 Aug 2015 22:27:50 +0100 Subject: gpgsm --gen-key segfault with ECC key on smartcard Message-ID: <20150819212750.GA12535@lady-voodoo.scabb> Hi, I'm getting a SEGV running gpgsm --gen-key with GnuPG 2.1.6. The issue comes from libksba. Here is a backtrace: $ gpg --version gpg (GnuPG) 2.1.6 libgcrypt 1.6.3 $ gdb gpgsm GNU gdb (Gentoo 7.7.1 p1) 7.7.1 Copyright (C) 2014 Free Software Foundation, Inc. (gdb) r --gen-key Starting program: /usr/bin/gpgsm --gen-key gpgsm (GnuPG) 2.1.6; Copyright (C) 2015 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Please select what kind of key you want: (1) RSA (2) Existing key (3) Existing key from card Your selection? 3 Serial number of the card: D276000124010200FFFE50FF6A060000 Available keys: (1) 1EE6350B308927412446FE9E39191C9A2107D817 OPENPGP.1 (2) 41AC7E51641A4053606B139F18FDD044D49C0CF1 OPENPGP.3 Your selection? 2 Possible actions for a RSA key: (1) sign, encrypt (2) sign (3) encrypt Your selection? 2 Enter the X.509 subject name: o=test Enter email addresses (end with an empty line): > test at test > Enter DNS names (optional; end with an empty line): > Enter URIs (optional; end with an empty line): > Create self-signed certificate? (y/N) These parameters are used: Key-Type: card:OPENPGP.3 Key-Length: 1024 Key-Usage: sign Name-DN: o=test Name-Email: test at test Proceed with creation? (y/N) y Now creating certificate request. This may take a while ... Program received signal SIGSEGV, Segmentation fault. 0x00007ffff76ba49c in get_ecc_curve_oid (buf=0x0, buflen=7, r_oidlen=r_oidlen at entry=0x7fffffffd070) at /usr/src/debug/dev-libs/libksba-1.3.3/libksba-1.3.3/src/keyinfo.c:328 328 buflen = strlen (curve_names[i].name); (gdb) bt #0 0x00007ffff76ba49c in get_ecc_curve_oid (buf=0x0, buflen=7, r_oidlen=r_oidlen at entry=0x7fffffffd070) at /usr/src/debug/dev-libs/libksba-1.3.3/libksba-1.3.3/src/keyinfo.c:328 #1 0x00007ffff76d5683 in _ksba_keyinfo_from_sexp (sexp=sexp at entry=0x69b000 "(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:\371_c\373\331|\237\062\253a\306\376\347\377\356\260\376`f\305r\333C\001\344?\346\370\224\034Y)))", r_der=0x69b908, r_derlen=0x69b910) at /usr/src/debug/dev-libs/libksba-1.3.3/libksba-1.3.3/src/keyinfo.c:1055 #2 0x00007ffff76cff54 in _ksba_certreq_set_public_key (cr=, key=key at entry=0x69b000 "(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:\371_c\373\331|\237\062\253a\306\376\347\377\356\260\376`f\305r\333C\001\344?\346\370\224\034Y)))") at /usr/src/debug/dev-libs/libksba-1.3.3/libksba-1.3.3/src/certreq.c:355 #3 0x00007ffff76bac85 in ksba_certreq_set_public_key (cr=, key=key at entry=0x69b000 "(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:\371_c\373\331|\237\062\253a\306\376\347\377\356\260\376`f\305r\333C\001\344?\346\370\224\034Y)))") at /usr/src/debug/dev-libs/libksba-1.3.3/libksba-1.3.3/src/visibility.c:888 #4 0x0000000000425b3a in create_request (writer=, sigkey=0x0, public=0x69b000 "(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:\371_c\373\331|\237\062\253a\306\376\347\377\356\260\376`f\305r\333C\001\344?\346\370\224\034Y)))", carddirect=0x696980 "OPENPGP.3", para=0x673ac0, ctrl=0x7fffffffdb40) at /usr/src/debug/app-crypt/gnupg-2.1.6/gnupg-2.1.6/sm/certreqgen.c:909 #5 proc_parameters (ctrl=ctrl at entry=0x7fffffffdb40, para=para at entry=0x673ac0, out_fp=out_fp at entry=0x671940, outctrl=outctrl at entry=0x7fffffffd460) at /usr/src/debug/app-crypt/gnupg-2.1.6/gnupg-2.1.6/sm/certreqgen.c:752 #6 0x0000000000426fa8 in read_parameters (ctrl=ctrl at entry=0x7fffffffdb40, fp=fp at entry=0x696ec0, out_fp=out_fp at entry=0x671940) at /usr/src/debug/app-crypt/gnupg-2.1.6/gnupg-2.1.6/sm/certreqgen.c:390 #7 0x00000000004270bb in gpgsm_genkey (ctrl=ctrl at entry=0x7fffffffdb40, in_stream=in_stream at entry=0x696ec0, out_stream=out_stream at entry=0x671940) at /usr/src/debug/app-crypt/gnupg-2.1.6/gnupg-2.1.6/sm/certreqgen.c:1361 #8 0x0000000000427924 in gpgsm_gencertreq_tty (ctrl=ctrl at entry=0x7fffffffdb40, output_stream=output_stream at entry=0x671940) at /usr/src/debug/app-crypt/gnupg-2.1.6/gnupg-2.1.6/sm/certreqgen-ui.c:408 #9 0x000000000040a66a in main (argc=0, argv=0x7fffffffdce8) at /usr/src/debug/app-crypt/gnupg-2.1.6/gnupg-2.1.6/sm/gpgsm.c:1895 (gdb) fr 0 #0 0x00007ffff76ba49c in get_ecc_curve_oid (buf=0x0, buflen=7, r_oidlen=r_oidlen at entry=0x7fffffffd070) at /usr/src/debug/dev-libs/libksba-1.3.3/libksba-1.3.3/src/keyinfo.c:328 328 buflen = strlen (curve_names[i].name); (gdb) info args buf = 0x0 buflen = 7 r_oidlen = 0x7fffffffd070 (gdb) print curve_names $1 = {{ oid = 0x7ffff76dc3c0 "1.2.840.10045.3.1.1", name = 0x7ffff76dc3d4 "NIST P-192" }, { oid = 0x7ffff76dc3c0 "1.2.840.10045.3.1.1", name = 0x7ffff76dc3df "prime192v1" }, { oid = 0x7ffff76dc3c0 "1.2.840.10045.3.1.1", name = 0x7ffff76dc3ea "secp192r1" }, { oid = 0x7ffff76dc3f4 "1.3.132.0.33", name = 0x7ffff76dc401 "secp224r1" }, { oid = 0x7ffff76dc40b "1.2.840.10045.3.1.7", name = 0x7ffff76dc41f "NIST P-256" }, { oid = 0x7ffff76dc40b "1.2.840.10045.3.1.7", name = 0x7ffff76dc42a "prime256v1" }, { oid = 0x7ffff76dc40b "1.2.840.10045.3.1.7", name = 0x7ffff76dc435 "secp256r1" }, { oid = 0x7ffff76dc43f "1.3.132.0.34", name = 0x7ffff76dc44c "secp384r1" }, { oid = 0x7ffff76dc456 "1.3.132.0.35", name = 0x7ffff76dc463 "secp521r1" }, { oid = 0x7ffff76dc46d "1.3.36.3.3.2.8.1.1.1", name = 0x7ffff76dc482 "brainpoolP160r1" }, { oid = 0x7ffff76dc492 "1.3.36.3.3.2.8.1.1.3", name = 0x7ffff76dc4a7 "brainpoolP192r1" }, { oid = 0x7ffff76dc4b7 "1.3.36.3.3.2.8.1.1.5", name = 0x7ffff76dc4cc "brainpoolP224r1" }, { oid = 0x7ffff76dc4dc "1.3.36.3.3.2.8.1.1.7", name = 0x7ffff76dc4f1 "brainpoolP256r1" }, { oid = 0x7ffff76dc501 "1.3.36.3.3.2.8.1.1.9", name = 0x7ffff76dc516 "brainpoolP320r1" }, { oid = 0x7ffff76dc526 "1.3.36.3.3.2.8.1.1.11", name = 0x7ffff76dc53c "brainpoolP384r1" }, { oid = 0x7ffff76dc54c "1.3.36.3.3.2.8.1.1.13", name = 0x7ffff76dc562 "brainpoolP512r1" }, { oid = 0x0, name = 0x0 }} (gdb) print i $2 = (gdb) print buflen $3 = 7 (gdb) fr 1 #1 0x00007ffff76d5683 in _ksba_keyinfo_from_sexp (sexp=sexp at entry=0x69b000 "(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:\371_c\373\331|\237\062\253a\306\376\347\377\356\260\376`f\305r\333C\001\344?\346\370\224\034Y)))", r_der=0x69b908, r_derlen=0x69b910) at /usr/src/debug/dev-libs/libksba-1.3.3/libksba-1.3.3/src/keyinfo.c:1055 1055 curve_oid = get_ecc_curve_oid (parm[idxtbl[0]].value, (gdb) info args sexp = 0x69b000 "(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:\371_c\373\331|\237\062\253a\306\376\347\377\356\260\376`f\305r\333C\001\344?\346\370\224\034Y)))" r_der = 0x69b908 r_derlen = 0x69b910 (gdb) fr 2 #2 0x00007ffff76cff54 in _ksba_certreq_set_public_key (cr=, key=key at entry=0x69b000 "(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:\371_c\373\331|\237\062\253a\306\376\347\377\356\260\376`f\305r\333C\001\344?\346\370\224\034Y)))") at /usr/src/debug/dev-libs/libksba-1.3.3/libksba-1.3.3/src/certreq.c:355 355 return _ksba_keyinfo_from_sexp (key, &cr->key.der, &cr->key.derlen); (gdb) info args cr = key = 0x69b000 "(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:\371_c\373\331|\237\062\253a\306\376\347\377\356\260\376`f\305r\333C\001\344?\346\370\224\034Y)))" (gdb) fr 3 #3 0x00007ffff76bac85 in ksba_certreq_set_public_key (cr=, key=key at entry=0x69b000 "(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:\371_c\373\331|\237\062\253a\306\376\347\377\356\260\376`f\305r\333C\001\344?\346\370\224\034Y)))") at /usr/src/debug/dev-libs/libksba-1.3.3/libksba-1.3.3/src/visibility.c:888 888 return _ksba_certreq_set_public_key (cr, key); (gdb) info args cr = key = 0x69b000 "(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:\371_c\373\331|\237\062\253a\306\376\347\377\356\260\376`f\305r\333C\001\344?\346\370\224\034Y)))" (gdb) fr 4 #4 0x0000000000425b3a in create_request (writer=, sigkey=0x0, public=0x69b000 "(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:\371_c\373\331|\237\062\253a\306\376\347\377\356\260\376`f\305r\333C\001\344?\346\370\224\034Y)))", carddirect=0x696980 "OPENPGP.3", para=0x673ac0, ctrl=0x7fffffffdb40) at /usr/src/debug/app-crypt/gnupg-2.1.6/gnupg-2.1.6/sm/certreqgen.c:909 909 err = ksba_certreq_set_public_key (cr, public); (gdb) info args writer = sigkey = 0x0 public = 0x69b000 "(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:\371_c\373\331|\237\062\253a\306\376\347\377\356\260\376`f\305r\333C\001\344?\346\370\224\034Y)))" carddirect = 0x696980 "OPENPGP.3" para = 0x673ac0 ctrl = 0x7fffffffdb40 (gdb) fr 5 #5 proc_parameters (ctrl=ctrl at entry=0x7fffffffdb40, para=para at entry=0x673ac0, out_fp=out_fp at entry=0x671940, outctrl=outctrl at entry=0x7fffffffd460) at /usr/src/debug/app-crypt/gnupg-2.1.6/gnupg-2.1.6/sm/certreqgen.c:752 752 rc = create_request (ctrl, para, cardkeyid, public, sigkey, writer); (gdb) info args ctrl = 0x7fffffffdb40 para = 0x673ac0 out_fp = 0x671940 outctrl = 0x7fffffffd460 (gdb) fr 6 #6 0x0000000000426fa8 in read_parameters (ctrl=ctrl at entry=0x7fffffffdb40, fp=fp at entry=0x696ec0, out_fp=out_fp at entry=0x671940) at /usr/src/debug/app-crypt/gnupg-2.1.6/gnupg-2.1.6/sm/certreqgen.c:390 390 rc = proc_parameters (ctrl, para, out_fp, &outctrl); (gdb) info args ctrl = 0x7fffffffdb40 fp = 0x696ec0 out_fp = 0x671940 (gdb) fr 7 #7 0x00000000004270bb in gpgsm_genkey (ctrl=ctrl at entry=0x7fffffffdb40, in_stream=in_stream at entry=0x696ec0, out_stream=out_stream at entry=0x671940) at /usr/src/debug/app-crypt/gnupg-2.1.6/gnupg-2.1.6/sm/certreqgen.c:1361 1361 rc = read_parameters (ctrl, in_stream, out_stream); (gdb) info args ctrl = 0x7fffffffdb40 in_stream = 0x696ec0 out_stream = 0x671940 (gdb) fr 8 #8 0x0000000000427924 in gpgsm_gencertreq_tty (ctrl=ctrl at entry=0x7fffffffdb40, output_stream=output_stream at entry=0x671940) at /usr/src/debug/app-crypt/gnupg-2.1.6/gnupg-2.1.6/sm/certreqgen-ui.c:408 408 err = gpgsm_genkey (ctrl, fp, output_stream); (gdb) info args ctrl = 0x7fffffffdb40 output_stream = 0x671940 (gdb) fr 9 #9 0x000000000040a66a in main (argc=0, argv=0x7fffffffdce8) at /usr/src/debug/app-crypt/gnupg-2.1.6/gnupg-2.1.6/sm/gpgsm.c:1895 1895 gpgsm_gencertreq_tty (&ctrl, fpout); (gdb) info args argc = 0 argv = 0x7fffffffdce8 Is there any other information that I can provide ? Thanks, -- Bertrand -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 195 bytes Desc: Digital signature URL: From patrick at enigmail.net Tue Aug 25 08:19:43 2015 From: patrick at enigmail.net (Patrick Brunschwig) Date: Tue, 25 Aug 2015 08:19:43 +0200 Subject: Error with GnuPG 2.1.7 Binary Release Message-ID: <55DC08FF.3010206@enigmail.net> The binary release of GnuPG 2.1.7 for Windows (https://www.gnupg.org/ftp/gcrypt/binary/gnupg-w32-2.1.7_20150811.exe) seems to output wrong data during decryption. It looks like every CRLF in the decrypted data is decrypted as CRLF CRLF. Details can be found here: https://sourceforge.net/p/enigmail/forum/support/thread/155c911b/ -Patrick From Alexander.Strobel at giepa.de Tue Aug 25 09:09:21 2015 From: Alexander.Strobel at giepa.de (Alexander Strobel) Date: Tue, 25 Aug 2015 09:09:21 +0200 Subject: Error with GnuPG 2.1.7 Binary Release In-Reply-To: <55DC08FF.3010206@enigmail.net> References: <55DC08FF.3010206@enigmail.net> Message-ID: <55DC14A1.6010902@giepa.de> Looks like this is the same as bug 1973. (https://bugs.gnupg.org/gnupg/issue1973) Regards Alex Strobel www.gpg4o.com Am 25.08.2015 um 08:19 schrieb Patrick Brunschwig: > The binary release of GnuPG 2.1.7 for Windows > (https://www.gnupg.org/ftp/gcrypt/binary/gnupg-w32-2.1.7_20150811.exe) > seems to output wrong data during decryption. > > It looks like every CRLF in the decrypted data is decrypted as CRLF > CRLF. Details can be found here: > https://sourceforge.net/p/enigmail/forum/support/thread/155c911b/ > > -Patrick > > _______________________________________________ > Gnupg-devel mailing list > Gnupg-devel at gnupg.org > http://lists.gnupg.org/mailman/listinfo/gnupg-devel > From wk at gnupg.org Tue Aug 25 16:01:37 2015 From: wk at gnupg.org (Werner Koch) Date: Tue, 25 Aug 2015 16:01:37 +0200 Subject: Error with GnuPG 2.1.7 Binary Release In-Reply-To: <55DC08FF.3010206@enigmail.net> (Patrick Brunschwig's message of "Tue, 25 Aug 2015 08:19:43 +0200") References: <55DC08FF.3010206@enigmail.net> Message-ID: <87a8tftqke.fsf@vigenere.g10code.de> On Tue, 25 Aug 2015 08:19, patrick at enigmail.net said: > It looks like every CRLF in the decrypted data is decrypted as CRLF > CRLF. Details can be found here: Must be the case for all 2.1 versions. The reason is that in libgpg-error the macro HAVE_DOSISH_SYSTEM is not anymore defined but that is used to call setmode. I just pushed a fix to libgpg-error to fix that. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Tue Aug 25 19:17:10 2015 From: wk at gnupg.org (Werner Koch) Date: Tue, 25 Aug 2015 19:17:10 +0200 Subject: [PATCH gpgme] Relax ttyname_r error checks In-Reply-To: (Daiki Ueno's message of "Mon, 27 Jul 2015 16:19:52 +0900") References: Message-ID: <87wpwjs2y1.fsf@vigenere.g10code.de> On Mon, 27 Jul 2015 09:19, ueno at gnu.org said: > This patch was originally attached to: > https://lists.gnupg.org/pipermail/gnupg-devel/2015-July/030090.html Thanks. Will go into 1.6.0 Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Wed Aug 26 10:52:07 2015 From: wk at gnupg.org (Werner Koch) Date: Wed, 26 Aug 2015 10:52:07 +0200 Subject: [Announce] GPGME 1.6.0 released Message-ID: <87bndusa88.fsf@vigenere.g10code.de> Hello! We are pleased to announce version 1.6.0 of GPGME. GnuPG Made Easy (GPGME) is a C language library that allows to add support for cryptography to a program. It is designed to make access to public key crypto engines as included in GnuPG easier for applications. GPGME provides a high-level crypto API for encryption, decryption, signing, signature verification, and key management. * Noteworthy changes in version 1.6.0 - Added gpgme_set_offline to do a key listinging w/o requiring CRL. - Added gpgme_set_status_cb to allow a user to see some status messages. - Added an export mode for secret keys. - More precise error codes are returned if GnuPG >= 2.1.8 is used. - The passphrase handler for the loopback mode has been improved and may also be used with genkey. - [w32] The standard GnuPG 2.1 install directory is now seached for gpgconf.exe before a registry specified directory and the Gpg4win install directory. - [w32] gpgme-w32spawn.exe will now only be searched in the gpgme DLL directory. * Download You may download this library and its OpenPGP signature from: ftp://ftp.gnupg.org/gcrypt/gpgme/gpgme-1.6.0.tar.bz2 (961k) ftp://ftp.gnupg.org/gcrypt/gpgme/gpgme-1.6.0.tar.bz2.sig The SHA-1 checksum is 21510323495f6220f8f67610c3c27a23d761d43d gpgme-1.6.0.tar.bz2 * Support Please send questions regarding the use of GPGME to the gnupg-devel mailing list: https://lists.gnupg.org/mailman/listinfo/gnupg-devel/ If you need commercial support, you may want to consult this listing: https://gnupg.org/service.html For the GnuPG team, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 180 bytes Desc: not available URL: -------------- next part -------------- _______________________________________________ Gnupg-announce mailing list Gnupg-announce at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-announce From wk at gnupg.org Wed Aug 26 11:04:44 2015 From: wk at gnupg.org (Werner Koch) Date: Wed, 26 Aug 2015 11:04:44 +0200 Subject: [Announce] Libgpg-error 1.20 released Message-ID: <877fois9n7.fsf@vigenere.g10code.de> Hello! We are pleased to announce version 1.20 of Libgpg-error. Libgpg-error is a C language library to provides common error codes and a set useful functions. It is mainly used by GnuPG related software like GnuPG, GPGME, GPA, and Libgcrypt. * Noteworthy changes in version 1.20 - New macros for GCC attributes. - Make es_set_binary actually work for Windows. - Allow building without thread support. - Build without a build timestamp by default. * Download You may download this library and its OpenPGP signature from: ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.20.tar.bz2 (752k) ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.20.tar.bz2.sig The SHA-1 checksum is 89c961f63469739fe816a56dcdd86c2e1897cace libgpg-error-1.20.tar.bz2 * Support Please send questions regarding the use of Libgpg-error to the gnupg-devel mailing list: https://lists.gnupg.org/mailman/listinfo/gnupg-devel/ If you need commercial support, you may want to consult this listing: https://gnupg.org/service.html For the GnuPG team, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 180 bytes Desc: not available URL: -------------- next part -------------- _______________________________________________ Gnupg-announce mailing list Gnupg-announce at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-announce From astieger at suse.com Wed Aug 26 13:40:18 2015 From: astieger at suse.com (Andreas Stieger) Date: Wed, 26 Aug 2015 13:40:18 +0200 Subject: gpgme licence text updates Message-ID: <55DDA5A2.1060401@suse.com> Hello, some license text updates for your consideration. The following changes since commit c8e7870281950ae3b943c819147d4329198c0520: Post release updates (2015-08-26 10:16:39 +0200) are available in the git repository at: https://github.com/andreasstieger/gpgme license for you to fetch changes up to f748fed9f1a50f360eab2090c3f94b2051cf64d1: Update FSF address - code (2015-08-26 13:27:28 +0200) ---------------------------------------------------------------- Andreas Stieger (4): Use verbatim GPL-2.0 license text file Use verbatim LGPL-2.1 license text file Update FSF address - tests Update FSF address - code COPYING | 41 +++++++++++---------- COPYING.LESSER | 84 ++++++++++++++++++++------------------------ acinclude.m4 | 2 +- doc/Makefile.am | 2 +- doc/lesser.texi | 4 +-- lang/Makefile.am | 2 +- lang/cl/Makefile.am | 4 +-- lang/cl/gpgme-package.lisp | 2 +- lang/cl/gpgme.asd.in | 4 +-- lang/cl/gpgme.lisp | 2 +- m4/pkg.m4 | 2 +- src/ath-pthread.c | 4 +-- src/ath.c | 4 +-- src/ath.h | 4 +-- src/conversion.c | 4 +-- src/data-compat.c | 4 +-- src/data-fd.c | 4 +-- src/data-mem.c | 4 +-- src/data-stream.c | 4 +-- src/data-user.c | 4 +-- src/data.c | 4 +-- src/data.h | 4 +-- src/debug.h | 4 +-- src/decrypt-verify.c | 4 +-- src/decrypt.c | 4 +-- src/delete.c | 4 +-- src/edit.c | 4 +-- src/encrypt-sign.c | 4 +-- src/encrypt.c | 4 +-- src/engine-g13.c | 4 +-- src/engine-gpgsm.c | 4 +-- src/engine-uiserver.c | 4 +-- src/engine.h | 4 +-- src/error.c | 4 +-- src/funopen.c | 4 +-- src/genkey.c | 4 +-- src/get-env.c | 4 +-- src/gpgconf.c | 4 +-- src/gpgme.def | 2 +- src/import.c | 4 +-- src/isascii.c | 4 +-- src/key.c | 4 +-- src/ops.h | 4 +-- src/passphrase.c | 4 +-- src/posix-sema.c | 4 +-- src/posix-util.c | 4 +-- src/priv-io.h | 4 +-- src/progress.c | 4 +-- src/putc_unlocked.c | 4 +-- src/sema.h | 4 +-- src/setenv.c | 2 +- src/sig-notation.c | 4 +-- src/sign.c | 4 +-- src/signers.c | 4 +-- src/spawn.c | 4 +-- src/status-table.c | 4 +-- src/stpcpy.c | 4 +-- src/trust-item.c | 4 +-- src/trustlist.c | 4 +-- src/util.h | 4 +-- src/vasprintf.c | 4 +-- src/verify.c | 4 +-- src/version.c | 4 +-- src/vfs-create.c | 4 +-- src/vfs-mount.c | 4 +-- src/w32-ce.h | 4 +-- src/w32-glib-io.c | 4 +-- src/w32-io.c | 4 +-- src/w32-qt-io.cpp | 4 +-- src/w32-sema.c | 4 +-- src/wait-global.c | 4 +-- src/wait-private.c | 4 +-- src/wait-user.c | 4 +-- src/wait.c | 4 +-- src/wait.h | 4 +-- tests/gpg/Makefile.am | 2 +- tests/gpg/mkdemodirs.in | 2 +- tests/gpg/t-decrypt-verify.c | 4 +-- tests/gpg/t-decrypt.c | 4 +-- tests/gpg/t-edit.c | 4 +-- tests/gpg/t-encrypt-large.c | 4 +-- tests/gpg/t-encrypt-sign.c | 4 +-- tests/gpg/t-encrypt-sym.c | 4 +-- tests/gpg/t-encrypt.c | 4 +-- tests/gpg/t-eventloop.c | 4 +-- tests/gpg/t-export.c | 4 +-- tests/gpg/t-file-name.c | 4 +-- tests/gpg/t-genkey.c | 4 +-- tests/gpg/t-gpgconf.c | 4 +-- tests/gpg/t-import.c | 4 +-- tests/gpg/t-keylist-sig.c | 4 +-- tests/gpg/t-keylist.c | 4 +-- tests/gpg/t-sig-notation.c | 4 +-- tests/gpg/t-sign.c | 4 +-- tests/gpg/t-signers.c | 4 +-- tests/gpg/t-support.h | 4 +-- tests/gpg/t-thread1.c | 4 +-- tests/gpg/t-trustlist.c | 4 +-- tests/gpg/t-verify.c | 4 +-- tests/gpg/t-wait.c | 4 +-- tests/gpgsm/Makefile.am | 2 +- tests/gpgsm/t-decrypt.c | 4 +-- tests/gpgsm/t-encrypt.c | 4 +-- tests/gpgsm/t-export.c | 4 +-- tests/gpgsm/t-genkey.c | 4 +-- tests/gpgsm/t-import.c | 4 +-- tests/gpgsm/t-keylist.c | 4 +-- tests/gpgsm/t-sign.c | 4 +-- tests/gpgsm/t-support.h | 4 +-- tests/gpgsm/t-verify.c | 4 +-- tests/t-data.c | 4 +-- tests/t-engine-info.c | 4 +-- tests/t-version.c | 4 +-- 113 files changed, 269 insertions(+), 278 deletions(-) -- Andreas Stieger Project Manager Security SUSE Linux GmbH, GF: Felix Imend?rffer, Jane Smithard, Graham Norton, HRB 21284 (AG N?rnberg) From wk at gnupg.org Thu Aug 27 12:15:36 2015 From: wk at gnupg.org (Werner Koch) Date: Thu, 27 Aug 2015 12:15:36 +0200 Subject: gpgme licence text updates In-Reply-To: <55DDA5A2.1060401@suse.com> (Andreas Stieger's message of "Wed, 26 Aug 2015 13:40:18 +0200") References: <55DDA5A2.1060401@suse.com> Message-ID: <87egipqbp3.fsf@vigenere.g10code.de> On Wed, 26 Aug 2015 13:40, astieger at suse.com said: > some license text updates for your consideration. You may not update the text of the licence: Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. > Update FSF address - code (2015-08-26 13:27:28 +0200) We do this when we change something in the header blurb, but there is no reason to update the address in all files. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From astieger at suse.com Thu Aug 27 13:00:17 2015 From: astieger at suse.com (Andreas Stieger) Date: Thu, 27 Aug 2015 13:00:17 +0200 Subject: gpgme licence text updates In-Reply-To: <87egipqbp3.fsf@vigenere.g10code.de> References: <55DDA5A2.1060401@suse.com> <87egipqbp3.fsf@vigenere.g10code.de> Message-ID: <55DEEDC1.4070203@suse.com> Hello, On 08/27/2015 12:15 PM, Werner Koch wrote: > On Wed, 26 Aug 2015 13:40, astieger at suse.com said: > >> some license text updates for your consideration. > > You may not update the text of the licence: The updated text submitted *is* the license! It was updated by the FSF. You are versioning a previous edit. You can check yourself: wget -O COPYING https://www.gnu.org/licenses/gpl-2.0.txt wget -O COPYING.LESSER https://www.gnu.org/licenses/lgpl-2.1.txt Andreas -- Andreas Stieger Project Manager Security SUSE Linux GmbH, GF: Felix Imend?rffer, Jane Smithard, Graham Norton, HRB 21284 (AG N?rnberg) -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: OpenPGP digital signature URL: From wk at gnupg.org Fri Aug 28 15:18:24 2015 From: wk at gnupg.org (Werner Koch) Date: Fri, 28 Aug 2015 15:18:24 +0200 Subject: [Announce] Libassuan 2.3.0 released Message-ID: <878u8vmtzz.fsf@vigenere.g10code.de> Hello! The GnuPG Project is pleased to announce the availability of Libassuan 2.3.0. Libassuan is a generic IPC library used by GnuPG, GPGME, and a few other packages. This release fixes two bugs and introduces new support functions for the socket wrappers. Noteworthy changes in version 2.3.0 =================================== * Now wipes out the memory of the context structure before freeing. The context may have stored sensitive data in its line buffers. * Fixed a problem with the data length limit in assuan_inquire. * Returns GPG_ERR_SOURCE_ASSUAN with errors from functions w/o a context. * Two new functions to tweak the behaviour of the socket wrappers. * Experimental code to support Cygwin's local sockets. * By default build without a build timestamp. * Interface changes relative to the 2.2.1 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ assuan_sock_set_flag NEW. assuan_sock_get_flag NEW. Getting the Software ==================== You may download the library and its OpenPGP signature from ftp://ftp.gnupg.org/gcrypt/libassuan/libassuan-2.3.0.tar.bz2 (531k) ftp://ftp.gnupg.org/gcrypt/libassuan/libassuan-2.3.0.tar.bz2.sig or https://gnupg.org/ftp/gcrypt/libassuan/libassuan-2.3.0.tar.bz2 (531k) https://gnupg.org/ftp/gcrypt/libassuan/libassuan-2.3.0.tar.bz2.sig The SHA-1 checksum is: 23f7ea010983b869f765c36d169dec51c8296cff libassuan-2.3.0.tar.bz2 Documentation ============= The file assuan.info has the complete manual of the library. It is also possible to read the manual online at https://gnupg.org/documentation/manuals/assuan/ or as PDF at https://gnupg.org/documentation/manuals/assuan.pdf You can search the GnuPG mailing list archives or ask on the gnupg-devel mailing list for advise on how to use Libassuan. Support ======== Please consult the archive of the gnupg-devel mailing list before reporting a bug . We suggest to send bug reports for a new release to this list in favor of filing a bug at . For commercial support requests we keep a list of known service companies at: https://gnupg.org/service.html If you are a developer and you may need a certain feature for your project, please do not hesitate to bring it to the gnupg-devel mailing list for discussion. Thanks ====== We have to thank all the people who helped with this release, be it testing, coding, translating, suggesting, auditing, administering the servers, spreading the word, and answering questions on the mailing lists. Maintenance and development of GnuPG and related software is possible due to many individual and corporate donations; for a list of non-anonymous donors see . For the GnuPG hackers, Werner p.s. This is a announcement only mailing list. Please send replies only to the gnupg-devel 'at' gnupg.org mailing list. -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 180 bytes Desc: not available URL: -------------- next part -------------- _______________________________________________ Gnupg-announce mailing list Gnupg-announce at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-announce From jan at nitrokey.com Fri Aug 28 16:06:28 2015 From: jan at nitrokey.com (Jan Suhr) Date: Fri, 28 Aug 2015 16:06:28 +0200 Subject: exclusive vs. shared smart card access In-Reply-To: <87io81qbyb.fsf@vigenere.g10code.de> References: <0507f793213856ea05955bfbeee9d117@suhr.org> <87io81qbyb.fsf@vigenere.g10code.de> Message-ID: <55E06AE4.3020903@nitrokey.com> Hi Niibe and who it may concern! This issue has been discussed previously but since Werner seems to be positive about it now, I will give it another try: GnuPG uses an exclusive mode when accessing OpenPGP Cards. This prevents, or at least makes it complicated, to use OpenPGP Cards with GPG and other applications on the same system. In fact it is a repeating problem Nitrokey users are reporting. To my knowledge most other software (e.g. OpenSC, PKCS#11 drivers) use shared access rather than exclusive access. It seems to be best practice. We tested GPG in shared mode for several weeks and couldn't find any issue. Also the performance seems to be identical. Hence I would like to request changing smart card access to shared mode. The necessary modification is simple: Change the third parameter of pcsc_connect() from PCSC_SHARE_EXCLUSIVE to PCSC_SHARE_SHARED at: GPG 1.4: Once in g10/apdu.c GPG 2.0: Once in scd/apdu.c and twice in scd/pcsc-wrapper.c GPG 2.1: Once in scd/apdu.c Best regards, Jan From jacob at appelbaum.net Sat Aug 29 15:12:12 2015 From: jacob at appelbaum.net (Jacob Appelbaum) Date: Sat, 29 Aug 2015 13:12:12 +0000 Subject: exclusive vs. shared smart card access In-Reply-To: <55E06AE4.3020903@nitrokey.com> References: <0507f793213856ea05955bfbeee9d117@suhr.org> <87io81qbyb.fsf@vigenere.g10code.de> <55E06AE4.3020903@nitrokey.com> Message-ID: Dear Jan, On 8/28/15, Jan Suhr wrote: > Hi Niibe and who it may concern! > This issue has been discussed previously but since Werner seems to be > positive about it now, I will give it another try: > > GnuPG uses an exclusive mode when accessing OpenPGP Cards. This > prevents, or at least makes it complicated, to use OpenPGP Cards with > GPG and other applications on the same system. In fact it is a repeating > problem Nitrokey users are reporting. To my knowledge most other > software (e.g. OpenSC, PKCS#11 drivers) use shared access rather than > exclusive access. It seems to be best practice. > > We tested GPG in shared mode for several weeks and couldn't find any > issue. Also the performance seems to be identical. Hence I would like to > request changing smart card access to shared mode. > > The necessary modification is simple: Change the third parameter of > pcsc_connect() from PCSC_SHARE_EXCLUSIVE to PCSC_SHARE_SHARED at: > GPG 1.4: Once in g10/apdu.c > GPG 2.0: Once in scd/apdu.c and twice in scd/pcsc-wrapper.c > GPG 2.1: Once in scd/apdu.c What are the security considerations of this change? Would this allow one application to auth to the card and another application to perform operations, for example? If not, has anyone confirmed that? All the best, Jacob From gniibe at fsij.org Mon Aug 31 08:21:58 2015 From: gniibe at fsij.org (NIIBE Yutaka) Date: Mon, 31 Aug 2015 15:21:58 +0900 Subject: agent: Fix SSH public key for EdDSA. (was: SSH with ed25519) In-Reply-To: <55CB4E33.9090900@fsij.org> References: <55CB4E33.9090900@fsij.org> Message-ID: <55E3F286.7060003@fsij.org> On 08/12/2015 10:46 PM, NIIBE Yutaka wrote: > I forgot when I tested OpenSSH with Ed25519, it worked at that > time. Today, I needed a patch like this: > > diff --git a/agent/command-ssh.c b/agent/command-ssh.c > index 2a3037c..7526634 100644 > --- a/agent/command-ssh.c > +++ b/agent/command-ssh.c > @@ -1964,6 +1964,11 @@ ssh_key_to_blob (gcry_sexp_t sexp, int with_secret, > err = gpg_error (GPG_ERR_INV_SEXP); > goto out; > } > + if (data[0] == 0x40) > + { > + data++; > + datalen--; > + } > err = stream_write_string (stream, data, datalen); > if (err) > goto out; I committed following fix. Since the function ssh_key_to_blob can be called WITH_SECRET=1, we need to distinguish elements. * agent/command-ssh.c (ssh_key_to_blob): Remove the prefix 0x40. diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 3d29f97..689241f 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -1964,6 +1964,11 @@ ssh_key_to_blob (gcry_sexp_t sexp, int with_secret, err = gpg_error (GPG_ERR_INV_SEXP); goto out; } + if (*p_elems == 'q') + { /* Remove the prefix 0x40. */ + data++; + datalen--; + } err = stream_write_string (stream, data, datalen); if (err) goto out; -- From jan at nitrokey.com Mon Aug 31 18:11:50 2015 From: jan at nitrokey.com (Jan Suhr) Date: Mon, 31 Aug 2015 18:11:50 +0200 Subject: exclusive vs. shared smart card access In-Reply-To: References: <0507f793213856ea05955bfbeee9d117@suhr.org> <87io81qbyb.fsf@vigenere.g10code.de> <55E06AE4.3020903@nitrokey.com> Message-ID: Dear Jacob, Am 29.08.2015 15:12, schrieb Jacob Appelbaum: > Dear Jan, > > On 8/28/15, Jan Suhr wrote: >> Hi Niibe and who it may concern! >> This issue has been discussed previously but since Werner seems to be >> positive about it now, I will give it another try: >> >> GnuPG uses an exclusive mode when accessing OpenPGP Cards. This >> prevents, or at least makes it complicated, to use OpenPGP Cards with >> GPG and other applications on the same system. In fact it is a >> repeating >> problem Nitrokey users are reporting. To my knowledge most other >> software (e.g. OpenSC, PKCS#11 drivers) use shared access rather than >> exclusive access. It seems to be best practice. >> >> We tested GPG in shared mode for several weeks and couldn't find any >> issue. Also the performance seems to be identical. Hence I would like >> to >> request changing smart card access to shared mode. >> >> The necessary modification is simple: Change the third parameter of >> pcsc_connect() from PCSC_SHARE_EXCLUSIVE to PCSC_SHARE_SHARED at: >> GPG 1.4: Once in g10/apdu.c >> GPG 2.0: Once in scd/apdu.c and twice in scd/pcsc-wrapper.c >> GPG 2.1: Once in scd/apdu.c > > What are the security considerations of this change? Would this allow > one application to auth to the card and another application to perform > operations, for example? If not, has anyone confirmed that? This would probably be possible. However, a malicious application would be able to phish the PIN by presenting a fake PIN entry dialog and do all sorts of bad things with the smart card, nomatter if shared or exclusive mode. Such applications shouldn't get access to the smart card in the first place. I think we will end up with better security for the user by reducing usability obstacles and making smart card usage a pleasant user experience. Again, shared access is best practice for all other smart card frameworks I'm aware of. Kind regards, Jan From jacob at appelbaum.net Mon Aug 31 18:20:14 2015 From: jacob at appelbaum.net (Jacob Appelbaum) Date: Mon, 31 Aug 2015 16:20:14 +0000 Subject: exclusive vs. shared smart card access In-Reply-To: References: <0507f793213856ea05955bfbeee9d117@suhr.org> <87io81qbyb.fsf@vigenere.g10code.de> <55E06AE4.3020903@nitrokey.com> Message-ID: Dear Jan, On 8/31/15, Jan Suhr wrote: > Dear Jacob, > > Am 29.08.2015 15:12, schrieb Jacob Appelbaum: >> Dear Jan, >> >> On 8/28/15, Jan Suhr wrote: >>> Hi Niibe and who it may concern! >>> This issue has been discussed previously but since Werner seems to be >>> positive about it now, I will give it another try: >>> >>> GnuPG uses an exclusive mode when accessing OpenPGP Cards. This >>> prevents, or at least makes it complicated, to use OpenPGP Cards with >>> GPG and other applications on the same system. In fact it is a >>> repeating >>> problem Nitrokey users are reporting. To my knowledge most other >>> software (e.g. OpenSC, PKCS#11 drivers) use shared access rather than >>> exclusive access. It seems to be best practice. >>> >>> We tested GPG in shared mode for several weeks and couldn't find any >>> issue. Also the performance seems to be identical. Hence I would like >>> to >>> request changing smart card access to shared mode. >>> >>> The necessary modification is simple: Change the third parameter of >>> pcsc_connect() from PCSC_SHARE_EXCLUSIVE to PCSC_SHARE_SHARED at: >>> GPG 1.4: Once in g10/apdu.c >>> GPG 2.0: Once in scd/apdu.c and twice in scd/pcsc-wrapper.c >>> GPG 2.1: Once in scd/apdu.c >> >> What are the security considerations of this change? Would this allow >> one application to auth to the card and another application to perform >> operations, for example? If not, has anyone confirmed that? > > This would probably be possible. However, a malicious application would > be able to phish the PIN by presenting a fake PIN entry dialog and do > all sorts of bad things with the smart card, nomatter if shared or > exclusive mode. Such applications shouldn't get access to the smart card > in the first place. I think we will end up with better security for the > user by reducing usability obstacles and making smart card usage a > pleasant user experience. > It sounds like there is a problem with the authentication protocol for the card, doesn't it? If it is indeed possible to have one application authenticate while another application uses the card as an oracle, I'd be worried about enabling such a mode. It is true that people can present a false dialog box but it is another thing entirely if they simply need to wait and will win every time. > Again, shared access is best practice for all other smart card > frameworks I'm aware of. I feel like I must not understand something or something is very wrong with the best practices. Sorry if I'm not understanding correctly... All the best, Jacob