diff options
108 files changed, 3618 insertions, 902 deletions
@@ -38,15 +38,194 @@ List of Copyright holders Authors with a FSF copyright assignment ======================================= -The list of authors who signed a FSF copyright assignment is kept in -the GIT master branch's copy of this file. +Ales Nyakhaychyk <[email protected]> Translations [be] + +Andrey Jivsov <[email protected]> Assigns past and future changes for ECC. + (g10/ecdh.c. other changes to support ECC) + +Ben Kibbey <[email protected]> Assigns past and future changes. + +Birger Langkjer <[email protected]> Translations [da] + +Maxim Britov <[email protected]> Translations [ru] + +Daniel Resare <[email protected]> Translations [sv] +Per Tunedal <[email protected]> Translations [sv] +Daniel Nylander <[email protected]> Translations [sv] + +Daiki Ueno <[email protected]> Assigns Past and Future Changes. + (changed:passphrase.c and related code) + +David Shaw <[email protected]> Assigns past and future changes. + (all in keyserver/, + a lot of changes in g10/ see the ChangeLog, + bug fixes here and there) + +Dokianakis Theofanis <[email protected]> Translations [el] + +Edmund GRIMLEY EVANS <[email protected]> Translations [eo] + +Florian Weimer <[email protected]> Assigns past and future changes + (changed:g10/parse-packet.c, include/iobuf.h, util/iobuf.c) + +g10 Code GmbH <[email protected]> Assigns past and future changes + (all work since 2001 as indicated by mail addresses in ChangeLogs) + +Gaël Quéri <[email protected]> Translations [fr] + (fixed a lot of typos) + +Gregory Steuck <[email protected]> Translations [ru] + +Nagy Ferenc László <[email protected]> Translations [hu] + +Ivo Timmermans <[email protected]> Translations [nl] + +Jacobo Tarri'o Barreiro <[email protected]> Translations [gl] + +Janusz Aleksander Urbanowicz <[email protected]> Translations [pl] +Jakub Bogusz <[email protected]> Translations [pl] + +Jedi Lin <[email protected]> Translations [zh-tw] + +Jouni Hiltunen <[email protected]> Translations [fi] +Tommi Vainikainen <[email protected]> Translations [fi] + +Laurentiu Buzdugan <[email protected]> Translations [ro] + +Magda Procha'zkova' <[email protected]> Translations [cs] + +Michael Roth <[email protected]> Assigns changes. + (wrote cipher/des.c., changes and bug fixes all over the place) + +Michal Majer <[email protected]> Translations [sk] + +Marco d'Itri <[email protected]> Translations [it] + +Marcus Brinkmann <[email protected]> + (gpgconf and fixes all over the place) + +Matthew Skala <[email protected]> Disclaimer + (wrote cipher/twofish.c) + +Moritz Schulte <[email protected]> + (ssh support gpg-agent) + +Niklas Hernaeus <[email protected]> Disclaimer + (weak key patches) + +Nilgun Belma Buguner <[email protected]> Translations [tr] + +Nils Ellmenreich <nils 'at' infosun.fmi.uni-passau.de> + Assigns past and future changes + (configure.in, cipher/rndlinux.c, FAQ) + +Paul Eggert <[email protected]> + (configuration macros for LFS) + +Pavel I. Shajdo <[email protected]> Translations [ru] + (man pages) + +Pedro Morais <[email protected]> Translations [pt_PT] + +Rémi Guyomarch <[email protected]> Assigns past and future changes. + (g10/compress.c, g10/encr-data.c, + g10/free-packet.c, g10/mdfilter.c, g10/plaintext.c, util/iobuf.c) + +Stefan Bellon <[email protected]> Assigns past and future changes. + (All patches to support RISC OS) + +Timo Schulz <[email protected]> Assigns past and future changes. + (util/w32reg.c, g10/passphrase.c, g10/hkp.c) + +Tedi Heriyanto <[email protected]> Translations [id] + +Thiago Jung Bauermann <[email protected]> Translations [pt_BR] +Rafael Caetano dos Santos <[email protected]> Translations [pt_BR] + +Toomas Soome <[email protected]> Translations [et] + +Urko Lusa <[email protected]> Translations [es_ES] + +Walter Koch <[email protected]> Translations [de] + +Werner Koch <[email protected]> Assigns GNU Privacy Guard and future changes. + (started the whole thing, wrote the S/MIME extensions, the + smartcard daemon and the gpg-agent) + +Yosiaki IIDA <[email protected]> Translations [ja] + +Yuri Chornoivan, yurchor at ukr dot net: Translations [uk] + +Yutaka Niibe Assigns Past and Future Changes + (scd/) Authors with a DCO ================== -The list of authors who signed the Developer's Certificate of Origin -is kept in the GIT master branch's copy of this file. +Andre Heinecke <[email protected]> +2014-09-19:4525694.FcpLvWDUFT@esus: + +Andreas Schwier <[email protected]> +2014-07-22:[email protected]: + +Arnaud Fontaine <arnaud.fontaine at ssi.gouv.fr> +2016-10-17:[email protected]: + +Ben McGinnes <[email protected]> +2017-12-16:[email protected]: + +Christian Aistleitner <[email protected]> +2013-05-26:[email protected]: + +Damien Goutte-Gattat <[email protected]> +2015-01-17:[email protected]: + +Daniel Kahn Gillmor <[email protected]> +2014-09-24:[email protected]: + +Hans of Guardian <[email protected]> +2013-06-26:[email protected]: + +Ineiev <[email protected]> +2017-05-09:[email protected]: + +James Bottomley <[email protected]> +2018-02-01:[email protected]: + +Jonas Borgström <[email protected]> +2013-08-29:[email protected]: + +Joshua Rogers <[email protected]> +2014-12-22:[email protected]: + +Jussi Kivilinna <[email protected]> +2018-02-11:[email protected]: + +Kyle Butt <[email protected]> +2013-05-29:CAAODAYLbCtqOG6msLLL0UTdASKWT6u2ptxsgUQ1JpusBESBoNQ@mail.gmail.com: + +Phil Pennock <[email protected]> +Phil Pennock <[email protected]> +2017-01-19:[email protected]: + +Rainer Perske <[email protected]> +2017-10-24:permail-2017102014511105be2aed00002fc6-perske@message-id.uni-muenster.de: + +Stefan Tomanek <[email protected]> +2014-01-30:[email protected]: + +Tobias Mueller <[email protected]> +2016-11-23:[email protected]: + +Werner Koch <[email protected]> +2013-03-29:[email protected]: + +William L. Thomson Jr. <[email protected]> +2017-05-23:[email protected]: + +Yann E. MORIN <[email protected]> +2016-07-10:[email protected]: Other authors @@ -1,48 +1,7 @@ -Noteworthy changes in version 2.2.8 (unreleased) +Noteworthy changes in version 2.3.0 (unreleased) ------------------------------------------------ - -Noteworthy changes in version 2.2.7 (2018-05-02) ------------------------------------------------- - - * gpg: New option --no-symkey-cache to disable the passphrase cache - for symmetrical en- and decryption. - - * gpg: The ERRSIG status now prints the fingerprint if that is part - of the signature. - - * gpg: Relax emitting of FAILURE status lines - - * gpg: Add a status flag to "sig" lines printed with --list-sigs. - - * gpg: Fix "Too many open files" when using --multifile. [#3951] - - * ssh: Return an error for unknown ssh-agent flags. [#3880] - - * dirmngr: Fix a regression since 2.1.16 which caused corrupted CRL - caches under Windows. [#2448,#3923] - - * dirmngr: Fix a CNAME problem with pools and TLS. Also use a fixed - mapping of keys.gnupg.net to sks-keyservers.net. [#3755] - - * dirmngr: Try resurrecting dead hosts earlier (from 3 to 1.5 hours). - - * dirmngr: Fallback to CRL if no default OCSP responder is configured. - - * dirmngr: Implement CRL fetching via https. Here a redirection to - http is explictly allowed. - - * dirmngr: Make LDAP searching and CRL fetching work under Windows. - This stopped working with 2.1. [#3937] - - * agent,dirmngr: New sub-command "getenv" for "getinfo" to ease - debugging. - - See-also: gnupg-announce/2018q2/000424.html - - -Noteworthy changes in version 2.2.6 (2018-04-09) ------------------------------------------------- + Changes also found in 2.2.6: * gpg,gpgsm: New option --request-origin to pretend requests coming from a browser or a remote site. @@ -87,11 +46,7 @@ Noteworthy changes in version 2.2.6 (2018-04-09) * Allow the use of UNC directory names as homedir. [#3818] - See-also: gnupg-announce/2018q2/000421.html - - -Noteworthy changes in version 2.2.5 (2018-02-22) ------------------------------------------------- + Changes also found in 2.2.5: * gpg: Allow the use of the "cv25519" and "ed25519" short names in addition to the canonical curve names in --batch --gen-key. @@ -134,11 +89,7 @@ Noteworthy changes in version 2.2.5 (2018-02-22) with statically linked versions of the core GnuPG libraries. Also use --enable-wks-tools by default by Speedo builds for Unix. - See-also: gnupg-announce/2018q1/000420.html - - -Noteworthy changes in version 2.2.4 (2017-12-20) ------------------------------------------------- + Changes also found in 2.2.4: * gpg: Change default preferences to prefer SHA512. @@ -167,11 +118,7 @@ Noteworthy changes in version 2.2.4 (2017-12-20) * New configure option --enable-run-gnupg-user-socket to first try a socket directory which is not removed by systemd at session end. - See-also: gnupg-announce/2017q4/000419.html - - -Noteworthy changes in version 2.2.3 (2017-11-20) ------------------------------------------------- + Changes also found in 2.2.3: * gpgsm: Fix initial keybox creation on Windows. [#3507] @@ -191,8 +138,7 @@ Noteworthy changes in version 2.2.3 (2017-11-20) See-also: gnupg-announce/2017q4/000417.html -Noteworthy changes in version 2.2.2 (2017-11-07) ------------------------------------------------- + Changes also found in 2.2.2: * gpg: Avoid duplicate key imports by concurrently running gpg processes. [#3446] @@ -235,9 +181,7 @@ Noteworthy changes in version 2.2.2 (2017-11-07) See-also: gnupg-announce/2017q4/000416.html - -Noteworthy changes in version 2.2.1 (2017-09-19) ------------------------------------------------- + Changes also found in 2.2.1: * gpg: Fix formatting of the user id in batch mode key generation if only "name-email" is given. @@ -257,7 +201,14 @@ Noteworthy changes in version 2.2.1 (2017-09-19) certificates are configured. If build with GNUTLS, this was already the case. - See-also: gnupg-announce/2017q3/000415.html + Release dates of 2.2.x versions: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Version 2.2.1 (2017-09-19) + Version 2.2.2 (2017-11-07) + Version 2.2.3 (2017-11-20) + Version 2.2.4 (2017-12-20) + Version 2.2.5 (2018-02-22) + Version 2.2.6 (2018-04-09) Noteworthy changes in version 2.2.0 (2017-08-28) @@ -1,6 +1,6 @@ The GNU Privacy Guard 2 ========================= - Version 2.2 + Version 2.3 (devel) Copyright 1997-2018 Werner Koch Copyright 1998-2018 Free Software Foundation, Inc. @@ -26,7 +26,8 @@ Note that the 2.0 series of GnuPG will reach end-of-life on 2017-12-31. It is not possible to install a 2.2.x version along - with any 2.0.x version. + with any 2.0.x version. However, it is possible to install GnuPG + 1.4 along with any 2.x version. * BUILD INSTRUCTIONS diff --git a/agent/agent.h b/agent/agent.h index cf50d9280..9fdbc76d3 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -230,6 +230,7 @@ struct server_control_s char *lc_ctype; char *lc_messages; unsigned long client_pid; + int client_uid; /* The current pinentry mode. */ pinentry_mode_t pinentry_mode; diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index a0886814f..af4eb06f2 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -598,8 +598,9 @@ start_pinentry (ctrl_t ctrl) nodename = utsbuf.nodename; #endif /*!HAVE_W32_SYSTEM*/ - if ((optstr = xtryasprintf ("OPTION owner=%lu %s", - ctrl->client_pid, nodename))) + if ((optstr = xtryasprintf ("OPTION owner=%lu/%d %s", + ctrl->client_pid, ctrl->client_uid, + nodename))) { assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); diff --git a/agent/call-scd.c b/agent/call-scd.c index 16139fdc9..51d9abd70 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -89,7 +89,6 @@ struct inq_needpin_parm_s const char *getpin_cb_desc; assuan_context_t passthru; /* If not NULL, pass unknown inquiries up to the caller. */ - int any_inq_seen; /* The next fields are used by inq_writekey_parm. */ const unsigned char *keydata; @@ -727,7 +726,6 @@ inq_needpin (void *opaque, const char *line) size_t pinlen; int rc; - parm->any_inq_seen = 1; if ((s = has_leading_keyword (line, "NEEDPIN"))) { line = s; @@ -811,30 +809,6 @@ hash_algo_option (int algo) } -static gpg_error_t -cancel_inquire (ctrl_t ctrl, gpg_error_t rc) -{ - gpg_error_t oldrc = rc; - - /* The inquire callback was called and transact returned a - cancel error. We assume that the inquired process sent a - CANCEL. The passthrough code is not able to pass on the - CANCEL and thus scdaemon would stuck on this. As a - workaround we send a CANCEL now. */ - rc = assuan_write_line (ctrl->scd_local->ctx, "CAN"); - if (!rc) { - char *line; - size_t len; - - rc = assuan_read_line (ctrl->scd_local->ctx, &line, &len); - if (!rc) - rc = oldrc; - } - - return rc; -} - - /* Create a signature using the current card. MDALGO is either 0 or * gives the digest algorithm. DESC_TEXT is an additional parameter * passed to GETPIN_CB. */ @@ -875,7 +849,6 @@ agent_card_pksign (ctrl_t ctrl, inqparm.getpin_cb_arg = getpin_cb_arg; inqparm.getpin_cb_desc = desc_text; inqparm.passthru = 0; - inqparm.any_inq_seen = 0; inqparm.keydata = NULL; inqparm.keydatalen = 0; @@ -888,9 +861,6 @@ agent_card_pksign (ctrl_t ctrl, put_membuf_cb, &data, inq_needpin, &inqparm, NULL, NULL); - if (inqparm.any_inq_seen && (gpg_err_code(rc) == GPG_ERR_CANCELED || - gpg_err_code(rc) == GPG_ERR_ASS_CANCELED)) - rc = cancel_inquire (ctrl, rc); if (rc) { @@ -974,7 +944,6 @@ agent_card_pkdecrypt (ctrl_t ctrl, inqparm.getpin_cb_arg = getpin_cb_arg; inqparm.getpin_cb_desc = desc_text; inqparm.passthru = 0; - inqparm.any_inq_seen = 0; inqparm.keydata = NULL; inqparm.keydatalen = 0; snprintf (line, DIM(line), "PKDECRYPT %s", keyid); @@ -982,9 +951,6 @@ agent_card_pkdecrypt (ctrl_t ctrl, put_membuf_cb, &data, inq_needpin, &inqparm, padding_info_cb, r_padding); - if (inqparm.any_inq_seen && (gpg_err_code(rc) == GPG_ERR_CANCELED || - gpg_err_code(rc) == GPG_ERR_ASS_CANCELED)) - rc = cancel_inquire (ctrl, rc); if (rc) { @@ -1111,15 +1077,11 @@ agent_card_writekey (ctrl_t ctrl, int force, const char *serialno, parms.getpin_cb_arg = getpin_cb_arg; parms.getpin_cb_desc= NULL; parms.passthru = 0; - parms.any_inq_seen = 0; parms.keydata = keydata; parms.keydatalen = keydatalen; rc = assuan_transact (ctrl->scd_local->ctx, line, NULL, NULL, inq_writekey_parms, &parms, NULL, NULL); - if (parms.any_inq_seen && (gpg_err_code(rc) == GPG_ERR_CANCELED || - gpg_err_code(rc) == GPG_ERR_ASS_CANCELED)) - rc = cancel_inquire (ctrl, rc); return unlock_scd (ctrl, rc); } @@ -1344,7 +1306,6 @@ agent_card_scd (ctrl_t ctrl, const char *cmdline, inqparm.getpin_cb_arg = getpin_cb_arg; inqparm.getpin_cb_desc = NULL; inqparm.passthru = assuan_context; - inqparm.any_inq_seen = 0; inqparm.keydata = NULL; inqparm.keydatalen = 0; @@ -1354,8 +1315,6 @@ agent_card_scd (ctrl_t ctrl, const char *cmdline, pass_data_thru, assuan_context, inq_needpin, &inqparm, pass_status_thru, assuan_context); - if (inqparm.any_inq_seen && gpg_err_code(rc) == GPG_ERR_ASS_CANCELED) - rc = cancel_inquire (ctrl, rc); assuan_set_flag (ctrl->scd_local->ctx, ASSUAN_CONVEY_COMMENTS, saveflag); if (rc) diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 20dc3febe..df63ed713 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -262,6 +262,11 @@ static gpg_error_t ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec, static gpg_error_t ssh_key_extract_comment (gcry_sexp_t key, char **comment); +struct peer_info_s +{ + unsigned long pid; + int uid; +}; /* Global variables. */ @@ -3616,10 +3621,11 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock) /* Return the peer's pid. */ -static unsigned long -get_client_pid (int fd) +static void +get_client_info (int fd, struct peer_info_s *out) { - pid_t client_pid = (pid_t)0; + pid_t client_pid = (pid_t)(-1); + uid_t client_uid = (uid_t)-1; #ifdef SO_PEERCRED { @@ -3634,8 +3640,10 @@ get_client_pid (int fd) { #if defined (HAVE_STRUCT_SOCKPEERCRED_PID) || defined (HAVE_STRUCT_UCRED_PID) client_pid = cr.pid; + client_uid = cr.uid; #elif defined (HAVE_STRUCT_UCRED_CR_PID) client_pid = cr.cr_pid; + client_pid = cr.cr_uid; #else #error "Unknown SO_PEERCRED struct" #endif @@ -3646,6 +3654,15 @@ get_client_pid (int fd) socklen_t len = sizeof (pid_t); getsockopt (fd, SOL_LOCAL, LOCAL_PEERPID, &client_pid, &len); +#if defined (LOCAL_PEERCRED) + { + struct xucred cr; + len = sizeof (struct xucred); + + if (!getsockopt (fd, SOL_LOCAL, LOCAL_PEERCRED, &cr, &len)) + client_uid = cr.cr_uid; + } +#endif } #elif defined (LOCAL_PEEREID) { @@ -3654,6 +3671,7 @@ get_client_pid (int fd) if (getsockopt (fd, 0, LOCAL_PEEREID, &unp, &unpl) != -1) client_pid = unp.unp_pid; + client_uid = unp.unp_euid; } #elif defined (HAVE_GETPEERUCRED) { @@ -3661,7 +3679,8 @@ get_client_pid (int fd) if (getpeerucred (fd, &ucred) != -1) { - client_pid= ucred_getpid (ucred); + client_pid = ucred_getpid (ucred); + client_uid = ucred_geteuid (ucred); ucred_free (ucred); } } @@ -3669,7 +3688,8 @@ get_client_pid (int fd) (void)fd; #endif - return (unsigned long)client_pid; + out->pid = (client_pid == (pid_t)(-1)? 0 : (unsigned long)client_pid); + out->uid = (int)client_uid; } @@ -3680,12 +3700,15 @@ start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client) estream_t stream_sock = NULL; gpg_error_t err; int ret; + struct peer_info_s peer_info; err = agent_copy_startup_env (ctrl); if (err) goto out; - ctrl->client_pid = get_client_pid (FD2INT(sock_client)); + get_client_info (FD2INT(sock_client), &peer_info); + ctrl->client_pid = peer_info.pid; + ctrl->client_uid = peer_info.uid; /* Create stream from socket. */ stream_sock = es_fdopen (FD2INT(sock_client), "r+"); diff --git a/agent/command.c b/agent/command.c index 20abb2882..1a08cfcc0 100644 --- a/agent/command.c +++ b/agent/command.c @@ -843,7 +843,7 @@ static const char hlp_genkey[] = "\n" " C: GENKEY\n" " S: INQUIRE KEYPARAM\n" - " C: D (genkey (rsa (nbits 2048)))\n" + " C: D (genkey (rsa (nbits 3072)))\n" " C: END\n" " S: D (public-key\n" " S: D (rsa (n 326487324683264) (e 10001)))\n" @@ -3351,7 +3351,7 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd) for (;;) { - pid_t client_pid; + assuan_peercred_t client_creds; rc = assuan_accept (ctx); if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1) @@ -3364,12 +3364,20 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd) break; } - client_pid = assuan_get_pid (ctx); - ctrl->server_local->connect_from_self = (client_pid == getpid ()); - if (client_pid != ASSUAN_INVALID_PID) - ctrl->client_pid = (unsigned long)client_pid; + rc = assuan_get_peercred (ctx, &client_creds); + if (rc) + { + log_info ("Assuan get_peercred failed: %s\n", gpg_strerror (rc)); + client_creds->pid = assuan_get_pid (ctx); + ctrl->client_uid = -1; + } + ctrl->server_local->connect_from_self = + (client_creds->pid == getpid ()); + if (client_creds->pid != ASSUAN_INVALID_PID) + ctrl->client_pid = (unsigned long)client_creds->pid; else ctrl->client_pid = 0; + ctrl->client_uid = client_creds->uid; rc = assuan_process (ctx); if (rc) diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index bf05174fa..06cd1c840 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -878,11 +878,11 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist, log_debug ("XXX pubkey_algo=%d\n", pubkey_algo); log_debug ("XXX is_protected=%d\n", is_protected); log_debug ("XXX protect_algo=%d\n", protect_algo); - log_printhex ("XXX iv", iv, ivlen); + log_printhex (iv, ivlen, "XXX iv"); log_debug ("XXX ivlen=%d\n", ivlen); log_debug ("XXX s2k_mode=%d\n", s2k_mode); log_debug ("XXX s2k_algo=%d\n", s2k_algo); - log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt); + log_printhex (s2k_salt, sizeof s2k_salt, "XXX s2k_salt"); log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count); log_debug ("XXX curve='%s'\n", curve); for (idx=0; skey[idx]; idx++) diff --git a/agent/divert-scd.c b/agent/divert-scd.c index 88b35cd21..b85b490c1 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -169,7 +169,7 @@ encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo, memcpy (frame, asn, asnlen); memcpy (frame+asnlen, digest, digestlen); if (DBG_CRYPTO) - log_printhex ("encoded hash:", frame, asnlen+digestlen); + log_printhex (frame, asnlen+digestlen, "encoded hash:"); *r_val = frame; *r_len = asnlen+digestlen; diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index 46697bae1..06a8e0b6f 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -64,8 +64,8 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, if (DBG_CRYPTO) { - log_printhex ("keygrip:", ctrl->keygrip, 20); - log_printhex ("cipher: ", ciphertext, ciphertextlen); + log_printhex (ctrl->keygrip, 20, "keygrip:"); + log_printhex (ciphertext, ciphertextlen, "cipher: "); } rc = agent_key_from_file (ctrl, NULL, desc_text, ctrl->keygrip, &shadow_info, diff --git a/agent/protect.c b/agent/protect.c index 7b5abf21b..16ae715e1 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -163,7 +163,7 @@ calibrate_s2k_count_one (unsigned long count) /* Measure the time we need to do the hash operations and deduce an - S2K count which requires about 100ms of time. */ + S2K count which requires roughly some targeted amount of time. */ static unsigned long calibrate_s2k_count (void) { @@ -175,11 +175,11 @@ calibrate_s2k_count (void) ms = calibrate_s2k_count_one (count); if (opt.verbose > 1) log_info ("S2K calibration: %lu -> %lums\n", count, ms); - if (ms > 100) + if (ms > AGENT_S2K_CALIBRATION) break; } - count = (unsigned long)(((double)count / ms) * 100); + count = (unsigned long)(((double)count / ms) * AGENT_S2K_CALIBRATION); count /= 1024; count *= 1024; if (count < 65536) diff --git a/autogen.rc b/autogen.rc index 3ea03e08f..aa565911a 100644 --- a/autogen.rc +++ b/autogen.rc @@ -1,7 +1,7 @@ # autogen.sh configuration for GnuPG -*- sh -*- display_name=GnuPG - #version_parts=3 case "$myhost:$myhostsub" in diff --git a/autogen.sh b/autogen.sh index b23855061..4b511bf95 100755 --- a/autogen.sh +++ b/autogen.sh @@ -469,6 +469,7 @@ EOF chmod +x .git/hooks/commit-msg if [ x"${display_name}" != x ]; then git config format.subjectPrefix "PATCH ${display_name}" + git config sendemail.to "${patches_to}" fi fi fi diff --git a/build-aux/speedo.mk b/build-aux/speedo.mk index 320d4403d..d9b4a7515 100644 --- a/build-aux/speedo.mk +++ b/build-aux/speedo.mk @@ -282,7 +282,7 @@ endif # Version numbers of the released packages gnupg_ver_this = $(shell cat $(topsrc)/VERSION) -gnupg_ver := $(shell awk '$$1=="gnupg22_ver" {print $$2}' swdb.lst) +gnupg_ver := $(shell awk '$$1=="gnupg24_ver" {print $$2}' swdb.lst) libgpg_error_ver := $(shell awk '$$1=="libgpg_error_ver" {print $$2}' swdb.lst) libgpg_error_sha1:= $(shell awk '$$1=="libgpg_error_sha1" {print $$2}' swdb.lst) @@ -1227,7 +1227,7 @@ installer: all w32_insthelpers $(w32src)/inst-options.ini $(bdir)/README.txt define MKSWDB_commands - ( pref="#+macro: gnupg22_w32_" ;\ + ( pref="#+macro: gnupg24_w32_" ;\ echo "$${pref}ver $(INST_VERSION)_$(BUILD_DATESTR)" ;\ echo "$${pref}date $(2)" ;\ echo "$${pref}size $$(wc -c <$(1)|awk '{print int($$1/1024)}')k";\ diff --git a/common/Makefile.am b/common/Makefile.am index fcbe7ea66..94318dae4 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -94,7 +94,8 @@ common_sources = \ name-value.c name-value.h \ recsel.c recsel.h \ ksba-io-support.c ksba-io-support.h \ - compliance.c compliance.h + compliance.c compliance.h \ + pkscreening.c pkscreening.h if HAVE_W32_SYSTEM diff --git a/common/argparse.c b/common/argparse.c index 90d0ff7f3..331998bb2 100644 --- a/common/argparse.c +++ b/common/argparse.c @@ -1,32 +1,23 @@ -/* [argparse.c wk 17.06.97] Argument Parser for option handling - * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc. +/* argparse.c - Argument Parser for option handling * Copyright (C) 1997-2001, 2006-2008, 2013-2017 Werner Koch + * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc. + * Copyright (C) 2015-2017 g10 Code GmbH * * This file is part of GnuPG. * - * GnuPG is free software; you can redistribute and/or modify this - * part of GnuPG under the terms of either - * - * - the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at - * your option) any later version. - * - * or - * - * - the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * or both in parallel, as here. + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. * - * GnuPG is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copies of the GNU General Public License - * and the GNU Lesser General Public License along with this program; - * if not, see <https://gnu.org/licenses/>. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: LGPL-2.1+ */ /* This file may be used as part of GnuPG or standalone. A GnuPG diff --git a/common/argparse.h b/common/argparse.h index cdd18d9a2..4167d667a 100644 --- a/common/argparse.h +++ b/common/argparse.h @@ -1,31 +1,23 @@ /* argparse.h - Argument parser for option handling. - * Copyright (C) 1998,1999,2000,2001,2006 Free Software Foundation, Inc. + * Copyright (C) 1997-2001, 2006-2008, 2013-2017 Werner Koch + * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc. + * Copyright (C) 2015-2017 g10 Code GmbH * * This file is part of GnuPG. * - * GnuPG is free software; you can redistribute and/or modify this - * part of GnuPG under the terms of either + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. * - * - the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at - * your option) any later version. + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * or - * - * - the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * or both in parallel, as here. - * - * GnuPG is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copies of the GNU General Public License - * and the GNU Lesser General Public License along with this program; - * if not, see <https://www.gnu.org/licenses/>. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: LGPL-2.1+ */ #ifndef GNUPG_COMMON_ARGPARSE_H diff --git a/common/asshelp.c b/common/asshelp.c index f3a92f9e5..5209ea6cf 100644 --- a/common/asshelp.c +++ b/common/asshelp.c @@ -93,7 +93,7 @@ my_libassuan_log_handler (assuan_context_t ctx, void *hook, return 0; /* Temporary disabled. */ if (msg) - log_string (GPGRT_LOG_DEBUG, msg); + log_string (GPGRT_LOGLVL_DEBUG, msg); return 1; } @@ -307,6 +307,71 @@ unlock_spawning (lock_spawn_t *lock, const char *name) } } + +/* Helper for start_new_gpg_agent and start_new_dirmngr. + * Values for WHICH are: + * 0 - Start gpg-agent + * 1 - Start dirmngr + * SECS give the number of seconds to wait. SOCKNAME is the name of + * the socket to connect. VERBOSE is the usual verbose flag. CTX is + * the assuan context. DID_SUCCESS_MSG will be set to 1 if a success + * messages has been printed. + */ +static gpg_error_t +wait_for_sock (int secs, int which, const char *sockname, + int verbose, assuan_context_t ctx, int *did_success_msg) +{ + gpg_error_t err = 0; + int target_us = secs * 1000000; + int elapsed_us = 0; + /* + * 977us * 1024 = just a little more than 1s. + * so we will double this timeout 10 times in the first + * second, and then switch over to 1s checkins. + */ + int next_sleep_us = 977; + int lastalert = secs+1; + int secsleft; + + while (elapsed_us < target_us) + { + if (verbose) + { + secsleft = (target_us - elapsed_us + 999999)/1000000; + /* log_clock ("left=%d last=%d targ=%d elap=%d next=%d\n", */ + /* secsleft, lastalert, target_us, elapsed_us, */ + /* next_sleep_us); */ + if (secsleft < lastalert) + { + log_info (which == 1? + _("waiting for the dirmngr to come up ... (%ds)\n"): + _("waiting for the agent to come up ... (%ds)\n"), + secsleft); + lastalert = secsleft; + } + } + gnupg_usleep (next_sleep_us); + elapsed_us += next_sleep_us; + err = assuan_socket_connect (ctx, sockname, 0, 0); + if (!err) + { + if (verbose) + { + log_info (which == 1? + _("connection to the dirmngr established\n"): + _("connection to the agent established\n")); + *did_success_msg = 1; + } + break; + } + next_sleep_us *= 2; + if (next_sleep_us > 1000000) + next_sleep_us = 1000000; + } + return err; +} + + /* Try to connect to the agent via socket or start it if it is not running and AUTOSTART is set. Handle the server's initial greeting. Returns a new assuan context at R_CTX or an error @@ -433,25 +498,8 @@ start_new_gpg_agent (assuan_context_t *r_ctx, log_error ("failed to start agent '%s': %s\n", agent_program, gpg_strerror (err)); else - { - for (i=0; i < SECS_TO_WAIT_FOR_AGENT; i++) - { - if (verbose) - log_info (_("waiting for the agent to come up ... (%ds)\n"), - SECS_TO_WAIT_FOR_AGENT - i); - gnupg_sleep (1); - err = assuan_socket_connect (ctx, sockname, 0, 0); - if (!err) - { - if (verbose) - { - log_info (_("connection to agent established\n")); - did_success_msg = 1; - } - break; - } - } - } + err = wait_for_sock (SECS_TO_WAIT_FOR_AGENT, 0, + sockname, verbose, ctx, &did_success_msg); } unlock_spawning (&lock, "agent"); @@ -468,7 +516,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx, } if (debug && !did_success_msg) - log_debug ("connection to agent established\n"); + log_debug ("connection to the agent established\n"); err = assuan_transact (ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL); @@ -485,7 +533,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx, NULL, NULL, NULL, NULL, NULL, NULL)) { if (verbose) - log_info (_("connection to agent is in restricted mode\n")); + log_info (_("connection to the agent is in restricted mode\n")); err = 0; } } @@ -542,7 +590,7 @@ start_new_dirmngr (assuan_context_t *r_ctx, dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR); if (verbose) - log_info (_("no running Dirmngr - starting '%s'\n"), + log_info (_("no running dirmngr - starting '%s'\n"), dirmngr_program); if (status_cb) @@ -584,29 +632,8 @@ start_new_dirmngr (assuan_context_t *r_ctx, log_error ("failed to start the dirmngr '%s': %s\n", dirmngr_program, gpg_strerror (err)); else - { - int i; - - for (i=0; i < SECS_TO_WAIT_FOR_DIRMNGR; i++) - { - if (verbose) - log_info (_("waiting for the dirmngr " - "to come up ... (%ds)\n"), - SECS_TO_WAIT_FOR_DIRMNGR - i); - gnupg_sleep (1); - err = assuan_socket_connect (ctx, sockname, 0, 0); - if (!err) - { - if (verbose) - { - log_info (_("connection to the dirmngr" - " established\n")); - did_success_msg = 1; - } - break; - } - } - } + err = wait_for_sock (SECS_TO_WAIT_FOR_DIRMNGR, 1, + sockname, verbose, ctx, &did_success_msg); } unlock_spawning (&lock, "dirmngr"); diff --git a/common/exechelp-posix.c b/common/exechelp-posix.c index 7237993a2..425f2b4d5 100644 --- a/common/exechelp-posix.c +++ b/common/exechelp-posix.c @@ -1,6 +1,6 @@ /* exechelp.c - Fork and exec helpers for POSIX - * Copyright (C) 2004, 2007, 2008, 2009, - * 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH * * This file is part of GnuPG. * @@ -26,6 +26,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: (LGPL-3.0+ OR GPL-2.0+) */ #include <config.h> @@ -784,30 +785,32 @@ gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count, } } - if (ec == 0) - for (i = 0; i < count; i++) - { - if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]) == 127) - { - log_error (_("error running '%s': probably not installed\n"), - pgmnames[i]); - ec = GPG_ERR_CONFIGURATION; - } - else if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i])) - { - if (dummy) - log_error (_("error running '%s': exit status %d\n"), - pgmnames[i], WEXITSTATUS (r_exitcodes[i])); - else - r_exitcodes[i] = WEXITSTATUS (r_exitcodes[i]); - ec = GPG_ERR_GENERAL; - } - else if (!WIFEXITED (r_exitcodes[i])) - { - log_error (_("error running '%s': terminated\n"), pgmnames[i]); - ec = GPG_ERR_GENERAL; - } - } + for (i = 0; i < count; i++) + { + if (r_exitcodes[i] == -1) + continue; + + if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]) == 127) + { + log_error (_("error running '%s': probably not installed\n"), + pgmnames[i]); + ec = GPG_ERR_CONFIGURATION; + } + else if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i])) + { + if (dummy) + log_error (_("error running '%s': exit status %d\n"), + pgmnames[i], WEXITSTATUS (r_exitcodes[i])); + else + r_exitcodes[i] = WEXITSTATUS (r_exitcodes[i]); + ec = GPG_ERR_GENERAL; + } + else if (!WIFEXITED (r_exitcodes[i])) + { + log_error (_("error running '%s': terminated\n"), pgmnames[i]); + ec = GPG_ERR_GENERAL; + } + } xfree (dummy); return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec); diff --git a/common/exechelp-w32.c b/common/exechelp-w32.c index da174508e..86b1d6869 100644 --- a/common/exechelp-w32.c +++ b/common/exechelp-w32.c @@ -1,6 +1,6 @@ /* exechelp-w32.c - Fork and exec helpers for W32. - * Copyright (C) 2004, 2007, 2008, 2009, - * 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH * * This file is part of GnuPG. * @@ -26,6 +26,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: (LGPL-3.0+ OR GPL-2.0+) */ #include <config.h> diff --git a/common/exechelp-w32ce.c b/common/exechelp-w32ce.c index ec9f01441..3d68a01d1 100644 --- a/common/exechelp-w32ce.c +++ b/common/exechelp-w32ce.c @@ -1,6 +1,6 @@ /* exechelp-w32.c - Fork and exec helpers for W32CE. - * Copyright (C) 2004, 2007, 2008, 2009, - * 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc. + * Copyright (C) 2010-2012, 2014-2016 g10 Code GmbH * * This file is part of GnuPG. * @@ -26,6 +26,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: (LGPL-3.0+ OR GPL-2.0+) */ #include <config.h> diff --git a/common/exechelp.h b/common/exechelp.h index 2b40ba098..9e1f56f70 100644 --- a/common/exechelp.h +++ b/common/exechelp.h @@ -1,5 +1,6 @@ /* exechelp.h - Definitions for the fork and exec helpers * Copyright (C) 2004, 2009, 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH * * This file is part of GnuPG. * @@ -25,6 +26,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: (LGPL-3.0+ OR GPL-2.0+) */ #ifndef GNUPG_COMMON_EXECHELP_H diff --git a/common/iobuf.c b/common/iobuf.c index 5a9fd7caf..02c9b491c 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -59,10 +59,8 @@ /*-- Begin configurable part. --*/ -/* The size of the internal buffers. - NOTE: If you change this value you MUST also adjust the regression - test "armored_key_8192" in armor.test! */ -#define IOBUF_BUFFER_SIZE 8192 +/* The standard size of the internal buffers. */ +#define DEFAULT_IOBUF_BUFFER_SIZE (64*1024) /* To avoid a potential DoS with compression packets we better limit the number of filters in a chain. */ @@ -70,6 +68,10 @@ /*-- End configurable part. --*/ +/* The size of the iobuffers. This can be chnages using the + * iobuf_set_buffer_size fucntion. */ +static unsigned int iobuf_buffer_size = DEFAULT_IOBUF_BUFFER_SIZE; + #ifdef HAVE_W32_SYSTEM # ifdef HAVE_W32CE_SYSTEM @@ -92,6 +94,7 @@ typedef struct int keep_open; int no_cache; int eof_seen; + int delayed_rc; int print_only_name; /* Flags indicating that fname is not a real file. */ char fname[1]; /* Name of the file. */ } file_filter_ctx_t; @@ -167,7 +170,7 @@ static int translate_file_handle (int fd, int for_write); to be sent to A's filter function. If A is a IOBUF_OUTPUT_TEMP filter, then this also enlarges the - buffer by IOBUF_BUFFER_SIZE. + buffer by iobuf_buffer_size. May only be called on an IOBUF_OUTPUT or IOBUF_OUTPUT_TEMP filters. */ static int filter_flush (iobuf_t a); @@ -451,12 +454,20 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, if (control == IOBUFCTRL_UNDERFLOW) { - assert (size); /* We need a buffer. */ + log_assert (size); /* We need a buffer. */ if (a->eof_seen) { rc = -1; *ret_len = 0; } + else if (a->delayed_rc) + { + rc = a->delayed_rc; + a->delayed_rc = 0; + if (rc == -1) + a->eof_seen = -1; + *ret_len = 0; + } else { #ifdef HAVE_W32_SYSTEM @@ -487,29 +498,39 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, int n; nbytes = 0; - do - { - n = read (f, buf, size); - } - while (n == -1 && errno == EINTR); - if (n == -1) - { /* error */ - if (errno != EPIPE) - { - rc = gpg_error_from_syserror (); - log_error ("%s: read error: %s\n", - a->fname, strerror (errno)); - } - } - else if (!n) - { /* eof */ - a->eof_seen = 1; - rc = -1; - } - else - { - nbytes = n; - } + read_more: + do + { + n = read (f, buf + nbytes, size - nbytes); + } + while (n == -1 && errno == EINTR); + if (n > 0) + { + nbytes += n; + if (nbytes < size) + goto read_more; + } + else if (!n) /* eof */ + { + if (nbytes) + a->delayed_rc = -1; + else + { + a->eof_seen = 1; + rc = -1; + } + } + else /* error */ + { + rc = gpg_error_from_syserror (); + if (gpg_err_code (rc) != GPG_ERR_EPIPE) + log_error ("%s: read error: %s\n", a->fname, gpg_strerror (rc)); + if (nbytes) + { + a->delayed_rc = rc; + rc = 0; + } + } #endif *ret_len = nbytes; } @@ -569,6 +590,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, else if (control == IOBUFCTRL_INIT) { a->eof_seen = 0; + a->delayed_rc = 0; a->keep_open = 0; a->no_cache = 0; } @@ -1053,6 +1075,30 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buffer, return rc; } + +/* Change the default size for all IOBUFs to KILOBYTE. This needs to + * be called before any iobufs are used and can only be used once. + * Returns the current value. Using 0 has no effect except for + * returning the current value. */ +unsigned int +iobuf_set_buffer_size (unsigned int kilobyte) +{ + static int used; + + if (!used && kilobyte) + { + if (kilobyte < 4) + kilobyte = 4; + else if (kilobyte > 16*1024) + kilobyte = 16*1024; + + iobuf_buffer_size = kilobyte * 1024; + used = 1; + } + return iobuf_buffer_size / 1024; +} + + #define MAX_IOBUF_DESC 32 /* * Fill the buffer by the description of iobuf A. @@ -1105,7 +1151,7 @@ iobuf_alloc (int use, size_t bufsize) if (bufsize == 0) { log_bug ("iobuf_alloc() passed a bufsize of 0!\n"); - bufsize = IOBUF_BUFFER_SIZE; + bufsize = iobuf_buffer_size; } a = xcalloc (1, sizeof *a); @@ -1213,7 +1259,7 @@ iobuf_cancel (iobuf_t a) iobuf_t iobuf_temp (void) { - return iobuf_alloc (IOBUF_OUTPUT_TEMP, IOBUF_BUFFER_SIZE); + return iobuf_alloc (IOBUF_OUTPUT_TEMP, iobuf_buffer_size); } iobuf_t @@ -1288,7 +1334,7 @@ do_open (const char *fname, int special_filenames, return NULL; } - a = iobuf_alloc (use, IOBUF_BUFFER_SIZE); + a = iobuf_alloc (use, iobuf_buffer_size); fcx = xmalloc (sizeof *fcx + strlen (fname)); fcx->fp = fp; fcx->print_only_name = print_only; @@ -1335,7 +1381,7 @@ do_iobuf_fdopen (int fd, const char *mode, int keep_open) fp = INT2FD (fd); a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT, - IOBUF_BUFFER_SIZE); + iobuf_buffer_size); fcx = xmalloc (sizeof *fcx + 20); fcx->fp = fp; fcx->print_only_name = 1; @@ -1373,7 +1419,7 @@ iobuf_esopen (estream_t estream, const char *mode, int keep_open) size_t len = 0; a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT, - IOBUF_BUFFER_SIZE); + iobuf_buffer_size); fcx = xtrymalloc (sizeof *fcx + 30); fcx->fp = estream; fcx->print_only_name = 1; @@ -1398,7 +1444,7 @@ iobuf_sockopen (int fd, const char *mode) size_t len; a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT, - IOBUF_BUFFER_SIZE); + iobuf_buffer_size); scx = xmalloc (sizeof *scx + 25); scx->sock = fd; scx->print_only_name = 1; @@ -1599,13 +1645,13 @@ iobuf_push_filter2 (iobuf_t a, increased accordingly. We don't need to allocate a 10 MB buffer for a non-terminal filter. Just use the default size. */ - a->d.size = IOBUF_BUFFER_SIZE; + a->d.size = iobuf_buffer_size; } else if (a->use == IOBUF_INPUT_TEMP) /* Same idea as above. */ { a->use = IOBUF_INPUT; - a->d.size = IOBUF_BUFFER_SIZE; + a->d.size = iobuf_buffer_size; } /* The new filter (A) gets a new buffer. @@ -1922,7 +1968,7 @@ filter_flush (iobuf_t a) if (a->use == IOBUF_OUTPUT_TEMP) { /* increase the temp buffer */ - size_t newsize = a->d.size + IOBUF_BUFFER_SIZE; + size_t newsize = a->d.size + iobuf_buffer_size; if (DBG_IOBUF) log_debug ("increasing temp iobuf from %lu to %lu\n", diff --git a/common/iobuf.h b/common/iobuf.h index 22e02daad..16156383c 100644 --- a/common/iobuf.h +++ b/common/iobuf.h @@ -259,6 +259,12 @@ struct iobuf_struct EXTERN_UNLESS_MAIN_MODULE int iobuf_debug_mode; +/* Change the default size for all IOBUFs to KILOBYTE. This needs to + * be called before any iobufs are used and can only be used once. + * Returns the current value. Using 0 has no effect except for + * returning the current value. */ +unsigned int iobuf_set_buffer_size (unsigned int kilobyte); + /* Returns whether the specified filename corresponds to a pipe. In particular, this function checks if FNAME is "-" and, if special filenames are enabled (see check_special_filename), whether diff --git a/common/logging.c b/common/logging.c index c4eaca411..88860e715 100644 --- a/common/logging.c +++ b/common/logging.c @@ -63,6 +63,10 @@ #include "logging.h" #include "sysutils.h" +#if defined(GPGRT_ENABLE_LOG_MACROS) && defined(log_debug_string) + /* Nothing to do; the libgpgrt functions are used. */ +#else /* Use our own logging functions. */ + #ifdef HAVE_W32_SYSTEM # ifndef S_IRWXG # define S_IRGRP S_IRUSR @@ -885,7 +889,7 @@ log_logv (int level, const char *fmt, va_list arg_ptr) * Note that PREFIX is an additional string and independent of the * prefix set by log_set_prefix. */ void -log_logv_with_prefix (int level, const char *prefix, +log_logv_prefix (int level, const char *prefix, const char *fmt, va_list arg_ptr) { do_logv (level, 0, NULL, prefix, fmt, arg_ptr); @@ -977,7 +981,7 @@ log_debug (const char *fmt, ...) * printed with LFs expanded to include the prefix and a final --end-- * marker. */ void -log_debug_with_string (const char *string, const char *fmt, ...) +log_debug_string (const char *string, const char *fmt, ...) { va_list arg_ptr ; @@ -1011,7 +1015,7 @@ log_flush (void) dump, with TEXT just an empty string, print a trailing linefeed, otherwise print an entire debug line. */ void -log_printhex (const char *text, const void *buffer, size_t length) +log_printhex (const void *buffer, size_t length, const char *text) { if (text && *text) log_debug ("%s ", text); @@ -1039,14 +1043,16 @@ log_printsexp () {} is found in sexputils.c */ - +/* Print a microsecond timestamp followed by a FORMAT. */ void -log_clock (const char *string) +log_clock (const char *fmt, ...) { -#if 0 +#if ENABLE_LOG_CLOCK static unsigned long long initial; struct timespec tv; unsigned long long now; + char clockbuf[50]; + va_list arg_ptr; if (clock_gettime (CLOCK_REALTIME, &tv)) { @@ -1059,11 +1065,21 @@ log_clock (const char *string) if (!initial) initial = now; - log_debug ("[%6llu] %s", (now - initial)/1000, string); -#else - /* You need to link with -ltr to enable the above code. */ - log_debug ("[not enabled in the source] %s", string); -#endif + snprintf (clockbuf, sizeof clockbuf, "[%6llu] ", (now - initial)/1000); + va_start (arg_ptr, fmt); + do_logv (GPGRT_LOG_DEBUG, 0, NULL, clockbuf, fmt, arg_ptr); + va_end (arg_ptr); + +#else /*!ENABLE_LOG_CLOCK*/ + + /* You may need to link with -ltr to use the above code. */ + va_list arg_ptr; + + va_start (arg_ptr, fmt); + do_logv (GPGRT_LOG_DEBUG, 0, NULL, "[no clock] ", fmt, arg_ptr); + va_end (arg_ptr); + +#endif /*!ENABLE_LOG_CLOCK*/ } @@ -1101,3 +1117,5 @@ _log_assert (const char *expr, const char *file, int line) abort (); /* Never called; just to make the compiler happy. */ } #endif /*!GPGRT_HAVE_MACRO_FUNCTION*/ + +#endif /* Use our own logging functions. */ diff --git a/common/logging.h b/common/logging.h index 2225100cb..a20b8f895 100644 --- a/common/logging.h +++ b/common/logging.h @@ -38,6 +38,35 @@ #include "mischelp.h" #include "w32help.h" +#if defined(GPGRT_ENABLE_LOG_MACROS) && defined(log_debug_string) + /* We use the libgpg-error provided log functions. but we need one + * more function: */ +# ifdef GPGRT_HAVE_MACRO_FUNCTION +# define BUG() bug_at ( __FILE__, __LINE__, __FUNCTION__) +static inline void bug_at (const char *file, int line, const char *func) + GPGRT_ATTR_NORETURN; +static inline void +bug_at (const char *file, int line, const char *func) +{ + gpgrt_log (GPGRT_LOGLVL_BUG, "there is a bug at %s:%d:%s\n", + file, line, func); + abort (); +} +# else +# define BUG() bug_at ( __FILE__, __LINE__) +static inline void bug_at (const char *file, int line) + GPGRT_ATTR_NORETURN; +static inline void +bug_at (const char *file, int line) +{ + gpgrt_log (GPGRT_LOGLVL_BUG, "there is a bug at %s:%d\n", file, line); + abort (); +} +# endif /*!GPGRT_HAVE_MACRO_FUNCTION*/ + + +#else /* Use gnupg internal logging functions. */ + int log_get_errorcount (int clear); void log_inc_errorcount (void); void log_set_file( const char *name ); @@ -88,18 +117,27 @@ enum jnlib_log_levels { GPGRT_LOG_BUG, GPGRT_LOG_DEBUG }; +#define GPGRT_LOGLVL_BEGIN GPGRT_LOG_BEGIN +#define GPGRT_LOGLVL_CONT GPGRT_LOG_CONT +#define GPGRT_LOGLVL_INFO GPGRT_LOG_INFO +#define GPGRT_LOGLVL_WARN GPGRT_LOG_WARN +#define GPGRT_LOGLVL_ERROR GPGRT_LOG_ERROR +#define GPGRT_LOGLVL_FATAL GPGRT_LOG_FATAL +#define GPGRT_LOGLVL_BUG GPGRT_LOG_BUG +#define GPGRT_LOGLVL_DEBUG GPGRT_LOG_DEBUG + void log_log (int level, const char *fmt, ...) GPGRT_ATTR_PRINTF(2,3); void log_logv (int level, const char *fmt, va_list arg_ptr); -void log_logv_with_prefix (int level, const char *prefix, - const char *fmt, va_list arg_ptr); +void log_logv_prefix (int level, const char *prefix, + const char *fmt, va_list arg_ptr); void log_string (int level, const char *string); void log_bug (const char *fmt, ...) GPGRT_ATTR_NR_PRINTF(1,2); void log_fatal (const char *fmt, ...) GPGRT_ATTR_NR_PRINTF(1,2); void log_error (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); void log_info (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); void log_debug (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); -void log_debug_with_string (const char *string, const char *fmt, - ...) GPGRT_ATTR_PRINTF(2,3); +void log_debug_string (const char *string, const char *fmt, + ...) GPGRT_ATTR_PRINTF(2,3); void log_printf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); void log_flush (void); @@ -107,10 +145,11 @@ void log_flush (void); raw dump, with TEXT being an empty string, print a trailing linefeed, otherwise print an entire debug line with TEXT followed by the hexdump and a final LF. */ -void log_printhex (const char *text, const void *buffer, size_t length); +void log_printhex (const void *buffer, size_t length, const char *text); -void log_clock (const char *string); +void log_clock (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); +#endif /* Use gnupg internal logging functions. */ /* Some handy assertion macros which don't abort. */ diff --git a/common/miscellaneous.c b/common/miscellaneous.c index 62ac05a84..0b374e6c8 100644 --- a/common/miscellaneous.c +++ b/common/miscellaneous.c @@ -45,14 +45,14 @@ my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr) /* Map the log levels. */ switch (level) { - case GCRY_LOG_CONT: level = GPGRT_LOG_CONT; break; - case GCRY_LOG_INFO: level = GPGRT_LOG_INFO; break; - case GCRY_LOG_WARN: level = GPGRT_LOG_WARN; break; - case GCRY_LOG_ERROR:level = GPGRT_LOG_ERROR; break; - case GCRY_LOG_FATAL:level = GPGRT_LOG_FATAL; break; - case GCRY_LOG_BUG: level = GPGRT_LOG_BUG; break; - case GCRY_LOG_DEBUG:level = GPGRT_LOG_DEBUG; break; - default: level = GPGRT_LOG_ERROR; break; + case GCRY_LOG_CONT: level = GPGRT_LOGLVL_CONT; break; + case GCRY_LOG_INFO: level = GPGRT_LOGLVL_INFO; break; + case GCRY_LOG_WARN: level = GPGRT_LOGLVL_WARN; break; + case GCRY_LOG_ERROR:level = GPGRT_LOGLVL_ERROR; break; + case GCRY_LOG_FATAL:level = GPGRT_LOGLVL_FATAL; break; + case GCRY_LOG_BUG: level = GPGRT_LOGLVL_BUG; break; + case GCRY_LOG_DEBUG:level = GPGRT_LOGLVL_DEBUG; break; + default: level = GPGRT_LOGLVL_ERROR; break; } log_logv (level, fmt, arg_ptr); } diff --git a/common/openpgpdefs.h b/common/openpgpdefs.h index 85a4251de..8699a178d 100644 --- a/common/openpgpdefs.h +++ b/common/openpgpdefs.h @@ -51,6 +51,7 @@ typedef enum PKT_ATTRIBUTE = 17, /* PGP's attribute packet. */ PKT_ENCRYPTED_MDC = 18, /* Integrity protected encrypted data. */ PKT_MDC = 19, /* Manipulation detection code packet. */ + PKT_ENCRYPTED_AEAD= 20, /* AEAD encrypted data packet. */ PKT_COMMENT = 61, /* new comment packet (GnuPG specific). */ PKT_GPG_CONTROL = 63 /* internal control packet (GnuPG specific). */ } @@ -115,7 +116,8 @@ typedef enum SIGSUBPKT_FEATURES = 30, /* Feature flags. */ SIGSUBPKT_SIGNATURE = 32, /* Embedded signature. */ - SIGSUBPKT_ISSUER_FPR = 33, /* EXPERIMENTAL: Issuer fingerprint. */ + SIGSUBPKT_ISSUER_FPR = 33, /* Issuer fingerprint. */ + SIGSUBPKT_PREF_AEAD = 34, /* Preferred AEAD algorithms. */ SIGSUBPKT_FLAG_CRITICAL = 128 } @@ -142,6 +144,16 @@ typedef enum cipher_algo_t; +/* Note that we encode the AEAD algo in a 3 bit field at some places. */ +typedef enum + { + AEAD_ALGO_NONE = 0, + AEAD_ALGO_EAX = 1, + AEAD_ALGO_OCB = 2 + } +aead_algo_t; + + typedef enum { PUBKEY_ALGO_RSA = 1, diff --git a/common/pkscreening.c b/common/pkscreening.c new file mode 100644 index 000000000..a3bfb474e --- /dev/null +++ b/common/pkscreening.c @@ -0,0 +1,159 @@ +/* pkscreening.c - Screen public keys for vulnerabilities + * Copyright (C) 2017 Werner Koch + * + * This file is part of GnuPG. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdlib.h> + +#include "util.h" +#include "pkscreening.h" + + +/* Helper */ +static inline gpg_error_t +my_error (gpg_err_code_t ec) +{ + return gpg_err_make (default_errsource, ec); +} + + +/* Emulation of the new gcry_mpi_get_ui function. */ +static gpg_error_t +my_mpi_get_ui (unsigned int *v, gcry_mpi_t a) +{ + gpg_error_t err; + unsigned char buf[8]; + size_t n; + int i, mul; + + if (gcry_mpi_cmp_ui (a, 16384) > 0) + return my_error (GPG_ERR_ERANGE); /* Clearly too large for our purpose. */ + + err = gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, a); + if (err) + return err; + + *v = 0; + for (i = n - 1, mul = 1; i >= 0; i--, mul *= 256) + *v += mul * buf[i]; + + return 0; +} + + +/* Detect whether the MODULUS of a public RSA key is affected by the + * ROCA vulnerability as found in the Infinion RSA library + * (CVE-2017-15361). Returns 0 if not affected, GPG_ERR_TRUE if + * affected, GPG_ERR_BAD_MPI if an opaque RSA was passed, or other + * error codes if something weird happened */ +gpg_error_t +screen_key_for_roca (gcry_mpi_t modulus) +{ + static struct { + unsigned int prime_ui; + const char *print_hex; + gcry_mpi_t prime; + gcry_mpi_t print; + } table[] = { + { 3, "0x6" }, + { 5, "0x1E" }, + { 7, "0x7E" }, + { 11, "0x402" }, + { 13, "0x161A" }, + { 17, "0x1A316" }, + { 19, "0x30AF2" }, + { 23, "0x7FFFFE" }, + { 29, "0x1FFFFFFE" }, + { 31, "0x7FFFFFFE" }, + { 37, "0x4000402" }, + { 41, "0x1FFFFFFFFFE" }, + { 43, "0x7FFFFFFFFFE" }, + { 47, "0x7FFFFFFFFFFE" }, + { 53, "0x12DD703303AED2" }, + { 59, "0x7FFFFFFFFFFFFFE" }, + { 61, "0x1434026619900B0A" }, + { 67, "0x7FFFFFFFFFFFFFFFE" }, + { 71, "0x1164729716B1D977E" }, + { 73, "0x147811A48004962078A" }, + { 79, "0xB4010404000640502" }, + { 83, "0x7FFFFFFFFFFFFFFFFFFFE" }, + { 89, "0x1FFFFFFFFFFFFFFFFFFFFFE" }, + { 97, "0x1000000006000001800000002" }, + { 101, "0x1FFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 103, "0x16380E9115BD964257768FE396" }, + { 107, "0x27816EA9821633397BE6A897E1A" }, + { 109, "0x1752639F4E85B003685CBE7192BA" }, + { 113, "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 127, "0x6CA09850C2813205A04C81430A190536" }, + { 131, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 137, "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 139, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 149, "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 151, "0x50C018BC00482458DAC35B1A2412003D18030A" }, + { 157, "0x161FB414D76AF63826461899071BD5BACA0B7E1A" }, + { 163, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 167, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" } + }; + gpg_error_t err; + int i; + gcry_mpi_t rem; + unsigned int bitno; + + /* Initialize on the first call. */ + if (!table[0].prime) + { + /* We pass primes[i] to the call so that in case of a concurrent + * second thread the already allocated space is reused. */ + for (i = 0; i < DIM (table); i++) + { + table[i].prime = gcry_mpi_set_ui (table[i].prime, table[i].prime_ui); + if (gcry_mpi_scan (&table[i].print, GCRYMPI_FMT_HEX, + table[i].print_hex, 0, NULL)) + BUG (); + } + } + + /* Check that it is not NULL or an opaque MPI. */ + if (!modulus || gcry_mpi_get_flag (modulus, GCRYMPI_FLAG_OPAQUE)) + return my_error (GPG_ERR_BAD_MPI); + + /* We divide the modulus of an RSA public key by a set of small + * PRIMEs and examine all the remainders. If all the bits at the + * index given by the remainder are set in the corresponding PRINT + * masks the key is very likely vulnerable. If any of the tested + * bits is zero, the key is not vulnerable. */ + rem = gcry_mpi_new (0); + for (i = 0; i < DIM (table); i++) + { + gcry_mpi_mod (rem, modulus, table[i].prime); + err = my_mpi_get_ui (&bitno, rem); + if (gpg_err_code (err) == GPG_ERR_ERANGE) + continue; + if (err) + goto leave; + if (!gcry_mpi_test_bit (table[i].print, bitno)) + goto leave; /* Not vulnerable. */ + } + + /* Very likely vulnerable */ + err = my_error (GPG_ERR_TRUE); + + leave: + gcry_mpi_release (rem); + return err; +} diff --git a/common/pkscreening.h b/common/pkscreening.h new file mode 100644 index 000000000..a64758924 --- /dev/null +++ b/common/pkscreening.h @@ -0,0 +1,26 @@ +/* pkscreening.c - Screen public keys for vulnerabilities + * Copyright (C) 2017 Werner Koch + * + * This file is part of GnuPG. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef GNUPG_COMMON_PKSCREENING_H +#define GNUPG_COMMON_PKSCREENING_H + +gpg_error_t screen_key_for_roca (gcry_mpi_t modulus); + + +#endif /*GNUPG_COMMON_PKSCREENING_H*/ diff --git a/common/sysutils.c b/common/sysutils.c index e90010c44..55a7ee9ec 100644 --- a/common/sysutils.c +++ b/common/sysutils.c @@ -340,11 +340,10 @@ gnupg_usleep (unsigned int usecs) struct timespec req; struct timespec rem; - req.tv_sec = 0; - req.tv_nsec = usecs * 1000; - + req.tv_sec = usecs / 1000000; + req.tv_nsec = (usecs % 1000000) * 1000; while (nanosleep (&req, &rem) < 0 && errno == EINTR) - req = rem; + req = rem; } #else /*Standard Unix*/ diff --git a/common/util.h b/common/util.h index c6d19c64b..f3722812d 100644 --- a/common/util.h +++ b/common/util.h @@ -59,6 +59,11 @@ /* Hash function used with libksba. */ #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write) +/* The length of the keygrip. This is a SHA-1 hash of the key + * parameters as generated by gcry_pk_get_keygrip. */ +#define KEYGRIP_LEN 20 + + /* Get all the stuff from jnlib. */ #include "../common/logging.h" #include "../common/argparse.h" diff --git a/configure.ac b/configure.ac index 59a2e6084..0665115dc 100644 --- a/configure.ac +++ b/configure.ac @@ -27,8 +27,8 @@ min_automake_version="1.14" # another commit and push so that the git magic is able to work. m4_define([mym4_package],[gnupg]) m4_define([mym4_major], [2]) -m4_define([mym4_minor], [2]) -m4_define([mym4_micro], [8]) +m4_define([mym4_minor], [3]) +m4_define([mym4_micro], [0]) # To start a new development series, i.e a new major or minor number # you need to mark an arbitrary commit before the first beta release @@ -51,7 +51,7 @@ AC_INIT([mym4_package],[mym4_version], [https://bugs.gnupg.org]) # When changing the SWDB tag please also adjust the hard coded tags in # build-aux/speedo.mk and Makefile.am -AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg22", [swdb tag for this branch]) +AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg24", [swdb tag for this branch]) NEED_GPG_ERROR_VERSION=1.24 @@ -116,8 +116,8 @@ use_tls_library=no large_secmem=no show_tor_support=no - -GNUPG_BUILD_PROGRAM(gpg, yes) +# gpg is a required part and can't be disabled anymore. +build_gpg=yes GNUPG_BUILD_PROGRAM(gpgsm, yes) # The agent is a required part and can't be disabled anymore. build_agent=yes @@ -244,6 +244,15 @@ fi AC_DEFINE_UNQUOTED(SECMEM_BUFFER_SIZE,$SECMEM_BUFFER_SIZE, [Size of secure memory buffer]) +AC_MSG_CHECKING([calibrated passphrase-stretching (s2k) duration]) +AC_ARG_WITH(agent-s2k-calibration, + AC_HELP_STRING([--with-agent-s2k-calibration=MSEC], + [calibrate passphrase stretching (s2k) to MSEC milliseconds]), + agent_s2k_calibration=$withval, agent_s2k_calibration=100) +AC_MSG_RESULT($agent_s2k_calibration milliseconds) +AC_DEFINE_UNQUOTED(AGENT_S2K_CALIBRATION, $agent_s2k_calibration, + [Agent s2k calibration time (ms)]) + AC_MSG_CHECKING([whether to enable trust models]) AC_ARG_ENABLE(trust-models, AC_HELP_STRING([--disable-trust-models], @@ -548,9 +557,12 @@ AH_BOTTOM([ # endif #endif -/* Provide the es_ macro for estream. */ +/* Enable the es_ macros from gpgrt. */ #define GPGRT_ENABLE_ES_MACROS 1 +/* Enable the log_ macros from gpgrt. */ +#define GPGRT_ENABLE_LOG_MACROS 1 + /* Tell libgcrypt not to use its own libgpg-error implementation. */ #define USE_LIBGPG_ERROR 1 @@ -602,7 +614,7 @@ AC_PROG_RANLIB AC_CHECK_TOOL(AR, ar, :) AC_PATH_PROG(PERL,"perl") AC_CHECK_TOOL(WINDRES, windres, :) -AC_PATH_PROG(YAT2M, "yat2m") +AC_PATH_PROG(YAT2M, "yat2m", "./yat2m" ) AC_ARG_VAR(YAT2M, [tool to convert texi to man pages]) AM_CONDITIONAL(HAVE_YAT2M, test -n "$ac_cv_path_YAT2M") AC_ISC_POSIX @@ -1623,7 +1635,7 @@ if test "$GCC" = yes; then AC_MSG_RESULT($_gcc_wopt) fi if test x"$_gcc_wopt" = xyes ; then - mycflags="$mycflags -W -Wno-sign-compare" + mycflags="$mycflags -W -Wno-sign-compare -Wno-format-zero-length" mycflags="$mycflags -Wno-missing-field-initializers" fi @@ -1698,6 +1710,19 @@ AC_ARG_ENABLE(optimization, fi]) # +# log_debug has certain requirements which might hamper portability. +# Thus we use an option to enable it. +# +AC_MSG_CHECKING([whether to enable log_clock]) +AC_ARG_ENABLE(log_clock, + AC_HELP_STRING([--enable-log-clock], + [enable log_clock timestamps]), + enable_log_clock=$enableval, enable_log_clock=no) +AC_MSG_RESULT($enable_log_clock) +if test "$enable_log_clock" = yes ; then + AC_DEFINE(ENABLE_LOG_CLOCK,1,[Defined to use log_clock timestamps]) +fi + # Add -Werror to CFLAGS. This hack can be used to avoid problems with # misbehaving autoconf tests in case the user supplied -Werror. # diff --git a/dirmngr/crlcache.c b/dirmngr/crlcache.c index 0b2fe1641..fbe3beea1 100644 --- a/dirmngr/crlcache.c +++ b/dirmngr/crlcache.c @@ -1349,7 +1349,7 @@ cache_isvalid (ctrl_t ctrl, const char *issuer_hash, { log_error (_("WARNING: invalid cache record length for S/N ")); log_printf ("0x"); - log_printhex ("", sn, snlen); + log_printhex (sn, snlen, ""); } else if (opt.verbose) { diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 31f8e0f46..6fdfe36c2 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -787,12 +787,12 @@ my_ntbtls_log_handler (void *opaque, int level, const char *fmt, va_list argv) (void)opaque; if (level == -1) - log_logv_with_prefix (GPGRT_LOG_INFO, "ntbtls: ", fmt, argv); + log_logv_prefix (GPGRT_LOGLVL_INFO, "ntbtls: ", fmt, argv); else { char prefix[10+20]; snprintf (prefix, sizeof prefix, "ntbtls(%d): ", level); - log_logv_with_prefix (GPGRT_LOG_DEBUG, prefix, fmt, argv); + log_logv_prefix (GPGRT_LOGLVL_DEBUG, prefix, fmt, argv); } } #endif @@ -1203,6 +1203,14 @@ main (int argc, char **argv) current_logfile = xstrdup (logfile); } + if (debug_wait) + { + log_debug ("waiting for debugger - my pid is %u .....\n", + (unsigned int)getpid()); + gnupg_sleep (debug_wait); + log_debug ("... okay\n"); + } + #ifndef HAVE_W32_SYSTEM if (strchr (socket_name, ':')) { diff --git a/dirmngr/http.c b/dirmngr/http.c index 6846107d0..049aefc29 100644 --- a/dirmngr/http.c +++ b/dirmngr/http.c @@ -1101,7 +1101,7 @@ http_start_data (http_t hd) if (!hd->in_data) { if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP)) - log_debug_with_string ("\r\n", "http.c:request-header:"); + log_debug_string ("\r\n", "http.c:request-header:"); es_fputs ("\r\n", hd->fp_write); es_fflush (hd->fp_write); hd->in_data = 1; @@ -1902,7 +1902,7 @@ send_request (http_t hd, const char *httphost, const char *auth, return gpg_err_make (default_errsource, gpg_err_code_from_syserror ()); if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP)) - log_debug_with_string (request, "http.c:request:"); + log_debug_string (request, "http.c:request:"); cookie = xtrycalloc (1, sizeof *cookie); if (! cookie) @@ -2217,7 +2217,7 @@ send_request (http_t hd, const char *httphost, const char *auth, } if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP)) - log_debug_with_string (request, "http.c:request:"); + log_debug_string (request, "http.c:request:"); /* First setup estream so that we can write even the first line using estream. This is also required for the sake of gnutls. */ @@ -2253,7 +2253,7 @@ send_request (http_t hd, const char *httphost, const char *auth, for (;headers; headers=headers->next) { if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP)) - log_debug_with_string (headers->d, "http.c:request-header:"); + log_debug_string (headers->d, "http.c:request-header:"); if ((es_fputs (headers->d, hd->fp_write) || es_fflush (hd->fp_write)) || (es_fputs("\r\n",hd->fp_write) || es_fflush(hd->fp_write))) { @@ -2504,7 +2504,7 @@ parse_response (http_t hd) return GPG_ERR_EOF; if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP)) - log_debug_with_string (line, "http.c:response:\n"); + log_debug_string (line, "http.c:response:\n"); } while (!*line); diff --git a/dirmngr/misc.c b/dirmngr/misc.c index 6291a9a35..1270b834d 100644 --- a/dirmngr/misc.c +++ b/dirmngr/misc.c @@ -284,7 +284,7 @@ dump_string (const char *string) else { log_printf ( "[ "); - log_printhex (NULL, string, strlen (string)); + log_printhex (string, strlen (string), NULL); log_printf ( " ]"); } } diff --git a/doc/DETAILS b/doc/DETAILS index 16e77c79a..52051ed2c 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -237,12 +237,14 @@ described here. *** Field 18 - Compliance flags - Space separated list of asserted compliance modes for this key. + Space separated list of asserted compliance modes and + screening result for this key. Valid values are: - 8 :: The key is compliant with RFC4880bis - 23 :: The key is compliant with compliance mode "de-vs". + - 6001 :: Screening hit on the ROCA vulnerability. *** Field 19 - Last update @@ -534,9 +536,10 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB: actual key used for descryption. <fpr2> is the fingerprint of the primary key. <otrust> is the letter with the ownertrust; this is in general a 'u' which stands for ultimately trusted. -*** DECRYPTION_INFO <mdc_method> <sym_algo> +*** DECRYPTION_INFO <mdc_method> <sym_algo> [<aead_algo>] Print information about the symmetric encryption algorithm and the MDC method. This will be emitted even if the decryption fails. + For an AEAD algorithm AEAD_ALGO is not 0. *** DECRYPTION_FAILED The symmetric decryption failed - one reason could be a wrong @@ -556,8 +559,10 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB: --override-session-key. It is not an indication that the decryption will or has succeeded. -*** BEGIN_ENCRYPTION <mdc_method> <sym_algo> +*** BEGIN_ENCRYPTION <mdc_method> <sym_algo> [<aead_algo>] Mark the start of the actual encryption process. + MDC_METHOD shall be 0 if an AEAD_ALGO is not 0. Users should + however ignore MDC_METHOD if AEAD_ALGO is not 0. *** END_ENCRYPTION Mark the end of the actual encryption process. diff --git a/doc/HACKING b/doc/HACKING index bd1685678..17c58269b 100644 --- a/doc/HACKING +++ b/doc/HACKING @@ -33,9 +33,9 @@ not be copied to the ChangeLog, separate it by a line consisting of two dashes at the begin of a line. The one-line summary usually starts with a keyword to identify the -mainly affected subsystem. If more than one keyword is required the -are delimited by a comma (e.g. =scd,w32:=). Commonly found keywords -are +mainly affected subsystem (that is not the directory). If more than +one keyword is required they are delimited by a comma +(e.g. =scd,w32:=). Commonly found keywords are - agent :: The gpg-agent component - build :: Changes to the build system @@ -207,10 +207,6 @@ Note that such a comment will be removed if the git commit option - The predefined macro =__func__=: : log_debug ("%s: Problem with foo\n", __func__); - - Variable declaration inside a for(): - : for (int i = 0; i < 5; ++) - : bar (i); - Although we usually make use of the =u16=, =u32=, and =u64= types, it is also possible to include =<stdint.h>= and use =int16_t=, =int32_t=, =int64_t=, =uint16_t=, =uint32_t=, and =uint64_t=. But do diff --git a/doc/Makefile.am b/doc/Makefile.am index d47d83ede..cb69cd993 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -22,7 +22,7 @@ AM_CPPFLAGS = include $(top_srcdir)/am/cmacros.am examples = examples/README examples/scd-event examples/trustlist.txt \ - examples/vsnfd.prf examples/debug.prf \ + examples/vsnfd.prf examples/debug.prf examples/qualified.txt \ examples/systemd-user/README \ examples/systemd-user/dirmngr.service \ examples/systemd-user/dirmngr.socket \ @@ -43,7 +43,7 @@ helpfiles = help.txt help.be.txt help.ca.txt help.cs.txt \ profiles = -EXTRA_DIST = samplekeys.asc mksamplekeys com-certs.pem qualified.txt \ +EXTRA_DIST = samplekeys.asc mksamplekeys com-certs.pem \ gnupg-logo.eps gnupg-logo.pdf gnupg-logo.png gnupg-logo-tr.png \ gnupg-module-overview.png gnupg-module-overview.pdf \ gnupg-card-architecture.png gnupg-card-architecture.pdf \ @@ -113,16 +113,8 @@ DISTCLEANFILES = gnupg.tmp gnupg.ops yat2m-stamp.tmp yat2m-stamp \ gnupg-module-overview.eps \ $(myman_pages) gnupg.7 -if HAVE_YAT2M -YAT2M_CMD = $(YAT2M) -YAT2M_DEP = $(YAT2M) -else -YAT2M_CMD = ./yat2m -YAT2M_DEP = yat2m - yat2m: yat2m.c $(CC_FOR_BUILD) -o $@ $(srcdir)/yat2m.c -endif mkdefsinc: mkdefsinc.c Makefile ../config.h $(CC_FOR_BUILD) -I. -I.. -I$(srcdir) $(AM_CPPFLAGS) \ @@ -155,12 +147,12 @@ yat2m-stamp: $(myman_sources) defs.inc @touch yat2m-stamp.tmp incd="`test -f defsincdate || echo '$(srcdir)/'`defsincdate"; \ for file in $(myman_sources) ; do \ - $(YAT2M_CMD) $(YAT2M_OPTIONS) --store \ + $(YAT2M) $(YAT2M_OPTIONS) --store \ --date "`cat $$incd 2>/dev/null`" \ `test -f '$$file' || echo '$(srcdir)/'`$$file ; done @mv -f yat2m-stamp.tmp $@ -yat2m-stamp: $(YAT2M_DEP) +yat2m-stamp: $(YAT2M) $(myman_pages) gnupg.7 : yat2m-stamp defs.inc @if test -f $@; then :; else \ diff --git a/doc/examples/README b/doc/examples/README index 77ee80741..4d6a5be87 100644 --- a/doc/examples/README +++ b/doc/examples/README @@ -9,3 +9,5 @@ trustlist.txt A list of trustworthy root certificates gpgconf.conf A sample configuration file for gpgconf. systemd-user Sample files for a Linux-only init system. + +qualified.txt Sample file for qualified.txt. diff --git a/doc/qualified.txt b/doc/examples/qualified.txt index c0e4da582..eba11f244 100644 --- a/doc/qualified.txt +++ b/doc/examples/qualified.txt @@ -29,7 +29,7 @@ # # Germany # -# The information for Germany is available +# The information for Germany is available # at http://www.bundesnetzagentur.de #******************************************* @@ -74,7 +74,7 @@ DB:45:3D:1B:B0:1A:F3:23:10:6B:DE:D0:09:61:57:AA:F4:25:E0:5B de #Serial number: 02 # Issuer: /CN=9R-CA 1:PN/O=Regulierungsbehörde für # Telekommunikation und Post/C=DE -# Subject: /CN=9R-CA 1:PN/O=Regulierungsbehörde für +# Subject: /CN=9R-CA 1:PN/O=Regulierungsbehörde für # Telekommunikation und Post/C=DE # validity: 2004-11-25 14:59:11 through 2007-12-31 14:56:59 # key type: 1024 bit RSA @@ -118,7 +118,7 @@ A0:8B:DF:3B:AA:EE:3F:9D:64:6C:47:81:23:21:D4:A6:18:81:67:1D de # key usage: certSign # policies: 1.3.36.8.1.1:N: # chain length: unlimited -# [checked: 2008-06-25] +# [checked: 2008-06-25] 44:7E:D4:E3:9A:D7:92:E2:07:FA:53:1A:2E:F5:B8:02:5B:47:57:B0 de # ID: 0x46A2CC8A @@ -130,7 +130,7 @@ A0:8B:DF:3B:AA:EE:3F:9D:64:6C:47:81:23:21:D4:A6:18:81:67:1D de # key usage: certSign # policies: 1.3.36.8.1.1:N: # chain length: unlimited -# [checked: 2008-06-25] +# [checked: 2008-06-25] AC:A7:BE:45:1F:A6:BF:09:F2:D1:3F:08:7B:BC:EB:7F:46:A2:CC:8A de @@ -215,7 +215,7 @@ E0:BF:1B:91:91:6B:88:E4:F1:15:92:22:CE:37:23:96:B1:4A:2E:5C de # key type: 2048 bit RSA # key usage: certSign crlSign # chain length: 1 -#[checked: 2007-12-13 via received ZIP file with qualified signature from +#[checked: 2007-12-13 via received ZIP file with qualified signature from # /CN=Dr. Matthias Stehle/O=Deutscher Sparkassenverlag # /C=DE/SerialNumber=DSV0000000008/SN=Stehle/GN=Matthias Georg] C9:2F:E6:50:DB:32:59:E0:CE:65:55:F3:8C:76:E0:B8:A8:FE:A3:CA de @@ -230,7 +230,7 @@ C9:2F:E6:50:DB:32:59:E0:CE:65:55:F3:8C:76:E0:B8:A8:FE:A3:CA de # key type: 2048 bit RSA # key usage: certSign crlSign # chain length: 1 -#[checked: 2007-12-13 via received ZIP file with qualified signature from +#[checked: 2007-12-13 via received ZIP file with qualified signature from # /CN=Dr. Matthias Stehle/O=Deutscher Sparkassenverlag # /C=DE/SerialNumber=DSV0000000008/SN=Stehle/GN=Matthias Georg"] D5:C7:50:F2:FE:4E:EE:D7:C7:B1:E4:13:7B:FB:54:84:3A:7D:97:9B de diff --git a/doc/gpg.texi b/doc/gpg.texi index 805a01fc3..00ac03308 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2246,6 +2246,16 @@ works properly with such messages, there is often a desire to set a maximum file size that will be generated before processing is forced to stop by the OS limits. Defaults to 0, which means "no limit". +@item --chunk-size @var{n} +@opindex chunk-size +The AEAD encryption mode encrypts the data in chunks so that a +receiving side can check for transmission errors or tampering at the +end of each chunk and does not need to delay this until all data has +been received. The used chunk size is 2^@var{n} byte. The lowest +allowed value for @var{n} is 6 (64 byte) and the largest is 62 (4 +EiB). The default value for @var{n} is 30 which creates chunks not +larger than 1 GiB. + @item --input-size-hint @var{n} @opindex input-size-hint This option can be used to tell GPG the size of the input data in @@ -2583,6 +2593,16 @@ is the default. @itemx --no-force-v4-certs These options are obsolete and have no effect since GnuPG 2.1. +@item --force-aead +@opindex force-aead +Force the use of AEAD encryption over MDC encryption. AEAD is a +modern and faster way to do authenticated encrytion than the old MDC +method. See also options @option{--aead-algo} and +@option{--chunk-size}. + +This option requires the use of option @option{--rfc4880bis} to +declare that a not yet standardized feature is used. + @item --force-mdc @opindex force-mdc Force the use of encryption with a modification detection code. This @@ -2614,6 +2634,16 @@ preferences, as GPG will only select an algorithm that is usable by all recipients. The most highly ranked cipher in this list is also used for the @option{--symmetric} encryption command. +@item --personal-aead-preferences @var{string} +@opindex personal-aead-preferences +Set the list of personal AEAD preferences to @var{string}. Use +@command{@gpgname --version} to get a list of available algorithms, +and use @code{none} to set no preference at all. This allows the user +to safely override the algorithm chosen by the recipient key +preferences, as GPG will only select an algorithm that is usable by +all recipients. The most highly ranked cipher in this list is also +used for the @option{--symmetric} encryption command. + @item --personal-digest-preferences @var{string} @opindex personal-digest-preferences Set the list of personal digest preferences to @var{string}. Use @@ -2820,6 +2850,12 @@ Set all useful debugging flags. Set stdout into line buffered mode. This option is only honored when given on the command line. +@item --debug-set-iobuf-size @var{n} +@opindex debug-iolbf +Change the buffer size of the IOBUFs to @var{n} kilobyte. Using 0 +prints the current size. Note well: This is a maintainer only option +and may thus be changed or removed at any time without notice. + @item --faked-system-time @var{epoch} @opindex faked-system-time This option is only useful for testing; it sets the system time back or @@ -2972,17 +3008,28 @@ Use @var{name} as cipher algorithm. Running the program with the command @option{--version} yields a list of supported algorithms. If this is not used the cipher algorithm is selected from the preferences stored with the key. In general, you do not want to use this option as -it allows you to violate the OpenPGP standard. +it allows you to violate the OpenPGP standard. The option @option{--personal-cipher-preferences} is the safe way to accomplish the same thing. +@item --aead-algo @var{name} +@opindex aead-algo +Specify that the AEAD algorithm @var{name} is to be used. This is +useful for symmetric encryption where no key preference are available +to select the AEAD algorithm. Runing @command{@gpgname} with option +@option{--version} shows the available AEAD algorithms. In general, +you do not want to use this option as it allows you to violate the +OpenPGP standard. The option @option{--personal-aead-preferences} is +the safe way to accomplish the same thing. + @item --digest-algo @var{name} @opindex digest-algo Use @var{name} as the message digest algorithm. Running the program -with the command @option{--version} yields a list of supported algorithms. In -general, you do not want to use this option as it allows you to -violate the OpenPGP standard. @option{--personal-digest-preferences} is the -safe way to accomplish the same thing. +with the command @option{--version} yields a list of supported +algorithms. In general, you do not want to use this option as it +allows you to violate the OpenPGP standard. The option +@option{--personal-digest-preferences} is the safe way to accomplish +the same thing. @item --compress-algo @var{name} @opindex compress-algo @@ -3004,8 +3051,9 @@ significant in low memory situations. Note, however, that PGP (all versions) only supports ZIP compression. Using any algorithm other than ZIP or "none" will make the message unreadable with PGP. In general, you do not want to use this option as it allows you to -violate the OpenPGP standard. @option{--personal-compress-preferences} is the -safe way to accomplish the same thing. +violate the OpenPGP standard. The option +@option{--personal-compress-preferences} is the safe way to accomplish +the same thing. @item --cert-digest-algo @var{name} @opindex cert-digest-algo diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index ebe58bc61..1736ff111 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -852,15 +852,9 @@ purposes. Note that even if a certificate is listed in this file, this does not mean that the certificate is trusted; in general the certificates listed -in this file need to be listed also in @file{trustlist.txt}. - -This is a global file an installed in the data directory -(e.g. @file{@value{DATADIR}/qualified.txt}). GnuPG installs a suitable -file with root certificates as used in Germany. As new Root-CA -certificates may be issued over time, these entries may need to be -updated; new distributions of this software should come with an updated -list but it is still the responsibility of the Administrator to check -that this list is correct. +in this file need to be listed also in @file{trustlist.txt}. This is a global +file an installed in the sysconf directory (e.g. +@file{@value{SYSCONFDIR}/qualified.txt}). Every time @command{gpgsm} uses a certificate for signing or verification this file will be consulted to check whether the certificate under @@ -1082,7 +1076,7 @@ key. The algorithm must be capable of signing. This is a required parameter. The only supported value for @var{algo} is @samp{rsa}. @item Key-Length: @var{nbits} -The requested length of a generated key in bits. Defaults to 2048. +The requested length of a generated key in bits. Defaults to 3072. @item Key-Grip: @var{hexstring} This is optional and used to generate a CSR or certificate for an diff --git a/doc/howto-create-a-server-cert.texi b/doc/howto-create-a-server-cert.texi index 55f1a91a4..30e28bdd0 100644 --- a/doc/howto-create-a-server-cert.texi +++ b/doc/howto-create-a-server-cert.texi @@ -31,14 +31,14 @@ Let's continue: @cartouche @example - What keysize do you want? (2048) - Requested keysize is 2048 bits + What keysize do you want? (3072) + Requested keysize is 3072 bits @end example @end cartouche -Hitting enter chooses the default RSA key size of 2048 bits. Smaller -keys are too weak on the modern Internet. If you choose a larger -(stronger) key, your server will need to do more work. +Hitting enter chooses the default RSA key size of 3072 bits. Keys +smaller than 2048 bits are too weak on the modern Internet. If you +choose a larger (stronger) key, your server will need to do more work. @cartouche @example @@ -124,7 +124,7 @@ request: @example These parameters are used: Key-Type: RSA - Key-Length: 2048 + Key-Length: 3072 Key-Usage: sign, encrypt Name-DN: CN=example.com Name-DNS: example.com @@ -224,7 +224,7 @@ To see the content of your certificate, you may now enter: aka: (dns-name example.com) aka: (dns-name www.example.com) validity: 2015-07-01 16:20:51 through 2016-07-01 16:20:51 - key type: 2048 bit RSA + key type: 3072 bit RSA key usage: digitalSignature keyEncipherment ext key usage: clientAuth (suggested), serverAuth (suggested), [...] fingerprint: 0F:9C:27:B2:DA:05:5F:CB:33:D8:19:E9:65:B9:4F:BD:B1:98:CC:57 diff --git a/doc/wks.texi b/doc/wks.texi index 6d622828f..4508ae2a1 100644 --- a/doc/wks.texi +++ b/doc/wks.texi @@ -338,10 +338,11 @@ the submission address: The output of the last command looks similar to this: @example - sec rsa2048 2016-08-30 [SC] + sec rsa3072 2016-08-30 [SC] C0FCF8642D830C53246211400346653590B3795B uid [ultimate] key-submission@@example.net - ssb rsa2048 2016-08-30 [E] + bxzcxpxk8h87z1k7bzk86xn5aj47intu@@example.net + ssb rsa3072 2016-08-30 [E] @end example Take the fingerprint from that output and manually publish the key: diff --git a/g10/Makefile.am b/g10/Makefile.am index cc4ef5cb6..b8b92d702 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -131,7 +131,8 @@ gpg_sources = server.c \ passphrase.c \ decrypt.c \ decrypt-data.c \ - cipher.c \ + cipher-cfb.c \ + cipher-aead.c \ encrypt.c \ sign.c \ verify.c \ diff --git a/g10/build-packet.c b/g10/build-packet.c index d4a1d6a53..b4e03d007 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -42,6 +42,7 @@ static u32 calc_plaintext( PKT_plaintext *pt ); static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt ); static int do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed ); static int do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed ); +static int do_encrypted_aead (iobuf_t out, int ctb, PKT_encrypted *ed); static int do_compressed( IOBUF out, int ctb, PKT_compressed *cd ); static int do_signature( IOBUF out, int ctb, PKT_signature *sig ); static int do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops ); @@ -106,6 +107,7 @@ build_packet (IOBUF out, PACKET *pkt) break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: + case PKT_ENCRYPTED_AEAD: new_ctb = pkt->pkt.encrypted->new_ctb; break; case PKT_COMPRESSED: @@ -158,6 +160,9 @@ build_packet (IOBUF out, PACKET *pkt) case PKT_ENCRYPTED_MDC: rc = do_encrypted_mdc (out, ctb, pkt->pkt.encrypted); break; + case PKT_ENCRYPTED_AEAD: + rc = do_encrypted_aead (out, ctb, pkt->pkt.encrypted); + break; case PKT_COMPRESSED: rc = do_compressed (out, ctb, pkt->pkt.compressed); break; @@ -612,11 +617,8 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc ) IOBUF a = iobuf_temp(); log_assert (ctb_pkttype (ctb) == PKT_SYMKEY_ENC); + log_assert (enc->version == 4 || enc->version == 5); - /* The only acceptable version. */ - log_assert( enc->version == 4 ); - - /* RFC 4880, Section 3.7. */ switch (enc->s2k.mode) { case 0: /* Simple S2K. */ @@ -627,23 +629,26 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc ) default: log_bug ("do_symkey_enc: s2k=%d\n", enc->s2k.mode); } - iobuf_put( a, enc->version ); - iobuf_put( a, enc->cipher_algo ); - iobuf_put( a, enc->s2k.mode ); - iobuf_put( a, enc->s2k.hash_algo ); - if( enc->s2k.mode == 1 || enc->s2k.mode == 3 ) { - iobuf_write(a, enc->s2k.salt, 8 ); - if( enc->s2k.mode == 3 ) - iobuf_put(a, enc->s2k.count); + iobuf_put (a, enc->version); + iobuf_put (a, enc->cipher_algo); + if (enc->version == 5) + iobuf_put (a, enc->aead_algo); + iobuf_put (a, enc->s2k.mode); + iobuf_put (a, enc->s2k.hash_algo); + if (enc->s2k.mode == 1 || enc->s2k.mode == 3) + { + iobuf_write (a, enc->s2k.salt, 8); + if (enc->s2k.mode == 3) + iobuf_put (a, enc->s2k.count); } - if( enc->seskeylen ) - iobuf_write(a, enc->seskey, enc->seskeylen ); + if (enc->seskeylen) + iobuf_write (a, enc->seskey, enc->seskeylen); - write_header(out, ctb, iobuf_get_temp_length(a) ); - rc = iobuf_write_temp( out, a ); + write_header (out, ctb, iobuf_get_temp_length(a)); + rc = iobuf_write_temp (out, a); - iobuf_close(a); - return rc; + iobuf_close (a); + return rc; } @@ -812,6 +817,32 @@ do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed ) } +/* Serialize the symmetrically AEAD encrypted data packet + * (rfc4880bis-03, Section 5.16) described by ED and write it to OUT. + * + * Note: this only writes only packet's header. The caller must then + * follow up and write the actual encrypted data. This should be done + * by pushing the the cipher_filter_aead. */ +static int +do_encrypted_aead (iobuf_t out, int ctb, PKT_encrypted *ed) +{ + u32 n; + + log_assert (ctb_pkttype (ctb) == PKT_ENCRYPTED_AEAD); + + n = ed->len ? (ed->len + ed->extralen + 4) : 0; + write_header (out, ctb, n ); + iobuf_writebyte (out, 1); /* Version. */ + iobuf_writebyte (out, ed->cipher_algo); + iobuf_writebyte (out, ed->aead_algo); + iobuf_writebyte (out, ed->chunkbyte); + + /* This is all. The caller has to write the encrypted data */ + + return 0; +} + + /* Serialize the compressed packet (RFC 4880, Section 5.6) described by CD and write it to OUT. diff --git a/g10/call-agent.c b/g10/call-agent.c index 6ee82a5a4..1445f4e44 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -195,7 +195,7 @@ warn_version_mismatch (assuan_context_t ctx, const char *servername, int mode) err = get_assuan_server_version (ctx, mode, &serverversion); if (err) log_log (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED? - GPGRT_LOG_INFO : GPGRT_LOG_ERROR, + GPGRT_LOGLVL_INFO : GPGRT_LOGLVL_ERROR, _("error getting version from '%s': %s\n"), servername, gpg_strerror (err)); else if (compare_version_strings (serverversion, myversion) < 0) @@ -1512,7 +1512,7 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock) char *p; kbnode_t kbctx, node; int nkeys; - unsigned char grip[20]; + unsigned char grip[KEYGRIP_LEN]; err = start_agent (ctrl, 0); if (err) @@ -1892,10 +1892,16 @@ agent_pksign (ctrl_t ctrl, const char *cache_nonce, snprintf (line, sizeof line, "PKSIGN%s%s", cache_nonce? " -- ":"", cache_nonce? cache_nonce:""); + + if (DBG_CLOCK) + log_clock ("enter signing"); err = assuan_transact (agent_ctx, line, put_membuf_cb, &data, default_inq_cb, &dfltparm, NULL, NULL); + if (DBG_CLOCK) + log_clock ("leave signing"); + if (err) xfree (get_membuf (&data, NULL)); else diff --git a/g10/card-util.c b/g10/card-util.c index 3148de0fa..587f181f2 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -553,9 +553,9 @@ current_card_status (ctrl_t ctrl, estream_t fp, print_isoname (fp, "Name of cardholder: ", "name", info.disp_name); print_name (fp, "Language prefs ...: ", info.disp_lang); - tty_fprintf (fp, "Sex ..............: %s\n", - info.disp_sex == 1? _("male"): - info.disp_sex == 2? _("female") : _("unspecified")); + tty_fprintf (fp, "Salutation .......: %s\n", + info.disp_sex == 1? _("Mr."): + info.disp_sex == 2? _("Mrs.") : ""); print_name (fp, "URL of public key : ", info.pubkey_url); print_name (fp, "Login data .......: ", info.login_data); if (info.private_do[0]) @@ -1119,7 +1119,7 @@ change_sex (void) int rc; data = cpr_get ("cardedit.change_sex", - _("Sex ((M)ale, (F)emale or space): ")); + _("Salutation (M = Mr., F = Mrs., or space): ")); if (!data) return -1; trim_spaces (data); @@ -1140,7 +1140,7 @@ change_sex (void) rc = agent_scd_setattr ("DISP-SEX", str, 1, NULL ); if (rc) - log_error ("error setting sex: %s\n", gpg_strerror (rc)); + log_error ("error setting salutation: %s\n", gpg_strerror (rc)); xfree (data); write_sc_op_status (rc); return rc; @@ -1153,7 +1153,8 @@ change_cafpr (int fprno) char *data; const char *s; int i, c, rc; - unsigned char fpr[20]; + unsigned char fpr[MAX_FINGERPRINT_LEN]; + int fprlen; data = cpr_get ("cardedit.change_cafpr", _("CA fingerprint: ")); if (!data) @@ -1161,7 +1162,7 @@ change_cafpr (int fprno) trim_spaces (data); cpr_kill_prompt (); - for (i=0, s=data; i < 20 && *s; ) + for (i=0, s=data; i < MAX_FINGERPRINT_LEN && *s; ) { while (spacep(s)) s++; @@ -1175,8 +1176,9 @@ change_cafpr (int fprno) fpr[i++] = c; s += 2; } + fprlen = i; xfree (data); - if (i != 20 || *s) + if ((fprlen != 20 && fprlen != 32) || *s) { tty_printf (_("Error: invalid formatted fingerprint.\n")); return -1; @@ -1184,7 +1186,7 @@ change_cafpr (int fprno) rc = agent_scd_setattr (fprno==1?"CA-FPR-1": fprno==2?"CA-FPR-2": - fprno==3?"CA-FPR-3":"x", fpr, 20, NULL ); + fprno==3?"CA-FPR-3":"x", fpr, fprlen, NULL ); if (rc) log_error ("error setting cafpr: %s\n", gpg_strerror (rc)); write_sc_op_status (rc); @@ -1346,12 +1348,11 @@ show_keysize_warning (void) return; shown = 1; tty_printf - (_("Note: There is no guarantee that the card " - "supports the requested size.\n" - " If the key generation does not succeed, " - "please check the\n" - " documentation of your card to see what " - "sizes are allowed.\n")); + (_("Note: There is no guarantee that the card supports the requested\n" + " key type or size. If the key generation does not succeed,\n" + " please check the documentation of your card to see which\n" + " key types and sizes are supported.\n") + ); } @@ -2134,7 +2135,8 @@ static struct { "fetch" , cmdFETCH , 0, N_("fetch the key specified in the card URL")}, { "login" , cmdLOGIN , 1, N_("change the login name")}, { "lang" , cmdLANG , 1, N_("change the language preferences")}, - { "sex" , cmdSEX , 1, N_("change card holder's sex")}, + { "salutation",cmdSEX , 1, N_("change card holder's salutation")}, + { "sex" ,cmdSEX , 1, NULL }, /* Backward compatibility. */ { "cafpr" , cmdCAFPR , 1, N_("change a CA fingerprint")}, { "forcesig", cmdFORCESIG, 1, N_("toggle the signature force PIN flag")}, { "generate", cmdGENERATE, 1, N_("generate new keys")}, diff --git a/g10/cipher-aead.c b/g10/cipher-aead.c new file mode 100644 index 000000000..f9a996c80 --- /dev/null +++ b/g10/cipher-aead.c @@ -0,0 +1,448 @@ +/* cipher-aead.c - Enciphering filter for AEAD modes + * Copyright (C) 2018 Werner koch + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-3.0+ + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "gpg.h" +#include "../common/status.h" +#include "../common/iobuf.h" +#include "../common/util.h" +#include "filter.h" +#include "packet.h" +#include "options.h" +#include "main.h" + + +/* The size of the buffer we allocate to encrypt the data. This must + * be a multiple of the OCB blocksize (16 byte). */ +#define AEAD_ENC_BUFFER_SIZE (64*1024) + + +/* Wrapper around iobuf_write to make sure that a proper error code is + * always returned. */ +static gpg_error_t +my_iobuf_write (iobuf_t a, const void *buffer, size_t buflen) +{ + if (iobuf_write (a, buffer, buflen)) + { + gpg_error_t err = iobuf_error (a); + if (!err || !gpg_err_code (err)) /* (The latter should never happen) */ + err = gpg_error (GPG_ERR_EIO); + return err; + } + return 0; +} + + +/* Set the nonce and the additional data for the current chunk. If + * FINAL is set the final AEAD chunk is processed. This also reset + * the encryption machinery so that the handle can be used for a new + * chunk. */ +static gpg_error_t +set_nonce_and_ad (cipher_filter_context_t *cfx, int final) +{ + gpg_error_t err; + unsigned char nonce[16]; + unsigned char ad[21]; + int i; + + switch (cfx->dek->use_aead) + { + case AEAD_ALGO_OCB: + memcpy (nonce, cfx->startiv, 15); + i = 7; + break; + + case AEAD_ALGO_EAX: + memcpy (nonce, cfx->startiv, 16); + i = 8; + break; + + default: + BUG (); + } + + nonce[i++] ^= cfx->chunkindex >> 56; + nonce[i++] ^= cfx->chunkindex >> 48; + nonce[i++] ^= cfx->chunkindex >> 40; + nonce[i++] ^= cfx->chunkindex >> 32; + nonce[i++] ^= cfx->chunkindex >> 24; + nonce[i++] ^= cfx->chunkindex >> 16; + nonce[i++] ^= cfx->chunkindex >> 8; + nonce[i++] ^= cfx->chunkindex; + + if (DBG_CRYPTO) + log_printhex (nonce, 15, "nonce:"); + err = gcry_cipher_setiv (cfx->cipher_hd, nonce, i); + if (err) + return err; + + ad[0] = (0xc0 | PKT_ENCRYPTED_AEAD); + ad[1] = 1; + ad[2] = cfx->dek->algo; + ad[3] = cfx->dek->use_aead; + ad[4] = cfx->chunkbyte; + ad[5] = cfx->chunkindex >> 56; + ad[6] = cfx->chunkindex >> 48; + ad[7] = cfx->chunkindex >> 40; + ad[8] = cfx->chunkindex >> 32; + ad[9] = cfx->chunkindex >> 24; + ad[10]= cfx->chunkindex >> 16; + ad[11]= cfx->chunkindex >> 8; + ad[12]= cfx->chunkindex; + if (final) + { + ad[13] = cfx->total >> 56; + ad[14] = cfx->total >> 48; + ad[15] = cfx->total >> 40; + ad[16] = cfx->total >> 32; + ad[17] = cfx->total >> 24; + ad[18] = cfx->total >> 16; + ad[19] = cfx->total >> 8; + ad[20] = cfx->total; + } + if (DBG_CRYPTO) + log_printhex (ad, final? 21 : 13, "authdata:"); + return gcry_cipher_authenticate (cfx->cipher_hd, ad, final? 21 : 13); +} + + +static gpg_error_t +write_header (cipher_filter_context_t *cfx, iobuf_t a) +{ + gpg_error_t err; + PACKET pkt; + PKT_encrypted ed; + unsigned int blocksize; + unsigned int startivlen; + enum gcry_cipher_modes ciphermode; + + log_assert (cfx->dek->use_aead); + + blocksize = openpgp_cipher_get_algo_blklen (cfx->dek->algo); + if (blocksize != 16 ) + log_fatal ("unsupported blocksize %u for AEAD\n", blocksize); + + err = openpgp_aead_algo_info (cfx->dek->use_aead, &ciphermode, &startivlen); + if (err) + goto leave; + + log_assert (opt.chunk_size >= 6 && opt.chunk_size <= 62); + cfx->chunkbyte = opt.chunk_size - 6; + cfx->chunksize = (uint64_t)1 << (cfx->chunkbyte + 6); + cfx->chunklen = 0; + cfx->bufsize = AEAD_ENC_BUFFER_SIZE; + cfx->buflen = 0; + cfx->buffer = xtrymalloc (cfx->bufsize); + if (!cfx->buffer) + return gpg_error_from_syserror (); + + memset (&ed, 0, sizeof ed); + ed.new_ctb = 1; /* (Is anyway required for the packet type). */ + ed.len = 0; /* fixme: cfx->datalen */ + ed.extralen = startivlen + 16; /* (16 is the taglen) */ + ed.cipher_algo = cfx->dek->algo; + ed.aead_algo = cfx->dek->use_aead; + ed.chunkbyte = cfx->chunkbyte; + + init_packet (&pkt); + pkt.pkttype = PKT_ENCRYPTED_AEAD; + pkt.pkt.encrypted = &ed; + + if (DBG_FILTER) + log_debug ("aead packet: len=%lu extralen=%d\n", + (unsigned long)ed.len, ed.extralen); + + write_status_printf (STATUS_BEGIN_ENCRYPTION, "0 %d %d", + cfx->dek->algo, ed.aead_algo); + print_cipher_algo_note (cfx->dek->algo); + + if (build_packet( a, &pkt)) + log_bug ("build_packet(ENCRYPTED_AEAD) failed\n"); + + log_assert (sizeof cfx->startiv >= startivlen); + gcry_randomize (cfx->startiv, startivlen, GCRY_STRONG_RANDOM); + err = my_iobuf_write (a, cfx->startiv, startivlen); + if (err) + goto leave; + + err = openpgp_cipher_open (&cfx->cipher_hd, + cfx->dek->algo, + ciphermode, + GCRY_CIPHER_SECURE); + if (err) + goto leave; + + if (DBG_CRYPTO) + log_printhex (cfx->dek->key, cfx->dek->keylen, "thekey:"); + err = gcry_cipher_setkey (cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen); + if (err) + return err; + + cfx->wrote_header = 1; + + leave: + return err; +} + + +/* Get and write the auth tag to stream A. */ +static gpg_error_t +write_auth_tag (cipher_filter_context_t *cfx, iobuf_t a) +{ + gpg_error_t err; + char tag[16]; + + err = gcry_cipher_gettag (cfx->cipher_hd, tag, 16); + if (err) + goto leave; + err = my_iobuf_write (a, tag, 16); + if (err) + goto leave; + + leave: + if (err) + log_error ("write_auth_tag failed: %s\n", gpg_strerror (err)); + return err; +} + + +/* Write the final chunk to stream A. */ +static gpg_error_t +write_final_chunk (cipher_filter_context_t *cfx, iobuf_t a) +{ + gpg_error_t err; + char dummy[1]; + + err = set_nonce_and_ad (cfx, 1); + if (err) + goto leave; + + gcry_cipher_final (cfx->cipher_hd); + + /* Encrypt an empty string. */ + err = gcry_cipher_encrypt (cfx->cipher_hd, dummy, 0, NULL, 0); + if (err) + goto leave; + + err = write_auth_tag (cfx, a); + + leave: + return err; +} + + +/* The core of the flush sub-function of cipher_filter_aead. */ +static gpg_error_t +do_flush (cipher_filter_context_t *cfx, iobuf_t a, byte *buf, size_t size) +{ + gpg_error_t err = 0; + int finalize = 0; + size_t n; + + /* Put the data into a buffer, flush and encrypt as needed. */ + if (DBG_FILTER) + log_debug ("flushing %zu bytes (cur buflen=%zu)\n", size, cfx->buflen); + do + { + if (cfx->buflen + size < cfx->bufsize) + n = size; + else + n = cfx->bufsize - cfx->buflen; + + if (cfx->chunklen + cfx->buflen + n >= cfx->chunksize) + { + size_t n1 = cfx->chunksize - (cfx->chunklen + cfx->buflen); + finalize = 1; + if (DBG_FILTER) + log_debug ("chunksize %ju reached;" + " cur buflen=%zu using %zu of %zu\n", + (uintmax_t)cfx->chunksize, (uintmax_t)cfx->buflen, + n1, n); + n = n1; + } + + memcpy (cfx->buffer + cfx->buflen, buf, n); + cfx->buflen += n; + buf += n; + size -= n; + + if (cfx->buflen == cfx->bufsize || finalize) + { + if (DBG_FILTER) + log_debug ("encrypting: size=%zu buflen=%zu %s n=%zu\n", + size, cfx->buflen, finalize?"(finalize)":"", n); + + if (!cfx->chunklen) + { + if (DBG_FILTER) + log_debug ("start encrypting a new chunk\n"); + err = set_nonce_and_ad (cfx, 0); + if (err) + goto leave; + } + + if (finalize) + gcry_cipher_final (cfx->cipher_hd); + if (DBG_FILTER) + { + if (finalize) + log_printhex (cfx->buffer, cfx->buflen, "plain(1):"); + else if (cfx->buflen > 32) + log_printhex (cfx->buffer + cfx->buflen - 32, 32, + "plain(last32):"); + } + + /* Take care: even with a buflen of zero an encrypt needs to + * be called after gcry_cipher_final and before + * gcry_cipher_gettag - at least with libgcrypt 1.8 and OCB + * mode. */ + err = gcry_cipher_encrypt (cfx->cipher_hd, cfx->buffer, cfx->buflen, + NULL, 0); + if (err) + goto leave; + if (finalize && DBG_FILTER) + log_printhex (cfx->buffer, cfx->buflen, "ciphr(1):"); + err = my_iobuf_write (a, cfx->buffer, cfx->buflen); + if (err) + goto leave; + cfx->chunklen += cfx->buflen; + cfx->total += cfx->buflen; + cfx->buflen = 0; + + if (finalize) + { + if (DBG_FILTER) + log_debug ("writing tag: chunklen=%ju total=%ju\n", + (uintmax_t)cfx->chunklen, (uintmax_t)cfx->total); + err = write_auth_tag (cfx, a); + if (err) + goto leave; + + cfx->chunkindex++; + cfx->chunklen = 0; + finalize = 0; + } + } + } + while (size); + + leave: + return err; +} + + +/* The core of the free sub-function of cipher_filter_aead. */ +static gpg_error_t +do_free (cipher_filter_context_t *cfx, iobuf_t a) +{ + gpg_error_t err = 0; + + if (DBG_FILTER) + log_debug ("do_free: buflen=%zu\n", cfx->buflen); + + if (cfx->buflen) + { + if (DBG_FILTER) + log_debug ("encrypting last %zu bytes of the last chunk\n",cfx->buflen); + + if (!cfx->chunklen) + { + if (DBG_FILTER) + log_debug ("start encrypting a new chunk\n"); + err = set_nonce_and_ad (cfx, 0); + if (err) + goto leave; + } + + gcry_cipher_final (cfx->cipher_hd); + err = gcry_cipher_encrypt (cfx->cipher_hd, cfx->buffer, cfx->buflen, + NULL, 0); + if (err) + goto leave; + err = my_iobuf_write (a, cfx->buffer, cfx->buflen); + if (err) + goto leave; + /* log_printhex (cfx->buffer, cfx->buflen, "wrote:"); */ + cfx->chunklen += cfx->buflen; + cfx->total += cfx->buflen; + + /* Get and write the authentication tag. */ + if (DBG_FILTER) + log_debug ("writing tag: chunklen=%ju total=%ju\n", + (uintmax_t)cfx->chunklen, (uintmax_t)cfx->total); + err = write_auth_tag (cfx, a); + if (err) + goto leave; + cfx->chunkindex++; + cfx->chunklen = 0; + } + + /* Write the final chunk. */ + if (DBG_FILTER) + log_debug ("creating final chunk\n"); + err = write_final_chunk (cfx, a); + + leave: + xfree (cfx->buffer); + cfx->buffer = NULL; + gcry_cipher_close (cfx->cipher_hd); + cfx->cipher_hd = NULL; + return err; +} + + +/* + * This filter is used to encrypt data with an AEAD algorithm + */ +int +cipher_filter_aead (void *opaque, int control, + iobuf_t a, byte *buf, size_t *ret_len) +{ + cipher_filter_context_t *cfx = opaque; + size_t size = *ret_len; + int rc = 0; + + if (control == IOBUFCTRL_UNDERFLOW) /* decrypt */ + { + rc = -1; /* not used */ + } + else if (control == IOBUFCTRL_FLUSH) /* encrypt */ + { + if (!cfx->wrote_header && (rc=write_header (cfx, a))) + ; + else + rc = do_flush (cfx, a, buf, size); + } + else if (control == IOBUFCTRL_FREE) + { + rc = do_free (cfx, a); + } + else if (control == IOBUFCTRL_DESC) + { + mem2str (buf, "cipher_filter_aead", *ret_len); + } + + return rc; +} diff --git a/g10/cipher.c b/g10/cipher-cfb.c index b950d0c3f..79b21bd8a 100644 --- a/g10/cipher.c +++ b/g10/cipher-cfb.c @@ -1,4 +1,4 @@ -/* cipher.c - En-/De-ciphering filter +/* cipher-cfb.c - Enciphering filter for the old CFB mode. * Copyright (C) 1998-2003, 2006, 2009 Free Software Foundation, Inc. * Copyright (C) 1998-2003, 2006, 2009, 2017 Werner koch * @@ -117,7 +117,8 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a) * This filter is used to en/de-cipher data with a symmetric algorithm */ int -cipher_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len) +cipher_filter_cfb (void *opaque, int control, + iobuf_t a, byte *buf, size_t *ret_len) { cipher_filter_context_t *cfx = opaque; size_t size = *ret_len; @@ -177,7 +178,7 @@ cipher_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len) } else if (control == IOBUFCTRL_DESC) { - mem2str (buf, "cipher_filter", *ret_len); + mem2str (buf, "cipher_filter_cfb", *ret_len); } return rc; diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c index 736534d75..a3151b5ed 100644 --- a/g10/decrypt-data.c +++ b/g10/decrypt-data.c @@ -1,6 +1,6 @@ /* decrypt-data.c - Decrypt an encrypted data packet - * Copyright (C) 1998, 1999, 2000, 2001, 2005, - * 2006, 2009 Free Software Foundation, Inc. + * Copyright (C) 1998-2001, 2005-2006, 2009 Free Software Foundation, Inc. + * Copyright (C) 1998-2001, 2005-2006, 2009, 2018 Werner Koch * * This file is part of GnuPG. * @@ -32,22 +32,70 @@ #include "../common/compliance.h" +static int aead_decode_filter (void *opaque, int control, iobuf_t a, + byte *buf, size_t *ret_len); static int mdc_decode_filter ( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len); static int decode_filter ( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len); -typedef struct decode_filter_context_s +/* Our context object. */ +struct decode_filter_context_s { + /* Recounter (max value is 2). We need it becuase we do not know + * whether the iobuf or the outer control code frees this object + * first. */ + int refcount; + + /* The cipher handle. */ gcry_cipher_hd_t cipher_hd; + + /* The hash handle for use in MDC mode. */ gcry_md_hd_t mdc_hash; - char defer[22]; - int defer_filled; - int eof_seen; - int refcount; - int partial; /* Working on a partial length packet. */ - size_t length; /* If !partial: Remaining bytes in the packet. */ -} *decode_filter_ctx_t; + + /* The start IV for AEAD encryption. */ + byte startiv[16]; + + /* The holdback buffer and its used length. For AEAD we need 32+1 + * bytes but we use 48 byte. For MDC we need 22 bytes. */ + char holdback[48]; + unsigned int holdbacklen; + + /* Working on a partial length packet. */ + unsigned int partial : 1; + + /* EOF indicator with these true values: + * 1 = normal EOF + * 2 = premature EOF (tag incomplete) + * 3 = premature EOF (general) */ + unsigned int eof_seen : 2; + + /* The actually used cipher algo for AEAD. */ + byte cipher_algo; + + /* The AEAD algo. */ + byte aead_algo; + + /* The encoded chunk byte for AEAD. */ + byte chunkbyte; + + /* The decoded CHUNKBYTE. */ + uint64_t chunksize; + + /* The chunk index for AEAD. */ + uint64_t chunkindex; + + /* The number of bytes in the current chunk. */ + uint64_t chunklen; + + /* The total count of decrypted plaintext octets. */ + uint64_t total; + + /* Remaining bytes in the packet according to the packet header. + * Not used if PARTIAL is true. */ + size_t length; +}; +typedef struct decode_filter_context_s *decode_filter_ctx_t; /* Helper to release the decode context. */ @@ -69,6 +117,99 @@ release_dfx_context (decode_filter_ctx_t dfx) } +/* Set the nonce and the additional data for the current chunk. This + * also reset the decryption machinery * so that the handle can be + * used for a new chunk. If FINAL is set the final AEAD chunk is + * processed. */ +static gpg_error_t +aead_set_nonce_and_ad (decode_filter_ctx_t dfx, int final) +{ + gpg_error_t err; + unsigned char ad[21]; + unsigned char nonce[16]; + int i; + + switch (dfx->aead_algo) + { + case AEAD_ALGO_OCB: + memcpy (nonce, dfx->startiv, 15); + i = 7; + break; + + case AEAD_ALGO_EAX: + memcpy (nonce, dfx->startiv, 16); + i = 8; + break; + + default: + BUG (); + } + nonce[i++] ^= dfx->chunkindex >> 56; + nonce[i++] ^= dfx->chunkindex >> 48; + nonce[i++] ^= dfx->chunkindex >> 40; + nonce[i++] ^= dfx->chunkindex >> 32; + nonce[i++] ^= dfx->chunkindex >> 24; + nonce[i++] ^= dfx->chunkindex >> 16; + nonce[i++] ^= dfx->chunkindex >> 8; + nonce[i++] ^= dfx->chunkindex; + + if (DBG_CRYPTO) + log_printhex (nonce, i, "nonce:"); + err = gcry_cipher_setiv (dfx->cipher_hd, nonce, i); + if (err) + return err; + + ad[0] = (0xc0 | PKT_ENCRYPTED_AEAD); + ad[1] = 1; + ad[2] = dfx->cipher_algo; + ad[3] = dfx->aead_algo; + ad[4] = dfx->chunkbyte; + ad[5] = dfx->chunkindex >> 56; + ad[6] = dfx->chunkindex >> 48; + ad[7] = dfx->chunkindex >> 40; + ad[8] = dfx->chunkindex >> 32; + ad[9] = dfx->chunkindex >> 24; + ad[10]= dfx->chunkindex >> 16; + ad[11]= dfx->chunkindex >> 8; + ad[12]= dfx->chunkindex; + if (final) + { + ad[13] = dfx->total >> 56; + ad[14] = dfx->total >> 48; + ad[15] = dfx->total >> 40; + ad[16] = dfx->total >> 32; + ad[17] = dfx->total >> 24; + ad[18] = dfx->total >> 16; + ad[19] = dfx->total >> 8; + ad[20] = dfx->total; + } + if (DBG_CRYPTO) + log_printhex (ad, final? 21 : 13, "authdata:"); + return gcry_cipher_authenticate (dfx->cipher_hd, ad, final? 21 : 13); +} + + +/* Helper to check the 16 byte tag in TAGBUF. The FINAL flag is only + * for debug messages. */ +static gpg_error_t +aead_checktag (decode_filter_ctx_t dfx, int final, const void *tagbuf) +{ + gpg_error_t err; + + if (DBG_FILTER) + log_printhex (tagbuf, 16, "tag:"); + err = gcry_cipher_checktag (dfx->cipher_hd, tagbuf, 16); + if (err) + { + log_error ("gcry_cipher_checktag%s failed: %s\n", + final? " (final)":"", gpg_strerror (err)); + return err; + } + if (DBG_FILTER) + log_debug ("%stag is valid\n", final?"final ":""); + return 0; +} + /**************** * Decrypt the data, specified by ED with the key DEK. @@ -80,8 +221,8 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) byte *p; int rc=0, c, i; byte temp[32]; - unsigned blocksize; - unsigned nprefix; + unsigned int blocksize; + unsigned int nprefix; dfx = xtrycalloc (1, sizeof *dfx); if (!dfx) @@ -91,8 +232,10 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) if ( opt.verbose && !dek->algo_info_printed ) { if (!openpgp_cipher_test_algo (dek->algo)) - log_info (_("%s encrypted data\n"), - openpgp_cipher_algo_name (dek->algo)); + log_info (_("%s.%s encrypted data\n"), + openpgp_cipher_algo_name (dek->algo), + ed->aead_algo? openpgp_aead_algo_name (ed->aead_algo) + /**/ : "CFB"); else log_info (_("encrypted with unknown algorithm %d\n"), dek->algo ); dek->algo_info_printed = 1; @@ -109,19 +252,18 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) goto leave; } - { - char buf[20]; - - snprintf (buf, sizeof buf, "%d %d", ed->mdc_method, dek->algo); - write_status_text (STATUS_DECRYPTION_INFO, buf); - } + write_status_printf (STATUS_DECRYPTION_INFO, "%d %d %d", + ed->mdc_method, dek->algo, ed->aead_algo); if (opt.show_session_key) { - char numbuf[25]; + char numbuf[30]; char *hexbuf; - snprintf (numbuf, sizeof numbuf, "%d:", dek->algo); + if (ed->aead_algo) + snprintf (numbuf, sizeof numbuf, "%d.%u:", dek->algo, ed->aead_algo); + else + snprintf (numbuf, sizeof numbuf, "%d:", dek->algo); hexbuf = bin2hex (dek->key, dek->keylen, NULL); if (!hexbuf) { @@ -139,95 +281,188 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) blocksize = openpgp_cipher_get_algo_blklen (dek->algo); if ( !blocksize || blocksize > 16 ) log_fatal ("unsupported blocksize %u\n", blocksize ); - nprefix = blocksize; - if ( ed->len && ed->len < (nprefix+2) ) + if (ed->aead_algo) { - /* An invalid message. We can't check that during parsing - because we may not know the used cipher then. */ - rc = gpg_error (GPG_ERR_INV_PACKET); - goto leave; - } + enum gcry_cipher_modes ciphermode; + unsigned int startivlen; - if ( ed->mdc_method ) - { - if (gcry_md_open (&dfx->mdc_hash, ed->mdc_method, 0 )) - BUG (); - if ( DBG_HASHING ) - gcry_md_debug (dfx->mdc_hash, "checkmdc"); - } + if (blocksize != 16) + { + rc = gpg_error (GPG_ERR_CIPHER_ALGO); + goto leave; + } - rc = openpgp_cipher_open (&dfx->cipher_hd, dek->algo, - GCRY_CIPHER_MODE_CFB, - (GCRY_CIPHER_SECURE - | ((ed->mdc_method || dek->algo >= 100)? - 0 : GCRY_CIPHER_ENABLE_SYNC))); - if (rc) - { - /* We should never get an error here cause we already checked - * that the algorithm is available. */ - BUG(); - } + rc = openpgp_aead_algo_info (ed->aead_algo, &ciphermode, &startivlen); + if (rc) + goto leave; + log_assert (startivlen <= sizeof dfx->startiv); + if (ed->chunkbyte > 56) + { + log_error ("invalid AEAD chunkbyte %u\n", ed->chunkbyte); + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } - /* log_hexdump( "thekey", dek->key, dek->keylen );*/ - rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen); - if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY ) - { - log_info(_("WARNING: message was encrypted with" - " a weak key in the symmetric cipher.\n")); - rc=0; - } - else if( rc ) - { - log_error("key setup failed: %s\n", gpg_strerror (rc) ); - goto leave; - } + /* Read the Start-IV. */ + if (ed->len) + { + for (i=0; i < startivlen && ed->len; i++, ed->len--) + { + if ((c=iobuf_get (ed->buf)) == -1) + break; + dfx->startiv[i] = c; + } + } + else + { + for (i=0; i < startivlen; i++ ) + if ( (c=iobuf_get (ed->buf)) == -1 ) + break; + else + dfx->startiv[i] = c; + } + if (i != startivlen) + { + log_error ("Start-IV in AEAD packet too short (%d/%u)\n", + i, startivlen); + rc = gpg_error (GPG_ERR_TOO_SHORT); + goto leave; + } - if (!ed->buf) - { - log_error(_("problem handling encrypted packet\n")); - goto leave; - } + dfx->cipher_algo = ed->cipher_algo; + dfx->aead_algo = ed->aead_algo; + dfx->chunkbyte = ed->chunkbyte; + dfx->chunksize = (uint64_t)1 << (dfx->chunkbyte + 6); - gcry_cipher_setiv (dfx->cipher_hd, NULL, 0); + if (dek->algo != dfx->cipher_algo) + log_info ("Note: different cipher algorithms used (%s/%s)\n", + openpgp_cipher_algo_name (dek->algo), + openpgp_cipher_algo_name (dfx->cipher_algo)); - if ( ed->len ) - { - for (i=0; i < (nprefix+2) && ed->len; i++, ed->len-- ) + rc = openpgp_cipher_open (&dfx->cipher_hd, + dfx->cipher_algo, + ciphermode, + GCRY_CIPHER_SECURE); + if (rc) + goto leave; /* Should never happen. */ + + if (DBG_CRYPTO) + log_printhex (dek->key, dek->keylen, "thekey:"); + rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen); + if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY) { - if ( (c=iobuf_get(ed->buf)) == -1 ) - break; - else - temp[i] = c; + log_info (_("WARNING: message was encrypted with" + " a weak key in the symmetric cipher.\n")); + rc = 0; } + else if (rc) + { + log_error("key setup failed: %s\n", gpg_strerror (rc)); + goto leave; + } + + if (!ed->buf) + { + log_error(_("problem handling encrypted packet\n")); + goto leave; + } + } - else + else /* CFB encryption. */ { - for (i=0; i < (nprefix+2); i++ ) - if ( (c=iobuf_get(ed->buf)) == -1 ) - break; - else - temp[i] = c; - } + nprefix = blocksize; + if ( ed->len && ed->len < (nprefix+2) ) + { + /* An invalid message. We can't check that during parsing + because we may not know the used cipher then. */ + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } - gcry_cipher_decrypt (dfx->cipher_hd, temp, nprefix+2, NULL, 0); - gcry_cipher_sync (dfx->cipher_hd); - p = temp; - /* log_hexdump( "prefix", temp, nprefix+2 ); */ - if (dek->symmetric - && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) ) - { - rc = gpg_error (GPG_ERR_BAD_KEY); - goto leave; - } + if ( ed->mdc_method ) + { + if (gcry_md_open (&dfx->mdc_hash, ed->mdc_method, 0 )) + BUG (); + if ( DBG_HASHING ) + gcry_md_debug (dfx->mdc_hash, "checkmdc"); + } - if ( dfx->mdc_hash ) - gcry_md_write (dfx->mdc_hash, temp, nprefix+2); + rc = openpgp_cipher_open (&dfx->cipher_hd, dek->algo, + GCRY_CIPHER_MODE_CFB, + (GCRY_CIPHER_SECURE + | ((ed->mdc_method || dek->algo >= 100)? + 0 : GCRY_CIPHER_ENABLE_SYNC))); + if (rc) + { + /* We should never get an error here cause we already checked + * that the algorithm is available. */ + BUG(); + } + + + /* log_hexdump( "thekey", dek->key, dek->keylen );*/ + rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen); + if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY ) + { + log_info(_("WARNING: message was encrypted with" + " a weak key in the symmetric cipher.\n")); + rc=0; + } + else if( rc ) + { + log_error("key setup failed: %s\n", gpg_strerror (rc) ); + goto leave; + } + + if (!ed->buf) + { + log_error(_("problem handling encrypted packet\n")); + goto leave; + } + + gcry_cipher_setiv (dfx->cipher_hd, NULL, 0); + + if ( ed->len ) + { + for (i=0; i < (nprefix+2) && ed->len; i++, ed->len-- ) + { + if ( (c=iobuf_get(ed->buf)) == -1 ) + break; + else + temp[i] = c; + } + } + else + { + for (i=0; i < (nprefix+2); i++ ) + if ( (c=iobuf_get(ed->buf)) == -1 ) + break; + else + temp[i] = c; + } + + gcry_cipher_decrypt (dfx->cipher_hd, temp, nprefix+2, NULL, 0); + gcry_cipher_sync (dfx->cipher_hd); + p = temp; + /* log_hexdump( "prefix", temp, nprefix+2 ); */ + if (dek->symmetric + && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) ) + { + rc = gpg_error (GPG_ERR_BAD_KEY); + goto leave; + } + + if ( dfx->mdc_hash ) + gcry_md_write (dfx->mdc_hash, temp, nprefix+2); + } dfx->refcount++; - dfx->partial = ed->is_partial; + dfx->partial = !!ed->is_partial; dfx->length = ed->len; - if ( ed->mdc_method ) + if (ed->aead_algo) + iobuf_push_filter ( ed->buf, aead_decode_filter, dfx ); + else if (ed->mdc_method) iobuf_push_filter ( ed->buf, mdc_decode_filter, dfx ); else iobuf_push_filter ( ed->buf, decode_filter, dfx ); @@ -287,16 +522,16 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) log_assert (dfx->cipher_hd); log_assert (dfx->mdc_hash); - gcry_cipher_decrypt (dfx->cipher_hd, dfx->defer, 22, NULL, 0); - gcry_md_write (dfx->mdc_hash, dfx->defer, 2); + gcry_cipher_decrypt (dfx->cipher_hd, dfx->holdback, 22, NULL, 0); + gcry_md_write (dfx->mdc_hash, dfx->holdback, 2); gcry_md_final (dfx->mdc_hash); - if ( dfx->defer[0] != '\xd3' - || dfx->defer[1] != '\x14' + if ( dfx->holdback[0] != '\xd3' + || dfx->holdback[1] != '\x14' || datalen != 20 - || memcmp (gcry_md_read (dfx->mdc_hash, 0), dfx->defer+2, datalen)) + || memcmp (gcry_md_read (dfx->mdc_hash, 0), dfx->holdback+2, datalen)) rc = gpg_error (GPG_ERR_BAD_SIGNATURE); - /* log_printhex("MDC message:", dfx->defer, 22); */ + /* log_printhex("MDC message:", dfx->holdback, 22); */ /* log_printhex("MDC calc:", gcry_md_read (dfx->mdc_hash,0), datalen); */ } @@ -307,6 +542,329 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) } +/* Fill BUFFER with up to NBYTES-OFFSET from STREAM utilizing + * information from the context DFX. Returns the new offset which is + * the number of bytes read plus the original offset. On EOF the + * respective flag in DFX is set. */ +static size_t +fill_buffer (decode_filter_ctx_t dfx, iobuf_t stream, + byte *buffer, size_t nbytes, size_t offset) +{ + size_t nread = offset; + int c; + + if (dfx->partial) + { + for (; nread < nbytes; nread++ ) + { + if ((c = iobuf_get (stream)) == -1) + { + dfx->eof_seen = 1; /* Normal EOF. */ + break; + } + buffer[nread] = c; + } + } + else + { + for (; nread < nbytes && dfx->length; nread++, dfx->length--) + { + c = iobuf_get (stream); + if (c == -1) + { + dfx->eof_seen = 3; /* Premature EOF. */ + break; + } + buffer[nread] = c; + } + if (!dfx->length) + dfx->eof_seen = 1; /* Normal EOF. */ + } + + return nread; +} + + +/* The core of the AEAD decryption. This is the underflow function of + * the aead_decode_filter. */ +static gpg_error_t +aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len) +{ + const size_t size = *ret_len; /* The allocated size of BUF. */ + gpg_error_t err; + size_t totallen = 0; /* The number of bytes to return on success or EOF. */ + size_t off = 0; /* The offset into the buffer. */ + size_t len; /* The current number of bytes in BUF+OFF. */ + + log_assert (size > 48); /* Our code requires at least this size. */ + + /* Copy the rest from the last call of this function into BUF. */ + len = dfx->holdbacklen; + dfx->holdbacklen = 0; + memcpy (buf, dfx->holdback, len); + + if (DBG_FILTER) + log_debug ("aead_underflow: size=%zu len=%zu%s%s\n", size, len, + dfx->partial? " partial":"", dfx->eof_seen? " eof":""); + + /* Read and fill up BUF. We need to watch out for an EOF so that we + * can detect the last chunk which is commonly shorter than the + * chunksize. After the last data byte from the last chunk 32 more + * bytes are expected for the last chunk's tag and the following + * final chunk's tag. To detect the EOF we need to try reading at least + * one further byte; however we try to read 16 extra bytes to avoid + * single byte reads in some lower layers. The outcome is that we + * have up to 48 extra extra octets which we will later put into the + * holdback buffer for the next invocation (which handles the EOF + * case). */ + len = fill_buffer (dfx, a, buf, size, len); + if (len < 32) + { + /* Not enough data for the last two tags. */ + err = gpg_error (GPG_ERR_TRUNCATED); + goto leave; + } + if (dfx->eof_seen) + { + /* If have seen an EOF we copy only the last two auth tags into + * the holdback buffer. */ + dfx->holdbacklen = 32; + memcpy (dfx->holdback, buf+len-32, 32); + len -= 32; + } + else + { + /* If have not seen an EOF we copy the entire extra 48 bytes + * into the holdback buffer for processing at the next call of + * this function. */ + dfx->holdbacklen = len > 48? 48 : len; + memcpy (dfx->holdback, buf+len-dfx->holdbacklen, dfx->holdbacklen); + len -= dfx->holdbacklen; + } + /* log_printhex (dfx->holdback, dfx->holdbacklen, "holdback:"); */ + + /* Decrypt the buffer. This first requires a loop to handle the + * case when a chunk ends within the buffer. */ + if (DBG_FILTER) + log_debug ("decrypt: chunklen=%ju total=%ju size=%zu len=%zu%s\n", + (uintmax_t)dfx->chunklen, (uintmax_t)dfx->total, size, len, + dfx->eof_seen? " eof":""); + + while (len && dfx->chunklen + len >= dfx->chunksize) + { + size_t n = dfx->chunksize - dfx->chunklen; + byte tagbuf[16]; + + if (DBG_FILTER) + log_debug ("chunksize will be reached: n=%zu\n", n); + + if (!dfx->chunklen) + { + /* First data for this chunk - prepare. */ + err = aead_set_nonce_and_ad (dfx, 0); + if (err) + goto leave; + } + + /* log_printhex (buf, n, "ciph:"); */ + gcry_cipher_final (dfx->cipher_hd); + err = gcry_cipher_decrypt (dfx->cipher_hd, buf+off, n, NULL, 0); + if (err) + { + log_error ("gcry_cipher_decrypt failed (1): %s\n", + gpg_strerror (err)); + goto leave; + } + /* log_printhex (buf, n, "plai:"); */ + totallen += n; + dfx->chunklen += n; + dfx->total += n; + off += n; + len -= n; + + if (DBG_FILTER) + log_debug ("ndecrypted: %zu (nchunk=%zu) bytes left: %zu at off=%zu\n", + totallen, dfx->chunklen, len, off); + + /* Check the tag. */ + if (len < 16) + { + /* The tag is not entirely in the buffer. Read the rest of + * the tag from the holdback buffer. Then shift the holdback + * buffer and fill it up again. */ + memcpy (tagbuf, buf+off, len); + memcpy (tagbuf + len, dfx->holdback, 16 - len); + dfx->holdbacklen -= 16-len; + memmove (dfx->holdback, dfx->holdback + (16-len), dfx->holdbacklen); + + if (dfx->eof_seen) + { + /* We should have the last chunk's tag in TAGBUF and the + * final tag in HOLDBACKBUF. */ + if (len || dfx->holdbacklen != 16) + { + /* Not enough data for the last two tags. */ + err = gpg_error (GPG_ERR_TRUNCATED); + goto leave; + } + } + else + { + len = 0; + dfx->holdbacklen = fill_buffer (dfx, a, dfx->holdback, 48, + dfx->holdbacklen); + if (dfx->holdbacklen < 32) + { + /* Not enough data for the last two tags. */ + err = gpg_error (GPG_ERR_TRUNCATED); + goto leave; + } + } + } + else /* We already have the full tag. */ + { + memcpy (tagbuf, buf+off, 16); + /* Remove that tag from the output. */ + memmove (buf + off, buf + off + 16, len - 16); + len -= 16; + } + err = aead_checktag (dfx, 0, tagbuf); + if (err) + goto leave; + dfx->chunklen = 0; + dfx->chunkindex++; + + continue; + } + + /* The bulk decryption of our buffer. */ + if (len) + { + if (!dfx->chunklen) + { + /* First data for this chunk - prepare. */ + err = aead_set_nonce_and_ad (dfx, 0); + if (err) + goto leave; + } + + if (dfx->eof_seen) + { + /* This is the last block of the last chunk. Its length may + * not be a multiple of the block length. */ + gcry_cipher_final (dfx->cipher_hd); + } + err = gcry_cipher_decrypt (dfx->cipher_hd, buf + off, len, NULL, 0); + if (err) + { + log_error ("gcry_cipher_decrypt failed (2): %s\n", + gpg_strerror (err)); + goto leave; + } + totallen += len; + dfx->chunklen += len; + dfx->total += len; + if (DBG_FILTER) + log_debug ("ndecrypted: %zu (nchunk=%zu)\n", totallen, dfx->chunklen); + } + + if (dfx->eof_seen) + { + + if (dfx->chunklen) + { + if (DBG_FILTER) + log_debug ("eof seen: holdback has the last and final tag\n"); + log_assert (dfx->holdbacklen >= 32); + err = aead_checktag (dfx, 0, dfx->holdback); + if (err) + goto leave; + dfx->chunklen = 0; + dfx->chunkindex++; + off = 16; + } + else + { + if (DBG_FILTER) + log_debug ("eof seen: holdback has the final tag\n"); + log_assert (dfx->holdbacklen >= 16); + off = 0; + } + + /* Check the final chunk. */ + err = aead_set_nonce_and_ad (dfx, 1); + if (err) + goto leave; + gcry_cipher_final (dfx->cipher_hd); + /* Decrypt an empty string (using HOLDBACK as a dummy). */ + err = gcry_cipher_decrypt (dfx->cipher_hd, dfx->holdback, 0, NULL, 0); + if (err) + { + log_error ("gcry_cipher_decrypt failed (final): %s\n", + gpg_strerror (err)); + goto leave; + } + err = aead_checktag (dfx, 1, dfx->holdback+off); + if (err) + goto leave; + err = gpg_error (GPG_ERR_EOF); + } + + leave: + if (DBG_FILTER) + log_debug ("aead_underflow: returning %zu (%s)\n", + totallen, gpg_strerror (err)); + + /* In case of an auth error we map the error code to the same as + * used by the MDC decryption. */ + if (gpg_err_code (err) == GPG_ERR_CHECKSUM) + err = gpg_error (GPG_ERR_BAD_SIGNATURE); + + /* In case of an error we better wipe out the buffer than to convey + * partly decrypted data. */ + if (err && gpg_err_code (err) != GPG_ERR_EOF) + memset (buf, 0, size); + + *ret_len = totallen; + + return err; +} + + +/* The IOBUF filter used to decrypt AEAD encrypted data. */ +static int +aead_decode_filter (void *opaque, int control, IOBUF a, + byte *buf, size_t *ret_len) +{ + decode_filter_ctx_t dfx = opaque; + int rc = 0; + + if ( control == IOBUFCTRL_UNDERFLOW && dfx->eof_seen ) + { + *ret_len = 0; + rc = -1; + } + else if ( control == IOBUFCTRL_UNDERFLOW ) + { + log_assert (a); + + rc = aead_underflow (dfx, a, buf, ret_len); + if (gpg_err_code (rc) == GPG_ERR_EOF) + rc = -1; /* We need to use the old convention in the filter. */ + + } + else if ( control == IOBUFCTRL_FREE ) + { + release_dfx_context (dfx); + } + else if ( control == IOBUFCTRL_DESC ) + { + mem2str (buf, "aead_decode_filter", *ret_len); + } + + return rc; +} + static int mdc_decode_filter (void *opaque, int control, IOBUF a, @@ -357,15 +915,16 @@ mdc_decode_filter (void *opaque, int control, IOBUF a, } if (n == 44) { - /* We have enough stuff - flush the deferred stuff. */ - if ( !dfx->defer_filled ) /* First time. */ + /* We have enough stuff - flush the holdback buffer. */ + if ( !dfx->holdbacklen ) /* First time. */ { memcpy (buf, buf+22, 22); n = 22; } else { - memcpy (buf, dfx->defer, 22); + + memcpy (buf, dfx->holdback, 22); } /* Fill up the buffer. */ if (dfx->partial) @@ -396,13 +955,13 @@ mdc_decode_filter (void *opaque, int control, IOBUF a, dfx->eof_seen = 1; /* Normal EOF. */ } - /* Move the trailing 22 bytes back to the defer buffer. We + /* Move the trailing 22 bytes back to the holdback buffer. We have at least 44 bytes thus a memmove is not needed. */ n -= 22; - memcpy (dfx->defer, buf+n, 22 ); - dfx->defer_filled = 1; + memcpy (dfx->holdback, buf+n, 22 ); + dfx->holdbacklen = 22; } - else if ( !dfx->defer_filled ) /* EOF seen but empty defer buffer. */ + else if ( !dfx->holdbacklen ) /* EOF seen but empty holdback. */ { /* This is bad because it means an incomplete hash. */ n -= 22; @@ -411,9 +970,9 @@ mdc_decode_filter (void *opaque, int control, IOBUF a, } else /* EOF seen (i.e. read less than 22 bytes). */ { - memcpy (buf, dfx->defer, 22 ); + memcpy (buf, dfx->holdback, 22 ); n -= 22; - memcpy (dfx->defer, buf+n, 22 ); + memcpy (dfx->holdback, buf+n, 22 ); dfx->eof_seen = 1; /* Normal EOF. */ } @@ -1,5 +1,5 @@ /* dek.h - The data encryption key structure. - * Copyright (C) 2014 Werner Koch + * Copyright (C) 2014, 2017 Werner Koch * * This file is part of GnuPG. * @@ -26,14 +26,25 @@ typedef struct int algo; /* The length of the key (in bytes). */ int keylen; + /* Whether we've already printed information about this key. This - is currently only used in decrypt_data() and only if we are in - verbose mode. */ - int algo_info_printed; - int use_mdc; + * is currently only used in decrypt_data() and only if we are in + * verbose mode. */ + int algo_info_printed : 1; + + /* AEAD shall be used. The value is the AEAD algo. */ + int use_aead : 4; + + /* MDC shall be used. */ + int use_mdc : 1; + /* This key was read from a SK-ESK packet (see proc_symkey_enc). */ - int symmetric; - byte key[32]; /* This is the largest used keylen (256 bit). */ + int symmetric : 1; + + /* This is the largest used keylen (256 bit). */ + byte key[32]; + + /* The cacheid for the S2K. */ char s2k_cacheid[1+16+1]; } DEK; diff --git a/g10/ecdh.c b/g10/ecdh.c index 6c2a56b84..6587cc4b4 100644 --- a/g10/ecdh.c +++ b/g10/ecdh.c @@ -76,7 +76,7 @@ pk_ecdh_default_params (unsigned int qbits) } log_assert (i < DIM (kek_params_table)); if (DBG_CRYPTO) - log_printhex ("ECDH KEK params are", kek_params, sizeof(kek_params) ); + log_printhex (kek_params, sizeof(kek_params), "ECDH KEK params are"); return gcry_mpi_set_opaque (NULL, kek_params, 4 * 8); } @@ -159,7 +159,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, 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 ); + log_printhex (secret_x, secret_x_size, "ECDH shared secret X is:"); } /*** We have now the shared secret bytes in secret_x. ***/ @@ -179,7 +179,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, kek_params_size = (nbits+7)/8; if (DBG_CRYPTO) - log_printhex ("ecdh KDF params:", kek_params, kek_params_size); + log_printhex (kek_params, kek_params_size, "ecdh KDF params:"); /* Expect 4 bytes 03 01 hash_alg symm_alg. */ if (kek_params_size != 4 || kek_params[0] != 3 || kek_params[1] != 1) @@ -236,7 +236,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, } if(DBG_CRYPTO) - log_printhex ("ecdh KDF message params are:", message, message_size); + log_printhex (message, message_size, "ecdh KDF message params are:"); } /* Derive a KEK (key wrapping key) using MESSAGE and SECRET_X. */ @@ -272,7 +272,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, /* We could have allocated more, so clean the tail before returning. */ memset (secret_x+secret_x_size, 0, old_size - secret_x_size); if (DBG_CRYPTO) - log_printhex ("ecdh KEK is:", secret_x, secret_x_size ); + log_printhex (secret_x, secret_x_size, "ecdh KEK is:"); } /* And, finally, aeswrap with key secret_x. */ @@ -338,7 +338,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, } if (DBG_CRYPTO) - log_printhex ("ecdh encrypting :", in, data_buf_size ); + log_printhex (in, data_buf_size, "ecdh encrypting :"); err = gcry_cipher_encrypt (hd, data_buf+1, data_buf_size+8, in, data_buf_size); @@ -354,7 +354,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, data_buf[0] = data_buf_size+8; if (DBG_CRYPTO) - log_printhex ("ecdh encrypted to:", data_buf+1, data_buf[0] ); + log_printhex (data_buf+1, data_buf[0], "ecdh encrypted to:"); result = gcry_mpi_set_opaque (NULL, data_buf, 8 * (1+data_buf[0])); if (!result) @@ -391,7 +391,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, data_buf_size = data_buf[0]; if (DBG_CRYPTO) - log_printhex ("ecdh decrypting :", data_buf+1, data_buf_size); + log_printhex (data_buf+1, data_buf_size, "ecdh decrypting :"); err = gcry_cipher_decrypt (hd, in, data_buf_size, data_buf+1, data_buf_size); @@ -407,7 +407,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, data_buf_size -= 8; if (DBG_CRYPTO) - log_printhex ("ecdh decrypted to :", in, data_buf_size); + log_printhex (in, data_buf_size, "ecdh decrypted to :"); /* Padding is removed later. */ /* if (in[data_buf_size-1] > 8 ) */ diff --git a/g10/encrypt.c b/g10/encrypt.c index c68d6d5d1..c6c9e3a03 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -47,12 +47,12 @@ static int write_pubkey_enc_from_list (ctrl_t ctrl, /**************** * Encrypt FILENAME with only the symmetric cipher. Take input from - * stdin if FILENAME is NULL. + * stdin if FILENAME is NULL. If --force-aead is used we use an SKESK. */ int encrypt_symmetric (const char *filename) { - return encrypt_simple( filename, 1, 0 ); + return encrypt_simple( filename, 1, opt.force_aead); } @@ -67,45 +67,173 @@ encrypt_store (const char *filename) } -/* *SESKEY contains the unencrypted session key ((*SESKEY)->KEY) and - the algorithm that will be used to encrypt the contents of the SED - packet ((*SESKEY)->ALGO). If *SESKEY is NULL, then a random - session key that is appropriate for DEK->ALGO is generated and - stored there. - - Encrypt that session key using DEK and store the result in ENCKEY, - which must be large enough to hold (*SESKEY)->KEYLEN + 1 bytes. */ -void -encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey) +/* Encrypt a session key using DEK and store a pointer to the result + * at R_ENCKEY and its length at R_ENCKEYLEN. + * + * R_SESKEY points to the unencrypted session key (.KEY, .KEYLEN) and + * the algorithm that will be used to encrypt the contents of the + * SKESK packet (.ALGO). If R_SESKEY points to NULL, then a random + * session key that is appropriate for DEK->ALGO is generated and + * stored at R_SESKEY. If AEAD_ALGO is not 0 the given AEAD algorithm + * is used for encryption. + */ +gpg_error_t +encrypt_seskey (DEK *dek, aead_algo_t aead_algo, + DEK **r_seskey, void **r_enckey, size_t *r_enckeylen) { - gcry_cipher_hd_t hd; - byte buf[33]; + gpg_error_t err; + gcry_cipher_hd_t hd = NULL; + byte *buf = NULL; + DEK *seskey; + + *r_enckey = NULL; + *r_enckeylen = 0; - log_assert ( dek->keylen <= 32 ); - if (!*seskey) + if (*r_seskey) + seskey = *r_seskey; + else { - *seskey=xmalloc_clear(sizeof(DEK)); - (*seskey)->algo=dek->algo; - make_session_key(*seskey); + seskey = xtrycalloc (1, sizeof(DEK)); + if (!seskey) + { + err = gpg_error_from_syserror (); + goto leave; + } + seskey->algo = dek->algo; + make_session_key (seskey); /*log_hexdump( "thekey", c->key, c->keylen );*/ } - /* The encrypted session key is prefixed with a one-octet algorithm id. */ - buf[0] = (*seskey)->algo; - memcpy( buf + 1, (*seskey)->key, (*seskey)->keylen ); - - /* We only pass already checked values to the following function, - thus we consider any failure as fatal. */ - if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1)) - BUG (); - if (gcry_cipher_setkey (hd, dek->key, dek->keylen)) - BUG (); - gcry_cipher_setiv (hd, NULL, 0); - gcry_cipher_encrypt (hd, buf, (*seskey)->keylen + 1, NULL, 0); + + if (aead_algo) + { + unsigned int noncelen; + enum gcry_cipher_modes ciphermode; + byte ad[4]; + + err = openpgp_aead_algo_info (aead_algo, &ciphermode, &noncelen); + if (err) + goto leave; + + /* Allocate space for the nonce, the key, and the authentication + * tag (16). */ + buf = xtrymalloc_secure (noncelen + seskey->keylen + 16); + if (!buf) + { + err = gpg_error_from_syserror (); + goto leave; + } + + gcry_randomize (buf, noncelen, GCRY_STRONG_RANDOM); + + err = openpgp_cipher_open (&hd, dek->algo, + ciphermode, GCRY_CIPHER_SECURE); + if (!err) + err = gcry_cipher_setkey (hd, dek->key, dek->keylen); + if (!err) + err = gcry_cipher_setiv (hd, buf, noncelen); + if (err) + goto leave; + + ad[0] = (0xc0 | PKT_SYMKEY_ENC); + ad[1] = 5; + ad[2] = dek->algo; + ad[3] = aead_algo; + err = gcry_cipher_authenticate (hd, ad, 4); + if (err) + goto leave; + + memcpy (buf + noncelen, seskey->key, seskey->keylen); + gcry_cipher_final (hd); + err = gcry_cipher_encrypt (hd, buf + noncelen, seskey->keylen, NULL,0); + if (err) + goto leave; + err = gcry_cipher_gettag (hd, buf + noncelen + seskey->keylen, 16); + if (err) + goto leave; + *r_enckeylen = noncelen + seskey->keylen + 16; + *r_enckey = buf; + buf = NULL; + } + else + { + /* In the old version 4 SKESK the encrypted session key is + * prefixed with a one-octet algorithm id. */ + buf = xtrymalloc_secure (1 + seskey->keylen); + if (!buf) + { + err = gpg_error_from_syserror (); + goto leave; + } + buf[0] = seskey->algo; + memcpy (buf + 1, seskey->key, seskey->keylen); + + err = openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1); + if (!err) + err = gcry_cipher_setkey (hd, dek->key, dek->keylen); + if (!err) + err = gcry_cipher_setiv (hd, NULL, 0); + if (!err) + err = gcry_cipher_encrypt (hd, buf, seskey->keylen + 1, NULL, 0); + if (err) + goto leave; + *r_enckeylen = seskey->keylen + 1; + *r_enckey = buf; + buf = NULL; + } + + /* Return the session key in case we allocated it. */ + *r_seskey = seskey; + seskey = NULL; + + leave: gcry_cipher_close (hd); + if (seskey != *r_seskey) + xfree (seskey); + xfree (buf); + return err; +} + + +/* Return the AEAD algo if we shall use AEAD mode. Returns 0 if AEAD + * shall not be used. */ +aead_algo_t +use_aead (pk_list_t pk_list, int algo) +{ + int can_use; + + if (!opt.flags.rfc4880bis) + { + if (opt.force_aead) + log_info ("Warning: Option %s currently requires option '%s'\n", + "--force-aead", "--rfc4880bis"); + return 0; + } + + can_use = openpgp_cipher_get_algo_blklen (algo) == 16; + + /* With --force-mdc we clearly do not want AEAD. */ + if (opt.force_mdc) + return 0; + + /* However with --force-aead we want AEAD. */ + if (opt.force_aead) + { + if (!can_use) + { + log_info ("Warning: request to use AEAD ignored for cipher '%s'\n", + openpgp_cipher_algo_name (algo)); + return 0; + } + return default_aead_algo (); + } - memcpy( enckey, buf, (*seskey)->keylen + 1 ); - wipememory( buf, sizeof buf ); /* burn key */ + /* AEAD does only work with 128 bit cipher blocklength. */ + if (!can_use) + return 0; + + /* If all keys support AEAD we can use it. */ + return select_aead_from_pklist (pk_list); } @@ -174,9 +302,9 @@ encrypt_simple (const char *filename, int mode, int use_seskey) PACKET pkt; PKT_plaintext *pt = NULL; STRING2KEY *s2k = NULL; - byte enckey[33]; + void *enckey = NULL; + size_t enckeylen = 0; int rc = 0; - int seskeylen = 0; u32 filesize; cipher_filter_context_t cfx; armor_filter_context_t *afx = NULL; @@ -229,6 +357,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey) if ( mode ) { int canceled; + aead_algo_t aead_algo; s2k = xmalloc_clear( sizeof *s2k ); s2k->mode = opt.s2k_mode; @@ -252,23 +381,42 @@ encrypt_simple (const char *filename, int mode, int use_seskey) "due to the S2K mode\n")); } + /* See whether we want to use AEAD. */ + aead_algo = use_aead (NULL, cfx.dek->algo); + if ( use_seskey ) { DEK *dek = NULL; - seskeylen = openpgp_cipher_get_algo_keylen (default_cipher_algo ()); - encrypt_seskey( cfx.dek, &dek, enckey ); - xfree( cfx.dek ); cfx.dek = dek; + rc = encrypt_seskey (cfx.dek, aead_algo, &dek, &enckey, &enckeylen); + if (rc) + { + xfree (cfx.dek); + xfree (s2k); + iobuf_close (inp); + release_progress_context (pfx); + return rc; + } + /* Replace key in DEK. */ + xfree (cfx.dek); + cfx.dek = dek; } - if (opt.verbose) - log_info(_("using cipher %s\n"), - openpgp_cipher_algo_name (cfx.dek->algo)); + if (aead_algo) + cfx.dek->use_aead = aead_algo; + else + cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo); - cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo); + if (opt.verbose) + log_info(_("using cipher %s.%s\n"), + openpgp_cipher_algo_name (cfx.dek->algo), + cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead) + /**/ : "CFB"); } - if (do_compress && cfx.dek && cfx.dek->use_mdc + if (do_compress + && cfx.dek + && (cfx.dek->use_mdc || cfx.dek->use_aead) && is_file_compressed(filename, &rc)) { if (opt.verbose) @@ -293,20 +441,24 @@ encrypt_simple (const char *filename, int mode, int use_seskey) if ( s2k ) { - PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc + seskeylen + 1 ); - enc->version = 4; + /* Fixme: This is quite similar to write_symkey_enc. */ + PKT_symkey_enc *enc = xmalloc_clear (sizeof *enc + enckeylen); + enc->version = cfx.dek->use_aead ? 5 : 4; enc->cipher_algo = cfx.dek->algo; + enc->aead_algo = cfx.dek->use_aead; enc->s2k = *s2k; - if ( use_seskey && seskeylen ) + if (enckeylen) { - enc->seskeylen = seskeylen + 1; /* algo id */ - memcpy (enc->seskey, enckey, seskeylen + 1 ); + enc->seskeylen = enckeylen; + memcpy (enc->seskey, enckey, enckeylen); } pkt.pkttype = PKT_SYMKEY_ENC; pkt.pkt.symkey_enc = enc; if ((rc = build_packet( out, &pkt ))) log_error("build symkey packet failed: %s\n", gpg_strerror (rc) ); xfree (enc); + xfree (enckey); + enckey = NULL; } if (!opt.no_literal) @@ -363,12 +515,15 @@ encrypt_simple (const char *filename, int mode, int use_seskey) /* Register the cipher filter. */ if (mode) - iobuf_push_filter ( out, cipher_filter, &cfx ); + iobuf_push_filter (out, + cfx.dek->use_aead? cipher_filter_aead + /**/ : cipher_filter_cfb, + &cfx ); /* Register the compress filter. */ if ( do_compress ) { - if (cfx.dek && cfx.dek->use_mdc) + if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead)) zfx.new_ctb = 1; push_compress_filter (out, &zfx, default_compress_algo()); } @@ -407,6 +562,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey) if (pt) pt->buf = NULL; free_packet (&pkt, NULL); + xfree (enckey); xfree (cfx.dek); xfree (s2k); release_armor_context (afx); @@ -438,23 +594,33 @@ setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek) static int -write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek, - iobuf_t out) +write_symkey_enc (STRING2KEY *symkey_s2k, aead_algo_t aead_algo, + DEK *symkey_dek, DEK *dek, iobuf_t out) { - int rc, seskeylen = openpgp_cipher_get_algo_keylen (dek->algo); - + int rc; + void *enckey; + size_t enckeylen; PKT_symkey_enc *enc; - byte enckey[33]; PACKET pkt; - enc=xmalloc_clear(sizeof(PKT_symkey_enc)+seskeylen+1); - encrypt_seskey(symkey_dek,&dek,enckey); + rc = encrypt_seskey (symkey_dek, aead_algo, &dek, &enckey, &enckeylen); + if (rc) + return rc; + enc = xtrycalloc (1, sizeof (PKT_symkey_enc) + enckeylen); + if (!enc) + { + rc = gpg_error_from_syserror (); + xfree (enckey); + return rc; + } - enc->version = 4; + enc->version = aead_algo? 5 : 4; enc->cipher_algo = opt.s2k_cipher_algo; + enc->aead_algo = aead_algo; enc->s2k = *symkey_s2k; - enc->seskeylen = seskeylen + 1; /* algo id */ - memcpy( enc->seskey, enckey, seskeylen + 1 ); + enc->seskeylen = enckeylen; + memcpy (enc->seskey, enckey, enckeylen); + xfree (enckey); pkt.pkttype = PKT_SYMKEY_ENC; pkt.pkt.symkey_enc = enc; @@ -462,7 +628,7 @@ write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek, if ((rc=build_packet(out,&pkt))) log_error("build symkey_enc packet failed: %s\n",gpg_strerror (rc)); - xfree(enc); + xfree (enc); return rc; } @@ -676,14 +842,17 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, gnupg_status_compliance_flag (CO_DE_VS), NULL); - cfx.dek->use_mdc = use_mdc (pk_list,cfx.dek->algo); + cfx.dek->use_aead = use_aead (pk_list, cfx.dek->algo); + if (!cfx.dek->use_aead) + cfx.dek->use_mdc = !!use_mdc (pk_list, cfx.dek->algo); /* Only do the is-file-already-compressed check if we are using a - MDC. This forces compressed files to be re-compressed if we do - not have a MDC to give some protection against chosen ciphertext - attacks. */ - - if (do_compress && cfx.dek->use_mdc && is_file_compressed(filename, &rc2)) + * MDC or AEAD. This forces compressed files to be re-compressed if + * we do not have a MDC to give some protection against chosen + * ciphertext attacks. */ + if (do_compress + && (cfx.dek->use_mdc || cfx.dek->use_aead) + && is_file_compressed (filename, &rc2)) { if (opt.verbose) log_info(_("'%s' already compressed\n"), filename); @@ -697,17 +866,18 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, make_session_key (cfx.dek); if (DBG_CRYPTO) - log_printhex ("DEK is: ", cfx.dek->key, cfx.dek->keylen ); + log_printhex (cfx.dek->key, cfx.dek->keylen, "DEK is: "); rc = write_pubkey_enc_from_list (ctrl, pk_list, cfx.dek, out); if (rc) goto leave; /* We put the passphrase (if any) after any public keys as this - seems to be the most useful on the recipient side - there is no - point in prompting a user for a passphrase if they have the - secret key needed to decrypt. */ - if(use_symkey && (rc = write_symkey_enc(symkey_s2k,symkey_dek,cfx.dek,out))) + * seems to be the most useful on the recipient side - there is no + * point in prompting a user for a passphrase if they have the + * secret key needed to decrypt. */ + if (use_symkey && (rc = write_symkey_enc (symkey_s2k, cfx.dek->use_aead, + symkey_dek, cfx.dek, out))) goto leave; if (!opt.no_literal) @@ -750,7 +920,10 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, cfx.datalen = filesize && !do_compress ? filesize : 0; /* Register the cipher filter. */ - iobuf_push_filter (out, cipher_filter, &cfx); + iobuf_push_filter (out, + cfx.dek->use_aead? cipher_filter_aead + /**/ : cipher_filter_cfb, + &cfx); /* Register the compress filter. */ if (do_compress) @@ -777,7 +950,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, /* Algo 0 means no compression. */ if (compr_algo) { - if (cfx.dek && cfx.dek->use_mdc) + if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead)) zfx.new_ctb = 1; push_compress_filter (out,&zfx,compr_algo); } @@ -887,11 +1060,13 @@ encrypt_filter (void *opaque, int control, efx->cfx.dek->algo = opt.def_cipher_algo; } - efx->cfx.dek->use_mdc = use_mdc (efx->pk_list,efx->cfx.dek->algo); + efx->cfx.dek->use_aead = use_aead (efx->pk_list, efx->cfx.dek->algo); + if (!efx->cfx.dek->use_aead) + efx->cfx.dek->use_mdc = !!use_mdc (efx->pk_list,efx->cfx.dek->algo); make_session_key ( efx->cfx.dek ); if (DBG_CRYPTO) - log_printhex ("DEK is: ", efx->cfx.dek->key, efx->cfx.dek->keylen); + log_printhex (efx->cfx.dek->key, efx->cfx.dek->keylen, "DEK is: "); rc = write_pubkey_enc_from_list (efx->ctrl, efx->pk_list, efx->cfx.dek, a); @@ -900,13 +1075,16 @@ encrypt_filter (void *opaque, int control, if(efx->symkey_s2k && efx->symkey_dek) { - rc=write_symkey_enc(efx->symkey_s2k,efx->symkey_dek, - efx->cfx.dek,a); - if(rc) + rc = write_symkey_enc (efx->symkey_s2k, efx->cfx.dek->use_aead, + efx->symkey_dek, efx->cfx.dek, a); + if (rc) return rc; } - iobuf_push_filter (a, cipher_filter, &efx->cfx); + iobuf_push_filter (a, + efx->cfx.dek->use_aead? cipher_filter_aead + /**/ : cipher_filter_cfb, + &efx->cfx); efx->header_okay = 1; } @@ -967,9 +1145,11 @@ write_pubkey_enc (ctrl_t ctrl, if ( opt.verbose ) { char *ustr = get_user_id_string_native (ctrl, enc->keyid); - log_info (_("%s/%s encrypted for: \"%s\"\n"), + log_info (_("%s/%s.%s encrypted for: \"%s\"\n"), openpgp_pk_algo_name (enc->pubkey_algo), openpgp_cipher_algo_name (dek->algo), + dek->use_aead? openpgp_aead_algo_name (dek->use_aead) + /**/ : "CFB", ustr ); xfree (ustr); } diff --git a/g10/filter.h b/g10/filter.h index 2c1e513ce..6daf273fa 100644 --- a/g10/filter.h +++ b/g10/filter.h @@ -88,15 +88,52 @@ struct compress_filter_context_s { typedef struct compress_filter_context_s compress_filter_context_t; -typedef struct { - DEK *dek; - u32 datalen; - gcry_cipher_hd_t cipher_hd; - unsigned int wrote_header : 1; - unsigned int short_blklen_warn : 1; - unsigned long short_blklen_count; - gcry_md_hd_t mdc_hash; - byte enchash[20]; +typedef struct +{ + /* Object with the key and algo */ + DEK *dek; + + /* Length of the data to encrypt if known - 32 bit because OpenPGP + * requires partial encoding for a larger data size. */ + u32 datalen; + + /* The current cipher handle. */ + gcry_cipher_hd_t cipher_hd; + + /* Various processing flags. */ + unsigned int wrote_header : 1; + unsigned int short_blklen_warn : 1; + unsigned long short_blklen_count; + + /* The encoded chunk byte for AEAD. */ + byte chunkbyte; + + /* The decoded CHUNKBYTE. */ + uint64_t chunksize; + + /* The chunk index for AEAD. */ + uint64_t chunkindex; + + /* The number of bytes in the current chunk. */ + uint64_t chunklen; + + /* The total count of encrypted plaintext octets. Note that we + * don't care about encrypting more than 16 Exabyte. */ + uint64_t total; + + /* The hash context and a buffer used for MDC. */ + gcry_md_hd_t mdc_hash; + byte enchash[20]; + + /* The start IV for AEAD encryption. */ + byte startiv[16]; + + /* Using a large buffer for encryption makes processing easier and + * also makes sure the data is well aligned. */ + char *buffer; + size_t bufsize; /* Allocated length. */ + size_t buflen; /* Used length. */ + } cipher_filter_context_t; @@ -146,8 +183,12 @@ gpg_error_t push_compress_filter2 (iobuf_t out,compress_filter_context_t *zfx, int algo, int rel); /*-- cipher.c --*/ -int cipher_filter( void *opaque, int control, - iobuf_t chain, byte *buf, size_t *ret_len); +int cipher_filter_cfb (void *opaque, int control, + iobuf_t chain, byte *buf, size_t *ret_len); + +/*-- cipher-aead.c --*/ +int cipher_filter_aead (void *opaque, int control, + iobuf_t chain, byte *buf, size_t *ret_len); /*-- textfilter.c --*/ int text_filter( void *opaque, int control, diff --git a/g10/getkey.c b/g10/getkey.c index c77b40918..1120e883e 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -2445,8 +2445,8 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated) { PKT_user_id *uid = uidnode->pkt->pkt.user_id; PKT_signature *sig = signode->pkt->pkt.signature; - const byte *p, *sym, *hash, *zip; - size_t n, nsym, nhash, nzip; + const byte *p, *sym, *aead, *hash, *zip; + size_t n, nsym, naead, nhash, nzip; sig->flags.chosen_selfsig = 1;/* We chose this one. */ uid->created = 0; /* Not created == invalid. */ @@ -2501,6 +2501,9 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated) p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM, &n); sym = p; nsym = p ? n : 0; + p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_AEAD, &n); + aead = p; + naead = p ? n : 0; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH, &n); hash = p; nhash = p ? n : 0; @@ -2509,7 +2512,7 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated) nzip = p ? n : 0; if (uid->prefs) xfree (uid->prefs); - n = nsym + nhash + nzip; + n = nsym + naead + nhash + nzip; if (!n) uid->prefs = NULL; else @@ -2521,6 +2524,11 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated) uid->prefs[n].type = PREFTYPE_SYM; uid->prefs[n].value = *sym++; } + for (; naead; naead--, n++) + { + uid->prefs[n].type = PREFTYPE_AEAD; + uid->prefs[n].value = *aead++; + } for (; nhash; nhash--, n++) { uid->prefs[n].type = PREFTYPE_HASH; @@ -2541,6 +2549,12 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated) if (p && n && (p[0] & 0x01)) uid->flags.mdc = 1; + /* See whether we have the AEAD feature. */ + uid->flags.aead = 0; + p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n); + if (p && n && (p[0] & 0x01)) + uid->flags.aead = 1; + /* And the keyserver modify flag. */ uid->flags.ks_modify = 1; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n); @@ -3359,6 +3373,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock) PKT_public_key *main_pk; prefitem_t *prefs; unsigned int mdc_feature; + unsigned int aead_feature; if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY) { @@ -3420,7 +3435,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock) * all preferences. * Do a similar thing for the MDC feature flag. */ prefs = NULL; - mdc_feature = 0; + mdc_feature = aead_feature = 0; for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next) { if (k->pkt->pkttype == PKT_USER_ID @@ -3429,6 +3444,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock) { prefs = k->pkt->pkt.user_id->prefs; mdc_feature = k->pkt->pkt.user_id->flags.mdc; + aead_feature = k->pkt->pkt.user_id->flags.aead; break; } } @@ -3442,6 +3458,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock) xfree (pk->prefs); pk->prefs = copy_prefs (prefs); pk->flags.mdc = mdc_feature; + pk->flags.aead = aead_feature; } } } @@ -105,6 +105,7 @@ enum cmd_and_opt_values oBatch = 500, oMaxOutput, oInputSizeHint, + oChunkSize, oSigNotation, oCertNotation, oShowNotation, @@ -197,6 +198,7 @@ enum cmd_and_opt_values oWithSubkeyFingerprint, oWithICAOSpelling, oWithKeygrip, + oWithKeyScreening, oWithSecret, oWithWKDHash, oWithColons, @@ -221,6 +223,7 @@ enum cmd_and_opt_values oDebugLevel, oDebugAll, oDebugIOLBF, + oDebugSetIobufSize, oStatusFD, oStatusFile, oAttributeFD, @@ -244,6 +247,7 @@ enum cmd_and_opt_values oRFC2440Text, oNoRFC2440Text, oCipherAlgo, + oAEADAlgo, oDigestAlgo, oCertDigestAlgo, oCompressAlgo, @@ -302,6 +306,7 @@ enum cmd_and_opt_values oNoForceMDC, oDisableMDC, oNoDisableMDC, + oForceAEAD, oS2KMode, oS2KDigest, oS2KCipher, @@ -370,6 +375,7 @@ enum cmd_and_opt_values oDefaultPreferenceList, oDefaultKeyserverURL, oPersonalCipherPreferences, + oPersonalAEADPreferences, oPersonalDigestPreferences, oPersonalCompressPreferences, oAgentProgram, @@ -594,6 +600,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")), ARGPARSE_p_u (oMaxOutput, "max-output", "@"), ARGPARSE_s_s (oInputSizeHint, "input-size-hint", "@"), + ARGPARSE_s_i (oChunkSize, "chunk-size", "@"), ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")), ARGPARSE_s_n (oQuiet, "quiet", "@"), @@ -604,6 +611,8 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oDisableMDC, "disable-mdc", "@"), ARGPARSE_s_n (oNoDisableMDC, "no-disable-mdc", "@"), + ARGPARSE_s_n (oForceAEAD, "force-aead", "@"), + ARGPARSE_s_n (oDisableSignerUID, "disable-signer-uid", "@"), ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")), @@ -636,6 +645,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_s (oDebugLevel, "debug-level", "@"), ARGPARSE_s_n (oDebugAll, "debug-all", "@"), ARGPARSE_s_n (oDebugIOLBF, "debug-iolbf", "@"), + ARGPARSE_s_u (oDebugSetIobufSize, "debug-set-iobuf-size", "@"), ARGPARSE_s_i (oStatusFD, "status-fd", "@"), ARGPARSE_s_s (oStatusFile, "status-file", "@"), ARGPARSE_s_i (oAttributeFD, "attribute-fd", "@"), @@ -669,6 +679,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_s (oS2KCipher, "s2k-cipher-algo", "@"), ARGPARSE_s_i (oS2KCount, "s2k-count", "@"), ARGPARSE_s_s (oCipherAlgo, "cipher-algo", "@"), + ARGPARSE_s_s (oAEADAlgo, "aead-algo", "@"), ARGPARSE_s_s (oDigestAlgo, "digest-algo", "@"), ARGPARSE_s_s (oCertDigestAlgo, "cert-digest-algo", "@"), ARGPARSE_s_s (oCompressAlgo,"compress-algo", "@"), @@ -788,6 +799,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprints", "@"), ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"), ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"), + ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"), ARGPARSE_s_n (oWithSecret, "with-secret", "@"), ARGPARSE_s_n (oWithWKDHash, "with-wkd-hash", "@"), ARGPARSE_s_n (oWithKeyOrigin, "with-key-origin", "@"), @@ -825,6 +837,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_s (oDefaultPreferenceList, "default-preference-list", "@"), ARGPARSE_s_s (oDefaultKeyserverURL, "default-keyserver-url", "@"), ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-preferences","@"), + ARGPARSE_s_s (oPersonalAEADPreferences, "personal-aead-preferences","@"), ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-preferences","@"), ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-preferences", "@"), @@ -836,6 +849,7 @@ static ARGPARSE_OPTS opts[] = { /* Aliases. I constantly mistype these, and assume other people do as well. */ ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-prefs", "@"), + ARGPARSE_s_s (oPersonalAEADPreferences, "personal-aead-prefs", "@"), ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-prefs", "@"), ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"), @@ -948,6 +962,8 @@ int g10_errors_seen = 0; static int utf8_strings = 0; static int maybe_setuid = 1; +static unsigned int opt_set_iobuf_size; +static unsigned int opt_set_iobuf_size_used; static char *build_list( const char *text, char letter, const char *(*mapf)(int), int (*chkf)(int) ); @@ -1010,6 +1026,18 @@ build_list_cipher_algo_name (int algo) } static int +build_list_aead_test_algo (int algo) +{ + return openpgp_aead_test_algo (algo); +} + +static const char * +build_list_aead_algo_name (int algo) +{ + return openpgp_aead_algo_name (algo); +} + +static int build_list_md_test_algo (int algo) { /* By default we do not accept MD5 based signatures. To avoid @@ -1030,7 +1058,7 @@ build_list_md_algo_name (int algo) static const char * my_strusage( int level ) { - static char *digests, *pubkeys, *ciphers, *zips, *ver_gcry; + static char *digests, *pubkeys, *ciphers, *zips, *aeads, *ver_gcry; const char *p; switch( level ) { @@ -1090,13 +1118,20 @@ my_strusage( int level ) p = ciphers; break; case 36: + if (!aeads) + aeads = build_list ("AEAD: ", 'A', + build_list_aead_algo_name, + build_list_aead_test_algo); + p = aeads; + break; + case 37: if( !digests ) digests = build_list(_("Hash: "), 'H', build_list_md_algo_name, build_list_md_test_algo ); p = digests; break; - case 37: + case 38: if( !zips ) zips = build_list(_("Compression: "),'Z', compress_algo_to_string, @@ -1117,6 +1152,7 @@ build_list (const char *text, char letter, membuf_t mb; int indent; int i, j, len; + int limit; const char *s; char *string; @@ -1127,7 +1163,8 @@ build_list (const char *text, char letter, len = 0; init_membuf (&mb, 512); - for (i=0; i <= 110; i++ ) + limit = (letter == 'A')? 4 : 110; + for (i=0; i <= limit; i++ ) { if (!chkf (i) && (s = mapf (i))) { @@ -1248,6 +1285,10 @@ set_debug (const char *level) if (opt.debug) parse_debug_flag (NULL, &opt.debug, debug_flags); + + if (opt_set_iobuf_size || opt_set_iobuf_size_used) + log_debug ("iobuf buffer size is %uk\n", + iobuf_set_buffer_size (opt_set_iobuf_size)); } @@ -2128,6 +2169,7 @@ set_compliance_option (enum cmd_and_opt_values option) opt.escape_from = 1; opt.not_dash_escaped = 0; opt.def_cipher_algo = 0; + opt.def_aead_algo = 0; opt.def_digest_algo = 0; opt.cert_digest_algo = 0; opt.compress_algo = -1; @@ -2144,6 +2186,7 @@ set_compliance_option (enum cmd_and_opt_values option) opt.escape_from = 0; opt.not_dash_escaped = 0; opt.def_cipher_algo = 0; + opt.def_aead_algo = 0; opt.def_digest_algo = 0; opt.cert_digest_algo = 0; opt.compress_algo = -1; @@ -2160,6 +2203,7 @@ set_compliance_option (enum cmd_and_opt_values option) set_compliance_option (oOpenPGP); opt.compliance = CO_DE_VS; opt.force_mdc = 1; + opt.def_aead_algo = 0; /* Fixme: Change other options. */ break; @@ -2289,12 +2333,14 @@ main (int argc, char **argv) const char *trustdb_name = NULL; #endif /*!NO_TRUST_MODELS*/ char *def_cipher_string = NULL; + char *def_aead_string = NULL; char *def_digest_string = NULL; char *compress_algo_string = NULL; char *cert_digest_string = NULL; char *s2k_cipher_string = NULL; char *s2k_digest_string = NULL; char *pers_cipher_list = NULL; + char *pers_aead_list = NULL; char *pers_digest_list = NULL; char *pers_compress_list = NULL; int eyes_only=0; @@ -2358,6 +2404,7 @@ main (int argc, char **argv) opt.bz2_compress_level = -1; /* defaults to standard compress level */ /* note: if you change these lines, look at oOpenPGP */ opt.def_cipher_algo = 0; + opt.def_aead_algo = 0; opt.def_digest_algo = 0; opt.cert_digest_algo = 0; opt.compress_algo = -1; /* defaults to DEFAULT_COMPRESS_ALGO */ @@ -2637,6 +2684,10 @@ main (int argc, char **argv) opt.input_size_hint = string_to_u64 (pargs.r.ret_str); break; + case oChunkSize: + opt.chunk_size = pargs.r.ret_int; + break; + case oQuiet: opt.quiet = 1; break; case oNoTTY: tty_no_terminal(1); break; case oDryRun: opt.dry_run = 1; break; @@ -2704,6 +2755,11 @@ main (int argc, char **argv) case oDebugIOLBF: break; /* Already set in pre-parse step. */ + case oDebugSetIobufSize: + opt_set_iobuf_size = pargs.r.ret_ulong; + opt_set_iobuf_size_used = 1; + break; + case oStatusFD: set_status_fd ( translate_sys2libc_fd_int (pargs.r.ret_int, 1) ); break; @@ -2742,6 +2798,10 @@ main (int argc, char **argv) opt.with_keygrip = 1; break; + case oWithKeyScreening: + opt.with_key_screening = 1; + break; + case oWithSecret: opt.with_secret = 1; break; @@ -2965,6 +3025,8 @@ main (int argc, char **argv) case oDisableMDC: opt.disable_mdc = 1; break; case oNoDisableMDC: opt.disable_mdc = 0; break; + case oForceAEAD: opt.force_aead = 1; break; + case oDisableSignerUID: opt.flags.disable_signer_uid = 1; break; case oS2KMode: opt.s2k_mode = pargs.r.ret_int; break; @@ -3118,6 +3180,9 @@ main (int argc, char **argv) case oCipherAlgo: def_cipher_string = xstrdup(pargs.r.ret_str); break; + case oAEADAlgo: + def_aead_string = xstrdup (pargs.r.ret_str); + break; case oDigestAlgo: def_digest_string = xstrdup(pargs.r.ret_str); break; @@ -3397,6 +3462,9 @@ main (int argc, char **argv) case oPersonalCipherPreferences: pers_cipher_list=pargs.r.ret_str; break; + case oPersonalAEADPreferences: + pers_aead_list = pargs.r.ret_str; + break; case oPersonalDigestPreferences: pers_digest_list=pargs.r.ret_str; break; @@ -3759,6 +3827,13 @@ main (int argc, char **argv) if ( openpgp_cipher_test_algo (opt.def_cipher_algo) ) log_error(_("selected cipher algorithm is invalid\n")); } + if (def_aead_string) + { + opt.def_aead_algo = string_to_aead_algo (def_aead_string); + xfree (def_aead_string); def_aead_string = NULL; + if (openpgp_aead_test_algo (opt.def_aead_algo)) + log_error(_("selected AEAD algorithm is invalid\n")); + } if( def_digest_string ) { opt.def_digest_algo = string_to_digest_algo (def_digest_string); xfree(def_digest_string); def_digest_string = NULL; @@ -3818,6 +3893,9 @@ main (int argc, char **argv) keygen_set_std_prefs(pers_cipher_list,PREFTYPE_SYM)) log_error(_("invalid personal cipher preferences\n")); + if (pers_aead_list && keygen_set_std_prefs (pers_aead_list, PREFTYPE_AEAD)) + log_error(_("invalid personal AEAD preferences\n")); + if(pers_digest_list && keygen_set_std_prefs(pers_digest_list,PREFTYPE_HASH)) log_error(_("invalid personal digest preferences\n")); @@ -3826,6 +3904,21 @@ main (int argc, char **argv) keygen_set_std_prefs(pers_compress_list,PREFTYPE_ZIP)) log_error(_("invalid personal compress preferences\n")); + /* Check chunk size. Please fix also the man page if you chnage + * the default. The limits are given by the specs. */ + if (!opt.chunk_size) + opt.chunk_size = 30; /* Default to 1 GiB chunks. */ + else if (opt.chunk_size < 6) + { + opt.chunk_size = 6; + log_info (_("chunk size invalid - using %d\n"), opt.chunk_size); + } + else if (opt.chunk_size > 62) + { + opt.chunk_size = 62; + log_info (_("chunk size invalid - using %d\n"), opt.chunk_size); + } + /* We don't support all possible commands with multifile yet */ if(multifile) { @@ -3876,7 +3969,7 @@ main (int argc, char **argv) /* Check our chosen algorithms against the list of legal algorithms. */ - if(!GNUPG) + if(!GNUPG && !opt.flags.rfc4880bis) { const char *badalg=NULL; preftype_t badtype=PREFTYPE_NONE; @@ -3887,6 +3980,12 @@ main (int argc, char **argv) badalg = openpgp_cipher_algo_name (opt.def_cipher_algo); badtype = PREFTYPE_SYM; } + else if(opt.def_aead_algo + && !algo_available(PREFTYPE_AEAD, opt.def_aead_algo, NULL)) + { + badalg = openpgp_aead_algo_name (opt.def_aead_algo); + badtype = PREFTYPE_AEAD; + } else if(opt.def_digest_algo && !algo_available(PREFTYPE_HASH,opt.def_digest_algo,NULL)) { @@ -3916,6 +4015,12 @@ main (int argc, char **argv) badalg, gnupg_compliance_option_string (opt.compliance)); break; + case PREFTYPE_AEAD: + log_info (_("AEAD algorithm '%s'" + " may not be used in %s mode\n"), + badalg, + gnupg_compliance_option_string (opt.compliance)); + break; case PREFTYPE_HASH: log_info (_("digest algorithm '%s'" " may not be used in %s mode\n"), @@ -3941,6 +4046,7 @@ main (int argc, char **argv) * is not. This is us being nice to the user informing her early * that the chosen algorithms are not available. We also check * and enforce this right before the actual operation. */ + /* FIXME: We also need to check the AEAD algo. */ if (opt.def_cipher_algo && ! gnupg_cipher_is_allowed (opt.compliance, cmd == aEncr @@ -42,14 +42,15 @@ #define MAX_EXTERN_MPI_BITS 16384 /* The maximum length of a binary fingerprints. This is used to - provide a static buffer and will be increased if we need to support - longer fingerprints. - Warning: At some places we still use 20 instead of this macro. */ -#define MAX_FINGERPRINT_LEN 20 + * provide a static buffer and will be increased if we need to support + * longer fingerprints. Warning: At some places we have some + * assumption on a 20 byte fingerprint. + * Watch out for FIXME(fingerprint) */ +#define MAX_FINGERPRINT_LEN 32 /* The maximum length of a formatted fingerprint as returned by - format_hexfingerprint(). */ -#define MAX_FORMATTED_FINGERPRINT_LEN 50 + * format_hexfingerprint(). */ +#define MAX_FORMATTED_FINGERPRINT_LEN 59 /* diff --git a/g10/gpgcompose.c b/g10/gpgcompose.c index 2b42bfbf9..094bc7614 100644 --- a/g10/gpgcompose.c +++ b/g10/gpgcompose.c @@ -2283,9 +2283,11 @@ sk_esk (const char *option, int argc, char *argv[], void *cookie) DEK *sesdekp = &sesdek; /* Now encrypt the session key (or rather, the algorithm used to - encrypt the SED plus the session key) using ENCKEY. */ - ske->seskeylen = 1 + sesdek.keylen; - encrypt_seskey (&s2kdek, &sesdekp, ske->seskey); + encrypt the SKESK plus the session key) using ENCKEY. */ + err = encrypt_seskey (&s2kdek, 0, &sesdekp, + (void**)&ske->seskey, (size_t *)&ske->seskeylen); + if (err) + log_fatal ("encrypt_seskey failed: %s\n", gpg_strerror (err)); /* Save the session key for later. */ session_key = sesdek; @@ -2573,7 +2575,7 @@ encrypted (const char *option, int argc, char *argv[], void *cookie) cfx->datalen = 0; - filter_push (out, cipher_filter, cfx, PKT_ENCRYPTED, cfx->datalen == 0); + filter_push (out, cipher_filter_cfb, cfx, PKT_ENCRYPTED, cfx->datalen == 0); debug ("Wrote encrypted packet:\n"); @@ -2746,7 +2748,7 @@ literal_name (const char *option, int argc, char *argv[], void *cookie) { struct litinfo *li = cookie; - if (argc <= 1) + if (argc <= 0) log_fatal ("Usage: %s NAME\n", option); if (strlen (argv[0]) > 255) diff --git a/g10/import.c b/g10/import.c index c07f67fe2..9fc769df9 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1115,6 +1115,24 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock) problem=1; } } + else if(prefs->type==PREFTYPE_AEAD) + { + if (openpgp_aead_test_algo (prefs->value)) + { + /* FIXME: The test below is wrong. We should + * check if ...algo_name yields a "?" and + * only in that case use NUM. */ + const char *algo = + (openpgp_aead_test_algo (prefs->value) + ? num + : openpgp_aead_algo_name (prefs->value)); + if(!problem) + check_prefs_warning(pk); + log_info(_(" \"%s\": preference for AEAD" + " algorithm %s\n"), user, algo); + problem=1; + } + } else if(prefs->type==PREFTYPE_HASH) { if(openpgp_md_test_algo(prefs->value)) @@ -2257,6 +2275,7 @@ transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats, { char countbuf[35]; + /* FIXME: Support AEAD */ /* Note that the IVLEN may be zero if we are working on a dummy key. We can't express that in an S-expression and thus we send dummy data for the IV. */ diff --git a/g10/kbnode.c b/g10/kbnode.c index c2aaacd76..64def0509 100644 --- a/g10/kbnode.c +++ b/g10/kbnode.c @@ -415,13 +415,14 @@ dump_kbnode (KBNODE node) { PKT_public_key *pk = node->pkt->pkt.public_key; - log_printf (" keyid=%08lX a=%d u=%d %c%c%c%c\n", + log_printf (" keyid=%08lX a=%d u=%d %c%c%c%c%c\n", (ulong)keyid_from_pk( pk, NULL ), pk->pubkey_algo, pk->pubkey_usage, pk->has_expired? 'e':'.', pk->flags.revoked? 'r':'.', pk->flags.valid? 'v':'.', - pk->flags.mdc? 'm':'.'); + pk->flags.mdc? 'm':'.', + pk->flags.aead? 'a':'.'); } else log_printf ("\n"); diff --git a/g10/keydb.h b/g10/keydb.h index c5671d665..c65af0204 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -235,6 +235,7 @@ int algo_available( preftype_t preftype, int algo, int select_algo_from_prefs( PK_LIST pk_list, int preftype, int request, const union pref_hint *hint); int select_mdc_from_pklist (PK_LIST pk_list); +aead_algo_t select_aead_from_pklist (pk_list_t pk_list); void warn_missing_mdc_from_pklist (PK_LIST pk_list); void warn_missing_aes_from_pklist (PK_LIST pk_list); diff --git a/g10/keyedit.c b/g10/keyedit.c index c3eca93a0..00b4e7280 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1144,7 +1144,7 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock) if (err) log_log ((gpg_err_code (err) == GPG_ERR_CANCELED || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) - ? GPGRT_LOG_INFO : GPGRT_LOG_ERROR, + ? GPGRT_LOGLVL_INFO : GPGRT_LOGLVL_ERROR, _("key %s: error changing passphrase: %s\n"), keystr_with_sub (keyid, subid), gpg_strerror (err)); @@ -3066,6 +3066,23 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose) tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES)); } tty_printf ("\n "); + tty_printf (_("AEAD: ")); + for (i = any = 0; prefs[i].type; i++) + { + if (prefs[i].type == PREFTYPE_AEAD) + { + if (any) + tty_printf (", "); + any = 1; + /* We don't want to display strings for experimental algos */ + if (!openpgp_aead_test_algo (prefs[i].value) + && prefs[i].value < 100) + tty_printf ("%s", openpgp_aead_algo_name (prefs[i].value)); + else + tty_printf ("[%d]", prefs[i].value); + } + } + tty_printf ("\n "); tty_printf (_("Digest: ")); for (i = any = 0; prefs[i].type; i++) { @@ -3120,7 +3137,7 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose) } tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_NONE)); } - if (uid->flags.mdc || !uid->flags.ks_modify) + if (uid->flags.mdc || uid->flags.aead || !uid->flags.ks_modify) { tty_printf ("\n "); tty_printf (_("Features: ")); @@ -3130,6 +3147,12 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose) tty_printf ("MDC"); any = 1; } + if (!uid->flags.aead) + { + if (any) + tty_printf (", "); + tty_printf ("AEAD"); + } if (!uid->flags.ks_modify) { if (any) @@ -3168,12 +3191,15 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose) for (i = 0; prefs[i].type; i++) { tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' : + prefs[i].type == PREFTYPE_AEAD ? 'A' : prefs[i].type == PREFTYPE_HASH ? 'H' : prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?', prefs[i].value); } if (uid->flags.mdc) tty_printf (" [mdc]"); + if (uid->flags.aead) + tty_printf (" [aead]"); if (!uid->flags.ks_modify) tty_printf (" [no-ks-modify]"); tty_printf ("\n"); @@ -3319,6 +3345,8 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock) } if (uid->flags.mdc) es_fputs (",mdc", fp); + if (uid->flags.aead) + es_fputs (",aead", fp); if (!uid->flags.ks_modify) es_fputs (",no-ks-modify", fp); } diff --git a/g10/keygen.c b/g10/keygen.c index a4949f486..9e9cead07 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -46,11 +46,10 @@ #include "../common/mbox-util.h" -/* The default algorithms. If you change them remember to change them - also in gpg.c:gpgconf_list. You should also check that the value +/* The default algorithms. If you change them, you should ensure the value is inside the bounds enforced by ask_keysize and gen_xxx. See also get_keysize_range which encodes the allowed ranges. */ -#define DEFAULT_STD_KEY_PARAM "rsa2048/cert,sign+rsa2048/encr" +#define DEFAULT_STD_KEY_PARAM "rsa3072/cert,sign+rsa3072/encr" #define FUTURE_STD_KEY_PARAM "ed25519/cert,sign+cv25519/encr" /* When generating keys using the streamlined key generation dialog, @@ -91,7 +90,7 @@ enum para_name { pHANDLE, pKEYSERVER, pKEYGRIP, - pSUBKEYGRIP, + pSUBKEYGRIP }; struct para_data_s { @@ -128,6 +127,9 @@ struct opaque_data_usage_and_pk { }; +/* FIXME: These globals vars are ugly. And using MAX_PREFS even for + * aeads is useless, given that we don't expects more than a very few + * algorithms. */ static int prefs_initialized = 0; static byte sym_prefs[MAX_PREFS]; static int nsym_prefs; @@ -135,7 +137,11 @@ static byte hash_prefs[MAX_PREFS]; static int nhash_prefs; static byte zip_prefs[MAX_PREFS]; static int nzip_prefs; -static int mdc_available,ks_modify; +static byte aead_prefs[MAX_PREFS]; +static int naead_prefs; +static int mdc_available; +static int ks_modify; +static int aead_available; static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, const char *algostr, const char *usagestr, @@ -327,6 +333,8 @@ set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf) log_info(_("too many digest preferences\n")); else if(type==3) log_info(_("too many compression preferences\n")); + else if(type==4) + log_info(_("too many AEAD preferences\n")); else BUG(); @@ -347,10 +355,10 @@ set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf) int keygen_set_std_prefs (const char *string,int personal) { - byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS]; - int nsym=0, nhash=0, nzip=0, val, rc=0; + byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS], aead[MAX_PREFS]; + int nsym=0, nhash=0, nzip=0, naead=0, val, rc=0; int mdc=1, modify=0; /* mdc defaults on, modify defaults off. */ - char dummy_string[20*4+1]; /* Enough for 20 items. */ + char dummy_string[25*4+1]; /* Enough for 25 items. */ if (!string || !ascii_strcasecmp (string, "default")) { @@ -384,6 +392,11 @@ keygen_set_std_prefs (const char *string,int personal) strcat(dummy_string,"S7 "); strcat(dummy_string,"S2 "); /* 3DES */ + if (opt.flags.rfc4880bis && !openpgp_aead_test_algo (AEAD_ALGO_OCB)) + strcat(dummy_string,"A2 "); + if (opt.flags.rfc4880bis && !openpgp_aead_test_algo (AEAD_ALGO_EAX)) + strcat(dummy_string,"A1 "); + if (personal) { /* The default internal hash algo order is: @@ -476,6 +489,11 @@ keygen_set_std_prefs (const char *string,int personal) if(set_one_pref(val,3,tok,zip,&nzip)) rc=-1; } + else if ((val=string_to_aead_algo (tok))) + { + if (set_one_pref (val, 4, tok, aead, &naead)) + rc = -1; + } else if (ascii_strcasecmp(tok,"mdc")==0) mdc=1; else if (ascii_strcasecmp(tok,"no-mdc")==0) @@ -521,6 +539,29 @@ keygen_set_std_prefs (const char *string,int personal) opt.personal_cipher_prefs[i].value = 0; } } + else if (personal == PREFTYPE_AEAD) + { + xfree(opt.personal_aead_prefs); + + if (!naead) + opt.personal_aead_prefs = NULL; + else + { + int i; + + opt.personal_aead_prefs= + xmalloc(sizeof(prefitem_t *)*(naead+1)); + + for (i=0; i<naead; i++) + { + opt.personal_aead_prefs[i].type = PREFTYPE_AEAD; + opt.personal_aead_prefs[i].value = sym[i]; + } + + opt.personal_aead_prefs[i].type = PREFTYPE_NONE; + opt.personal_aead_prefs[i].value = 0; + } + } else if(personal==PREFTYPE_HASH) { xfree(opt.personal_digest_prefs); @@ -573,7 +614,9 @@ keygen_set_std_prefs (const char *string,int personal) memcpy (sym_prefs, sym, (nsym_prefs=nsym)); memcpy (hash_prefs, hash, (nhash_prefs=nhash)); memcpy (zip_prefs, zip, (nzip_prefs=nzip)); + memcpy (aead_prefs, aead, (naead_prefs=naead)); mdc_available = mdc; + aead_available = !!naead; ks_modify = modify; prefs_initialized = 1; } @@ -582,6 +625,7 @@ keygen_set_std_prefs (const char *string,int personal) return rc; } + /* Return a fake user ID containing the preferences. Caller must free. */ PKT_user_id * @@ -595,8 +639,8 @@ keygen_get_std_prefs(void) uid->ref=1; - uid->prefs=xmalloc((sizeof(prefitem_t *)* - (nsym_prefs+nhash_prefs+nzip_prefs+1))); + uid->prefs = xmalloc ((sizeof(prefitem_t *)* + (nsym_prefs+naead_prefs+nhash_prefs+nzip_prefs+1))); for(i=0;i<nsym_prefs;i++,j++) { @@ -604,6 +648,12 @@ keygen_get_std_prefs(void) uid->prefs[j].value=sym_prefs[i]; } + for (i=0; i < naead_prefs; i++, j++) + { + uid->prefs[j].type = PREFTYPE_AEAD; + uid->prefs[j].value = aead_prefs[i]; + } + for(i=0;i<nhash_prefs;i++,j++) { uid->prefs[j].type=PREFTYPE_HASH; @@ -619,8 +669,9 @@ keygen_get_std_prefs(void) uid->prefs[j].type=PREFTYPE_NONE; uid->prefs[j].value=0; - uid->flags.mdc=mdc_available; - uid->flags.ks_modify=ks_modify; + uid->flags.mdc = mdc_available; + uid->flags.aead = aead_available; + uid->flags.ks_modify = ks_modify; return uid; } @@ -666,6 +717,49 @@ add_feature_mdc (PKT_signature *sig,int enabled) xfree (buf); } + +static void +add_feature_aead (PKT_signature *sig, int enabled) +{ + const byte *s; + size_t n; + int i; + char *buf; + + s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n ); + if (s && n && ((enabled && (s[0] & 0x02)) || (!enabled && !(s[0] & 0x02)))) + return; /* Already set or cleared */ + + if (!s || !n) + { /* Create a new one */ + n = 1; + buf = xmalloc_clear (n); + } + else + { + buf = xmalloc (n); + memcpy (buf, s, n); + } + + if (enabled) + buf[0] |= 0x02; /* AEAD supported */ + else + buf[0] &= ~0x02; + + /* Are there any bits set? */ + for (i=0; i < n; i++) + if (buf[i]) + break; + + if (i == n) + delete_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES); + else + build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n); + + xfree (buf); +} + + static void add_keyserver_modify (PKT_signature *sig,int enabled) { @@ -727,6 +821,14 @@ keygen_upd_std_prefs (PKT_signature *sig, void *opaque) delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_SYM); } + if (naead_prefs) + build_sig_subpkt (sig, SIGSUBPKT_PREF_AEAD, aead_prefs, naead_prefs); + else + { + delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_AEAD); + delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_AEAD); + } + if (nhash_prefs) build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, hash_prefs, nhash_prefs); else @@ -745,6 +847,7 @@ keygen_upd_std_prefs (PKT_signature *sig, void *opaque) /* Make sure that the MDC feature flag is set if needed. */ add_feature_mdc (sig,mdc_available); + add_feature_aead (sig, aead_available); add_keyserver_modify (sig,ks_modify); keygen_add_keyserver_url(sig,NULL); @@ -1648,7 +1751,7 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root, if (nbits < 1024) { - nbits = 2048; + nbits = 3072; log_info (_("keysize invalid; using %u bits\n"), nbits ); } else if (nbits > maxsize) @@ -2117,7 +2220,7 @@ get_keysize_range (int algo, unsigned int *min, unsigned int *max) default: *min = opt.compliance == CO_DE_VS ? 2048: 1024; *max = 4096; - def = 2048; + def = 3072; break; } diff --git a/g10/keyid.c b/g10/keyid.c index ba35ec21f..a9034ee46 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -73,7 +73,7 @@ pubkey_letter( int algo ) is copied to the supplied buffer up a length of BUFSIZE-1. Examples for the output are: - "rsa2048" - RSA with 2048 bit + "rsa3072" - RSA with 3072 bit "elg1024" - Elgamal with 1024 bit "ed25519" - ECC using the curve Ed25519. "E_1.2.3.4" - ECC using the unsupported curve with OID "1.2.3.4". @@ -83,7 +83,7 @@ pubkey_letter( int algo ) If the option --legacy-list-mode is active, the output use the legacy format: - "2048R" - RSA with 2048 bit + "3072R" - RSA with 3072 bit "1024g" - Elgamal with 1024 bit "256E" - ECDSA using a curve with 256 bit @@ -839,8 +839,22 @@ format_hexfingerprint (const char *fingerprint, char *buffer, size_t buflen) /* Half way through we add a second space. */ + 1); } + else if (hexlen == 64 || hexlen == 50) /* v5 fingerprint */ + { + /* The v5 fingerprint is commonly printed truncated to 25 + * octets. We accept the truncated as well as the full hex + * version here and format it like this: + * B2CCB6 838332 5D61BA C50F9F 5E CD21A8 0AC8C5 2565C8 C52565 + */ + hexlen = 50; + space = 8 * 6 + 2 + 8 + 1; + } else /* Other fingerprint versions - print as is. */ { + /* We truncated here so that we do not need to provide a buffer + * of a length which is in reality never used. */ + if (hexlen > MAX_FORMATTED_FINGERPRINT_LEN - 1) + hexlen = MAX_FORMATTED_FINGERPRINT_LEN - 1; space = hexlen + 1; } @@ -853,7 +867,7 @@ format_hexfingerprint (const char *fingerprint, char *buffer, size_t buflen) { for (i = 0, j = 0; i < 40; i ++) { - if (i && i % 4 == 0) + if (i && !(i % 4)) buffer[j ++] = ' '; if (i == 40 / 2) buffer[j ++] = ' '; @@ -863,9 +877,29 @@ format_hexfingerprint (const char *fingerprint, char *buffer, size_t buflen) buffer[j ++] = 0; log_assert (j == space); } + else if (hexlen == 50) /* v5 fingerprint */ + { + for (i=j=0; i < 24; i++) + { + if (i && !(i % 6)) + buffer[j++] = ' '; + buffer[j++] = fingerprint[i]; + } + buffer[j++] = ' '; + buffer[j++] = fingerprint[i++]; + buffer[j++] = fingerprint[i++]; + for (; i < 50; i++) + { + if (!((i-26) % 6)) + buffer[j++] = ' '; + buffer[j++] = fingerprint[i]; + } + buffer[j++] = 0; + log_assert (j == space); + } else { - strcpy (buffer, fingerprint); + mem2str (buffer, fingerprint, space); } return buffer; @@ -948,7 +982,7 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array) else { if (DBG_PACKET) - log_printhex ("keygrip=", array, 20); + log_printhex (array, 20, "keygrip="); /* FIXME: Save the keygrip in PK. */ } gcry_sexp_release (s_pkey); @@ -963,18 +997,18 @@ gpg_error_t hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip) { gpg_error_t err; - unsigned char grip[20]; + unsigned char grip[KEYGRIP_LEN]; *r_grip = NULL; err = keygrip_from_pk (pk, grip); if (!err) { - char * buf = xtrymalloc (20*2+1); + char * buf = xtrymalloc (KEYGRIP_LEN * 2 + 1); if (!buf) err = gpg_error_from_syserror (); else { - bin2hex (grip, 20, buf); + bin2hex (grip, KEYGRIP_LEN, buf); *r_grip = buf; } } diff --git a/g10/keylist.c b/g10/keylist.c index 199cd1330..1f501fc97 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -45,6 +45,7 @@ #include "../common/zb32.h" #include "tofu.h" #include "../common/compliance.h" +#include "../common/pkscreening.h" static void list_all (ctrl_t, int, int); @@ -696,6 +697,37 @@ print_key_data (PKT_public_key * pk) } } + +/* Various public key screenings. (Right now just ROCA). With + * COLON_MODE set the output is formatted for use in the compliance + * field of a colon listing. + */ +static void +print_pk_screening (PKT_public_key *pk, int colon_mode) +{ + gpg_error_t err; + + if (is_RSA (pk->pubkey_algo) && pubkey_get_npkey (pk->pubkey_algo)) + { + err = screen_key_for_roca (pk->pkey[0]); + if (!err) + ; + else if (gpg_err_code (err) == GPG_ERR_TRUE) + { + if (colon_mode) + es_fprintf (es_stdout, colon_mode > 1? " %d":"%d", 6001); + else + es_fprintf (es_stdout, + " Screening: ROCA vulnerability detected\n"); + } + else if (!colon_mode) + es_fprintf (es_stdout, " Screening: [ROCA check failed: %s]\n", + gpg_strerror (err)); + } + +} + + static void print_capabilities (ctrl_t ctrl, PKT_public_key *pk, KBNODE keyblock) { @@ -922,6 +954,9 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, if (opt.with_key_data) print_key_data (pk); + if (opt.with_key_screening) + print_pk_screening (pk, 0); + if (opt.with_key_origin && (pk->keyorg || pk->keyupdate || pk->updateurl)) { @@ -1063,6 +1098,8 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip); if (opt.with_key_data) print_key_data (pk2); + if (opt.with_key_screening) + print_pk_screening (pk2, 0); } else if (opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE && !skip_sigs) @@ -1227,6 +1264,9 @@ print_compliance_flags (PKT_public_key *pk, gnupg_status_compliance_flag (CO_DE_VS)); any++; } + + if (opt.with_key_screening) + print_pk_screening (pk, 1+any); } @@ -1915,6 +1955,9 @@ print_card_serialno (const char *serialno) * pub dsa2048 2007-12-31 [SC] [expires: 2018-12-31] * 80615870F5BAD690333686D0F2AD85AC1E42B367 * + * pub rsa2048 2017-12-31 [SC] [expires: 2028-12-31] + * 80615870F5BAD690333686D0F2AD85AC1E42B3671122334455 + * * Some global options may result in a different output format. If * SECRET is set, "sec" or "ssb" is used instead of "pub" or "sub" and * depending on the value a flag character is shown: diff --git a/g10/main.h b/g10/main.h index af25d559c..453d1226a 100644 --- a/g10/main.h +++ b/g10/main.h @@ -31,7 +31,9 @@ (i.e. uncompressed) rather than 1 (zip). However, the real world issues of speed and size come into play here. */ -#if GPG_USE_AES128 +#if GPG_USE_AES256 +# define DEFAULT_CIPHER_ALGO CIPHER_ALGO_AES256 +#elif GPG_USE_AES128 # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_AES #elif GPG_USE_CAST5 # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_CAST5 @@ -39,6 +41,12 @@ # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_3DES #endif +#if GCRYPT_VERSION_NUMBER < 0x019000 +# define DEFAULT_AEAD_ALGO AEAD_ALGO_OCB +#else +# define DEFAULT_AEAD_ALGO AEAD_ALGO_EAX +#endif + #define DEFAULT_DIGEST_ALGO ((GNUPG)? DIGEST_ALGO_SHA256:DIGEST_ALGO_SHA1) #define DEFAULT_S2K_DIGEST_ALGO DIGEST_ALGO_SHA1 #ifdef HAVE_ZIP @@ -121,6 +129,12 @@ int openpgp_cipher_blocklen (cipher_algo_t algo); int openpgp_cipher_test_algo(cipher_algo_t algo); const char *openpgp_cipher_algo_name (cipher_algo_t algo); +gpg_error_t openpgp_aead_test_algo (aead_algo_t algo); +const char *openpgp_aead_algo_name (aead_algo_t algo); +gpg_error_t openpgp_aead_algo_info (aead_algo_t algo, + enum gcry_cipher_modes *r_mode, + unsigned int *r_noncelen); + pubkey_algo_t map_pk_gcry_to_openpgp (enum gcry_pk_algos algo); int openpgp_pk_test_algo (pubkey_algo_t algo); int openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use); @@ -149,12 +163,14 @@ void obsolete_scdaemon_option (const char *configname, unsigned int configlineno, const char *name); int string_to_cipher_algo (const char *string); +aead_algo_t string_to_aead_algo (const char *string); int string_to_digest_algo (const char *string); const char *compress_algo_to_string(int algo); int string_to_compress_algo(const char *string); int check_compress_algo(int algo); int default_cipher_algo(void); +aead_algo_t default_aead_algo(void); int default_compress_algo(void); void compliance_failure(void); @@ -223,7 +239,9 @@ void display_online_help( const char *keyword ); /*-- encode.c --*/ int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek); -void encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey); +gpg_error_t encrypt_seskey (DEK *dek, aead_algo_t aead_algo, DEK **r_seskey, + void **r_enckey, size_t *r_enckeylen); +aead_algo_t use_aead (pk_list_t pk_list, int algo); int use_mdc (pk_list_t pk_list,int algo); int encrypt_symmetric (const char *filename ); int encrypt_store (const char *filename ); @@ -324,7 +342,7 @@ gpg_error_t generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock, int overwrite_filep( const char *fname ); char *make_outfile_name( const char *iname ); char *ask_outfile_name( const char *name, size_t namelen ); -int open_outfile (int inp_fd, const char *iname, int mode, +int open_outfile (int out_fd, const char *iname, int mode, int restrictedperm, iobuf_t *a); char *get_matching_datafile (const char *sigfilename); iobuf_t open_sigfile (const char *sigfilename, progress_filter_context_t *pfx); diff --git a/g10/mainproc.c b/g10/mainproc.c index c7deeab5f..69de865e7 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -245,46 +245,116 @@ add_signature (CTX c, PACKET *pkt) return 1; } -static int +static gpg_error_t symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen) { + gpg_error_t err; gcry_cipher_hd_t hd; + unsigned int noncelen, keylen; + enum gcry_cipher_modes ciphermode; + + if (dek->use_aead) + { + err = openpgp_aead_algo_info (dek->use_aead, &ciphermode, &noncelen); + if (err) + return err; + } + else + { + ciphermode = GCRY_CIPHER_MODE_CFB; + noncelen = 0; + } - if(slen < 17 || slen > 33) + /* Check that the session key has a size of 16 to 32 bytes. */ + if ((dek->use_aead && (slen < (noncelen + 16 + 16) + || slen > (noncelen + 32 + 16))) + || (!dek->use_aead && (slen < 17 || slen > 33))) { log_error ( _("weird size for an encrypted session key (%d)\n"), (int)slen); - return GPG_ERR_BAD_KEY; + return gpg_error (GPG_ERR_BAD_KEY); } - if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1)) - BUG (); - if (gcry_cipher_setkey ( hd, dek->key, dek->keylen )) - BUG (); - gcry_cipher_setiv ( hd, NULL, 0 ); - gcry_cipher_decrypt ( hd, seskey, slen, NULL, 0 ); - gcry_cipher_close ( hd ); - - /* Now we replace the dek components with the real session key to - decrypt the contents of the sequencing packet. */ - - dek->keylen=slen-1; - dek->algo=seskey[0]; + err = openpgp_cipher_open (&hd, dek->algo, ciphermode, GCRY_CIPHER_SECURE); + if (!err) + err = gcry_cipher_setkey (hd, dek->key, dek->keylen); + if (!err) + err = gcry_cipher_setiv (hd, noncelen? seskey : NULL, noncelen); + if (err) + goto leave; - if(dek->keylen > DIM(dek->key)) - BUG (); + if (dek->use_aead) + { + byte ad[4]; + + ad[0] = (0xc0 | PKT_SYMKEY_ENC); + ad[1] = 5; + ad[2] = dek->algo; + ad[3] = dek->use_aead; + err = gcry_cipher_authenticate (hd, ad, 4); + if (err) + goto leave; + gcry_cipher_final (hd); + keylen = slen - noncelen - 16; + err = gcry_cipher_decrypt (hd, seskey+noncelen, keylen, NULL, 0); + if (err) + goto leave; + err = gcry_cipher_checktag (hd, seskey+noncelen+keylen, 16); + if (err) + goto leave; + /* Now we replace the dek components with the real session key to + * decrypt the contents of the sequencing packet. */ + if (keylen > DIM(dek->key)) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + dek->keylen = keylen; + memcpy (dek->key, seskey + noncelen, dek->keylen); + } + else + { + gcry_cipher_decrypt (hd, seskey, slen, NULL, 0 ); + /* Here we can only test whether the algo given in decrypted + * session key is a valid OpenPGP algo. With 11 defined + * symmetric algorithms we will miss 4.3% of wrong passphrases + * here. The actual checking is done later during bulk + * decryption; we can't bring this check forward easily. We + * need to use the GPG_ERR_CHECKSUM so that we won't run into + * the gnupg < 2.2 bug compatible case which would terminate the + * process on GPG_ERR_CIPHER_ALGO. Note that with AEAD (above) + * we will have a reliable test here. */ + if (openpgp_cipher_test_algo (seskey[0])) + { + err = gpg_error (GPG_ERR_CHECKSUM); + goto leave; + } - memcpy(dek->key, seskey + 1, dek->keylen); + /* Now we replace the dek components with the real session key to + * decrypt the contents of the sequencing packet. */ + keylen = slen-1; + if (keylen > DIM(dek->key)) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + dek->algo = seskey[0]; + dek->keylen = keylen; + memcpy (dek->key, seskey + 1, dek->keylen); + } /*log_hexdump( "thekey", dek->key, dek->keylen );*/ - return 0; + leave: + gcry_cipher_close (hd); + return err; } static void proc_symkey_enc (CTX c, PACKET *pkt) { + gpg_error_t err; PKT_symkey_enc *enc; enc = pkt->pkt.symkey_enc; @@ -294,19 +364,21 @@ proc_symkey_enc (CTX c, PACKET *pkt) { int algo = enc->cipher_algo; const char *s = openpgp_cipher_algo_name (algo); + const char *a = (enc->aead_algo ? openpgp_aead_algo_name (enc->aead_algo) + /**/ : "CFB"); if (!openpgp_cipher_test_algo (algo)) { if (!opt.quiet) { if (enc->seskeylen) - log_info (_("%s encrypted session key\n"), s ); + log_info (_("%s.%s encrypted session key\n"), s, a ); else - log_info (_("%s encrypted data\n"), s ); + log_info (_("%s.%s encrypted data\n"), s, a ); } } else - log_error (_("encrypted with unknown algorithm %d\n"), algo); + log_error (_("encrypted with unknown algorithm %d.%s\n"), algo, a); if (openpgp_md_test_algo (enc->s2k.hash_algo)) { @@ -334,6 +406,7 @@ proc_symkey_enc (CTX c, PACKET *pkt) if (c->dek) { c->dek->symmetric = 1; + c->dek->use_aead = enc->aead_algo; /* FIXME: This doesn't work perfectly if a symmetric key comes before a public key in the message - if the @@ -344,9 +417,24 @@ proc_symkey_enc (CTX c, PACKET *pkt) come later. */ if (enc->seskeylen) { - if (symkey_decrypt_seskey (c->dek, - enc->seskey, enc->seskeylen)) + err = symkey_decrypt_seskey (c->dek, + enc->seskey, enc->seskeylen); + if (err) { + log_info ("decryption of the symmetrically encrypted" + " session key failed: %s\n", + gpg_strerror (err)); + if (gpg_err_code (err) != GPG_ERR_BAD_KEY + && gpg_err_code (err) != GPG_ERR_CHECKSUM) + log_fatal ("process terminated to be bug compatible" + " with GnuPG <= 2.2\n"); + if (c->dek->s2k_cacheid[0]) + { + if (opt.debug) + log_debug ("cleared passphrase cached with ID:" + " %s\n", c->dek->s2k_cacheid); + passphrase_clear_cache (c->dek->s2k_cacheid); + } xfree (c->dek); c->dek = NULL; } @@ -650,6 +738,7 @@ proc_encrypted (CTX c, PACKET *pkt) else if (!result && !opt.ignore_mdc_error && !pkt->pkt.encrypted->mdc_method + && !pkt->pkt.encrypted->aead_algo && openpgp_cipher_get_algo_blklen (c->dek->algo) != 8 && c->dek->algo != CIPHER_ALGO_TWOFISH) { @@ -664,17 +753,25 @@ proc_encrypted (CTX c, PACKET *pkt) write_status (STATUS_DECRYPTION_FAILED); } else if (!result || (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE + && !pkt->pkt.encrypted->aead_algo && opt.ignore_mdc_error)) { + /* All is fine or for an MDC message the MDC failed but the + * --ignore-mdc-error option is active. For compatibility + * reasons we issue GOODMDC also for AEAD messages. */ write_status (STATUS_DECRYPTION_OKAY); if (opt.verbose > 1) log_info(_("decryption okay\n")); - if (pkt->pkt.encrypted->mdc_method && !result) + + if (pkt->pkt.encrypted->aead_algo) + write_status (STATUS_GOODMDC); + else if (pkt->pkt.encrypted->mdc_method && !result) write_status (STATUS_GOODMDC); else if (!opt.no_mdc_warn) log_info (_("WARNING: message was not integrity protected\n")); } - else if (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE) + else if (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE + || gpg_err_code (result) == GPG_ERR_TRUNCATED) { glo_ctrl.lasterr = result; log_error (_("WARNING: encrypted message has been manipulated!\n")); @@ -684,6 +781,7 @@ proc_encrypted (CTX c, PACKET *pkt) else { if ((gpg_err_code (result) == GPG_ERR_BAD_KEY + || gpg_err_code (result) == GPG_ERR_CHECKSUM || gpg_err_code (result) == GPG_ERR_CIPHER_ALGO) && *c->dek->s2k_cacheid != '\0') { @@ -1393,7 +1491,8 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a) case PKT_PUBKEY_ENC: proc_pubkey_enc (ctrl, c, pkt); break; case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break; case PKT_ENCRYPTED: - case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break; + case PKT_ENCRYPTED_MDC: + case PKT_ENCRYPTED_AEAD:proc_encrypted (c, pkt); break; case PKT_COMPRESSED: rc = proc_compressed (c, pkt); break; default: newpkt = 0; break; } @@ -1409,6 +1508,7 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a) case PKT_PUBKEY_ENC: case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: + case PKT_ENCRYPTED_AEAD: write_status_text( STATUS_UNEXPECTED, "0" ); rc = GPG_ERR_UNEXPECTED; goto leave; @@ -1436,7 +1536,8 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a) case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break; case PKT_PUBKEY_ENC: proc_pubkey_enc (ctrl, c, pkt); break; case PKT_ENCRYPTED: - case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break; + case PKT_ENCRYPTED_MDC: + case PKT_ENCRYPTED_AEAD: proc_encrypted (c, pkt); break; case PKT_PLAINTEXT: proc_plaintext (c, pkt); break; case PKT_COMPRESSED: rc = proc_compressed (c, pkt); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig (c, pkt); break; @@ -1463,7 +1564,8 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a) case PKT_PUBKEY_ENC: proc_pubkey_enc (ctrl, c, pkt); break; case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break; case PKT_ENCRYPTED: - case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break; + case PKT_ENCRYPTED_MDC: + case PKT_ENCRYPTED_AEAD: proc_encrypted (c, pkt); break; case PKT_PLAINTEXT: proc_plaintext (c, pkt); break; case PKT_COMPRESSED: rc = proc_compressed (c, pkt); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig (c, pkt); break; diff --git a/g10/misc.c b/g10/misc.c index 97809692e..1e6df5f67 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -71,6 +71,11 @@ #include "../common/zb32.h" +/* FIXME: Libgcrypt 1.9 will support EAX. Until we kame this a + * requirement we hardwire the enum used for EAX. */ +#define MY_GCRY_CIPHER_MODE_EAX 14 + + #ifdef ENABLE_SELINUX_HACKS /* A object and a global variable to keep track of files marked as secured. */ @@ -397,7 +402,7 @@ print_further_info (const char *format, ...) log_info (_("(further info: ")); va_start (arg_ptr, format); - log_logv (GPGRT_LOG_CONT, format, arg_ptr); + log_logv (GPGRT_LOGLVL_CONT, format, arg_ptr); va_end (arg_ptr); log_printf (")\n"); } @@ -583,6 +588,80 @@ openpgp_cipher_algo_name (cipher_algo_t algo) } +/* Return 0 if ALGO is supported. Return an error if not. */ +gpg_error_t +openpgp_aead_test_algo (aead_algo_t algo) +{ + /* FIXME: We currently have no easy way to test whether libgcrypt + * implements a mode. The only way we can do this is to open a + * cipher context with that mode and close it immediately. That is + * a bit costly. So we look at the libgcrypt version and assume + * nothing has been patched out. */ + switch (algo) + { + case AEAD_ALGO_NONE: + break; + + case AEAD_ALGO_EAX: +#if GCRYPT_VERSION_NUMBER < 0x010900 + break; +#else + return 0; +#endif + + case AEAD_ALGO_OCB: + return 0; + } + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + + +/* Map the OpenPGP AEAD algorithm with ID ALGO to a string + * representation of the algorithm name. For unknown algorithm IDs + * this function returns "?". */ +const char * +openpgp_aead_algo_name (aead_algo_t algo) +{ + switch (algo) + { + case AEAD_ALGO_NONE: break; + case AEAD_ALGO_EAX: return "EAX"; + case AEAD_ALGO_OCB: return "OCB"; + } + + return "?"; +} + + +/* Return information for the AEAD algorithm ALGO. The corresponding + * Libgcrypt ciphermode is stored at R_MODE and the required number of + * octets for the nonce at R_NONCELEN. On error and error code is + * returned. Note that the taglen is always 128 bits. */ +gpg_error_t +openpgp_aead_algo_info (aead_algo_t algo, enum gcry_cipher_modes *r_mode, + unsigned int *r_noncelen) +{ + switch (algo) + { + case AEAD_ALGO_OCB: + *r_mode = GCRY_CIPHER_MODE_OCB; + *r_noncelen = 15; + break; + + case AEAD_ALGO_EAX: + *r_mode = MY_GCRY_CIPHER_MODE_EAX; + *r_noncelen = 16; + break; + + default: + log_error ("unsupported AEAD algo %d\n", algo); + return gpg_error (GPG_ERR_INV_CIPHER_MODE); + } + return 0; +} + + /* Return 0 if ALGO is a supported OpenPGP public key algorithm. */ int openpgp_pk_test_algo (pubkey_algo_t algo) @@ -1113,6 +1192,39 @@ string_to_cipher_algo (const char *string) return val; } + +/* + * Map an AEAD mode string to a an AEAD algorithm number as defined by + * rrc4880bis. Also support the "An" syntax as used by the preference + * strings. + */ +aead_algo_t +string_to_aead_algo (const char *string) +{ + int result; + + if (!string) + result = 0; + if (!ascii_strcasecmp (string, "EAX")) + result = 1; + else if (!ascii_strcasecmp (string, "OCB")) + result = 2; + else if ((string[0]=='A' || string[0]=='a')) + { + char *endptr; + + string++; + result = strtol (string, &endptr, 10); + if (!*string || *endptr || result < 1 || result > 2) + result = 0; + } + else + result = 0; + + return result; +} + + /* * Wrapper around gcry_md_map_name to provide a fallback using the * "Hn" syntax as used by the preference strings. @@ -1229,6 +1341,18 @@ default_cipher_algo(void) return opt.s2k_cipher_algo; } + +aead_algo_t +default_aead_algo(void) +{ + if(opt.def_aead_algo) + return opt.def_aead_algo; + else if(opt.personal_aead_prefs) + return opt.personal_aead_prefs[0].value; + else + return DEFAULT_AEAD_ALGO; +} + /* There is no default_digest_algo function, but see sign.c:hash_for() */ diff --git a/g10/openfile.c b/g10/openfile.c index 78f4dbbcb..f4730da22 100644 --- a/g10/openfile.c +++ b/g10/openfile.c @@ -171,32 +171,34 @@ ask_outfile_name( const char *name, size_t namelen ) * 2 = use ".sig" * 3 = use ".rev" * - * If INP_FD is not -1 the function simply creates an IOBUF for that - * file descriptor and ignore INAME and MODE. Note that INP_FD won't - * be closed if the returned IOBUF is closed. With RESTRICTEDPERM a - * file will be created with mode 700 if possible. - */ + * With RESTRICTEDPERM a file will be created with mode 700 if + * possible. + * + * If OUT_FD is not -1 the function simply creates an IOBUF for that + * file descriptor and ignores INAME and MODE. Note that OUT_FD won't + * be closed if the returned IOBUF is closed. This is used for gpg's + * --server mode. */ int -open_outfile (int inp_fd, const char *iname, int mode, int restrictedperm, +open_outfile (int out_fd, const char *iname, int mode, int restrictedperm, iobuf_t *a) { int rc = 0; *a = NULL; - if (inp_fd != -1) + if (out_fd != -1) { char xname[64]; - *a = iobuf_fdopen_nc (inp_fd, "wb"); + *a = iobuf_fdopen_nc (out_fd, "wb"); if (!*a) { rc = gpg_error_from_syserror (); - snprintf (xname, sizeof xname, "[fd %d]", inp_fd); + snprintf (xname, sizeof xname, "[fd %d]", out_fd); log_error (_("can't open '%s': %s\n"), xname, gpg_strerror (rc)); } else if (opt.verbose) { - snprintf (xname, sizeof xname, "[fd %d]", inp_fd); + snprintf (xname, sizeof xname, "[fd %d]", out_fd); log_info (_("writing to '%s'\n"), xname); } } diff --git a/g10/options.h b/g10/options.h index 96b76f8f2..dab6e9f8b 100644 --- a/g10/options.h +++ b/g10/options.h @@ -62,6 +62,9 @@ struct * progress info and to decide on how to allocate buffers. */ uint64_t input_size_hint; + /* The AEAD chunk size expressed as a power of 2. */ + int chunk_size; + int dry_run; int autostart; int list_only; @@ -82,6 +85,7 @@ struct int with_fingerprint; /* Option --with-fingerprint active. */ int with_subkey_fingerprint; /* Option --with-subkey-fingerprint active. */ int with_keygrip; /* Option --with-keygrip active. */ + int with_key_screening;/* Option --with-key-screening active. */ int with_tofu_info; /* Option --with-tofu_info active. */ int with_secret; /* Option --with-secret active. */ int with_wkd_hash; /* Option --with-wkd-hash. */ @@ -91,8 +95,10 @@ struct int no_armor; int list_packets; /* Option --list-packets active. */ int def_cipher_algo; + int def_aead_algo; int force_mdc; int disable_mdc; + int force_aead; int def_digest_algo; int cert_digest_algo; int compress_algo; @@ -176,6 +182,7 @@ struct const char *def_preference_list; const char *def_keyserver_url; prefitem_t *personal_cipher_prefs; + prefitem_t *personal_aead_prefs; prefitem_t *personal_digest_prefs; prefitem_t *personal_compress_prefs; struct weakhash *weak_digests; @@ -318,7 +325,6 @@ struct { #define DBG_TRUST (opt.debug & DBG_TRUST_VALUE) #define DBG_HASHING (opt.debug & DBG_HASHING_VALUE) #define DBG_IPC (opt.debug & DBG_IPC_VALUE) -#define DBG_IPC (opt.debug & DBG_IPC_VALUE) #define DBG_CLOCK (opt.debug & DBG_CLOCK_VALUE) #define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE) #define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE) diff --git a/g10/packet.h b/g10/packet.h index 43c097e72..e8397eaee 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -72,7 +72,8 @@ typedef enum { PREFTYPE_NONE = 0, PREFTYPE_SYM = 1, PREFTYPE_HASH = 2, - PREFTYPE_ZIP = 3 + PREFTYPE_ZIP = 3, + PREFTYPE_AEAD = 4 } preftype_t; typedef struct { @@ -93,12 +94,14 @@ typedef struct /* A symmetric-key encrypted session key packet as defined in RFC 4880, Section 5.3. All fields are serialized. */ typedef struct { - /* RFC 4880: this must be 4. */ + /* We support version 4 (rfc4880) and 5 (rfc4880bis). */ byte version; - /* The cipher algorithm used to encrypt the session key. (This may - be different from the algorithm that is used to encrypt the SED - packet.) */ + /* The cipher algorithm used to encrypt the session key. Note that + * this may be different from the algorithm that is used to encrypt + * bulk data. */ byte cipher_algo; + /* The AEAD algorithm or 0 for CFB encryption. */ + byte aead_algo; /* The string-to-key specifier. */ STRING2KEY s2k; /* The length of SESKEY in bytes or 0 if this packet does not @@ -106,7 +109,8 @@ typedef struct { S2K function on the password is the session key. See RFC 4880, Section 5.3.) */ byte seskeylen; - /* The session key as encrypted by the S2K specifier. */ + /* The session key as encrypted by the S2K specifier. For AEAD this + * includes the nonce and the authentication tag. */ byte seskey[1]; } PKT_symkey_enc; @@ -290,6 +294,7 @@ typedef struct struct { unsigned int mdc:1; + unsigned int aead:1; unsigned int ks_modify:1; unsigned int compacted:1; unsigned int primary:2; /* 2 if set via the primary flag, 1 if calculated */ @@ -386,6 +391,7 @@ typedef struct struct { unsigned int mdc:1; /* MDC feature set. */ + unsigned int aead:1; /* AEAD feature set. */ unsigned int disabled_valid:1;/* The next flag is valid. */ unsigned int disabled:1; /* The key has been disabled. */ unsigned int primary:1; /* This is a primary key. */ @@ -456,12 +462,13 @@ typedef struct { typedef struct { /* Remaining length of encrypted data. */ u32 len; - /* When encrypting, the first block size bytes of data are random - data and the following 2 bytes are copies of the last two bytes - of the random data (RFC 4880, Section 5.7). This provides a - simple check that the key is correct. extralen is the size of - this extra data. This is used by build_packet when writing out - the packet's header. */ + /* When encrypting in CFB mode, the first block size bytes of data + * are random data and the following 2 bytes are copies of the last + * two bytes of the random data (RFC 4880, Section 5.7). This + * provides a simple check that the key is correct. EXTRALEN is the + * size of this extra data or, in AEAD mode, the length of the + * headers and the tags. This is used by build_packet when writing + * out the packet's header. */ int extralen; /* Whether the serialized version of the packet used / should use the new format. */ @@ -471,8 +478,17 @@ typedef struct { Note: this is ignored when encrypting. */ byte is_partial; /* If 0, MDC is disabled. Otherwise, the MDC method that was used - (currently, only DIGEST_ALGO_SHA1 is supported). */ + (only DIGEST_ALGO_SHA1 has ever been defined). */ byte mdc_method; + /* If 0, AEAD is not used. Otherwise, the used AEAD algorithm. + * MDC_METHOD (above) shall be zero if AEAD is used. */ + byte aead_algo; + /* The cipher algo for/from the AEAD packet. 0 for other encryption + * packets. */ + byte cipher_algo; + /* The chunk byte from the AEAD packet. */ + byte chunkbyte; + /* An iobuf holding the data to be decrypted. (This is not used for encryption!) */ iobuf_t buf; diff --git a/g10/parse-packet.c b/g10/parse-packet.c index a64d4f723..e933abfa0 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1,7 +1,6 @@ /* parse-packet.c - read packets - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - * 2007, 2009, 2010 Free Software Foundation, Inc. - * Copyright (C) 2014 Werner Koch + * Copyright (C) 1998-2007, 2009-2010 Free Software Foundation, Inc. + * Copyright (C) 2014, 2018 Werner Koch * Copyright (C) 2015 g10 Code GmbH * * This file is part of GnuPG. @@ -18,6 +17,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-3.0+ */ #include <config.h> @@ -82,6 +82,9 @@ static int parse_compressed (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int new_ctb); static int parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int new_ctb, int partial); +static gpg_error_t parse_encrypted_aead (IOBUF inp, int pkttype, + unsigned long pktlen, PACKET *packet, + int partial); static int parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int new_ctb); static int parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen, @@ -636,6 +639,7 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos, case PKT_PLAINTEXT: case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: + case PKT_ENCRYPTED_AEAD: case PKT_COMPRESSED: iobuf_set_partial_body_length_mode (inp, c & 0xff); pktlen = 0; /* To indicate partial length. */ @@ -823,6 +827,9 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos, case PKT_MDC: rc = parse_mdc (inp, pkttype, pktlen, pkt, new_ctb); break; + case PKT_ENCRYPTED_AEAD: + rc = parse_encrypted_aead (inp, pkttype, pktlen, pkt, partial); + break; case PKT_GPG_CONTROL: rc = parse_gpg_control (inp, pkttype, pktlen, pkt, partial); break; @@ -1098,19 +1105,17 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, { PKT_symkey_enc *k; int rc = 0; - int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen; + int i, version, s2kmode, cipher_algo, aead_algo, hash_algo, seskeylen, minlen; if (pktlen < 4) - { - log_error ("packet(%d) too short\n", pkttype); - if (list_mode) - es_fprintf (listfp, ":symkey enc packet: [too short]\n"); - rc = gpg_error (GPG_ERR_INV_PACKET); - goto leave; - } + goto too_short; version = iobuf_get_noeof (inp); pktlen--; - if (version != 4) + if (version == 4) + ; + else if (version == 5) + ; + else { log_error ("packet(%d) with unknown version %d\n", pkttype, version); if (list_mode) @@ -1128,6 +1133,15 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, } cipher_algo = iobuf_get_noeof (inp); pktlen--; + if (version == 5) + { + aead_algo = iobuf_get_noeof (inp); + pktlen--; + } + else + aead_algo = 0; + if (pktlen < 2) + goto too_short; s2kmode = iobuf_get_noeof (inp); pktlen--; hash_algo = iobuf_get_noeof (inp); @@ -1162,6 +1176,7 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, + seskeylen - 1); k->version = version; k->cipher_algo = cipher_algo; + k->aead_algo = aead_algo; k->s2k.mode = s2kmode; k->s2k.hash_algo = hash_algo; if (s2kmode == 1 || s2kmode == 3) @@ -1192,10 +1207,20 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, if (list_mode) { es_fprintf (listfp, - ":symkey enc packet: version %d, cipher %d, s2k %d, hash %d", - version, cipher_algo, s2kmode, hash_algo); + ":symkey enc packet: version %d, cipher %d, aead %d," + " s2k %d, hash %d", + version, cipher_algo, aead_algo, s2kmode, hash_algo); if (seskeylen) - es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8); + { + /* To compute the size of the session key we need to know + * the size of the AEAD nonce which we may not know. Thus + * we show only the seize of the entire encrypted session + * key. */ + if (aead_algo) + es_fprintf (listfp, ", encrypted seskey %d bytes", seskeylen); + else + es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8); + } es_fprintf (listfp, "\n"); if (s2kmode == 1 || s2kmode == 3) { @@ -1212,6 +1237,13 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, leave: iobuf_skip_rest (inp, pktlen, 0); return rc; + + too_short: + log_error ("packet(%d) too short\n", pkttype); + if (list_mode) + es_fprintf (listfp, ":symkey enc packet: [too short]\n"); + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; } @@ -1392,6 +1424,11 @@ dump_sig_subpkt (int hashed, int type, int critical, for (i = 0; i < length; i++) es_fprintf (listfp, " %d", buffer[i]); break; + case SIGSUBPKT_PREF_AEAD: + es_fputs ("pref-aead-algos:", listfp); + for (i = 0; i < length; i++) + es_fprintf (listfp, " %d", buffer[i]); + break; case SIGSUBPKT_REV_KEY: es_fputs ("revocation key: ", listfp); if (length < 22) @@ -1554,6 +1591,7 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type) case SIGSUBPKT_KEY_FLAGS: case SIGSUBPKT_KS_FLAGS: case SIGSUBPKT_PREF_SYM: + case SIGSUBPKT_PREF_AEAD: case SIGSUBPKT_PREF_HASH: case SIGSUBPKT_PREF_COMPR: case SIGSUBPKT_POLICY: @@ -1636,6 +1674,7 @@ can_handle_critical (const byte * buffer, size_t n, int type) case SIGSUBPKT_ISSUER: /* issuer key ID */ case SIGSUBPKT_ISSUER_FPR: /* issuer fingerprint */ case SIGSUBPKT_PREF_SYM: + case SIGSUBPKT_PREF_AEAD: case SIGSUBPKT_PREF_HASH: case SIGSUBPKT_PREF_COMPR: case SIGSUBPKT_KEY_FLAGS: @@ -3170,6 +3209,9 @@ parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen, ed->buf = NULL; ed->new_ctb = new_ctb; ed->is_partial = partial; + ed->aead_algo = 0; + ed->cipher_algo = 0; /* Only used with AEAD. */ + ed->chunkbyte = 0; /* Only used with AEAD. */ if (pkttype == PKT_ENCRYPTED_MDC) { /* Fixme: add some pktlen sanity checks. */ @@ -3261,6 +3303,81 @@ parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen, } +static gpg_error_t +parse_encrypted_aead (iobuf_t inp, int pkttype, unsigned long pktlen, + PACKET *pkt, int partial) +{ + int rc = 0; + PKT_encrypted *ed; + unsigned long orig_pktlen = pktlen; + int version; + + ed = pkt->pkt.encrypted = xtrymalloc (sizeof *pkt->pkt.encrypted); + if (!ed) + return gpg_error_from_syserror (); + ed->len = 0; + ed->extralen = 0; /* (only used in build_packet.) */ + ed->buf = NULL; + ed->new_ctb = 1; /* (packet number requires a new CTB anyway.) */ + ed->is_partial = partial; + ed->mdc_method = 0; + /* A basic sanity check. We need one version byte, one algo byte, + * one aead algo byte, one chunkbyte, at least 15 byte IV. */ + if (orig_pktlen && pktlen < 19) + { + log_error ("packet(%d) too short\n", pkttype); + if (list_mode) + es_fputs (":aead encrypted packet: [too short]\n", listfp); + rc = gpg_error (GPG_ERR_INV_PACKET); + iobuf_skip_rest (inp, pktlen, partial); + goto leave; + } + + version = iobuf_get_noeof (inp); + if (orig_pktlen) + pktlen--; + if (version != 1) + { + log_error ("aead encrypted packet with unknown version %d\n", + version); + if (list_mode) + es_fputs (":aead encrypted packet: [unknown version]\n", listfp); + /*skip_rest(inp, pktlen); should we really do this? */ + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + + ed->cipher_algo = iobuf_get_noeof (inp); + if (orig_pktlen) + pktlen--; + ed->aead_algo = iobuf_get_noeof (inp); + if (orig_pktlen) + pktlen--; + ed->chunkbyte = iobuf_get_noeof (inp); + if (orig_pktlen) + pktlen--; + + /* Store the remaining length of the encrypted data. We read the + * rest during decryption. */ + ed->len = pktlen; + + if (list_mode) + { + es_fprintf (listfp, ":aead encrypted packet: cipher=%u aead=%u cb=%u\n", + ed->cipher_algo, ed->aead_algo, ed->chunkbyte); + if (orig_pktlen) + es_fprintf (listfp, "\tlength: %lu\n", orig_pktlen); + else + es_fprintf (listfp, "\tlength: unknown\n"); + } + + ed->buf = inp; + + leave: + return rc; +} + + /* * This packet is internally generated by us (in armor.c) to transfer * some information to the lower layer. To make sure that this packet diff --git a/g10/pkclist.c b/g10/pkclist.c index dc19204de..8b5d0422a 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -1468,9 +1468,12 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype, support. All this doesn't mean IDEA is actually available, of course. */ implicit=CIPHER_ALGO_3DES; - break; + case PREFTYPE_AEAD: + /* No implicit algo. */ + break; + case PREFTYPE_HASH: /* While I am including this code for completeness, note that currently --pgp2 mode locks the hash at MD5, so this @@ -1553,6 +1556,8 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype, prefs=NULL; if(preftype==PREFTYPE_SYM && opt.personal_cipher_prefs) prefs=opt.personal_cipher_prefs; + else if(preftype==PREFTYPE_AEAD && opt.personal_aead_prefs) + prefs=opt.personal_aead_prefs; else if(preftype==PREFTYPE_HASH && opt.personal_digest_prefs) prefs=opt.personal_digest_prefs; else if(preftype==PREFTYPE_ZIP && opt.personal_compress_prefs) @@ -1646,6 +1651,32 @@ select_mdc_from_pklist (PK_LIST pk_list) } +/* Select the AEAD flag from the pk_list. We can only use AEAD if all + * recipients support this feature. Returns the AEAD to be used or 0 + * if AEAD shall not be used. */ +aead_algo_t +select_aead_from_pklist (PK_LIST pk_list) +{ + pk_list_t pkr; + int aead; + + if (!pk_list) + return 0; + + for (pkr = pk_list; pkr; pkr = pkr->next) + { + if (pkr->pk->user_id) /* selected by user ID */ + aead = pkr->pk->user_id->flags.aead; + else + aead = pkr->pk->flags.aead; + if (!aead) + return 0; /* At least one recipient does not support it. */ + } + + return default_aead_algo (); /* Yes, AEAD can be used. */ +} + + /* Print a warning for all keys in PK_LIST missing the MDC feature. */ void warn_missing_mdc_from_pklist (PK_LIST pk_list) diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index d7ba95391..0185097a4 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -255,7 +255,7 @@ get_it (ctrl_t ctrl, * CSUM */ if (DBG_CRYPTO) - log_printhex ("DEK frame:", frame, nframe); + log_printhex (frame, nframe, "DEK frame:"); n = 0; if (sk->pubkey_algo == PUBKEY_ALGO_ECDH) @@ -361,7 +361,7 @@ get_it (ctrl_t ctrl, if (DBG_CLOCK) log_clock ("decryption ready"); if (DBG_CRYPTO) - log_printhex ("DEK is:", dek->key, dek->keylen); + log_printhex (dek->key, dek->keylen, "DEK is:"); /* Check that the algo is in the preferences and whether it has * expired. Also print a status line with the key's fingerprint. */ diff --git a/g10/sig-check.c b/g10/sig-check.c index e5de025ca..fc6983993 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -210,33 +210,32 @@ check_signature2 (ctrl_t ctrl, } - if (!rc && sig->sig_class < 2 && is_status_enabled ()) - { - /* This signature id works best with DLP algorithms because - * they use a random parameter for every signature. Instead of - * this sig-id we could have also used the hash of the document - * and the timestamp, but the drawback of this is, that it is - * not possible to sign more than one identical document within - * one second. Some remote batch processing applications might - * like this feature here. - * - * Note that before 2.0.10, we used RIPE-MD160 for the hash - * and accidentally didn't include the timestamp and algorithm - * information in the hash. Given that this feature is not - * commonly used and that a replay attacks detection should - * not solely be based on this feature (because it does not - * work with RSA), we take the freedom and switch to SHA-1 - * with 2.0.10 to take advantage of hardware supported SHA-1 - * implementations. We also include the missing information - * in the hash. Note also the SIG_ID as computed by gpg 1.x - * and gpg 2.x didn't matched either because 2.x used to print - * MPIs not in PGP format. */ - u32 a = sig->timestamp; - int nsig = pubkey_get_nsig (sig->pubkey_algo); - unsigned char *p, *buffer; - size_t n, nbytes; - int i; - char hashbuf[20]; + if( !rc && sig->sig_class < 2 && is_status_enabled() ) { + /* This signature id works best with DLP algorithms because + * they use a random parameter for every signature. Instead of + * this sig-id we could have also used the hash of the document + * and the timestamp, but the drawback of this is, that it is + * not possible to sign more than one identical document within + * one second. Some remote batch processing applications might + * like this feature here. + * + * Note that before 2.0.10, we used RIPE-MD160 for the hash + * and accidentally didn't include the timestamp and algorithm + * information in the hash. Given that this feature is not + * commonly used and that a replay attacks detection should + * not solely be based on this feature (because it does not + * work with RSA), we take the freedom and switch to SHA-1 + * with 2.0.10 to take advantage of hardware supported SHA-1 + * implementations. We also include the missing information + * in the hash. Note also the SIG_ID as computed by gpg 1.x + * and gpg 2.x didn't matched either because 2.x used to print + * MPIs not in PGP format. */ + u32 a = sig->timestamp; + int nsig = pubkey_get_nsig( sig->pubkey_algo ); + unsigned char *p, *buffer; + size_t n, nbytes; + int i; + char hashbuf[20]; /* We use SHA-1 here. */ nbytes = 6; for (i=0; i < nsig; i++ ) @@ -521,25 +520,29 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig, gcry_md_putc (digest, 0); n = 6; } - /* Add some magic per Section 5.2.4 of RFC 4880. */ - buf[0] = sig->version; - buf[1] = 0xff; - buf[2] = n >> 24; - buf[3] = n >> 16; - buf[4] = n >> 8; - buf[5] = n; - gcry_md_write( digest, buf, 6 ); + /* add some magic per Section 5.2.4 of RFC 4880. */ + buf[0] = sig->version; + buf[1] = 0xff; + buf[2] = n >> 24; + buf[3] = n >> 16; + buf[4] = n >> 8; + buf[5] = n; + gcry_md_write( digest, buf, 6 ); } - gcry_md_final( digest ); - - /* Convert the digest to an MPI. */ - result = encode_md_value (pk, digest, sig->digest_algo ); - if (!result) - return GPG_ERR_GENERAL; - - /* Verify the signature. */ - rc = pk_verify (pk->pubkey_algo, result, sig->data, pk->pkey); - gcry_mpi_release (result); + gcry_md_final( digest ); + + /* Convert the digest to an MPI. */ + result = encode_md_value (pk, digest, sig->digest_algo ); + if (!result) + return GPG_ERR_GENERAL; + + /* Verify the signature. */ + if (DBG_CLOCK && sig->sig_class <= 0x01) + log_clock ("enter pk_verify"); + rc = pk_verify( pk->pubkey_algo, result, sig->data, pk->pkey ); + if (DBG_CLOCK && sig->sig_class <= 0x01) + log_clock ("leave pk_verify"); + gcry_mpi_release (result); if (!rc && sig->flags.unknown_critical) { diff --git a/g10/sign.c b/g10/sign.c index 4cf0cd39a..df71ccce1 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -1326,9 +1326,6 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr) s2k->hash_algo = S2K_DIGEST_ALGO; algo = default_cipher_algo(); - if (!opt.quiet || !opt.batch) - log_info (_("%s encryption will be used\n"), - openpgp_cipher_algo_name (algo) ); cfx.dek = passphrase_to_dek (algo, s2k, 1, 1, NULL, &canceled); if (!cfx.dek || !cfx.dek->keylen) { @@ -1337,7 +1334,15 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr) goto leave; } - cfx.dek->use_mdc = use_mdc (NULL, cfx.dek->algo); + cfx.dek->use_aead = use_aead (NULL, cfx.dek->algo); + if (!cfx.dek->use_aead) + cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo); + + if (!opt.quiet || !opt.batch) + log_info (_("%s.%s encryption will be used\n"), + openpgp_cipher_algo_name (algo), + cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead) + /**/ : "CFB"); /* now create the outfile */ rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out); @@ -1376,12 +1381,15 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr) } /* Push the encryption filter */ - iobuf_push_filter( out, cipher_filter, &cfx ); + iobuf_push_filter (out, + cfx.dek->use_aead? cipher_filter_aead + /**/ : cipher_filter_cfb, + &cfx); /* Push the compress filter */ if (default_compress_algo()) { - if (cfx.dek && cfx.dek->use_mdc) + if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead)) zfx.new_ctb = 1; push_compress_filter (out, &zfx,default_compress_algo() ); } diff --git a/g10/tdbdump.c b/g10/tdbdump.c index 2c6f5c2fa..73a6c2c57 100644 --- a/g10/tdbdump.c +++ b/g10/tdbdump.c @@ -129,7 +129,7 @@ import_ownertrust (ctrl_t ctrl, const char *fname ) char *p; size_t n, fprlen; unsigned int otrust; - byte fpr[20]; + byte fpr[MAX_FINGERPRINT_LEN]; int any = 0; int rc; @@ -171,7 +171,7 @@ import_ownertrust (ctrl_t ctrl, const char *fname ) continue; } fprlen = p - line; - if( fprlen != 32 && fprlen != 40 ) { + if( fprlen != 32 && fprlen != 40 && fprlen != 64) { log_error (_("error in '%s': %s\n"), fname, _("invalid fingerprint") ); continue; @@ -183,10 +183,12 @@ import_ownertrust (ctrl_t ctrl, const char *fname ) } if( !otrust ) continue; /* no otrust defined - no need to update or insert */ - /* convert the ascii fingerprint to binary */ - for(p=line, fprlen=0; fprlen < 20 && *p != ':'; p += 2 ) - fpr[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]); - while (fprlen < 20) + /* Convert the ascii fingerprint to binary */ + for(p=line, fprlen=0; + fprlen < MAX_FINGERPRINT_LEN && *p != ':'; + p += 2 ) + fpr[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]); + while (fprlen < MAX_FINGERPRINT_LEN) fpr[fprlen++] = 0; rc = tdbio_search_trust_byfpr (ctrl, fpr, &rec); diff --git a/g10/tofu.c b/g10/tofu.c index 091d5b0d0..762b19b7a 100644 --- a/g10/tofu.c +++ b/g10/tofu.c @@ -2083,13 +2083,16 @@ build_conflict_set (ctrl_t ctrl, tofu_dbs_t dbs, * policy to ask due to a conflict. */ for (iter = conflict_set; iter; iter = iter->next) { + /* Fixme: Why the check against N+1? */ int l = strlen (iter->d); - if (!(l == 2 * MAX_FINGERPRINT_LEN - || l == 2 * MAX_FINGERPRINT_LEN + 1)) + if (!(l == 2 * 20 + || l == 2 * 20 + 1 + || l == 2 * 32 + || l == 2 * 32 + 1)) { log_error (_("TOFU db corruption detected.\n")); - print_further_info ("fingerprint '%s' is not %d characters long", - iter->d, 2 * MAX_FINGERPRINT_LEN); + print_further_info ("fingerprint '%s' is %d characters long", + iter->d, l); } if (l >= 1 && iter->d[l - 1] == '!') @@ -2469,10 +2472,11 @@ get_policy (ctrl_t ctrl, tofu_dbs_t dbs, PKT_public_key *pk, /* See if the key is signed by an ultimately trusted key. */ { int fingerprint_raw_len = strlen (fingerprint) / 2; - char fingerprint_raw[20]; + char fingerprint_raw[MAX_FINGERPRINT_LEN]; int len = 0; - if (fingerprint_raw_len != sizeof fingerprint_raw + /* FIXME(fingerprint) */ + if (fingerprint_raw_len != 20 /*sizeof fingerprint_raw */ || ((len = hex2bin (fingerprint, fingerprint_raw, fingerprint_raw_len)) != strlen (fingerprint))) @@ -3210,7 +3214,7 @@ show_statistics (tofu_dbs_t dbs, *p = ' '; } - log_string (GPGRT_LOG_INFO, msg); + log_string (GPGRT_LOGLVL_INFO, msg); xfree (msg); if (policy == TOFU_POLICY_AUTO) @@ -3275,7 +3279,7 @@ show_warning (const char *fingerprint, strlist_t user_id_list) log_fatal ("format failed: %s\n", gpg_strerror (gpg_error_from_syserror())); xfree (tmpmsg); - log_string (GPGRT_LOG_INFO, text); + log_string (GPGRT_LOGLVL_INFO, text); xfree (text); es_free (set_policy_command); diff --git a/g13/call-syshelp.c b/g13/call-syshelp.c index 8a50c3ff4..b160ba32d 100644 --- a/g13/call-syshelp.c +++ b/g13/call-syshelp.c @@ -366,7 +366,7 @@ create_inq_cb (void *opaque, const char *line) void *ciphertext; size_t ciphertextlen; - log_printhex ("plain", plaintext, plaintextlen); + log_printhex (plaintext, plaintextlen, "plain"); err = g13_encrypt_keyblob (parm->ctrl, plaintext, plaintextlen, &ciphertext, &ciphertextlen); diff --git a/g13/g13tuple.c b/g13/g13tuple.c index b10ebbc9a..6693826ad 100644 --- a/g13/g13tuple.c +++ b/g13/g13tuple.c @@ -318,7 +318,7 @@ dump_tupledesc (tupledesc_t tuples) if (n < 100 && all_printable (value, n)) log_printf ("%.*s\n", (int)n, (const char*)value); else - log_printhex ("", value, n); + log_printhex (value, n, ""); break; case KEYBLOB_TAG_CONT_NSEC: @@ -327,11 +327,11 @@ dump_tupledesc (tupledesc_t tuples) if (!convert_uint (value, n, &uint)) log_printf ("%llu\n", uint); else - log_printhex ("", value, n); + log_printhex (value, n, ""); break; default: - log_printhex ("", value, n); + log_printhex (value, n, ""); break; } } diff --git a/kbx/kbxutil.c b/kbx/kbxutil.c index 07774f2d9..2cfd07019 100644 --- a/kbx/kbxutil.c +++ b/kbx/kbxutil.c @@ -137,14 +137,14 @@ my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr) /* Map the log levels. */ switch (level) { - case GCRY_LOG_CONT: level = GPGRT_LOG_CONT; break; - case GCRY_LOG_INFO: level = GPGRT_LOG_INFO; break; - case GCRY_LOG_WARN: level = GPGRT_LOG_WARN; break; - case GCRY_LOG_ERROR:level = GPGRT_LOG_ERROR; break; - case GCRY_LOG_FATAL:level = GPGRT_LOG_FATAL; break; - case GCRY_LOG_BUG: level = GPGRT_LOG_BUG; break; - case GCRY_LOG_DEBUG:level = GPGRT_LOG_DEBUG; break; - default: level = GPGRT_LOG_ERROR; break; + case GCRY_LOG_CONT: level = GPGRT_LOGLVL_CONT; break; + case GCRY_LOG_INFO: level = GPGRT_LOGLVL_INFO; break; + case GCRY_LOG_WARN: level = GPGRT_LOGLVL_WARN; break; + case GCRY_LOG_ERROR:level = GPGRT_LOGLVL_ERROR; break; + case GCRY_LOG_FATAL:level = GPGRT_LOGLVL_FATAL; break; + case GCRY_LOG_BUG: level = GPGRT_LOGLVL_BUG; break; + case GCRY_LOG_DEBUG:level = GPGRT_LOGLVL_DEBUG; break; + default: level = GPGRT_LOGLVL_ERROR; break; } log_logv (level, fmt, arg_ptr); } diff --git a/scd/apdu.c b/scd/apdu.c index cd98cc91c..66a16f820 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -473,7 +473,7 @@ dump_reader_status (int slot) if (reader_table[slot].atrlen) { log_info ("slot %d: ATR=", slot); - log_printhex ("", reader_table[slot].atr, reader_table[slot].atrlen); + log_printhex (reader_table[slot].atr, reader_table[slot].atrlen, ""); } } @@ -499,6 +499,7 @@ host_sw_string (long err) case SW_HOST_ABORTED: return "aborted"; case SW_HOST_NO_PINPAD: return "no pinpad"; case SW_HOST_ALREADY_CONNECTED: return "already connected"; + case SW_HOST_CANCELLED: return "cancelled"; default: return "unknown host status error"; } } @@ -605,7 +606,7 @@ pcsc_error_to_sw (long ec) { case 0: rc = 0; break; - case PCSC_E_CANCELLED: rc = SW_HOST_ABORTED; break; + case PCSC_E_CANCELLED: rc = SW_HOST_CANCELLED; break; case PCSC_E_NO_MEMORY: rc = SW_HOST_OUT_OF_CORE; break; case PCSC_E_TIMEOUT: rc = SW_HOST_CARD_IO_ERROR; break; case PCSC_E_NO_SERVICE: @@ -736,7 +737,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, return err; if (DBG_CARD_IO) - log_printhex (" PCSC_data:", apdu, apdulen); + log_printhex (apdu, apdulen, " PCSC_data:"); if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1)) send_pci.protocol = PCSC_PROTOCOL_T1; @@ -1440,7 +1441,7 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen, return err; if (DBG_CARD_IO) - log_printhex (" raw apdu:", apdu, apdulen); + log_printhex (apdu, apdulen, " raw apdu:"); maxbuflen = *buflen; if (pininfo) @@ -1709,7 +1710,7 @@ my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen, *buflen = 0; if (DBG_CARD_IO) - log_printhex (" APDU_data:", apdu, apdulen); + log_printhex (apdu, apdulen, " APDU_data:"); if (apdulen < 4) { @@ -2842,7 +2843,7 @@ send_le (int slot, int class, int ins, int p0, int p1, log_debug (" response: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen); if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA)) - log_printhex (" dump: ", result, resultlen); + log_printhex (result, resultlen, " dump: "); } if (sw == SW_SUCCESS || sw == SW_EOF_REACHED) @@ -2915,7 +2916,7 @@ send_le (int slot, int class, int ins, int p0, int p1, log_debug (" more: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen); if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA)) - log_printhex (" dump: ", result, resultlen); + log_printhex (result, resultlen, " dump: "); } if ((sw & 0xff00) == SW_MORE_DATA @@ -2961,7 +2962,7 @@ send_le (int slot, int class, int ins, int p0, int p1, xfree (result_buffer); if (DBG_CARD_IO && retbuf && sw == SW_SUCCESS) - log_printhex (" dump: ", *retbuf, *retbuflen); + log_printhex (*retbuf, *retbuflen, " dump: "); return sw; } @@ -3121,7 +3122,7 @@ apdu_send_direct (int slot, size_t extended_length, log_debug (" response: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen); if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA)) - log_printhex (" dump: ", result, resultlen); + log_printhex (result, resultlen, " dump: "); } if (handle_more && (sw & 0xff00) == SW_MORE_DATA) @@ -3177,7 +3178,7 @@ apdu_send_direct (int slot, size_t extended_length, log_debug (" more: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen); if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA)) - log_printhex (" dump: ", result, resultlen); + log_printhex (result, resultlen, " dump: "); } if ((sw & 0xff00) == SW_MORE_DATA @@ -3246,7 +3247,7 @@ apdu_send_direct (int slot, size_t extended_length, } if (DBG_CARD_IO && retbuf) - log_printhex (" dump: ", *retbuf, *retbuflen); + log_printhex (*retbuf, *retbuflen, " dump: "); return 0; } diff --git a/scd/apdu.h b/scd/apdu.h index 6751e8c9b..8a0d4bda8 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -71,7 +71,8 @@ enum { SW_HOST_NO_READER = 0x1000c, SW_HOST_ABORTED = 0x1000d, SW_HOST_NO_PINPAD = 0x1000e, - SW_HOST_ALREADY_CONNECTED = 0x1000f + SW_HOST_ALREADY_CONNECTED = 0x1000f, + SW_HOST_CANCELLED = 0x10010 }; struct dev_list; diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 9fcfa191e..c17452555 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -98,7 +98,7 @@ static struct { { 0x0065, 1, 0, 1, 0, 0, 0, 0, "Cardholder Related Data"}, { 0x005B, 0, 0x65, 0, 0, 0, 0, 0, "Name" }, { 0x5F2D, 0, 0x65, 0, 0, 0, 0, 0, "Language preferences" }, - { 0x5F35, 0, 0x65, 0, 0, 0, 0, 0, "Sex" }, + { 0x5F35, 0, 0x65, 0, 0, 0, 0, 0, "Salutation" }, { 0x006E, 1, 0, 1, 0, 0, 0, 0, "Application Related Data" }, { 0x004F, 0, 0x6E, 1, 0, 0, 0, 0, "AID" }, { 0x0073, 1, 0, 1, 0, 0, 0, 0, "Discretionary Data Objects" }, @@ -563,7 +563,7 @@ dump_all_do (int slot) if (data_objects[i].binary) { log_info ("DO '%s': ", data_objects[i].desc); - log_printhex ("", buffer, buflen); + log_printhex (buffer, buflen, ""); } else log_info ("DO '%s': '%.*s'\n", @@ -593,7 +593,7 @@ dump_all_do (int slot) if (valuelen > 200) log_info ("[%u]\n", (unsigned int)valuelen); else - log_printhex ("", value, valuelen); + log_printhex (value, valuelen, ""); } else log_info ("DO '%s': '%.*s'\n", @@ -5081,7 +5081,7 @@ parse_algorithm_attribute (app_t app, int keyno) curve = ecc_curve (buffer + 1, oidlen); if (!curve) - log_printhex ("Curve with OID not supported: ", buffer+1, buflen-1); + log_printhex (buffer+1, buflen-1, "Curve with OID not supported: "); else { app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECC; @@ -5099,7 +5099,7 @@ parse_algorithm_attribute (app_t app, int keyno) } } else if (opt.verbose) - log_printhex ("", buffer, buflen); + log_printhex (buffer, buflen, ""); xfree (relptr); } @@ -5141,7 +5141,7 @@ app_select_openpgp (app_t app) if (opt.verbose) { log_info ("AID: "); - log_printhex ("", buffer, buflen); + log_printhex (buffer, buflen, ""); } app->card_version = buffer[6] << 8; @@ -5174,7 +5174,7 @@ app_select_openpgp (app_t app) if (opt.verbose) { log_info ("Historical Bytes: "); - log_printhex ("", buffer, buflen); + log_printhex (buffer, buflen, ""); } parse_historical (app->app_local, buffer, buflen); xfree (relptr); diff --git a/scd/app-p15.c b/scd/app-p15.c index 0bb5f9e51..190292433 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -2274,7 +2274,7 @@ read_ef_tokeninfo (app_t app) } memcpy (app->app_local->serialno, p, objlen); app->app_local->serialnolen = objlen; - log_printhex ("Serialnumber from EF(TokenInfo) is:", p, objlen); + log_printhex (p, objlen, "Serialnumber from EF(TokenInfo) is:"); leave: xfree (buffer); @@ -2781,7 +2781,7 @@ micardo_mse (app_t app, unsigned short fid) gpg_strerror (err)); return err; } - log_printhex ("keyD record:", buffer, buflen); + log_printhex (buffer, buflen, "keyD record:"); p = find_tlv (buffer, buflen, 0x83, &n); if (p && n == 4 && ((p[2]<<8)|p[3]) == fid) { diff --git a/scd/iso7816.c b/scd/iso7816.c index 081b0808c..29208c254 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -93,8 +93,9 @@ map_sw (int sw) case SW_HOST_CARD_IO_ERROR: ec = GPG_ERR_EIO; break; case SW_HOST_GENERAL_ERROR: ec = GPG_ERR_GENERAL; break; case SW_HOST_NO_READER: ec = GPG_ERR_ENODEV; break; - case SW_HOST_ABORTED: ec = GPG_ERR_CANCELED; break; + case SW_HOST_ABORTED: ec = GPG_ERR_INV_RESPONSE; break; case SW_HOST_NO_PINPAD: ec = GPG_ERR_NOT_SUPPORTED; break; + case SW_HOST_CANCELLED: ec = GPG_ERR_CANCELED; break; default: if ((sw & 0x010000)) diff --git a/sm/certchain.c b/sm/certchain.c index a361acaf0..4e18caf55 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -119,7 +119,8 @@ do_list (int is_error, int listmode, estream_t fp, const char *format, ...) } else { - log_logv (is_error? GPGRT_LOG_ERROR: GPGRT_LOG_INFO, format, arg_ptr); + log_logv (is_error? GPGRT_LOGLVL_ERROR: GPGRT_LOGLVL_INFO, + format, arg_ptr); log_printf ("\n"); } va_end (arg_ptr); diff --git a/sm/certcheck.c b/sm/certcheck.c index 1102bccad..51f1a9402 100644 --- a/sm/certcheck.c +++ b/sm/certcheck.c @@ -374,7 +374,7 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval, return gpg_error (GPG_ERR_BUG); } if (DBG_CRYPTO) - log_printhex ("public key: ", p, n); + log_printhex (p, n, "public key: "); rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n); ksba_free (p); diff --git a/sm/certdump.c b/sm/certdump.c index edee76fa2..9567c67f5 100644 --- a/sm/certdump.c +++ b/sm/certdump.c @@ -167,7 +167,7 @@ gpgsm_dump_string (const char *string) else { log_printf ( "[ "); - log_printhex (NULL, string, strlen (string)); + log_printhex (string, strlen (string), NULL); log_printf ( " ]"); } } diff --git a/sm/certreqgen-ui.c b/sm/certreqgen-ui.c index 9772a3baf..4f8a1ac9d 100644 --- a/sm/certreqgen-ui.c +++ b/sm/certreqgen-ui.c @@ -138,7 +138,7 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream) unsigned int nbits; int minbits = 1024; int maxbits = 4096; - int defbits = 2048; + int defbits = 3072; const char *keyusage; char *subject_name; membuf_t mb_email, mb_dns, mb_uri, mb_result; diff --git a/sm/certreqgen.c b/sm/certreqgen.c index 44318702a..1d610c1bb 100644 --- a/sm/certreqgen.c +++ b/sm/certreqgen.c @@ -26,7 +26,7 @@ $ cat >foo <<EOF %echo Generating a standard key Key-Type: RSA - Key-Length: 2048 + Key-Length: 3072 Name-DN: CN=test cert 1,OU=Aegypten Project,O=g10 Code GmbH,L=Ddorf,C=DE Name-Email: [email protected] # Do a commit here, so that we can later print a "done" @@ -468,7 +468,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, /* Check the keylength. NOTE: If you change this make sure that it macthes the gpgconflist item in gpgsm.c */ if (!get_parameter (para, pKEYLENGTH, 0)) - nbits = 2048; + nbits = 3072; else nbits = get_parameter_uint (para, pKEYLENGTH); if ((nbits < 1024 || nbits > 4096) && !cardkeyid) diff --git a/sm/decrypt.c b/sm/decrypt.c index 60ed14a64..b0ab63f00 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -72,7 +72,7 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc, } if (DBG_CRYPTO) - log_printhex ("pkcs1 encoded session key:", seskey, seskeylen); + log_printhex (seskey, seskeylen, "pkcs1 encoded session key:"); n=0; if (seskeylen == 24 || seskeylen == 16) @@ -115,7 +115,7 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc, } if (DBG_CRYPTO) - log_printhex ("session key:", seskey+n, seskeylen-n); + log_printhex (seskey+n, seskeylen-n, "session key:"); rc = gcry_cipher_open (&parm->hd, parm->algo, parm->mode, 0); if (rc) diff --git a/sm/fingerprint.c b/sm/fingerprint.c index fbcec5883..4bf378a1c 100644 --- a/sm/fingerprint.c +++ b/sm/fingerprint.c @@ -196,7 +196,7 @@ gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array) return NULL; } if (DBG_X509) - log_printhex ("keygrip=", array, 20); + log_printhex (array, 20, "keygrip="); return array; } @@ -277,6 +277,70 @@ gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits) } +/* If KEY is an RSA key, return its modulus. For non-RSA keys or on + * error return NULL. */ +gcry_mpi_t +gpgsm_get_rsa_modulus (ksba_cert_t cert) +{ + gpg_error_t err; + gcry_sexp_t key; + gcry_sexp_t list = NULL; + gcry_sexp_t l2 = NULL; + char *name = NULL; + gcry_mpi_t modulus = NULL; + + { + ksba_sexp_t ckey; + size_t n; + + ckey = ksba_cert_get_public_key (cert); + if (!ckey) + return NULL; + n = gcry_sexp_canon_len (ckey, 0, NULL, NULL); + if (!n) + { + xfree (ckey); + return NULL; + } + err = gcry_sexp_sscan (&key, NULL, (char *)ckey, n); + xfree (ckey); + if (err) + return NULL; + } + + list = gcry_sexp_find_token (key, "public-key", 0); + if (!list) + list = gcry_sexp_find_token (key, "private-key", 0); + if (!list) + list = gcry_sexp_find_token (key, "protected-private-key", 0); + if (!list) + list = gcry_sexp_find_token (key, "shadowed-private-key", 0); + + gcry_sexp_release (key); + if (!list) + return NULL; /* No suitable key. */ + + l2 = gcry_sexp_cadr (list); + gcry_sexp_release (list); + list = l2; + l2 = NULL; + + name = gcry_sexp_nth_string (list, 0); + if (!name) + ; + else if (gcry_pk_map_name (name) == GCRY_PK_RSA) + { + l2 = gcry_sexp_find_token (list, "n", 1); + if (l2) + modulus = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); + } + + gcry_free (name); + gcry_sexp_release (l2); + gcry_sexp_release (list); + return modulus; +} + /* For certain purposes we need a certificate id which has an upper diff --git a/sm/gpgsm.c b/sm/gpgsm.c index da1783df2..b0547876a 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -156,6 +156,7 @@ enum cmd_and_opt_values { oWithMD5Fingerprint, oWithKeygrip, oWithSecret, + oWithKeyScreening, oAnswerYes, oAnswerNo, oKeyring, @@ -393,6 +394,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"), ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"), ARGPARSE_s_n (oWithSecret, "with-secret", "@"), + ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"), ARGPARSE_s_s (oDisableCipherAlgo, "disable-cipher-algo", "@"), ARGPARSE_s_s (oDisablePubkeyAlgo, "disable-pubkey-algo", "@"), ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"), @@ -1295,6 +1297,10 @@ main ( int argc, char **argv) opt.with_keygrip = 1; break; + case oWithKeyScreening: + opt.with_key_screening = 1; + break; + case oOptions: /* config files may not be nested (silently ignore them) */ if (!configfp) @@ -1800,8 +1806,7 @@ main ( int argc, char **argv) /* The next one is an info only item and should match what proc_parameters actually implements. */ es_printf ("default_pubkey_algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, - "RSA-2048"); - es_printf ("compliance:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, "gnupg"); + "RSA-3072"); } break; diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 325948aff..d3fbde515 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -85,6 +85,8 @@ struct int with_keygrip; /* Option --with-keygrip active. */ + int with_key_screening; /* Option --with-key-screening active. */ + int pinentry_mode; int request_origin; @@ -259,6 +261,7 @@ unsigned long gpgsm_get_short_fingerprint (ksba_cert_t cert, unsigned char *gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array); char *gpgsm_get_keygrip_hexstring (ksba_cert_t cert); int gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits); +gcry_mpi_t gpgsm_get_rsa_modulus (ksba_cert_t cert); char *gpgsm_get_certid (ksba_cert_t cert); diff --git a/sm/import.c b/sm/import.c index 8796cd206..ca693824a 100644 --- a/sm/import.c +++ b/sm/import.c @@ -836,7 +836,7 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats) log_error ("can't calculate keygrip\n"); goto leave; } - log_printhex ("keygrip=", grip, 20); + log_printhex (grip, 20, "keygrip="); /* Convert to canonical encoding using a function which pads it to a multiple of 64 bits. We need this padding for AESWRAP. */ diff --git a/sm/keylist.c b/sm/keylist.c index 9997da812..ea2a22093 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -37,6 +37,7 @@ #include "../common/i18n.h" #include "../common/tlv.h" #include "../common/compliance.h" +#include "../common/pkscreening.h" struct list_external_parm_s { @@ -238,6 +239,38 @@ print_key_data (ksba_cert_t cert, estream_t fp) #endif } + +/* Various public key screenings. (Right now just ROCA). With + * COLON_MODE set the output is formatted for use in the compliance + * field of a colon listing. */ +static void +print_pk_screening (ksba_cert_t cert, int colon_mode, estream_t fp) +{ + gpg_error_t err; + gcry_mpi_t modulus; + + modulus = gpgsm_get_rsa_modulus (cert); + if (modulus) + { + err = screen_key_for_roca (modulus); + if (!err) + ; + else if (gpg_err_code (err) == GPG_ERR_TRUE) + { + if (colon_mode) + es_fprintf (fp, colon_mode > 1? " %d":"%d", 6001); + else + es_fprintf (fp, " screening: ROCA vulnerability detected\n"); + } + else if (!colon_mode) + es_fprintf (fp, " screening: [ROCA check failed: %s]\n", + gpg_strerror (err)); + gcry_mpi_release (modulus); + } + +} + + static void print_capabilities (ksba_cert_t cert, estream_t fp) { @@ -348,10 +381,19 @@ email_kludge (const char *name) /* Print the compliance flags to field 18. ALGO is the gcrypt algo * number. NBITS is the length of the key in bits. */ static void -print_compliance_flags (int algo, unsigned int nbits, estream_t fp) +print_compliance_flags (ksba_cert_t cert, int algo, unsigned int nbits, + estream_t fp) { + int any = 0; + if (gnupg_pk_is_compliant (CO_DE_VS, algo, NULL, nbits, NULL)) - es_fputs (gnupg_status_compliance_flag (CO_DE_VS), fp); + { + es_fputs (gnupg_status_compliance_flag (CO_DE_VS), fp); + any++; + } + + if (opt.with_key_screening) + print_pk_screening (cert, 1+any, fp); } @@ -526,7 +568,7 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity, es_putc (':', fp); /* End of field 15. */ es_putc (':', fp); /* End of field 16. */ es_putc (':', fp); /* End of field 17. */ - print_compliance_flags (algo, nbits, fp); + print_compliance_flags (cert, algo, nbits, fp); es_putc (':', fp); /* End of field 18. */ es_putc ('\n', fp); @@ -1253,6 +1295,9 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret, } } + if (opt.with_key_screening) + print_pk_screening (cert, 0, fp); + if (have_secret) { char *cardsn; diff --git a/sm/qualified.c b/sm/qualified.c index 564e77929..6a7b47306 100644 --- a/sm/qualified.c +++ b/sm/qualified.c @@ -58,7 +58,7 @@ read_list (char *key, char *country, int *lnr) if (!listname) { - listname = make_filename (gnupg_datadir (), "qualified.txt", NULL); + listname = make_filename (gnupg_sysconfdir (), "qualified.txt", NULL); listfp = fopen (listname, "r"); if (!listfp && errno != ENOENT) { diff --git a/sm/verify.c b/sm/verify.c index 10b3f4378..b7b9fa8be 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -512,10 +512,10 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) if (DBG_X509) { if (msgdigest) - log_printhex ("message: ", msgdigest, msgdigestlen); + log_printhex (msgdigest, msgdigestlen, "message: "); if (s) - log_printhex ("computed: ", - s, gcry_md_get_algo_dlen (algo)); + log_printhex (s, gcry_md_get_algo_dlen (algo), + "computed: "); } fpr = gpgsm_fpr_and_name_for_status (cert); gpgsm_status (ctrl, STATUS_BADSIG, fpr); diff --git a/tests/openpgp/Makefile.am b/tests/openpgp/Makefile.am index f6014c9c5..e5be42b41 100644 --- a/tests/openpgp/Makefile.am +++ b/tests/openpgp/Makefile.am @@ -102,9 +102,6 @@ XTESTS = \ issue2929.scm \ issue2941.scm -# Temporary removed tests: -# trust-pgp-4.scm - # XXX: Currently, one cannot override automake's 'check' target. As a # workaround, we avoid defining 'TESTS', thus automake will not emit @@ -268,7 +265,7 @@ sample_msgs = samplemsgs/clearsig-1-key-1.asc \ EXTRA_DIST = defs.scm trust-pgp/common.scm $(XTESTS) $(TEST_FILES) \ mkdemodirs signdemokey $(priv_keys) $(sample_keys) \ - $(sample_msgs) ChangeLog-2011 run-tests.scm trust-pgp-4.scm \ + $(sample_msgs) ChangeLog-2011 run-tests.scm \ setup.scm shell.scm all-tests.scm signed-messages.scm CLEANFILES = prepared.stamp x y yy z out err $(data_files) \ @@ -279,6 +276,12 @@ CLEANFILES = prepared.stamp x y yy z out err $(data_files) \ gnupg-test.stop random_seed gpg-agent.log tofu.db \ passphrases sshcontrol S.gpg-agent.ssh report.xml +if DISABLE_REGEX +EXTRA_DIST += trust-pgp-4.scm +else +XTESTS += trust-pgp-4.scm +endif + clean-local: -rm -rf private-keys-v1.d openpgp-revocs.d tofu.d gpgtar.d diff --git a/tests/openpgp/all-tests.scm b/tests/openpgp/all-tests.scm index d687fe49b..e12b175b9 100644 --- a/tests/openpgp/all-tests.scm +++ b/tests/openpgp/all-tests.scm @@ -48,7 +48,7 @@ (define setup-extended-key-format (setup* "extended-key-format")) (define all-tests - (parse-makefile-expand (in-srcdir "tests" "openpgp" "Makefile.am") + (parse-makefile-expand "Makefile" (lambda (filename port key) (parse-makefile port key)) "XTESTS")) diff --git a/tests/openpgp/armor.scm b/tests/openpgp/armor.scm index 3c117dd10..a1b0aa938 100755 --- a/tests/openpgp/armor.scm +++ b/tests/openpgp/armor.scm @@ -191,7 +191,7 @@ nW1ff9rt1YcTH9LiiE4EGBECAAYFAjnKLe0AEgkQ3uyMCd5BWw4HZUdQRwABAZeBAKDsa7tc (info "Checking armored_key_8192") (pipe:do (pipe:echo armored_key_8192) - (pipe:gpg '(--import))) + (pipe:gpg '(--debug-set-iobuf-size=8 --import))) (define nopad_armored_msg "-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.11-svn5139 (GNU/Linux) @@ -758,10 +758,10 @@ wg7Md81a5RI3F2FG8747t9gX (info "Importing alpha_seckey") (pipe:do (pipe:echo alpha_seckey) - (pipe:gpg '(--import))) + (pipe:gpg '(--debug-set-iobuf-size=8 --import))) (info "Checking for bug #1179") (tr:do (tr:pipe-do (pipe:echo nopad_armored_msg) - (pipe:gpg '(--decrypt)))) + (pipe:gpg '(--debug-set-iobuf-size=8 --decrypt)))) diff --git a/tests/openpgp/defs.scm b/tests/openpgp/defs.scm index 95376521d..afd69a0f3 100644 --- a/tests/openpgp/defs.scm +++ b/tests/openpgp/defs.scm @@ -351,6 +351,7 @@ "allow-preset-passphrase" "no-grab" "enable-ssh-support" + "s2k-count 65536" (if (flag "--extended-key-format" *args*) "enable-extended-key-format" "#enable-extended-key-format") (string-append "pinentry-program " (tool 'pinentry)) diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index b10b146f4..924f90785 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -88,7 +88,7 @@ gc_error (int status, int errnum, const char *fmt, ...) va_list arg_ptr; va_start (arg_ptr, fmt); - log_logv (GPGRT_LOG_ERROR, fmt, arg_ptr); + log_logv (GPGRT_LOGLVL_ERROR, fmt, arg_ptr); va_end (arg_ptr); if (errnum) |